I am trying to assemble a database insert with PDO through an array but am just missing it somewhere and am looking for some help on what I'm missing. The array is an associative array. Error thrown is:
Fatal error: Uncaught exception \'PDOException\' with message \'SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens\' in /var/www/html/themonastery.org/mot/receiver.php:70
Stack trace:
#0 /var/www/html/themonastery.org/mot/receiver.php(70): PDOStatement->execute()
#1 {main}
thrown in /var/www/html/themonastery.org/mot/receiver.php on line 70
Code I'm using is:
/** PDO Stuff **/
//require and instantiate pdo instance
require_once "dependancies/pdo.func.php";
$dbh = pdo_connect();
//implode query
$keys = implode(',', array_keys($clean));
$vals = implode(',', array_fill(0, count($clean), '?'));
$insert = array_values($clean);
//pdo prepare
$sth = $dbh->prepare("INSERT INTO backupDB ($keys) VALUES ($vals)");
//set loop condition
$waiting = true;
while($waiting) {
try {
$dbh->beginTransaction();
$i=1;
foreach($clean as $insert) {
// bindvalue is 1-indexed, so $k+1
$sth->bindValue($i++, $insert, PDO::PARAM_STR);
$sth->execute();
sleep(1);
}
$dbh->commit();
$waiting = false;
} catch(PDOException $e) {
if(stripos($e->getMessage(), 'DATABASE IS LOCKED') !== false) {
//sleep for 0.25 seconds and try again.
$dbh->commit();
usleep(250000);
} else {
$dbh->rollBack();
throw $e;
}
}
}
Here's the associative array,
array (
'full_name' => 'First Middle Last Suffix',
'first_name' => 'First',
'middle_name' => 'Middle',
'last_name' => 'Last Suffix',
'address' => 'The Address',
'city' => 'City',
'state' => 'State Abbr',
'zip' => 'Zip code',
'country' => 'Country Abbr',
'email' => 'dev#null.com',
'password' => 'd41d8cd98f00b204e9800998ecf8427e',
'ordinationDate' => '2012-04-15',
'birthday' => '1982-14-01',
'isValidAge' => '1',
)
And by request here's a var_dump of $keys and $vals
$keys = string(123) "full_name,first_name,middle_name,last_name,address,city,state,zip,country,email,password,ordinationDate,birthday,isValidAge"
$vals = string(27) "?,?,?,?,?,?,?,?,?,?,?,?,?,?"
Here's the column names from the DB
id full_name first_name middle_name last_name address city state zip country email password ordinationDate birthday isValidAge sex timestamp ulc_edit_time osc_sync guid
Change this:
$i=1;
foreach($clean as $insert) {
// bindvalue is 1-indexed, so $k+1
$sth->bindValue($i++, $insert, PDO::PARAM_STR);
$sth->execute();
sleep(1);
}
to this:
$i=1;
foreach($clean as $insert) {
// bindvalue is 1-indexed, so $k+1
$sth->bindValue($i++, $insert, PDO::PARAM_STR);
sleep(1);
}
$sth->execute();
PDO::execute() need to be at the end of all bindValues() (see http://php.net/manual/en/pdostatement.execute.php#example-995)
Additionaly, I have the follow function to bind correct data type (need some changes for your case):
public function bindValue($key = null, $value = null) {
if($key == null) {
return;
}
if(is_int($value)) {
$param = PDO::PARAM_INT;
} elseif(is_bool($value)) {
$param = PDO::PARAM_BOOL;
} elseif(is_null($value)) {
$param = PDO::PARAM_NULL;
} elseif(is_string($value)) {
$param = PDO::PARAM_STR;
} else {
$param = FALSE;
}
$this->_query->bindValue($key, $value, $param);
}
Related
I have these following functions.
public function importExcelFile(){
$file = $_FILES['file']['tmp_name'];
$data = extract_excel_data($file);
$i = 0;
foreach($data['values'] as $dataValues) {
$categories = [];
$brands = [];
$models = [];
foreach($dataValues as $value){
if(array_filter($value)) {
/* If a row does not contain brand/category/model for the product then fetch the resp. info. from previous row */
if(empty(trim($value[0]))) {
$categories[] = $prev_cat;
} else {
$categories[] = strtoupper(trim($value[0]));
$prev_cat = strtoupper(trim($value[0]));
}
if(empty(trim($value[1]))) {
$brands[] = $prev_brand;
} else {
$brands[] = strtoupper(trim($value[1]));
$prev_brand = strtoupper(trim($value[1]));
}
if(empty(trim($value[2]))) {
$models[] = $prev_model;
} else {
$models[] = $value[2];
$prev_model = $value[2];
}
}
}
//insert device category
$this->insert_setups('category', $categories);
//insert brand
$this->insert_setups('brand', $brands);
// Check if branch already exists in the database
$check_branch = $this->global_model->getDetailByWhere('branch', array('name'=>$data['branch'][$i].' branch'))->result();
$branch_arr = [];
//insert branch
if(empty($check_branch)) {
$branch_arr = array(
'name' => $data['branch'][$i].' branch',
'location' => $data['branch'][$i],
'status' => 1,
'created_by' => $this->session->userdata('id'),
'created_on' => date('Y-m-d')
);
$this->global_model->insertData('branch', $branch_arr);
}
$branch_id = $this->global_model->getDetailByWhere('branch', array('name'=>$data['branch'][$i].' branch'))->row()->id;
$db_device_categories = [];
$db_brands = [];
// get categoris, brands
$db_device_categories = $this->arrangeArray('category', $where =array());
$db_brands = $this->arrangeArray('brand', $where =array());
//detail_print($db_brands);
// insert new models from database
foreach(array_unique($models) as $model_key=>$model){
$check_model = $this->global_model->getDetailByWhere('model', array('name'=>$model))->result();
$insert = [];
if(empty($check_model)){
$insert = array(
'name' => $model,
'item_type' => 1,
'category_id' => $db_device_categories[$categories[$model_key]],
'brand_id' => $db_brands[$brands[$model_key]],
'created_by' => $this->session->userdata("id"),
'created_on' => date('Y-m-d'),
);
$this->global_model->insertData('model', $insert);
}
}
$db_device_models = [];
// get models from database
$db_device_models = $this->arrangeArray('model', $where = array('item_type'=>1));
$categoriy_id = [];
$brand_id = [];
$model_id = [];
$opening_stock = [];
// arrange the exported array with respective id
foreach($dataValues as $values){
if(array_filter($values)) {
if(empty(trim($values[0]))) {
$category_id = $prev_cat;
} else {
$category_id = strtoupper(trim($values[0]));
$prev_cat = strtoupper(trim($values[0]));
}
if(empty(trim($values[1]))) {
$brand_id = $prev_brand;
} else {
$brand_id = strtoupper(trim($values[1]));
$prev_brand = strtoupper(trim($values[1]));
}
if(empty(trim($values[2]))) {
$model_id = $prev_model;
} else {
$model_id = $values[2];
$prev_model = $values[2];
}
$opening_stock[] = array(
'category_id' => $db_device_categories[$category_id],
'brand_id' => $db_brands[$brand_id],
'model_id' => $db_device_models[$model_id],
'imei' => (string)$values[3],
'cost_price' => isset($values[5]) ? $values[5] : 0,
'selling_price' => isset($values[6]) ? $values[6] : 0
);
}
}
$group_by_model = [];
// group the array by model_id
foreach(array_unique($models) as $model1){
$where = $db_device_models[$model1];
$group_by_model[] = array_filter($opening_stock, function($elements) use ($where){
return $elements["model_id"] == $where;
});
}
if(!$this->purchase_model->insertOpeningStock($group_by_model, $branch_id)){
$this->session->set_flashdata('error', 'Opening stock of devices insertion failed.');
redirect('purchase/uploadExcelFile');
}
$i++;
}
$this->session->set_flashdata('success', 'Opening stock of devices added successfully.');
redirect('purchase/uploadExcelFile');
}
private function arrangeArray($table, $where){
$list = $this->global_model->getDetailByWhere($table, $where)->result_array();
foreach($list as $item){
$name = $item['name'];
$arranged_list[$name] = $item['id'];
}
return !empty($arranged_list) ? $arranged_list : NULL;
}
private function insert_setups($table_name, $setups){
foreach(array_unique($setups) as $value){
$check_setup = $this->global_model->getDetailByWhere($table_name, array('name'=>$value))->result();
if(empty($check_setup)){
$insert = array(
'name' => $value,
'created_by' => $this->session->userdata("id"),
'created_on' => date('Y-m-d'),
);
$this->global_model->insertData($table_name, $insert);
}
}
}
What this function does is, it extracts data from the uploaded excel file and inserts the data to various tables accordingly. Now as you can see, there are multiple queries running in different locations inside the importExcelFile() method. So my question is, how do I use codeigniter transaction in such a way that all the queries inside this function are performed atomically. If any one query fails, all other query's work is rolled back. Also, is this code considered clean ?
P.S. I'm so sorry if my last question was inappropriate here.
this might be helpful to you.
transactions in codeigniter
$this->db->trans_begin();
$this->db->query('AN SQL QUERY...');
$this->db->query('ANOTHER QUERY...');
$this->db->query('AND YET ANOTHER QUERY...');
if ($this->db->trans_status() === FALSE)
{
$this->db->trans_rollback();
}
else
{
$this->db->trans_commit();
}
I have a sql UPDATE query in PDO that should update a name and a permissions string.
But instead it just places the id of that row inside all columns.
Here is my code:
public function saveRole($roleID, $name, $permissions)
{
$sql = "UPDATE roles SET name = :name, permissions = :permissions WHERE id = :id";
//this one sets a string variable in the PDO wrapper class
PDO::setSQL($sql);
//this one sets an array inside the PDO wrapper class
PDO::setData([
'name' => $name,
'permissions' => $permissions,
'id' => $roleID,
]);
PDO::execute();
return PDO::getResponse(true);
}
As you see, I've written a wrapper for PDO, which looks like this:
static function execute($sql = null, $data = null, $fetchmode = \PDO::FETCH_OBJ)
{
//check if data and SQL are set in function call, if so, use function call params, if not use class params ($this->SQL & $this->data)
self::connect();
try
{
$stmnt = self::$con->prepare(self::$sql);
$stmnt->setFetchMode($fetchmode);
if (sizeof(self::$data) > 0)
{
foreach (self::$data as $key => $value)
{
$stmnt->bindParam(':' . $key, $value);
}
}
$stmnt->execute();
self::$stmnt = $stmnt;
self::$data = [];
self::$sql = '';
self::$lastResponse = new pdoReturn(true, $stmnt);
return;
} catch (\PDOException $exception)
{
self::$data = [];
self::$sql = '';
self::$lastResponse = new pdoReturn(false, $exception);
return;
}
}
function setSQL($sql) {
if (!is_string($sql))
return false;
if (strlen($sql) == 0)
return false;
$this->sql = $sql;
return true;
}
function setData($data) {
if (!is_array($data))
return false;
$this->data = $data;
return true;
}
As you see, I've written a wrapper for PDO
For the immediate fix, change
$stmnt = self::$con->prepare(self::$sql);
$stmnt->setFetchMode($fetchmode);
if (sizeof(self::$data) > 0)
{
foreach (self::$data as $key => $value)
{
$stmnt->bindParam(':' . $key, $value);
}
}
$stmnt->execute();
to
$stmnt = self::$con->prepare(self::$sql);
$stmnt->setFetchMode($fetchmode);
$stmnt->execute(self::$data);
Then read about your first database wrapper's childhood diseases and fix other issues such as statefulness and error reporting.
I never thought i would trip up on such an easy task, what i'm doing is getting rows from MySQL, and showing them on a form, the user can then update the values if needed:
<?php
include('includes/db_connection.php');
include('includes/sessions.php');
include('includes/functions.php');
include('includes/header.php');
include('includes/navbar-logged.php');
// AUTHENTICATION //
$row = DB::getInstance()->selectOneByField('membership', 'member_username', $member);
if ($row['member_user_class'] != 'Site Administrator') {
stderr("Sorry, <b>no authorization</b> to access this page.");
}
// AUTHENTICATION //
// CLOUD KEYS //
if (isset($_POST['submitCloudKeys']))
{
// TRY/CATCH //
try {
foreach ($_POST['cloudId'] as $val) {
DB::getInstance()->update(
'clouds',
'cloud_id',
$val,
[
'cloud_key' => $_POST['cloud_key'][$val]
]);
stdmsg('Cloud keys \'<b>'.$_POST['cloud_key'][$val].'</b>\' have been <b>updated</b>.');
}
} catch (Exception $e) {
stderr($e);
}
}
$rows = DB::getInstance()->select('SELECT * FROM `clouds`');
?>
<div class="panel panel-primary">
<div class="panel-heading">Current cloud hosts.</div>
<div class="panel-body">
<form action="clouds.php" method="post" class="form-horizontal container-fluid" role="form">
<?php $x = 0; ?>
<?php $z = 0; ?>
<?php foreach ($rows as $row) { ?>
<div class="row form-group">
<div class="col-sm-4 text-right"><label for="txtNetwork" class="control-label"><?php echo htmlspecialchars($row['cloud_name']) ?>:</div>
<div class="col-sm-8">
<input type="text" name="cloud_key[]" value="<?php echo htmlspecialchars($row['cloud_key']) ?>" size="30" class="form-control" />
<input type="hidden" name="cloudId[]" value="<?php echo $row['cloud_id']; ?>" />
</div>
</div>
<?php } ?>
<div class="row form-group">
<div class="col-sm-12 text-right">
<button type="submit" name="submitCloudKeys" class="btn btn-default">Update</button>
</div>
</div>
</form>
</div>
<div class="panel-footer">Update the <b>cloud hosts</b> keys.</div>
</div>
<?php
include('includes/footer.php');
I'm getting an error:
PDOException: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'b447297ddb6be7377......................' in 'field list' in /home/admin/web/wraithpbns.com/public_html/includes/DB.php:268
Stack trace: #0 /home/admin/web/wraithpbns.com/public_html/includes/DB.php(268): PDOStatement->execute()
#1 /home/admin/web/wraithpbns.com/public_html/clouds.php(26): DB->update('clouds', 'cloud_id', '1', Array)
#2 {main}
The table names in MySQL are all correct, i don't see why i'm not able to update the form values, the "Unknown column" part is showing me the key value i'm trying to update, i have never had this issue before, any help would be appreciated guys!
UPDATED METHODS:
<?php
class DB
{
private static $instance;
public static function getInstance() {
if(is_null(self::$instance)) {
self::$instance = new DB();
}
return self::$instance;
}
public static function map(array $rows = array(), $keyColumn, $valueColumn = null) {
$result = array();
foreach($rows as $row) {
if(is_null($valueColumn)) {
$result[$row[$keyColumn]] = $row;
} else {
$result[$row[$keyColumn]] = $row[$valueColumn];
}
}
return $result;
}
private $pdo;
private function __construct() {
try {
$this->pdo = new PDO(
sprintf('%s:host=%s;dbname=%s',
DRIVER,
HOST,
DATA
),
USER,
PASS,
array(
PDO::ATTR_PERSISTENT => true,
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8; SET CHARACTER SET utf8;'
)
);
} catch(Exception $ex) {
throw new Exception('Cannot connect to database.');
}
}
public function execute($query, array $params = []) {
$normParams = $this->normalizeParams($params);
$command = $this->pdo->prepare($query);
$command->closeCursor();
$status = $command->execute($normParams);
if(!$status) {
throw new Exception('DB::execute(): Can\'t execute query:');
}
return $status;
}
public function select($query, array $params = [], $fetchType = PDO::FETCH_ASSOC) {
$normParams = $this->normalizeParams($params);
$command = $this->pdo->prepare($query);
$command->closeCursor();
foreach($normParams as $paramName => $paramValue) {
if(is_array($paramValue)
&& isset($paramValue['type'])
&& isset($paramValue['value'])) {
$command->bindValue($paramName, $paramValue['value'], $paramValue['type']);
} else {
$command->bindValue($paramName, $paramValue);
}
}
if(!$command->execute()) {
throw new Exception('DB::select(): Can\'t execute query.');
}
return $command->fetchAll($fetchType);
}
public function selectValues($query, array $params = [], $fetchType = PDO::FETCH_ASSOC) {
$row = $this->selectOne($query, $params, $fetchType);
if(empty($row)) {
throw new Exception('DB::selectValues(): No values selected.');
} else {
return $row;
}
}
public function selectValue($query, array $params = []) {
$values = $this->selectValues($query, $params, PDO::FETCH_NUM);
return $values[0];
}
public function selectAll($tableName, $fetchType = PDO::FETCH_ASSOC) {
return $this->select(
sprintf('
SELECT *
FROM `%s`',
$tableName
),
[],
$fetchType
);
}
public function selectByField($tableName, $fieldName, $value, $fetchType = PDO::FETCH_ASSOC) {
return $this->select(
sprintf('
SELECT *
FROM `%s`
WHERE `%s` = :value',
$tableName,
$fieldName
),
[
':value' => $value
],
$fetchType
);
}
public function selectOne($query, array $params = [], $fetchType = PDO::FETCH_ASSOC) {
$rows = $this->select($query, $params, $fetchType);
return array_shift($rows);
}
public function selectOneByField($tableName, $fieldName, $value, $fetchType = PDO::FETCH_ASSOC) {
$rows = $this->selectByField($tableName, $fieldName, $value, $fetchType);
return array_shift($rows);
}
public function get($tableName, $fieldName, $value, $fetchType = PDO::FETCH_ASSOC) {
return $this->selectOneByField($tableName, $fieldName, $value, $fetchType);
}
public function insert($tableName, array $fields) {
$normParams = $this->normalizeParams($fields);
$paramNames = implode(', ', array_keys($normParams));
$fieldNames = '`' . implode('`, `', array_keys($fields)) . '`';
$command = $this->pdo->prepare(
sprintf('
INSERT INTO `%s` (%s)
VALUES (%s)',
$tableName,
$fieldNames,
$paramNames
)
);
$command->closeCursor();
if(!$command->execute($normParams)) {
throw new Exception('DB::insert(): Can\'t execute query.');
}
return $this->pdo->lastInsertId();
}
public function bulkInsert($tableName, array $rows = []) {
if(empty($rows)) {
return;
}
$fieldNames = array_keys($this->normalizeParams($rows[0]));
$normParams = [];
$paramNames = '';
$counter = 0;
foreach($rows as $row) {
$paramNames .= ((0 < $counter)? ',': '') . '(';
$nextParamNames = [];
foreach($row as $paramKey => $paramValue) {
$nextParamNames[] = ':' . $paramKey . $counter;
$normParams[':' . $paramKey . $counter] = $paramValue;
}
$paramNames .= implode(',', $nextParamNames);
$paramNames .= ')';
$counter++;
}
$command = $this->pdo->prepare(
sprintf('
INSERT INTO `%s` %s
VALUES %s',
$tableName,
$fieldNames,
$paramNames
)
);
$command->closeCursor();
if(!$command->execute($normParams)) {
throw new Exception('DB::bulkInsert(): Can\'t execute query.');
}
}
public function update($tableName, $fieldName, $fieldValue, array $updateFields, $updateAll = false) {
if(is_null($fieldName)) {
if(!$updateAll) {
throw new SystemException('Attempt to update all table records without confirmation.');
}
$sqlWhere = '';
} else {
$sqlWhere = sprintf('WHERE `%s` = %s', $fieldName, $fieldValue);
}
// echo $sqlWhere;
//
// exit;
$normUpdateFields = $this->normalizeParams($updateFields);
$sqlSetRows = [];
foreach($updateFields as $updateFieldName => $updateFieldValue) {
$sqlSetRows[] = sprintf('`%s` = %s', $updateFieldName, $updateFieldValue);
}
$sqlSet = implode(', ', $sqlSetRows);
$command = $this->pdo->prepare(
$sql = sprintf('
UPDATE `%s`
SET %s
%s',
$tableName,
$sqlSet,
$sqlWhere
)
);
$command->closeCursor();
foreach($normUpdateFields as $updateFieldName => $updateFieldValue) {
if(is_array($updateFieldValue)
&& isset($updateFieldValue['type'])
&& isset($updateFieldValue['value'])) {
$command->bindValue($updateFieldName, $updateFieldValue['value'], $updateFieldValue['type']);
} else {
$command->bindValue($updateFieldName, $updateFieldValue);
}
}
if(!empty($sqlWhere)) {
$command->bindValue(':' . $fieldName, $fieldValue);
}
if(!$command->execute()) {
throw new Exception('DB::update(): Can\'t execute query.');
}
}
public function remove($tableName, $fieldName = null, $value = null, $removeAll = false) {
$isExecuted = false;
if(is_null($fieldName)
&& is_null($value)
&& $removeAll) {
$isExecuted = $this->execute(sprintf('DELETE FROM `%s`', $tableName));
} else if(!is_null($fieldName)
&& !is_null($value)) {
$isExecuted = $this->execute(
sprintf('
DELETE FROM `%s`
WHERE `%s` = :value',
$tableName,
$fieldName
),
[
':value' => $value
]
);
}
if(!$isExecuted) {
throw new Exception('DB::remove(): Can\'t execute query.');
}
}
protected function normalizeParams(array $params = []) {
$normParams = [];
foreach($params as $paramKey => $paramValue) {
$normParams[(strlen($paramKey) && (':' === $paramKey{0}))? $paramKey: ':' . $paramKey] = $paramValue;
}
return $normParams;
}
/**
* Replaces any parameter placeholders in a query with the value of that
* parameter. Useful for debugging. Assumes anonymous parameters from
* $params are are in the same order as specified in $query
*
* #param string $query The sql query with parameter placeholders
* #param array $params The array of substitution parameters
* #return string The interpolated query
*/
public function interpolateQuery($query, $params) {
$keys = array();
# build a regular expression for each parameter
foreach ($params as $key => $value) {
if (is_string($key)) {
$keys[] = '/:'.$key.'/';
} else {
$keys[] = '/[?]/';
}
}
$query = preg_replace($keys, $params, $query, 1, $count);
#trigger_error('replaced '.$count.' keys');
return $query;
}
}
You have an logic issue within your update method ,
first , you are assigning a value then you are trying to bind a value,
$sqlWhere = sprintf('WHERE `%s` = %s', $fieldName, $fieldValue);
// ^^ ^^^^^^^^^^^^
and the same for your set clause :
$sqlSetRows[] = sprintf('`%s` = %s', $updateFieldName, $updateFieldValue);
// ^^ ^^^^^^^^^^^^^^^^^^
then as I told, you are trying to bind those values again using bindValue whether in your where clause :
$command->bindValue(':' . $fieldName, $fieldValue);
or in your this loop :
foreach($normUpdateFields as $updateFieldName => $updateFieldValue) {
....
$command->bindValue($updateFieldName, $updateFieldValue);
to solve you have two ways :
1 ) fix this by passing the write keys as follows :
$sqlWhere = sprintf('WHERE `%s` = :%s', $fieldName, $fieldName);
and for your set clause :
$sqlSetRows[] = sprintf('`%s` = :%s', $updateFieldName, $updateFieldName);
2 ) directly inject those values and leave your bindValue method which is not preferable:
$sqlSetRows[] = sprintf('`%s`="%s"', $updateFieldName, $updateFieldValue);
and $sqlWhere = sprintf('WHERE%s="%s"', $fieldName, $fieldValue);
I have an issue with my INSERT query, $pdo->execute return false, with error code 00000
Query
string 'INSERT INTO module_test (img_name, description, priority) VALUES(:img_name, :description, :priority)' (length=100)
errorInfo() return:
array (size=3)
0 => string '00000' (length=5)
1 => null
2 => null
Code:
private function Init($query, $parameters = "")
{
# Connect to database
if (!$this->bConnected) {
$this->Connect();
}
try {
# Prepare query
$this->sQuery = $this->pdo->prepare($query);
# Add parameters to the parameter array
$this->bindMore($parameters);
# Bind parameters
if (!empty($this->parameters)) {
foreach ($this->parameters as $param => $value) {
$type = PDO::PARAM_STR;
switch ($value[1]) {
case is_int($value[1]):
$type = PDO::PARAM_INT;
break;
case is_bool($value[1]):
$type = PDO::PARAM_BOOL;
break;
case is_null($value[1]):
$type = PDO::PARAM_NULL;
break;
}
// Add type when binding the values to the column
$this->sQuery->bindValue($value[0], $value[1], $type);
}
}
# Execute SQL
var_dump($query);
var_dump($this->sQuery->execute());
var_dump($this->sQuery->errorInfo());
}
catch (PDOException $e) {
# Write into log and display Exception
echo $this->ExceptionLog($e->getMessage(), $query);
die();
}
# Reset the parameters
$this->parameters = array();
}
public function query($query, $params = null, $fetchmode = PDO::FETCH_ASSOC)
{
$query = trim(str_replace("\r", " ", $query));
$this->Init($query, $params);
$rawStatement = explode(" ", preg_replace("/\s+|\t+|\n+/", " ", $query));
# Which SQL statement is used
$statement = strtolower($rawStatement[0]);
if ($statement === 'select' || $statement === 'show') {
return $this->sQuery->fetchAll($fetchmode);
} elseif ($statement === 'insert' || $statement === 'update' || $statement === 'delete') {
return $this->sQuery->rowCount();
} else {
return NULL;
}
}
public function insert($table, $keyValue)
{
$fieldString = '';
$valueString = '';
$i = 1;
foreach ($keyValue as $key => $currKeyValue)
{
$fieldString .= $key;
$valueString .= ':'.$key;
if($i != count($keyValue))
{
$fieldString .= ', ';
$valueString .= ', ';
}
$i++;
}
$query = 'INSERT INTO '.$table.' ('.$fieldString.') VALUES('.$valueString.')';
$this->query($query, $keyValue);
}
Parameters array
F:\Dev\wamp\wamp64\www\include\class\Database.class.php:216:
array (size=3)
'img_name' => string 'ttt1' (length=4)
'description' => string 'ttt1' (length=4)
'priority' => int 0
I already try this query in phpmyadmin and everything worked well.
If someone know how to solve this?
thanks
PS: sorry for my bad english
PDO is reported not to fill the errorInfo property in certain circumstances.
Instead, you have to make it throw an exception, which is the most reliable way to get the error message. To do so, in your constructor, add this line
$this->pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
Also note that your class is a genuine example of all the mistakes one could make writing a PDO wrapper. I compiled the most popular mistakes in an article, Your first database wrapper's childhood diseases and your class contains every single one of them.
I wrote an global function that getting array with keys and values, and inserting it to mysql db. something like this:
function insert_to_db($table, $data, $is_using_id) {
// I'm connecting to db before this code.
global $mysqli;
// .. Checking for errors ..
// .. if using id, remove the id from the values like this:
$columns = array_keys($data);
$values = array_values($data);
if ($is_using_id == true) {
unset($values[0]);
// Reorder the array after unset()
$values = array_merge($values);
}
// ..
// Generating text for use at the mysqli::prepare
$columns_text = "";
$i = 0;
while ($i < count($columns)) {
$column = $columns[$i];
if ($i == 0) {
$columns_text = $column;
} else {
$columns_text = $columns_text.", ".$column;
}
$i++;
}
unset($i);
unset($column);
$values_text = "";
// b_p_f is the $types string for mysqli-stmt::bind_param
$b_p_f = "";
// Generating text for use at the mysqli::prepare
$i = -1;
while ($i < count($values)) {
echo "\$i equals to {$i}<br>";
if ($is_using_id == true && $i == -1) {
// Null because id is calculated automatically by mysql
$values_text = "NULL";
} else if ($is_using_id == false && $i == 0) {
$value = $values[$i];
$values_text = "?";
if (is_numeric($value))
{
$b_p_f = 'i';
} else {
$b_p_f = 's';
}
} else {
$value = $values[$i];
$values_text = $values_text.", ?";
if (is_numeric($value))
{
echo "Value: {$value} Found as numberic<br>";
$b_p_f = $b_p_f.'i';
} else {
echo "Value: {$value} Found as non-numberic<br>";
$b_p_f = $b_p_f.'s';
}
}
$i++;
}
unset($i);
unset($value);
echo "b_p_f:";
var_dump($b_p_f);
echo " values:";
var_dump($values);
$stmt = $mysqli->prepare("INSERT INTO ".$table." (".$columns_text.") VALUES (".$values_text.")");
if (!$stmt) {
return array("error"=>"true", "error_mysqli"=>$mysqli->error, "MORE"=>"INSERT INTO ".$table." (".$columns_text.") VALUES (".$values_text.")");
}
$stmt->bind_param($b_p_f, $values);
if ($stmt->execute()) {
return array("error"=>"false", "inserted_id"=>$mysqli->insert_id);
} else {
return array("error"=>"true", "error_stmt"=>$stmt->error, "MORE"=>"INSERT INTO ".$table." (".$columns_text.") VALUES (".$values_text.")");
}
}
Then I am calling to the function:
function hash_password($password) {
$options = [ 'cost' => 12 ];
return password_hash($password, PASSWORD_BCRYPT,$options);
}
$data = array(
"ID" => NULL,
"first_name" => "Alexander",
"last_name" => "Margolis",
"email" => "shay24590#gmail.com",
"username" => "smartDonkey",
"password" => "Incorrect",
"birthday" => "12-12",
"date_added" => time(),
"total_points" => 0,
"cafe_added" => 0,
"review_placed"=> 0);
$data["password"] = hash_password($data["password"]);
var_dump ( insert_to_db("user", $data, true) );
And I see on the screen
array(3) {
["error"]=> string(4) "true"
["error_stmt"]=> string(53) "No data supplied for parameters in prepared statement" ["MORE"]=> string(178) "..."
}
Why am I getting this? What is the problem?
Also, If I pass the value instead of ? to the mysql::prepare, it works! So - it means that the problem is with mysqli stmt bind_param..
I know that this question similar to others, but I didn't found one that helps my problem. and sorry for my english and for the long function. thank you!
I've moved to PDO, and instead of calling $stmt->bind_param($b_p_f, $values); you can call $pdo_stmt->execute($values) where $values is an Array.