2012-01-23 3 views
6

Можно ли закрыть выходной поток скрипта PHP? У меня есть сценарий, который должен выполнять некоторую пост-обработку, но во время и после последующей обработки он больше не будет отправлять какие-либо данные клиенту, поэтому я хотел бы закрыть соединение до обработки сообщения.PHP: закрыть выходной поток

Редактировать: В моем приложении у меня есть кеш, который нужно перестраивать время от времени. Однако я не хочу замедлять пользователя. То, что я хочу, - это определить в конце скрипта, если кеш нужно перестроить. Поэтому я хочу сначала закрыть выходной поток, поэтому пользователь получает его данные, а затем я хочу восстановить кеш. На самом деле это не так важно, но я думаю, что лучше сначала закрыть соединение, поэтому пользователь не заметит, что кеш перестраивается, если это занимает много времени.

+0

Почему вы должны сделать это? Можете ли вы опубликовать немного своего кода, чтобы помочь нам понять немного больше? –

+0

+1 к тому, что сказал Джонатан. Расскажите нам немного больше о том, почему вы хотите это сделать. –

ответ

4

ОБНОВЛЕНИЕ

Способ обрабатывать этот случай является комбинацией буферизации вывода и соответствующих заголовков HTTP.

От HTTP/1.1 Specification Section 14.10:

HTTP/1.1 определяет «закрыть» вариант подключения для отправителя к сигнала о том, что соединение будет закрыто после завершения ответа.

Таким образом, если мы пройдем вдоль HTTP Content-Length заголовка в дополнение к Подключение: закрыть, браузер знает, чтобы закрыть соединение после указанной длины будет получен ответ:

  1. Буфер ВСЕ вывод скрипта, чтобы сохранить возможность отправки заголовков
  2. После того, как у вас есть полные выходные данные, отправьте соответствующие заголовки клиенту
  3. Продолжить r обработка ... но не пытайтесь отправить вывод или вы получите ошибки, потому что отправлены заголовки.

Также будьте осторожны, так как вы можете столкнуться с ограничениями времени выполнения скриптов в веб-сервере SAPI, если вы слишком много обрабатываете. Наконец, вы должны сказать PHP игнорировать «пользовательский прерывание» в этом конкретном скрипте, используя ignore_user_abort(), потому что браузер закроет соединение в результате того, что вы делаете, и вы хотите, чтобы PHP продолжал обрабатывать.

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

Вы можете изучить раздел руководства PHP на Connection handlingdocs.

В качестве альтернативы, почему бы не начать буферизацию вывода? Затем вы можете захватить весь вывод, который будет отправлен, а затем решить позже, если вы действительно хотите что-либо сделать с ним.

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

Буферизация вывода по-прежнему сохраняет выходной поток в браузере открытым. Поэтому предположим, что мне нужно сделать некоторую пост-обработку, которая занимает несколько секунд или около того, браузер будет ждать, пока эта пост-обработка не будет выполнена. Особенно с AJAX это значительно замедлит работу с web-приложениями. Поэтому я хочу иметь возможность закрыть соединение с браузером, чтобы браузер мог обрабатывать выходные данные, а затем продолжить обработку сообщений. – Tiddo

+0

@ Tiddo Я обновил свой ответ (верю, что это) правильное решение. – rdlowrey

+0

Это довольно приятное решение! Я собираюсь попробовать это через минуту. Редактировать: он отлично работает! Большое спасибо! – Tiddo

0

У меня не хватает репутации комментировать, но я хочу поделиться тем, что в @rdlowrey ответ GZIP может быть проблемой.

Если у вас есть GZIP позволило Transfer-Encoding заголовок всегда должен быть установлен на Chunked, даже если вы пытаетесь изменить его с header("Transfer-encoding: none"); поэтому он не будет посылать Content-Length заголовок.

Как я мог решить это с помощью следующего раньше:

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

и затем раствор:

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

 Смежные вопросы

  • Нет связанных вопросов^_^