web-dev-qa-db-fra.com

Comment vider la sortie après chaque appel `echo`?

J'ai un script php qui ne produit que des journaux sur le client.
Lorsque je répète quelque chose, je souhaite que celui-ci soit transféré au client à la volée.
(Car pendant le traitement du script, la page est vide)
J'avais déjà joué avec ob_start() et ob_flush(), mais ils ne fonctionnaient pas.

Quelle est la meilleure solution?

PS: il est un peu sale de mettre une couleur à la fin de l'appel echo ...

EDIT: Ni les réponses ont fonctionné, PHP ou Apache Fault? 

47
CuSS

Modifier:

Je lisais les commentaires sur la page de manuel et suis tombé sur un bogue qui indique que ob_implicit_flushne fonctionne pas et que ce qui suit est une solution de contournement:

ob_end_flush();

# CODE THAT NEEDS IMMEDIATE FLUSHING

ob_start();

Il se peut même que le client ne reçoive pas le paquet du serveur avant que celui-ci ait créé suffisamment de caractères pour envoyer ce qu’il considère être un paquet digne d’être envoyé.


Ancienne réponse:

Vous pouvez utiliser ob_implicit_flush qui indiquera à la mise en mémoire tampon de sortie de la désactiver pendant un certain temps:

ob_implicit_flush(true);

# CODE THAT NEEDS IMMEDIATE FLUSHING

ob_implicit_flush(false);
32
amphetamachine

J'ai eu le même problème et l'un des exemples affichés dans le manuel a fonctionné. Un jeu de caractères doit être spécifié comme l'une des affiches déjà mentionnées. http://www.php.net/manual/en/function.ob-flush.php#109314

header( 'Content-type: text/html; charset=utf-8' );
echo 'Begin ...<br />';
for( $i = 0 ; $i < 10 ; $i++ )
{
    echo $i . '<br />';
    flush();
    ob_flush();
    sleep(1);
}
echo 'End ...<br />';
56
Teno

Alors voici ce que j'ai découvert.

Flush ne fonctionnerait pas sous le mod_gzip d'Apache ni le gzip de Nginx car, logiquement, il gzippe le contenu. Pour ce faire, il doit 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 aussi ces lignes sous la main, surtout 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 to make the buffer achieve the minimum size in order to flush data
    echo str_repeat(' ',1024*64);

    sleep(1);
}
29
Roger

Le fait de rincer apparemment sans succès est un effet secondaire de la détection automatique des jeux de caractères.

Le navigateur n’affiche rien tant qu’il ne connaît pas le jeu de caractères dans lequel il doit être affiché et, si vous ne spécifiez pas le jeu de caractères, il doit essayer de le deviner. Le problème est qu’il ne peut pas deviner avec de bonnes données sans assez de données. C’est pourquoi les navigateurs semblent avoir cette mémoire tampon de 1024 octets (ou similaire) à remplir avant d’afficher quoi que ce soit.

La solution consiste donc à s'assurer que le navigateur ne doit pas deviner le jeu de caractères. 

Si vous envoyez du texte, ajoutez un '; charset = utf-8 'à son type de contenu, et s'il s'agit de HTML, ajoutez le jeu de caractères à la balise méta appropriée.

10
nobody

ce que vous voulez, c'est la méthode flush ..... exemple:

echo "log to client";
 flush();
7
GSto

Pour ceux qui arrivent en 2018:

La SEULE solution a fonctionné pour moi:

<?php

    if (ob_get_level() == 0) ob_start();
    for ($i = 0; $i<10; $i++){

        echo "<br> Line to show.";
        echo str_pad('',4096)."\n";    

        ob_flush();
        flush();
        sleep(2);
    }

    echo "Done.";

    ob_end_flush();
?>

et il est très important de garder la partie "4096" car il semble que "remplisse" le tampon ...

7
Ari Waisberg

Pourquoi ne pas créer une fonction pour faire écho, comme ceci:

function fecho($string) {
 echo $string;
 ob_flush();
}
5
cam8001

J'ai eu une chose similaire à faire. En utilisant

// ini_set("output_buffering", 0);  // off 
ini_set("zlib.output_compression", 0);  // off
ini_set("implicit_flush", 1);  // on   

fait le flushing de sortie fréquent dans mon cas.

Mais je devais vider la sortie juste à un point particulier (dans une boucle que je lance), donc en utilisant les deux 

ob_flush();
flush();

ensemble a travaillé pour moi.

