Close statement object before starting a new with prepared statements - php

I'm quite new at using prepared statements and is wondering if I should close the stmt_init() after each call or could I just keep it open?
$stmt = $mysqli->stmt_init();
if($stmt->prepare("SELECT player_draws, player_turn, player_passes, swapped FROM ".$prefix."_gameplayer WHERE fk_game_id = ? AND fk_player_id = ?")){
$stmt->bind_param('ii', $currgame, $playerid);
$stmt->execute();
$stmt->bind_result($udraws, $uturn, $upass, $uswaps);
$stmt->fetch();
echo $udraws.'-'.$uturn.'-'.$upass.'-'.$uswaps.'<br>';
// Close statement object
$stmt->close();
}
$stmt = $mysqli->stmt_init();
if($stmt->prepare("SELECT player_draws, player_turn, player_passes, swapped FROM ".$prefix."_gameplayer WHERE fk_game_id = ? AND fk_player_id != ?")){
$stmt->bind_param('ii', $currgame, $playerid);
$stmt->execute();
$stmt->bind_result($odraws, $oturn, $opass, $oswaps);
$stmt->fetch();
echo $odraws.'-'.$oturn.'-'.$opass.'-'.$oswaps.'<br>';
// Close statement object
$stmt->close();
}
Is one of them better for the database considering calls?
Thanks in advance!

...A prepared statement or a parameterized statement is used to execute the same statement repeatedly with high efficiency...
EDIT
Since the queries are different each of them will need to be prepared separately but you should be able to reuse the $mysqli->stmt_init();
On a side note someone mentions this in the comments:
*if you are repeating an statement in an loop using bind_param and so on inside it for a larger operation. i thougt id would be good to clean it with stmt->close. but it broke always with an error after aprox. 250 operations . As i tried it with stmt->reset it worked for me.*

Related

Parametrized queries in PHP

