Understanding PHP Prepared Statements - php

I have a website, and the user has just logged in and it redirects them to the User Dashboard. I have the user_id in a SESSION so I can use that for my SELECT queries to grab other information about the user.
My question is, how can I use Prepared Statments to just grab the variables that I need for that page, without using a foreach statement or a while statement. It will just be for that specific user logged in, not displaying information for multiple users.
Every example I look up is like this:
$query = "SELECT Name, CountryCode FROM City ORDER by ID DESC LIMIT 150,5";
if ($stmt = $mysqli->prepare($query)) {
/* execute statement */
$stmt->execute();
/* bind result variables */
$stmt->bind_result($name, $code);
/* fetch values */
while ($stmt->fetch()) {
printf ("%s (%s)\n", $name, $code);
}
/* close statement */
$stmt->close();
}
/* close connection */
$mysqli->close();
Does it have to be in a while statement? I just need the variables at the top, so I can display my regular page and then use the variables when I need to. Does that make sense?
Just looking to learn more and get a better understanding of how this works.

If you just need the top record:
/* fetch values */
$stmt->fetch();
printf ("%s (%s)\n", $name, $code);
$stmt->fetch will fetch the first row, you don't need the while unless you want to continue through all the rows.

Related

MySQL returns only the first character of the fields, but works fine on local

I don't know what is going on exactly, but all only the first character is returned for all my columns when I uploaded my website. It works perfectly fine on a local machine.
I found a similar question here, but I didn't manage to find the answer:
https://stackoverflow.com/questions/10507848/mysql-query-returns-only-the-first-letter-of-strings-only-when-page-is-viewed-on
// Log Table Query
unset($stmt);
$stmt = $db->stmt_init();
$stmt = $db->prepare( "SELECT * FROM logs ORDER BY `id` DESC" );
$stmt->store_result();
$stmt->bind_result($r_id, $r_time, $r_logger, $r_message, $r_category);
$stmt->execute();
while( $stmt->fetch() )
{
var_dump($r_message);
var_dump($r_category);
}
$stmt->close();
This outputs on localhost for example:
string(5) "Hello"String(3) "Cow"
But on the live server:
string(1) "H"String(1) "C"
Any ideas?
Edit
I think that this applies only to string types. The integer types return for example:
int(2893)
I'm assuming that your database or table config is similar to your localhost (better to double check your table).
I noticed one mistake:1. You called store_result() before calling execute(). As per http://php.net/manual/en/mysqli-stmt.store-result.php execute() should be called first.
See my code this might solve your problem:
/* unsetting doesn't matter you're
going to overwrite it anyway */
unset($stmt);
/* you dont need to initialize $stmt with $db->stmt_init(),
$db->prepare() method will create it for you */
$stmt = $db->stmt_init();
$stmt = $db->prepare("SELECT * FROM logs ORDER BY `id` DESC");
/* execute the query first before storing
the result and binding it your variables */
if (!$stmt->execute()) {
echo "query execution error";
exit();
}
/* store the result */
$stmt->store_result();
/* then bind your variables */
$stmt->bind_result($r_id, $r_time, $r_logger, $r_message, $r_category);
/* fetch data and display */
while($stmt->fetch()) {
var_dump($r_message);
var_dump($r_category);
}
$stmt->close();
Let me know if this solved your problem.
Alternatively, you can use the straight forward way since you're not giving any input parameter like WHERE first_name LIKE <input here> to your query:
$result = $db->query("SELECT * FROM logs ORDER BY `id` DESC");
if ($result === false) {
echo "query execution error";
exit();
}
/* You can use either MYSQLI_NUM or MYSQLI_ASSOC os MYSQLI_BOTH
see php.net for more info */
echo "<pre>";
while($line = $result->fetch_array(MYSQLI_NUM)) {
print_r($line);
echo "\n";
}
echo "</pre>";
As suggested in the question you linked, try the code without unset($stmt) and $stmt = db->stmt_init() Instead, you might use free_result()
// Log Table Query
$stmt->free_result(); //Free old results first
$stmt = $db->prepare( "SELECT * FROM logs ORDER BY `id` DESC" );
$stmt->store_result();
$stmt->bind_result($r_id, $r_time, $r_logger, $r_message, $r_category);
$stmt->execute();
while( $stmt->fetch() )
{
var_dump($r_message);
var_dump($r_category);
}
$stmt->close();

