Php prepared statements mysqli

PHP MySQL Prepared Statements

Prepared statements are very useful against SQL injections.

Prepared Statements and Bound Parameters

A prepared statement is a feature used to execute the same (or similar) SQL statements repeatedly with high efficiency.

Prepared statements basically work like this:

  1. Prepare: An SQL statement template is created and sent to the database. Certain values are left unspecified, called parameters (labeled «?»). Example: INSERT INTO MyGuests VALUES(?, ?, ?)
  2. The database parses, compiles, and performs query optimization on the SQL statement template, and stores the result without executing it
  3. Execute: At a later time, the application binds the values to the parameters, and the database executes the statement. The application may execute the statement as many times as it wants with different values

Compared to executing SQL statements directly, prepared statements have three main advantages:

  • Prepared statements reduce parsing time as the preparation on the query is done only once (although the statement is executed multiple times)
  • Bound parameters minimize bandwidth to the server as you need send only the parameters each time, and not the whole query
  • Prepared statements are very useful against SQL injections, because parameter values, which are transmitted later using a different protocol, need not be correctly escaped. If the original statement template is not derived from external input, SQL injection cannot occur.

Prepared Statements in MySQLi

The following example uses prepared statements and bound parameters in MySQLi:

Example (MySQLi with Prepared Statements)

$servername = «localhost»;
$username = «username»;
$password = «password»;
$dbname = «myDB»;

// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);

// Check connection
if ($conn->connect_error) die(«Connection failed: » . $conn->connect_error);
>

// prepare and bind
$stmt = $conn->prepare(«INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?)»);
$stmt->bind_param(«sss», $firstname, $lastname, $email);

// set parameters and execute
$firstname = «John»;
$lastname = «Doe»;
$email = «john@example.com»;
$stmt->execute();

$firstname = «Mary»;
$lastname = «Moe»;
$email = «mary@example.com»;
$stmt->execute();

$firstname = «Julie»;
$lastname = «Dooley»;
$email = «julie@example.com»;
$stmt->execute();

echo «New records created successfully»;

Code lines to explain from the example above:

In our SQL, we insert a question mark (?) where we want to substitute in an integer, string, double or blob value.

Then, have a look at the bind_param() function:

This function binds the parameters to the SQL query and tells the database what the parameters are. The «sss» argument lists the types of data that the parameters are. The s character tells mysql that the parameter is a string.

The argument may be one of four types:

We must have one of these for each parameter.

Читайте также:  Api gateway python fastapi

By telling mysql what type of data to expect, we minimize the risk of SQL injections.

Note: If we want to insert any data from external sources (like user input), it is very important that the data is sanitized and validated.

Prepared Statements in PDO

The following example uses prepared statements and bound parameters in PDO:

Example (PDO with Prepared Statements)

$servername = «localhost»;
$username = «username»;
$password = «password»;
$dbname = «myDBPDO»;

