web:php:chap6

Ceci est une ancienne révision du document !


Chapitre 7 : Accès aux bases de données (sans framework)

PDO : PHP Data Objects

  • Depuis PHP 5
  • Orienté objet
  • Interface commune à de multiples bases de données (+ de 10), via un driver spécifié dans le DSN
  • Référence aux types de champs
  • Protection des noms des objets : SELECT * FROM `nomTable`

<?php
$dbo = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
?>

Data Source Name : chaîne définissant les paramètres de connexion à une base

BDD DSN
Mysql mysql:host=localhost;port=3307;dbname=testdb
PostgreSQL pgsql:host=localhost;port=5432;dbname=testdb;user=bruce;password=mypass
Oracle oci:dbname=localhost:1521/mydb

<?php
try {
	$dbo = new PDO('mysql:host=localhost;dbname=test',$user, $pass);
	$dbo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);		
			
} catch (PDOException $e) {
	print "Error!: " . $e->getMessage() . "<br/>";
	die();
}
?>

-- Port par défaut du serveur

<?php
	$dbo = new PDO('mysql:host=localhost;dbname=test;port=3306',$user, $pass);
?>

-- Définition de l'encodage

<?php
	$dbo = new PDO('mysql:host=localhost;dbname=test;port=3306',$user, $pass);
	$dbo->exec("SET CHARACTER SET utf8");

?>

ou

<?php
    $dbo=new PDO("mysql:host=localhost;dbname=test;charset=UTF8");
?>

PDO::query retourne un PDOStatement (jeu d'enregistrements)
qu'il est ensuite possible de parcourir avec un foreach (retourne false en cas d’échec):

<?php
    $sql = 'SELECT name, color, calories FROM fruit ORDER BY name';
    $statement=$dbo->query($sql);
    foreach  ($statement as $row) {
        print $row['name'] . "\t";
        print  $row['color'] . "\t";
        print $row['calories'] . "\n";
  }
?>

Produit le résultat :

apple   red     150
banana  yellow  250
kiwi    brown   75
lemon   yellow  25
orange  orange  300
pear    green   150
watermelon      pink    90

<?php
    $sql = 'SELECT name, calories FROM fruit WHERE calories >100 ORDER BY name';
    $statement=$dbo->query($sql);
    foreach  ($statement as $row) {
        print $row['name'] . "\t";
        print $row['calories'] . "\n";
  }
?>

Produit le résultat :

apple   red     150
banana  yellow  250
orange  orange  300
pear    green   150

A la différence des instructions de sélection, la mise à jour ne retourne pas de jeu d'enregistrements.

PDO::exec() exécute une requête SQL et retourne le nombre de lignes affectées par la requête.

<?php
$dbo = new PDO('mysql:host=localhost;dbname=test', $user, $pass);

/* Effacement de toutes les lignes de la table FRUIT dont la couleur est rouge*/
$count = $dbo->exec("DELETE FROM fruit WHERE couleur = 'rouge'");

/* Retourne le nombre de lignes effacées */
print("Retourne le nombre de lignes effacées :\n");
print("Effacement de $count lignes.\n");
?>

L'exemple ci-dessus va afficher :

Retourne le nombre de lignes effacées :
Effacement de 2 lignes.

Consiste à modifier une instruction SQL existante, de façon malveillante (pour suppression de données, acquisition de droits, visualisation de données…)

Exemple :

URL afficheClient.php?id=1

<?php
  $id = $_GET["id"]; // Attention, aucun contrôle !
  $query  = "SELECT * FROM clients where id=".$id.";";
  $result = $dbo->query($sql);
?>

exemple d'injection possible :

1;DELETE FROM clients WHERE 1=1

via l'URL afficheClient.php?id=1;DELETE FROM clients WHERE 1=1

Conséquence : Suppression de toutes les données de la table client

  1. Se connecter à la BDD avec un utilisateur ayant des droits limités.
  2. Vérifiez que les données ont bien le type attendu. Utiliser is_numeric(), ctype_digit()… ou modifiez les avec settype(), ou sprintf()
  3. Utiliser des requêtes paramétrées

Version corrigée avec sprintf de la requête précédente :

<?php
  $id = $_GET["id"];
  $query  = sprintf("SELECT * FROM clients where id=%d;",$id);
  $result = $dbo->query($sql);
?>

  • Anti-injection
  • Réutilisation

PDOStatement PDO::prepare ( string $statement [, array $driver_options = array() ] )

Prépare une requête SQL à être exécutée, et retourne un PDOStatement

<?php
   $sql = 'SELECT nom, couleur, calories FROM fruit WHERE calories < :calories AND couleur = :couleur';
   $sta = $dbo->prepare($sql);
?>

Avec paramètres nommés

<?php
   $sta->bindValue(':calories', $calories, PDO::PARAM_INT);
   $sta->bindValue(':couleur', $couleur, PDO::PARAM_STR);
?>

<?php
   $sta->execute();
?>

Version avec paramètres fictifs

<?php
   $calories = 150;
   $couleur = 'rouge';
   $sta = $dbh->prepare('SELECT nom, couleur, calories FROM fruit WHERE calories < ? AND couleur = ?');
   $sta->bindValue(1, $calories, PDO::PARAM_INT);
   $sta->bindValue(2, $couleur, PDO::PARAM_STR);
   $sta->execute();
?>

PDOStatement::fetchAll — Retourne un tableau contenant toutes les lignes du jeu d'enregistrements

<?php
   $calories=100;
   $sta = $dbo->prepare("SELECT nom, couleur FROM fruit WHERE calories> ?");
   $sta->bindValue(1, $calories, PDO::PARAM_INT);
   $sta->execute();

   /* Récupération de toutes les lignes d'un jeu de résultats */
   print("Récupération de toutes les lignes d'un jeu de résultats :\n");
   $result = $sta->fetchAll();
   print_r($result);
?>

Classes/Enregistrements

Utilisation de PDO::FETCH_CLASS

<?php
class Fruit {
    public $name;
    public $colour;
}

   $sta = $dbo->prepare("SELECT name, colour FROM fruit");
   $sta->execute();

   $result = $sta->fetchAll(PDO::FETCH_CLASS, "Fruit");
   var_dump($result);
?>

Résultat :

array(3) {
  [0]=>
  object(fruit)#1 (2) {
    ["name"]=>
    string(5) "apple"
    ["colour"]=>
    string(5) "green"
  }
  [1]=>
  object(fruit)#2 (2) {
    ["name"]=>
    string(4) "pear"
    ["colour"]=>
    string(6) "yellow"
  }
  [2]=>
  object(fruit)#3 (2) {
    ["name"]=>
    string(10) "watermelon"
    ["colour"]=>
    string(4) "pink"
  }
}
  • web/php/chap6.1699453452.txt.gz
  • Dernière modification : il y a 12 mois
  • de jcheron