PHP Multiple Mysql Insert script explanation. How? - php

I need help understanding this clever PHP Multiple Mysql Insert code.
Allow me to stress that, I've found the parsing of JSON data online and the rest is mine.
It works flawlessly but there are things I don't fully understand about it...
How is it building the insert string? If you could comment the code that's wonderful...
Is it repeatedly inserting or is it one giant insert PDO execute?
I've notice that it uses bindValue instead of bindParameter. Is this because of the nature of this dynamic PHP script?
Optional: If you know of a simple and clear way to do this, by all means, let me know if you get a chance.
JSON POST DATA
[
{
"PK_LINE_ITEM_ID":555,
"DESCRIPTION":"LINE ITEM 5",
"QUANTITY":0,
"UNIT":"SF",
"COST":0,
"TOTAL":"0.00"
},
{
"PK_LINE_ITEM_ID":777,
"DESCRIPTION":"LINE ITEM 7",
"QUANTITY":0,
"UNIT":"SF",
"COST":0,
"TOTAL":"0.00"
},
{
"PK_LINE_ITEM_ID":999,
"DESCRIPTION":"LINE ITEM 9",
"QUANTITY":0,
"UNIT":"SF",
"COST":0,
"TOTAL":"0.00"
}
]
PHP script (data_post_json_insert_all.php)
<?php
/* Status Codes
return 0 = Nothing to Update (n/a)
return 1 = Successful Insert Query
return 2 = Database Connection refused
return 3 = MySQL Query Error OR Wrong URL Parameters */
/* Disable Warnings so that we can return ONLY what we want through echo. */
mysqli_report(MYSQLI_REPORT_STRICT);
// First get raw POST input
$raw_post = file_get_contents('php://input');
// Run through url_decode..
$url_decoded = urldecode($raw_post);
// Run through json_decode...
// false to allow for reference to oject. eg. $column->name instead of $column["name"] in the foreach.
$json_decoded = json_decode($url_decoded, true);
$table_name = 'tbl_xyz';
// INCLUDE DB CONNECTION STRING
include 'php_pdo_mysql_connect.php';
pdoMultiInsert($table_name, $json_decoded, $link);
function pdoMultiInsert($mysql_table, $json_decoded, $pdo_object) {
//Will contain SQL snippets.
$rows_sql = [];
//Will contain the values that we need to bind.
$to_bind = [];
//Get a list of column names to use in the SQL statement.
$column_names = array_keys($json_decoded[0]);
//Loop through our $json_decoded array.
// begin outter for each
foreach($json_decoded as $array_index => $row) {
$params = [];
// begin inner for each --------------------------------
foreach($row as $column_name => $column_value) {
$param = ":" . $column_name . $array_index;
$params[] = $param;
$to_bind[$param] = $column_value;
} // end inner for each --------------------------------
$rows_sql[] = "(" . implode(", ", $params) . ")";
} // end outter for each
//Construct our SQL statement
$sql = "INSERT INTO `$mysql_table` (" . implode(", ", $column_names) . ") VALUES " . implode(", ", $rows_sql);
//Prepare our PDO statement.
$pdo_statement = $pdo_object->prepare($sql);
//Bind our values.
foreach($to_bind as $param => $val) {
$pdo_statement->bindValue($param, $val);
}
//Execute our statement (i.e. insert the json_decoded data).
return $pdo_statement->execute();
}
$link = null;
$stmt = null;
// return 1 = Successful Insert Query
echo '1';
Thanks

1) The script uses a bidimensional array to make it easier to prepare the insert query.
It will create an array for each row (using the column name as the index and the field value as the value), and then a second array containing those rows. So the array represents all the data that will be inserted, exactly as it should be included.
Then, they implode each line using a coma as glue - so you'll have each value separated with a coma and put parenthesis on it. Then just implode the second array using a coma as glue again, wich will mount the whole insert values query.
2) Execute is runing outside any repeat loop, so it's only one giant insert.
3) bindParam will bound the query to a variable, and if this variable changes in the future, it will change in the query too. bindValue append the final value at the runtime. Take a look at this thread.
4) This script is meant to be generic and work with different table setups - and it's a good way of doing it.

Related

How to fetch data using loop PHP statement from mysql to ios?

