I'm going through a video tutorial about doing a menu using a db. Instead of doing it with procedural PHP like in the video, I tried doing it with prepared statements OOP style. It doesn't work and I can't figure out why.
It runs fine until line 17, where it dies with this error:
Fatal error: Call to a member function bind_param() on a non-object in C:\wamp\www\widget_corp\content.php on line 17
And here's the code:
<?php
$query = $connection->prepare('SELECT menu_name, id FROM subjects ORDER BY position ASC;');
$query->execute();
$query->bind_result($menu_name, $sid);
while ($query->fetch()){
echo "<li>{$menu_name} {$sid}</li>";
$query2 = $connection->prepare('SELECT menu_name FROM pages WHERE subject_id = ? ORDER BY position ASC;');
$query2->bind_param("i", $sid); //This is line 17
$query2->execute();
$query2->bind_result($menu_name);
echo "<ul class='pages'>";
while ($query2->fetch()){
echo "<li>{$menu_name}</li>";
}
echo "</ul>";
}
$query->close();
?>
Is it impossible to do a prepared statement within stmt->fetch();?
Figured it out:
After executing and binding the result, it has to be stored (if another prepared statement is to be put in the fetch). So the fetching in this case has to be read from a buffered result.
In other words, can't execute another query until a fetch on the same connection is in progress.
The working code:
$query = $connection->prepare("SELECT menu_name, id FROM subjects ORDER BY position ASC;");
$query->execute();
$query->bind_result($menu_name, $sid);
$query->store_result();
$stmt = mysqli_prepare($con,"SELECT menu_name, id FROM subjects ORDER BY position ASC");
mysqli_stmt_execute($stmt);
mysqli_stmt_bind_result($stmt, $menu_name, $id);
while (mysqli_stmt_fetch($stmt))
{
$stmt2 = mysqli_prepare($con2,"SELECT menu_name FROM pages WHERE subject_id = ? ORDER BY position ASC;");
mysqli_stmt_bind_param($stmt2,$id);
mysqli_stmt_execute($stmt2);
mysqli_stmt_bind_result($stmt2, $name);
while (mysqli_stmt_fetch($stmt2))
echo $name;
}
look at the $con and $con2, you can not execute a prepare statement within another ps using the same connection !!!
Yes, you can have several prepared statements : one of the ideas of prepared statements is "prepare once, execute several times".
So, you should prepare the statement outside of the loop -- so it's prepared only once
And execute it, several times, insidde the loop.
The Fatal error you get means that $query2 on line 17, is not an object -- which means the prepare failed.
A prepare typically fails when there is an error in it ; are you sure your query is valid ? The tables and columns names are OK ?
You should be able to get an error message, when the prepare fails, using mysqli->error() -- or PDO::errorInfo()
You don't say what DB extension you are using but you don't seem to test the return value of any function you are using. You can't assume that DB calls will always run flawlessly.
Related
So I'm trying to execute the following sql query:
$stmt = $connect->query("SELECT `FID`,`StorageID`,`DestructionDate` FROM `files` WHERE `DestructionDate` < ':date'");
$stmt->bindValue(":date",$date);
$stmt->execute();
while ($row = $stmt->fetch()) {
$fid = $row['FID'];
echo $fid . " ";
}
The above code will return all records from files, it simply ignores the WHERE statement at all, and just to be clear, when I run the same statement on phpMyAdmin it runs just fine, in fact I even tried binding the value inside the query itself like this
$stmt = $connect->query("SELECT FID,StorageID,DestructionDate FROM files WHERE DestructionDate < '$date'");
And the query was executed correctly and only gave me the records that satisfy the WHERE condition, so the error is definitely in the bindValue() and execute() lines.
From docs:
PDO::query — Executes an SQL statement, returning a result set as a PDOStatement object
You possibly want PDO::prepare() followed by PDOStatement::execute(). (There's normally no need to painfully bind params one by one.)
Additionally, you have bogus quotes around the placeholder:
':date'
You'll note that as soon as you execute the statement because params won't match.
2 solutions :
First:
$stmt = $connect->prepare("SELECT `FID`,`StorageID`,`DestructionDate` FROM `files` WHERE `DestructionDate` < :date");
$stmt->execute(array('date' => $date);
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
Second:
$stmt = $connect->prepare("SELECT `FID`,`StorageID`,`DestructionDate` FROM `files` WHERE `DestructionDate` < ?");
$stmt->execute(array($date));
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
In both cases, you don't need to 'quote' the string to be replaced (:date or ?) because PDO parse the value in the right type corresponding to the column to match.
I'm having some trouble using a variable declared in PHP with an SQL query. I have used the resources at How to include a PHP variable inside a MySQL insert statement but have had no luck with them. I realize this is prone to SQL injection and if someone wants to show me how to protect against that, I will gladly implement that. (I think by using mysql_real_escape_string but that may be deprecated?)
<?php
$q = 'Hospital_Name';
$query = "SELECT * FROM database.table WHERE field_name = 'hospital_name' AND value = '$q'";
$query_result = mysqli_query($conn, $query);
while ($row = mysqli_fetch_assoc($query_result)) {
echo $row['value'];
}
?>
I have tried switching '$q' with $q and that doesn't work. If I substitute the hospital name directly into the query, the SQL query and PHP output code works so I know that's not the problem unless for some reason it uses different logic with a variable when connecting to the database and executing the query.
Thank you in advance.
Edit: I'll go ahead and post more of my actual code instead of just the problem areas since unfortunately none of the answers provided have worked. I am trying to print out a "Case ID" that is the primary key tied to a patient. I am using a REDCap clinical database and their table structure is a little different than normal relational databases. My code is as follows:
<?php
$q = 'Hospital_Name';
$query = "SELECT * FROM database.table WHERE field_name = 'case_id' AND record in (SELECT distinct record FROM database.table WHERE field_name = 'hospital_name' AND value = '$q')";
$query_result = mysqli_query($conn, $query);
while ($row = mysqli_fetch_assoc($query_result)) {
echo $row['value'];
}
?>
I have tried substituting $q with '$q' and '".$q."' and none of those print out the case_id that I need. I also tried using the mysqli_stmt_* functions but they printed nothing but blank as well. Our server uses PHP version 5.3.3 if that is helpful.
Thanks again.
Do it like so
<?php
$q = 'mercy_west';
$query = "SELECT col1,col2,col3,col4 FROM database.table WHERE field_name = 'hospital_name' AND value = ?";
if($stmt = $db->query($query)){
$stmt->bind_param("s",$q); // s is for string, i for integer, number of these must match your ? marks in query. Then variable you're binding is the $q, Must match number of ? as well
$stmt->execute();
$stmt->bind_result($col1,$col2,$col3,$col4); // Can initialize these above with $col1 = "", but these bind what you're selecting. If you select 5 times, must have 5 variables, and they go in in order. select id,name, bind_result($id,name)
$stmt->store_result();
while($stmt->fetch()){ // fetch the results
echo $col1;
}
$stmt->close();
}
?>
Yes mysql_real_escape_string() is deprecated.
One solution, as hinted by answers like this one in that post you included a link to, is to use prepared statements. MySQLi and PDO both support binding parameters with prepared statements.
To continue using the mysqli_* functions, use:
mysqli_prepare() to get a prepared statement
mysqli_stmt_bind_param() to bind the parameter (e.g. for the WHERE condition value='$q')
mysqli_stmt_execute() to execute the statement
mysqli_stmt_bind_result() to send the output to a variable.
<?php
$q = 'Hospital_Name';
$query = "SELECT value FROM database.table WHERE field_name = 'hospital_name' AND value = ?";
$statement = mysqli_prepare($conn, $query);
//Bind parameter for $q; substituted for first ? in $query
//first parameter: 's' -> string
mysqli_stmt_bind_param($statement, 's', $q);
//execute the statement
mysqli_stmt_execute($statement);
//bind an output variable
mysqli_stmt_bind_result($stmt, $value);
while ( mysqli_stmt_fetch($stmt)) {
echo $value; //print the value from each returned row
}
If you consider using PDO, look at bindparam(). You will need to determine the parameters for the PDO constructor but then can use it to get prepared statements with the prepare() method.
I am busy trying to execute a set of statements that involve the use of a temporary table.
My goal is to create the temporary table, insert values to it and then do a like comparison of the temporary tables contents to another table.
These statements are working perfectly in phpmyadmin when executed from RAW SQL, but I'm assuming that the table is not available when I try to insert the data.
Below is the code for my php function + mysqli execution:
function SearchArticles($Tags){
global $DBConn, $StatusCode;
$count = 0;
$tagCount = count($Tags);
$selectText = "";
$result_array = array();
$article_array = array();
foreach($Tags as $tag){
if($count == 0){
$selectText .= "('%".$tag."%')";
}else {
$selectText .= ", ('%".$tag."%')";
}
$count++;
}
$query = "CREATE TEMPORARY TABLE tags (tag VARCHAR(20));";
$stmt = $DBConn->prepare($query);
if($stmt->execute()){
$query2 = "INSERT INTO tags VALUES ?;";
$stmt = $DBConn->prepare($query2);
$stmt->bind_param("s", $selectText);
if($stmt->execute()){
$query3 = "SELECT DISTINCT art.ArticleID FROM article as art JOIN tags as t ON (art.Tags LIKE t.tag);";
$stmt = $DBConn->prepare($query3);
if($stmt->execute()){
$stmt->store_result();
$stmt->bind_result($ArticleID);
if($stmt->num_rows() > 0){
while($stmt->fetch()){
array_push($article_array, array("ArticleID"=>$ArticelID));
}
array_push($result_array, array("Response"=>$article_array));
}else{
array_push($result_array, array("Response"=>$StatusCode->Empty));
}
}else{
array_push($result_array, array("Response"=>$StatusCode->SQLError));
}
}else{
array_push($result_array, array("Response"=>$StatusCode->SQLError));
}
}else{
array_push($result_array, array("Response"=>$StatusCode->SQLError));
}
$stmt->close();
return json_encode($result_array);
}
The first statement executes perfectly, however the second statement gives me the error of:
PHP Fatal error: Call to a member function bind_param() on a non-object
If this is an error to do with the Temp table not existing, how do i preserve this table long enough to run the rest of the statements?
I have tried to use:
$stmt = $DBConn->multi_query(query);
with all the queries in one, but i need to insert data to one query and get data from the SELECT query.
Any help will be appreciated, thank you!
You have a simple syntax error use the brackets around the parameters like this
INSERT INTO tags VALUES (?)
This is not an issue with the temporary table. It should remain throughout the same connection (unless it resets with timeout, not sure about this part).
The error is that $stmt is a non-object. This means that your query was invalid (syntax error), so mysqli refused to create an instance of mysqli_stmt and returned a boolean instead.
Use var_dump($DBConn->error) to see if there are any errors.
Edit: I just noticed that your query $query2 is INSERT INTO tags VALUES ? (the ; is redundant anyway). If this becomes a string "text", this would become INSERT INTO tags VALUES "text". This is a SQL syntax error. You should wrap the ? with (), so it becomes INSERT INTO tags VALUES (?).
In conclusion, change this line:
$query2 = "INSERT INTO tags VALUES ?;";
to:
$query2 = "INSERT INTO tags VALUES (?);";
also note that you don't need the ; to terminate SQL statements passed into mysqli::prepare.
I don't know why this query won't return a value because when I copy the "echoed" portion into phpmyadmin I do get a record returning:
echo $_GET["cname"];
// Query template
$sql = 'SELECT C.cid FROM `Contact` C WHERE C.email="'.$_GET["cname"].'"';
echo $sql;
// Prepare statement
$stmt = $conn->prepare($sql);
$stmt->execute();
$stmt->bind_result( $res_cid);
echo $res_cid;
$res_cid is apparently 0, but I don't know why because when I paste that query manually into phpmyadmin I do get a value... So why doesn't it return anything?
As already mentioned in the comments - you should make sure your code is secured. You better use the bindparam for that.
As for your question - after you execute your query and bind_result you should also fetch to get the actual value from the database, based on your query:
// Prepare statement
$stmt = $conn->prepare($sql);
$stmt->execute();
$stmt->bind_result( $res_cid);
// Fetch to get the actual result
$stmt->fetch();
echo $res_cid;
I'm running two queries in my script room.php. Both are using MySQLi prepared statements, and their code are as follows:
/* Get room name */
$stmt = $mysqli->prepare('SELECT name FROM `rooms` WHERE r_id=?');
$stmt->bind_param('i', $roomID);
$stmt->execute();
$stmt->bind_result($roomName)
/* Add this user to the room */
$stmt = $mysqli->prepare('INSERT INTO `room_users` (r_id, u_id) VALUES (?, ?)');
$stmt->bind_param('ii', $roomID, $_SESSION['userID']);
$stmt->execute();
When I run the script, I get this error:
Fatal error: Call to a member function bind_param() on a non-object in C:\wamp\www\room.php on line 24
Which is the second query. If I remove the first query from the script, everything runs fine. Likewise if I remove the second query. Which leads me to believe there's a problem because I'm reusing the $stmt object. If I try the second query using $stmt2 I still get the error.
All my database tables and fields exist, so there's nothing wrong with the queries.
All of the mysqli functions/methods can fail in which case they will return false. I.e. if prepare() fails $stmt isn't an object you can call a method on but a bool(false). You have to check the return values and add some error handling, e.g.
$stmt = $mysqli->prepare('SELECT name FROM `rooms` WHERE r_id=?');
if ( !$stmt ) {
printf('errno: %d, error: %s', $mysqli->errno, $mysqli->error);
die;
}
$b = $stmt->bind_param('i', $roomID);
if ( !$b ) {
printf('errno: %d, error: %s', $stmt->errno, $stmt->error);
}
$b = $stmt->execute();
if ( !$b ) {
and so on and on
see http://docs.php.net/mysqli-stmt.errno et al
in this case you probably bumped into the problem that you can't create an other statement while there are still results/result sets pending for the previous statement.
see http://docs.php.net/mysqli-stmt.close:
Closes a prepared statement. mysqli_stmt_close() also deallocates the statement handle. If the current statement has pending or unread results, this function cancels them so that the next query can be executed.