- Significant performance benefit if you are running the same query multiple times. Creating a normal query (non-prepared) has the additional overhead of parsing the statement for syntax errors and setup for the query to be ran. When using prepared statements in MySQL this overhead is only preformed once (the first time) thus increasing each subsequent use.
- Passing variables as parameters is more secure than passing unvalidated data into a SQL query. Prepared statements make it harder to perform SQL Injection by seperating SQL logic from from the data.
- Binding variables is cleaner and more convenient for the developer.
Types
There are two types of prepared statements: bound parameter and bound result. As you can guess, bound parameter prepared statements take an input (insert, update) SQL statement and allows the developer to create a template for SQL execution. Bound result prepared statements allow the developer to extract data from a bound SQL query.
SQL Code
To create a template in a prepared statement replace all values with question marks (?). Lets examine a non-prepared insert query:
Bound Parameters
Code:
INSERT INTO CodeCall (FirstName, LastName) VALUES ('Jordan','DeLozier');Code:
INSERT INTO CodeCall (FirstName, LastName) VALUES (?, ?);
Code:
SELECT FirstName,LastName FROM CodeCall WHERE FirstName='Jordan';
Code:
SELECT FirstName,LastName FROM CodeCall WHERE FirstName=?;
There is no SQL conversion for bound results. Rather, bound results assign the results to variables similar to list() language construct or extract().
PHP Code
Natuarlly, you'll need an active MySQLi connection. You can find my database and table structure in the attached SQL file. I'll be using user root with no password, you may need to change.
PHP Code:
<?php
$mysqli = new mysqli("localhost", "root", "", "cctutorial_mysqli");
/* check connection */
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
} Quote:
| Warning: mysqli::mysqli() [mysqli.mysqli]: (42000/1044): Access denied for user ''@'localhost' to database 'cctutorial_mysqli' in C:\wamp\www\PHP_Test\mysqli_prepared.php on line 3 Connect failed: Access denied for user ''@'localhost' to database 'cctutorial_mysqli' |
Bound Parameters
Now that we have that out of the way we will want to create our prepared statement:
PHP Code:
/* Create the prepared statement */
if ($stmt = $mysqli->prepare("INSERT INTO CodeCall (FirstName, LastName) values (?, ?)")) {
/* Bind our params */
$stmt->bind_param('ss', $firstName, $lastName);
/* Set our params */
$firstName = "Jordan";
$lastName = "DeLozier";
/* Execute the prepared Statement */
$stmt->execute();
/* Echo results */
echo "Inserted {$lastName},{$firstName} into database\n";
/* Set our params for second query */
$firstName = "John";
$lastName = "Ciacia";
/* Execute second Query */
$stmt->execute();
echo "Inserted {$lastName},{$firstName} into database\n";
/* Close the statement */
$stmt->close();
}
else {
/* Error */
printf("Prepared Statement Error: %s\n", $mysqli->error);
}
PHP Code:
$stmt = $mysqli->prepare("INSERT INTO CodeCall (FirstName, LastName) values (?, ?)")
PHP Code:
printf("Prepared Statement Error: %s\n", $mysqli->error);
PHP Code:
$stmt->bind_param('ss', $firstName, $lastName);
i - Integer
d - Decimal
s - String
b - Blob (sent in packets)
If you have 5 variables and they are all strings you specify five types ("sssss") as the first param. If you have 3 strings, 1 integer and 1 decimal you specify the types as such: "sssid". Of course, they must be in the correct order. If the integer is first and the decimal is third it would look like this: "isdss".
Next we assign the variables values. Notice that the variables had no value even though we bound them.
PHP Code:
$firstName = "Jordan";
$lastName = "DeLozier";
PHP Code:
$stmt->execute();
PHP Code:
/* Set our params for second query */
$firstName = "John";
$lastName = "Ciacia";
/* Execute second Query */
$stmt->execute();
Quote:
| Inserted DeLozier,Jordan into database Inserted Ciacia,John into database |
Quote:
| Prepared Statement Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INSERTs INTO CodeCall (FirstName, LastName) values (?, ?)' at line 1 |
Bound Results
That covers input and most of the information there will apply to output so I will make this section short. Using the same script above we will add another prepared statement and select the data that we just inserted.
PHP Code:
/* Create the prepared statement */
if ($stmt = $mysqli->prepare("SELECT FirstName,LastName FROM CodeCall ORDER BY LastName")) {
/* Execute the prepared Statement */
$stmt->execute();
/* Bind results to variables */
$stmt->bind_result($firstName, $lastName);
/* fetch values */
while ($stmt->fetch()) {
printf("%s %s\n", $lastName, $firstName);
}
/* Close the statement */
$stmt->close();
}
else {
/* Error */
printf("Prepared Statement Error: %s\n", $mysqli->error);
}
You should see the following output:
Quote:
| Ciacia John DeLozier Jordan |
MySQLi offers many benefits over traditional mysql and allows you to use all of the features of MySQL 4.1.3. You should use this extension if you are developing in PHP version 5 or above and using MySQL 4.1.3+. Using prepared statements will allow you to save resources (CPU, Memory, etc) which could be vital in many circumstances (shared hosting comes to mind) and reduce the thread of SQL Injection.
I've attached an exported SQL file that contains my table structure - you will need to create a database named cctutorial_mysqli or change the PHP code accordingly. I've also attached the MySQLi PHP script that was created during this tutorial. If you have any questions feel free to ask here.
discuss this topic to forum
