web-dev-qa-db-fra.com

PHP Flush qui fonctionne ... même dans Nginx

Est-il possible d'écho à chaque exécution de la boucle? Par exemple:

foreach(range(1,9) as $n){
    echo $n."\n";
    sleep(1);
}

Au lieu de tout imprimer à la fin de la boucle, j'aimerais qu'elle affiche chaque résultat à la fois.

25
Roger

SOLUTION FINALE

C'est ce que j'ai découvert:

Flush ne fonctionnerait pas avec le mod_gzip d’Apache ni avec le gzip de Nginx car, logiquement, il gzippait le contenu. Pour ce faire, il devait mettre le contenu en tampon pour le gzip. Tout type de serveur Web gzipping aurait une incidence sur cela. En bref, côté serveur, nous devons désactiver gzip et réduire la taille de la mémoire tampon de fastcgi. Alors:

  • Dans php.ini:

    . output_buffering = Off

    . zlib.output_compression = Off

  • Dans nginx.conf:

    . gzip off;

    . proxy_buffering off;

Ayez également ces lignes sous la main, spécialement si vous n'avez pas accès à php.ini:

  • @ini_set ('zlib.output_compression', 0);

  • @ini_set ('implicit_flush', 1);

  • @ob_end_clean ();

  • set_time_limit (0);

Enfin, si vous en avez un, commentez le code ci-dessous:

  • ob_start ('ob_gzhandler');

  • ob_flush ();

PHP code de test:

ob_implicit_flush(1);

for($i=0; $i<10; $i++){
    echo $i;

    //this is for the buffer achieve the minimum size in order to flush data
    echo str_repeat(' ',1024*64);

    sleep(1);
}

En relation:

33
Roger

Le moyen le plus simple d’éliminer la mise en mémoire tampon de nginx consiste à émettre un en-tête:

header('X-Accel-Buffering: no');

Ceci élimine à la fois proxy_buffering et (si vous avez nginx> = 1.5.6), fastcgi_buffering. Le bit fastcgi est crucial si vous utilisez php-fpm. L'en-tête est également beaucoup plus pratique à faire selon les besoins.

Docs sur X-Accel-BufferingDocs sur fastcgi_buffering

32
Andy Fowler

Solution facile sur le serveur nginx: 

fastcgi_keep_conn on; # < solution

proxy_buffering off;
gzip off;
24
Ondrej Prochazka

Je ne voulais pas avoir à désactiver gzip pour tout le serveur ou tout un répertoire, juste pour quelques scripts, dans quelques cas spécifiques.

Tout ce dont vous avez besoin est ceci avant que quoi que ce soit ne soit répercuté:

header('Content-Encoding: none;');

Ensuite, faites la chasse comme d'habitude:

ob_end_flush();
flush();

Nginx semble comprendre que l'encodage a été désactivé et ne gzip pas.

10
Redzarf

Vous devez vider le tampon php dans le navigateur

foreach(range(1,9) as $n){
    echo $n."\n";
    flush();
    sleep(1);
}

Voir: http://php.net/manual/en/function.flush.php

5
Petah

J'ai trouvé que vous pouvez définir:

header("Content-Encoding:identity");

dans votre script php pour désactiver nginx gzipping sans avoir à modifier le nginx.conf

2
ttk

Vous pouvez accomplir cela en vidant le tampon de sortie au milieu de la boucle.

Exemple:

ob_start();
foreach(range(1,9) as $n){
    echo $n."\n";
    ob_flush();
    flush();
    sleep(1);
}

Notez que vos paramètres php.ini peuvent déterminer si cela fonctionnera ou non si la compression zlib est activée. 

2
Andy Baird

J'ai eu un problème avec gzip venant de mon moteur php-fpm. Ce code est le seul qui fonctionne pour moi:

function myEchoFlush_init() {
    ini_set('zlib.output_compression', 0);
    ini_set('output_buffering', 'Off');
    ini_set('output_handler', '');
    ini_set('implicit_flush', 1);
    ob_implicit_flush(1);
    ob_end_clean();
    header('Content-Encoding: none;');

}

function myEchoFlush($str) {
    echo $str . str_repeat(' ', ini_get('output_buffering') * 4) . "<br>\n";
}

Ceci est ma fonction de test: elle vérifie max_execution_time:

public function timeOut($time = 1, $max = 0) {
    myEchoFlush_init();
    if ($max) ini_set('max_execution_time', $max);
    myEchoFlush("Starting infinite loop for $time seconds. It shouldn't exceed : " . (ini_get('max_execution_time')));
    $start = microtime(true);
    $lastTick = 1;
    while (true) {
        $tick = ceil(microtime(true) - $start);
        if ($tick > $lastTick) {
            myEchoFlush(microtime(true) - $start);
            $lastTick = $tick;
        }
        if ($tick > $time) break;
    }
    echo "OK";
}
1
Nicolas Thery