<?php for($i=0;$i<20;$i++) { echo 'printing...<br />'; ob_flush(); flush(); usleep(300000); } ?>
Url, который содержит код: http://domainsoutlook.com/sandbox/delayed.php
У меня есть выделенный сервер, поэтому я могу внести изменения. Я использую apache и nginx в качестве прокси-сервера.
Вы используете ob_flush
без ob_flush
, поэтому для него нечего ob_flush
.
Это также зависит от веб-сервера и прокси-сервера и его настроек.
Вы должны отключить буферизацию для Nginx (добавьте «proxy_buffering off» в конфигурационный файл и перезапустите Nginx)
Кроме того, проверьте, содержит ли ваш php.ini «output_buffering = Off» и «zlib.output_compression = Off».
Вот что я узнал:
Флеш не работал бы с помощью apache mod_gzip или gzip от Nginx, потому что, по логике, это gzipping содержимое, и для этого он должен буферизовать контент, чтобы его gzip. Любой вид gzipping веб-сервера повлияет на это. Короче говоря, на стороне сервера нам нужно отключить gzip и уменьшить размер буфера fastcgi. Так:
В php.ini:
, output_buffering = Off
, zlib.output_compression = Off
В nginx.conf:
, gzip off;
, proxy_buffering off;
Также имейте это в виду, особенно если у вас нет доступа к php.ini:
@ini_set ( 'zlib.output_compression', 0);
@ini_set ( 'implicit_flush', 1);
@ob_end_clean ();
set_time_limit (0);
Наконец, если у вас есть это, выполните приведенный ниже код:
ob_start ( 'ob_gzhandler');
ob_flush ();
Код проверки PHP:
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); }
Основной файл php;
<?php header('Content-Type: text/HTML; charset=utf-8'); header( 'Content-Encoding: none; ' );//disable apache compressed session_start(); ob_end_flush(); ob_start(); set_time_limit(0); error_reporting(0); ..... bla bla for(each)........ { bla bla.. echo "<br>>>>".$i."<<<br>"; ob_flush(); flush(); //ie working must } ?>
работает..
Другой возможной причиной является mod_security. Похоже, что у него есть собственные буферы. Поэтому, если вы используете его, вам придется установить:
SecResponseBodyAccess Off
Вид грязного обходного пути, но пока что это единственный способ заставить его работать.
Вы должны заполнить буфер, чтобы его можно было сбросить в браузер. Используйте это после эха
echo str_pad('',4096)."\n";
Полный код:
<?php if (ob_get_level() == 0) ob_start(); for( $i=0 ; $i<20 ; $i++) { echo 'printing...<br />'; echo str_pad('',4096)."\n"; ob_flush(); flush(); usleep(300000); } ob_end_flush(); ?>
Просто хотел добавить к ответу Роджера.
Если вы используете модуль FastCGI php5- fpm в Apache2, вы также должны убедиться, что добавляете
-промывать
аргумент в вашей конфигурации Apache2, т.е.
<IfModule mod_fastcgi.c> ... FastCgiExternalServer /usr/lib/cgi-bin/php5-fcgi -flush -socket /tmp/php5-fpm.sock -idle-timeout 480 -pass-header Authorization </IfModule>
Как я читал, это кажется очень трудным pb для решения, и единственный (грязный) способ, который я нашел, пишет что-то бесполезное для вывода, чтобы заполнить буферы. – без ssl – без output_buffering, необходим сброс, буферы nginx могут быть опущены до тех пор, пока размер заголовка php – с output_buffering, ob_flush необходимо добавить, чтобы иметь такое же поведение, как и выше – с ssl, есть еще один буфер для ssl и NGX_SSL_BUFSIZE исправлено в компиляции nginx
Вот мой файл test.php (назовите его с? Size = … для изменения записи пространства в цикле)
<!DOCTYPE html> <html> <head></head> <body> <?php $vars = array('output_buffering', 'zlib.output_compression'); print('<p>'); foreach ($vars as $var) { print("$var : "); var_dump(ini_get($var)); print('<br />'); } print("ob_get_level() : " .ob_get_level()); print('</p>'); if (ob_get_level()) { $bytes = ob_get_length(); ob_flush(); } $nb_iterations = !empty($_GET['nb']) ? max(2, (int) $_GET['nb']) : 5; $size = !empty($_GET['size']) ? $_GET['size'] : 0; for ($i = 1; $i < $nb_iterations; $i++) { sleep(1); print(str_repeat(' ', 1024 * $size )); print("<p>wait $i s</p>"); if (ob_get_level()) { $bytes += ob_get_length(); print($bytes + strlen($bytes)); ob_flush(); // this is working, results aren't depending on output_buffering value } flush(); // this is needed } ?> </body> </html>
И нижний conf, который я могу установить, – это
location ~ ^/test.php$ { gzip off; fastcgi_pass unix:/var/run/php5-fpm/ssl.socket; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param SCRIPT_FILENAME $request_filename; # if too low => upstream sent too big header while reading response header from upstream fastcgi_buffer_size 128; fastcgi_buffers 2 128; fastcgi_busy_buffers_size 128; }
В php.ini:
output_buffering = Выкл. zlib.output_compression = Выкл.
В nginx.conf:
fastcgi_keep_conn on; # <решение
proxy_buffering off; gzip off;
Я заметил, что браузеры реагируют по-разному. Например, Chrome хранится на входе навсегда и, похоже, не заботится о его отображении ранее. Неудивительно, что Firefox будет отображать ввод раньше, если применяются приведенные выше советы (внесенные другими stackoverflowers), поэтому попробуйте Firefox.
Я смог выполнить только этот способ: добавление session_write_close ();
if (ob_get_level() == 0) { if(!ob_start("ob_gzhandler"))ob_start(); } echo ('bla bla bla'); $ans=ob_get_contents(); ob_end_clean(); header('Connection: close'); header('Content-Length: '.strlen($ans)); header('Status: 200'); echo $ans; session_write_close(); ob_flush(); flush();
Проверьте свой сервер api с помощью
echo phpinfo();
Если вы нашли свой сервер api
Server API : CGI/FastCGI
в CentOS добавьте эту строку в "/etc/httpd/conf.d/fcgid.conf"
OutputBufferSize 0
Чтобы проверить, перезапустите сервер Apache и попробуйте выполнить код ниже
ob_start(); for($i = 0; $i < 10; $i ++) { echo $i; echo '<br />'; flush(); ob_flush(); sleep(1); }
if(!ob_get_level()) ob_start(); echo json_encode(array('valid'=>true,'msg'=>'Flush occured.')); $size = ob_get_length(); header("Content-Type: application/json"); // Set the content length of the response. header("Content-Length: {$size}"); //Close the connection if you want to. header("Connection: close"); // Flush all output. ob_end_flush(); ob_flush(); flush(); // Close current session (if it exists). if(session_id()) session_write_close();