My system is composed of 3 components.
ios - php - mysql
If ios users select multiple 'id's,
then, ios app posts these selected 'id' request to server,
and, the server finds the data based on selected 'id's in MySQL.
and finally, the server passes these data to ios app.
These are the PHP statements I tried.
<?php
$id_0 = $_POST['0'];
$id_1 = $_POST['1'];
$id_2 = $_POST['2'];
$id_3 = $_POST['3'];
...
$id_n = $_POST['n'];
$conn = mysqli_connect('address', 'user', 'password', 'database');
$sql = "SELECT * FROM firstname WHERE id = '$id_0'";
if ($result = mysqli_query($conn, $sql)) {
$resultArray = array();
$tempArray = array();
while($row = $result->fetch_object()) {
$tempArray = $row;
array_push($resultArray, $tempArray);
}
} else {
}
mysqli_close($conn);
?>
To get multiple 'id' data, I found that I need to use loop statement.
But the problem is, the number of selected id are variable.
I think that in this code, I need two loop statement.
To get multiple data based on multiple id(the number of id are variable)
To append these data into array
I don't know how to use loop statement when the range is not defined.
How can I use loop statement in PHP, and how can I rearrange these codes?
I'm sure this question is a duplicate but I can't find an exact source.
Your current method means you need to run a whole MySQL query for each iteration.
As the query results will never change what the iteration contains, therefore; you can simply rework it to use MySQL IN to load all of your variables at once:
Step 1) Take all the values and place them in a single array.
$new = []; //new array
foreach ($_POST as $key=>$id){
// Check it is a numeric key
// Check id value is valid to avoid importing other POST values
if((int)$key == $key && (int)$id == $id){
$new[] = $id;
}
}
The above code block is nessecary to stop using values from $_POST['button'] or other posted data that should not be included. This step can be removed if you can clarify your posted data, such as saving all ids to a $_POST['id'] array itself.
Step 2) Empty the array of null/void or repeated values.
$new = array_unique($new);
Step 3) Turn the array into a string, inside the SQL
$arrayString = implode(',',$new);
Step 4) Plug the string into the SQL IN clause:
$sql = "SELECT * FROM firstname WHERE id IN (" . $arrayString . ") ORDER BY id";
Simplified and reduced:
$new = []; //new array
foreach ($_POST as $key=>$id){
if((int)$key == $key && (int)$id == $id){
$new[] = $id;
}
}
$new = array_unique($new);
$sql = "SELECT * FROM firstname WHERE id IN (" .
implode(',',$new) . ") ORDER BY id";
The SQL query above will give you an array of arrays, each one a different row. You can the order them, sort them and output them in PHP as you wish.
See also: This Q&A.
BUT
As expressed by others, you really, REALLY should be using Prepared Statements with MySQLi.
See also here, here and here to see further how to do it and WHY you should do it.
Top Tips:
Numerical columns (typical of id columns) in MySQL do not need the ' quotes.
Until you're using Prepared Statements you can typecast the variables to integers ((int)$var) to limit risk.
It is better to specify the columns you need rather than to use the * catch-all.
Your $_POST data should be an array $_POST['ids'][...].
Eat five different pieces of fruit or veg' a day.
Never trust user input!

Create array with key and value in loop PHP

