【问题标题】:WordPress prepared statement with IN() condition带有 IN() 条件的 WordPress 准备好的语句
【发布时间】:2012-05-24 22:21:44
【问题描述】:

我在这样的字符串中有三个值:

$villes = '"paris","fes","rabat"';

当我将它输入到这样的准备好的语句中时:

$sql    = 'SELECT distinct telecopie FROM `comptage_fax` WHERE `ville` IN(%s)';
$query  = $wpdb->prepare($sql, $villes);

echo $query; 显示:

SELECT distinct telecopie FROM `comptage_fax` WHERE `ville` IN('\"CHAPELLE VIVIERS \",\"LE MANS \",\"QUEND\"')

它不是将字符串写成三个单独的值——它只是一个带有双引号的字符串。

如何在 WordPress 中正确实现具有多个值的预处理语句?

【问题讨论】:

    标签: php mysql wordpress prepared-statement in-clause


    【解决方案1】:

    试试这个代码:

    // Create an array of the values to use in the list
    $villes = array("paris", "fes", "rabat");    
    
    // Generate the SQL statement.
    // The number of %s items is based on the length of the $villes array
    $sql = "
      SELECT DISTINCT telecopie
      FROM `comptage_fax`
      WHERE `ville` IN(".implode(', ', array_fill(0, count($villes), '%s')).")
    ";
    
    // Call $wpdb->prepare passing the values of the array as separate arguments
    $query = call_user_func_array(array($wpdb, 'prepare'), array_merge(array($sql), $villes));
    
    echo $query;
    

    【讨论】:

    • 请注意,这可以说是一种过于复杂的方法,但它的优势在于能够改变数组的内容,并且代码将相应地适应而无需修改。所以你可以用 30 个城镇而不是 3 个城镇填充 $villes,它仍然可以工作。
    • 可能需要考虑将其添加到 codex 或向核心提交补丁,以便您可以将此方法用于 IN 语句。
    • 如何在 WHERE 区域附近添加 AND 语句。 WHERE ville IN(".implode(', ', array_fill(0, count($villes), '%s')).") AND table_name.name = '%s'
    • 感谢您的代码,它可以帮助我满足我的需要 :) 这是我的解决方案:stackoverflow.com/a/29000133/1993427
    • 现在,如果您的数组是$prepare 中的最后一项,您可以使用扩展使代码更简洁:$wpdb->prepare($sql,...$ville);
    【解决方案2】:

    WordPress 已经为此提供了功能,请参阅esc_sql()。下面是这个函数的定义:

    转义数据以用于 MySQL 查询。通常你应该使用 wpdb::prepare() 来准备查询。有时,转义是必需的或有用的。 一个例子是准备一个用于 IN 子句的数组。

    你可以这样使用它:

    $villes = ["paris", "fes", "rabat"];
    $villes = array_map(function($v) {
        return "'" . esc_sql($v) . "'";
    }, $villes);
    $villes = implode(',', $villes);
    $query = "SELECT distinct telecopie FROM `comptage_fax` WHERE `ville` IN (" . $villes . ")"
    

    【讨论】:

      【解决方案3】:

      功能:

      function escape_array($arr){
          global $wpdb;
          $escaped = array();
          foreach($arr as $k => $v){
              if(is_numeric($v))
                  $escaped[] = $wpdb->prepare('%d', $v);
              else
                  $escaped[] = $wpdb->prepare('%s', $v);
          }
          return implode(',', $escaped);
      }
      

      用法:

      $arr = array('foo', 'bar', 1, 2, 'foo"bar', "bar'foo");
      
      $query = "SELECT values
      FROM table
      WHERE column NOT IN (" . escape_array($arr) . ")";
      
      echo $query;
      

      结果:

      SELECT values
      FROM table
      WHERE column NOT IN ('foo','bar',1,2,'foo\"bar','bar\'foo')
      

      可能会或可能不会更有效,但它是可重复使用的。

      【讨论】:

        【解决方案4】:

        First 是一组现代的非 WordPress 技术,使用 mysqli 准备好的语句,数组中的值数量未知。第二个 sn-p 将是 WordPress 的等价物。

        假设输入数据的索引数组是不受信任的,并且可以从$_GET['villes'] 访问。准备好的语句是现代标准,专业开发人员更喜欢旧的/不受信任的转义技术。接下来的 sn-p 将返回具有数组中指定的 ville 值之一的行。如果数组未声明或为空,则返回数据库表中的所有行。

        原生 PHP 技术

        $sql = "SELECT DISTINCT telecopie FROM comptage_fax";
        if (!empty($_GET['villes'])) {
            $count = count($_GET['villes']);
            $commaDelimitedPlaceholders = implode(',', array_fill(0, $count, '?'));
            $stmt = $conn->prepare("$sql WHERE ville IN ($commaDelimitedPlaceholders)");
            $stmt->bind_param(str_repeat('s', $count), ...$_GET['villes']);
            $stmt->execute();
            $result = $stmt->get_result();
        } else {
            $result = $conn->query($sql);
        }
        

        从这一点开始,您可以访问不同的 telecopie 值的行(从技术上讲,这是一个可迭代的结果集对象),就像使用简单的 foreach() 迭代关联数组的索引数组一样。

        foreach ($result as $row) {
            echo $row['telecopie'];
        }
        

        使用 WordPress 的辅助方法语法更简单,因为变量绑定和查询执行由 get_results() 处理:

        $sql = "SELECT DISTINCT telecopie FROM comptage_fax";
        if (!empty($_GET['ville']) {
            $commaDelimitedPlaceholders = implode(',', array_fill(0, count($_GET['ville']), '%s'));
            $sql = $wpdb->prepare("$sql WHERE ville IN ($commaDelimitedPlaceholders)", $_GET['ville']);
        }
        $result = $wpdb->get_results($sql, ARRAY_A);
        

        从这一点来看,$result 是关联数组的索引数组——特别是因为ARRAY_A$result 不是第一个原生 php sn-p 中的结果集对象。这意味着您可以在数据上使用经典的循环语言构造函数或完整的 array_ 函数。

        有用的参考资料:

        【讨论】:

          【解决方案5】:

          这是我为$wpdb 清理IN (...) 值的方法。

          1. 我使用一个辅助函数将列表的每个值通过$wpdb->prepare() 传递,以确保它被正确转义。
          2. 准备好的值列表通过sprintf()插入到SQL查询中。

          辅助函数:

          // Helper function that returns a fully sanitized value list.
          function _prepare_in ( $values ) {
              return implode( ',', array_map( function ( $value ) {
                  global $wpdb;
          
                  // Use the official prepare() function to sanitize the value.
                  return $wpdb->prepare( '%s', $value );
              }, $values ) );
          };
          

          示例用法:

          // Sample 1 - note that we use "sprintf()" to build the SQL query!
          $status_cond = sprintf(
              'post_status IN (%s)',
              _prepare_in( $status )
          );
          $posts = $wpdb->get_col( "SELECT ID FROM $wpdb->posts WHERE $status_cond;" );
          
          
          // Sample 2:
          $posts = $wpdb->get_col( sprintf( "
              SELECT ID
              FROM $wpdb->posts
              WHERE post_status IN (%s) AND post_type IN (%s)
              ;",
              _prepare_in( $status ),
              _prepare_in( $post_types )
          ) );
          

          【讨论】:

            【解决方案6】:

            prepare 函数还将array 作为第二个参数。

            您可以尝试像这样转换$villes

            当前

            <?php
            $villes = '"paris","fes","rabat"';
            ?
            

            改成

            <?php
            $villes = array("paris","fes","rabat");
            ?>
            

            现在,尝试将$villes 传递给准备函数,看看它是否有效。希望对您有所帮助。

            【讨论】:

            • 我已经尝试过了,但它只传递数组的第一个元素
            猜你喜欢
            • 2023-04-08
            • 2023-02-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多