MySQLi Prepared SELECT Statement not returning proper value? [duplicate]

I would like to see an example of how to call using bind_result vs. get_result and what would be the purpose of using one over the other.
Also the pro and cons of using each.
What is the limitation of using either and is there a difference.
Although both methods work with * queries, when bind_result() is used, the columns are usually listed explicitly in the query, so one can consult the list when assigning returned values in bind_result(), because the order of variables must strictly match the structure of the returned row.
Example 1 for $query1 using bind_result()
$query1 = 'SELECT id, first_name, last_name, username FROM `table` WHERE id = ?';
$id = 5;
$stmt = $mysqli->prepare($query1);
/*
Binds variables to prepared statement
i corresponding variable has type integer
d corresponding variable has type double
s corresponding variable has type string
b corresponding variable is a blob and will be sent in packets
*/
$stmt->bind_param('i',$id);
/* execute query */
$stmt->execute();
/* Store the result (to get properties) */
$stmt->store_result();
/* Get the number of rows */
$num_of_rows = $stmt->num_rows;
/* Bind the result to variables */
$stmt->bind_result($id, $first_name, $last_name, $username);
while ($stmt->fetch()) {
echo 'ID: '.$id.'<br>';
echo 'First Name: '.$first_name.'<br>';
echo 'Last Name: '.$last_name.'<br>';
echo 'Username: '.$username.'<br><br>';
}
Example 2 for $query2 using get_result()
$query2 = 'SELECT * FROM `table` WHERE id = ?';
$id = 5;
$stmt = $mysqli->prepare($query2);
/*
Binds variables to prepared statement
i corresponding variable has type integer
d corresponding variable has type double
s corresponding variable has type string
b corresponding variable is a blob and will be sent in packets
*/
$stmt->bind_param('i',$id);
/* execute query */
$stmt->execute();
/* Get the result */
$result = $stmt->get_result();
/* Get the number of rows */
$num_of_rows = $result->num_rows;
while ($row = $result->fetch_assoc()) {
echo 'ID: '.$row['id'].'<br>';
echo 'First Name: '.$row['first_name'].'<br>';
echo 'Last Name: '.$row['last_name'].'<br>';
echo 'Username: '.$row['username'].'<br><br>';
}
bind_result()
Pros:
Works with outdated PHP versions
Returns separate variables
Cons:
All variables have to be listed manually
Requires more code to return the row as array
The code must be updated every time when the table structure is changed
get_result()
Pros:
Returns associative/enumerated array or object, automatically filled with data from the returned row
Allows fetch_all() method to return all returned rows at once
Cons:
requires MySQL native driver (mysqlnd)
Examples you can find on the respective manual pages, get_result() and bind_result().
While pros and cons are quite simple:
get_result() is the only sane way to handle results
yet it could be not always available on some outdated and unsupported PHP version
In a modern web application the data is never displayed right off the query. The data has to be collected first and only then output has to be started. Or even if you don't follow the best practices, there are cases when the data has to be returned, not printed right away.
Keeping that in mind let's see how to write a code that returns the selected data as a nested array of associative arrays using both methods.
bind_result()
$query1 = 'SELECT id, first_name, last_name, username FROM `table` WHERE id = ?';
$stmt = $mysqli->prepare($query1);
$stmt->bind_param('s',$id);
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($id, $first_name, $last_name, $username);
$rows = [];
while ($stmt->fetch()) {
$rows[] = [
'id' => $id,
'first_name' => $first_name,
'last_name' => $last_name,
'username' => $username,
];
}
and remember to edit this code every time a column is added or removed from the table.
get_result()
$query2 = 'SELECT * FROM `table` WHERE id = ?';
$stmt = $mysqli->prepare($query2);
$stmt->bind_param('s', $id);
$stmt->execute();
$rows = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
and this code remains the same when the table structure is changed.
And there's more.
In case you decide to automate the boring routine of preparing/binding/executing into a neat function that would be called like this
$query = 'SELECT * FROM `table` WHERE id = ?';
$rows = prepared_select($query, [$id])->fetch_all(MYSQLI_ASSOC);
with get_result() it will be quite a plausible task, a matter of just a few lines. But with bind_param() it will will be a tedious quest.
That's why I call the bind_result() method "ugly".
get_result() is only available in PHP by installing the MySQL native driver (mysqlnd). In some environments, it may not be possible or desirable to install mysqlnd.
Notwithstanding, you can still use mysqli to do SELECT * queries, and get the results with the field names - although it is slightly more complicated than using get_result(), and involves using PHP's call_user_func_array() function. See example at How to use bind_result() instead of get_result() in php which does a simple SELECT * query and outputs the results (with the column names) to an HTML table.
Main difference I've noticed is that bind_result() gives you error 2014, when you try to code nested $stmt inside other $stmt, that is being fetched (without mysqli::store_result() ):
Prepare failed: (2014) Commands out of sync; you can't run this command now
Example:
Function used in main code.
function GetUserName($id)
{
global $conn;
$sql = "SELECT name FROM users WHERE id = ?";
if ($stmt = $conn->prepare($sql)) {
$stmt->bind_param('i', $id);
$stmt->execute();
$stmt->bind_result($name);
while ($stmt->fetch()) {
return $name;
}
$stmt->close();
} else {
echo "Prepare failed: (" . $conn->errno . ") " . $conn->error;
}
}
Main code.
$sql = "SELECT from_id, to_id, content
FROM `direct_message`
WHERE `to_id` = ?";
if ($stmt = $conn->prepare($sql)) {
$stmt->bind_param('i', $myID);
/* execute statement */
$stmt->execute();
/* bind result variables */
$stmt->bind_result($from, $to, $text);
/* fetch values */
while ($stmt->fetch()) {
echo "<li>";
echo "<p>Message from: ".GetUserName($from)."</p>";
echo "<p>Message content: ".$text."</p>";
echo "</li>";
}
/* close statement */
$stmt->close();
} else {
echo "Prepare failed: (" . $conn->errno . ") " . $conn->error;
}

