PHP
PDO
Jrme CUTRONA
[Link]@[Link]
[Link] Programmation Web 2013-2014 1
PDO
PDO : PHP Data Objects
Extension PHP fournissant une interface pour
accder une base de donnes
Fournit une interface d'abstraction pour l'accs
aux donnes
Ne fournit PAS une abstraction de base de
donnes
SQL spcifique au moteur
Fonctionnalits prsentes / absentes
Interface oriente objet
[Link] Programmation Web 2013-2014 2
Bases de donnes supportes
Nom du driver Bases de donnes supportes
PDO_DBLIB FreeTDS / Microsoft SQL Server / Sybase
PDO_FIREBIRD Firebird/Interbase 6
PDO_IBM IBM DB2
PDO_INFORMIX IBM Informix Dynamic Server
PDO_MYSQL MySQL 3.x/4.x/5.x
PDO_OCI Oracle Call Interface
PDO_ODBC ODBC v3 (IBM DB2, unixODBC et win32 ODBC)
PDO_PGSQL PostgreSQL
PDO_SQLITE SQLite 3 et SQLite 2
PDO_4D 4D
[Link] Programmation Web 2013-2014 3
Classes prdfinies
PDO :
connexion PHP / base de donnes
__construct()
exec(), prepare(), query()
errorCode(), errorInfo()
getAttributes(), setAttribute()
lastInsertId(), quote()
beginTransaction()
commit(), rollBack()
getAvailableDrivers()
[Link] Programmation Web 2013-2014 4
Classes prdfinies
PDOStatement :
requte prpare, jeu de rsultats
bindColumn(), bindParam(), bindValue(),
closeCursor()
errorCode(), errorInfo()
fetch(), fetchAll(), fetchColumn(), fetchObject(),
setFetchMode(), nextRowset()
rowCount(), columnCount(), getColumnMeta()
getAttribute(), setAttribute()
execute()
debugDumpParams()
[Link] Programmation Web 2013-2014 5
Connexions et gestionnaire de connexion
Instanciation d'un objet PDO
$dbh=new PDO(DSN [, user [, pass [, options]]]);
DSN : Data Source Name
nom_du_driver:syntaxe_spcifique_au_driver
Ex : mysql:host=localhost;dbname=ma_base
user : nom d'utilisateur, pass : mot de passe
options : tableau associatif
spcifiques au driver
Ex : array(PDO::ATTR_PERSISTENT => true)) ;
Fin de connexion : $dbh=null ; ou unset($dbh) ;
[Link] Programmation Web 2013-2014 6
Gestion des erreurs de connexion
Connexion par construction d'un objet
Gestion envisageable des erreurs
Aucune
Fin brutale (exit, die)
tat
Exception
En cas d'erreur de connexion
Objet PDOException lanc
PDOException hrite de Exception
[Link] Programmation Web 2013-2014 7
Gestion des erreurs de connexion
<?php
try {
$dbh = new PDO('mysql:host=h;dbname=db',
$user, $pass) ;
$dbh = null ;
}
catch (PDOException $e) {
echo "Erreur: ".$e->getMessage()."<br/>" ;
die() ;
}
?>
[Link] Programmation Web 2013-2014 8
Gestion des erreurs (hormis connexion)
PDO::ERRMODE_SILENT (par dfaut)
Mode silencieux, mise en place d'un code d'erreur
PDO : errorCode() / errorInfo()
PDOStatement : errorCode() / errorInfo()
PDO::ERRMODE_WARNING
Mise en place du code d'erreur
mission d'une erreur de type E_WARNING
PDO::ERRMODE_EXCEPTION
Mise en place du code d'erreur
Objet PDOException lanc
[Link] Programmation Web 2013-2014 9
Gestion des erreurs (hormis connexion)
<?php
try {
$dbh = new PDO('mysql:host=h;dbname=db',
$user, $pass) ;
$dbh->setAttribute(PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION);
$dbh = null ;
}
catch (PDOException $e) {
echo "Erreur: ".$e->getMessage()."<br/>" ;
die() ;
}
?>
[Link] Programmation Web 2013-2014 10
Gestion des erreurs : code d'erreur
<?php
$pdo = new PDO("mysql:host=localhost") ;
$pdostat = $pdo->query("COUCOU") ;
if ($pdo->errorCode()) {
echo "ERREUR !!\n" ; Code SQLSTATE
echo "<pre>\n" ;
var_dump($pdo->errorInfo()) ;
echo "</pre>\n" ; Code erreur spcifique
} du driver
?>
ERREUR !!
array(3) { Chane erreur
[0]=> string(5) "42000" spcifique au driver
[1]=> int(1064)
[2]=> string(47) "Erreur de syntaxe prs de 'COUCOU' la ligne 1"
}
[Link] Programmation Web 2013-2014 11
Gestion des erreurs : exceptions
<?php
try {
$pdo = new PDO("mysql:host=localhost") ;
$pdo->setAttribute(PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION) ;
$pdostat = $pdo->query("COUCOU") ;
} Code erreur spcifique
du driver
catch (Exception $e) {
echo "ERREUR : ".$e->getMessage() ;
Code SQLSTATE Chane erreur
}
spcifique au driver
?>
ERREUR : SQLSTATE[42000]: Syntax error or access violation: 1064
Erreur de syntaxe prs de 'COUCOU' la ligne 1
[Link] Programmation Web 2013-2014 12
Excution d'une requte
PDOStatement PDO::query ( string statement )
Rsultat de requte Requte
<?php
try {
$pdo = new PDO("mysql:host=localhost") ;
$pdostat = $pdo->query("SELECT * FROM clients") ;
}
catch (Exception $e) {
echo "ERREUR : ".$e->getMessage() ;
}
?>
[Link] Programmation Web 2013-2014 13
Exploitation des rsultats d'une requte
Rcupration des donnes ligne ligne
Une ligne peut tre :
un tableau index
un tableau associatif
un tableau mixte (par dfaut)
un objet anonyme
un objet d'une classe dfinie par l'utilisateur
Rcupration des donnes d'une colonne
[Link] Programmation Web 2013-2014 14
Exploitation des rsultats d'une requte (1)
try {
$pdo=new PDO("mysql:host=localhost;dbname=mysql") ;
$pdo->setAttribute(PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION);
$pdostat = $pdo->query("SELECT * FROM user") ;
$pdostat->setFetchMode(PDO::FETCH_ASSOC) ;
foreach ($pdostat as $ligne) {
echo implode(';', $ligne)."<br>\n" ;
}
}
catch (Exception $e) {
echo "ERREUR : ".$e->getMessage() ;
}
[Link] Programmation Web 2013-2014 15
Exploitation des rsultats d'une requte (2)
try {
$pdo=new PDO("mysql:host=localhost;dbname=mysql") ;
$pdo->setAttribute(PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION);
$pdostat = $pdo->query("SELECT * FROM user") ;
foreach ($pdostat->fetchAll(PDO::FETCH_ASSOC)
as $ligne) {
echo implode(';', $ligne)."<br>\n" ;
}
}
catch (Exception $e) {
echo "ERREUR : ".$e->getMessage() ;
}
[Link] Programmation Web 2013-2014 16
Exploitation des rsultats d'une requte (3)
try {
$pdo=new PDO("mysql:host=localhost;dbname=mysql") ;
$pdo->setAttribute(PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION);
$pdostat = $pdo->query("SELECT * FROM user") ;
while ($ligne
= $pdostat->fetch(PDO::FETCH_ASSOC)) {
echo implode(';', $ligne)."<br>\n" ;
}
}
catch (Exception $e) {
echo "ERREUR : ".$e->getMessage() ;
}
[Link] Programmation Web 2013-2014 17
Modes de rcupration des donnes (1)
PDO::FETCH_ASSOC
retourner chaque ligne dans un tableau index par les
noms des colonnes comme elles sont retournes
dans le jeu de rsultats correspondant. Si le jeu de
rsultats contient de multiples colonnes avec le
mme nom, PDO::FETCH_ASSOC retourne une
seule valeur par nom de colonne.
PDO::FETCH_NUM
retourner chaque ligne dans un tableau index par le
numro des colonnes comme elles sont retournes
dans le jeu de rsultats correspondant, en
commenant 0.
[Link] Programmation Web 2013-2014 18
Modes de rcupration des donnes (2)
PDO::FETCH_BOTH
retourner chaque ligne dans un tableau index par les
noms des colonnes ainsi que leurs numros, comme
elles sont retournes dans le jeu de rsultats
correspondant, en commenant 0.
PDO::FETCH_OBJ
retourner chaque ligne dans un objet avec les noms
de proprits correspondant aux noms des colonnes
comme elles sont retournes dans le jeu de rsultats.
[Link] Programmation Web 2013-2014 19
Modes de rcupration des donnes (3)
PDO::FETCH_BOUND
retourner true et assigner les valeurs des colonnes
du jeu de rsultats dans les variables PHP auxquelles
elles sont lies avec la mthode
PDOStatement::bindParam() ou la mthode
PDOStatement::bindColumn().
PDO::FETCH_CLASS |
PDO::FETCH_CLASSTYPE
retourner une nouvelle instance de la classe
demande, liant les colonnes aux proprits
nommes dans la classe.
Nom de la classe = 1re colonne.
[Link] Programmation Web 2013-2014 20
Modes de rcupration des donnes (4)
PDO::FETCH_INTO
met jour une instance existante de la classe
demande, liant les colonnes du jeu de rsultats aux
noms des proprits de la classe.
PDO::FETCH_LAZY
retourner chaque ligne en tant qu'objet avec les noms
des attributs correspondant aux noms des colonnes
retournes dans le jeu de rsultats.
PDO::FETCH_LAZY cre les noms des attributs de
l'objet comme ils sont rencontrs.
[Link] Programmation Web 2013-2014 21
Prparation d'une requte
Droulement d'une requte SQL
1. Analyse
2. Compilation
3. Optimisation
4. Excution
Excution rpte d'une requte : 1+2+3+4
Prparation d'une requte : 1+2+3
Excution rpte d'une requte prpare : 4
Prparation en fonction de paramtres :
Anonymes
Nomms
[Link] Programmation Web 2013-2014 22
Prparation d'une requte
PDOStatement PDO::prepare(string statement [,
array driver_options])
statement : la requte prparer. Peut contenir des
paramtres anonymes (?) ou nomms (:nom)
driver_options : tableau d'options du driver
retourne un objet PDOStatement qui effectuera
l'association des paramtres et excutera la requte
$pdo=new PDO("mysql:host=localhost;dbname=mysql") ;
$pdostat = $pdo->prepare(
"SELECT * FROM user WHERE User= ?") ;
[Link] Programmation Web 2013-2014 23
Association des paramtres d'une requte
bool PDOStatement::bindValue(mixed parameter,
mixed value [, int data_type])
parameter : le paramtre (nom ou position [1n])
value : sa valeur
data_type : le type de la valeur
PDO::PARAM_BOOL boolen.
PDO::PARAM_NULL NULL SQL.
PDO::PARAM_INT INTEGER SQL.
PDO::PARAM_STR CHAR, VARCHAR ou autre chane.
PDO::PARAM_LOB "objet large" SQL.
bool PDOStatement::execute([array parameters])
parameters : tableau associatif ou index des valeurs
[Link] Programmation Web 2013-2014 24
Prparation puis excution d'une requte (1)
$pdo=new PDO("mysql:host=localhost;dbname=mysql") ;
$pdo->setAttribute(PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION);
$pdostat = $pdo->prepare(
"SELECT * FROM user WHERE User= ?") ;
$pdostat->bindValue(1, 'root') ;
$pdostat->execute() ; paramtre anonyme
// Utilisation du rsultat
$pdostat->bindValue(1, 'cutrona') ;
$pdostat->execute() ;
// Utilisation du rsultat
Association
Prparation
Association d'une valeur
Excution
d'une valeur
delalarequte
de au
requte
au 1er paramtre
1er paramtre
[Link] Programmation Web 2013-2014 25
Prparation puis excution d'une requte (2)
$pdo=new PDO("mysql:host=localhost;dbname=mysql") ;
$pdo->setAttribute(PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION);
$pdostat = $pdo->prepare(
"SELECT * FROM user WHERE User= :utilisateur") ;
$pdostat->bindValue(':utilisateur', 'root') ;
$pdostat->execute() ; paramtre nomm
// Utilisation du rsultat
$pdostat->bindValue(':utilisateur', 'cutrona') ;
$pdostat->execute() ;
// Utilisation du rsultat
Association
Prparation
Excution
d'une valeur
de
dela
au
larequte
requte
paramtre nomm
[Link] Programmation Web 2013-2014 26
Prparation puis excution d'une requte (3)
$pdo=new PDO("mysql:host=localhost;dbname=mysql") ;
$pdo->setAttribute(PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION);
$pdostat = $pdo->prepare(
"SELECT * FROM user WHERE User= ?") ;
$pdostat->execute(array('root')) ;
// Utilisation du rsultat paramtre anonyme
$pdostat->execute(array('cutrona')) ;
// Utilisation du rsultat
Association
Association
Prparation
Excution
d'une
d'une valeur
valeur
de
delalaau
requte
au
requte
1er
1er paramtre
paramtre
[Link] Programmation Web 2013-2014 27
Prparation puis excution d'une requte (4)
$pdo=new PDO("mysql:host=localhost;dbname=mysql") ;
$pdo->setAttribute(PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION);
$pdostat = $pdo->prepare(
"SELECT * FROM user WHERE User= :utilisateur") ;
$pdostat->execute(
paramtre
array(':utilisateur' => 'root'nomm
)) ;
// Utilisation du rsultat
$pdostat->execute(
array(':utilisateur' => 'cutrona')) ;
// Utilisation du rsultat
Association
Prparation
Excution
d'une valeur
de
dela
au
larequte
requte
paramtre nomm
[Link] Programmation Web 2013-2014 28
Intrt des requtes prpares
Amlioration des performances en cas
d'excutions rptes
mulation faite par PDO si le driver ne les
supporte pas nativement
Protection automatique des valeurs des
paramtres pour interdire les attaques par
injection de code SQL
[Link] Programmation Web 2013-2014 29
Attaque par injection SQL ?
Ex : validation d'un login/pass sur un site
Requte consistant trouver un enregistrement
correspondant au couple login/pass fourni par
l'utilisateur
SELECT *
FROM membre
WHERE mail='{$_GET['mail']}'
AND passwd='{$_GET['passwd']}'
Et si on essayait de fournir un mot de passe un
peu particulier
[Link] Programmation Web 2013-2014 30
Exemple concret d'injection SQL (1)
$pdo = new PDO('mysql:host=localhost;dbname=test') ;
$pdostat = $pdo->query($req = <<<SQL
SELECT *
FROM membre
WHERE mail='{$_GET['mail']}'
AND passwd='{$_GET['passwd']}'
SQL
) ;
echo "Requte:\n$req\n" ;
if ($utilisateur = $pdostat->fetch())
echo "Bienvenue {$utilisateur['nom']}" ;
else
echo "Dsol..." ;
[Link] Programmation Web 2013-2014 31
Exemple concret d'injection SQL (2)
Saisie de l'utilisateur :
mail : whatever
pass : who_cares?
URL :
?mail=whatever&passwd=who_cares?
Requte:
SELECT *
FROM membre
WHERE mail='whatever'
AND passwd='who_cares?'
Dsol...
[Link] Programmation Web 2013-2014 32
Exemple concret d'injection SQL (3)
Saisie de l'utilisateur :
mail : whatever
pass : who_cares?' OR true!='
URL :
?mail=whatever&passwd=who_cares?'%20OR%20true!='
Requte:
SELECT *
FROM membre
WHERE mail='whatever'
AND passwd='who_cares?' OR true!=''
Bienvenue John
[Link] Programmation Web 2013-2014 33
Protection contre les injections SQL (1)
$pdo = new PDO('mysql:host=localhost;dbname=test') ;
$pdostat = $pdo->prepare($req = <<<SQL
SELECT *
FROM membre
WHERE mail=?
AND passwd=?
SQL
) ;
$pdostat->execute(array($_GET['mail'],
$_GET['passwd'])) ;
if ($utilisateur = $pdostat->fetch())
{ echo "Bienvenue {$utilisateur['nom']}\n" ; }
else { echo "Dsole...\n" ; }
[Link] Programmation Web 2013-2014 34
Protection contre les injections SQL (2)
$pdo = new PDO('mysql:host=localhost;dbname=test ') ;
$mail = $pdo->quote($_GET['mail']) ;
$passwd = $pdo->quote($_GET['passwd']) ;
$pdostat = $pdo->query($req = <<<SQL
SELECT *
FROM membre
WHERE mail=$mail
AND passwd=$passwd
SQLRequte:
) ; SELECT *
FROM membre
echo "Requte: \n$req\n" ;
WHERE mail=
if ($utilisateur 'whatever
= $pdostat ' ())
->fetch
AND "passwd=
{ echo 'who_cares?
Bienvenue {$utilisateur\'['nom
OR 'true!=
]}\n" ; \}''
Dsol...
else { echo "Dsole...\n" ; }
[Link] Programmation Web 2013-2014 35
Protection contre les injections SQL (3)
mysql_connect('localhost'); mysql_select_db('test');
$mail = mysql_real_escape_string ($_GET['mail']);
$passwd = mysql_real_escape_string ($_GET['passwd']);
$res = mysql_query($req = <<<SQL
SELECT * FROM membre
WHERE mail='$mail'
AND passwd='$passwd'
SQL
Requte:
) ;
SELECT * ($res) == 1 ) {
if (mysql_num_rows
FROM membre
$utilisateur = mysql_fetch_assoc($res) ;
echo "WHERE mail='
Bienvenue whatever['
{$utilisateur 'nom']}\n" ;
} AND passwd='who_cares?\' OR true!=\''
Dsol...
else { echo "Desole...\n" ; }
[Link] Programmation Web 2013-2014 36
Transactions
Transactions :
Atomicit, Consistance, Isolation et Durabilit
BEGIN puis COMMIT ou ROLLBACK
Mode PDO par dfaut :
Chaque requte est valide automatiquement
PDO::beginTransaction()
PDO::commit()
PDO::rollBack()
Tous les moteurs ne supportent pas les
transactions PDOException
[Link] Programmation Web 2013-2014 37