231 Chapitre 4 Du serveur au navigateur : interactions 1. Introduction : le flux de sortie Du serveur au navigateur : interactions Au-delà du simple langage et en prenant la dimension de son environnement, PHP évolue au sein d'une chaîne d'actions dont il est le premier maillon. Les interactions pour fournir du contenu du serveur jusqu'à l'utilisateur sont nombreuses et complexes. Nous étudierons dans ce chapitre les différentes approches que revêt la communication entre eux et les possibilités offertes par les nouveaux modes d'échanges : AJAX, WebSockets, SSE, etc. En premier lieu, il est nécessaire d'apporter un éclairage sur la première étape de ces échanges : le flux de sortie PHP et le processus de mise en tampon des données. Avant d'être envoyées à l'utilisateur par le serveur web (Apache dans notre cas), les données de sortie générées par PHP vont transiter par différents tampons de sortie. Ils seront vidés un à un pour être transmis à Apache, puis à l'utilisateur.
232 PHP et HTML5 Développez des applications web performantes Transit des données à travers les tampons de sortie 1.1 Tampon de sortie utilisateur Situé au plus haut niveau, le tampon utilisateur permet au développeur d'empiler toutes les données sortantes, en attente d'envoi, en gardant un accès total dessus. Le but est de maîtriser la sortie des données, quant à sa chronologie, pour n'envoyer des données qu'à un moment précis, ou quant à son contenu, en contrôlant les données en partance. Tant que ce tampon n'est pas vidé, aucune donnée ne sera transmise à l'utilisateur (et donc affichée). Il est possible d'empiler plusieurs tampons de sortie, chacun (une fois plein ou vidé intentionnellement) se déversant dans le tampon inférieur. Les données de sortie seront quant à elles toujours dirigées vers le tampon de plus haut niveau, c'est-à-dire le dernier créé. Editions ENI - All rights reserved
Du serveur au navigateur : interactions Chapitre 4 233 Il existe un certain nombre de fonctions PHP pour gérer ces tampons et nous verrons ici les principales : Fonction ob_start La fonction ob_start initialise un nouveau tampon de sortie. Dès l'appel à ob_start effectué, toutes les données sortantes seront empilées dans ce tampon jusqu'à ce qu'il soit plein ou vidé. À ce moment-là, son contenu sera déversé dans le tampon de niveau inférieur : soit un autre tampon utilisateur, soit le tampon de sortie PHP. La fonction ob_start prend en paramètres : output_callback : fonction de callback à appeler lorsque le tampon sera vidé. chunk_size : spécifie la taille du tampon en octets. flags : masque de drapeaux indiquant les opérations autorisées sur ce tampon (nettoyage, suppression...). Exemple : ob_start(null, 10); Cette instruction crée un tampon de 10 octets sans fonction de rappel. Fonction ob_end_flush Le rôle de la fonction ob_end_flush est simple : vider un tampon dans le tampon de niveau inférieur et le supprimer. Fonction ob_ flush La fonction ob_flush vide un tampon de sortie dans le tampon de niveau inférieur. Fonction ob_get_contents La fonction ob_get_contents retourne sous forme d'une chaîne de caractères le contenu du tampon. Exemple de mise en tampon simple : <?php echo "Ce texte ne s'affichera ";
234 PHP et HTML5 Développez des applications web performantes sleep(5); echo "que maintenant"; Dans cet exemple, la première partie de la chaîne ("Ce texte ne s'affichera") n'est pas affichée ; elle est placée dans le tampon créé précédemment. Après cinq secondes d'attente, la seconde partie de la chaîne est empilée dans le tampon. Celui-ci n'est vidé qu'avec la commande ob_end_flush. Exemple avec deux tampons : echo "Ceci est mon premier tampon"; echo "Ceci est mon second tampon"; ob_clean(); Dans cet exemple, deux tampons sont créés et empilés. Dans le premier on écrit la chaîne "Ceci est mon premier tampon", et dans le second, "Ceci est mon second tampon". L'appel à ob_clean va vider le tampon de plus haut niveau, c'est-à-dire le dernier créé, sans toucher au contenu du premier, qui sera vidé (et donc affiché) par l'appel à ob_end_flush. Exemple de tampon avec fonction de rappel : Dans cet exemple, nous allons placer une fonction de rappel pour chaque tampon : la fonction sautdeligne (qui remplace les sauts de ligne \n par des sauts HTML) pour le premier, et la fonction majuscule pour le second. function majuscule($chaine){ return strtoupper($chaine); } function sautdeligne($chaine){ return preg_replace('/\n/i', '<br>', $chaine); } ob_start("sautdeligne"); echo "\nceci est mon premier tampon"; ob_start("majuscule"); echo "\nceci est mon second tampon"; Editions ENI - All rights reserved
Du serveur au navigateur : interactions Chapitre 4 235 Affiche : <br>ceci est mon premier tampon<br>ceci EST MON SECOND TAMPON À noter dans cet exemple, les deux chaînes sont préfixées de <br>, et ceci parce qu'au moment du second appel à ob_end_flush(), le contenu du second tampon avait déjà été déversé dans le premier. Pour les mêmes raisons, seule la seconde chaîne est en majuscules. 1.2 Tampon PHP (output buffering) Parallèlement au tampon utilisateur et qu'il soit présent ou non, les données à transférer au client transitent de manière systématique, s'il est activé, par un tampon interne à PHP, l'output buffering dont le contenu n'est cette fois pas accessible au programmeur. La seule action possible sur ce buffer est de définir son comportement par la clé output_buffering dans php.ini. Celle-ci peut prendre trois valeurs : on : l'output buffering est activé et sa taille illimitée. off : l'output buffering est désactivé, les données de sortie se déverseront directement dans le buffer suivant. [entier] : dans ce cas, on active l'output buffering mais en spécifiant une taille maximum, au-delà de laquelle il sera vidé. 1.3 Tampon SAPI Enfin, juste avant d'être prises en charge par Apache, les données transitent dans un dernier tampon, celui de la SAPI. La SAPI (pour Server Application Programming Interface) est un module permettant d'interfacer un serveur (Apache, IIS...) avec un module applicatif externe (ici PHP). PHP peut fonctionner avec différentes SAPI : CGI, FastCGI, CLI, etc. Cette interface possède son propre buffer, constitué des données envoyées par PHP et à fournir via Apache au client.
236 PHP et HTML5 Développez des applications web performantes PHP n'a qu'une vision limitée de ce buffer : il ne peut y accéder mais il peut demander à la SAPI de le vider, via la commande flush (à ne pas confondre avec ob_flush). La commande flush a pour effet de vider le tampon PHP et celui de la SAPI. 1.4 Exemple concret Prenons pour exemple le code suivant : for ($i = 1; $i <= 5; $i++){ echo "<br>boucle $i"; } ob_flush(); sleep(2); On serait enclin à penser que cette boucle affiche une ligne toutes les deux secondes, grâce à ob_flush. En réalité, ob_flush se contente de verser le contenu du tampon utilisateur dans le tampon PHP. Il faudrait, pour que ce contenu n'y soit pas stocké, soit désactiver le tampon PHP, soit lui envoyer une chaîne suffisamment longue pour que le tampon se vide automatiquement. Dans php.ini, on peut lire (pour cet exemple) : output_buffering = 4096 Nous allons donc envoyer une chaîne de plus de 4096 octets, grâce à la fonction str_pad : for ($i = 1; $i <= 5; $i++){ echo "<br>boucle $i"; echo str_pad('', 4096, ' '); ob_flush(); sleep(2); Editions ENI - All rights reserved