This question already has an answer here:
Correct way to use LIKE '%{$var}%' with prepared statements?
(1 answer)
Closed last month.
Im am trying to build a dynamic prepared statement so that I can reuse the code. I am running into a problem when using %?% in my prepared state as it used LIKE. My code is as follows:
$where = " First_Name LIKE '%?%' ";
$vals = array('Mike');
$type = 's';
$dbd = mysqli_stmt_init($dbconnection);
if (mysqli_stmt_prepare($dbd, "SELECT * FROM Contacts WHERE $where" )) {
mysqli_stmt_bind_param($dbd, $type, ...$vals);
if (!mysqli_stmt_execute($dbd)) {
echo "Execute Error: " . mysqli_error($dbconnection);
} else {
//do nothing
}
} else {
echo "Prep Error: " . mysqli_error($dbconnection);
}
mysqli_stmt_get_result($dbd);
So when I use "First_Name = ?" it works fine so I think my issue is with the '%?%'. I have searched resolutions but couldn't find anything related to my dynamic prepared statement. Thank you for any help.
You need to bind the complete value, not just a portion of it. This means doing:
$where = "First_Name LIKE ?"
And then binding:
$vals = array('%Mike%');
Related
I am trying to migrate to Mysqli and I got my Mysql code to search for parameters like this:
$querySt = "SELECT userID FROM myTable";
if (isset($_POST["UserID"])) {
if (ctype_digit($_POST["UserID"])) {
addWhereIfNoHave();
$in_userID = mysql_real_escape_string($_POST["UserID"]);
$querySt .= " UserID = '$in_userID'";
}
}
if (isset($_POST["name"])) {
addWhereIfNoHave();
$in_name = mysql_real_escape_string($_POST["name"]);
$querySt .= " imgName LIKE LOWER('%$in_name%')";
}
if (isset($_POST["ScoreLessThan"])) {
if (ctype_digit($_POST["ScoreLessThan"])) {
addWhereIfNoHave();
$in_ScoreLessThan = mysql_real_escape_string($_POST["ScoreLessThan"]);
$querySt .= " Score < '$in_ScoreLessThan'";
}
}
...
...
there are other if statements here looking for other post data, and
they keep on adding parameters into mysql query string just like above.
...
...
//this function is called in those if statements above. It either adds "WHERE" or "AND".
function addWhereIfNoHave(){
global $querySt;
if (strpos($querySt, 'WHERE') !== false){
$querySt .= " OR";
return true;
}else{
$querySt .= " WHERE";
return false;
}
}
This function works ok looking for all the parameters input from PHP post. However, I am migrating this to Mysqli, and I have a bit of trouble converting this code to Mysqli version. For example,
$stmt = $conn->prepare("SELECT userID FROM myTable WHERE UserID = ? AND name= ?");
$stmt->bind_param('ss', $userid, $name);
Suppose, I wanna search the table using 2 variables, I bind 2 variables like above, but in the case of my Mysql above, I keep on extending additional parameters into the string before executing the mysql query.
But for Mysqli, how can we do this? Is it possible to bind additional parameters and extending the string for prepare statement like Mysql code above? How should this problem be approach for Mysqli?
My current problem is mainly with the bind_param. I could concatenate the search query further and add all the '?' into the prepare statement, but with different variable types and number variables needed to be specified in bind_param, this is where I am stuck.
This question already has answers here:
mysqli bind_param() expected to be a reference, value given
(3 answers)
Closed 6 years ago.
I am trying to implement dynamic sql query so that users has flexibility to use one or more filters to dig out the data he wants. I am using prepared statements to ensure that there is no SQL Injection. I am using WAMP Server 64 bit.
I referred to this article for writing my code: Sample
Following is my code:
$myqry="SELECT * FROM students WHERE ";
$initflag=0; //controls the first clause without AND and rest with AND
$paramtypes=array();
$paramvalues=array();
$params=array();
if(!empty($_POST['awr_admyear']))
{
$myqry.= "YEAR(adm_date)=? ";
$initflag=1;
$paramtypes[]='s';
$paramvalues[]=$_POST['awr_admyear'];
}
if(!empty($_POST['awr_admfrom']) && !empty($_POST['awr_admto']))
{
if($initflag==0)
$myqry.= "YEAR(adm_date) BETWEEN ? AND ? ";
else
$myqry.= "AND YEAR(adm_date) BETWEEN ? AND ? ";
$initflag=1;
$paramtype[]='s';
$paramtype[]='s';
$paramvalues[]=$_POST['awr_admfrom'];
$paramvalues[]=$_POST['awr_admto'];
}
if(!empty($_POST['awradm_no']))
{
if($initflag==0)
$myqry.= "adm_no LIKE ? ";
else
$myqry.= "AND adm_no LIKE ? ";
$initflag=1;
$paramtype[]='s';
$paramvalues[]=$_POST['awradm_no'];
}
$params = array_merge($paramtype,$paramvalues);
if(isset($myqry) && !(empty($myqry)))
{
if($result1 = $mysqli->prepare($myqry))
{
call_user_func_array(array($result1, 'bind_param'), $params);
if($result1->execute())
{
$finrest=$result1->get_result();
while($row= $finrest->fetch_assoc())
{
//and so on
I am getting the following error:
Warning: Parameter 2 to mysqli_stmt::bind_param() expected to be a reference, value given in..................
Where I am going wrong and what is the solution?
1) Follow this answer, mentioned here: mysqli bind_param() expected to be a reference, value given
2) Do the following changes:
$params = array_merge($paramtype,$paramvalues);
Replace it with:
$params[] = implode("", $paramtype);
$params = array_merge($params, $paramvalues);
$paramtype is array but bind_param needs first parameter should be string.
I was wondering if it's possible to prepare statements using PHP's pgsql library that do not require parameters.
I'm really used to preparing all my SQL statements in the beginning of a program instead of when I need them so my code always looks similar to this
<?php
$pgsqlCon = // code to connect
// prepare SQL statements
$sql = "SELECT * FROM table01 " .
"WHERE t01_idno >= $1";
pg_prepare($pgsqlCon, "table01_cur", $sql);
$sql = "SELECT * FROM table02 " .
"WHERE t02_idno = $1";
pg_prepare($pgsqlCon, "table02_sel", $sql);
// start main
$table01 = pg_execute($pgsqlCon, "table01_cur", array('1'));
while ($row = pg_fetch_row($table01)) {
echo "<span>found something<br /></span>";
}
$table02 = pg_execute($pgsqlCon, "table02_sel", array('1'));
while ($row = pg_fetch_row($table02)) {
echo "<span>found something else<br /></span>";
}
?>
So I would like to prepare statements that don't require parameters in this way as well if that is possible.
I had the same problem and sadly this usage is not documented in the official documentation.
Looking at it you can see that the third argument is not optional (i.e. not in brackets [..]) and indeed, as the above comment says, passing an empty array() as the third argument works.
So after preparing a statement with no arguments one could execute it like so:
$rs = pg_execute($connection, $stmt, array());
I have a piece of code that reads a crash log and other metadata from a MySQL database before sending it back to the requester as JSON (this code is called by an AJAX function on another page). Optionally, filters can be specified with GET, which alter the prepared statement to filter for only the specified results - for example, to only show results from one app version. Here is the code in question:
$conn = new mysqli($sql_servername, $sql_username, $sql_password, "Crashes");
if ($conn->connect_error) {
//failed
die();
}
$sql="
SELECT ID,phone,appver,osver,user_agent,username,message,app_name,date_received FROM Crashes WHERE ";
$params="";
$params2="";
if (isset($_GET["filter_phone"])) {
$sql .= "phone = ? AND "; //i.e "WHERE phone = ? AND (...osver = ? AND appver = ? etc)"
$params.="s";
$params2.=', $_GET["filter_phone"]';
}
if (isset($_GET["filter_appver"])) {
$sql .= "appver = ? AND ";
$params.="s";
$params2.=', $_GET["filter_appver"]';
}
if (isset($_GET["filter_osver"])) {
$sql .= "osver = ? AND ";
$params.="s";
$params2.=', $_GET["filter_osver"]';
}
if (isset($_GET["filter_user_agent"])) {
$sql .= "user_agent = ? AND ";
$params.="s";
$params2.=', $_GET["filter_user_agent"]';
}
if (isset($_GET["filter_username"])) {
$sql .= "username = ? AND ";
$params.="s";
$params2.=', $_GET["filter_username"]';
}
if (isset($_GET["filter_message"])) {
$sql .= "message = ? AND ";
$params.="s";
$params2.=', $_GET["filter_message"]';
}
if (isset($_GET["filter_app_name"])) {
$sql .= "app_name = ? AND ";
$params.="s";
$params2.=', $_GET["filter_app_name"]';
}
$sql.="1";
//echo "\$params: ".$params."<br>";
//echo "\$params2: ".$params2."<br>";
//echo "<br>\$stmt->bind_param(\$params$params2);<br>";
//echo var_dump($_GET);
$stmt = $conn->prepare($sql);
exec("\$stmt->bind_param(\$params$params2);");
if ($stmt->execute()) {
//echo "<br>Success!";
} else {
//echo "<br>Failure: ".$stmt->error;
}
$result = $stmt->get_result();
$out = array();
while ($row = $result->fetch_assoc()) {
array_push($out, $row);
}
echo json_encode($out);
This code works perfectly when no filters are specified - however, when any filter is specified, the statement fails with the error No data supplied for parameters in prepared statement. I have verified that the code in the exec() should be (for example, if the user_agent filter is set) $stmt->bind_param($params, $_GET["filter_user_agent"]);
Additionally, the SQL query works perfectly when I use the query but just manually replace the ?s with the filters, so it does not appear to be a problem with the initial query, but rather the prepared statement. Help would be much appreciated.
NB: The commented out echos are for debug purposes, and are usually disabled, but I have left them in to show how I got the information that I currently have.
EDIT: Answered my own question below - the error was that I was using exec() - a function which executes external shell commands, whereas what I wanted was eval(), which evaluates a string input and the executes it as a PHP script.
Turns out I was simply mistaken as to the function of exec(). (Too much Python?) exec() runs an external shell command, whereas what I was looking for was eval() which evaluates and runs any string inputted as PHP code.
Looks like you never actually use the values $params and $params2. You concatenate them, but where is your $stmt->bind_param()? It's commented out?
I don't see a $conn->prepare("") either. Did you omit some code?
$conn is defined as a mysqli object and then again never used. Something's not right here.
Edit:
Try exec("\$stmt->bind_param(\$params\$params2);"); I assume you somehow execute the code and escape the variables - following that logic you should escape both params and params2, perhaps?
This question already has answers here:
Can I bind an array to an IN() condition in a PDO query?
(23 answers)
Closed 8 years ago.
This is my code:
if(isset($_POST['abc']))
{
$things['abc'] = mysqli_real_escape_string($connect, implode("','", $_POST['abc']));
$result = mysqli_query($connect, "SELECT * FROM this_list WHERE abc_column IN ('{$things['abc']}')");
if (!$result)
{
echo "Error fetching results: " . mysqli_error();
}
else
{
while ($row = mysqli_fetch_array($result))
{
$abc[] = $row['description'];
}
}
}
The above code uses mysqli_real_escape_string(), and $things is an array with checkbox values that is received via POST. This array contains the list of strings separated by comma that I am using in the query.
When I was searching on the net, I noticed that some people say mysqli_real_escape_string() may prevent sql injection, I was thinking maybe prepared statement for checkbox values might be more safer against sql injection.
I have used prepared statement with separate parameters to prevent sql injection. But I am stuck on this one and I dont know how to change the above code to a prepare() statement since it uses an array $things['abc']. I tried searching and everytime I search array in prepared statement, I am getting info on Java, etc.. Can someone enlighten me on how I can do this with php please?
EDIT:
After the help from onetrickpony code below, this is what I have now:
if(isset($_POST['abc']))
{
$ph = rtrim(str_repeat('?,', count($_POST['abc'])), ',');
$query = sprintf("SELECT col1 FROM abc_table WHERE col2 IN (%s)", $ph);
$stmt = mysqli_prepare($connect, $query);
// bind variables
$params = array();
foreach($_POST['abc'] as $v)
$params[] = &$v;
array_unshift($params, $stmt, str_repeat('s', count($_POST['abc']))); // s = string type
call_user_func_array('mysqli_stmt_bind_param', $params);
mysqli_stmt_execute($stmt);
// Get the data result from the query.
mysqli_stmt_bind_result($stmt, $col1);
/* fetch values and store them to each variables */
while (mysqli_stmt_fetch($stmt)) {
$name[] = $col1;
echo $name;
}
//loop to echo and see whats stored in the array above
foreach($name as $v) {
echo $v;
}
// Close the prepared statement.
$stmt->close();
}
In the above code, the sqli method for prepare statement seems to work which is great. However, when I use the mysqli_stmt_bind_result(), the $name[] array inside the while loop only seems to print the last row.
UPDATE:
onetrickpony's code with the mysqli method for using php array in a Prepared Statement worked fine and it was a very good approach he had suggested. However, I have been having nightmare with the second half of the code which is trying to get the fetched array results to work. After trying for more than a day, I have given up on that and I have made the switch to PDO. Again onetrickpony's advise below was totally worth it. Making the switch to PDO made the code so much easier and simpler and couldnt believe it.
Try this:
// build placeholder string (?,?...)
$ph = rtrim(str_repeat('?,', count($_POST['abc'])), ',');
$query = sprintf("SELECT * FROM this_list WHERE abc_column IN (%s)", $ph);
$stm = mysqli_prepare($connect, $query);
// bind variables (see my notes below)
$params = array();
foreach($_POST['abc'] as $v)
$params[] = &$v;
// s = string type
array_unshift($params, $stm, str_repeat('s', count($_POST['abc'])));
call_user_func_array('mysqli_stmt_bind_param', $params);
mysqli_stmt_execute($stm);
It appears that mysqli_stmt_bind_param cannot be called multiple times to bind multiple variables. And even worse, it requires referenced variables. I'd recommend you switch to PDO, just because of these limitations that force you to write ugly code :)