I am trying to understand the difference between mysqli's query() and prepare(). I have code like below, and I would like to get the same results from both. However the prepare() does not work as expected. why?
// this works
if ($query = $this->db->query("SELECT html FROM static_pages WHERE page = 'cities'")) {
$result = $query->fetch_row();
echo $result[0];
$query->close();
}
//this does not work
//result is empty
$cities = 'cities';
$stmt = $this->db->prepare("SELECT html FROM static_pages WHERE page = ?");
$stmt -> bind_param("s", $cities);
$stmt->execute();
$stmt->bind_result($result);
$stmt->fetch();
echo $result;
$stmt->close();
$this->db->close();
these are my server configs as requested:
OS
Vista 64bit / PHP Version 5.2.9
mysqli
MysqlI Support enabled
Client API library version 5.0.51a
Client API header version 5.0.51a
MYSQLI_SOCKET /tmp/mysql.sock
Directive Local Value Master Value
mysqli.default_host no value no value
mysqli.default_port 3306 3306
mysqli.default_pw no value no value
mysqli.default_socket no value no value
mysqli.default_user no value no value
mysqli.max_links Unlimited Unlimited
mysqli.reconnect Off Off
Can you try $stmt->store_result(); between $stmt->execute(); and $stmt->bind_result($result); ?
Any of the mysqli_* functions can fail. In this case the return value is false and the error/errno properties of the mysqli or mysqli_stmt object contains more information about the error. The script has to test each and every return value and react appropriately on error condition (e.g. it doesn't make sense to prepare the statement if the connection failed).
<?php
$foo = new Foo;
$foo->init();
$foo->bar();
class Foo {
public function bar() {
$cities = 'cities';
$stmt = $this->db->prepare("SELECT html FROM soTest WHERE page = ?");
if ( !$stmt ) {
echo "prepare failed\n";
echo "error: ", $this->db->error, "\n";
return;
}
$rc = $stmt->bind_param("s", $cities);
if ( !$rc ) {
echo "bind_param failed\n";
echo "error: ", $stmt->error, "\n";
return;
}
$rc=$stmt->execute();
if ( !$rc ) {
echo "execute failed\n";
echo "error: ", $stmt->error, "\n";
return;
}
$rc = $stmt->bind_result($result);
if ( !$rc ) {
echo "bind_result failed\n";
echo "error: ", $stmt->error, "\n";
return;
}
$rc = $stmt->fetch();
if ( !$rc ) {
echo "no such record\n";
}
else {
echo 'result: ', $result, "\n";
}
$stmt->close();
}
public function init() {
$this->db = new mysqli('localhost', 'localonly', 'localonly', 'test');
if ($this->db->connect_error) {
die('connection failed: ' . $this->db->connect_error);
}
$rc = $this->db->query('CREATE TEMPORARY TABLE
soTest (id int auto_increment, html varchar(16), page varchar(16),primary key(id))'
);
if ( !$rc ) { die('error: '.$this->db->error); }
$rc = $this->db->query("INSERT INTO soTest (html,page) VALUES ('htmlFoo','foo'),('htmlCities','cities')");
if ( !$rc ) { die('error: '.$this->db->error); }
}
}
Keep CWE-209: Information Exposure Through an Error Message in mind. Printing the actual error message in my example script is only for testing. And you might use a slightly more sophisticated error handling than just die().
Should be echo $result; not echo $results;
Related
I'm a beginner in PHP programming.
I have an SP in SQL Server with input, output and ReturnValue parameters that returns data from an sample table.
CREATE PROCEDURE [dbo].[sp_PHP]
#in1 int, #in2 int, #out3 int OUTPUT
WITH EXEC AS CALLER
AS
SET #out3 = #in1 * #in2
SELECT * FROM PHP
RETURN #in1 + #in2
This is my PHP code
<?php
try
{
$conn = new PDO("sqlsrv:Server=xxxxx,1433;Database=xxxxxx", "xx", "xx");
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch (Exception $e)
{
die(print_r($e->getMessage()));
}
$query = '{? = CALL sp_PHP(?, ?, ?)}';
$stmt = $conn->prepare($query);
$returnVariable = -1;
$inputVariable1 = 18;
$inputVariable2 = 24;
$outputVariable3 = -1;
$stmt->bindParam(1,$returnVariable, PDO::PARAM_INT | PDO::PARAM_INPUT_OUTPUT, 100);
$stmt->bindParam(2,$inputVariable1, PDO::PARAM_INT);
$stmt->bindParam(3,$inputVariable2, PDO::PARAM_INT);
$stmt->bindParam(4,$outputVariable3, PDO::PARAM_INT | PDO::PARAM_INPUT_OUTPUT, 100);
$stmt->execute();
$results = $stmt->fetchAll(PDO::FETCH_BOTH);
foreach($results as $row) {
echo $row['PHP_ID'].' '.$row['PHP_Char'].'<br>';
}
echo '<hr>';
echo 'Return value: '.$returnVariable.'<br>';
echo 'Output parameter: '.$outputVariable3.'<br>';
?>
If I remove the line in the SP
SELECT * FROM PHP
and don't read the data received in PHP with following code
$results = $stmt->fetchAll(PDO::FETCH_BOTH);
foreach($results as $row) {
echo $row['PHP_ID'].' '.$row['PHP_Char'].'<br>';
}
I receive the correct values of $returnVariable (42) and $outputVariable3 (432).
But if I read (and show) the data read from the SP, $returnVariable and $outputVariable3 are equal to -1 (the assigned value)
I wanto to read output parameter, ReturnValue and data at the same time.
Is it possible? Where am I wrong?
Thanks!!
Solution:
The value of the output (or input/output) parameter is accessible when you consume all results returned by the stored procedure (PDO and not PDO versions). In your case you need to move throw resultsets with PDOStatement::nextRowset to get the values for the output parameters.
Example:
I've reproduced your example and next code works for me.
<?php
$server = 'server\instance,port';
$database = 'database';
$uid = 'user';
$pwd = 'password';
try {
$conn = new PDO("sqlsrv:server=$server;Database=$database", $uid, $pwd);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch( PDOException $e ) {
die( "Error connecting to SQL Server".$e->getMessage());
}
try {
$sql = "{? = CALL sp_PHP(?, ?, ?)}";
#$sql = "EXEC ? = sp_PHP(?, ?, ?)";
$stmt = $conn->prepare($sql);
$returnVariable = -1;
$inputVariable1 = 18;
$inputVariable2 = 24;
$outputVariable3 = -1;
$stmt->bindParam(1, $returnVariable, PDO::PARAM_INT | PDO::PARAM_INPUT_OUTPUT, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE);
$stmt->bindParam(2, $inputVariable1, PDO::PARAM_INT);
$stmt->bindParam(3, $inputVariable2, PDO::PARAM_INT);
$stmt->bindParam(4, $outputVariable3, PDO::PARAM_INT | PDO::PARAM_INPUT_OUTPUT, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE);
$stmt->execute();
do {
echo 'Result set:'."<br>";
while ($row = $stmt->fetch( PDO::FETCH_ASSOC) ){
print_r($row)."<br>";
}
echo "<br>";
echo "<br>";
} while ($stmt->nextRowset());
} catch( PDOException $e ) {
die( "Error executing query" );
}
$stmt = null;
$conn = null;
echo 'Stored procedure return value: '.$returnVariable."</br>";
echo 'Stored procedure output parameter: '.$outputVariable3."</br>";
?>
This method is part of a larger class, and am trying to get it to return an array of objects containing the same classes. However, it doesn't seem to be entering the while loop, and I can't figure out why. Any suggestions?
The expected result would be an array of objects containing this data http://sqlfiddle.com/#!9/b6e23/1.
public static function getAllFacts($groupID)
{
$factTable = array();
$conn = new mysqli($GLOBALS['hostName'], $GLOBALS['userName'], $GLOBALS['password'], $GLOBALS['database']);
if ($conn->connect_error)
{
echo "Database connection error (source table)<br>";
}
$query = "SELECT factID, sourceID, factTXT, citationID, noteGroupID, factCreated, factsGroupID FROM facts WHERE factsGroupID = ?";
$stmt = $conn->prepare($query);
if ($stmt)
{
$stmt->bind_param("i", $groupID);
$stmt->execute();
$stmt->store_result();
$stmt->bind_result(
$factID,
$sourceID,
$factTXT,
$citaitionID,
$noteGroupID,
$factCreated,
$factsGroupID
);
$row = 0;
while ($stmt->fetch())
{
$numRows = $stmt->num_rows;
echo "numRows: " . $numRows . "<br>";
$factTable[$row] = new self($factID, $sourceID, $factTxt, $citationTxt, $noteGroupID, $factCreated, $factsGroupID, $numRows);
$row++;
}
$stmt->close();
}
else
{
echo "Statement failed. (source table) <br>";
}
return $factTable;
}
This question already has answers here:
Build SELECT query with dynamic number of LIKE conditions as a mysqli prepared statement
(2 answers)
Closed 3 years ago.
I'm trying to make a function that receive a query (sql) and a parameter (array) but I receive this error:
PHP Warning: Parameter 2 to mysqli_stmt::bind_param() expected to be
a reference, value given
My code is:
function dbRead($query, $param) {
$mysqli = new mysqli(DB::READ_HOST, DB::READ_USER, DB::READ_PASS, DB::NAME);
// Check that connection was successful.
if ($mysqli->connect_error) {
$result = "Connection error";
} else {
// Check that $conn creation succeeded
if ($conn = $mysqli->prepare($query)) {
call_user_func_array(array($conn, 'bind_param'), $param);
$conn->execute();
$result = $conn->get_result();
$result = $result->fetch_array();
$conn->close();
} else {
$result = "Prepare failed";
}
}
$mysqli->close();
return $result;
}
$test = dbRead('SELECT * FROM user WHERE id=? and email=?', array(123,'example#example.com'))
And if my function code is
function dbRead($query, $param) {
$mysqli = new mysqli(DB::READ_HOST, DB::READ_USER, DB::READ_PASS, DB::NAME);
// Check that connection was successful.
if ($mysqli->connect_error) {
$result = "Connection error";
} else {
// Check that $conn creation succeeded
if ($conn = $mysqli->prepare($query)) {
$ref = array();
foreach ($param as $key => $value) {
$ref[$key] = &$param[$key];
}
call_user_func_array(array($conn, 'bind_param'), $ref);
$conn->execute();
$result = $conn->get_result();
$result = $result->fetch_array();
$conn->close();
} else {
$result = "Prepare failed";
}
}
$mysqli->close();
return $result;
}
I receive this error
PHP Warning: mysqli_stmt::bind_param(): Number of elements in type
definition string doesn't match number of bind variables
My PHP version is 5.4.36
I was trying to do something very similar and pieced together the solution from a few different posts on PHP References and bind_param. What's probably not immediately clear from the bind_param examples (or you forgot) is that the first argument is a string of the parameter types, one character per parameter (in your case, likely "is" for int and string), and you already got that the rest of the arguments must be references in your second function definition.
So, creating the arguments array should be something like this instead:
$ref = array("is");
foreach ($param as $value)
$ref[count($ref)] = &$value;
Though there are many ways to do it... and you should probably pass in the argument types along with the query, but MySQL seems to be relaxed when it comes to type exact types. I also prefer to pass the connection around, and support multiple result rows, e.g.:
function doRead($conn, $query, $argTypes, $args){
$success = false;
$execParams = array($argTypes);
foreach($args as $a)
$execParams[count($execParams)] = &$a;
if (!$stmt = $conn->prepare($query)){
echo "Prepare failed: (" . $conn->errno . ") " . $conn->error;
}else if (!call_user_func_array(array($stmt, "bind_param"), $execParams)){
echo "Param Bind failed, [" . implode(",", $args) . "]:" . $argTypes . " (" . $stmt->errno . ") " . $stmt->error;
} else if (!$stmt->execute()) {
echo "Execute failed: (" . $stmt->errno . ") " . $stmt->error;
} else
$success = true;
$ret = array();
if($success){
$res = $stmt->get_result();
while ($row = $res->fetch_array(MYSQLI_ASSOC))
array_push($ret, $row);
}
$stmt->close();
return $ret;
}
I'm new to mysqli, I wrote a function as below.
1 - I couldn't find a way for SELECT * query and having bind_result to assign each column value to the same name variable. (e.g. name column value of #row stores to $name)
I think bind_result() has no function on a SELECT * query?
2 - So I tried another option, to fetch all rows and assign them to appropriate variable manually through a loop. I think I should use $query->fetch_all() or $query->fetch_assoc() for looping but I encounter with this:
Fatal error: Call to undefined method mysqli_result::fetch_all()
or
Fatal error: Call to undefined method mysqli_result::fetch_assoc()
However I did a phpinfo() and saw mysqlnd was enabled and php version is 5.4.7 (running XAMPP v1.8.1)
And 3- what finally I did is below idea that doesn't work either.
function the_names($name)
{
global $db;
if($query = $db->prepare("SELECT * FROM users where name=?"))
{
$query->bind_param('s', $name);
if($query->execute())
{
$query->store_result();
if($query->num_rows > 1)
{
while($row = $query->fetch())
{
echo $row['name']; // Here is the problem
}
}
else
echo "not valid";
$query->close();
}
}
}
I need a way to store all fetched data as what bind_result() does, or having them in an array for later use, and it's much better to know both. tnx
One word to answer all your questions at once - PDO
It has everything you are trying to get from mysqli (in vain):
function the_names($name)
{
global $db;
$query = $db->prepare("SELECT * FROM users where name=?");
$query->execute(array($name));
return $query->fetchAll();
}
$names = the_names('Joe');
foreach ($names as $row) {
echo $row['name'];
}
Note the proper way of using a function. it should never echo anything, but only return the data for the future use
If your mysqli code doesn't have binding_param() you can just write code like below :
$mysqli = new mysqli("localhost" , "root" , "" , "database_name");
$result = $mysqli->query( "SELECT * FROM users where name=" . $name) ;
while ( $row = $result->fetch_assoc() ) {
echo $row["name"];
}
If you use binding_param() code , you also need to set bind_result()
$db = new mysqli("localhost" , "root" , "" , "database_name");
function the_names($name){
global $db;
/* Prepared statement, stage 1: prepare */
if (!($query = $db->prepare("SELECT * FROM users where name=?"))) { # prepare sql
echo "Prepare failed: (" . $db->errno . ") " . $db->error;
}
/* Prepared statement, stage 2: bind and execute */
if (!$query->bind_param("s", $name)) { # giving param to "?" in prepare sql
echo "Binding parameters failed: (" . $query->errno . ") " . $query->error;
}
if (!$query->execute()) {
echo "Execute failed: (" . $query->errno . ") " . $query->error;
}
$query->store_result(); # store result so we can count it below...
if( $query->num_rows > 0){ # if data more than 0 [ that also mean "if not empty" ]
# Declare the output field of database
$out_id = NULL;
$out_name = NULL;
$out_age = NULL;
if (!$query->bind_result($out_id, $out_name , $out_age)) {
/*
* Blind result should same with your database table !
* Example : my database
* -users
* id ( 11 int )
* name ( 255 string )
* age ( 11 int )
* then the blind_result() code is : bind_result($out_id, $out_name , $out_age)
*/
echo "Binding output parameters failed: (" . $query->errno . ") " . $query->error;
}
while ($query->fetch()) {
# print the out field
printf("id = %s <br /> name = %s <br /> age = %s <br />", $out_id, $out_name , $out_age);
}
}else{
echo "not valid";
}
}
the_names("panji asmara");
Reference :
http://php.net/manual/en/mysqli.quickstart.prepared-statements.php
I am using the following code for reading a String from a mysql function:
<?php
print_r($_POST);
try {
$dbh = new PDO("mysql:dbname=mydb;host=myhost", "myuser", "mypass" );
$value = $_POST['myLname'];
print $value ;
//print $dbh ;
$stmt = $dbh->prepare("CALL check_user_exists(?)");
$stmt->bindParam(1, $value, PDO::PARAM_STR | PDO::PARAM_INPUT_OUTPUT, 50);
// call the stored procedure
$stmt->execute();
print "procedure returned $value\n";
echo "PDO connection object created";
$dbh = null;
} catch(PDOException $e) {
echo $e->getMessage();
}
?>
This is not reading the returned value , however if I read the value usimg mysql* like :
<?php
$dbhost='myhost';
$dbuser='mydb';
$dbpassword='mypass';
$db='mydb';
$con=mysql_connect($dbhost, $dbuser, $dbpassword) or die("Could not connect: " . mysql_error()); ;
mysql_select_db($db,$con);
$qry_str = "select check_user_exists('chadhass#hotmail.com')";
$rset = mysql_query($qry_str) or exit(mysql_error());
$row = mysql_fetch_assoc($rset);
mysql_close($con);
foreach($row as $k=>$v)
{
print $k.'=>'.$v;
}
?>
This returns correctly . ANy idea wha am I missing ?
function :
CREATE
FUNCTION `check_user_exists`(in_email
VARCHAR(100)) RETURNS varchar(1) CHARSET utf8
READS SQL DATA
BEGIN
DECLARE vcount INT;
DECLARE vcount1 INT;
SELECT COUNT(*) INTO vcount FROM USERS
WHERE USEREMAIL=in_email;
IF vcount=1 then
SELECT COUNT(*) INTO vcount1 FROM USERS
WHERE USEREMAIL=in_email and isactive=1;
if vcount1=1 then
return('1');
else
return('0');
end if;
ELSE
RETURN('2');
END IF;
END
code that worked for PDO ::
<?php
//print_r($_POST);
try {
$dbh = new PDO(PDO("mysql:dbname=mydb;host=myhost", "myuser", "mypass" );
$value = $_POST['myLname'];
$result = $dbh->prepare("select check_user_exists(?) as retval");
$result->bindParam(1, $value, PDO::PARAM_STR, 2);
$result->setFetchMode(PDO::FETCH_CLASS, 'stdClass');
$result->execute();
$obj = $result->fetch();
print($obj->retval);
echo "PDO connection object created";
$dbh = null;
}
catch(PDOException $e)
{
echo $e->getMessage();
}
?>
The reason is, you aren't fetching the results from the query.
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);