2 Questions about saving data from multiple checkbox (I have few of them in my form) in a database with PDO (PHP). I just show the relevant parts of the code to make it more simple for everyone.
A) The code I wrote works (still saving all data correctly) but it gives me still a failure message, which you can see below. Why, or what can I do better?
B) It saves the checked checkboxes as an array in the database. Later on I want to change data by getting the data from the database back into my original form - will it make problems, if its saved like an array? If yes, what would you recommend to do then better.
Warning: implode ( ) : Invalid arguments passed on line ... for
$p2 = implode(',',$product_2);
$p3 = implode(',',$product_3);
$p1 = implode(',',$product_1); which I defined first seems to be fine
<?php
if(isset($_POST['send']))
{
require("php/tconnect.php");
$id = $_POST['id'];
$name = $_POST['name'];
$date = $_POST['date'];
$p1 = implode(',',$product_1);
$p2 = implode(',',$product_2);
$p3 = implode(',',$product_3);
$sql = "INSERT INTO database (id, name, date) VALUES (:id, :name, :date, '$p1', '$p2', '$p3')";
$stmt = $dbh->prepare($sql);
$stmt->bindValue(':id', $id);
$stmt->bindValue(':name', $name);
$stmt->bindValue(':date', $date);
$stmt->execute();
echo "Datas saved";
}
?>
HTML
<input type="checkbox" name="product_1[]" value="apple" id="product_1_apple">
Apple
</label>
<label class="checkbox-inline">
<input type="checkbox" name="product_1[]" value="Banana" id="product_1_banana">
Banana
</label>
and the next tables looks similar
<input type="checkbox" name="product_2[]" value="water" id="product_2_water">
Water
</label>
<label class="checkbox-inline" >
<input type="checkbox" name="product_2[]" value="juice" id="product_2_juice">
Juice
</label>
Since $product_1, $product_2 and $product_3 seems to be related with the input arrays from the HTML I suppose that you have in another part of the code something like this:
$product_1 = $_POST['product_1'];
$product_2 = $_POST['product_2'];
$product_3 = $_POST['product_3'];
Now, the problem is that those variables are related to an array of checkboxes, but when no checkbox is selected in the page for a group, instead of getting an empty array for that group the array is not added to $_POST (you can see it using var_dump($_POST)).
I suspect that in your tests you were only marking checkboxes for product_1, so you get an array for that product but no for the other ones. To prevent the error you can fill each of the products variables using something like this:
if(isset($_POST['product_1'])) // if the array is defined in $_POST
$product_1 = $_POST['product_1']; // fill with the array from the form
else $product_1 = array(); // fill with empty array, you get the empty string with implode()
// repeat for product_2 and product_3
Also, you are mixing prepared statements, which are good, with inserting the values directly in the query string, which is bad because it can lead to SQL Injection, you should use bindValue() for all the values of the table:
$sql = "INSERT INTO database (id, name, date) VALUES (:id, :name, :date, :p1, :p2, :p3)";
$stmt = $dbh->prepare($sql);
$stmt->bindValue(':id', $id);
$stmt->bindValue(':name', $name);
$stmt->bindValue(':date', $date);
$stmt->bindValue(':p1', $p1);
$stmt->bindValue(':p2', $p2);
$stmt->bindValue(':p3', $p3);
Related
I am referencing to a question here: Can I concatenate multiple MySQL rows into one field?
In this question multiple rows of a column are listed and separated by a "," using the GROUP_CONCAT function. I want to achieve something in reverse by concatenating multiple user inputs into a single database entry. Something like this:
<form action="server.php" method="POST">
<div>
<input type="text" name="value1">
<input type="text" name="value2">
<input type="text" name="value3">
<button type="submit" name="submit">submit</button>
</div>
</form>
and php:
<?php
if (isset($_POST['submit'])) {
$value1 = mysqli_real_escape_string($conn, $_POST['value1']);
$value2 = mysqli_real_escape_string($conn, $_POST['value2']);
$value3 = mysqli_real_escape_string($conn, $_POST['value3']);
$sql = "INSERT INTO database (col1)
VALUES GROUP_CONCAT('$value1', '$value2', '$value3');";
mysqli_query($conn, $sql);
header("Location: ../web_page/client_database_page.php?add_client=success");
}
?>
I know some of you will say that it would not be good practice to do this and I should have an individual column for each user input, however there is a reason for not doing it this way. The user inputs are added based on the number of variables from another database. In this database a user can insert additional user inputs from the website, but it would not automatically add a column to the input database. So a single column row should be able to contain all the user inputs and than later be separated for interpretation when called from the database.
Anybody have any ideas?
How about grouping your input values as an array then using implode() function in PHP before you insert into DB, like:
<form action="server.php" method="POST">
<div>
<input type="text" name="values[]">
<input type="text" name="values[]">
<input type="text" name="values[]">
<button type="submit" name="submit">submit</button>
</div>
</form>
Then, in PHP:
if (isset($_POST['submit'])) {
$values = $_POST['values'];
$escaped_values = array_map([$conn, 'mysqli_real_escape_string'], $values);
$concat_values = implode(",", $escaped_values);
$sql = "INSERT INTO database (col1) VALUES ('$concat_values');";
mysqli_query($conn, $sql);
header("Location: ../web_page/client_database_page.php?add_client=success");
}
Here, I used comma , as separator on each values. Just change it to your preference.
EDIT:
Another solution would be to use JSON for this so you can easily access the data when retrieved. Depending on your MySQL version, you can use the JSON data type for the col1 column/field.
ALTER TABLE `table_name` CHANGE COLUMN `col1` `col1` JSON;
Then modify the code to:
$json = json_encode($_POST['values']);
$sql = "INSERT INTO database (col1) VALUES ('$json');";
And then later when you retrieve the data you can do something like:
$values = json_decode($row['col1'], true);
Which you can then iterate to echo multiple <input> tags with values taken from the db.
You can simply concat values using PHP. No need to use GROUP_CONCAT for this.
Try code like below:
$sql = "INSERT INTO database (col1) VALUES ('$value1 $value2 $value3');";
Note: Values can be separated by comma , or any other separator instead of space.
I have a form in html with various fields, in particular a select and textarea. by pressing the button I create other n select and textarea (n given by keyboard).
I then have a php file that inserts the data into the database. everything works but not correctly inserted the data of the textarea (which in the file called $quantita) that does not take all the order (for sesmpio if I write 1, 2, 5 inserts 1,2,5) but only a value (if I write just takes 1,2,5 1,1,1).
html
<?php
$pro = 'sito';
$dd = mysqli_connect('localhost', 'root', '', $pro);
$re = mysqli_query ($dd,"SELECT Codice, Nome FROM prodotti");
echo"<div class='box'>";
echo"Prodotto";
echo"<select class='inse' name='po[]'>";
while($row=mysqli_fetch_array($re)){
echo"<option value=".$row['Codice'].">".$row['Nome']."</option>";
}
echo"</select>";
echo"<br>";
echo"Quantità <textarea name='qua[]' rows='1' cols='4'></textarea></div><br>";
?>
</div>
<br><button type="submit" id="ok">OK!</button><br>
</form>
php
<?php
$nordine = $_POST['nor'];
$datao = $_POST['dao'];
$datac = $_POST['dac'];
$quantita = $_POST['qua'];
$prodotto = $_POST['po'];
$data = 'sito';
$db = mysqli_connect('localhost', 'root', '', $data);
$result = mysqli_multi_query ($db, "INSERT INTO ordini
(Nordine,DataO,DataC)
VALUES('$nordine','$datao','$datac')");
if ($prodotto && $quantita){
foreach ($prodotto as $result1){
foreach ($quantita as $result2){
mysqli_query ($db, "INSERT INTO ordpro
(Prodotto, Ordini, Quantita)
VALUES('". mysqli_real_escape_string($db,$result1)."','$nordine','". mysqli_real_escape_string($db,$result2)."')");
}
}
}
echo"<p>Hai inserito un nuovo record <a href='ordini.php'> torna alla home </a></p>";
?>
From your HTML I think that po[0] should go with qua[0] and po[1] should go with qua[1] etc etc
So your 2 foreach loops are doing the wrong thing and storing all the quas with each po
You should also be using prepared and paramterised statement when using any data provided by the user in POST or GET.
An additional benefit of using prepared statements for multiple updates is that you can prepare it once and execute it many times, thus reducing the round trips to the database. Also the query needs to be compiled and optimized by MYSQL only once, making it almost like using a Stored Procedure.
NOTE: This also means you no longer need to use mysqli_real_escape_string() on the users data.
So the loops should be amended like this
$sql = "INSERT INTO ordpro (Prodotto, Ordini, Quantita) VALUES (?,?,?)";
$stmt = mysqli_prepare($db, $sql);
if ($prodotto && $quantita){
foreach ($prodotto as $idx => $prod){
$stmt->bind_param('sss', $prod, $nordine, $quantita[$idx]);
$stmt->execute();
}
}
Note2 I have used sss (string) as the data types for all 3 variables. You may need to check that this is correct and amend accordingly. The id fields may need to be changed to i where appropriate
I have an input form with two values as a key, constructed this way:
<input name="verificarPago['.$x['pagoID'].'-'.$x['userID'].']" type="text">
So, the HTML would look like, for example, like this:
<input name="verificarPago[4-10]" type="text">
Besides that I have the value that the user can type, for example "Juan".
The inputs are created programmatically, and I want to save them each three values (in the example: 4, 10, Juan) into a database.
So, when the user submits the form, I thought on using foreach in order to access the elements in that array, but my problem is: How may I explode the keys to access the two values separately?
I've tried this (I'm not taking into account security now, I'm trying to prove the concept):
$verificar = $_POST['verificarPago'];
foreach ($verificar as $pago => $curso) {
//I'm pretty much stuck here.
$verificar= array_flip(explode("-", $verificar));
//I want to insert the three items into the database
$verificarPago = "INSERT pagosVerificados SET userID = '$usuario', pagoID = '$pago', cursoID = '$curso'";
$cargarPago = mysqli_query($conectar, $verificarPago);
}
I've tried adding to the form another input type, so the values wouldn't be together, but that way I should do a foreach inside a foreach and that renders duplicated results (and with errors as well).
Without addressing any architectural issues, adding error-checking, or addressing security problems, here's how to do what you're asking for
$verificar = $_POST['verificarPago'];
foreach ($verificar as $ids => $text) {
list($pagoID, $cursoID) = explode("-", $ids);
$sql = "INSERT INTO pagosVerificados (userID, pagoID, cursoID, someVarcharField)
VALUES ($usuario, $pagoID, $cursoID, '$text');";
$cargarPago = mysqli_query($conectar, $sql);
}
This is a tad inefficient though - executing an insert for every iteration. Since mysql supports bulk inserts, you can modify the generation of the query to leverage that.
$verificar = $_POST['verificarPago'];
$rows = array();
foreach ($verificar as $ids => $text) {
list($pagoID, $cursoID) = explode("-", $ids);
$rows[] = "($usuario, $pagoID, $cursoID, '$text')";
}
$sql = "INSERT INTO pagosVerificados (userID, pagoID, cursoID, someVarcharField) VALUES "
. implode(',', $rows)
. ";";
$cargarPago = mysqli_query($conectar, $sql);
Now it's just one round-trip to the database
This is a bizarre way of passing values over POST. But, to expand on Peter's answer and address the glaring security issues, you can also use prepared statements. They're designed to be prepared once and then executed multiple times so are perfect for the job.
$verificar = $_POST['verificarPago'];
$sql = "INSERT INTO pagosVerificados (userID, pagoID, cursoID, someVarcharField) VALUES (?, ?, ?, ?)"
$stmt = $conectar->prepare($sql);
foreach ($verificar as $ids => $text) {
list($pagoID, $cursoID) = explode("-", $ids);
$stmt->bindParam("iiis", $usuario, $pagoID, $cursoID, $text);
$stmt->execute();
}
It's been years since I've worked with mysqli, but this should do the trick. You'll want to include some error checking in there as well.
I have a form that looks like this:
<form>
<textarea name="text1"></textarea>
<textarea name="text2"></textarea>
<textarea name="text3"></textarea>
</form>
However, the number of textareas is determined dynamically so there will not always be just 3.
I want to insert the $_POST of each textarea into a different row with PDO. If they were all going in the same row, I would just use this:
$query = $db->prepare("INSERT INTO responses (text1, text2, text3) VALUES (:text1, :text2, :text3)");
$query->bindValue('text1', $_POST['text1'], PDO::PARAM_STR);
$query->bindValue('text2', $_POST['text2'], PDO::PARAM_STR);
$query->bindValue('text3', $_POST['text3'], PDO::PARAM_STR);
$query->execute();
Although the issue of a changing number of textareas is not addressed by that either.. I was considering using count($_POST) and iterating with a for loop?
How can I go about inserting an unknown number of fields into there own row with PDO?
Change your HTML to send it as an array:
<textarea name="text[]"></textarea>
<textarea name="text[]"></textarea>
<textarea name="text[]"></textarea>
Then you can just loop over the array $_POST['text']
You could probably even do:
$params = array_fill(0, count($_POST['text']), '(?)');
$db->prepare("INSERT INTO responses (text) VALUES " . implode(", ", $params));
$query->execute($_POST['text']);
I am not sure the best way to do this or if it's even possible. Basically I have a checkbox that looks like this:
php
foreach($clients as $client){
echo'
<input type="checkbox" name="client_data[]" value="'.$class_id.'">
'.$client['first_name'].' ('.$client['nickname'].') '.$client['last_name'].'
<br />';
} // foreach($client
HTML looks like this
<form method="post" action="">
<input type="checkbox" value="?" name="client_data[]">
Dwayne (The Rock) Johnson<br>
<input type="checkbox" value="?" name="client_data[]">
Steve (Puddin) Robinson<br>
<input type="submit" value="Add" name="exist_to_class">
</form>
When the form is submitted I want to insert the
$first_name, $nickname, $lastname
into the db with a query that looks like this:
mysql_query("INSERT INTO `clients` (`user_id`, `first_name`, `last_name`, `nickname` `class_id`)
VALUES ('$user_id', '$first_name, '$last_name', '$nickname', '$class_id')");
Is this possible or am I even close on how I am attempting to set this up? I have not had much luck so far.
My db table looks like this:
I need to be able to enter the client multiple time with different class_id's.
What is the best way to accomplish this?
Here is the code that call the function to insert data into db:
if (isset($_POST['exist_to_class'])){
if (empty($_POST['client_data']) === true){
$errors [] = 'You much select a client to be added to the class.';
} else {
if (isset($_POST['client_data']) && !empty($_POST['client_data']));
list($first_name, $nickname, $last_name) = explode('|', $_POST['client_data']);
exist_client_to_class($class_id);
header('Location: view_class.php?class_id='.$class_id.' ');
}
} //isset
And here is my query:
function exist_client_to_class($class_id, $user_id){
$class_id = (int)$class_id;
$user_id = (int)$user_id;
mysql_query("INSERT INTO `clients` (`user_id`, `first_name`, `last_name`, `nickname` `class_id`)
VALUES ('$user_id', '$first_name, '$last_name', '$nickname', '$class_id')");
}
What am I doing wrong?
You can't pass more than one variable through a single checkbox. Marc B is right, in that if this is a database-backed application then the right way to do it would be to have the checkbox send the ID for the person who's selected, and use the ID to look up whatever information you need about them.
If you're not using a database, a quick-and-dirty way to do this would be to put the information about the person into an array and then run it through serialize() to turn it into a string and use that as the value attribute. On the other end you can run it through unseialize() to get back the array with the values you wanted.
Remember that if you do this, you need to either escape your sql query or (very strongly preferred) use a prepared query.
okay, you may path string in value as Asad suggested and than split it on the server, like this
foreach($clients as $client){
echo'
<input type="checkbox" name="client_data" value="'.$class_id.'|'.$client['first_name'].'|'.$client['nickname'].'|'.$client['last_name'].'">
'.$client['first_name'].' ('.$client['nickname'].') '.$client['last_name'].'
<br />';
} // foreach($client
and on the server have something like
list($class_id, $first_name, $nickname, $last_name) = explode('|', $_POST['client_data'])
mysql_query("INSERT INTO `clients` (`user_id`, `first_name`, `last_name`, `nickname` `class_id`)
VALUES ('$user_id', '$first_name, '$last_name', '$nickname', '$class_id')");
I am not sure where from $class_id variable in template and $user_id in the model, so you have to figure it out, also drawback here is that if in some variable will be placed delimiter | data will be split wrong. To avoid it you may use hidden inputs associated somehow with the main checkbox (javascript, logic or whaterver will play best in your case)
UPD: oh yea you may serialize/unserialize data as array http://us3.php.net/serialize as octern suggestion