Dynamic Prepared Statement Readymade Function that Prepare Statement ONLY ONCE - php

I want a function that prepare statement only once. ( Not every time whenever function called for the same Query ).
Because One of Advantage of Prepared Statement is: preparation on the query is done only once (although the statement is executed multiple times)
So whenever I call this Function it will Prepare Statement every time and it's not proper because we will miss taking one of the biggest advantage of Prepared Statement. So that, I put the Condition if( !empty($stmtName) and !isset($GLOBALS[$stmtName]) ) that Check Statement is Already set or not. ( If not then and only then Statement will prepare ) using this we will cover that advantage. But, It generates Binding Parameter failed ERROR.
My Function is here...
function qryInsert( $stmtName, $table, $field, $params, $formats )
{
$query = " INSERT INTO ".$table
." ".( (isset($field) and !empty($field)) ? " ( ".(implode(", ",$field))." ) " : " " ). " "
." VALUES( ". implode(", ", array_map(function($val) { return "?"; }, $field))." ) ";
/*if(!isset($con) or empty($con))
{
$con = $this->connection();
}*/
$a_params = array();
$a_params = array();
$param_type = '';
$n = count($formats);
for($i = 0; $i < $n; $i++)
{
$param_type .= $formats[$i];
}
$a_params[] = & $param_type;
for($i = 0; $i < $n; $i++)
{
$a_params[] = & $params[$i];
}
if( !empty($stmtName) and !isset($GLOBALS[$stmtName]) )
{
$GLOBALS[$stmtName] = $GLOBALS['con']->prepare($query);
// $stmt = $con->prepare($query);
}
if(!($GLOBALS[$stmtName]))
{
echo " Prepare failed: (" . $con->errno . ") " . $con->error; // . " <br> Query : <span style='color:tomato;'> ".$query." </span>"
}
else
{
if(!(call_user_func_array(array($GLOBALS[$stmtName], 'bind_param'), $a_params)))
{
echo "Binding parameters failed: (" . $GLOBALS[$stmtName]->errno . ") " . $GLOBALS[$stmtName]->error;
}
else
{
if(!($GLOBALS[$stmtName]->execute()))
{
echo "Execute failed: (" . $GLOBALS[$stmtName]->errno . ") " . $GLOBALS[$stmtName]->error;
}
else
{
if($meta = $GLOBALS[$stmtName]->result_metadata())
{
while ($field = $meta->fetch_field())
{
$columns[] = &$row[$field->name];
}
if(call_user_func_array(array($GLOBALS[$stmtName], 'bind_result'), $columns))
{
while ($GLOBALS[$stmtName]->fetch())
{
foreach($row as $key => $val)
{
$x[$key] = $val;
}
$results[] = $x;
}
}
else
{
echo " Error occur while Bindig Result...";
}
}
}
}
}
$GLOBALS[$stmtName]->close();
return $results;
}
INPUT:
qryInsert("insStud", "student_master", array("roll_no","name"), array(21,"Mahetab"), array("i","s"));
qryInsert("insStud", "student_master", array("roll_no","name"), array(8,"Sahil"), array("i","s"));
qryInsert("insStud", "student_master", array("roll_no","name"), array(10,"Mahammad"), array("i","s"));
OUTPUT:
First time Record will Insert...
After that raised Binding Parameter failed error...
Without this Condition if( !empty($stmtName) and !isset($GLOBALS[$stmtName]) )
My Code is Work Fine... It havn't any issue... Because It will prepare statement everytime
I used $GLOBALS variable so that whenever function called it uses same GLOBALS variable Otherwise function Perform operation with their private variable which doesn't work properly

Problem Solved...
Just wants to remove $GLOBALS[$stmtName]->close(); statement...
Because It closed statement every time function called...
So, that Binding Parameters failed...

Related

Dynamic amount of bindParam

