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