Which is correct way to get last inserted id in mysqli prepared statements procedural style?

i am using mysqli prepared statement to insert record in the table like this
$link = mysqli_connect('localhost', 'my_user', 'my_password', 'world');
/* check connection */
if (!$link) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
$stmt = mysqli_prepare($link, "INSERT INTO CountryLanguage VALUES (?, ?, ?, ?)");
mysqli_stmt_bind_param($stmt, 'sssd', $code, $language, $official, $percent);
$code = 'DEU';
$language = 'Bavarian';
$official = "F";
$percent = 11.2;
/* execute prepared statement */
mysqli_stmt_execute($stmt);
if(mysqli_stmt_affected_rows($stmt) > 0){
//if insert is successful then get the insrted id.
}
/* close statement and connection */
mysqli_stmt_close($stmt);
/* close connection */
mysqli_close($link);
and would like to get the last inserted id , as the table has record_num field which is auto increment .
so my question is should i place connection name or the statement name inside the function.
i.e
1)
echo mysqli_insert_id($link);
Source: http://php.net/manual/en/mysqli.insert-id.php
2)
echo mysqli_stmt_insert_id($stmt);
Source: http://php.net/manual/en/mysqli-stmt.insert-id.php
which one is correct ?
which one will give me last insrted id by the $stmt ?
there are no other inserts are being done using the same stmt one the same page..*
Update:
according to the note from http://php.net/manual/en/mysqli-stmt.insert-id.php
I am doing only single insert so i guess i can use
mysqli_stmt_insert_id($stmt)
but while doing multiple inserts using prepared statements using
echo mysqli_insert_id($link);
is best practice.
You should use
mysqli_insert_id($link);
Because of this note on the PHP manual you referred us to
mysqli_stmt_insert_id
It should be noted that using mysqli_stmt->insert_id will not result in a unique ID being returned for each execution of a prepared insert statement. In practice, it appears that the first insertion ID is returned. If you are performing multiple inserts with the same prepared statement (one invocation of mysqli_stmt::prepare and multiple invocations of mysqli_stmt::execute() for a given statement), and need to keep the unique ID for each insert, use mysqli_connection->insert_id.
for procedural language you need to use below code,
mysqli_insert_id($link));
yes as you mention in 1 point.
Correct is 1) - link, as stated in documentation:
http://php.net/manual/en/mysqli.insert-id.php

question about mysqli prepared statements

