Intéressé par des cours d'informatique en ligne ?
Visitez mon nouveau site https://www.yesik.it !

Dans cet article d'introduction, nous allons voir comment il est possible d'utiliser PDO pour se connecter à une base de données MySQL à partir d'un script PHP.

PDO

PDOPHP Data Objects – est une extension de PHP pour accéder à une base de données.

PDO est fourni en standard à partir de PHP5.1, et ne fonctionne pas avec les versions de PHP antérieures à PHP5.0.

Vous pouvez vérifier que PDO est disponible sur votre version de PHP à l'aide de la fonction PHP phpinfo.

<?php
    phpinfo();
?>

Copiez le script ci-dessus dans votre réportoire web, et accédez-y avec votre navigateur. Si dans la page qui s'affiche, vous voyez apparaitre une section "PDO", c'est que cette extension est disponible. Dans le cas contraire, reportez-vous au manuel de php pour savoir comment l'installer.

Avantage

L'avantage principal de PDO est d'offrir une interface uniforme d'accés à une base de données sous PHP.

Ainsi, contrairement à ce qui se passait sous PHP4, Il n'est donc plus nécessaire d'utiliser une API différente pour chaque SGBD. Avec PDO, les mêmes classes et les mêmes méthodes peuvent être utilisées quelle que soit le système de gestion de base de données sous-jacent (MySQL, PostgreSQL, Oracle, etc.).

Limitation

Si PDO offre une interface d'accès similaire à toute base de données sous PHP, ça n'est pas pour autant une couche d'abstraction. En effet, si les classes et les méthodes sont les mêmes, le code SQL lui reste spécifique à chaque base de données.

Pour contourner cette limitation – et au cas où l'on souhaite faciliter une éventuelle migration vers une autre base de données – il sera judicieux d'utiliser une au l'autre des techniques suivantes pour faciliter la migration:

Un premier programme avec PDO

Note:

Pour le reste de cet article, nous supposerons que vous utilisez MySQL.

Voici un fragment de code PHP permettant de se connecter à une base de données MySQL avec PDO:

/* Data Source Name */
$dsn = 'mysql:host=localhost;dbname=hello';
 
$user = 'user';
$password = 'secret';
 
try
{
    /* Connection */
    $dbh = new PDO($dsn, $user, $password);
 
    /* Générer des exceptions en cas d'anomalie */
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
 
    echo 'Success';
}
catch (PDOException $e)
{
    echo 'Error PDO: ' . $e->getMessage();
}

Les points importants à noter sont les suivants:

Remarque:

De tout ce code, la seule instruction à modifier pour changer de base de données ou de SGBD est celle qui définit le DSN. Par exemple, pour accéder à une base de données via ODBC, il suffirait de modifier le DSN ainsi:

$dsn = "odbc:hello";

Vous le constatez, le format exact du DSN est spécifique à chaque SGBD!

Si vous testez l'exemple donné au début de cette section, vous obtiendrez vraisemblablement un des messages suivants:

Success!
Félicitations, vous avez réussi à vous connecter!
Error PDO: could not find driver
Oups! Avez-vous pensé à installer le driver PDO spécifique à votre base de données? En effet, pour fonctionner, PDO nécessite un driver spécifique pour chaque SGBD. C'est ce driver qui convertit les instructions PDO en commandes spécifiques au SGBR. Pour l'installer, vous pouvez par exemple chercher PDO dans votre gestionnaire de paquet...
Error PDO: SQLSTATE[42000] [1049] Unknown database 'hello'
Etes-vous certain que la base de données hello existe? Sous MySQL, cherchez donc la commande CREATE DATABASE.
Error PDO: SQLSTATE[42000] [1044] Access denied for user 'user'@'localhost' to database 'hello'
Etes-vous certain que l'utilisateur user possède les droits nécessaires pour accéder à la base hello? Sous MySQL cherchez donc la commande GRANT.
Error PDO: SQLSTATE[28000] [1045] Access denied for user 'user'@'localhost' (using password: YES)
Etes-vous certain d'avoir donné le bon mot de passe pour accéder à la base de données?

