PHP SSE (Server Sent Events) + KeyHelp

For topics beyond KeyHelp. / Für Themen jenseits von KeyHelp.
bernhard
Posts: 144
Joined: Fri 29. May 2020, 14:36

Re: PHP SSE (Server Sent Events) + KeyHelp

Post by bernhard »

Nein, also so wie ich das verstehe ist es bei SSE eben genau anders! Und deshalb brauch ich auch SSE und nicht AJAX.

Der Grund dafür ist, dass ich ein Skript am Server laufen habe, das länger dauert. Ich möchte den Progress an den Client schicken, damit man sich auskennt, was gerade passiert. Konkret verwende ich das ProcessWire CMS und lösche eine unbekannte Zahl von "Pages":

Code: Select all

foreach($pages->find("template=foo") as $p) {
  $p->delete();
}
Da das auch 1000e "Pages" sein können (und das Skript potentiell mehrere Sekunden läuft), möchte ich den Status per SSE an meinen Client schicken. Ca so:

Code: Select all

foreach($pages->find("template=foo") as $p) {
  // send SSE event "Trashing page $p"
  // Anm: $p wird automatisch zur page id konvertiert wenn es als string verwendet wird
  $p->delete();
}
Per AJAX geht das nicht, denn da würde ich erst eine Antwort bekommen, wenn das ganze Skript fertig ist. Also nutzlos!

Ich hoffe das hilft beim Verständnis und vielen Dank für deine Hilfe!
User avatar
24unix
Posts: 1626
Joined: Sun 21. Jun 2020, 17:16
Location: Kollmar
Contact:

Re: PHP SSE (Server Sent Events) + KeyHelp

Post by 24unix »

baumrock wrote: Sun 23. Jan 2022, 12:15 Per AJAX geht das nicht, denn da würde ich erst eine Antwort bekommen, wenn das ganze Skript fertig ist. Also nutzlos!
Den Status hat Du auf dem Server in einer Variablen?
Die kannst Du doch einfach per AJAX auslesen und updaten.
mfg Micha
--
If Bill Gates had a nickel for every time Windows crashed …
… oh wait, he does.
User avatar
OlliTheDarkness
Posts: 1854
Joined: Tue 14. Aug 2018, 16:41
Location: Essen (NRW)

Re: PHP SSE (Server Sent Events) + KeyHelp

Post by OlliTheDarkness »

baumrock wrote: Sun 23. Jan 2022, 12:15 Nein, also so wie ich das verstehe ist es bei SSE eben genau anders! Und deshalb brauch ich auch SSE und nicht AJAX.

Der Grund dafür ist, dass ich ein Skript am Server laufen habe, das länger dauert. Ich möchte den Progress an den Client schicken, damit man sich auskennt, was gerade passiert. Konkret verwende ich das ProcessWire CMS und lösche eine unbekannte Zahl von "Pages":

Code: Select all

foreach($pages->find("template=foo") as $p) {
  $p->delete();
}
Da das auch 1000e "Pages" sein können (und das Skript potentiell mehrere Sekunden läuft), möchte ich den Status per SSE an meinen Client schicken. Ca so:

Code: Select all

foreach($pages->find("template=foo") as $p) {
  // send SSE event "Trashing page $p"
  // Anm: $p wird automatisch zur page id konvertiert wenn es als string verwendet wird
  $p->delete();
}
Per AJAX geht das nicht, denn da würde ich erst eine Antwort bekommen, wenn das ganze Skript fertig ist. Also nutzlos!

Ich hoffe das hilft beim Verständnis und vielen Dank für deine Hilfe!
Ja ne, dann is das doch vollkommen richtig.

Weil die Verarbeitung also Ausgabe erfolgt ja "live" und durch den flush(); wird der Puffer regelmässig ausgeworfen und eben nicht erst wenn er komplett durchlaufen wurde.

Glaub grad ich hab nen 200%igen Verständinissfehler :lol:

Es ist Sonntag, ich brauch mal grad nen Kaffee oder besser nen Schnaps :lol:

AJax ist da aber doch auch ne möglichkeit indem deine "Abfrage" in ne Var. wirfst.

EDIT

Unix war schneller.
Mit freundlichen Grüßen
OlliTheDarkness

**************************************************************
Helden leben lange, Legenden sterben nie

:!: World Hack Organization :!:
**************************************************************
bernhard
Posts: 144
Joined: Fri 29. May 2020, 14:36

Re: PHP SSE (Server Sent Events) + KeyHelp

Post by bernhard »

Den Status hat Du auf dem Server in einer Variablen?
Die kannst Du doch einfach per AJAX auslesen und updaten.
Nein, das geht nicht. Mein Skript läuft potentiell mehrere Sekunden lang und ich kann den Status per AJAX nicht abfragen. Deswegen will ich ja SSE verwenden. Siehe dieses Beispiel:

