MySQL PDO inserting wrong values (CSV data source) - php

I have a table like so.
CREATE TABLE `GBPAUD` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`currency_pair` varchar(11) NOT NULL DEFAULT '',
`date` datetime NOT NULL,
`sell` float NOT NULL,
`buy` float NOT NULL,
`spread` float NOT NULL,
PRIMARY KEY (`id`)
)
I have written a script that opens CSV files, itterates the rows and inserts them into the table.
After the script has run and i look in the database the table appears like this.
The code that inserts the data looks like so.
private function insert($currencyPair, $date, $buy, $sell, $spread){
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$result_set = $this->pdo->prepare("INSERT INTO ".str_replace('_', '', $this->instrument)." (currency_pair, date, sell, buy, spread) VALUES (:currency_pair, :date, :sell, :buy, :spread)");
$result = $result_set->execute(array(':currency_pair' => $currencyPair, ':date' => $date, ':buy' => (float)$buy, ':sell' => (float)$sell, 'spread' => (float)$spread));
}
I print out the values just before the exacute stament and the values are correct.
Array
(
[:currency_pair] => GBP/AUD
[:date] => 2007-11-01 14:06:04.000
[:buy] => 2.273400
[:sell] => 2.272500
[spread] => 0
)
Anyone have any idea why its not inserting my data?
EDIT:
DB connection code
define("DSN", "mysql:dbname=rates_test;host=localhost;port=3306");
define("USER", "blah");
define("PASS", "blah");
$pdo = new PDO(DSN, USER, PASS);
EDIT 2
I have taken the insert out of the function and added to the while loop im doing so you can see whats happening.
while( false !== ( $data = fgetcsv($file) ) ) {
if(array(null) !== $data){ //skip blank lines
$currencyPair = $data[$column['columns']['instrument']];
$date = $data[$column['columns']['date']];
$sell = $data[$column['columns']['sell']];
$buy = $data[$column['columns']['buy']];
$spread = (float)$buy - (float)$sell;
echo "value => " . $currencyPair . "\r\n";
echo "value => " . $date . "\r\n";
echo "value => " . $sell . "\r\n";
echo "value => " . $buy . "\r\n";
echo "value => " . $spread . "\r\n";
echo var_dump(array(':currency_pair' => $currencyPair, ':date' => $date, ':buy' => (float)$buy, ':sell' => (float)$sell, ':spread' => (float)$spread));
$result_set = $this->pdo->prepare("INSERT INTO ".str_replace('_', '', $this->instrument)." (currency_pair, date, sell, buy, spread) VALUES (:currency_pair, :date, :sell, :buy, :spread)");
$result = $result_set->execute(array(':currency_pair' => $currencyPair, ':date' => $date, ':buy' => (float)$buy, ':sell' => (float)$sell, ':spread' => (float)$spread));
}
}
and here is the result
value => GBP/AUD
value => 2007-10-28 21:21:48.000
value => 2.229000
value => 2.229900
value => 0
array(5) {
[":currency_pair"]=> string(15) "GBP/AUD"
[":date"]=> string(47) "2007-10-28 21:21:48.000"
[":buy"]=> float(0)
[":sell"]=> float(0)
[":spread"]=> float(0)
}
Edit 3:
I solved it, but its a bit hacky. Also i have no control over over these CSV's so any invisible characters can be in it. Can anyone please confirm if this is enough to handle any invisible characters there may be? ( i have not put this into a function yet, but i am doing the same for ever variable im inserting)
$buy = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $buy);
$buy = (strpos($buy, ':') && strpos($buy, '-')) ? array_shift(explode('.', $buy)) : $buy;
I do not like what i am doing with the date, but i cannot think of any other ways (i cannot parse a legitamate date straight from the CSV because of the invisable characters) even without the invisible characters removed i cannot parse a date because some feilds have more than 6 micro seconds (PHP can only handel 6)