So I am trying to make an undetermined amount of bindParam calls within a foreach, but for some reason it fails. I know the $sql variable is working fine, but I am pretty sure it is failing at the bindParam. Is there any reason for this?
$sql = "INSERT INTO " . $row1["rand"] . " (" . $areas . ") VALUES (" . $vals . ")";
echo $sql;
$entry2 = $conn->prepare("'".$sql."'");
//echo "swag";
foreach($splitHeader as $element){
if(strlen($element)>0) {
$thisVal = "':" . $element . "'";
$entry2->bindParam($thisVal,$_POST[$element]);
}
}
$entry2->execute();
The number of parameters that you define in the query must match the number of parameters that you bind.
You would need to loop twice trough your data : once to dynamically construct a sql statement (that you can then prepare), and then a second time to bind the parameters, before finally calling execute.
Here is an adaptation of your code that demonstrates the principle :
$cols = "";
$vals = "";
foreach( $splitHeader as $element ) {
if( strlen($element) > 0 ) {
if ( strlen($cols) > 0 ) {
$cols .= ", ";
$vals .= ", ";
}
$cols .= $element;
$vals .= "?";
}
}
$sql = "INSERT INTO " . $row1["rand"] . " (". $cols . ") VALUES(". $vals . ")";
echo $sql;
$sth = $conn->prepare($sql);
$i = 1;
foreach($splitHeader as $element){
if( strlen($element) > 0 ) {
$sth->bindParam( $i, $_POST[$element] );
$i++;
}
}
$sth->execute();

PHP code does not behave the same if called via function

The same code used as below works fine, but when you un-comment the function and try to call the function, it does not behave the same?
Am trying to standardize the CRUD using functions, but running into issues.
The print_r does not display the output when called inside a function but works when called as is outside of a function
the return value does not return when called via a function
I would like to get the return values via the function and decide what to do next.
Appreciate if you could help me out. Thanks
<?php
//function verifyemail($p_email) {
echo "insde function - " . $p_email;
try {
// $p_email = "r#gmail.com";
include 'db.php';
connectDB('msme_db',1) ;
$sql = "select count(*) as p_exists from msme_users where user_email = '$p_email' ;" ;
echo $sql ;
$result = $__conn->prepare($sql);
$result->execute();
$result->setFetchMode(PDO::FETCH_ASSOC);
$row = $result->fetch() ;
//print_r ($row);
if ($row)
{
$i = $row['p_exists'] ;
return $row !== false ? $row : 'x';
}
} catch (PDOException $e) {
echo " in catch" ;
die("Error occurred:" . $e->getMessage());
}
//} // End of Function
//$email = "r#gmail.com";
//echo sprintf('Email %s is %s', $mail, verifyemail($email)) ;
print_r($row) ;
?>
Problems I see:
1. you have return command in if statement
if ($row)
{
$i = $row['p_exists'] ;
return $row !== false ? $row : 'x';
}
so if is true then you return from function and if is not true then you don't
check this by putting echo inside and see if you see anything
if ($row)
{
echo 'IF Statemen in line: ' . __LINE__ . '<br>' . PHP_EOL;
$i = $row['p_exists'] ;
return $row !== false ? $row : 'x';
}
you should rewrite the code so you always return form the function and use if statement only to assign value to $i or $row
ie like that:
function verifyemail($p_email) {
echo "insde function - " . $p_email;
try {
// $p_email = "r#gmail.com";
include 'db.php';
connectDB('msme_db',1) ;
$sql = "select count(*) as p_exists from msme_users where user_email = '$p_email' ;" ;
echo $sql ;
$result = $__conn->prepare($sql);
$result->execute();
$result->setFetchMode(PDO::FETCH_ASSOC);
$row = $result->fetch() ;
//print_r ($row);
if ($row)
{
$i = $row['p_exists'] ; //<== where do you use $i?
$row !== false ? $row : 'x';
}
} catch (PDOException $e) {
echo " in catch" ;
die("Error occurred:" . $e->getMessage());
}
return $row; //<== here you rentrun from the function
}
// End of Function
// ^ here is place for the comment, not in the line where } is
//$email = "r#gmail.com";
//echo sprintf('Email %s is %s', $mail, verifyemail($email)) ;
print_r($row) ;
?>
If you use return statement without the function body so in the global code scope you end the php script execution
so the code
print_r($row) ;
is never executed
to summarize - put echo statements
echo 'line: ' . __LINE__ . '<br>' . PHP_EOL;
into if statement and other places and check numbers with the code and you'll probably see what you havn't seen where your execution flows where not.
and move return statement outside if statement, perfectly at the end of the function.

