Here's my dilemma, I'm at a loss. I'm trying to add multiple values from an array into a database by looping through them with a prepared mysql statement:
If I "execute" the statement within the foreach loop it only adds the
last entry from the array.
If I "execute" it outside of the loop it inserts 3 individual rows to the database. I would like all columns filled out under one created now() date and row.
If I prepare the $stmt before the foreach loop, then it errors undefined variable. So I've put it after defining in the loop, even though in w3schools it shows that you can define the "bind_param" variables prior to setting parameters, which I don't understand either. Thanks!
foreach ($products as $v) {
$product_was = $v['name'];
$product_now = $v['name'];
$was = $v['was'];
$now = $v['now'];
$stmt = $conn->prepare("INSERT INTO $table_name (date_created, $product_was, $product_now) VALUES (now(), ?, ?)");
$stmt->bind_param("ss", $was, $now);
$stmt->execute();
}
$stmt->close();
$conn->close();
Related
I'm looking for a SQL-injection-secure technique to insert a lot of rows (ca. 2000) at once with PHP and MySQLi.
I have an array with all the values that have to be include.
Currently I'm doing that:
<?php
$array = array("array", "with", "about", "2000", "values");
foreach ($array as $one)
{
$query = "INSERT INTO table (link) VALUES ( ?)";
$stmt = $mysqli->prepare($query);
$stmt ->bind_param("s", $one);
$stmt->execute();
$stmt->close();
}
?>
I tried call_user_func_array(), but it caused a stack overflow.
What is a faster method to do this (like inserting them all at once?), but still secure against SQL injections (like a prepared statement) and stack overflows?
You should be able to greatly increase the speed by putting your inserts inside a transaction. You can also move your prepare and bind statements outside of your loop.
$array = array("array", "with", "about", "2000", "values");
$query = "INSERT INTO table (link) VALUES (?)";
$stmt = $mysqli->prepare($query);
$stmt ->bind_param("s", $one);
$mysqli->query("START TRANSACTION");
foreach ($array as $one) {
$stmt->execute();
}
$stmt->close();
$mysqli->query("COMMIT");
I tested this code with 10,000 iterations on my web server.
Without transaction: 226 seconds.
With transaction: 2 seconds.
Or a two order of magnitude speed increase, at least for that test.
Trying this again, I don't see why your original code won't work with minor modifications:
$query = "INSERT INTO table (link) VALUES (?)";
$stmt = $mysqli->prepare($query);
$stmt->bind_param("s", $one);
foreach ($array as $one) {
$stmt->execute();
}
$stmt->close();
Yes, you can build a single big query manually, with something like:
$query = "";
foreach ($array as $curvalue) {
if ($query)
$query .= ",";
$query .= "('" . $mysqli->real_escape_string($curvalue) . "')";
}
if ($query) {
$query = "INSERT INTO table (link) VALUES " . $query;
$mysqli->query($query);
}
You should first convert your array into a string. Given that it is an array of strings (not a two-dimentional array), you can use the implode function.
Please be aware that each value should be enclosed into parenthesis and properly escaped to ensure a correct INSERT statement and to avoid the risk of an SQL injection. For proper escaping you can use the quote method of the PDOConnection -- assuming you're connecting to MySQL through PDO. To perform this operation on every entry of your array, you can use array_map.
After escaping each value and imploding them into a single string, you need to put them into the INSERT statement. This can be done with sprintf.
Example:
<?php
$connection = new PDO(/*...*/);
$connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dataToBeSaved = [
'some',
'data',
'with "quotes"',
'and statements\'); DROP DATABASE facebook_main; --'
];
$connection->query(
sprintf(
'INSERT INTO table (link) VALUES %s',
implode(',',
// for each entry of the array
array_map(function($entry) use ($connection) {
// escape it and wrap it in parenthesis
return sprintf('(%s)', $connection->quote($entry));
}, $dataToBeSaved)
)
)
);
Note: depending on the amount of records you're willing to insert into the database, you may want to split them into several INSERT statements.
I have a booking system and need to insert the details into mysql database. All of my variables are strings and one of them is an array - so I need to insert the same information for each array element ($ticketnumber). I have tried doing it with a foreach loop, but it doesn't seem to work. How do I do this with only one INSERT statement as people may choose different number of tickets to buy?
Here is part of the code:
<?php
$day = $_SESSION['date'];
$time = $_SESSION['time'];
$name = $_REQUEST['name'];
$ticketnumber = $_REQUEST['tickets']; //this is the array variable
foreach ($ticketnumber as $ticket){
$sql = "INSERT INTO table VALUES ('$name', '$day', '$time', '$ticket');";
$handle = $conn->prepare($sql);
$handle->execute();
}
?>
The values of my array in this case are(it varies depending on how many tickets you check):
array(2) { [0]=> string(3) "010" [1]=> string(3) "011" }
This matched the value of $ticket as well, why is that happening?
My session and connection to the database are established before this. I also tried replacing the array variable with a string and the insert statement works.
Any help is appreciated!
Thank you.
If you concatenate values into the SQL string as you are doing, there's not much benefit to using a prepared statement. Instead, prepare a statement with placeholders and execute it repeatedly for the various different values.
Create an array of parameters
$params['day'] = $_SESSION['date'];
$params['time'] = $_SESSION['time'];
$params['name'] = $_REQUEST['name'];
Create the prepared statement with placeholders where your values will be bound
$sql = "INSERT INTO table VALUES (:name, :day, :time, :ticket);";
$handle = $conn->prepare($sql);
Execute the statement in a loop for each value in $ticketnumber.
$ticketnumber = $_REQUEST['tickets'];
foreach ($ticketnumber as $ticket) {
$params['ticket'] = $ticket; // assign the current ticket to the array of values
$handle->execute($params); // the values are bound to the prepared statement
}
You don't really need to explicitly close or null the connection (especially not inside the loop as others have pointed out).
I'm trying to combine an SQLite transaction and prepared statement to get the best insert speed for thousands of records. However, all the inserted lines are empty.
Printing the variables before inserting shows that they have the correct data and there are no errors.
$db->beginTransaction();
$insert_stmt = $db->prepare("INSERT INTO `table` VALUES (:id, :value2, :value3, :value4)");
$insert_stmt->bindValue(":id", $id);
$insert_stmt->bindValue(":value2", $value2);
$insert_stmt->bindValue(":value3", $value3);
$insert_stmt->bindValue(":value4", $value4);
foreach ($records as $record)
{
$id = $record["id"];
$value2 = $record["value2"];
$value3 = $record["value3"];
$value4 = $record["value4"];
$insert_stmt->execute();
print_r($db->errorInfo()); // print errors
}
$db->commit();
What's wrong with the code?
How can I get better output? Printing the prepared statements before executing for example, to see if there's something wrong with it.
You have to put the bindValue calls into your loop.
The values get copied into the statement when you execute bindValue. Whatever happens to the variable you used to do that afterwards does not matter.
I'm looking for a SQL-injection-secure technique to insert a lot of rows (ca. 2000) at once with PHP and MySQLi.
I have an array with all the values that have to be include.
Currently I'm doing that:
<?php
$array = array("array", "with", "about", "2000", "values");
foreach ($array as $one)
{
$query = "INSERT INTO table (link) VALUES ( ?)";
$stmt = $mysqli->prepare($query);
$stmt ->bind_param("s", $one);
$stmt->execute();
$stmt->close();
}
?>
I tried call_user_func_array(), but it caused a stack overflow.
What is a faster method to do this (like inserting them all at once?), but still secure against SQL injections (like a prepared statement) and stack overflows?
You should be able to greatly increase the speed by putting your inserts inside a transaction. You can also move your prepare and bind statements outside of your loop.
$array = array("array", "with", "about", "2000", "values");
$query = "INSERT INTO table (link) VALUES (?)";
$stmt = $mysqli->prepare($query);
$stmt ->bind_param("s", $one);
$mysqli->query("START TRANSACTION");
foreach ($array as $one) {
$stmt->execute();
}
$stmt->close();
$mysqli->query("COMMIT");
I tested this code with 10,000 iterations on my web server.
Without transaction: 226 seconds.
With transaction: 2 seconds.
Or a two order of magnitude speed increase, at least for that test.
Trying this again, I don't see why your original code won't work with minor modifications:
$query = "INSERT INTO table (link) VALUES (?)";
$stmt = $mysqli->prepare($query);
$stmt->bind_param("s", $one);
foreach ($array as $one) {
$stmt->execute();
}
$stmt->close();
Yes, you can build a single big query manually, with something like:
$query = "";
foreach ($array as $curvalue) {
if ($query)
$query .= ",";
$query .= "('" . $mysqli->real_escape_string($curvalue) . "')";
}
if ($query) {
$query = "INSERT INTO table (link) VALUES " . $query;
$mysqli->query($query);
}
You should first convert your array into a string. Given that it is an array of strings (not a two-dimentional array), you can use the implode function.
Please be aware that each value should be enclosed into parenthesis and properly escaped to ensure a correct INSERT statement and to avoid the risk of an SQL injection. For proper escaping you can use the quote method of the PDOConnection -- assuming you're connecting to MySQL through PDO. To perform this operation on every entry of your array, you can use array_map.
After escaping each value and imploding them into a single string, you need to put them into the INSERT statement. This can be done with sprintf.
Example:
<?php
$connection = new PDO(/*...*/);
$connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dataToBeSaved = [
'some',
'data',
'with "quotes"',
'and statements\'); DROP DATABASE facebook_main; --'
];
$connection->query(
sprintf(
'INSERT INTO table (link) VALUES %s',
implode(',',
// for each entry of the array
array_map(function($entry) use ($connection) {
// escape it and wrap it in parenthesis
return sprintf('(%s)', $connection->quote($entry));
}, $dataToBeSaved)
)
)
);
Note: depending on the amount of records you're willing to insert into the database, you may want to split them into several INSERT statements.
I have a php function getContactList():
$res = getContactList(trim($_POST['username']), trim($_POST['password']));
which returns this array:
$contactList[] = array('name' => $name, 'email' =>$email);
I need to store the contents of this array into a MySQL database.
Somehow can i store the entire contents of the array in the database at one go ??
The number of array items will be more than 500 at each go , so i wanna avoid the usual looping practice and calling the "Insert" statement in the for loop as this will need a long time to execute.
Note: I need to store the results in separate columns - One for Name and another for Email. With 500 items in that array I need to have 500 rows inserted - one Name-Email pair per row.
$values = array();
// the above array stores strings such as:
// ('username', 'user#domain.com')
// ('o\'brien', 'baaz#domain.com')
// etc
foreach($contactList as $i => $contact) {
$values[] = sprintf(
"('%s', '%s')",
mysql_real_escape_string($contact['name'], $an_open_mysql_connection_identifier),
mysql_real_escape_string($contact['email'], $an_open_mysql_connection_identifier)
);
}
$query = sprintf(
"INSERT INTO that_table(name, email) VALUES %s",
implode(",", $values)
);
If you are trying to insert many rows, i.e. run the same query many times, use a prepared statement.
Using PDO, you can do this:
// prepare statement
$stmt = $dbh->prepare("INSERT INTO contacts (email, name) VALUES (:email, :name);");
// execute it a few times
foreach($contactList as $contact) {
$stmt->bindValue(':email', $contact['email'], PDO::PARAM_STR);
$stmt->bindValue(':name', $contact['name'], PDO::PARAM_STR);
$stmt->execute();
}
PDO will also take care of proper string escaping.
use the standard php serialize function
$serData_str = serialize($contactList);
then save it in the DB
after reading your data from DB simply unserialize it
$myData_arr = unserialize($serContactList);
In the loop you can create an insert statement and execute it after the loop. the insert statement will include all content.
The statement would look like
INSERT INTO employee (name) VALUES ('Arrayelement[1]'),('Arrayelement[2]'), ('Arrayelement[3]'),('Arrayelement[4]');