构建用于搜索的动态准备语句

时间:2019-03-16 23:20:29

标签: php mysql

如何更改此语句以添加另一个搜索参数,例如" AND username LIKE ? "

当前,在我的网站上搜索内容可以很好地达到预期效果,但是我也想在列表用户名中进行搜索,而不仅仅是列表标题。这是给我带来麻烦的部分。

代码相当复杂,但是我将尽量减少所讨论的代码:

    $fetch_paginated_listings = "SELECT * FROM table WHERE end_date >= CURDATE() ";
    $search_param = $_GET['search'];
    $search_param = (strlen($search_param) > 175) ? substr($search_param,0,175) : $search_param; //Limit the uesr input. If users fill up the search bar, they can crash the db!

    /*Following code is to dynamically populate a prepared statement. Reference: https://www.pontikis.net/blog/dynamically-bind_param-array-mysqli*/
    $a_bind_params = explode(' ', $search_param);
    $a_param_type = array();
    foreach ($a_bind_params as $item) {
      array_push($a_param_type, 's');
      $fetch_paginated_listings .= " AND l_title LIKE ? "; //here, try to add this: " AND l_username LIKE ? " and array_push another 's' to $a_param_type
    }
    /* Bind parameters. Types: s = string, i = integer, d = double,  b = blob */
    $a_params = array();
    $param_type = '';
    $n = count($a_param_type);
    for($i = 0; $i < $n; $i++) {
      $param_type .= $a_param_type[$i];
    }
    /* with call_user_func_array, array params must be passed by reference */
    $a_params[] = & $param_type;
    for($i = 0; $i < $n; $i++) {
      /* with call_user_func_array, array params must be passed by reference */
      $a_bind_params[$i] = "%".$a_bind_params[$i]."%";
      $a_params[] = & $a_bind_params[$i];
    }

    $fetch_paginated_listings .= ' ORDER BY l_title ';    
    $fetch_paginated_listings .= ' 
    LIMIT
        ' . (($pagination->get_page() - 1) * $records_per_page) . ', ' . $records_per_page . '';

    $stmt_fetch_paginated_listings = $conn->prepare($fetch_paginated_listings);
    if($stmt_fetch_paginated_listings === false) {
      trigger_error('Wrong SQL: ' . $fetch_paginated_listings . ' Error: ' . $conn->errno . ' ' . $conn->error, E_USER_ERROR);
    }

    /* use call_user_func_array, as $stmt->bind_param('s', $param); does not accept params array */
    call_user_func_array(array($stmt_fetch_paginated_listings, 'bind_param'), $a_params);

    $stmt_fetch_paginated_listings->execute();

到目前为止我的尝试:

    foreach ($a_bind_params as $item) {
      array_push($a_param_type, 's');
      array_push($a_param_type, 's');
      $fetch_paginated_listings .= " AND l_title LIKE ? ";
      $fetch_paginated_listings .= " AND l_username LIKE ? ";
    }

^它给出的错误是“未定义的偏移量3,未定义的偏移量4,未定义的偏移量5”,也许是因为我找不到添加额外字段的正确位置。

我知道过尝试,但是我很沮丧。我该怎么办?

编辑:

假设用户在搜索输入字段中输入“ foo bar”,然后将单词“ foo”和“ bar”放置在长度为2的数组中。

1-查询检查名为“ title”的列以查看是否存在匹配项

2-它还检查名为“用户名”的列,以查看是否存在匹配项

3-为了安全起见,使用准备好的语句完成查询

4-为了实现这种类型的语句(可变数量的数组字符串),您必须构建一个动态的多关键字预处理语句。我以此为参考:https://www.pontikis.net/blog/dynamically-bind_param-array-mysqli

5-我已完成查询的第一部分,即单个占位符的查询成功

6-我被困在尝试搜索用户名列,因为它需要另一个占位符

7-当用户搜索“ foo bar”时,查询应以如下形式结束,但使用占位符:SELECT * FROM table WHERE title LIKE %foo% AND title LIKE %bar% AND username LIKE %foo% AND username LIKE %bar%

2 个答案:

答案 0 :(得分:1)

就您所走的路而言,您一直处在正确的轨道上。您错过的是如何获取正确数量的绑定参数。 $ a_bind_params具有足够的标题参数,但是当您向其添加用户名时,必须将其加倍。即,如果$ a_bind_params = ['bottle','soda'],则新数组需要为['bottle','soda','bottle','soda']或['bottle','bottle','苏打水,'苏打水']

答案 1 :(得分:0)

正如@TimMorton的回答所言,这些是我所做的修改(hacky,但是有效!)

foreach ($a_bind_params as $item) {
      array_push($a_param_type, 'ss'); //added another s
      $fetch_paginated_listings .= " AND l_title LIKE ? AND l_username LIKE ? "; //added the second parameter
    }

然后在for循环中:

for($i = 0; $i < $n; $i++) {
      $a_bind_params[$i] = "%".$a_bind_params[$i]."%";
      $a_params[] = & $a_bind_params[$i];
      $a_params[] = & $a_bind_params[$i]; //added this line
    }

它有效:)