I just wrapped a bit of code around your posted code and it works fine. I did not even change the code for the spread to :spread suggestion.
I did however add a try/catch block as I see you set the mode to throw Exceptions, but the catch block was never activated.
<?php
class tst
{
private $pdo;
private $instrument = 'gbp_aud';
public function __construct()
{
/*** mysql hostname ***/
$hostname = 'localhost';
/*** mysql username ***/
$username = 'test';
/*** mysql password ***/
$password = 'test';
/*** database name ***/
$dbname = 'test';
try {
$this->pdo = new PDO("mysql:host=$hostname;dbname=$dbname;charset=UTF8", $username, $password);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$this->pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
$this->pdo->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND,'SET NAMES UTF8');
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
exit;
}
}
private function insert($currencyPair, $date, $buy, $sell, $spread){
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try {
$result_set = $this->pdo->prepare("INSERT INTO ".str_replace('_', '', $this->instrument)." (currency_pair, date, sell, buy, spread) VALUES (:currency_pair, :date, :sell, :buy, :spread)");
$result = $result_set->execute(array(':currency_pair' => $currencyPair, ':date' => $date, ':buy' => (float)$buy, ':sell' => (float)$sell, 'spread' => (float)$spread));
}
catch(PDOException $e) {
print_r($this->pdo->errorInfo());
exit;
}
}
public function doit($currencyPair, $date, $buy, $sell, $spread){
$this->insert($currencyPair, $date, $buy, $sell, $spread);
}
}
$test = new tst();
$currencyPair = 'GBP/AUD';
$date = '2007-11-01 14:06:04.000';
$buy = 2.273400;
$sell = 2.272500;
$spread = 0;
$test->doit($currencyPair, $date, $buy, $sell, $spread);
$currencyPair = 'GBP/AUD';
$date = '2007-11-02 13:06:04.000';
$buy = 2.276600;
$sell = 2.278800;
$spread = 0.4;
$test->doit($currencyPair, $date, $buy, $sell, $spread);
Results:
I just read your last question, and I have to assume that you still have some odd characters in your data feed to this process.
Do a var_dump() of the array that you feed to the ->execute() statement, that will likely show more than a simple print_r()
UPDATE
The issue is that the older files are encoded in UNICODE and the new files are simple ASCII single byte encoded.
I converted the Older files offline so to speak back to ASCII and this code loaded an old and new file quite happily
The only remaining complication if that the older files dont have column names on row 1 and the field order is a little different, but thats just a FLOC. See the code below.
<?php
class tst
{
private $pdo;
private $instrument = 'gbp_aud';
public function __construct()
{
/*** mysql hostname ***/
$hostname = 'localhost';
/*** mysql username ***/
$username = 'test';
/*** mysql password ***/
$password = 'test';
/*** database name ***/
$dbname = 'test';
try {
$this->pdo = new PDO("mysql:host=$hostname;dbname=$dbname;charset=UTF8", $username, $password);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$this->pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
$this->pdo->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND,'SET NAMES UTF8');
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
exit;
}
}
private function insert($currencyPair, $date, $buy, $sell, $spread){
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try {
$result_set = $this->pdo->prepare("INSERT INTO ".str_replace('_', '', $this->instrument)." (currency_pair, date, sell, buy, spread) VALUES (:currency_pair, :date, :sell, :buy, :spread)");
$result = $result_set->execute(array(':currency_pair' => $currencyPair, ':date' => $date, ':buy' => (float)$buy, ':sell' => (float)$sell, 'spread' => (float)$spread));
}
catch(PDOException $e) {
print_r($this->pdo->errorInfo());
exit;
}
}
public function doit($currencyPair, $date, $buy, $sell, $spread){
$this->insert($currencyPair, $date, $buy, $sell, $spread);
}
}
$test = new tst();
// One old and one new format file
$files = array('GBP_AUD_Week1.csv', 'GBP_AUD_Week5.csv');
foreach ($files as $file) {
$old_format = true;
if (($handle = fopen($file, "r")) !== FALSE) {
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
// test old or new file layout
if ( $data[0] == 'lTid' ) {
// New file layout
$old_format = false;
// Skip the title row
continue;
}
if ( $old_format ) {
$test->doit($data[1], $data[2], $data[3], $data[4], $data[4]-$data[3]);
} else {
$test->doit($data[2], $data[3], $data[4], $data[5], $data[5]-$data[4]);
}
}
fclose($handle);
}
}

Related

How to create an object of a class only once in a Multi Step form PHP

