Module 02 Fondamentaux

Module 02 : Les fondamentaux de la programmation, avec PHP

Langage de programmation haut niveau #

Un langage de programmation de haut niveau est plus qu’un ensemble d’instructions qui vous permet de donner des ordres à un ordinateur, c’est également un outil pour penser et organiser vos idées sur des processus de calcul permettant de résoudre un problème donné. Comme tout langage, les langages de programmation permettent de combiner des idées simples pour des idées complexes. Un langage de programmation se base sur trois éléments essentiels :

Primitives #

echo 1 ;
echo 0 + 1 ;
echo 5 / 2 ;
echo 3 ** 2 ;
echo 1 + 2 * 5;
echo 10 / 3 + 7 * 5 + 1 ;
echo (5 * 2) * (5 + 1) ;
echo 12.5 - 7.3 + 5.0 / 3;
echo 64 % 2 ;
echo 9 % 2 ;
echo 'a' ;
echo 'a' . 'b';
echo 'une chaine' ;
echo 'une chaine' . ' '. 'concatenée' . ' '. 'avec une autre chaine' ;
echo 1 == 2 ;
echo 2 == 2 ;
echo 3 >= 2 ;
echo 2 != 2 ;
echo true ;
echo !true ;
echo true && false ;
echo true || false ;
echo 5 <= 2 && 25 > 12.5 ;
echo sqrt(3**4 + 5**2);

echo est une instruction qui permet d’afficher le résultat sur la sortie (écran)

PHP est un langage typé dynamiquement #

En PHP, il n’est pas nécessaire de définir le type de données référencée par une variable, le type est déduit au runtime :

$message = "hello, world";
//Imprimer la valeur de la variable sur la sortie
echo $message;
//Imprimer le type de la variable sur la sortie 
echo gettype($message);
echo gettype(new stdClass());
//Afficher le contenu et le type de la variable $message
var_dump($message);

Types principaux : boolean, int, double, string, array, object, NULL (absence de valeur), callable.

Voir tous les types du langage PHP.

Sur les opérateurs PHP #

$action = (empty($_POST['action'])) ? 'default' : $_POST['action'];

Opérateurs de comparaison #

Comparaison :

<?php
//Opérateurs de comparaison :
//@link https://www.php.net/manual/en/language.operators.comparison.php

if(1 == '1') echo "1 == '1' est VRAI" . PHP_EOL;
if(1 === '1') echo "1 === '1' est FAUX" . PHP_EOL;
if(1 !== '1') echo "1 !== '1' est VRAI". PHP_EOL;

Constantes #

Pour créer des constantes, utiliser la primitive define() :

define("CONSTANT", "Hello world.");
echo CONSTANT; // outputs "Hello world."

define('ANIMALS', [
    'dog',
    'cat',
    'bird'
]);

echo ANIMALS[1]; // outputs "cat"

//Afficher toutes les constantes définies et accessibles dans ce script
print_r(get_defined_constants());

Par convention, écrire les constantes en MAJUSCULES. On utilisera souvent des constantes en WordPress, notamment pour la configuration.

Flot de contrôle (structures de contrôle) #

Qu’est ce que le flot de contrôle ? #

Altérations du flot de contrôle #

Le flot de contrôle définit des chemins ou flots d’execution du programme. Le flot “naturel” d’un programme est donné par son code source, de haut en bas : les instructions sont exécutées dans l’ordre dans lequel elles sont écrites.

Il est possible de moduler ce flot en faisant des sauts (jumps) d’une instruction à l’autre. Il existe trois manières de moduler le flot :

Structures de contrôle : if #

Exécuter des instructions uniquement si une condition est vraie.

<?php
$age = 18;

//Structure if simple
if ($age >= 18) {
    //Ce code est exécuté seulement si la condition est vraie
    echo "Accès autorisé\n";
}
//Ensuite le reste du code est exécuté
echo "Bienvenue qui que vous soyez\n";

L’expression placée entre parenthèses ($age >= 18) doit pouvoir s’évaluer à vrai (true) ou faux (false).

Structures de contrôle : if/else #

<?php
$age = 16;

if ($age >= 18) {
    echo "Accès autorisé";
} else {
    echo "Accès refusé";
}

Expressions évaluables à “vrai” ou “faux” #

On parle de prédicat. Par exemple la phrase “il est en train de pleuvoir” est un prédicat que l’on peut évaluer à vrai ou faux (soit il pleut, soit il ne pleut pas)

Écrire des prédicats en PHP #

En PHP, un prédicat est une expression de comparaison ou une expression logique. Pour cela, on utilise les opérateurs relationnels (de comparaison) et logiques :

$age >= 18        // true ou false
$quantity > 0    // true ou false
$isAdmin == true // true ou false
$age >= 18 && $hasTicket   // ET
$age < 18  || $isStudent  // OU
!$isBlocked               // NON

Prédicats usuels #

$a == $b   // égal à
$a != $b   // différent de
$a <  $b   // inférieur à
$a >  $b   // supérieur à
$a <= $b   // inférieur ou égal
$a >= $b   // supérieur ou égal

Exemples #

<?php
$quantity = 3;

if ($quantity > 0) {
    echo "Commande valide";
} else {
    echo "Quantité invalide";
}
<?php
$quantity = 2;
$inStock = true;

if ($quantity > 0 && $inStock) {
    echo "Commande acceptée";
}

Exercice 1 #

Pour chaque expression, indiquer si elle vaut true ou false:

//Valeurs de $a et $b données
$a = 5;
$b = 10;

$a < $b
$a == $b
$a != $b
$a >= 2 * 5
$b / 2 < 5

Exercice 2 #

Écrire le prédicat correspondant à la phrase L'utilisateur est connecté et n’est pas bloqué à l’aide des variables $isLoggedIn et $isBlocked

Structures de contrôle : for #

Répéter une ou plusieurs instructions

<?php
//Boucle for
for($i = 0 ; $i < 100; $i = $i + 1){ 
  //Ici on répète "imprime le nombre" autant de fois que nécessaire 
  echo "$i ";
}

Structures de contrôle : combiner for et if #

<?php

//Indiquer si un nombre est pair ou impair
for($i = 0 ; $i < 100; $i = $i + 1){
    if($i % 2 === 0){
        echo "$i est un nombre pair";
    }else{
        echo "$i est un nombre impair";
    }
}

Structures de contrôle : for syntaxe alternative #

<?php

//Boucle for
for($i = 0 ; $i < 100; $i = $i + 1) :
    //Embranchement avec if/else (tests)
    if($i % 2 === 0) :
        echo "$i est un nombre pair";
    else :
        echo "$i est un nombre impair";
    endif;
