Vous êtes sur la page 1sur 37

PHP

PDO
Jrme CUTRONA
jerome.cutrona@univ-reims.fr

22:29:23 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


22:29:27 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

22:29:31 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()

22:29:34 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()

22:29:38 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) ;
22:29:42 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

22:29:45 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() ;
}
?>

22:29:49 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

22:29:53 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() ;
}
?>
22:29:56 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"
}

22:30:00 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

22:30:03 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() ;
}
?>
22:30:07 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

22:30:11 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() ;
}

22:30:14 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() ;
}

22:30:18 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() ;
}

22:30:22 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.

22:30:25 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.

22:30:29 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.
22:30:33 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.

22:30:36 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
22:30:40 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= ?") ;

22:30:43 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
22:30:47 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

22:30:51 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

22:30:54 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

22:30:58 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

22:31:02 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

22:31:05 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

22:31:09 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..." ;

22:31:13 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...

22:31:16 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

22:31:20 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" ; }

22:31:23 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" ; }
22:31:27 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" ; }
22:31:31 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
22:31:34 Programmation Web 2013-2014 37