首頁  >  問答  >  主體

php PDO 以可編輯值取代查詢中的匿名參數('?')

<p>我想要一個方法來顯示 SQL 查詢在用實際參數取代匿名參數 (<code>?</code>) 時的外觀。 </p><p> 這<strong>僅</strong>用於可讀性目的和調試,不會用作實際查詢。 </p> <p>我發現這個函數在大多數情況下都有效:</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>更換?與實際值:</p> <pre class="brush:php;toolbar:false;">$data = array( 'item' => '1, 'type' => 'Are you ok.' );</pre> <pre class="brush:php;toolbar:false;">UPDATE `list` set `item`=?,`type`=? WHERE (`id` = ?) ; UPDATE `list` set `item`="1",`type`="Are you ok." WHERE (`id` = 1) ;</pre> <p>但如果該值包含 ?我最終得到的是:</p> <pre class="brush:php;toolbar:false;">$data = array( 'item' => '1, 'type' => 'Are you ok?' );</pre> <pre class="brush:php;toolbar:false;">UPDATE `list` set `item`="1",`type`="Are you ok2" WHERE (`id` = ?) ; </pre> <p>我怎麼能做到這一點,所以只能綁定?已被替換。 </p>
P粉654894952P粉654894952385 天前464

全部回覆(1)我來回復

  • 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', 
                ''.(is_numeric($param) ? $param : '\'' . $param . '\''), 
                $interm, 
                1);
    

    它只會取代用 "`' 引用的區塊之外的 ?

    可以在此處查看示範。

    請記住,這不是完全成熟的解析器。例如,它不知道評論。因此錯誤替換的可能性仍然很高。

    回覆
    0
  • 取消回覆