try $conn = new PDO(«mysql:host=$servername;dbname=$dbname», $username, $password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

// prepare sql and bind parameters
$stmt = $conn->prepare(«INSERT INTO MyGuests (firstname, lastname, email)
VALUES (:firstname, :lastname, :email)»);
$stmt->bindParam(‘:firstname’, $firstname);
$stmt->bindParam(‘:lastname’, $lastname);
$stmt->bindParam(‘:email’, $email);

// insert a row
$firstname = «John»;
$lastname = «Doe»;
$email = «john@example.com»;
$stmt->execute();

// insert another row
$firstname = «Mary»;
$lastname = «Moe»;
$email = «mary@example.com»;
$stmt->execute();

// insert another row
$firstname = «Julie»;
$lastname = «Dooley»;
$email = «julie@example.com»;
$stmt->execute();

echo «New records created successfully»;
> catch(PDOException $e) echo «Error: » . $e->getMessage();
>
$conn = null;
?>

Источник

mysqli_stmt_prepare

Prepares a statement for execution. The query must consist of a single SQL statement.

The statement template can contain zero or more question mark ( ? ) parameter markers⁠—also called placeholders. The parameter markers must be bound to application variables using mysqli_stmt_bind_param() before executing the statement.

  • mysqlnd on Linux returns an error code of 1153. The error message means got a packet bigger than max_allowed_packet bytes .
  • mysqlnd on Windows returns an error code 2006. This error message means server has gone away .
  • libmysqlclient on all platforms returns an error code 2006. This error message means server has gone away .

Parameters

Procedural style only: A mysqli_stmt object returned by mysqli_stmt_init() .

The query, as a string. It must consist of a single SQL statement.

The SQL statement may contain zero or more parameter markers represented by question mark ( ? ) characters at the appropriate positions.

Note:

The markers are legal only in certain places in SQL statements. For example, they are permitted in the VALUES() list of an INSERT statement (to specify column values for a row), or in a comparison with a column in a WHERE clause to specify a comparison value. However, they are not permitted for identifiers (such as table or column names).

Return Values

Returns true on success or false on failure.

Errors/Exceptions

If mysqli error reporting is enabled ( MYSQLI_REPORT_ERROR ) and the requested operation fails, a warning is generated. If, in addition, the mode is set to MYSQLI_REPORT_STRICT , a mysqli_sql_exception is thrown instead.

Examples

Example #1 mysqli_stmt::prepare() example

mysqli_report ( MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT );
$mysqli = new mysqli ( «localhost» , «my_user» , «my_password» , «world» );

/* create a prepared statement */
$stmt = $mysqli -> stmt_init ();
$stmt -> prepare ( «SELECT District FROM City WHERE Name=?» );

/* bind parameters for markers */
$stmt -> bind_param ( «s» , $city );

/* execute query */
$stmt -> execute ();

Читайте также:  Удалить число из массива в java

/* bind result variables */
$stmt -> bind_result ( $district );

printf ( «%s is in district %s\n» , $city , $district );

mysqli_report ( MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT );
$link = mysqli_connect ( «localhost» , «my_user» , «my_password» , «world» );

/* create a prepared statement */
$stmt = mysqli_stmt_init ( $link );
mysqli_stmt_prepare ( $stmt , «SELECT District FROM City WHERE Name=?» );

/* bind parameters for markers */
mysqli_stmt_bind_param ( $stmt , «s» , $city );

/* execute query */
mysqli_stmt_execute ( $stmt );

/* bind result variables */
mysqli_stmt_bind_result ( $stmt , $district );

/* fetch value */
mysqli_stmt_fetch ( $stmt );

printf ( «%s is in district %s\n» , $city , $district );

The above examples will output:

Amersfoort is in district Utrecht

See Also

  • mysqli_stmt_init() — Initializes a statement and returns an object for use with mysqli_stmt_prepare
  • mysqli_stmt_execute() — Executes a prepared statement
  • mysqli_stmt_fetch() — Fetch results from a prepared statement into the bound variables
  • mysqli_stmt_bind_param() — Binds variables to a prepared statement as parameters
  • mysqli_stmt_bind_result() — Binds variables to a prepared statement for result storage
  • mysqli_stmt_get_result() — Gets a result set from a prepared statement as a mysqli_result object
  • mysqli_stmt_close() — Closes a prepared statement

User Contributed Notes 9 notes

Note that if you’re using a question mark as a placeholder for a string value, you don’t surround it with quotation marks in the MySQL query.

mysqli_stmt_prepare($stmt, «SELECT * FROM foo WHERE foo.Date > ?»);

mysqli_stmt_prepare($stmt, «SELECT * FROM foo WHERE foo.Date > ‘?'»);

If you put quotation marks around a question mark in the query, then PHP doesn’t recognize the question mark as a placeholder, and then when you try to use mysqli_stmt_bind_param(), it gives an error to the effect that you have the wrong number of parameters.

The lack of quotation marks around a string placeholder is implicit in the official example on this page, but it’s not explicitly stated in the docs, and I had trouble figuring it out, so figured it was worth posting.

Turns out you can’t directly use a prepared statement for a query that has a placeholder in an IN() clause.

There are ways around that (such as constructing a string that consists of n question marks separated by commas, then using that set of placeholders in the IN() clause), but you can’t just say IN (?).

This is a MySQL restriction rather than a PHP restriction, but it’s not really documented in the MySQL docs either, so I figured it was worth mentioning here.

(Btw, turns out someone else had previously posted the info that I put in my previous comment, about not using quotation marks. Sorry for the repeat; not sure how I missed the earlier comment.)

If you select LOBs use the following order of execution or you risk mysqli allocating more memory that actually used

1)prepare()
2)execute()
3)store_result()
4)bind_result()

