PDO bindParam not working in foreach - php

I am using PDO for an application but getting a problem for PDO bindParam(). I have an array and I want to use the values of array for PDO bindParam() using for loop or foreach() but an unexpected result is getting by foreach(). When I used bindParam() in for loop, it worked fine. What I tried was
$con = $this->connection();
$stmt = $con->prepare($sql);
for($i = 0; $i < count($params); $i++){
$stmt->bindParam($i + 1, $params[$i], PDO::PARAM_STR, 10);
}
$stmt->execute();
$result = $stmt->fetchAll();//$result is OK
But when I used bindParam() in foreach() then I got an empty array() as result. Below the codes
$con = $this->connection();
$stmt = $con->prepare($sql);
foreach($params as $key=>$val){ //Here
$stmt->bindParam($key + 1, $val, PDO::PARAM_STR, 10);
}
$stmt->execute();
$result = $stmt->fetchAll(); //$result is an empty array
I'm wondering why this happened. I can't find out the reason. Any information will be appreciated.
EDIT : I solved my problem using bindValue() instead.

use bindValue() instead of bindParam(). bindParam() binds to a reference, so when you execute the query all the parameters use the last value of $val.

If you already have the items in an array, there's no reason to call $stmt->bindParam in a loop; just do:
$con = $this->connection();
$stmt = $con->prepare($sql);
$stmt->execute($params);
$result = $stmt->fetchAll();
Per the PHP documentation:
Execute the prepared statement. If the prepared statement included
parameter markers, you must either:
call PDOStatement::bindParam() to bind PHP variables to the parameter
markers: bound variables pass their value as input and receive the
output value, if any, of their associated parameter markers
or pass an array of input-only parameter values

Related

What's the correct syntax for returning a single value using PDO and mySQL?

I'm trying to switch my sql to PDO but I'm having trouble getting even this simple query to return a value. Surely it can't be this difficult. I've done the same query the old fashioned way and it works perfectly as expected. The PDO version returns nothing. What's the trick here?
This first version returns the value I expect.
$customfieldid = 676;
$entityid = 9784549;
$entitytype = 'familyoverview';
$sql = "select value
from customfieldvalues
where customfieldid = ".$customfieldid."
and entityid = ".$entityid."
and entitytype = '".$entitytype."'";
$result = mysql_query($sql);
if($row = mysql_fetch_array($result)) {
$mysqlvalue = $row["value"];
echo "<br>mysql value: ".$mysqlvalue;
}
This PDO version returns nothing.
$sql = "select value
from customfieldvalues
where customfieldid = :customfieldid
and entityid = :entityid
and entitytype = :entitytype";
$stmt = $pdo->prepare($sql);
//$stmt->bindValue(':customfieldid', $customfieldid, PDO::PARAM_INT);
//$stmt->bindValue(':entityid', $entityid, PDO::PARAM_INT);
//$stmt->bindValue(':entitytype', $entitytype, PDO::PARAM_STR);
$stmt->bindValue(':customfieldid', 676, PDO::PARAM_INT);
$stmt->bindValue(':entityid', 9784549, PDO::PARAM_INT);
$stmt->bindValue(':entitytype', 'familyoverview', PDO::PARAM_STR);
$pdovalue = $stmt->fetchColumn();
echo "<br>pdo value: ".$pdovalue;
I've confirmed that I have a pdo database connection. I've tried using the third parameter and omitting the third parameter in the bindValue calls. I've also tried hardcoding the values in the bindValue calls vs passing them in but none of that makes any difference.
Your PDO code is missing a call to $stmt->execute(), so the query is never sent to the MySQL server and executed. Without executing the query, there can't be any results.

mysqli_stmt::bind_result(): Number of bind variables doesn't match number of fields in prepared statement in