endfor;

Sera utile dans les templates ! Plus lisible, plus pratique pour produire du HTML

Structures de contrôle : while et do-while #

<?php

$i = 1;
while ($i <= 10) {
    echo $i++;  /* La valeur affichée est $i avant l'incrémentation
                   (post-incrémentation)  */
}

$i = 0;
do {
    echo $i;
} while ($i > 0);

En savoir plus sur while, sur do-while

Structures de contrôle : while et do-while, syntaxe alternative #

<?php

$i = 1;
while ($i <= 10) :
    echo $i++;  
endwhile;

Structures de contrôle : switch #

Alternative à if/else si les cas sont énumérables et tests d’égalité uniquement

<?php

$i=2;
switch ($i) {
    case 0:
        echo "i égal 0";
        break;
    case 1:
        echo "i égal 1";
        break;
    case 2:
        echo "i égal 2";
        break;
}

En savoir plus sur switch

Syntaxe alternative #

$i=2;
switch ($i) :
    case 0:
        echo "i égal 0";
        break;
    case 1:
        echo "i égal 1";
        break;
    case 2:
        echo "i égal 2";
        break;
endswitch;

Structures de contrôle : foreach #

Syntaxe commode pour parcourir des collections d’items. Permet de se passer ou non de l’index.

<?php
$arr = array(1, 2, 3, 4);

//Parcourir un tableau en parcourant uniquement ses valeurs
foreach ($arr as $value) {
    //$value est une variable locale à la boucle qui contiendra chaque valeur du tableau (1, puis 2, puis 3, puis 4)
    //a chaque itération
    echo $value . PHP_EOL;
}
//Parcourir un tableau en parcourant ses clefs ET ses valeurs
//Syntaxe: foreach(tableau as clef => valeur)
foreach($arr as $index => $value){
    echo "Index: {$index} - Value: {$value} \n";
}

En savoir plus sur foreach

Structures de contrôle : foreach syntaxe alternative #

Les accolades ouvrantes et fermantes de la boucle sont remplacées par le caractère : et par une instruction endforeach; :

<?php
$arr = array(1, 2, 3, 4);

// foreach($arr as $index => $value){
//     echo "Index: {$index} - Value: {$value} \n";
// }

foreach($arr as $index => $value) :
    echo "Index: {$index} - Value: {$value} \n";
endforeach;

Syntaxes alternatives dans les templates #

Lorsque l’on utilise PHP pour générer des pages HTML, les structures de contrôle usuelles offrent une syntaxe alternative afin d’améliorer (un peu) la lisibilité du code source de la page.

Prenons un exemple :

//Tout le HTML est généré depuis un code PHP
$items = ['pomme', 'poire', 'raisin'];
echo "<ul>";
foreach($items as $item){
    echo "<li>$item</li>";
}
echo "</ul>";

Structures de contrôle, syntaxes alternatives dans les templates #

Dans un template, le script PHP est essentiellement constitué de texte (code HTML), le contenu est donc imprimé sur la sortie sans modification. Les balises PHP ne sont ouvertes que pour insérer des données dynamiques :

//Le HTML est écrit directement, PHP est seulement utilisé pour les données dynamiques
<?php $items = ['pomme', 'poire', 'raisin']; ?>
<ul>
<?php foreach ($items as $item) { ?>
        <li><?php echo $item ?></li>
<?php } ?>
</ul>

Syntaxe encore difficile à lire…

Syntaxes alternatives dans les templates (foreach) #

Idem que précédemment mais avec la syntaxe alternative pour le foreach :

//Le HTML est écrit directement, PHP est seulement utilisé pour les données dynamiques
<?php $items = ['pomme', 'poire', 'raisin']; ?>
<ul>
<?php foreach ($items as $item) :?>
        <li><?php echo $item ?></li>
<?php endforeach; ?>
</ul>

Cette syntaxe alternative est plus lisible, notamment lorsque les pages à générer deviennent plus complexes.

En savoir plus sur la syntaxe alternative

Syntaxes alternatives dans les templates (if/else) #

La structure de contrôle if/else (embranchement) dispose également d’une syntaxe alternative.

<?php $items = ['pomme', 'poire', 'raisin']; ?>
//...
//Syntaxe alternative pour le if
<?php if(!empty($items)) : ?>
    <!-- Cette balise sera écrite dans la page web si la liste d'items n'est pas vide -->
    <p> Il y a des items dans la liste ! </p>
<?php else : ?>
    <!-- Cette balise sera écrite dans la page web sinon -->
    <p> La liste est vide ! </p>
<?php endif; ?>

Les variables en PHP #

En PHP, pas besoin de déclarer une variable avant de lui affecter une valeur. Un nom de variable doit toujours commencer par un dollar ($).

//La variable $message contient la valeur 'hello, world' de type 'string'
$message = 'hello, world';
//Un tableau (collection de valeurs)
$monTableau = [1, 2, 3];
$nombre = 12;
$nombreRationnel = -1.5;

Inspecter #

Pour inspecter le contenu d’une variable et/ou son type. Utile pour débuger et comprendre son programme et regarder les valeurs

$name = "Jane Doe";
//Ecrire la valeur sur la sortie
echo $name;
$grades = [12, 10, 19, 8];
//Imprimer le contenu d'un tableau de manière lisible
print_r($grades);
//Imprimer le contenu de n'importe quelle variable et des types des données
var_dump($grades);

Les chaînes de caractères #

<?php 
echo 'ceci est une chaîne simple';
echo 'Vous pouvez également ajouter des nouvelles lignes
dans vos chaînes
de cette façon';

// Echapper des caractères spéciaux avec l'antislash (ici la guillemet simple avec \') pour signifier qu'il fait partie de la chaîne
echo 'Arnold a dit : "I\'ll be back"';
echo 'Voulez-vous supprimer C:\*.*?';

$firstName = "Jane";

//Les simples quotes ne permettent aucune interprétation de caractères spéciaux dans la chaine
echo 'La variable $firstName ne sera pas interpolée ici (remplacée par sa valeur)\n';

//Les doubles quotes effectuent des interprétations de caractères spéciaux (interpolation, caractère de retour à la ligne, etc.)
echo "La variable $firstName sera interpolée ici (remplacée par sa valeur)\n";

Syntaxe Heredoc #

Une autre façon de délimiter une chaîne de caractères est la syntaxe Heredoc : <<<. Après cet opérateur, un identifiant est fourni (ici END), suivi d’une nouvelle ligne. La chaîne de caractères en elle-même vient ensuite, suivie du même identifiant pour fermer la notation.

