Mis à jour le 30/10/2013
  • Facile
Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Introduction du cours

Trop souvent, on doit repenser des scripts parce qu'on a eu la mauvaise idée de placer un setcookie() ou un header() après avoir affiché du code HTML au client. Vous avez mal pensé votre script, soit.

La première chose que je vous suggère, c'est de corriger votre script de manière à ce que les en-têtes soient envoyés avant tout code HTML. Mais au-delà, il existe une solution bien pratique qui réglera beaucoup de vos soucis. :p Et j'ai nommé : la tamporisation* de sortie.

* tamporisation : vous avez bien lu ; on fait ici référence à un tampon qui bloque le flux de sortie des scripts PHP.

* tamporisation : vous avez bien lu ; on fait ici référence à un tampon qui bloque le flux de sortie des scripts PHP.

Perception du problème

Oui, je sais : c'est assez laid à dire, « tamporisation de sortie ». Sachez que le terme bufferisation de sortie signifie exactement la même chose, et c'est probablement celui que vous verrez le plus souvent. Par contre, j'utilise le premier car il est plus français. ;)

Lorsque vous chargez un script PHP pour un site web, il retourne des données au navigateur. Généralement, vous ne vous préoccupez que de retourner du HTML, parfois quelques cookies ou d'autres informations d'en-tête avec header(). Donc, selon ce que vous savez jusqu'à maintenant, si je fais :

<?php
echo 'Salut !';
?>

… ça retourne au navigateur du visiteur le mot « Salut ! », logique. Si je veux faire une redirection en PHP en modifiant les en-têtes HTTP, et que je procède ainsi :

<?php
echo 'Salut !';
header('Location: page.php');
?>

… vous vous en doutez, on obtiendra l'erreur suivante :

Citation : erreur

Warning: Cannot modify header information - headers already sent by (output started at c:\www\lol.php:2) in c:\www\lol.php on line 3

Cela est normal : on ne peut pas dire au navigateur qu'on redirige vers une autre page alors qu'on a déjà commencé à lui donner la première. C'est comme si au restaurant, vous disiez au serveur que vous changiez de commande alors que le cuisinier a déjà commencé à préparer votre plat ! :p Maintenant, que dites-vous de ce code ?

<?php
$output = '';
$output .= 'Salut !';
header('Location: page.php');
echo $output;
?>

Ça fait une erreur ? Évidemment, ça n'en fait pas. Dans un premier temps, on initialise une variable $output, on lui assigne la valeur d'une chaîne de caractères vide. Jusqu'ici, on n'a fait aucun retour de HTML au navigateur. Ensuite, on ajoute à cette variable la valeur « Salut ! ». Si vous ne comprenez pas la signification du .=, je vous suggère de revoir le chapitre du cours de M@teo21 sur la concaténation. ;) Encore une fois, on n'a rien retourné au navigateur. On fait notre redirection avec header(), puis on affiche la valeur de $output. Donc, aucune erreur, notre code a été affiché après la redirection ! :D

Mine de rien, vous avez maintenant le principe de la tamporisation de sortie : on stocke tout ce qu'on veut afficher dans une variable, et à la fin (et seulement à la fin, sinon on perd tout l'intérêt), on affiche son contenu.

Les fonctions de PHP pour la tamporisation de sortie

Initialiser et vider le tampon de sortie

Maintenant qu'on sait ce que c'est, on va voir comment ça marche ! :) PHP nous offre toute une gamme de fonctions pour la tamporisation de sortie ; nous n'en utiliserons que deux, car ce sont les principales. Ces fonctions, ce sont ob_start() et ob_end_flush().

  • ob_start() : cette fonction initialise le tampon de sortie, c'est-à-dire que tout ce que vous affichez après son appel (avec echo et print) est mis dans le tampon au lieu d'être retourné au navigateur.

  • ob_end_flush() : lors de l'appel de cette fonction, tout le contenu de votre tampon est retourné au navigateur et donc, affiché.

Le principe est simple, on va appeler ob_start() au tout début, et ob_end_flush() à la toute fin. Ce que vous afficherez entre les deux avec print et echo (ou avec ?>...<?php) sera stocké dans le tampon (buffer), puis affiché à la fin. Exemple :

<?php
ob_start(); /* On initialise le tampon. */
 
 
/* Trois façons d'ajouter du texte au buffer : */
echo 'Blablabla voici du texte qui sera mis dans dans le buffer';
 
?>
Encore du texte qui sera mis dans le buffer !
<?php
 
print 'OMG, encore du texte à mettre dans le buffer ! Il va déborder !?';
 
