Explorer les Livres électroniques
Catégories
Explorer les Livres audio
Catégories
Explorer les Magazines
Catégories
Explorer les Documents
Catégories
http://netbeans.org/kb/trails/php.html
Chapitre 1 : Qu’est-ce que Php ?
Bibliothèques intégrées :
Beaucoup de bibliothèques intégrées existent et permettent la création de pdf, d’images etc ... à la volée,
l’envoi et la réception de mails, la connexion et la communication avec d’autres serveurs webs.
PEAR et PECL :
Modules additionnels de php obtenus à l’aide de PEAR.
Outils liés à Php :
SPIP ?
FPDF : librairie pour tout ce qui traite des pdfs.
PhPEDit : Editeur de code php.
Symfony : Framework php
EasyPhp : Auto-installeur de Apache, Php et SQL
1
2 Chapitre 2 : Installer et configurer
Configuration de php.ini :
• open_basedir =”/Repertoire/limitee” ; si cette option n’est pas commentée, elle est interdit tout accès
par Php aux fichiers et répertoire qui ne se trouvent pas dans /Repertoire/limitee
• max_execution_time = 30 ; spécifie le temps maximum d’exécution d’un script php. Au-delà de ce
temps, le script s’arrête et le navigateur renvoie un message d’erreur. Si 0 est mis, le temps d’exécution
est illimité.
• memory_limit = 128M; Mémoire maximale alloué à un script php.
• options à garder à off sauf pour assurer une compatibilité avec des vieux scripts php :
register_globals = off ;
magic_quotes_gpc = off ; directive qui servait à se prémunir des attaques par injection sql.
• include_path = ”.:/php/includes”; directive servant à définir où php va chercher les fichiers appelés
par include. Il est possible de définir plusieurs adresses dans lesquelles Php cherchera successivement les
fichiers recherchés. Par défaut, php cherche dans le répertoir PEAR.
Deux possibilités :
1. dans un fichier php en utilisant la fonction ini_set(directive, valeur de la directive) : change en local pour
le script la valeur de la directive ; la fonction ini_get(directive, valeur de la directive) permet de récupérer
la valeur de la directive pour la tester si besoin ou autre ; ini_restore(directive, valeur de la directive)
permet de rétablir la valeur initiale de la directive ;
2
2. dans httpd.conf d’Apache, les instructions
php_flag directive on (ou off) ; permet la modification d’une directive à valeur binaire pour un répertoir
ou un virtual host spécifique
et php_value directive ValeurDeLaDirective permet de faire la même chose mais pour une directive à
valeur textuelle ;
• en programme autonome : ça revient à la méthode ligne de commande en liant le type de fichier .php au
programme php.exe. L’exécution sera alors lancé dans une fenêtre DOS ;
• en mode embarqué : le php est alors utilisé comme langage de script par une autre application.
$NomDeLaVariable ValeurDeLaVariable;
Le premier caractère après le $ ne peut pas être un chiffre ou un caractère interdit (ex : @ . et -)
Typage des variables : typage faible et dynamique. Le typage d’une variable dépend du type de la
ValeurDeLaVariable et peut changer suivant les affectations.
3
Portée des variables : Elles n’existent que dans le bloc <?php ?> et disparaissent dès qu’on en sort (et
donc à l’affichage des pages html produites.
Les variables locales : ce sont celles définies dans un bloc interne au bloc principal <?php ?>. Par exemple
les variables déclarées dans le prototype d’une fonction :
function Calcul($var1,$var2)
sont locales.
Les variables globales sont définies au niveau du bloc <?php ?> ont une portée globale et peuvent être
appelés dans un sous-bloc en utilisant le tableau $GLOBALS des variables globales qui permet d’appeler une
variable globale par son nom comme suit :
$GLOBALS[’NomDeLaVariableGlobaleAppelée’]
On peut aussi déclarer localement une variable comme global ce qui signifie que la variable a déjà été déclarée
en dehors du bloc courant au niveau du bloc <?php ?>. Par exemple :
function CalculPrix($produit)
{
global $NomCalculateur;
utilise($produit, $NomCalculateur);
};
Dans ce cas, la variable $NomCalculateur a été déclarée ailleurs et l’instruction préfixe global le spécifie
tandis que produit est une variable locale.
Constantes :
Les constantes sont déclarées avec l’instruction
define(”ChaineCorrespondantAuNomDeLaConstante”,”ValeurDeLaConstante”);
Une constante ne peut pas jamais être changés de valeur une fois déclarée.
Php gère tout seul les types de variables : booléen,entier, virgule flottante et chaine.
4
GetType($var1) : type de la variable var1.
ATTENTION une valeur commençant par 0 est un octale, une valeur commençant par 0x est un hexadécimal.
Egalité entre nombres à virgules flottantes. Deux nombres à virgule flottante ne sont pas forcément égaux
et il faut donc prendre une marge d’erreur dans le cadre de test d’égalité.
Interprétation de variable dans des chaines de caractères. Dans une expression de chaines de caractères, les
appels $var1 renvoi la valeur de la variable var1 dans la chaine et il est même possible en utilisant les accolades
{} de faire réference à des valeurs d’un tableau ou une propriete d’un objet. Les accolades servent ainsi à insérer
le résultat d’une expression complexe dans une chaine.
L’usage des accolades : {} doivent impérativement encadrer le $ de toute variable y intervenant sauf à
vouloir explicitement utiliser le principe des variables dynamiques.
ATTENTION : en dehors d’une chaine, $var1 désigne la variable de nom var1 et non sa valeur.
Insertion de caractère spéciaux avec le caractère d’échappement : Comme en C++, le caractère \ permet
d’insérer des caractères normalement interdit tel quel dans une expression car correspondant à des caractères
réservés par l’interpréteur php. \” correspond ainsi au char ”, \$ permet d’afficher $, etc...
Comme en C++ :
\n fait un retour à la ligne, \r fait un retour chariot et \t fait une tabulation.
ATTENTION ces trois dernières instructions font des nouvelles lignes ou retour chariot dans le code Html
produit en résultat par php et non dans le navigateur directement...
Toute chaine php est un tableau commençant à l’indice 0 mais contrairement à C++, elle ne se termine pas
par \0 et n’a donc pas de caractère de fin de chaine propre.
Tableau classique :
5
$tabclassic = array(10, ”element bidon”, 23.5); /// tableau dont l’élément 0 est un entier, l’élément 1 une
chaine et le 2 un double
$tabAsso = array(
”prénom” => ”Bernard”,
”ville” => ”Paris”,
”travail” => ”ingénieur”);
Il est possible d’emboiter les instructions array de manière à avoir des matrices ou des tableaux de tableaux,
et il et aussi possible de mixer tableau classique et associatif en les imbriquant...
Attention pour avoir accès dans une chaine à la valeur d’un élément d’un tableau, il faut encadrer l’expression
de la valeur dans des accolades ET incorporer l’expression entre crochets dans une expression de chaine (càd
entre deux guillements ” ou apostrophes ’ suivant le délimiteur choisi pour l’expression de chaine :
Transtypage
Les casts marchent comme en C++. Exemple : (integer) var1 renvoie une nouvelle variable temporaire de
type integer si possible. La fonction settype(var1,’integer’) fait la même chose.
Pour identifier le type d’une variable, on utilise la fonction gettype qui renvoie une chaine indiquant le type.
Les seules subtilités concernent les chaines et les booléens.
Une chaine est convertit en valeur numérique si le début de la chaine correspond à des chiffres et donc :
echo 3+”fils2chacal”; /// donne 3
echo 3+”1conreste1con”; /// donne 4
Pour les booléens, est considéré comme FALSE les constantes FALSE et NULL, une chaine vide ou contenant
uniquement 0, le nombre entier ou réel 0 et un tableau vide. Tout le reste est considéré comme TRUE en cas
de cast vers le type boolean.
Un cast vers une chaine fait que TRUE devient 1, et que NULL, et FALSE deviennent une chaine vide
(par contre contrairement à ce que dit le bouquin, 0 ou 0.0 devient ”0”) et les tableaux, objets et ressources
afficheront leur type comme valeur.
ATTENTION pour les objets, le transtypage vers le type chaine peut être surchargé en définissant explicite-
ment la méthode __toString().
6
4 Chapitre 4 : Traitements de base
Opérateur d’affectation :
L’opérateur d’affectation binaire = renvoie la valeur de la variable quand on fait $var1 = $var2 +3 de sorte
que echo $var1 =$var2 +3 ne fait pas qu’affecter une valeur à $var1, il renvoie aussi une valeur.
Les Références :
Toutes les affectations qui ne concernent pas les objets sont faites par copie par défaut. cependant en écrivant
$var1 = &$var2; on définit $var1 comme une référence sur $var2.
Toutes les affectations utilisant un objet comme leftvalue se fait par référence !!
Opérateurs de concaténation :
l’opérateur de concaténation est le symbole ”.” et il s’utilise avec deux variables comme suit $var1.$var2
du moment que les deux variables sont assimilables (et castables éventuellement) en chaine. Il existe aussi un
opérateur .= analogue à +=
Opérateurs de comparaison:
Pareil qu’en C++ avec en sus les opérateurs === et !== qui compare la valeur et le type de la variable
pour égalité. ça permet de blinder certains tests et évite notamment des égalités non souhaités en chaine et
nombre.
Opérateurs logiques : RAS à part l’opérateur XOR qui est le ou exclusif (soit l’un, soit l’autre mais pas
les deux, ni aucun des deux).
7
• l’instruction foreach permet de parcourir les élements d’un tableau. La syntaxe dépend de la nature
classique ou associative du tableau :
Dans les boucles ( for,foreach, while et do while), l’instruction continue permet de sauter les instructions du
bloc de la boucle pour passer au test suivant. Exemple : on génère 10 variables aléatoires, et on affiche le nombre
s’il est supérieur strictement à 5 :
$Binaire = 0.0;
for($i =0;$i<10; $i++)
{
$Binaire = mt_rand(0.0,10.0);
echo ’<br> le nombre vaut :’.$Binaire;
if ($Binaire <=5)
{
continue; /// càd on revient à i++ et on repasse dans le bloc
};
$temp = $Binaire-5;
echo ’<br> le nombre dépasse 5 de ’.$temp.’ !!’;
};
Par rapport au C++, elles sont déclarées sans que le type de retour soit spécifié (beurk ! mais bon, c’est
comme ça !)
Comme en C++, les arguments présentant des valeurs par défaut sont mis en fin de liste.
Les arguments sont toujours passés par copie par défaut sauf si :
• l’argument est une objet : tout objet est toujours passé par référence.
• l’argument est déclaré comme une référence : Pour déclarer une variable argument comme étant une
référence il faut précéder la déclaration de l’argument de &. Ainsi la déclaration de prototype suivante :
func($var1, &$var2)
est celle d’une fonction dont le premier est passé par copie et le deuxième par référence.
8
Les références et les fonctions : Tout argument de fonction déclarés comme référence est modifié définitive-
ment suite à l’exécution du bloc de la fonction (si modif il y a bien sur).
Attention renvoyer en retour de fonction une référence ne suffit pas à renvoyer une référence mais renvoie au
final une copie de la référence. Pour cela, il faut aussi que le retour de la fonction soit déclaré comme référence.
ex :
func1(&$toto...)
{
...
return $toto;
}
le code $titi = func1() fait que la valeur de $titi est recopié de la valeur de la référence renvoyé par func1. Pour
déclarer une fonction comme renvoyant une référence, il faut précéder la déclaration du nom de la fonction de
& et bien sur s’assurer que c’est bien une référence qui est renvoyée, comme suit :
&func2(...)
{
return $toto;
}
Attention il ne faut pas écrire return &$toto, le symbole & provoque une erreur. Le symbole & doit uniquement
figurer devant le nom de la fonction (ici func2) pour que le renvoi par référence s’effectue.
list($var1,$var2,$var3)=FonctionQuiRetourneUnTabDeDim3
Attention le nb d’arguments de list() peut être inférieur ou égal à n mais jamais supérieur.
9
La syntaxe de l’opération est la suivante :
include(”NomDuFichier.php”)
Notons qu’il n’est pas nécessaire de spécifier le chemin d’accès si le répertoire de travail est bien spécifié dans
ph.ini. Notons ensuite que la chaine peut être remplacée par une variable chaine de caractère et on peut donc
”dynamiser” les includes. Notamment pour alléger les écritures, on peut déclarer des constantes symboliques
pour référer chaque fichier (et concentrer tout dans un classpath.php ou un filepath.php...) comme suit :
define(NOMSYMBOLIQUE, ”NomDuFichier.php”);
include(NOMSYMBOLIQUE);
IMPORTANT : pour éviter les include multiples qui feront planter l’exécution et/ou la compilation, il vaut mieux
require_once(string ”NomDuFichier.php”) et include_once(”NomDuFichier.php”) qui reviennent à combiner
#include et #pragma once en une seule instruction. L’ennui, c’est qu’en C++, le #pragma once agissait au
niveau du fichier inclus alors que le require_once agit lui au niveau du fichier incluant et donc un require_once
d’un fichier suivi plus loin d’un require du même fichier fait planter. Il Faut donc utiliser require_once tout le
temps pour éviter les merdes...
Un masque est une instruction %kekchose au sein d’une chaine de caractère. Le %kekchose est alors remplacé
par la valeur d’une variable passé en argument de la fonction printf. L’affichage de la variable est alors formaté
suivant le ”kekchose” %kekchose. On appelle le kekchose un spécificateur de conversion.
Chaque spécification de conversion est constituée d’un signe de pourcentage (%), suivi d’un ou plusieurs des
éléments suivants, dans cet ordre :
1. Un signe optionnel qui force un nombre à être positif ou négatif (- ou +). Par défaut, seul le signe -
est utilisé sur un nombre s’il est négatif. Ce spécificateur force également les nombres positifs à avoir un
signe + d’attaché, et a été ajouté en PHP 4.3.0 ;
2. Un remplisseur optionnel qui indique quel caractère sera utilisé pour compléter le résultat jusqu’à la
longueur requise. Ce peut être le caractère d’espace, ou le caractère 0. Par défaut, le remplissage se fait
avec des espaces. Un autre caractère de remplissage peut être spécifié en le préfixant avec un guillemet
simple (’) : ATTENTION si l’espace est choisi comme remplisseur, sur internet explorer, tous les espaces
contigus sont concaténés dans ce cas en un seul ;
3. Un spécificateur d’alignement qui indique si le résultat doit être aligné à gauche ou à droite. Par
défaut, le résultat est aligné à droite(contrairement à ce que dit la doc de phpEdit). Le caractère - fera
que le résultat sera justifié à gauche ;
4. (ajout BG) un spécificateur du nombre minimum de caractères : si la longueur de la chaine en
argument est inférieur strictement à ce nombre, la chaine est complété à gauche ou à droite à l’aide du
remplisseur optionnel ;
10
5. Un spécificateur de précision qui indique le nombre de décimales qui doivent être affichées pour les
nombres à virgule flottante (ATTENTION c’est bien ici le nombre de chiffres après la virgule). Lorsque
vous utilisez ce spécificateur dans une chaîne, il agit comme un point de coupure, définissant une limite
maximale de caractères de la chaîne INITIALE passé en argument (ça signifie que la chaine est tronquée
de la longueur excédentaire, c’est alors toujours la fin de la chaine qui est éliminée). Ce qui est drôle,
c’est que bien que tronquée (pour une chaine) ou arrondi (pour un float), le remplissage peut ensuite se
produire car le php compte ensuite le nombre de caractères de la valeur tronquée de la variable pour savoir
s’il fait du remplissage ;
6. Un spécificateur de type qui indique le type avec lequel l’argument sera traité. Plusieurs types possibles :
Exemple :
% −0 # − 10.5f
signifie que le signe - apparaitra, que la chaine sera complétée par le caractère #, sera justifiée à gauche,
que 10 caractères minimum devront apparaitre (les caractères manquants seront alors des # et que le nombre
float sera de 5 caractères max.
ATTENTION quand on tronque une string (s), le 5 s’applique au nombre total de caractères tandis que
dans le cas d’un double, c’est uniquement le nombre de chiffres après la virgule qui compte ! Dans le cas d’un
nombre entier ou décimal, la troncature ne sert à rien.
Ordonnancement des arguments sur sprintf et fonctions natives analogues : les arguments associés
dans l’ordre aux différents %kekchose du masque mais en l’occurrence, il est possible de donner un ordre dans
le masque de saisie. Pour spécifier l’ordre d’arrivée d’un argument dans ssprintf par rapport au masque, les
11
arguments dynamiques %kekchose du masque doivent intégrer un numéro correspondant à l’ordre de prise en
compte. Exemple : Affichage des dates suivant la langue du navigateur :
• sprintf : fait pareil que printf mais au lieu d’afficher en flux de sortie, envoie la chaine à afficher dans
une variable ;
• sscanf : permet de faire l’inverse de sprintf puisque suivant la string paramétrée ou masque, on récupère
les morceaux distincts. Cette fonction renvoie un tableau et est donc récupérable via la fonction native
list() ; Le prototype est :
sscanf(texteAParser,”masquedeparsing”)
rappelons qu’un exemple de parsing est ”%s %d” qui correspond à une chaine, un espace puis un nombre
décimal. ATTENTION quand le masque comporte une chaine (càd %s), la lecture de la chaine s’arrête
uniquement sur un espace et ce quelle que soit les caractères suivant %s dans le masque de saisie. Ce qui
n’est pas vraie pour les autres types de variables. Ex : Avec le masque ”%02d-%02d-%04d”, sscanf renvoie
les trois éléments numériques d’une date à partir d’une chaine du type ”08-06-2010”. Par contre le masque
”%s-%02d-%04d”, renvoie un chaine unique qui correspond à la chaine en entrée !! Le parsing a alors
échoué. Même en utilisant un masque précisant la longueur de %s, ça ne marche pas !!
• ord(’a’) : renvoie le code ASCII d’un caractère (attention ’a’ correspond à n’importe quel caractère et
non à a) ;
12
Conversions et formattages :
Suivant le contexte, certaines caractères sont considérés comme spéciaux dans une chaine et peuvent aboutir
à exécuter une commande non sollicitée si leur caractère spéciale n’est pas neutralisée ou échappée.
• Les fonctions stripslashes et stripcslashes font exactement l’inverse des deux fonctions respectives
précédentes sauf que stripclashes ne prend pas de liste de caractères à rétablir. Elles retirent les ’\’ en
convertissant toutefois tous les \n \r \t et \nnn ASCIIS dans leur équivalent affichage (retour chariot,
ligne, etc.) ;
Neutralisation simple des caractères spéciaux des chaines pour les requêtes de SGBD :
Normalement chaque API de base de données a ses fonctions de protection. Dans PHP notamment, la
couche SGBD PDO a la fonction quote()
htmlspecialchars(ChaineAProtéger,
Optionnel ENT_COMPAT ou ENT_NOQUOTES ou ENT_QUOTES,
Optionnel JeuDeCaractèresPourLaConversion);
La première option permet d’ajouter les guillemets et/ou les apostrophes dans la liste des caractères échap-
pés. Du coup, dans le code source, les caractères spéciaux du php pourront être neutralisés tandis qu’à l’affichage
final du code HTML, ce sont les caractères spéciaux de l’HTML qui le seront (il seront alors convertis en entités
HTML du type &kekchose;) ; La seconde option permet de définir l’encodage de la chaine à l’arrivée (ex : ISO-
8859-1 qui contient surtout les lettres anglo-saxonnes, ISO-8859-15 qui élargit le jeu précédent aux caractères
accentués français, espagnol, norvégien etc., l’utf-8 qui correspond à l’unicode avec une place mémoire optimisé)
htmlEntities() (même prototype) : convertit les caractères spéciaux à neutraliser mais aussi tous les
caractères php qui ont un équivalent entité en HTML. La différence avec la fonction htmlspecialchars est
uniquement visible dans le code source HTML. A l’affichage dans le navigateur (càd une fois le code HTML
exécuté) est identique entre les deux fonctions. exemple : la chaine
”<br>pété”
13
est converti par htmlspecialchars comme
”<br;&rtpété”
alors que HTMLEntities transforme ça en
”<br;&rtp;ét;é”
La fonction html_entity_decode() transforme les entities html (&kekchose) en équivalent html de sorte
que par exemple :
html_entity_decode(”<br;&rtpété”)=”<br>pété”
A noter que la fonction get_html_translation_table permet
Suppression de balises HTML :
• LC_CTYPE : pour la fonction strtoupper() qui transforme les minuscules d’une phrase en majuscules
suivant les règles de grammaires locales (ex : les rosbeefs transforment toutes les premières lettres de
chaque mot d’une phrase en majuscules et les frenchies seulement la première lettre de chaque phrase.
• LC_MONETARY : pour les conventions monétaires ;
Quelques localisations :
Primary
language
Sublanguage
Language string
Chinese Chinese ”chinese”
Chinese Chinese (simplified) ”chinese-simplified” or ”chs”
Chinese Chinese (traditional) ”chinese-traditional” or ”cht”
Czech Czech ”csy” or ”czech”
Danish Danish ”dan” or ”danish”
Dutch Dutch (default) ”dutch” or ”nld”
14
Dutch Dutch (Belgian) ”belgian”, ”dutch-belgian”, or ”nlb”
English English (default) ”english”
English English (Australian) ”australian”, ”ena”, or ”english-aus”
English English (Canadian) ”canadian”, ”enc”, or ”english-can”
English English (New Zealand) ”english-nz” or ”enz”
English English (United Kingdom) ”eng”, ”english-uk”, or ”uk”
English English (United States) ”american”, ”american english”, ”american-english”, ”english-american”, ”english-
us”, ”english-usa”, ”enu”, ”us”, or ”usa”
Finnish Finnish ”fin” or ”finnish”
French French (default) ”fra” or ”french”
French French (Belgian) ”frb” or ”french-belgian”
French French (Canadian) ”frc” or ”french-canadian”
French French (Swiss) ”french-swiss” or ”frs”
German German (default) ”deu” or ”german”
German German (Austrian) ”dea” or ”german-austrian”
German German (Swiss) ”des”, ”german-swiss”, or ”swiss”
Greek Greek ”ell” or ”greek”
Hungarian Hungarian ”hun” or ”hungarian”
Icelandic Icelandic ”icelandic” or ”isl”
Italian Italian (default) ”ita” or ”italian”
Italian Italian (Swiss) ”italian-swiss” or ”its”
Japanese Japanese ”japanese” or ”jpn”
Korean Korean ”kor” or ”korean”
Norwegian Norwegian (default) ”norwegian”
Norwegian Norwegian (Bokmal) ”nor” or ”norwegian-bokmal”
Norwegian Norwegian (Nynorsk) ”non” or ”norwegian-nynorsk”
Polish Polish ”plk” or ”polish”
Portuguese Portuguese (default) ”portuguese” or ”ptg”
Portuguese Portuguese (Brazilian) ”portuguese-brazil” or ”ptb”
Russian Russian (default) ”rus” or ”russian”
Slovak Slovak ”sky” or ”slovak”
Spanish Spanish (default) ”esp” or ”spanish”
Spanish Spanish (Mexican) ”esm” or ”spanish-mexican”
Spanish Spanish (Modern) ”esn” or ”spanish-modern”
Swedish Swedish ”sve” or ”swedish”
Turkish Turkish ”trk” or ”turkish”
Jeux de caractères :
Une foultitude de jeux de caractères existent et il fait éviter de s’y perdre. Initialement on a le US-ASCII qui
ne comportaient que les caractères anglosaxons, le jeu ISO-8859-15 comportent tous les symboles français dont
le €. Le jeu idéal est le jeu UTF-8 car il comporte tous les jeux de caractères de toutes les langues connues...
En fait pour bien comprendre le systèmes des jeux de caractères dans le cadre du développement d’un site
web avec php, il faut comprendre qu’il y a trois choses essentielles à bien considérer séparément :
• le jeu de caractères : c’est un ensemble de caractères qu’on peut trouver dans un ou plusieurs langages
humains suivant le jeu de caractères considérés. par exemple : le jeu de caractères US qui comporte
les 26 lettres de l’alphabet, les 10 chiffres et quelques autres caractères comme ’ ” (, ) etc. Le jeu le plus
petit est justement ce dernier jeu de caractères et le plus grand est l’unicode qui contient pratiquement
tous les caractères connus des langues humaines ;
15
• L’encodage : c’est la traduction informatique d’un jeu de caractères. A la base, les premiers encodages
de jeux de caractères étaient tels que chaque caractère était codé sur un octet. Cependant pour les jeux
de caractères les plus larges, les 8 bits d’un octet étaient insuffisants et donc certains encodages utilisent
jusqu’à 4 octets au lieu de 1. On peut notamment citer l’iSO-8859 qui est l’encodage du jeu ASCII-US,
l’encodage ISO-8859-15 qui est une version étendue du précédent et englobe aussi les caractères latins
comme les caractères accentués et les lettres spéciales type ”nié” espganol, et l’UTF-8 dont la taille encodé
de chaque caractère varie de 1 à 4 octets : UTF-8 est ainsi un encodage de l’Unicode et qui a pour
particularité d’englober notamment l’encodage ISO-8859-15 qui est l’encodage des caractères occidentaux
de sorte qu’un caractère occidental est codé sur un octet en UTF-8. Cette taille variable du caractère
encodé a pour mérite de ne pas faire trop augmenter la taille des caractères encodé quand pour la plupart,
ils correspondent aux caractères occidentaux.
La liste des encodages gérés par php au sein du module mbstring est la suivante :
– pass
– auto
– wchar
– byte2be
– byte2le
– byte4be
– byte4le
– BASE64
– UUENCODE
– HTML-ENTITIES
– Quoted-Printable
– 7bit
– 8bit
– UCS-4
– UCS-4BE
– UCS-4LE
– UCS-2
– UCS-2BE
– UCS-2LE
– UTF-32
– UTF-32BE
– UTF-32LE
– UTF-16
– UTF-16BE
– UTF-16LE
– UTF-8
– UTF-7
– UTF7-IMAP
16
– ASCII
– EUC-JP
– SJIS : encodage japonais ;
– eucJP-win
– SJIS-win
– CP51932
– JIS
– ISO-2022-JP
– ISO-2022-JP-MS
– Windows-1252 (ou CP1252) : encodage des caractères sous windows ;
– Windows-1254
– Windows-1256 (ou CP1256) : encodage arabe (pas dans php);
– Windows-1257 (ou CP1257) ; encodage lituanien (pas dans php);
– ISO-8859-1 : Encodage français avant l’euro ;
– ISO-8859-2 : vieil encodage roumain
– ISO-8859-3
– ISO-8859-4
– ISO-8859-5
– ISO-8859-6
– ISO-8859-7 :Encodage grec avant l’euro ;
– ISO-8859-8
– ISO-8859-9
– ISO-8859-10
– ISO-8859-13
– ISO-8859-14
– ISO-8859-15 : Encodage français après l’euro ;
– ISO-8859-16 : nouvel Encodage roumain ;
– EUC-CN
– CP936
– HZ
– EUC-TW
– BIG-5
– EUC-KR
– UHC
– ISO-2022-KR
– Windows-1251
– CP866
– KOI8-R : Encodage russe ;
17
– KOI8-U : encodage ukrainien et bulgare ;
– ArmSCII-8
– CP850 : encodage des chaines de caractères DOS ;
• l’encodage du fichier et des flux : Quand un flux est récupéré, il est encodé suivant un encodage donné et
utilisé au sein d’un fichier qui est lui encodé potentiellement autrement. Pour éviter les problèmes, il faut
alors :
Pour info, quelques pages wikipedia sur le sujet sont bien faites et propose des liens complets sur le sujet de
l’encodage des jeux de caractères :
http://fr.wikipedia.org/wiki/Codage_de_caract%C3%A8res
http://edutechwiki.unige.ch/fr/Encodage_de_caract%C3%A8res
Mon fichier.htm
devient:
Mon%20fichier.htm
En principe il faudrait aussi appliquer ce principe pour tous les caractères accentués, mais le problème se
corse:
http://edutechwiki.unige.ch/fr/Encodage_de_caractères
devient en ISO hexadecimal (et peut marcher, mais il ne faut pas parier):
http://edutechwiki.unige.ch/fr/Encodage_de_caract%E8res
http://edutechwiki.unige.ch/fr/Encodage_de_caract%C3%A8res
Maintenant pour revenir aux simples ”blancs”: certains logiciels ont de la peine à traduire un caractère blanc
dans un lien vers une solution correcte (%20). Pour les autres caractères: si vos noms de fichiers dans le texte
sont en UTF-8 et sur le serveur en ISO-latin voir Windows cela peut aussi poser problème (à développer).
Et c’est pour cela qu’on déconseille normalement d’utiliser des blancs pour des fichiers et leurs liens.
18
L’encodage d’un fichier peut-être choisie en l’ouvrant avec le bloc-notes puis en choisissant Enregistrer sous
puis en cliquant sur le menu déroulant ”Encodage” !!
mb_convert_variables($JeuCibleEnChaine,
$JeuInitialEnChaine,
$texteAConvertir_1,
$texteAConvertir_2,...)
ATTENTION cette merde de fonction fait DEUX CONVERSIONS. D’abord de l’encodage courant (celui
donné par un appel à mb_internal_coding) vers $JeuInitialEnChaine, puis de $JeuInitialEnChaine vers $Jeu-
CibleEnChaine. Bizarre...
Pour détecter l’encodage courant, il faut utiliser la fonction mb_internal_coding() qui renvoie en chaine
l’encodage utilisé.
Pour changer l’encodage courant, cette même fonction est utilisée en passant en argument le nouveau en-
codage sous forme de chaine type ”UTF-8” ou ”ISO-8859-1” (encodage français). Dans ce cas, mb_internal_coding
renvoie TRUE ou FALSE au lieu de l’encodage courant pour dire si le changement a marché ou pas.
La fonction utf8_encode permet d’encoder en utf-8 une chaine initialement encodée avec le jeu ISO-8859-1
Les Fonctions de manipulation de chaine courante (quand mb_ est spécifié, c’est que la fonction
existe dans le module mbstring) :
• (mb_) strstr(chaine1,chaine2) : renvoie le bout de chaine1 à partir duquel chaine2 commence
19
• (mb_) stristr : idem mais sans respecter la casse ;
• (mb_) substr(chaine, pos, longueur) : comme mid en Visual Basic sauf que l’indiçage commence à
0 et non à 1 ;
• print_r($Tableau) : Pour afficher la structure d’un tableau ou d’une variable si c’est une variable qui
est passé en argument ;
20
• var_dump($Tableau) : pareil mais ajoute des infos sur les types des éléments du tableau ou de la
variable ;
• count($Tableau, optional COUNT_RECURSIVE) : donne le nb d’éléments d’un tableau. Pour
un tableau de tableaux, donne le nb de tableaux dans le tableau (logique, non ?) ; Renvoie un entier.
ATTENTION, si l’argument n’est pas un tableau et ne vaut pas NULL, la fonction renvoie 1. L’ajout de
l’option COUNT_RECURSIVE renvoie le nombre d’éléments d’un tableau de tableau. L’ennui, c’est
que le nombre renvoyé est le nombre d’éléments dans le tableau plus le nombre d’élements dans chaque
élément si celui-ci est à chaque fois un tableau. Ex : Pour un tableau de deux tableaux de trois éléments,
count renvoie 8 et non 6 ;
• in_array($VarCherchée,$tableau,optional BOOL) : Permet de savoir si la valeur de $VarCherchée
est est un des éléments du tableau (si $VarCherchée est contenu dans un élément comme une sous-chaine
dans une chaine plus grande par exemple, ça ne marche pas et la fonction renvoie FALSE. En option,
on peut aussi imposer que la variable $VarCherchée soit du même type que l’élément trouvé (BOOL =
TRUE, FALSE par défaut). Notons que la variable cherchée peut être aussi un tableau ou un objet (!!),
Renvoie un BOOL ;
• sort($TableauATrier, optional OPTION) : trie en ordre croissant les éléments d’un tableau en
prenant en argument un tableau par référence. On peut forcer le type de tri en comparaison numérique
en mettant SORT_NUMERIC (attention le classement des valeurs non-numériques est bizarre et la
doc phpedit considère que dans ce cas le résultat est imprévisible), ou en comparaison textuelle avec
SORT_STRING (ou avec SORT_LOCALE_STRING pour utiliser le jeu . Par défaut, on a SORT_REGULAR,
qui implique que les chiffres sont considérés comme précédant les lettres dans l’ordre des caractères. IM-
PORTANT : le tri se fait en réallouant les clefs dans l’ordre obtenu.
• rsort() : pareil que la précédente mais dans l’ordre décroissant.
• asort() : pareil que sort mais la clef de chaque élément reste la même.
• arsort() : pareil que rsort mais la clef de chaque élément reste la même.
• ksort() : pareil que asort mais trie en trouvant l’ordre croissant des clefs des éléments.
• krsort() : pareil que ksort mais en sens inverse ;
• ATTENTION : Le tri des chaines comportant des lettres et des nombres fait que ces derniers sont triés
chiffre par chiffre de sorte que ”Toto12” sera ainsi compris entre ”Toto1” et ”Toto2”. La fonction natsort()
permet de s’assurer que le tri est fait dans l’ordre des nombres et dans ce cas cette fonction trie en fonction
de la casse. La fonction natcasesort() trie elle sans en tenir compte. Il n’y a pas de fonctions inverses
équivalentes ;
• usort($tableauAtrier, $StringNomFonction) : C’est le bon vieux sort du C++ !! Le deuxième
argument est une chaine de caractère qui doit correspondre au nom de la fonction de comparaison qui
détermine le critère de comparaison.
21
• array_multisort($tableau1,{Optional Liste de $CRITERE},$tableau2,{Optional Liste de
$CRITERE}) : Le couteau suisse des fonctions de tri. En fait, le tri d’un tableau à plusieurs colonnes.
Si aucune liste de critères n’est spécifié, le tableau 2 est trié en utilisant comme clef de tri les valeurs
du tableau 1. En cas d’égalité, c’est les valeurs du tableau suivant qui déterminent l’ordre. Si les listes
de critères sont utilisées, chaque tableau est trié suivant la liste qui suit. Les critères sont SORT_ASC,
SORT_DESC, SORT_REGULAR, SORT_STRING, et SORT_NUMERIC... En fait, chaque tableau
passé en argument peut être considéré comme une des colonnes d’un seul tableau les concaténant tous.
• extract() : uniquement pour un tableau associatif. Cela crée en mémoires autant de variables que le
nombre d’éléments du tableau et chaque variable est crée avec pour nom la clef de l’élément correspondant.
FONCTION SURPUISSANTE SI ON Y PENSE !!
• implode($Separateur, $tableau) : transforme un tableau en une chaine des valeurs de chaque élément
du tableau séparé les uns des autres de la chaine de separation ;
• explode($Separateur, $tableau) : fait l’inverse.
• array_slice($tab, $clefIni, $NbMax) : renvoie un sous-tableau du tableau de $tab. Le premier élément
du nouveau tableau est de clef $clefIni et le tableau contient au maximum les NbMax-1 éléments suivants
du tableau $tab ;
• array_splice($tab, $Offset,optional $lenght, optional $tabReplacement) : fonction tordue dont
les subtilités me semblent pas d’une grande utilité mais bon... Quand $Offset est >0, la fonction supprime
du tableau $tab tous les éléments à partir de celui de position offset et renvoie un tableau qui correspond
au sous-tableau supprimé. Quand offset est <0, c’est pareil sauf que l’index est compté depuis la fin avec
le dernier élément du tableau valant -1. Quand lenght (=n) est spécifié,et qu’il est >0, les n premiers
éléments à partir de l’offset compris sont supprimés, quand lenght(=n) est négatif, les n derniers éléments
du tableau à partir de l’offset sont préservés. Enfin quand un tabReplacement est spécifié, le sous-tableau
supprimé est aussi remplacé par le tableau de replacement même si les deux n’ont pas la même taille.
Dernier truc, si lenght est nul et qu’un tableau de remplacement est spécifié, ce dernier est simplement
inséré dans le tableau d’input initial à la position d’offset ;
• array_keys($tab) : renvoie un tableau contenant les clefs du tableau $tab ;
• array_values($tab) : renvoie un tableau contenant les valeurs (et non les clefs) du tableau $tab ; CETTE
FONCTION PERMET DE CONVERTIR UN TABLEAU ASSOCIATIF EN TABLEAU CLASSIQUE ;
• array_flip($tab) : renvoie un tableau ou sont inversés clef et valeur de chaque élément du tableau ;
• array_merge($tab1, $tab2,...,$tabn,...) : renvoi un tableau qui est la fusion des tableaux en entrée.
Le $tab1 est a ses éléments en premier, puis le $tab2, etc. Si ce sont des tableaux associatifs avec des clefs
communes, le tableau fusionné ne comporte qu’une seule telle clef et c’est la valeur du dernier tableau
ayant cette clef qui est gardé...
22
est insuffisant (càd si le tableau initial a 7 éléments et qu’on demande un split en tableau de taille 3, il y
aura deux tableaux de taille 3 et un tableau de taille 1 ;
FONCTIONS DE GESTION D’UN TABLEAU COMME UNE LISTE :
• array_push($tab, $elem) : ajoute $Elem en dernier élément du tableau $tab ; Attention le pointeur
sous-jacent du tableau passe au premier élément du tableau (notamment faire gaffe quand cette fonction
est utilisé dans une boucle foreach qui se base sur le déplacement du pointeur explicite du tableau) ;
• array_pop($tab) : renvoie le dernier élément du tableau $tab tout en le supprimant ; Attention le
pointeur sous-jacent du tableau passe au premier élément du tableau (notamment faire gaffe quand cette
fonction est utilisé dans une boucle foreach qui se base sur le déplacement du pointeur explicite du tableau)
;
• array_unshift() ajoute un élément en début de tableau et array_shift() élémine un élément en début
de tableau comme le font array_pop et push en fin de tableau...
Deplacement du pointeur interne d’un tableau : Les fonctions reset(), end(), prev() et next() perme-
ttent de déplacer manuellement le pointeur interne du tableau et renvoie ensuite la valeur de l’élément pointé
du tableau. Ces quatres fonctions prennent toutes un tableau en argument. reset() met le pointeur sur le
premier élément, end() le met sur le dernier élément du tableau, prev et next se passent de commentaires... Si
le pointeur est déplacé hors des limites, la fonction prev ou next renvoie FALSE.
NOTE IMPORTANTE : Les variables dites EGPCS sont les variables globales accessibles dans tout php
(Environnement, GET, POST, Cookie, Session). Voir plus loin.
• highlight_string($chaine) : permet d’afficher une chaine de code php de manière colorée et avec un
affichage du code HTML équivalent pour produire le code php tel que traité en interne par php ;
• highlight_file($file) : pareil mais avec le contenu d’un fichier
23
7.2 Fonctions mathématiques :
• max(a,b, c,...) : trivial. Prend aussi des tableaux en arguments, la fonction renvoie alors un tableau de
max élément à élément. Si un seul nombre est à virgule flottante, ils sont tous considérés comme tels ;
• min : pareil mais c’est le minimum ;
• round($a, Optional $Prec) : arrondi à l’entier le plus proche sachant que l’entier supérieur est privilégié en
cas d’équidistance...Prec signifie à quel chiffre après la virgule on arrondit. Si Prec est négatif, on arrondit
à la puissance de dix correspondante ;
• ceil($a) : arrondit $a à l’entier supérieur ;
• floor($a) : arrondit $a à l’entier inférieur ;
• mt_rand($min, $max) : le bon vieux mersenne twister qui génère un entier entre $min et $max ;
24
• mktime(heure,minute, seconde,mois,jour, annee) : renvoie un timestamp en fonction des arguments
passés (un septième argument permettait de prendre en compte l’heure d’été et d’hiver mais cette version
de la fonction est deprecated ;
• strftime(format,TimestampUNIX) : fait pareil que strtotime mais prend en compte les paramètres
de localisaton (fixé avec setlocale() pour formater les dates avec le vocabulaire de la langue en locale.
ATTENTION la chaine de format utilisé par strftime diffère des autres fonctions car chaque format DOIT
être précédé du symbole %.
• checkdate(mois, jour, annee) : renvoie TRUE si le triplet jour/mois/annee est cohérent et FALSE
sinon ;
• checkdnsrr($Host,$HostType) : permet de vérifier l’existence d’une adresse IP, d’un nom de domaine
internet, etc... ATTENTION : cette fonction ne marche pas sur Windows mais il est possible de créer sa
propre fonction :
function MyCheckDNSrr($hostname)
{
if (empty($hostname)===FALSE)
{
exec(”nslookup $hostname”,$result);
foreach($result as $line)
{
echo ”<br> $line”;
if (preg_match(” ’$hostname” ’,$line))
{
return true;
}
};
return false;
}
}
A propos de la commande nslookup, elle permet d’obtenir des information sur les noms de domaine existants
:
Comment utiliser la commande NSLookup
25
Vous êtes ici : Accueil > Pas à pas > Comment utiliser la commande NSLookup
Publié le 30/06/2008 vers 13h par : Saïda AZIRI
NSLookup (Name Server Lookup) est une commande qui permet de tester la résolution des noms d’hôtes en
adresses IP et inversement. Elle permet un rapide diagnostique des problèmes de résolution DNS.
Lorsque vous tapez nslookup dans une invite de commande, le nom d’hôte et l’adresse IP du serveur DNS
sont affichées par défaut .
Lorsque l’on saisie un nom d’hôte ou un FQDN, une adresse IP est renvoyée.
Dans cet exemple, nslookup fournit le nom et les adresses IP des serveurs de google.fr.
Par défaut la commande nslookup interroge le serveur DNS sur les enregistrements de type A (mappage
entre un nom d’hôte et une adresse IPv4). Il est possible d’interroger le serveur DNS sur divers enregistrement
en utilisant la commande Set type = xx (remplacer xx par l’un des types suivants : MX, NS, A, SOA, CNAME,
hinfo, any).
Une fois qu’on change le type de requête, les enregistrements retournés restent sur le type spécifié. Pour
revenir sur les enregistrements de type A, tapez : Set-type = A ou fermer la fenêtre nslookup.
1.1 Set-type = MX
Recueillir des informations sur les enregistrements MX (serveurs de messagerie) :
> set type=MX
> gmail.com
26
* Les deux premières lignes indique le nom et l’adresse IP du serveur DNS local.
* Les cinq lignes suivantes montrent que le domaine gmail.com à 5 enregistrements MX. Les enregistrements
MX possèdent une priorité, également appelé coût. Les mails sont envoyés au serveur ayant le coût le plus faible
(5). S’il n’est pas joignable, les mails sont envoyés aux serveurs avec le coût juste au dessus (10).De même s’ils
ne sont pas joignables, les serveurs avec un coût de 50 seront contactés.
* Les dernières lignes montrent les adresses IP des serveurs MX distants. ( On remarque les mêmes serveurs
dans les 5 lignes précédentes).
1.2 Set type =NS
L’enregistrement de ressource de type NS (Name Server) identifie les serveurs DNS de la zone DNS. Permet
d’identifier le Serveur de noms autoritaire pour un domaine ou l’enregistrement NS du domaine.
> Set type = NS
> microsoft.com
27
* Primary Name Server : Nom du serveur qui héberge actuellement la zone DNS principale et qui fait autorité
sur la zone DNS. Le nom doit être un FQDN.
* Responsible mail addr : indique l’adresse email de la personne responsable de la zone. Attention, l’adresse
doit être de type user.exemple.lanet non user@exemple.lan.
* Serial : Il s’agit d’un numéro de série en 32 bit qui s’incrémente à chaque fois qu’une modification intervient
sur le serveur. Ce numéro est de type : YYYYMMDDnn (Année, mois, jour, version). (Changement intervenu le
24 Juin 2008 en version 1). Si il y d’autre modification dans la même journée, le numéro de version s’incrémente.
* Refresh : Le nombre de seconde depuis que le second serveur à reçu une copie de la zone. Entre parenthèse
est indiqué le temps avant la prochaine vérification pour obtenir une nouvelle copie.
* Retry : Nombre de seconde que le premier serveur doit attendre dans le cas ou un refresh à échoué, avant
d’effectuer un nouveau refresh avec un second serveur DNS.
* Expire : Nombre de seconde avant qu’un serveur secondaire ne considère ses informations de zone comme
n’étant plus autoritative. Si la copie que le serveur détient est plus vieille que 28 jours, elle est considérée comme
invalide.
* Default TTL (Time To Live) = Nombre définit en seconde, qu’un enregistrement de zone est valide dans
le cache.
1.4 Set type =PTR
> Set type =PTR
> Adresse IP
Les enregistrements PTR(PoinTeRs, pointeurs ) sont des requêtes inversés vers des noms d’hôtes.
1.5 Set type =A
> set type=A
> nom d’hote
Les enregistrements A(Adresses lookups) constituent le type de requêtes par défaut lorsqu’on lance nslookup.
Ce sont requêtes directes, nom vers adresse IP.
1.6 Set type =CNAME
> set type=CNAME
> nom d’hôte
DNS permet d’attribuer des alias à une machine. Les enregistrements CNAME (Canonical NAME) sont
utiles pour renvoyer le nom principal d’une machine.
1.7 Set type =AAAA
Il est également possible d’obtenir des adresses IPv6 :
> set type=AAAA ou bien set type=any
> www.kame.net/
28
1.8 Set type =ANY
ANY est utilisé pour retrouver tous les enregistrements.
29
7.6 Fonctions de chiffrement
(a) Le stockage de mot de passe : seuls le hachage d’un mot de passe est stocké et non le mot de passe
lui-même ;
(b) La création d’identifiant :
(c) la vérification d’intégrité d’un fichier téléchargé
• crc32($FileouString) : transforme l’input en entier signé. Attention pour échanger avec un autre prgm
que php ou pour l’afficher, il faut convertir cet entier signé en non-signé (du coup, la valeur non-signé peut
aller deux fois plus, et il ne suffit pas de multiplier par -1 la valeur de sortie). Algo trop facile à casser.
Utile uniquement pour le contrôle de fichier. ATTENTION dans le cas d’un fichier, pour hacher le fichier
et non son nom, il faut écrire crc32(file_get_contents($NomDuFile));
• md5($FileouString,optional $Raw ) : pareil mais avec un algo plus complexe et utilisable pour le
hachage de mot de passe. affiche une chaine héxadécimale en sortie de 32 caractères. Si l’option $Raw est
mis à TRUE, la fonction affiche l’équivalent en binaire !! (c’est donc plus long...) ;
• md5_file($CheminFile) : fait l’équivalent de md5(file_get_contents($NomDuFile))
• sha1() et sha1_file() : strictement pareil que md5() et md5_file();
• crypt($FileouString,$Alea) : algo de hachage qui utilise en sus du string à hacher un nombre aléatoire
pour rendre plus difficile la découverte du mot de passe. ATTENTION : l’algo interne est initialement
l’algo DES qui est pourri. Suivant le système, on peut forcer le recours aux algos md5 ou blowfish, en
utilisant respectivement une chaine $alea commençant par $1$ et comportant 12 caractères ou $2$ et
comportant 16 caractères ($x$ comptent les 12 ou 16 caractères) ; Si un password est bon, le code php
suivant :
crypt($password, $Alea) == $Alea renvoie TRUE
30
7.7 Fonctions d’exécution de code
UN TRUC QUI TUE : Il est possible de générer du code php dynamiquement au sein de php !!!
La fonction php qui permet cela est la fonction eval()
• eval($CodeChaine) : Cette fonction exécute le bout de code présent dans la chaine $CodeChaine jusqu’à
la fin de la chaine $CodeChaine ou jusqu’au premier return. ATTENTION : Tous les caractères spéciaux
PHP doivent être échappés dans la chaine sous d’échec de la fonction eval ; BREF UNE TUERIE !!
Un exemple de gestion d’entrée/sortie de mot de passe est donné au chapitre 7 aux pages 172 et 173.
Enfin !! Ce chapitre traite de la gestion des entrées-sorties de donnés au travers de la page web !
Note à propos du paramètre register_globals dans php.ini : Cette option mis à on établit un référencement
entre certaines variables globales de PHP et les données de la page web. Idéal pour les flemmards mais dangereux
car l’utilisateur peut alors venir taper plus facilement le coeur de php et donc du serveur d’où un sérieux souci
de sécurité.
Le coeur des formulaires web est lié au HTML et donc on va se taper un petit bout d’apprentissage HTML :
8.1 HTML
8.1.1 Les caractères spéciaux d’HTML
Les principaux caractères sont ’<’, ’>’ et ’&’. Les deux premiers car ce sont les balises ouvrantes et fermantes
et le dernier car c’est le caractère spécial qui aide à définir une entité HTML (Les entités HTML permettent
l’affichage de caractères spéciaux).
Pour échapper cette caractère et permettre l’affichage tel quel ces caractères, il faut avoir recours à la
fonction htmlentities(). Enfin pour échapper les guillemets et apostrophes, il faut utiliser htmlentities($Chaine
,ENT_QUOTES)
L’USAGE de HTMLEntities vaut surtout quand on cherche à afficher une chaine dans un attribut HTML.
ATTENTION : DANS UNE BONNE PART DES EXEMPLES ET DES EXERCICES, l’appel à htmlentities
a volontairement été squizzé pour alléger la lecture.
ENFIN pour l’affichage des entités HTML &xxx, si la suite de caractères &xxx ne correspond à rien, les
caractères &xxx seront affichés et non le caractère spécial qui correspondrait à &xxx
31
8.1.2 Les Formulaires HTML
Un formulaire HTML est créer à partir des balises <form> et </form>. Toutes les instructions délimitées par
ces deux balises constituent le bloc de définition du formulaire
La balise <form> intègre plusieurs arguments potentiels :
<form action =”fichier.php” method =”GET ou POST” enctype = ”MethodeEncodagePourEnvoiDeFichier>
• action : défini le fichier ouvert une fois le bouton d’envoi du formulaire appuyé (attention ce bouton ne
figure pas dans l’instruction form mais doit apparaitre kekpart dans le bloc ;
• method : GET signifie que les données saisies dans le formulaire sont envoyés par URL tandis que POST
envoie les données dans des supervariables qui sont ensuite tapables par php ;
• enctype : quand on souhaite un fichier via un formulaire, il est nécessaire de renseigner la méthode
d’encodage du fichier envoyé en l’occurrence, souvent ’multipart/form-data’.
• des zones de texte : ça marche avec les balises <textarea> </textarea>. Les paramètres associés
à la première balise sont :
• des cases à cocher : la balise correspondante est <input type =’checkbox’> et fait apparaître une
case à cocher, l’attriibut value permet de cocher la case par défaut càd en mettant l’attribut checked
=’checked’. IMPORTANT : si on souhaite lier plusieurs boutons à cocher, on doit donner comme valeur
à l’attribut name un nom de tableau càd un nom suivi de [] et ce nom doit être le même pour toutes les
cases qu’on souhaite lier.
32
• des boutons radio (groupe de boutons à cocher et à a choix unique exclusif) : cela fonctionne comme les
cases à cocher sauf que tous les boutons partageant un même nom sont à choix exclusif càd un seul d’entre
eux peut être cocher ; Une ligne peut être sélectionné par défaut : il faut ajouter l’attribut selected sans
lui passer une quelconque valeur (càd pas de =’kekchose’).
• Des boutons de validation avec <input type =’submit’ value =’texteDuBouton’ name =
’NomPHPDuBouton’ > ;
• des listes déroulantes : La balise est alors <select> puis </select>. Chaque ligne sélectionnable
de la listed déroulante s’écrit encadré des balises <option name= ’...’ value =’X’> textdeLaligne
</option>. Notons que ce que récupére le serveur est la valeur de l’attribut value et non pas TextDe-
LaLigne. Une ligne peut être sélectionné par défaut : il faut ajouter l’attribut selected sans lui passer
une quelconque valeur (càd pas de =’kekchose’. Si l’attribut size est de valeur supérieure à ’1’, la liste
n’est plus déroulante mais une liste simple avec une barre de défilement vertical si le nb de possibilités
excède la valeur de l’attribut size. Si par aileurs l’attribut multiple et lui aussi sans valeur nécessaire -
est ajouté à la balise <select >, il est possible de choisir plusieurs éléments de la liste.
ATTENTION : Tous les choix par défauts ne sont affichés qu’au premier affichage de la page, un simple
refresh ne remet pas les valeurs par défauts.
ATTENTION : tout appel à un affichage au sein d’un bloc balise <select> </select> ne produit aucun
affichage !
• des champs cachés : cela sert à stocker des infos cachés à l’affichage. Cette information est cepen-
dant visible en éditant le code HTML. La balise est <input type =’hidden’ name =’xxx’ value
=’chainecachée’>. cela sert surtout à sauvegarder l’information issue d’une ou de plusieurs pages précé-
dentes pour pouvoir restituer l’affichage de ces pages si retour en arrière il y a...
• des champs de mot de passe : la balise est <input type =’password’ name =’mot_de_passe’
size =8 value =’valeurpardefautdumotdepasse’> ;
• des images cliquables : avec la balise <input type =’image’ name =’imagePetra’ src = ’Chem-
inVersImage’ alt =’texteAfficherEnCasPbAvecImage’ >. Quand l’image est cliqué, le navigateur
renvoie les coordonnées de la position du clic avec le formulaire. Note : les attributs height et width de la
balise permettent de redimensionner l’image.
• des interfaces d’envoi de fichier : ATTENTION : pour l’utilisation de cette interface dans un formu-
laire, il est nécessaire d’ajouter un attribut enctype de valeur ’multipart/form-data’ à la balise <form
...> est alors <input type =’file’ ... >
ATTENTION quand une balise de bouton ne se trouve pas dans une balise de formulaire, cliquer dessus ne sert
à rien car le script php associé est définie dans la balise de formulaire.
8.2 Principes d’interaction entre les formulaires HTML et leurs scripts de gestion
correspondants :
Chaque formulaire intègre un attribut action qui spécifie quelle action est éxécuté dès lors qu’une action de
validation est lancée. Ce lancement intervient dès lors qu’une balise de bouton appartenant au bloc de balises
du formulaire est cliqué. ça peut être aussi bien un bouton qu’un image cliquable. L’action déclenché peut-être
un lien vers une page html, une image, une adresse mail (ce qui en fait provoque l’ouverture d’un mail en
écriture à destination de l’adresse spécifiée).
33
Quand l’action est un script php, le script php correspondant est le script de gestion du formulaire.
Comment récupérer les valeurs renseignés dans les formulaires dans le script de gestion.
Simple, dans php, il existe des tableaux de variables dites superglobales qui se comportent comme des
variables php globales dans le script de gestion désigné par l’attribut action du formulaire.
Les tableaux recensant les variables contenant les valeurs renseignés dans un formulaire sont :
• $_GET[] : contient toutes les données envoyées par l’URL ;
• $_POST[] : contient les données envoyées par un formulaire quand l’attribut method vaut ’POST’ ;
• $_FILE[] : contient les informations sur les fichiers envoyés par l’utilisateur ;
• $_REQUEST : qui est une fusion des tableaux $_GET, $_POST et de $_COOKIE (voir plus loin pour
ce dernier) ;
Chaque élément d’un tableau correspond à un des objets de saisie du formulaire à partir duquel les données au
script désigné par l’attribut action du formulaire.
La clef de chaque élément correspond à l’attribut name de l’objet de saisie HTML, et la valeur associé
correspond à l’attribut value.
Il faut savoir que pour :
• une liste déroulante ou pas à choix unique, l’élément dans $_REQUEST est unique et renvoie la value de
la balise sélectionnée en choix ;
• idem pour un groupe de bouton radio ;
• une liste avec l’attribut multiple renvoi comme élément dans $_REQUEST un tableau comportant autant
d’éléments que le nombre sélectionné.
• une image cliquée renvoie un tableau à deux dimensions avec l’abcisse d’abord puis l’ordonnée en nombre
de pixels, ces deux données ne pouvant donc respectivement pas excéder la taille spécifiée par les attributs
width et height ;
• Pour savoir, si une variable est présente dans les tableaux $_GET,$_POST etc. Utiliser la fonction
isset($NomDeLaVariableCherchee) est la meilleure solution ;
A propos des chaines récupérés via un formulaire pour ensuite être affiché à nouveau dans un page HTML,
notamment par exemple dans une zone de texte. Un retour à la ligne saisie dans une zone de texte est codé
comme ’\n’ mais réécrit dans une page html, le saut à la ligne est ignoré car il faut à la place mettre une
balise <br>. Pour ça, après récupération d’une chaine dans un tableau de superglobales, si on souhaite afficher
derrière cette chaine et seulement dans ce cas, il faut convertir les caractères classiques ’\n’ de sauts de ligne
en balise HTML correspondante. Pour cela, l’affichage de la chaine PHP peut être fait en utilisant la fonction
nl2br($ChaineAAfficher). On écrira alors :
echo ”<br>”.nl2br($Chaine);
au lieu de
echo ”<br> $Chaine”;
Truc : si la chaine rentrée dans le formulaire intègre les balises <br> au lieu de retour à la ligne ’\n’ classiques,
l’affichage initiale sera avec les <br> mais l’affichage finale sera avec retour à la ligne apparent si l’information
initiale n’est pas filtré des balises HTML. ATTENTION : Il vaut mieux filtrer (càd ) les balises contenus dans
les chaines entrées dans les formulaires.
34
8.3 Les fonctions de filtrage des données à la récupération dans les tableaux des
variables superglobales
Le hic avec les tableaux de var superglobales, c’est que si on connait certes les clefs et donc les noms des
variables, on peut avoir des surprises sur le type et le contenu de la valeur de chaque superglobales si on ne
filtre pas.
Le principe est donc de ne pas récupérer les variables bourrinement en utilisant une instruction du type :
$VarPhp = $_REQUEST[’NomDeLaClefSouhaitee’]
car on s’expose à des risques d’attaques par injection, à des incohérences de types et ou autre problème.
La solution est de :
• systématiquement avoir une idée minimale du type de la variable attendue dans le tableau superglobales
• d’utiliser une fonction de filtrage qui assure que le type de la donnée est bien celle attendue ;
• paramétrer la fonction de filtrage correctement pour s’assurer que la chaine contenu dans la valeur associée
à la clef associée au tableau ne contient pas de caractères incorrectes.
Pour cela, le module d’extension Filter Php est d’une grande utilité :
Le filtrage peut être fait à deux niveaux :
• soit au niveau des contenus des variables php qui ont servi à lire dans les superglobales ;
• soit directement au niveau des superglobales.
• filter_input($CONSTANTESOURCE,$ClefDeLaValeurAFiltrer,$FILTRE, $OPTIONDEFILTRAGE)
: Filtre la valeur de la superglobale de clef $ClefDeLaValeurAFiltrer se trouvant dans le tableau super-
globale désigné par $CONSTANTESOURCE. ATTENTION : cette fonction ne va fonctionner que dans
le cas où la variable superglobale est unidimensionnelle et n’est donc pas un TABLEAU associatif (l’autre
35
possibilité). Dans le cas contraire, elle renverra FALSE. Il vaut mieux s’assurer à l’avance si la clef recher-
chée correspond à un tableau associatif. La nature de $FILTRE est variable : elle peut correspondre à
une de constantes entières ci-dessous. Elle peut correspondre à une combinaison de constantes entières, ce
qui revient à cumuler les filtres. Dans ce cas, $FILTRE vaut plusieurs constantes entières séparés de | de
sorte qu’on peut avoir :
FILTER_SANITIZE_STRIPPED|FILTER_SANITIZE_NUMBER_FLOAT
Enfin si on souhaite avoir un filtrage intégrant des options de filtrage plus complexe, $FILTRE peut être
défini comme un tableau associatif (voir la fonction filter_input_array pour la spécification du tableau
associatif). Les valeurs possibles pour $FILTRE sont de trois types :
36
∗ FILTER_SANITIZE_STRIPPED : retire les balises HTML ; flags possibles :
· * FILTER_FLAG_NO_ENCODE_QUOTES - This flag does not encode quotes
· * FILTER_FLAG_STRIP_LOW - Strip characters with ASCII value below 32
· * FILTER_FLAG_STRIP_HIGH - Strip characters with ASCII value above 32
· * FILTER_FLAG_ENCODE_LOW - Encode characters with ASCII value below 32
· * FILTER_FLAG_ENCODE_HIGH - Encode characters with ASCII value above 32
· * FILTER_FLAG_ENCODE_AMP - Encode the & character to &
∗ FILTER_SANITIZE_STRING : autre nom du filtre précédent en fait...
∗ FILTER_SANITIZE_EMAIL : retire tous les caractères foireux qui ne devraient pas se trouver
dans une adresse mail (ce qui veut dire qu’il laisse notamment $-_.+!*’{}|^~[]‘#%/?@&= ;
∗ FILTER_SANITIZE_SPECIAL_CHARS : transforme les caractères spéciaux HTML et XML
en entités HTML càd This filter is used to escape ”<>& and characters with ASCII value below
32 ; les flags possibles sont :
· * FILTER_FLAG_STRIP_LOW - Strip characters with ASCII value below 32
· * FILTER_FLAG_STRIP_HIGH - Strip characters with ASCII value above 32
· * FILTER_FLAG_ENCODE_HIGH - Encode characters with ASCII value above 32
∗ FILTER_SANITIZE_NUMBER_INT : retire tous les caractères qui n’ont rien à voir avec
un nombre entier ; A noter l’absence des flags et options du filtre VALIDATE équivalent ;
ATTENTION : ce qui est filtré n’est pas nécessairement un nombre et peut aussi bien être une
expression mathématique. Il faut comprendre que les filtres prennent des chaines de caractères
en argument et renvoie des chaines ! Ainsi ”5-2f+3pp” filtré donnera ”5-2+3” ;
∗ FILTER_SANITIZE_NUMBER_FLOAT : retire tous les caractères qui n’ont rien à voir avec
un nombre à virgule flottante ; Ainsi ”5-2f+3.3pp” filtré donnera ”5-2+3.3” ; flags possibles :
· * FILTER_FLAG_ALLOW_FRACTION - Allow fraction separator (like . )
· * FILTER_FLAG_ALLOW_THOUSAND - Allow thousand separator (like , )
· * FILTER_FLAG_ALLOW_SCIENTIFIC - Allow scientific notation (like e and E)
∗ FILTER_SANITIZE_URL : retire tous les caractères qui n’ont rien à voir avec la syntaxe d’une
adresse URL ; This filter allows all letters, digits and $-_.+!*’(),{}|\\^~[]‘”><#%;/?:@&= ; Pas
de flags possibles ; ”http://www.w3schooåøls.coøm” filtré renvoie ainsi ”http://www.w3schools.com”
;
∗ FILTER_SANITIZE_ENCODED : retire tous les caractères étendues d’une URL en leur équiv-
alent %xx (cette écriture correspond à l’affichage des caractères hors ASCII quand on veut les af-
ficher dans une URL. A VERIFIER) ; It works a lot like the urlencode() function. ”http://www.w3schools.com”
filtré devient ainsi ”http%3A%2F%2Fwww.w3schools.com” ; flags possibles :
· * FILTER_FLAG_STRIP_LOW - Strip characters with ASCII value below 32
· * FILTER_FLAG_STRIP_HIGH - Strip characters with ASCII value above 32
· * FILTER_FLAG_ENCODE_LOW - Encode characters with ASCII value below 32
· * FILTER_FLAG_ENCODE_HIGH - Encode characters with ASCII value above 32
∗ FILTER_SANITIZE_MAGIC_QUOTES : applique la fonction addslashes() (qui opères sur
les caractères spéciaux propres au PHP, càd ’ ” \ ) et opère un échappement des caractères
empêchant les injections sql comme le faisait l’option magic_quotes_gpc dans php.ini ;
∗ FILTER_CALLBACK : calls a user defined function to filter the value. exemple :
function convertSpace($string)
{
return str_replace(” ”, ”_”, $string);
37
}
$string = ”Peter is a great guy!”;
echo filter_var($string, FILTER_CALLBACK,
array(”options”=>”convertSpace”));
Résultat : P eter_is_a_great_guy!
A noter que la fonction passé en argument peut être une fonction php dès lors qu’elle renvoie
une string. Par exemple : strtoupper qui donnerait :
En ce qui concerne les options de filtrage (autrement appelés dans la doc php FLAGS), on peut avoir
• FILTER_FLAG_STRIP_HIGH : Supprime les caractères dont les valeurs ASCII sont supérieures à 127.
• FILTER_FLAG_ENCODE_LOW : Encode les caractères dont les valeurs ASCII sont inférieures à 32.
• FILTER_FLAG_ENCODE_HIGH : Encode les caractères dont les valeurs ASCII sont supérieures à 127.
• FILTER_FLAG_ENCODE_AMP : Encode &, càd échappe le ”et commercial”.
38
• FILTER_FLAG_ALLOW_THOUSAND : Alloue une notation scientifique (e, E) dans le filtre ”num-
ber_float”.
• FILTER_FLAG_SCHEME_REQUIRED : Schéma requis dans le filtre ”validate_url”.
• FILTER_FLAG_HOST_REQUIRED : Hôte requis dans le filtre ”validate_url”.
• FILTER_FLAG_PATH_REQUIRED : Chemin requis dans le filtre ”validate_url”.
• FILTER_FLAG_QUERY_REQUIRED : Requête requise dans le filtre ”validate_url”.
• FILTER_FLAG_IPV4 : N’autorise que les adresses IPv4 dans le filtre ”validate_ip”.
• FILTER_FLAG_IPV6 : N’autorise que les adresses IPv6 dans le filtre ”validate_ip”.
• FILTER_FLAG_NO_RES_RANGE : N’autorise pas les adresses réservées dans le filtre ”validate_ip”.
• FILTER_FLAG_NO_PRIV_RANGE : N’autorise pas les adresses privées dans le filtre ”validate_ip”.
Qu’est ce qu’une option ?
Une option permet un contrôle de la valeur filtrée. Ce contrôle s’effectue AVANT l’application du filtre
définie à l’aide de la constante de filtrage et des flags associés.
Un exemple de filtrage avec filter_input avec un tableau associatif pour les flags et options. Imaginons qu’on
souhaite filtrer une chaine contenu dans le tableau $_POST avec pour clef str et qui doit correspondre à un
entier devant être compris entre 18 et 62. L’appel de la fonction se fait de la façon suivante :
Pour un filtre vérifiant une expression régulière sur un clef Exp dans la superglobale $_POST :
A noter que dans les deux exemples précédents, il n’y a pas de FLAGS. Le filtrage sur l’entier autorisant la
récupération de nombre octaux s’écrirait :
ou
Dans le cas, de l’utilisation de la fonction filter_input_array si un tableau $_POST incorporant les clefs
Exp et str, l’appel se ferait comme suit :
filter_input_array(INPUT_POST,array(”Str” =>
array(”filters” => FILTER_VALIDATE_NUMBER_INT,
”flags” => FILTER_FLAG_ALLOW_OCTAL,
39
”options” => array(”min_range” => $min, ”max_range”
=> $max))))
qui filtre différentes variables issues de formulaires HTML dont Salaire_de_Nico et Langages_maitrisees_1000_Pattes
qui sont des tableaux,
Le filtrage pour ces deux clefs renverra :
Pour parvenir au filtrage de ces deux clefs, je suggère le recours au code suivant
IL FAUT BIEN RETENIR que les filtres de validation NE convertisse PAS les données et donc si les données
ne correspondent pas : aucune donnée filtrée n’est renvoyé. Seul FALSE est renvoyé. Enfin si la clef cherché
dans les tableaux superglobaux n’existe pas, c’est NULL qui est renvoyé
Quand on utilise un filtre de conversion, les données sont transformés. Si cette transformation échoue, c’est
FALSE qui est renvoyé. Si la clef cherchée n’existe pas, c’est NULL qui renvoyé.
8.4 La récupération sur le serveur d’un fichier envoyé via un formulaire HTML
Les fichiers peuvent être envoyés en ayant recours à une interface d’envoi de fichier présent dans un bloc HTML
<form ... enctype =’multipart/form-data’> >/form> comportant dans la balise de début un attribut enctype
spécifiant le type d’encodage. . L’interface se définit avec une balise :
40
Les fichiers sont alors acessibles en php via le tableau de superglobales $_FILES. Ce tableau est à double
entrée, et pour accéder aux variables superglobales associées à un fichier de nom ’NomDuFichier’, il faut écrire
:
$_FILES[’NomDuFichier’][’VarSuperGlobale’]
Pour chaque fichier, on peut accéder aux superglobales suivantes :
• ’name’ : nom et adresse originels du fichier côté client ;
• ’size’ : taille du fichier en nombre d’octets ;
• ’tmp_name’ : nom et adresse temporaires du fichier coté serveur. Le fichier passé par un formulaire HTML
est stocké temporairement côté serveur dans le répertoire
• ’type’ : Le type MIME du fichier téléchargé
• ’error’ : Le type d’erreur rencontré lors du téléchargement. Il s’agit d’un entier correspondant à l’énumération
suivante :
Du coté serveur, tous les fichiers sont téléchargés dans le répertoire tmp de wamp (càd au même niveau que
le répertoire www des fichiers webs). IMPORTANT : Ce fichier est détruit à la fin de l’exécution de chaque
script. Pour conserver ce fichier côté serveur au de-là du temps d’exécution d’un script, il faut utiliser la fonction
move_uploaded_file :
A noter que php limite la taille des fichiers avec sa directive post_max_size dans le php.ini. La valeur par
défaut est de 8 Mo càd que dans php.ini, on trouve :
post_max_size = 8M
41
• Les failles de divulgation provoqué par la réception de noms de fichiers ;
Une filtrage des données reçues est donc nécessaire au minimum pour éviter les attaques par injection et les
usages suspects de fichiers
Pour se protéger de ses menaces, la question sera largement abordée dans le chapitre 27 ayant trait à la
sécurité.
Deux remarques :
• Tout temps passé en dehors du script via par exemple un appel à une base de données ou à des fonctions
system via system() n’est pas décompté dans le temps d’éxécution du script.
• Le temps d’exécution maximal d’un script peut être mis à l’infini en settant max_execution_time à 0.
Attention set_time_limit(0) n’a que pour fait de forcer la fin d’un script...
• ATTENTION : le serveur web a lui-même une directive limitant le temps d’exécution d’un script php.
Timeout est la directive en question pour Apache. Cette directive n’est pas activé par défaut et est mesurée
en nombre de secondes.
POUR FINIR AVEC LES FORMULAIRES, un schéma d’interaction entre client et serveur via des formu-
laires est donné page 205 du livre : On peut le résumer par le jeu d’étapes suivantes :
42
9 Environnement web et superglobales
• l’en-tête : qui contient tous les informations techniques que s’échangent le client et le serveur ;
• le contenu : qui correspond au code HTML ou php définissant ce qui est affiché sur la page web.
ATTENTION : dans une page web, toute ligne vide signifie que le bloc d’en-tête est terminé. De même tout
appel à une fonction d’affichage implique que le bloc d’en-tête est terminé. A partir de ce moment, il n’est plus
possible d’appeler une fonction php agissant sur l’en-tête comme header(), set_cookie() ou session_start().
Deux tableaux de variables superglobales correspondent aux informations technique décrivant la relation
client-serveur associé à une page web :
• $_SERVER[] : qui regroupe toutes les informations concernant la réception d’une requête auprès du
serveur web ;
• $_ENV[] : contient les variables d’environnement du système dans lequel tourne PHP ;
ATTENTION : Pour maitriser le sujet, il est nécessaire de maitriser comment se définit et se structure
une en-tête de page HTML. C’est compliqué. Un lien vers un doc spécifiant comment fonctionne
une en-tête est disponible dans la définition de la fonction header() de l’aide PHPEdit (ou sur
php.net).
Le tableau superglobale $_SERVER contient les informations liées à la réception de la requête envoyé par le
navigateur et reçu par le serveur. Cette requête est envoyée via le protocole HTTP (HyperText Transfert Pro-
tocol) qui définit le code HTML (HyperText Markup Language). Les informations présentes dans $_SERVER
sont :
43
• $_SERVER[’HTTP_ACCEPT_LANGUAGE’] : Contenu de l’en-tête Accept-Language: de la requête
courante, si elle existe. Par exemple : ’fr’. Correspond aux langues acceptées ?????
• $_SERVER[’HTTP_ACCEPT_ENCODING’] : Contenu de l’en-tête Accept-Encoding: de la requête
courante, si elle existe. Par exemple : ’gzip’. ????
• $_SERVER[’HTTP_CACHE_CONTROL’]
JE FINIRAI LA REVUE DE CES SUPERGLOBALES UNE AUTRE FOIS, SEULS ’DOCUMENT_ROOT’
et ’SERVER_NAME’ ont un intérêt dans l’immédiat.
Attention la liste des superglobales dans $_SERVER n’est pas fixe et notamment les variables gérant
l’authentification HTTP ne sont pas présentes. Il faut les créer au moyen de la fonction header()
header() ajoute une superglobale au tableau $_SERVER qui vaut ValeurDeLaVarEntete et dont la clef
est NomDeLaVarEntete. $ReplaceOrNOt vaut TRUE par défaut ce qui signifie que deux appels de header
avec le même NomDeLaVarEntete et le même DomaineEnTete dans $ChaineVarEntete fait que la valeur
de la variable NomDeLaVarEntete est écrasé avec la valeur ValeurDeLaVarEntete passée la deuxième fois.
• checker les deux valeurs par rapport à leurs valeurs stockées coté serveur ;
• si les variables n’existent pas ou ne sont pas de bonnes valeurs, l’instruction suivante permet de demander
l’identification à l’utilisateur :
header(’WWW-Authenticate:Basicrealm=’.$titre.” ”)
44
avec : $titre le message qu’on souhaite passer à l’utilisateur au moment de l’identification. La fenêtre
d’identification suivante apparaît alors :
45
l’utilisateur. Sans compter que deux personnes peuvent avoir en même temps, la même adresse IP. Par exemple
: deux personnes d’une même boite se connectant en même temps...Par ailleurs, il ne faut pas perdre de vue
que de plus en plus, ce sont les adresses IPv6 qui vont s’imposer...
Le nom d’hote du client peut être récupéré dans la superglobale $_SERVER[’REMOTE_HOST’]. Cepen-
dant cette variable peut ne pas exister. On peut vérifier avec isset et en cas d’inexistence, utiliser gethost-
byaddr($IPAdresse) avec $IPAdresse valant $_SERVER[’REMOTE_ADDR’] qui existe toujours dans
$_SERVER. ATTENTION : Comme $IPAdresse est plus ou moins fiable, le nom de l’hôte obtenu avec geth-
ostbyaddr est aussi plus ou moins fiable...
Contrairement aux deux autres, ces deux infos vu du pt de vue du serveur ne sont pas bidonnables. Elles sont
acessibles avec $_SERVER[’SERVER_ADDR’] et $_SERVER[’SERVER_PORT’] . A noter que si
on se connecte en local à son serveur web, il n’est pas possible de connaitre IP publique.
http://www.NomDeDomaine/CheminDeLaPageVue?variable1=Valeur1&variable2=Valeur2
et les deux variables passés sont de noms variable1 et variable2 tandis que leurs valeurs respectives
sont Valeur1 et Valeur 2. La variable $_SERVER[’REQUEST_URI’] contient donc par
rapport à l’adresse URL précédente :
/CheminDeLaPageVue?variable1=Valeur1&variable2=Valeur2
46
– $_SERVER[’QUERY_STRING’] : La variable superglobale suivante permet de récupérer exclu-
sivement uniquement ce qui suit le point d’interrogation dans $_SERVER[’REQUEST_URI’].
Par rapport à notre exemple d’adresse URL ci-dessus, $_SERVER[’QUERY_STRING’] con-
tient la chaine :
variable1=Valeur1&variable2=Valeur2
A noter que le recours à la fonction explode avec ’&’ puis ’=’ comme séparateur permet de récupérer
un tableau de toutes la variables passés en arguments de la requête URL. Les noms et les clefs de
chaque variable sont alors disponibles alternativement comme élément du tableau. Par exemple :
un premier explode donne un tableau dont l’élément 0 vaut ’variable1=Valeur1’ et l’élément 1 vaut
’variable2=Valeur2’. Un deuxième explode sur le caractère ’=’ sur chaque élément de ce premier
tableau donne deux tableaux dont le premier a pour premier élément ’variable1’ et pour deuxième
élément Valeur2. ATTENTION dans les url, seuls les caractères alphanumériques sont tolérés et
donc quand les valeurs de variables sont passés dans l’URL, les caractères non-alphanumériques sont
encodées en url càd avec une syntaxe de type %xx. Pour récupérer dans une variable, des valeurs
encodés, on utilise la fonction urldecode. De même façon pour encrypter des variables et leurs
valeurs de manière à les incorporer dans une requête URL, il faut utiliser la fonction urlencode.
A noter l’existence des fonctions rawurlencode et rawurldecode qui font la même chose mais les
espaces apparaissant dans une chaine et qui sont retranscrites avec le caractère ’+’ dans l’URL ne
sont pas restitués en espace par la fonction rawurldecode.
IMPORTANT : Pour récupérer les variables et les valeurs de $_SERVER[’QUERY_STRING’],
il est préférable d’utiliser la fonction parse_str() qui renvoie un tableau associatif dont les clefs sont
les noms des variables et les valeurs associés sont leurs valeurs correspondantes. Comme toute bonne
fonction couteau suisse, parse_str a deux fonctions un peu différentes suivant la liste d’arguments
: parse_str($AdresseURL) qui crée directement les variables issue de l’URL avec leur nom de
variables et leur valeur. Truc con : dans le cas de ce premier usage, il faut connaître à l’avance
le noms des variables qui vont être crées. L’autre usage est parse_str($AdresseURL, Optional
$TableauDeVariables) qui crée le tableau associatif...
– $_SERVER[’PATH_INFO’] : il est possible d’adopter une arborescence virtuelle pour gérer et
structurer l’ensemble des fichiers de script HTML et php. Dans ce cas, la partie virtuelle du chemin
est contenu dans $_SERVER[’PATH_INFO’].
• Les informations fournies par le client : Ces informations concernent le client : la page dite
référente du client et les caractéristiques des contenus gérés par le client.
47
∗ $_SERVER[’HTTP_ACCEPT’] : permet de spécifier les préférences du client en matière
de format de fichier web acceptés par son navigateur : XML, XHTML, HTML etc. en affectant
une priorité entre chaque format (la priorité max étant 1 sur une échelle allant de 0 à 1) La
chaine de caractère renvoyé par $_SERVER[’HTTP_ACCEPT’] est de la forme :
Format1;q=x,Format2;q=y,Format3;q=z,...
ce qui signifie que le format Format1 est accepté avec la priorité x, le format Format2 avec la
priorité y, le format Format3 avec la priorité z et ainsi de suite. Quand la priorité n’est pas
spécifié, elle vaut 1 càd la priorité maximale. Un exemple est le suivant :
text/xml,text/html;q=0.8,*/*;q=0.1
ce qui signifie que le XML est le format préféré puis le html avec 0.8 en priorité et tous les autres
types de fichiers (*/*) avec q = 0.1.
IMPORTANT : récupérer cette chaine et l’analyser permet au serveur de servir au mieux le client
;
∗ $_SERVER[’HTTP_ACCEPT_LANGUAGE’] : permet d’identifier la langue de l’utilisateur
côté client. Autant dire que c’est VITAL. Comme pour la superglobale $_SERVER[’HTTP_ACCEPT’],
la chaine contenue dans $_SERVER[’HTTP_ACCEPT_LANGUAGE’] donne un ordre de préférence
entre plusieurs valeurs acceptées par le client. chez moi, j’ai :
fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3
càd français de France préféré en premier puis l’anglo-américain et puis l’anglais ;
∗ $_SERVER[’HTTP_ACCEPT_CHARSET’] : permet de savoir quelle est le jeu de car-
actères utilisé par le client càd utf-8, ISO-machin et cie... TRES IMPORTANT donc ; ATTEN-
TION : le navigateur client peut accepter PLUSIEURS encodages possibles et comme pour la su-
perglobale $_SERVER[’HTTP_ACCEPT’], la chaine contenue dans $_SERVER[’HTTP_ACCEPT_CHARS
donne un ordre de préférence entre plusieurs valeurs acceptées par le client.
ISO-8859-1,utf-8;q=0.7,*;q=0.7
∗ $_SERVER[’HTTP_ACCEPT_ENCODING’] : détermine quels format de compression,
le navigateur accepte. Contrairement aux trois autres cas, il n’y a pas de système de préférences, le
navigateur accepte tous les types d’encodages de la liste $_SERVER[’HTTP_ACCEPT_ENCODING’]
sans chichi. Chez moi, ça donne :
gzip,deflate
– Le nom et le numéro de version du navigateur : Ces informations sont contenues dans la
superglobales $_SERVER[’HTTP_USER_AGENT’]. Cela a surtout pour utilité d’identifier si le
navigateur client est un navigateur de pc, de mac, d’ipad, iphone ou autre et permet donc d’adapter
son site éventuellement à ces clients les plus typiques. MAIS sinon il faut éviter d’adapter son site à
chaque navigateur, c’est une perte de temps et une source de complications inutiles...
C’est là que c’est drôle : le contenu de $_ENV dépend du sytème. Peut-être reviendra-t’on dessus mais à ce
stade, une boucle sur $_ENV ne renvoie RIEN !!!
48
• $_SERVER[’SCRIPT_NAME’] : donne l’adresse relative du script en cours d’utilisation à partir du
répertoire racine des fichiers web sur le serveur. A l’inverse ...
• $_SERVER[’PATH_TRANSLATED’] : donne lui le chemin absolu ;
Last but not the least :
Par ailleurs, en php, chaque cookie associé au nom de domaine de la page est stocké dans le tableau
superglobale $_COOKIE.
Maintenant du fait que les cookies sont crées côté client. AUCUNE information critique ne peut être
raisonnablement stockés côté client. Càd que toute information pouvant mettre en jeu la sécurité du client ou
l’intégrité du serveur ne peut être stocké sous forme de cookie. Par ailleurs, la taille des cookies est généralement
limitée par les navigateurs eux-mêmes ( généralement 4 ko) et leur nombre par domaine est souvent limité (20
max le plus souvent).
Il est donc FORTEMENT conseillé de créer :
• des petits cookies, càd des petits fichiers de 4 ko ;
• peu de cookies : vaut mieux donc 1 cookie de 3ko que 3 cookies de 1 ko du fait de la limitation en nb de
cookie ;
• des cookies ne contenant pas d’information joue sur des paramètres critiques du serveur (genre le prix du
clic comme une régie publicitaire avait pu le faire) ;
49
• des cookies contenant des informations confidentielles du client vu que ces mêmes données sont alors
potentiellement accessible par tiers (par exemple, le cas le plus simple d’une même machine utilisée par
plusieurs personnes) ;
• des cookies qui ne sont pas indispensables au bon échange entre client et serveur car certains navigateurs
ou certains clients peuvent limiter ou carrément interdire l’usage des cookies. De ce fait, si les cookies sont
conçus comme indispensables à l’échange, c’est l’usage du site web par le client qui est compromis !
Mais à quoi servent donc ces satanés cookies ?? Pas dur :
• Pré-remplir des formulaires web avec des informations non-critiques. Le cookie est alors pour simplifier
la vie de l’utilisateur ;
• faire des statistiques à destination du serveur notamment par exemple stocker la dernière date de connexion
du client au serveur. Du fait de la loi des grands nombres et à l’aide d’un contrôle des valeurs, le bidonnage
par un utilisateur de ses propres cookies n’aura que peu ou pas d’impact.
Une petite remarque : dans le cas des statistiques ou d’autres données à caractères informationnelles à des-
tination du serveur, il est aussi possible de créer des cookies contenant des informations cryptées à l’aide des
fonctions de hachage et de cryptage vu auparavant. Attention cependant à ne pas se servir de cet argument
pour commencer à stocker dans les cookies des informations ou des paramètres critiques.
Au première accès au site web, le serveur envoie au client une page web avec un cookie dans le bloc d’en-tête.
Ensuite à chaque requête du client, celui-ci renvoie dans la requête HTTP le cookie au serveur qui va se servir
de l’information contenu pour faciliter l’échange informationnel entre client et serveur.
Où sont stockés les cookies ? Cela dépend de la durée de vie de chaque cookie : si elle est limitée, le
cookie est stocké sur le disque dur à un emplacement réservé dont le chemin dépend de l’OS. En l’occurence,
sur Windows XP, ça va être c:\Document and Settings\votre_login\Local Settings. Sur Vista, c’est pas clair
mais sur firefox on peut accéder aux cookies associés à une page donnée en faisant Outils => Informations sur
la page => Sécurité => Voir les cookies.
50
Impact de l’activation du buffering sur l’utilisation de setcookie : Le buffering est une option
présente dans php.ini qui permet de ne pas envoyer au client ligne par ligne l’exécution de la page html construite
à partir du script php. Cette option est écrite dans php.ini comme :
output_buffering=on
Indépendament de ce paramètre de php.ini, la mise en tampon peut être directement géré dans le code php
à l’aide du jeu de fonctions suivant :
• ob_start(optional $Output_CallBack,optional $ChunkSize, optional $Erase) : met en buffer
toutes les instructions html produites par php, à l’exception des instructions d’en-têtes (qui ne peuvent
être mis au buffer que via la directive Output_buffering de php.ini), à la suite de l’appel ob_start et ce
soit jusqu’à ce que la chaine stockée correspondante dépasse la valeur $ChunkSize en octets, soit jusqu’à
l’appel de la fonction ob_end_flush() ou ob_clean(). L’option $Erase permet de conserver le contenu du
tampon jusqu’à la fin du script courant et donc après l’appel éventuel à ob_end_flush ou ob_end_clean.
Enfin $Output_CallBack est le nom d’une fonction utilisateur php qui peut-être défini pour retraiter la
chaine stockée dans le buffer avant son envoi au client ; NOTE : il est possible d’imbriquer plusieurs
tampons à l’aide de plusieurs appels à ob_start.
• ob_end_clean() : détruit le tampon et donc son contenu.
• ob_flush() : Envoi le contenu du tampon au client et efface son contenu ;
• ob_end_flush : idem mais ferme par ailleurs le tampon courant ;
• ob_get_contents() : renvoie la chaine correspondant au contenu du tampon sans effacer ce dernier ;
• ob_get_lenght() : renvoie la taille en octets (?) du contenu du tampon (ou buffer en anglais);
TRUC : Pour être sur de vider et de fermer tous les tampons mémoires ouverts :
while(@ob_end_flush()==true)
ATTENTION : Inutile d’essayer d’écrire dans $_COOKIE, ce tableau superglobale est en lecture seul. Il
faut passer obligatoirement par la fonction setcookie.
ATTENTION : $_COOKIE est le tableau des valeurs de cookies envoyés par le client. Il est impossible de
modifier sa valeur dans un bloc de code php sans passer par un renvoi de header par le client, ce renvoi contenant
51
une instruction setcookie($NomCookie, $NouvelleValeurCookie). Inutile donc d’essayer d’incrémenter la valeur
d’un cookie dans une boucle, ça ne changera pas sa valeur... Il faut passer par setcookie appelé dans un header
de page en train d’être chargé
Supprimer un cookie :
il faut alors supprimer à la fois la variable dans le tableau superglobale $_COOKIE ET le fichier crée dans
le système de fichiers du client. DEUX appels sont donc nécessaires :
• Pour supprimer le fichier cookie, il faut réexécuter la dernière instruction setcookie s’étant appliqué au
cookie qu’on souhaite éliminer avec pour seul changement passer en valeur une chaine vide ” ” ou ”. Dans
le bouquin, il est dit que seul setcookie($NomDuCookie) mais cela ne semblait pas bien marcher quand le
output_buffering est activé...
• Pour supprimer la variable PHP $_COOKIE[’$NomDuCookie’] : unset($_COOKIE[’$NomDuCookie’]);
setcookie($NomDuCookie,$ChaineValeurCookie)
la durée de vie du cookie est par défaut celle de la session courante du navigateur. Pour spécifier une date
d’expiration à un cookie, il faut utiliser l’appel suivant :
setcookie($NomDuCookie,$ChaineValeurCookie,$TimestampDateExpiration)
setcookie(”TotoCookie”,serialize($Toto),mktime(0,0,0,2011,12,3))
Pour récupérer l’info, il faut alors désérializer la chaine contenu dans le cookie avec la fonction unserialize.
Par exemple :
$NewToto=unserialize($_COOKIE[’TotoCookie’]);
la variable $NewToto a alors la même structure que $Toto ( ça correspond à une copie de $Toto)
52
On peut restreindre l’existence d’un cookie à un domaine donné et /ou à un répertoire (et donc tous ses
sous-répertoires et fichiers) et surtout si le cookie est installé uniquement en connexion sécurisée (càd en SSL
via le protocole https) ou non. La surdéfinition correspondante de setcookie est :
setcookie($ChaineNomCookie,
$ChaineValeurCookie,
$TimeStamp,
$RepertoireValide,
$NomDomaineValide,
$SSLTrue,
$httponly )
Si on ne souhaite pas restreindre le répertoire, on met ”/” comme valeur par défaut à $RepertoireValide.
Si on ne souhaite pas restreindre le nom de domaine, on ne renseigne $NomDomaineValide.
Par défaut, un cookie est valide pour tout le domaine courant. Chez moi, c’est toto.localhost.
$NomDomaineValide est une chaine qui contient le nom de domaine souhaité TOUJOURS précédé d’un
point.
Le nom de domaine spécifié peut-être partiel par exemple, on peut mettre ’.php.net’ ce qui rendra le cookie
valide pour les domaines www.php.net ou www.toto.php.net.
$RepertoireValide est une chaine qui contient le nom de répertoire souhaité TOUJOURS précédé d’un ’/’.
$SSL doit valeur true si on souhaite que le cookie ne soit valide que dans le cadre de connexion sécurisée.
Par défaut, ça vaut false)
$httponly passé à true signifie que le cookie n’est accessible que par connexion HTTP. Cela signifie notam-
ment que le cookie n”est pas accessible via des langages de script côté client notamment javascript. Cela limite
les ATTAQUES de type XSS. ATTENTION : certains navigateurs refuse l’usage de cette option...
Ce tableau est renseignée par php et est donc en lecture et écriture directe contrairement à $_COOKIE
qui est n’est manipulable qu’à partir de la fonction couteau-suisses setcookie(). ATTENTION : dès lors qu’une
session est crée, une fichier de session est crée sur le serveur. Celui-ci n’est pas détruit à la fin d’un script mais
est détruit à une date ultérieure aléatoire par PHP. On peut cependant s’en débarasser explicitement.
Du fait de son caractère temporaire, tout nouvelle information apportée par le client et enregistrée dans le
fichier de session via le tableau superglobale $_SESSION doit ensuite être sauvé sur un fichier plus pérenne sur
le serveur par exemple sur une base de données.
53
11.0.1 Pour débuter une session :
Pour amorcer l’utilisation du tableau superglobale $_SESSION, il faut utiliser l’instruction session_start().
Avant cela, le tableau $_SESSION n’est pas accessible pour le script courant. L’effet de session_start() est de
:
1. Rendre accessible le tableau superglobal $_SESSION en lecture et en écriture ;
2. débuter l’écriture du fichier de session correspondant.
3. créer un cookie spécial du nom de PHPSESSID à destination du client. Ce cookie permet de donner au
client un identifiant. Ce cookie n’a pas par défaut de durée de vie et est donc effacée du client dès que la
session de navigateur est fermée ; A noter que la durée de vie du cookie est indépendant de celle du fichier
de session ou de la durée de vie de $_SESSION.
ATTENTION : session_start() doit être utilisée avant tout envoi d’affichage ou de header notamment parce
qu’il incorpore le cookie de session PHPSESSID.
Remarque : La directive php session.auto_start mise à 1 fait que toute page web contient automatiquement
en première instruction session_start(). IL FAUT EVITER CELA car cela empêche une gestion fine des sessions
et des cookies.
La fonction session_destroy() permet de fermer la session courante : càd elle détruit le fichier de session.
ATTENTION : après un appel de session_destroy(), le tableau superglobale $_SESSION reste inchangée.
Pour effacer ce dernier, il faut ajouter l’instruction :
unset($_SESSION);
ATTENTION : tout appel à session_id DOIT être fait avant l’appel à session_start() sinon les éventuels
modifications ne seront pas prises en compte.
ATTENTION : jouer avec les ids de session peut être casse-gueule en terme de sécurité.
INFO : la constante globale SID permet d’avoir à l’ID de la session courante comme le renverrait session_id
Il est parfois intéressant de régénérer l’id de session. C’est ce que fait la fonction session_regenerate_id().
54
11.0.6 Pour changer ou récupérer le nom du cookie d’Id de session :
session_name(Optional $NewName) : permet de récupérer le nom de session quand $NewName n’est
pas spécifié. Dans le cas inverse, le nom du cookie de session est remplacé par le nom passé en argument.
ATTENTION : $NewName ne doit contenir que des caractères alphanumériques. Par ailleurs, ce changement
de nom du cookie ne sera valide que pour le script courant. Les autres scripts utiliseront le nom par défaut
PHPSESSID. Enfin il faut appeler cette fonction AVANT session_start() pour que ça prenne effet. La valeur
par défaut peut être changé dans php.ini via la directive session.name = PHPSESSID.
Remarque : Ne pas oublier qu’une bonne part des directives php peuvent être modifiées localement dans
un script à l’aide de la fonction ini_set($DirectiveName,$NewValue)
session.save_path=”C:/ProgramFiles/wamp2/tmp”
Ce qui signifie notamment que les fichiers de session ne sont pas sauvés dans le répertoire des fichiers web ”www”.
ca évite que le client puisse avoir accès aux fichiers de sessions qui vont garder potentiellement des informations
confidentielles...
cette fonction DOIT être appelé AVANT session_start().
sess_superjoe
Cela se fait en ajoutant de nouvelles clefs au tableau superglobal $_SESSION. Par exemple :
$_SESSION[’NewVar’] =10; /// création de la var NewVar
$_SESSION[’NewVar’] = ”Beautiful”; /// modification de la valeur de la variable
unset($_SESSION[’NewVar’]); /// Effacement de la variable ’NewVar’
Pour effacer toutes les données de $_SESSION, il NE FAUT PAS FAIRE unset($_SESSION) car c’est trop
bourrin, $_SESSION devient totalement inacessible. La solution est de lui affecter un tableau vide en valeur
comme suit :
$_SESSION=array();
Attention :
$_SESSION= 0;
55
fait que $_SESSION n’est plus un tableau. Il faut alors repasser par la fonction array() pour redéfinir $_SES-
SION correctement :
$_SESSION=array();
Le recours direct à :
$_SESSION[’Nom’]=”Marie-Estelle”;
aurait renvoyé une erreur stipulant que $_SESSION n’est pas un tableau.
session_set_cookie_params($DureeVie,
Optional $Path,
Optional $Domaine,
Optional $Secure,
Optional $httponly,
Optional $)
ATTENTION : Cette modification des params du cookie d’ID de session ne sont valides que pour le script
dans lequel il est appelé, et par ailleurs, il faut impérativement l’appeler avant l’instruction session_start(). La
solution pour rendre ”permanent” est d’appeler session_set_cookie_params pour chaque script et avant chaque
appel à session_start().
Pour récupérer les paramètres courant du cookie de session, il faut utiliser la fonction session_get_cookie_params()
Les paramètres par défaut du cookie de session sont settables dans php.ini avec les directives suivantes :
• session.cookie_lifetime =”0” ;
• session.cookie_path =”/” ;
• session.cookie_domain = ” ”;
• session.cookie_secure = ” ”.
56
11.0.12 Modification du serializer de php :
Les fonctions serialize et unserialize utilisent un module de serialization installé avec php. Il est possible d’en
choisir un autre à l’aide de la directive php suivante :
Attention à spécifier un serializer qui tourne correctement... A voir si on a besoin de prendre un serializer
plus léger et/ou plus secure que celui installé...
Php verouille le fichier de session pour éviter que plusieurs scripts tape en même temps sur le fichier de session.
Le problème d’un accès multiple apparaît quand on a par exemple plusieurs fenêtres ouvertes sur un même site.
Dans ce cas, un seul et unique script va avoir l’accès et php va locker autimatiquement le fichier de session. Les
autres scripts n’auront alors pas du tout accès normalement au fichier de sesson ce qui peut empêcher le bon
fonctionnement des scripts surnuméraires. Les fonctions suivantes sont là pour résoudre ce problème :
• session_readonly() : appeler à la place de session_start, il permet à un script d’avoir accès à $_SESSION
et au fichier de session en lecture seulement ; ATTENTION CETTE FONCTION NE SEMBLE PAS
EXISTER !!
session.cache_limiter
57
• ”public” : la page web est resservie tel quelle à tous les utilisateurs quelque soit la session et l’id corre-
spondant de chacun. Idéal pour une page fixe, à proscrire pour une page un tant soit peu dynamique...
• ”private_no_expire” : la page n’est resservie qu’au utilisateur doté du bon id de session ; Pas de date
d’expiration pour la mise en cache de cette page ; Bien réfléchir à quelle page aurait ce type de mise en
cache. Idéalement un portail fixe sans mise à jour de données ;
• ”private” : pareil que le précédent mais la mise en cache est limitée dans le temps via la directive ses-
sion.cache_expire qui donne en secondes la durée de la mise en cache potentielle ;
• ”nocache” : Pas de mise en cache autorisées à part pour le bouton page précédente du navigateur et
d’autres rares cas particuliers ;
Les fichiers de session ont une durée de vie limitée aléatoire sur le serveur. Le principe est simple et est gouverné
par deux directives de php.ini : session.gc_probability et session.gc_maxlifetime. L’effacement des fichiers de
session a lieu comme suit :
• A chaque démarrage de session, un nombre aléatoire compris entre 0 et 1 est tiré ;
• Si sa valeur est inférieure ou égale à session.gc_probability/session.gc_divisor, tous les fichiers dont l’âge
en secondes dépasse session.gc_maxlifetime sont effacés.
session.gc_probability = 1
session.gc_divisor = 1000
session.gc_maxlif etime = 1440
58
11.0.19 Echange d’identifiant entre client et serveur :
A la première connexion du client au serveur, le cookie d’id de session n’existe pas côté client, et c’est le serveur
qui en renvoyant la première page va demander au client de créer le cookie d’id de session.
Cependant il est possible que le navigateur client ne permettent pas la création de cookie. Dans ce cas, il est
techniquement possible d’intégrer l’id de session dans l’URL (v.page 249) cependant cela expose l’id de session
dans l’URL, ce qui n’est pas souhaitable en terme de sécurité. Si le client ne veut pas utiliser de cookie, en clair
tant pis pour lui ! La configuration en terme de directive php est alors la suivante :
session.use_trans_id =0
session.use_cookie =1
session.use_only_cookie =1
La première ligne permet d’empêcher la transmission d’ID par URL.
59
11.0.22 Conseils de sécurité ayant trait aux sessions :
1. Controler l’accès aux fichiers de session : En cas de partage d’un serveur, spécifier l’adresse de
sauvegarde des sessions dans un répertoire à accès restreint est capital pour éviter que qui que ce soit
accède aux fichiers de sessions :
session.save_path=”/home/utilisateur/repertoire/personnel
2. Ne pas faire passer d’id de session par URL : La possibilité d’utiliser l’ID de session par l’URL quand
l’utilisateur refuse les cookies est une très mauvaise chose car une copie malheureuse de lien, le fait que
l’URL de la page précédente est contenu dans la requête HTTP courante compromet la sécurité de la
session et de l’identité de son utilisateur. Bref pour s’assurer que ces problèmes n’apparaissent pas, il faut
setter :
session.use_trans_sid =0
session.use_cookies =1
session.use_only_cookies =1
4. Utiliser la fonction session_regenerate_id dès AVANT et APRES que l’utilisateur soit identifié pour
limiter les ATTAQUES par fixation de session (v. plus loin le chapitre sur la sécurité) ;
5. Stocker le maximum d’informations sur l’utilisateur dans sa session pour permettre de contre-checker son
identité. Par exemple, si les infos sont très différentes d’une connexion à l’autre, on peut détruire sa
session et redemander une authentification...
6. NE JAMAIS STOCKER de mot de passe ou d’infos trop confidentielles dans la session. Par exemple,
pour le couple login/ mot de passe, on peut stocker le login et stocker le fait que password était valide et
non le pasword lui-même.
Un chapitre sympa sur la programmation orientée objet. Pourquoi ce chapitre arrive après les cookies et les
sessions ? Je n’en sais rien. L’ordre des chapitres n’est pas très cohérent de toute manière ...
60
12.1.1 Structure d’une classe :
class Personnage
{
/// Bloc des attributs de la classe
private $PtsDeVie =100; /// Déclaration d’une valeur par défaut : 100 ici
/// Blocs des déclarations des constantes locales uniquement accessibles au sein de la classe
const GUERRIER =1 ; /// ça fonctionne comme un enum ;
const SOLDAT =2; // le hic, c’est que c’en est pas un de sorte que ces constantes n’ont pas
const BOURREAU =3 ; /// d’unité logique au sein de la classe
/// Pour accéder à une constante de classe au sein de la même classe, il faut écrire self::NOMCONSTANTE
return $this->Force; /// ATTENTION le getteur renvoie une référence sur Force et non une copie !
}
/// Bloc de méthodes
{
/// contrairement au C++ où on a un fichier d’en-tête et un fichier source
///pour chaque classe, en php, le bloc d’exécution d’une fonction suit directement la
/// déclaration du prototype.
}
};
Best Practices :
1. TOUJOURS DECLARER LES ATTRIBUTS COMME PROTECTED ou PRIVATE pour pouvoir gérer
leur lecture/écriture plus finement ;
61
12.1.2 Les spécificateurs de portée des attributs et méthodes :
sont identiques au C++. Une méthode ou attribut private n’est accessible qu’au sein de la classe, protected :
acsessible au sein de la classe et des classes dérivées
$Thor=new Personnage();
Comme d’hab, les parenthèses vides correspondent au constructeur par défaut. Comme d’hab en C++, il faut
bien sur que l’existence de la classe a été déclarée pour faire le new. La bonne pratique est de faire l’include ou
le require nécessaire...
L’accès aux membres attributs et méthodes se fait en appelant une instance suivi de ’->’. TOUTES les instances
de classes étant des références, quelque part ça revient à considérer qu’on accède aux instances de classes comme
si on accédait à un pointeur de classe en C++.
ATTENTION : Par défaut, tout accès à un attribut membre se fait PAR REFERENCE !!
• get_class($Object) : Cette fonction permet d’avoir le nom de la classe de l’objet passé en argument ;
• get_parent_class($Objet) : Cette fonction permet d’avoir le nom de la classe immédiatement parente de
l’objet passé en argument ; Notons qu’on peut aussi bien passer un nom de classe en argument qu’une
instance de classe.
12.1.6 $this
$this se comporte globalement comme en C++. Notamment dans le cadre d’héritage, il se réfère toujours à la
classe dans lequel il est cité. Cité dans le code d’une classe abstraite, il se comporte comme une référence sur
une instance de cette classe abstraite. Rappel : il n’est pas possible de définir une instance de la classe mère.
par contre, une référence c’est possible (et en C++, un pointeur c’est aussi possible).
62
12.1.7 __Tostring()
Fonction qui permet de renvoyer une chaine de caractères quand l’affichage de la classe est demandée. Générale-
ment on formate le retour du genre ”NOMCLASSE:Attribut1=Valeur1;Attribut2=Valeur2;...” mais aucune règle
n’est spécialement requise. attention cette fonction DOIT renvoyer une chaine. Un exemple d’écriture de cette
fonction est :
function __tostring() {
return ”<br> Le personnage est de nom $this->Nom, de force $this->Force, d’agilité $this->Agilite et
d’endurance $this->Endurance”;
};
Tout affichage d’une instance d’une classe où __tostring aboutit à une erreur fatale.
Supposons qu’une classe Perso possède trois attributs définis : Nom, Prénom et age. Si dans du code, j’écris :
$Toto=new Perso();
$Toto->a = ”Valeura”;
$Toto->b = ”Valeurb”;
$Toto->c = ”Valeurc”;
$Toto->Pognon =110;
L’instance $Toto aura gagné un attribut du nom de Pognon. Pire encore si une classe mère a un attribut
Pognon privé et que $Toto en dérive, si le Pognon n’est logiquement pas accessible (par exemple en faisant
echo $Toto->Pognon), l’attribut Pognon peut-être crée en faisant $Toto->Pognon =NimporteQuoi; Bonjour
l’angoisse sur la possibilité de coder crade et sur la sécurité de la chose...
En utilisant les mutateurs qui sont définis en php avec les fonctions natives __get et __set :
function __get($nom)
On compare alors la valeur de nom avec les noms des attributs pour décider quelle valeur renvoyer quand la
donnée membre de nom $nom est appelé.
function __set($nom,$valeur)
EN FAIT, __set agit comme une redéfinition de l’opérateur = pour les données membres de la classe dans
cette fonction est appelée. L’idée est de comparer là aussi $nom avec les noms des attributs membres de la classe
de manière à affecter au membre la valeur $valeur. Notons que si l’attribut de nom $nom est aussi une instance
d’une autre classe, il faut contrôler la nature de la classe de $valeur avant de décider de l’affecter. L’affectation
peut se faire ensuite
63
12.1.10 Copie d’instance de classe : = clone
Tout recours à l’opérateur d’affectation ”=” entre deux instances d’une même classe de type a= b conduit à ce
que a devienne une référence de b (ATTENTION : si a était une instance d’une autre classe, a deviendrait aussi
une référence de b et donc la nature et le contenu précédent de b serait totalement perdu). Si on souhaite que
a soit seulement une copie de b, il faut définir la fonction membre native __clone() dans la classe voulue.
Php crée toujours un fonction __clone() par défaut pour chaque classe. Celle-ci fonctionne comme un
opérateur de sorte que :
a = clone b
fait que a est une copie bit à bit de b.
correspond à une copie bourrine de la c Quand on définit sa propre version de __clone(), la fonction _clone
par défaut est exécuté puis la version utilisateur de sorte que celle-ci ne vient qu’en complément
Attention : dans le cadre d’une fonction dérivée, la fonction __clone appelée est toujours celle de l’objet
copié, et EN AUCUN cas, la fonction __clone de la classe mère ou grand mère n’est appelée.Par contre, il est
possible d’appeler la fonction __clone mère en écrivant parent::__clone();
A NOTER : Quand on rajoute implicitement un membre à une instance de classe, et que cette dernière est
cloné, le clone récupère aussi le nouveau membre rajouté implicitement.
Va savoir pourquoi mais quand a === b, pour les objets le triple = ne compare plus les valeurs et la nature
de l’objet mais dit si a est une référence de b !! Complètement débile alors que quand a et b ne sont pas des
objets, il vérifie bien que a et b ont la même valeur ET sont du même type !!
L’opérateur == lui teste l’égalité classique.
12.1.12 Constructeurs
C’est une fonction de nom __construct qui permet de définir un constructeur. Comme en C++, il faut appeler
explicitement le constructeur de la classe parent pour que celui-ci opère comme suit Parent::__construct(...)
ATTENTION : il ne peut y avoir qu’un seul et unique constructeur par classe !!! Par contre, en ne donnant
pas d’arguments au constructeur, il est possible de définir autant de constructeur qu’on souhaite en consid-
érant __construct comme une fonction sans nombre défini d’arguments avec les fonctions func_num_args(),
func_get_arg() et func_get_args(). ça exige une petite gymnastique de codage mais c’est possible.
64
12.1.13 Destructeur en PHP
Le destructeur est défini en php comme à l’aide de l’expression native __destruct(). Dans l’absolu, le destructeur
pour un objet donné si cet objet n’est plus référencé ou si la fonction unset est appelé sur la variable. Du fait du
garbage collector présent en php, le destructeur est surtout utile pour fermer les ressources ouvertes : fichiers,
connexion vers le serveur de base de données etc.
Destructeur et héritage : Pas dur, pour que la destructeur d’une classe mère soit appelé dans une classe
dérivée, il faut que cet appel soit explicite dans le destructeur de la classe dérivée càd parent::__destruct();
Comme dans la plupart des langages objets modernes, une seule classe mère possible (mais autant d’Interfaces
qu’on veut). Pour qu’une classe A hérite d’une classe B, à la définition de la classe A, on doit avoir :
class A extends B
• les méthodes et attributs hérités peuvent être redéfinis dans la classe dérivée ;
• Une méthode dérivée a son nombre de paramètre optionnel et son nombre de paramètres obligatoires
contraint par ceux de la méthode de même nom de la classe mère :
– Le nombre de paramètres obligatoires de la méthode fille doit être inférieure au nombre de paramètres
possibles (càd nb de params obligatoires + nb de param optionnel) de la méthode mère (ATTEN-
TION, quand la méthode mère ne comporte pas d’arguments (ex :func() ), le nombre de paramètres
possibles est infini) ;
– Le nombre de paramètres possibles de la classe dérivée doit être supérieure ou égal au nombre de
paramètres possibles de la classe mère ;
– En cas de contradiction d’une de ces deux règles peu claires, un message d’erreur E_STRICT est
renvoyé (v. chapitre sur les erreurs) ;
Notons que :
• is_sub_class_of($object,$className) : renvoie true si $object est une instance d’une classe dérivée
de la classe de nom $className ;
• get_parent_class($objet) : renvoie le nom de la classe mère de $objet si elle existe.
65
12.1.15 Spécificateur d’accès aux méthodes et aux attributs
• Toute méthode de classe peut s’appeler de manière statique en précédant le nom de la fonction de
NomDeLaClasse::NomFonction(...)
Autrement l’accès aux méthodes et aux classes peuvent être précisés avant la déclaration de la méthode ou
de l’attribut. par défaut, l’accès est public. Comme en C++, les trois types d’accès sont public, protected et
private et fonctionnent comme en C++ sauf qu’il n’y a pas de spécificateur d’accès pour les classes qui sont
toutes considérées comme public par défaut :
• accès public : méthode ou attribut accessibles partout ;
• accès protected : méthode ou attribut seulement du code dans les blocs de la classe et de ses classes
dérivées ;
• accès private : accès uniquement dans les blocs de code de la classe .
RUSE : il est toujours possible de rendre public, un attribut ou une méthode private ou protected en
l’encapsulant dans une méthode public.
Dans le cas d’une méthode privé, la surdéfinition dans une classe dérivée aboutit en quelque sorte à créer
une méthode de même nom propre à la classe dérivée. (Evident non ? Bizarre que le bouquin se prenne le
chou là-dessus)
L’horreur de php et une de ses forces suivant qu’on aime est le faible typage de PHP. Pour les horrifiés, il est
possible et (FORTEMENT recommandé) de typer les arguments d’une fonction dès lors que l’argument est un
objet. ca permet d’éviter de faire des contrôles basés sur instanceof à tout bout de champ en spécifiant le type
de chaque argument d’une fonction.
une fonction FaireCalcul($a,$b) a deux arguments non typés tandis que la définition suivante
FaireCalcul(Classe1 $a,Classe2 $b) stipule que $a DOIT être de type Classe1 et $b de type Classe2.
RUSE : Pour retrouver un typage fort du langage, on peut encapsuler les types élémentaires dans des classes
propres.
Une méthode est déclarée abstraite avec le mot clé abstract avant la déclaration de la fonction et avant le
spécificateur d’accès.
Une méthode abstraite ne peut être déclarée private. Elle peut seulement être protected ou public.
Une classe peut être abstraite sans avoir une seule méthode abstraite, un peu bizarre mais possible.
Notons qu’une classe abstraite peut avoir un constructeur __construct() et des attributs...
66
12.1.19 Interfaces
Les interfaces fonctionnent en php comme en java. Ce sont des listes de fonctions correspondant à une même
unité sémantique ou logique et encapsulé dans une classe abstraite sans AUCUN attributs.
Une classe (normale, abstraite ou finale) peut dériver de plusieurs interfaces (alors qu’il ne peut y avoir
qu’une seule classe mère).
Toutes les méthodes d’une interface sont FORCEMENT d’accès PUBLIC. On ne peut pas avoir de méthodes
d’interface protected ou private.
Une classe ClasseX hérite d’une ou de plusieurs interface à l’aide du mot clé implements comme suit :
Notons qu’une classe abstraite peut hériter d’interfaces et qu’une interface peut elle-même hériter d’autres
interfaces...
IMPORTANT : Une classe ClasseY héritant de ClassX appartient à quatre types possibles : ClasseY,
ClasseX, InterfA, InterfB. Du coup, dans un appel typé de fonction, on peut utiliser comme type l’un de ces 4
types pour faire référence à une instance de la classeY.
12.1.23 Accès statique aux méthodes d’une classe au sein de cette classe :
Supposons qu’on soit dans la classe Tata dans une méthode a définie comme statique et qu’on souhaite accéder
à une méthode b non déclarée comme statique, on peut alors y accéder statiquement en écrivant self::b(...).
C’est équivalent à Tata::b(...).
67
12.1.24 autochargement des définitions de classe :
ça se fait en définissant une fonction __autoload($NomClasseACharger). On encapsule alors une instruction
require_once($CheminFichierPHPDeLaClasse) dans le bloc d’exécution de la fonction __autoload. Utilité ?
En fait quand PHP rencontre une classe inconnu, il recours automatiquement alors à la fonction __autoload.
Cette fonction permet de faire un require dynamique en passant l’argument de la classe en argument. Du coup,
plus besoin de faire des listes de require pour chaque fichier de classe, il suffit d’appeler le require du fichier
contenant la classe requise.
Par exemple, supposons que le nom d’une classe soit structuré comme suit ”C_Prefixe_NomClasse” avec
le prefixe étant le type abstrait, interface, final ou normale d’une classe, le code suivant permet d’appeler les
classes qui se trouveraient dans le répertoire Repclasse :
function __autoload($nomclasse)
{
NOTONS QUE CE SYSTEME permet une gestion dynamique des includes plutôt qu’une gestion statique
avec un require sur un fichier classpath.php contenant les require_once de toutes les classes de l’architecture.
Pourquoi ? Parce que contrairement au C++, chaque page php doit être légère car elle est ré-interprété par php
à chaque exécution (càd à chaque chargement de page) et donc il vaut mieux donc faire uniquement les require
des classes nécessaires.
Quand une instance de classe est sauvé dans le tableau superglobale $_SESSION, seul les attributs et le nom de
la classe sont sauvés. ATTENTION : Quand on cherche à récupérer une instance de classe depuis $_SESSION,
la classe récupéré DOIT avoir été déclaré AVANt session_start(); Par ailleurs, si sur une page, la classe n’est
pas déclaré, même si aucun appel n’est fait à l’objet, celui-ci tel qu’enregistré dans $_SESSION perdra sa classe
pour devenir __PHP_Incomplete_Class_Name.
La principale difficulté de la gestion des classes avec les sessions est quand des instance de classes sont
liés à des ressources externes type fichiers, connexion réseau et fichier DOM (Document Object Model?). En
effet, quand l’instance de classe est sauvé dans le fichier de $_SESSION, une photographie de ses valeurs est
sauvegardé, or si d’autres modifs affectent le lien de l’instance avec les ressources externes, la modif du lien n’est
68
pas prise en compte tant que l’instance n’est pas à nouveau sauvé dans $_SESSION. Par ailleurs, la fermeture
ou le refresh de la page web conduit au reload des objets tels qu’ils ont été sauvé la dernière fois en session, et
non suivant leur dernier état avant le refresh ou la fermeture. Pour gérer ces problèmes, php permet de définir
deux fonction __sleep() et __wakeup() qui vont effectuer toutes les opérations nécessaires respectivement à
la sauvegarde et au rechargement d’instances de classes. Ces méthodes seront respectivement appelées par votre
script lors de l’utilisation de serialize() et de unserialize(), ces deux appels étant encapsulés dans les instruction
de sauvegarde et de lecture dans $_SESSION :
LA fonction __sleep DOIT renvoyer un array dont chaque élément est une chaine de caractère correspondant
chacune au nom EXACT d’un attribut de la classe. Si une classe contient trois membres $a, $b et $c et que la
fonction __sleep() est définie comme :
function __sleep()
{
/// instructions de fermetures des connexions aux ressources externes (BDD, fichier externe,DOM etc.)
$DonneesSauvees= array(’a’,’b’);
return $DonneesSauvees;
}
seul les attributs $a et $b récupéreront leur valeur respective quand session_start sera appelé.
function __wakeup()
{
$this->c = 10; /// valeur par défaut de l’attribut dont la valeur n’a pas été sauvé
};
Derrière ce jolie mot ”accessor” se cache très certainement en C++ l’utilisation des template de fonctions...
De la même manière que l’accès aux attributs d’une classe peut être controlé par les fonctions __get et
__set, l’accès aux méthodes d’une classe peut lui aussi être controlé avec la fonction magique __call(). Le
prototype de cette fonction est :
__call($NomDelaFonctionAppelee,$ArgumentsFonction)
Le nom de la fonction appelée n’a pas besoin d’être le nom d’une fonction déjà explicitement défini, il
peut être une chaine qu’on parse de manière à ensuite rediriger l’appel désirée vers la fonction Func désirée.
$ArgumentsFonction est de type array et sert à définir quel(s) argument(s) utiliser avec la fonction Func. Si
l’appel de fonction comporte x arguments, le tableau $ArgumentsFonction les intégrera comme éléments dans
l’ordre d’appel de la fonction.
NOTE : En fait, __call est une sorte de fonction template...
69
12.2 Eléments de Design Patterns en PHP
Honnêtement je m’en cogne un peu à ce stade, il faut juste savoir qu’une classe peut hériter de l’interface native
Iterator. De ce fait, une instance de la classe en question devient manipulable dans une boucle foreach comme
suit :
avec $liste une instance d’une classe implémentant l’interface native iterator.
Une classe implémentant itérateur doit quelque part incorporer :
• un index permettant de parcourir la liste sous-jacente à l’objet ;
• une liste d’éléments avec pour chaque une clef et une valeur ;
Elle doit aussi implémenter les fonctions suivantes :
Note : Faire qu’une classe implémente directement l’interface native iterator n’est pas forcément super dans la
mesure où cela contraint la structure de la classe. il est possible de faire plutôt implémenter la classe Iterator
Aggregate. La classe doit alors seulement fournir l’implémentation de la fonction GetIterator() qui doit renvoyer
un objet de type Iterator, càd un objet implémentant seulement l’interface iterator.
70
12.2.3 Notations d’index : l’interface ArrayAccess
L’héritage de l’interface permet de forcer un objet à se comporter comme un tableau et nécessite l’implémentation
des fonctions suivantes :
• offsetExists($index) : vérifie qu’un élémente existe à l’index indiqué ;
• offsetGet($index) : Getteur de l’élément d’index $index ;
• offsetGet($index, $valeur) : sette l’élément d’index $index à $valeur ;
Il y a un passage sur l’UML et le php. Le seul point intéressant sur le sujet se trouve au chapitre sur les outils
de développement...
Les classes d’introspection sont les suivantes et correspondent chacune à une des structures qu’il est possible
de rencontrer dans du code php :
• ReflectionFunction : permet d’explorer une function ;
71
12.3.1 Introspection de classe :
Pas dur, on crée une instance de ReflectionClass en utilisant le constructeur qui prend en argument le nom de
la classe à explorer :
Reflection::export($ReflecClass)
pour avoir les informations sur la structure de la classe TotoClass. L’affichage est assez claire pour ne pas
avoir besoin de le commenter plus ici...
72
• getProperty($name) : renvoie un instance de ReflectionProperty si la méthode de nom $name existe
dans la classe ciblée. ATTENTION dans le cas contraire, une erreur fatale est produite ;
• getProperties(optional $filter) : renvoie un tableau de ReflectionProperty correspondant aux attributs
de la classe ciblée ; le filtre s’utilise comme pour getMethods avec 4 constantes seulement :IS_STATIC,
IS_PUBLIC, IS_PROTECTED et IS_PRIVATE
• hasConstant($name) : renvoie true si la constante de nom $name existe dans la classe ciblée ;
• getConstants() : renvoie un tableau associatif de toutes les constantes présentes dans la classe ciblée ;
• getConstant($name) : renvoie la valeur de l’entier correspondant à la constante de nom $name. Plante
fatal si $Name n’existe pas ;
• getInterfaces() : renvoie un tableau associatif de ReflectionClass contenant toutes les interfaces implé-
mentées par la classe ciblée ;
• getInterfaceNames() : renvoie un tableau numérique contenant tous les noms des interfaces implémen-
tées par la classe ciblée ;
• getModifiers() : renvoie un entier (qui est en fait un enum) qui correspond aux modificateurs qui
préfixe les déclarations d’attributs, de membres, de function ou de classe (type : abstract protected pour
une méthode abstract protected);
• isInstance($objet) : renvoie true si $objet est une instance de la classe ciblée ;
• newInstance(...) : permet de créer une instance de la classe ciblée. La fonction fait appel à un nombre
variable d’arguments de manière à coller à la fonction __construct appeler de manière sous-jacente.
• newInstanceArgs (array $args ) : pareil en passant les arguments $args élément par élément comme
argument sucessif de __construct. (quelle est l’utilité respective des deux fonctions ?) ;
• getParentClass() : renvoie une instance de ReflexionClass de la classe parent de la classe ciblée si la classe
parente existe, ERREUR FATALE sinon !
• isSubclassOf($class ) : renvoie true si la classe ciblée est une classe dérivée de $class ;
• getStaticProperties() : renvoie un tableau contenant tous les attributs statiques d’une classe ;
• getStaticPropertyValue($AttributName, optional string $Default) : renvoie la valeur de l’attribut statique
de nom $AttributName de la classe ciblée. Effet de l’option ? inconnu ...;
• setStaticPropertyValue(string $AttributName, string $valeur) : sette l’AttributName de la classe ciblée à
$valeur ;
• getDefaultProperties() : renvoie dans un tableau associatif les valeurs par défaut des attributs de la classe
ciblée ainsi que leur nom en clef en face ; (est par défaut un attribut qui est déclaré dans la classe. Un
attribut peut ne pas être par défaut s’il est ajouté de manière sauvage (v. attributs sauvage précédemment)
• isIterateable() : true si la classe ciblée implémente l’interface Iterator ;
73
• implementsInterface($NomInterface) : Renvoie true si la classe ciblée implémente l’interface de nom $in-
terface ;
• getExtension() : renvoie un objet de type ReflexionExtension si la classe ciblée fait partie d’une extension.
• getExtensionName() : renvoie le nom de l’extension à laquelle appartient éventuellement la classe ciblée,
vide si pas classe ciblée pas dans une extension ;
• inNamespace($NameSpaceName) : renvoie true si la classe ciblée appartient au Namespace de nom
$NameSpaceName ;
• getNamespaceName () : renvoie le nom du namespace auquel appartient la classe ciblée, renvoie VIDE si
la classe n’appartient à aucun namespace ;
Pas dur, on crée une instance de ReflectionMethod ou ReflexionFunction basée sur la fonction ciblée, puis la
fonction peut-être exécuté à partir de la classe de réflexion en utilisant la méthode membre invoke.
Exemple :
Le chapitre traite de la lecture, écriture et manipulation de fichiers. Pourquoi il n’est pas arrivé avant, mystère
... Ce chapitre est indispensable à la gestion des flux et au traitement des sockets TCP/IP...
74
– FILE_BINARY Avec ce drapeau, le fichier est lu en mode binaire. C’est la configuration par
défaut et ne peut être utilisé avec FILE_TEXT.
La valeur de $context correspond à une ressource de contexte valide, créée avec la fonction stream_context_create().
Si vous n’avez pas besoin d’utiliser un contexte particulier, vous pouvez ignorer ce paramètre en affectant
la valeur NULL.
La valeur d’offset correspond à la position à partir de laquelle on commence à lire.
La valeur de maxlen correspond à la taille maximal de données à lire.
RENVOIE FALSE si une erreur survient.
• readfile(string $filename, Optional bool $use_include_path, Optional resource $context) :
ouvre un fichier se trouvant à l’adresse $filename et affiche directement son contenu sur la sortie de
flux principale (l’écran), $use_include_path indique si le fichier $filename doit être recherché dans
les répertoires d’include de la directive php.ini include_path, $context identique à la fonction précédente
mais rien n’est précisé ni dans le bouquin, ni sur le site de php.net
• fopen ( string $filename , string $mode [, bool $use_include_path [, resource $context ]] ) :
ouvre le fichier de nom $filename en mode $mode. Ce mode est un des 8 modes suivants auquel on ajoute
un indicateur de traduction de fin de lignes :
75
• file(string $filename, Optional int $flags, Optional resource $context) : ouvre le fichier $filename
et renvoie un tableau dont chaque élément est une ligne du fichier ouvert ; Les flags possibles sont les
suivants :
L’option $context est une ressource de contexte valide, créée avec la fonction stream_context_create(voir
plus loin).
• parse_ini_file(string $filename, Optional bool $process_sections, Optional integer $scan-
ner_mode ) : ouvre le fichier de nom $filename et s’il est bien structuré comme un .ini classique,
renvoie un tableau associatif dont chaque élément contient chacun une directive en clef et sa valeur en
valeur. Attention si une directive est définie comme constante avant l’appel à parse_ini_file par exemple
: define(’session.name’, BGSESSID), la valeur de session.name (PHPSESSID par défaut) sera écrasée par
BGSESSID dans le tableau renvoyée (MAIS PAS DANS LE FICHIER php.ini)
– $process_sections : Si true, le tableau renvoyé est un tableau composée dont chaque sous-tableau
correspond à une sous-section du .ini (une sous-section est signalé par un nom compris entre [] type
[PHP] ou [Xdebug] dans php.ini ;
– $scanner_mode : deux valeurs possibles : INI_SCANNER_NORMAL par défaut et INI_SCANNER_RAW
qui fait que ne sont pas retenus dans le tableau renvoyé les valeurs optionnelles du .ini ouvert; AT-
TENTION INI_SCANNER_RAW peut faire planter l’appel de la fonction...
• fgetcsv(resource $handle, Optional int $length, Optional string $delimiter, Optional string
$enclosure , Optional string $escape ) : permet de lire spécifiquement un fichier csv en lui donnant
le handle récupérée avec l’usage de fopen sur le chemin d’accès au fichier .csv (Note : un .csv formate un
fichier comme un tableau de n ligne et de m colonnes); $lenght correspond à la longueur maximale d’une
ligne du fichier (par défaut l’infini); $delimiter est le caractère de séparation d’une cellule du tableau
.csv à l’autre sur une même ligne (d’où csv : comma separated values), $enclosure spécifie le caractère
de délimitation (par défaut ”), $escape spécifie le caractère d’échappement (par défaut \) ; ATTENTION
fgetcsv lit seulement une ligne du tableau csv à la fois. POUR lire n LIGNES DE SUITE, il faut
appeler n fois la fonction fgetcsv. A chaque appel de fgetcsv, le handle ou pointeur ”bouge”
d’une ligne.
Un exemple d’usage de lecture de tableau et affichage d’un .csv est le suivant :
$handleCSV = fopen($CheminFichierIndice,”rb”);
$csvCAC = fgetcsv($handleCSV,1000);
$row = 0;
/// on récupère les têtes de colonne
$num = count($csvCAC);
76
for ($i= 0;$i<$num;$i++)
{
$TetCol[$i] = $csvCAC[$i];
}
while (($csvCAC = fgetcsv($handleCSV,1000)) !== FALSE)
{
$num = count($csvCAC);
echo ”<p> $num champs à la ligne $row: <br /></p>\n”;
$row++;
for ($c=0; $c < $num; $c++)
{
echo $TetCol[$c].” = ”.$csvCAC[$c] . ”<br />\n”;
}
}
fclose($handleCSV);
• file_put_contents( string $filename , mixed $data, Optional int $flags, Optional resource
$context ) : ouvre un fichier du nom de $filename (écrase le fichier si existant) et écrit $data dedans.
$data doit être soit une string soit un tableau, soit une ressource de flux. Si $data est ressource de flux de
type stream, c’est le buffer restant qui écrit dans le fichier. Les flags peuvent être les suivants et combinés
avec l’opérateur ¦ :
$context peut être une ressource de contexte valide créée avec la fonction stream_context_create().
UTILISER cette fonction revient à utiliser successivement les fonctions fopen(), fwrite(), et fclose().
• filesize($CheminNomFichier) : renvoie la taille du fichier de nom $CheminNomFichier ;
• fscanf() : identique à sscanf sauf que sscanf utilise une chaine de caractère en entrée alors que fscanf
utilise un handle de fichier. fscanf permet d’utiliser une expression régulière pour récupérer une chaine
préformaté (v. chapitre 5) ;
77
• fwrite($handleFichier, $string, Optional $length ) : ecrit la chaine $string dans le fichier ouvert
avec fopen et dont le handle est $handleFichier. Si $Lenght est spécifié, au maximum $Lenght octets
seront écrits (càd min entre mb_strlen($string) et $lenght. ATTENTION : quoiqu’il arrive, un deuxième
appel à fwrite n’écrase pas ce qui a été écrit sur le même fichier dans un premier appel ; ATTENTION :
un appel de fread après fwrite ne renvoie qu’une chaine vide car le pointeur interne de lecture se situe à
la fin du fichier après l’usage de fwrite, il faut repositionner le pointeur avec rewind ou fseek (v.plus bas)
pour lire le contenu du fichier à partir de la position souhaitée. SI LE FICHIER EST ouvert en mode ”a”
ou ”a+”, quelque soit la position du pointeur interne de lecture/écriture, la chaine $string est ajouté en
fin de fichier de sorte que rien n’est écrasé. Pour remplacer un bout du fichier, il faut ouvrir le fichier avec
fopen en mode ”r+”;
• fputs(...) : c’est exactement la même fonction que fwrite, c’est an fait un alias...
• fgetc($handle) : lit et renvoie le caractère sur lequel pointe le pointeur interne puis avance ce pointeur
d’un octet ;
• fgets($handle) : lit et renvoie la ligne courante sur lequel pointe le pointeur interne puis avance ce
pointeur jusqu’à l’octet succédant à la fin de ligne (\n ou \r ou autre suivant OS). Si la ligne courante est
la dernière du fichier, le pointeur pointera sur la fin du fichier ; IMPORTANT : la fonction stream_get_line
fait la même chose mais en mieux !!
• fseek($handle, int $offset, Optional $whence) : modifie la position du pointeur du fichier de handle
$handle. Le pointeur est décalé $Offset octets vers la fin ou le début du fichier suivant la valeur $whence.
$whence a trois valeurs possibles :
– SEEK_SET : valeur par défaut de $whence, dans ce cas, l’exécution de fseek($handleFichier, $Offset)
positionne le pointeur au $OffSet ième octets du fichier en partant du début ;
– SEEK_CUR : positionne à la position courante + $OffSet Octets ;
– SEEK_END : positionne à la fin du fichier décalé de $OffSet Octets (ATTENTION : $OffSet si on
souhaite que le pointeur pointe encore à l’intérieur du fichier);
• ftell($handle) : renvoie la position courante du pointeur dans le fichier dont le handle est $handle.
• feof($Handle) : renvoie true si le pointeur interne du fichier de handle $Handle est à la fin du fichier.
C’est la fonction la plus rapide pour ce boulot.
ATTENTION : Le fait que le pointeur interne tape en dehors du fichier courant NE POSE AUCUN PB.
78
13.1.2 Tampons mémoires et écriture fichiers :
En appelant les fonctions d’écriture précédente, les informations ne sont pas forcément écrites instantanément
dans le fichier cible. PHP utilise un tampon mémoire dans lequel est stocké en premier lieu l’information à
écrire. PHP ne recopie dans le fichier que par paquets ou juste avant la fermeture des fichiers (par exemple, si
fread suit fwrite, le tampon mémoire est écrit dans le fichier avant l’exécution de fread).
Cependant on peut :
• forcer PHP à écrire avec l’instruction fflush($Handle) qui va vider le tampon et écrire son contenu dans
le fichier dont le handle est $Handle ;
• setter la taille du buffer avec set_file_buffer($FileHandle, $BufferEnOctets) ou stream_set_write_buffer($F
$BufferEnOctets)
La fonction flock() :
• flock($HandleFichier, $Operation) : locke le fichier de handle $HandleFichier suivant le mode $Op-
eration retenu. Les modes possibles sont :
– LOCK_SH : donne un verrou partagé en lecture (n clients peuvent ainsi accéder au fichier ciblé) ;
– LOCK_EX : donne un verrou exclusif en écriture ( 1 seul client sur le fichier en écriture)
– LOCK_UN : délocke le fichier s’il était locké.
A noter que fclose équivaut à unlocker le fichier comme si flock(.,LOCK_UN) avait été appelé.
ATTENTION comme flock est appelé après fopen. Si l’ouverture se fait en mode w ou w+, le fichier est
tronqué à l’ouverture et dans ce cas, deux clients peuvent éventuellement se trouver à lire et surtout écrire
en même temps. LE BOUQUIN en parle page 327 -328 MAIS CE N’EST ABSOLUMENT PAS CLAIR.
GROS HIC, le verrouillage n’est valable que sur un processus et apparemment sur Apache sous Windows,
le recours aux multi-threads empêchent un verrouillage efficace.
VOIR COMMENT GERER LE PB !!!!
79
• ftruncate() : permet de gérer plus finement le pb des accès concurrents en écriture. RECHERCHE A
FAIRE.
Fichiers temporaires :
On peut créer des fichiers temporaires qui seront stockés dans le répertoire temporaire et seront automa-
tiquement détruits à la fin du script :
• tmpfile() : crée un fichier temporaire et renvoie le handle correspondant ;
• tempnam(string $Dir, string $prefix) : Crée un fichier temporaire dans le répertoire $Dir. Le nom du
fichier commencera par la chaine $prefix. Renvoie le nom et le chemin absolu complet du fichier
et non son handle. ATTENTION : sous Windows, le prefix sera limité à trois caractères et $prefix sera
amputé des caractères surnuméraires si besoin est !
• sys_get_temp_dir() : renvoie le chemin du repertoire tmp du système ;
80
13.1.7 Gestion des répertoires :
Un répertoire est en fait un fichier classique avec quelques caractéristiques propres mais en tant que fichier, il
est donc manipulable comme n’importe quel autre fichier. Pour identifier un fichier en tant que répertoire, on
peut utiliser la fonction is_dir() :
• is_dir($FileName) : renvoie true si $FileName est un répertoire, false sinon ;
• is_file($FileName) : renvoie true si $FileName est un fichier, false sinon. Renvoie false si $FileName
est un répertoire ;
• mkdir( string $pathname, Optional int $mode, Optional bool $recursive, Optional resource
$context) : Crée le répertoire correspondant au chemin $pathname. L’option $mode régule les droits
d’accès au répertoire crée. ATTENTION : l’option $mode est ignorée sur Windows de sorte que le répertoire
crée l’est toujours avec les droits d’accès les plus laches (tout le monde a accès au répertoire crée), L’option
$Recursive permet de demander la création des répertoires parents présents dans le chemin $pathname
s’il n’existe pas. $context correspond à la notion de context qu’on verra plus loin (Grrr...)
• rmdir( string $dirname, Optional resource $context ) : flingue le répertoire dont le nom est
$dirname. L’option sera vu plus tard...
Parcourir un répertoire Deux approches permettent de manipuler les répertoires, la première est une
approche fonctionnelle basée sur les fonctions opendir(), readdir, rewinddir(), et closedir() :
• opendir(string $path, Optional resource $context ) : ouvre le répertoire dont le chemin est $path
et renvoie un handler dessus ; Pour l’option, on verra plus tard.
• readdir(Optional handle $dir_handle ) : Lit les fichiers un par un dans le dernier répertoire ouvert
avec l’instruction opendir, et lit sinon dans le répertoire dont le handler est $dir_handle ; Un appel à
read_dir() renvoie le nom du fichier en cours de lecture et false dès que tous les fichiers dans le répertoire
cible ont déjà été lus. L’ordre de lecture est l’ordre dans lequel les fichiers ont été enregistrés dans le
répertoire. ATTENTION : parmi ces fichiers, on trouve les répertoires contenus dans le répertoire cible
et on trouve notamment deux répertoires spéciaux qui sont ”.” et ”..” qui correspondent respectivement
au répertoire cible lui-même et à son répertoire parent. NOTE : readdir utilise un pointeur interne qui
désigne à chaque appel de readdir le fichier suivant. De ce fait, une fois un fichier appelé, il est impossible
de revenir dessus avec seulement des appels de readdir. Le pointeur interne ne fait qu’avancer avec readdir.
NOTE : le pointeur interne est en fait crée par la fonction opendir.
• rewinddir( handler $dir_handle ) : une suite d’appel à readdir fait qu’un fichier contenu dans le
répertoire cible ne sera jamais lu qu’une fois. rewinddir() permet de faire revenir le pointeur interne au
début de la liste des fichiers du répertoire cible ;
• closedir( handler $dir_handle ) : fermer le répertoire désigné par le handle $dir_handle et ouvert
avec opendir ;
Une approche est d’avoir à un objet de type Directory avec l’instruction dir qui renvoie un tel objet.
81
• dir($PathName, Optional ressource $context) : renvoie un objet de type directory correspondant
au répertoire de chemin $PathName. ATTENTION : si le chemin n’est pas valide, un warning est affiché
et l’exécution du script est arrêté !! Il faut donc utiliser file_exists avant pour s’assurer que le répertoire
existe .
Cet objet a alors comme méthodes : read(), rewind(), close() qui ont les mêmes prototypes que les fonctions
précédentes correspondantes à ceci près qu’il est inutile de spécifier le handle vu qu’il s’agit de l’objet sur lesquel
les méthodes sont appelées...
• Chdir($NewCurDir) : renvoie true si la fonction est parvenue à faire en sorte que le répertoire courant
est le répertoire $NewCurDir ; ATTENTION : Le changement de répertoire courant n’est valide que
jusqu’à la fin du script, ensuite le répertoire courant redevient celui spécifiée par la directive docroot ;
82
Informations sur les fichiers : Le truc à savoir c’est que la récup d’informations sur les fichiers est couteuse
en perf pour php et donc celui-ci garde en fait un max d’infos en cache et ressert l’info stocké en cache pour
répondre à des demandes d’informations sur les fichiers. De ce fait, si on veut être sur que les informations
ne sont pas datées, il faut appeler la fonction clearstatcache. Concrêtement le résultat d’un premier appel
à une fonction d’information (dont la liste suit) est stocké dans le cache. Suite à un second appel, php ressert
alors le résultat stocké et ne réexécute pas la fonction de récup d’info elle-même. Les fonctions impactées sont
: stat(), lstat(), file_exists(), is_writable(), is_readable(), is_executable(), is_file(), is_dir(),
is_link(), filectime(), fileatime(), filemtime(), fileinode(), filegroup(), fileowner(), filesize(), file-
type(), et fileperms().
• clearstatcache(Optional bool $clear_realpath_cache, Optional string $filename ) : Sans op-
tions, vide tout le cache php d’informations sur le système de fichiers, si $clear_realpath_name vaut true,
nettoie le cache réel (?), si $filename est aussi spécifié et que la première option vaut true, seul le cache
d’informations concernant le fichier de nom $filename est vidé ;
Les fonctions impactées (en dehors de celles déjà vues) :
• file_exists($filename) : renvoie true si le fichier, répertoire OU le lien $filename existe, false sinon
• stat($filename) : renvoie un tableau associatif contenant des infos sur le fichier ciblé. Chaque info est
stocké dans ce tableau. Une fois avec une clef numérique car la première version de cette fonction renvoyait
un tableau classique et une autre fois avec une clef associative car la nouvelle version de la fonction autorise
de récupérer les infos en utilisant des clefs associatives plus intuitives que les clefs numériques. De ce fait,
en plus de retourner ces attributs dans un tableau numérique, les infos peuvent être lues à l’aide de leurs
indices, tels que notés près de chacun des paramètres. Les infos contenus dans le tableau sont les suivantes
:Numéro Nom (depuis PHP 4.0.6) Description
– 0 dev volume
– 1 ino Numéro d’inode (*)
– 2 mode droit d’accès à l’inode
– 3 nlink nombre de liens
– 4 uid userid du propriétaire (*)
– 5 gid groupid du propriétaire (*)
– 6 rdev type du volume, si le volume est une inode
– 7 size taille en octets
– 8 atime date de dernier accès (Unix timestamp)
– 9 mtime date de dernière modification (Unix timestamp)
– 10 ctime date de dernier changement d’inode (Unix timestamp)
– 11 blksize taille de bloc (**)
– 12 blocks nombre de blocs alloués (**)
83
• lstat() : fait pareil que stat sauf que lstat récupère des infos sur le lien symbolique et non sur le lien
physique s’il y a une différence. Ex : si on fait un stat sur un raccourci pointant sur un fichier, on obtiendra
des infos sur le fichier avec stat, et on obtiendra des infos sur le raccourci avec lstat ; PROBLEME : lstat
et stat ne marchent pas sur les raccourcis de fichiers sous Windows VERIFIER.
Les dates associées aux fichiers : Trois dates sont associées à chaque fichier : date de création, date de
modifcation (dernier accès en écriture seule), date de dernier accès (lecture, écriture ou exécution)
• filectime($filename) : renvoie la date de création du fichier sous forme de timestamp (ATTENTION :
sous la plupart des systèmes UNIX, il n’y a pas de date de création et c’est alors la date de modif qui est
renvoyé) ;
• filemtime($filename) : renvoie la dernière date de modification du fichier sous forme de timestamp
UNIX (utiliser la fonction date pour récupérer un format de date classique) ;
• fileatime($filename) : renvoie la dernière date d’accès au fichier sous forme de timestamp UNIX.
ATTENTION : pour motif de perf, la traque de la dernière date d’accès est souvent désactivée sur les
serveurs...
Autres fonctions :
• filesize($Nomfichier) : renvoie la taille en octets du fichier ciblé ;
• fileinode($NomFichier) : renvoie l’id du fichier sur le disque, càd l’inode et renvoie false si un problème
survient ; VERIFIER si ça marche sur Windows car renvoie toujours 0 ( et ce n’est pas égale à false)
• fstat(...) : pareil que stat mais prend un handle de fichier en argument au lieu d’un nom de fichier ;
• disk_free_space($path) : renvoie en octets l’espace disque disponible sur la partition auquel appartient
le chemin $path ; (marche pas avec les fichiers distants)
• disk_total_space($path) : pareil mais renvoie l’espace disque total dispo et non dispo ;
• realpath($CheminVersFichier) : renvoie le chemin absolu correspondant à l’adresse $CheminVers-
Fichier, utile quand cette dernière est une adresse relative ou un lien symbolique ;
• dirname($CheminVersFichier) : renvoie la partie chemin contenu dans l’adresse $CheminVersFichier
(en clair tout le chemin sauf le nom du fichier lui-même. ATTENTION : renvoie le chemin relatif amputé
du nom dans le cas d’un chemin relatif ;
• basename($CheminVersFichier) : fait l’inverse de dirname, càd renvoie le nom du fichier contenu
dans le chemin (avec le suffixe type .php ou .xls) ;
• pathinfo($CheminVersFichier, Optional int $options) : renvoie un tableau associatif contenant le
dirname (comme un appel à dirname()), le basename (comme un appel à basename()), l’extensionname
(ex : php ou xls càd sans le ”.” comme dans .php) et le filename (comme basename mais sans le suffixe type
.php ou .xls) ; Options est une composition de constantes entières avec | . Les constantes possibles sont :
PATHINFO_DIRNAME, PATHINFO_BASENAME, PATHINFO_EXTENSION et PATHINFO_FILENAME.
Par défaut, tous les éléments sont retournés. ATTENTION si Options est utilisé et que toutes les infos ne
sont pas demandés, c’est une chaine de caractère qui est renvoyé et non plus un tableau... un peu débile
de changer le type de retour, non ? LA chaine de retour renvoyée dépend des options choisies. Rien de
vraiment intéressant et un peu bizarre dans le comportement dans ce cas d’ailleurs...
• readlink() : FONCTION PAS IMPLEMENTEE SOUS WINDOWS !!
84
Permissions et droits d’accès sur fichiers : Un fichier a un propriétaire utilisateur et groupe, des droits
d’exécution, de lecture, et de modification. Pour récupérer les droits associées, on utilise :
• fileperms($filename) : renvoie les droits associées au fichier, répertoire ou autre lien de nom $filename.
ATTENTION : la valeur renvoyé est une valeur numérique qui doit être analysé pour récupérer réellement
l’info. Le code suivant utilise le retour de fileperms pour renvoyer une chaine décrivant le type de l’objet
associé au filename (”l” : lien symbolique, ’-’ : régulier (càd un fichier normal), ’b’ : bloc spécial, ’d’
: dossier, ’c’ :caractère spécial, ’p’ : PIPE info et ’u’ : unknown) et pour l’user courant, le group user
courant et les autres users, les droits en lecture (r), écriture (w) et exécution (x) sur le fichier ciblé.
Quand l’utilisateur courant, le groupe utilisateur de l’utilisateur courant, ou les autres users n’a pas un
droit donné, on trouvera dans la chaine le symbole ’-’ à la place de ’r’,’w’ ou ’x’ ;
Gestion des droits sous windows : La gestion des droits sous Unix est gérée avec chmod alors que sous
windows, c’est géré avec le système ACL (Acess Control List) et en pratique l’appli native windows ICACLS
(ou CACLS pour les versions de Windows antérieure à Vista) appelé en ligne de commande permet d’officier.
Il faut donc exécuter icacls sous php pour gérer les droits windows :
85
Cacls cacls est l’instruction shell utilisable en ligne de commande sous windows pour gérer les droits sur
les fichiers et répertoires. Elle est appelée avec shell_exec(”cacls suite de l’instruction) : La doc issue du site de
microsoft est plutôt bien faite :
86
87
88
89
ATTENTION : l’instruction cacls est considéré comme DEPRECATED et Mircosoft recommande l’usage
de icacls à la place !
La commande icacls avec shell_exec : Depuis Vista, la gestion des droits a encore été raffiné sous
windows par rapport à cacls (cette dernière instruction reste toutefois utilisable). La doc microsoft sur icacls
est aussi très bien faite :
90
91
92
93
94
95
96
Le site de Microsoft peut être consulté au besoin pour avoir accès au forum des commandes CACLS et
ICACLS :
http://technet.microsoft.com/en-us/library/cc753525%28WS.10%29.aspx#BKMK_examples
Le bout de code suivant permet de récupérer les droits d’utilisateur associés à un fichier donné :
$FilePath = ”CheminFichier”; /// on stocke le chemin du fichier
$command = ”icacls CheminFichier”; /// on prépare la commande d’appel de l’appli icacls
exec($Command, $FilePath); /// on exécute la commande définie
foreach($Result as $Key => $Value)
{
if (left($Value,1) != ” ”)
{
$Message = ” ”;
for ($i = mb_strlen($Value);$i>0;$i–)
{
if (mid($Value,$i,1)== ” ” && $Message ==” ”)
$Message = right($Value,mb_strlen($Value)-i);
}
}
else
{
$Message = trim($Value);
}
echo ”<br>”.$Message;
}
• Les sockets TCP/IP permettant d’ouvrir des connexions vers la plupart des services réseaux : serveurs
webs, DNS, services web, etc.)
• Avec Interaction : PHP échange des données pendant l’exécution du prgm externe ;
97
14.1.1 Exécution de prgm externes sans interaction :
Programme en tache de fond : Il s’agit de déconnecter le fonctionnement d’un script des processus appelés
via l’instruction exec ou system. Pour ça, il faut rediriger les flux de sortie et les flux standard. Par ailleurs,
en temps normal la fin de php implique la fermeture des programmes fils appelées avec exec ou system. Dans
un config de web serveur Apache, Apache redémarre tous ses programmes fils au bout d’un certain nombre de
requêtes. Pour éviter la terminaison non sollicitée de programmes appelées par exec, il faut utiliser l’instruction
nohup dans la commande appelée par exec ou system.
Exemple : nohup ”/etc/initd/apache startssl” >/dev/null 2>&1
Ce que dit le bouquin indirectement sur le sujet : les UTILISATEURS DE WINDOWS PEUVENT ALLER
SE FAIRE VOIR !!!
A COMPLETER : comment lancer un programme déconnecté de php en tache de fond (et comment le
killer !!)
ATTENTION : partant de cette base, un programme peut avoir plusieurs flux d’un même type. Les flux 0,
1 et 2 sont alors ceux d’input, d’output et d’erreur et les suivants (3,4 etc.) seront d’input ou d’output suivant
ce qu’il a été spécifié dans la conception du prgm...
98
Ouverture des flux : Les flux d’un programme peuvent s’ouvrir individuellement et indépendament les uns
des autres de sorte qu’il est possible d’être seulement à l’écoute pour un prgm (flux output) et seulement en
écriture pour un autre (flux input).
• popen($Commande, $Mode) : ouvre le flux d’écriture ou de lecture du programme appelé par $Com-
mande suivant le $Mode choisie :
• proc_open($Commande,
$DescriptorSpec,
$Pipes,
Optional $cwd,
Optional $TabEnv,
Optional $ArrayOptions) : Exécute une commande et ouvre les pointeurs de
fichiers pour les entrées / sorties. Concrêtement cela signifie que PHP va exécuter le prgm désigné par
$Commande et va ensuite associé à chaque flux du programme soit rien, soit un fichier, soit un pipe. Dans
le cas de fichier, le flux correspondant du prgm est écrit dans le fichier désigné dans le tableau associatif
$DescriptorSpec. Dans le cas d’un pipe, le flux correspondant est un flux de données directe entre le
processus fils càd le prgm désigné par $Commande et le processus père càd PHP. La fonction renvoie une
ressource ou handler sur le prgm désigné par commande. Par ailleur $Pipes correspond au tableau des
handlers pointant sur les flux tels qu’utilisé par le processus père càd PHP. Voilà pour le principe général,
en détail :
– $DescriptorSpec indique comment le processus fils va diriger ses flux d’input, d’output et d’erreur
: Cette variable est alors un tableau dont chaque élément a pour clef le numéro du flux (0 pour input,
1 pour écriture, 2 pour le flux d’erreur et les entiers suivants pour les autres flux) tandis que la valeur
correspond à un sous-tableau indiquant comment le flux du prgm fils est redirigé : nulle part, vers
un fichier ou vers un flux directement récupéré par le prgm père :
Un exemple est alors :
$Descriptor = array( ’0’ => array(’file’, ’BernardGourionDirectory/Info.bg’,’r’) ,
’1’ => array(’pipe’, ’w’) ,
’2’ => array(’pipe’,’w’))
/// l’input du prgm fils est à diriger par le prgm dans le fichier ’Info.bg’ du répertoire BernardGou-
rionDirectory où le prgm a le droit de lecture.
/// l’output du prgm fils est à diriger dans un pipe (ou flux) direct vers le prgm père càd ici PHP.
/// le flux d’erreur du prgm fils est à diriger dans un pipe (ou flux) direct vers le prgm père càd ici
PHP. ATTENTION quand le flux d’erreur du prgm fils est redirigé dans un pipe, il est apparemment
préférable de le faire en mode ’a’ append qu’en mode ’w’ sous peine d’erreur.
– $pipes : il s’agit d’un tableau des descripteurs des flux crées par proc_open et dont va pouvoir se
servir PHP ( le processus père) pour interagir avec le prgm appelé par la commande $Commande.
Chaque valeur d’un élément du tableau correspond au handler associé dans l’ordre au flux défini dans
99
$Descriptor. ATTENTION : ce tableau ne contient que les descripteurs des flux (pipes) crées. Les
fichiers crées ne font pas partie de ce tableau. En fait, vu qu’on a le nom des fichiers, suffit de les
ouvrir avec fopen ou autre fonction.
– $cwd : option qui permet de spécifier le dossier initial de travail de la commande. Cela doit être
un chemin absolu vers le dossier ou NULL si vous voulez utiliser la valeur par défaut (le dossier de
travail du processus courant PHP) ;
– $TabEnv : Un tableau contenant les variables d’environnement pour la commande qui doit être
exécutée, ou NULL pour utiliser le même environnement que le processus PHP courant ;
– $ArrayOptions : Vous permet de spécifier des options supplémentaires. Les options actuellement
supportées sont :
∗ suppress_errors (windows uniquement): suppression des erreurs générées par cette fonction
lorsque définit à TRUE ;
∗ bypass_shell (windows uniquement): bypass du shell cmd.exe lorsque définit à TRUE ;
∗ context: contexte du flux utilisé lors de l’ouverture des fichiers (créé avec la fonction stream_context_create())
∗ binary_pipes: ouverture des pipes en mode binaire, au lieu d’utiliser l’encodage habituel stream_encoding
ATTENTION il faut impérativement fournir une variable dans lequel stocké le retour de proc_open sinon
il sera impossible de récupérer les flux.
IMPORTANT : les commentaires de la fonction proc_open du site http://php.net/manual/fr/function.proc-
open.php proposent quelques classes et bout de code notamment :
– 1. Deux classes ProcessManager et Process qui permet de gérer simultanément plusieurs processes
ouverts avec proc_open ;
2. Un code permettant de récupérer les flux de sortie et d’erreur en temps réel ;
3. Une méthode pour gérer des processus vivants en même temps que PHP continue d’exécuter le
reste de ces scripts...
• proc_get_status($HandlerProgramme) : Renvoie un tableau associatif d’informations sur le pro-
cessus dont le handler a été passé en argument. Le tableau renvoyé comporte les clefs et valeurs associées
suivantes :
100
Fermeture d’un processus ouvert avec proc_open : A l’issue de l’appel de proc_open, suivant le
descripteur $DescriptorSpec passé en argument, un ou plusieurs flux ont été ouverts pour communication
directe entre le processus père php et le processus fils. Avant de fermer le processus fils appelé par l’argument
$Commande de proc_open proprement dit, il faut fermer les flux qui ont été ouvert avec pclose avant
d’appeler proc_close pour flinguer le processus lui-même.
• pclose($HandlerPipe) : ferme le flux dont le handler est $HandlerPipe ; les flux ouverts par proc_open
sont listés dans le 3ième argument de proc_open ;
• proc_close($HandlerPrgm) : ferme le processus dont le handler est $HandlerPrgm.
Protéger le recours à appels de programmes externes par un client : Lorsqu’un appel à un programme
externe est à l’initiative du client avec possibilité pour lui de passer son instruction, il est clair qu’il faut être
prudent et pour cela deux fonctions permettent d’incorporer un filtrage de l’instruction passé par le client :
• la directive safe_mode_exec_dir de php.ini permet de spécifier une liste de répertoires dans lesquels
se trouvent les seuls programmes utilisables ;
• ATTENTION : dès lors qu’un programme externe est appelé, celui-ci n’a pas les limitations imposées par
Apache ou php, et la directive safe_mode_exec_dir est donc particulièrement importante pour empêcher
l’exécution de programmes dont on ne connait pas le comportement.
Pour communiquer avec des services TCP/IP comme les serveurs web ou telnet, il faut que php ouvre une socket
réseau. (socket veut dire connexion en anglais)
Une socket réseau est une connexion réseau qui peut être de type :
101
• TCP : càd une connexion permanente entre php et la cible ;
• UDP : une connexion ”non connecté” càd que l’adresse de destination doit être spécifié à chaque envoi car
kekpart on se reconnecte à chaque envoi. C’est un peu analogue à des envois de courriers physiques.
Enfin par défaut, les sockets sont ouvertes en mode bloquant, ce qui signifie que PHp attend que les données
à lire arrivent de la socket, ou que le socket soit close avant de rendre la main pour la suite de l’exécution du
script.
L’autre mode est le mode non-bloquant qui permet alors d’ouvrir la socket, de la consulter pour savoir si de
nouvelles données sont disponibles et de continuer le script quoiqu’il arrive. Quelque part dans ce cas, on gère
les lecture successives en attente de données à l’aide d’un boucle.
– La chaine $hostname doit correspondre à une adresse IP ou une adresse réseau type www.php.net.
On peut par ailleurs préfixer cette chaine par la chaine ”ssl://” ou ”tls://” qui sont équivalents tous
les deux et correspondent à un protocole de sécurisation des échanges sur internet. Par défaut, le
protocole est ”http://”. A noter que le ”tls” est une évolution de ”ssl” en 2001 ;
– Si le port $port est spécifié, la connexion se fera sur la machine où php réside sur le port indiqué ;
– $errno : Si fourni, contient le numéro de l’erreur système qui survient lors de l’appel système à
connect(). Si la valeur retournée par errno est 0 et que la fonction retourne FALSE, ce peut être une
indication laissant penser que l’erreur est survenue avant l’appel à connect(). La plupart du temps,
cela est du à un problème d’initialisation du socket.
– $errstr : Si fourni permet de récupérer l’éventuelmessage d’erreur sous la forme d’une chaîne de
caractères. Cette chaine est alors encodé en ASCII.
– $timeout : Si fourni permet de spécifier le délai d’attente maximal, en secondes. Si vous avez
besoin de définir un délai limite pour lire/écrire des données à travers cette socket, utilisez la fonction
stream_set_timeout(), comme le paramètre timeout de la fonction fsockopen() uniquement appliqué
lors de la connexion de la socket.
Pour info, la liste des différents modes de transport, format URL, dont PHP dispose en interne pour les
flux qui exploitent les sockets, tels que fsockopen() et stream_socket_client() sont :
– TCP,
– UDP,
– SSL,
– TLS
ATTENTION Ces modes de transport ne s’appliquent pas à l’extension sockets (?).
Renvoie FALSE si l’ouverture de socket a échoué, et un handler (pointeur) si cela a marché ;
102
14.2.2 Gestion du mode d’accès aux sockets
• stream_set_blocking(ressource $Stream, int $mode) : sette le mode d’accès au handler $Stream
au mode $mode). Le mode est non-bloquant si $mode vaut 0 (et pas FALSE attention) (càd php lit
le flux mais poursuit son exécution même en cas d’absence réponse, et il est bloquant si le $mode vaut
1 (et pas true);
• feof(ressource $Stream) : permet de savoir si des données peuvent encore arriver du flux dont le handler
est $Stream; renvoie true si plus aucune donnée ne peut arriver, false sinon ; L’utilisation de cette fonction
est plus subtile qu’il n’y parait. Quand la lecture du flux implique de lire le dernier caractère du flux, cela
n’implique pas qu’un appel consécutif renvoie true. Pour cela, il faut chercher à lire une nouvelle fois le
flux de sorte que le pointeur sur le flux dépasse le caractère final du flux. Ce n’est alors que dans cette
situation que feof retourne bien TRUE.
ATTENTION il faut que le pointeur (ou handler) $Stream soit valide pour que feof puisse renvoyer TRUE.
En effet, en cas d’erreur de ce type, feof renvoie false au lieu de true. Sinon le comportement général de
la fonction feof est retourner TRUE si le pointeur handle est à la fin du fichier ou si une erreur survient,
sinon, retourne FALSE.
DERNIERE CHOSE, dans le cas d’une lecture de flux avec une boucle utilisant comme condition de
continuation feof($Flux)===false, du fait que feof ne renvoie false que dans le cas ou le $handler pointe sur
une position strictement postéreure au caractère de fin de flux, il est chaudement recommandé de préférer
une boucle de type do {...}while(feof($Flux)===false) que de type while(feof($Flux)===false)
• stream_set_timeout($SocketHandler, $TimeOut) : fixe la durée en s aude-là de laquelle php
considère que la connexion s’il n’a eu aucune réponse ou donnée durant ce temps ;
– timed_out (booléen) : TRUE si le flux a atteint de délai d’expiration en attendant des données
durant le dernier appel aux fonctions fread() et fgets() ;
– blocked (booléen) : TRUE si le flux est en mode bloquant. Voir aussi stream_set_blocking().
– eof (booléen) : TRUE si le flux a atteint la fin du fichier. Notez que pour les sockets, cette valeur
peut être TRUE même si unread_bytes est non nul. Pour déterminer s’il reste des données à lire,
utilisez plutôt la fonction feof().
– unread_bytes (entier) : le nombre d’octets actuellement placés dans le buffer interne à PHP.
IMPORTANT : Vous ne devriez pas utiliser cette valeur dans un script.
– stream_type(chaîne de caractères) : un nom, qui décrit l’implémentation sous-jacente de flux.
– wrapper_type (chaîne de caractères) : un nom qui décrit le gestionnaire de protocole pour
ce flux. Voyez Liste des protocoles supportés pour plus d’informations sur les gestionnaires (cf
http://fr.php.net/manual/fr/wrappers.php ATTENTION le nombre de gestionnaire de flux
est important et il est possible de définir ses propres protocoles ;
– wrapper_data (mixed) : des données spécifiques au gestionnaire liés à ce flux. Voyez Liste des
protocoles supportés pour plus d’informations sur les gestionnaires et leurs données.
103
– filters(tableau) : un tableau contenant les noms de tous les filtres qui ont été attachés à ce flux.
La documentation sur les filtres peut être trouvée sur l’annexe concernant les filtres.
– mode(chaîne de caractères) : le type d’accès requis pour ce flux ( voir le tableau 1 de la référence
de la fonction fopen())
– seakable(booléen) : si on peut rechercher dans le flux courant.
– uri(chaîne de caractères) : l’URI/nom de fichier associé à ce flux.
Une connection réseau est définie par deux sockets réseau : une pour écouter (recevoir des données), une
sur laquelle on lit des données. Pour créer un connection réseau, on suit les étapes suivantes :
1. On crée la socket sur laquelle on va écouter (socket serveur) ou on va lire (socket client) avec la fonction
socket_create :
$resource socket_create(int $domain , int $type , int $protocol ) : Crée une socket réseau dont
:
• le domaine de communication est spécifié par $domain (AF_INET pour un protocol de type IPv4
càd adresse IP classique en TCP (http ou ssl) ou UDP, AF_INET6 pareil mais avec une adresse
IPv6, AF_UNIX : protocole de communication locale UNIX),
• le type de communication est définie par $type qui peut prendre l’une des valeurs constantes suivantes
:
– SOCK_STREAM : connection basée sur des flux de données ”reliable”, ”full duplex”, ”connection-
based” sans limite de taille, càd le type de socket utilisé par TCP ;
– SOCK_DGRAM : connection basée sur des envois connection-less càd on ne sait pas si l’envoi
de données réussit et la taille données envoyées est fixe càd connu à l’envoi, c’est le type de socket
utilisé par UDP ;
– SOCK_SEQPACKET : fournit une connection à double sens fiable et séquencé pour des data-
grammes de longueur maximale fixe. A client d’une telle connection lit tout le paquet envoyé à
chaque requête de lecture sur ce flux, il ne peut pas lire partiellement un tel flux.
104
– SOCK_RAW : protocole d’accès brut. Ce type de socket peut-être utilisé pour construire manuelle-
ment tout type de protocole de communication ; un usage commun est la requête ICMP (Internet
Control Message Protocol) (comme le simple ping) : En fait, le protocole IP ne gère que les trans-
ferts de données et ne gère pas l’envoi de messages d’erreur. C’est le protocole ICMP qui permet
cela. c’est grâce à ce protocole qu’une machine émettrice peut savoir qu’il y a eu un incident de
réseau. Pour plus de détail, voir le site wiki sur ICMP.
– SOCK_RDM : pratiquement jamais utilisée. Voir le net pour plus d’infos.
• le protocole de communication : ICMP, TCP ou UDP :
– ICMP :The Internet Control Message Protocol is used primarily by gateways and hosts to report
errors in datagram communication. The ”ping” command (present in most modern operating
systems) is an example application of ICMP ;
– UDP : The User Datagram Protocol is a connectionless, unreliable, protocol with fixed record
lengths. Due to these aspects, UDP requires a minimum amount of protocol overhead.
– TCP : The Transmission Control Protocol is a reliable, connection based, stream oriented, full
duplex protocol. TCP guarantees that all data packets will be received in the order in which
they were sent. If any packet is somehow lost during communication, TCP will automatically
retransmit the packet until the destination host acknowledges that packet. For reliability and
performance reasons, the TCP implementation itself decides the appropriate octet boundaries of
the underlying datagram communication layer. Therefore, TCP applications must allow for the
possibility of partial record transmission.
• et renvoie son handler $ressource si la création a été couronnée de succès, FALSE sinon.
IMPORTANT : En cas d’erreur à la création, le code erreur peut être récupérée avec la fonction socket_last_error()
puis transcrite en explication textual avec socket_strerror() ;
2. POUR UNE SOCKET SERVER : On lie la socket crée avec un nom d’adresse avec la fonction socket_bind().
Ce DOIT être fait avant tout appel à socket_listen() :
bool socket_bind ( resource $socket , string $address [, int $port = 0 ] ) : lit la socket de
handler $socket à l’adresse $address. Celle-ci doit alors être une adresse IP ou IPv6 (PAS un nom de
domaine !!) si le domaine de la socket est de type AF_INET ou resp AF_INET6 et de type chemin de
socket de domain UNix si le domaine est de type AF_UNIX. L’option $Port dans le cad AF_INET pour
préciser sur quel port la connexion réseau aura lieu ; RENVOIE true en cas de succès et false sinon, les
deux fonctions socket_last_error et socket_strerror servent à récupérer le message d’erreur éventuel ;
3. POUR UNE SOCKET CLIENT, on connecte la socket de handler $socket à l’adresse $address avec la
connection socket_connect :
bool socket_connect ( resource $socket , string $address [, int $port = 0 ] ) : Fait la connection
entre la $socket et l’adresse $address. Si l’adresse est de type IP ou IPv6, le $port DOIT être spécifié ;
OU
POUR UNE SOCKET SERVER, on met la socket en écoute (càd en attente de connection externe) avec
socket_listen :
bool socket_listen ( resource $socket [, int $backlog = 0 ] ) : après que la création de la socket
$socket avec socket_create et son attachement à une adresse réseau avec socket_bind, on peut la mettre
en écoute de connection. $backlog sert à spécifier combien de requête de connexion peuvent être mises
en attente. S’il y a dépassement, suivant le protocole de communication (?) soit l’émetteur de la requête
reçoit un message d’erreur ECONNREFUSED, soit la requête sera ignorée par le serveur et l’émetteur
pourra réémettre sa requête...
105
POUR RESUMER :
Pour créer une socket client (qui lit des données sur le réseau) :
Pour créer une socket serveur (qui reçoit des données sur le réseau) :
Création d’une socket client : fsockopen et stream_socket_client ont pratiquement le même rôle :
Comme vu auparavant, la fonction fsockopen avait un côté tout en un : elle créait une socket et la con-
nectait à l’adresse spécifiée. Sa seule faiblesse ? son incapacité à créer une socket de connection sécurisée de
type ssl. stream_socket_client fonctionne de manière identique avec un prototype identique à l’exception :
Là je resuce le site php.net car j’en ai marre et de toute manière stream_socket_server encapsule les appels
successifs socket_create, socket_bind, socket_listen :
• local_socket : The type of socket created is determined by the transport specified using standard URL
formatting: transport://target. For Internet Domain sockets (AF_INET) such as TCP and UDP, the
target portion of the remote_socket parameter should consist of a hostname or IP address followed by
a colon and a port number. For Unix domain sockets, the target portion should point to the socket file
on the filesystem. Depending on the environment, Unix domain sockets may not be available. A list
of available transports can be retrieved using stream_get_transports(). See List of Supported Socket
Transports for a list of bulitin transports.
• errno : If the optional errno and errstr arguments are present they will be set to indicate the actual system
level error that occurred in the system-level socket(), bind(), and listen() calls. If the value returned in
errno is 0 and the function returned FALSE, it is an indication that the error occurred before the bind()
call. This is most likely due to a problem initializing the socket. Note that the errno and errstr arguments
will always be passed by reference.
• errstr : See errno description.
106
• flags : A bitmask field which may be set to any combination of socket creation flags. For UDP sockets,
you must use STREAM_SERVER_BIND as the flags parameter.
Une fois le serveur à l’écoute de connexions extérieures avec stream_socket_server ou socket_listen, il faut
que php puisse savoir, côté serveur, si quelqu’un se connecte à la socket server. La fonction stream_socket_accept
sert à cela :
• resource stream_socket_accept ( resource $server_socket [, float $timeout = ini_get(”default_socket_t
[, string &$peername ]] ) : renvoie un handler de socket correspondant à une connexion extérieur sur
le socket $server_socket du serveur, le $timeout correspond au temps qu’à la socket_serveur pour ac-
cepter la connection (?), tandis que $peername correspond à l’adresse du client connecté si le transport le
permet (grosso modo pas le udp) . ATTENTION : il ne faut pas utiliser cette fonction avec une connection
de type UDP.
Pour le UDP, on a :
• string stream_socket_recvfrom ( resource $socket , int $length [, int $flags = 0 [, string
&$address ]] ) : accepts data from a remote socket $socket up to $length bytes, connected or not.
The value of flags can be any combination of the following: STREAM_OOB = > Process OOB (out-
of-band) data. STREAM_PEEK => Retrieve data from the socket, but do not consume the buffer.
Subsequent calls to fread() or stream_socket_recvfrom() will see the same data. If $address is provided
it will be populated with the address of the remote socket. Returns the read data, as a string
• int stream_socket_sendto ( resource $socket , string $data [, int $flags = 0 [, string $address
]] ) : Sends a message to a socket, whether it is connected or not càd Sends the specified data $data
through the socket $socket. $flag peut seulement valoir STREAM_OOB => Process OOB (out-of-
band) data. $address : The address specified when the socket stream was created will be used unless an
alternate address is specified in address. If specified, it must be in dotted quad (or [ipv6]) format. Returns
a result code, as an integer.
J’AI PAS TESTE LE FONCTIONNEMENT DE CES DEUX DERNIERES FONCTIONS... A VRAI
DIRE, JE NE COMPRENDS PAS BIEN LEUR FONCTIONNEMENT...
14.4 Gestion Unifiée des flux (fichiers distants et locaux, sockets, flux) et Stream-
Contexts
En fait, un bon nombre de fonctions d’accès sont utilisables sans distinction avec un flux, un socket réseau, un
fichier distant ou un fichier local.
Par exemple, la fonction fopen s’applique à n’importe quel flux et pas seulement un fichier. Elle peut donc
être utilisé à la place de fsockopen. Par ailleurs, chaque fonction peut accepter un StreamContext
La seule vraie différence est dans la désignation du nom du flux concerné. Le nom a la structure suivante :
transport : //cible : port
transport correspond au protocole d’accès à la cible (fichier local ou distant, socket réseau, flux
d’entrée/sortie de prgms) qui est soit un gestionnaire de flux, soit un gestionnaire de transports
de sockets. Le port n’est spécifié que dans le cas d’accès à des sockets réseaux.
transport peut avoir les valeurs suivantes et suivant la valeur, le type d’accès est limité :
107
• ”file” : la cible est fichier local NOTE : c’est le protocole de transport par défaut si transport vaut ” ”;
• ”compress.zlib” : la cible est un fichier local compressé avec gzip (extension gz). Accès en écriture
append seule ou en lecture seule, jamais les deux en même temps (càd r,a mais pas r+, w ou w+) (ne pas
oublier qu’un accès w écrase le fichier avant de l’ouvrir pour écriture...) ; le module gzip doit être activé
pour que ça marche... Pour effacer des fichiers compressés, il faut utiliser le protocole de transport file
• ”compress.bzip2” : la cible est un fichier local compressé avec gzip (extension bz2). Même type d’accès
que pour zlib ; ATTENTION : le module bzip doit être activé pour que ça marche...
• ”http” : pour accéder à un fichier distant suivant le protocole http. Si l’accès nécessite un nom d’utilisateur
login et mot de passe password, le protocole devient : ”http://login:password@”. Accès en lecture seule
des données de la cible. Par ailleurs, les informations d’en-têtes ne seront disponibles que par le clef
”http_response_header” du tableau renvoyé par un appel à stream_get_meta_data ; Par ailleurs, la
lecture peut être modifié en ce sens qu’il est possible de définir les en-têtes envoyées dans la requête HTTP
via les options de contexte (càd définir un streamcontext) ; Notamment la clef ’method’ spécifie le type
de requête GET ou POST, la clef header permet de spécifier des en-têtes arbitraires et la clef ’content’
contient définit le contenu de la requête (utilisé le plus souvent pour envoyer des informations en POST).
Note : Ce protocole de transport utilise le protocole réseau TCP ;
• ”ftp” : pour accéder à un fichier distant sur un serveur ftp. Si l’accès nécessite un nom d’utilisateur
login et mot de passe password, le protocole devient : ”ftp://login:password@”. Accès en lecture et en
écriture (modes r, w et a) mais pas simultanément en lecture et écriture (w+ et a+). la fonction unlink
peut permettre d’effacer un fichier sur un serveur ftp. Un accès en mode w sera refusé sauf si l’option de
contexte overwrite est présente dans un streamContext à la valeur true. Note : Ce protocole de transport
utilise le protocole réseau TCP;
• ”https” : pour accéder à un fichier distant de manière sécurisée suivant le protocole https. Ce protocole
de transport utilise le protocole réseau SSL ; sinon pareil que ”http” ;
• ”ftps” : pour accéder à un fichier distant de manière sécurisée suivant le protocole ftps. Ce protocole de
transport utilise le protocole réseau SSL ; sinon pareil que ”ftp” ;
• ”tcp://” : permet d’accéder à la socket réseau Cible ; le port doit être spécifié pour l’accès à la cible soit
garanti (sauf dans le cas des sockets UNIX où le port doit toujours valoir 0 A VERIFIER) ; Un appel à
fsockopen équivaut à fopen avec ”tcp://” en protocole de transport ; La cible peut être un DNS ou une
adresse IP ou IPv6 (cette dernière doit alors être écrite entre []) ;
• ”udp://” : pareil que ”tcp://” sauf que la cible est de type UDP (accès distant en mode non connecté) ;
• ”unix://” ou ”udg” : accès à des sockets Unix ;
• ”tls://” et ”ssl://” : ce sont des surcouches du protocole ”tcp://” et en partagent donc les params et
les options. Ces deux protocoles de transport ont cependant des options de context propres (voir les
StreamContext plus bas) :
– l’option verify_peer indique à true que le certificat SSL du client sera analysé et vérifié ;
– allow_self_certificate permet les certificats autosignés ;
– cafile et capath permettent de spécifier un nom de fichier de vérification et le nom du répertoire
contenant ce fichier pour vérification de la certification ;
– local_cert : permet de spécifier l’adresse local (donc chez le client) du certificat à utiliser pour
vérification ;
108
– passphrase : le mot de passe associé à ce certificat ;
– CN_match : permet de vérifier que le common name correspond à un masque défini (???? Voir le
chapitre sur le sécurité ???);
IMPORTANT : si la directive allow_url_fopen est désactivé dans php.ini; Les accès distants ne sont
pas dispos !!
IMPORTANT : pour les protocoles sécurisés soit dispo dans la config php, il faut que le module exten-
sion=php_openssl.dll soit spécifié dans php.ini
• ”php://stdin” : permet d’accéder au flux d’entrée du processus PHP ; Accès en lecture uniquement ; A
notre que c’est un accès bas niveau en ce sens qu’aucun filtrage n’est possible sur les données lues ; il faut
utiliser le protocole de transport php://input pour cela ; ATTENTION UN PEU CONFUS
• ”php://input” : pareil que précédemment sauf qu’on a accès au ”système d’entrée classique” de php et
que les fonctions de filrage de flux d’entrée sont utilisables. php://input permet de lire des données POST
bruts. C’est moins gourmand en mémoire que $HTTP_RAW_POST_DATA et il n’y a pas de directive
spéciale dans php.ini. php://input n’est pas disponible avec enctype=”multipart/form-data” ;
• ”php://stdout” : permet d’accéder au flux de sortie du processus PHP ; Accès en écriture uniquement
; A notre que c’est un accès bas niveau en ce sens qu’aucun filtrage n’est possible sur les données ; il faut
utiliser le protocole de transport php://output pour cela ;
• ”php://output” : pareil que précédemment sauf qu’on a accès au ”système de sortie classique” de php
et que les fonctions de filrage de flux de sortie sont utilisables ; php://output vous permet d’écrire dans
le buffer de sortie, de la même manière que print() et echo().
• ”php://stderr” : idem que ”php://stdout” pour le flux d’erreur de php ;
• ”php://filter” : est une sorte de méta-gestionnaire, prévu pour qui permet l’utilisation de filtre avec les
données d’entrée au moment du démarrage du script. C’est pratique avec des fonctions compactes comme
readfile(), file() et file_get_contents() où il n’y a pas d’opportunité d’appliquer un filtre aux données
lues.Le gestionnaire de php://filter prend les ’paramètres’ suivants dans le ’chemin’. L’utilisation de ce pro-
tocole de transport et la lecture de la page web suivante éclaire bien son utilisation : http://php.net/manual/fr/wrappers
• ”php://memory” : permet d’accéder aux données en mémoire. Une sorte de tas façon C++;
• ”php://temp” : fonctionne de la même façon, mais utilise des fichiers temporaires pour stocker les don-
nées lorsqu’une certaine limite mémoire est atteinte (par défaut, 2 Mo). L’utilisation de ce protocole de
transport et la lecture de la page web suivante éclaire bien son utilisation : http://php.net/manual/fr/wrappers.php.php
IMPORTANT : A propos des protocoles de transport associées à php :
109
110
14.4.1 Liste des protocoles de transport gérés par une version de php :
• stream_get_wrappers() : renvoie la liste des gestionnaires de flux disponibles sur php. Sur ma config
actuel de php :
Array ( [0] => php
[1] => file
[2] => glob
[3] => data
[4] => http
[5] => ftp
[6] => zip
[7] => compress.zlib
[8] => phar )
• stream_get_transports() : Liste les gestionnaires de transports de sockets disponibles ; Sur ma config
actuelle de php : tcp et udp. Les protocoles de transport sécurisés ne sont pas actuellement dispos car
dans php.ini, la ligne concernant le module ssl est en commentaire ;extension=php_openssl.dll
A PROPOS des protocoles de transports sécurisés : If you can’t get the ssl protocol as a registered
transport protocol even though you has add the extension=php_openssl.dll line on php.ini, maybe you
haven’t the libeay32.dll and / or ssleay32.dll files on your installation or in system32 folder.
Une fois, la ligne décommenté et le serveur Apache redémarré, l’appel à stream_get_transports donne :
tcp
udp
ssl
sslv3
sslv2
tls
Lecture et écriture :
• fgetc : v chapitre sur la gestion des fichiers ;
• fgets : idem ; IMPORTANT : la fonction stream_get_line fait la même chose mais en mieux !!
• fread : idem ;
111
• fwrite : idem ;
• feof : v plus haut ;
ainsi que toutes les autres fonctions de lecture/ouverture/gestion de fichiers.
Fonctions de fermeture
• fclose : qui peut fermer tous les types de flux et qui a été vu et revu plus haut ;
112
14.4.3 Fonctions spécifiques d’utilisation des flux
• stream_socket_get_name(resource $handle , bool $want_peer ) : permet de récupérer le nom
du flux de handler $handle. Si $want_peer est false, le nom de la socket locale sera retourné sinon ce
sera le nom de la socket distante ; IMPORTANT : cette fonction renvoie l’adresse IP du flux quand c’est
une socket réseau et une chaine vide quand le flux est autre chose qu’un flux de socket réseau ;
La liste des transports possibles pour désigner un accès à un flux dans transport : //cible : port présentée plus
haut n’est pas limitative car php permet la création de protocoles de transport personnalisé. Ce protocole prend
alors la forme d’une classe devant implémenter la liste des fonctions suivantes :
• stream_open
• stream_close
• stream_read
• stream_writer
• stream_eof
• stream_tell
• stream_seek
• stream_stat
La fonction stream_wrapper_register pour associer un nom à la classe de transport crée. Bizarrement les 8
fonctions précédentes ne font pas partie d’une interface et donc la classe de transport n’a donc pas besoin d’en
implémenter une..
Pour plus détails, lire les pages 374-376 du livre PHP5 avancé...
Et le pire, c’est que ce n’est pas très, très compliqué à comprendre et le bouquin en dit un minimum...
113
14.5.1 Définition :
Les contextes sont des options accompagnant un flux, et sont passés en dernier argument des fonctions de
créations/ouverture de flux comme fopen, stream_socket_client et stream_socket_server. Un context est un
tableau associatif à double entrée (càd un tableau associatif contenant que des tableaux associatif). Un tel
tableau se présente comme suit :
$options = array(
’Abstraction’ =>array( ’NomOption’ = > ValeurOption);
);
par exemple :
$options = array(
’ftp’ =>array( ’overwrite’ = >TRUE);
);
indique que l’option overwrite du protocole d’accès ftp est mis à TRUE (la connexion client a l’autorisation
d’écraser les fichiers se trouvant sur le serveur distant.
114
$severity,
$message,
$message_code,
$bytes_transferred,
$bytes_max)
{
switch($notification_code) {
case STREAM_NOTIFY_RESOLVE:
case STREAM_NOTIFY_AUTH_REQUIRED:
case STREAM_NOTIFY_COMPLETED:
case STREAM_NOTIFY_FAILURE:
case STREAM_NOTIFY_AUTH_RESULT:
var_dump($notification_code, $severity, $message, $message_code, $bytes_transferred,
$bytes_max);
/* Ignore */
break;
case STREAM_NOTIFY_REDIRECTED:
echo ”Being redirected to: ”, $message;
break;
case STREAM_NOTIFY_CONNECT:
echo ”Connected...”;
break;
case STREAM_NOTIFY_FILE_SIZE_IS:
echo ”Got the filesize: ”, $bytes_max;
break;
case STREAM_NOTIFY_MIME_TYPE_IS:
echo ”Found the mime-type: ”, $message;
break;
case STREAM_NOTIFY_PROGRESS:
echo ”Made some progress, downloaded ”, $bytes_transferred, ” so far”;
break;
}
echo ”\n”;
}
$ctx = stream_context_create();
stream_context_set_params($ctx, array(”notification” => ”stream_notification_callback”));
file_get_contents(”http://php.net/contact”, false, $ctx);
?>
A NOTER : Nombreuses sont les fonctions de gestion pouvant accepter des StreamContext ;
115
14.6 Les filtres associés aux fonctions de gestion des flux
Les filtres de flux sont des classes d’objets natifs ou personnalisés qui permettent d’incorporer directement à
la lecture/écriture des flux des filtres de données, et ce de manière transparente. Natif car certains filtres
sont prédéfinis nativement tandis qu’il est possible de créer son propre filtre personnalisé avec une classe
implémentant l’interface php_user_filter. ”transparent” car les appels aux fonctions sur flux avec ou sans
filtres sont strictement les mêmes car l’ajout de filtres de traitement se fait uniquement en utilisant les fonctions
stream_filter_append() et stream_filter_prepend(). Il est possible d’utiliser plusieurs filtres successifs
dans les traitements des flux : par exemple, un premier filtre strtolower suivi d’un string.strip_tags ce qui
signifie que la chaine est d’abord mise en petites lettres puis supprimes les balises html ou hp présents dans la
chaine.
L’ordre des filtres utilisés dépend de l’ordre des deux fonctions stream_filter_append et stream_filter_prepend.
La première fait que le filtre s’applique après les tous les filtres déjà associés au flux géré et la seconde fait au
contraire que le filtre s’applique en premier ;
• resource stream_filter_append ( resource $stream , string $filtername [, int $read_write
[, mixed $params ]] ) : Associe le filtre de nom $filtername au flux $stream. Le filtre s’applique
en dernier par rapport à ceux déjà associés à $stream. Le filtre est associé par défaut pour un accès
en lecture si le flux a été ouvert en lecture, et pour un accès en écriture si le flux a été ouvert comme
telle. $read_write permet alors de forcer le filtrage en lecture (STREAM_FILTER_READ), écriture
(STREAM_FILTER_WRITE) ou les deux (STREAM_FILTER_ALL) ; $params permet d’associer
des valeurs de paramètres au filtre $filtername, maintenant aucun exemple concret... RENVOIE un
handler sur le filtre ajouté ;
• resource stream_filter_prepend ( resource $stream , string $filtername [, int $read_write
[, mixed $params ]] ) : pareil mais ajoute le filtre en tête de liste des filtres ; ATTENTION : si des
données sont présents dans le tampon associé au flux, le filtre ajouté avec stream_filter_prepend NE
SERONT PAS filtrés avec le filtre (précision importante si on ajoute un filtre en cours de lecture/écriture
sur un flux) ;
ATTENTION : Quand l’une ou l’autre de ces fonctions est utilisé pour un ajout en écriture ou en lecture,
c’est comme si le filtre était ajouté deux fois !!. RENVOIE un handler sur le filtre ajouté ;
ATTENTION : chaque filtre de la liste des filtres associés à $stream a son propre tampon mémoire.
la mécanique est que si trois f1, f2 et f3 s’appliquent successivement, le bout de flux filtrée passent
successivement par le tampon de f1, f2 et f3 et en particulier, si un filtre f4 s’ajoute en cours de lecture,
s’il est ajouté après f4, il s’appliquera à ce qui est dans le tampon de f3 alors qu’il ne s’appliquera pas s’il
est ajouté au début avant f1 avec stream_filter_prepend...
• array stream_get_filters() : RENVOIE un tableau de tous les filtres natifs gérés par php. cette liste
dépend aussi des extensions php. Attention, dans la liste, parfois c’est le nom du module d’extension suivi
de ”.*” qui apparait et alors la liste des filtres associés à ce module n’est pas connue directement.
• bool stream_filter_remove ( resource $stream_filter ) : renvoie true si le filtre de handler
$stream_filter a bien été retiré. Attention : pas besoin de spécifier le flux auquel est associé le filtre
à retirer.
IMPORTANT : toute classe de filtre personnalisé doit être ajouté à la liste des filtres reconnus par php avec la
fonction stream_filter_register()
116
La classe implémente l’interface php_user_filter qui contient les méthodes suivantes : filter(), onclose et
oncreate()
• filter($in, $out, &$consomme, $ferme) : convertit la chaine $in en une chaine $out, $Consomme
est le nombre de caractères lus sur le flux, ce paramètre doit être incrémenté du nombre de paramètre
traités en ENTREE, $ferme indique avec TRUE si le flux est sur le point de se fermer càd dans ce cas
que PHP fait son dernier appel au filtre ; RENVOIE un entier enum : PSFS_PASS_ON si la conversion
est successful, PSFS_FEED_ME qui indique que rien n’a été retourné et que le filtre attend des données
supplémentaires avant d’agir (En fait, ça tient qu’à ce stade, les bout de données sont gérés avec des
stream_buckets). PSFS_ERR_FATAL indique une erreur fatale dans le processus ; le filtrage s’arrêtant
alors. Un exemple d’implémentation avec l’utilisation des stream_buckets :
function filter($in, $out, &$consomme, $ferme)
{
// lit une chaine de caractères sur l’entrée et le récupère dans un stream_bucket
while ($donnee = stream_bucket_make_writable($in)
{
// convertit la chaine lue ($donnee->data)
donnee->data = strtoupper($donnee->data);
// ajoute la chaine lue à la sortie
stream_bucket_append($out, $donnee);
return PSFS_PASS_ON;
}
}
• oncreate() : permet de faire les initialisation nécessaires au filtre ; appelé juste avant l’utilisation du
filtre ;
14.6.2 Utilisation des filtres utilisateurs pour les fonctions d’acc ès rapides aux flux :
Certaines fonctions comme file_get_contents ne renvoient aucun descripteur de flux (càd handler de flux). Dans
ce cas, il est possible d’utiliser des fonctions de filtres en spécifiant directement ceux-ci dans l’adresse du flux
ciblé. Une adresse classique s’écrit :
transport://cible:port
117
Insérer le flux se fait ainsi :
php://filter/read=ReadFilter1|ReadFilter2|.../write=WriteFilter1|.../resource=transport://cible:port
ce qui signifie que les filtres ReadFilter1, ReadFilter2 etc. seront appliqués à la lecture du flux tandis que les
filtres WriteFilter1, WriteFilter2 etc. seront appliqués à la lecture du flux. Le flux en question est celui désigné
par resource.
PHP a un flux d’entrée qui est géré en interne par PHP et Apache en second lieu. La gestion du flux de sortie
est par contre elle à la charge de PHP.
• de convertir le contenu du tampon à l’encodage désiré : càd par exemple UTF-8 au lieu de ISO-8859-1
• de récupérer tout ce qui a été envoyé vers le flux de sortie dans une variable. On peut ainsi carrément
empêcher l’envoi vers le flux de sortie en copiant puis en effaçant le contenu du tampon ;
Les fonctions permettant de gérer ce tampon sont les suivantes (on fait juste un rappel car on les a vu plus tôt
):
• ob_start() : démarre la mise en tampon de ce qui serait autrement envoyé à l’affichage ;
• ob_end_clean() : arrête la mise en tampon, et vide le contenu du tampon SANS envoi vers le flux de
sortie ;
118
• ob_end_flush() : pareil mais stope la mise en tampon ;
• on_get_contents() : récupère le contenu du tampon mais ne le vide pas, ni ne l’arrête. C’est une sorte de
copie en somme ;
• ob_clean() : vide le contenu du tampon ;
• ob_get_lenght() : récupère la taille en octets du contenu du tampon mémoire du flux de sortie. Renvoie
FALSE si aucun tampon mémoire n’existe pour le flux de sortie ; Attention en cas d’usage d’un filtre de
compression, la taille renvoyée reste la même car ce qui est compressé, c’est ce qui est envoyé vers le flux
de sortie et non le contenu du tampon.
• ob_get_level() : spécifie le nombre de tampon encore présent.
Des filtes automatiques peuvent s’appliquer au contenu du tampon mémoire sans avoir à récupérer le contenu
du tampon avec ob_get_contents() :
Tout filtre de nom Filtrelambda, automatique ou personnalisé, peut être associé à un tampon mémoire avec la
fonction ob_start() comme suit :
ob_start(’FiltreLambda’);
Le contenu du tampon aura été alors filtré avec le filtre lambda au préalable.
119
15.1.4 Les filtres automatiques du tampon mémoire du flux de sortie de PHP :
Le filtre de compression du module zlib : Un tampon peut être associé au filtre de compression des
données :
Les protocoles de transport http (et https) permettent l’envoi de données compressés pour gagner de la
bande passante. La fonction de filtre associé est ob_gzhandler(). Pour utiliser ce filtre de compression, il faut
appeler ob_start de la façon suivante :
ob_start(”ob_gzhandler”)
Après tous les appels aux autres fonctions ob_kekchose sont identiques pour gérer le tampon crée.
ATTENTION : si la directive zlib.outputcompression vaut ’on’ dans php.ini, toutes les données envoyés
vers le flux d sortie sont déjà compressés par défaut, et ob_start(”ob_gzhandler”) enclenchera pour le tampon
concerné une double compression des données contenues rendant illisibles les données affichées pour le tam-
pon concerné. Par ailleurs, j’ai cherché à provoquer le pb de la double compression en changeant le php.ini
sans toutefois y parvenir... ;-) En fait, c’est normal, c’est impossible d’avoir ob_start(”ob_gzhandler”) avec
zlib.outputcompression à on.
Les filtres de conversion d’un encodage à l’autre : Deux modules permettent d’ajouter un filtre de
conversion d’encodages au fonction de manipulation de flux :
• mbstring
• iconv
Globalement iconv est plus rapide mais nettement moins utile dans la mesure où il gère moins d’encodages que
mbstring. Ce dernier révise aussi certaines fonctions de manipulation de chaines pour prendre en compte les
caractères multi-octets. mbstring est donc notre choix ;
La callback function à associé à ob_start est ”mb_output_handler” (ob_start(”mb_output_handler”)
pour créer un tampon dont toutes les sorties sont converties dans l’encodage cible. L’effet de la fonction de filtrage
dépend alors de la directive mbstring.http_output se trouvant dans php.ini et qui spécifie quel est l’encodage
cible (utf-8 au hasard...). Notons que :
• la conversion a lieu si aucun encodage n’est spécifié dans le header content-type ;
• la directive mbstring.http_output peut être setté dans le script avec ini_set() ;
• ou avec la fonction mb_http_output() :
mb_http_output ([ string $encoding ] ) : Renvoie l’encodage cible courant tel que setté avec
la directive php mbstring.http_output OU sette cette directive à $encoding si cette variable optionnel est
spécifié et RENVOIE TRUE si le changement s’est opéré correctement ou false sinon.
Les filtres utilisateurs Un filtre utilisateur peut être défini comme toute fonction prenant une chaine en
entrée et renvoyant une chaine en sortie. A tout appel de ob_flush() ou ob_end_flush(). Le contenu du tampon
passe en entrée de la fonction utilisateur et la chaine renvoyée par la fonction filtre utilisateur est envoyée vers
le flux de sortie.
IMPORTANT : les filtres appliqués au tampon mémoires sont différents des filtres associés aux fonctions de
gestion des flux. Idéalement il vaut mieux éviter les redondances ou les doubles filtrages malheureux de ce fait.
120
RUSE : si on souhaite cumuler les filtres, on peut aussi bien créer un filtre utilisateur qui appelle deux
autres fonctions de filtrage dans son bloc d’exécution.
La directive output_buffering de php passé à ”on” permet d’activer une mémoire tampon automatiquement
à chaque début de script comme si ob_start avait été appelé. En settant la directive à une valeur entière, on
fixe la taille du tampon utilisé.
ATTENTION : L’usage d’output_buffering revient à un appel automatique de ob_start() et on peut donc
utiliser ob_flush, ob_end_flush, ob_end_clean et ob_clean et cie dessus comme si ces appels étaient précédés
d’un ob_start()
ATTENTION : Dans le cas de l’activation du module de compression zlib (càd en settant zlib.outputcompression
= On), un output buffer se met bien à exister automatiquement mais par contre, cet outputBuffer ne peut pas
être détruit ni vider avec les fonctions ob_machin,on peut juste utiliser flush pour le vider. Du coup, ce buffer
existe jusqu’à la fin du script et PHP se charge de le supprimer tout seul.
IMPORTANTE : Si on souhaite utiliser la compression et l’outputbuffering sans avoir à gérer différemment
l’output buffer implicite lié à la directive output_buffering passé à on, il faut setter :
output_buffering = On,
output_handler = ob_gzhandler ;
zlib.output_compression_level = 6
Un petit chapitre technique et marrant je crois sur l’envoi et la réception de mail en PHP.
On passe sur l’utilité des mails car elle est évidente : entre la lettre d’information automatisé, la disposition
d’une gestionnaire de courrier, le forum (qui est un dérivé des techniques mails) et la validation d’inscription
sur site web.
IMPORTANT : un mail peut être envoyé en format texte ou html mais globalement html fait plus sérieux...
ATTENTION : Plusieurs librairies et modules d’extensions php de gestion de mails existent en php. Nous
allons utiliser IMAP.
Deux directives de configuration sont à setter dans php.ini :
• SMTP = AdresseDuServeurSMTP ; SMTP doit indiquer l’adresse du serveur SMTP du fournisseur d’accès,
càd mail.NomDomaineDuFAI ou smtp.NomDomaineDuFAI ;
• sendmail_from = AdresseMail@parDefaut ; cette directive sert à spécifier l’adresse par défaut de tout
mail envoyé ; (en l’occurrence, pour le moment, chez moi c’est bg@pricingnation.com
121
16.1 Courrier électronique au format texte
NomChamp : ValeurDuChamp
exemple :
From : bg@pricingnation.com Tue Oct 1 12:00:50 2004
To : bernardgourion@yahoo.fr
Date : Wed, 8 Sept 2010 10:54:00 1768
Simple, non ?
– ATTENTION : RFC 822 n’est pas la seule norme gouvernant la structure des mails.
∗ RFC 821 : Simple Mail Transfert Protocol (SMTP)
∗ RFC 822 : Standard for ARPA Internet text messages
∗ RFC 2060 : Internet Message Access Protocol (IMAP)
∗ RFC 1939 : Post Office Protocol Version 3 (POP3)
∗ RFC 2076 : Common Internet Message Headers.
∗ RFC 2045, RFC 2046, RFC 2047, RFC 2048, RFC 2049 : Multipurpose Internet Mail Extensions
(MIME) == > Norme servant à définir les mails au format html incoporant du texte, du son et
de l’image !!
122
comportement, remplacez ces occurrences par un double point. Par exemple tout message devra être
passé par la fonction suivante :
• ATTENTION : envoyer des mails massivement avec la fonction mail est inefficient car pour chaque mail,
la fonction va ouvrir et fermer une socket réseau. Il faut alors utiliser la fonction mail du namespace
PEAR qui est une extension de php.
Pour cela, il faut ajouter dans la variable $header de l’appel de la fonction mail :
123
• ”MIME-Version: X.Y” : qui spécifie le numéro de version X.Y du format MIME (Multipurpose Internet
Mail Extensions). Le numéro de version habituel est 1.0 ;
• ”Content-type: TypeDeContenu” : qui spécifie le type et le sous-type des données contenues dans le
message. Les possibilités sont :
Pour surmonter ces deux limitations, on peut ajouter un champ ”Content-transfer-encoding:” avec pour
valeur ”7bit” dans le header du message. Ce champ permet de spécifier que le mail est codé en 7 bits pour
l’envoi pour ensuite être décodé dans l’encodage spécifié avec le sous-champ charset du champ Content-type.
Normalement quand la messagerie est compatible MIME, c’est totalement transparent... Bref 90 % du temps,
on s’en fouut !
Envoyer un mail au format html : pas dur, il faut setter ”Content-type: text/html” puis écrire le message
124
Envoi de messages dont le content-type vaut multipart/mixed Ce genre de mail est de type MIME.
Le mail doit alors avoir une structure bien particulière : Le début du mail correspond à son en-tête, puis chaque
partie du contenu est elle-même précédé d’un en-tête spécifiant le type de contenu (fichier attaché, image, texte,
ou autre). Chacune de ses en-têtes de partie est précédé de deux lignes : une vide et une contenant un code
délimiteur. Ce délimiteur doit être le même sur tous l’ensemble du message
Tout en-tête ou contenu doit être suivi d’une ligne vide.
Pour envoyer des pièces jointes, il faut convertir la pièce jointe au format RFC 2045 compatible avec le
format MIME.
Pour cela, il faut :
125
• Dans le contenu associé au header précédant, le fichier attaché s’ajoute en demandant l’affichage brutale
de $attache : $msg .= $attache . ”\n”;
Les fonctions utilisés ci-dessus sont :
• string chunk_split ( string $body [, int $chunklen = 76 [, string $end = ”\r\n” ]] ) : Scinde la
chaîne body en segments de chunklen octets de longueur. Cette fonction est très pratique pour convertir
les résultats de base64_encode() au format de la RFC 2045. Elle insère le paramètre end tous les chunklen
caractères. Retourne la chaîne scindée.
• string base64_encode ( string $data ) : Encode data en base64. Cet encodage est fait pour permettre
aux informations binaires d’être manipulées par les systèmes qui ne gèrent pas correctement les 8 bits,
comme les corps de mail. Une chaîne encodée base64 prend environ 33 % de plus que les données initiales.
Pour l’envoi d’un fichier image dans un mail texte, le code suivant peut être utilisé :
function AddPlainTextHeader(&$msg,$delim)
{
/// En-tête de la première partie
$msg .= ”–$delim\n”;
$msg .= ”Content-Type: text/plain; charset=\”utf-8\” \n”;
$msg .= ”Content-Transfer-Encoding:8bit \n”;
$msg .= ”\n”;
}
126
$msg .= $Texte.”\n”;
$msg .= ”\n”;
$attache = file_get_contents($CheminFichier);
$attache = chunk_split(base64_encode($attache));
AddImageHeader($msg,$delim,$CheminFichier);
$msg .= $attache .”\n”;
$msg .= ”\n”;
mail($To,$Subject,$msg,”Reply-to:$Expediteur\nFrom: $Expediteur\nCc: $Cc\nBcc: $Bcc\n”.$header);
}
Maintenant si on veut utiliser du html et insérer l’image dans le html, il faut ajuster le code précédent :
• Dans le header du texte affiché, il faut mettre text/html au lieu de text/plain ;
• pour insérer l’image dans le coeur du message Html, il faut associer le fichier image avec un id html comme
suit :
$msg.= ”Voici l’image : <img src=’cid:IdImage’ alt=\”\” >”;
• Dans la partie concernant l’image à afficher, après la ligne $msg.=”Content-Transfer-Encoding: base64\n”,
il faut ajouter :
$msg .= ”Content-ID: <IdImage>\n”;
Le résultat de cette dernière manip est de lier l’image affiché à la balise img dont l’attribut src vaut IdImage.
ATTENTION si aucun src ne vaut IdImage, l’image est quand même affiché mais comme dans un mail
dont le Content-Type vaut text/plain. Par ailleurs, si l’affichage du fichier n’est pas demandé, même si l’Id est
correctement lié, l’image sera considéré comme fichier attaché et n’apparaitra pas dans le coeur du texte html.
Deux protocoles alternatifs régissent les échanges de mails entre client mail et serveur mail :
• POP3 (Post Office Protocol) : Tous les fichiers mails sont téléchargés intégralement en local sur le client
mail. Les échanges avec le serveur ne sont pas cryptés et dont le login et le mot de passe du client sur le
serveur... Bref ça prend de la place et ce n’est pas safe du tout !! Sans compter qu’il ne peut jamais y
avoir plus d’un client connecté à un même compte.
• IMAP (Internet Mail Access Protocol) : Beaucoup plus souple, ce protocole permet plein de choses dont
le seul téléchargements du sujet des mails, une récupération filtrée etc. etc.
Pour récupérer ses mails stockés sur un serveur distant, il faut ouvrir un flux pointant sur la boite à lettres :
127
[, array $params = NULL ]]] ) : essaie de créer un handler sur le flux
correspondant à la boite mail défini par une adresse du server mail $mailbox(v.plus bas), un username
$username, un mot de passe $password.
ATTENTION : Cette fonction peut aussi être utilisée pour ouvrir des flots sur des serveurs POP3 et
NNTP mais quelques fonctions et fonctionnalités ne sont disponibles qu’avec les serveurs IMAP.
Une attention toute particulière doit être porté à la définition de $mailbox
– $mailbox : C’est une chaine de caractère qui DOIT avoir la forme suivante :
{NomDeServeur:port/protocole/flag}NOMDUREPERTOIREPRINCIPALE
∗ NomDeServeur : cela dépend du serveur hébergeant la boite mail. NomDeServeur a souvent
l’écriture suivante : TypeProtocole.mail.NomDuFAI.fr Par exemple : pop.mail.yahoo.fr est le
nom du serveur de mail de yahoo.fr accessible suivante le protocole pop.
∗ port : difficile de savoir quel est le bon port d’accès à la boite. Pour yahoo.fr, c’est 110...
∗ protocole : smtp, pop3 ou imap.
∗ flag : flag optionnel. La liste des flags possibles est la suivante :
· service=service : pour l’accès à la mailbox, par défaut : ”imap”
· user=user : de l’utilisateur distant pour l’identification sur le serveur
· authuser=user : distance d’identification ; si spécifié, ce sera le nom de l’utilisateur dont
le mot de passe est utilisé (e.g. administrator)
· anonymous : accès distant en anonyme
· debug : télémétrie d’enregistrement du protocole dans les logs de déboguage de l’application
· secure : transmet pas un mot de passe en clair à travers le réseau
· imap, imap2, imap2bis, imap4, ou imap4rev1 : équivalent de /service=imap
· pop3 : équivalent de /service=pop3
· nntp équivalent de /service=nntp
· norsh : pas utiliser rsh ou ssh pour établir une session de pré identification IMAP
· ssl : Secure Socket Layer pour crypter la session
· validate-cert : les certificats depuis le serveur TLS/SSL (c’est le comportement par défaut)
· novalidate-cert : pas valider les certificats depuis le serveur TLS/SSL, nécessaire si le
serveur utilise des certificats auto-signés
· tls : l’utilisation de start-TLS pour chiffrer la session et rejette les connexions aux serveurs
qui ne le supporte pas
· notls : n’utilise pas start-TLS pour chiffrer la session, y compris avec les serveurs qui le
supporte
· readonly : un accès en lecture seule sur mailbox (IMAP uniquement ; ignoré sous NNTP,
et une erreur avec SMTP et POP3)
∗ NOMDUREPERTOIREPRINCIPALE : c’est INBOX dans la plupart des cas...
– $username : le nom d’utilisateur de la messagerie ;
– $password : le mot de passe associé ;
– $Options : options est un masque optionnel de bit vide par défaut , qui peut prendre une ou
plusieurs des valeurs suivantes (on les combine avec |):
∗ * OP_READONLY : Ouvre une boîte aux lettres en lecture seule
∗ * OP_ANONYMOUS : Ne pas utiliser, ou modifier le fichier .newsrc pour les news (NNTP
uniquement)
128
∗ * OP_HALFOPEN : Pour les noms IMAP et NNTP, ouvre une connexion mais n’ouvre pas une
boîte aux lettres.
∗ * CL_EXPUNGE : Supprime automatiquement la boîte aux lettres de la liste, lors de la termi-
naison du flux (voir aussi imap_delete() and imap_expunge())
∗ * OP_DEBUG : négociations de déboguage du protocole
∗ * OP_SHORTCACHE : Cache court (elt uniquement)
∗ * OP_SILENT : Ne pas transmettre les événements (utilisation interne)
∗ * OP_PROTOTYPE : Retourne le prototype du driver
∗ * OP_SECURE : Ne pas effectuer des identifications non sécurisées
– $n_retries : Optionnel, 0 par défaut. Le nombre maximal de tentatives de connexion.
– $params : Paramètres optionnels de connexion ; Un tableau de paramètres dont les clés peuvent
être utilisées pour définir un ou plusieurs paramètres de connexion. La doc php web n’en dit pas plus.
• La liste suivante permet de connaitre les adresses serveur des principaux FAI :
– ∗ 9 Telecom
* Serveur POP : pop.neuf.fr
* Serveur SMTP : smtp.neuf.fr
* Serveur IMAP : imap.neuf.fr
∗ 9ONLINE
* Serveur POP : pop.9online.fr
* Serveur SMTP : smtp.9online.fr
∗ ALICE ADSL
* Serveur POP : pop.alice.fr, pop.aliceadsl.fr
* Serveur SMTP : smtp.alice.fr , smtp.aliceadsl.fr
* Serveur IMAP : imap.aliceadsl.fr
∗ AOL
* Serveur POP : pop.aol.com (port=110)
* Serveur SMTP : smtp.neuf.fr
* Serveur IMAP : imap.fr.aol.com
∗ ALTERN.ORG
* Serveur POP : pop.altern.org ou altern.org
* Serveur SMTP : non
* Serveur IMAP : imap.altern.org (à modifier)
∗ Bouygues BBOX
* Serveur POP : pop3.bbox.fr
* Serveur SMTP : smtp.bbox.fr
* Serveur IMAP : imap4.bbox.fr
∗ Bouygues Télécom
* Serveur POP : pop.bouygtel.fr
* Serveur SMTP : smtp.bouygtel.fr
* Serveur IMAP : imap.bouygtel.fr
∗ CARAMAIL
* Serveur POP : pop.lycos.co.uk
* Serveur SMTP : smtp.lycos.co.uk
* Serveur IMAP : non
129
∗ CEGETEL
* Serveur POP : pop.cegetel.net
* Serveur SMTP : smtp.cegetel.net
* Serveur IMAP : imap.cegetel.net
∗ CLUB INTERNET
* Serveur POP : pop3.club-internet.fr
* Serveur SMTP : mail.club-internet.fr
* Serveur IMAP : imap.club-internet.fr
∗ DARTY BOX (DARTYBOX)
* Serveur POP : pop.dbmail.com
* Serveur SMTP : smtpauth.dbmail.com
* Plus d’informations : o dartybox-news.fr/index.php?/pages/14-configuration-outlook-express
∗ ESTVIDEO COMMUNICATION
* Serveur POP : pop.evhr.net
* Serveur SMTP : smtp.evhr.net
∗ FREE
* Serveur POP : pop.free.fr
* Serveur SMTP : smtp.free.fr
* Serveur IMAP : imap.free.fr
∗ FREESURF
* Serveur POP : pop.freesurf.fr
* Serveur SMTP : smtp.freesurf.fr
* Serveur IMAP : imap.freesurf.fr
∗ GAWAB
* Serveur POP : pop.gawab.com
* Serveur SMTP : smtp.gawab.com
* Serveur IMAP : imap.gawab.com
∗ GMAIL
* Serveur POP : pop.gmail.com (avec port 995 et /ssl en flag de connection. Eventuellement sur
activation de l’option POP de GMail)
* Serveur SMTP : smtp.gmail.com
* Serveur IMAP : imap.gmail.com
* Plus d’informations : o http://gmail.google.com/support/bin/answer.py?answer=10350
∗ HOTMAIL
* Serveur POP : pop3.live.com (Port 995 avec connexion SSL)
* Serveur SMTP : smtp.live.com (Port 25 avec connexion SSL)
* Serveur IMAP : non
* Plus d’informations : o Relever sa boîte Hotmail avec un logiciel de messagerie o Marche à
suivre pour configurer Mozilla Thunderbird avec Hotmail)
∗ IFrance
* Serveur POP : pop.ifrance.com
* Serveur SMTP : smtp.ifrance.com
* Serveur IMAP : non
∗ LA POSTE
* Serveur POP : pop.laposte.net
* Serveur SMTP : smtp.laposte.net
* Serveur IMAP : imap.laposte.net
∗ MAGIC ONLINE
130
* Serveur POP : pop2.magic.fr
* Serveur SMTP : smtp.magic.fr
* Serveur IMAP : non
∗ NERIM
* Serveur POP : pop.nerim.net
* Serveur SMTP : smtp.nerim.net
∗ NET COURRIER
* Serveur POP : mail.netcourrier.com
* Serveur SMTP : idem que celui de votre FAI
* Serveur IMAP : mail.netcourrier.com
∗ NOOS
* Serveur POP : pop.noos.fr
* Serveur SMTP : mail.noos.fr
* Serveur IMAP : imap.noos.fr
∗ Numéricable
* Serveur POP : pop.numericable.fr
* Serveur SMTP : smtp.numericable.fr
* Serveur IMAP : imap.numericable.fr
∗ ORANGE
* Serveur POP : pop.orange.fr
* Serveur SMTP : smtp.orange.fr
* Serveur SMTP sécurisé : smtp-msa.orange.fr Port : 587 (activer l’authentification smtp)
* Serveur IMAP : imap.orange.fr
o Aide pour paramétrage FAI Orange avec messageries non Orange
∗ SYMPATICO
* Serveur POP : pop1.sympatico.ca
* Serveur SMTP : smtp1.sympatico.ca
* Serveur IMAP : non
∗ SFR
* Serveur POP : pop.sfr.fr
* Serveur SMTP : smtp.sfr.fr
* Serveur IMAP : imap.sfr.fr
∗ TELE2
* Serveur POP : pop.tele2.fr
* Serveur SMTP : smtp.tele2.fr
* Serveur IMAP : non
∗ TISCALI
* Serveur POP : pop.tiscali.fr
* Serveur SMTP : smtp.tiscali.fr
* Serveur IMAP : non
∗ TISCALI-FREESBEE
* Serveur POP : pop.freesbee.fr
* Serveur SMTP : smtp.freesbee.fr
* Serveur IMAP : non
∗ VOILA
* Serveur POP : non
* Serveur SMTP : non
* Serveur IMAP : non
131
∗ WANADOO
* Serveur POP : pop.wanadoo.fr
* Serveur SMTP : smtp.wanadoo.fr
* Serveur IMAP : non
∗ YAHOO
* Serveur POP : pop.mail.yahoo.fr (sur activation de l’option POP3 de Yahoo) Port 995 Avec
connexion SSL
* Serveur SMTP : smtp.mail.yahoo.fr Port 465 Avec connexion SSL
* Serveur IMAP : non
* Page de configuration détaillée (en anglais).
A FINIR
En fait, ce chapitre est consacré à un rappel de sql or j’ai déjà rédigé un tutoriel sql dans fichier tutoriel Symfony.
Depuis PHP 5, une extension unique de PHP permet de piloter une base de donnée quelle que soit la nature
du SGBD sous-jacent. Auparavant l’extension la plus répandue était l’extension mysql de PHP4. mysqli peut
aussi être utilisée sous PHP 5 (i pour ”improved” càd améliorée).
En ce qui me concerne, c’est PDO qui m’intéresse. L’exposé de mysqli est beaucoup trop sommaire dans le
le bouquin pour y passer du temps.
PDO unifie la notion de connection vers les SGBD. PDO est une extension PHP écrite en C ce qui la rend très
rapide. Cen n’est cependant pas totalement une abstraction de la gestion des base des données car il existe une
extension PDO pour chaque type de SGBD (ex : pdo_mysql, pdo_sqlite, pdo_odbc, etc.).
L’utilisation d’une base de données via PDO sur pHP se fait en 5 étapes majeures :
1. Connexion
132
3. Requête
4. Exploitation des résultats
5. Fermeture de la connexion
Notion de DSN : Data Source Name Un DSN spécifie l’adresse d’une source de données à un client
souhaitant manipuler des données. Si j’écris source de données, c’est qu’un DSN peut tout autant être une base
de données qu’un fichier Access, Excel, ou autre...
Le DSN dépend de la source de données auquel on souhaite se connecter. En l’occurence pour pdo_mysql,
le DSN a les éléments suivants :
• host : adresse du serveur distant sur lequel réside la base de données (nom ou adresse IP pour un serveur
distant ou localhost pour un serveur en local) ;
• dbname : nom de la base à utiliser ;
• port : Optionnel, port TCP/IP de la connexion à utiliser ;
• unix_socket : Optionnel, adresse de la socket unix pour une connexion en local sur un réseau unix.
”NOMSGBD:host=NomHost;dbname=NOMBASE;port=NUMPORT;unix_socket=NUMSOCK”
Dans le cas d’une connexion à une base mysql sur une config Apache Windows ou linux, ça donne plus
précisément :
”mysql:host=NomHost;dbname=NOMBASE”
Les deux derniers arguments étant facultatifs.
ATTENTION : la nature des éléments d’un DSN change suivant le SGBD !!! Voir la page 462 du bouquin
pour en voir d’autres.
133
Les fonctions PHP d’exécution d’instruction sql : Les requêtes sql sont exécutées en utilisant les fonc-
tions exec ou query :
• exec(String $RequeteSQL) : A COMPLETER : la fonction exec exécute la requête SQL passée en
argument en renvoyant seulement le nombre de lignes ou le nombre de modifications générales effectuées.
Elle est donc utiliser pour les requêtes SQL ne renvoyant pas de données comme INSERT, UPDATE,
DELETE ou ALTER ; RENVOIE le nb de modifs ou FALSE si erreur ; RENVOIE :
– le nombre de lignes qui ont été modifiées ou effacées pour la requête SQL qui vous exécutez.
– Si aucune ligne n’est affectée, la fonction PDO::exec() retournera 0.
– FALSE si la requête produit une erreur côté sql.
ATTENTION : Dans le cas d’une requête d’effacement de tous les enregistrements d’une table, exec
ne renvoie pas le nombre de lignes effacées car pour aller plus vite, PHP efface alors tout le fichier
correspondant à la table avant de le recréer illico.
• query(String $RequeteSQL) : La fonction query exécute la requête SQL passée en argument et renvoie
un objet de classe PDOStatement qui encapsule les données obtenues par la requête sql ; RENVOIE un
objet de classe PDOexception pour des instructions de type SELECT, EXPLAIN ( ???), SHOW (???) et
DESC (????), ou FALSE si erreur.
Ca, c’est l’usage courante de la fonction : le prototype complet de la fonction peut prendre 3 autres formes
différentes :
PDOStatement PDO::query ( string $statement , int $PDO::FETCH_COLUMN , int $colno
)
PDOStatement PDO::query ( string $statement , int $PDO::FETCH_CLASS , string $class-
name , array $ctorargs )
PDOStatement PDO::query ( string $statement , int $PDO::FETCH_INTO , object $object
)
A partir de ces deux fonctions PDO, on peut exécuter la plupart des instructions SQL
Connexion au serveur de données en PHP Pour cela, il faut créer un objet de classe PDO en appelant
son constructeur explicite qui prend en argument :
new PDO($dsn,$user,$password);
avec :
”$dsn=’mysql:host=localhost;dbname=publication”
Dans le cas d’une connexion à une base se trouvant en local et s’appelant ’publication’.
134
Les Connexions persistantes Etablir une connexion persistante permet d’éviter d’avoir à se reconnecter à
une base à chaque requête sachant que cela prend un temps conséquent...
Pour spécifier que la connexion à une base est persistante, il faut ajouter un tableau associatif d’option en
argument du constructeur de l’objet de classe PDO comme suit :
new PDO($dsn, $user, $password, array(PDO::ATTR_PERSISTENT => true)
ATTENTION Apache peut avoir plusieurs threads et dans cas, il y aura autant de connexions persistentes
que de threads apache pour un même utilisateur. Si le nombre d’utilisateurs devient grand, le SGBD peut être
saturé car le nombre de connexions persistentes sera NbUsers x NbthreadsApache...
Gérer les erreurs de connexion EN cas d’erreur lors d’un appel à exec ou query sur une requête sql, un
objet de classe PDOexception est renvoyé.
ATTENTION SECURITE la non interception d’une PDOexception via try catch fait que PHP génère
un fichier de traces contenant tous le contenu de la requête dont au minimum le user et le password qui
peuvent ensuite être potentiellement récupérés par un pirate lisant le fichier de traces... IL FAUT DONC
IMPERATIVEMENT GERER LES ERREURS avec PDO.
Fermer une connexion Pour fermer une connexion à une base, il faut assigner NULL à l’objet PDO
correspondant ou attendre la fin du script. Le mieux étant de le faire explicitement pour éviter les mauvaises
surprises.
Gérer ses données de connexion avec un fichier de configuration Pour éviter d’avoir à redéfinir
constamment ses données de connexion à une base de données pour créer un objet PDO dès qu’une connexion
est nécessaire, le mieux est d’intégrer la création de l’objet PDO d’une base dans un fichier script dédié qui sera
ensuite mis en include ou require dans tous les autres fichiers de scripts appelant la base de données souhaitée.
La classe PDO qui représente une connexion entre PHP et un serveur de base de données a les méthodes
membres suivantes :
• Le constructeur __construct qui est appelé avec l’opérateur new et qu’on a déjà vu ;
• bool beginTransaction ( void ) : Démarre une transaction (càd un bloc de requêtes devant toutes réussir
sous peine de les annuler toutes v. plus bas). Désactive le mode autocommit. Lorsque l’autocommit est
désactivé, les modifications faites sur la base de données via les instances des objets PDO ne sont pas
appliquées tant que vous ne mettez pas fin à la transaction en appelant la fonction PDO::commit().
L’appel de PDO::rollBack() annulera toutes les modifications faites à la base de données et remettra la
connexion en mode autocommit. ATTENTION : Quelques bases de données, dont MySQL, exécuteront
automatiquement un COMMIT lorsqu’une requête de définition de langage de base de données (DDL)
comme DROP TABLE ou CREATE TABLE est exécutée dans une transaction. Cela concerne notamment
toutes les instructions impactant la structure d’une table de la base concernée ou la base elle-même. Ce
COMMIT implicite vous empêchera d’annuler toutes autres modifications faites dans cette transaction.
RENVOIE TRUE en cas de succès ou FALSE si une erreur survient.
135
• bool commit ( void ) : Valide une transaction (càd un bloc de requêtes devant toutes réussir sous peine
de les annuler toutes v. plus bas) ; remet la connexion en mode autocommit après en attendant l’appel à la
fonction PDO::beginTransaction() pour débuter une nouvelle transaction. ATTENTION : comme indiqué
pour la fonction beginTransaction, les requêtes modifiant la structure des tables remettent automatique-
ment en place le mode autocommit neutralisant l’effet de la fonction commit(). Si une transaction n’est
pas validée explicitement avec commit, alors, on présume que quelque chose s’est mal passé et l’annulation
de la transaction intervient afin de garantir la sécurité de vos données. Lorsque le script se termine ou
lorsque la connexion est sur le point de se fermer, si vous avez une transaction en cours, PDO l’annulera
automatiquement.
• mixed errorCode ( void ) : Retourne le SQLSTATE associé avec la dernière opération sur la base de
données. ATTENTION cette fonction n’est pas fiable pour renvoyer le code d’erreur quand on fait des
requêtes avec PDO. Elle ne renvoie de valeurs correctes que lorsqu’apparemment les requêtes ne passent
pas par les classes et méthodes de PDO. Bref vaut mieux utiliser la méthode errorInfo suivante. Par
ailleurs, errorinfo renvoie lui aussi le SQLSTATE d’où l’inutilité de cette fonction...
• array errorInfo ( void ) : Retourne les informations associées à l’erreur lors de la dernière opération
sur la base de données : renvoie un tableau à trois entrées : La première contient le SQLSTATE qui est
souvent défaillant (v. la fonction errorCode à ce sujet pour savoir pourquoi), la seconde contient le code
erreur issue du driver PDO et la seconde le texte de l’erreur ;
• int exec ( string $statement ) : DEJA VU. Exécute une requête SQL et retourne le nombre de lignes
affectées
• mixed getAttribute ( int $attribute ) : Récupère un attribut d’une connexion à une base de données
• array getAvailableDrivers ( void ) : Retourne la liste des pilotes PDO disponibles
• string lastInsertId ([ string $name = NULL ] ) : Retourne l’identifiant de la dernière ligne insérée
ou la valeur d’une séquence
• PDOStatement prepare ( string $statement [, array $driver_options = array() ] ) : Prépare une
requête à l’exécution et retourne un objet
• PDOStatement query ( string $statement ) : Exécute une requête SQL, retourne un jeu de résultats
en tant qu’objet PDOStatement, ou FALSE si une erreur survient ;
• string quote ( string $string [, int $parameter_type = PDO::PARAM_STR ] ) : Protège une
chaîne pour l’utiliser dans une requête SQL PDO, càd échappe les caractères spéciaux de SQL dans la
chaine passée en argument. $parameter_type permet éventuellement de spécifier le type de données
pour les drivers qui ont des styles particuliers de protection (obscure mais on s’en fout). Quoiqu’il arrive
il est fortement recommandé d’utiliser des requêtes préparées plutôt que traiter le problème des caractères
spéciaux à échapper avec des appels à quote à la volée... Voir la fonction prepare pour les requêtes
préparées. RENVOIE la chaine échappée ou FALSE si le $parameter_type est incorrect...
• bool rollBack ( void ) : Annule la transaction courante, initié par la fonction PDO::beginTransaction().
C’est une erreur que d’appeler cette méthode s’il n’y a aucune transaction active.
Si la base de données est en mode autocommit, cette fonction restaurera le mode autocommit après
l’annulation de la transaction.
Quelques bases de données, dont MySQL, exécuteront automatiquement un COMMIT lorsqu’une requête
de définition de langage de base de données (DDL) comme DROP TABLE ou CREATE TABLE est exé-
cutée dans une transaction. Ce COMMIT implicite vous empêchera d’annuler toutes autres modifications
faites dans cette transaction. RENVOIE TRUE en cas de succès ou FALSE si une erreur survient.
136
• bool setAttribute ( int $attribute , mixed $value ) : Configure un attribut PDO
Un objet de type PDOstatement est renvoyée par une requête appelée avec query(). L’affichage du contenu de
l’objet de type PDOstatement se fait avec les deux fonctions suivantes :
• PDOStatement::
137
Pour renvoyer le nombre de lignes du tableau de retour, il suffit d’utiliser la fonction count sur le tableau
renvoyé. Deuxième solution : utiliser une requête sql avec COUNT.
IMPORTANT : si une doute subsiste sur la taille du tableau renvoyé par une requête sql, il vaut mieux
d’abord une faire requête COUNT. Si les données ont besoin d’être traités, il vaut mieux utiliser la fonction
fetch() et boucler sur les enregistrements.
L’apostrophe est le caractère spécial à protéger dans une chaine devant servir comme requête SQL. L’apostrophe
agit délimiteur de chaine en SQL. C’est avec ce caractère que les attaques par injection ont lieu. Pour échapper
un caractère apostrophe dans une chaine, c’est à dire pour que SQL le prenne pour une vraie apostrophe et non
comme un délimiteur, il faut échapper le caractère apostrophe avec le caractère spécial ’\’ de sorte que dans :
”J\’ai faim”
SQL considère que la sous-chaine ”ai faim” N’est PAS une instruction SQL mais partie intégrante de la chaine
”j’ai faim” qu’on cherche à passer à SQL.
PDO fournit la fonction quote pour échapper les apostrophes des chaines d’une requête SQL. Cependant un
développeur peut oublier cet appel à quote
Si l’hébergeur propose un serveur en ligne qui a magic_quotes_gpc à on et qu’il interdit d’en changer la
valeur, voilà comment contourner cette config :
magic_quotes_gpc impacte les superglobales $_GET, $_POST, $_COOKIE, $_REQUEST. Pour em-
pêcher cela, il faut incorporer en début de tout script le bloc de code suivant :
• if (get_magic_quotes_gpc())
{
array_walk_recursive($_GET, ’stripslashes’);
array_walk_recursive($_POST, ’stripslashes’);
array_walk_recursive($_COOKIE, ’stripslashes’);
array_walk_recursive($_REQUEST, ’stripslashes’);
}
On peut également utiliser l’échappement à la volée en vérifiant la présence de la directive qui dans ce cas aura
déjà oeuvré :
if (!get_magic_quotes_gpc())
{
$lastname = $pdo->quote($_POST[’lastname’]);
138
}
else
{
$lastname = $_POST[’lastname’];
};
Cette fonction devrait plutôt figurer dans le chapitre sur les tableaux mais bon...
PDO utilise un code erreur unifié quel que soit le SGBD sous-jacent. La gestion d’erreurs de PDO peut être :
• de ne pas afficher les erreurs (une sorte d’opérateur @ appliqué à tous les appels PDO) : C’est le mode
silencieux qui est le mode par défaut. Les méthodes errorinfo et errorcode permettent cependant de
récupérer des infos sur les erreurs produits et enregistrés dans l’instance PDO qui gère la connexion au
SGBD ;
• d’utiliser le mode erreur classique ;
• ou d’avoir recours aux exceptions PHP pour renvoyer des erreurs ;
Le mode Exception implique de travailler avec des blocs try et catch. Voir le chapitre dédié à la gestion des
erreurs.
139
18.3 Gestion des transactions
Une transaction est un bloc d’instructions sql qui doivent être toutes exécutées sans erreur sous peine de quoi,
elles sont toutes annulées.
ATTENTION : de ce fait, les format de tables permettant les transactions sont les tables de type InnoDB
qui permettent d’annuler l’exécution d’instructions sql précédentes. Cela tient au fait que les tables innoDB
enregistrent les différences successives à partir d’un état initial de la table et non l’état courant de la table...
PDO ne vérifie la possibilité d’utiliser des transactions qu’au niveau du pilote. Si certaines conditions
à l’exécution empêchent les transactions de fonctionner, PDO::beginTransaction() retournera tout de même
TRUE sans erreur si le serveur accepte de démarrer une transaction.
Un exemple serait d’utiliser des transactions sur des tables au format MyISAM du serveur de base de données
MySQL.
IMPORTANT : pour utiliser des transactions, il vaut mieux travailler en mode Exception pour la gestion
des erreurs de la connexion PDO. Sinon en mode classique, il faut utiliser la fonction ErrorInfo pour s’assurer
après chaque requête que l’instruction query ou exec n’a pas renvoyé d’erreur...
$pdh->beginTransaction();
2. on stocke ses requêtes dans des string comme d’hab’, et on les exécute avec $pdh->exec ou ->query suivant
le type de requête ;
$ReqStr =”PremiereRequeteTypeExec”;
$res=$pdh->exec($ReqStr);
...
$LastReq = ”DernierRequeteTypeQuery”;
$LastRes = $pdh->query($LastReq);
3. Si aucune erreur n’a eu lieu, on utilise l’instruction commit de l’instance PDO pour valider définitivement
les requêtes effectuées
$dbh->commit()
4. sinon une Exception de classe PDOException a été lancée et on doit utiliser la fonction RollBack de
l’instance PDO pour annuler toutes les requêtes de la transaction :
$dbh->rollBack()
140
18.4 Les requêtes préparées
L’idée des requêtes préparées est de créer des modèles de requêtes pour les requêtes les plus utilisées. Les requêtes
préparées ont deux avantages :
• La vitesse d’exécution en cas de requêtes multiples : Un requête classique passe par 4 étapes successives
pour s’exécuter : Analyse, Précompilation, Optimisation et Exécution Finale. Une requête préparée ne
passe par ce cycle que la première fois. Les fois suivantes, elle repasse uniquement par la dernière étape ;
• La sécurité : Les requêtes sont automatiquement protégées par PDO contre les attaques par injection
SQL.
La requête s’écrit comme avant dans une chaine de caractères. La différence est qu’on souhaite créer un modèle
de requête. Ce modèle est donc une requête dont certains éléments sont spécifiés comme dynamiques.
Pour déclarer un paramètre ou une valeur de paramètres comme dynamique, il suffit de le remplacer par un
point d’interrogation ou par une paramètre nommé comme suit :
$pdoStat= $pdh->prepare($sql)
3. Il reste à lier les paramètres nommés à des valeurs concrêtes. Pour ça, deux méthodes:
141
(a) Exécution directe de la requête via la fonction execute de l’instance PDOStatement crée au point
précédent. Dans ce cas, les valeurs des paramètres nommés sont fixés en passant un tableau associatif
dont les clefs sont les noms des paramètres nommés et les éléments les valeurs comme suit :
$pdoStat->execute($TabParam);
avec $titre et $auteur contenant respectivement les chaines donnant le titre et l’auteur souhaités.
(b) Lier d’abord les paramètres nommés à des variables PHP prééxistantes. Pour ça, soit la valeur de la
variable PHP est lié une fois au paramètre avec la fonction BindValue, soit elle est lié dynamique-
ment à une variable PHP avec la fonction BindParam. Dans le second cas, une fois le lien fait avec
BindParam, si la valeur de la variable PHP change, le paramère nommé change automatiquement
pour prendre la même valeur. Le paramètre nommé est alors une référence sur la variable PHP. Dans
le premier cas, la valeur de la variable PHP a seulement été recopié dans le paramètre nommé au
moment du lien mais après chacun vit sa vie...Par exemple, ça donnerait :
$pdoStat->BindParam(”:titre”, $titre);
$pdoStat->BindValue(”:auteur”, $auteur);
Comme le lien des paramètres nommés a été fait, la fonction execute de l’instance pdostatement
peut-être appelée sans argument :
$pdoStat->execute();
– $parameter : Pour une requête préparée utilisant les marqueurs (ou paramètre nommé), cela sera
un nom de paramètre de la forme :nom. Pour une requête préparée utilisant les points d’interrogation
(comme paramètre fictif), cela sera un nombre entier correspondant à la position du paramètre dans
la requête. Si c’est le premier ? de la requête, ce sera 1, si c’est le deuxième ce sera 2, etc. Par
exemple :
$sth=$dbh->prepare(’SELECT nom, couleur, calories
FROM fruit
WHERE calories < ? AND couleur = ? ’);
$sth->bindValue(1, $calories, PDO::PARAM_INT);
$sth->bindValue(2, $couleur, PDO::PARAM_STR);
– $data_type : permet de spécifier explicitement le type de données pour le paramètre $parameter
en utilisant les constantes de la classe PDO :
∗ PDO::PARAM_BOOL : type booléen ;
∗ PDO::PARAM_NULL : Représente le type de données NULL SQL ;
∗ PDO::PARAM_INT : Représente le type de données INTEGER SQL.
142
∗ PDO::PARAM_STR : Représente les types de données CHAR, VARCHAR ou les autres types
de données sous forme de chaîne de caractères SQL.
∗ PDO::PARAM_LOB : Représente le type de données ”objet large” SQL.
∗ PDO::PARAM_STMT : Représente un type de jeu de résultats (càd un retour de requête sur
SGBD). N’est actuellement pas supporté par tous les pilotes.
∗ PDO::PARAM_INPUT_OUTPUT : Spécifie que le paramètre est un paramètre INOUT pour
une procédure stockée. Vous devez utiliser l’opérateur OR avec un type de données explicite
PDO::PARAM_*. (V. plus bas les procédures stockées).
RENVOIE TRUE en cas de succès ou FALSE si une erreur survient.
– appeler la fonction PDOStatement::bindParam() pour lier les variables PHP aux marqueurs de
positionnement : les variables liées passent leurs valeurs en entrée et reçoivent les valeurs de sortie,
s’il y en a, de leurs marqueurs de positionnement respectifs
– ou passer un tableau de valeurs de paramètres, uniquement en entrée comme vu plus haut ;
RENVOIE true si succès ou FALSE sinon.
Sql sous windows renvoie des résultats de requêtes qui sont encodés en CP1252. Il faut donc convertir les
résultats issus de query avec l’instruction mb_convert_encoding comme suit :
$PDOStat = $dbh->query($MaQuerySql);
...
$TrucaAfficher = mb_convert_encoding($ChaineIssuDePDOStat, ”utf-8”, ”CP1252”);
echo ”On peut afficher sereinement ” . $TrucaAfficher;
143
19 Chapitre 19 : Erreurs et Exceptions
Un chapitre sur la gestion erreurs qui arrive comme un cheveu sur la soupe entre le chapitre sur PDO et celui
sur xml, et surtout un chapitre qui arrive très tard dans le livre alors qu’on a eu déjà bon nombre d’exemples
implicites de gestion d’erreurs...
Une erreur en programmation est l’écart existant entre ce que devrait faire une application et ce qu’elle fait.
1. Intercepter les erreurs pour les gérer directement par le code : proposer un service dégradé, prévenir les
développeurs, arrêter l’exécution du code si besoin est ;
2. Enregistrer les erreurs dans un journal d’erreurs pour les historiser afin de traiter ultérieurement les
bogues qu’elles révèlent.
En faisant précéder une instruction php par l’opérateur @, PHP ignore l’apparition d’une éventuelle d’erreur.
Notons que cela n’empêche pas l’apparition de l’erreur en soi, cela demande juste à PHP de passer outre mais
rien ne garantit derrière que l’erreur ne va pas en provoquer d’autres...
L’usage de l’opérateur @ est donc à éviter...
2. Les assertions : affirmation fonctionnelle et logique définie par le développeur ; PHP renvoie une erreur si
les assertions implémentés ne sont pas respectées (par exemple : une corrélation doit être comprise entre
0 et 1, ou un prix doit être positif) ;
3. Les exceptions : Elles permettent d’envoyer et de recevoir des messages plus évolués d’erreurs ;
144
19.3 Les erreurs PHP
Ce sont des messages renvoyés par PHP en cas de comportement anormal du code, càd : une erreur de syntaxe,
ou une erreur lié à l’utilisation incorrecte d’une fonction ou d’une variable.
Les erreurs PHP ont 4 caractéristiques :
1. Un niveau d’importance :
2. Un message explicatif :
3. Le nom du script en cause :
4. Le numéro de la ligne en cause
Avant de voir les différentes méthodes pour gérer les erreurs, il faut voir comment la config de php influe sur la
gestion d’erreurs.
Dans php.ini, la directive display_errors = on spécifie que les erreurs sont affichés à l’écran. Idéal en
développement, à proscrire en production !! (mettre donc dans ce cas display_errors = off )
Quand display_errors = off, il faut que les erreurs soient sauvés dans un log et donc il faut que spécifier
les directives suivantes dans php.ini
log_errors = on
error_log = /Chemin/Vers/Fichier/Erreur/phplog.txt
Une config de développement error_reporting = E_ALL | E_STRICT (la première valeur demande
l’affichage de toutes les erreurs
E_STRICT permet d’obtenir des suggestions de PHP
pour modifier votre
code, assurant ainsi une meilleure interopérabilité et com-
patibilité de
celui-ci.
display_errors = on
log_errors = on
log_errors_max_len = 1024
track_errors = off
error_log = /Chemin/Vers/Fichier/Erreur/phplog.txt
145
Modifier la gestion d’erreurs depuis PHP : La fonction error_reporting() permet de changer la valeur
Les niveaux d’erreurs php : Certaines erreurs sont liés à des dysfonctionnements internes de PHP et non
Les erreurs HTML Compte tenu de la nature double html/php d’un script php, des erreurs HTML peuvent
se produire. Dans le cas d’une erreur html, si la directive html_errors = On, toute erreur html redirige vers
le site officiel du langage html. On peut aussi rediriger vers une adresse locale en spécifiant les directives :
docref_root = ”http://AdresseExemple/manual/”
docref_ext = ”.html”
La première directive spécifie le chemin de redirection (ne pas oublier le ”/” final) et la seconde donne le
suffixe du fichier ciblé.
146
La gestion d’erreur par condition de résultat de fonction La syntaxe la plus courante est la suivante :
If (!FonctionATester() )
{
L’ennui de cette approche est qu’elle prend de la place et rend moins lisible le code.
une solution est de passer par l’opérateur Or :
Cette syntaxe est plus courte mais il faut définir une procédure d’erreur pour chaque fonction. Il est possible
de faire plus simple avec la fonction TriggerError() comme suit :
Le niveau d’erreur spécifié ici n’est pas le seul possible. Voir la définition de la fonction trigger_error
– error_msg : Le message d’erreur désigné pour cette erreur. Il est limité en longueur à 1024 caractères.
Tous caractères après les 1024 seront ignorés ;
– error_type : Le type d’erreur désigné pour cette erreur. Cela ne fonctionne qu’avec la famille de
constantes E_USER et sera par défaut E_USER_NOTICE.
147
Personnaliser ses messages d’erreurs Deux directives de php permettent de personnaliser l’affichage des
messages d’erreurs PHP :
• error_prepend_string = ”INSTRUCTION HTML” : permet de faire précéder tout affichage
d’erreur PHP d’une instruction html ;
• error_append_string = ”INSTRUCTION HTML” : permet de faire suivre tout affichage d’erreur
PHP d’une insruction html ;
Les deux directives doivent être complémentaires car si la première contient une balise ouvrante, la deuxième
doit contenir la balise fermante. Par exemple, pour que tous les messages d’erreur soient en rouges :
Journalisation des erreurs Le log d’erreur doit surtout être activé en production. Il est aussi utile en dév
pour s’assurer de ne pas laisser passer d’erreurs...
En terme de gestion des erreurs, il faut vider régulièrement le log des erreurs au fur et à mesure qu’on les
résoud. Par ailleurs, il faut aussi le recopier pour garder traces des erreurs passés ou ne pas le saturer en cas
d’un grand nombre d’erreur. La directive activant le logging des erreurs est log_errors= on
Le répertoire de sauvegarde du fichier de log peut aussi être personnalisé avec la directive :
error_log = Chemin/Vers/Repertoire/Du/Log/NomFichierLog.txt
ignore_repeated_errors = on
Dans ce cas, les erreurs répétés d’une même source sont ignorés. On peut aussi agréger les erreurs répétés
de plusieurs sources en mettant dans php.ini la directive suivante :
ignore_repeated_sources = on
On peu aussi rediriger les messages d’erreur vers le log du système mais c’est franchement à éviter (V.
page 506-510 du bouquin pour ça). Il faut utiliser successivement les fonctions define_syslog_variables()
pour initialiser certaines constantes relatives à la journalisation système, openlog() pour ouvrir le log système,
syslog() pou y écrire des messages et closelog() pour le fermer.
Envoi manuel de messages vers le log d’erreurs : On peut envoyer un message d’erreur vers le log
directement en utilisant la fonction error_log() :
• bool error_log ( string $message [, int $message_type = 0 [, string $destination [, string
$extra_headers ]]] ) :Envoie un message d’erreur à l’historique du serveur web, à un port TCP ou un
fichier. En dehors de la chaine $message, les options de cette fonction sont :
– $message_type : Spécifie la destination du message d’erreur. Les types possibles de messages sont
:
∗ 0 : est envoyé à l’historique PHP, qui est basé sur l’historique système ou un fichier, en fonction
de la configuration de error_log. C’est l’option par défaut.
148
∗ 1 est envoyé par email à l’adresse destination. C’est le seul type qui utilise le quatrième paramètre
extra_headers.
∗ 2 n’est plus une option.
∗ 3 est ajouté au fichier destination. Une nouvelle ligne est automatiquement ajoutée à la fin de
la chaîne message.
∗ 4 est envoyé directement au gestionnaire d’identification SAPI.
– $destination : Cela dépend du paramètre message_type décrit ci-dessus.
– $extra_headers : Les en-têtes supplémentaires. Ils sont utilisés lorsque le paramètre message_type
est défini à 1. Ce type de message utilise la même fonction interne que la fonction mail().
RENVOIE TRUE en cas de succès ou FALSE si une erreur survient. ATTENTION la longueur de la
chaone envoyable est déterminée par la directive log_errors_max_len de php.ini
Créer son propre gestionnaire d’erreurs Plutôt que de laisser PHP utiliser son gestionnaire d’erreur in-
terne, on peut définir son propre gestionnaire d’erreurs ce qui revient à définir une fonction de rappel, par exemple
MaFonctionGestionErreur et forcer PHP à l’utiliser avec la fonction set_error_handler(’MaFonctionGestionErreur’).
Il est possible de réactiver le gestionnaire d’erreurs interne de PHP avec la fonction restore_error_handler()
On peut aussi imbriquer plusieurs gestionnaire d’erreurs et en activer un suivant a partie du code où on se
trouve avec set_error_handler().
ATTENTION : En cas d’erreur fatales PHP du type, E_ERROR, E_PARSE, E_CORE_XXX, E_COMPILE_XXX,
PHP stoppe automatiquement l’exécution et empêche la récupération de l’erreur par un gestionnaire person-
nalisé, il faut donc bien penser son système de gestionnaires d’erreurs...
149
19.4 Les assertions
Gérer les erreurs générés par PHP n’est pas suffisant car sauf à contrôler systématiquement tout avec des syntaxes
de contrôles (v gérer les erreurs pas le code), des failles logiques tenant à l’architecture objet apparaissent
sans pour autant déclencher d’erreurs PHP. Par exemple, si dans mon univers objet, j’ai une variable réelle
représentant une corrélation ou une Recovery du capital d’un titre, le type double de PHP est beaucoup trp
permissif car un double en PHP vaut, je simplifie, entre -∞ et +∞ alors qu’une corrélation est toujours comprise
entre -1 et 1 et une recovery est toujours comprise entre 0 et 1.
De ce fait, soit j’ajoute du code de contrôle à chaque calcul de variable pour m’assurer que le domaine de
définition théorique est bien respectée, soit j’utilise les assertions.
Une assertion est une affirmation fonctionnelle et logique définie par le développeur : ”Une corrélation est
comprise entre -1 et 1” et ”Une recovery est comprise entre 0 et 1” sont deux assertions.
Une assertion est une structure de contrôle qui permet de vérifier la cohérence de la valeur d’une variable
ou d’un objet et de signaler quand cette cohérence n’est plus respectée.
Il faut utiliser une assertion uniquement pour valider une affirmation qui ne doit pas pouvoir être fausse. C’est
donc une mécanique de sécurité qui ne doit pas faire partie de la logique applicative. Par exemple, supposons
que j’étudie la corrélation Spot/vol d’une action, je m’attends à ce que cette correl soit négative, cependant elle
peut ne pas l’être, contrôler sa négativité avec une assertion n’a alors pas de sens car la positivité, quoique très
peu probable, est possible. Par contre, contrôler que la valeur absolue de la corrél ne dépasse pas strictement 1
a du sens.
Les assertions et les données externes : Si une donnée est fournie par l’extérieure, une valeur impossible est
possible soit parce que l’utilisateur s’est trompé soit qu’il est malveillant. Donc dans le cas de récupération de
donnée externe, NE JAMAIS UTILISER une assertion. Il faut utiliser des structures de contrôles classiques de
type if ... elseif...
Pour être clair, une assertion s’occupe des valeurs impossibles potentiellement générés par son code. Et un
code clean doit donc fonctionner avec ou sans assertions.
Pour résumer :
1. Il est recommandé de n’utiliser les assertions que comme outil de déboguage. Vous pouvez
les utiliser pour les vérifications d’usage : ces conditions doivent normalement être vraies,
et indiquer une erreur de programmation si ce n’est pas le cas. Vous pouvez aussi vérifier
la présence de certaines extensions ou limitations du système.
2. Les assertions ne doivent pas être utilisées pour faire des opérations de vérifications en
production, comme des vérifications de valeur d’argument. En conditions normales, votre
code doit être en état de fonctionner si la vérification d’assertion est désactivée.
150
19.4.2 Définir une assertion
assert(”ExpressionLogiqueRenvoyantUnBooleen”)
Par exemple, pour une corrélation contenu dans une variable $Correl, ça donne :
• bool assert ( mixed $assertion ) : va vérifier l’assertion $assertion et prendre la mesure appropriée
si le résultat est FALSE. $assertion peut être une chaine contenant une expression logique PHP sur des
variables PHP. $assertion peut aussi correspondre à AUTRE CHOSE (voir la fonction assert_options).
Coder avec des assertions ralentit d’autant plus le code qu’il y a d’assertions. Cependant une fois le code bétonné
et sécurisé, il est possible de se passer des assertions sans avoir à les supprimer ou à les mettre en commentaires
une à une, simplement en les désactivant soit avec :
• en jouant sur les directives de configuration de php.ini qui sont les directives cités dans la définition de la
fonction assert_options() notamment la directive assert.active à on ou off pour activer ou désactiver
les assertions ;
151
19.4.4 Ajouter un message d’erreur personnalisé à un alerte erreur généré par une assertion
fausse
Il est possible d’incorporer un message d’erreur personnalisé à la chaine contenant l’expression logique de
l’assertion. ATTENTION : Le bouquin se plante sur le sujet puisque le bouquin propose la syntaxe fausse
suivante :
assert(”EXP RESSION LOGIQU E P HP ”); // Message d’erreur personnalisé
Dans ce cas, le message d’erreur étant mis comme un vrai commentaire, ça ne peut évident pas marcher sauf à
imaginer que PHP puisse distinguer les commentaires qui suivent les appels de la fonction assert.
LA VRAIE syntaxe est la suivante :
Cette fois-ci, le message d’erreur personnalisé fait partie intégrante de l’instruction assert ce qui semble et est
plus correcte...
CONSEIL SUR LES ASSERTIONS : Il est recommandé de ne pas utiliser de fonction utilisateur dans
l’expression logique car les assertions ne doivent pas dépendre dans leur fonctionnement d’autre chose que
d’expression simples et/ou que de fonctions utilisateurs éprouvé càd error-proof.
152
19.5 Les exceptions
Les exceptions permettent d’envoyer des messages d’erreurs plus évolués et sophistiqués.
Dans PHP, toutes les exceptions sont des classes dérivant de la classe Exception. Cette classe contient quatre
données membres protected qui déterminent les quatres éléments d’un message d’erreur intégré dans une classe
dérivant de Exception :
• string $message : le message d’erreur sous forme littéral. ex :”L’erreur est du type machine etc...” ;
Un deuxième argument optionnel, le code d’erreur, peut être ajoutée (valeur par défaut = NULL). PHP se
charge par ailleurs de renseigner le fichier $file et le numéro de ligne $line. 4 getteurs sont fournis de base dans
la classe Exception :
• getFile() :
• getMessage() :
• getLine() :
• getCode() :
Créer ses propres classes Exception cela se fait en créant une classe dérivée de Exception. On peut alors
ajouter des données et méthodes membres qui vont gérer spécifiquement nos erreurs. Par exemple :
private $TypePricer;
private $TypeModel;
public __construct($message, $TypePricer, $TypeModel)
{
$this->TypePricer = $TypePricer;
$this->TypeModel = $TypeModel ;
parent::__construct($message);
}
153
Public function getTypePricer()
{
return $this->TypePricer;
}
return $this->TypeModel;
}
};
Lancement d’une exception Créer une Exception n’a aucune incidence directe sur le fonctionnement
courant de PHP. Une instance d’exception est objet comme les autres tant qu’il n’a pas été lancé. On lance
l’exception avec l’instruction native throw comme suit :
throw $ErrorPricer;
Une fois cette dernière instruction exécutée par PHP :
1. PHP récupère l’objet de type Exception et lui ajoute le numéro de ligne et le nom de fichier dans lequel
l’instruction thow a été utilisée.
2. Puis PHP saute au premier gestionnaire d’exception capable de gérer le type de l’instance d’Exception
récupérée.
Gestionnaire d’Exception Un gestionnaire d’exception est ni plus ni moins qu’un bloc de code de type :
try
{
catch(TypeException $e)
{
... code exécuté dans le cas de l’apparition d’un erreur de type TypeException
... dans le bloc de code classique
154
Dans le cas du gestionnaire précédant, si le type d’erreur TypeException est Exception, toutes les exceptions
lancées dans le bloc de code classique sont attrapées par l’instruction catch.
Cependant on peut vouloir affiner en utilisant plusieurs catch comme suit :
try
{
catch(TypeException1 $e)
{
... code exécuté dans le cas de l’apparition d’un erreur de type TypeException1
... dans le bloc de code classique
}
catch(TypeException2 $e)
{
... code exécuté dans le cas de l’apparition d’un erreur de type TypeException2
... dans le bloc de code classique
}
catch(TypeException3 $e)
{
... code exécuté dans le cas de l’apparition d’un erreur de type TypeException3
... dans le bloc de code classique
Bien entendu, les types TypeException1, TypeException2 et TypeException3 doivent alors tous être des
instances de classes dérivant de Exception ou directement de type Exception. (Dans ce dernier cas, si PHP ne
s’est pas déjà arrêté dans un bloc catch, il s’arrête automatiquement dans le premier bloc catch attrapant une
exception de type Exception).
PHP va alors passer dans le premier catch dont le type d’exception est du type de l’exception lancé.
Les gestionnaires d’Exception peuvent s’imbriquer. Dans ce cas, si le gestionnaire fils n’est pas en mesure
d’attraper tous les types d’exceptions de son bloc try, c’est le catch du gestionnaire parent qui prend la relève.
Par ex :
try
{
try
155
{
/// instructions
throw new TypeExceptionB(...);
}
catch (TypeExceptionA)
{
Dans notre exemple ci-dessus, si une Exception de type TypeExceptionB est lancé, les blocs 1 et 2 ne seront
jamais exécutés car PHP saute directement au premier catch adéquat, passant d’abord par tous les catch du
gestionnaire d’exceptions fils puis passant par tous les catchs du gestionnaire d’exception parent.
156