Passer de MySQL à MySQLi ou PDO

2 messages   •   Page 1 sur 1
Avatar de l’utilisateur
Modérateur PHPfrance
Modérateur PHPfrance | 10415 Messages

02 Juin 2016, 13:42

Passer de MySQL à MySQLi ou PDO

Pourquoi ?

Selon la version de PHP utilisée, plusieurs extensions vous permettent de vous connecter à une base de données MySQL.
En PHP 5, vous pouviez choisir entre MySQL (dépréciée à partir de la version 5.5), MySQLi et PDO_MySQL.
A partir de PHP 7, seuls MySQLi et PDO_MySQL sont disponibles.

Pour la petite histoire et afin de vous permettre de briller devant la machine à café (ou juste passer pour un geek ;)), sachez que l'extension MySQL est apparue avec la version 2 de PHP. Aujourd'hui seule la maintenance de cette extension est encore assurée, c'est à dire que l'extension n'évolue plus, alors que le SGBD MySQL continue de s'améliorer. L'extension MySQL ne permet notamment pas l'utilisation de requêtes préparées, de procédures stockées ou de requêtes multiples.
Enfin, il s'agit d'une interface procédurale uniquement, elle n'est donc pas orientée objet, ce qui peut faire désordre quand vous voulez faire de la POO.

Il est donc recommandé pour vos nouveaux projets d'utiliser soit l'extension MySQLi, soit l'extension PDO_MySQL et pour vos anciens projets, de ne pas trop attendre pour les migrer afin d'éviter les mauvaises surprises lorsque votre hébergeur décidera de passer à PHP 7 ;)


De MySQL vers MySQLi

Il est important de noter que MySQL fonctionne uniquement en mode procédurale, tandis que MySQLi fonctionne avec une interface orientée objet. Si vous ne maîtrisez pas la programmation orientée objet ou voulez migrer rapidement, il est également possible d'utiliser cette extension en mode procédurale. Prenez garde cependant car les noms des méthodes et les arguments ne sont pas les mêmes dans ces deux modes.

Connexion

En général, la première chose que vous faites avec MySQL, c'est de vous connecter au serveur et de sélectionner une base de données avec mysql_connect() et mysql_select_db().

// Connexion MySQL
$connection = mysql_connect( 'host', 'username', 'password', new_link, client_flags);
$database = mysql_select_db( 'database', $link);
$connection est un identifiant de connexion MySQL et $database un simple booléen indiquant si la connexion a la base de données à aboutie ou non.

MySQLi propose deux méthodes équivalentes mysqli_connect() et mysqli_select_db(). Il est cependant possible d'utiliser uniquement mysqli_connect() et de spécifier directement le nom de la base de données dès la connexion :
// Connexion MySQLi
$connection = mysqli_connect( 'host', 'username', 'password', 'database', 'port', 'socket');
$connection est alors un objet qui représente la connexion au serveur MySQL.

Vous pouvez également profiter de l'interface orientée objet de MySQLi. La connexion se fait alors en instanciant un nouvel objet MySQLi :
$mysqli = new mysqli('host', 'username', 'password', 'database');

Si vous préférez continuer de spécifier le nom de la base de données indépendamment de la connexion, vous pouvez utiliser mysqli_select_db().
$database = mysqli_select_db($link, 'database');
ATTENTION : les paramètres sont inversés par rapport à mysql_select_db(), il ne suffit donc pas juste d'ajouter un "i" !

Mettre à jour votre code php pour vous connecter à la base de données devrait donc être relativement simple :)

IMPORTANT : avec MySQL, vous n'étiez pas obligé de spécifier l'identifiant de connexion à chaque requête. En effet, l'identifiant de la dernière connexion ouverte était utilisé si aucun nouvel identifiant n'était spécifié. Avec MySQLi cet identifiant est obligatoire et doit être passé en premier dans vos appel procéduraux.

L'attribut new_link n'existe plus et doit désormais être géré via la création d'une nouvelle connexion si nécessaire.
Les constantes clients (client_flags) sont abandonnées avec MySQLi.

