如何通过PDO *转义字符串以插入MySQL而不使用预处理语句(遗留应用程序)

时间:2016-09-21 08:56:25

标签: php mysql pdo

我知道准备好的陈述是要走的路,但我有一个很大的遗留应用程序,我正在转换。

我已经将它从mysqli更改为PDO作为第一步,现在将其中的所有查询转换为预准备语句。但是有数百个,所以需要时间。

在此期间,我应该使用什么函数来转义字符串?

我尝试了$PDO->quote,但似乎做了两件事:

1)用引号括起一个字符串 2)转换'在字符串中\'

我可以轻松地修剪开始/结束报价,但最后我得到了结果。被插入数据库。我认为正确的逃避将是转换'到了',所以我不确定为什么要反斜杠?

我知道这是可怕的,但这是我在此期间提出的那个问题...

$s = str_replace("''","'",$s);
$s = str_replace("''","'",$s);
$s = str_replace("''","'",$s);
$s = str_replace("''","'",$s);
$s = str_replace("''","'",$s);
$s = str_replace("''","'",$s);

$s = str_replace("'","''",$s);

我应该做什么呢?而且,当我将所有内容转换为准备好的语句时,这是一个权宜之计。

这就是应用程序的用法,mysqli-style:

function SQLSafe($s) {
    global $DB;
    $s = get_magic_quotes_gpc() ? stripslashes($s) : $s;
    $s = $DB->escape_string($s);
    return $s;
}

其中$ DB是

$DB = new mysqli(DB_SERVER, DB_USER, DB_PASSWORD, DB_NAME);
$DB->set_charset('utf8');
$DB->query("SET NAMES 'utf8' COLLATE 'utf8_general_ci'");

并使用如下:

$DB->query("INSERT INTO USERS (username) VALUES ('" . SQLSafe($username) . "')");

3 个答案:

答案 0 :(得分:0)

据我所知,mysqli_real_escape_string()PDO::quote()在MySQL上下文中表现相似 - 唯一的区别是前者没有添加周围的引号,所以你这样使用它:

$email = mysqli_real_escape_string($conn, filter_input(INPUT_POST, 'email'));
$sql = "SELECT user_id, user_name
    FROM user
    WHERE email='$email'";

...后者确实添加了它们,所以你这样使用它:

$email = $pdo->quote(filter_input(INPUT_POST, 'email'));
$sql = "SELECT user_id, user_name
    FROM user
    WHERE email=$email";

如果修复SQL的查询太多,我建议你编写一个自定义包装函数并用它来搜索+替换mysqli_real_escape_string调用,例如:

/**
 * Emulates mysqli_real_escape_string()
 * 
 * @param PDO $pdo
 * @param mixed $input
 * @return string Escaped input, not surrounded in quotes 
 */
function pdo_real_escape_string (PDO $pdo, $input) {
    $output = $pdo->quote($input);
    return $output[0] === "'"
        ? mb_substr($output, 1, -1, 'utf-8' /* or whatever */)
        : $output;
}

请注意这是一个丑陋的黑客准备好的陈述是唯一明智的方法。例如,null值将变为空字符串('')。它只是暂时取代同样丑陋的黑客。

每个数据库驱动程序实现(或不执行)PDO::quote()也没有任何价值。这意味着驱动程序作者可以选择如何解释文档的这一部分:

  

PDO::quote()在输入字符串周围添加引号(如果需要)   并使用a转义输入字符串中的特殊字符   引用适合底层驱动程序的样式。

一些快速测试表明MySQL驱动程序总是添加这样的引号,但是YMMV。

答案 1 :(得分:0)

我倾向于回答你所遇到的真正问题,而不是因为错误的转弯你偶然发现的XY问题。

如果您确实从 mysqli 而不是mysql ext转换,那么您可以使用mysqli并使用此扩展的内置预准备语句。只需确保系统中存在mysqli_stmt::get_result()方法。

如果它不是mysqli而是基于mysql ext的代码,你实际上是在重写,那么我认为你的目标是渐进式重写没有意义。只需坐下来重写每个PDO准备好的语句。 你必须重写你的所有代码,即使你用这种奇怪的方法从PDO引用中删除引号。为什么两次做同样的工作?

答案 2 :(得分:0)

我现在可以看到我遇到的问题只是我错误地将字符串传递了O'Hare两次。因此,O\'Hare成为第一个O\\\'Hare,然后是function SQLSafe($s) { global $PDO; return substr($PDO->quote($s), 1, -1); } 。这就是我在数据库中以反斜杠结束的原因,这是我的错误,并且我正在使用的PDO->引用函数没有错。

所以这个功能现在只是:

get_magic_quotes_gpc

(我删除了关于function SQLSafe(string $s): string { global $PDO; $s = $PDO->quote($s); if ($s[0] === "'") { $s = substr($s, 1, -1); } return $s; } 的行,因为它总是从php5.4返回FALSE)

好的,在对数值数据发表评论后,我已将其更改为

Day, Month, Year