So leeren Sie Daten in den Browser, fahren aber mit der Ausführung fort
Lesezeit: 6 Minuten
aWebDeveloper
Ich habe ein ob_start() und ein entsprechendes ob_flush(). Ich möchte einen Teil der Daten löschen und den Rest weiter ausführen. Verwenden ob_flush() hat nicht geholfen. Auch wenn möglich muss der Rest passieren, ohne dass das Laden im Browser angezeigt wird.
BEARBEITEN:
Ich möchte kein Ajax verwenden
Soll nach dem ersten ob_flush eine andere Ausgabe angezeigt werden? Oder möchten Sie, dass die Anfrage vollständig abgeschlossen wird, soweit der Client dies erkennen kann, und dann eine Art Verarbeitung im Hintergrund fortgesetzt wird?
– Korbin
14. Mai 2012 um 7:34 Uhr
Alles, was Sie brauchen, ist flush(), wenn Ihre Ausgabepufferung bereits in php.ini deaktiviert ist, aber damit dies funktioniert, müssen Sie Apache, NginX usw. konfigurieren.
– PJ Brunet
13. November 2013 um 1:55 Uhr
Zombaya
Ich habe das in der Vergangenheit gemacht und so habe ich es gelöst:
ob_start();
/*
* Generate your output here
*/
// Ignore connection-closing by the client/user
ignore_user_abort(true);
// Set your timelimit to a length long enough for your script to run,
// but not so long it will bog down your server in case multiple versions run
// or this script get's in an endless loop.
if (
!ini_get('safe_mode')
&& strpos(ini_get('disable_functions'), 'set_time_limit') === FALSE
){
set_time_limit(60);
}
// Get your output and send it to the client
$content = ob_get_contents(); // Get the content of the output buffer
ob_end_clean(); // Close current output buffer
$len = strlen($content); // Get the length
header('Connection: close'); // Tell the client to close connection
header("Content-Length: $len"); // Close connection after $len characters
echo $content; // Output content
flush(); // Force php-output-cache to flush to browser.
// See caveats below.
// Optional: kill all other output buffering
while (ob_get_level() > 0) {
ob_end_clean();
}
Wie ich bereits in einigen Kommentaren gesagt habe, sollten Sie darauf achten, Ihren Inhalt zu gzippen, da dies die Länge Ihres Inhalts ändert, aber nicht den Header darüber ändert. Es kann auch Ihre Ausgabe puffern, sodass sie nicht sofort an den Client gesendet wird.
Sie könnten versuchen, Apache wissen zu lassen, dass Ihre Inhalte nicht gzip werden sollen, indem Sie verwenden apache_setenv('no-gzip', '1');. Dies funktioniert jedoch nicht, wenn Sie Rewrite-Regeln verwenden, um zu Ihrer Seite zu gelangen, da dann auch diese Umgebungsvariablen geändert werden. Zumindest hat es das für mich getan.
Weitere Einschränkungen zum Freigeben Ihrer Inhalte an den Benutzer finden Sie im Handbuch.
Nur zu Ihrer Information, die PHP-Funktion ist ob_get_contentS
– Bob Gregor
11. November 2013 um 20:55 Uhr
Corbin
ob_flush schreibt den Puffer. Mit anderen Worten, ob_flush weist PHP an, Apache (oder nginx/lighttpd/whatever) die Ausgabe zu geben und PHP sie dann zu vergessen. Sobald Apache die Ausgabe hat, macht er damit, was er will. (Mit anderen Worten, nach ob_flush es liegt außerhalb Ihrer Kontrolle, ob es sofort in den Browser geschrieben wird oder nicht).
Also, kurze Antwort: Es gibt keinen garantierten Weg, das zu tun.
Nur eine Vermutung, Sie suchen wahrscheinlich nach AJAX. Wann immer Leute versuchen, das Laden von Seiteninhalten zu manipulieren, wie Sie es tun, ist AJAX fast immer der richtige Weg.
Wenn Sie eine Aufgabe im Hintergrund fortsetzen möchten, können Sie verwenden ignore_user_abort, wie hier ausgeführt, ist jedoch oft nicht der optimale Ansatz. Sie verlieren im Wesentlichen die Kontrolle über diesen Thread, und meiner Meinung nach gehört ein Webserver-Thread nicht zu einer starken Verarbeitung.
Ich würde versuchen, es aus dem Web zu extrahieren. Dies könnte einen Cron-Eintrag bedeuten oder einfach einen Hintergrundprozess innerhalb von PHP starten (ein Prozess, der zwar innerhalb der Skriptausführung gestartet wurde, stirbt jedoch nicht mit dem Skript, und das Skript wartet nicht darauf, dass es beendet wird, bevor es stirbt).
Wenn Sie diesen Weg gehen, bedeutet dies, dass Sie bei Bedarf sogar eine Art Statussystem erstellen können. Dann könnten Sie die Ausführung überwachen und den Benutzer regelmäßig über den Fortschritt informieren. (Technisch könnte man ein Statussystem mit a erstellen ignore_user_abort-ed-Skript auch, aber es scheint mir nicht so sauber zu sein.)
Wenn sich ein neuer Benutzer anmeldet, möchte ich viele Daten speichern. Diese Daten sollten sofort gespeichert werden, aber den Benutzer nicht unterbrechen, dh das Laden im Browser anzeigen
Oben zwei Funktionen sind die Schlüsselfaktoren, die ignore_user_abort verhindert Fehler u fastcgi_finish_request schließt Client-Verbindung.
Alex Wilke
fastcgi_finish_request
Diese Funktion überträgt alle Antwortdaten an den Client und beendet die Anfrage. Dadurch können zeitaufwändige Aufgaben ausgeführt werden, ohne dass die Verbindung zum Client offen bleibt.
funktioniert nicht auf Apache. (PHP 5 >= 5.3.3, PHP 7)
Verwenden:
header("Content-Length: $len");
..wo $len ist die Länge der an den Client zu übertragenden Daten.
Ich habe nicht den Hintergrund, um zu wissen, wann und wo dies funktionieren wird, aber ich habe ein paar Browser ausprobiert, und alle kamen sofort zurück mit:
<?PHP
header("Content-length:5");
echo "this is more than 5";
sleep(5);
?>
Bearbeiten: Chrome, IE und Opera wurden angezeigt thiswährend Firefox angezeigt wurde this is more than 5. Alle haben die Anfrage danach jedoch geschlossen.
Deshalb muss die Inhaltslänge genauso lang sein wie der eigentliche Inhalt. Und hüten Sie sich vor gzip, da dies die Länge Ihrer Antwort verändert.
– Zombaja
14. Mai 2012 um 8:36 Uhr
@Zombaya, ich sehe jedoch nicht, wie das relevant ist. Solange er nicht versucht, seine Ausgabe nach einer bestimmten Menge zu unterbrechen, sollte dies funktionieren, um die Anfrage nach dem Senden der erforderlichen Daten zu beenden.
– Mähwalker
14. Mai 2012 um 8:38 Uhr
Nun, als ich es versuchte und die Länge nicht mit der tatsächlichen Länge übereinstimmte, wurde die Verbindung nicht immer geschlossen und weiter geladen.
– Zombaja
14. Mai 2012 um 8:45 Uhr
@Zombaya, warum stimmt die Länge nicht mit der tatsächlichen Länge überein? Warum konnte er nicht einfach tun header("Content-Length: ".strlen($content));
– Mähwalker
14. Mai 2012 um 8:46 Uhr
Das funktioniert normalerweise, aber wenn Sie Apache so konfiguriert haben, dass es die gzip-Komprimierung auf Ihren ausgegebenen Webseiten verwendet, ändert es den Inhalt Ihrer Antwort, aber nicht den Content-Length-Header. Damit hatte ich in der Vergangenheit etwas Probleme.
– Zombaja
14. Mai 2012 um 8:50 Uhr
10185600cookie-checkSo leeren Sie Daten in den Browser, fahren aber mit der Ausführung fortyes
Soll nach dem ersten ob_flush eine andere Ausgabe angezeigt werden? Oder möchten Sie, dass die Anfrage vollständig abgeschlossen wird, soweit der Client dies erkennen kann, und dann eine Art Verarbeitung im Hintergrund fortgesetzt wird?
– Korbin
14. Mai 2012 um 7:34 Uhr
Alles, was Sie brauchen, ist flush(), wenn Ihre Ausgabepufferung bereits in php.ini deaktiviert ist, aber damit dies funktioniert, müssen Sie Apache, NginX usw. konfigurieren.
– PJ Brunet
13. November 2013 um 1:55 Uhr