Accéder aux données

Pour cette section, nous supposons que vous disposez dans la base hello de la table world suivante:

CREATE TABLE `world` (
  `country` varchar(255) NOT NULL,
  `surface` decimal(10,0) DEFAULT NULL,
  `population` decimal(10,0) DEFAULT NULL,
  PRIMARY KEY  (`country`),
  KEY `surface` (`surface`),
  KEY `population` (`population`)
INSERT INTO `world` VALUES 
	('Algeria','2381741','32906000'),
	('Angola','1246700','16095000'),
	('Argentina','2780403','38592000'),
	('Australia','7692024','20329000'),
	('Bangladesh','147570','138600000'),
	('Belgium','30528','10479000'),
	('Brazil','8514877','184184000'),
	('United Kingdom','242514','60227000'),
	('Burkina Faso','267950','12802000'),
	('Chile','756096','16267000'),
	('Ecuador','256370','13215000'),
	('Egypt','1001450','74033000'),
	('Spain','505996','43398000'),
	('South Africa','1220813','46888000'),
	('Ethiopia','1127708','78986000'),
	('Philippines','319457','85237000'),
	('Ghana','238533','22535000'),
	('Guatemala','109027','12701000'),
	('Indonesia','1922728','219898000'),
	('India','3166414','1097000000'),
	('Iraq','438317','27996000'),
	('Iran','1745150','68467000'),
	('Italy','301336','58607000'),
	('Japan','377915','127773000'),
	('Yemen','538589','21096000'),
	('Cambodia','181035','13661000'),
	('Cameroon','475442','17795000'),
	('Canada','9984670','32299000'),
	('Kazakhstan','2723900','15147000'),
	('Kenya','582646','35267000'),
	('China','9572900','1303720000'),
	('Colombia','1141748','46039000'),
	('Congo, The Democratic Republic of the ','2344858','58741000'),
	('Korea, Democratic People’s Republic of (North Korea)','122762','23616000'),
	('Korea, Republic of (South Korea)','99646','48294000'),
	('Greece','131957','11104000'),
	('Cuba','110860','11243000'),
	('Madagascar','587041','17730000'),
	('Malawi','118484','12341000'),
	('Malaysia','329876','26128000'),
	('Mali','1248574','11611000'),
	('Morocco','458560','30495000'),
	('Mexico','1967183','103947000'),
	('Mozambique','799380','19420000'),
	('Myanmar','676577','47967000'),
	('Netherlands','41528','16320000'),
	('Nepal','147181','27094000'),
	('Niger','1189546','12546000'),
	('Nigeria','923768','133767000'),
	('Côte d’Ivoire','322461','19097000'),
	('Pakistan','880254','158081000'),
	('Peru','1285129','27947000'),
	('Portugal','92090','10549000'),
	('Poland','312683','38165000'),
	('France','547030','60996000'),
	('Romania','238391','21634000'),
	('Germany','357046','82469000'),
	('Zambia','752612','11478000'),
	('Saudi Arabia','2149690','23612000'),
	('Senegal','196722','10848000'),
	('Sri Lanka','65610','19668000'),
	('Sudan','2505890','36900000'),
	('Syria','185180','18138000'),
	('Taiwan, Province of China','36188','22726000'),
	('Tanzania','945088','37379000'),
	('Thailand','513120','64839000'),
	('Chad','1284000','10146000'),
	('Czech Republic','78867','10236000'),
	('Tunisia','163610','10029000'),
	('Turkey','783562','72065000'),
	('Uganda','241550','28947000'),
	('Ukraine','603628','47075000'),
	('Hungary','93030','10087000'),
	('Uzbekistan','449220','26593000'),
	('Venezuela','916445','26577000'),
	('Russian Federation','17098242','143150000'),
	('Viet Nam','329315','83120000'),
	('United States','9629088','295896000'),
	('Zimbabwe','390757','13120000');

Une fois l'objet de la classe PDO obtenu pour se connecter à la base de données, effectuer une requête se fait par l'intermédiaire d'un autre objet, celui-ci de la classe PDOStatement.

Cet objet, qui est la représentation lors de l'exécution du programme d'une requête SQL, peut être obtenu grâce à la méthode prepare de l'objet de la classe PDO. Tout ceci semble complexe, mais le code correspondant est relativement simple:

/* On stocke la requête dans une variable */
$sql = "SELECT country,surface FROM world";
/* On obtient l'instance de la classe PDOStatement 
   qui correspond à cette requête */
$stmt = $dbh->prepare($sql);
/* Enfin, on exécute la requête */
$stmt->execute();

Soyez prêt au cas où une exception se produirait

Tout ne va pas forcément bien: On peut par exemple imaginer que la table soit inexistante. Ou encore que la connexion au SGBD-R ait été perdue pour une raison ou une autre. Et mille autres raisons encore pour que ce code échoue.

Bref, ce fragment de code est tout à fait susceptible de générer une exception! Soyez donc préparé à cela en vous assurant qu'il existe quelque part dans la pile d'appel un bloc catch capable de gérer une exception de la classe PDOException.

Maintenant que nous avons exécuté la requête sur le serveur de base de données, il va falloir traiter les lignes récupérées. Cela va se faire grâce à une boucle qui va récupérer les lignes une par une, jusqu'à ce que l'ensemble des réponses soit épuisé:

while($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
    echo $row["country"], "\t", $row["surface"], "\n";
}

Remarque:

La constante PDO::FETCH_ASSOC indique que nous souhaitons récupérer chaque ligne sous la forme d'un tableau associatif. Cela nous permet d'accéder facilement aux valeurs individuelles de champs à l'aide de la syntaxe $row[nom_de_colonne].

Il existe cependant d'autre manière de récupérer ces données. Parmi celles-ci PDO::FETCH_OBJ et PDO::FETCH_BOUND sont aussi d'un grand intérêt. N'hésitez pas à vous reporter à la documentation de PDO pour en savoir plus!

Gérer les paramètres

Nous allons maintenant voir comment gérer les paramètres d'une requête. Par exemple, nous pourrions désirer récupérer la liste des pays dont la population dépasse un certain seuil choisi par l'utilisateur.

Pour arriver à ce résultat, nous n'avons besoin de faire que deux modifications dans le code source. Tout d'abord, nous allons changer la requête:

/* On stocke la requête dans une variable */
$sql = "SELECT country,surface FROM world WHERE population >= :minPopulation";

Vous remarquez l'ajout d'une clause WHERE, et surtout qu'au lieu de "coder en dur" la valeur limite, nous avons utilisé un paramètre de requête :minPopulation.

Il suffit ensuite d'associer ce paramètre formel à une valeur juste avant d'exécuter la requête:

/* On obtient l'instance de la classe PDOStatement 
   qui correspond à cette requête */
$stmt = $dbh->prepare($sql);
 
/* on associe le paramètre formel à une valeur */
$stmt->bindValue(':minPopulation', 500000000, PDO::PARAM_INT);
 
/* Enfin, on exécute la requête */
$stmt->execute();

Bien entendu, au lieu de coder en dur la valeur, celle-ci peut provenir d'une variable, et être, par exemple, extraite des paramètres de la requête http:

/* Extrait le seuil de population de la requête http GET */
$minPopulation = array_key_exists("minPopulation", $_GET) ? 
		    $_GET["minPopulation"] : 0;
 
/* on associe le paramètre formel à la valeur stockée dans la variable */
$stmt->bindValue(':minPopulation', $minPopulation, PDO::PARAM_INT);

Et voilà, en faisant la synthèse de tout ceci, vous devriez obtenir un programme PHP capable d'afficher la liste des pays dont la population dépasse un certain seuil. Par exemple la requête suivante permet de savoir quels pays atteignent ou dépassent les 500 millions d'habitants:

sh$ curl 'http://localhost/test-pdo.php?minPopulation=500000000'

Ressources