Binding params for PDO statement inside a loop doesn't work
If you apply this from the PDO manual
PDOStatement::bindParam
Binds a PHP variable to a corresponding named or question mark placeholder in the SQL statement that was used to prepare the statement. Unlike PDOStatement::bindValue(), the variable is bound as a reference and will only be evaluated at the time that PDOStatement::execute() is called.
You will understand that in your loop you are using the same variable X times. Overwriting it each time round the loop.
So when the actual binding is done, at the time you ->execute()
your prepared query, you only have one value, the last from your loop in those variables
Binding params for PDO statement inside a loop
The problem is that bindParam
requires a reference. It binds the variable to the statement, not the value. Since the variable in a foreach
loop is unset at the end of each iteration, you can't use the code in the question.
You can do the following, using a reference in the foreach
:
foreach ($reindex as $key => &$value) { //pass $value as a reference to the array item
$stmt->bindParam($key, $value); // bind the variable to the statement
}
Or you could do this, using bindValue
:
foreach ($reindex as $key => $value) {
$stmt->bindValue($key, $value); // bind the value to the statement
}
HOW TO LOOP PHP'S PDO BIND PARAM
It is better to use ?
placeholders in a query and pass array of data to execute
:
$sql = "SELECT * FROM users WHERE id = ? OR fname = ?";
$array = array("10002345", "Josh"); // you don't even need keys here
$stmt = $conn->prepare($sql);
$stmt->execute($array);
PDO bindParam() PHP Foreach Loop
You should use bindParam
like this:
$sql = 'SELECT * FROM Organization WHERE City = :City AND State= :State';
$wherestr = array('string1', 'string2');
$stmt = $db->prepare($sql);
$stmt->bindParam(':City', $wherestr[0]);
$stmt->bindParam(':State', $wherestr[1]);
$stmt->execute();
if you insist using foreach
, here is a way:
$stmt = $db->prepare($sql);
$params = array(':City' => 'string1', ':State' => 'string2');
foreach ($params as $key => &$val) {
$stmt->bindParam($key, $val);
}
$stmt->execute();
note that we use pass by reference in the loop, which is a must.
PDO bindParam not working in loop
Trying to bindParam
to an array element like $array['key']
causes a few issues because its bound as reference, but its not. Its, just not done that way.
So three ways:
$stmt = $dbh->prepare($sql);
// bind to variables that can be a reference
$stmt->bindParam(":GROUP_ID", $id, PDO::PARAM_INT);
$stmt->bindParam(":INSTALLED_VERSION_NUM_1", $pt1, PDO::PARAM_INT);
$stmt->bindParam(":INSTALLED_VERSION_NUM_2", $pt2, PDO::PARAM_INT);
foreach ($installed_groups as $installed_group){
$installed_version_parts = explode('.', $installed_group['version']);
// assign the referenced vars their new value before execute
$id = $installed_group['group_id'];
$pt1 = $installed_version_parts[1];
$pt2 = $installed_version_parts[2];
$stmt->execute();
}
Or: (less efficient)
$stmt = $dbh->prepare($sql);
foreach ($installed_groups as $installed_group){
$installed_version_parts = explode('.', $installed_group['version']);
// use bindValue (not bindParam) INSIDE the loop
// bindValue doesn't set them by reference, so any value expression works
$stmt->bindValue(":GROUP_ID", $installed_group['group_id'], PDO::PARAM_INT);
$stmt->bindValue(":INSTALLED_VERSION_NUM_1", $installed_version_parts[1], PDO::PARAM_INT);
$stmt->bindValue(":INSTALLED_VERSION_NUM_2", $installed_version_parts[2], PDO::PARAM_INT);
$stmt->execute();
}
Or:
$stmt = $dbh->prepare($sql);
foreach ($installed_groups as $installed_group){
$installed_version_parts = explode('.', $installed_group['version']);
// pass them on execute directly
$stmt->execute(array(':GROUP_ID'=>$installed_group['group_id'],
':INSTALLED_VERSION_NUM_1'=>$installed_version_parts[1],
':INSTALLED_VERSION_NUM_2'=>$installed_version_parts[2]));
}
Loop bindParam from key value post array in pdo prepared statements
Yes, it's safe. If you're using parameterized queries, you won't be vulnerable to injection attacks.
That being said, it seems that you're reinventing the wheel here, which is most often not the right way to do things. However; that's outside the scope of your question.
Also please see this very similar question where the accepted answer has this to say:
Use prepared statements and parameterized queries. These are SQL statements that are sent to and parsed by the database server separately from any parameters. This way it is impossible for an attacker to inject malicious SQL.
PHP bind in for loop
Had to change
$locn= "'" . $location . "%'";
TO
$locn= $location . "%";
I realized that with binding, there is no need for single quote.
Safe Way To Loop PDO Statement
Use numbered parameters instead of named parameters, and build the query and parameters dynamically.
$sql = "INSERT INTO inbox (efrom,subject,msg,eread,date) VALUES ";
// array_fill will create an array of N "(?, ?, ?, ?, ?)" strings
// implode will then join them together with comma separators
$sql .= implode(', ', array_fill(0, count($inbox_from), "(?, ?, ?, ?, ?)"));
$STH = $DBH->prepare($sql);
$params = array();
// Populate the $params array with all the input values
foreach ($inbox_from as $i => $from) {
$params[] = $from;
$params[] = $inbox_subject[$i];
$params[] = $inbox_msg[$i];
$params[] = $inbox_read[$i];
$params[] = $inbox_date[$i];
}
$STH->execute($params);
You can leave the id
field out of the column list, and it will be filled in automatically using auto-increment.
To remove duplicate messages, you can do:
$check_stmt = $DBH->prepare("SELECT COUNT(*) AS count FROM inbox WHERE msg = :msg");
$check_stmt->bindParam(':msg', $msg);
$messages_seen = array();
foreach ($inbox_msg as $i => $msg) {
// Check if the message is already in the DB
$check_stmt->execute();
$first_row = $check_stmt->fetch(PDO::FETCH_OBJ);
$check_stmt->fetchAll(); // Fetch the rest of the query to get in sync
if ($first_row->count > 0) {
$messages_seen[$msg] = true; // Remember that we already saw this message
} elseif (!isset($messages_seen[$msg])) // If we haven't already seen this message
$params[] = $inbox_from[$i];
$params[] = $inbox_subject[$i];
$params[] = $msg;
$params[] = $inbox_read[$i];
$params[] = $inbox_date[$i];
$messages_seen[$msg] = true; // Remember that we added this message
}
}
$sql = "INSERT INTO inbox (efrom,subject,msg,eread,date) VALUES ";
// There's 1 (...) group for every 5 parameters, so divide the length of $params by 5 to know how many of them to put in the SQL
$sql .= implode(', ', array_fill(0, count($params)/5, "(?, ?, ?, ?, ?)"));
$STH = $DBH->prepare($sql);
$STH->execute($params);
When adding an index on a TEXT datatype, you have to specify the number of bytes of the text to store in the index. So it should be something like:
CREATE INDEX ix_msg ON inbox (msg(200));
PDO BindParam won't bind on while loop every time
You are preparing each incomplete query fragment inside the loop. You should only prepare once and you should prepare the complete SQL query.
Update: Not sure where you looked for documentation, but the bindParam() manual page has several examples:
<?php
/* Execute a prepared statement by binding PHP variables */
$calories = 150;
$colour = 'red';
$sth = $dbh->prepare('SELECT name, colour, calories
FROM fruit
WHERE calories < :calories AND colour = :colour');
$sth->bindParam(':calories', $calories, PDO::PARAM_INT);
$sth->bindParam(':colour', $colour, PDO::PARAM_STR, 12);
$sth->execute();
?>
You won't get anything useful if you do this inside the loop:
$stmt->bindParam( ':s'.$x, $currTerm );
... but you remove and create a new $stmt
object right before.
Related Topics
PHP Syntax for Arrays: Different Behaviour Between PHP Versions
PHP 7.4 Deprecated Get_Magic_Quotes_Gpc Function Alternative
What Are Fragment Urls and Why to Use Them
Str_Replace() on Multibyte Strings Dangerous
PHP Code to Test Pdo Is Available
Onbeforeprint() and Onafterprint() Equivalent for Non Ie Browsers
Php's JSON_Encode Does Not Escape All JSON Control Characters
Escape String to Use in Mail()
Soap-Error: Parsing Wsdl: Couldn't Load from <Url>
How to Echo Out Table Rows from the Db (Php)
Why Is Mime_Content_Type() Deprecated in PHP
Php: How to Sort the Characters in a String
MySQL Select Query Within a Serialized Array
Retrieve JSON Post Data in Codeigniter
Is MySQL_Insert_Id Safe to Use
Failed to Open Stream: Http Wrapper Does Not Support Writeable Connections