$postid = $_GET['p'];
$stmt = $conn->prepare("SELECT * FROM posts WHERE post_id=:postid");
$stmt->bindValue(':postid', $postid);
$stmt->execute();
while($postRows = mysqli_fetch_assoc($stmt)){
$posts[] = $postRows;
}
The above code does not work.
Usually I'd do:
$postid = mysqli_real_escape_string($conn,$_GET['p']);
$result = mysqli_query($conn,"SELECT * FROM posts WHERE post_id='$postid'");
while($postRows = mysqli_fetch_assoc($result)){
$posts[] = $postRows;
}
which works for me.
I can't seem to get my head around this because online explanations do a poor job of actually explaining how to do these, so I have been using mysqli_real_escape_string instead but I understand it can be vulnerable.
Can anyone help me understand how to properly do these queries?
You can try this code
$stmt = $conn->prepare("SELECT * FROM posts WHERE post_id=:postid");
$stmt->bindValue(':postid', $postid, PDO::PARAM_INT);
$stmt->execute();
$posts = $stmt->fetchAll(PDO::FETCH_ASSOC);
This could help you:Mysql prepare statement - Select
And an Example from PHP on using bindValue()website(http://php.net/manual/en/pdostatement.bindvalue.php example#2):
<?php
/* Execute a prepared statement by binding PHP variables */
$calories = 150;
$colour = 'red';
$sth = $dbh->prepare('SELECT name, colour, calories
FROM fruit
WHERE calories < ? AND colour = ?');
$sth->bindValue(1, $calories, PDO::PARAM_INT);
$sth->bindValue(2, $colour, PDO::PARAM_STR);
$sth->execute();
?>
In this example they are specifying parameter type in the bindValue() statement such as PDO::PARAM_STR and PDO::PARAM_INT. You too try specifying your parameter as such.
Or you can also prepare statements and bind values using bindParam(':placeholder',$variable_or_value); (http://www.w3schools.com/php/php_mysql_prepared_statements.asp)
Prepared statements are used for executing same query multiple times with different or changing values. It gives more efficiency. For simple or random queries there is no need to prepare statements infact it will only decrease the effificeny b creating overheads for preparations. And prepared statements are generally applied on INSERT and UPDATE statements
I guess what you want to do might be:
$stmt = $conn->prepare('SELECT * FROM posts WHERE post_id = ?');
//Use 's' for a string or 'i' for an integer
$stmt->bind_param('s', $postid);
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc())
{ }
As I said in comments, you are mixing MySQL APIs (mysqli_ and PDO).
You need to use the same API from connecting to querying. Those different APIs do not intermix.
In order to use PDO, you need to:
Connect using PDO http://php.net/manual/en/pdo.connections.php
Query with PDO http://php.net/manual/en/pdo.query.php
Then if you want to use PDO with prepared statements:
http://php.net/pdo.prepared-statements
You cannot connect with mysqli_ then mix MySQL functions with PDO.
That's how it rolls.
Footnotes:
If you want to stick with mysqli_, then it too has prepared statements.
http://www.php.net/manual/en/mysqli.quickstart.prepared-statements.php
The choice is yours. Remember to use the same MySQL API.
Error checking:
http://php.net/manual/en/pdo.error-handling.php - if using all PDO
http://php.net/manual/en/mysqli.error.php - If using all MySQLi
Add error reporting to the top of your file(s) which will help find errors.
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
// rest of your code
Sidenote: Displaying errors should only be done in staging, and never production.

Order of execution for prepared statement in php

I've read everything there is to read about prepared statements and im still not sure about the order of execution... (many use different order).
Is this a good order ?
$sql = 'SELECT * FROM ... WHERE ... = ?';
$conn = ...connection to database...
$stmt = $conn->stmt_init();
$stmt->prepare($sql);
$stmt->bind_param('i', $param);
$stmt->execute();
$stmt->store_result(); // results are cached and accessed from memeory, therefore faster but use more memory
$num_rows = $stmt->num_rows; // how many? (can only be use with store_result() )
$stmt->bind_result($column, ...);
$stmt->fetch(); // use in loop if necessary
$stmt->free_result(); // use only with store_result()
$stmt->close(); // close prepared statement
$conn->close(); // close database
Apparently not.
Although order is quite all right, many operators you have used are superfluous and useless. Also, there should be no connection related code in the context of execution single query.
include 'db.php'; // here goes connect
$sql = 'SELECT * FROM ... WHERE ... = ?';
$stmt->prepare($sql);
$stmt->bind_param('i', $param);
$stmt->execute();
$stmt->bind_result($column, ...);
$stmt->fetch();
is enough. Note that you never need row_count if you have data.

how to use mysqli_fetch_array with prepared statements

so everyone told me to use prepared statements, but i have no idea what to do now.
$stmt = mysqli_prepare($con, "SELECT * FROM search WHERE `name2` LIKE '?' AND `approved`='approved'");
mysqli_stmt_bind_param($stmt, 's', $name);
/* execute prepared statement */
mysqli_stmt_execute($stmt);
That is my code, how do i make an array from it like
while ($row=mysqli_fetch_array($result))
from non-prepared
Glad to see you are deciding to use PDO!
//using MySQL
//refer here for reference http://www.php.net/manual/en/ref.pdo-mysql.php
$pdo = new PDO('mysql:host=xxx;port=xxx;dbname=xxx', $username, $password)
//write query
$sql = "SELECT * FROM search WHERE `name2` LIKE '?' AND `approved`='approved'";
//tell query what to replace ? marks with
$fill_array = array($name); // one item in array for the one ? in $sql above
//send query to DB for preparation
$prepare = $pdo->prepare($sql);
//send variables to DB, DB will bind them to the proper place and execute query
$prepare->execute($fill_array);
//get your array. I personally recommend PDO::FETCH_ASSOC but you are using ARRAY
$result = $prepare->fetchAll(PDO::FETCH_ARRAY);
echo '<pre>'.print_r($result, true).'</pre>';
Voila!
Please not that you will have to write code to escape $name and check for things like % signs and underscores because if someone literally types in % then the LIKE statement will return all records where approved='approved'

loop prepare statements, what needs to be repeated?

I'm using statements to protect against sql injections... My question is what do i need to repeat when looping multiple queries?
If you look at the second query, im not sure if the prepare statement needs to be insde the foreach loop
Something wrong with this summary code?
open database connection
// connect to database
$conn = connect('r');
launch first query
$sql = "SELECT ... FROM ... WHERE xxx = ?";
$stmt = $conn->stmt_init();
$stmt->prepare($sql);
$stmt->bind_param('i', $albumid);
$stmt->bind_result(..., ...);
$stmt->execute();
$stmt->store_result();
$num_rows = $stmt->num_rows;
if ($num_rows > 0) {
loop results...
}
$stmt->free_result();
second query with repeats:
$sql = "SELECT ... FROM ... WHERE xxx = ?";
$stmt = $conn->stmt_init();
$stmt->prepare($sql); ///??????? inside or outside foreach loop ?????
foreach (... as $key => ...) {
$stmt->bind_param('i', $key);
$stmt->bind_result(...);
$stmt->execute();
$stmt->store_result();
$num_rows = $stmt->num_rows;
if ($num_rows > 0) {
loop results...
}
$stmt->free_result();
}
close database
// close database
$conn->close();
You don't have to prepare the query multiple times. Just bind the parameters and execute it multiple times.
From the PHP Manual:
For a query that you need to issue multiple times, you will realize
better performance if you prepare a PDOStatement object using
PDO::prepare() and issue the statement with multiple calls to
PDOStatement::execute().
Hope this helps.

PHP prepared statement within a prepared statement

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.

Categories