How to use HTML5 Server-Sent Events (SSE)

Hi,

See: http://www.w3schools.com/HTML/html5_serversentevents.asp

With just native PHP on the server side it’s a no-brainer, but how do I get this running with Slim3?

I need this badly for a project that updates a browser-client every 3 seconds

This is the first time I’ve heard of SSE (yes, my bad) but a first thought would be that if you don’t get a satisfying answer in the time you need, couldn’t the same thing be achieved by calling an Ajax function scheduled through setInterval()?

Maybe this helps, I just wanted to offer this suggestion.

That’s the way I’m doing it right now :slight_smile: … but It creates a lot of overhead as some intervals are 1 sec. The server is flooded with requests, compared to a simple loop that writest a few bytes every few seconds using SSE.

@SlimStorm, have a look at this comment in Adding SSE requests to Slim.

Presto, I did it. Reworked the CallbackStream in https://github.com/phly/psr7examples and that did the trick.

Javascript snippet

var evtSource = new EventSource(send_url); evtSource.onmessage = function(event) { if ( event.data.substr(0,3) == 'END') { evtSource.close(); } else { $('#result').html(event.data); } };

Controller part (Slim3)

$output = new CallbackStream(function () use ($request) { for ($i=0; $i<10; $i++) { $time = date('r'); echo "data: The server time is: {$time}\n\n"; ob_flush(); flush(); sleep(2); } echo "data: END\n\n"; ob_flush(); flush(); return ''; }); return (new Response()) ->withHeader('Content-Type', 'text/event-stream') ->withHeader('Cache-Control', 'no-cache') ->withBody($output);

CallbackStream helper class

[code]<?php
namespace Helper;

use Psr\Http\Message\StreamInterface;

/**

  • Callback-based stream implementation.

  • Wraps a callback, and invokes it in order to stream it.

  • Only one invocation is allowed; multiple invocations will return an empty

  • string for the second and subsequent calls.
    /
    class CallbackStream implements StreamInterface
    {
    /
    *

    • @var callable
      */
      private $callback;

    /**

    • Whether or not the callback has been previously invoked.
    • @var bool
      */
      private $called = false;

    public function __construct(callable $callback)
    {
    $this->callback = $callback;
    }

    /**

    • @return string
      */
      public function __toString()
      {
      return $this->output();
      }

    /**

    • Execute the callback with output buffering.

    • @return null|string Null on second and subsequent calls.
      */
      public function output()
      {
      if ($this->called) {
      return;
      }

      $this->called = true;

      call_user_func($this->callback);
      return;
      }

    /**

    • @return void
      */
      public function close()
      {
      }

    /**

    • @return null|callable
      */
      public function detach()
      {
      $callback = $this->callback;
      $this->callback = null;
      return $callback;
      }

    /**

    • @return int|null Returns the size in bytes if known, or null if unknown.
      */
      public function getSize()
      {
      }

    /**

    • @return int|bool Position of the file pointer or false on error.
      */
      public function tell()
      {
      return 0;
      }

    /**

    • @return bool
      */
      public function eof()
      {
      return $this->called;
      }

    /**

    • @return bool
      */
      public function isSeekable()
      {
      return false;
      }

    /**

    • @link http://www.php.net/manual/en/function.fseek.php
    • @param int $offset Stream offset
    • @param int $whence Specifies how the cursor position will be calculated
    • based on the seek offset. Valid values are identical to the built-in
      
    • PHP $whence values for `fseek()`.  SEEK_SET: Set position equal to
      
    • offset bytes SEEK_CUR: Set position to current location plus offset
      
    • SEEK_END: Set position to end-of-stream plus offset.
      
    • @return bool Returns TRUE on success or FALSE on failure.
      */
      public function seek($offset, $whence = SEEK_SET)
      {
      return false;
      }

    /**

    /**

    • @return bool
      */
      public function isWritable()
      {
      return false;
      }

    /**

    • @param string $string The string that is to be written.
    • @return int|bool Returns the number of bytes written to the stream on
    • success or FALSE on failure.
      

    */
    public function write($string)
    {
    return false;
    }

    /**

    • @return bool
      */
      public function isReadable()
      {
      return true;
      }

    /**

    • @param int $length Read up to $length bytes from the object and return
    • them. Fewer than $length bytes may be returned if underlying stream
      
    • call returns fewer bytes.
      
    • @return string|false Returns the data read from the stream, false if
    • unable to read or if an error occurs.
      

    */
    public function read($length)
    {
    return $this->output();
    }

    /**

    • @return string
      */
      public function getContents()
      {
      return $this->output();
      }

    /**

    • @link http://php.net/manual/en/function.stream-get-meta-data.php
    • @param string $key Specific metadata to retrieve.
    • @return array|mixed|null Returns an associative array if no key is
    • provided. Returns a specific key value if a key is provided and the
      
    • value is found, or null if the key is not found.
      

    */
    public function getMetadata($key = null)
    {
    if ($key === null) {
    return array();
    }
    return null;
    }
    }
    [/code]

1 Like