I have a class formhandller like this
<?php
include "config.php";
class formhandller {
var $dbinstance;
var $lastinsertedid;//The id from the basic information tabel
function __construct(){
$this->connectDb();
}
function pdoMultiInsert($tableName, $data, $pdoObject){
//Will contain SQL snippets.
$rowsSQL = array();
//Will contain the values that we need to bind.
$toBind = array();
//Get a list of column names to use in the SQL statement.
$columnNames = array_keys($data[0]);
//Loop through our $data array.
foreach($data as $arrayIndex => $row){
$params = array();
foreach($row as $columnName => $columnValue){
$param = ":" . $columnName . $arrayIndex;
$params[] = $param;
$toBind[$param] = $columnValue;
}
$rowsSQL[] = "(" . implode(", ", $params) . ")";
}
//Construct our SQL statement
$sql = "INSERT INTO `$tableName` (" . implode(", ", $columnNames) . ") VALUES " . implode(", ", $rowsSQL);
//Prepare our PDO statement.
$pdoStatement = $pdoObject->prepare($sql);
//Bind our values.
foreach($toBind as $param => $val){
$pdoStatement->bindValue($param, $val);
}
//Execute our statement (i.e. insert the data).
try {
return $pdoStatement->execute();
} catch(PDOException $e) {
var_dump($e->getMessage());
//show error
error_log($query." :".$e->getMessage(). "\n", 3, getcwd() . "/var/tmp/sql_error.log");
exit;
}
}
private function connectDb(){
try {
//create PDO connection
$this->dbinstance = new PDO("mysql:host=".DBHOST.";dbname=".DBNAME, DBUSER, DBPASS);
$this->dbinstance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
//show error
error_log($query." :".$e->getMessage(). "\n", 3, getcwd() . "/var/tmp/sql_error.log");
exit;
}
}
public function postBasicinformation(){
//Add the variables coming from the form .
$stmt = $this->dbinstance->prepare('INSERT INTO basic_information (company,name,designation,email,direct_line,mobile) VALUES (:company, :name, :designation, :email, :directline, :mobile)');
$stmt->execute(array(
':company' => $_POST['company'],
':name' => $_POST['name'],
':designation' => $_POST['designation'],
':email' => $_POST['email'],
':directline' => $_POST['directline'],
':mobile' => $_POST['mobile'],
));
$this->lastinsertedid = $this->dbinstance->lastInsertId('id');
//echo $this->lastinsertedid;
//$this->dbinstance=null;
}
public function postProjectawards(){
//An example of adding to our "rows" array on the fly.
for($i=0;$i<sizeof($_POST['nominee_company']);$i++){
$rowsToInsert[] = array(
'biid' => $this->lastinsertedid,
'award_type' => 'pa',
'category' => $_POST['nominee_category'][$i],
'company' => $_POST['nominee_company'][$i],
'name' => $_POST['nominee_name'][$i],
'designation' => $_POST['nominee_designation'][$i],
'award_title' => $_POST['nominee_title'][$i],
'contact' => $_POST['nominee_contact'][$i],
'email' => $_POST['nominee_email'][$i],
'remark' => $_POST['remarks'][$i]
);
}
//var_dump($rowsToInsert);
//Call our custom function.
$y =$this->pdoMultiInsert('nominee', $rowsToInsert, $this->dbinstance);
//$this->dbinstance=null;
}
}
Now my redirect page is like this
<?php
include "controller/formhandller.php";
$x = new formhandller();
if(isset($_POST['steps'])){
if($_POST['steps']==1){
$x->postBasicinformation();
$url = "nominee.php";
header('Location: '.$url);
die();
}
if($_POST['steps']==2){
$x->postProjectawards();
$url = "nominee2.php";
header('Location: '.$url);
die();
}
}
else {
header('Location: '.'index.php');
die();
}
When I am saving the first step that is using postBasicinformation() this function .
It saves in a table called basic_information and gets the id of the inserted row and initialize it to the variable
$lastinsertedid
I want to use this variable in all the next steps to store in other tables.
But right now I am getting NULL
any Idea
Thanks.
I think you are getting confused about the life cycle of a php script.
Anything you do in xxx.php is lost once that script finishes. All objects instantiated during the execution of xxx.php with be lost forever once it finishes.
If you want to preserve some information created in xxx.php for use in yyy.php you have to save it somewhere, either a file or a database or the SESSION or possibly a caching system.
I think this is where you are getting confused. So as you said in a comment if you want to use this lastinsertid in another script the most obvious place to save it between scripts is the $_SESSION array

Create JSON with specific format using PHP