Insert array of unspecified length in MYSQLI

It's far from perfect, but I'm trying to create a function to insert data into a SQL table, using MySQLI. I want to create a generic function, to insert different types of data in different databases. I have the following so far:
/**
* Add data to specified table. Data consist of column name as key, and value.
* Table is a string of the table to insert into.
* #param array $data
* #param string $table
* #return string
*/
private function insert( $data = array(), $table = null ){
foreach( $data as $key => $value ){
// Create arrays of separate keys and values
$keys[] = $key;
$values[] = $value;
// Get type of data
switch( gettype( $value ) ){
case "integer":
$types[] = "i";
break;
case "string":
$types[] = "s";
break;
default:
$types[] = "i";
break;
};
// for each variable, add a questionmark
$vars[] = "?";
}
// Create strings out of the data
$key = implode( ",", $keys );
$var = implode( ",", $vars );
$type = implode( "", $types );
$value = '"' . implode( '\", \"', $values ) . '"';
// prepare SQL statement
// var_dump( $sql ) = 'INSERT INTO table (var1,var2,var3) VALUES (?,?,?)'
$sql = "INSERT INTO " . $table . " (" . $key . ") VALUES (" . $var . ")";
// Prepare SQL insert
// $this->conn = new mysqli($this->server, $this->user, $this->pass, $this->name);
if( ! ( $stmt = $this->conn->prepare( $sql ) ) ) {
return "Preparing failed!: (" . $this->conn->errno . ") " . $this->conn->error;
}
// Bind parameters. THIS IS WHERE THE ISSUE IS!
if( ! $stmt->bind_param( $type, $values ) ) {
return "Binding failed! (" . $stmt->errno . ") " . $stmt->error;;
}
// Execute the statement
if( ! $stmt->execute() ){
return "Executing failed! (" . $stmt->errno . ") " . $stmt->error;;
}
}
The issue is at binding the parameters. I can't find a good way to bind them, as I've got multiple variables with values and keys, but they're all in array format, and bind_param requires a new variable for each
In short, I'm looking for a way to add an array of unspecified length into my SQL (in a secure way, ofcourse).
If you are using php 5.6+, you can use the ... operator to unpack an array.
In your example:
$stmt->bind_param( $type, ...$values )
See example #14 in the manual.
/* Bind parameters. Types: s = string, i = integer, d = double, b = blob */
$a_params = array();
$param_type = '';
$n = count($a_param_type);
for($i = 0; $i < $n; $i++) {
$param_type .= $a_param_type[$i];
}
/* with call_user_func_array, array params must be passed by reference */
$a_params[] = & $param_type;
for($i = 0; $i < $n; $i++) {
/* with call_user_func_array, array params must be passed by reference */
$a_params[] = & $a_bind_params[$i];
}
/* Prepare statement */
$stmt = $conn->prepare($sql);
if($stmt === false) {
trigger_error('Wrong SQL: ' . $sql . ' Error: ' . $conn->errno . ' ' . $conn->error, E_USER_ERROR);
}
/* use call_user_func_array, as $stmt->bind_param('s', $param); does not accept params array */
call_user_func_array(array($stmt, 'bind_param'), $a_params);
/* Execute statement */
$stmt->execute();
/* Fetch result to array */
$res = $stmt->get_result();
while($row = $res->fetch_array(MYSQLI_ASSOC)) {
array_push($a_data, $row);
}
Reference: http://www.pontikis.net/blog/dynamically-bind_param-array-mysqli

all of my php syntax is true,but update query is not working in while loop

