web-dev-qa-db-fra.com

Comment désactiver la mise en mémoire tampon de sortie dans PHP

J'ai écrit un script de relais simple qui se connecte à une caméra Web et lit à partir de la prise et génère ces données à l'aide de la fonction d'impression. Les données sont des données MJPG avec des limites déjà configurées. Je viens de sortir les données lues.

Le problème est PHP semble mettre ces données en mémoire tampon. Lorsque je règle la caméra sur 1 FPS, le flux se fige pendant 7 à 8 secondes, puis affiche rapidement 8 images. Si je règle la résolution à une taille énorme, la caméra se déplace à plus ou moins 1 image par seconde. Je suppose alors qu'une certaine mise en mémoire tampon se produit (car les tailles énormes remplissent le tampon rapidement, et les tailles faibles ne le font pas), et je ne peux pas comprendre comment désactiver cette mise en mémoire tampon. Quelqu'un sait-il comment le faire?

Code:

ignore_user_abort(false);

$boundary = "myboundary";

//Set this so PHP doesn't timeout during a long stream
set_time_limit(0);

$socketConn = @fsockopen ("192.168.1.6", 1989, $errno, $errstr, 2);
if (!$socketConn)
exit();
stream_set_timeout($socketConn, 10);
fputs ($socketConn, "GET /mjpeg HTTP/1.0\r\n\r\n");

//Setup Header Information
header("Cache-Control: no-cache");
header("Cache-Control: private");
header("Pragma: no-cache");
header("Content-type: multipart/x-mixed-replace; boundary=$boundary");

@ini_set('implicit_flush', 1);
for ($i = 0; $i < ob_get_level(); $i++)
ob_end_flush();
ob_implicit_flush(1);

stream_set_blocking($f2, false);

//Send data to client
while (connection_status() == CONNECTION_NORMAL)
{
    $chunk = fread($socketConn, 128);
    print $chunk;   
}

fclose($socketConn);
29
Ioncannon

tl; dr version

Faites deux choses:

  1. Désactivez le tampon de sortie de l'espace utilisateur, soit ...

    • Globalement, soit par ...

      • Désactiver output_buffering Dans votre php.ini, ou
      • Désactiver output_buffering Dans votre configuration Apache à l'aide de

        php_flag "output_buffering" Off
        
    • ou juste pour le script qui vous intéresse, soit par ...

      • appeler ob_end_flush(), ou
      • appel de ob_end_clean()
  2. De plus, désactivez le tampon de sortie au niveau du serveur autant que possible, soit:

    • appeler ob_implicit_flush() au début de votre script, ou
    • appeler flush() après chaque echo instruction ou autre instruction qui ajoute une sortie au corps de la réponse

Version plus longue

De façon confuse, il existe deux couches de mise en mémoire tampon qui peuvent être pertinentes et la documentation PHP fait une mauvaise distinction entre les deux.

Le tampon de sortie

La première couche est généralement désignée par les documents PHP comme "tampon de sortie". Cette couche de mise en mémoire tampon affecte uniquement la sortie vers le corps de la réponse HTTP , pas les en-têtes. Vous pouvez activer la mise en mémoire tampon de sortie avec ob_start() , et la désactiver avec ob_end_flush() ou ob_end_clean() . Vous pouvez également faire démarrer automatiquement tous vos scripts avec une mise en mémoire tampon de sortie en utilisant l'option output_buffering dans php.ini.

La valeur par défaut de cette option pour versions de production de php.ini est 4096, ce qui signifie que les 4096 premiers octets de sortie seront mis en mémoire tampon dans le tampon de sortie, point auquel il sera vidé et mis en tampon de sortie est désactivé.

Vous pouvez désactiver cette couche de mise en mémoire tampon globalement en définissant output_buffering Sur Off dans votre fichier php.ini (ou en utilisant

php_flag "output_buffering" Off

dans votre configuration Apache, si vous utilisez Apache). Vous pouvez également le désactiver pour un seul script en appelant ob_end_clean() ou ob_end_flush() au début du script.

Le tampon d'écriture et le tampon du serveur Web

Au-delà du tampon de sortie se trouve ce que le manuel PHP se réfère au "tampon d'écriture", plus tout système de tampon de votre serveur Web. Si vous utilisez PHP = avec Apache via mod_php, et n'utilisez pas mod_gzip, vous pouvez appeler flush() pour les vider; avec d'autres backends, cela pourrait fonctionner aussi, bien que le manuel soit hésitant à donner des assurances:

La description

void flush ( void )

Vide les tampons d'écriture de PHP et quel que soit le backend PHP utilise (CGI, un serveur Web, etc.). Cela tente de pousser la sortie actuelle jusqu'à le navigateur avec quelques mises en garde.

flush () peut ne pas être en mesure de remplacer le schéma de mise en mémoire tampon de votre serveur Web et il n'a aucun effet sur la mise en mémoire tampon côté client dans le navigateur. Cela n'affecte pas non plus le mécanisme de mise en mémoire tampon de sortie de l'espace utilisateur de PHP. Cela signifie que vous devrez appeler à la fois ob_flush () et flush () pour vider les tampons de sortie ob si vous utilisez ceux.

Il y a aussi quelques façons de faire PHP appeler automatiquement flush() chaque fois que vous echo quoi que ce soit (ou faire autre chose qui fait écho à la sortie de la réponse) corps).

La première consiste à appeler ob_implicit_flush() . Notez que cette fonction porte un nom trompeur; étant donné son préfixe ob_, toute personne raisonnable s'attendrait à ce que cela affecte le "tampon de sortie", tout comme ob_start, ob_flush etc. Cependant, ce n'est pas le cas; ob_implicit_flush(), comme flush(), affecte le tampon de sortie au niveau du serveur et n'interagit en aucune façon avec le tampon de sortie contrôlé par les autres fonctions ob_.

La seconde consiste à activer globalement le vidage implicite en définissant le drapeau implicit_flush sur On dans votre php.ini. Cela revient à appeler ob_implicit_flush() au début de chaque script. Notez que le manuel déconseille cela, citant cryptiquement "implications sérieuses en termes de performances", dont j'explore certaines dans ce réponse liée de manière tangentielle .

50
Mark Amery

Plutôt que de désactiver la mise en mémoire tampon de sortie, vous pouvez simplement appeler flush() après chaque opération de lecture. Cela évite d'avoir à jouer avec la configuration du serveur et rend votre script plus portable.

17
DaveRandom

La mise en mémoire tampon de sortie peut être superposée et j'ai eu des cas où le code précédent avait fait plusieurs niveaux. Cela les effacera tous.

while (ob_get_level()) ob_end_clean(); 
// or ob_end_flush() if you want the contents of the buffer.
9
Yehosef

Nous pouvons donner le code ci-dessous dans le fichier .htaccess pour désactiver la mise en mémoire tampon de sortie en PHP

php_flag "output_buffering" off
2
Binod

Je sais que cette question est un peu ancienne, mais pour en revenir à cette question, vous pouvez désactiver la mise en mémoire tampon de sortie script par script, comme ceci:

if (ob_get_level())
   ob_end_clean();

Cela devrait désactiver tous les tampons de sortie pour tout script qui le suit.

0
Solomon Closson