mysql_connect
, mysql_query
…pg_connect
, pg_query
…$pdo = new PDO($dsn, $user, $pass);
driver:infos
.
driver
dépend de la BD utilisée. Exemples : mysql
ou pgsql
pgsql:host=localhost;dbname=mydatabase
mysql:host=mysql.info.unicaen.fr;port=3306;dbname=jml_3;charset=utf8
oci:dbname=//localhost:1521/mydb
ibm:DRIVER={IBM DB2 ODBC DRIVER};DATABASE=accounts; HOSTNAME=1.2.3,4;PORT=23456;PROTOCOL=TCPIP;
Pour MySQL, les informations du DSN ont la forme de couples clef=valeur
séparés par des points-virgules. Attention à ne pas mettre d'espaces !
host
, le nom ou l'IP de la machine sur laquelle tourne le serveur
port
, le port du host sur lequel le serveur MySQL écoute (optionnel, vaut 3306 par défaut)
dbname
, le nom de la base de données à utiliser
charset
, l'encodage de caractères de la base — très important pour éviter certaines failles de sécurité (voir plus loin)
mysql.info.unicaen.fr
https://NUMETU.users.info.unicaen.fr/phpmyadmin
attention, sur phpmyadmin de sandbox et ensweb c'est localhost, mais pour les étu c'est bien mysql.info.unicaen.fr
$pdo->setAttribute($attribute, $value);
, ou
passer les options dans le constructeur avec un tableau associatifPDO::ATTR_ERRMODE
PDO::ERRMODE_SILENT
(option par défaut) : les erreurs sont signalées seulement
par le code d'erreur renvoyé par la fonction ⇒ il faut absolument vérifier le code d'erreur à chaque appel à changer absolument !
PDO::ERRMODE_WARNING
: émet un message de niveau E_WARNING en cas d'erreurPDO::ERRMODE_EXCEPTION
: renvoie une PDOException
avec code et
information sur l'erreurEn pratique : $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
fortement recommandé pour bénéficier de la gestion des exceptions
query
Elle renvoie le résultat sous forme d'objet PDOStatement
,
via lequel on peut récupérer les données sous divers formats
<?php
/* requête select */
$requete = 'SELECT * FROM users;';
$stmt = $pdo->query($requete);
/* récupération de la ligne courante */
$ligne = $stmt->fetch();
var_export($ligne);
/* requêtes insert/update/delete */
$requete = "INSERT INTO users VALUES ('Toto', 'Dupont');";
$stmt = $pdo->query($requete);
/* pas de lignes à récupérer dans le PDOStatement, mais
* on peut vouloir savoir combien de lignes ont été affectées: */
echo 'Nombre de lignes affectées :' . $stmt->rowCount();
?>
PDOStatement
obtenus suite à un SELECT
ont en particulier deux méthodes permettant de récupérer les données :
fetch
ne renvoie qu'une seule ligne de résultatfetchAll
renvoie un tableau avec tous les résultats attention, ne pas utiliser s'il y a potentiellement beaucoup de résultats !
fetch
:
PDO::FETCH_ASSOC
: tableau indexé avec les noms de colonnesPDO::FETCH_BOTH
(défaut) : retourne un tableau indexé par les noms de colonnes mais aussi par les numéros de colonnesPDO::FETCH_OBJ
: retourne un objet anonyme avec les propriétés qui correspondent aux noms des colonnesPDO::FETCH_INTO
: met à jour une instance existante de la classe demandéefetchAll
fetch
et fetchAll
<?php
$stmt = $pdo->query("SELECT name, species FROM animals");
$tableau = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($tableau as $ligne) {
/* les champs correspondant à des indices */
echo "Nom :" . $ligne['name'];
echo "Espèce :" . $ligne['species'];
}
$stmt = $pdo->query("SELECT name, species FROM animals");
/* on peut préciser le mode globalement : */
$stmt->setFetchMode(PDO::FETCH_OBJ);
/* utilisation classique de fetch() :
on récupère une ligne à la fois, tant qu'il en reste */
while (($ligne = $stmt->fetch()) !== false) {
/* les champs correspondent à des attributs */
echo "Nom :" . $ligne->name;
echo "Espèce :" . $ligne->species;
}
?>
La méthode query
n'est à utiliser que
pour faire des requêtes « constantes », c'est-à-dire avec une chaîne de caractères
littérale, sans variables
Ne pas respecter cette consigne rend votre site vulnérable aux injections SQL
demo : si on met une apostrophe dans un champ ? et que peut-on faire de plus ?
<?php
/* --- À NE PAS FAIRE --- */
$login = $_GET['login'];
$pdo->query("SELECT name FROM users WHERE login='$login'"); // très dangereux !
?>
'; DROP TABLE users; --
(le grand classique)PDO permet la préparation de requêtes par le moteur SQL
sécurité vis-à-vis des injections SQL
$rq = "UPDATE users SET name=:nom, birthday=:naissance WHERE id=:id"
PDOStatement
) :
$stmt = $pdo->prepare($rq);
$data = array(
':id' => 23456,
':nom' => 'Rachel',
':naissance' => '2023-12-04',
);
$stmt->execute($data);
Avec un SELECT
, on utilise aussi execute
<?php
/*** préparation ***/
$rq = "SELECT * FROM animals WHERE species = :espece AND name = :nom";
$stmt = $pdo->prepare($rq);
/*** remplissage des paramètres ***/
$data = array(":espece" => "humain", ":nom" => "Jean-Michel");
/*** exécution du statement ***/
$stmt->execute($data);
/*** récupération du résultat ***/
$result = $stmt->fetchAll();
?>
Attention à bien appeler execute
avant de faire
fetch
/fetchAll
!
LIMIT
en SQL attend des entiers sans guillemets :
<?php
$rq = "SELECT name FROM animals LIMIT :nb";
$stmt = $pdo->prepare($rq);
$data = array(":nb" => 10);
/* ne fonctionne pas : la requête exécutée est *
* SELECT name FROM animals LIMIT '10' */
$stmt->execute($data);
$result = $stmt->fetchAll();
bindValue
PDO::PARAM_STR
(par défaut)PDO::PARAM_INT
PDO::PARAM_BOOL
<?php
$rq = "SELECT name FROM animals LIMIT :nb";
$stmt = $pdo->prepare($rq);
$stmt->bindValue(":nb", 10, PDO::PARAM_INT);
$stmt->execute();
$result = $stmt->fetchAll();
PDO::ATTR_EMULATE_PREPARES
à false
ne pas le faire peut créer une vulnérabilité dont même les requêtes préparées ne protègent pas si elles ne sont qu'émulées.
Au passage, il n'y a qu'un seul encodage à utiliser dans MySQL : utf8mb4
(et pas utf8
, qui n'est pas le vrai UTF-8 !)
Une dernière chose : la méthode lastInsertId()
de PDO
renvoie la valeur de la clef primaire autoincrémentée de la dernière entrée ajoutée
(si le SGBD supporte cette fonction).
peut être utile pour MySQL (pour PostgreSQL, utiliser INSERT… RETURNING
semble plus simple)