how to dynamically bind parameters using prepared statement?

允我心安 提交于 2019-12-18 07:05:09

问题


I am trying to write prepared statement for user input. parameter numbers are variable depends on user input. i am trying this code

php code:

$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'];
        }
    }
}

when i print_r $inputArray output is this:

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

there is no error showing in error log. what is wrong i am doing here please tell me.


回答1:


100% Tested / Successful Code:

The % wrapping goes around the parameters, not the placeholders. (see inline comments for additional explanations)

$string = " b c ";

$strings = array_unique(preg_split('~\s+~', $string, -1, PREG_SPLIT_NO_EMPTY));  // isolate and remove duplicates
$where = '';
$types = '';
foreach ($strings as $s) {
    $params[] = "%{$s}%";  // wrap values in percent signs for LIKE
    $where .= (!$where ? " WHERE" : " OR") . " name LIKE ?";  // build clause
    $types .= 's';
}
// echo "<div>{$where}</div>";  // uncomment if you wish to see what is generated

if (!$conn = new mysqli("host", "user", "pass", "db")) {
    echo "Database Connection Error: " , $conn->connect_error;
} else {
    $query = "SELECT id, name FROM info{$where}";
    if(!$stmt = $conn->prepare($query)) {
        echo "Syntax Error @ prepare: " , $conn->error;  // don't show to public
    }else{
        if ($where) {
            array_unshift($params, $types);  // prepend the type values string
            $ref = [];  // add references
            foreach ($params as $i => $v) {
                $ref[$i] = &$params[$i];  // pass by reference as required/advised by the manual
            }
            call_user_func_array([$stmt, 'bind_param'], $ref);
        }    

        if (!$stmt->execute()) {
            echo "Error @ bind_param/execute: " , $stmt->error;  // don't show to public
        } elseif (!$stmt->bind_result($id, $name)) {
            echo "Error @ bind_result: " , $stmt->error;  // don't show to public
        } else {
            while ($stmt->fetch()) {
                echo "<div>$id : $name</div>"; 
            }
            $stmt->close();
        }
    }
}

p.s. If you are using php5.6 or higher, then you can enjoy the more brief syntax afforded by the splat/spread operator (...).

if ($where) {
    if (!$stmt->bind_param($types, ...$params)) {
        echo "MySQL Query Syntax Error: <b>Failed to bind placeholders and data</b>";  // $stmt->error;
    }
} 



回答2:


Write a generic query handler and pass it your query, the array of parameters, and the list of parameter types. Get back an array of results or messages. Here's my own personal version for mysqli (I mostly use PDO, but have a similar function set up for that as well). Do the same for inserts, updates, and deletes. Then simply maintain your one library and use it for everything you do :) Note that if you start with this, you'll probably want to do a better job of dealing with connection errors, etc.

<?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);
        }
    }
}

?>


来源:https://stackoverflow.com/questions/51010509/how-to-dynamically-bind-parameters-using-prepared-statement

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!