I have a table in my server database with the following columns:
|---category--|---name---|---description---|
So, lets say for example that we have the following data inside the table:
|---CategoryA--|---name1---|---description1---|
|---categoryB--|---name2---|---description2---|
|---categoryA--|---name3---|---description3---|
|---categoryA--|---name4---|---description4---|
I would like to create a .php file, and when i call it from my Android app i would like to get a JSON as response. The json file would like to have the following format:
{
"CategoryA":[
{"name":"name1","description":"description1"},
{"name":"name3","description":"description3"},
{"name":"name4","description":"description4"}
],
"KatigotiaB":[
{"name":"name2","description":"description2"}
]
}
I have created a .php file that returns me the data in JSON format, but not in the specific format i want. Here is my .php file:
<?php
header('content-type: text/html; charset=utf-8');
try {
$pdo = new PDO('mysql:host=****;dbname=****', '****', '****', array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
echo 'ERROR: ' . $e->getMessage();
}
$stmt = $pdo->prepare("SELECT * FROM `db`.`table`;");
$stmt->execute();
$results = array();
while ($obj = $stmt->fetch(PDO::FETCH_ASSOC)) {
array_push($results, $obj);
}
function replace_unicode_escape_sequence($match) {
return mb_convert_encoding(pack('H*', $match[1]), 'UTF-8', 'UTF-16BE');
}
$str = preg_replace_callback('/\\\\u([0-9a-f]{4})/i', 'replace_unicode_escape_sequence', json_encode($results));
echo $str;
?>
and the result is:
[{"category":"CategoryA","name":"name1","description":"description1"},
{"category":"CategoryB","name":"name2","description":"description2"},
{"category":"CategoryA","name":"name3","description":"description3"},
{"category":"CategoryA","name":"name4","description":"description4"}]
As i'm an Android developer and my php knowledge is limited, how could i recreate my .php file in order to get the correct JSON format?
UPDATE:
that works
foreach ($nameDescriptionPairs as $nameDescriptionPair) {
$result[$row['category']][] = array(
'name' => $nameDescriptionPair['name'],
'description' => $nameDescriptionPair['description']
);
}
Solution #1 (simple):
<?php
$host = 'localhost';
$database = '******';
$user = '******';
$password = '******';
$result = [];
try {
$pdo = new PDO(
"mysql:host=$host; dbname=$database;",
$user,
$password,
[PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"]
);
$stmt = $pdo->prepare("SELECT category, name, description FROM `YOUR_TABLE_HERE`");
$stmt->execute();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$result[$row['category']][] = [
'name' => $row['name'],
'description' => $row['description'],
];
}
} catch (Exception $e) {
echo 'ERROR: ' . $e->getMessage();
}
header('content-type: application/json; charset=utf-8');
echo json_encode($result);
Solution #2 (geeky):
One note to my code: I used hex conversion to prevent problems with quotes. Thus, even if any column has any number of ", the code will work fine.
<?php
function hexToStr($hex) {
$string = '';
for ($charIter = 0; $charIter < strlen($hex) - 1; $charIter += 2) {
$string .= chr(hexdec($hex[$charIter] . $hex[$charIter + 1]));
}
return $string;
}
//----------------------
$host = 'localhost';
$database = '******';
$user = '******';
$password = '******';
$result = [];
try {
$pdo = new PDO(
"mysql:host=$host; dbname=$database;",
$user,
$password,
[PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"]
);
$query = <<<QUERY
SELECT category, CONCAT('[', GROUP_CONCAT( CONCAT( '{"name":"', hex( name ) , '", "description":"', hex( description ) , '"}' ) ), ']') raw_json
FROM `YOUR_TABLE_HERE`
GROUP BY category
QUERY;
$stmt = $pdo->prepare($query);
$stmt->execute();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$nameDescriptionPairs = json_decode($row['raw_json'], true);
foreach ($nameDescriptionPairs as $nameDescriptionPair) {
$result[$row['category']][] = [
'name' => hexToStr($nameDescriptionPair['name']),
'description' => hexToStr($nameDescriptionPair['description'])
];
}
}
} catch (Exception $e) {
echo 'ERROR: ' . $e->getMessage();
}
header('content-type: application/json; charset=utf-8');
echo json_encode($result);
One major issue is you're setting the content-type to text/html. You're not printing HTML, this should be set to JSON:
header('content-type: application/json; charset=utf-8');
Not sure if it has any effect, but your callback is unnecessary:
$str = preg_replace_callback('/\\\\u([0-9a-f]{4})/i', 'replace_unicode_escape_sequence', json_encode($results));
If you truly don't want json_encode to escape unicode, use the JSON_UNESCAPED_UNICODE option found here: http://php.net/manual/en/function.json-encode.php
$str = json_encode($results, JSON_UNESCAPED_UNICODE);
Beyond that, you could also use JSON_PRETTY_PRINT to format it, but line breaks and such shouldn't matter to the app interpreting the JSON if it is made aware that it is JSON (what setting content-type correctly should do).

Variables not being saved to database in PHP

I'm having an issue with a piece of my code. It works perfectly fine, except it won't save itself to the database. This is the code:
function createOrder($user, $cart, $price, $method) {
try {
$username = "root";
$password = "";
$connection = new PDO('mysql:host=localhost;dbname=dreamlineslaapsystemen', $username, $password);
$connection->beginTransaction();
$productList=$_SESSION['products'];
$orderList=$_SESSION['orders'];
$orderItems=$_SESSION['orderitems'];
$orderid = generateOrderid();
$allOrders = array();
for($i=0; $i<count($orderList); $i++) {
array_push($allOrders, $orderList[$i]->getID());
}
while(in_array($orderid, $allOrders)) {
$orderid = generateOrderid();
}
$today = date("Y-m-d H:i:s");
$order = new Order($orderid, $user->getID(), $price, $today, $method);
$newOrder = array(
':id' => $orderid,
':userid' => $user->getID(),
':date' => $today,
':method' => $method
);
$addOrder = $connection->prepare('INSERT INTO orders(id, userid, date) VALUES (:id, :userid, :date, :method');
$addOrder->execute($newOrder);
array_push($orderList, $order);
foreach($cart->getCart() as $item => $amount) {
$itemid=null;
for($i=0; $i<count($productList);$i++) {
if($productList[$i]->getID()==$item) {
$orderitem = new Orderitem($orderid, $i, $amount);
array_push($orderItems, $orderitem);
$newOrderitem = array(
':orderid' => $orderid,
':productid' => $i,
':amount' => $amount
);
$addOrderitem = $connection->prepare('INSERT INTO orderitems(orderid, productid, amount) VALUES (:orderid, :productid, :amount');
$addOrderitem->execute($newOrderitem);
}
}
}
$connection->commit();
$_SESSION['orders']=$orderList;
$_SESSION['orderitems']=$orderItems;
return $orderid;
} catch(PDOException $e) {
$connection->rollback();
print "Er is iets fout gegaan: " . $e->getMessage() . "<br>";
return null;
}
}
It does add everything to the arrays and sessions and when I do var_dump to see if it is all stored correctly in the sessions/arrays. It just won't add to the database.
You have 3 columns yet you are inserting 4 values. I assume you have a method column in your table and your insert statements lacks closing ) parenthesis.
$addOrderitem = $connection->prepare('INSERT INTO orderitems(orderid, productid, amount, method) VALUES (:orderid, :productid, :amount, :method'));
$addOrderitem = $connection->prepare('INSERT INTO orderitems(orderid, productid, amount) VALUES (:orderid, :productid, :amount'));

