MySQLi foreach bind_param() - php

I'm sending an array of values from a form. I want to loop through the database table looking for these IDs. As I get this message I understand something is wrong...
Fatal error: Call to a member function bind_param() on a non-object in /home/d15155/tool/pdf.php on line 56
if (count($_POST['q']) == 0){
}
else {
foreach($_POST['q'] as $quality){
# Prepare statement
$stmt = $mysqli->prepare("SELECT the_question, the_sub_questions, the_quality, the_time FROM my_questions WHERE the_category='2' AND the_headline='5' AND quality_id = ? ORDER BY the_sort_order ASC");
$stmt->bind_param('i', $quality);
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($the_question, $the_sub_questions, $the_quality, $the_time);
$stmt->fetch();
$konkretaexempel .= utf8_encode($the_question) . " <br />";
}
}
I want to add the results into a long string (then to be used in a PDF).
EDIT
Removed the foreach and the array and it still getting the same error message. I have checked and the database connection is OK.
if (count($_POST['q']) == 0){
}
else {
$stmt = $mysqli->prepare("SELECT the_question, the_sub_questions, the_quality, the_time FROM my_questions WHERE the_category='2' AND the_headline='5' AND quality_id = ? ORDER BY the_sort_order ASC");
$stmt->bind_param('i', '27');
$stmt->execute();
$stmt->bind_result($the_question, $the_sub_questions, $the_quality, $the_time);
$stmt->fetch();
$konkretaexempel .= utf8_encode($the_question) . " <br />";
}

Sean's tip in the comments is probably more than a side note here; it will get rid off the problem: There can be only one active query/statement per connection and after the single ->fetch() the statement is still active (a while-loop would fix that, but no need for that here). When you re-use the $stmt instance as suggested any old result set will be discarded.
Your script currently is like
<?php
$mysqli = setup();
if (count($_POST['q']) == 0){
myErrorHandling();
}
else {
foreach($_POST['q'] as $quality){
$stmt = $mysqli->prepare("SELECT x, y FROM soFoo WHERE id = ?");
if ( !$stmt ) { die('prepare failed'); }
$stmt->bind_param('i', $quality);
$stmt->execute();
$stmt->bind_result($x, $y);
$stmt->fetch();
printf("x=%d,y=%s\r\n", $x, $y);
}
}
function setup() {
// for demonstration purposes only
$_POST = [ 'q'=> [
1,3,5
]];
mysqli_report(MYSQLI_REPORT_STRICT);
$mysqli = new mysqli('localhost', 'localonly', 'localonly', 'test');
$mysqli->query('
CREATE TEMPORARY TABLE soFoo (
id int auto_increment,
x int,
y varchar(32),
primary key(id)
)
');
$stmt = $mysqli->prepare('INSERT INTO soFoo (x,y) VALUES (?,?)');
$stmt->bind_param('ss', $x, $y);
foreach( range('a','z') as $x=>$y ) {
$stmt->execute();
}
return $mysqli;
}
and the output is
x=0,y=a
prepare failed
Now when I move the calls to prepare/bind_param to before the loop
<?php
$mysqli = setup();
if (count($_POST['q']) == 0){
myErrorHandling();
}
else {
$stmt = $mysqli->prepare("SELECT x, y FROM soFoo WHERE id = ?");
if ( !$stmt ) { die('prepare failed'); }
$stmt->bind_param('i', $quality);
foreach($_POST['q'] as $quality){
$stmt->execute();
$stmt->bind_result($x, $y);
$stmt->fetch();
printf("x=%d,y=%s\r\n", $x, $y);
}
}
function setup() {
... same as before...
}
the output is
x=0,y=a
x=2,y=c
x=4,y=e
as expected.

Related

PHP call SQL Server SP returning data, output parameters and return value

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>";
?>

mysqli prepared statement while fetch doesn't work

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;
}

How to handle unknown multiple/single result with php pdo?

I just thought about this case and how to do it a bit more "professional". Does not seem to as if this the way to go even though I do not know any other. Somebody?!
$query = "SELECT col1 FROM ".PREFIX."table WHERE (col2 = :something)";
$stmt = $dbh->prepare($query);
$stmt->bindParam(":something", $something, PDO::PARAM_STR);
$stmt->execute();
$stmt->bindColumn(1, $col1, PDO::PARAM_STR);
/* get number of rows */
$num_rows = $dbh->query("SELECT FOUND_ROWS()")->fetchColumn();
if($num_rows == 1) {
$stmt->fetch();
$result = $col1;
} else {
while($stmt->fetch()) {
$result[] = $col1;
}
}

Return the id (auto increment) of an inserted line

