samedi 23 mars 2013

Gérer d'encodage de la connection

Pour forcer l'échange en UTF8 avec MySQL, nous devons envoyer une requète au serveur pour lui expliquer que nous allons communiquer avec lui en UTF8, de façon standard, cela se joue au moment de la connection, et Ô bonheur, l'Object PDO est prévus pour ça (Quel heureux hazard !).
En effet, la ligne :
?
1
$connection = new PDO( $dns, $utilisateur, $motDePasse );
Nous permet d'ajouter un 4ème paramètres pour préciser des options de connection, comme par exemple une requète à exécuter au moment ou la connection est établie, cela donne :
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Connection au serveur
try {
  $dns = 'mysql:host=localhost;dbname=ma_base_de-donnees';
  $utilisateur = 'sergio';
  $motDePasse = 'azerty';
 
  // Options de connection
  $options = array(
    PDO::MYSQL_ATTR_INIT_COMMAND    => "SET NAMES utf8"
  );
 
  // Initialisation de la connection
  $connection = new PDO( $dns, $utilisateur, $motDePasse, $options );
} catch ( Exception $e ) {
  echo "Connection à MySQL impossible : ", $e->getMessage();
  die();
}
Notez l'ajout de la variable $options (un array) qui va contenir une option 'MYSQL_ATTR_INIT_COMMAND', cette options permet d'envoyer une requètes au moment ou la connection est établie, la requètes en question "SET NAMES utf8" indique simplement à MySQL que nous allons echanger nos données en UTF8.
Bon la version moins standard consiste simplement à faire cette requète juste après la connection :
?
1
2
3
4
5
6
7
8
9
10
11
// Connection au serveur
try {
  $dns = 'mysql:host=localhost;dbname=ma_base_de-donnees';
  $utilisateur = 'sergio';
  $motDePasse = 'azerty';
  $connection = new PDO( $dns, $utilisateur, $motDePasse );
  $connection->query("SET NAMES utf8");
} catch ( Exception $e ) {
  echo "Connection à MySQL impossible : ", $e->getMessage();
  die();
}
Ca reviens au même, mais disons que la première version, certes plus verbeuse, est plus "élégante" (et accessoirement, nous allons par la suite ajouter des paramètres dans les options).

Envoyer des SELECT

Pour selectionner des enregistrements, nous utiliserons la méthode query($requete).
?
1
2
3
4
5
// On établis la connection
require_once('conf/connection.php');
 
// On envois la requète
$select = $connection->query("SELECT * FROM createurs");
La variable $select contiend maintenant le résultat de la requète, mais sous une forme un peu particulière : un PDOStatement. Vous pourrez allé consulter la documentation pour obtenir des informations complémentaires sur cette classe.
http://www.php.net/manual/fr/class.pdostatement.php : Documentation officiel pour PDOStatement
Cet objet contiend la réponse du serveur de données à la requète que nous lui avons envoyé. Cette objet va nous permettre de gérer l'affichage des données reçues, pour cela il existe plusieurs méthodes :

Avec setFetchMode / fetch