Je n'ai pas pu. désactiver "output_buffering" avec ini_set (...), devait le tourner directement dans php.ini, phpinfo () montre son réglage comme "pas de valeur" lorsqu'il est éteint, est-ce que Ordinaire? .

3
freedayum

La fonction correcte à utiliser est flush().

<html>
<body>
<p>
Hello! I am waiting for the next message...<br />
<?php flush(); sleep(5); ?>
I am the next message!<br />
<?php flush(); sleep(5); ?>
And I am the last message. Good bye.
</p>
</body>
</html>

Veuillez noter qu'il existe un "problème" avec IE, qui ne génère le contenu vidé que lorsqu'il est au moins de 256 octets; votre première partie de la page doit donc comporter au moins 256 octets.

2
Dennis G

Cela fonctionne bien pour moi (Apache 2.4/PHP 7.0):

@ob_end_clean();
echo "lorem ipsum...";
flush();
sleep(5);
echo "<br>dolor...";
flush();
sleep(5);
echo "<br>sit amet";
1
Radacina

Un logiciel anti-virus peut également interférer avec le vidage de la sortie. Dans mon cas, Kaspersky Anti-Virus 2013 contenait des fragments de données avant de les envoyer au navigateur, alors que j'utilisais une solution acceptée. 

1
marcovtwout

Ceci est mon code: (travail pour PHP7) 

private function closeConnection()
{
    @Apache_setenv('no-gzip', 1);
    @ini_set('zlib.output_compression', 0);
    @ini_set('implicit_flush', 1);

    ignore_user_abort(true);
    set_time_limit(0);

    ob_start();
    // do initial processing here
    echo json_encode(['ans' => true]);

    header('Connection: close');
    header('Content-Length: ' . ob_get_length());
    ob_end_flush();
    ob_flush();
    flush();
}
0
Dmitry Matrosov

Essaye ça:

while (@ob_end_flush());      
ob_implicit_flush(true);

echo "first line visible to the browser";
echo "<br />";

sleep(5);

echo "second line visible to the browser after 5 secs";

Notez simplement que de cette manière, vous désactivez le tampon de sortie pour votre script actuel. Je suppose que vous pouvez le réactiver avec ob_start () (je ne suis pas sûr).

L'important est qu'en désactivant votre tampon de sortie comme ci-dessus, vous ne pourrez plus rediriger votre script php à l'aide de la fonction header(), car php ne peut envoyer qu'une seule fois par en-tête HTTP d'exécution de script. Vous pouvez cependant rediriger en utilisant javascript. Laissez juste votre script php faire écho aux lignes suivantes:

        echo '<script type="text/javascript">';
        echo 'window.location.href="'.$url.'";';
        echo '</script>';
        echo '<noscript>';
        echo '<meta http-equiv="refresh" content="0;url='.$url.'" />';
        echo '</noscript>'; 
        exit;
0
Grigoreas P.

Une chose qui n'est pas souvent mentionnée est la compression gzip qui reste activée en raison de détails dans divers environnements d'hébergement.

Voici une approche moderne, utilisant PHP-FPM comme Fast CGI, qui ne nécessite pas de règle de réécriture .htaccess ni de variable d’environnement:

Dans php.ini ou .user.ini:

output_buffering = 0
zlib.output_compression = 0
implicit_flush = true
output_handler = 

Dans le script PHP:

header('Content-Encoding: none'); // Disable gzip compression
ob_end_flush(); // Stop buffer
ob_implicit_flush(1); // Implicit flush at each output command

Voir ce commentaire sur la documentation officielle PHP pour ob_end_flush () need.

0
ZalemCitizen

Notez que si vous êtes sur certains sites d'hébergement partagé comme Dreamhost, vous ne pouvez pas du tout désactiver la mise en mémoire tampon de la sortie PHP sans passer par différentes routes:

Changer le cache du tampon de sortie Si vous utilisez PHP FastCGI, PHP les fonctions flush (), ob_flush () et ob_implicit_flush () ne le seront pas fonctionner comme prévu. Par défaut, la sortie est mise en mémoire tampon à un niveau supérieur que PHP (spécifiquement, par le module Apache mod_deflate qui est similaire dans la forme/fonction à mod_gzip).

Si vous avez besoin d'une sortie non tamponnée, vous devez utiliser CGI (au lieu de FastCGI) ou contacter le support technique pour demander que mod_deflate soit désactivé pour votre site.

https://help.dreamhost.com/hc/en-us/articles/214202188-PHP-overview

0
Matthew Lock