PHP - BD PostgreSQL S. Lanquetin LE2I Aile sciences de l'ingénieur Bureau G206 sandrine.lanquetin@u-bourgogne.fr Présentation Connexion (I) PostgreSQL s'appuie sur le modèle relationnel mais apporte les extensions suivantes : les classes, l'héritage, les types de données utilisateurs (tableaux, structures, listes..), les fonctions, Site http://postgresql.org/ l pg_connect( ) : renvoie true si la connexion est établie $id_connexion = pg_connect("dbname=nom_base host=nom_serveur port=num_port user=nom_utilisateur password=mot_passe" l pg_pconnect ( ) : connexion persistante (ne se referme pas automatiquement en fin de script). l pg_dbname( ) : retourne le nom de la base de données l $nom_base = pg_dbname ($id_connexion pg_close( ) : permet de fermer la connexion pg_close($id_connexion l On peut intégrer ce code dans un fichier que l on pourra joindre par include. (Sécuriser le mot de passe de connexion). 3 4 Connexion (II) Requête 5 l Exemple 1 : if( $id =pg_connect("dbname=nom_base host=nom_serveur port=num_port user=nom_utilisateur password=mot_passe")) { if(pg_dbname($id ) == "nom_base" ) { echo "Succès de connexion."; /* code du script */ else { exit("echec de connexion à la base." pg_close($id else { exit("echec de connexion au serveur de base de données." 6 l pg_query(..) pour envoyer une requête à une base de données retourne un identifiant de résultat ou FALSE si échec. $id_resultat = pg_query($id_connexion, $requete Les requêtes les plus couramment utilisées : CREATE (création d une table), SELECT (sélection), INSERT (insertion), UPDATE (mise à jour des données), DELETE (suppression), ALTER (modification d une table), etc. $result= pg_query ($id_connexion, "SELECT adresse FROM users WHERE name = pg_escape_string($name) " 1
Extraction des données (I) Extraction des données (II) l Affichage des résultats ligne par ligne. SQL > SELECT * FROM etudiants; ID NOM OPTION ---------------------------- 1 arthur image 1ère ligne 2 clement multimedia 2ème ligne 3 vincent image pour multimedia 3è ligne l plusieurs valeurs=>tableau, tableau associatif, ou objet. pg_fetch_row($result) : retourne une ligne de résultat sous la forme d un tableau. Les éléments du tableau étant les valeurs des attributs de la ligne. Retourne FALSE s il n y a plus aucune ligne. if($result = pg_query($requet)) { while($ligne = pg_fetch_row($result)) { $id = $ligne[0]; $nom = $ligne[1]; $option = $ligne[2]; else { 7 8 Ici, on accède aux valeurs de la ligne par leur indice dans le tableau. Extraction des données (III) Extraction des données (III) pg_fetch_array($result) : retourne tableau et tableau associatif. pg_fetch_assoc($result) : retourne un tableau associatif. Les clés étant les noms des attributs et leurs valeurs associées leurs valeurs respectives. Retourne FALSE s il n y a plus aucune ligne. 9 if($result = pg_query($requet)) { while($ligne = pg_fetch_array($result)) { $id = $ligne['id'];//$id = $ligne[0]; $nom = $ligne['nom']; $option = $ligne['option']; else { Ici, on accède aux valeurs de la ligne par l attribut dans le tableau associatif. 10 if($result = pg_query($requet)) { while($ligne = pg_fetch_assoc($result)) { $id = $ligne['id']; $nom = $ligne['nom']; $option = $ligne['option']; else { Ici, on accède aux valeurs de la ligne par l attribut dans le tableau associatif. Extraction des données (IV) Fonctions additionnelles 11 pg_fetch_object($result) : retourne un objet. Les attributs de l objet correspondent à ceux de la ligne de résultat. Et les valeurs des attributs de l objet correspondent à ceux de la ligne de résultat. Retourne FALSE s il n y a plus aucune ligne. Exemple 3 : if($result = pg_query($requet)) { while($ligne = pg_fetch_object($result)) { $id = $ligne->id; $nom = $ligne->nom; $option = $ligne->option; echo "$id - $name, $address <br />"; else { Ici, on accède aux valeurs par S. leur Lanquetin attribut - L3 : Introduction dans l objet. Technologie pour le Web 12 Quelques fonctions supplémentaires très utiles : l pg_free_result($result) : efface de la mémoire du serveur les lignes de résultat de la requête identifiées par $ result. l pg_num_fields($result) : retourne le nombre d attributs dans un résultat. l pg_num_rows($result) : retourne le nombre d'enregistrement dans un résultat. l Penser à bien tester la valeur de retour des fonctions (pg_query et les autres) afin de détecter toute erreur 2
Fonctions additionnelles l $nom_hote = pg_host($id_connexion) : retourne le nom de l'hôte pour la connexion spécifiée l $option_connexion = pg_options($id_connexion) : retourne les options d'une connexion SQL l $num_port = pg_port($id_connexion) : retourne le numéro de port pour la connexion indiquée l pg_set_client_encoding($id_connexion, $encodage) : détermine l'encodage du client (SQL_ASCII, UNICODE, ) l $encodage = pg_client_encoding($id_connexion) : retourne l'encodage du client; MySQL 13 Présentation Connexion (I) l MySQL : base de données implémentant le langage de requête SQL. l mysql_connect( ) : connection au serveur $server retourne l identifiant de connexion si succès, FALSE sinon l phpmyadmin : outil pour administrer aisément les bases de données MySQL avec php. http://www.phpmyadmin.net. $id_connexion = mysql_connect($server,$user,$password) l mysql_pconnect ( ) : connexion persistante (ne se referme pas automatiquement en fin de script). 15 l Avec MySQL vous pouvez créer plusieurs bases de données sur un serveur. Une base est composée de tables contenant des enregistrements. http://www.mysql.com/. l Documentation MySQL : http://www.mysql.com/documentation/ En français chez nexen : http://dev.nexen.net/ docs/mysql/. 16 if(mysql_select_db($base[,$idconnexion]) ) l mysql_select_db( ) : choix de la base $base, retourne TRUE en cas de succès, sinon FALSE l mysql_close ( ) : permet de fermer la connexion mysql_close($id_connexion l intégration de ce code avec include. (Sécuriser le mot de passe de connexion). Connexion (II) Requête l Exemple 1 : l mysql_query(..) pour envoyer une requête à une base de données retourne un identifiant de résultat ou FALSE si échec. if( $id =mysql_connect("nom_serveur","nom_utilisateur","mot_passe")) { if($id_db=mysql_select_db($base,$id) ) { echo "Succès de connexion."; /* code du script */ else { exit("echec de connexion à la base." mysql_close($id else { exit("echec de connexion au serveur de base de données." $id_resultat = mysql_query($requete Les requêtes les plus couramment utilisées : CREATE (création d une table), SELECT (sélection), INSERT (insertion), UPDATE (mise à jour des données), DELETE (suppression), ALTER (modification d une table), etc. $result = mysql_query( SELECT adresse FROM users WHERE name =\. mysql_real_escape_string($name). \ l Attention, contrairement à Oracle SQL, les requêtes MySQL ne se terminent pas par un point virgule ; 17 18 3
Extraction des données (I) Extraction des données (II) l Affichage des résultats ligne par ligne. SQL > SELECT * FROM etudiants; ID NOM OPTION ---------------------------- 1 arthur image 1ère ligne 2 clement multimedia 2ème ligne 3 vincent image pour multimedia 3ème ligne l plusieurs valeurs=>tableau, tableau associatif, ou objet. mysql_fetch_row($result) : retourne une ligne de résultat sous la forme d un tableau. Les éléments du tableau étant les valeurs des attributs de la ligne. Retourne FALSE s il n y a plus aucune ligne. if($result = mysql_query($requet)) { while($ligne = mysql_fetch_row($result)) { $id = $ligne[0]; $nom = $ligne[1]; $option = $ligne[2]; else { 19 20 Ici, on accède aux valeurs de la ligne par leur indice dans le tableau. Extraction des données (III) Extraction des données (III) mysql_fetch_array($result) : retourne tableau et tableau associatif. mysql_fetch_assoc($result) : retourne un tableau associatif. Les clés étant les noms des attributs et leurs valeurs associées leurs valeurs respectives. Retourne FALSE s il n y a plus aucune ligne. 21 if($result = mysql_query($requet)) { while($ligne = mysql_fetch_array($result)) { $id = $ligne["id"]; $nom = $ligne["nom"]; $option = $ligne["option"]; else { Ici, on accède aux valeurs de la ligne par l attribut dans le tableau associatif. 22 if($result = mysql_query($requet)) { while($ligne = mysql_fetch_assoc($result)) { $id = $ligne["id"]; $nom = $ligne["nom"]; $option = $ligne["option"]; else { Ici, on accède aux valeurs de la ligne par l attribut dans le tableau associatif. Extraction des données (IV) Fonctions additionnelles 23 mysql_fetch_object($result) : retourne un objet. Les attributs de l objet correspondent à ceux de la ligne de résultat. Et les valeurs des attributs de l objet correspondent à ceux de la ligne de résultat. Retourne FALSE s il n y a plus aucune ligne. Exemple 3 : if($result = mysql_query($requet)) { while($ligne = mysql_fetch_object($result)) { $id = $ligne->id; $nom = $ligne->nom; $option = $ligne->option; echo "$id - $name, $address <br />"; else { Ici, on accède aux valeurs par S. leur Lanquetin attribut - L3 : Introduction dans l objet. Technologie pour le Web 24 Quelques fonctions supplémentaires très utiles : l mysql_free_result($result) : efface de la mémoire du serveur les lignes de résultat de la requête identifiées par $requet. Très utile pour améliorer les performances du serveur. l mysql_insert_id([$id]) : retourne l identifiant d un attribut clé primaire AUTO_INCREMENT de la dernière insertion. l mysql_num_fields($result) : retourne le nombre d attributs du résultats. l mysql_num_rows($result) : retourne le nombre de lignes du résultats. Et ainsi permet de remplacer le while par un for. Penser à bien tester la valeur de retour des fonctions (mysql_query et les autres) afin de détecter toute erreur et d éviter les Warnings. 4
Qu'est ce que PDO PDO l PHP Data Objects l Interface d'abstraction à l'accès de données l Écrit en C l Fournit avec php 5.1 extension pour php 5.0 l Ne fonctionne pas avec les versions antérieures! 25 26 Les BD supportées Installation l MySQL 3,4,5 l PostgreSQL l SQLite 2 & 3 l ODBC l DB2 l Oracle l Firebird l FreeTDS/Sybase/MSSQL l Activer PDO php.ini : extension=php_pdo.dll l Activer le driver PDO de la base de données choisie extension=php_pdo_mysql.dll extension=php_pdo_pgsql.dll 27 28 Afficher drivers PDO disponibles Connexion l Lancer ce script pour connaître les drivers disponibles l Création d'une instance de la classe de base de PDO Connexion MySQL foreach( get_loaded_extensions () as $extension) { if(strpos(strtolower($extension), 'pdo')!== FALSE) { echo $extension.'<br/>'; // connexion => création d une instance $bd = new PDO('mysql:host=localhost;dbname=test', $user, $pass // déconnexion $bd = null; 29 30 5
Connexion Erreurs de connexion l Création d'une instance de la classe de base de PDO Connexion PostgreSQL // connexion => création d une instance $bd = new PDO('pgsql:host=localhost; port=5432; dbname=testbd', 'toto', 'pass' // déconnexion $bd = null; l Gestion des erreurs de connexion try { $bd = new PDO( catch (PDOException $e) { echo $e->getmessage( 31 32 Connexion persistante Requêtes l Tableau des options du driver passé au constructeur PDO l query() pour récupérer une information SELECT // connexion persistante $bd = new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(pdo::attr_persistent => true) // récupération de tous les éléments de la base table dans l'ordre croissant $bd ->query("select item FROM table ORDER BY item ASC" l exec() pour modifier la BD INSERT UPDATE DELETE // ajout d'un élément à la BD $bd ->exec("insert INTO table VALUES(' ','login', 'pass') " 33 34 Requêtes Requêtes l exec() retourne le nombre de lignes affectées par l'opération ou false en cas d'erreur Rque : Aucune ligne ne peut être modifiée : 0 false // ajout d'un élément à la BD $ nb_chgmt = $bd ->exec("insert INTO table VALUES(' ','login', 'pass') " if (!$nb_chgmt) // attention pas correct if ($ nb_chgmt!== false) // Correct l query() retourne un objet PDOStatement ou false en cas d'erreur // ajout d'un élément à la BD $ nb_chgmt = $bd ->query("select item FROM table ORDER BY item ASC" if (!$nb_chgmt) // attention pas correct if ($ nb_chgmt!== false) // Correct 35 36 6
Requêtes l query() retourne un objet PDOStatement ou false en cas d'erreur l Préparation de l'objet PDOStatement avec PDO::prepare() Appel avec PDOStatement::execute() Requête préparée l Compilé une fois, exécuté n fois l Séparation claire entre structure et données, prévention des injections SQL l Souvent plus rapide que query() et exec() 37 Requête préparée l Sans marqueur Requête préparée l Avec marqueur nominatif // préparation de la requête $requete_prepare=$bd->prepare("select identifiant FROM membres" // exécution de la requête $requete_prepare->execute( // affichage du résultat de la requête while($lignes=$requete_prepare->fetch(pdo::fetch_obj)) { echo $lignes->identifiant.'<br />'; // préparation de la requête $requete_prepare=$bd->prepare("select identifiant FROM membres WHERE ID_membre = :id" // exécution de la requête $requete_prepare->execute(array( ':id' => 1 ) // affichage du résultat de la requête $lignes=$requete_prepare->fetch(pdo::fetch_obj echo $lignes->identifiant.'<br />'; Requête préparée Requête préparée l Avec marqueur? // préparation de la requête $requete_prepare=$bd>prepare("select identifiant FROM membres WHERE ID_membre =? " // exécution de la requête $requete_prepare->execute(array(1 ) // affichage du résultat de la requête $lignes=$requete_prepare->fetch(pdo::fetch_obj echo $lignes->identifiant.'<br />'; // préparation de la requête $stmt = $bd->prepare( SELECT * FROM users WHERE id=? // exécution de la requête $stmt->execute(array($_get[ id ]) // affichage du résultat de la requête $stmt->fetch(pdo::fetch_assoc 7
Résultats de la requête l Flexibilité de PDO pour la récupération des données : Array Strings Objets Fonction de rappel Chargement tardif Itérateurs Résultats de la requête : tableaux $res = $db->query("select * FROM table" while ($row = $res->fetch(pdo::fetch_num)){ // $row == tableau avec indices des colonnes $res = $db->query("select * FROM table" while ($row = $res->fetch(pdo::fetch_assoc)){ // $row == tableau avec noms des colonnes $res = $db->query("select * FROM table" while ($row = $res->fetch(pdo::fetch_both)){ // $row == tableau avec indices et noms des colonnes Résultats de la requête : String l Résultats en une seule colonne $res = $db->query("select users WHERE login='login' AND password='password' " // fetch(pdo::fetch_column) if ($res->fetchcolumn()) { // retourne un string // login OK else { /* échec de l'authentication */ Résultats de la requête : Objet l Récupération d'une ligne comme une instance de stdclass où nom_colonne= nom_propriété. $res = $db->query("select * FROM table" while ($obj = $res->fetch(pdo::fetch_obj)) { // $obj == instance de stdclass Résultats de la requête : Classe l Nouvelle instance d'une classe de votre choix avec colonne = membre de la classe $res = $db->query("select * FROM table" $res->setfetchmode( PDO::FETCH_CLASS, "ma_classe", array('optional'='constructor Params') while ($obj = $res->fetch()) { // $obj == instance de ma_classe Résultats de la requête : Classe l Détermine le nom de la classe à partir de la valeur de la première colonne $res = $db->query( SELECT * FROM foo $res->setfetchmode( PDO::FETCH_CLASS PDO::FETCH_CLASSTYPE while ($obj = $res->fetch()) { // $obj == instance de classe avec comme //nom la valeur de la 1ere colonne 8
Résultats de la requête : Objet défini Résultats de la requête : Itérateur l Récupération des données dans un objet existant $u = new userobject; $res = $bd->query( SELECT * FROM users $res->setfetchmode(pdo::fetch_into, $u while ($res->fetch()) { // classe existante avec colonne // correspondant aux propriétés $res = $bd>query( SELECT * FROM users, PDO::FETCH_ASSOC foreach ($res as $row) { // $row = tableau représentant les valeurs //des lignes Lazy Fetching l Ligne -> objet avec nom variable = noms colonnes $res = $bd>query( SELECT * FROM users, PDO::FETCH_LAZY foreach ($res as $row) { echo $row[ name ]; // récupération des noms de colonnes uniquement Callback Function l Mode de récupération où le résultat est traité par une fonction function draw_message($subject,$email) { $res = $bd>query("select * FROM msg" $res->fetchall( PDO::FETCH_FUNC, "draw_message" Problème des requêtes directes l Requête interprétée à chaque exécution =>gâchis en cas de requête répétée l Sécurité : les données de l'utilisateur peuvent contenir des éléments menant à une injection SQL Caractères spéciaux l quote() Protège une chaîne pour l'utiliser dans une requête SQL PDO (guillemets autour de la chaine protection des caractères spéciaux $qry = "SELECT * FROM users WHERE login=".$db->quote($_post['login'])." AND passwd=".$db->quote($_post['pass'] 9
Récupération partielle de données l closecursor() : Ferme le curseur, permettant à la requête d'être de nouveau exécutée $res = $db->query("select * FROM users" foreach ($res as $v) { if ($res['name'] == 'end') { $res->closecursor( break; Informations de connexion l getattribute() pour obtenir des informations de connexion // version de la base de données $db->getattribute(pdo::attr_server_version // version de la bibliothèque cliente $db->getattribute(pdo::attr_client_version // metainformations sur le serveur de base de données $db->getattribute(pdo::attr_server_info // statut de connexion $db->getattribute(pdo::attr_connection_status http://www.php.net/manual/fr/book.pdo.php http://www.siteduzero.com/tutoriel-3-34790-pdointerface-d-acces-aux-bdd.html 57 10