I have basic question about mysqli prepared statements. For example, I want to execute a SELECT query, Should I do it like:
<?
$city = "Amersfoort";
if ($stmt = $mysqli->prepare("SELECT District FROM City WHERE Name=?")) {
$stmt->bind_param("s", $city);
$stmt->execute();
$stmt->bind_result($district);
$stmt->close();
}
$mysqli->close();
?>
In the above code, is bind_result also required? What exactly it does?
Also, do I need need to close mysqli connection after each query?
Thanks.
bind_result makes it so that when you iterate over the results of the query, the columns from the result set are automatically mapped to local variables.
For example, suppose you execute a query that returns a result set with three columns like this:
$query = "SELECT Name, CountryCode, District FROM myCity";
You want to execute the query and do something with the results, let's say print them:
if ($result = $mysqli->query($query)) {
while ($row = $result->fetch_row()) {
printf("%s (%s,%s)\n", $row[0], $row[1], $row[2]);
}
}
The "problem" with the above code is that $row[0] is not very descriptive. An alternative way is to use bind_result, which goes like this:
$query = "SELECT Name, CountryCode, District FROM myCity";
if ($stmt = $mysqli->prepare($query)) {
$stmt->bind_result($name, $countryCode, $district);
while ($stmt->fetch()) {
printf("%s (%s,%s)\n", $name, $countryCode, $district);
}
}
As you see, when using bind_result each time you call fetch the variables $name, $countryCode, $district are automatically populated with the values from the current result row. There are some details that you must ensure, read the documentation for more info.
To answer your other question: you do not need to, and indeed you must not close the connection after each query (unless you know very well what you are doing).
bind_result assigns the variable to which data will be written. And you can keep the connection open. Just make sure you call $stmt->fetch() after $stmt->bind_result($district);
Check out Example #1 here:
http://www.php.net/manual/en/mysqli-stmt.bind-result.php

How to create a secure mysql prepared statement in php?

