I have the parameters to send to a prepared statement in an array, I am using call_user_func_array and using it as such call_user_func_array(array($stmt, "bind_param"), array_merge(array($types), $params_fixed)), where $types contains the types and $params_fixed contains the parameters.
I ran it and got the error Warning: Parameter 2 to mysqli_stmt::bind_param() expected to be a reference, value given in ..., I searched for this error and an answer was to send the parameters by reference so I added an ampersand before the $params_fixed parameter however now I get the error Fatal error: Call-time pass-by-reference has been removed in ....
How can I resolve this issue? What am I missing here?
NOTE: Before learning I had to use call_user_func_array, I was using it as such $stmt->bind_param($types, ...$params_fixed)
NOTE 2: below is the code for filling the array to send
$params_fixed = array();
$types = "";
if($param_count > 0) {
foreach($params as $param) {
switch(gettype($param)) {
case "boolean":
$types = $types . "i";
$params_fixed[] = $param ? 1 : 0;
break;
case "integer":
$types = $types . "i";
$params_fixed[] = &$param;
break;
case "double":
$types = $types . "d";
$params_fixed[] = &$param;
break;
case "string":
$types = $types . "s";
$params_fixed[] = &$param;
break;
default:
$types = $types . "s";
$params_fixed[] = null;
break;
}
}
}
NOTE 3: below is the code in question
public function query($sql, ...$params) {
$param_num_sql = substr_count($sql, "?");
$param_count = count($params);
if($param_num_sql != $param_count) {
$this->error = 'parameters don\'t match';
return null;
}
$params_fixed = array();
$types = "";
if($param_count > 0) {
foreach($params as $param) {
$types = $types . "s";
$params_fixed[] = &$param;
// switch(gettype($param)) {
// case "boolean":
// $types = $types . "i";
// $params_fixed[] = $param ? 1 : 0;
// break;
// case "integer":
// $types = $types . "i";
// $params_fixed[] = $param;
// break;
// case "double":
// $types = $types . "d";
// $params_fixed[] = $param;
// break;
// case "string":
// $types = $types . "s";
// $params_fixed[] = $param;
// break;
// default:
// $types = $types . "s";
// $params_fixed[] = null;
// break;
// }
}
}
if($param_num_sql == 0) {
$result = $this->conn->query($sql);
} else {
$stmt = $this->conn->prepare($sql);
//call_user_func_array(array($stmt, "bind_param"), array_merge(array($types), $params_fixed));
//if(!$stmt->bind_param($types, ...$params_fixed)) {
echo "<br/>types: $types<br/>";
echo '<br/>';
print_r($params_fixed);
echo '<br/>';
if(!call_user_func_array(array($stmt, "bind_param"), array_merge(array($types), $params_fixed))) {
// an error occurred
}
$stmt->execute();
$result = $stmt->get_result();
$stmt->close();
}
if($result != null && $result->num_rows > 0)
return $result->fetch_all();
else
return null;
}
and below is the code calling this method
$dbcon->query($query, $fname, $mname, $lname, $dob, $mobile, $home, $email, $area, $city, $street, $bldg, $floor, $car_capacity, $status, $prefer_act, $volunteer_days, $backup_days);
try like this
$mysqli = new mysqli('localhost', 'root','','mydb');
$stmt=$mysqli->prepare("select * from blog where id=? and date=?");
$title='1';
$text='2016-04-07';
call_user_func_array(array($stmt, "bind_param"),array_merge(array('ss'),array(&$title,&$text)));
$stmt->execute();
$result = $stmt->get_result();
print_r($result->fetch_array());
echo $stmt->error;
ok if you have parameters coming from the array
$mysqli = new mysqli('localhost', 'root','','jobspace');
$stmt=$mysqli->prepare("select * from listings where listing_type_sid=? and user_sid=?");
$title='6';
$text='8';
$arr=array($title,$text);
foreach($arr as &$ar){
$new[]=&$ar;
}
$types = implode(array_fill(0,count($arr),'s'));
call_user_func_array(array($stmt, "bind_param"),array_merge(array($types),$new));
$stmt->execute();
$result = $stmt->get_result();
print_r($result->fetch_array());
echo $stmt->error;
Related
I'm passing an array of values through a bind_param function, the way I do this is like this:
<?php
class Query{
private $_mysqli;
/*
* #param object $mysqli
*/
public function __construct($mysqli)
{
$this->_mysqli = $mysqli;
}
/*
* #param string query
* #param string $types
* #param array $values
*/
public function read($query = "", $type = "", $params = array())
{
$query = ($query === "") ? die("Read error: Query") : $query;
$type = ($type === "") ? die("Read error: Type") : array($type);
$params = (count($params) == 0) ? die("Read error: Params") : $params;
$values = array();
foreach($params as $key => $value) {
$values[$key] = &$params[$key];
}
if ($stmt = $this->_mysqli->prepare($query))
{
call_user_func_array(array($stmt, "bind_param"), array_merge($type, $values));
$stmt->execute();
$fields = array();
for($i=0; $i<count($params); $i++){
$fields[$i] = $params[$i];
}
call_user_func_array(array($stmt, "bind_result"), $fields);
$array = array();
while($data = $stmt->fetch())
{
$array[] = $data;
}
return $array;
}
}
}
This is the way I use my function
<?php
//$mysqli is the mysqli connection
$query = new Query($mysqli);
$query_str = "SELECT * FROM users WHERE voornaam = ? AND achternaam = ?";
$types = "ss";
$params = array("Firstname", "Lastname");
var_dump($query->read($query_str, $types, $params));
?>
The part where I get stucked is:
<?php
$fields = array();
for($i=0; $i<count($params); $i++){
$fields[$i] = $params[$i];
}
call_user_func_array(array($stmt, "bind_result"), $fields);
$array = array();
while($data = $stmt->fetch())
{
$array[] = $data;
}
?>
Im not sure where it goes wrong, I have a feeling at the while loop.
hope you guys can help me making this function working :)
you are binding results , so you don't need to assign your fetched data to new variable,
mysqli_stmt::bind_result -- mysqli_stmt_bind_result — Binds variables
to a prepared statement for result storage
while you are using call_user_func_array , and according to this comment, your loop :
while($data = $stmt->fetch())
{
$array[] = $data;
}
may be as follows:
while($stmt->fetch())
{
// params which you had bind it into bindParams
$array[] = $params;
}
This question already has answers here:
How to apply bindValue method in LIMIT clause?
(11 answers)
Closed 6 years ago.
I'm trying to use a dynamic PDO query (add where clause to the query if the variable is true) but i have a problem with integers values, this is my code:
$params = array();
$cond = array();
$query = "SELECT value FROM `table`";
if (!empty($firstname)) {
$cond[] = "firstname = :fn";
$params[':fn'] = $firstname;
}
if (!empty($lastname)) {
$cond[] = "lastname = :ln";
$params[':ln'] = $lastname;
}
if (count($cond)) {
$query .= ' WHERE ' . implode(' AND ', $cond);
}
$query .= " LIMIT :min, :max";
$params[':min'] = $min; // INTEGER VALUE
$params[':max'] = $max; // INTEGER VALUE
$stmt = $db->prepare($query);
$stmt->execute($params);
The problem is that PDOStatement::execute treated all values as PDO::PARAM_STR and LIMIT need integer values.
I tried with PDOStatement::bindValue using PDO::PARAM_INT parameter but i don't know how to use it in a dynamic query.
You already have an array of keys and values to bind in $params, so after you prepare the statement, loop through it and bind accordingly:
$params = array();
$cond = array();
$query = "SELECT value FROM `table`";
if (!empty($firstname)) {
$cond[] = "firstname = :fn";
$params[':fn'] = $firstname;
}
if (!empty($lastname)) {
$cond[] = "lastname = :ln";
$params[':ln'] = $lastname;
}
if (count($cond)) {
$query .= ' WHERE ' . implode(' AND ', $cond);
}
$query .= " LIMIT :min, :max";
$params[':min'] = $min; // INTEGER VALUE
$params[':max'] = $max; // INTEGER VALUE
$stmt = $db->prepare($query);
foreach($params as $key => $value)
{
if(is_int($value))
{
$stmt->bindValue($key, $value, PDO::PARAM_INT);
}
else
{
$stmt->bindValue($key, $value, PDO::PARAM_STR);
}
}
$stmt->execute($params);
Notice, that you must use bindValue, since bindParam will not work. The PHP manual states why:
Unlike PDOStatement::bindValue(), the variable is bound as a reference and will only be evaluated at the time that PDOStatement::execute() is called.
And once a foreach iteration is passed, $value no longer exists and can't be used as a reference. This is precisely the reason you must use bindValue
You can bind the Value with the optional 3rd Parameter on bindParam
Like this:
$stmt->bindParam($key, $value, PDO::PARAM_INT);
If that not work try
$stmt->bindParam($key, intval($value), PDO::PARAM_INT);
This works fine for me:
foreach($params as $key => &$value)
$stmt->bindValue($key, $value, get_type($value));
Here is my get_type() function:
function get_type($value) {
switch(true) {
case is_null($value):
return PDO::PARAM_NULL;
case is_int($value):
return PDO::PARAM_INT;
case is_bool($value):
return PDO::PARAM_BOOL;
default:
return PDO::PARAM_STR;
}
}
I'm sure there are better ways to solve this, but hey it works
(Better use PDO::bindValue() than PDO::bindParam())
I have a query and it looks like:
if (strlen($search->q)) {
$where[] = ' AND (`name` LIKE :q)';
$arr['q'] = "%" . $search->q . "%";
}
$sql = 'SELECT
*,
FROM
`shop_products`
WHERE
1=1
'.implode('', $where);
Not I'm trying to get products from DB:
$result->products = $db->query($sql, $arr, $search->limitstart, $search->limit)->fetchAll();
My query function:
public function query($sql, $params=array(), $offset = null, $limit = null){
if (!is_null($offset) && !is_null($limit)) {
$sql .= ' LIMIT :limit OFFSET :offset';
$params['limit'] = (int)$limit;
$params['offset'] = (int)$offset;
}
$stmt = $this->database->prepare($sql);
if (!empty($params)) {
foreach($params as $key => $value) {
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;
}
if($param) $stmt->bindValue(":$key", $value, $param);
}
}
$stmt->execute();
return $stmt;
}
My problem that LIKE instruction does not work. How can I solve this problem and fix my code?
Warning: Missing argument 1 for MysqlDB::__construct(), called in C:\xampp\htdocs\ripplezsolution\index.php on line 9 and defined in C:\xampp\htdocs\ripplezsolution\phpinclude\include\MySqlDb.php on line 10
Warning: Missing argument 2 for MysqlDB::__construct(), called in C:\xampp\htdocs\ripplezsolution\index.php on line 9 and defined in C:\xampp\htdocs\ripplezsolution\phpinclude\include\MySqlDb.php on line 10
Warning: Missing argument 3 for MysqlDB::__construct(), called in C:\xampp\htdocs\ripplezsolution\index.php on line 9 and defined in C:\xampp\htdocs\ripplezsolution\phpinclude\include\MySqlDb.php on line 10
Warning: Missing argument 4 for MysqlDB::__construct(), called in C:\xampp\htdocs\ripplezsolution\index.php on line 9 and defined in C:\xampp\htdocs\ripplezsolution\phpinclude\include\MySqlDb.php on line 10
Notice: Undefined variable: host in C:\xampp\htdocs\ripplezsolution\phpinclude\include\MySqlDb.php on line 11
Notice: Undefined variable: username in C:\xampp\htdocs\ripplezsolution\phpinclude\include\MySqlDb.php on line 11
Notice: Undefined variable: password in C:\xampp\htdocs\ripplezsolution\phpinclude\include\MySqlDb.php on line 11
Notice: Undefined variable: db in C:\xampp\htdocs\ripplezsolution\phpinclude\include\MySqlDb.php on line 11
This is my MysqlDB.php code
<?php
class MysqlDB {
protected $_mysql;
protected $_where = array();
protected $_query;
protected $_paramTypeList;
public function __construct ($host, $username, $password, $db) {
$this->_mysql = new mysqli($host, $username, $password, $db)
or die('There was a problem connecting to the database');
}
public function query($query)
{
$this->_query = filter_var($query, FILTER_SANITIZE_STRING);
$stmt = $this->_prepareQuery();
$stmt->execute();
$results = $this->_dynamicBindResults($stmt);
return $results;
}
/**
* A convenient SELECT * function.
*
* #param string $tableName The name of the database table to work with.
* #param int $numRows The number of rows total to return.
* #return array Contains the returned rows from the select query.
*/
public function get($tableName, $numRows = NULL)
{
$this->_query = "SELECT * FROM $tableName";
$stmt = $this->_buildQuery($numRows);
$stmt->execute();
$results = $this->_dynamicBindResults($stmt);
return $results;
}
/**
*
* #param <string $tableName The name of the table.
* #param array $insertData Data containing information for inserting into the DB.
* #return boolean Boolean indicating whether the insert query was completed succesfully.
*/
public function insert($tableName, $insertData)
{
$this->_query = "INSERT into $tableName";
$stmt = $this->_buildQuery(NULL, $insertData);
$stmt->execute();
if ($stmt->affected_rows)
return true;
}
public function update($tableName, $tableData)
{
$this->_query = "UPDATE $tableName SET ";
$stmt = $this->_buildQuery(NULL, $tableData);
$stmt->execute();
if ($stmt->affected_rows)
return true;
}
public function delete($tableName) {
$this->_query = "DELETE FROM $tableName";
$stmt = $this->_buildQuery();
$stmt->execute();
if ($stmt->affected_rows)
return true;
}
public function where($whereProp, $whereValue)
{
$this->_where[$whereProp] = $whereValue;
}
protected function _determineType($item)
{
switch (gettype($item)) {
case 'string':
return 's';
break;
case 'integer':
return 'i';
break;
case 'blob':
return 'b';
break;
case 'double':
return 'd';
break;
}
}
protected function _buildQuery($numRows = NULL, $tableData = false)
{
$hasTableData = null;
if (gettype($tableData) === 'array') {
$hasTableData = true;
}
// Did the user call the "where" method?
if (!empty($this->_where)) {
$keys = array_keys($this->_where);
$where_prop = $keys[0];
$where_value = $this->_where[$where_prop];
// if update data was passed, filter through
// and create the SQL query, accordingly.
if ($hasTableData) {
$i = 1;
$pos = strpos($this->_query, 'UPDATE');
if ( $pos !== false) {
foreach ($tableData as $prop => $value) {
// determines what data type the item is, for binding purposes.
$this->_paramTypeList .= $this->_determineType($value);
// prepares the reset of the SQL query.
if ($i === count($tableData)) {
$this->_query .= $prop . " = ? WHERE " . $where_prop . "= " . $where_value;
} else {
$this->_query .= $prop . ' = ?, ';
}
$i++;
}
}
} else {
$this->_paramTypeList = $this->_determineType($where_value);
$this->_query .= " WHERE " . $where_prop . "= ?";
}
}
if ($hasTableData) {
$pos = strpos($this->_query, 'INSERT');
if ($pos !== false) {
$keys = array_keys($tableData);
$values = array_values($tableData);
$num = count($keys);
foreach ($values as $key => $val) {
$values[$key] = "'{$val}'";
$this->_paramTypeList .= $this->_determineType($val);
}
$this->_query .= '(' . implode($keys, ', ') . ')';
$this->_query .= ' VALUES(';
while ($num !== 0) {
($num !== 1) ? $this->_query .= '?, ' : $this->_query .= '?)';
$num--;
}
}
}
if (isset($numRows)) {
$this->_query .= " LIMIT " . (int) $numRows;
}
$stmt = $this->_prepareQuery();
if ($hasTableData) {
$args = array();
$args[] = $this->_paramTypeList;
foreach ($tableData as $prop => $val) {
$args[] = &$tableData[$prop];
}
call_user_func_array(array($stmt, 'bind_param'), $args);
} else {
if ($this->_where)
$stmt->bind_param($this->_paramTypeList, $where_value);
}
return $stmt;
}
protected function _dynamicBindResults($stmt)
{
$parameters = array();
$results = array();
$meta = $stmt->result_metadata();
while ($field = $meta->fetch_field()) {
$parameters[] = &$row[$field->name];
}
call_user_func_array(array($stmt, 'bind_result'), $parameters);
while ($stmt->fetch()) {
$x = array();
foreach ($row as $key => $val) {
$x[$key] = $val;
}
$results[] = $x;
}
return $results;
}
protected function _prepareQuery()
{
if (!$stmt = $this->_mysql->prepare($this->_query)) {
trigger_error("Problem preparing query", E_USER_ERROR);
}
return $stmt;
}
public function __destruct()
{
$this->_mysql->close();
}
}
?>
and i'm calling a function insert() through index.php
<?php
ob_start();
session_start();
require_once("phpinclude/include/membersite_config.php");
require_once("phpinclude/include/MySqlDB.php");
$DB = new MysqlDB('172.90.13.97','king','mi*****hhh','kxxxx_database');
if (isset($_GET['action'])){$action = htmlentities($_GET['action']);}
else{$action = NULL;}
$mysqldb = new MysqlDB();
?>
<?php if($action=='add_cart'){?>
<?php $data=array($arrival, $departure, $result, $roomID, $category_price); $table='tb_cart';?>
<?php $this->mysqldb->insert($table, $data); ?>
<?php }?>
Problem is in this line
$mysqldb = new MysqlDB();
The constructor requries arguments which are not passed. You need to pass $host, $username, $password, $db to constructor.
Your code acutally makes no sense. You could use $DB instead of creating new object. You also use $this->mysqldb in no object context. There are plenty of errors in your code.
To fix:
Remove this line $mysqldb = new MysqlDB();
Change <?php $this->mysqldb->insert($table, $data); ?> to $DB->insert($table, $data);
Script should +- look like:
<?php
ob_start();
session_start();
require_once("phpinclude/include/membersite_config.php");
require_once("phpinclude/include/MySqlDB.php");
$DB = new MysqlDB('172.90.13.97','king','mi*****hhh','kxxxx_database');
$action = !empty($_GET['action']) ? htmlentities($_GET['action']) : null;
if ($action == 'add_cart') {
$data = array(
'arrival' => $arrival,
'departure' => $departure,
'result' => $result,
'roomID' => $roomID,
'category_price' => $category_price
);
$DB->insert('tb_cart', $data);
}
I'm trying to setup prepared statements on a server that is unable to use get_result(). Below are the functions I call. This is working code I have on a site that is on a server that can use get_result() so I know the code works to an extent.
((EDIT HERE))
With this code my $dbarray is coming back blank. I'm simply trying to make it return the rows being pulled from the db.
Here are my two functions used.
protected static function BuildParam($parameters){
//If $where is an array then we have to extract the values and their type so we can bind_param();
if(is_array($parameters)){
foreach($parameters as $value){
$param = (is_array($value) ? $value[1] : $value);
$params[] = $param;
$paramType = '';
switch($param){
case is_int($param):
$paramType .= 'i';
break;
case is_float($param):
$paramType .= 'd';
break;
case is_string($param):
$paramType .= 's';
break;
default:
$paramType .= 'b';
}
}
$params = array_merge(array($paramType), array_values($params));
if (strnatcmp(phpversion(),'5.3') >= 0) //Reference is required for PHP 5.3+
{
$refs = array();
foreach($params as $key => $value)
$refs[$key] = &$params[$key];
return $refs;
}
return $params;
}
}
//string $q = mysql query
//array $parameters = where clause parameters
protected function QueryFetchArray($q, $parameters = ''){
$mysqli = new mysqli(DB_SERVER, DB_USER, DB_PASS, DB_NAME);
$stmt = $mysqli->prepare($q);
//If $parameters is an array (if there are parameters)
if(is_array($parameters)){
call_user_func_array(array($stmt, 'bind_param'), self::BuildParam($parameters));
}
$stmt -> execute();
((EDIT HERE))
//What I use on the new server that I cannot use on this server
//$result = $stmt -> get_result();
//This is where I'm stuck and trying to replace the above line
while($row = $stmt->fetch()){$result[] = $row;}
$stmt -> close();
if($result !== NULL){
$dbarray = mysqli_fetch_array($result, MYSQLI_ASSOC);
}else{
$dbarray = NULL;
}
return $dbarray;
}