Si vous utilisiez une connexion permanente à MySQL avec mysql_pconnect() et souhaitez conserver cette persistance avec MySQLi, il vous faut simplement préfixer le nom de l'hôte par la valeur 'p:'. Ainsi au lieu de 'localhost' vous auriez 'p:localhost'.

Gestion des erreurs de connexion

En cas d'erreur lors de la connexion à la base de données, MySQL proposait les méthodes mysql_error() et mysql_errno().
Leurs équivalent MySQLi sont simplement mysqli_connect_error() et mysqli_connect_errno().
$link = mysqli_connect("localhost", "my_user", "my_password", "world");
/* Vérification de la connexion */
if (mysqli_connect_errno()) {
echo "Echec de la connexion: " . mysqli_connect_error();
exit();
}

En mode orienté objet, ces informations sont accessibles via les attributs connect_error et connect_errno de votre instance MySQLi :
$mysqli = new mysqli("localhost", "my_user", "my_password", "world");
/* Vérification de la connexion */
if ($mysqli->connect_errno) {
echo "Echec de la connexion: " . $mysqli->connect_error;
exit();
}


Migration des méthodes MySQL

La majorité des méthodes MySQL ont une méthode procédurale équivalente en MySQLi et sont simples à migrer puisqu'il s'agit uniquement d'ajouter un "i" à mysql et d'ajouter ou déplacer l'identifiant de connexion en premier dans la liste des paramètres de la fonction. Pour les principales :

mysql_affected_rows      -> mysqli_affected_rows($link)                   || $mysqli->affected_rows;
mysql_close -> mysqli_close($link) || mysqli::close()
mysql_data_seek -> mysqli_data_seek($result, $offset) || mysqli_result::data_seek($offset)
mysql_errno -> mysqli_errno($link) || $mysqli->errno
mysql_error -> mysqli_error($link) || $mysqli->error
mysql_fetch_array -> mysqli_fetch_array($result, $type) || mysqli_result::fetch_array($resulttype)
mysql_fetch_assoc -> mysqli_fetch_assoc($result) || mysqli_result::fetch_assoc()
mysql_fetch_lengths -> mysqli_fetch_lengths($result) || $mysqli_result->lengths
mysql_fetch_object -> mysqli_fetch_object($result, $class, $params) || mysqli_result::fetch_object($class, $params)
mysql_fetch_row -> mysqli_fetch_row($result) || mysqli_result::fetch_row()
mysql_field_seek -> mysqli_field_seek($result, $fieldnr) || mysqli_result::field_seek($fieldnr)
mysql_free_result -> mysqli_free_result($result) || mysqli_result::free_result()
mysql_insert_id -> mysqli_insert_id($link) || $mysqli->insert_id
mysql_num_rows -> mysqli_num_rows($result) || $mysqli_result->num_rows;
mysql_query -> mysqli_query($link, $query) || mysqli::query($query)
mysql_real_escape_string -> mysqli_real_escape_string($link, $str) || mysqli::real_escape_string($str)
mysql_select_db -> mysqli_select_db($link, $dbname) || mysqli::select_db($dbname)
mysql_set_charset -> mysqli_set_charset($link, $charset) || mysqli::set_charset($charset)

Nota : en mode orienté objet, les équivalents des méthodes procédurales peuvent être des attributs ou des méthodes. Celles-ci sont à appeler à partir des objets mysqli ou mysqli_result (résultat de la méthode query).

D'autres méthodes sont en revanche un peu plus complexes à migrer, mais la plupart sont relativement peu utilisées, donc pas d'inquiétude et au pire, vous avez toujours la documentation officielle de php et les forums de phpfrance pour vous aider :)

De MySQL vers PDO

- Bientôt sur vos écrans -
Ce n'est pas en améliorant la bougie que l'on a inventé l'ampoule...

Avatar de l’utilisateur
Modérateur PHPfrance
Modérateur PHPfrance | 10415 Messages

