PHP
MySQL

MySQLからSELECTした値をINSERTするときにエスケープは必要か?

コード

<?php

$c = mysql_connect('localhost', 'mysql', 'mysql');
mysql_select_db('testdb');

var_dump($r = mysql_Query('SELECT * FROM test'));
var_dump(mysql_fetch_array($r));
var_dump(mysql_error());

$text = "You can't escape";

echo "これはエラー\n";
$sql = "INSERT INTO test (text) VALUE('" . $text . "')";
echo $sql . "\n";
var_dump(mysql_Query($sql));
var_dump(mysql_error());
echo "\n\n";

echo "これは?\n";
$sql = "INSERT INTO test (text) VALUE('" . mysql_real_escape_string($text) . "')";
echo $sql . "\n";
var_dump(mysql_Query($sql));
var_dump(mysql_error());
echo "\n\n";

echo "入れたtextはどんな値で取得できる?\n";
var_dump($r = mysql_Query('SELECT * FROM test'));
var_dump($a = mysql_fetch_array($r));
var_dump(mysql_error());
echo "\n\n";

echo "値の再利用はどうなる?\n";
$sql = "INSERT INTO test (text) VALUE('" . $a['text'] . "')";
echo $sql . "\n";
var_dump($r = mysql_Query($sql));
var_dump(mysql_fetch_array($r));
var_dump(mysql_error());

出力

resource(8) of type (mysql result)
bool(false)
string(0) ""
これはエラー
INSERT INTO test (text) VALUE('You can't escape')
bool(false)
string(156) "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 't escape')' at line 1"


これは?
INSERT INTO test (text) VALUE('You can\'t escape')
bool(true)
string(0) ""


入れたtextはどんな値で取得できる?
resource(9) of type (mysql result)
array(2) {
  [0]=>
  string(16) "You can't escape"
  ["text"]=>
  string(16) "You can't escape"
}
string(0) ""


値の再利用はどうなる?
INSERT INTO test (text) VALUE('You can't escape')
bool(false)
PHP Warning:  mysql_fetch_array() expects parameter 1 to be resource, boolean given in /tmp/pdo.php on line 36
NULL
string(156) "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 't escape')' at line 1"

結論

mysqliやPDOを使おう
DBに入っていた値でも、エスケープされたままINSERT SELECTされるわけではないので、再利用する場合は再度エスケープしよう。

全体にかけるのも:no_good:

パラメーター増えたときにひとつひとつ長ーい関数にかけるのも辛いので、最終SQLにかけちゃえばいいじゃないか

$text = "You can't escape";
$sql = "INSERT INTO test (text) VALUE('" . $text . "')";
echo mysql_real_escape_string($sql) . "\n";
INSERT INTO test (text) VALUE(\'You can\'t escape\')

はい。そうですね。
あくまで

mysql_real_escape_string() は、MySQL のライブラリ関数 mysql_real_escape_string をコールしています。 これは以下の文字について先頭にバックスラッシュを付加します。 \x00, \n, \r, \, ', " そして \x1a.

ですし、人がどのようなSQLを意図していたかなんてただのstringからではそうそうわからないでしょう。