<?php
// no indentation
echo <<<END
$$$$$$$\  $$\   $$\ $$$$$$$\  
$$  __$$\ $$ |  $$ |$$  __$$\ 
$$ |  $$ |$$ |  $$ |$$ |  $$ |
$$$$$$$  |$$$$$$$$ |$$$$$$$  |
$$  ____/ $$  __$$ |$$  ____/ 
$$ |      $$ |  $$ |$$ |      
$$ |      $$ |  $$ |$$ |      
\__|      \__|  \__|\__|                                  
END;

Syntaxe Heredoc : stocker le résultat dans une variable #

$text= <<<FOOBAR
À d’autres la satiété ! Toi, tu gardes ton désir, désir exubérant qui déborde toujours : moi qui te poursuis sans cesse, je viens par-dessus le marché faire addition à tes tendres caprices.

Toi, dont le désir est si large et si spacieux, ne daigneras-tu pas une fois absorber mon désir dans le tien ? Ton désir sera-t-il toujours si gracieux aux autres sans jeter sur mon désir un rayon de consentement ?

La mer, qui est toute eau, reçoit pourtant la pluie encore, et ajoute abondamment à ses réservoirs : ainsi toi, riche de désir, ajoute à tes désirs la goutte du mien, et élargis ton caprice.

Ne te laisse pas accabler par tant de tentations, bonnes ou mauvaises : confonds-les toutes en une, et aime Will dans ce désir unique (1). 
FOOBAR;
echo $text;

Quelques fonctions utiles pour manipuler les chaînes de caractères #

sprintf, number_format, strtolower, strtoupper, ucwords, strpos, date, mktime


$x = 'bOnJoUr eT bIeNvEnUe';
echo "<p><code>strtolower('$x')</code> = " . strtolower($x) . '<br>';
echo "<code>ucwords('$x')</code> = " . ucwords($x) . '<br>';
echo "<code>ucwords(strtolower('$x'))</code> = " . ucwords(strtolower($x)) . ' </p>';
echo '<h5>Mise en forme avec <a href="http://php.net/manual/fr/function.sprintf.php"><code>sprintf()</code></a></h5>';
echo '<p>Mise en forme d\'une date : ' . sprintf('%02d/%02d/%04d', 1, 1, 1981) . '</p>';

echo '<h5>Mise en forme avec <a href="http://php.net/manual/fr/function.number-format.php"><code>number_format()</code></a></h5>';
$x = 1234.567;
echo "<p><code>number_format($x)</code> = " . number_format($x) . '<br>';
echo "<code>number_format($x,1)</code> = " . number_format($x, 1) . '<br>';
echo "<code>number_format($x,2,',',' ')</code> = " . number_format($x, 2, ',', ' ') . '</p>';

echo '<p><code>date("d/m/Y H:i:s", mktime(11, 45, 30, 4, 10, 2017))</code> = ' . date("d/m/Y H:i:s", mktime(11, 45, 30, 4, 10, 2017)) . '<br>';
echo 'Unix a fêté sa milliardième seconde le ' . date("d/m/Y H:i:s", 1000000000) . '</p>';
echo '<p>Date du jour au format JJ/MM/AAAA : ' . date('d/m/Y') . '<p>';

Les tableaux en PHP #

Les tableaux en PHP sont très (trop) puissants et versatiles :

$array = [1, 2, 3, ['a','b','c', [1,2,3]]];
//La fonction count() permet de connaître le nombre d'éléments dans le tableau
echo "Taille du tableau : " . count($array) . PHP_EOL;

En savoir plus

Les tableaux associatifs en PHP #

En PHP, un tableau est une collection de couples clé/valeur : [clé => valeur]

//Tableau : on déclare les clefs et les valeurs
$magasin = [
    'citron' => 5,
    'banane' => 12,
    'poireau' => 20
];

//Parcourir un tableau en parcourant ses clefs ET ses valeurs
//Syntaxe: foreach(tableau as clef => valeur)
foreach($magasin as $product => $quantity){
    //Equivalent "string literals" avec les back tick en JS
    //Ici $product et $quantity vont être remplacées par
    //leurs valeurs dans la chaîne.
    echo "Produit: {$product} - Quantité: {$quantity} \n";
}

//Ajouter un élément
$magasin['riz'] = 12;
//Supprimer un élément
unset($magasin['riz']);

Fonctions utiles sur les tableaux #

$array = [1,2,3];
//count : Retourne le nombre d'éléments
count($array);
//implode: Construit une chaine à partir des éléments d'un tableau, avec un séparateur
$array = ['lastname', 'email', 'phone'];
//in_array : permet de tester si un élément est dans le tableau
if(in_array('email', $array)){
    echo "email est dans le tableau";
}
//shuffle : mélange les éléments du tableau de manière aléatoire
shuffle($array);
var_dump(implode(",", $array)); // string(20) "lastname,email,phone"

Voir toutes les fonctions natives de PHP pour manipuler le tableaux

NULL #

NULL est un type spécial et une valeur qui indique l’absence de valeur. La fonction isset() est parfaitement adaptée pour tester la présence d’une valeur ou d’une clef dans un tableau.

$var = NULL;
//Test avec la fonction isset :
if(!isset($var)){
    echo "la variable ne contient aucune valeur !";
}

En savoir plus

Moyens d’abstraction #

Un aspect essentiel de la programmation est de pouvoir nommer les choses afin de pouvoir raisonner et donner du sens à nos programmes.

Une fois une procédure (suite d’instructions, action) clairement identifiée, la nommer pour en faire une boîte noire et l’utiliser sans avoir besoin de se soucier de comment elle accomplit sa tâche.

Exemples de procédure #

Moyens d’abstraction : fonctions #

Une fonction (ou procédure) est une unité de programmation qui est définie par :

Déclarer et utiliser ses fonctions en PHP #

Une fonction, avant d’être appelée (exécutée), doit être déclarée avec le mot clef function. Une fonction peut prendre des arguments (ou pas) et retourne toujours quelque chose (si pas d’instruction return, elle retourne NULL)

On indique le type des données des arguments et de retour de la fonction (type hinting)

//Déclaration de la fonction
function sayHi(string $firstName, string $lastName) : string{
    //Le corps de la fonction (les instructions à faire)
    //Pour interpolation, il faut utiliser les guillemets doubles
    //Les guillemets simples n'interprètent pas le contenu de la chaine
    $msg = "Hello $firstName $lastName !";
    //La fonction retourne son résultat (une chaîne de caractère)
    return $msg;
}