If you skip 3) or exchange 3) and 4) then mysqli will allocate memory for the maximal length of the column which is 255 for tinyblob, 64k for blob(still ok), 16MByte for MEDIUMBLOB — quite a lot and 4G for LONGBLOB (good if you have so much memory). Queries which use this order a bit slower when there is a LOB but this is the price of not having memory exhaustion in seconds.

Читайте также:  Session handling in java servlet

If you wrap the placeholders with quotation marks you will experience warnings like «Number of variables doesn’t match number of parameters in prepared statement» (at least with INSERT Statements).

The `prepare` , `bind_param`, `bind_result`, `fetch` result, `close` stmt cycle can be tedious at times. Here is an object that does all the mysqli mumbo jumbo for you when all you want is a select leaving you to the bare essential `preparedSelect` on a prepared stmt. The method returns the result set as a 2D associative array with the `select`ed columns as keys. I havent done sufficient error-checking and it also may have some bugs. Help debug and improve on it.

class DB
public $connection ;

#establish db connection
public function __construct ( $host = «localhost» , $user = «user» , $pass = «» , $db = «bible» )
$this -> connection = new mysqli ( $host , $user , $pass , $db );

if( mysqli_connect_errno ())
echo( «Database connect Error : »
. mysqli_connect_error ( $mysqli ));
>
>

#store mysqli object
public function connect ()
return $this -> connection ;
>

#run a prepared query
public function runPreparedQuery ( $query , $params_r )
$stmt = $this -> connection -> prepare ( $query );
$this -> bindParameters ( $stmt , $params_r );

if ( $stmt -> execute ()) return $stmt ;
> else echo( «Error in $statement : »
. mysqli_error ( $this -> connection ));
return 0 ;
>

# To run a select statement with bound parameters and bound results.
# Returns an associative array two dimensional array which u can easily
# manipulate with array functions.

public function preparedSelect ( $query , $bind_params_r )
$select = $this -> runPreparedQuery ( $query , $bind_params_r );
$fields_r = $this -> fetchFields ( $select );

foreach ( $fields_r as $field ) $bind_result_r [] = &$< $field >;
>

$this -> bindResult ( $select , $bind_result_r );

$result_r = array();
$i = 0 ;
while ( $select -> fetch ()) foreach ( $fields_r as $field ) $result_r [ $i ][ $field ] = $ $field ;
>
$i ++;
>
$select -> close ();
return $result_r ;
>

#takes in array of bind parameters and binds them to result of
#executed prepared stmt

#returns a list of the selected field names

private function fetchFields ( $selectStmt )
$metadata = $selectStmt -> result_metadata ();
$fields_r = array();
while ( $field = $metadata -> fetch_field ()) $fields_r [] = $field -> name ;
>

return $fields_r ;
>
>
#end of class

#An example of the DB class in use

$DB = new DB ( «localhost» , «root» , «» , «bible» );
$var = 5 ;
$query = «SELECT abbr, name from books where id > ?» ;
$bound_params_r = array( «i» , $var );

$result_r = $DB -> preparedSelect ( $query , $bound_params_r );

#loop thru result array and display result

foreach ( $result_r as $result ) echo $result [ ‘abbr’ ] . » : » . $result [ ‘name’ ] . «
» ;
>

Источник

Оцените статью