I've already got username, password and other variables stored, but I keep getting an error "Invalid parameter number: number of bound variables does not match number of tokens" in this line:
$database->query(
'INSERT INTO users_inactive(verCode, username, password, email, date, type)
VALUES (:vercode, :username, :password, :email, :date, :type)',
array(
':vercode' => $verCode,
':username' => $username,
':password' => $password,
':email' => $email,
':date' => $date,
':type'=>'customer')
);
Is there anything wrong with it? I've made sure each of these columns is available in my user_inactive table.
This is the $database wrapper function:
public function query($query, $bind = null, $fetch = 'FETCH_ASSOC') {
/* Prepare the query statement */
$this->statement = $this->pdo->prepare($query);
/* Bind each value supplied from $bind */
if($bind != null) {
foreach($bind as $select => $value) {
/* For each type of value give the appropriate param */
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;
}
/* Bid value */
if($param) {
$this->statement->bindValue($select, $value, $param);
}
}
}
/* Execute Query & check for any errors */
if(!$this->statement->execute()){
$result = array(
1 => 'false',
2 => '<b>[DATABASE] Error - Query:</b> There was an error in sql syntax',
);
return $result;
}
/* Return all content */
if($fetch == 'FETCH_ASSOC') {
$result = $this->statement->fetch(PDO::FETCH_ASSOC);
} elseif($fetch == 'FETCH_BOTH') {
$result = $this->statement->fetch(PDO::FETCH_BOTH);
} elseif($fetch == 'FETCH_LAZY') {
$result = $this->statement->fetch(PDO::FETCH_LAZY);
} elseif($fetch == 'FETCH_OBJ') {
$result = $this->statement->fetch(PDO::FETCH_OBJ);
} elseif($fetch == 'fetchAll') {
$result = $this->statement->fetchAll();
}
return $result;
}
}
Taken from Tutis Login.
Just some clues,You are probably missing some colons. Check out here
PHP Mysql PDO number of bound variables does not match number of tokens
Or probably there is some case sensitive going on on your colons
The error seems to be in your wrapper function. PDO::PARAM_NULL == 0, so this value does not pass through
if($param) {
...
}
So you do not call bindValue() for NULL values. Instead, use:
if ($param !== FALSE) {
...
}
EDIT - reading again your code, this would be better code of the foreach() block, producing less cryptic error messages in the future :)
foreach($bind as $select => $value) {
/* For each type of value give the appropriate param */
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 {
// Report error about invalid type and return from the function
...
}
// we should bind every value from $bind array, unconditionally!
$this->statement->bindValue($select, $value, $param);
}
Give this a shot:
<?php
$sql = $database->prepare(
'INSERT INTO users_inactive(verCode, username, password, email, date, type)
VALUES (:vercode, :username, :password, :email, :date, :type)');
$sql->execute(array(
'vercode' => $verCode,
'username' => $username,
'password' => $password,
'email' => $email,
'date' => $date,
'type'=>'customer')
);
Related
For example, I have a couple of tables in my database, e.g., user, product, etc. Fro every table, I have at least an associated class with a couple of methods, such as addUser, updateUserName, updateUserPassword, etc. For every method, I need to prepare the SQL when using PDO, which looks like this:
$sql = "INSERT INTO `user`
(`id`,`username`,`password`,`log`)
VALUES
(:id, :username, :password, :log)";
Then I store the values in an array like this:
$array = array('id'=>$id, 'username'=>$username, 'password'=>$password, 'log'=>$log);
Then I use the PDO thing:
$pdo = new PDO($dsn, $user, $password);
$mysql = $pdo->prepare($sql);
$mysql->execute($array);
So it seems that for all different methods inside the User class, I need to do this "prepare" thing. Isn't it too tedious? Is there a more efficient way to do so, especially the part where I store the values in an array considering there exist a table with many columns in which case I would end up with a very long prepare sentence?
Since Your own is insert and update try these
//to query the database with prepared statements
public function query ($sql, $parameters = array()) {
//setting error to false to prevent interferance from previous failed queries
$this->_error = false;
//prepare SQL statement
if ($this->_query = $this->_pdo->prepare ($sql)) {
//checking to see whether any parameters were submitted along
if (count($parameters)) {
//setting the initial position for the binding values
$position = 1;
//getting the individual parameters and binding them with their respective fields
foreach ($parameters as $param) {
$this->_query->bindValue ($position, $param);
$position++;
}
}
}
//executing the sql
if ($this->_query->execute()) {
//getting the number of rows returned
$this->_count = $this->_query->rowCount();
//keeping the results returned
$this->_results = $this->_query->fetchAll (PDO::FETCH_OBJ);
} else {
$this->_error = true;
}
//returning all values of $this
return $this;
}
//to insert data into a prescribed table
public function insert ($table, $parameters = array()) {
//checking if the $fields are not empty
if (count($parameters)) {
//making the keys of the array fields
$fields = array_keys ($parameters);
//creating the to-bind-values in the form (?, ?, ...)
$values = '';
$x = 1;
foreach ($parameters as $field => $value) {
//$value is different from $values
$values .= '?';
if ($x < count($parameters)) {
$values .= ', ';
$x++;
}
}
//generating $sql
$sql = "INSERT INTO `{$table}` (`".implode ('`, `', $fields)."`) VALUES ({$values})";
//executing the sql
if (!$this->query($sql, $parameters)->error()) {
return true;
}
}
return false;
}
//to update data in a prescribed table
public function update ($table, $id = null, $parameters = array()) {
//checking that $parameters is not an empty array
if (count($parameters)) {
$set = '';
$x = 1;
foreach ($parameters as $field => $value) {
$set .= "`{$field}` = ?";
if ($x < count($parameters)) {
$set .= ', ';
$x++;
}
}
if ($id) {
//generating query
$sql = "UPDATE `{$table}` SET {$set} WHERE `id` = {$id}";
} else {
$sql = "UPDATE `{$table}` SET {$set} WHERE 1";
}
//executing the query
if (!$this->query($sql, $parameters)->error()) {
return true;
}
}
return false;
}
I'm attempting to write a parameterized query with PDO that accepts a number of inputs and acts as a search on a specific table.
There are a number of columns I wish to search on but each of which could be optional. The query simplified might look like:
SELECT * FROM item
WHERE name LIKE '%?%'
AND col2 IN (?, ?, .......)
AND col3 IN (?, ?, .......)
...
and with the IN clause, there could be any number (0 or more) of terms for each column.
Since the IN clause won't work with 0 values, and in PDO I'd have to iterate over each array passed in for each IN clause - I'm wondering if there's a better way to structure this as it seems like a big mess.
You can use "call_user_func_array" to make it dynamic. This is what I use:
public function selectMSData($handlename, $sql, $type='', $params = array())
{
if ( ! is_string($sql) || ! is_array($params) ) {
die('wrong param types');
}
$this->dbconnect($handlename); //connect to db and save connection with handle-name
$result = array();
$aRows = 0;
if(sizeof($params)==0) {
//simple query without runtime parameters
$msres = $this->dbhandle[$handlename]->query($sql);
if($msres === false) {
//log error
} else {
while($mres = $msres->fetch_array(MYSQLI_ASSOC)) {
$aRows++;
$result[] = $mres;
}
}
} else {
//prepared statement using runtime parameters
$stmt = $this->dbhandle[$handlename]->prepare($sql);
if(!$stmt) {
//log error
}
$valArr = array();
$valArr[] = $type;
foreach($params as $pkey => $pval) {
$valArr[] = &$params[$pkey];
}
call_user_func_array(array(&$stmt, 'bind_param'), $valArr);
if(!$stmt->execute()) {
//log error
};
$stmt->store_result(); //fetch is super-slow for text-fields if you don't buffer the result!!
$meta = $stmt->result_metadata();
while ($field = $meta->fetch_field()) {
$resfields[] = &$row[$field->name];
}
call_user_func_array(array($stmt, 'bind_result'), $resfields);
while ($stmt->fetch()) {
foreach($row as $key => $val) {
$c[$key] = $val;
}
$result[] = $c;
$aRows++;
}
$stmt->close();
}
$this->result = $result;
return $aRows;
}
and you call it like this:
$db->selectMSData('my_db_name', 'SELECT * FROM example WHERE a=? AND b=? LIMIT 1', 'ss', array($a, $b));
I am trying to establish a data connection to the MySql and create prepared statements, where the query_f function takes in any number of parameters, where the first parameter is the sql statement, and the other parameters are the values that would be substituted in the prepared statement.
Here is what I have. The first error I got is when I am trying to bind the values to the statement.
function query_f(/* query, [...] */){
$user = "root";
$pass = "root";
$host = "localhost";
$database = "mcnair";
$conn = mysqli_connect($host,$user,$pass);
if(!$conn)
{
echo "Cannot connect to Database";
}
else
{
mysqli_select_db($conn, $database);
}
// store query
$query = func_get_arg(0);
$parameters = array_slice(func_get_args(), 1);
$param = "'".implode("','",$parameters)."'";
// Prepare the statement
$stmt = mysqli_prepare($conn, $query);
if ($stmt == false)
{
echo "The statement could not be created";
exit;
}
// Bind the parameters
$bind = mysqli_stmt_bind_param($stmt, 's', $param);
echo mysqli_stmt_error($stmt);
if ($bind == false)
{
echo "Could not bind";
}
else
{
echo "Bind successful";
}
// Execute the statement
$execute = mysqli_stmt_execute($stmt);
if ($execute = false)
{
echo "Could not execute";
}
// fetch the data
$fetch = mysqli_stmt_fetch($stmt)
if ($fetch == false)
{
echo "Could not fetch data";
}
else
{
return $fetch;
}
}
And the function call I am using is:
query_f("SELECT Hash FROM alumni WHERE Username = '?'", "zm123");
How about using a class (instead of a function) and using mysqli in the OO way and not in the procedural way?
This is a simplified version of what I use. Not perfect, so if anyone would like to suggest improvements, I'm all ears.
class Connection {
private $connection;
public function __construct()
{
//better yet - move these to a different file
$dbhost = '';
$dbuname = '';
$dbpass = '';
$dbname = '';
$this->connection = new mysqli($dbhost, $dbuname, $dbpass, $dbname);
}
/*
* This is the main function.
*
* #param $arrayParams = array (0 => array('s' => 'Example string'), 1 => array('s' => 'Another string'), 2 => array('i' => 2), 3 => array('d' => 3.5) )
*/
public function executePrepared($sql, $arrayParams)
{
$statement = $this->prepareStatement($sql);
if ($statement) {
$this->bindParameter($statement, $arrayParams);
$this->executePreparedStatement($statement);
$result = $this->getArrayResultFromPreparedStatement($statement);
//only close if you are done with the statement
//$this->closePreparedStatement($statement);
} else {
$result = false;
}
return $result;
}
public function prepareStatement($sql)
{
$statement = $this->connection->prepare($sql) or $this->throwSqlError($this->connection->error);
return $statement;
}
public function bindParameter(&$statement, $arrayTypeValues)
{
$stringTypes = '';
$arrayParameters = array();
$arrayParameters[] = $stringTypes;
foreach ($arrayTypeValues as $currentTypeVale) {
foreach ($currentTypeVale as $type => $value) {
$stringTypes .= $type;
$arrayParameters[] = &$value;
}
}
$arrayParameters[0] = $stringTypes;
call_user_func_array(array($statement, "bind_param"), $arrayParameters);
}
public function getArrayResultFromPreparedStatement(&$statement)
{
$statement->store_result();
$variables = array();
$data = array();
$meta = $statement->result_metadata();
while($field = $meta->fetch_field())
$variables[] = &$data[$field->name]; // pass by reference
call_user_func_array(array($statement, 'bind_result'), $variables);
$i = 0;
$arrayResults = array();
while($statement->fetch())
{
$arrayResults[$i] = array();
foreach($data as $k=>$v)
{
$arrayResults[$i][$k] = $v;
}
$i++;
}
return $arrayResults;
}
public function executePreparedStatement($statement)
{
$result = $statement->execute() or $this->throwSqlError($statement->error);
return $result;
}
public function closePreparedStatement($statement)
{
$statement->close();
}
public function throwSqlError()
{ ... }
}
I've got a working insert for a single input field but when I try to add a couple more it seems to break everything. I have a database connection working fine and including that correctly at the top of the page when I change the "isset" to have the 3 columns it breaks.
This is my set statement;
if(isset($_POST['title, question, tags']))
{
$success = insertData('questions', 'title', $_POST['title']);
$success = insertData('questions', 'question', $_POST['question']);
$success = insertData('questions', 'tags', $_POST['tags']);
if(!$success)
echo 'Sorry failed :(';
}
The function I call from a functions php file;
function insertData($tablename, $columnName, $value)
{
$sql = 'INSERT into '.$tablename.'('.$columnName.') VALUES(:Value)';
$mysqlConnection = getConnection();
$statement = $mysqlConnection->prepare($sql);
$statement->bindValue(":Value", $value, PDO::PARAM_STR);
$bReturn = false;
try
{
$statement->execute();
$bReturn = true;
}
catch(PDOExecption $e)
{
echo $e->getMessage();
}
return $bReturn;
}
Does anyone know where I'm going wrong here?
if(isset($_POST['title, question, tags']))
Is not correct syntax
instead You can do:
if(isset($_POST['title']) && isset($_POST['question']) && isset($_POST['tags']))
or even
if(isset($_POST['title'], $_POST['question'], $_POST['tags']))
It would be easier to do execute it without binding:
insertData
function insertData($tablename, $params){
//build query string
$column_string = implode(',', array_keys($params));
$value_string = implode(',', array_fill(0, count($params), '?'));
$sql_string = "INSERT INTO {$tablename} ({$columnString}) VALUES ({$value_string})";
//prepare query
$mysqlConnection = getConnection();
$statement = $mysqlConnection->prepare($sql_string);
//execute query
$success = $statement->execute(array_values($params));
//return boolean success
return $success;
}
But If you really need to bind, you can do it the following way:
function insertDataBind($tablename, $params){
//build query string
$column_string = implode(',', array_keys($params));
$value_string = implode(',:', array_keys($params));
$sql_string = "INSERT INTO {$tablename} ({$column_string}) VALUES (:{$value_string})";
//prepare query
$mysqlConnection = getConnection();
$statement = $mysqlConnection->prepare($sql);
//bind
foreach($params as $key=>$value){
$statement->bindValue($key, $value);
}
//execute query
$success = $statement->execute();
//return boolean success
return $success;
}
usage:
if(isset($_POST['title'], $_POST['question'], $_POST['tags'])){
$params = array('title' => $_POST['title'],
'question'=>$_POST['question'],
'tags'=>$_POST['tags']
);
$success = insertData('questions', $params);
if(!$success)
echo 'Sorry failed :(';
}
I'm still learning PDO so I might of missed something but basically I'm trying to insert a row into a table and then select the generated id.
I'm not sure if it likes both queries in one pdo statement. Here is the code I'm using to execute the SQL.
public function ExecuteQuery($sql, $params = array())
{
if($this->_handle == null)
$this->Connect();
$query = $this->_handle->prepare($sql);
foreach($params as $key => $value)
{
if(is_int($value)){
$query->bindValue(':'.$key, $value, \PDO::PARAM_INT);
}else if(is_bool($value)){
$query->bindValue(':'.$key, $value, \PDO::PARAM_BOOL);
}else if(is_null($value)){
$query->bindValue(':'.$key, $value, \PDO::PARAM_NULL);
}else{
$query->bindValue(':'.$key, $value, \PDO::PARAM_STR);
}
}
$query->execute();
$x = $query->fetchAll(\PDO::FETCH_ASSOC);
var_dump($x);
return $x;
}
This function is part of a database class, $this->_handle is the PDO object.
public function Connect()
{
try {
$this->_handle = new \PDO('mysql:host='.$this->_host.';dbname='.$this->_database, $this->_username, $this->_password);
$this->_handle->setAttribute( \PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION );
}
catch(PDOException $e) {
echo $e->getMessage();
}
}
And the SQL I'm running is this:
INSERT INTO `users` (`Username`, `Password`, `PasswordSalt`, `Email`, `IsAdmin`, `LoginAttempts`, `LastLogin`, `LastLoginAttempt`, `Created`) VALUES (:username, :password, :passwordsalt, :email, :isadmin, :loginattempts, :lastlogin, :lastloginattempt, :created); SELECT LAST_INSERT_ID() as 'id'
The user is created and is there in the users table but it errors after that.
Can anyone see what am doing wrong? :)
Cheers!
I'm pretty sure the mysql driver for PDO (maybe mysql itself?) does not support multi-query prepared statements.
Instead of SELECT LAST_INSERT_ID() in your query, use Conexion::$cn->lastInsertId() after your $query->execute()
I think this is correct:
function ExecuteQuery($sql, $params = array())
{
if(Conexion::$cn== null)
Conexion::Connect();
$paramString="";
foreach($params as $k=>$v)
{
$param = " :".$k." ,";
$paramString .= $param;
}
$sql.=substr($paramString,0,-2);
$query = Conexion::$cn->prepare($sql);
foreach($params as $key => $value)
{
echo "entro";
$query->bindParam(":".$key, $value);
}
$query->execute();
$x = $query->fetchAll(\PDO::FETCH_ASSOC);
var_dump($x);
return $x;
}
public function Connect()
{
try {
$dns='dblib:host='.Conexion::$server.";dbname=".Conexion::$db.";";
Conexion::$cn = new \PDO($dns, Conexion::$user, Conexion::$passw);
Conexion::$cn->setAttribute( \PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION );
}
catch(PDOException $e)
{
echo $e->getMessage();
}
}