2012-01-23 30 views
6

Có thể đóng luồng đầu ra của tập lệnh PHP không? Tôi có một kịch bản mà cần phải làm một số xử lý bài, nhưng trong và sau khi xử lý bài nó sẽ không gửi bất kỳ dữ liệu cho khách hàng nữa, vì vậy tôi muốn đóng kết nối trước khi xử lý bài.PHP: luồng đầu ra gần

Chỉnh sửa: Trong ứng dụng của tôi, tôi có bộ nhớ cache cần phải được xây dựng lại sau đó. Tuy nhiên, tôi không muốn làm chậm người dùng. Những gì tôi muốn là để xác định ở phần cuối của kịch bản nếu bộ nhớ cache cần phải được xây dựng lại. Vì vậy, tôi muốn đóng luồng đầu ra trước tiên, vì vậy người dùng nhận dữ liệu của nó và sau đó tôi muốn xây dựng lại bộ nhớ cache. Nó không phải là thực sự quan trọng để làm điều này, nhưng tôi nghĩ rằng nó tốt hơn để đóng kết nối đầu tiên, do đó, người dùng sẽ không nhận thấy rằng bộ nhớ cache đang được xây dựng lại nếu phải mất một thời gian dài.

+0

Tại sao bạn cần phải làm điều này? Bạn có thể đăng một chút mã của mình để giúp chúng tôi hiểu thêm một chút không? –

+0

+1 theo những gì Jonathan nói. Hãy cho chúng tôi biết thêm một chút về lý do bạn muốn thực hiện điều này. –

Trả lời

4

CẬP NHẬT

Cách để xử lý trường hợp này là sự kết hợp của bộ đệm đầu ra và các tiêu đề HTTP thích hợp.

Từ HTTP/1.1 Specification Section 14.10:

HTTP/1.1 định nghĩa "gần" tùy chọn kết nối cho người gửi để dấu hiệu cho thấy kết nối sẽ được đóng lại sau khi kết thúc phản ứng .

Vì vậy, nếu chúng ta vượt qua cùng một HTTP Content-Length tiêu đề, thêm vào kết nối: gần, trình duyệt biết để đóng kết nối sau khi chiều dài đáp ứng quy định được nhận:

  1. Đệm tất cả đầu ra tập lệnh để bạn duy trì khả năng gửi tiêu đề
  2. Khi bạn có dữ liệu đầu ra đầy đủ, hãy gửi tiêu đề thích hợp cho ứng dụng khách
  3. Tiếp tục r xử lý ... nhưng không cố gắng gửi đầu ra hoặc bạn sẽ nhận được lỗi vì tiêu đề đã được gửi.

Ngoài ra, hãy cẩn thận vì bạn có thể chạy lên chống lại giới hạn thời gian thực thi tập lệnh trong máy chủ web SAPI nếu bạn xử lý quá nhiều. Cuối cùng, bạn nên yêu cầu PHP bỏ qua "người dùng hủy bỏ" trong tập lệnh cụ thể này bằng cách sử dụng ignore_user_abort() vì trình duyệt sẽ đóng kết nối do kết quả của những gì bạn đang làm và bạn muốn PHP tiếp tục xử lý.

<?php 
ignore_user_abort(); 
ob_start(); 

// do stuff, generate output 

// get size of the content 
$length = ob_get_length(); 

// tell client to close the connection after $length bytes received 
header('Connection: close'); 
header("Content-Length: $length"); 

// flush all output 
ob_end_flush(); 
ob_flush(); 
flush(); 

// close session if you have one ... 
// continue your processing tasks ... 
?> 

Bạn có thể kiểm tra hướng dẫn phần PHP trên Connection handlingdocs.

Hoặc, tại sao không bắt đầu lưu vào bộ đệm đầu ra? Sau đó, bạn có thể nắm bắt tất cả các đầu ra sẽ được gửi sau đó quyết định sau này nếu bạn thực sự muốn làm bất cứ điều gì với nó.

<?php 

echo 'before output buffering'; 
ob_start(); 
echo 'after output buffering'; 
$output = ob_get_contents(); 

// script's only output to this point will be 'before output buffering' 

// I changed my mind, send the output ... 
ob_end_flush(); 
?> 
+0

Đệm đầu ra vẫn giữ luồng đầu ra cho trình duyệt mở. Vì vậy, giả sử tôi cần phải thực hiện một số xử lý bài đăng mất vài giây hoặc lâu hơn, trình duyệt sẽ đợi cho đến khi quá trình xử lý bài đăng xong. Đặc biệt với AJAX, điều này sẽ làm chậm ứng dụng web rất nhiều. Vì vậy, tôi muốn có thể đóng kết nối với trình duyệt, vì vậy trình duyệt có thể xử lý đầu ra và sau đó tiếp tục xử lý bài đăng. – Tiddo

+0

@Tiddo Tôi đã cập nhật câu trả lời của mình với (những gì tôi tin là) giải pháp đúng. – rdlowrey

+0

Đó là một giải pháp khá hay! Tôi sẽ thử điều đó sau một phút. Chỉnh sửa: Nó hoạt động tuyệt vời! Cảm ơn rất nhiều! – Tiddo

0

tôi không có đủ uy tín để bình luận, nhưng tôi muốn chia sẻ rằng trong câu trả lời @rdlowrey gzip có thể là một vấn đề.

Nếu bạn có gzip kích hoạt các Chuyển mã hóa tiêu đề luôn được thiết lập để chunked, ngay cả khi bạn cố gắng thay đổi nó với header("Transfer-encoding: none"); do đó nó sẽ không gửi Content-Length tiêu đề.

Con đường tôi có thể giải quyết này đã được sử dụng tiếp theo trước:

<? 
@ini_set('zlib.output_compression', 'Off'); 
@ini_set('output_buffering', 'Off'); 
@ini_set('output_handler', ''); 
@apache_setenv('no-gzip', 1); 
?> 

Và sau đó là giải pháp:

<? 
ignore_user_abort(); 
ob_start(); 

// do stuff, generate output 

// get size of the content 
$length = ob_get_length(); 

// tell client to close the connection after $length bytes received 
header('Connection: close'); 
header("Content-Length: $length"); 

// flush all output 
ob_end_flush(); 
flush(); 

// close session if you have one ... 
// continue your processing tasks ... 
?> 
Các vấn đề liên quan