2013-02-22 33 views
6

Tôi có một tập lệnh PHP gửi một số lượng lớn các bản ghi và tôi muốn xóa từng bản ghi ngay khi có sẵn: khách hàng có thể xử lý từng bản ghi khi nó đến, nó không cần đợi toàn bộ câu trả lời. Tôi nhận thấy nó mất nhiều thời gian hơn cho toàn bộ quá trình chuyển vì nó cần được gửi trong nhiều gói, nhưng nó vẫn cho phép máy khách bắt đầu hoạt động sớm hơn.Ngăn chặn đệm đầu ra bằng PHP và Apache

Tôi đã thử tất cả các chức năng khác nhau của flush()ob_flush() nhưng dường như không có dữ liệu nào thực sự được gửi qua dòng trước khi trang được hoàn tất. Tôi đã xác nhận rằng nó không phải là trình duyệt web bởi vì tôi đã thử nghiệm nó bằng cách sử dụng telnet.

Trả lời

4

Giải pháp duy nhất có hiệu quả đối với tôi là đặt chỉ thị output_buffering trong php.ini thành "Tắt". Tôi không muốn làm điều này cho toàn bộ máy chủ, chỉ là một tài nguyên cụ thể này. Thông thường, bạn có thể sử dụng ini_set từ tập lệnh PHP, nhưng vì bất kỳ lý do gì php không cho phép output_buffering được đặt theo cách này (xem the php manual).

Hóa ra là nếu bạn đang sử dụng Apache, bạn có thể đặt một số chỉ thị php ini (bao gồm output_buffering) từ cấu hình máy chủ của bạn, bao gồm tệp .htaccess. Vì vậy, tôi đã sử dụng sau đây trong một tập tin .htaccess để vô hiệu hóa output_buffering chỉ cho rằng một tập tin:

<Files "q.php"> 
    php_value output_buffering Off 
</Files> 

Và sau đó trong cấu hình máy chủ tĩnh của tôi, tôi chỉ cần AllowOverride Options=php_value (hoặc một cái búa lớn, như AllowOverride All) theo thứ tự để được phép trong tệp .htaccess.

+1

Không chắc chắn nếu điều này luôn luôn sai hoặc một cái gì đó đã thay đổi trong PHP5.6, nhưng tôi đã phải sử dụng 'php_flag output_buffering Off' để có được' Off' để làm việc. – RiggsFolly

+0

Tôi đặt "output_buffering" từ php.ini từ 4096 thành Tắt và khởi động lại toàn bộ máy chủ, được xác minh bằng phpinfo(); nhưng tôi vẫn phải đối mặt với cùng một vấn đề, máy chủ đang chờ tải trang trước khi gửi dữ liệu đến trình duyệt. Có một cài đặt khác trong Apache2 hoặc Ubuntu 16.04 không? Tôi đang sử dụng PHP7. – Tarik

3

Bạn không đề cập đến máy chủ web bạn đang sử dụng, nhưng tôi sẽ đi ra ngoài một chi ở đây và đoán Apache2. Tôi đánh gần như điều bạn mô tả. Tôi đã cố gắng để có được kịch bản cgi của tôi để trả lại thông tin vì nó đã sẵn sàng, thay vì đệm toàn bộ điều. Làm việc lộng lẫy trong curl, vv, nhưng đệm trong một trình duyệt (khá nhiều bất kỳ trình duyệt), mà ít nhất là buồn bã. Tôi đã đi qua các bước chính xác mà bạn mô tả. Độ phân giải trong trường hợp của tôi là để sửa đổi sites-enabled/terrifico.com tập tin cấu hình trong Apache2 (dòng trong câu hỏi bắt đầu với

SetEnvIfNoCase

(Bạn có thể bỏ qua những thứ trên và dưới dòng đó, tôi chỉ thấy để tiện tham khảo về nơi tôi đặt nó.)

<VirtualHost *:80> 
ServerAdmin [email protected] 
ServerName test.terrifico.com 
ServerAlias test.terrifico.com 

SetEnvIfNoCase Request_URI \.cgi$ no-gzip dont-vary 

DocumentRoot /var/www/test.terrifico.com 

Từ nhìn chằm chằm vào lưu lượng mạng đi tới đi lui, cuối cùng cũng hiểu ra nguyên với tôi rằng trình duyệt đã được quảng cáo rằng nó chấp nhận giảm phát cho bất cứ điều gì (đó là văn bản). Đó là sự khác biệt giữa trình duyệt và curl, ví dụ. Bit nổi bật là

Accept-Encoding: gzip, deflate, sdch

Có một chút thông tin về chunking, nhưng điều đó không ảnh hưởng đến vấn đề cụ thể này. Vì vậy, trình duyệt đã yêu cầu mod_deflate để khởi động, điều này đã đánh bại các byte của tôi một cách cẩn thận khi tôi nhận được chúng trong tập lệnh cgi của tôi. Bạn có thể thay đổi nó trong trình duyệt, nhưng nó có vẻ hợp lý hơn để thay đổi nó trên máy chủ một lần cho các tác phẩm.

Có lẽ điều này sẽ hữu ích.

2

Để tắt bộ đệm đầu ra tại thời gian chạy trong PHP mà không thay đổi php.ini hoặc có tệp .htaccess, chỉ cần sử dụng ob_end_flush() hoặc ob_end_clean() ở đầu tập lệnh. Ví dụ:

này nên đầu ra mà không có đệm:

<?php 
ob_end_clean(); 

for ($i = 0; $i < 5; $i++) 
{ 
    echo "$i\n"; 
    flush(); 
    usleep(0.5e6); 
} 

này kết quả đầu ra với đệm (tất cả cùng một thời điểm) nếu output_buffering được bật, không phụ thuộc vào flush() gọi:

<?php 

for ($i = 0; $i < 5; $i++) 
{ 
    echo "$i\n"; 
    flush(); 
    usleep(0.5e6); 
} 

Mặc dù nó tên, ob_implicit_flush gọi flush(), không phải ob_flush(), ngầm sau mỗi lần xuất. Điều này có thể hữu ích trong trường hợp này sau khi đóng bộ đệm đầu ra ở đầu:

<?php 
ob_end_clean(); // disable output buffer 
ob_implicit_flush(); // call flush() automatically after every output 

for ($i = 0; $i < 5; $i++) 
{ 
    echo "$i\n"; 
    usleep(0.5e6); 
} 

Điều này sửa lỗi phía PHP. Có thể có một cái gì đó khác đang xảy ra với mod_deflate hoặc tương tự (xem câu trả lời của Ted Collins), và tôi đã quan sát thấy rằng Firefox cần ít nhất 1024 byte trước khi nó bắt đầu xuất ra bất cứ điều gì cả.

+0

Mã này không gấp 3 lần cùng một.- –

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