SELECT * FROM in MySQLi - php

My site is rather extensive, and I just recently made the switch to PHP5 (call me a late bloomer).
All of my MySQL query's before were built as such:
"SELECT * FROM tablename WHERE field1 = 'value' && field2 = 'value2'";
This made it very easy, simple and friendly.
I am now trying to make the switch to mysqli for obvious security reasons, and I am having a hard time figuring out how to implement the same SELECT * FROM queries when the bind_param requires specific arguments.
Is this statement a thing of the past?
If it is, how do I handle a query with tons of columns involved? Do I really need to type them all out every time?

I could be wrong, but for your question I get the feeling that bind_param() isn't really the problem here. You always need to define some conditions, be it directly in the query string itself, of using bind_param() to set the ? placeholders. That's not really an issue.
The problem I had using MySQLi SELECT * queries is the bind_result() part. That's where it gets interesting. I came across this post from Jeffrey Way: http://jeff-way.com/2009/05/27/tricky-prepared-statements/(This link is no longer active). The script basically loops through the results and returns them as an array — no need to know how many columns there are, and you can still use prepared statements.
In this case it would look something like this:
$stmt = $mysqli->prepare(
'SELECT * FROM tablename WHERE field1 = ? AND field2 = ?');
$stmt->bind_param('ss', $value, $value2);
$stmt->execute();
Then use the snippet from the site:
$meta = $stmt->result_metadata();
while ($field = $meta->fetch_field()) {
$parameters[] = &$row[$field->name];
}
call_user_func_array(array($stmt, 'bind_result'), $parameters);
while ($stmt->fetch()) {
foreach($row as $key => $val) {
$x[$key] = $val;
}
$results[] = $x;
}
And $results now contains all the info from SELECT *. So far I found this to be an ideal solution.

"SELECT * FROM tablename WHERE field1 = 'value' && field2 = 'value2'";
becomes
"SELECT * FROM tablename WHERE field1 = ? && field2 = ?";
which is passed to the $mysqli::prepare:
$stmt = $mysqli->prepare(
"SELECT * FROM tablename WHERE field1 = ? && field2 = ?");
$stmt->bind_param( "ss", $value, $value2);
// "ss' is a format string, each "s" means string
$stmt->execute();
$stmt->bind_result($col1, $col2);
// then fetch and close the statement
OP comments:
so if i have 5 parameters, i could potentially have "sssis" or something (depending on the types of inputs?)
Right, one type specifier per ? parameter in the prepared statement, all of them positional (first specifier applies to first ? which is replaced by first actual parameter (which is the second parameter to bind_param)).

While you are switching, switch to PDO instead of mysqli, It helps you write database agnositc code and have better features for prepared statements.
http://www.php.net/pdo
Bindparam for PDO:
http://se.php.net/manual/en/pdostatement.bindparam.php
$sth = $dbh->prepare("SELECT * FROM tablename WHERE field1 = :value1 && field2 = :value2");
$sth->bindParam(':value1', 'foo');
$sth->bindParam(':value2', 'bar');
$sth->execute();
or:
$sth = $dbh->prepare("SELECT * FROM tablename WHERE field1 = ? && field2 = ?");
$sth->bindParam(1, 'foo');
$sth->bindParam(2, 'bar');
$sth->execute();
or execute with the parameters as an array:
$sth = $dbh->prepare("SELECT * FROM tablename WHERE field1 = :value1 && field2 = :value2");
$sth->execute(array(':value1' => 'foo' , ':value2' => 'bar'));
It will be easier for you if you would like your application to be able to run on different databases in the future.
I also think you should invest some time in using some of the classes from Zend Framwework whilst working with PDO. Check out their Zend_Db and more specifically [Zend_Db_Factory][2]. You do not have to use all of the framework or convert your application to the MVC pattern, but using the framework and reading up on it is time well spent.

Is this statement a thing of the past?
Yes. Don't use SELECT *; it's a maintenance nightmare. There are tons of other threads on SO about why this construct is bad, and how avoiding it will help you write better queries.
See also:
What is the reason not to use select *?
Performance issue in using SELECT *?
Why is using '*' to build a view bad?

You can still use it (mysqli is just another way of communicating with the server, the SQL language itself is expanded, not changed). Prepared statements are safer, though - since you don't need to go through the trouble of properly escaping your values each time. You can leave them as they were, if you want to but the risk of sql piggybacking is reduced if you switch.

you can use get_result() on the statement.
http://php.net/manual/en/mysqli-stmt.get-result.php

