2011-01-16 34 views
11
<?php 
for($i=0;$i<20;$i++) 
{ 
    echo 'printing...<br />'; 
    ob_flush(); 
    flush(); 

    usleep(300000); 
} 

?> 

Url có chứa mã: http://domainsoutlook.com/sandbox/delayed.phpphp tuôn ra không làm việc

Tôi có một máy chủ chuyên dụng vì vậy tôi có thể làm cho những thay đổi. Tôi đang chạy apache và nginx như máy chủ proxy.

+4

Apache _and_ nginx? Tôi nghĩ nginx sẽ đủ. – jwueller

+0

Bạn đang mong đợi điều gì sẽ xảy ra? –

+0

Nên 'ob_flush()' đến sau 'flush()', và bạn cũng là vòng lặp. cần phải bắt đầu một bộ đệm đầu ra với 'ob_start()' trước vòng lặp – RobertPitt

Trả lời

8

Bạn đang sử dụng ob_flush mà không cần ob_start, vì vậy không có gì để tuôn ra cho nó.

Nó cũng phụ thuộc vào máy chủ web và proxy cũng như cài đặt của máy chủ web.

Bạn nên vô hiệu hóa đệm cho Nginx (thêm "proxy_buffering tắt;" vào tập tin cấu hình và khởi động lại Nginx)

Ngoài ra, kiểm tra xem php.ini của bạn có chứa "output_buffering = Off" và "zlib.output_compression = Tắt ".

+0

nơi tệp cấu hình nginx thường là nơi tôi có thể thêm những giá trị –

+0

Nên là '/ etc/nginx.conf' – schnaader

+0

để tôi thêm dòng này cho nginx trong mô-đun lõi http –

31

Vì vậy, đó là những gì tôi phát hiện ra:

Flush sẽ không làm việc dưới mod_gzip Apache hoặc gzip Nginx vì, một cách logic, nó được gzipping nội dung, và để làm điều đó thì phải đệm nội dung gzip nó. Bất kỳ loại máy chủ web gzipping sẽ ảnh hưởng đến điều này. Tóm lại, ở phía máy chủ, chúng ta cần phải tắt gzip và giảm kích thước bộ đệm fastcgi. Vì vậy:

  • Trong php.ini:

    . output_buffering = Tắt

    . zlib.output_compression = Tắt

  • Trong nginx.conf:

    . gzip tắt;

    . proxy_buffering off;

Cũng có những dòng này trong tay, đặc biệt nếu bạn không có acces vào php.ini:

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

  • @ini_set ('implicit_flush', 1);

  • @ob_end_clean();

  • set_time_limit (0);

Cuối cùng, nếu bạn có nó, coment mã dưới đây:

  • ob_start ('ob_gzhandler');

  • ob_flush();

mã kiểm tra 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); 
} 
+7

Điều cuối cùng "vang lên 64k ** khoảng trắng ** vô nghĩa" đã làm thủ thuật cho tôi. Cảm ơn Roger. – humanityANDpeace

+0

. proxy_buffering off; là vấn đề trong cấu hình của tôi. Cảm ơn! – Noam

+0

Tôi đã làm tất cả những điều này nhưng không làm việc trên apos sống centos7 với php 5.5.Làm việc trơn tru tại địa phương ngay cả với output_buffering = 4096 – Azghanvi

0

Khi tôi đọc, có vẻ như một pb thực sự khó khăn để giải quyết, và chỉ (bẩn) cách tôi tìm thấy là viết một cái gì vô dụng để đầu ra để lấp đầy bộ đệm.. - không có ssl - không có output_buffering, cần thiết, bộ đệm nginx có thể được hạ xuống cho đến khi kích thước tiêu đề php - với output_buffering, ob_flush cần được thêm vào để có cùng hành vi như trên - với ssl, có một bộ đệm khác ssl và NGX_SSL_BUFSIZE được cố định trong nginx biên soạn

đây là tập tin test.php của tôi (gọi nó với? size = ... để thay đổi không gian viết trong vòng lặp)

<!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> 

và conf thấp hơn tôi có thể được đặt là

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; 
} 
10

Tệp php chính;

<?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 

} 
?> 

nó làm việc ..

+1

Nội dung mã hóa là những gì làm việc cho tôi trên nginx - mà không cần phải tắt nó đi cho toàn bộ máy chủ. Cảm ơn emin! – Redzarf

+1

Đặt 'Content-Encoding' cuối cùng đã làm cho công việc đỏ bừng trên Firefox, nhưng bằng cách nào đó Chrome vẫn đang chờ phản hồi nén, vì vậy nó đã ném ra một lỗi' ERR_CONTENT_DECODING_FAILED'. – skerit

0

Trong php.ini:

output_buffering = Tắt zlib.output_compression = Tắt

Trong nginx.conf:

fastcgi_keep_conn trên; # < giải pháp

proxy_buffering off; tắt gzip;

1

Một nguyên nhân khác có thể là mod_security. Có vẻ như nó có bộ đệm riêng. Vì vậy, nếu bạn đang sử dụng nó, bạn sẽ phải thiết lập:

SecResponseBodyAccess Off 

Loại cách giải quyết dơ bẩn nhưng cho đến nay nó là cách duy nhất tôi có nó hoạt động.

1

Bạn phải lấp đầy bộ đệm để bộ đệm có thể được chuyển sang trình duyệt. Sử dụng này sau khi vang

echo str_pad('',4096)."\n"; 

Toàn bộ mã:

<?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(); 
?> 
0

tôi đã nhận thấy rằng trình duyệt phản ứng khác nhau. Chrome, ví dụ, giữ cho đầu vào mãi mãi, và dường như không quan tâm đến việc hiển thị nó trước đó. Không ngạc nhiên, Firefox sẽ hiển thị đầu vào trước đó, nếu các mẹo ở trên (được đóng góp bởi các stackoverflowers khác) được áp dụng, vì vậy hãy thử với Firefox.

1

Chỉ muốn thêm vào câu trả lời của Roger.

Nếu bạn đang sử dụng FastCGI php5-fpm mô-đun trong vòng Apache2 bạn cũng phải chắc chắn rằng bạn đang thêm

-flush

luận trong cấu hình Apache2 của bạn, ví dụ:

<IfModule mod_fastcgi.c> 
... 
     FastCgiExternalServer /usr/lib/cgi-bin/php5-fcgi -flush -socket /tmp/php5-fpm.sock -idle-timeout 480 -pass-header Authorization 
</IfModule> 
0

Tôi chỉ có thể tuôn ra theo cách này - thêm 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(); 
0

Kiểm tra api máy chủ của bạn với

echo phpinfo(); 

Nếu bạn tìm thấy máy chủ api của bạn

Server API : CGI/FastCGI 

trong CentOS sau đó thêm dòng này trong "/etc/httpd/conf.d/fcgid .conf "

OutputBufferSize 0 

Để kiểm tra, khởi động lại Apache se rver và thử bên dưới mã

ob_start(); 
for($i = 0; $i < 10; $i ++) { 
    echo $i; 
    echo '<br />'; 
    flush(); 
    ob_flush(); 
    sleep(1); 
} 
0
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(); 
+0

Bạn có thể vui lòng xây dựng trên mã này không và cách này trả lời câu hỏi? Cảm ơn. – iehrlich

Các vấn đề liên quan