//Appel de la fonction
echo sayHi('Jane', 'Doe');

En savoir plus sur les fonctions.

Interface (signature) et corps (body) #

Boîte noire #

w:800

Bien nommer une fonction, bien nommer les arguments #

Il est recommandé d’utiliser le mode impératif à la 2eme personne du présent pour nommer une fonction (ou infinitive en anglais). Une fonction agit, elle manipule des données. Un verbe est donc un bon nom de fonction. Par exemple, search, create-new-game ou enleve-voyelles représentent de très bons choix.

Il est aussi important de bien nommer les arguments pour que l’utilisateur·ice de votre fonction comprenne facilement à quoi ils correspondent. N’utilisez jamais de noms à un caractère comme a ou i, sauf si la fonction est triviale ou mathématique. Aujourd’hui nous disposons d’outils d’autocomplétion, nous n’avons aucune excuse pour ne pas donner des noms longs mais significatifs à nos variables et à nos fonctions.

Type hinting #

PHP est un langage typé dynamiquement, ce qui apporte de la flexibilité mais peut conduire à des comportements inattendus ! (bugs).

Depuis PHP 7, il est possible (et recommandé) de déclarer les types des arguments et retours de fonction.

Type hinting en pratique #

Cela assure à l’execution que la valeur passée en argument à une fonction est du type attendu, sinon une erreur fatale TypeError est lancée (si coercition désactivée) et interrompt l’exécution du programme.

<?php
//Déclaration de fonction utilisant le *type hinting* : attend une chaîne et un entier, retourne une chaîne
function repeat(string $str, int $times): string {
    if($times == 0)
      return '';
    return $str . repeat($str, $times - 1) ;
}

echo repeat("ha", 13);

TOUJOURS utiliser le type hinting !

Conversion automatique #

Attention, concernant les valeurs scalaires ou primitives (string, int, float, etc.), PHP tente par défaut de convertir (coerce) vers le type attendu (défini par le type hinting)

<?php
function sum(int $a, int $b): int {
    return $a + $b;
}

var_dump(sum(1.5,2.5)); // Affiche int(3)

Conversion automatique et typage strict #

Pour empêcher PHP de faire cette conversion (qui peut provoquer des comportement inattendus!), on peut activer le mode typage strict par fichier, avec l’instruction declare(strict_types=1);

Elle peut aussi éviter des problèmes non anticipés…

Dans ce mode, seule une variable correspondant exactement au type attendu dans la déclaration sera acceptée sinon une TypeError sera levée, sauf si la conversion garantit l’intégrité de la donnée (int -> float)

<?php
declare(strict_types=1);

var_dump(sum(1.5, 2.5));

Sortie :

PHP Fatal error:  Uncaught TypeError: sum(): Argument #1 ($a) must be of type int, float given

Typage strict #

En résumé #

Site web dynamique avec PHP #

PHP est particulièrement adapté pour réaliser des sites web dynamiques.

Un site web écrit en PHP peut facilement interagir avec des bases de données et effectuer des opérations complexes côté serveur pour générer du contenu web dynamique personnalisé à chaque requête HTTP.

Soumettre des données au serveur #

Pour envoyer des données à un service web (site web), on utilise un formulaire, soit la balise <form> HTML. Le formulaire contient des balises <input> permettant au client de saisir les données nécessaires au traitement de sa demande (voir cours Dev Front)

Une balise form possède notamment deux attributs :

<!-- Formulaire sera posté sur l'URL {origine de la page web}/confirm-order.php, avec la méthode POST -->
<form action="/confirm-order.php" method="POST">
    <label for="quantity">Quelle quantité de riz basmati (kg) souhaitez-vous ? </label>
    <input type="number" name="quantity" id="quantity">
    <input type="submit" value="Valider la commande" name="order">
</form>

Cycle requête/réponse typique #

  1. Le client émet une requête HTTP GET monsite.com avec son navigateur favori;
  2. La requête arrive sur la machine identifiée par le nom de domaine monsite.com. Sur cette machine, le serveur web récupère la requête et identifie le script PHP à appeler;
  3. Le serveur web exécute le script PHP identifié;
  4. Le script PHP, à l’exécution, effectue diverses actions : lecture/écriture de fichiers, récupération/création/formatage de données etc.
  5. Le script PHP génère le contenu de la page web (du HTML) à retourner au client;
  6. Le serveur web récupère la sortie du script et le retourne au client dans une réponse HTTP;
  7. Le client reçoit la réponse HTTP. Le navigateur récupère le contenu de la réponse (ici du HTML) et traite le document HTML : création du DOM, rendu graphique (abordé dans le cours Dev Front);
  8. Le client visualise la réponse. La page web contient des liens et/ou des formulaires invitant le client à poursuivre sa navigation via une nouvelle requête (GET ou POST);
  9. Retour au 1.

On parle de programmation CGI lorsqu’un serveur web, au lieu de servir un fichier HTML statique, execute un programme dont la sortie est retournée au client

PHP dans le contexte web #

Pour générer la page web, le script PHP est exécuté par un autre programme : le serveur web (Apache, Nginx, Caddy, etc.). Le serveur web transmet au script PHP toutes les informations nécessaires pour que le script puisse faire son travail et générer sa réponse via des tableaux spéciaux appelés variables super globales.

Lire la page Variables externes à PHP de la documentation officielle.

Variables Super Globales #

Les variables Super Globales sont des variables fournies aux scripts PHP à l’exécution contenant toutes les informations sur l’environnement du script, la requête HTTP, le client, le serveur, etc.

Ce sont des tableaux associatifs PHP, qui commencent, par convention, par un underscore (_).

#Un tableau associatif des valeurs passées au script courant via le protocole HTTP et la méthode POST 
$_POST;
#Un tableau associatif des valeurs passées au script courant via le protocole HTTP et la méthode GET 
$_GET;
#$_SERVER est un tableau contenant des informations telles que les en-têtes, les chemins et les emplacements de script. Crée par le serveur web (programme)
$_SERVER;
#Un tableau associatif des valeurs téléchargées au script courant via le protocole HTTP et la méthode POST
$_FILES;
#Un tableau associatif de variables, passé au script courant, via des cookies HTTP. 
$_COOKIE;
#Un tableau associatif qui contient par défaut le contenu des variables $_GET, $_POST et $_COOKIE. 
$_REQUEST;

Ne modifiez jamais vous-même ces tableaux, accédez-y en lecture seulement.

Formulaire en pratique #

