2

For my DIY project I want to retrieve data from an 3rd party API which returns with the 'text/event-stream' header.

Because the connection doesn't close, I do it with a timeout as shown here:

$url='https://example.com/api/';
$ctx = stream_context_create(array('http'=>
    array(
        'timeout' => 1 // second
    )
));
$data = file_get_contents($url, false, $ctx);

Besides being super hacky, it is slow and it feels bad.

Is it possible to only catch the first data-element (JSON) from an event-stream?

So far I couldn't find any satisfying solution for my problem. Maybe I am lacking the correct vocabulary to search with.

Help very appreciated.

Luxx
  • 392
  • 3
  • 6
  • 2
    Can't you just `fopen` the stream, read as much data as you need, and close it when the stream is no longer needed? – Karolis Nov 17 '19 at 22:16
  • The mods deleted my answer as I was too lazy to type the same one out twice, and I disagree with their deletion policy. Anyway, there's a helpful answer to your question here https://stackoverflow.com/a/70942426/120603 – TrojanName Feb 01 '22 at 15:30

1 Answers1

0

The following code worked for me to read a single event. The event stream seems to have a double EOL after each event. At least in my case. I am not sure if this is the case for all such streams.

readEvent can be called multiple times to read more then one event.

$handle = fopen($url, "rb");

function readEvent($handle) {
    $line = '';
    while (true) {
        $byte = fread($handle, 1);
        if ($line == '') {
            $timeStamp = DateTime::createFromFormat('U.u', microtime(true));
        }
        if ($byte === "\n") {
            fread($handle, 1); // skip one empty line (not sure if that is only necessary on the stream I am consuming)
            return ['timeStamp' => $timeStamp, 'event' => $line];
        }
        $line .= $byte;
    }
}

$event = readEvent($handle);
echo '1st event: ' . PHP_EOL;
echo '- received: ' . $event['timeStamp']->format("Y-m-d H:i:s.u") . PHP_EOL;
echo '- event: ' . $event['event'] . PHP_EOL;

fclose($handle);
Alex
  • 32,506
  • 16
  • 106
  • 171