【问题标题】:PDO::prepare() not escaping special characters in SQLPDO::prepare() 不转义 SQL 中的特殊字符
【发布时间】:2013-06-22 22:55:10
【问题描述】:

我有来自HTMLtextarea 元素的输入值,因为它包含撇号(')字符,例如:'Adam's garden',所以无法插入到 MySQL 表中。因此,我按照 PHP 文档的建议使用了 PDO::prepare() 函数,但我仍然无法将此数据插入表中,但是当我删除撇号以获取 'Adams garden' 时,值已成功插入

我认为PDO::prepare() 函数应该处理 SQL 语句的引号和转义特殊字符。 PHP 文档确实说过要使用 PDO::prepare() 和绑定参数,但我没有将我的 php 变量绑定到查询参数。绑定参数是绝对必要的,还是仅仅因为这是使用PDO::prepare() 函数的常用方式而被声明?

我如何在输入变量中引用和转义特殊字符?

编辑: 我正在使用字符串连接来执行多个 SQL INSERT。撇号位于下面示例代码的$evData['Description'] 字段中。

$evQuery ="INSERT INTO ep_events
        VALUES(NULL, '" .$evData['Title'] ."', '" .$evData['Venue'] ."', '" .$evData['Address'] ."', '" .$evData['Description'] ."')";


$tkQuery ="INSERT INTO ep_tickets VALUES";
foreach ($tkData as $ref =>$tkObj){
    for($i=0; $i<$tkObj['Quantity']; $i++){
        $tkQuery .='(NULL, LAST_INSERT_ID(), "' .$tkObj['Name'] .'", "' .$tkObj['Price'] .'"),';
    }
}

$tkQuery =rtrim($tkQuery, ',');

$query ='START TRANSACTION;' .$evQuery ."; " .$tkQuery .';' .'COMMIT;';
$stm =$db->prepare($query);     
$stm->execute();

这是 PHP 文档部分:

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

如果你使用这个函数来构建 SQL 语句,你就是 强烈推荐使用 PDO::prepare() 来准备 SQL 语句 使用绑定参数而不是使用 PDO::quote() 进行插值 用户输入到 SQL 语句中。带绑定的预处理语句 参数不仅更便携,更方便,不受 SQL 的影响 注入,但执行起来通常比插值快得多 查询,因为服务器端和客户端都可以缓存已编译的表单 的查询。 http://www.php.net/manual/en/pdo.quote.php

【问题讨论】:

  • 不要引用文档,而是向我们展示您的代码。
  • 为什么不能将撇号插入数据库...?
  • PDO prepared statements的可能重复

标签: php mysql pdo escaping quoting


【解决方案1】:

PDO::prepare 只创建一个准备好的语句。查询必须正确参数化,您必须将参数发送到execute(或以其他方式绑定它们)才能正确转义。例如:

$ta = $_REQUEST['textarea'];
$stmt = $pdo->prepare("INSERT INTO t1 VALUES (?)");
$stmt->execute(array($ta));

你可能正在做的是

$pdo->prepare("INSERT INTO t1 VALUES ('" . $_REQUEST['ta'] . "')")->execute();

在这种情况下输入不会被转义。

【讨论】:

  • 这里的教训是不要使用字符串连接。
  • 感谢@ExplodionPills,您的演示几乎与我所做的完全一样,但没有得到想要的转义。 @tadman:我正在使用字符串连接,因为我正在做多个INSERTS,即:VALUES(val1, val2),(val3, val4),...
  • @ExplosionPills,我已经编辑了OP并添加了相关代码sn-p。
  • @okeyxyz 你还在做字符串连接。你需要从字面上使用?
  • @ExplosionPills 是的,我知道。那是我的原始代码。我已经根据您的建议进行了审查,效果很好。谢谢
【解决方案2】:

SQL 语句就是代码。当您使用连接(或其他)构建 SQL 查询时,您正在执行代码生成。当您生成 php 代码 (eval ("echo '$variable';");) 或 HTML 代码 (&lt;h1&gt;&lt;?= $header?&gt;&lt;/h1&gt;) 时,此代码生成也会出现同样的问题。生成的代码中没有“数据”,只有代码本身。

有几种方法可以避免不必要的行为。

  1. 打包/解包:数据库使用 base64_encode/FROM_BASE64 作为数据变量,eval 使用 base64_encode/base64_decode,html 使用 htmlentities。

  2. 转义:$PDO::quote() 用于数据库的数据变量,用于 eval 的某些函数(例如 return '\'' . str_replace(array('\\', '\''), array('\\\\', '\\\''), $var) . '\'';

  3. (错误)删除“危险”结构:(例如 `$v = preg_replace('/UNION(?:\s+ALL)?\s+SELECT/i', '--', $ a);) 用于数据库,strip_tags 用于 HTML。

  4. 从代码中分离数据:为数据库准备语句,生成函数并将数据传递给它以进行评估,使用文档对象模型构建 HTML。

因此,预准备语句的主要思想是将数据与代码分离。因此,您必须直接指定数据在哪里以及代码在哪里。

使用prepared statement插入的最简单方法是

$pdo->prepare('INSERT INTO `table` (`text`) VALUES(?);')->execute(array($text));

请记住,准备好的语句是避免麻烦的首选方法。如果你可以使用准备好的语句——使用它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多