I have an array like:
$postdata[1] = 'This';
$postdata[2] = 'That';
$postdata[3] = 'The other';
And I want to loop through the array and update all of the rows where ID corresponds to the array key. Like:
foreach ($postdata as $key => $value) {
if ($key == 1) {
$update = $db->query("UPDATE site_email_templates SET Content='$postdata[1]' WHERE ID = 1");
} else if ($key == 2) {
$update = $db->query("UPDATE site_email_templates SET Content='$postdata[2]' WHERE ID = 2");
} else if ($key == 3) {
$update = $db->query("UPDATE site_email_templates SET Content='$postdata[3]' WHERE ID = 3");
}
}
What would be the simplest way to do this, not particularly knowing how many array keys there are, and keeping it all in one query?
You need to use prepared statements in order to avoid errors and vulnerabilities of all sorts and also to get some minor performance gain
$stmt = $db->prepare("UPDATE site_email_templates SET Content=? WHERE ID = ?");
$stmt->bind_param("ss", $content, $id);
foreach ($postdata as $id => $content)
{
$stmt->execute();
}
Reference: How can I prevent SQL injection in PHP?
Note: My answer is based on the PDO driver which in many aspects is better than mysqli. If you need mysqli solution please check the other answer provided by #Your Common Sense
The code below is tested on real environment and served with prepared statement preventing SQL-injection:
$sql = "UPDATE `site_email_templates` SET `Content` = (:content) WHERE `Id` = (:id)";
$stmt = $dbConn->prepare($sql);
foreach ($postdata as $id => $content)
{
$stmt->execute([':id' => $id, ':content' => $content]);
}
For more details about SQL injection you can read more:
https://www.owasp.org/index.php/SQL_Injection
For maximal speed, IODKU can do all the updates in a single statement. Caution: You should not use this for updating if you don't know that the ids exist.
INSERT INTO t
(id, -- A PRIMARY or UNIQUE key
col1, col2) -- column(s) to change
VALUES
(111, 22, 33),
(222, 33, 44),
...
ON DUPLICATE KEY UPDATE
col1 = VALUES(col1),
col2 = VALUES(col2);
You must provide some way to "bind" or "escape" the values to avoid sql-injection.
Related
I have an array like:
$postdata[1] = 'This';
$postdata[2] = 'That';
$postdata[3] = 'The other';
And I want to loop through the array and update all of the rows where ID corresponds to the array key. Like:
foreach ($postdata as $key => $value) {
if ($key == 1) {
$update = $db->query("UPDATE site_email_templates SET Content='$postdata[1]' WHERE ID = 1");
} else if ($key == 2) {
$update = $db->query("UPDATE site_email_templates SET Content='$postdata[2]' WHERE ID = 2");
} else if ($key == 3) {
$update = $db->query("UPDATE site_email_templates SET Content='$postdata[3]' WHERE ID = 3");
}
}
What would be the simplest way to do this, not particularly knowing how many array keys there are, and keeping it all in one query?
You need to use prepared statements in order to avoid errors and vulnerabilities of all sorts and also to get some minor performance gain
$stmt = $db->prepare("UPDATE site_email_templates SET Content=? WHERE ID = ?");
$stmt->bind_param("ss", $content, $id);
foreach ($postdata as $id => $content)
{
$stmt->execute();
}
Reference: How can I prevent SQL injection in PHP?
Note: My answer is based on the PDO driver which in many aspects is better than mysqli. If you need mysqli solution please check the other answer provided by #Your Common Sense
The code below is tested on real environment and served with prepared statement preventing SQL-injection:
$sql = "UPDATE `site_email_templates` SET `Content` = (:content) WHERE `Id` = (:id)";
$stmt = $dbConn->prepare($sql);
foreach ($postdata as $id => $content)
{
$stmt->execute([':id' => $id, ':content' => $content]);
}
For more details about SQL injection you can read more:
https://www.owasp.org/index.php/SQL_Injection
For maximal speed, IODKU can do all the updates in a single statement. Caution: You should not use this for updating if you don't know that the ids exist.
INSERT INTO t
(id, -- A PRIMARY or UNIQUE key
col1, col2) -- column(s) to change
VALUES
(111, 22, 33),
(222, 33, 44),
...
ON DUPLICATE KEY UPDATE
col1 = VALUES(col1),
col2 = VALUES(col2);
You must provide some way to "bind" or "escape" the values to avoid sql-injection.
This question already has answers here:
How can I bind an array of strings with a mysqli prepared statement?
(7 answers)
Use an array in a mysqli prepared statement: `WHERE .. IN(..)` query [duplicate]
(8 answers)
Closed 2 years ago.
I have an array full of random content item ids. I need to run a mysql query (id in the array goes in the WHERE clause), using each ID that's in the array, in the order that they appear in the said array. How would I do this?
This will be an UPDATE query, for each individual ID in the array.
As with nearly all "How do I do SQL from within PHP" questions - You really should use prepared statements. It's not that hard:
$ids = array(2, 4, 6, 8);
// prepare an SQL statement with a single parameter placeholder
$sql = "UPDATE MyTable SET LastUpdated = GETDATE() WHERE id = ?";
$stmt = $mysqli->prepare($sql);
// bind a different value to the placeholder with each execution
for ($i = 0; $i < count($ids); $i++)
{
$stmt->bind_param("i", $ids[$i]);
$stmt->execute();
echo "Updated record ID: $id\n";
}
// done
$stmt->close();
Alternatively, you can do it like this:
$ids = array(2, 4, 6, 8);
// prepare an SQL statement with multiple parameter placeholders
$params = implode(",", array_fill(0, count($ids), "?"));
$sql = "UPDATE MyTable SET LastUpdated = GETDATE() WHERE id IN ($params)";
$stmt = $mysqli->prepare($sql);
// dynamic call of mysqli_stmt::bind_param hard-coded eqivalent
$types = str_repeat("i", count($ids)); // "iiii"
$args = array_merge(array($types), $ids); // ["iiii", 2, 4, 6, 8]
call_user_func_array(array($stmt, 'bind_param'), ref($args)); // $stmt->bind_param("iiii", 2, 4, 6, 8)
// execute the query for all input values in one step
$stmt->execute();
// done
$stmt->close();
echo "Updated record IDs: " . implode("," $ids) ."\n";
// ----------------------------------------------------------------------------------
// helper function to turn an array of values into an array of value references
// necessary because mysqli_stmt::bind_param needs value refereces for no good reason
function ref($arr) {
$refs = array();
foreach ($arr as $key => $val) $refs[$key] = &$arr[$key];
return $refs;
}
Add more parameter placeholders for other fields as you need them.
Which one to pick?
The first variant works with a variable number of records iteratively, hitting the database multiple times. This is most useful for UPDATE and INSERT operations.
The second variant works with a variable number of records too, but it hits the database only once. This is much more efficient than the iterative approach, obviously you can only do the same thing to all affected records. This is most useful for SELECT and DELETE operations, or when you want to UPDATE multiple records with the same data.
Why prepared statements?
Prepared statements are a lot safer because they make SQL injection attacks impossible. This is the primary reason to use prepared statements, even if it is more work to write them. A sensible habit to get into is: Always use prepared statements, even if you think it's "not really necessary." Neglect will come and bite you (or your customers).
Re-using the same prepared statement multiple times with different parameter values is more efficient than sending multiple full SQL strings to the database, because the database only needs to compile the statement once and can re-use it as well.
Only parameter values are sent to the database on execute(), so less data needs to go over the wire when used repeatedly.
In longer loops the execution time difference between using a prepared statement and sending plain SQL will become noticeable.
Using the "IN" Clause
Might be what you're after
$ids = array(2,4,6,8);
$ids = implode($ids);
$sql="SELECT * FROM my_table WHERE id IN($ids);";
mysql_query($sql);
otherwise, what's wrong with
$ids = array(2,4,6,8);
foreach($ids as $id) {
$sql="SELECT * FROM my_table WHERE ID = $id;";
mysql_query($sql);
}
Amen to Tomalak's comment on statements.
However, if you do not wish to use mysqli, you can always use intval() to prevent injection:
$ids = array(2, 4, 6, 8);
for ($i = 0; $i < count($ids); $i++)
{
mysql_query("UPDATE MyTable SET LastUpdated = GETDATE() WHERE id = " . intval($ids[$i]));
}
$values_filtered = array_filter('is_int', $values);
if (count($values_filtered) == count($values)) {
$sql = 'update table set attrib = 'something' where someid in (' . implode(',', $values_filtered) . ');';
//execute
} else {
//do something
}
You could do something like the following, however you need to be VERY careful that the array only contains integers otherwise you could end up with SQL injection.
You really don't want to be doing multiple queries to get the content out if you can help it. Something like this might be what you are after.
foreach ($array as $key = $var) {
if ((int) $var <= 0) {
unset($array[$key]);
}
}
$query = "SELECT *
from content
WHERE contentid IN ('".implode("','", $array)."')";
$result = mysql_query($query);
I have a module which allows admins to add some users (maybe multiple) to a group.
PHP
$user_id = $_POST["user_id"]; //this can be an array
$group_id = $_POST["group_id"];
$sql = "INSERT IGNORE INTO users_groups (user_id, group_id)
VALUES ($user_id[0],$group_id)";
for ( $i = 1; $i < count($user_id); $i++)
{
$sql .= ", ($user_id[$i],$group_id)"
}
As you can see the sql-query depends on how much users the admin has selected.
How can I use this code with prepared statements because the post-variables come from a user (SQL injections...)
UPDATE
I have two selectboxes:
one for the user selection (multiple selection is possible -> array): $_POST["user_id"]
one for the group selection (only one selection is possible): $_POST["group_id"]
And now I want a prepared SQL statement for inserting user_id and group_id to the many-to-many-table (users_groups). The problem is that the number of values which have to be inserted can change (depending how much users the admin has selected in the selectbox).
I want to change the prepared query depending on how much users the admin has selected.
For example:
the admin selected two users -> sql: INSERT IGNORE INTO users_groups (user_id, group_id) VALUES ($user_id[0],$group_id), ($user_id[1],$group_id)
the admin selected four users -> sql: INSERT IGNORE INTO users_groups (user_id, group_id) VALUES ($user_id[0],$group_id), ($user_id[1],$group_id), ($user_id[2],$group_id), ($user_id[3],$group_id)
My question: How can I do this automaticaly and with prepared sql statements because I dont want to have like 10 times if(count($user_id) == number) {...?
UPDATE 2
If I would do this manually the code would look like this:
$sql = $db->prepare("INSERT IGNORE INTO users_groups (user_id, group_id) VALUES (?, ?)");
$sql->bind_param('ii', $user_id[0], $group_id);
UPDATE 3
To check whether there are only integers in the post variables:
$user_id = filter_input_array(INPUT_POST, 'user_id', FILTER_SANITIZE_NUMBER_INT);
$user_id = abs($user_id);
$group_id = filter_input(INPUT_POST, 'group_id', FILTER_SANITIZE_NUMBER_INT);
$group_id = abs($group_id);
To create the SQL statement, you can use this to generate as many placeholders as you will need for all of your user_id values.
$user_ids = $_POST["user_id"]; //this can be an array
$group_id = $_POST["group_id"];
$placeholders = implode(', ', array_fill(0, count($user_ids), "(?, ?)"));
$sql = "INSERT IGNORE INTO users_groups (user_id, group_id) VALUES $placeholders";
Then to bind the values, if you are using pdo, something like this should work:
$stmt = $pdo->prepare($sql);
$i = 1;
foreach ($user_ids as $user_id) {
$stmt->bindValue($i++, $user_id);
$stmt->bindValue($i++, $group_id);
}
Or if you are using mysqli, you could try this approach using reflection (taken from a user note in the php docs here) the note does state that this needs PHP 5.3+, which hopefully you do have.
$stmt = $mysqli->prepare($sql);
$values[] = str_repeat('ii', count($user_ids));
foreach ($user_ids as $user_id) {
$values[] = $user_id;
$values[] = $group_id;
}
$ref = new ReflectionClass('mysqli_stmt');
$method = $ref->getMethod("bind_param");
$method->invokeArgs($stmt, $values);
$stmt->execute();
Or, because I'm stubborn and the thing from the php docs user note doesn't seem to work, which after reading more I don't see how it could work, considering the php doc for ReflectionMethod::invokeArgs specifically says
Note: If the function has arguments that need to be references, then they must be references in the passed argument list.
then using call_user_func_array could possibly work.
$stmt = $mysqli->prepare($sql);
$type = str_repeat('ii', count($user_ids));
foreach ($user_ids as $user_id) {
$values[] = $user_id;
$values[] = $group_id;
}
foreach ($values as $key => $value) {
$value_references[$key] = &$values[$key];
}
call_user_func_array('mysqli_stmt_bind_param',
array_merge(array($stmt, $type), $value_references));
But what a pain. I really like pdo.
I have the following query
$products = $this->mysqliengine->query("select * from temp_all_product where download_status = 0") or die($this->mysqliengine->error());
$temp_status_update = $this->mysqliengine->prepare("update temp_all_product set download_status = ? where id = ?") or die($this->mysqliengine->error);
$temp_status_update->bind_result($download_status, $id);
while($product = $products->fetch_assoc()) {
$id = $product['id'];
$download_status = 1;
$temp_status_update->execute();
}
In the above statement I can select the values from temp table but unable to update the status. What is the problem here
You need to use bind_param in your update statement instead of bind_result.
$temp_status_update->bind_param('dd', $download_status, $id);
The 'dd' just tells the system that each input is a number.
http://www.php.net/manual/en/mysqli-stmt.bind-param.php
#eggyal was merely suggesting that you could replace all your code with a single update statement. Your remark about LIMIT does not make much sense.
Suggestion: If you don't have much invested in mysqli then switch to PDO. It allows using named parameters which can make your code more robust and easier to maintain:
$sql = "UPDATE temp_all_product SET download_status = :status where id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute(array('status' => 1, 'id' => $product['id']));
Plus you can configure it to throw exceptions so you don't need all this error checking.
http://www.php.net/manual/en/book.pdo.php
http://net.tutsplus.com/tutorials/php/pdo-vs-mysqli-which-should-you-use/
I want to edit a table from my database.That table have many data.
I will show sample.Do I need to write many mysql update statement?Have other method to write a only one statement? I am beginner for php? Thank all my friend.Sorry for my english.
mysql_query("UPDATE `mytablename` SET `mobiletitle` = '$mobiletitle1',
`mobilepublished` = '1',
`mobiletext` = '$mobilefulltext1',
WHERE `id` ='$id1';");
mysql_query("UPDATE `mytablename` SET `mobiletitle` = '$mobiletitle2',
`mobilepublished` = '1',
`mobiletext` = '$mobilefulltext2',
WHERE `id` ='$id2';");
mysql_query("UPDATE `mytablename` SET `mobiletitle` = '$mobiletitle3',
`mobilepublished` = '1',
`mobiletext` = '$mobilefulltext3',
WHERE `id` ='$id3';");
etc.............
mysql_query("UPDATE `mytablename` SET `mobiletitle` = '$mobiletitle30',
`mobilepublished` = '1',
`mobiletext` = '$mobilefulltext30',
WHERE `id` ='$id30';");
You want to update multiple rows from one table with specific data, so bad news you have to do it one by one.... but you can improve your code. If I where you I will create a function and I just call it, something like
function update_my_data($movilefilltex1,$id1){
mysql_query("UPDATE `mytablename` SET `mobiletitle` = '$mobiletitle1',
`mobilepublished` = '1',
`mobiletext` = '$mobilefulltext1',
WHERE `id` ='$id1';");
.......
}
So to make the multiple insert you can call update_my_data(value1,valu2) the times that you need. for example in a loop or just whenever you need it.
If there is a UNIQUE index on id (and there will be if it's your PRIMARY KEY), you could use INSERT ... ON DUPLICATE KEY UPDATE:
INSERT INTO mytablename (id, mobiletitle, mobilepublished, mobiletext) VALUES
('$id1', '$mobiletitle1', 1, '$mobilefulltext1'),
('$id2', '$mobiletitle2', 1, '$mobilefulltext2'),
-- etc.
ON DUPLICATE KEY UPDATE
mobiletitle = VALUES(mobiletitle),
mobilepublished = VALUES(mobilepublished)
mobiletext = VALUES(mobiletext);
Note that this will, of course, insert new records if they don't already exist; whereas your multiple-UPDATE command approach will not (it would raise an error instead).
In either case, you could build/execute the SQL dynamically from within a loop in PHP.
I would also caution that you would be well advised to consider passing your variables to MySQL as parameters to a prepared statement, especially if the content of those variables is outside of your control (as you might be vulnerable to SQL injection). If you don't know what I'm talking about, or how to fix it, read the story of Bobby Tables.
Putting it all together (using PDO instead of the deprecated MySQL extension that you were using):
for ($i = 1; $i <= 30; $i++) {
$sqls[] = '(?, ?, 1, ?)';
$arr[] = ${"id$i"};
$arr[] = ${"mobiletitle$i"};
$arr[] = ${"mobilefulltext$i"};
}
$sql = 'INSERT INTO mytablename (id, mobiletitle, mobilepublished, mobiletext)
VALUES
' . implode(',', $sqls)
. 'ON DUPLICATE KEY UPDATE
mobiletitle = VALUES(mobiletitle),
mobilepublished = VALUES(mobilepublished)
mobiletext = VALUES(mobiletext)';
$db = new PDO("mysql:dbname=$db", $user, $password);
$qry = $db->prepare($sql);
$qry->execute($arr);
Note that you might also consider storing your 1..30 variables in arrays.
update table1,table2 SET table1.column1 = 'valueX',table2.coulumn2 = 'valueX' where table1.column = table2.coulumn2 ;