【问题标题】:how to dynamically bind parameters using prepared statement?如何使用准备好的语句动态绑定参数?
【发布时间】:2018-12-03 06:20:04
【问题描述】:

我正在尝试为用户输入编写准备好的语句。参数编号是可变的,取决于用户输入。我正在尝试这段代码

php代码:

$string          = "my name";
$search_exploded = explode( " ", $string );
$num             = count( $search_exploded );
$cart            = array();
for ( $i = 1; $i <= $num; $i ++ ) {
    $cart[] = 's';
}
$str          = implode( '', $cart );
$inputArray[] = &$str;
$j            = count( $search_exploded );
for ( $i = 0; $i < $j; $i ++ ) {
    $inputArray[] = &$search_exploded[ $i ];
}
print_r( $inputArray );
foreach ( $search_exploded as $search_each ) {
    $x ++;
    if ( $x == 1 ) {
        $construct .= "name LIKE %?%";
    } else {
        $construct .= " or name LIKE %?%";
    }
}
$query = "SELECT * FROM info WHERE $construct";
$stmt  = mysqli_prepare( $conn, $query );
call_user_func_array( array( $stmt, 'bind_param' ), $inputArray );
if ( mysqli_stmt_execute( $stmt ) ) {

    $result = mysqli_stmt_get_result( $stmt );
    if ( mysqli_num_rows( $result ) > 0 ) {
        echo $foundnum = mysqli_num_rows( $result );
        while( $row = mysqli_fetch_array( $result, MYSQLI_ASSOC ) ) {

            echo $id = $row['id'];
            echo $name = $row['name'];
        }
    }
}

当我 print_r $inputArray 的输出是这样的:

   Array ( [0] => ss [1] => my [2] => name ) 

错误日志中没有显示错误。 我在这里做错了什么请告诉我。

【问题讨论】:

  • 你在 $query 中得到了什么?
  • 你在 " " 上爆炸你的 $string,所以你会期望你的 foreach() 给你两个条目:myname
  • 这是查询:SELECT * FROM info WHERE name LIKE %?% or name LIKE %?%
  • 是的,我想在姓名栏中搜索“我的”和“姓名”。
  • 将 LIKE 与绑定变量一起使用时,您必须在绑定变量中包含 % 符号,而不是 SQL。

标签: php mysqli prepared-statement


【解决方案1】:

% 环绕参数,而不是占位符。

我的 sn-p 将使用面向对象的 mysqli 语法,而不是您的代码演示的过程语法。

首先你需要设置必要的成分:

  1. WHERE 子句表达式 -- 由 OR 分隔
  2. 你的值的数据类型——你的值是字符串,所以使用“s”
  3. 要绑定到准备好的语句的参数

我将把#2 和#3 组合成一个变量,以便使用 splat 运算符 (...) 进行更简单的“解包”。数据类型字符串必须是第一个元素,然后一个或多个元素将表示绑定值。

作为逻辑包含,如果 WHERE 子句中没有条件,则使用预准备语句没有任何好处;直接查询表即可。

代码:(100% 测试/成功代码

$string = "my name";

$conditions = [];
$parameters = [''];
foreach (array_unique(explode(' ', $string)) as $value) {
    $conditions[] = "name LIKE ?";
    $parameters[0] .= 's';
    $parameters[] = "%{$value}%";
}
// $parameters now holds ['ss', '%my%', '%name%']

$query = "SELECT * FROM info";
if ($conditions) {
    $stmt = $conn->prepare($query . ' WHERE ' . implode(' OR ', $conditions));
    $stmt->bind_param(...$parameters);
    $stmt->execute();
    $result = $stmt->get_result();
} else {
    $result = $conn->query($query);
}
foreach ($result as $row) {
    echo "<div>{$row['name']} and whatever other columns you want</div>"; 
}

对于寻找类似动态查询技术的任何人:

【讨论】:

    【解决方案2】:

    编写一个通用查询处理程序并将您的查询、参数数组和参数类型列表传递给它。取回一组结果或消息。这是我自己的 mysqli 个人版本(我主要使用 PDO,但也为此设置了类似的功能)。对插入、更新和删除执行相同的操作。然后只需维护您的一个库并将其用于您所做的所有事情:) 请注意,如果您从这里开始,您可能希望更好地处理连接错误等。

    <?php
    
    // this is normally in an include() file
    function getDBConnection(){
    
        // your DB credentials
    
        $hostname="127.0.0.1";
        $username="ausername";
        $password="supersecret";
        $database="some_db_name";
    
        $con = new mysqli($hostname, $username,$password, $database);
        if($con->connect_error) {
          return false;
        }
        return $con;
    }
    
    // generic select function.
    // takes a query string, an array of parameters, and a string of
    // parameter types
    // returns an array - 
    //   if $retVal[0] is true, query was successful and returned data
    //   and $revVal[1...N] contain the results as an associative array
    //   if $retVal[0] is false, then $retVal[1] either contains the 
    //   message "no records returned" OR it contains a mysql error message
    
    function selectFromDB($query,$params,$paramtypes){
    
        // intitial return;
        $retVal[0]=false;
    
        // establish connection
        $con = getDBConnection();
        if(!$con){
            die("db connection error");
            exit;
        }
    
        // sets up a prepared statement
        $stmnt=$con->prepare($query);
        $stmnt->bind_param($paramtypes, ...$params);
        $stmnt->execute();
    
        // get our results
        $result=$stmnt->get_result()->fetch_all(MYSQLI_ASSOC);
        if(!$result){
        $retVal[1]="No records returned";
        }else{
            $retVal[0]=true;
            for($i=0;$i<count($result);$i++){
                $retVal[]=$result[$i];
            }
        }
    
        // close the connection
        $con->close();
    
        return $retVal;
    
    }
    
    $myusername=$_POST['username'];
    $mypassword=$_POST['password'];
    
    // our query, using ? as positional placeholders for our parameters
    $q="SELECT useridnum,username FROM users WHERE username=? and password=?";
    
    // our parameters as an array - 
    $p=array($myusername,$mypassword);
    
    // what data types are our params? both strings in this case
    $ps="ss";
    
    // run query and get results
    $result=selectFromDB($q,$p,$ps);
    
    // no matching record OR a query error
    if(!$result[0]){
        if($result[1]=="no records returned"){
            // no records
            // do stuff
        }else{
            // query error
            die($result[1]);
            exit;
        }   
    }else{  // we  have matches!
        for($i=1;$i<count($result);$i++){
            foreach($result[$i] as $key->$val){
                print("key:".$key." -> value:".$val);
            }
        }
    }
    
    ?>
    

    【讨论】:

    • 这个 sn-p 将不支持可变数量的绑定变量。
    猜你喜欢
    • 1970-01-01
    • 2020-12-11
    • 2014-03-20
    • 1970-01-01
    • 2014-06-12
    相关资源
    最近更新 更多