<!-- Formulaire sera posté sur l'URL {origine de la page web}/confirm-order.php, avec la méthode POST -->
<form action="/confirm-order.php" method="POST">
    <label for="quantity">Quelle quantité de riz basmati (kg) souhaitez-vous ? </label>
    <input type="number" name="quantity" id="quantity">
    <input type="submit" value="Valider la commande" name="order">
</form>

Récupérer les données côté serveur #

Pour récupérer les données côté serveur, on utilise la variable superglobale $_POST :

<?php
//Script confirm-order.php
$quantity = $_POST['quantity'];
//Je peux travailler avec la valeur fournie par le client, par exemple préparer sa commande

Il faudra évidemment prendre des précautions pour manipuler les données soumises au serveur, comme on le verra par la suite.

Si on avait utilisé la méthode GET pour soumettre le formulaire, on aurait du utiliser le tableau $_GET

Démo variables super-globales #

Accéder à la démo sur le dépôt du cours.

Traitement de formulaire #

On peut traiter le formulaire envoyé par le client :

Le traitement du formulaire se fait grâce aux variables super globales qui mettent à disposition du script PHP les données envoyées par le client.

Le service web peut alors effectuer sa logique basée sur le contenu du formulaire et rendre le service adéquat à son client.

Démo traitement de formulaire #

Fonctions PHP utiles pour le web et le traitement de formulaires #

#Retourne vrai si la clé foobar existe dans $_POST (valeur soumise pour ce champ avec l'attribut name égal à 'foobar')
$bool = isset($_POST['foobar']);
#Échapper les balises HTML
htmlentities($untrustedString);
#Génère une chaîne de requête en encodage URL
http_build_query($data);
#Analyse une URL et retourne ses composants
parse_url($url);
#Récupère plusieurs variables et les filtre
filter_var_array($array, $filters);
#Cette fonction est utile pour récupérer plusieurs valeurs sans avoir à appeler plusieurs fois la fonction filter_input(). 
filter_input_array(INPUT_POST, $args);
#Récupère une variable externe et la filtre
$search_html = filter_input(INPUT_GET, 'search', FILTER_SANITIZE_SPECIAL_CHARS);

En savoir plus sur filter_input, filter_input_array

Sécurisation des données et validation des formulaires avec PHP #

Les formulaires exposées par un service web permettent à n’importe quel client de soumettre des données. Le client peut envoyer n’importe quelle donnée, autant de fois qu’il le désire et peut essayer, s’il est mal intentionné, de briser ou de pénétrer dans votre service web.

Chaque formulaire agrandit la surface d’attaque de votre service web.

Règle d’or : NE JAMAIS FAIRE CONFIANCE AU CLIENT. Toute donnée envoyée par un client doit être validée par le serveur.

Quid des contraintes mises sur les input dans votre page HTML ? D’un point de vue sécurité, elles ne valent rien. RIEN. Un client peut les modifier à sa guide, il peut même soumettre des données à votre serveur sans utiliser votre formulaire. Les contraintes sur les input servent simplement à guider votre client et l’informer sur ce que vous attendez (UX).

Le serveur a le dernier mot #

Par définition, tout ce qui se passe côté client (côté front) est public et ne peut pas être sécurisé. C’est donc au serveur, ici à vos scripts PHP, de vérifier toute donnée entrante provenant de l’extérieur. Le serveur doit vérifier toute donnée soumise via une requête GET (paramètres d’URL) ou POST (corps de la requête) avant de les manipuler et de les utiliser pour réaliser le service attendu.

Pour sécuriser les données entrantes dans le service web, il existe plusieurs stratégies :

Bonne pratique #

Identifier clairement les données dans votre script PHP qui proviennent de l’extérieur, et sont potentiellement dangereuses pour votre service, et celles qui ont été validées.

//On déclare un tableau qui contient toutes les données validées
$clean = [];
//Si une donnée est validée, on l'ajoute dans le tableau
if(isset($_POST['color']) && in_array($_POST['color'], $acceptedColors)){
    $clean['color'] = $_POST['color'];
}

Valider des données #

La validation est le cas idéal et doit être utilisée dès que possible. Cela consiste à comparer la valeur fournie à une liste de valeurs acceptées. Si la valeur fournie n’est pas dans la liste, elle est rejetée (liste blanche)

//Liste des valeurs acceptées
$acceptedColors = ['red', 'white','blue'];
//Si la donnée 'color' soumise est dans la liste, on l'accepte et on poursuit le traitement
if(isset($_POST['color']) && in_array($_POST['color'], $acceptedColors)){
    $clean['color'] = $_POST['color'];
}else{
    echo "Couleur invalide";
    exit;
}

Côté client, utiliser la validation se traduit par le fait de proposer le moins d’inputs “ouverts” possibles (input text) et de privilégier les inputs “fermés” : choix parmi une liste (select, checkbox, radio buttons). Fermer au maximum les questions que vous posez aux clients pour améliorer l’experience utilisateur et la sécurité de votre service.

Sanitization/Filtrage #

Lorsqu’il n’est pas possible de valider des données (un nom, un prénom par exemple), i.e quand le nombre possible de réponses est impossible à déterminer à l’avance, on peut ajouter une couche de filtrage des données.

Filtrer (sanitize) les données consister à modifier les données entrantes pour les rendre inoffensives, généralement en supprimant ou remplaçant des caractères. Par exemple, en retirant tous les caractères spéciaux qui pourraient être utilisés pour former des balises HTML, à savoir <, > et />.

Pour cela, en PHP, on peut utiliser les fonctions filter_var, filter_input, filter_input_array

Attention, une politique de filtration/sanitization n’apporte aucune garantie. À utiliser judicieusement, utiliser des filtres éprouvés (fournis par PHP).

Échappement de caractères spéciaux #

L’échappement est, avec la validation, le meilleur mécanisme de défense pour votre application. Contrairement au filtrage (sanitization), l’échappement ne modifie pas les données entrantes mais s’assure que, dans un contexte donné, cette donnée soit utilisée de manière sécurisée en échappant (rendant inoffensif) les caractères jugés dangereux pour ce contexte.

Par exemple :

Recommandation/Mantra : Don’t sanitize input. Escape output.

Démos sur la sécurisation des données externes et de formulaires #

PHP comme moteur de templates (template engine) #

Par définition, PHP est un moteur de templates (imparfait) : à partir d’un unique script PHP, il est possible de générer un nombre indéterminé de pages web différentes en fournissant au script les données à présenter.

Pour créer des templates modulaires (avec des parties réutilisables), il est essentiel de diviser nos scripts PHP en plusieurs fichiers. Ainsi, un même script peut être réutilisé dans différents contextes.

