Client serveur avec event-stream « server-sent events »

C’est quoi le event-stream??? Ben je ne connaissais pas jusqu’à hier!!! Je l’ai découvert en cherchant une solution pour pousser la mise à jour d’une page vers le visiteur qui est en train de la consulter. Et ceci sans faire un timing de reload mais en realtime.

A la base je bossais sur un projet d’écran d’affichage. L’idée est que l’écran doit être automatiquement mise à jour quand le gestionnaire de l’écran modifiait les slides qui défilent. (Je vais bientôt mettre le projet sur GitHub).

Comment ça marche le event-stream?

C’est un peut comme du client-serveur. Le browser du visiteur (dans mon cas le panneau d’affichage) est le client. Le site hébergé sur le serveur est la partie serveur. Jusque là normal. Mais habituellement si on veut que les informations s’actualisent le visiteur doit faire un F5 ou Ctrl+R ou Ctrl+F5. Problème… moi je n’ai personne pour faire à la mano cette action sur mon écran sans clavier à 3 mètres de haut sur le mur! Et bien là c’est le serveur qui pousse (en continue) les modifications vers le browser qui lui reste à l’écoute en permanence. Il n’y a pas de connexion comme le WebSocket. Voici les sites qui m’ont permis de comprendre le fonctionnement:

https://developer.mozilla.org/fr/docs/Server-sent_events/Using_server-sent_events

http://www.html5rocks.com/en/tutorials/eventsource/basics/?redirect_from_locale=fr

http://www.developerdrive.com/2012/03/pushing-updates-to-the-web-page-with-html5-server-sent-events/

Pour aller au plus simple, un example. On va créer 3 pages: client.php, sendMsg.php et admin.php. Le répertoire qui contient ces pages devra être en lecture et écriture par le serveur web (www-data, apache…)

On va modifier du contenu à partir de la page admin.php, ce contenue sera poussé par sendMsg.php vers la page visitée (client.php) par un utilisateur.

Le serveur (sendMsg.php)

<?php

header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');

/**
 * Constructs the SSE data format and flushes that data to the client.
 *
 * @param string $id Timestamp/id of this connection.
 * @param string $msg Line of text that should be transmitted.
 *
 */
function sendMsg($id, $event,$retry,$msg) {
  echo "id: $id" . PHP_EOL;
  echo "event: $event" . PHP_EOL;
  echo "retry: $retry" .PHP_EOL;
  echo "data: $msg\n\n" . PHP_EOL;
  echo PHP_EOL;
  ob_flush();
  flush();
}

if (is_file('check.txt')) {
    $serverTime = time();
    sendMsg($serverTime,'refreshMe','1000','1');
    sleep(5);
    unlink('check.txt');
}

?>
</file>

Que fait ce script:

il envoie (stream) le message ($msg) en continue en demandant au client de le consulter toutes les secondes (1000).\\
Il émet pendant 5 secondes (sleep) , c’est l’existence du fichier check.txt qui déclenche ou arrête le stream.

===== Le client (client.php) =====

<code><!DOCTYPE html>
<html>
<head>
</head>
<body>

    <?php include_once('include.inc'); ?>

    <script type="text/javascript">
        if (!!window.EventSource) {
          var source = new EventSource("sendMsg.php");
        } else {
          alert('Navigateur incompatible!!');
        }

        source.addEventListener('refreshMe', function(e) {
          if (e.data == 1){
   source.close();
              setTimeout(function(){location.reload()},5000);
            }
        }, false);
    </script>
</body>
</html>

Que fait ce script:

Il affiche le contenu du fichier include.inc. Ce fichier étant modifié par admin.php, il le recharge à chaque fois que la page est actualisée (reload). Le rechargement est déclenché quand la valeur ‘1’ est envoyée par sendMsg.php qu’il écoute en continue (grâce à EventSource)

La page d’admin (admin.php)

<code><?php
if($_POST['check'] == 1){

 touch('check.txt');
  file_put_contents('include.inc', $_POST['message']);

}
?>

<!DOCTYPE>


</file>

Que fait le script:

On saisi du texte qui sera écrit dans include.inc qui sera chargé par la page vue par le visiteur ET déclenchera le stream en créant le fichier check.txt.

Et voilà, à vous de tester et l’intégrer à vos besoins.

Dernière modification : le 2017/10/01