PDO nous offre la libertée d'utiliser la réponse au format que nous voulons, nous pouvons dire que nous voulons traiter les enregistrements reçus comme des tableaux, comme des objets typés, etc... Comme nous débutons, nous allons traiter les enregistrements comme des objets simples.
Donc juste après avoir envoyé la requète (ou avant peu importe), nous allons "configurer" notre objet PDOStatement pour qu'ils nous livre les enregistrements comme des objets :
?
1
2
// On indique que nous utiliserons les résultats en tant qu'objet
$select->setFetchMode(PDO::FETCH_OBJ);
Notre variables $select contiend maintenant un objet pour chaque enregistrement obtenu, pour traiter tous les résultats nous allons utilise la boucle TANT QUE (la boucle while) :
?
1
2
3
4
5
6
// Nous traitons les résultats en boucle
while( $enregistrement = $select->fetch() )
{
  // Affichage d'un des champs
  echo '<h1>', $enregistrement->nom, ' ', $enregistrement->prenom, '</h1>';
}
Normalement, vous verrez une liste de nom de personnes connues appraitre dans un titre H1...
Si la réponse ne contiens pas de résutats, $select->fetch() va retourner NULL/FALSE. (Et donc l'éxécution de la boucle sera interrompue).
Si vous faites une requète qui ne doit retourner qu'un seul enregistrement, vous n'avez pas besoin d'utiliser une boucle pour traiter les résultats, mais utilisez quand même une condition pour éviter un message d'erreur disgracieux au moment de l'affichage :
?
1
2
3
4
5
6
7
8
9
10
11
12
// Traitement d'un seul résultat
$enregistrement = $select->fetch();
 
// On test si la variable $enregistrement, au cas
// ou elle serait vide.
if( $enregistrement ) {
  echo '<h1>', $enregistrement->nom, ' ', $enregistrement->prenom, '</h1>';
}
// La requète n'a pas retournée de résultat
else {
  echo "Aucun résultat";
}

Méthode fetch(PDO::FETCH_OBJ)

Petite variante avec une ligne de moins, dans cette exemple, le format de récupération (Format Objet) est précisé au moment du fetch() :
?
1
2
3
4
5
6
7
8
// Nous traitons les résultats en boucle
// C'est lors de l'utilisation de fetch() que nous spécifions
// le format de récupération pour le traitement.
while( $enregistrement = $select->fetch(PDO::FETCH_OBJ) )
{
  // Affichage d'un des champs
  echo '<h1>', $enregistrement->nom, ' ', $enregistrement->prenom, '</h1>';
}

Méthode fetchAll

Cette méthode va convertir notre objet de résultats en un tableau d'objet, ensuite nous traitons le tableau comme un tableau classique, ce cas d'application est surtout utilisé pour traiter des listes de résultats (Lorsque l'on s'attend à plusieurs résultats) :
?
1
2
3
4
5
6
7
8
9
// On transforme les résultats en tableaux d'objet
$createurs = $select->fetchAll(PDO::FETCH_OBJ);
 
// On traite le tableau $créateur
while( $enregistrement = next($createurs) )
{
  // Affichage d'un des champs
  echo '<h1>', $enregistrement->nom, ' ', $enregistrement->prenom, '</h1>';
}
Je n'ai pas fait de test de performance sur ces différentes méthodes, pour ma part j'aime bien la dernière car cela me permet potentiellement de manipuler le tableau... Sinon j'utilise la précédente quand je n'attend qu'un seul résultat.

C'est quoi ces caractères bizarres ???

Si vous avez mis des caractères spéciaux dans l'une des données affichées, c'est le drame.
Rien ne sert de vérifier le format de document ça ne viens pas de lui :P (Mais faites le quand même ça ne coute rien).
En effet, lors d'un echange avec le serveur web, l'encodage de transmission n'est pas formement l'UTF8 !!!
Pour corriger/forcer ça nous avons 2 solutions :
  • Une solution standard mais pas très lisible
  • Une solution moins standard mais plus facile à lire.

Envoyer des requètes

Une fois connecter au serveur MySQL avec notre objet PDO, nous allons pouvoir commencer à envoyer des requètes au serveur. Il existe plusieurs façon d'envoyer des requètes avec PDO, d'abord, tout dépend du type de requètes.
On distingue 2 types de requètes :
  • Les requètes qui selectionnent des enregistrements : SELECT
  • Les requètes qui transforment les enregistrements : UPDATE / INSERT / DELETE

Erreur levée par PDO

PDO étant orienté objet, il lève des exceptions en cas de problème. Les erreurs levée sont des PDOException, voici les différents type d'erreurs que vous pouvez rencontrer lorsque vous instanciez un objet PDO.

Erreur "could not find driver"

Cette erreur surviens si vous avez mal renseigné le moteur de base de données dans la DNS ou si le drivers choisi n'est pas supporté par votre serveur. Dans le cas du drivers MySQL, il est généralement actif par défaut sur la majorité des hébergements (et biensur activé par défaut sur W/Mamp).

Erreur "Unknown MySQL server host"

Cette erreur surviens quand le nom du serveur est mal renseigné / indisponible (MySQL dans notre cas). Chez certains "gros" hébergeurs, le nom du serveur beb n'est généralement pas localhost.

Erreur "Can't connect to MySQL server"

Dans le cadres des accès distants (le serveur MySQL n'est pas sur la même machine que le serveur Web), Vous obtiendrez ce message si le serveur est planté / indisponible, ou si le serveur auquel vous tenter d'accéder n'est pas un serveur de données MySQL.
Le message d'erreur appraît généralement après un certains temps (assez long) de chargement, vous verrez que la page "mouline" dans le vide. Il peut arrivé que votre serveur web lance un timeout avant que cette erreur ne survienne (votre page attend la réponse du serveur de données, mais ce dernier a mis trop de temps à répondre, du coup votre page se crash).

Erreur "Unknown database <db_name>"

Là le nom de la base de données est incorrect, ou plus grave, la base de données n'existe plus...

Erreur "Access denied for user"

Un grand classique, vous n'avez pas le droit d'accéder au serveur. Soit votre identifiant, soit votre mot de passe, soit les deux sont mal renseignés.

Intercepter les erreurs de connection avec un try { catch }

Le bloc try / catch est très pratique pour intercepter ce type d'erreur (on appelle ce genre d'erreur des Exception) :
?
1
2
3
4
5
6
7
8
9
10
// Connection au serveur
try {
  $dns = 'mysql:host=localhost;dbname=formation';
  $utilisateur = 'db_rider';
  $motDePasse = 'azerty';
  $connection = new PDO( $dns, $utilisateur, $motDePasse );
} catch ( Exception $e ) {
  echo "Connection à MySQL impossible : ", $e->getMessage();
  die();
}
La fonction die() porte bien son nom, elle va tuer le script PHP (toutes les lignes situées après le die ne seront jamais executées).
Il est fortement recommandé de se créer un fichier php (par exemple connection.php) contenant ces quelques lignes. En effet, si l'une de vos pages necessite alors un accès à la base de données, il vous suffira d'inclure ce fichier avec require_once.
?
1
require_once('conf/connection.php');

Connecting people !

Voici la connection type à un serveur MySQL. Notez que la connection au serveur de données est établie au moment où l'objet PDO est instancier :
?
1
2
3
4
5
// Connection au serveur
$dns = 'mysql:host=localhost;dbname=formation';
$utilisateur = 'db_rider';
$motDePasse = 'azerty';
$connection = new PDO( $dns, $utilisateur, $motDePasse );
La DNS, c'est en quelques sorte le point d'entrée pour accéder à notre base de données, il débute par le code du moteur de base de données (on appel ça l'engine parfois). Dans notre cas c'est mysql:
Ensuite on trouve l'adresse du serveur : host=localhost
Puis le nom de la base de données : dbname=formation
Et parfois on trouve aussi le port : port=3606, quand le port est spécifié, la variable $dns ressemble à ça :
?
1
2
// DNS où le port est spécifié
$dns = 'mysql:host=localhost;dbname=formation;port=3606';          
Quand le port est celui utilisé par défaut par le moteur de base de données, le spécifier est facultatif. Dans notre cas par exemle, le moteur de base de données est MySQL, pas conséquent, préciser le port 3606 est inutile (c'est le port par défaut).
L'accès au serveur est spécifier dans une chaine de caractère (la DNS), les paramètres s'expliment sour la forme parametre=valeur séparés par des point-virgules. Dans notre cas : "mysql:host=nomServeur;dbname=studio_formation"
Ensuite, le 2ème et le 3ème paramètres sont simplement les identifiant / Mot de passe MySQL, dans cet exemple on suppose que vous avez créez un utilisateur formation avec le mot de passe azerty ayant des droits d'accès à la base de données formation.

Qu'est-ce que la PDO ?

PDO (PHP Data Objects), extension définissant l'interface pour accéder à une base de données depuis PHP.
Elle est orientée objet, la classe s’appelant PDO.
Peu importe le SGBD utilisé, le code est unique, ce qui permet un "déplacement" rapide, puisqu'il faut juste changer les arguments envoyés au constructeur.
L'extension n'est pas activée dans PHP5, par défaut, il faut donc décommenter la ligne de "php_pdo.dll" dans php.ini. Il faut ensuite écrire "extension=php_pdo_[SGBD utilisé].dll", pour activer le SGBD.
  • Format :
$connexionAvecPDO = new PDO('SGBD:host=Serveur/Hôte;port=Port;dbname=Base de donnée', Utilisateur, Mot De Passe);
PDO constitue une couche d'abstraction. Elle intervient entre le serveur d'application et le serveur de base de données. La couche d'abstraction permet de séparer le traitement de la base de données. Ainsi on peut migrer vers un autre SGBD sans pour autant changer le code déjà développé.
Pour récupérer les enregistrements d’une table de la base de données, la méthode classique en PHP consiste à parcourir cette table ligne par ligne en procédant à des aller-retour entre le serveur d’application et le serveur de base de données. Ceci risque d’alourdir le traitement surtout si les deux serveurs sont installés chacun sur une machine différente. PDO remédie à ce problème en permettant de récupérer en une seule reprise tous les enregistrements de la table sous forme d’une variable PHP de type tableau à deux dimensions ce qui réduit visiblement le temps de traitement

Programmez en orienté objet en PHP

Bienvenue dans ce tutoriel sur la programmation orientée objet (souvent abrégé par ses initiales « POO ») en PHP.
Ici, vous allez découvrir un nouveau moyen de penser votre code, un nouveau moyen de le concevoir. Vous allez le représenter de façon orienté objet, un moyen de conception inventé dans les années 1970 et qui prend de plus en plus de place aujourd'hui. La principale raison de ce succès est due à de nombreux avantages apportés par ce paradigme, comme une organisation plus cohérente de vos projets, une maintenance plus facile et une distribution de votre code plus aisée.
Cependant, avant de vous lancer dans ce (très) vaste domaine, vous devez avoir quelques connaissances au préalable.
Ce qui doit être acquis
Afin de suivre au mieux ce tutoriel, il est indispensable voire obligatoire :
  • d'être à l'aise avec PHP et sa syntaxe. Si ce n'est pas le cas, le Site du Zéro propose un tutoriel ;
  • d'avoir bien pratiqué ;
  • d'être patient ;
  • d'avoir PHP 5 sur son serveur. Je ne parlerai pas de POO en PHP 4 car sous cette version de PHP, certaines fonctions indispensables de la POO ne sont pas présentes (on ne peut donc pas vraiment parler de POO).
Si vous avez déjà pratiqué d'autres langages apportant la possibilité de programmer orienté objet, c'est un gros plus, surtout si vous savez programmer en Java (PHP a principalement tiré son modèle objet de ce langage).