Heim  >  Fragen und Antworten  >  Hauptteil

PHP PDO ersetzt den anonymen Parameter („?“) in der Abfrage durch einen bearbeitbaren Wert

<p>Ich möchte zeigen, wie die SQL-Abfrage aussieht, wenn die anonymen Parameter (<code>?</code>) durch tatsächliche Parameter ersetzt werden. </p><p> Dies dient <strong>nur</strong> der besseren Lesbarkeit und dem Debuggen und wird nicht als tatsächliche Abfrage verwendet. </p> <p>Ich habe festgestellt, dass diese Funktion in den meisten Fällen funktioniert: </p> <pre class="brush:php;toolbar:false;">return array_reduce($this->bindValues, function ($sql, $binding) { return preg_replace('/?/', is_numeric($binding) ? $binding : '"' . $binding . '"', $sql, 1); }, $this->query);</pre> <p>Ersetzen? und tatsächlicher Wert: </p> <pre class="brush:php;toolbar:false;">$data = array( 'item' => '1, 'type' => 'Geht es dir gut?' );</pre> <pre class="brush:php;toolbar:false;">UPDATE `list` set `item`=?,`type`=? WHERE (`id` = ?) ; UPDATE `list` set `item`="1",`type`="Sind Sie in Ordnung?" WHERE (`id` = 1) ;</pre> <p>Aber wenn der Wert ? enthält, erhalte ich Folgendes: </p> <pre class="brush:php;toolbar:false;">$data = array( 'item' => '1, 'type' => 'Geht es dir gut?' );</pre> <pre class="brush:php;toolbar:false;">UPDATE `list` set `item`="1",`type`="Are you ok2" </pre> <p>Wie kann ich das so gestalten, dass es nur bindet? wurde ersetzt. </p>
P粉654894952P粉654894952436 Tage vor493

Antworte allen(1)Ich werde antworten

  • P粉619896145

    P粉6198961452023-09-03 10:06:17

    首先,考虑使用命名参数而不是<代码>?。在这种情况下,您不需要替换任何内容:命名参数清晰且相当容易在日志中显示,并且大多数 dbms 客户端都支持用于调试目的。

    如果命名参数不可行(由于当前代码库较大或任何其他原因),您有两种主要方法:

    1. 使用 SQL 查询解析器。它将产生最可靠的结果。
    2. 使用某种自己编写的“替代者”。它的结果永远不会是理想的或完全可靠的,但在性能和开发方面都应该很快。

    如果您选择后一种方式,这里是如何快速而肮脏地完成它的示例:

    分多个步骤进行替换:

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

    注意:此替换的结果不应永远用作程序中的查询。这种替代有可能实现以下任何或所有功能:

    • SQL 注入,
    • 如果初始查询包含 ? 而不是作为参数(例如在注释中),结果不准确,
    • 如果初始查询或任何参数包含替换字符串(在我们的示例中为 \?),结果将不准确。
    <?php
    $query = 'UPDATE `list` set `item`=?,`type`=? WHERE  (`id` = ?);';
    $params = array(
        'item' => '1',
        'type' => 'Are you o\'k?',
        'id'   => 2
    );
    
    function substitute_params($query, $params) {
        $prep_params =  str_replace(array("'","?"),array("''","\\?"),$params);
        $query = array_reduce($prep_params, function ($interm, $param) {
            return preg_replace('/(?<!\\\\)\\?/m', 
                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 o''k?' WHERE  (`id` = 2);
    

    编辑:要尝试降低常量字符串和带引号的名称内问号的影响,您可以尝试使用此替换:

            return preg_replace('/^([^"\'`]*?(?:(?:`[^`]*?`[^"\'`]*?)*?(?:"[^"]*?"[^"\'`]*?)*?(?:\'[^\']*?\'[^\'"`]*?)*?)*?)(?<!\\\\)\\?/m', 
                '${1}'.(is_numeric($param) ? $param : '\'' . $param . '\''), 
                $interm, 
                1);
    

    它仅替换用 "`' 引用的块之外的 ?

    可以在此处查看演示。

    请记住,这不是完全成熟的解析器。例如,它不知道评论。因此错误替换的可能性仍然很大。

    Antwort
    0
  • StornierenAntwort