$now = time();
$end = $now + 600;
setcookie('debut', $now, $end);
ob_end_flush(); /* On vide le tampon et on retourne le contenu au client. */
?>

Récupérer le contenu du buffer (tampon)

À tout moment pendant l'exécution de votre script ( entre ob_start() et ob_end_flush() ), vous pouvez récupérer le contenu du buffer avec la fonction ob_get_contents(). Ça peut être pratique parfois (mais rarement primordial), à vous de voir là où ça pourrait vous servir. Exemple avec ob_get_contents :

<?php
ob_start(); /* On initialise le tampon. */
 
 
/* Trois façons d'ajouter du texte au buffer : */
echo 'Blablabla voici du texte qui sera mis dans dans le buffer';
 
?>
Encore du texte qui sera mis dans le buffer !
<?php
 
print 'OMG, encore du texte à mettre dans le buffer ! Il va déborder !?';
 
$now = time();
$end = $now + 600;
setcookie('debut', $now, $end);
 
$contents = ob_get_contents(); // Que vaut $contents ??
ob_end_flush(); /* On vide le tampon et on retourne le contenu au client. */
?>

Vous vous en doutez, $contents vaut alors :

Citation : $contents

Blablabla voici du texte qui sera mis dans dans le bufferEncore du texte qui sera mis dans le buffer !OMG, encore du texte à mettre dans le buffer ! Il va déborder !?

Autres fonctions utiles

Voici une liste d'autres fonctions utiles à connaître, vous trouverez des détails plus précis dans la documentation de PHP :

  • ob_flush() affiche le contenu du tampon de sortie (contrairement à ob_end_flush, cela ne détruit pas votre buffer, ça ne fait que le retourner au navigateur, vous pouvez donc continuer à l'utiliser après) ;

  • ob_clean() réinitialise le tampon de sortie, c'est-à-dire qu'elle le remet à zéro sans le retourner au navigateur : vous perdez tout ce que vous avez affiché avant son appel.

Aller plus loin : fonction de callback

Si vous avez trouvé jusqu'ici ce dont vous aviez besoin, et que vous ne désirez pas pousser la machine plus loin (ça arrive :p ), cette partie n'est pas pour vous. Ici, on verra comment utiliser les paramètres facultatifs de la fonction ob_start(). J'insiste sur le fait qu'ils sont facultatifs. Ainsi, le code ci-dessous initialise bel et bien le tampon de sortie :

<?php
ob_start();
?>

Un callback, qu'est-ce que c'est ?

Un callback est l'appel d'une fonction définie par l'utilisateur, ou d'une fonction native de PHP à partir des paramètres d'une autre. Voyez le site de PHP à ce sujet. La fonction call_user_func() nous permet justement d'appeler une fonction en donnant son nom en premier argument. Les paramètres qui suivent le nom correspondront respectivement aux paramètres de la fonction que vous appelez. Testez le code ci-dessous pour vous en convaincre :

<?php
function AfficherNom($nom) {
     echo('Ton nom est ' . $nom);
     return(true);
}
call_user_func('AfficherNom', 'Alex');
?>

En tamporisation de sortie, on peut donner un callback en paramètre à ob_start(). La fonction donnée en callback sera appelée au retour du buffer au navigateur, avec ob_end_flush() par exemple, et le contenu du tampon sera remplacé par ce que retourne la fonction de callback. Supposons que nous désirions impérativement censurer les mots suivants de tout notre site : patate, nain, chose. Il existe plusieurs solutions, mais nous pouvons le faire avec un callback :

<?php
function Censurer($buffer) {
     // Ici c'est notre fonction qui sera appelée avec ob_end_flush().
     $buffer = str_replace(array('patate', 'nain', 'chose'), '<span style="color: red;"> [Censuré] </span>', $buffer);
     return $buffer;
}
 
// On initialise le buffer :
ob_start('Censurer');
 
//… le contenu de notre page :
echo "J'aime bien les nains, surtout ceux qui mangent des patates et qui aiment faire des choses.";
/* 
   Ici, la fonction ob_end_flush() va être appelée,
   ce qui provoquera le retour du tampon au navigateur.
   Mais avant, notre fonction de callback sera
   automatiquement appelée pour appliquer la censure.
*/
ob_end_flush();
?>

Citation : Résultat

J'aime bien les [Censuré] s, surtout ceux qui mangent des [Censuré] s et qui aiment faire des [Censuré] s.

Encore une fois, c'est du facile tout ça. :-°

Ce n'était pas difficile, hein ? Si ? :euh: Alors allez voir la doc de PHP à propos de la tamporisation de sortie.

Exemple de certificat de réussite
Exemple de certificat de réussite