I was looking for a nice and complete example of how to bind multiple query parameters dynamically to any SELECT, INSERT, UPDATE and DELETE query. Alec mentions in his answer a way of how to bind result, for me the get_result() after execute() function for SELECT queries works just fine, and am able to retrieve all the selected results into an array of associative arrays.
Anyway, I ended up creating a function where I am able to dynamically bind any amount of parameters to a parametrized query ( using call_user_func_array function) and obtain a result of the query execution. Below is the function with its documentation (please read before it before using - especially the $paremetersTypes - Type specification chars parameter is important to understand)
/**
* Prepares and executes a parametrized QUERY (SELECT, INSERT, UPDATE, DELETE)
*
* #param[in] $dbConnection mysqli database connection to be used for query execution
* #param[in] $dbQuery parametrized query to be bind parameters for and then execute
* #param[in] $isDMQ boolean value, should be set to TRUE for (DELETE, INSERT, UPDATE - Data manipulaiton queries), FALSE for SELECT queries
* #param[in] $paremetersTypes String representation for input parametrs' types as per http://php.net/manual/en/mysqli-stmt.bind-param.php
* #param[in] $errorOut A variable to be passed by reference where a string representation of an error will be present if a FAUILURE occurs
* #param[in] $arrayOfParemetersToBind Parameters to be bind to the parametrized query, parameters need to be specified in an array in the correct order
* #return array of feched records associative arrays for SELECT query on SUCCESS, TRUE for INSERT, UPDATE, DELETE queries on SUCCESS, on FAIL sets the error and returns NULL
*/
function ExecuteMySQLParametrizedQuery($dbConnection, $dbQuery, $isDMQ, $paremetersTypes, &$errorOut, $arrayOfParemetersToBind)
{
$stmt = $dbConnection->prepare($dbQuery);
$outValue = NULL;
if ($stmt === FALSE)
$errorOut = 'Failed to prepare statement for query: ' . $dbQuery;
else if ( call_user_func_array(array($stmt, "bind_param"), array_merge(array($paremetersTypes), $arrayOfParemetersToBind)) === FALSE)
$errorOut = 'Failed to bind required parameters to query: ' . $dbQuery . ' , parameters :' . json_encode($arrayOfParemetersToBind);
else if (!$stmt->execute())
$errorOut = "Failed to execute query [$dbQuery] , erorr:" . $stmt->error;
else
{
if ($isDMQ)
$outValue = TRUE;
else
{
$result = $stmt->get_result();
if ($result === FALSE)
$errorOut = 'Failed to obtain result from statement for query ' . $dbQuery;
else
$outValue = $result->fetch_all(MYSQLI_ASSOC);
}
}
$stmt->close();
return $outValue;
}
usage:
$param1 = "128989";
$param2 = "some passcode";
$insertQuery = "INSERT INTO Cards (Serial, UserPin) VALUES (?, ?)";
$rowsInserted = ExecuteMySQLParametrizedQuery($dbConnection, $insertQuery, TRUE, 'ss', $errorOut, array(&$param1, &$param2) ); // Make sure the parameters in an array are passed by reference
if ($rowsInserted === NULL)
echo 'error ' . $errorOut;
else
echo "successfully inserted row";
$selectQuery = "SELECT CardID FROM Cards WHERE Serial like ? AND UserPin like ?";
$arrayOfCardIDs = ExecuteMySQLParametrizedQuery($dbConnection, $selectQuery, FALSE, 'ss', $errorOut, array(&$param1, &$param2) ); // Make sure the parameters in an array are passed by reference
if ($arrayOfCardIDs === NULL)
echo 'error ' . $errorOut;
else
{
echo 'obtained result array of ' . count($arrayOfCardIDs) . 'selected rows';
if (count($arrayOfCardIDs) > 0)
echo 'obtained card id = ' . $arrayOfCardIDs[0]['CardID'];
}

Related

PHP PDO Query isn't reading bind values

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.

Using PHP variable in SQL query

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.

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

Best way to avoid preparing the same PDO statement more than once?

