Multiple queries with MySqli - php

I'm making a query using PHP/MySqli like this:
$sql = $mysqli->prepare("SELECT * FROM rooms
WHERE 1
LIMIT 0, 30 ");
$result = "['Number', 'Status', 'Category', 'Pbx Number', 'Price for today'],";
$sql->execute();
$sql->bind_result($id, $number, $status, $category, $pbx);
while ($sql->fetch()) {
$result .= " ['$number', '$status', '$category', '$pbx'," . priceForRoom($mysqli, $number, time()) . "],";
}
$sql->free_result();
return ($result);
It all works fine, as long as priceForRoom() doesn't need to connect to the mysqli db to return a value. But, as soon as I implement priceForRoom() and use mysqli I get this error:
Commands out of sync; you can't run this command now
So many people got the same error, but I still don't understand how can I fix this. I don't want to store the results in an array, how can I use mysqli_store_result without going procedural-style? I'd like to keep my code object oriented: where should I ask mysqli to store the result?

You need to store the results fetched to your variables before you can use them again.
Hence
$sql->bind_result($id, $number, $status, $category, $pbx);
while ($sql->fetch()) {
$sql->store_result();
Read up more about store_result() on php.net.

Related

SELECT with mysqli returns null

I'm trying to select a row from a table using mysqli but all I can get is a bunch of null values and I don't really know why. The same query works using normal php mysql and if I try to perform the same query on phpMyAdmin using the parameter I pass goes through fine.
Here's the code:
$con = mysqli_connect('localhost', 'user', 'pass',"db");
if (mysqli_connect_errno()){
die("Failed to connect to MySQL: " . mysqli_connect_error());
}
$coupon = $_GET['coupon'];
$sql = mysqli_prepare($con, "SELECT * FROM coupon WHERE coupon=?");
$sql->bind_param('s', $coupon);
$sql->execute();
$sql->store_result();
echo $sql;
returns
"affected_rows":null,
"insert_id":null,
"num_rows":null,
"param_count":null,
"field_count":null,
"errno":null,
"error":null,
"error_list":null,
"sqlstate":null,
"id":null
I already tried to search for an answer either here and on google but I couldn't find anything close to my problem.
What am I doing wrong?
You must decide if you're using procedural or OOP approach. From your code, it seems you call the procedural version of mysqli extension and afterwards you try using objects. See the documentation examples, both object oriented and procedural and decide on a single one.
author's final solution (moved from question content):
As suggested by user #RiggsFolly I wasn't fetching the results at all, plus I was mixing procedural and OOP approaches as suggested by user #Alex . Here's the working code for future reference to anyone who will arrive here with a similar problem:
$coupon = $_GET['coupon'];
if ($sql = mysqli_prepare($con, "SELECT * FROM coupon WHERE coupon=?;")){
mysqli_stmt_bind_param($sql, 's', $coupon);
mysqli_stmt_execute($sql);
mysqli_stmt_bind_result($sql, $ID, $coupon, $discount, $uses);
mysqli_stmt_fetch($sql);
$data = array(
'ID' => $ID,
'coupon' => $coupon,
'discount' => $discount,
'uses' => $uses
);
echo json_encode($data);
}else{
echo json_encode(FALSE);
}

mysqli handle prepared procedure call with multiple result sets with different columns

Is there a way to handle multiple result sets from a single prepared query when the result sets have different columns?
I have a procedure like this:
CREATE PROCEDURE usp_CountAndList (in_SomeValue int)
BEGIN
SELECT COUNT(*) AS ListCount FROM Table WHERE SomeValue = in_SomeValue;
SELECT
Name, Cost, Text
FROM Table WHERE SomeValue = in_SomeValue
ORDER BY
Name
LIMIT 25;
END
And my PHP code looks like this:
$some_value = $_POST["SomeValue"];
if($some_value != null) {
$dbh = mysqli_connect(...connection stuff...) or die ('I cannot connect to the database.');
$query = $dbh->prepare("CALL usp_CountAndList( ? );");
$query->bind_param("i", $some_value);
if($query->execute() == true) {
$meta = $query->result_metadata();
$fields = $meta->fetch_fields();
var_dump($fields);
$query->store_result();
$query->bind_result($list_count);
while($query->fetch()) {
print_r("<TR>");
print_r("<TD>" . $list_count ."</TD>");
print_r("</TR>\n");
}
$query->free_result();
$dbh->next_result();
$meta = $query->result_metadata();
$fields = $meta->fetch_fields();
var_dump($fields);
$query->store_result();
$query->bind_result($name, $cost, $text);
while($query->fetch()) {
print_r("<TR>");
print_r("<TD>" . $name . "</TD>");
print_r("</TR>\n");
}
$query->free_result();
$dbh->next_result();
}
else {
print_r("Query failed: " . $query->error . "<BR>\n");
exit(0);
}
$query->close();
$dbh->close();
}
The issue I'm running into is that it looks like I'm getting the same meta-data for the second result set, even though it is returning a completely different set of columns, which means that my second bind_result call results in the following error:
PHP Warning: mysqli_stmt::bind_result() [<a href='mysqli-stmt.bind-result'>mysqli-stmt.bind-result</a>]: Number of bind variables doesn't match number of fields in prepared statement
I've banged my head against this for a while and am just not clear on what I'm doing wrong...it almost seems like a mysqli bug. Does anyone have some example code to show how to do what I'm attempting?
Basically there are a few requirements to make this work properly...
MYSQL 5.5.3 or higher
PHP 5.3 for mysqlnd support
This is a compile time setting so if you are using shared hosting you probably cannot change this.
Basically in your example, use $query->next_result() instead of $dbh->next_result().
mysqli_stmt::next_result
I've only found one SO example of some else attempting to do this.

Do I need to bind result when fetching all results for security?

When I was learning about SQL security and preventing SQL injection, I learnt that its better to use bindparam when fetching results for an id like this:
//Prepare Statement
$stmt = $mysqli->prepare("SELECT * FROM my_table WHERE id=?");
if ( false===$stmt ) {
die('prepare() failed: ' . htmlspecialchars($mysqli->error));
}
$rc = $stmt->bind_param("i", $id);
if ( false===$rc ) {
die('bind_param() failed: ' . htmlspecialchars($stmt->error));
}
$rc = $stmt->execute();
if ( false===$rc ) {
die('execute() failed: ' . htmlspecialchars($stmt->error));
}
// Get the data result from the query. You need to bind results for each column that is called in the prepare statement above
$stmt->bind_result($col1, $col2, $col3, $col4);
/* fetch values and store them to each variables */
while ($stmt->fetch()) {
$id = $col1;
$abc = $col2;
$def = $col3;
$xyz = $col4;
}
$stmt->close();
$mysqli->close();
Atm, when I am fetching all results, I am using this:
$query= "SELECT * FROM my_table";
$result=mysqli_query($connect, $query);
if (!$result)
{
die('Error fetching results: ' . mysqli_error());
exit();
}
echo '<table border="1">'; // start a table tag in the HTML
//Storing the results in an Array
while ($row = mysqli_fetch_array($result)) //Creates a loop to loop through results
{
echo "<tr><td>" . $row['abc'] . "</td><td>" . $row['def'] . "</td><td>" . $row['xyz'] . "</td></tr>";
}
echo '</table>'; //Close the table in HTML
My question is:
For my second code, do I need to use bind_result when fetching all results for any security reasons similar to my first example?
If yes, how can I use prepare statement with bind_result when I am fetching all results and not using $id?
If I use the second example the way it is for fetching all results, are there any security issues?
1) For my second code, do I need to use bind_result when fetching all results for any security reasons similar to my first example?
No. bind_result() has nothing to do with security. You can use whatever method you wish with any query.
2) If yes, how can I use prepare statement with bind_result when I am fetching all results and not using $id?
Exactly the same way as with any other query. There is no difference actually. and having any particular variable doesn't matter at all.
3) If I use the second example the way it is for fetching all results, are there any security issues?
There is always a security issue. But none from the area of SQL injection in this snippet. You may wish to check for XSS issues.
Just to clarify your ambiguous question:
In case you are confusing bind_result with bind_param, here is a rule of thumb: you have to use a placeholder (and thus bind_param()) for the every variable that is going into query. Always. No exceptions.
From this rule you can simply tell if you need to use prepare() or not in any particular case.
Also, there is no need for such a long and windy code in the first example.
$stmt = $mysqli->prepare("SELECT * FROM my_table WHERE id=?");
$rc = $stmt->bind_param("i", $id);
$rc = $stmt->execute();
$stmt->bind_result($id, $abc, $def, $xyz);
while ($stmt->fetch()) {
echo $id;
}
Just set mysqli in exception mode before connect:
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