I insert data into a table called 'roster'. The first column (id_roster) is an id using mysql auto-increment.
I run a SELECT to find the id_roster
I use this id_roster to insert it into a table 'roster_par_membre' along with other data
if ($insert_stmt = $mysqli->prepare("INSERT INTO `roster`(`nom_roster`, `description_roster`, `id_organisation`, `created_by`, `creation_date`,`modified_by`) VALUES (?, ?, ?, ?, ?, ?)")) {
$insert_stmt->bind_param('ssiisi', $roster_name, $description_roster, $organisation_id, $user_id, $creation_date, $user_id);
if (!$insert_stmt->execute()) {
$reponse = 'Sorry, a database error occurred; please try later';
} else {
// if INSERT OK -> create a new line in roster_membre table
//1. get the roster_id
$sql = "SELECT r.id_roster
FROM roster r
WHERE r.nom_roster = ?
LIMIT 1";
$stmt = $mysqli->prepare($sql);
if ($stmt) {
$stmt->bind_param('s', $roster_name);
$stmt->execute(); // Execute the prepared query.
$stmt->store_result();
$stmt->bind_result($id_roster);
$stmt->fetch();
$level = 1;
//2. create a line with the roster_id and insert the membre as level 1
$insert_stmt = $mysqli->prepare("INSERT INTO `roster_par_membre`(`id_membre`, `id_roster`, `level`, `modified_by`) VALUES (?,?,?,?)");
$insert_stmt->bind_param('iiii', $user_id, $id_roster, $level, $user_id);
$insert_stmt->execute();
$reponse = 'success';
}
So far the code is working but it is not very nice.
Is there a way when we create a new line in a table to directly return a value (id with auto-increment) to be used in a sql query (to insert data into a second table)? or maybe to merge the two query (the two INSERT) in one statment?
short edit: it is an AJAX $response the return value (JSON)
Ok,solution:
//1. get the roster_id
$sql = "SELECT r.id_roster
FROM roster r
WHERE r.nom_roster = ?
LIMIT 1";
$stmt = $mysqli->prepare($sql);
if ($stmt) {
$stmt->bind_param('s', $roster_name);
$stmt->execute(); // Execute the prepared query.
$stmt->store_result();
$stmt->bind_result($id_roster);
$stmt->fetch();
Just need to replace all this part by
$id_roster = $mysqli->insert_id;
nice and easy. THANKS to albanx
these are the functions I used for query on projects that I do not want to use any framework (just php):
/**
*
* Executes query methods
* #param string $query the query string
* #param array $vals array of values
* #param bool $show show the query
* #return int/array/false
*/
function q($query, $vals=array(), $show_query=false)
{
$conn = new mysqli(...)
$offset = 0;
foreach ($vals as $v)
{
$cv = $conn->real_escape_string($v);//escape the value for avoiding sql injection
$fv = ($v===NULL) ? 'NULL':"'".$cv."'"; //if value is null then insert NULL in db
$qpos = strpos($query, '?', $offset);//replace the ? with the valeue
$query = substr($query, 0, $qpos).$fv.substr($query, $qpos+1);
$offset = $qpos+strlen($cv)+1;
}
$result = $conn->query($query);
if($show || $result===false) echo $query."<br>";
$rows = array();
if($result===true)
{
return $conn->affected_rows;
}
else if($result===false)
{
return false;
}
else
{
while ($row = $result->fetch_array(MYSQLI_ASSOC) )
{
$rows[]=$row;
}
}
return $rows;
}
function lastid()
{
return $this->qval("SELECT LAST_INSERT_ID()");
}
Usage example:
q('INSERT INTO USER(name, email) VALUES(?,?)', array('admin','admin#admin.com'));
$id = lastid();

Best Way To Show User Their Photo

Okay so I was wondering what is the best way to show a user their own photo and if my way is safe or what should i change.
url:
http://localhost/project/everyone/myphoto.php?num=2
php code:
$user_id = $_SESSION['user_id'];
if (isset($_GET['num'])) {
$num = $_GET['num'];
if ($stmt = $dbconn->prepare("SELECT 1 FROM t_photos WHERE id ='$num' AND user_id ='$user_id' LIMIT 1")) {
$stmt->execute();
$stmt->store_result();
$rows = $stmt->num_rows;
if ($rows === 1) {
$stmt = $dbconn->prepare("SELECT url,uploaddate FROM t_photos WHERE id = ?");
$stmt->bind_param('i', $num); // Bind "$email" to parameter.
$stmt->execute(); // Execute the prepared query.
$stmt->store_result();
$stmt->bind_result($photopath, $uploadtime); // get variables from result.
$stmt->fetch();
} else {
$error2 = "Error 2";
require 'notfound.php';
die();
}
}
}
html & Php code :
<div id="pathwrap">
<div class="photowrap">
<?php if (isset($photopath)) {
echo '<img src="' . $photopath . '">';
} ?>
</div>
</div>
This is how I would do it with PDO and Exception style:
function requestCurrentUserPhoto(){
if( !isset($_GET['num']) ){
throw new Exception('Bad request. The generated link missing get prop num.');
}
if( !isset($_SESSION['user_id']) ){
throw new Exception('Bad request. The generated link linked to a guest.');
}
$sth = $dbh->prepare('SELECT url,uploaddate FROM t_photos WHERE id = :id AND user_id = :user_id LIMIT 1');
$sth->execute(array(
':id' => (int) $_GET['num'],
':user_id' => (int) $_SESSION['user_id']
));
$result = $sth->fetch(PDO::FETCH_ASSOC);
if( $result === false ){
throw new Exception('Bad request. The generated link linked to a non-existence photo or unauthorized user.');
}
//optional...
if( empty($result['url']) || empty($result['uploaddate']) ){
throw new Exception('Bad database table row. There is a invalid photo row in t_photos');
}
return $result;
}
This code should be safe. And it should also check if the code that is related got any errors.

Categories