Currently I save prepared statements into a private variable, because I ignore how they really work in the deepness, and do it just in case.
So the question is really simple, if I iterate over the same $PDO->prepare(), will it prepare again the same query?
foreach( $arr as $docid ) {
if( $this->dbLink === null ) { // PDO resource, saved in the object.
throw new Exception( 'Must first connect to DB' );
}
if( $this->queryCheckAccess === null ) {
$query = 'SELECT * from something where id = :id';
$this->queryCheckAccess = $this->dbLink->prepare($query);
}
else {
$result = $this->queryCheckAccess->execute(array(':id'=>$docid));
}
}
Will it matter ? Or the DB Engine / PHP is smart enough to know that it is the same prepared statement?
Thanks a lot.
----------------- EDIT --------------
I think I was misunderstood.
What I ask is what happens if I do:
$query = 'SELECT * from something where id = :id';
$this->queryCheckAccess = $this->dbLink->prepare($query);
$query = 'SELECT * from something where id = :id';
$this->queryCheckAccess = $this->dbLink->prepare($query);
$query = 'SELECT * from something where id = :id';
$this->queryCheckAccess = $this->dbLink->prepare($query);
$query = 'SELECT * from something where id = :id';
$this->queryCheckAccess = $this->dbLink->prepare($query);
And what happens if I do:
if( $this->queryCheckAccess === null ) {
$query = 'SELECT * from something where id = :id';
$this->queryCheckAccess = $this->dbLink->prepare($query);
}
Will the engine prepare the query 4 times in the first example? Or will notice it is the same query and just "jump" that?
Your code only prepares the query once, because after the first loop iteration, it's not NULL so it the conditional block won't run. But it's a waste of time to check the condition every time through the loop.
But to answer your question, if you prepare() the same query, it does do redundant work, even if the query is identical to the one you prepared before. So you should avoid that.
But you don't need to prepare inside the loop at all. Prepare once before you start the loop, and bind a variable to the parameter. You don't need to bind every time in the loop, just change the value of that variable.
if( $this->dbLink === null ) { // PDO resource, saved in the object.
throw new Exception( 'Must first connect to DB' );
}
$query = 'SELECT * from something where id = :id';
$this->queryCheckAccess = $this->dbLink->prepare($query);
$this->queryCheckAccess->bindParam(':id' => $docidparam);
foreach( $arr as $docid ) {
$docidparam = $docid;
$result = $this->queryCheckAccess->execute();
}
I'm not sure if you can bind the variable and also use it as the loop variable, there might be a scope conflict.
Another suggestion for this query: why not just run one query to search for a list of values?
$list = implode(",", array_fill(1, count($arr), "?"));
$query = "SELECT * FROM something WHERE id IN ( $list )";
$this->queryCheckAccess = $this->dbLink->prepare($query);
$this->queryCheckAccess->execute($arr);
PS: Also you should check for errors. If you enable PDO error mode EXCEPTION, then errors will automatically throw exceptions. If you don't enable that mode, you need to check the return value of prepare() and execute(), which return false if there's an error.
I just RUN a code similar to your example, and enabled MySQL Query LOG I found that all prepare requests are sent to MySQL Server
Prepare SELECT * FROM test_table WHERE username = ?
Close stmt
Prepare SELECT * FROM test_table WHERE username = ?
Close stmt
Prepare SELECT * FROM test_table WHERE username = ?
Close stmt
Prepare SELECT * FROM test_table WHERE username = ?
Close stmt
Test code:
$sth = $dbh->prepare($sql);
$sth = $dbh->prepare($sql);
$sth = $dbh->prepare($sql);
$sth = $dbh->prepare($sql);
$sth = $dbh->prepare($sql);
$sth->bindParam(1, $user);
$sth->execute();
Then, the best way is to prepare once, and Bind different values and then execute.
$sth = $dbh->prepare($sql);
$user = "test";
$sth->bindParam(1, $user);
$sth->execute();
$user = "test2";
$sth->bindParam(1, $user);
$sth->execute();
$user = "test";
$sth->bindParam(1, $user);
$sth->execute();
No, that's one of the main features of prepared statements. If you're going to run the same query multiple times but with different variables then preparing the query will give you a speed increase. Especially if you make use of transactions (requires InnoDB storage engine).
To answer the question from the title (which is quite different from questions in the body), the best way to avoid preparing the same statement more than once, apparently would be to avoid running multiple similar queries at all.
To answer the question from the question body - no, DB Engine / PHP is not "smart" enough to know that it is the same query were prepared again. With every new prepare() call another statement is created. And I would be first to hate such a "smart" behavior. The "smarter" your tool, the more unpredictable results you get.
To answer the real problem in the code, a smart developer would use a right tool to save himself a trouble.
With safeMysql whole mess will be reduced to one query and one line of code
$data = $this->dbLink->getAll('SELECT * from somth where id IN (?a)', $arr);
S0 - no multiple queries, no multiple preparations, no multiple questions.
By the way, you are losing first id with your code.
Yet you're losing all of them but last one if you don't use the result in place.

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