I'm trying to update a number of rows in MySql with a prepared PDO statement. It doesn't emit any error but the rows remains untouched. What am I doing wrong?
I replaced username, password and database name with xxx for the sake of security when posting on Stack Overflow.
<?php
header('Access-Control-Allow-Origin: *');
$jsonp = false;
error_reporting(E_ALL);
ini_set("display_errors", 1);
$db = new PDO('mysql:host=localhost;dbname=xxx;charset=utf8', 'xxx', 'xxx');
$party = ($_POST['party']);
$id = ($_POST['id']); /* String with ids. Ex. "1, 2, 3" */
$state = ($_POST['state']);
$code = ($_POST['fetchCode']);
$stmt = $db->prepare("UPDATE wishes SET state = :state WHERE fetchCode = :code AND partyID = :party AND id IN (:id)");
$stmt->bindParam(':party', $party);
$stmt->bindParam(':id', $id);
$stmt->bindParam(':state', $state);
$stmt->bindParam(':code', $code);
$stmt->execute();
echo json_encode("Done");
?>
In your $_POST['id'] there is space after comma. Please try to avoid spaces before and after comma.
Secondly you can add third parameter PARAM_STR to $stmt->bindParam(':id', $id,PARAM_STR); so that it could be treated as a string while preparing query.
Also add error handler to see the error like :
if (!$stmt) {
echo "\nPDO::errorInfo():\n";
print_r($db->errorInfo());
}
One last thing which can help in debugging is you can see what is your final query getting prepared by echo $stmt->queryString
Related
I want to use prepared statements to prevent SQL injections. However, my prepared statement doesn't execute. I think because I get the error message echoed out.
$sql = "SELECT user.username, posted, title, context, tags.name AS sport, image FROM post, user, tags WHERE post.user = user.id AND post.tag = tags.id $extra ORDER BY posted $order;";
echo $sql;
$stmt = $conn -> prepare($sql);
if (isset($_POST["search"])) {
$stmt->bind_param("ss", $search, $search);
}
$stmt->execute();
$stmt->bind_result($username, $posted, $title, $context, $name);
if (!$stmt->errno) {
// Handle error here
echo "An error has occured. Please try again.";
};
while ($stmt->fetch()) {
echo "<article>";
echo "<h1><span>$title</span><span class=\"tags\">$sport</span></h1>";
echo "<figure><img src=\"$image\"></figure>";
echo "<p>$context</p>";
echo "<p class=\"publisher\">Published $posted by #$username</p>";
echo "</article>";
}
$extra is this code :
if (isset($_POST["search"])) {
$search = "%{$_POST['search']}%";
$extra ="AND (context LIKE ? OR username LIKE ?)";
}
However even if there's no search, an error message still appears. Am I doing the prepared statements wrong?
UPDATE:
It seems like it's able to fetch out the right number of rows, however I can't seem to get the result out.
I decided to flip from mysqli/mysqlnd to PDO, however I am encountering a problem I had the last time I did this. I am trying this again as it seems that PDO allegedly supports passing a variable that contains an array of values to the execute() param for binding to the query without having to use things like call_user_func_array.
The code I have for demonstration is :
$bind_arguments[] = "dogs";
$bind_arguments[] = "cats";
$bind_arguments[] = "birds";
$db = new PDO('mysql:dbname=' . SQL_DATA . ';host=' . SQL_SERVER, SQL_USERNAME, SQL_PASSWORD, array (
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
));
$sql = 'SELECT `name` FROM `pets` WHERE `type` = ? OR `type` = ? OR `type` = ?';
$result = Array();
try {
if($stmt = $db->prepare($sql)) {
$stmt->execute($bind_arguments);
$result = $stmt->fetchAll();
}
} catch(PDOException $e) {
echo 'Wrong SQL: ' . $sql . ' Error: ' . $e->getMessage(); exit;
}
$db = null;
var_export($result); // null
I don't get any exceptions, however $result is null. If I do the regular query using Navicat (or using mysqli) It works!
See Example #5, which shows I should be able to do this (posting example from there here for reference) :
<?php
/* Execute a prepared statement using an array of values for an IN clause */
$params = array(1, 21, 63, 171);
/* Create a string for the parameter placeholders filled to the number of params */
$place_holders = implode(',', array_fill(0, count($params), '?'));
/*
This prepares the statement with enough unnamed placeholders for every value
in our $params array. The values of the $params array are then bound to the
placeholders in the prepared statement when the statement is executed.
This is not the same thing as using PDOStatement::bindParam() since this
requires a reference to the variable. PDOStatement::execute() only binds
by value instead.
*/
$sth = $dbh->prepare("SELECT id, name FROM contacts WHERE id IN ($place_holders)");
$sth->execute($params);
?>
Also see Example #1 posted below for convenience :
<?php
$sth = $dbh->prepare("SELECT name, colour FROM fruit");
$sth->execute();
/* Fetch all of the remaining rows in the result set */
print("Fetch all of the remaining rows in the result set:\n");
$result = $sth->fetchAll();
print_r($result);
?>
So why is this not working ? What am I doing wrong ?
Update
I made some typos when posting my code (which was stripped out of a larger class) for StackOverflow's MVCE requirements. These typos were not present in the original class. I have updated them in the code above. - sorry for any confusion this may have caused.
You are assigning values to $bind_array and $bnid_array but are sending in $bind_arguments to execute(). Try changing $bnid_array to $bind_array and use $stmt->execute($bind_array);
UPDATE:
WORKING CODE, Thanks jon for the push in the right direction.
<?php
$stmt2 = $conn->prepare("SELECT * FROM userItems WHERE id=:id");
foreach ($moodItems as $id2)
{
// bind the parameters
$stmt2->bindValue(":id", $id2);
if ($stmt2->execute()) {
if($result = $stmt2->fetch(PDO::FETCH_ASSOC)) {
// initialise an array for the results
$itemName2 = $result['itemName'];
$name2 = $result['userId'];
echo $itemName2."<br>";
echo $name2."<br>";
}
}
}
?>
I am having trouble using a SQL query in a foreach loop. I am trying to use the value from the first query(which is an array) and use it in the second query.
The first query works correctly to give me the proper value(array).But for some reason when I try to use the array in the foreach it does not work properly, it does not show any errors...it just does not fetch any data from the database.
IE/ echo $itemName2; <----does not get any info from database
Any help would be great. Thanks.
here is the code I am working with:
<?php
$attrs = array(PDO::ATTR_PERSISTENT => true);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// prepare the statement.
$stmt = $conn->prepare("SELECT * FROM userMoodboard WHERE name=:name");
// bind the parameters
$stmt->bindValue(":name", $loggedInUser->username);
// initialise an array for the results
if ($stmt->execute()) {
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$imageUrl = $row['imageUrl'];
$moodItems = $row['moodItems'];
$moodItems = json_decode($moodItems);
?>
<img src='<?php echo $imageUrl;?>' class="thumbnail"></img>
<?php
$stmt = $conn->prepare("SELECT * FROM userItems WHERE id=:id");
foreach ($moodItems as $id)
{
// bind the parameters
$stmt->bindValue(":id", $id);
// initialise an array for the results
if($stmt->execute()) {
$itemName2 = $row['itemName'];
$name2 = $row['userId'];
echo $itemName2;
echo $name2;
}
}
}
}
?>
There are a couple of things wrong with your code, but we'll start with your second statement.
$stmt = $conn->prepare("SELECT userId FROM userItems WHERE id=:id");
foreach ($moodItems as $id)
{
// bind the parameters
$stmt->bindValue(":id", $id);
// initialise an array for the results
if($stmt->execute()) {
$itemName2 = $row['itemName'];
$name2 = $row['userId'];
echo $itemName2;
echo $name2;
}
}
You are trying to pull out $row['itemName'] and $row['userId'], however, you never SELECT the itemName column in that query. So if you want that information, you'll have to select it first. Aside from that, you execute the query, but you never fetch the row with information.
Those are the basics of why the second portion will not work how you want it to.
Now, for the bigger picture. Most of the block of code you provide is a nested if for your first $stmt->execute() and then within a while($row = ... Which, by itself is fine. However, later within the same block, you prepare another statement, which is perfectly acceptable, but you assign it to the same $stmt variable that you are using for the loop in the first place, which will also cause you problems. You'll want to assign a new variable for your second prepared statement, so you can work with the new data-set. Also, going back to the previous block I posted in, you'll want to fetch it to a variable that is not $row, as that is also a used variable.
UPDATE: As pointed out by Jon, my answer applies to Zend_Db_Adapter and not to PDOStatement (which you are using). My apologies.
The problem probably is that you're doing $stmt->execute() on the second SQL query. execute() does not return results, what you want to do is to fetch(), which does return results.
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();
I know this particular query works, as I tested it with unprepared, procedural methods. Here it is:
$name = 'introduction';
$mysqli = new mysqli('localhost', 'user', 'pass', 'db') or die('There was a problem connecting to the database.');
$stmt = $mysqli->prepare("SELECT name, content FROM sections WHERE name = ?");
$stmt->bind_param('s', $name);
$stmt->execute();
$stmt->bind_result($content);
$stmt->fetch();
echo $content;
$stmt->close();
I realized that, since I have an id column as an index in the sections table, I needed to bind that as a result as well, given the above statement at php.net, (thanks again, Bill).
Here's the new code:
$name = 'introduction';
$mysqli = new mysqli('localhost', 'user', 'pass', 'db') or die('There was a problem connecting to the database.');
$stmt = $mysqli->prepare("SELECT name, content FROM sections WHERE name = ?");
$stmt->bind_param('s', $name);
$stmt->execute();
$stmt->bind_result($id, $name, $content);
$stmt->fetch();
echo $content;
$stmt->close();
Thanks again to all who can offer suggestions. (I'm curious: I find it hard to debug when using the OOP style of prepared statements in this way. Is there, for example, an easy way to simply see the query that was actually used?)
If I do the following, just as a quick-and-dirty example:
$name = 'introduction';
#mysql_connect('host', 'user', 'pass');
#mysql_select_db('db');
$query = "SELECT name,content FROM sections WHERE name = '$name'";
$result = mysql_query($query) or die(mysql_error());
while($row = mysql_fetch_object($result)) {
$content = $row->content;
echo $content;
}
My data appears and all is well. If, however, I do the following:
$name = 'introduction';
$mysqli = new mysqli('localhost', 'user', 'pass', 'db') or die('There was a problem connecting to the database.');
$stmt = $mysqli->prepare("SELECT name, content FROM sections WHERE name = ?");
$stmt->bind_param('s', $name);
$stmt->execute();
$stmt->bind_result($name, $content);
$stmt->fetch();
echo $content;
$stmt->close();
Which I believe is correct (feel free to yell if not, of course), I get nothing. What's more, with that code, when I do an html validation (just in case), I get an internal server warning (500), which I take to be a problem with the sql code. Am I just nuts?
I don't see anything wrong with your preparation of the statement or use of parameters, but there is something wrong in your binding results:
http://php.net/manual/en/mysqli-stmt.bind-result.php says:
Note that all columns must be bound
after mysqli_stmt_execute() and prior
to calling mysqli_stmt_fetch().
(emphasis mine)
The above doc should be taken as all columns in your query, not all columns in your table.
Okay, I just tried this myself. If I omit the $name column, it gives this warning:
PHP Warning: mysqli_stmt::bind_result(): Number of bind variables doesn't
match number of fields in prepared statement in mysqli.php on line 9
PHP Stack trace:
PHP 1. {main}() /Users/bill/workspace/PHP/mysqli.php:0
PHP 2. mysqli_stmt->bind_result() /Users/bill/workspace/PHP/mysqli.php:9
But it does fetch the data.
If I bind both $name and $content to the results of the query, it works without error or warning.
So I'm forced to ask you: are you sure there's a row in the database that matches your condition? That is, where name = 'introduction'? Keep in mind that in SQL, string comparisons are case-sensitive by default.
One mistake I see people make frequently is that they connect to a different database in their PHP script than the database they use for ad hoc queries. So you need to be absolutely sure you're verifying that the data exists in the right database.
Shouldn't that be
$stmt->bind_result($name, $content);
As you select 2 columns