php PDO 将查询中的匿名参数('?')替换为可修改值

问题描述 投票:0回答:2

我想要一种方法来显示 SQL 查询如何使用匿名参数 (

?
) 代替实际参数。
only 用于可读性和调试,不会用作实际查询。

我发现这个功能在大多数情况下都有效:

return array_reduce($this->bindValues, function ($sql, $binding) {
  return preg_replace('/\?/', is_numeric($binding) ? $binding : '"' . $binding . '"', $sql, 1);
}, $this->query);

替换?实际值:

    $data = array(
        'item' => '1,
        'type' => 'Are you ok.'
    );
UPDATE `list` set `item`=?,`type`=? WHERE  (`id` = ?) ;
UPDATE `list` set `item`="1",`type`="Are you ok." WHERE (`id` = 1) ;

但是如果值包含 ?我结束了:

    $data = array(
        'item' => '1,
        'type' => 'Are you ok?'
    );
UPDATE `list` set `item`="1",`type`="Are you ok2" WHERE (`id` = ?) ;

我怎样才能使这项工作,所以只有约束力?被替换。

php sql string pdo preg-replace
2个回答
1
投票

首先,考虑使用命名参数代替

?
。在这种情况下,您不需要替换任何东西:命名参数很清楚并且很容易在日志中显示,并且大多数 dbms 客户端都支持用于调试目的。

如果命名参数不可行(由于当前代码库较大或任何其他原因),您可以尝试分多个步骤进行替换:

  1. 通过将
    ?
    替换为其他极不可能出现在参数或查询中的内容来准备您的参数。例如
    \?
    .
  2. 使用正则表达式替换参数,这将匹配
    ?
    ,但不会匹配第一步的替换。对于替换为
    \?
    它将是
    (?<!\\)?
  3. 将所有
    \?
    替换为
    ?
    结果。

注意:此替换的结果应该never在您的程序中用作查询。这种替代有可能实现上述任何或所有:

  • SQL 注入,
  • 如果初始查询包含
    ?
    不作为参数(例如在字符串常量内部),则结果不准确,
  • 如果初始查询或任何参数包含替换字符串(在我们的示例中为
    \?
    ),则结果不准确。
<?php
$query = 'UPDATE `list` set `item`=?,`type`=? WHERE  (`id` = ?);';
$params = array(
    'item' => '1',
    'type' => 'Are you ok?',
    'id'   => 2
);

function substitute_params($query, $params) {
    $a = array_map(function($val) { return str_replace("?","\\?",$val); }, $params);
    $query = array_reduce($a, function ($interm, $param) {
        return preg_replace('/(?<!\\\\)\\?/', 
            is_numeric($param) ? $param : '\'' . $param . '\'', 
            $interm, 
            1);
    }, $query);
    return "-- Not to be used as a query to database. For demonstration purposes only!\n"
      .str_replace("\\?", "?", $query);
}
echo substitute_params($query, $params);
?>

输出:

-- Not to be used as a query to database. For demonstration purposes only!
UPDATE `list` set `item`=1,`type`='Are you ok?' WHERE  (`id` = 2);

-1
投票

您始终可以使用纯字符串操作:

<?php

$str = 'UPDATE `list` set `item`=?,`type`=? WHERE  (`id` = ?);';

$data = array(
    'item' => '1',
    'type' => 'Are you ok?'
);

$pos = 0;
$index = 0;
do {
    $pos = strpos($str, '?', $pos);
    if ($pos === false) {
        break;
    }
    $binding = array_values($data)[$index%count($data)];
    $replacement = is_numeric($binding) ? $binding : '"' . $binding . '"';
    $str = substr_replace($str, $replacement, $pos, 1);
    $pos += strlen($replacement);
    $index++;
} while ($pos !== false);

echo $str; // Outputs UPDATE `list` set `item`=1,`type`="Are you ok?" WHERE  (`id` = 1);

3v4l代码

© www.soinside.com 2019 - 2024. All rights reserved.