02 Juin 2016, 13:42

Exemples MySQLi (Orienté Objet)

1) Connexion à la BDD

<?php

define('HOST', 'localhost');
define('USER', 'mon_user');
define('PASS', 'mon_password');
define('DBNAME', 'phpfrance');

$db = new mysqli(HOST, USER, PASS, DBNAME); // création d'une instance MySQLi nommée $db

if ($db->connect_errno) { // Vérification de la connexion
echo "Echec de la connexion: (" . $db->connect_errno . ") " . $db->connect_error;
exit(); // interruption de l'exécution
}

?>


2) Création d'une table

<?php

// Creation d'une table
$sql = 'CREATE TABLE IF NOT EXISTS eleve (
id INT NOT NULL AUTO_INCREMENT,
nom VARCHAR(200) NOT NULL,
age INT NOT NULL,
PRIMARY KEY(id)
)';

// Execution de la requête sql avec $db->query()
$succes = $db->query($sql);
if ($succes) {
echo "La table a bien été créée.";
}
else {
echo "Une erreur est survenue.";
}

?>


3) Insert simple / protection des données avec real_escape_string()

<?php

// Requête simple
$sql = "INSERT INTO eleve (nom, age) VALUES ('Bob', 19)";
// Requête dynamique
$sql = "INSERT INTO eleve (nom, age) VALUES ('" . $votre_nom . "', " . $votre_age . ")";
// Requête dynamique avec variables protégées
$sql = "INSERT INTO eleve (nom, age) VALUES ('" . $db->real_escape_string($votre_nom) . "', " . $db->real_escape_string($votre_age) . ")";

// Execution de la requête sql avec $db->query()
$succes = $db->query($sql);

?>
A noter : real_escape_string() permet uniquement de protéger le contenu de la variable. Il ne dispense pas de délimiter les chaînes de caractères avec des apostrophes dans la requête SQL.

4) Insert préparé / protection des données implicite

Les requêtes préparées sont utiles pour enregistrer plusieurs enregistrements similaires. On ne créer alors qu'une seule requête et on lui passe consécutivement les valeurs propres à chaque enregistrement.

Constantes i: type integer ; d: type double ; s: type string ; b: type blob
<?php 

// Requête préparée
$sqlPrepare = "INSERT INTO student (nom, age) VALUES(?, ?)";
$conn = $db->prepare($sqlPrepare);

// Exécution simple (nota : les requêtes préparées ne seraient pas justifiée dans ce cas)
$conn->bind_param("si", 'Bob', 19); // "si", s pour string et i pour integer.
$conn->execute();

// Exécutions multiple
$eleves = array(
array('Bob', 19),
array('Stuart', 21),
array('Kevin', 20)
);

foreach ($eleves as $e) {
$conn->bind_param("si", $e[0], $e[1]); // "si", s pour string et i pour integer.
$conn->execute();
}

?>
A noter : avec bind_param, il n'est pas nécessaire de prévoir les apostrophes autour des chaines dans la requête. Celles-ci sont automatiquement ajoutée si nécessaire en fonction du type du paramètre (string, int, ...)

5) Select * qui retourne plusieurs enregistrements (parcours avec fetch)

<?php

$sql = "SELECT * FROM eleve ORDER BY age DESC ";
if ($rs = $db->query($sql)) {
while ($row = $db->fetch_assoc($rs)) {
echo "Eleve : " . $row['nom'] . " / Age : " . $row['age'] . " ans. <br />";
}
$rs->free();
}
?>


6) Select avec max() qui retourne 1 seul enregistrement

<?php

$sql = "SELECT max(age) AS val FROM eleve";
if ($rs = $db->query($sql)) {
$row = $db->fetch_assoc($rs);
echo "L'élève le plus vieux a " . $row['val'] . " ans.";
}

$db->close();
?>
Ce n'est pas en améliorant la bougie que l'on a inventé l'ampoule...

2 messages   •   Page 1 sur 1