This is cancel_order function,that also in it will call the increase_gameamount() function, i am trying to call increament_gameamount() function it works but when I try to call it from while loop nothing changes in database.
//cancel function
function cancel_order($ord) {
global $conn;
$bqty = 0;
$gqty = 0;
$res = array();
echo "entered cancel function " . $ord . "<br>";
$st = "select (B_qty+G_qty) newqt, B_GM_ID from tb_basket b, tb_game g
where b.B_GM_ID = g.G_ID
and B_O_ID='$ord' ";
$sql = $conn->prepare($st);
$sql->execute();
$sql->bind_result($newqt, $gid);
$i = 0;
while($row = $sql->fetch()) {
$res[$i][0] = $newqt;
$res[$i][1] = $gid;
$i++;
}
$j = 0;
$sql->free_result();
$sql->close();
while($j < sizeof($res)) {
echo $gd = $res[$j][0] . "<br>";
echo $qty = $res[$j][1] . "<br>";
increament_gameamount($gd, $qty);
$j++;
}
}
//increament function
function increament_gameamount($gameid, $new_qty) {
global $conn;
echo "entered increament_gameamount function";
echo $gameid;
echo $new_qty;
$varupdateqty = $conn->prepare("update tb_game set G_qty=? where G_ID=?");
$varupdateqty->bind_param("ss", $new_qty, $gameid);
$varupdateqty->execute();
echo "Prepare failed: (" . $conn->errno . ") " . $conn->error;
}
As I stated in the comments I think you are failing on the WHERE of your query because
echo $gd=$res[$j][0]."<br>";
is making $gd a string like 125<br> and the DB cannot find that.
Also, this would cause an error but if the type of your column is int and you pass:
echo $qty=$res[$j][1]."<br>";
again you make $qty something like 1000<br> and that would fail again this would be an error the above for ID check would not.
UPDATE
Just realized I did not specifially state the resolution. Set the variables then echo them and you should be all good.
$gd=$res[$j][0];
$qty=$res[$j][1];
echo $gd . "<br>" . $qty . "<br>";

Mysqli Class Always returns NULL for results with one var passed through

