Quantcast
Channel: Yudiz Solutions Ltd.
Viewing all articles
Browse latest Browse all 595

MySQL Vs MySQLi Vs PDO

$
0
0

Overview

To understand the difference between MySQL, MySQLi and PDO first we need to understand all of it individually.

There are two or three PHP APIs for accessing the MySQL database depending on PHP version. The user who uses PHP 5, they can choose MySQL which is deprecated, Mysqli or PDO. The user who uses PHP 7, they have only two options either MySQL or PDO.

MySQL

This is the main original extension designed to develop PHP applications that interact with a MySQL database. It provides procedural interface but it is deprecated as of PHP 5.5.0 and has been removed as of PHP 7.0.0. So, I suggest to use either MySQLi or PDO extension.

MySQLi

The i stands for Improved. The MySQLi is an extension to work with MySQL version 4.1.13 or newer. MySQLi is introduced with PHP Version 5.0 and MySQLi takes advantage of the newer features of MySQL 5.

PDO

PDO stands for PHP Data Objects. It is a database access layer providing a uniform method of access to multiple databases. PDO supports twelve different databases which are as below:

  1. CUBRID
  2. MS SQL Server
  3. Firebird/Interbase
  4. IBM
  5. Informix
  6. MySQL
  7. MS SQL Server
  8. Oracle
  9. ODBC and DB2
  10. PostgreSQL
  11. SQLite
  12. 4D

PDO sadly has one disadvantage, it does not allow you to use all of the advanced features that are available in the latest versions of MySQL server. Consider example, PDO does not allow you to use MySQL’s support for Multiple Statements.

Difference between MySQL, MySQLi and PDO

The main differences of three extensions are as below.

MySQL MySQLi PDO
Introduced with PHP version 2.0 5.0 5.1
Development status Maintenance only in 5.x; removed in 7.x Yes Yes
Lifecycle Deprecated in 5.x; Removed in 7.x Active Active
Recommended for new projects No Yes Yes
OOP Interface No Yes Yes
Procedural Interface Yes Yes No
API supports non-blocking, asynchronous queries with mysqlnd No Yes No
Persistent Connections Yes Yes Yes
API supports Charsets Yes Yes Yes
API supports server-side Prepared Statement No Yes Yes
API supports client-side Prepared Statement No No Yes
API supports Stored Procedures No Yes Yes
API supports Multiple Statements No Yes Most
API supports Transactions No Yes Yes
Transaction can be controlled with SQL Yes Yes Yes
Supports all MySQL 5.1+ functionality No Yes Most

Now, let’s discuss some functional differences of above three extensions.

Connection to MySQL database

In MySQL function we can connect to the database by following code:

<?php
    $connection_link = mysql_connect("host.domain.com", "username", "password");
    mysql_select_db("database_name", $connection_link);
    mysql_set_charset('UTF-8', $connection_link);
?>

In MySQLi to create a connection just instantiating a new instance of MySQLi and using a username with a password connecting to the database, as follow:

<?php
     $mysqli_db = new mysqli(‘host.domain.com’, 'username', 'password', 'database_name');
?>

In PDO We need to create a new PDO object. The constructor accepts four parameters for specifying the database source which are DSN (data source name) and optionally username, password. DSN is basically a string of options of driver to use and connection details of database.

<?php
    $pdo = new PDO('mysql:host=host.domain.com;dbname=database_name;charset=utf8','username','password'); 
?>

You can pass fourth parameter as of several driver options as an array. Some PDO drivers do not support native prepared statements, so I recommend pass the parameter which put PDO into exception mode, so PDO performs emulation of the prepare. You can also manually enable this emulation. To use the native server-side prepared statements, you should explicitly set it false. Prepare emulation should be turned off to use PDO safely.

It will throw PDOException object if there is any connection error, we can catch it to handle Exception. So we can set attributes after PDO construction with the setAttribute method:

<?php
    $db = new PDO('mysql:host=localhost.com;dbname=data;charset=utf8', 'user', 'pass');
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
?>

Error Handling

In MySQL

<?php
    $my_result = mysql_query("SELECT * FROM table", $connection_link) or die(mysql_error($connection_link));
?>

We cannot handle the thing in die but die is not a good approach to handle error. Die will end the script abruptly and then echo the error to the screen which you usually don’t want to show to your users, and let hackers to discover your schema.

In MySQLi

mysqli::$error – mysqli_error : Returns a string description of the last error.

<?php
    if (!$mysqli->query("SET a=1")) {
        printf("Errormessage: %s\n", $mysqli->error);
    }
?>

In PDO

In PDO a better solution is exceptions. Anything in PDO should be wrapped in a try-catch block. Also we can force PDO into error mode by setting the error mode attribute from following error modes.

PDO::ERRMODE_SILENT: By setting this error code you must check each result then check $db->errorInfo() to get error details.

PDO::ERRMODE_WARNING: It provides Run-time warnings (E_WARNING) not fatal errors. It’s execution does not halt the script.

PDO::ERRMODE_EXCEPTION: It throw exceptions that shows an error raised by PDO. You should not throw a PDOException with your own code. It acts much like or die(mysql_error()), when it isn’t caught. But we can catch these PDOException and handle as we want.

We can set these error modes as follow:

<?php
    $db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT );
    $db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
    $db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
?>

You can add a try/catch block as like below:

<?php
    try {
        $db->query('hello'); //Invalid query
    }
    catch (PDOException $ex) {
        //$ex->getMessage();
        echo "An Error has occurred";
    }
?>

You can set a user friendly error message instead of exception message. You should use try/catch block for your PDO part also you can use it outside the function that has the PDO functions.

<?php
    function get_data($db) {
        $stmt = $db->query("SELECT * FROM `data_table`");
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
    try {
        get_data($db);
    } catch(PDOException $ex) {
        echo "An Error has occurred";
        //$ex->getMessage(); // you can log these errors
    }
?>

Fetching Data from database

In MySQL

Using loop on results the username for each row will be the out as following:

<?php
    $my_result = mysql_query('SELECT * from data') or die(mysql_error());
    $num_rows = mysql_num_rows($my_result);
    while($row = mysql_fetch_assoc($my_result)) {
        echo $row['field1'];
    }
?>

In MySQLIi

Using loop on results the username for each row will be the out as following:

<?php
    while($row = $my_result->fetch_assoc()){
        echo $row['username'] . '\n';
    }
?>

In PDO

PDOStatement::fetchAll() – Returns an array containing all of the resultset rows PDOStatement::fetchColumn() – Returns a single column from the next row of a resultset. PDOStatement::fetchObject() – Fetches the next row and returns it as an object. PDOStatement::setFetchMode() – Set the default fetch mode for this statement

query() returns a PDOStatement object by that you can fetch the data directly by using foreach and for loop also.

<?php
    $stmt = $db->query('SELECT * FROM `data_table`');
    $my_results = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>

Getting the Row Count

Instead of using mysql_num_rows() in MySQL and mysqli_num_rows() or $my_result->num_rows in MySQLi to get the number of returned rows, you can get a PDOStatement and do rowcount, like:

<?php
    $stmt = $db->query('SELECT * FROM `data_table`');
    $row_count = $stmt->rowCount();
    echo $row_count.' rows selected';
?>

Update statements

We use mysql_affected_rows() in MySQL and mysqli_affected_rows() or $my_result->affected_rows in MySQLi.  In PDO, we can do the same by:

<?php
    $affected_rows = $db->exec("UPDATE table SET field='value'");
    echo $affected_rows;
?>

There are some functionalities that are not supported by MySQL and supported by remaining both MySQLi and PDO.

Prepared Statements

A prepared statement is a precompiled SQL statement that can be executed multiple times by sending the data to the server.

The flow of the prepared statement is as follows:

  1. Prepare: The statement template is created by the application and sent to the DBMS. Some parameters are left unspecified by placeholders “?” like as below:
    INSERT INTO data (fname, lname) VALUES (?, ?)
  2. Bind: The DBMS parses, compiles, and performs query optimization on statement template and stores the result without executing it.
  3. Execute: The application binds values for the parameters and the DBMS executes the statement. The application may execute the statement as many times as it wants with different values.

Named placeholders: You can use a descriptive names preceded by a colon, instead of question marks. We don’t care about position or order of value in named placeholder:

$stmt->bindParam(':foo', $foo);

Unnamed placeholders: In unnamed placeholders we must follow the proper order of the elements.

In MySQLi

<?php
    $id = '2';
    $stmt = $db->prepare("SELECT `name` FROM `users` WHERE `id` = ?");
    $stmt->bind_param('i', $id);
    $stmt->execute();
    $stmt->bind_result($out_name);
    while($stmt->fetch()){
        echo $out_name . '\n';
    }
?>

In PDO

<?php
    $id = '2';
    $stmt = $db->prepare("SELECT `name` FROM `users` WHERE `id` = ?");
    $stmt->bind_param('i', $id);
    $stmt->execute();
    $stmt->bind_result($out_name);
    while($stmt->fetch()){
        echo $out_name . '\n';
    }
?>

API Support

Both PDO and MySQLi provides an object-oriented approach, but MySQLi provides a procedural way also like old mysql extension. New users may prefer MySQLi because of procedural interface which is similar to old mysql extension, So migrating from the old mysql extension is easier. But after mastering in PDO, you can use it with any database you like.

Security

Both PDO and MySQLi provide SQL injection security, as long as developers follow them with features like escaping and parameter binding with prepared statements.

For example a hacker is trying to inject some malicious SQL through the ‘name’ HTTP query parameter (POST):

$_POST['name'] = "'; DELETE FROM users; /*"

If we fail to escape, it will be added in query “as it is”, it will delete all rows from users table as PDO and MySQLi support multiple queries.

In PDO, “manual” escaping

$name = PDO::quote($_POST['name']);
$pdo->query("SELECT * FROM users WHERE name = $name");

In MySQLi, “manual” escaping

$name = mysqli_real_escape_string($_POST['name']);
$mysqli->query("SELECT * FROM users WHERE name = '$name'");

PDO::quote() not only escapes the string, but it also quotes it. But mysqli_real_escape_string() will only escape the string, you will need to apply the quotes manually.

Conclusion

There are only two possibilities to use extension because MySQL is deprecated as of PHP 5.5.0 and removed as of PHP 7.0.0.

  1. MySQLi
  2. PDO

As per my opinion, if there are possibilities to use more than one database drivers or another than MySQL in your project then you can use PDO, otherwise use MySQLi because PDO not support latest functionalities of MySQL.


Viewing all articles
Browse latest Browse all 595

Trending Articles