概要
SQLでは一般にシングルクォート(')
やダブルクォート(")
で文字列を囲う。
1 |
INSERT INTO table(text) VALUES ('text contents'); |
テキストの内容としてクォートを含む場合、そのまま記述したりテキストボックスの入力内容をそのまま使ってしまうと文字列境界との区別がつかず、エラーが発生してしまう。
そこでSQLデータの書き込み時に、SQLとして適切に解釈可能なようにエスケープする必要がある。
シングルクォートのエスケープ
SQLエスケープ
SQL標準では、シングルクォートを文字として扱う場合にクォートを2つ連続させる('')
。
PHPからSQLを操作する際にシングルクォートを含む文字列をリテラルとして扱う場合、以下のような方法がある。
- query文字列をダブルクォート
(")
で囲う - テキストリテラルをシングルクォート
(')
で囲う - テキストリテラル中のシングルクォートはこれを2回続けて
('')
SQL標準でエスケープする
1 2 3 4 |
$query = "INSERT INTO test_text_table(text) VALUES ('I''m fine.')"; mysqli_query($dblink, $query); // I'm fine. |
定義済み関数によるエスケープ
PHPの文字列として扱う場合、シングルクォートをバックスラッシュでエスケープすることができる(\')
。この場合、リテラルの解釈後には1文字のシングルクォートとして扱われる。また、テキストボックスに入力された文字列にクォートが入っているケースも考えられる。
ところで、このような文字列をそのままquery構文に渡してしまうとSQLが文字列境界として扱うので不都合が生じる。そこで、PHPに準備されたエスケープ用の関数を使う。この関数の手続き型の構文は以下の通り。
$escaped_string = mysqli_real_escape_string($dblink, $original_string);
第1引数にmysqli_connect()
で得られるデータベースリンクが必要な点に注意。
たとえばターゲットの文字列をPHPの変数として扱う場合、以下の手順が考えられる。
- クォートを含む可能性がある文字列を
mysqli_real_escape_string()
関数でエスケープする- リテラルとして文字列を準備する場合は、シングルクォートで囲い、文字列中のシングルクォートをバックスラッシュでエスケープする
- queryに文字列変数を渡す際に
- 文字列変数の内容がシングルクォートで囲われるようにする
- そのため、文字列前後の構文をダブルクォートで囲う
1 2 3 4 5 |
$string = mysqli_real_escape_string($dblink, 'I\'m fine.'); $query = "INSERT INTO test_text_table(text) VALUES ('" . $string . "')"; mysqli_query($dblink, $query); // I'm fine. |
ダブルクォートのエスケープ
ダブルクォートもSQLでは文字列境界として扱われるので、queryの構文中にリテラルで書くとエラーとなる。
テキストボックスなどからの入力の場合はそのままmysqli_real_escape_string()
でエスケープするといいが、リテラルの場合は全体をシングルクォートで囲ってやるとよい。
1 2 3 4 5 |
$string = mysqli_real_escape_string($dblink, 'He said "I\'m fine."'); $query = "INSERT INTO test_text_table(text) VALUES ('" . $string . "')"; mysqli_query($dblink, $query); // He said "I'm fine." |
読み込み時
エスケープされた文字列がSQLで保存されると、クォートが1つずつの文字列として記録されている。それらを含むテキストをフェッチして変数に代入すると、適正に表示される。
1 2 3 4 5 6 7 8 9 10 |
$query = 'SELECT id, text FROM test_text_table'; $query_result = mysqli_query($dblink, $query); while ($record = mysqli_fetch_assoc($query_result)) { echo $record['id'] . '-' . $record['text'] . '<br>'; } mysqli_free_result($query_result); // 1-I'm fine. // 2-I'm fine. // 3-He said "I'm fine." |