Passing $_POST values to output individual results information

My goal is to create a general template to be used to INSERT INTO testquiz (a MySQL table). This will be used for storing quiz results and user information (name and email are the only user input in the database) from quiz takers. I am new to PHP/MySQL and feel like I am just stumbling around.
My problem is that I am unable to get the $_POST values that are generated by the quiz to appear in the database. I know the values are being generated because they will display with a basic echo. There is a 'send to email' feature that works with the values that is working as well. I can get this code to work if I manually assign values to the $_POST array by uncommenting the first comment block.
What am I missing here?
Sidenote: I'll take security suggestions as well. Thank you.
Code below (user specific information omitted):
<?php
//disable magic quotes (PHP book says it's a good idea)
if (get_magic_quotes_gpc())
{
$process = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);
while (list($key, $val) = each($process))
{
foreach ($val as $k => $v)
{
unset($process[$key][$k]);
if (is_array($v))
{
$process[$key][stripslashes($k)] = $v;
$process[] = &$process[$key][stripslashes($k)];
}
else
{
$process[$key][stripslashes($k)] = striplashes($v);
}
}
}
unset($process);
}
/* //Manually declare $_POST variables (can be disabled)
$_POST['v'] = '6.5.1';
$_POST['sp'] = 80;
$_POST['psp'] = 75;
$_POST['tp'] = 80;
$_POST['sn'] = 'user';
$_POST['se'] = 'abc123#fake.com';
$_POST['qt'] = 'Test Quiz';
*/
//Assign $_POST values to static variables???
$version = $_POST['v'];
$points = $_POST['sp'];
$passing_percent = $_POST['psp'];
$gained_score = $_POST['tp'];
$username = $_POST['sn'];
$email = $_POST['se'];
$quiz_title = $_POST['qt'];
//MySQL database connection PDO
try
{
$pdo = new PDO('mysql:host=localhost;dbname=quizresults', 'user', 'password');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->exec('SET NAMES "utf8"');
}
catch (PDOException $e)
{
$error = 'Unable to connect to the database server.';
include 'error.html.php';
exit();
}
//Prepare input for database entry
try
{
$sql = $pdo->prepare("INSERT INTO testquiz (version, points, passing_percent, gained_score, username, email, quiz_title, date) VALUES (:version, :points, :passing_percent, :gained_score, :username, :email, :quiz_title, CURDATE())");
$sql->execute(array(":version" => $version, ":points" => $points, ":passing_percent" => $passing_percent, ":gained_score" => $gained_score, ":username" => $username, ":email" => $email, ":quiz_title" => $quiz_title));
//echo for debugging purposes
echo $version . '<br />', $points . '<br />', $passing_percent . '<br />', $gained_score . '<br />', $username . '<br />', $email . '<br />', $quiz_title . '<br />', date(DATE_ATOM);
}
catch (PDOException $e)
{
$error = 'Error adding quiz results to database: ' . $e->getMessage();
include 'error.html.php';
exit();
}
//Calculate user score
$points_num = (int)$points;
$passing_num = ((int)$passing_percent)/100 * (int)$gained_score;
//Write results to a text file
$f = fopen("result.txt", "w") or die("Error opening file 'result.txt' for writing");
fwrite($f, "--------------------------\n");
fwrite($f, "User name: ".$username."\n");
fwrite($f, "User email: ".$email."\n");
fwrite($f, "Quiz title: ".$quiz_title."\n");
fwrite($f, "Points awarded: ".$points."\n");
fwrite($f, "Total score: ".$gained_score."\n");
fwrite($f, "Passing score: ".$passing_num."\n");
if ($points_num >= $passing_num)
{
fwrite($f, "User passes\n");
}
else
{
fwrite($f, "User fails\n");
}
fwrite($f, "--------------------------\n");
if($f)
{
fclose($f);
}
?>
I'm not sure if this will fix everything but
$sql->execute(array(":version" => $version, ":points" => $points, ":passing_percent" => $passing_percent, ":gained_score" => $gained_score, ":username" => $username, ":email" => $email, ":quiz_title" => $quiz_title));
should be:
$sql->execute(array("version" => $version, "points" => $points, "passing_percent" => $passing_percent, "gained_score" => $gained_score, "username" => $username, "email" => $email, "quiz_title" => $quiz_title));
(remove the : from the array. it is only for PDO to 'name' the variables).