I am new to using prepared statements in mysql with php. I need some help creating a prepared statement to retrieve columns.
I need to get information from different columns. Currently for a test file, I use the completely unsecure SQL statement:
$qry = "SELECT * FROM mytable where userid='{$_GET['userid']}' AND category='{$_GET['category']}'ORDER BY id DESC"
$result = mysql_query($qry) or die(mysql_error());
Can someone help me create a secure mysql statement using input from url parameters (as above) that is prepared?
BONUS: Prepared statements are suppose to increase speed as well. Will it increase overall speed if I only use a prepared statement three or four times on a page?
Here's an example using mysqli (object-syntax - fairly easy to translate to function syntax if you desire):
$db = new mysqli("host","user","pw","database");
$stmt = $db->prepare("SELECT * FROM mytable where userid=? AND category=? ORDER BY id DESC");
$stmt->bind_param('ii', intval($_GET['userid']), intval($_GET['category']));
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($column1, $column2, $column3);
while($stmt->fetch())
{
echo "col1=$column1, col2=$column2, col3=$column3 \n";
}
$stmt->close();
Also, if you want an easy way to grab associative arrays (for use with SELECT *) instead of having to specify exactly what variables to bind to, here's a handy function:
function stmt_bind_assoc (&$stmt, &$out) {
$data = mysqli_stmt_result_metadata($stmt);
$fields = array();
$out = array();
$fields[0] = $stmt;
$count = 1;
while($field = mysqli_fetch_field($data)) {
$fields[$count] = &$out[$field->name];
$count++;
}
call_user_func_array(mysqli_stmt_bind_result, $fields);
}
To use it, just invoke it instead of calling bind_result:
$stmt->store_result();
$resultrow = array();
stmt_bind_assoc($stmt, $resultrow);
while($stmt->fetch())
{
print_r($resultrow);
}
You can write this instead:
$qry = "SELECT * FROM mytable where userid='";
$qry.= mysql_real_escape_string($_GET['userid'])."' AND category='";
$qry.= mysql_real_escape_string($_GET['category'])."' ORDER BY id DESC";
But to use prepared statements you better use a generic library, like PDO
<?php
/* Execute a prepared statement by passing an array of values */
$sth = $dbh->prepare('SELECT * FROM mytable where userid=? and category=?
order by id DESC');
$sth->execute(array($_GET['userid'],$_GET['category']));
//Consider a while and $sth->fetch() to fetch rows one by one
$allRows = $sth->fetchAll();
?>
Or, using mysqli
<?php
$link = mysqli_connect("localhost", "my_user", "my_password", "world");
/* check connection */
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
$category = $_GET['category'];
$userid = $_GET['userid'];
/* create a prepared statement */
if ($stmt = mysqli_prepare($link, 'SELECT col1, col2 FROM mytable where
userid=? and category=? order by id DESC')) {
/* bind parameters for markers */
/* Assumes userid is integer and category is string */
mysqli_stmt_bind_param($stmt, "is", $userid, $category);
/* execute query */
mysqli_stmt_execute($stmt);
/* bind result variables */
mysqli_stmt_bind_result($stmt, $col1, $col2);
/* fetch value */
mysqli_stmt_fetch($stmt);
/* Alternative, use a while:
while (mysqli_stmt_fetch($stmt)) {
// use $col1 and $col2
}
*/
/* use $col1 and $col2 */
echo "COL1: $col1 COL2: $col2\n";
/* close statement */
mysqli_stmt_close($stmt);
}
/* close connection */
mysqli_close($link);
?>
I agree with several other answers:
PHP's ext/mysql has no support for parameterized SQL statements.
Query parameters are considered more reliable in protecting against SQL injection issues.
mysql_real_escape_string() can also be effective if you use it correctly, but it's more verbose to code.
In some versions, international character sets have cases of characters that are not escaped properly, leaving subtle vulnerabilities. Using query parameters avoids these cases.
You should also note that you still have to be cautious about SQL injection even if you use query parameters, because parameters only take the place of literal values in SQL queries. If you build SQL queries dynamically and use PHP variables for the table name, column name, or any other part of SQL syntax, neither query parameters nor mysql_real_escape_string() help in this case. For example:
$query = "SELECT * FROM $the_table ORDER BY $some_column";
Regarding performance:
The performance benefit comes when you execute a prepared query multiple times with different parameter values. You avoid the overhead of parsing and preparing the query. But how often do you need to execute the same SQL query many times in the same PHP request?
Even when you can take advantage of this performance benefit, it is usually only a slight improvement compared to many other things you could do to address performance, like using opcode caching or data caching effectively.
There are even some cases where a prepared query harms performance. For example in the following case, the optimizer can't assume it can use an index for the search, because it must assume the parameter value might begin with a wildcard:
SELECT * FROM mytable WHERE textfield LIKE ?
Security with MySQL in PHP (or any other language for that matter) is a largely discussed issue. Here are a few places for you to pick up some great tips:
http://webmaster-forums.code-head.com/showthread.php?t=939
http://www.sitepoint.com/article/php-security-blunders/
http://dev.mysql.com/tech-resources/articles/guide-to-php-security.html
http://www.scribd.com/doc/17638718/Module-11-PHP-MySQL-Database-Security-16
The two most major items in my opinion are:
SQL Injection: Be sure to escape all of your query variables with PHP's mysql_real_escape_string() function (or something similar).
Input Validation: Never trust the user's input. See this for a tutorial on how to properly sanitize and validation your inputs.
If you're going to use mysqli - which seems the best solution to me - I highly recommend downloading a copy of the codesense_mysqli class.
It's a neat little class that wraps up and hides most of the cruft that accumulates when using raw mysqli such that using prepared statements only takes a line or two extra over the old mysql/php interface
Quite late, but this might help someone:
/**
* Execute query method. Executes a user defined query
*
* #param string $query the query statement
* #param array(Indexed) $col_vars the column variables to replace parameters. The count value should equal the number of supplied parameters
*
* Note: Use parameters in the query then supply the respective replacement variables in the second method parameter. e.g. 'SELECT COUNT(*) as count FROM foo WHERE bar = ?'
*
* #return array
*/
function read_sql($query, $col_vars=null) {
$conn = new mysqli('hostname', 'username', 'user_pass', 'dbname');
$types = $variables = array();
if (isset($col_vars)) {
for ($x=0; $x<count($col_vars); $x++) {
switch (gettype($col_vars[$x])) {
case 'integer':
array_push($types, 'i');
break;
case 'double':
array_push($types, 'd');
break;
default:
array_push($types, 's');
}
array_push($variables, $col_vars[$x]);
}
$types = implode('', $types);
$sql = $conn->prepare($query);
$sql -> bind_param($types, ...$variables);
$sql -> execute();
$results = $sql -> get_result();
$sql -> close();
}else {
$results = $conn->query($query) or die('Error: '.$conn->error);
}
if ($results -> num_rows > 0) {
while ($row = $results->fetch_assoc()) {
$result[] = $row;
}
return $result;
}else {
return null;
}
}
You can then invoke the function like so:
read_sql('SELECT * FROM mytable where userid = ? AND category = ? ORDER BY id DESC', array($_GET['userid'], $_GET['category']));

Categories