Every time I call a query with my class for select * from table where blank=blank it always comes up "NULL" on a var_dump for the results at the end of the class. I'm still stuck on this and don't know why it's doing it, but it sends no responses for sure, because I'm getting nothing back.
mysqli.class.php
<?php
class DATABASE
{
//set up variables only for this class
private $db_host;
private $db_user;
private $db_pass;
private $db_name;
private $connection;
private $paramaters = array();
private $results = array();
private $numrows;
//call connection on call of class
public function __construct($db_host, $db_user, $db_pass, $db_name)
{
$this->host = $db_host;
$this->user = $db_user;
$this->pass = $db_pass;
$this->name = $db_name;
$this->mysqli = new mysqli($this->host, $this->user, $this->pass, $this->name) or die('There was a problem connecting to the database! Error #: '. $this->mysqli->connect_errno);
}
//close mysqli connection on class close
public function __destruct()
{
$this->mysqli->close();
}
//query
public function select($fields, $table, $where, $whereVal, $type, $orderByVal, $ASDESC, $limitVal, $sets, $setVal)
{
switch($type)
{
case "regular":
if ($where == null)
{
$queryPre = "SELECT " . $fields . " FROM " . $table;
$querySuff = "";
} else {
$queryPre = "SELECT " . $fields . " FROM " . $table;
$querySuff = " WHERE " . $where . " = ?";
}
break;
case "orderByLimit":
$queryPre = "SELECT " . $fields . " FROM " . $table;
$querySuff = " ORDER BY " . $orderByVal . " " . $ASDESC . " LIMIT " . $limitVal;
break;
case "update":
if ($where == null)
{
$queryPre = "UPDATE " . $table;
//need for loop for multiple sets, check for is_array and do multiple if so.
$querySuff = " SET " . $sets . " = " . $setVal;
} else {
$queryPre = "UPDATE " . $table;
//need for loop for multiple sets, check for is_array and do multiple if so.
$querySuff = " SET " . $sets . " = " . $setVal . " WHERE " . $where . " = ?";
}
break;
case "insert":
if ($sets == null)
{
$queryPre = "INSERT INTO " . $table;
$querySuff = " VALUES(" . setVal . ")";
} else {
$queryPre = "INSERT INTO " . $table . " (" . $sets . ")";
$querySuff = " VALUES(" . setVal . ")";
}
case "delete":
if ($where == null)
{
$queryPre = "DELETE FROM " . $table;
$querySuff = "";
} else {
$queryPre = "DELETE FROM " . $table;
$querySuff = " WHERE " . $where . " = ?";
}
}
//$sql = $queryPre . "" . $querySuff;
//var_dump($sql);
//exit;
$stmt = $this->mysqli->prepare($queryPre . "" . $querySuff) or die('There was a problem preparing the Query! Error#: '. $this->mysqli->errno);
if ($whereVal == null)
{
$stmt = $this->bindVars($stmt,$setVal);
} else {
$stmt = $this->bindVars($stmt,$whereVal);
}
$stmt->execute();
$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;
}
$stmt->close();
//var_dump($results);
if ($results == "" || $results == NULL)
{
return null;
} else {
return $results;
}
}
private function bindVars($stmt,$params)
{
if ($params != null)
{
$types = '';
//initial sting with types
if (is_array($params))
{
foreach($params as $param)
{
//for each element, determine type and add
if(is_int($param))
{
$types .= 'i'; //integer
} elseif (is_float($param))
{
$types .= 'd'; //double
} elseif (is_string($param))
{
$types .= 's'; //string
} else {
$types .= 'b'; //blob and unknown
}
}
} else {
if (is_int($params))
{
$types = 'i';
} elseif (is_float($params))
{
$types = 'd';
} elseif (is_string($params))
{
$types = 's';
} else {
$types = 'b';
}
}
$bind_names[] = $types;
if (is_array($params))
{
//go through incoming params and added em to array
for ($i=0; $i<count($params);$i++)
{
//give them an arbitrary name
$bind_name = 'bind' . $i;
//add the parameter to the variable variable
$$bind_name = $params[$i];
//now associate the variable as an element in an array
$bind_names[] = &$$bind_name;
}
} else {
$int0 = 0;
$bind_name = 'bind' . $int0;
$$bind_name = $params;
$bind_names[] = &$$bind_name;
}
call_user_func_array(array($stmt,'bind_param'),$bind_names);
}
return $stmt; //return the bound statement
}
}
?>
example to call and check fields - process_availability.php:
<?php
//require necessary files
require('../config/dbconfig.php');
include('../classes/mysqli.class.php');
//initiate connection
$mysqli = new DATABASE($db_host,$db_user,$db_pass,$db_name);
//take type of check
$checktype = $_POST['type'];
//check the user name
if ($checktype == "username") {
//change post to variable
$username = $_POST['username'];
//check if user name is empty
if ($username == "") {
$validuser = array("empty", "false");
echo implode(',', $validuser);
exit;
}
//if user name is more characters than 30
if (strlen($username) > 30) {
$validuser = array("max", "false");
echo implode(',', $validuser);
exit;
}
//search for same user name in database
$resultsU = $mysqli->select('*','users','username',$username,'regular',null,null,null,null,null);
//var_dump($resultsU);
if (is_array($resultsU))
{
var_dump($resultsU);
foreach($resultsU as $rowU)
{
//return results
if($rowU['username'] == "" || $rowU['username'] == NULL)
{
//user name is blank
$validuser = array("yes", "true");
echo implode(',', $validuser);
exit;
}
else {
//username is not blank, so it's taken
$validuser = array("no", "false");
echo implode(',', $validuser);
exit;
}
}
}
}
And just to show what I'm actually doing with the information, here is a PART of the java (just handles username mostly, there is a ton more for email, ect not included):
fiddle
And, of coarse, the link to the page: page link
I've been fixing other things on here, and on a technicality it works. I get a response if there IS something in the database that matches the username i type, but if there is no match, for some reason it doesn't respond at all.....
Specifically...right at the bottom of the 2nd to last function in the class:
$stmt->close();
//var_dump($results);
if ($results == "" || $results == NULL)
{
return null;
} else {
return $results;
}
When you are returning no results to the client, you need to indicate to the client that this is what you have done, and the code shown above simply outputs nothing in this case. While it is easily possible to handle this empty response correctly on the client side a better solution would be to do one of the following:
If you need the data from the result, json_encode() the results before sending them back to the client. This would mean that if the were no results you would return an empty array, but it would still be valid JSON and crucially you can easily check whether the result array is empty on the client side using result.length.
If you don't actually need the result data and all you need is to determine whether there were any results, you can simply return a 1 or a 0. This kind of boolean response takes minimal bandwidth and minimal processing, and the best thing about it is all you need to do is evaluate it as a boolean on the client side - i.e. if (result) { /* do stuff */ }

Categories