Par exemple, le header et le footer d’un site web sont généralement identiques d’une page à l’autre. On peut donc placer ces morceaux de templates (template parts) ou composants dans des fichiers header.php et footer.php et les utiliser (importer) dans le script index.php qui génère la page d’accueil.

Répartir le code PHP dans différents fichiers et l’importer au besoin #

Pour utiliser le code PHP placé dans un autre fichier, on peut utiliser le construct require_once:

<?php
//Inclure tout le contenu (UNE FOIS) du fichier foo.php dans le script courant
require_once './foo.php';
//Inclure tout le contenu (UNE FOIS) du fichier foo.php dans le script courant
require_once './bar.php';
//N'aura aucun effet
require_once './bar.php';

Il existe d’autres construct pour inclure des scripts : include, include_once, require, etc.. Pour le moment, privilégier require_once.

Précisions sur le mécanisme d’import de script PHP 1 #

Le require_once n’agit pas comme un simple copier/coller textuel brut du contenu du script importé (comme #include en C), mais comme une évaluation du script. Conséquences :

Précisions sur le mécanisme d’import de script PHP 2 #

Fichier component.php :

<?php $last_component = "p"; ?>
<p>Un composant</p>

Fichier index.php :

//require_once ouvre, compile et execute le script component.php comme si on avait fait 'php component.php'
require_once 'component.php';
echo $last_component;

Exécuter le script index.php produit la sortie suivante :

<p>Un composant</p>
p

Démo : site avec des templates #

Structures de contrôle, syntaxes alternatives dans les templates 1 #

Lorsque l’on utilise PHP pour générer des pages HTML, on peut utiliser une syntaxe alternative afin d’améliorer la lisibilité du code source de la page.

Prenons un exemple :

//Tout le HTML est généré depuis un code PHP
$items = ['pomme', 'poire', 'raisin'];
echo "<ul>";
foreach($items as $item){
    echo "<li>$item</li>";
}
echo "</ul>";

Il existe de nombreuses façons de construire le code source d’une page HTML avec PHP.

Structures de contrôle, syntaxes alternatives dans les templates 2 #

Le script PHP est essentiellement constitué de texte (code HTML), le contenu est donc imprimé sur la sortie sans modification (voir fonctionnement de PHP dans le Module 1). Les balises PHP ne sont ouvertes que pour insérer des données dynamiques :

//Le HTML est écrit directement, PHP est seulement utilisé pour les données dynamiques
<?php $items = ['pomme', 'poire', 'raisin']; ?>
<ul>
<?php foreach ($items as $item) { ?>
        <li><?php echo $item ?></li>
<?php } ?>
</ul>

Structures de contrôle, syntaxes alternatives dans les templates 3 #

Idem que précédemment mais avec la syntaxe alternative pour le foreach : les accolades ouvrantes et fermantes de la boucle sont remplacées par le caractère : et par une instruction endforeach;

//Le HTML est écrit directement, PHP est seulement utilisé pour les données dynamiques
<?php $items = ['pomme', 'poire', 'raisin']; ?>
<ul>
<?php foreach ($items as $item) :?>
        <li><?php echo $item ?></li>
<?php endforeach; ?>
</ul>

Cette syntaxe alternative est plus lisible, notamment lorsque les pages à générer deviennent plus complexes.

En savoir plus sur la syntaxe alternative

Structures de contrôle, syntaxes alternatives dans les templates 4 #

La structure de contrôle if/else (embranchement) dispose également d’une syntaxe alternative.

<?php $items = ['pomme', 'poire', 'raisin']; ?>
//...
//Syntaxe alternative pour le if
<?php if(!empty($items)) : ?>
    <!-- Cette balise sera écrite dans la page web si la liste d'items n'est pas vide -->
    <p> Il y a des items dans la liste ! </p>
<?php else : ?>
    <!-- Cette balise sera écrite dans la page web sinon -->
    <p> La liste est vide ! </p>
<?php endif; ?>

Exemple concret d’usage de la syntaxe alternative dans les templates d’un thème Wordpress #

Exemple d’usage de la syntaxe alternative pour la Loop Wordpress, un pattern au coeur du fonctionnement du CMS :

//Script PHP en charge d'afficher la liste des articles, d'un article, etc.
//S'il y a des posts (articles), parcourir les posts (while)
//Affiche le contenu du post (the_content()) et passer au post suivant (the_post())
 <?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
    <div class="entry">
        <?php the_content(); ?>
    </div>
 <?php endwhile;?>

Démo structures de contrôles, syntaxe alternative #

Accéder à la démo sur le dépôt du cours.

Créer des templates #

Illustration avec le code source du template de la page principale d’un thème Wordpress

Manipuler des fichiers en PHP #

PHP offre tous les outils nécessaires pour manipuler des fichiers (créer, supprimer, lire, écrire).

Un fichier texte est un moyen simple, universel et efficace de persister des données sur le disque. En effet, “PHP n’a pas de mémoire”. Lorsqu’un script termine son execution, toutes les données manipulées sont perdues. Dans le contexte du web, chaque requête HTTP est traitée par un script PHP de manière indépendante. A chaque fin d’execution, toute la mémoire allouée au script (par exemple le contenu des variables) est libérée.

Nous pouvons nous servir de simples fichiers textes comme système de mémoire pour notre site web, et permettre aux scripts de maintenir des données d’un traitement à l’autre. C’est une base de données simple et minimale, mais qui peut s’avérer largement suffisante dans bien des cas d’utilisation.

Travailler avec des fichiers : création et écriture #

//Ouverture d'un fichier en écriture (le crée s'il n'existe pas)
$file = fopen('data.txt', 'w');
//Écriture dans le fichier
fwrite($file, 'Cette ligne sera écrite dans le fichier.');
//Fermeture du fichier
fclose($file);
//Supprimer le fichier
unlink('data.txt');

Voir la liste de toutes les fonctions relatives à la manipulation de fichiers.

Travailler avec des fichiers: lecture ligne par ligne #

//Ouverture du fichier en mode lecture ('r')
$file = fopen('data.txt', 'r');
//Vérifier que le fichier existe et a bien été ouvert
if(!$file){
    echo "Une erreur s'est produite à l'ouverture du fichier";
    exit;
}
//Lire un fichier ligne par ligne
$lines=[];
//Tant que ce n'est pas la fin du fichier, lire la prochaine ligne avec fgets
while(!feof($file)){
    //Lire ligne par ligne avec fgets
    $line = fgets($file);
    $lines[] = $line;
}
var_dump($lines);

Il est possible de lire byte par byte avec fgetc

Travailler avec des fichiers: lecture en bloc #

//Lit tout le contenu d'un fichier et retourne le contenu sous forme de chaine de caractère
$content = file_get_contents('somefile');
//Lit tout le contenu d'une URL
$content = file_get_contents('https://google.com');

Travailler avec des fichiers : format CSV 1 #

Le format CSV est un format simple et efficace pour stocker des données au format texte. Chaque ligne du texte correspond à une ligne d’un tableau et les virgules correspondent aux séparations entre les colonnes de ce tableau. Par défaut, la séparation entre les colonnes est marquée par une virgule.

Exemple de fichier CSV : 3 enregistrements (la première ligne contient les noms des colonnes et est ignorée) sur 3 colonnes.

Sexe,Prénom,Année de naissance
M,Alphonse,1932
F,Béatrice,1964
F,Charlotte,1988

Travailler avec des fichiers : format CSV 2 #

PHP fournit des fonctions natives pour faciliter le travail avec le format CSV. Ces fonctions se chargent de formater les données, en écriture et en lecture. Utilisez-les ! Elles permettent notamment de valider le format du fichier pour éviter des erreurs de lecture ou d’écriture.

Écrire les données avec fputcsv 3 #

<?php
//Des données que l'on souhaite écrire sur le disque
$list = array (
   array('aaa', 'bbb', 'ccc', 'dddd'),
   array('123', '456', '789'),
   array('"aaa"', '"bbb"')
);

//Ouverture d'un fichier avec l'extension .csv (convention) en mode écriture 'w'
$fp = fopen('file.csv', 'w');

//Ecriture 
foreach ($list as $fields) {
    fputcsv($fp, $fields);
}
//Fermeture du fichier
fclose($fp);

En savoir plus sur fputcsv

Lire les données avec fgetcsv 4 #

<?php
$row = 1;
//Si le fichier existe et a pu être ouvert en lecture
if (($file = fopen("test.csv", "r")) !== FALSE) {
    //Tant qu'on est pas à la fin du fichier, lire le fichier
    //ligne par ligne
    while (($line = fgetcsv($file, 1000, ",")) !== FALSE) {
        $num = count($line);
        echo "<p> $num champs à la ligne $row: <br /></p>\n";
        $row++;
        for ($c=0; $c < $num; $c++) {
            echo $line[$c] . "<br />\n";
        }
    }
    fclose($file);
}

En savoir plus sur fgetcsv

Démos sur la manipulation de fichiers textes et fichiers au format CSV #

Créer des URLs dynamiques 1 #

Il est facile de créer des URLs de manière dynamique (en fonction du contenu de la base de données par exemple) pour chaque ressource (post, article, étudiant, rendez-vous, etc.) avec les paramètres d’URL (query part).

Ainsi, votre site expose autant de ressources et donc de pages HTML que nécessaire de manière automatique.

C’est ce que fait YouTube par exemple. Voici une URL d’une vidéo Youtube :

https://www.youtube.com/watch?v=-I-VpPMzG7c

Créer des URLs dynamiques 2 #

Dans nos templates on peut donc générer des URL dynamiquement (en fonction du contenu) en créant des URL de la forme :

//Chaque URL est unique et la ressource est identifiée par la valeur du paramètre d'URL 'id'
GET http://localhost:5001/student.php?id=1
GET http://localhost:5001/student.php?id=2
...
GET http://localhost:5001/student.php?id=200

Pour produire la page web présentant un·e étudiant·e il suffit :

Lorsqu’un·e nouvel·le étudiant·e est enregistrée (nouvel id), iel a automatiquement sa page web !

Démo création d’URLs dynamiques #

Accéder à la démo sur la création d’URLs dynamiques à partir d’enregistrements dans un fichier CSV sur le dépôt du cours.

Connexion à une base de données MySQL avec PHP #

Cycle classique d’une application avec base de données 1 #

Cycle classique d’une application avec base de données 2 #

Prérequis côté serveur #

Pour se connecter à une base MySQL, il faut :

Vérification rapide :

php -m | grep pdo

Paramètres de connexion #

Une connexion PDO nécessite :

Exemple de DSN (Data Source Name) MySQL :

mysql:host=localhost;dbname=demo

Une base de données est “comme” un petit système d’exploitation : elle définit des utilisateurs avec des droits

Connexion simple avec PDO #

<?php

$dsn = 'mysql:host=localhost;dbname=demo;charset=utf8mb4';
$user = 'user';
$password = 'password';

$pdo = new PDO($dsn, $user, $password);

Connexion PDO (correcte) #

<?php

$dsn = 'mysql:host=localhost;dbname=demo;charset=utf8mb4';
$user = 'user';
$password = 'password';

$options = [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES   => false,
];

$pdo = new PDO($dsn, $user, $password, $options);

Gestion des erreurs de connexion #

<?php

try {
    $pdo = new PDO($dsn, $user, $password, $options);
} catch (PDOException $e) {
    echo "Erreur de connexion à la base de données";
    exit;
}

Organisation du code (bonne pratique) #

Isoler la connexion dans un fichier (un module !) dédié db.php :

<?php
//Connexion ouverte avec la base de donnée stockée dans la variable $pdo
$pdo = new PDO($dsn, $user, $password, $options);

Depuis le reste de votre application :

require_once 'db.php';
//Utiliser $pdo dans l'application

Première requête SQL (SELECT) #

Utiliser la méthode fetchAll() :

$sql = 'SELECT * FROM students';
$stmt = $pdo->query($sql);
$students = $stmt->fetchAll();

Affichage dans un template #

<ul>
<?php foreach ($students as $student) : ?>
    <li>
        <?php echo htmlentities($student['firstname']) ?>
        <?php echo htmlentities($student['lastname']) ?>
    </li>
<?php endforeach; ?>
</ul>

Sécurité : Injection SQL #

Une injection SQL consiste à injecter du code SQL via une donnée fournie par le client, afin de modifier la requête exécutée par le serveur.

Entrée malveillante typique : ' OR '1'='1

# NE JAMAIS FAIRE ÇA !
$id = $_POST['id'];
$sql = "SELECT * FROM students WHERE id = '$id'";
$result = $pdo->query($sql);

Si le client envoie (via un input de formulaire par ex) : ' OR '1'='1

La requête devient :

-- 1=1 est toujours vrai !
SELECT * FROM students WHERE id = '' OR '1'='1'

Démo : Injection SQL #

Requêtes préparées (fondamental) #

Toute donnée externe DOIT passer par une requête préparée.

$sql = 'SELECT * FROM students WHERE id = :id';
$stmt = $pdo->prepare($sql);
$stmt->execute(['id' => $_POST['id']]);
$student = $stmt->fetch();

Bénéfices immédiats :

Opérations d’écriture en base de données #

Lire des données (SELECT) ne suffit pas. Une application web doit aussi créer, modifier et supprimer des données. On parle de CRUD (Create Read Update Delete), opérations de base d’édition de données.

Ces opérations correspondent aux instructions SQL suivantes :

Rappel : toutes ces opérations DOIVENT utiliser des requêtes préparées.

Enregistrer avec INSERT #

$sql = '
    INSERT INTO students (firstname, lastname, email)
    VALUES (:firstname, :lastname, :email)
';

$stmt = $pdo->prepare($sql);
$stmt->execute([
    'firstname' => $firstname,
    'lastname'  => $lastname,
    'email'     => $email,
]);

//Récupérer l’identifiant généré
$studentId = $pdo->lastInsertId();

Mettre à jour avec UPDATE #

$sql = '
    UPDATE students
    SET firstname = :firstname,
        lastname  = :lastname,
        email     = :email
    WHERE id = :id
';

$stmt = $pdo->prepare($sql);
$stmt->execute([
    'id'        => $id,
    'firstname' => $firstname,
    'lastname'  => $lastname,
    'email'     => $email,
]);

Toujours utiliser une clause WHERE sinon UPDATE s’applique à tous les enregistrements de la table !

Supprimer avec DELETE #

$sql = 'DELETE FROM students WHERE id = :id';

$stmt = $pdo->prepare($sql);
$stmt->execute(['id' => $id]);

//Nombre de lignes affectées : vérifier qu’un DELETE (ou UPDATE) a bien eu un effet
$affectedRows = $stmt->rowCount();

Conseils #

SQL : Créer une base de données simple (avec MySQL) #

-- Créer une base de données pour notre site ("répertoire")
CREATE DATABASE blog;

use blog

-- Table qui contiendra nos articles
CREATE TABLE posts (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    content TEXT NOT NULL,
    author VARCHAR(100) NOT NULL,
    image_path VARCHAR(255),    
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

SQL : Insérer des données #

-- Insérer quelques posts manuellement pour commencer

INSERT INTO posts (title, content, author, image_path) VALUES
('Mon premier post', 'Bienvenue sur mon blog !', 'Jane', 'uploads/post1.jpg'),
('PHP is simple', "PHP est un langage de programmation facile à prendre en main", 'John', 'uploads/post2.jpg');

Récupérer et afficher les articles dans le site PHP #

<?php
$host = 'localhost';
$db   = 'mon_site';
$user = 'utilisateur';
$pass = 'motdepasse';
$charset = 'utf8mb4';

$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$options = [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
];

try {
    $pdo = new PDO($dsn, $user, $pass, $options);
} catch (PDOException $e) {
    die("Erreur de connexion : " . $e->getMessage());
}

$sql = "SELECT id, title, content, author, image_path, created_at, updated_at
        FROM posts
        ORDER BY created_at DESC";
$stmt = $pdo->query($sql);
$posts = $stmt->fetchAll();

foreach ($posts as $post) {
    echo "<h2>" . htmlspecialchars($post['title']) . "</h2>";
    echo "<p><em>Par " . htmlspecialchars($post['author']) . " le " . $post['created_at'] . "</em></p>";
    if ($post['image_path']) {
        echo "<img src='" . htmlspecialchars($post['image_path']) . "' alt='Image de l\'article' style='max-width:300px;'><br>";
    }
    echo "<p>" . nl2br(htmlspecialchars($post['content'])) . "</p><hr>";
}

Exercices #

Authentification : session user #

Authentification avec les cookies #

Les cookies permettent de se souvenir d’un utilisateur entre différentes pages.

Un cookie est écrit sous forme de paire clé=valeur, comme les paramètres d’URL ou les champs d’un formulaire HTML. Par exemple :

sessionId=abc123xyz

En PHP, pour créer un cookie, utiliser la fonction setcookie() :

<?php
//clé, valeur, date d'expiration (timestamp)
setcookie("user", "Jone Doe", time() + 3600); // cookie valable 1 heure

En plus de cette clé/valeur, un cookie peut contenir des attributs optionnels séparés par des points-virgules, qui définissent son comportement dans le navigateur.

Authentification basique #

  1. Créer un formulaire de connexion avec les champs login et password sur l’URL login.php.
  2. Lors de la connexion (traitement du formulaire) :
    1. Vérifier le login et mot de passe.
    2. Si corrects, créer un cookie avec l’identifiant de l’utilisateur.
<?php
if ($_POST['username'] === 'admin' && $_POST['password'] === '1234') {
    //Authentification réussie, déposer un cookie côté client avec des informations sur l'user
    setcookie("auth_user", "admin", time() + 3600, "/");
    echo "Connexion réussie !";
}

Sur chaque page nécessitant une connexion #

<?php
if (isset($_COOKIE['auth_user'])) {
    echo "Bienvenue " . htmlspecialchars($_COOKIE['auth_user']);
} else {
    echo "Veuillez vous connecter.";
    //Rediriger avec la fonction header()
    header("Location: login.php");
}

Si le cookie n’existe pas ou est expiré : rediriger l’user vers la page de connexion (login.php).

C’est un usage simplifié ici : n’importe quel client pourrait créer son propre cookie et se faire passer pour un user connecté !

Déconnexion #

<?php
setcookie("auth_user", "", time() - 3600, "/"); // supprime le cookie (valeur vide)
header("Location: login.php");
exit;

Authentification sécurisée avec les sessions PHP #

Démarrer une session #

<?php
session_start(); // toujours au début du script
?>

Stocker des informations dans la session #

Utiliser la variable super globale $_SESSION pour lire/écrire des informations propres à la session client :

$_SESSION['user'] = 'john';
$_SESSION['role'] = 'admin';
$_SESSION['panier'] = ['produit1', 'produit2'];

Lire les informations #

Sur une ressource qui nécessite authentification par exemple :

// PHP traite le cookie avec l'identifiant et regarde si une session avec cet identifiant existe. 
// Si c'est le cas, les données sont chargées dans $_SESSION.
session_start();
if (isset($_SESSION['user'])) {
    echo "Bienvenue " . $_SESSION['user'];
} else {
    echo "Veuillez vous connecter.";
}

Stoper une session (déconnexion) #

Sur la ressource logout.php par exemple :

<?php
session_start();
session_destroy(); // supprime la session côté serveur, libère les données associées.

Avant/Après #

Quelques précautions avec les cookies #

Projet #