PHP Commands Out of Sync error

I am using two prepared statements in PHP/MySQLi to retrieve data from a mysql database. However, when I run the statements, I get the "Commands out of sync, you can't run the command now" error.
Here is my code:
$stmt = $mysqli->prepare("SELECT id, username, password, firstname, lastname, salt FROM members WHERE email = ? LIMIT 1";
$stmt->bind_param('s', $loweredEmail);
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($user_id, $username, $db_password, $firstname, $lastname, $salt);
$stmt->fetch();
$stmt->free_result();
$stmt->close();
while($mysqli->more_results()){
$mysqli->next_result();
}
$stmt1 = $mysqli->prepare("SELECT privileges FROM delegations WHERE id = ? LIMIT 1");
//This is where the error is generated
$stmt1->bind_param('s', $user_id);
$stmt1->execute();
$stmt1->store_result();
$stmt1->bind_result($privileges);
$stmt1->fetch();
What I've tried:
Moving the prepared statements to two separate objects.
Using the code:
while($mysqli->more_results()){
$mysqli->next_result();
}
//To make sure that no stray result data is left in buffer between the first
//and second statements
Using free_result() and mysqli_stmt->close()
PS: The 'Out of Sync' error comes from the second statement's '$stmt1->error'
In mysqli::query If you use MYSQLI_USE_RESULT all subsequent calls will return error Commands out of sync unless you call mysqli_free_result()
When calling multiple stored procedures, you can run into the following error: "Commands out of sync; you can't run this command now".
This can happen even when using the close() function on the result object between calls.
To fix the problem, remember to call the next_result() function on the mysqli object after each stored procedure call. See example below:
<?php
// New Connection
$db = new mysqli('localhost','user','pass','database');
// Check for errors
if(mysqli_connect_errno()){
echo mysqli_connect_error();
}
// 1st Query
$result = $db->query("call getUsers()");
if($result){
// Cycle through results
while ($row = $result->fetch_object()){
$user_arr[] = $row;
}
// Free result set
$result->close();
$db->next_result();
}
// 2nd Query
$result = $db->query("call getGroups()");
if($result){
// Cycle through results
while ($row = $result->fetch_object()){
$group_arr[] = $row;
}
// Free result set
$result->close();
$db->next_result();
}
else echo($db->error);
// Close connection
$db->close();
?>
I hope this will help
"Commands out of sync; you can't run this command now"
Details about this error can be found in the mysql docs. Reading those details makes it clear that the result sets of a prepared statement execution need to be fetched completely before executing another prepared statement on the same connection.
Fixing the issue can be accomplished by using the store result call. Here is an example of what I initially was trying to do:
<?php
$db_connection = new mysqli('127.0.0.1', 'user', '', 'test');
$post_stmt = $db_connection->prepare("select id, title from post where id = 1000");
$comment_stmt = $db_connection->prepare("select user_id from comment where post_id = ?");
if ($post_stmt->execute())
{
$post_stmt->bind_result($post_id, $post_title);
if ($post_stmt->fetch())
{
$comments = array();
$comment_stmt->bind_param('i', $post_id);
if ($comment_stmt->execute())
{
$comment_stmt->bind_result($user_id);
while ($comment_stmt->fetch())
{
array_push($comments, array('user_id' => $user_id));
}
}
else
{
printf("Comment statement error: %s\n", $comment_stmt->error);
}
}
}
else
{
printf("Post statement error: %s\n", $post_stmt->error);
}
$post_stmt->close();
$comment_stmt->close();
$db_connection->close();
printf("ID: %d -> %s\n", $post_id, $post_title);
print_r($comments);
?>
The above will result in the following error:
Comment statement error: Commands out of sync; you can't run this command now
PHP Notice: Undefined variable: post_title in error.php on line 41
ID: 9033 ->
Array
(
)
Here is what needs to be done to make it work correctly:
<?php
$db_connection = new mysqli('127.0.0.1', 'user', '', 'test');
$post_stmt = $db_connection->prepare("select id, title from post where id = 1000");
$comment_stmt = $db_connection->prepare("select user_id from comment where post_id = ?");
if ($post_stmt->execute())
{
$post_stmt->store_result();
$post_stmt->bind_result($post_id, $post_title);
if ($post_stmt->fetch())
{
$comments = array();
$comment_stmt->bind_param('i', $post_id);
if ($comment_stmt->execute())
{
$comment_stmt->bind_result($user_id);
while ($comment_stmt->fetch())
{
array_push($comments, array('user_id' => $user_id));
}
}
else
{
printf("Comment statement error: %s\n", $comment_stmt->error);
}
}
$post_stmt->free_result();
}
else
{
printf("Post statement error: %s\n", $post_stmt->error);
}
$post_stmt->close();
$comment_stmt->close();
$db_connection->close();
printf("ID: %d -> %s\n", $post_id, $post_title);
print_r($comments);
?>
A couple things to note about the above example:
The bind and fetch on the statement still works correctly.
Make sure the results are freed when the processing is done.
For those of you who do the right thing and use stored procedures with prepared statements.
For some reason mysqli cannot free the resources when using an output variable as a parameter in the stored proc. To fix this simply return a recordset within the body of the procedure instead of storing the value in an output variable/parameter.
For example, instead of having SET outputVar = LAST_INSERT_ID(); you can have SELECT LAST_INSERT_ID(); Then in PHP I get the returned value like this:
$query= "CALL mysp_Insert_SomeData(?,?)";
$stmt = $mysqli->prepare($query);
$stmt->bind_param("is", $input_param_1, $input_param_2);
$stmt->execute() or trigger_error($mysqli->error); // trigger_error here is just for troubleshooting, remove when productionizing the code
$stmt->store_result();
$stmt->bind_result($output_value);
$stmt->fetch();
$stmt->free_result();
$stmt->close();
$mysqli->next_result();
echo $output_value;
Now you are ready to execute a second stored procedure without having the "Commands out of sync, you can't run the command now" error. If you were returning more than one value in the record set you can loop through and fetch all of them like this:
while ($stmt->fetch()) {
echo $output_value;
}
If you are returning more than one record set from the stored proc (you have multiple selects), then make sure to go through all of those record sets by using $stmt->next_result();

Problem with Mysqli SELECT statement not returning anything

I'm sure this will somebody no time at all.
I know that MySqli works on this server as i have tried inserts and they work fine.
I also know that the information I'm trying to obtain is in the database and i can connect to the database without any problems. But I can't for the life of me figure out why this isn't working. I've tried both OO and Procedural but neither of them work. Can someone tell me what it is i'm supposed to be doing? Thanks
$table = 'newcms_broadcasting';
$sql = "SELECT first_info1 FROM $table WHERE region_id = ?";
echo $sql;
//echo $sql;
$region = '1';
$stmt = mysqli_prepare($connection, $sql);
mysqli_stmt_bind_param("s", $region);
mysqli_execute();
mysqli_bind_result($result);
echo 'blah';
// display the results
mysqli_fetch($stmt);
echo "name: $result";
// clean up your mess!
mysqli_close($stmt);
When using procedural style, you should pass $stmt into mysqli_stmt_bind_param, mysqli_stmt_execute, mysqli_bind_result etc
mysqli_stmt_bind_param($stmt, "s", $region);
mysqli_stmt_execute($stmt);
mysqli_bind_result($stmt, $result);
while (mysqli_stmt_fetch($stmt)) {
print_r($result);
}
you forgot to include your compiled statement in binding results:
mysqli_stmt_bind_result($stmt, $result);
also note, that mysqli_fetch is deprecated, have you tried using a classic fetching while loop?
while (mysqli_stmt_fetch($stmt)) {
print_r($result);
}

Categories