PHP propose trois API différentes pour se connecter à MySQL. Il s'agit des mysql
(supprimé à partir de PHP 7), mysqli
et PDO
extensions.
El mysql_*
étaient autrefois très populaires, mais leur utilisation n'est plus encouragée. L'équipe de documentation discute de la situation de la sécurité des bases de données, et éduquer les utilisateurs pour qu'ils s'éloignent de l'extension ext/mysql communément utilisée en fait partie (consultez le site de l'équipe de documentation). php.internals : dépréciation de ext/mysql ).
Et l'équipe de développeurs PHP ultérieurs a pris la décision de générer E_DEPRECATED
des erreurs lorsque les utilisateurs se connectent à MySQL, que ce soit par le biais de mysql_connect()
, mysql_pconnect()
ou la fonctionnalité de connexion implicite intégrée dans ext/mysql
.
ext/mysql
était officiellement déprécié à partir de PHP 5.5 et a été supprimé à partir de PHP 7 .
Vous voyez la boîte rouge ?
Quand vous allez sur n'importe quel mysql_*
Dans la page du manuel de la fonction, vous voyez une boîte rouge, expliquant qu'elle ne doit plus être utilisée.
Pourquoi
S'éloigner de ext/mysql
n'est pas seulement une question de sécurité, mais aussi d'accès à toutes les fonctionnalités de la base de données MySQL.
ext/mysql
a été construit pour MySQL 3.23 et n'a reçu que très peu d'ajouts depuis, tout en conservant la compatibilité avec cette ancienne version, ce qui rend le code un peu plus difficile à maintenir. Fonctions manquantes qui ne sont pas supportées par ext/mysql
inclure : ( _du manuel PHP_ ).
*Raison de ne pas utiliser `mysql_` función** :
- Pas en développement actif
- Supprimé à partir de PHP 7
- Manque d'une interface OO
- Ne prend pas en charge les requêtes non bloquantes et asynchrones.
- N'appuie pas les déclarations préparées ou requêtes paramétrées
- Ne prend pas en charge les procédures stockées
- Ne prend pas en charge les déclarations multiples
- Ne prend pas en charge transactions
- Ne supporte pas toutes les fonctionnalités de MySQL 5.1
Point ci-dessus cité dans la réponse de Quentin
L'absence de prise en charge des instructions préparées est particulièrement importante, car elles constituent une méthode plus claire et moins sujette aux erreurs pour l'échappement et la citation des données externes que l'échappement manuel avec un appel de fonction séparé.
Voir le comparaison des extensions SQL .
Suppression des avertissements de dépréciation
Pendant que le code est converti en MySQLi
/ PDO
, E_DEPRECATED
Les erreurs peuvent être supprimées en définissant error_reporting
en php.ini d'exclure E_DEPRECATED:
error_reporting = E_ALL ^ E_DEPRECATED
Notez que cela cachera également autres avertissements de dépréciation qui, cependant, peut être pour d'autres choses que MySQL. ( _du manuel PHP_ )
L'article PDO ou MySQLi : lequel utiliser ? par Dejan Marjanovic vous aidera à choisir.
Et un meilleur moyen est PDO
et j'écris maintenant un simple PDO
tutoriel.
Un tutoriel simple et court sur PDO
Q. La première question qui m'est venue à l'esprit est : qu'est-ce que le `PDO` ?
A. " PDO - Objets de données PHP - est une couche d'accès aux bases de données fournissant une méthode uniforme d'accès à plusieurs bases de données".
Connexion à MySQL
Avec mysql_*
ou on peut le dire à l'ancienne (déprécié en PHP 5.5 et plus)
$link = mysql_connect('localhost', 'user', 'pass');
mysql_select_db('testdb', $link);
mysql_set_charset('UTF-8', $link);
Avec PDO
: Tout ce que vous devez faire est de créer un nouveau PDO
objet. Le constructeur accepte des paramètres pour spécifier la source de la base de données PDO
Le constructeur de l'application prend principalement quatre paramètres, à savoir DSN
(nom de la source de données) et éventuellement username
, password
.
Ici, je pense que vous êtes familier avec tout sauf DSN
ce qui est nouveau dans PDO
. A DSN
est essentiellement une chaîne d'options qui indique PDO
le pilote à utiliser et les détails de connexion. Pour plus d'informations, consultez PDO MySQL DSN .
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password');
Nota: vous pouvez également utiliser charset=UTF-8
mais parfois cela provoque une erreur, il est donc préférable d'utiliser utf8
.
S'il y a une erreur de connexion, un message d'erreur sera généré. PDOException
qui peut être attrapé pour gérer Exception
plus loin.
Bonne lecture : Connexions et gestion des connexions ¶
Vous pouvez également transmettre plusieurs options de pilote sous forme de tableau au quatrième paramètre. Je recommande de passer le paramètre qui met PDO
en mode exception. Parce que certains PDO
ne prennent pas en charge les déclarations préparées natives. PDO
réalise l'émulation de la préparation. Il vous permet également d'activer manuellement cette émulation. Pour utiliser les instructions préparées natives côté serveur, vous devez explicitement définir la fonction false
.
L'autre solution consiste à désactiver l'émulation de la préparation, qui est activée dans l'onglet "Préparation". MySQL
par défaut, mais l'émulation de préparation doit être désactivée pour utiliser le pilote PDO
en toute sécurité.
J'expliquerai plus tard pourquoi l'émulation de préparation doit être désactivée. Pour trouver la raison, veuillez vérifier ce poste .
Il est uniquement utilisable si vous utilisez une ancienne version de MySQL
ce que je ne recommande pas.
Vous trouverez ci-dessous un exemple de la façon dont vous pouvez le faire :
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF-8',
'username',
'password',
array(PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
Peut-on définir des attributs après la construction de PDO ?
Oui nous pouvons également définir certains attributs après la construction de PDO avec la fonction setAttribute
método:
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF-8',
'username',
'password');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
Traitement des erreurs
La gestion des erreurs est beaucoup plus facile dans PDO
que mysql_*
.
Une pratique courante lors de l'utilisation de mysql_*
est :
//Connected to MySQL
$result = mysql_query("SELECT * FROM table", $link) or die(mysql_error($link));
OR die()
n'est pas une bonne façon de gérer l'erreur puisque nous ne pouvons pas gérer la chose en die
. Cela mettra simplement fin au script de manière abrupte et fera ensuite écho de l'erreur à l'écran, ce que vous ne voulez généralement PAS montrer à vos utilisateurs finaux, et laissera des pirates sanguinaires découvrir votre schéma. Alternativement, les valeurs de retour de mysql_*
peuvent souvent être utilisées en conjonction avec les fonctions mysql_error() pour gérer les erreurs.
PDO
propose une meilleure solution : les exceptions. Tout ce que nous faisons avec PDO
doit être enveloppé dans un try
- catch
bloc. Nous pouvons forcer PDO
dans l'un des trois modes d'erreur en définissant l'attribut de mode d'erreur. Les trois modes de traitement des erreurs sont les suivants.
-
PDO::ERRMODE_SILENT
. Il ne fait que définir des codes d'erreur et agit à peu près de la même manière que mysql_*
où vous devez vérifier chaque résultat et ensuite regarder $db->errorInfo();
pour obtenir les détails de l'erreur.
-
PDO::ERRMODE_WARNING
Soulevez E_WARNING
. (Avertissements d'exécution (erreurs non fatales). L'exécution du script n'est pas interrompue).
-
PDO::ERRMODE_EXCEPTION
: Lancer des exceptions. Elle représente une erreur soulevée par PDO. Vous ne devez pas lancer une PDOException
à partir de votre propre code. Voir Exceptions pour plus d'informations sur les exceptions en PHP. Il se comporte de la même manière que or die(mysql_error());
quand on ne l'attrape pas. Mais contrairement à or die()
El PDOException
peut être attrapé et traité avec élégance si vous choisissez de le faire.
Bonne lecture :
Comme :
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT );
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
Et vous pouvez l'emballer dans try
- catch
comme ci-dessous :
try {
//Connect as appropriate as above
$db->query('hi'); //Invalid query!
}
catch (PDOException $ex) {
echo "An Error occured!"; //User friendly message/message you want to show to user
some_logging_function($ex->getMessage());
}
Vous n'avez pas à vous occuper de try
- catch
en ce moment. Vous pouvez l'attraper à n'importe quel moment approprié, mais je vous recommande vivement d'utiliser try
- catch
. De plus, il peut être plus judicieux de l'attraper en dehors de la fonction qui appelle la fonction PDO
truc :
function data_fun($db) {
$stmt = $db->query("SELECT * FROM table");
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
//Then later
try {
data_fun($db);
}
catch(PDOException $ex) {
//Here you can handle error and show message/perform action you want.
}
En outre, vous pouvez gérer par or die()
ou nous pouvons dire comme mysql_*
mais il sera très varié. Vous pouvez masquer les messages d'erreur dangereux dans la production en tournant display_errors off
et en lisant votre journal d'erreurs.
Maintenant, après avoir lu tout ce qui précède, vous vous dites probablement : qu'est-ce que c'est que ça, alors que je veux juste commencer à m'adonner à la simplicité ? SELECT
, INSERT
, UPDATE
ou DELETE
déclarations ? Ne vous inquiétez pas, c'est parti :
Sélection des données
Donc ce que vous faites dans mysql_*
est :
<?php
$result = mysql_query('SELECT * from table') or die(mysql_error());
$num_rows = mysql_num_rows($result);
while($row = mysql_fetch_assoc($result)) {
echo $row['field1'];
}
Maintenant dans PDO
vous pouvez le faire comme ça :
<?php
$stmt = $db->query('SELECT * FROM table');
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo $row['field1'];
}
Ou
<?php
$stmt = $db->query('SELECT * FROM table');
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
//Use $results
Note : Si vous utilisez la méthode comme ci-dessous ( query()
), cette méthode renvoie un PDOStatement
objet. Donc si vous voulez récupérer le résultat, utilisez-le comme ci-dessus.
<?php
foreach($db->query('SELECT * FROM table') as $row) {
echo $row['field1'];
}
Dans les données PDO, elle est obtenue via la fonction ->fetch()
une méthode de votre gestionnaire de déclaration. Avant d'appeler fetch, la meilleure approche est d'indiquer à PDO comment vous souhaitez que les données soient récupérées. Dans la section ci-dessous, je vous explique cela.
Modes de récupération
Notez l'utilisation de PDO::FETCH_ASSOC
dans le fetch()
y fetchAll()
code ci-dessus. Cela indique PDO
pour retourner les lignes sous la forme d'un tableau associatif avec les noms des champs comme clés. Il existe également de nombreux autres modes de récupération que je vais expliquer un par un.
Tout d'abord, j'explique comment sélectionner le mode fetch :
$stmt->fetch(PDO::FETCH_ASSOC)
Dans ce qui précède, j'ai utilisé fetch()
. Vous pouvez également utiliser :
Maintenant, je viens en mode "recherche" :
-
PDO::FETCH_ASSOC
: renvoie un tableau indexé par le nom de la colonne tel qu'il apparaît dans votre jeu de résultats.
-
PDO::FETCH_BOTH
(par défaut) : renvoie un tableau indexé à la fois par le nom de la colonne et par le numéro de colonne indexé à 0, tel qu'il apparaît dans votre jeu de résultats.
Il y a encore plus de choix ! Découvrez-les tous dans PDOStatement
Récupérer la documentation. .
Obtenir le nombre de lignes :
Au lieu d'utiliser mysql_num_rows
pour obtenir le nombre de rangs retournés, vous pouvez obtenir un PDOStatement
et faire rowCount()
comme :
<?php
$stmt = $db->query('SELECT * FROM table');
$row_count = $stmt->rowCount();
echo $row_count.' rows selected';
Obtenir le dernier ID inséré
<?php
$result = $db->exec("INSERT INTO table(firstname, lastname) VAULES('John', 'Doe')");
$insertId = $db->lastInsertId();
Insertion et mise à jour ou suppression de déclarations
Ce que nous faisons dans mysql_*
la fonction est :
<?php
$results = mysql_query("UPDATE table SET field='value'") or die(mysql_error());
echo mysql_affected_rows($result);
Et dans pdo, cette même chose peut être faite par :
<?php
$affected_rows = $db->exec("UPDATE table SET field='value'");
echo $affected_rows;
Dans la requête ci-dessus PDO::exec
exécute une instruction SQL et renvoie le nombre de lignes affectées.
<em>L'insertion et la suppression seront abordées plus tard.</em>
La méthode ci-dessus n'est utile que lorsque vous n'utilisez pas de variable dans la requête. Mais lorsque vous avez besoin d'utiliser une variable dans une requête, n'essayez jamais de faire comme ci-dessus et là pour déclaration préparée ou déclaration paramétrée est.
Déclarations préparées
Q. Qu'est-ce qu'une déclaration préparée et pourquoi en ai-je besoin ?
A. Une instruction préparée est une instruction SQL précompilée qui peut être exécutée plusieurs fois en envoyant uniquement les données au serveur.
Le déroulement typique de l'utilisation d'une déclaration préparée est le suivant ( cité dans Wikipedia trois 3 points ) :
-
Préparer : Le modèle de relevé est créé par l'application et envoyé au système de gestion de base de données (SGBD). Certaines valeurs ne sont pas spécifiées, appelées paramètres, placeholders ou variables de liaison (étiquetées ?
ci-dessous) :
INSERT INTO PRODUCT (name, price) VALUES (?, ?)
-
Le SGBD analyse, compile et optimise les requêtes sur le modèle d'instruction, puis stocke le résultat sans l'exécuter.
-
Exécuter : Plus tard, l'application fournit (ou lie) des valeurs pour les paramètres, et le SGBD exécute l'instruction (en retournant éventuellement un résultat). L'application peut exécuter l'instruction autant de fois qu'elle le souhaite avec des valeurs différentes. Dans cet exemple, elle peut fournir 'Pain' pour le premier paramètre et 1.00
pour le deuxième paramètre.
Vous pouvez utiliser une instruction préparée en incluant des placeholders dans votre SQL. Il existe trois types d'instructions préparées : les instructions sans placeholders (n'essayez pas avec la variable ci-dessus), les instructions avec placeholders non nommés et les instructions avec placeholders nommés.
Q. Alors maintenant, qu'est-ce qu'un espace réservé nommé et comment l'utiliser ?
A. Des caractères de remplacement nommés. Utilisez des noms descriptifs précédés de deux points, plutôt que de points d'interrogation. Nous ne nous soucions pas de la position/ordre de la valeur dans le nom du placeholder :
$stmt->bindParam(':bla', $bla);
bindParam(parameter,variable,data_type,length,driver_options)
Vous pouvez également lier en utilisant un tableau d'exécution :
<?php
$stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name");
$stmt->execute(array(':name' => $name, ':id' => $id));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
Une autre fonctionnalité intéressante pour OOP
amis est que les placeholders nommés ont la possibilité d'insérer des objets directement dans votre base de données, en supposant que les propriétés correspondent aux champs nommés. Par exemple :
class person {
public $name;
public $add;
function __construct($a,$b) {
$this->name = $a;
$this->add = $b;
}
}
$demo = new person('john','29 bla district');
$stmt = $db->prepare("INSERT INTO table (name, add) value (:name, :add)");
$stmt->execute((array)$demo);
Q. Alors maintenant, que sont les caractères de remplacement sans nom et comment les utiliser ?
A. Prenons un exemple :
<?php
$stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)");
$stmt->bindValue(1, $name, PDO::PARAM_STR);
$stmt->bindValue(2, $add, PDO::PARAM_STR);
$stmt->execute();
y
$stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)");
$stmt->execute(array('john', '29 bla district'));
Dans l'image ci-dessus, vous pouvez voir les ?
au lieu d'un nom comme dans un porte-nom. Dans le premier exemple, nous attribuons des variables aux différents espaces réservés ( $stmt->bindValue(1, $name, PDO::PARAM_STR);
). Ensuite, nous attribuons des valeurs à ces espaces et exécutons l'instruction. Dans le deuxième exemple, le premier élément du tableau est placé dans le premier emplacement de l'instruction ?
et le second au second ?
.
NOTE : Sur des espaces sans nom nous devons veiller à l'ordre correct des éléments du tableau que nous transmettons à la fonction PDOStatement::execute()
método.
SELECT
, INSERT
, UPDATE
, DELETE
requêtes préparées
-
SELECT
:
$stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name");
$stmt->execute(array(':name' => $name, ':id' => $id));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
-
INSERT
:
$stmt = $db->prepare("INSERT INTO table(field1,field2) VALUES(:field1,:field2)");
$stmt->execute(array(':field1' => $field1, ':field2' => $field2));
$affected_rows = $stmt->rowCount();
-
DELETE
:
$stmt = $db->prepare("DELETE FROM table WHERE id=:id");
$stmt->bindValue(':id', $id, PDO::PARAM_STR);
$stmt->execute();
$affected_rows = $stmt->rowCount();
-
UPDATE
:
$stmt = $db->prepare("UPDATE table SET name=? WHERE id=?");
$stmt->execute(array($name, $id));
$affected_rows = $stmt->rowCount();
NOTA:
Cependant PDO
et/ou MySQLi
ne sont pas totalement sûrs. Vérifiez la réponse Les instructions préparées de PDO sont-elles suffisantes pour empêcher les injections SQL ? par ircmaxell . Aussi, je cite une partie de sa réponse :
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->query('SET NAMES GBK');
$stmt = $pdo->prepare("SELECT * FROM test WHERE name = ? LIMIT 1");
$stmt->execute(array(chr(0xbf) . chr(0x27) . " OR 1=1 /*"));
3 votes
L'erreur doit être comme : Erreur fatale : Unecaught Error : Appel à une fonction non définie mysql_connect() ...
48 votes
Le fait qu'ils soient dépréciés est une raison suffisante pour les éviter.