【问题标题】:PHP: Error when using IN statement in query with SQL injection preventionPHP:在带有 SQL 注入预防的查询中使用 IN 语句时出错
【发布时间】:2015-07-19 16:46:47
【问题描述】:

我是 PHP 新手,希望有人可以帮助我。

我目前有以下 PHP,它是 jQuery 中 Ajax 调用的一部分。 当手动输入 ID 而不是 ?(例如 1,2,3,4,5)这会按预期工作但是当我使用下面的查询时它只返回一个项目如下所示,所以我相信 IN(?) 的组合和我防止 SQL 注入的尝试在这里不起作用。

谁能告诉我我在这里做错了什么?
此外,这会创建一个多维数组,我想知道这是否可以简化,因为我只需要每个项目的 ID (tID) 和值 (content)。

我的 PHP:

$content = implode(",", $_POST["content"]);  // an array containing IDs retrieved from Ajax
$languageFrm = $_POST["languageFrm"];

$stmt = $conn->prepare("SELECT tID, " . $languageFrm . " FROM TranslationsMain WHERE tID IN(?) ORDER BY tID");
$stmt->bind_param("s", $content);
$stmt->execute();
$result = $stmt->get_result();
while($arrTranslations = $result->fetch_assoc()){
    $translations[] = array("tID" => $arrTranslations["tID"], "content" => $arrTranslations[$languageFrm]);
}
var_dump($translations);

Ajax 中的当前结果:

array(1) {
  [0]=>
  array(2) {
    ["tID"]=>
    int(1)
    ["content"]=>
    string(6) "Value1"
  }
}

更新:
我的问题是,即使发布的链接和当前答案似乎是指正确的解决方案,我也无法让其余的 PHP 代码正常工作,因为每当我使用建议的解决方案之一时,我都会收到错误“Call to a member function fetch_assoc() on a non-object...” .

非常感谢您对此的任何帮助,
迈克

【问题讨论】:

标签: php arrays multidimensional-array associative-array


【解决方案1】:

您将字符串绑定到 SQL 代码中的单个参数。这意味着您的 SQL 转换为 SELECT something FROM table WHERE attribute IN ("1,2,3,4,5"),这显然不是您想要的。

您正在尝试将多个参数动态绑定到您的 SQL。这可以通过在准备好的语句中动态设置参数的数量来实现,如PHP manual under Example #5 of PDOStatement::execute() 所示。我在手册中添加了这个作为一般示例,因为它是一个非常常见的用例。


由于您在这里使用的是 MySQLi 而不是 PDO,因此我将提供 MySQLi 等效示例...

$params = $_POST["content"];

$place_holders = implode(',', array_fill(0, count($params), '?'));


$stmt = $conn->prepare("SELECT tID, " . /* no way on earth will I ever do
                                           this $languageFrm */ null .
                       " FROM TranslationsMain WHERE tID IN($place_holders) ORDER BY tID");
// substitute PDO::execute() for call_user_func_array to bind_params because MySQLi sucks
call_user_func_array([$stmt, 'bind_param'], $params);
$stmt->execute();
$result = $stmt->get_result();
while($arrTranslations = $result->fetch_assoc()){
    $translations[] = array(
                            "tID" => $arrTranslations["tID"],
                            "content" => $arrTranslations[$languageFrm],
                           );
}
var_dump($translations);

您仍然容易受到 SQL 注入的攻击

还请考虑到您的准备好的语句容易受到 SQL 注入的影响,因为您将用户提供的输入直接连接到来自行中 $_POST["languageFrm"] 的 SQL 语句是不安全的

$stmt = $conn->prepare("SELECT tID, " . $languageFrm .
        " FROM TranslationsMain WHERE tID IN(?) ORDER BY tID");

你准备好的语句中那个大红色的 $languageFRM 来自用户输入,是你的 SQL 代码的一部分,也就是说,你在查询中使用参数的所有努力在这里都毫无用处。

【讨论】:

  • 非常感谢 - 这很有帮助!
  • 更新:我查看了您的示例并相应地更新了我的代码,但看起来我无法使用我的其余代码(即 $stmt->execute(); 之后的所有内容)因为这会引发错误“调用非对象上的成员函数 fetch_assoc() ...”。你能告诉我如何调整这个吗?另外,我不确定,但在我看来,您可能必须将示例中的 ($place_holders) 替换为 (" . $place_holders . ") ?
  • 这表明$result 不是对象,进一步推断您对$stmt->get_result() 的调用失败。见what MySQLiStatement::getResult returns on failure。请注意,我指出的示例是针对 PDO,而您在此处使用的是 MySQLi。要使此代码适应 MySLQi,您需要使用 call_user_func_array 调用 MySQLiStatement::bindParam()。不,这个例子是正确的,因为 SQL 字符串在调用准备中包含大括号。
  • 非常感谢您的更新和解释。我按照建议应用了它,但它不起作用。如果我如上所述使用它,则 Dreamweaver 将 call_user_func_array 行标记为无效(可能是由于方括号),如果我使用 array($stmt, "bind_param") 代替,则 Dreamweaver 接受它,但我再次收到以下错误:“调用到非对象上的成员函数 fetch_assoc()..."。
  • 同样的逻辑适用。这仍然意味着 $result 不是对象。如果$result 不是告诉您$stmt->get_result() 失败的对象。如果$stmt->get_result() 失败,则表明它返回了false。因此,如果var_dump($result)false,则支持$stmt->get_result() 失败。现在,我将把语句失败的原因留给读者作为dig in the manual and find out how to get useful error information from mysql 的练习。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-16
  • 1970-01-01
  • 1970-01-01
  • 2020-02-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多