【问题标题】:Loading imploded arrays into $wpdb prepare failing将内爆数组加载到 $wpdb 准备失败
【发布时间】:2016-01-18 06:23:48
【问题描述】:

更新 1

$addressbits 内爆似乎存在问题。我手动添加了两个变量,然后搜索了一个以确保它不起作用,它失败了,然后输入了两个值并且搜索成功了。

更新 2

经过更多测试后,我发现如果数组中有多个项,prepare 函数会消除第二个内爆,不确定这是否是一个错误,但它确实很烦人。我正在考虑在数组创建函数中运行准备函数以进行清理,然后将其打印到查询中。

我正在为 wordpress 网站中的自定义表格构建搜索表单。我正在尝试将多个术语从文本字段传递到一个数组,然后将它们传递到 $wpdb->prepare() 进行清理。到目前为止,我的代码恰好一个术语可以正常工作...但是如果我再添加,它将无法正常工作,就好像没有为该字段输入任何术语。我最初认为这可能是尾随逗号的问题,但添加代码修剪不起作用,我什至用逗号连接以确保它们的存在,然后用 rtrim() 修剪,仍然不起作用。我还添加了逗号而不是修剪,仍然因多个术语而失败。我打开了错误报告,没有任何显示。

#explode search field values
$addressinput = explode(" ", $_GET['address']);

#create inputs for prepare
$addressbits = array();
foreach ($addressinput as $input) {
    $input = trim($input);
    if (!empty($input)) {
        $addressbits[] = $input ;
    }
}

#create prepare statements
$addressclean = array();
foreach ($addressinput as $clean) {
    $clean = trim($clean);
    if (!empty($clean)) {
        $addressclean[] = " and `display-address` LIKE '%%%s%%'";
    }
}


#if field is not empty, build and execute prepare statement, set variable
if (isset($_GET['address'])) {  
   $displayaddress = $wpdb->prepare( implode( $addressclean ) , implode(',' , $addressbits));

   }  else {

    $displayaddress = '';
  }

#query with pagination code

$customPagHTML     = "";
$query             = "select * from `record-display` where" . $code . $displayaddress . $format  . $name . " ORDER BY `date` DESC";
$total_query     = "SELECT COUNT(1) FROM (${query}) AS combined_table";
$total             = $wpdb->get_var( $total_query );
$items_per_page = 10;
$page             = isset( $_GET['cpage'] ) ? abs( (int) $_GET['cpage'] ) : 1;
$offset         = ( $page * $items_per_page ) - $items_per_page;
$result         = $wpdb->get_results( $query . "  LIMIT ${offset}, ${items_per_page}", ARRAY_A );
$totalPage         = ceil($total / $items_per_page);

【问题讨论】:

    标签: php wordpress


    【解决方案1】:

    所以你似乎有一些问题。

    首先,如果没有 $_GET['address'],则运行所有用于组装 $adressclean 的代码是没有意义的 - 它不会产生影响(在性能方面),但将其进一步向下移动会更有意义在if ( isset( $_GET['address'] ) ) { 内部。

    第二件事是你循环了几乎相同的数组两次。再说一遍 - 没什么大不了的,但除非你真的需要 $addressbits 变量,否则只需创建一个循环(即使你需要它,你实际上仍然可以做一个循环,只需执行 $addressbits[] = $input;)。

    第三件事是你错误地使用了$wpdb->prepare()。它希望您将每个替换变量作为另一个参数传递给函数。相反,您连接所有$addressbits 并将它们作为单个变量传递,而连接$addressclean 需要将多个参数传递给$wpdb->prepare()。 在 foreach 循环中转义每个片段更容易。 如果您不想这样做,那么您可以像最初那样编写代码,只需更新这些行(它们脱离上下文,但您应该能够弄清楚):

    $addressbits[] = '%' . $wpdb->esc_like( $input ) . '%';
    
    $addressclean[] = " and `display-address` LIKE %s";
    
    $prepare_params = $addressbits;
    array_unshift( $prepare_params, implode( $addressclean ) ); 
    $displayaddress = call_user_func_array( array( $wpdb, 'prepare', implode( $addressclean ), $addressbits );
    

    这将为所有 $addressbits 元素添加百分比,使其可以在LIKE 语句中使用。如您所见,我们去掉了$addressclean[] 中的单引号和所有额外的百分比。 最后,我们使用call_user_func_array() 将一组参数传递给$wpdb->prepare()。请注意,它实际上接收单独的参数,而不是单个数组(如有必要,请查看call_user_func_array() 上的文档)。

    最后一件事是,您无需运行完整的额外查询即可获得结果总数。请改用SQL_CALC_FOUND_ROWS - 尽管根据您的表结构,运行第二个查询可能会更好(尝试两种方法,看看哪种方法对您来说运行得更快)。

    无论如何,这是我建议的代码版本。请注意,我只是通过基于post_title 查询帖子表来尝试它。我不得不编造$code$format$name,因为你没有将它们包含在你的代码中。

    #if field is not empty, build and execute prepare statement, set variable
    if ( isset( $_GET['address'] ) ) {
        #explode search field values
        $addressinput = explode( ' ', $_GET['address'] );
        #create inputs for prepare
        $addressclean = array();
        foreach ( $addressinput as $input ) {
            $input = trim( $input );
            if ( ! empty( $input ) ) {
                $addressclean[] = $wpdb->prepare( '`display-address` LIKE %s', '%' . $wpdb->esc_like( $input ) . '%' );
            }
        }
    
        $displayaddress = $addressclean ? ' AND ( ' . implode( ' AND ', $addressclean ) . ' ) ' : '';
    }  else {
        $displayaddress = '';
    }
    
    #query with pagination code
    $items_per_page = 10;
    $page           = isset( $_GET['cpage'] ) ? absint( $_GET['cpage'] ) : 1;
    $offset         = ( $page * $items_per_page ) - $items_per_page;
    
    $customPagHTML  = "";
    $query          = "SELECT SQL_CALC_FOUND_ROWS * FROM `record-display` 
        WHERE $code
            $displayaddress
            $format
            $name
        GROUP BY {$wpdb->posts}.ID
        ORDER BY `post_date` DESC
        LIMIT {$offset}, {$items_per_page}";
    $result      = $wpdb->get_results( $query, ARRAY_A );
    $total       = $wpdb->get_var( "SELECT FOUND_ROWS()" );
    $totalPage   = ceil( $total / $items_per_page );
    

    【讨论】:

    • 感谢您的详细帖子!实际上,我昨晚很晚才意识到这一切,并得出了相同的结果。我想我刚刚对 wpdb prepare 的所有标准问题示例有了透视。感谢您对分页代码的额外建议,我还没有过多地研究它的性能方面。昨晚我方法的唯一区别是使用了准备,我选择了: $addressbits[] = " 和 display-address ".$wpdb->prepare("LIKE '%%%s%%'",$输入);
    • @photocode 太棒了!我查看了如何使用$wpdb 转义like 语句,这只是个人偏好使用esc_like() - 它看起来更干净,但我猜它也可能更令人困惑:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-26
    • 2017-10-23
    • 1970-01-01
    • 2018-11-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多