Initiation à PHP
Transcription
Initiation à PHP
Introduction à PHP Master Créations Images et Multimédia Multilingue / CAWEB 1.Historique Php est né du fruit du travail de Rasmus Lerdorf , une première version du langage voit le jour en 1994. La diffusion du langage debute dès 1995. Le nom initial du projet ( « Personal Home Page tools » sera rebaptisé « hypertext préprocessor ») . A l'heure actuelle ce langage est devenu très populaire chez les web designers, simple d'approche et surtout très puissant , il évolue constamment grâce à une communauté de développeurs très importante. On est aujourd’hui à la version 5 du langage PHP est distribué librement et gratuitement sous licence GNU GPL il est téléchargeable sur http://www.php.net 1.Historique Php est né du fruit du travail de Rasmus Lerdorf , une première version du langage voit le jour en 1994. La diffusion du langage debute dès 1995. Le nom initial du projet ( « Personal Home Page tools » sera rebaptisé « hypertext préprocessor ») . A l'heure actuelle ce langage est devenu très populaire chez les web designers, simple d'approche et surtout très puissant , il évolue constamment grâce à une communauté de développeurs très importante. On est aujourd’hui à la version 5 du langage PHP est distribué librement et gratuitement sous licence GNU GPL il est téléchargeable sur http://www.php.net 1.2 Principe de fonctionnement • PHP est avant tout un langage de script (scripting). • Le code inséré dans les pages HTML, est exécuté par le serveur sous réserve que les pages portent l'extension .php3 .php ou .php4. Le fichier contenant du code php est hébergé sur le serveur ; lors d’une requête HTTP , le code HTML est retourné tel quel et le code php est extrait et exécuté par le serveur . Les résultats seront intégrés au flot HTML. • Très simple à appréhender car possédant une syntaxe claire et très proche du langage C, le PHP reste une solution qui conviendra aux débutant comme aux professionnels, pour dynamiser un site Web ou l'interfacer avec une Base de données. 1.3 Php et la concurrence • Le PHP utilise une syntaxe très simple car elle reste très proche du langage C, langage maîtrisé par la plupart des développeurs. • Les autres langages du web sont : - ASP : c’est la réponse de Microsoft à PHP, ASP utilise une syntaxe basée sur VBScript (Version allégée de Visual Basic) - PERL : C’est un langage de script puissant, adapté à Internet mais difficile à maîtriser - CGI : Composants exécutables, rapide mais spécifiques à la plate formeserveur et pose souvent des problèmes de securité tout en étant complexe à développer. - JAVASCRIPT : Javascript est quand à lui interprété par le logiciel client ( = le navigateur ) des problèmes de sécurité sont inhérents à ce mode de fonctionnement - RUBY : Langage de script qui peu être utilisé pour le dvt web on parle surtout de RoR ( Ruby on Rails projet un peu jeune mais prometeur ! ) un framework de dvt web basé sur Ruby. L'appelation « ruby » vient d'un jeu de mot sur Perl. Ruby utilise la programmation dite MVC ( modèle vue contrôleur ) - Python : Comme python c'est un langage de script orienté objet qui utilise le modèle MVC on le couple souvent à Django ou Zope pour le dvt web. - JAVA, Webdev (...) 1.3.1 ASP : <html> <head> <title>De l'ASP dans le cours de ToMa !!!!!!</title> </head> <body bgcolor="white" text="black"> <% Dim strMessage strMessage = "Hello les copains" Response.Write (strMessage) Response.Write ("<br>") Response.Write ("Il est : " & Time()) %> </body> </html> 1.3.2 PERL : #!/usr/local/bin/perl print("content-type : text/html\n\n"); print("Hello les copains !"); ($secondes,$minutes,$heure)=localtime(time); print(''Il est $Heure:$minute:$secondes''); 1.4 Intégration et syntaxe de PHP • Avant d’utiliser PHP il faut s’assurer que notre hébergeur le supporte à moins qu’on désire travailler localement - installation possible sous windows du pack easyphp ( http://www.easyphp.org ) ou sous linux il faut utiliser le systeme de packetages ( rpms ) ou les fichiers binaires. • Les hébergeurs Wanadoo, Free… supportent le PHP (pas intégralement car certaines fonctions comme mail() ne sont pas toujours activées). • Intégrer du php dans une page est très simple à réaliser , une page type combine souvent HTML et PHP , il faut alors introduire une notation particulière pour distinguer les deux langages . 1.4.2 Integration dans une page HTML Il existe 4 méthodes pour intégrer PHP à l'intérieur d’un document HTML : A l'aide des tags courts <? et ?> <? echo (‘’ hello world !!!!"); ?> A l'aide des tags <?php et ?> <?php echo (" hello world !!!!"); ?> A l'aide de délimiteur de type ASP (<% et %>) <% echo (" hello world !!!! "); %> A l'aide de la balise <script language="..."> <script language="PHP"> <!-echo (" hello world !!!!"); //--> </script> 1.4.3 Notions importantes • • Extensions Selon la version du langage, les extensions sont différentes : version 2 (php) : ".phtml" version 3 : ".php3" version 4-5 : ".php" “.php4” … Selon les paramétrages du serveur, les anciennes extensions sont reconnues ou non. Les Variables : C’est une zone de mémoire vive ou on enregistre des informations comme du texte ou des nombres ... • Les règles à retenir : chaque ligne doit se terminer par un point-virgule (";") chaque variable commence par le signe dollar ("$") • Les commentaires peuvent prendre soit une ligne, soit plusieurs lignes. sur une ligne : //commentaire avec deux barres obliques #commentaire avec le signe dièse sur plusieurs lignes, /* lignes de commentaires */ 1.4.4 Premier script <? echo ‘’<marquee>HELLO WORLD</marquee> ‘’; ?> 1.5 Les types de données • • • • Les nombres entiers (integer). $nombre = 123; Les nombres à virgules (doubles). $a = 123.456; Les chaînes de caracteres (string) $chaine = ‘’desscimm"; Les tableaux (array ) $chiffres = array(6,7,5,3); $coolvibes = array("I","won’t","do","what","you","tell","me"); echo $coolvibes[3] ; 1.5.2 Notion de tableau • Les tableaux sont très important à maîtriser en PHP, car ce langage est souvent lié à des bases de données. Ces bases de données retournent plusieurs valeurs, et généralement sous forme de tableau. $site[0] = ‘’www.google.fr"; $site[1] = ‘’www.supersite.fr"; $site[2] = ‘’www.superloose.com"; 1.5.3 Les variables En PHP, les variables sont déclarées par le signe '$'. Elles servent à stocker des données dans le script, pour les réutiliser plus tard. <?php /* Definition des variables */ $a = 2; $b = 4; /* Addition */ $addition = $a + $b; // $addition vaut 6 echo $addition; /* Soustraction */ $soustraction = $b - $a; // $soustraction vaut 2 /* Multiplication */ $multi = $a * $b; // $multi vaut 8 echo $multi; /* Division */ $div = $b / $a; // $div vaut 2 echo $div; ?> • Comme en Javascript , on peut incrémenter ( ou le contraire ) la valeur d'une variable de 1 en écrivant : $variable++; ou $variable--; • 1.5.4 Les variables d’environnement • Il est possible en PHP d'obtenir des informations aussi diverses que le nom du navigateur de l'internaute ou le serveur utilisé. Ces informations sont stockées dans des variables spéciales appellés "variables d'environnement". La commande "phpinfo()" récapitule toutes ces variables : <? phpinfo(); ?> $REMOTE_ADDR par exemple, contient l'adresse IP du client $HTTP_USER_AGENT contiendra le nom du navigateur utilisé 1.5.6 Opérations sur les chaines de caractères • En PHP, la concaténation de deux chaînes se fait à l’aide du symbole "." <? $a = 'php c\’est'; $a = ''php c'est top''; $b = $a . ' top !'; echo $b; ?> 1.6 Les fonctions • PHP propose de nombreuses fonctions, mais on peut definir ses propres fonctions à l’aide de function(). • Exemple fichier fonction.php : <? function Arial($taille,$couleur,$texte) { print("<font face=Arial size=".$taille." color=".$couleur.">".$texte."</font><br/>"); } ?> 1.6 Les fonctions Exemple d’un script utilisant notre fonction <? function Arial($taille,$couleur,$texte) { print("<font face=Arial size=".$taille." color=".$couleur.">".$texte."</font><br/>"); } Arial("2","red", "super ..."); Arial("3","#0F74A3", " Genial ..."); ?> 1.7 Include et Require • Les deux fonctions include et require permettent d'insérer dans un script le code contenu dans un autre fichier. Ex : <?php include "mesfonctions.php";?> <?php require "http://www.cool.com/rastafari.php";?> 1.7 Include et Require • Dans notre exemple : Fichier index.php : <? include "MesFonctions.php"; Arial("2","red", "super ..."); Arial("3","#0F74A3", " Genial ..."); ?> Fichier MesFonctions.php : <? function Arial($taille,$couleur,$texte) { print("<font face=Arial size=".$taille." color=".$couleur.">".$texte."</font><br/>"); } ?> 1.7.2 Différences Include et Require ? • Avant la version 4.0.2, la méthode mot "require" pratiquait l'inclusion du fichier au moment de l'analyse (interprétation par php) et non de l'exécution du script. • Dans les versions actuelles la méthode include encas de non existence du fichier inclus affiche un avertissement et continue l'exécution du script alors que require génère une erreur et interrompt le script. • Il est donc conseillé d'utiliser la méthode require quand le fichier à inclure est vraiment requis par l'application php. Si on préfere la méthode include il faut tester l'existence du fichier ou non. • Si le fichier n'existe pas et qu'on utilise include, la fonction include renverra false ( = booléen ) <?php if( file_exists( 'SuPaFicHier.php' ) ) include 'SuPaFicHier.php'; else die("erreur fatale"); // die equivalent à exit() exit("erreur fatal"); ?> 1.8 Exemples de codes php : passage de variables à un script depuis un formulaire Fichier formulaire.html : <form name="formulaire" method="post" action="page.php"> ton ptit nom : <input type="text" name="nom"> <input type="submit’’ value=‘’envoyer’’> </form> Fichier page.php : <?php echo "bonjour ".$nom; ?> <?php echo "bonjour ".$_POST['nom']; ?> 1.8 Exemples de code php : afficher la date • La fonction date permet de décrire une date en retournant une chaîne de caractères sous le format désiré. Cette date est exprimée en fonction du timestamp qui est le nombre de secondes écoulées depuis le 1 Janvier 1970 (époque UNIX) echo time(); //donnes le nb de secondes écoulées Syntaxe : Chaîne date("format", "timestamp") L'argument timestamp est optionnel. S'il est vide, l'heure et la date courante seront utilisées. • Constantes de formatage : a am ou pm A AM ou PM dJour du mois, avec conservation des zéros "01" et "31"… D Jour de la semaine, abrégé en trois lettres ( en anglais "Mon" "Fri" … ) F Mois en anglais et en entier "january" …. h Heure, de 1 à 12 H Heure, de 0 à 23 ( format 24h) i Minutes J Jour du mois, avec suppression des zéros L Jour de la semaine m Chiffre du mois, de 01 à 12 M Abréviation du nom du mois en anglais Y Année, sur quatre unités "2001" 1.8 Exemples de codes PHP • <?php $datedujour=date(" j/m/Y"); echo $datedujour; ?> 1.8 Exemples de codes : dates et locales • strftime --Formate une date/heure locale avec les options locales string strftime ( string format [, int timestamp] ) Les mois et jours de la semaine, et toutes les chaînes dépendantes de la langue sont fixées avec la commande setlocale() Pour le paramètre format : %a : nom abrégé du jour de la semaine %A : nom complet du jour de la semaine %b : nom abrégé du mois %B : nom complet du mois %d : jour du mois en numérique (intervalle 01 à 31) %H : heure de la journée en numérique, et sur 24-heures %I : heure de la journée en numérique, et sur 12- heures %j : jour de l'année, en numérique (intervalle 001 à 366) %m : mois en numérique (intervalle 1 à 12) %M : minute en numérique %S : secondes en numérique %T : l'heure actuelle (égal à %H:%M:%S) 1.8 Exemples de codes : dates et locales <?php echo strftime("En Finlandais est "); setlocale(LC_ALL, "fi_FI.UTF-8"); echo strftime("%A, en Français "); setlocale(LC_ALL, "fr_FR.UTF-8"); echo strftime("%A et en Allemand "); setlocale(LC_ALL, "de_DE.UTF-8"); echo strftime("%A"); ?> 1.8 exemples de codes PHP : date de maj • Ce petit script va afficher la dernière date de mise à jour d’une page html à l’aide de la fonction DATE de la fonction filemtime et d’une variable d‘environnement $SCRIPT_FILENAME • <? echo("Dernière modification le "); echo(date("d/m/Y à H:i",filemtime($_SERVER['SCRIPT_FILENAME']))); ?> 2.0 Complément sur la gestion des variables • Un changement dans PHP pourrait rendre son apprentissage plus complexe. Depuis la version 4.2, la valeur par défaut de register_global est à Off cf php.ini ou phpinfo(); • Une variable envoyée par un formulaire (method=POST name =motdepasse) ne sera plus accessible avec $motdepasse mais avec $_POST['motdepasse']. 2.0 Complément sur la gestion des variables • Pourquoi ? – Pour sécuriser le code et empêcher l ’accès et la manipulation des variables . • Le code est en soi plus stable quand on gère les variables de cette manière , on sait exactement ce que l ’on fait Il faut constamment faire attention aux entrée (input) utilisateurs ( formulaires… ) • Pour aller plus loin : http://www.php.net/release_4_1_0.php ( section SECURITY: NEW INPUT MECHANISM ) http://www.php.net/manual/fr/security.registerglobals.php 2.1 REGISTER GLOBAL • La configuration du paramètre register_global est contrôlée dans le fichier de configuration php.ini. • Infos : http://www.php.net/manual/fr/configuration.php • Le paramètre register_global peut prendre deux valeurs, On et Off. Avant la version 4.2.0 la valeur par défaut était On mais cela a changé et il faut adapter son code pour les nouvelles versions ou les mises à jour de php chez votre hebergeur. • On peut voir la valeur du parametre REGISTER GLOBAL à l ’aide de la fonction phpinfo() 2.2 L ’origine des variables • • Par les url : une des façons les plus simples pour faire transiter des variables de pages en pages est l'insertion dans l'URL. On appelle ça communément la méthode GET. Anatomie d'une URL http://mastercaweb.u-strasbg.fr/script.php?variable=toto&foo=bar – http:// : C'est le protocole utilisé pour communiquer. – mastercaweb.u-strasbg.fr/ : C'est le nom d'hote, le nom DNS ou l'adresse IP du serveur référencé par cette url. – script.php : C'est le nom du script. – ? variable=toto &foo=bar : Il s'agit de la query ( requete) Elle permet d'envoyer des informations au script script.php • Avec la configuration register_global à On, le script "script.php" aurait automatiquement $var = 'test', $foo='bar'. Ces variables seraient des variables globales pour le script auquel vous accédez. 2.2 L ’origine des variables • Toutes les fois qu'un paramètre est indiqué dans l ’URL du script, PHP créé un tableau global nommé $HTTP_GET_VARS. • Il s'agit d'un tableau associatif. En prenant l'exemple précédent on aurait : • $HTTP_GET_VARS = array ('variable' => 'toto', 'foo' => 'bar');. • Depuis la version 4.1.0 une variable globale nommée $_GET contient exactement la même chose que $HTTP_GET_VARS. • Ce tableau est nommé superglobal 2.2 L ’origine des variables • Provenance : Formulaire • Une autre méthode commune pour passer une variable à un script est un formulaire sur une page web. 2.2 L ’origine des variables • Quand un utilisateur va cliquer sur le bouton "envoyer" le navigateur va soumettre le formulaire au script "script.php" avec une variable $foo qui aura la valeur que l'utilisateur aura rentrée. • Avec la configuration register_global à On, le script "script.php" aurait automatiquement attribué $foo='bar'. • De façon similaire à l'exemple précédent sur la provenance URL, PHP va générer automatiquement une tableau nommé $HTTP_POST_VARS. • Dans le cas de notre exemple : $HTTP_POST_VARS['foo'] = 'bar';. • Depuis la version 4.1.0 une variable globale nommée $_POST contient exactement la même chose que $HTTP_POST_VARS à savoir $_POST['foo'] qui aura pour valeur bar. 2.2 L ’origine des variables • Provenance : Un cookie : les cookies permettent de stocker des informations sur le disque dur de la machine cliente. • Dans l'exemple qui suit on va placer un cookie : /* durée de validité du cookie 24h */ setcookie('foo', 'bar', time()+86400, '', $HTTP_HOST); • Pour accéder aux valeurs du cookie on utilisera alors $_COOKIES["foo"] qui nous indiqueras sa valeur ie 'bar'. 2.2 L ’origine des variables • Provenance : Environnement ou Serveur : Le système d'exploitation ainsi que les serveur Web disposent de nombreuses variables qui peuvent être utilisées dans un script. • Une de ces variables les plus utilisées sont : Le nom du script lui même ainsi que le nom de l'hôte. • PHP créé automatiquement deux tableaux associatifs $HTTP_ENV_VARS et $HTTP_SERVER_VARS. • Apres PHP 4.1.0 les mêmes tableaux sont nommés : $_ENV et $_SERVER. ( voir fonction print_r ) 2.3 Utilisation des superglobales • Si vous utilisez plus d'une fois des variables passées en paramètre vous pouvez tout simplement les assigner à une variable. ex : $superCool = $_GET[superCool]; • Cela évitera de faire appel à des superglobales à chaque fois. • Cette technique peut aussi permettre d'éviter de recoder tous les scripts en assignant les bonnes valeurs aux bonnes variables en début de script. 2.3.2 Pourquoi superglobales ? • Normalement une variable utilisée dans une fonction est locale à celle ci. • Si on veut utiliser la variable globale dans une fonction global $superCool; • Les superglobales sont des exceptions à cette règle. Vous pouvez utiliser les superglobales $_GET, $_POST, $_COOKIE, $_ENV, $_SERVER et $_SESSION sans avoir besoin de les déclarer en globales. 2.4 Conclusion $_GET contient les variables passées par la méthode GET $_POST contient les variables passées par la méthode POST $_COOKIE contient les variables HTTP cookie $_SERVER contient les variables serveur (par ex. REMOTE_ADDR) contient les variables d'environnement • $_ENV Une fusion des variables GET. POST, COOKIE. • $_REQUEST En d'autres mots toutes les informations qui arrivent de l'utilisateur. Et d'un point de vue purement sécurité, ce n'est pas sûr. contient toutes les variables HTTP • $_SESSION enregistrées par le module de gestion de session • • • • 3.1 Les structures de controle <? while ( love & passion } { for( fight = 0 ; rights < freedom ; rights++ ) fight = standup( rights ); free( babylon ); } ?> 3.1 Les structures de controle if (condition) {exécute le code} <? // On affecte une valeur, à une variable. $un_nombre = 15 ; //Condition : if ( $un_nombre > 9) { // "Si" // on execute le code suivant. echo "Superieur à 9"; } ?> 3.1 Les structures de controle if (condition) {exécute le code} else {exécute le code} <? // On affecte une valeur, à une variable. $un_nombre = 5 ; //Condition : if ( $un_nombre > 9) { // Si // on execute le code suivant. echo "Superieur à 9"; }else{ // Ou echo "Alors Inferieur à 9"; } ?> 3.1 Les structures de controle if (condition) {exécute le code} elseif (condition) {exécute le code} else {exécute le code} <? ?> // On affecte une valeur, à une variable. $un_nombre = 5 ; //Condition : if ( $un_nombre > 9) { // "Si" // on execute le code suivant. echo "Superieur à 9"; }elseif( $un_nombre < 2) { // ou si // alors sinon on execute le code suivant. echo "Inferieur à 2"; }else{ // Ou echo "le nombre est inferieur à 9 et est superieur à 2 "; } 3.1 Les structures de controle • for(évaluation de l'expression (expr1); condition(expr2) ; expr3 ) { exécute le code} <? for ($i=0; $i < 10 ; $i++ ){ echo $i . " est inférieur à 10<br />"; } // Pour la variable $i initialisé à Zéro // Et si $i est inférieur à 10, on exécute le code entre {}. // Apres avoir exécuté le code entre {}, on exécute le code expr3, c'est à dire $i++. // et on reteste la condition ?> 3.1 Les structures de controle while ( condition ) {exécute le code } <? // on initialise la variable '$i' avec la valeur 0 $i = 0; // Tant que la variable $i est inférieur à 10 while ( $i <= 10 ) { // on execute le code suivante // affichage de la variable $i echo "$i<br />"; // incrementation de la variable , peut se noter aussi $i = $i +1 ; $i++; } ?> 3.1 Les structures de controle • Break <? // On initialise $i à 0. $i= 0; // Tant que 1, (boucle infinie) while (1){ // Si $i est supérieur à 10. if ($i > 10 ) { // On stoppe le while avec le break. break; } // Affichage d'un message. echo "Passage en boucle pour la $i eme fois.<br />" ; // incrementation. $i++; } ?> 3.1 Les structures de controle • foreach(évaluation de l'expression ) {exécute le code} <? // On crée une variable $Tableau, et on insére dedans plusieurs éléments. $Tableau = array("Punk","Post","Hard","Jazz"); // On met le pointeur du tableau au début. // Pour chaque élément du $Tableau représenté par $rock $i=0; foreach ($Tableau as $Rock ) { // on execute le code. echo "element $i du tableau : $Rock est un élément du tableau rock !<br />"; $i++; } ?> 3.1 Les structures de controle • switch ($variable) { case "valeur": exécute de code; break; } <? $valeur = "peace"; switch ($valeur){ // Si valeur est égale à peace on execute le code jusqu'au break. case "peace": echo "La valeur contenu dans valeur est 'peace'"; break; case "hate": echo "La valeur contenu dans valeur est 'hate'"; break; // Si on souhaite executé un morceau de code si la valeur ne fait pas partie des cases. default: echo "Je n'ai pas reconnu la valeur '$valeur'"; break; } ?> 3.1.2 Operateurs de comparaisons • • • • • • • • • $a == $b Egal TRUE si $a est égal à $b . $a === $b Identique TRUE si $a est égal à $b et qu'ils sont de même type (introduit en PHP 4). $a != $b Différent TRUE si $a est différent de $b . $a <> $b Différent TRUE si $a est différent de $b . $a !== $b Différent TRUE si $a est différent de $b ou bien qu'ils ne sont pas du même type. (introduit en PHP 4) $a < $b Plus petit que TRUE si $a est strictement plus petit que $b . $a > $b Plus grand TRUE si $a est strictement plus grand que $b . $a <= $b Inférieur ou égal TRUE si $a est plus petit ou égal à $b . $a >= $b Supérieur ou égal TRUE si $a est plus grand ou égal à $b . 3.1.3 Les operateurs logiques • && c'est l'équivalent du ET Ex: $toto=6; $titi=3; ($toto < 10 && $titi > 1) retourne VRAI • || c'est l'équivalent du OU Ex: $toto=6; $titi=3; ($toto==5 || $titi==5) retourne FAUX • ! C'est l'équivalent du NON Ex: $toto=6; $titi=3; !($toto==$titi) retourne VRAI 3.1,4 Création d’un site dynamique en php • Cahier des charges : créer l’ossature d’un site web dynamique • On utilisera plusieurs fichiers : – – – – – – Index.php la page qui permettra de générer le site navigation.htm menu du site homepage.htm page d’accueil du site liens.htm liens ouaibes Cv.htm page avec cv bas_page.htm affichage du bas de page 3.2 Envoyer des mails en php • Envoyer un mail en php est très facile , tout se résume en une ligne , à l’aide de la fonction mail() et de ses paramètres. • La fonction reçoit un minimum de paramètres , à qui veut on écrire tout d’abord , ( champ to: ) quel est le sujet du mail ( subject ) , le contenu de notre message et enfin l’expéditeur (champ from: ) • Le champ ( from: ) permet aussi de spécifier d’éventuels copies ( Cc ) ou copies cachées ( Bcc ). 3.2 Envoyer des mails en php • Envoyer un mail en php est très facile , tout se résume en une ligne , à l’aide de la fonction mail() et de ses paramètres. • La fonction reçoit un minimum de paramètres , à qui veut on écrire tout d’abord , ( champ to: ) quel est le sujet du mail ( subject ) , le contenu de notre message et enfin l’expéditeur (champ from: ) • Le champ ( from: ) permet aussi de spécifier d’éventuels copies ( Cc ) ou copies cachées ( Bcc ). 3.2 Exemples d’utilisation de mail() <? //On envoie un message à [email protected] mail(' [email protected] ', 'sujet : admiration !!!', "Bofh président !!\n Trop bien !!!!!!"); ?> <? ?> $destinataires = ' [email protected], [email protected] '; //On sépare les destinataires par une virgule. $sujet = 'plouf !!!'; mail($destinataires, $sujet, "Trop sympatoche\n kewwwwwwwwwwl ! "); 3.2 adresse de l'expediteur <? $destinataire = '[email protected],[email protected]'; $sujet = 'is there someone ?'; $entete = "From: [email protected]\n"; mail($destinataire, $sujet, "Hello \n someone's here ? ",$entete); ?> <? ?> $destinataire = '[email protected],[email protected]'; $sujet = 'is there someone ?'; $entetes = "From: [email protected]\n"; $entetes .= "Reply-to: [email protected]\n"; mail($destinataire, $sujet, "Hello \n someone's here ? ",$entetes); 3.2.1 Exemple d’utilisation de mail() <?php $to = ‘’[email protected]’’; $sujet = ‘’I luv ur software’’; $contenu = ‘’ Just joking man ! ‘’; $entetes = ‘’From: [email protected]\n‘’; $entetes .= "Reply-to: [email protected]\n"; $entetes .= "Cc: [email protected] \n"; $entetes .= "Bcc: [email protected] \n"; $reponse = mail($to,$sujet,$contenu,$entetes); if ($reponse ){ echo "message tipar !!!!!!!"; } else { die( "Mssieur le facteur je crois qu'on a un problème !!!!"); } ?> 3.3 Site dynamique multilingue • Principe : on va stocker le contenu texte dans des variables spéciales appelées « constantes » . • On utilisera un cookie pour retenir la langue choisie par le visiteur du site • On pourra determiner la langue à utiliser en fonction d'une variable d'env. : HTTP_ACCEPT_LANGUAGE . • On utilisera pour chaque langue un fichier à part pour faciliter la mise à jour. 3.3 Site dynamique multilingue •Les constantes : Ce sont des variables définies à l’aide de la fonction define() define(‘SUPER_CONSTANTE', ‘valeur de ma super constante'); •Par convention les noms des constantes sont toujours en majuscules pour les différencier des autres variables de nos scripts. define(‘SALUTATION’,’Yo c\’est super php!’); echo SALUTATION; 3.3 Site dynamique multilingue : lang_fr.php <?php define(‘MSG_BIENVENUE', 'Bienvenue sur mon site’); define(‘MSG_GENIAL‘,’C\’est super php!’); define(‘MSG_COPYLEFT‘,’Site fait par moi !’); define('LIEN_FR','francais'); define('LIEN_EN','anglais'); ?> 3.4 Site dynamique multilingue : lang_en.php <?php define(‘MSG_BIENVENUE', Welcome to my website’); define(‘MSG_GENIAL‘,’PHP is awesome :!’); define(‘MSG_COPYLEFT‘,’made by myself’); define('LIEN_FR','french'); define('LIEN_EN','english'); ?> 3.5 Intégration des fichiers choixlang.php <? ?> //premier cas pas de cookie ni variable langue initialisée on part sur la langue du navigateur If((!$_GET['lang'])&&(!$_COOKIE['lang'])){ $lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'],0,2); setCookie("lang",$lang,time()+86400); } //deuxieme cas une valeur dans le cookie Elseif(($_COOKIE['lang'])&&(!$_GET['lang'])){ $lang=$_COOKIE['lang']; } //sinon on se base sur la lang affecté en param Else{ $lang=$_GET['lang']; setCookie("lang",$lang,time()+86400); } // on switch sur lang pour savoir quel fichier inclure switch($lang){ case "fr": include "lang/lang_fr.php"; break; case "en": include "lang/lang_en.php"; break; default : include "lang/lang_fr.php"; break; } 3.6 Notre page web multilingue index.php <?php require(‘choixlang.php’); ?> <html> <body> <?php echo MSG_BIENVENUE; ?> <br/>Avis sur php : <?php echo MSG_GENIAL; ?> <br/>Auteur : <?php echo MSG_COPYLEFT; ?> <br/><br/> <a href=?lang=fr> <?php echo LIEN_FR; ?> <a href=?lang=en> <?php echo LIEN_EN; ?> </body> </html> 3.7 Les fichiers en PHP • Un fichier stocke sur le disque dur des éléments ( textes,images... ) • Php ignore la structure d’un fichier il traite de la même façon un fichier binaire ( images / sons / prog… ) qu’un fichier texte. • Quand on ouvre un fichier en php on doit indiquer comment php doit evaluer le fichier ( LECTURE - ECRITURE – MODIFICATION ) • On appelle "pointeur de fichier" la variable qui est affecté de la valeur de la fonction d'ouverture de fichier : $fp=fopen("leGentilFichier", 'a+'); fwrite($fp,"Barbatruc !!!!! \n"); 3.7 Lecture rapide d’un fichier • Readfile() : affiche le contenu d’un fichier à l’écran <? // affichage à l’ecran de MonSuperFichier.txt readfile(‘’MonSuperFichier.txt’’); // affichage url readfile(‘’http://www.perdu.com/’’); ?> 3.8 Ouverture d’un fichier La fonction fopen : fopen(NomDuFichier, ModeOuverture) • "r" - Ouvre en lecture seule et pointeur de fichier au début. • "r+" - Ouvre en lecture/écriture et pointeur de fichier au début. • "w" - Ouvre en ecriture seule - pointeur de fichier au début/réduit la taille du fichier à 0. Si le fichier n'existe pas, on tente de le créer. • "w+" - Ouvre en lecture/écriture, pointeur de fichier au début du fichier réduit la taille du fichier à 0. Si le fichier n'existe pas, on tente de le créer. • "a" - Ouvre en ecriture seule; place le pointeur de fichier à la fin du fichier file. Si le fichier n'existe pas, on tente de le créer. • "a+" - Ouvre en lecture et écriture; place le pointeur de fichier à la fin du fichier. Si le fichier n'existe pas, on tente de le créer. • Fopen renvoie un booléen : • if (!($f=fopen("exemple.txt","r"))) • exit("impossible d'ouvrir le fichier !!!!"); 3.8.2 Fermeture d’un fichier • Un fichier ouvert à l’aide de la fonction fopen doit être fermé on utilise ainsi la fonction fclose fclose (pointeurversmonfichier); 3.8.3 Exemples • <? // ouverture sur un serveur ftp $fp = fopen("ftp://login:mdp@nom_du_serveur_ftp/nom_du_fichier", "w"); // ouverture sur un serveur http $fp = fopen("http://www.perdu.com/","r"); // ouverture d'un fichier en local (sur le serveur); $fp = fopen("/mon_rep/mon_fichier.txt","r"); fclose($fp ); ?> • <? $fp = fopen("c:\MonRepertoire\info.txt", "r"); ?> 3.8.4 Lecture d’un fichier <? // ouverture du fichier en lecture $fp = fopen ( "MonSuperFichier.txt" ," r " ) ; // affichage du fichier fpassthru($fp ) ; fclose($fp ); ?> <? // affichage du fichier readfile(‘’MonSuperFichier.txt’’); ?> 3.8.5 Lecture d’un fichier ligne par ligne • fgets() parcourt un fichier ligne par ligne fgets(PointeurVersMonFichier[,longueur]) • fgets permet de lire une chaine dans un fichier (pointeurVersMonFichier est initialisé à l’aide de fopen) a partir de la position courante dont la longueur est specifié par longueur. 3.8.6 Lecture d’un fichier ligne par ligne • <? // ouverture du fichier $fp = fopen ("/mon_rep/mon_fichier.txt", "r"); while (!feof($fp )) { $contenuFichier = fgets($fp); // Ecrire à l'écran la chaîne lue echo $contenuFichier; } fclose ($fp ); ?> 3.8.7 Ecrire dans un fichier • fwrite (PointeurDeFichier, ChaineAEcrire [, Longueur]) fputs() est un alias de fwrite -> fwrite()=fputs() <? /* ouverture du fichier en mode lecture-écriture : le pointeur est à la fin du fichier */ $fp =fopen('fichier.txt' , 'a+'); // écriture de la ligne fwrite($fp ,"Nouvelle ligne à insérer \n"); // fermeture du fichier fclose ($fp ); ?> 3.8.7 se deplacer dans un fichier • Pour revenir au debut du fichier : rewind() Ex : <? $fichier= fopen(''superfichier.txt'',"r+"); $contenu= fgets($fichier,25); rewind($fichier); // rewiiiiiiiiiiiiiiiiiiiiiiiiind fclose($fichier); ?> • Se deplacer dans un fichier fseek() fseek(PointeurDeFichier,position) <? $fichier= fopen(''superfichier.txt'',"r+"); $contenu= fgets($fichier,25); fseek ($fichier,0); // rewiiiiiiiiiiiiiiiiiiiiiiiiind fclose($fichier); ?> • 3.8.9 Exemple : Ecrire un compteur en php • Il suffit de stocker quelque part le nombre de visite dans une base de donnée ou dans un fichier • On aura besoin d’un fichier "compteur.txt" qui stockera la valeur de notre compteur. On utilisera fwrite et fopen pour ecrire ou lire dans le fichier • Exemple : http://mastercaweb.u-strasbg.fr/bofh/ • Source : http://mastercaweb.ustrasbg.fr/bofh/compteur.phps 3.8.10 Exemples : Ecrire un livre d'or • Il suffit de stocker dans un fichier texte les contributions de nos visiteurs • On aura besoin d’un fichier "livredor.txt" qui stockera ce que nos visiteurs posteront à l'aide d'un formulaire • Exemple : http://mastercaweb.u-strasbg.fr/bofh/livredor/ • Source : http://mastercaweb.u-strasbg.fr/bofh/livredor/src/ 4.0 Les sessions • Les sessions est un moyen simple de conserver des variables sur toutes les pages d ’un site. • Jusqu'ici, on était arrivés à passer des variables de page en page via la méthode GET (en modifiant l'url : page.php? variable=valeur&variable2=valeur2) et via la méthode POST (=un formulaire). • Si on veut transmettre une ou plusieurs variables sur TOUTES les pages de son site, ca devient ingérable avec GET et POST... D'où l'invention des sessions. 4.0 Les sessions • Un visiteur se connecte. On demande à créer une session pour lui : PHP génère un identifiant unique pour ce visiteur du site. • Pour cela, on utilise la fonction session_start(). L ’identifiant est une chaine de caractères assez conséquente codée en hexadécimal. • Ex : a02bbffc6198e6e0cc2715047bc3766f • Ce numéro sert d'identifiant et est appelé "ID de session" (ou PHPSESSID). • PHP transmet automatiquement cet ID de page en page en utilisant un cookie ou via l'url (ex : mapage.php? PHPSESSID=a02bbffc6198e6e0cc2715047bc3766f). 4.0 Les sessions • A partir de là on peut créer une infinité de variables de session. Par exemple : $_SESSION['login'] contient le login du visiteur, $_SESSION['password'] contient le mot de passe etc... • L'avantage, c'est que le serveur conserve ces variables même lorsque la page PHP a fini d'être générée. • Quelque soit la page visitée, on peut récupérer par exemple le login et le mot de passe du visiteur ! • Lorsque le visiteur se déconnecte (il a cliqué sur un bouton "Déconnecter" ou est resté inactif trop longtemps), alors la session est fermée avec la fonction session_destroy() • Il ne faut jamais oublier d'appeler session_start() sur chacune des pages AVANT d'écrire le moindre code HTML. 4.1 Utilité des sessions • Un script qui demande un login / mot de passe pour qu'un visiteur puisse se "connecter" (s'authentifier). Ainsi, on peut enregistrer des variables de session et se souvenir du login du visiteur sur toutes les pages du site ! • Ce qui permet d'ailleurs de créer une zone d'administration sécurisée sur plusieurs fichiers SANS utiliser de .htaccess. Les variables de sessions sont suffisantes pour vérifier si le mot de passe est le bon. • on se sert des sessions sur les sites de vente en ligne. Cela permet de gérer un "panier" : on retient les produits que commande le client, quelle que soit la page où il est. Lorsqu'il valide sa commande, on récupère ces informations et on le fait payer… 4.2 Ecriture d'une variable de session • On utilisera session_start() et la superglobale $_SESSION[] <?php // initialisation session_start() ; $_SESSION['IlEstCommentBofh'] = 'il est cool'; ?> 4.3 Lecture d'une variable <?php // initialisation session_start() ; // tester la présence de la variable 'IlEstCommentBofh' dans la session if ( isset( $_SESSION['IlEstCommentBofh'] ) ) { echo 'IlEstCommentBofh a pour valeur ' ; // lecture de la variable de session 'langage' echo $_SESSION['IlEstCommentBofh'] ; } else { echo 'IlEstCommentBofh inconnu snif snif' ; } ?> 4.4 Fin de session <?php // on initialise et utilise la session session_start(); $_SESSION['IlEstCommentBofh'] = 'Il est cool'; echo $_SESSION['IlEstCommentBofh']; // affiche Il est cool // php is alive il travaille // on détruit la session session_destroy(); unset($_SESSION); $_SESSION['IlEstCommentBofh'] ; // n'affiche rien ?> 5.0 Les expressions régulières • Les expressions régulières sont des modèles créés à l'aide de caractères ASCII permettant de manipuler des chaînes de caractères et de trouver les portions de la chaîne correspondant au modèle. • Ce système vient de POSIX (norme à l'origine sous Unix). De nombreux scripts sous UNIX les utilisent. • Les expressions régulières permettent de rechercher des occurrences (= suite de caractères correspondant à ce que l'on recherche) grâce à une série de caractères spéciaux. L'expression régulière en elle-même est donc une chaîne de caractère contenant des caractères spéciaux et des caractères standards 5.1 Domaine d’application • Vérifier la validité des chaînes de caractères ( saisie dans un formulaire : email, entrée chiffrée, entrée texte, etc...) • Extraire des parties bien précises d'une chaîne, d'un texte, d'une page... • Modifier une date au format us (05-30-1977) au format fr notamment (30/05/1977) • Remplacer automatiquement toutes les adresses "http://" par des liens cliquables (cf forums, guestbook … ) • Pour créer son propre langage simplifié à partir de la norme HTML, bbCode ([b][/b]...) 5.1 Champ d’application • Il existe 2 types d'expressions régulières. • POSIX : ( Portable Operating System Interface plus le X d'UniX )c'est un langage d'expressions régulières mis en avant par PHP • PCRE : ( Perl Compatible Regular Expression ) :ces expressions régulières sont issues d'un autre langage (le Perl) plus complexes, elles sont surtout bien plus rapides et performantes. 5.2 Les fonctions utiles • preg_grep , preg_split , preg_quote , preg_match , preg_match_all , preg_replace , preg_replace_callback • Chaque fonction a sa particularité, certaines permettent de faire simplement une recherche, d'autre une recherche / remplacement, mais leur gros point commun c'est qu'elles utilisent un "langage" identique pour faire une recherche. 5.3 preg_match <? ?> if (preg_match("** REGEX **", "string’’)) { echo 'Le mot que vous cherchez se trouve dans la chaîne'; } else { echo 'Le mot que vous cherchez ne se trouve pas dans la chaîne'; } !(((https?|ftp)://(w{3}\.)?)(?<\!www)(\w+-?)*\.([a-z]{2,6}))! 5.1 Faire des recherches sur les chaines • une regex est toujours entourée de caractères spéciaux appelés délimiteurs. On peut choisir n'importe quel caractère spécial comme délimiteur, dans les exemples suivant on prendra par convention le délimiteur « ! » !Ma regex! /Ma regex/ 'Ma regex' 5.1 Faire des recherches sur les chaines • Pourquoi des délimiteurs ‘’ !MA REGEX! ‘’ ‘’ !MA REGEX!Options ‘’ • Exemple : <? if (preg_match("!ture!", ‘’la culture c’est comme la confiture…")) { echo 'VRAI'; } else { echo 'FAUX'; } ?> 5.1 Faire des recherches sur les chaines • Attention les regex sont sensibles à la casse • Pour ne pas faire la différence majuscules / minuscules on peut ajouter une option à notre regex CHAINE REGEX RESULTAT J’adore aller à Londres !Londres! VRAI J’adore aller à Londres !LONDRES! FAUX CHAINE REGEX RESULTAT J’adore aller à Londres !Londres!i VRAI J’adore aller à Londres !LONDRES!i VRAI 5.1 Faire des recherches sur les chaines • La barre oblique « | » signifie « ou » dans les regex : CHAINE REGEX RESULTAT J’adore aller à Londres !Londres|Amsterdam! VRAI J’adore aller à Muloose !Londres|Amsterdam! FAUX 5.1 faire des recherches dans des chaines • Les regex permettent des recherches précises et très structurés, dans les exemples précédant le mot pouvait se trouver n’importe ou dans la chaîne • ^ (accent circonflexe) : indique le début d'une chaîne. • $ (dollar) : indique la fin d'un chaîne. • Ainsi si on veut qu’un chaine commence par ‘’Yo’’ il faudra noter la regex de cette manière : !^Yo! • De même, si on veut vérifier que le chaîne se termine par ‘’ ca gaze ", on écrira cette regex : !ca gaze$! 5.1 faire des recherches dans des chaines CHAINE REGEX RESULTAT Yo Bob ca gaze !^Yo! VRAI Yo Bob ca gaze !ca gaze$! VRAI Yo Bob ca roule !ca gaze$! FAUX 5.2 Les classes de caractères. • !gr[aio]s! • Entre crochets = la classe de caractères. Cela signifie qu'une des lettres à l'intérieur peut convenir pour notre REGEX. • Notre regex reconnaît donc gras gros et gris 5.2 Les classes de caractères CHAINE REGEX RESULTAT La nuit, tous les chats sont gris !gr[aoi]s! La nuit, tous les chats sont gros !gr[aoi]s! VRAI VRAI Soyez réaliste demander l’impossible !^[aeiouy]! Kawai ![aeiouy]$! FAUX VRAI 5.3 Les intervalles de classes • Grâce au symbole "-" (le tiret), on peut autoriser toute une plage de caractères. Si on veut que la chaine contienne une lettre on écrira pas : [abcdefghijklmnopqrstuvwxyz] on peut utiliser les intervalles. • [a-z] ou [a-e] avec les chiffres : [0-9] , [1-8] … • On peu combiner les plages aussi : [a-z0-9]. Cela signifie "N'importe quelle lettre (minuscule) OU un chiffre". On peut aussi autoriser les majuscules, sans passer par les options : [a-zA-Z0-9]. [a-zA-Z0-9] =[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789] 5.3 Les classes de caractères. CHAINE REGEX RESULTAT Cette phrase contient une lettre ![a-z]! VRAI cette phrase ne comporte pas de majuscule ni de chiffres ![a-z0-9]! VRAI Cette phrase commence pas par un chiffre !^[0-9]! FAUX <h1>Une balise de titre HTML</h1> !<h[1-6]>! VRAI 5.3 Les classes de caractères • Pour omettre un caractère dans une classe on utilise aussi le symbole ‘^’ CHAINE REGEX RESULTAT Cette phrase ne contient pas de chiffre ![^0-9]! VRAI cette phrase ne comporte pas de majuscule ni de chiffre ![^A-Z0-9]! VRAI Cette phrase ne se termine pas par une voyelle ![^aeiouy]$! FAUX Cette phrase ne commence pas par une minuscule !^[^a-z]! VRAI 5.4 Les quantificateurs • Les quantificateurs, ce sont des symboles qui permettent de dire combien de fois peuvent se répéter un caractère, ou une suite de caractères. • ? (point d'interrogation) : ce symbole indique que la lettre est facultative. Elle peut y être 0 ou 1 fois. Ainsi, !a?! reconnaît 0 ou 1 "a". • + (signe plus) : la lettre est obligatoire. Elle peut apparaître 1 ou plusieurs fois. Ainsi, !a+! reconnaît "a", "aa", "aaa", "aaaa" … • * (étoile) : la lettre est facultative. Elle peut apparaître 0, 1 ou plusieurs fois. Ainsi, !a*! reconnaît "a", "aa", "aaa", "aaaa" etc... Comme c’est facultatif si a n’y est pas ça renvoi vrai aussi !!! • Les quantificateurs s'appliquent à la lettre directement derrière. On peut ainsi autoriser le mot ‘’disque" qu'il soit au singulier comme au pluriel, avec la regex !disques?! 5.4 Les quantificateurs • Pour répéter plusieurs lettres on peut utiliser les parenthèses : • !Prout(prout)*! : reconnaitra Proutproutproutprout … 5.4 Les quantificateurs CHAINE REGEX RESULTAT aaaaa !a+! VRAI bbbb !c?! VRAI Prouuuuuuuuuuut !^Prou+t! VRAI Blablablablabla !^Bla(bla)*$! VRAI 5.4 Les quantificateurs. • ? correspond à {0,1} • + correspond à {1,} • * correspond à {0,} 5.5 Les métacaractères. • « Ce sont des caractères pas comme les autres qui servent normalement à faire quelque chose de particulier. » • En PCRE (des Regex), les métacaractères qu'il faut connaître sont les suivants : !^$()[]{}?+*.\ 5.5 Les métacaractères : les termes reservés • "!" (point d'exclamation) : il sert toujours à indiquer la fin de la Regex. Si on cherche ‘’kestumedis !? ’’ La regex sera : ! kestumedis \!\?! • "]" (crochet fermant) : normalement, le crochet fermant indique la fin de la classe il faut là aussi mettre un antislash devant si on veut l’utiliser dans une regex. • "-" (tiret) : Le tiret sert à définir un intervalle de classe (comme [a-z]). [a-z0-9-] permet de chercher une lettre, un chiffre, ou un tiret. 5.5.2 Exemples : • • On va tester la saisie d’une adresse email dans un formulaire. Les regles pour une adresse email valide : – – – – On a tout d'abord le pseudonyme (au minimum une lettre). Il peut y avoir des lettres minuscules (pas de majuscules), des chiffres, des points, des tirets et des underscores "_". Il y a ensuite une arobase : @ Ensuite il y a le nom du fournisseur d'accès. Pour ce nom, que des minuscles, des chiffres, des tirets, des points et des underscores. Enfin, il y a l'extension (comme ".fr"). Cette extension comporte un point, suivi de 2 à 6 lettres (minuscules). 5.5.2 Valider une adresse email • !^$! Tout d’abord une fin et un début de chaine • Ensuite, on a des lettres, chiffres, tirets, points, underscores, au moins une fois. On utilise donc la classe [a-z0-9._-] à la suite de laquelle on rajoute le signe + : !^[a-z0-9._-]+$! • l'arobase : !^[a-z0-9._-]+@$! • Puis, encore une suite de lettres, chiffres, points, tirets au moins 2 fois : !^[a-z0-9._-]+@[a-z0-9._-]{2,}$! • Pour le point de .fr .com … : !^[a-z0-9._-]+@[a-z0-9._-]{2,}\.$! • Enfin l’extension (en minuscules) : !^[a-z0-9._-]+@[a-z0-9._-]{2,}\.[a-z]{2,6}$! 5.5.2 Valider une adresse email <? if (isset($_POST['mail'])) { if (preg_match("!^[a-z0-9._-]+@[a-z0-9._-]{2,}\.[a-z]{2,6}$!", $_POST['mail'])) { echo 'L\'adresse ' . $_POST['mail'] . ' est <strong>valide</strong> !'; } else { echo 'L\'adresse ' . $_POST['mail'] . ' n\'est pas valide, recommencez !'; } } ?> <form method="post"> <p> <label for="mail">Votre mail ?</label> <input id="mail" name="mail" /><br /> <input type="submit" value="Vérifier le mail" /> </p> </form> 5.5.3 les autres classes génériques \d tout caractère décimal [0-9] \D tout caractère qui n'est pas un caractère décimal [^0-9] \t Indique une tabulation \n Indique une nouvelle ligne \r Indique un retour chariot \s tout caractère blanc ( \n \r \t ) \S tout caractère qui n'est pas un caractère blanc \w tout caractère de [A-Za-z0-9_] plus les accentués \W tout caractère qui n'est pas un caractère [^A-Za-z0-9_] . tout caractère sauf \n 5.6 Captures et remplacement de chaines. • Les expressions regulieres permettent de faire des recherches très puissantes dans les chaines de caractères mais elle permettent aussi d ’effectuer des rechercher / remplacer • par exemple on pourra chercher s'il y a des adresses e-mail dans un message laissé par un visiteur et modifier automatiquement son message pour mettre un lien <a href="mailto:[email protected]"> devant chaque adresse, ce qui rendra les e-mails cliquables ! • On pourra ainsi rendre les liens http:// automatiquement cliquables eux aussi ou bien créer notre propre langage simplifié pour le visiteur, comme le fameux bbCode utilisé sur la plupart des forums. 5.6.1 Les parenthèses capturantes • Pour l ’instant on se servait des parenthèses pour répéter des éléments que l ’on veut chercher. • On va se servir de la fonction preg_replace pour substituer des chaines. • preg_replace($Modele, $chaine_a_remplacer, $chaine); • C'est avec cette fonction que nous allons pouvoir réaliser ce qu'on appelle une "capture" de chaîne. • Chaque fois qu ’on utilisera des parenthèses, ça va créer une "variable" contenant ce qu'elles entourent. 5.6.1 Les parenthèses capturantes • Exemple : !\[b\](.+)\[/b\]! • Les parenthèses ici sont inutiles dans le cas d ’une recherche simple, mais pour faire du rechercher remplacer ca va être utile. • A chaque parenthèse ouverte dans une regex, php va créer une variable appelée $1 (pour la première parenthèse), $2 pour la seconde etc… • On va se servir ensuite de ces variables pour modifier la chaîne (=faire un remplacement). 5.6.2 Mettre en gras du texte <? $texte = preg_replace('!\[b\](.+)\[/b\]!i', '<strong>$1</strong>', $texte); ?> • • • • premier paramètre la Regex. Attention chaque parenthèse va créer une variable ($1, $2 etc...) On ajoute l'option "i" pour que le code fonctionne aussi avec des majuscules ([B] [/B]) Ensuite on indique le texte de remplacement : "<strong>$1</strong>" Enfin, dernier paramètre, c'est le texte dans lequel on fait notre recherche / remplacement. 5.7 Regles à respecter • • • • • • • Avec plusieurs parenthèses, pour savoir le numéro d'une parenthèse il suffit de les compter dans l'ordre de gauche à droite. exemple !(anti)co(nsti)(tu(tion)nelle)ment! Il y a 4 parenthèses dans cette regex (donc $1, $2, $3 et $4). La parenthèse numéro 3 ($3) contient "tutionnelle", et la parenthèse $4 contient "tion" C ’est l'ordre dans lequel les parenthèses sont ouvertes qui est important. Les regex sont limitées à 99 parenthèses capturantes dans une Regex $99 est donc la valeur maximum. Il faut savoir qu ’une variable $0 est toujours créée, elle contient toute la Regex. Sur le même exemple que tout à l'heure : !(anti)co(nsti)(tu(tion)nelle)ment! $0 contient "anticonstitutionnellement". Pour ne pas qu ’une parenthèse soit capturante (=pour simplifier les comptes, ou ou si la regex est très complexe), il faut qu'elle commence par un point d'interrogation suivi d'un deux points ":" -> ? : 5.7 Regles à respecter !(anti)co(?:nsti)(tu(tion)nelle)ment! La seconde parenthèse n'est pas capturante ! Il ne nous reste que 3 variables (4 si on compte $0) : 1. $0 : anticonstitutionnellement 2. $1 : anti 3. $2 : tutionnelle 4. $3 : tion 5.8 Exemple concret du bbcode • Nous allons réaliser ce qu'on appelle un parser (= "parseur"). • Le parser va servir à transformer le texte rédigé par un visiteur (forum / chat / livre d ’or...), en un texte inoffensif mais qui accepte aussi du bbCode ! [b][/b] : pour mettre du texte en gras. • [i][/i] : pour mettre du texte en italique. • [color=red][/color] : pour colorer le texte • • Nous ferons en sorte de remplacer aussi automatiquement les URL (http://) par des liens cliquables. 5.8 Contraintes • Nous verrons tout d ’abord le texte en gras et en italique • cf code pour le gras pour le faire fonctionner on va ajouter des options au regex : – * i : pour accepter les majuscules comme les minuscules ([B] et [b] – * s : pour que le "point" fonctionne aussi pour les retours à la ligne (pour que le texte puisse être en gras sur plusieurs lignes) – * U : le U majuscule est une option qui signifie "Ungreedy" ("pas gourmand"). "Ce texte est [b]important[/b], il faut me [b]comprendre[/b] ! `` Sans l'option Ungreedy, la Regex aurait voulu mettre en gras tout ce qu'il y a entre le premier [b] et le dernier [/b] (c'est-à-dire "important[/b], il faut me [b]comprendre"), • En utilisant l'option "U", la Regex s'arrêtera au premier [/b]. 5.8 exemple bbcode <? $texte = preg_replace('!\[b\](.+)\[/b\]!isU', '<strong>$1</strong>', $texte); $texte = preg_replace('!\[i\](.+)\[/i\]!isU', '<i>$1</i>', $texte); $texte = preg_replace('!\[color=(red|green|blue|yellow|purple|olive)\](.+)\[/color\]!isU', '<span style="color=$1">$2</span>', $texte); $texte = preg_replace('!http://[a-z0-9._/-]+!i', '<a href="$0">$0</a>', $texte); ?> 6.0 Images dynamiques en php avec GD • GD est une librairie de fonctions permettant la création/manipulation d'images « à la volée » • Depuis php 4.3 une version de GD est intégrée au système de base. • Attention avec GD > 1,3 la génération d'images GIF n'est plus possible ou limitée mais le png remplacera avantageusement le GIF. • Il faut impérativement vérifier que GD soit installée sur le serveur pour pouvoir l'utiliser (cf php.ini ou phpinfo(); ) • Si GD n'est pas installée : « Fatal error: Call to undefined function » 6.0 GD : premier test Pour générer notre image : (image.php) <?php // on spécifie le type de document que l'on va créer (ici une image au format PNG header ("Content-type: image/png"); // on dessine une image vide de 200 pixels sur 100 $image = @ImageCreate (200, 100) or die ("Erreur lors de la création de l'image"); // on applique une couleur de fond, les couleurs sont au format RVB $couleur_fond = ImageColorAllocate ($image, 255, 0, 0); // 255 intensité de rouge à donf // on dessine notre image PNG ImagePng ($image); ?> Un fichier html appelant notre script : <html> <head> <title>Superbe demo GD</title> </head> <body> <img src="image.php"> </body> </html> 6.0 La librairie GD • Lorsque l'on utilise du HTML on a pas besoin d'utiliser les entêtes HTML par contre lorsque le résultat de notre script affiche une image il faut changer l'entête de notre fichier de sortie. header ("Content-type: image/png"); pour du png header ("Content-type: image/jpg"); pour du jpeg header("Content-type: image/gif"); //format gif header("Content-type: image/bmp"); //format bmp header("Content-type: image/xbm"); header("Content-type: application/x-shockwave-flash"); //animation flash 6.0 La librairie GD <?php if (isset($_POST['rouge']) && isset($_POST['vert']) && isset($_POST['bleu'])) { header ("Content-type: image/png"); $image = @ImageCreate (200, 100) or die ("Erreur lors de la création de l'image"); $couleur_fond = ImageColorAllocate ($image, $_POST['rouge'], $_POST['vert'], $_POST['bleu']); ImagePng($image); } else { echo 'Remplissez tous les champs du formulaire !!!'; } ?> <html> <head> <title>Demo surpuissante avec GD</title> </head> <body> Sélectionner l'intensité des différentes teintes :<br /> <form action="image2.php" method="post"> Rouge ( 0 - 255) : <input type="text" name="rouge"><br /> Vert ( 0 - 255) : <input type="text" name="vert"><br /> Bleu ( 0 - 255) : <input type="text" name="bleu"><br /> <input type="submit" value="gd rends moi fort!!!"> </form> </body> </html> 6.0 La librairie GD : fonctions utiles • • • • • • • • • • • $image = ImageCreate ($largeur, $hauteur) // permet de créer une image (png). $image = ImageCreateTrueColor ($largeur, $hauteur) // idem a ImageCreate mais pour les jpeg. $couleur = ImageColorAllocate ($image, $rouge, $vert, $bleu) // definis une couleur avec les intensités RGB ( Red Green Blue). ImageEllipse ($image, $x, $y, $l, $h, $couleur) // Dessine dans l'image $image une ellipse en partant du poit ($x,$y), de largeur $l, de hauteur $h et de couleur $couleur. ImageFilledEllipse ($image, $x, $y, $l, $h, $couleurl) // Idem que ImageEllipse mais avec une ellipse pleine. ImageFill ($image, $x, $y, $couleur) // colorie dans l'image $image un carré avec une position $x sur $y et de la couleur $couleur. ImageLine ($image, $x1, $y1, $x2, $y2, $couleur) // trace une ligne entre $x1,$y1 et $x2,$y2 et de couleur $couleur pour $image. ImageRectangle ($image, $x1, $y1, $x2, $y2, $couleur) // trace dans $image un rectangle de coin supérieur gauche ($x1, $y1) et de coin inférieur droit ($x2, $y2) de couleur $couleur. ImageFilledRectangle ($image, $x1, $y1, $x2, $y2, $couleur) // idem a ImageRectangle mais le rectangle sera plein. ImageSetPixel ($image, $x, $y, $couleur) // trace un point de coordonnées $x,$y de couleur $couleur dans l'image $image ImageSetThickness ($image, $epaisseur) // regle l'épaisseur des lignes tracées par toutes les fonctions de l'image $image 6.0 La librairie GD : fonctions utiles • • • • • • • • • • ImageString ($image, $police, $x, $y, $chaine, $couleur) // Dessine dans $image la chaîne de caractère $chaine à partir du point ($x,$y) avec la couleur $couleur et avec la taille de police de caractère $police (compris entre 0 et 5) ImageStringUp ($image, $police, $x, $y, $chaine, $couleur) // idem que ImageString mais texte vertical $tableau_image = GetImageSize ($fichier) // a partir d'une image $fichier,renvoie un tableau contenant les 4 éléments suivants: $tableau_image[0] = la largeur de l'image,$tableau_image[1] = hauteur de l'image,$tableau_image[2] donnce le type de l'image,$tableau_image[3] donne une chaine de caractère directement utilisatble dans <img> ImageColorTransparent ($image, $couleur) // la couleur $couleur de l'image $image est définis comme transparente attention uniquement pour les png et les gifs !!! ImageCopy ($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_l, $src_h) // Copie une partie rectangulaire de l'image $src_im dans l'image $dst_im. La partie à copier est délimitée par le point ($src_x, $src_y), la largeur $src_l et la hauteur $src_h. La copie est placée dans $dst_im à partir du point ($dst_x, $dst_y) ImageCopyResampled($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_l, $src_h) // idem que ImageCopy mais effectue également un redimensionnement. $image = ImageCreateFromJpeg ($fichier) // créer une image jpeg $image depuis $fichier. $im = ImageCreateFromPng ($fichier) // créer une image png $image depuis $fichier. $largeur = ImageSX ($image) // renvoie la largeur de l'image $image. $hauteur = ImageSY ($im) // renvoie la hauteur de l'image $image. 6.1 Scripts utiles Faire un copyright sur des images http://mastercaweb.u-strasbg.fr/bofh/gd/copyleft/ Test de miniatures en php http://mastercaweb.u-strasbg.fr/bofh/gd/ 8. Generer des pdfs • Plusieurs possibilités : – La libraire integré à php libpdf : http://www.pdflib.com/pdflib-cookbook/ – fpdf : http://www.fpdf.org – Google est votre ami … 9. Upload de fichiers en PHP • Pour faire de l'upload ( =envoi de fichier ) en php via un formulaire il faut préciser l'encodage à utiliser à l'aide le l'attribut enctype et placer une balise xhtml input type=file. <form method="POST" action="up.php" enctype="multipart/form-data"> Fichier : <input type="hidden" name="MAX_FILE_SIZE" value="666"> <input type="file" name="fichier_a_envoyer"> <input type="submit" name="envoyer" value="envoyer"> </form> 9. Upload de fichiers en PHP • <input type="hidden" name="MAX_FILE_SIZE" value="valeurmax"> • MAX_FILE_SIZE = la taille maximale (en octet) acceptée du fichier par PHP. • Il permet d'informer l'utilisateur/utilisatrice que le fichier à envoyer est trop conséquent avant l'envoi complet du fichier vers le serveur. • Attention ceci n'est pas un CONTROLE ! Juste une valeur de test de « confort » il est très facile de modifier cette valeur via un autre formulaire/via un script/ou des outils divers. • Le paramètre PHP (côté serveur) à propos de la taille maximale d'un fichier téléchargé, ne peut, lui, être trompé et doit être mentionné pour des questions de sécurité. 9. Upload de fichiers en PHP • Comme pour $_POST / $_GET / $_SESSION php va renseigner un table $_FILES avec les principales caractéristiques de notre fichier envoyé via notre formulaire html de soumission : – $_FILES['fichier_a_envoyer']['name'] son nom – $_FILES['fichier_a_envoyer']['tmp_name'] son chemin temporaire pendant l'envoi – $_FILES['fichier_a_envoyer']['size'] la taille du fichier – $_FILES['fichier_a_envoyer']['type''] son type – $_FILES['fichier_a_envoyer']['error''] code d'erreur eventuel 9. Les codes d'erreurs. UPLOAD_ERR_OK Valeur : 0. Aucune erreur, le téléchargement est correct. UPLOAD_ERR_INI_SIZE Valeur : 1. Le fichier téléchargé excède la taille de upload_max_filesize, configurée dans le php.ini. UPLOAD_ERR_FORM_SIZE Valeur : 2. Le fichier téléchargé excède la taille de MAX_FILE_SIZE, qui a été spécifiée dans le formulaire HTML. UPLOAD_ERR_PARTIAL Valeur : 3. Le fichier n'a été que partiellement téléchargé. UPLOAD_ERR_NO_FILE Valeur : 4. Aucun fichier n'a été téléchargé. UPLOAD_ERR_NO_TMP_DIR Valeur : 6. Un dossier temporaire est manquant. Introduit en PHP 5.0.3. UPLOAD_ERR_CANT_WRITE Valeur : 7. Échec de l'écriture du fichier sur le disque. Introduit en PHP 5.1.0. UPLOAD_ERR_EXTENSION Valeur : 8. Une extension PHP a arrêté l'envoi de fichier. PHP ne propose aucun moyen de déterminer quelle extension est en cause. L'examen du phpinfo() peut aider. Introduit en PHP 5.2.0. 9. Upload de fichiers en PHP • • • • • Pour envoyer le fichier via php on utilisera la fonction move_uploaded_file : bool move_uploaded_file ( string $filename , string $destination ) move_uploaded_file s'assure que le fichier filename est un fichier téléchargé par HTTP POST. Si le fichier est valide, il est déplacé jusqu'à destination. Si le fichier existe déjà il sera ecrasé. move_uploaded_file Retourne TRUE en cas de succès.Si filename est un fichier téléchargé, mais que pour une raison quelconque, il ne peut être déplacé, rien ne se passe, et move_uploaded_file() retourne FALSE. Attention aux limites pour la taille du fichier configuré dans le php.ini dans certain cas il faut surcharger ces paramètres à l'aide d'un .htaccess notamment dans un env. Apache : php_value post_max_size 10M php_value upload_max_filesize 10M 9. Upload de fichiers en PHP <?php /* * Script à ne pas utiliser pourquoi ? */ if(isset($_FILES['fichier_a_envoyer'])) { $dossier = 'repertoire_upload/'; $fichier = basename($_FILES['fichier_a_envoyer']['name']); if(move_uploaded_file($_FILES['fichier_a_envoyer']['tmp_name'], $dossier . $fichier)) { echo 'envoi effectué avec succès !'; } else { echo ''grrrrrrrrrrrrrrrr echec de l'envoi !''; } } ?> 9. Upload de fichiers en PHP Utiliser le script d'upload précèdent est très dangereux avant tout il faut verifier via php la taille le type du fichier, son nom ! • Pour la taille : $taille = filesize($_FILES[fichier_a_envoyer']['tmp_name']); if($taille>100000) { $erreur = 'Le fichier est trop fat...'; } • • Pour le type de fichier : $extensions = array('.png', '.gif', '.jpg', '.jpeg'); $extension = strstr($_FILES['fichier_a_envoyer']['name'], '.'); if(!in_array($extension, $extensions)) //Si l'extension n'est pas dans le tableau { $erreur = 'type de fichier interdit !!!!!!!!!!!'; } 9. Upload de fichiers en PHP • Le nom du fichier : $fichier = strtr($fichier, 'ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝàáâãäåçèéêëìíîïðòóôõöùúûüýÿ', 'AAAAAACEEEEIIIIOOOOOUUUUYaaaaaaceeeeiiiioooooouuuuyy'); . $fichier = preg_replace('/([^.a-z0-9]+)/i', '-', $fichier); • Le code complet ici : http://mastercaweb.u-strasbg.fr/bofh/upload/ 10.0 Conseils • • Écrire du code facile à lire : indenter son script Indentation = utilisation des tabulations pour présenter le code afin de le rendre plus lisible switch($page){ case "liens": $page_a_inclure = "liens"; $titre_section = "Les liens"; break; case "cv": $page_a_inclure = "cv"; $titre_section = "mon cv"; break; } $page_a_inclure = $page_a_inclure.".htm"; ?> switch($page) { case "liens": $page_a_inclure = "liens"; $titre_section = "Les liens"; break; case "cv": $page_a_inclure = "cv"; $titre_section = "mon cv"; break; } $page_a_inclure = $page_a_inclure.".htm"; ?> 10. Conseils • • • • • • • • Bien nommer ses variables : pas d'accents,espaces,caractères spéciaux ( = réservés ) Nommer de facon explicite ses variables : – Plutot $motdepasse ou $mot_de_passe mais pas $mdp – Bien préciser ce que contient la variable : $date_commande $login_visiteur Bien nommer les scripts que l'on utilise : – login_forum.php envoi_livredor.php etc... Utilisation de conventions de nommage : – CamelCase ( $UpperCamelCase) ou camelCase ($lowerCamelCase) – Notation Hongroise ($strMaChaine ) Documenter le code ( utilisation des commentaires ! ) Prévoir un fichier de paramétrage de l'application ( include ''config.php'' ; ) Penser à la sécurité en écrivant le code ( tester les variables, vérifier les saisies utilisateurs, appréhender l'environnement dans lequel on code ( conf php / apache ... ) Écrire des fonctions ( réutilisable dans d'autres applications ... ) 10. Conseils • Ne pas réécrire la roue : utilisation de librairies de code ou d'api. • Utilisation d'un système de gestion de version (vcs pour Version Control System) • Avantages d'un vcs : – Historique du code (permet de revenir sur une version du code chaque nouvelle version d'un fichier est appellée 'révision' et le n° de version est incrémentée de 1 – Conserve une trace de chaque changements effectués – Possibilité de travail mutualisé (modifs nommés par utilisateur/développeur) – Fusion entre copie locale et distance et non pas écrasement de la copie locale par la copie distante. • Un wiki est aussi un vcs sauf que ce ne sont pas des fichiers qui sont historisés mais des champs de bases de données. • Les vcs les plus connus (svn – subversion,bazaar,mercurial,cvs ,visual SourceSafe - krosoft) 10. Conseils • • • • Utilisation de frameworks chaudement recommandée ! Framework : « En programmation informatique, un framework est un kit de composants logiciels structurels, qui servent à créer les fondations ainsi que les grandes lignes de tout ou partie d'un logiciel (architecture). » (src : wikipédia) Avantages : – standardisation du code et du cycle de vie de l'application (specs,dvt,maintenance,évolution) – On gagne en fiabilité – Gains de productivité – Souvent « communauté active » autour d'un framework Frameworks orientés php : – PEAR – Zend Framework – Symfony – Prado – PhpMVC – Copix – CodeIgniter – CakePHP 10. Conseils • • • • Utilisation de frameworks chaudement recommandée ! Framework : « En programmation informatique, un framework est un kit de composants logiciels structurels, qui servent à créer les fondations ainsi que les grandes lignes de tout ou partie d'un logiciel (architecture). » (src : wikipédia) Avantages : – standardisation du code et du cycle de vie de l'application (specs,dvt,maintenance,évolution) – On gagne en fiabilité – Gains de productivité – Souvent « communauté active » autour d'un framework Frameworks orientés php : – PEAR – Zend Framework – Symfony – Prado – PhpMVC – Copix – CodeIgniter – CakePHP 10 Php et la sécurité • Php est un langage très courant, beaucoup utilisé on peut faire tout et n'importe quoi en php. • Php est utilisé un peu partout en développement d'applications web dans des domaines tel que : Traitement de formulaires, gestion de fichiers, exécution de commandes systèmes ( = commandes du serveur ) , interfaçage à des bases de données, fonctionnalités « réseaux » ( ouverture de connections à distance... ) • Le fait d'exécuter nos scripts sur un serveur et non pas simplement au niveau du client ( = le navigateur ) induisent de protéger au maximum ses scripts. • Il ne faut pas sous estimer la sécurité durant toute la phase d'élaboration du projet jusqu'à l'exploitation de l'application ( = phase de prod ) • Sécuriser ses scripts implique que le serveur est mis à jour régulierement et correctement paramétré. 10 Php et la sécurité : les regles de base • <mode parano>Ne jamais faire confiance aux données transmises par l'utilisateur/trice</mode parano> • Tester l'existence et la cohérence d'un script à inclure dans un autre script. • Limiter le plus possible les permissions ( = droits ) des utilisateurs/trices ->trop de liberté tue la liberté ! • Basé uniquement le contrôle au niveau client est illusoire ( blocage du javascript ... ) • Privilégier la méthode post à la méthode get ( les variables en clair dans l'url c'est bien mais pas top ! ) • Toujours embêter l'administrateur du serveur pour avoir une version à jour de php / apache et des outils web. • RTFM : http://fr.php.net/manual/fr/security.php 10 phpinfo() • Phpinfo() est une fonction très utile pour le développeur ( info sur la config = le fichier php.ini , paramétrages, environnement serveur, version des logiciels ... ) • Il faut éviter de permettre l'affichage du script utilisant phpinfo() aux utilisateurs/trices de notre application web. • Phpinfo() renseigne sur des mécanismes « clés » de php , ces derniers influent sur la façon d'interpréter du code php. • Les directives contenues dans le fichier php.ini dictent le comportement du langage, qui à son tour, autorise différents modes d’opération, en fonction des besoins et de l’environnement de l’utilisateur. • Le script exécutant la fonction phpinfo() est une mine d'or pour une personne mal intentionnée qui viendrait « visiter » notre serveur web. 10 fichier php.ini • safe_mode : ( safe_mode = on | off ) - de nombreuses fonctions sont limitées ou desactivées http://www.php.net/manual/fr/features.safe-mode.functions.php - une vérification stricte des permissions d'accès des fichiers est faite sur les fonctions concernées. - impossibilité d'utiliser l'upload de fichiers. - les variables d'environnement sont protégées. • safe_mode_exec_dir : ( safe_mode_exec_dir = /private_dir/ ) - autorise le répertoire indiqué à utiliser les fonctions interdites/limitées. 10 fichier php.ini • safe_mode_allowed_env_vars : ( safe_mode_allowed_env_vars = PHP_ ) - Seules les variables commençant par les préfixes explicités dans cette directives peuvent être utilisées. • disable_fonctions : ( disable_functions = FonctionPhp ) - Cette directive est indépendante du « safe mode » elle permet de déterminer les fonctions à désactiver ex : disable_functions = exec, system, mail • open_basedir : ( open_basedir = /usr/home/ftpuser/ ) - Cette directive (indépendante du safe_mode) limite les permissions d'accès aux seuls dossiers spécifiés ici. 10 fichier php.ini • display_errors : (display_errors = on | off ) - Cette directive désactive l'affichage vers le navigateur des messages d'erreur PHP. • log_errors : (log_errors = on | off), cette directive permettra la redirection des messages d'erreur vers les fichiers journaux (fichiers log sous unix), dans les journaux d'évènements (win), ou dans des fichiers spécifiés dans la directive error_log • error_log : (error_log = /var/log/erreurs_php.log ) : - Specifie le fichier dans lequel seront écrits les messages d'erreur. • register_globals ( register_globals = on | off ) : - Permet de rendre globales ou non les variables EGPCS (Environment, Get, Post, Cookie, Session). 10 fichier php.ini • allow_url_fopen : ( allow_url_fopen = on | off ) - Cette option permet de désactiver ou non toutes les fonctionnalités relatives à la manipulation des fichiers distants. • magic_quotes_gpc : ( magic_quotes_gpc = on | off ) - Cette directive permet d'échapper (par backslashes = \) les quotes, double quotes, backslashes et caractère NULL des chaînes de caractères issues des méthodes Get, Post et Cookies. • magic_quotes_runtime : ( magic_quotes_runtime = on | off ) - directive qui permet egallement d'échapper les quotes, double quotes, backslashes et caractère NULL, mais des chaînes de caractères provenant d'une ressource externe (base de données... ) • file_uploads : ( file_uploads = on | off ) - Autorise l'upload de fichiers sur le serveur via un script PHP 10 : La faille include • Il existe une littérature abondante sur le web concernant cette faille. • Il faut éviter d'utiliser des variables quand on veut inclure des fichiers dans un script : include($mon_repertoire. ''fonctions.php''); ou encore pire include($page); • Si on est administrateur on peut mettre allow_url_fopen sur off dans le php.ini • Le mieux reste de tester l'existence du fichier sur le serveur ou alors d'utiliser un switch et de prévoir un cas par défaut pour les valeurs de $page non prévues. • Le but de cette attaque est de faire exécuter en local sur le serveur qui héberge le script à risque un autre script hébergé sur un autre site. 10 Exploitation des variables globales • Comme pour la faille include il faut faire attention à nos variables un script d'authentification de ce genre pose probleme : <?php if ($password == "supermotdepasse") $login_ok = 1; ... if ($login_ok == 1) echo "Bienvenue dans l'interface d'administration"; ?> http://www.rogerfaitdanslaprogweb.com/login?login_ok=1 nous permettra de nous connecter !!!! 10 Authentification • • • • • • Pour un système d'authentification il ne faut pas stocker le mot de passe en clair !! On va utiliser la technique du 'hash' appellé fonction de hachage. Le hash : somme de contrôle, empreinte, hash, condensat, empreinte autrefois 'signature numérique' mais terme trop confus. Le hashage est une fonction de codage à sens unique : il est impossible (en principe) de retrouver un mot de passe à partir de son hash. L'algorithme de hashage le plus courant en PHP s'appelle le MD5 (128 bits), mais on parle aussi de SHA1 (160 bits) SHA-256, Whirlpool … Pour stocker le mdp : $password = md5($_POST['password']); $sql = "INSERT INTO users VALUES (..., '$password', ...)"; // pour le login $username = addslashes($_POST['username']); $password = md5($_POST['password']); $sql = "SELECT username FROM users WHERE username = '$username' AND password = '$password'"; [...] // on recupère dans $resultat le nb d'enregistrements renvoyé dans la requete if ($resultat == 1) { $login_ok = true; } else { $login_ok = false; } 10 La faille XSS • Le Cross site scripting, ( = XSS ) est une faille de sécurité courante dans les applications Web, l'astuce consiste bien souvent à injecter du javascript dans un formulaire de saisie, dans une variable php • L'exploitation d'une faille de type XSS peut permettre à un intrus de réaliser les opérations suivantes : -Affichage d'un contenu non interne au site (publicité, faux article) -Redirection (parfois de manière transparente) de l'utilisateur. -Vol d'informations, par exemple sessions et cookies. -Actions sur le site faillible, à l'insu de la victime et sous son identité (envois de messages, suppression de données, etc.) • Une faille de type XSS est à l'origine de la propagation des virus Samy ( http://namb.la/popular/tech.html ) sur MySpace en 2005 ainsi que de Yamanner sur Yahoo!Mail en 2006. 10 La faille XSS • Le meilleur moyen pour eviter la faille XSS : tester les saisies utilisateurs → <script type="text/javascript">alert('bouh la vilaine faille')</script> • Pour contrer utiliser la fonction htmlentities() de php : <?php if(isset($_POST['message'])) { echo htmlentities($_POST['message']); } ?> 10 La faille XSS • Autre technique utile pour annihiler le XSS : $input = str_replace(''<'', ''<'', $input); $input = str_replace(''>'', ''>'', $input); $input = str_replace(''script'', '''', $input); 10 Faire mumuse avec mail() • La fonction mail() interesse énormément les ''spammeurs'' ! • Mailbombeur : <? $to = "[email protected]"; $subject = "fear!!!!"; $message = "prout "; for($i=0; $i<5000; $i++) { mail($to, $subject, $message); } ?> 10 Injection d'entètes dans mail() mail([DESTINATAIRE],[SUJET],[MESSAGE],[HEADERS]); Dans le cas d'un formulaire de soumission de mail ( page contact d'un site ) si les champs ne sont pas filtrés/contrôlés on peut ajouter très facillement des entetes. <? $to="[email protected]"; if (!isset($_POST["send"])){?> <form method="POST" action=""> A: [email protected]<br> De: <input type="text" name="expediteur"><br> Sujet : <input type="text" name="sujet"><br> Message : <br><br> <textarea name="message" rows="10" cols="60" lines="20"></textarea><br> <input type="submit" name="send" value="Envoyer"> </form><? }else{ $from=$_POST["expediteur"]; if (mail($to,$_POST["sujet"],$_POST["message"],"From: $from\n")){ echo "Votre mail a bien été envoyé à $to.<br>"; }else{ // sinon, message d'erreur. echo "Votre mail n\'a pas pu être envoyé.<br>"; } • • 10 Injection d'entètes dans mail() Quand on enverra le formulaire : To: $destinataire Subject: $sujet $headers $message Le but de l'attaque par injections d'headers ( = entetes ... ) est d'inseré des entetes ( BCC,CC ... ) To: [email protected] Subject: Haxor From: [email protected] Cc:[email protected] Bcc:[email protected],[email protected] My Message... 10 Injection d'entètes dans mail() • Chaque entetes est separé par un retour à la ligne, il suffit de manipuler les variables de notre script. • Dans le champs expediteur : • ''[email protected]%0ACc:[email protected] %0ABcc:[email protected],[email protected]'' • %0A nous permets de signifier un retour à la ligne ( code hexadecimal ) • On aura donc : To: [email protected] Subject: prout From: [email protected] Cc:[email protected] Bcc:[email protected],[email protected] My Message... 10 Injection d'entètes dans mail() • Il est tout a fait possible d'avoir deux fois l'entete « to; » dans un email : • Dans le champs expediteur de notre formulaire : "[email protected] %0ATo:[email protected]" • Toujours dans notre exemple : To: [email protected] Subject: prout From: [email protected] To:[email protected] My Message... 10 Injection d'entètes dans mail() • Pour des formulaires de type « recommander ce site à un ami » <? $sujet="Visitez http://www.website.com !"; $message="Bonjour,\nUn ami vous conseille de visiter http://www.website.com.\n"; if (!isset($_POST["send"])){ ?> <form method="POST" action=""> A : <input type="text" name="destinataire"><br> De: <input type="text" name="expediteur"><br> <input type="submit" name="send" value="Envoyer"> </form> <? }else{ $from=$_POST["expediteur"]; $to=$_POST["destinataire"]; if (mail($to,$sujet,$message,"From: $from\n")){ echo "Votre mail a bien été envoyé à $to.<br>"; }else{ echo "Votre mail n\'a pas pu être envoyé.<br>"; }}?> 10 Injection d'entètes dans mail() • if (eregi("\r",$from) || eregi("\n",$from)){ die("stupid guy !!!"); } • La fonction eregi recherche les caractères de retour à la ligne, il faut tester ceci avant de forger les entetes finaux dans le script php de validation du formulaire. 10 Injection « SQL » • MySQL est un SGBD facile à utiliser, la plupart des scripts PHP utilisent MySQL pour gérer leurs données. • Imaginons un script du genre : [ ... ] $table ="contacts": $query = "INSERT INTO $table ('$nom', '$email')"; $result = mysql_query($query); [ ... ] • MySQL est aussi capable d'effectuer deux requetes simultanées : $query = "INSERT INTO contacts ('bofh', '[email protected]'); INSERT INTO contacts ('bill', '[email protected]')"; $result = mysql_query($query); 10 Injection « SQL » • Imaginons notre script avec un formulaire de soumission [ NOM ] bofh [ MAIL ] '[email protected]'); INSERT INTO contacts ('bill','[email protected]') [ NOM ] bofh [ MAIL ] '[email protected]'); DROP TABLE contacts 10 Injection « SQL » •Solution : il suffit d'utiliser la fonction addslashes(), qui ajoutera un backslash '\' devant les caracteres posant problème : quote ("), apostrophe (') et backslash(\). $nom = addslashes($nom); $email = addslashes($email); $query = "INSERT INTO $table ('$nom', '$email'); Ou $query = "INSERT INTO $table ('''.addslashes($nom).''', '''.addslashes($email).''')''; 11. Les frameworks de dvt web. Un framework web ? Wikipedia : « En programmation informatique, un framework est un kit de composants logiciels structurels, qui servent à créer les fondations ainsi que les grandes lignes de tout ou d’une partie d'un logiciel (architecture). » Framework : cadre pour coder proprement via un ensemble de bonnes pratiques Ne pas ré-inventer la roue (DRY : « Don't Repeat Yourself ») Boîte à outils/composants logiciels génériques Rapidité et qualité du développement Structuration du développement (Architecture Modèle/Vue/Contrôleur ) Des fonctionnalités par défaut pour le développement web Le Design Pattern Design pattern = patron de conception « un arrangement caractéristique de modules, reconnu comme bonne pratique en réponse à un problème de conception d'un logiciel. Il décrit une solution standard, utilisable dans la conception de différents logiciels » Mvc est un « design pattern » Le Modèle MVC Le Modèle de données : abstraction de la base de données, en charge de l'accès et des requêtes La Vue : présentation des données (HTML, XML, JSON, RSS) Le Contrôleur : implémentation de la logique métier, liant entre le Modèle et la Vue Le modèle MVC Modèle de données ORM Couche d'abstraction Objet-Relationnel Génération automatique de la base de donnée Une classe objet, une table de la base de données avec : -Les types de données -Les contraintes d'intégrité -Les relations entre les classes et leur cardinalité (ex : relation 1-n) L'ORM L'ORM fournit des instructions de hautniveau pour la manipulation des objets. Abstraction complète du SQL Utilisation de CRUD pour la persistance des données (Create, Read, Update, Delete) Evite d'avoir à coder les accès à la base de données l'ORM le fait pour nous (trop cool!) Les vues (=views/templates) Système de « template » Web : Variables interprétées dynamiquement Utilisation des instructions d'itération et de condition des langages de programmation Possibilité aussi de présenter des vues sous différents formats : JSON, XML, RSS, PDF. Gestion des URL Systeme de « routage » : Correspondance d’une URL à une methode ou action d'un controleur Base sur des expressions regulieres Le controlleur Decoupage du controleur en methodes (ou actions) Liant entre le modele et la vue en fonction des événements Connaissance du contexte HTTP (environnement, session, etc.) Des fonctionnalités supplémentaires... Conclusion Utilisation des frameworks chaudement recommandée Code propre facile à maintenir et à reprendre Attention néanmoins aux frameworks exotiques et jeunes (peu de doc, peu de retour d’expérience..) Il faut suivre les bonnes pratiques de dev. , normalisation du code, tests unitaires... Inconvénients : chemin long et difficile jusqu'à la maitrise du framework mais montée en compétence évidente. La programmation objet (poo) • Au début de l'informatique programmation procédurale voir séquentielle • Prog séquentielle : l'execution du code est toujours le même en générale ligne / ligne • Une procédure (routine,sous routine,fonction) contient un nombre d'étape (bloc de code ou instructions à suivre) à réaliser. • Limite de la prog. Procédurale : un programme peut vite devenir compliqué et on sait plus trop ce que fait le code => code spaghetti 10 i = 0 20 i = 1 + 1 30 IF i <> 10 then goto 70 40 IF i = 10 the goto 50 50 PRINT ''SUPER CODE'' 60 END 70 PRINT '' HELLO'' 80 GOTO 20 La programmation objet (poo) • En programmation objet tout est OBJET • Un objet = structure de données • Un objet regroupe non seulement les données mais egallement les mouens de traitement de ces données. • Un objet est définis par des propriétés qui étendent l'objet et par des méthodes qui servent à traiter les propriétés de l'objet. • D'ou viennent les objets ? Ils sont definis par des « constructeurs » appelés « classes » • Une classe regroupe des variables et des fonctions (propriétés et méthodes) • Chacune des fonction dans une classe aura accès aux variables de cette entité. Déclaration et utilisation d'une classe. • Il s'agit d'un bloc dont l'en-tête (=la signature) commence par le mot-clé class. • Extends est optionnel et annonce que la présente classe hérite (on parle de sous-classe) des propriétés / méthodes d'une autre classe class NomClasse [extends ClasseParent] { // déclarations des attributs (ou propriétés) ... // déclarations du constructeur et des méthodes ... } • Par convention de nommage les noms de classe commencent par une majuscules mais ce n'est pas obligatoire ! Poo : concepts de base • Instance de classe : instancier une classe c'est se servir d'une classe pour créer un objet. • Une classe réunie dans la même entité les données et les moyens de les gérer (les champs et les méthodes) c'est l'encapsulation • en interdisant la modif. directement des attributs, et en obligeant l'utilisation des fonctions définies pour les modifier (appelées interfaces), ce principe assure l'intégrité des données manipulés. • Il existe trois niveaux de visibilité pour une classe : – Publique : les fonctions de toutes les classes peuvent accéder aux données ou aux méthodes d'une classe définie avec le niveau de visibilité public. Il s'agit du plus bas niveau de protection des données – Protegée : l'accès aux données est réservé aux fonctions des classes héritières, c'est-à-dire par les fonctions membres de la classe ainsi que des classes dérivées. – privée: l'accès aux données est limité aux méthodes de la classe ellemême. Il s'agit du niveau de protection des données le plus élevé Les attributs des objets • Les attributs d'objets = les variables de la classe. • En php 4 Ils sont obligatoirement introduit par le mot-clé var Ex : var $attribut = valeur ; En php 5 public|private|protected $attribut = valeur ; • Le type de la variable est quelconque : entier, double, chaine ou tableau • L'accès des (futurs) objets à la valeur d'un attribut utilise la syntaxe suivante : $objet -> attribut; • Attention pas de $ devant le nom de l'attribut !!! L'accès aux membres d'une classe. // ClasseQuiTueTout.php class ClasseQuiTueTout { public $variablePublic = "variable 'public'"; private $variablePrivate = "variable 'private'"; protected $variableProtected = "variable 'protected'"; // Notre constructeur qui tue tout !!!! function __construct(){} } Les membres public d'une classe sont accessibles partout : $demoQuiTueTout = new ClasseQuiTueTout(); echo $demoQuiTueTout->variablePublic; // Renvois variable 'public' L'accès aux membres d'une classe. // ClasseQuiTueTout.php class ClasseQuiTueTout { public $variablePublic = "variable 'public'"; private $variablePrivate = "variable 'private'"; protected $variableProtected = "variable 'protected'"; // Notre constructeur qui tue tout !!!! function __construct(){} } Les membres public d'une classe sont accessibles partout : $demoQuiTueTout = new ClasseQuiTueTout(); echo $demoQuiTueTout->variablePrivate; // Renvois une erreur fatale (game over!!!!) // Fatal error: Cannot access private property ClasseQuiTueTout::$variablePrivate in /cheminDuScript/code_roxor.php on line xx L'accès aux membres d'une classe. // ClasseQuiTueTout.php class ClasseQuiTueTout { public $variablePublic = "variable 'public'"; private $variablePrivate = "variable 'private'"; protected $variableProtected = "variable 'protected'"; // Notre constructeur qui tue tout !!!! function __construct(){} // methode pour retourner notre variable privé function getVariablePrivate(){ return htmlentities($this->variablePrivate); } } Ensuite : $demoQuiTue = new ClasseQuiTueTout(); echo $demoQuiTue->getVariablePrivate(); L'accès aux membres d'une classe. // ClasseQuiTueTout.php class ClasseQuiTueTout { public $variablePublic = "variable 'public'"; private $variablePrivate = "variable 'private'"; protected $variableProtected = "variable 'protected'"; // Notre constructeur qui tue tout !!!! function __construct(){} // methode pour retourner notre variable privé function getVariablePrivate(){ return htmlentities($this->variablePrivate); } } class SousClasseQuiTache extends ClasseQuiTueTout { function __construct(){} function accesPrivate(){ echo $this->variablePrivate; } function accesProtected(){ echo $this->variableProtected; } } $demo = new SousClasseQuiTache(); echo $demo->accesProtected(); // Affiche variable 'protected' echo $demo->accesPrivate(); // Erreur d'accès Exemple de classe // la classe ''Personne'' class Personne { public $nom; public $prenom public $type; ... } // fin classe $personne = new Personne; // on affecte une valeur à ses attributs $prenom et $type $personne -> prenom = "luke"; $personne -> type = 'jedi'; Création de méthodes class Personne { private $nom; private $prenom; private $type; … Public function seServirDeLaForce() // se servir de la force et tout casser { ... } Public function attaquerEtoileNoire() // on va casser du méchant { ... } } Utilisation de $this • • La variable $this represente l'objet créé par la classe. En appellant $this on pourra appeler les methodes de notre objet ou modifier ses attributs. class Personne { private $nom, $type, $vaisseau, $force, $degats, $experience ; … public function domages($force) { $this->degats = $this->degats+$force } public function attaquer($perso) { $perso ->domages($this->force) } public function gagnerExperience() { $this->experience++; } Les accesseurs Pour pouvoir utiliser notre classe de tout à l'heure il va falloir definir la force et l’expérience de nos heros on va se servir des accesseurs et des mutateurs. class Classe { private $attribut; public function Classe(){ $this->attribut = null; } //Accesseur public function getAttribut(){ return $this->attribut; } //Mutateur public function setAttribut($valeur){ $this->attribut = $valeur; } } $objet = new Classe(); //Instanciation d'une classe $objet->setAttribut(10); echo $objet->getAttribut(); • Classe personne class Personne { private $nom, $type, $vaisseau, $force, $degats, $xp ; … public function setForce ($force) { if (!is_int ($force)) // S'il ne s'agit pas d'un nombre entier { trigger_error('La force d\'un personnage doit être un nombre entier', E_USER_WARNING); return; } if ($force > 100) // On vérifie bien qu'on ne souhaite pas assigner une valeur supérieure à 100 { trigger_error('La force d\'un personnage ne peut dépasser 100', E_USER_WARNING); return; } $this->force = $force; } ... Classe personne ... public function degats() { return $this->degats; } public function force() { return $this->force; } public function experience() { return $this->experience; } } Classe personne … public function setExperience ($experience) { if (!is_int ($experience)) // S'il ne s'agit pas d'un nombre entier { trigger_error('L\'expérience d\'un personnage doit être un nombre entier', E_USER_WARNING); return; } if ($experience > 100) // On vérifie bien qu'on ne souhaite pas assigner une valeur supérieure à 100 { trigger_error('L\'expérience d\'un personnage ne peut dépasser 100', E_USER_WARNING); return; } $this->experience = $experience; } Classe personne <?php $perso1 = new Personnage(); // Un premier personnage $perso2 = new Personnage(); // Un second personnage $perso1->setForce (10); $perso1->setExperience (2); $perso2->setForce (90); $perso2->setExperience (58); $perso1->frapper ($perso2); // $perso1 frappe $perso2 $perso1->gagnerExperience(); // $perso1 gagne de l'expérience $perso2->frapper ($perso1); // $perso2 frappe $perso1 $perso2->gagnerExperience(); // $perso2 gagne de l'expérience echo 'Le personnage 1 a ', $perso1->force(), ' de force, contrairement au deuxième personnage qui a ', $perso2->force(), ' de force.<br />'; echo 'Le personnage 1 a ', $perso1->experience(), ' d\'expérience, contrairement au deuxième personnage qui a ', $perso2->experience(), ' d\'expérience.<br />'; echo 'Le personnage 1 a ', $perso1->degats(), ' de dégâts, contrairement au deuxième personnage qui a ', $perso2->degats(), ' de dégâts.<br />'; ?> Le constructeur • Le constructeur est la fonction qui est appelée automatiquement par la classe lors de l'instanciation de la classe à l'aide de l'opérateur new. • La fonction constructeur a le même nom que la classe en php4 pour php5 : __construct() • Une fonction/methode devient le constructeur si elle porte le même nom que la classe (php < php5) class BaseClass { function __construct() { print "In BaseClass constructor\n"; } } class SubClass extends BaseClass { function __construct() { parent::__construct(); print "In SubClass constructor\n"; } } $obj = new BaseClass(); $obj = new SubClass(); Le constructeur <?php class Personnage { private $force; private $localisation; private $experience; private $degats; public function __construct ($force, $degats) // Constructeur demandant 2 paramètres. { echo 'Aller ca construit !'; // Message s'affichant une fois que tout objet est créé. $this->force = $force; // Initialisation de la force. $this->degats = $degats; // Initialisation des dégâts. $this->experience = 1; // Initialisation de l'expérience à 1. } // …. methodes ... } ?> <?php $perso1 = new Personnage (60, 0); // 60 de force, 0 dégât. $perso2 = new Personnage (100, 10); // 100 de force, 10 dégâts. ?> Exemple de connection Mysql class Connexion { private $server, $user, $password, $database; public function __construct ($server, $user, $password, $database) { $this->server = $server; $this->utilisat = $user; $this->password = $password; $this->database = $database; $this->connDb(); } private function connDb() { mysql_connect ($this->server, $this->user, $this->password); mysql_select_db ($this->database); } } Fichier appelant notre classe : <?php $connexion = new Connexion ('localhost', 'root', 'gotroot?', 'allyourbase'); ?> Comment appeler nos classes ? <?php function chargerClasse ($classe) { require $classe . '.class.php'; // inclusion de la classe } $perso = new Personne(); // Instanciation de la classe Personne qui n'est pas déclarée dans ce fichier ?> → renvois une erreur fatale il faut utiliser l'autoload de php : <?php function chargerClasse ($classe) { require $classe . '.class.php'; // On inclue la classe correspondante au paramètre passé } spl_autoload_register ('chargerClasse'); $perso = new Personne(); ? Charger nos classes Depuis php v5.3 : <?php function __autoload($class_name) { include $class_name . '.php'; } $obj = new MaClasse1(); $obj2 = new MaClasse2(); ?> Utiliser un ORM • Cf wikitruc : « Un mapping objet-relationnel (en anglais object-relational mapping ou ORM) est une technique de programmation informatique qui crée l'illusion d'une base de données orientée objet à partir d'une base de données relationnelle en définissant des correspondances entre cette base de données et les objets du langage utilisé. On pourrait le désigner par « correspondance entre monde objet et monde relationnel » Utiliser un ORM • • • • • Un ORM est votre ami : il permet d’accroître fortement la productivité au cours d'un dev. lié à des bases de données. Couramment utilisés dans de nombreux frameworks web : Symfony,Zend, et pas seulement en php, en .NET avec notamment NHibernate, Hibernate en Java, Django et SQLAlchemy en python. Souvent utiliser avec le design pattern MVC Avantages : – Si on maîtrise → génération de requêtes SQL plus stables, plus sécurisées et performantes – Gestion et prise en charge des accès à la base de données par l'ORM – Évolution et maintenabilité avec la possibilité de migrer rapidement vers un autre SGBD. Limites : – Performances sur des grosses bases. – Connaissances en POO obligatoires. – Gestion des relations 1 à n / n à n , verrous pas toujours simples à comprendre. – Utilisation mémoire importante. Utiliser un ORM ORM pour PHP • • • • • • PersistentObject : fait partie du projet eZ Components surtout connu pour eZ Publish (->CMS) Propel : projet plus ou moins maintenu actuellement ; beaucoup utilisé par la communauté Symfony à ses débuts (v1) , critique sur certains concepts qui éloigne Propel de la syntaxe SQL de base. PhpSimpleDB : ORM jeune, projet francophone, concept déroutant on commence par écrire nos requêtes sql et l'ORM va generer à la volée à la première execution les classes associées au modèle. PdoMap : bibliothèque greffée à l'extension php PDO (phpDataObjects) PDO est une couche d'abstraction entre le serveur executant le code php et la base de données. PdoMap encapsule les entités d'une base de données sous la forme d'objet. PDO quant à lui gêre la connexion et le requettage AGILE TOOLKIT ORM : approche plus minimaliste que certains autres ORMs Doctrine : ORM en vogue, notamment dans Symfony 1.x et Symfony 2, assez complexe, beaucoup de fonctionnalités. Grande force son DQL (=Doctrine Query Language) : le langage de requêtage inspiré de Hibernate et son HQL (ORM Java) problèmes de performance sur des grosses bases (doctrine est gourmand en ressources) Doctrine 2 est à suivre de prêt ! Il y a bien longtemps : <?php $connect = mysql_connect('localhost','root','ListenToLorieOrDie') or die ("argg"); mysql_select_db('base',$connect) or die ("argg"); mysql_query("INSERT INTO utilisateur VALUES ('666','bofh','[email protected]') "); $resultat = mysql_query("SELECT id,nom,email from utilisateur"); while ( $ligne = mysql_fetch_array($resultat)){ echo $ligne[id].' - '.$ligne[nom].' - '.$ligne[email].'<br>'; } mysql_close(); ?> Il y a bien moins longtemps... <?php $connexion = new PDO("mysql:host=localhost_hote;dbname=base", ''root'',''ListenToLorieOrDie''); $resultat=$connexion->query("SELECT id,nom,mail FROM utilisateurs"); $resultat->setFetchMode(PDO::FETCH_OBJ); while( $ligne = $resultat->fetch() ) // on récupère la liste des membres { echo 'Nom : '.$ligne->nom.' - email : '.$ligne->email. '<br />'; } $resultat->closeCursor(); ?> Il y a encore bien bien moins longtemps : <?php class Utilisateur { private $id; private $nom; private $mail; public __get($property) { return $this->$property; } public __set($property, $value) { $this->$property = $value; } public __construct() {} public __destruct() {} } ?> Il y a encore bien bien moins longtemps : <?php class UtilisateurDbAccess { public static function create($p) { try { if (!($u instanceof Utilisateur)) throw new Exception('Erreur impossible de créer l\'utilisateur'); $db = new PDO("pgsql:dbname=pdo;host=localhost", "nom", "mail" ); $request = $dbh->prepare("INSERT INTO utilisateur (nom, mail) values (:nom, :mail)"); $request->bindParam(':nom', $u->nom, PDO_PARAM_STR, 128); $request->bindParam(':mail', $u->mail, PDO_PARAM_STR, 128) return $request->execute(); } catch(Exception $e) { echo $e->getMessage(); } } public static function getUtilisateur($id) { // renvoyer un utilisateur en fonction de son id ... } ... } ?> Test de doctrine • • • • • Le choix d'utiliser la POO est intéressant et flexible mais gros soucis il faut multiplier les classes par le nombre de tables. Peux vite devenir galère si en cours de dvt le modèle de données change souvent. Pour nos tests notre choix va se porter sur Doctrine Il faut créer notre projet : monProjetDossier/ Ensuite récupérer la bibliothèque doctrine et la mettre dans monProjetDossier/lib/vendor/doctrine/ Sinon on peut utiliser la sandbox Doctrine (cf démo) // contenu fichierconfig.php (ce fichier par la suite sera inclus dans notre projet (via require_once) : require_once(dirname(__FILE__) . '/lib/vendor/doctrine/Doctrine.php'); spl_autoload_register(array('Doctrine', 'autoload')); $manager = Doctrine_Manager::getInstance(); //Création de la chaîne de connexion pour la base de données $conn = Doctrine_Manager::connection('mysql://root:bla@localhost/db'); Doctrine_Core::loadModels('models'); // Remplace la fonction d'autoload pour la class Doctrine_Core spl_autoload_register(array('Doctrine_Core', 'modelsAutoload')); ... Test de doctrine • Notre MCD : Test de doctrine Pour créer le schéma de notre base nous utiliserons un fichier au format YAML. YAML : acronyme récursif de « YAML Ain't Markup Language » c'est un format adapté à la representation de données comme XML,JSON... Attention que des espaces pas de tabulations ! • Ex d'un fichier YAML : # default values all: # number of results for pagination results_number: 30 • • ldap: # params ldap host: ldapuds.u-strasbg.fr port: 389 user: cn=app-gestion,ou=accounts,ou=operateurs,o=annuaire pass: pasfounan baseuser: o=annuaire version: 3 exploit: # informations pages recup email (RE) titre_RE: Récupération des e-mails @etu.unistra.fr (ldap) flashOk_RE: adr_ok Notre schéma YAML pour notre BD Music: columns: title: {type: string(128), notnull: true} album_id: {type: integer, notnull: true} relations: Album: {local: album_id, foreign: id} Album: columns: title: {type: string(128), notnull: true} relations: Musics: {type: many, class: Music, local: id, foreign: album_id} Artists: {class: Artist, refClass: ArtistAlbum, local: album_id, foreign: artist_id} Artist: columns: firstname: {type: string(32), notnull: true} lastname: {type: string(32), notnull: true} relations: Albums: {class: Album, refClass: ArtistAlbum, local: artist_id, foreign: album_id} ArtistAlbum: columns: artist_id: {type: integer, primary: true} album_id: {type: integer, primary: true} Gogogadget au générateur de base de données. <?php // fichier d'init de la base de données dans un dossier 'models' require_once('config.php'); Doctrine_Core::dropDatabases(); Doctrine_Core::createDatabases(); Doctrine_Core::generateModelsFromYaml('schema.yml', 'models'); Doctrine_Core::createTablesFromModels('models'); ?> Creer des données dans la base <?php // sexpistols.php require_once('config.php') $album = new Album(); $album->title = 'Nevermind the bollocks'; $album->save(); $music = new Music(); $music->title = 'Anarchy in the UK'; $music->Album = $album; $music->save(); $music = new Music(); $music->title = 'God save the queen'; $music->Album = $album; $music->save(); $artist = new Artist(); $artist->firstname = 'Johnny'; $artist->lastname = 'Rotten'; $artist->Albums[] = $album; $artist->save(); $artist = new Artist(); $artist->firstname = 'Sid'; $artist->lastname = 'Vicioust'; $artist->Albums[] = $album; $artist->save(); ?> Requêtage • Doctrine permet de s'affranchir des commandes SQL • Il propose son propre langage de requêtage : le DQL pour « doctrine query language ». <?php $q = Doctrine_Query::create()->from('Artist'); $artists = $q->execute(); foreach ($artists as $artist) echo $artist->firstname.' '.$artist->lastname."\n"; ?> <?php $q = Doctrine_Query::create() ->from('Artist a') ->where('a.id <= ? AND a.firstname LIKE ?', array(1, 'Sid%')); $artists = $q->execute(); foreach ($artists as $artist) echo $artist->firstname.' '.$artist->lastname."n"; ?> CRUD (Create/Update/Delete) <?php $q = Doctrine_Query::create() ->from('Artist a') ->leftJoin('Album al') ->where('a.id <= 1 AND a.firstname LIKE ?', array(1, 'Joh%')) ->execute(); $q2 = Doctrine_Query::create() ->from('Artist a') ->leftJoin('Album al') ->where('a.id <= 1 AND a.firstname LIKE ?', array(1, 'Joh%')) ->execute(array(),Doctrine::HYDRATE_ARRAY); //debug echo ''<pre>''. print_r($q). ''</pre> '' ; echo ''<pre>''. print_r($q2). ''</pre> '' ?> Jointures <?php $q = Doctrine_Query::create() ->from('Artist a') ->leftJoin('Album al') ->where('a.id <= 1 AND a.firstname LIKE ?', array(1, 'Joh%')); //affiche la requête SQL générée via le DQL echo $q->getSqlQuery(); ?> Hydratation • • • Dans Doctrine par défaut on récupère un objet qui encapsule d'autres objets, dans certains cas il n'est pas nécessaire de stocker l'objet doctrine et l'ensemble de ses entités. On peut ainsi changer « l'hydratation » de notre objet Ex : un simple affichage de données il est pratique et benefique pour la mémoire du serveur de ne pas retourner un objet doctrine complet ! $q = Doctrine_Query::create()->from('TABLE'); // Comportement par défaut, retourne un tableau d'objet $results = $q->execute(array(),Doctrine::HYDRATE_RECORD); // Retourne un tableau associatif où les clés sont les noms des champs $results = $q->execute(array(),Doctrine::HYDRATE_ARRAY); // Retourne un simple tableau où les champs sont dans l'ordre qu'ils ont été appelés $results = $q->execute(array(),Doctrine::HYDRATE_NONE); Hydratation <?php $q = Doctrine_Query::create() ->from('Artist a') ->leftJoin('Album al') ->where('a.id <= 1 AND a.firstname LIKE ?', array(1, 'Joh%')) ->execute(); $q2 = Doctrine_Query::create() ->from('Artist a') ->leftJoin('Album al') ->where('a.id <= 1 AND a.firstname LIKE ?', array(1, 'Joh%')) ->execute(array(),Doctrine::HYDRATE_ARRAY); //debug echo ''<pre>''. print_r($q). ''</pre> '' ; echo ''<pre>''. print_r($q2). ''</pre> '' ?> Les methodes « magiques » • Les methodes dites « magiques » ou « magic finders » sont très pratiques. <?php // Ici on recupère toutes les données de la table Artist $artists = Doctrine_Core::getTable('Artist')->findAll(); // Récupère la musique qui a pour id 1 $music = Doctrine_Core::getTable('Music')->findOneById(1); // Récupère le morceau God save the queen $music = Doctrine_Core::getTable('Music')->findOneByTitle('God Save the queen'); // Récupère l'album qui a pour id 1 si son nom est Nevermind the bollocks $album = Doctrine_Core::getTable('Album')->findOneByIdAndTitle(1, 'Nevermind the bollocks'); ?> Les transactions • • • Parfois la mise à jour/insertion de données est incertaine il peut être utile d'utiliser le mécanisme des transactions. Tout d'abord il faut pouvoir accéder à l'objet de connexion à notre base : $conn = Doctrine_Manager::connection(); // la méthode connection renvoie la connexion courante à la base de données. Ensuite 3 étapes commencer la transaction / mise à jour (commit) ou retour en arrière (rollback) : $conn = Doctrine_Manager::connection(); $conn->beginTransaction(); $conn->commit(); // les changements sont appliqués en base $conn->rollback(); // changements en base annulés en gros control+z :) Exemple concret de transaction. <?php $conn = Doctrine_Manager::connection(); $conn->beginTransaction(); try { $user = new User(); $user->username = 'marczuckerberg'; $user->password = 'google+casuxamort'; $user->email = '[email protected]'; $user->save(); $payment = new Payment(); $payment->amount = '200000000K'; $payment->date = '10-02-2012'; $payment->save(); $conn->commit(); } catch(Exception $e) { $conn->rollback(); } ?> Conclusion • Doctrine c'est bon mangez'en !!!!! • Et bon appétit bien sur ! Références • • • • • • • • http://www.php.net http://www.phpscripts-fr.net/ http://www.nexen.net/ http://www.phpsecure.info ... http://phpsec.org Http://www.siteduzero.com http://www.phpclasses.org/ Pour les cours : – http://mastercaweb.u-strasbg.fr/bofh/site/src/ – http://mastercaweb.u-strasbg.fr/bofh/sitemultilingue/src/ – http://mastercaweb.u-strasbg.fr/bofh/src/ ( divers ) – http://mastercaweb.u-strasbg.fr/bofh/compteur.phps ( compteur ) – http://mastercaweb.u-strasbg.fr/bofh/site2leretour/src/ – http://mastercaweb.u-strasbg.fr/bofh/mail/mail.phps – http://mastercaweb.u-strasbg.fr/bofh/mail/site2boul.phps – http://mastercaweb.u-strasbg.fr/bofh/bafh/src/ – http://mastercaweb.u-strasbg.fr/bofh/regex/ – http://mastercaweb.u-strasbg.fr/bofh/regex/src/ (regex) – http://mastercaweb.u-strasbg.fr/bofh/rexex_ep2/ – http://mastercaweb.u-strasbg.fr/bofh/regex_ep2/src/ (regex 2 ) HAPPY E N D !