Code: Select all

<?php
for($i=0; $i<10; $i++) {
  echo "Value of i = $i";
  sleep(1);
}
Du kannst den status von $i nicht per AJAX abfragen. Man könnte $i in eine log.txt schreiben und diese per AJAX auslesen, aber da das Skript den PHP thread für den aktuellen user blockt, würde ich auch per AJAX erst nach 10 Sekunden den Status zurückbekommen - was wiederum Sinnlos ist, weil das ist kein richtiges progress monitoring.

Ich will sowas:

Code: Select all

<?php
for($i=0; $i<10; $i++) {
  // send SSE status of $i to client
  // on the client do a console.log("status of $i = ...");
  sleep(1);
}
Siehe auch hier:

https://stackoverflow.com/questions/145 ... the-server
User avatar
24unix
Posts: 1626
Joined: Sun 21. Jun 2020, 17:16
Location: Kollmar
Contact:

Re: PHP SSE (Server Sent Events) + KeyHelp

Post by 24unix »

baumrock wrote: Sun 23. Jan 2022, 12:27 Du kannst den status von $i nicht per AJAX abfragen. Man könnte $i in eine log.txt schreiben und diese per AJAX auslesen, aber da das Skript den PHP thread für den aktuellen user blockt, würde ich auch per AJAX erst nach 10 Sekunden den Status zurückbekommen - was wiederum Sinnlos ist, weil das ist kein richtiges progress monitoring.
Ich denke schon, dass das klappen würde, kann es evtl. später mal ausprobieren.
Habe gerade eine andere Baustelle, mache gleich einen Thread dazu auf, evtl. hast Du eine idee.
mfg Micha
--
If Bill Gates had a nickel for every time Windows crashed …
… oh wait, he does.
bernhard
Posts: 144
Joined: Fri 29. May 2020, 14:36

Re: PHP SSE (Server Sent Events) + KeyHelp

Post by bernhard »

Bitte seht euch dieses Video an - das zeigt wie es lokal auf Windows+Laragon funktioniert (und funktionieren soll): https://calip.io/HkCWbYAB#ueAgNM5v

Der stream läuft immer 10 Sekunden und gibt aber jede Sekunde den Status von $i aus. Das 10Sekunden limit ist einfach nur lokal fürs entwickeln, damit ich nicht zig endlos laufende PHP threads aufmache (hatte da bei den ersten Versuchen Probleme).

Das ist der funktionierende code:

Code: Select all

<?php
date_default_timezone_set("America/New_York");
header("Content-Type: text/event-stream");

$i = 0;
while(true) {
  $i++;

  // manual limit of 10 runs for development
  if($i>=10) return;

  echo "data: value of i = $i\n\n";

  while (ob_get_level() > 0) ob_end_flush();
  flush();

  if(connection_aborted()) break;

  sleep(1);
}

Code: Select all

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <h1>Open DevTools Console + Network Tab!</h1>
  <script>
  const evtSource = new EventSource("sse.php", { withCredentials: true } );
  evtSource.onmessage = function(event) {
    console.log(event.data);
  }
  </script>
</body>
</html>
Und so sieht es auf meinem KeyHelp Server aus (das Skript läuft wieder 10s lang, aber gibt die Messages nicht jede Sekunde sondern auch immer erst am Ende der 10s aus (nämlich wenn das Skript abbricht)):

https://calip.io/DzhmJQo2#4mfu1aP6
Habe gerade eine andere Baustelle, mache gleich einen Thread dazu auf, evtl. hast Du eine idee.
Kann ich gerne schauen
bernhard
Posts: 144
Joined: Fri 29. May 2020, 14:36

Re: PHP SSE (Server Sent Events) + KeyHelp

Post by bernhard »

OlliTheDarkness hat eine Lösung gefunden!!!

Code: Select all

<?php
header("Cache-Control: no-cache");
header("Content-Type: text/event-stream");

$i = 0;
while(true) {
  $i++;

  echo "data: value of i = $i\n\n";
  echo str_pad('',8186)."\n";
  ob_flush();
  flush();

  if($i>=29) return;

  while(ob_get_level() > 0) ob_end_flush();
  if(connection_aborted()) break;
  sleep(1);
}
@Olli vielleicht kannst du hier schreiben, wo du das str_pad() gefunden hast bzw. woher du wusstest, dass das fehlt. Bzw. was das genau tut?

Danke!!
User avatar
24unix
Posts: 1626
Joined: Sun 21. Jun 2020, 17:16
Location: Kollmar
Contact:

Re: PHP SSE (Server Sent Events) + KeyHelp

Post by 24unix »

Was es tut ist klar: die Ausgabe von Echo 8186 spaces lang machen.

