How to deliver params for SELECT with IN in mysqli - php

My prepared query looks like this:
$sql = "SELECT $t1.id FROM $t1 WHERE $t1.name IN (?)";
When I try:
$stmt = Sql::$select->prepare($sql);
$string="'aaa','bbb','ccc'";
$stmt->bind_param('s', $string);
...it doesn't return the expected results. It treats the string as one name and not many separate names. How can it be solved?
The rest of the function:
$stmt->execute();
$stmt->store_result();
return $stmt;

Try altering query like this
$sql = "SELECT $t1.id FROM $t1 WHERE FIND_IN_SET($t1.name, ?)>0";
$stmt = Sql::$select->prepare($sql);
$string='aaa,bbb,ccc';
$stmt->bind_param('s', $string);
And this solution is not reliable.
Please see FIND_IN_SET(str,strlist)
Correct method is to use separate placeholders for each element in the IN statement.
Another suggestion, get rid of the IN statement and run through a loop in php to generate the query and bind the params.

The problem is that the bind_param function with 's' threats the parameter as a single string, so it is basically transforming your query to:
"SELECT $t1.id FROM $t1 WHERE $t1.name IN (''aaa','bbb','ccc'')";
A quick fix would be to change the string variable to:
$string="aaa','bbb','ccc";
Note: without the leading/trailing quotes (you can make this using trim($string, "'")
You may also try inverting the quotes: using " instead of ' if this does not work.
A more reliable and robust solution is to change the query to incude a ? for each string (using arrays with expolode() / implode() php functions.

Related

Unable to execute a query via PDO

I have a bunch of rows to have nieaktualny column (TINYINT(1)) modified from 0 to 1 for all rows with email_1 field equal to values from array $sprawdzone_temp. I have tried many approaches, via exec(), prepare(), execute() but none seems to work and I just have no idea why. No errors pop up when try/catching. When I am using phpMyAdmin, the queries work just fine.
Here's my PHP:
$sql = "UPDATE database.table SET `nieaktualny` = '1' WHERE `email_1` LIKE ?";
$stmt = $db->prepare($sql);
foreach($sprawdzone_temp as $email) {
$stmt->execute(array($email));
}
The array with data is fine, there seems to be something wrong with how I want to use PDO.
I suspect that your $sprawdzone_temp might not have the SQL Wildcard Characters
A wildcard character is used to substitute any other character(s) in a string.
Wildcard characters are used with the SQL LIKE operator. The LIKE operator is used in a WHERE clause to search for a specified pattern in a column.
There are two wildcards used in conjunction with the LIKE operator:
(%) - The percent sign represents zero, one, or multiple characters
2 . (_) - The underscore represents a single character
Therefore your code should be along these lines :
<?php
$sprawdzone_temp = "%".$sprawdzone_temp."%";
$sql = "UPDATE database.table SET `nieaktualny` = 1 WHERE `email_1` LIKE ?";
$stmt = $db->prepare($sql);
foreach($sprawdzone_temp as $email) {
$stmt->execute(array($email));
}
if(!$stmt){
echo "\nPDO::errorInfo():\n";
print_r($db->errorInfo());
}
?>
Update
I would suggest that you also try the SQL IN Operator, which allows you to specify multiple values in a WHERE clause.
The IN operator is a shorthand for multiple OR conditions.
<?php
$sprawdzone_temp = array($nadawca);
$in = str_repeat('?,', count($sprawdzone_temp) - 1) . '?';
$sql = "UPDATE database.table SET `nieaktualny` = 1 WHERE `email_1` in($in)";
$stmt = $db->prepare($sql);
$stmt->execute($sprawdzone_temp);
if (!$stmt) {
echo "\nPDO::errorInfo():\n";
print_r($db->errorInfo());
} else {
echo "record updated";
}
?>
tl;dr
I had to apply strip_tags to the emails that were later used in PDO query.
The issue was not in anything related to queries. The emails from the $sprawdzone_temp array were not prepared properly. When I print_r'ed the array, it looked normally, there was simply the proper email address without any spaces or similar. When I copy-pasted them from the print_r to phpMyAdmin, queries worked fine, but seemingly there was some illegal character that was interrupting the LIKE condition of SQL queries.
I have fixed that when I have randomly tried applying strip_tags when inserting the email addresses into the $sprawdzone_temp array. Now it works. Just out of curiosity - can I somehow print all the characters in a avalue - just to check what character was in there that caused the PDO query to stop?

How to deal with apostrophes and double quotes simultaneously in PHP

I have a HTML form, from which a PHP script extracts values, as shown below:
$dbc = mysqli_connect("all required info here...") or die("Error occurred");
$sent = "Any sentence here...which may contain apostrophe or double quotes or both";
$query = "SELECT * FROM myrecord WHERE sentence = '$sent'";
$result = mysqli_query($dbc, $query);
$data = mysqli_fetch_array($result);
mysqli_close($dbc);
The problem is, that the variable $sent can contain any string with a combination of either apostrophe or double quotes or both. This gives an error when going for execution of mysqli_query().
So even if I escape double quotes in initialization of $sent it will still create problem for execution of mysqli_query(). And if I escape both for ' and " then value of $sent does not remains what it actually needs to be (although I am not sure about whether escaping both ' and " will work or not).
Is there any built in function that automatically escapes all special characters of a string? Or any workaround that solves this problem?
[P.S. I have already searched some previous questions on stackoverflow and haven't been able to find a solution.]
What you want, and what you should do is used prepared statements (parameterized queries). With PDO, that would look something like this:
$stmt = $pdo->prepare('SELECT * FROM myrecord WHERE sentence = :sentence');
$stmt->execute([':sentence' => $sentence]);
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
//do stuff
}
mysqli supports them, too, but the API is slightly more cumbersome (IMO) - see mysqli_prepare docs for details:
$stmt = $mysqli->prepare('SELECT * FROM myrecord WHERE sentence = ?');
//or $stmt = mysqli_prepare($connection, $query);
Then, you bind the parameter (the value to be used in the WHERE clause) using bind_param:
$stmt->bind_param('s', $sentence);
//or mysqli_stmt_bind_param($stmt, 's', $sentence);
Then call execute - or mysqli_stmt_execute, and fetch the results using fetch - or mysqli_stmt_fetch...
As mentioned in the comments: the parameters and query string needn't be quoted in any way, because they're treated as separate entities. The result being that you can re-use the same prepared statement with different paramters:
$stmt = $pdo->prepare('SELECT * FROM table WHERE field = :field');
$fieldVals = [123, 46, 32]; // three values:
$results = array_fill_keys($fieldVals, null);
foreach ($fieldVals as $val) {
$stmt->execute([':field' => $val]);//execute with each value in $fieldVals array
$results[$val] = $stmt->fetchAll(PDO::FETCH_ASSOC); // fetch results for this field value
//optional, but good form:
$stmt->closeCursor();
}
you've now used the same statement 3 times, but only had to send the query string once. The query had to be parsed and processed once, and after that, you merely sent the paramters to the DB. This approach is generally faster, safer (prepared statements protect agains most injection attacks), and just all round better.

PHP and MySQL, call_user_func_array doesn't work with variable as argument

I'm trying to set up a dynamic MySQL query, using mysqli prepared statements. I need to compare multiple values (unknown how many) to a single column.
The following works:
$qs = '?,?';
$query = 'SELECT r_id FROM sometable WHERE someindex IN ('.$qs.')';
$statement = $db_conn->prepare($query);
call_user_func_array(array($statement, 'bind_param'), array('ss', 'Something', 'somethingelse'));
I get a result back from the DB, and can do as I please with the return. BUT, the following does not work:
$qs = '?,?';
$query = 'SELECT r_id FROM sometable WHERE someindex IN ('.$qs.')';
$statement = $db_conn->prepare($query);
$test = array('ss', 'Something', 'something else');
call_user_func_array(array($statement, 'bind_param'), $test);
With the only difference being the assignment of $test, instead of creating the array directly within call_user_func_array.
Similarly:
$one = 'pizza';
$two = 'pie';
call_user_func_array(array($statement, 'bind_param'), array('ss', $one, $two));
also does not work. The statement doesn't even execute.
If I can't put variable names directly into the statement, I can't have the dynamic queries. What's going on? Is there a fix for this, or maybe another (equally simple) way I can run a query on a single column, with an unknown number of terms? References or pointers (i.e. &$one) do not work either.
There seems to be a couple known issues with call_user_func_array back in 2012, or around there, but I can't find anything more recent. I am using PHP 5.5
EDIT 1
Known issue, back in 2007 here

How to use a quoted string variable in a MySqli prepared statement?

Sorry if this seems a really stupid question, but I'm struggling to get to grips with changing from Mysql to Mysqli and prepared statements.
So in mysql, I would have done this:
$q=('SELECT * FROM table WHERE field="'.$variable.'"');
$result = mysql_query($q);
I now know this is not good. So I now have the below:
$stmt = $mysqli->prepare('SELECT * FROM table WHERE field=? LIMIT 1');
$stmt->bind_param('s', $variable);
$stmt->execute();
Problem is that the query doesn't work. Say the ? is actually "tree". So the query becomes:
'SELECT * FROM table WHERE field=tree LIMIT 1'
If I tried to run that query in say phpmyadmin I get "Unknown column tree in where clause". Obviously if I put quotes around it then it works, hence the original query. So how can I get this to work if I can't use quotes, since then you are looking for the literal question mark?
For reference I am then using this code:
$meta = $stmt->result_metadata();
while ($field = $meta->fetch_field()) {
$parameters[] = &$row[$field->name];
}
call_user_func_array(array($stmt, 'bind_result'), $parameters);
while ($stmt->fetch()) {
foreach($row as $key => $val) {
$x[$key] = $val;
}
$results[] = $x;
}
As I can't use get_result() which is very annoying. I have PHP version 5.4, and even the mysqlnd driver, but can't enable it as I'm on a VPS and my host says it might affect other sites on that server. Consequently what is actually just two lines in MySql is actually now something like 15 lines in the 'improved' mysqli. Great.
Any help would be appreciated!
This:
$stmt = $mysqli->prepare('SELECT * FROM table WHERE field=? LIMIT 1');
$stmt->bind_param('s', $variable);
is not equivalent to this:
SELECT * FROM table WHERE field=tree LIMIT 1
Prepared statement placeholders are not the same as copy and pasting in values. You are binding the value "tree" as a string here, the database will actually understand this. The ? is not simply being replaced by the bound value, the database understands the difference between your query structure with its placeholders and the values you're binding into them. Binding the parameter this way is equivalent to running:
SELECT * FROM table WHERE field='tree' LIMIT 1
Consequently what is actually just two lines in MySql is actually now something like 15 lines in the 'improved' mysqli. Great.
Mysqli is not intended to be used as is. It is but a building material for the higher level library. When used wisely, it can give you data in one line:
$data = $db->getAll('SELECT * FROM table WHERE field=?s', $variable);
(BTW, the same goes for the old mysql ext as well)

MySQL Statement with question mark and colon

I am trying to decipher a particular statement that is in PHP program that is doing a Mysql query. The query has ?: and ? in it. What is there function?
$data = db_get_field("SELECT data FROM ?:order_data WHERE order_id = ?i AND type = 'A'", $order_id);
Thanks for any help.
Chris
They look like placeholders for prepared statements. You provide the ? where you will later provide an actual value. Consider this example from the PHP documentation:
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (?, ?)");
$stmt->bindParam(1, $name);
$stmt->bindParam(2, $value);
Source: http://php.net/manual/en/pdo.prepared-statements.php
Your particular example appears to be from CS-Cart. For instance, according to their documentation ?i forces the value passed into that placeholder to be converted to an integer (this is similar to the way sprintf works).
$number = 9;
echo sprintf( "I have %d tasks.", $number );
// Outputs "I have 9 tasks."
In the above case, $number is treated as an integer. If I tried to pass a string into that slot, I'd get very different results:
$number = "completed";
echo sprintf( "I have %d tasks.", $number );
// Outputs "I have 0 tasks."
Note here how my types didn't match up, and therefore 0 replaced completed in the output.
Bottom line, these are placeholders.
The characters ? are : identifiers to form a parametrized queries. Later you bind values to variables and the engine performs the query for multiple values. This works faster, as the query is compiled once by server rather than compiling it for each variable=value set.

Categories