PHP: закрыть поток вывода - PullRequest
       7

PHP: закрыть поток вывода

6 голосов
/ 24 января 2012

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

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

Ответы [ 3 ]

5 голосов
/ 24 января 2012

UPDATE

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

Из раздела спецификации HTTP / 1.1 14.10 :

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

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

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

Кроме того, будьте осторожны, так как вы можете столкнуться с ограничениями по времени выполнения скрипта на веб-сервере 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 по Обработка соединений docs .

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

<?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 голосов
/ 03 июня 2015

У меня недостаточно репутации, чтобы комментировать, но я хочу поделиться, что в ответе @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 ...
?>
0 голосов
/ 24 января 2012
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...