Aber warum? Ich habe (noch) keine Ahnung von SSE.
mfg Micha
--
If Bill Gates had a nickel for every time Windows crashed …
… oh wait, he does.
User avatar
OlliTheDarkness
Posts: 1854
Joined: Tue 14. Aug 2018, 16:41
Location: Essen (NRW)

Re: PHP SSE (Server Sent Events) + KeyHelp

Post by OlliTheDarkness »

Das macht eigendlich nichts besonderes.
Es begrenzt jediglich einen String bzw. in diesem Fall den Ausgabepuffer auf X.

Code: Select all

ob_flush();
  flush();
wirft dann letztlich nur str_pad('',8186) also den maxiemierten Ausgabepuffer. aus.

8186 kann auch durchaus kleiner gewählt werden.

Zum Nachlesen:
https://www.php.net/manual/de/function.str-pad.php
https://www.php.net/manual/de/function.ob-flush.php
https://www.php.net/manual/de/function.flush.php
Mit freundlichen Grüßen
OlliTheDarkness

**************************************************************
Helden leben lange, Legenden sterben nie

:!: World Hack Organization :!:
**************************************************************
bernhard
Posts: 144
Joined: Fri 29. May 2020, 14:36

Re: PHP SSE (Server Sent Events) + KeyHelp

Post by bernhard »

Ja was str_pad tut war mir klar, aber nicht warum es damit dann funktioniert. Aber die PHP docs haben dann geholfen! Ich hab - bevor ich hier gefragt habe - schon 100 verschiedene Einstellungen versucht. Nichts hat geklappt. Ich konnte jetzt meinen Code zum Laufen bringen und hab ihn etwas vereinfacht:

Code: Select all

<?php
header("Cache-Control: no-cache");
header("Content-Type: text/event-stream");
@apache_setenv('no-gzip', 1);
@ini_set('zlib.output_compression', 0);
@ini_set('implicit_flush', 1);
ob_implicit_flush(1);

$i = 0;
while(true) {
  $i++;
  echo "data: value of i = $i\n\n";
  flush();
  if(connection_aborted()) break;
  sleep(1);
}
So sieht das nun auch sauberer aus :) Vielen Dank Olli!!
User avatar
OlliTheDarkness
Posts: 1854
Joined: Tue 14. Aug 2018, 16:41
Location: Essen (NRW)

Re: PHP SSE (Server Sent Events) + KeyHelp

Post by OlliTheDarkness »

Nichts zu danken, hatten die grauen Hirnzellen am Sonntag wenigstens was zu tun und sind nicht bei Netflix komplett verblödet :lol: :lol: :lol: :lol: :lol:
Mit freundlichen Grüßen
OlliTheDarkness

**************************************************************
Helden leben lange, Legenden sterben nie

:!: World Hack Organization :!:
**************************************************************
bernhard
Posts: 144
Joined: Fri 29. May 2020, 14:36

Re: PHP SSE (Server Sent Events) + KeyHelp

Post by bernhard »

Ok ich hab jetzt noch ein bisschen getestet und die str_pad methode scheint am zuverlässigsten zu funktionieren!

Getestet habe ich mit Win+Laragon, WSL+DDEV, Ubuntu+Apache (KeyHelp)
bernhard
Posts: 144
Joined: Fri 29. May 2020, 14:36

Re: PHP SSE (Server Sent Events) + KeyHelp

Post by bernhard »

Hier das Resultat - vielen Dank nochmal :)

Image
User avatar
24unix
Posts: 1626
Joined: Sun 21. Jun 2020, 17:16
Location: Kollmar
Contact:

Re: PHP SSE (Server Sent Events) + KeyHelp

Post by 24unix »

Das schaut klasse aus, respekt!

Wenn ich meine API fertig habe, schaue ich mir SSE mal näher an.
mfg Micha
--
If Bill Gates had a nickel for every time Windows crashed …
… oh wait, he does.
bernhard
Posts: 144
Joined: Fri 29. May 2020, 14:36

Re: PHP SSE (Server Sent Events) + KeyHelp

Post by bernhard »

Danke 8-)

Bin auch super happy. Das war bis jetzt immer ein Krampf, solche Sachen mit AJAX zu lösen und wirklich gut war's für den Enduser auch nicht. Die Implementierung jetzt mit SSE ist super einfach und der User bekommt richtig gutes Feedback und kennt sich aus :)

Image

Falls ihr zufällig ein super flexibles und stabiles CMS sucht, freu ich mich euch im ProcessWire Forum wiederzusehen - dort beantworte ich mehr Fragen als ich stelle ;) :D ProcessWire ist mmn ein ähnlich guter Geheimtipp wie KeyHelp und weit weniger bekannt als es das verdienen würde.
Post Reply