I am using a prepared statement I have passed exactly the same amount of variable in bind_param as I am expecting but still it is giving me an error of variable count doesn't match.
$query = "select `shipping_name`,`shipping_address1`,`shipping_address12`,`shipping_city`,`shipping_state`,`shipping_postalcode`,`billing_name`,`billing_address2`,`billing_address22`,`billing_city`,`billing_state`,`billing_postalcode` from puppy_shipping where unique_id=?";
$stmt = $db->prepare($query);
$bind = 'ssssssssssss';
if ($stmt) {
$stmt->bind_param('s', $id);
$stmt->execute();
$stmt->bind_result($bind, $shipping_name, $shipping_address1, $shipping_address12, $shipping_city, $shipping_state, $shipping_postalcode, $billing_name, $billing_address2, $billing_address22, $billing_city, $billing_state, $billing_postalcode);
while ($stmt->fetch()) {
}
$stmt->close();
}
Your problem is with this line
$stmt->bind_result($bind, $shipping_name,$shipping_address1,$shipping_address12, ....);
You're trying to bind the variable-types, like you do with bind_param(), which is wrong - because this function does not have a parameter like that. bind_result()s only arguments are the values you select from the query, nothing else.
The solution is to simply remove $bind from your bind_result() call, making it
$stmt->bind_result($shipping_name, $shipping_address1, $shipping_address12, ....);
Reference
http://php.net/manual/en/mysqli-stmt.bind-result.php
Object oriented style
$stmt->bind_result($name, $code);
Procedural style
mysqli_stmt_bind_result($stmt, $name, $code);

Fatal error: [] operator not supported for strings multiple delete using PDO

I have this code that is supposed to delete all rows whose checkbox was checked (multiple delete using checkboxes).
if (isset($_POST['del'])) {
$stmt = $db->prepare("DELETE FROM `$tbl_name` WHERE id=:id");
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
$ids = array();
foreach ($_POST['del'] as $pval) {
$ids[] = (int)$pval;
$ids = implode(',',$ids);
$stmt->execute();
}
echo '<h1>Entries deleted.</h1>';
}
this is the form generation code:
echo '<td><input type="checkbox" name="del[]" value="' . (int)$row['id'] . '"></td>';
Everything works fine if single checkbox was checked, or single delete.
But for multiple checkboxes, it results to a fatal error:
Fatal error: [] operator not supported for strings in
Anything I missed?
The fatal error results from this line, as you overwrite the array $ids with the string result of implode() but on the next loop iteration attempt to append to it again with [].
$ids = implode(',',$ids);
That should be removed. You have already bound $id, so you can just execute() in the loop with $id.
if (isset($_POST['del'])) {
// Prepare the statement before the loop
$stmt = $db->prepare("DELETE FROM `$tbl_name` WHERE id=:id");
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
// Execute the prepared statement in the loop with the ids from $_POST
// This is all you need, since $id is bound
foreach ($_POST['del'] as $id) {
$stmt->execute();
}
echo '<h1>Entries deleted.</h1>';
}
That method uses a loop. You could also execute a single statement with positional parameters if you bound each value from $_POST['del'] with its own ?. That is more work, and probably only worth it if you will be deleting lots of items in each loop.

How to run the bind_param() statement in PHP?

I'm trying to make the following code work but I can't reach the execute() line.
$mysqli = $this->ConnectLowPrivileges();
echo 'Connected<br>';
$stmt = $mysqli->prepare("SELECT `name`, `lastname` FROM `tblStudents` WHERE `idStudent`=?");
echo 'Prepared and binding parameters<br>';
$stmt->bind_param('i', 2 );
echo 'Ready to execute<br>'
if ($stmt->execute()){
echo 'Executing..';
}
} else {
echo 'Error executing!';
}
mysqli_close($mysqli);
The output that I get is:
Connected
Prepared and binding parameters
So the problem should be at line 5, but checking the manual of bind_param() I can't find any syntax error there.
When binding parameters you need to pass a variable that is used as a reference:
$var = 1;
$stmt->bind_param('i', $var);
See the manual: http://php.net/manual/en/mysqli-stmt.bind-param.php
Note that $var doesn't actually have to be defined to bind it. The following is perfectly valid:
$stmt->bind_param('i', $var);
foreach ($array as $element)
{
$var = $element['foo'];
$stmt->execute();
}
here it is just a simple explaination
declare a variable to be bind
$var="email";
$mysqli = $this->ConnectLowPrivileges();
echo 'Connected<br>';
$var="email";
$stmt = $mysqli->prepare("SELECT name, lastname FROM tablename WHERE idStudent=?" LIMIT=1);
echo 'Prepared and binding parameters<br>';
$stmt->bindparam(1,$var);
Your actual problem is not at line 5 but rather at line 1.
You are trying to use unusable driver.
While PDO does exactly what you want.
$sql = "SELECT `name`, `lastname` FROM `tblStudents` WHERE `idStudent`=?"
$stm = $this->pdo->prepare($sql);
$stm->execute(array(2));
return $stm->fetch();
After all the years passed since this answer has been written, a new PHP feature emerged, called "argument unpacking". So, since version 5.6 you can pass a value into bind_param:
$stmt->bind_param('i', ...[2]);
But still you have a trouble with getting your data back out of a prepared statement :)