PHP PDO Insert Using Loop

I am having trouble using PDO to insert multiple records into a database. I can successfully add a single record, but as soon as I add the foreach loop, it fails. After reading a number of other SO questions regarding this, I believe I need to "bind" my variables, although I am completely confused on the proper syntax.
Here is the original function I created:
<? function addToDatabase () {
//Get All Variables
$timestamp = date("Y-m-d H:i:s");
$schoolName = $_SESSION['schoolName'];
$schoolStreet = $_SESSION['schoolStreet'];
$schoolCity = $_SESSION['schoolCity'];
$schoolState = $_SESSION['schoolState'];
$schoolZip = $_SESSION['schoolZip'];
$schoolContactName = $_SESSION['schoolContactName'];
$schoolContactTitle = $_SESSION['schoolContactTitle'];
$schoolContactPhone = $_SESSION['schoolContactPhone'];
$schoolCsontactEmail = $_SESSION['schoolContactEmail'];
$inputMethod = $_SESSION['inputMethod'];
$studentDataArray = $_SESSION['studentDataArray'];
$studentFirstNameField = $_SESSION['studentFirstNameField'];
$studentLastNameField = $_SESSION['studentLastNameField'];
$studentStreetField = $_SESSION['studentStreetField'];
$studentCityField = $_SESSION['studentCityField'];
$studentStateField = $_SESSION['studentStateField'];
$studentZipcodeField = $_SESSION['studentZipcodeField'];
$studentDOBField = $_SESSION['studentDOBField'];
$studentGenderField = $_SESSION['studentGenderField'];
$studentGradeField = $_SESSION['studentGradeField'];
//Connnect to Database
$host = 'myHost';
$un = 'myUsername';
$pw = 'myPassword';
$db_name = 'myTable';
try {
$conn = new PDO("mysql:host=$host;dbname=$dbName", $un, $pw);
echo 'Connected to database<br>';
$sql = "INSERT INTO studentData (originallyAddedOn, inputMethod, studentFirst, studentLast, studentStreet, studentCity, studentState, studentZip, studentDOB, studentGender, studentGrade, schoolName, schoolStreet, schoolCity, schoolState, schoolZip, schoolContactName, schoolContactTitle, schoolContactEmail, schoolContactPhone) VALUES (:originallyAddedOn, :inputMethod, :studentFirst, :studentLast, :studentStreet, :studentCity, :studentState, :studentZip, :studentDOB, :studentGender, :studentGrade, :schoolName, :schoolStreet, :schoolCity, :schoolState, :schoolZip, :schoolContactName, :schoolContactTitle, :schoolContactEmail, :schoolContactPhone)";
foreach ($studentDataArray as $student){
$q = $conn->prepare($sql);
echo $student[$studentFirstNameField]."<br>";
$q->execute(array( ':originallyAddedOn'=>$timestamp,
':inputMethod'=>$inputMethod,
':studentFirst'=>$student[$studentFirstNameField],
':studentLast'=>$student[$studentLastNameField],
':studentStreet'=>$student[$studentStreetField],
':studentCity'=>$student[$studentCityField],
':studentState'=>$student[$studentStateField],
':studentZip'=>$student[$studentZipField],
':studentDOB'=>$student[$studentDOBField],
':studentGender'=>$student[$studentGenderField],
':studentGrade'=>$student[$studentGradeField],
':schoolName'=>$schoolName,
':schoolStreet'=>$schoolStreet,
':schoolCity'=>$schoolCity,
':schoolState'=>$schoolState,
':schoolZip'=>$schoolZip,
':schoolContactName'=>$schoolContactName,
':schoolContactTitle'=>$schoolContactTitle,
':schoolContactEmail'=>$schoolContactEmail,
':schoolContactPhone'=>$schoolContactPhone));
}
// close the database connection
$dbh = null;
}
catch(PDOException $e) {
echo $e->getMessage();
}
}
The $studentDataArray looks similar to this:
0 => //student 1
array
[0] => 'Joe' //First
[1] => 'Smith' //Last
[2] => '101 Main St' //Street
[3] => 'Boston' //City
[4] => 'MA' //State
[5] => '01234' //Zip
[6] => '2000-01-01' //Date of Birth
[7] => 'Male' //Gender
[8] => '12' //Grade
1 => //Student 2
array
[0] => 'Jane'
[1] => 'Smith'
[2] => '99 Main St'
[3] => 'Boston'
[4] => 'MA'
[5] => '01234'
[6] => '2000-02-02'
[7] => 'Female'
[8] => '10'
UPDATE: For those that are interested, here is my final function after I fixed the errors:
<? function addToDatabase ($dataArray) {
//Connnect to Database
$host = 'myHost';
$un = 'myUsername';
$pw = 'myPassword';
$db_name = 'myTable';
try {
$conn = new PDO("mysql:host=$host;dbname=$dbName", $un, $pw);
echo 'Connected to database<br>';
$sql = "INSERT INTO studentData (originallyAddedOn, inputMethod, studentFirst, studentLast, studentStreet, studentCity, studentState, studentZip, studentDOB, studentGender, studentGrade, schoolName, schoolStreet, schoolCity, schoolState, schoolZip, schoolContactName, schoolContactTitle, schoolContactEmail, schoolContactPhone) VALUES (:originallyAddedOn, :inputMethod, :studentFirst, :studentLast, :studentStreet, :studentCity, :studentState, :studentZip, :studentDOB, :studentGender, :studentGrade, :schoolName, :schoolStreet, :schoolCity, :schoolState, :schoolZip, :schoolContactName, :schoolContactTitle, :schoolContactEmail, :schoolContactPhone)";
$q = $conn->prepare($sql);
foreach ($dataArray as $student){
$a = array (':originallyAddedOn'=>$student['timestamp'],
':inputMethod'=>$student['inputMethod'],
':studentFirst'=>$student['studentFirst'],
':studentLast'=>$student['studentLast'],
':studentStreet'=>$student['studentStreet'],
':studentCity'=>$student['studentCity'],
':studentState'=>$student['studentState'],
':studentZip'=>$student['studentZip'],
':studentDOB'=>$student['studentDOB'],
':studentGender'=>$student['studentGender'],
':studentGrade'=>$student['studentGrade'],
':schoolName'=>$student['schoolName'],
':schoolStreet'=>$student['schoolStreet'],
':schoolCity'=>$student['schoolCity'],
':schoolState'=>$student['schoolState'],
':schoolZip'=>$student['schoolZip'],
':schoolContactName'=>$student['schoolContactName'],
':schoolContactTitle'=>$student['schoolContactTitle'],
':schoolContactEmail'=>$student['schoolContactEmail'],
':schoolContactPhone'=>$student['schoolContactPhone']);
if ($q->execute($a)) {
// Query succeeded.
} else {
// Query failed.
echo $q->errorCode();
}
// close the database connection
$dbh = null;
echo "Insert Complete!";
}
}
catch(PDOException $e) {
echo $e->getMessage();
}
}
You dont need to bind your variables. Ive done this before with similar code. Its hard to say whats going wrong though. Do you get an exception - if so what is it?
The only thing i see wrong is you have your preparation inside the loop... should be more like:
try {
$conn = new PDO("mysql:host=$host;dbname=$dbName", $un, $pw);
echo 'Connected to database<br>';
$sql = "INSERT INTO studentData (originallyAddedOn, inputMethod, studentFirst, studentLast, studentStreet, studentCity, studentState, studentZip, studentDOB, studentGender, studentGrade, schoolName, schoolStreet, schoolCity, schoolState, schoolZip, schoolContactName, schoolContactTitle, schoolContactEmail, schoolContactPhone) VALUES (:originallyAddedOn, :inputMethod, :studentFirst, :studentLast, :studentStreet, :studentCity, :studentState, :studentZip, :studentDOB, :studentGender, :studentGrade, :schoolName, :schoolStreet, :schoolCity, :schoolState, :schoolZip, :schoolContactName, :schoolContactTitle, :schoolContactEmail, :schoolContactPhone)";
// prepare once... exceute many :-)
$q = $conn->prepare($sql);
foreach($studentDataArray as $student) {
$q->execute($yourDataArray);
// do other stuff if needed
}
} catch(PDOException $e) {
echo $e->getMessage();
}
For loops, do this (PDO or other database client libraries that support prepared statements):
prepare the SQL INSERT query.
bind the variables.
loop your array against the bind variables, execute once per iteration.
Profit.
For a PDO based example on an array with data to insert into some table that requires a single column named option.
First some data to be inserted into the database:
$options = [
['option' => "Insert Option A " . uniqid()],
['option' => "Insert Option B " . uniqid()],
['option' => "Insert Option C " . uniqid()],
];
Somewhere else, let's assume to have that $options array and care about the database interaction. This needs a connection:
$conn = new PDO('mysql:dbname=test;host=localhost', 'testuser', 'test');
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE);
Now let's prepare the insert query. Using named parameters here like in the question, sure this works with numbered parameters, too:
$stmt = $conn->prepare('INSERT INTO config (`OPTION`) VALUES (:OPTION);');
Now let's bind the named parameter to a variable here. Take note, that the variable is prefixed (here with insert). This is actually the aliasing to the option key in the input array:
$stmt->bindParam(':OPTION', $insert_option);
So now from the numbered list above, the points 1.) prepare the SQL INSERT query. and 2.) bind the variables. has been done.
Only left is the loop over the $options array to insert the values:
foreach ($options as $insert) {
extract($insert, EXTR_PREFIX_ALL, 'insert');
$stmt->execute();
}
Making use of extract allows to set multiple variables at once based on the input array in an aliased fashion without much ado.
The full example:
$options = [
['option' => "Insert Option A " . uniqid()],
['option' => "Insert Option B " . uniqid()],
['option' => "Insert Option C " . uniqid()],
];
$conn = new PDO('mysql:dbname=test;host=localhost', 'testuser', 'test');
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE);
# 1. Prepare
$stmt = $conn->prepare('INSERT INTO config (`OPTION`) VALUES (:OPTION);');
# 2. Bind
$stmt->bindParam(':OPTION', $insert_option);
# 3. Loop & Execute
foreach ($options as $insert) {
extract($insert, EXTR_PREFIX_ALL, 'insert');
$stmt->execute();
}

Categories