Home  >  Q&A  >  body text

Building a SELECT query as a mysqli prepared statement using a dynamic number of LIKE conditions

I'm trying to write prepared statements for user input. The number of parameters changes based on user input. Oam is 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) the output is:

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

No errors are shown in the error log.

What went wrong?

P粉269847997P粉269847997231 days ago354

reply all(2)I'll reply

  • P粉826429907

    P粉8264299072024-03-26 14:50:12

    Write a generic query handler and pass it your query, parameter array, and parameter type list. Returns a set of results or messages. This is my own personal version of mysqli (I mostly use PDO, but have similar functionality set up for this). Do the same for inserts, updates, and deletes. Then just maintain your one library and use it for everything you do :) Note that if you start with this, you may want to handle connection errors etc. better.

    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;$iclose();
    
        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$val){
                print("key:".$key." -> value:".$val);
            }
        }
    }
    
    ?>

    reply
    0
  • P粉787806024

    P粉7878060242024-03-26 12:36:45

    % Surround parameters, not placeholders.

    My code snippet will use object-oriented mysqli syntax, rather than the procedural syntax demonstrated by your code.

    First you need to set up the necessary ingredients:

    1. WHERE clause expression -- separated by OR
    2. Data type of the value - your value is a string, so use "s"
    3. Parameters to be bound to prepared statements

    I will combine #2 and #3 into a variable for easier "unpacking" using the splat operator (...). The data type string must be the first element, then one or more elements will represent the bound value.

    As a logical inclusion, if there is no condition in the WHERE clause, there is no benefit to using a prepared statement; just query the table directly.

    Code: (PHPize.online Demo)

    $string = "Bill N_d Dave";
    
    $conditions = [];
    $parameters = [''];
    foreach (array_unique(explode(' ', $string)) as $value) {
        $conditions[] = "name LIKE ?";
        $parameters[0] .= 's';
        // $value = addcslashes($value, '%_'); // if you want to make wildcards from input string literal. https://stackoverflow.com/questions/18527659/how-can-i-with-mysqli-make-a-query-with-like-and-get-all-results#comment132930420_36593020
        $parameters[] = "%{$value}%";
    }
    // $parameters now holds ['sss', '%Bill%', '%N_d%', '%Dave%']
    
    $query = "SELECT * FROM info";
    if ($conditions) {
        $stmt = $mysqli->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 "
    {$row['name']}
    \n"; }

    For anyone looking for similar dynamic query techniques:

    reply
    0
  • Cancelreply