Is it possible to use mysqli_fetch_object with a prepared statement

All the examples I see using mysqli_fetch_object use mysql_query(), I cannot get it to work with prepared statements. Does anyone know what is wrong with this code snippet, as fetch_object returns null.
$sql = "select 1 from dual";
printf("preparing %s\n", $sql);
$stmt = $link->prepare($sql);
printf("prepare statement %s\n", is_null($stmt) ? "is null" : "created");
$rc = $stmt->execute();
printf("num rows is %d\n", $stmt->num_rows);
$result = $stmt->result_metadata();
printf("result_metadata %s\n", is_null($result) ? "is null" : "exists");
$rc = $result->fetch_object();
printf("fetch object returns %s\n", is_null($rc) ? "NULL" : $rc);
$stmt->close();
The output is:
preparing select 1 from dual
prepare statement created
num rows is 0
result_metadata exists
fetch object returns NULL
This is the code I use to create an object from a prepared statement.
It could perhaps be used in a subclass of mysqli?
$query = "SELECT * FROM category WHERE id = ?";
$stmt = $this->_db->prepare($query);
$value = 1;
$stmt->bind_param("i", $value);
$stmt->execute();
// bind results to named array
$meta = $stmt->result_metadata();
$fields = $meta->fetch_fields();
foreach($fields as $field) {
$result[$field->name] = "";
$resultArray[$field->name] = &$result[$field->name];
}
call_user_func_array(array($stmt, 'bind_result'), $resultArray);
// create object of results and array of objects
while($stmt->fetch()) {
$resultObject = new stdClass();
foreach ($resultArray as $key => $value) {
$resultObject->$key = $value;
}
$rows[] = $resultObject;
}
$stmt->close();
MySql Native Driver extension (mysqlnd), has the get_result method:
$stmt->execute();
$obj = $stmt->get_result()->fetch_object();
I don't believe the interface works like that.
Going by the documentation and examples (http://www.php.net/manual/en/mysqli.prepare.php) it seems that $stmt->execute() does not return a resultset, but a boolean indicating success / failure (http://www.php.net/manual/en/mysqli-stmt.execute.php). To actually get the result, you need to bind variables to the resultset (aftere the execute call) using $stmt->bind_result (http://www.php.net/manual/en/mysqli-stmt.bind-result.php).
After you did all that, you can do repeated calls to $stmt->fetch() () to fill the bound variables with the column values from the current row. I don't see any mention of $stmt->fetch_object() nor do I see how that interface could work with a variable binding scheme like described.
So this is the story for "normal" result fetching from mysqli prepared statments.
In your code, there is something that I suspect is an error, or at least I am not sure you intended to do this.
You line:
$result = $stmt->result_metadata();
assignes the resultset metadata, which is itself represented as a resultset, to the $result variable. According to the doc (http://www.php.net/manual/en/mysqli-stmt.result-metadata.php) you can only use a subset of the methods on these 'special' kinds of resultsets, and fetch_object() is not one of them (at least it is not explicitly listed).
Perhaps it is a bug that fetch_object() is not implemented for these metadata resultsets, perhaps you should file a bug at bugs.mysql.com about that.

Categories