I'm using PDO, and I managed to get the table columns despite the table name and create the bind variables, like in ... VALUES (:foo, :bar);.
The method I'm trying to do this is insert().
public function insert()
{
// the variable names depend on what table is being used at the moment the script runs.
// These methods use the PDO `getColumnMeta()` to retrieve the name of each column
$sql = "INSERT INTO {$this->getTableName()}({$this->getTableColumns()}) "
. "VALUES ({$this->getTableColumns(true)})";
// The previous method gets the name of each column and returns a single string, like "foo, bar, [...]"
// and this function is used to separate each word, with the specified delimiter
$col = explode(", ", $this->getTableColumns());
// Now here lays the problem.
// I already know how to retrieve the columns name as a variable, and
// how to dynamically create the get method, using `ucfirst()`
// What I need would be something like this being inside of a
// loop to retrieve all the separated words from `$col` array.
$data = array(
$col[$i] => "\$this->entity->get".ucfirst($col[$i])."()",
)
/*
* From now on, is what I need to do.
*/
// Lets pretend the column names are "foo, bar".
$data = array(
":foo" => $this->entity->getFoo(),
":bar" => $this->entity->getBar()
)
// That'd be the final array I need, and then continue with
$stm = $this->db->prepare($sql);
$stm->execute($data);
}
You have to loop over $data array and add function as per your requirement.
Fetch values from `... VALUES (:foo, :bar); Then explode as you did in your code , then loop over $col array and add values to $data as required
foreach($col as $val){
$method = "get".ucfirst( $val);
$data[ $val] = call_user_func(array( $this->entity,$method));
}
Above code may work as follow
$data[':foo'] = $this->entity->getFoo();
$data[':bar'] = $this->entity->getBar();

Creating a dynamic MySQL query from URL paramaters

I am really trying to wrap my head around this and failing miserably. What I want to do it build a MySQL query based on the URL parameters passed by the URL. I am trying to create a re usable dynamic script that can do what it needs to do based on the URL parameter.
This is what I have come up with, and it appears that it does what it is supposed to do (no errors or anything) but nothing actually gets inserted in the database. I know somewhere I have made a dumb mistake (or thought something out wrong) so hopefully one of you guys can point me in the right direction.
Thanks!
//List all possible variables you can expect the script to receive.
$expectedVars = array('name', 'email', 'score', 'age', 'date');
// This is used for the second part of the query (WHERE, VALUES, ETC)
$fields = array('uName','uEmail','uScore','uAge','uDate');
// Make sure some fields are actually populated....
foreach ($expectedVars as $Var)
{
if (!empty($_GET[$Var]))
{
$fields[] = sprintf("'%s' = '%s'", $Var, mysql_real_escape_string($_GET[$Var]));
}
}
if (count($fields) > 0)
{
// Construct the WHERE Clause
$whereClause = "VALUES " . implode(",",$fields);
//Create the SQL query itself
$sql = ("INSERT INTO $mysql_table ($fields) . $whereClause ");
echo "1"; //It worked
mysql_close($con);
}
else
{
// Return 0 if query failed.
echo "0";
}
?>
You missed mysql_query($sql):
if(!mysql_query($sql)){
//die(mysql_error());
}
Please consider to use PDO or My SQLi using parametrize query because mysl_* function depreciated.
Your SQL is all wrong. You're using the field = value syntax for an INSERT, then you're concatenating an array as if it were a string ($fields), and you're missing a couple of parentheses around the values.
a couple of things: i've found for php <-> mysql its important to see what's going into mysql and experiement directly with those queries in phpmyadmin when i get stuck.
1 - in my code I output mysql_error() when the query fails or when a debug flag is set. this usually explains the sql issue in a way that can point me to a misspelled field name etc...
2 - this way i can feed that mysql query directly into phpmyadmin and tweak it until it gives me the results i want. (while i'm there i can also use explain to see if i need to optimize the table)
specifics in your code. unlike C languages sprintf is implied. here's how i'd write your code:
// List all possible variables you can expect the script to receive.
$expectedvars = array('name', 'email', 'score', 'age', 'date');
// This is used for the second part of the query (WHERE, VALUES, ETC)
// $fields = array('uName','uEmail','uScore','uAge','uDate');
$fields = array();
// Set only the variables that were populated ...
foreach ($expectedvars as $var) {
if (!empty($_GET[$var])) {
$name = "u" + ucwords($var); // convert var into mysql field names
$fields[] = "{$name} = " . mysql_real_escape_string($_GET[$var]);
}
}
// only set those fields which are passed in, let the rest use the mysql default
if (count($fields) > 0) {
// Create the SQL query itself
$sql = "INSERT INTO {$mysql_table} SET " . implode("," , $fields);
$ret = mysql_query($sql);
if (!$ret) {
var_dump('query_failed: ', $sql, $ret);
echo "0"; // Query failed
} else {
echo "1"; // It worked
}
} else {
// Return 0 if nothing to do
echo "0";
}
mysql_close($con);

How to store multiple parameters passed as POST in database

I have passed JSON encoded parameters by POST which we have captured and decoded in another PHP file. I have used the following code to do that.
$entityBody = file_get_contents('php://input');
$entityBody = json_decode($entityBody, true);
I have passed the JSON encoded parameters as follows:
{
"id": "5",
"name": "abcd",
"imei": "1234"
}
Actually the number of parameters I am passing by POST may be 15 to 20 which I am going to insert in a table i.e. each of them is a field in the table in mysql database. I am new to JSON and PHP. What method I know is that get value of each parameter after checking whether it is set like following:
if(isset($entityBody['id']))
...
elseif(isset(...))
...
It is clear there will be many if and else when there are many parameters. So is there any way so that I can store the parameters in table in more efficient way. If anyone helps me in doing that I will be really grateful.
use json_decode function to parse the json to an array or object.
$a = json_decode($entityBody);
$a->id;
refer http://php.net/manual/en/function.json-decode.php
If you're using prepared statements you could do something like this. Please note that you should consider how you implement something like this, and change it to suit your needs.
$json = '{"id": "5","name": "abcd","imei": "1234"}';
$array = json_decode($json, true);
if (!count($array) > 0) {
throw new Exception('No params set.');
}
$allowedKeys = array('id','name','imei'); // could be hard coded, or something like: SELECT * FROM yourdb.INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = yourtable
$queryParams = array();
foreach ($array as $key => $value) {
if (in_array($key, $allowedKeys)) {
$queryParams['keys'][] = $key;
$queryParams['values'][] = $value;
}
}
print_r($queryParams);
$query = 'INSERT INTO yourtable (' . implode(', ', $queryParams['keys']) . ') VALUES (?' . str_repeat(',?', count($queryParams['values'])-1) . ')';
print_r($query); // INSERT INTO yourtable (id, name, imei) VALUES (?,?,?)
Then you can just execute it with the $queryParams['values'] as the values :)
There's however no need to insert "id" if you're using auto increment, it will possibly just end up in some strange errors.

How to output multiple rows from an SQL query using the mysqli object

Assuming that the mysqli object is already instantiatied (and connected) with the global variable $mysql, here is the code I am trying to work with.
class Listing {
private $mysql;
function getListingInfo($l_id = "", $category = "", $subcategory = "", $username = "", $status = "active") {
$condition = "`status` = '$status'";
if (!empty($l_id)) $condition .= "AND `L_ID` = '$l_id'";
if (!empty($category)) $condition .= "AND `category` = '$category'";
if (!empty($subcategory)) $condition .= "AND `subcategory` = '$subcategory'";
if (!empty($username)) $condition .= "AND `username` = '$username'";
$result = $this->mysql->query("SELECT * FROM listing WHERE $condition") or die('Error fetching values');
$this->listing = $result->fetch_array() or die('could not create object');
foreach ($this->listing as $key => $value) :
$info[$key] = stripslashes(html_entity_decode($value));
endforeach;
return $info;
}
}
there are several hundred listings in the db and when I call $result->fetch_array() it places in an array the first row in the db.
however when I try to call the object, I can't seem to access more than the first row.
for instance:
$listing_row = new Listing;
while ($listing = $listing_row->getListingInfo()) {
echo $listing[0];
}
this outputs an infinite loop of the same row in the db. Why does it not advance to the next row?
if I move the code:
$this->listing = $result->fetch_array() or die('could not create object');
foreach ($this->listing as $key => $value) :
$info[$key] = stripslashes(html_entity_decode($value));
endforeach;
if I move this outside the class, it works exactly as expected outputting a row at a time while looping through the while statement.
Is there a way to write this so that I can keep the fetch_array() call in the class and still loop through the records?
Your object is fundamentally flawed - it's re-running the query every time you call the getListingInfo() method. As well, mysql_fetch_array() does not fetch the entire result set, it only fetches the next row, so your method boils down to:
run query
fetch first row
process first row
return first row
Each call to the object creates a new query, a new result set, and therefore will never be able to fetch the 2nd, 3rd, etc... rows.
Unless your data set is "huge" (ie: bigger than you want to/can set the PHP memory_limit), there's no reason to NOT fetch the entire set and process it all in one go, as shown in Jacob's answer above.
as a side note, the use of stripslashes makes me wonder if your PHP installation has magic_quotes_gpc enabled. This functionality has been long deprecrated and will be removed from PHP whenever v6.0 comes out. If your code runs as is on such an installation, it may trash legitimate escaping in the data. As well, it's generally a poor idea to store encoded/escaped data in the database. The DB should contain a "virgin" copy of the data, and you then process it (escape, quote, etc...) as needed at the point you need the processed version.

Categories