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();
Related
My problem is, how to make my code, return ID that is assigned to person i have in database, instead of 1-which i dont know from it comes.
Opiekun Prawny:<select id="text_box_od" name="fullname_opiekun" >
<?php
while($rows = $resultimie->fetch_assoc())
{
$full_name_opiekun = $rows['full_name_opiekun'];
echo "<option value='$full_name_opiekun'>$full_name_opiekun</option>";
}
?>
</select>
<?php
$con=mysqli_connect('localhost','root','','aplikacja_kolonijna');
if(!$con)
{
echo 'Data base not found';
}
$fullname_opiekun = $_POST['fullname_opiekun'];
$check = "SELECT id_opiekun FROM opiekun where concat(imie_opiekun,' ',nazwisko_opiekun,' - ',pesel_opiekun) like '$fullname_opiekun'";
$query = mysqli_query($con,$check);
$result = intval(mysqli_fetch_row($query));
echo $result;
echo $fullname_opiekun;
Actually person i'm calling is " Kazimierz Kowalczyk 14212312312"
and it's person i have in my database , but with ID 3.
My code, instead of return 3, when i check echo $result; , return 1, all the time, and i have now idea, how to make it work like i want.
When i'm checking echo $full_name_opiekun; it shows me that my SELECT works and returns to me " Kazimierz Kowalczyk 14212312312"... why i can't get right ID?
You need to remember that when you have some input to pass into SQL you must use prepared statements and bind the parameters. If you use prepared statements then to fetch a single value from the result you only need to use $stmt->bind_result($yourVariable) and then $stmt->fetch()
I have fixed your code and also switched error reporting on. You should always make sure it is on.
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$con = mysqli_connect('localhost', 'root', '', 'aplikacja_kolonijna');
$con->set_charset('utf8mb4'); // always set the charset
$fullname_opiekun = $_POST['fullname_opiekun'];
// Execute the query
$check = "SELECT id_opiekun FROM opiekun where concat(imie_opiekun,' ',nazwisko_opiekun,' - ',pesel_opiekun) like ?";
$stmt = $con->prepare($check);
$stmt->bind_param('s', $fullname_opiekun);
$stmt->execute();
// Bind the first column as a result
$stmt->bind_result($result);
$stmt->fetch(); // Fetch the value
echo $result;
echo $fullname_opiekun;
Don't cast the result array to an integer. You need to use the index.
You also should use prepared statements with parameterized queries, and use the error reporting function so you know when errors are returned.
$fullname_opiekun = $_POST['fullname_opiekun'];
$check = "SELECT id_opiekun FROM opiekun where concat(imie_opiekun,' ',nazwisko_opiekun,' - ',pesel_opiekun) like ?";
if ($stmt = mysqli_prepare($con, $check)) {
mysqli_stmt_bind_param($stmt, "s", $fullname_opiekun);
mysqli_stmt_bind_result($stmt, $id_opiekun);
mysqli_stmt_fetch($stmt);
echo $id_opiekun;
mysqli_stmt_close($stmt);
} else {
printf("Error message: %s\n", mysqli_error($con));
}
Don't complicate, this is enough:
//...
$check = "SELECT id_opiekun FROM opiekun where concat(imie_opiekun,' ',nazwisko_opiekun,' - ',pesel_opiekun) like '$fullname_opiekun'";
$query = mysqli_query($con,$check);
$result = mysqli_fetch_row($query);
echo $result[0]; // as `fetch_row` returns 0-indexed array
// example to fetch associative array:
//$result = mysqli_fetch_assoc($query);
//echo $result['id_opiekun'];
I'm using this code to insert a record with a unique id and then return the id-string just created:
$sql ="set #id=UUID();";
$sql .="INSERT INTO `items` (`id`,`parent`, `text`, `type`) VALUES(#id,'".$parent."', '".$text."', '".$type."');";
$sql .="select #id;";
if (mysqli_multi_query($conn, $sql)) {
while (mysqli_more_results($conn)) {
mysqli_use_result($conn);
mysqli_next_result($conn);
}//while
$result = array('id' => mysqli_store_result($conn)->fetch_row()[0]);
}//if
If everything works as it should, the three queries should return:
1/true (I guess)
1/true
object
I never used this function before and I was wondering: what happens if the insert query fails?
The third query will still be executed?
And in that case, how can I check the result of the second query?
Edit:
Or in general:
having a set of 10 queries, in case of failure how can I check which one has failed?
After some test...
Let's assume we have the following 3 queries:
$sql ="INSERT INTO `items` (`id`,`parent`) VALUES ('id',WRONG_NO_QUOTES);";
$sql .="INSERT INTO `items` (`id`,`parent`) VALUES ('id','right2');";
$sql .="INSERT INTO `items` (`id`,`parent`) VALUES ('id','right3');";
Using the code provided by the manual...
if (mysqli_multi_query($conn,$sql)) {
do {
/* store first result set */
if ($result = mysqli_store_result($conn)) {
while ($row = $result->fetch_row()) {
printf("%s\n", $row[0]);
}
$result->free();
}
/* print divider */
if (mysqli_more_results($conn)) {
printf("-----------------\n");
}
} while (mysqli_next_result($conn));
}
//...plus this....
if(mysqli_errno($conn)){
echo 'mysqli_errno:';
var_dump(mysqli_errno($conn));
echo'<br>';
}
...the output is:
mysqli_errno:
[...]test.php:39:int 1146
...and there are no changes to the database.
Conclusion:
When an error occours, the next queries are NOT executed.
AND the error can be easly catched at the end of the do/while loop.
EDIT
The code above generates a strict standards notice.
I edited it to avoid the notice and get a (basic) backtrace of the error:
$n=1;
$i=1;
if (mysqli_multi_query($conn,$sql)) {
do {
/* store first result set */
if ($result = mysqli_store_result($conn)) {
while ($row = $result->fetch_row()) {
echo $row[0];
}
$result->free();
}
/* print divider */
if (mysqli_more_results($conn)) {
echo "<hr>";
$n++;
mysqli_next_result($conn);
}else{$i=0;}
} while ($i>0);
}
if(mysqli_errno($conn)){
echo 'mysqli error on query number '.$n;
var_dump(mysqli_errno($conn));
}
Since my actual problem was to avoid competition between queries and get the right identifier (check: this question) I realized there is a simpler (and maybe better) way to reach the desired result (here using pdo extension):
$db = new PDO ("mysql:host=$hostname;dbname=$dbname", $user, $pass);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//No user defined variable here inside (safe)
$identifier=db->query("SELECT UUID();")->fetch()[0];
Having the identifier stored into a PHP variable, then I can treat every following query separately using pdo and prepared statements.
Below is some poorly written and heavily misunderstood PHP code with no error checking. To be honest, I'm struggling a little getting my head around the maze of PHP->MySQLi functions! Could someone please provide an example of how one would use prepared statements to collect results in an associative array whilst also getting a row count from $stmt? The code below is what I'm playing around with. I think the bit that's throwing me off is using $stmt values after store_result and then trying to collect an assoc array, and I'm not too sure why...
$mysqli = mysqli_connect($config['host'], $config['user'], $config['pass'], $config['db']);
$stmt = $mysqli->prepare("SELECT * FROM licences WHERE generated = ?");
$stmt->bind_param('i', $core['id']);
$result = $stmt->execute();
$stmt->store_result();
if ($stmt->num_rows >= "1") {
while($data = $result->fetch_assoc()){
//Loop through results here $data[]
}
}else{
echo "0 records found";
}
I feel a little cheeky just asking for code, but its a working demonstration of my circumstances that I feel I need to finally understand what's actually going on. Thanks a million!
I searched for a long time but never found documentation needed to respond correctly, but I did my research.
$stmt->get_result() replace $stmt->store_result() for this purpose.
So, If we see
$stmt_result = $stmt->get_result();
var_dump($stmt_result);
we get
object(mysqli_result)[3]
public 'current_field' => int 0
public 'field_count' => int 10
public 'lengths' => null
public 'num_rows' => int 8 #That we need!
public 'type' => int 0
Therefore I propose the following generic solution. (I include the bug report I use)
#Prepare stmt or reports errors
($stmt = $mysqli->prepare($query)) or trigger_error($mysqli->error, E_USER_ERROR);
#Execute stmt or reports errors
$stmt->execute() or trigger_error($stmt->error, E_USER_ERROR);
#Save data or reports errors
($stmt_result = $stmt->get_result()) or trigger_error($stmt->error, E_USER_ERROR);
#Check if are rows in query
if ($stmt_result->num_rows>0) {
# Save in $row_data[] all columns of query
while($row_data = $stmt_result->fetch_assoc()) {
# Action to do
echo $row_data['my_db_column_name_or_ALIAS'];
}
} else {
# No data actions
echo 'No data here :(';
}
$stmt->close();
$result = $stmt->execute(); /* function returns a bool value */
reference : http://php.net/manual/en/mysqli-stmt.execute.php
so its just sufficient to write $stmt->execute(); for the query execution.
The basic idea is to follow the following sequence :
1. make a connection. (now while using sqli or PDO method you make connection and connect with database in a single step)
2. prepare the query template
3. bind the the parameters with the variable
4. (set the values for the variable if not set or if you wish to change the values) and then Execute your query.
5. Now fetch your data and do your work.
6. Close the connection.
/*STEP 1*/
$mysqli = mysqli_connect($servername,$usrname,$pswd,$dbname);
/*STEP 2*/
$stmt = $mysqli->prepare("SELECT * FROM licences WHERE generated = ?");
/*Prepares the SQL query, and returns a statement handle to be used for further operations on the statement.*/
//mysqli_prepare() returns a statement object(of class mysqli_stmt) or FALSE if an error occurred.
/* STEP 3*/
$stmt->bind_param('i', $core['id']);//Binds variables to a prepared statement as parameters
/* STEP 4*/
$result = $stmt->execute();//Executes a prepared Query
/* IF you wish to count the no. of rows only then you will require the following 2 lines */
$stmt->store_result();//Transfers a result set from a prepared statement
$count=$stmt->num_rows;
/*STEP 5*/
//The best way is to bind result, its easy and sleek
while($data = $stmt->fetch()) //use fetch() fetch_assoc() is not a member of mysqli_stmt class
{ //DO what you wish
//$data is an array, one can access the contents like $data['attributeName']
}
One must call mysqli_stmt_store_result() for (SELECT, SHOW, DESCRIBE, EXPLAIN), if one wants to buffer the complete result set by the client, so that the subsequent mysqli_stmt_fetch() call returns buffered data.
It is unnecessary to call mysqli_stmt_store_result() for other queries, but if you do, it will not harm or cause any notable performance in all cases.
--reference: php.net/manual/en/mysqli-stmt.store-result.php
and http://www.w3schools.com/php/php_mysql_prepared_statements.asp
One must look up the above reference who are facing issue regarding this,
My answer may not be perfect, people are welcome to improve my answer...
If you would like to collect mysqli results into an associative array in PHP you can use fetch_all() method. Of course before you try to fetch the rows, you need to get the result with get_result(). execute() does not return any useful values.
For example:
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli($config['host'], $config['user'], $config['pass'], $config['db']);
$mysqli->set_charset('utf8mb4'); // Don't forget to set the charset!
$stmt = $mysqli->prepare("SELECT * FROM licences WHERE generated = ?");
$stmt->bind_param('i', $core['id']);
$stmt->execute(); // This doesn't return any useful value
$result = $stmt->get_result();
$data = $result->fetch_all(MYSQLI_ASSOC);
if ($data) {
foreach ($data as $row) {
//Loop through results here
}
} else {
echo "0 records found";
}
I am not sure why would you need num_rows, you can always use the array itself to check if there are any rows. An empty array is false-ish in PHP.
Your problem here is that to do a fetch->assoc(), you need to get first a result set from a prepared statement using:
http://php.net/manual/en/mysqli-stmt.get-result.php
And guess what: this function only works if you are using MySQL native driver, or "mysqlnd". If you are not using it, you'll get the "Fatal error" message.
You can try this using the mysqli_stmt function get_result() which you can use to fetch an associated array. Note get_result returns an object of type mysqli_result.
$stmt->execute();
$result = $stmt->get_result(); //$result is of type mysqli_result
$num_rows = $result->num_rows; //count number of rows in the result
// the '=' in the if statement is intentional, it will return true on success or false if it fails.
if ($result_array = $result->fetch_assoc(MYSQLI_ASSOC)) {
//loop through the result_array fetching rows.
// $ rows is an array populated with all the rows with an associative array with column names as the key
for($j=0;$j<$num_rows;$j++)
$rows[$j]=$result->fetch_row();
var_dump($rows);
}
else{
echo 'Failed to retrieve rows';
}
What's the best way to verify mysql executed successfully and then returned a result when you CANNOT use the following code:
$db = dbConnect();
//begin prepared statements to search db
$stmt = $db->prepare("SELECT email,authentication,email_confirm,externalid,password,id, admin FROM users WHERE email=?");
$stmt->bind_param('s',$email);
$stmt->execute();
$result = $stmt->get_result();
if (!$result){
//error statement
} if (!(mysqli_num_rows($result)==0)){
//action to perform
} else {
// no result returned
}
I was using get_result numerous times in my scripts, and my hosting provider doesn't have mysqlnd driver so I have to rewrite a lot of code. I know I am limited to bind_result and fetch(), but I need a little help rewriting the code since my mindset is stuck in the way I first did it.
I'm also using mysqli and not PDO.
The Mysqli fetch() function will return one of 3 values:
TRUE - Success. Data has been fetched
FALSE - Error occurred
NULL - No more rows/data exists or data truncation occurred
This means you can set your query like this:
$db = dbConnect();
$query = "SELECT email,authentication,email_confirm,externalid,password,id, admin FROM users WHERE email=?";
$stmt = $db->prepare();
$stmt->bind_param('s',$email);
$stmt->execute();
$stmt->bind_result($email,$auth,$email_confirm,$externalid,$password,$id,$admin);
// Will only execute loop if returns true
$record_count = 0;
while($result = $stmt->fetch())
{
// Increment counter
$record_count++;
// Do something with bound result variables
echo("Email is $email");
}
// After the loop we either ran out of results or had an error
if($result === FALSE)
{
echo("An error occurred: " . $db->error());
}
elseif($record_count == 0)
{
echo("No records exist.");
}
I am trying to learn PHP5 and am having a couple of problems with it. I am working with prepared statements and am trying to run the following code:
<?php
require_once 'includes/config.php';
$conn = new mysqli(DB_SERVER, DB_USER, DB_PASSWORD, DB_NAME) or
die('There was a problem connecting to the database.');
$query = "SELECT * FROM user_table";
if($stmt = $conn->prepare($query)) {
$stmt->execute();
while ($row = $stmt->fetch()) {
print_r ($row);
}
}
?>
I have 2 rows it should return each containing an id, login_name, login_password and a login_level.
When the statement runs it only prints the following:
11
Any help would be greatly appreciated.
The fetch() method returns TRUE, FALSE, or NULL depending on whether it succeeded in fetching the data. It doesn't return the data in an array. Instead it places the results in variables bound by the bind_result() method.
It returns 1 because 1 is TRUE in PHP.
What you should do is bind a variable with the [bind_result][1] method and then do:
while ($stmt->fetch()) {
printf ("%s\n", $variable);
}
A great example is on the bind result documentation page.
To be able to get that this way you first need to bind the result variables like this:
$stmt->execute();
// bind the result variables in order
$stmt->bind_result($id, $login_name, $login_password, $login_level);
// then get results
while ($stmt->fetch()) {
var_dump($id, $login_name, $login_password, $login_level);
}