Как отключить буферизацию вывода в PHP
Я написал простое реле скрипт, который подключается к веб-камере и читает из сокета и выводит эти данные с помощью функции печати. Данные-это данные MJPG с уже установленными границами. Я просто выводил данные, которые считывались.
проблема в том, что PHP, похоже, буферизует эти данные. Когда я установлю камеру на 1 FPS, подача замерзнет на 7-8 секунд, а затем быстро отобразит 8 кадров. Если я установлю разрешение на огромный размер, камера будет двигаться со скоростью более или менее 1 кадр в секунду. Я предполагаю, что происходит некоторая буферизация (поскольку огромные размеры быстро заполняют буфер, а низкие размеры-нет), и я не могу понять, как отключить эту буферизацию. Кто-нибудь знает как?
код:
ignore_user_abort(false);
$boundary = "myboundary";
//Set this so PHP doesn't timeout during a long stream
set_time_limit(0);
$socketConn = @fsockopen ("192.168.1.6", 1989, $errno, $errstr, 2);
if (!$socketConn)
exit();
stream_set_timeout($socketConn, 10);
fputs ($socketConn, "GET /mjpeg HTTP/1.0rnrn");
//Setup Header Information
header("Cache-Control: no-cache");
header("Cache-Control: private");
header("Pragma: no-cache");
header("Content-type: multipart/x-mixed-replace; boundary=$boundary");
@ini_set('implicit_flush', 1);
for ($i = 0; $i < ob_get_level(); $i++)
ob_end_flush();
ob_implicit_flush(1);
stream_set_blocking($f2, false);
//Send data to client
while (connection_status() == CONNECTION_NORMAL)
{
$chunk = fread($socketConn, 128);
print $chunk;
}
fclose($socketConn);
5 ответов
tl; dr version
сделать две вещи:
-
отключите выходной буфер пользовательского пространства...
-
глобально, либо...
- выключить
output_buffering
в вашем php.Ини, или -
выключить
output_buffering
в конфигурации Apache с помощьюphp_flag "output_buffering" Off
- выключить
-
или только для сценария, о котором вы заботитесь, любой...
- вызов
ob_end_flush()
или - вызов
ob_end_clean()
- вызов
-
-
кроме того, отключите выходной буфер уровня сервера столько, сколько сможете, либо:
- вызов
ob_implicit_flush()
в начале вашего скрипта, или - вызов
flush()
послеecho
оператор или другой оператор, который добавляет вывод в ответ тело
- вызов
версия
запутанно, есть два уровня буферизации, которые могут быть релевантными, и документация PHP делает плохую работу по различению между ними.
выходной буфер
первый слой обычно упоминается в документах PHP как "выходной буфер". Этот уровень буферизации влияет только на вывод в тело ответа HTTP, а не заголовков. Вы можете включить буферизация вывода с помощью ob_start()
, и выключите его с ob_end_flush()
или ob_end_clean()
. Вы также можете автоматически запускать все ваши скрипты с буферизацией вывода при использовании output_buffering
опция в php.ini.
значение по умолчанию этой опции для производственные версии php.ini равно 4096, что означает, что первые 4096 байт вывода будут буферизованы в выходном буфере, и в этот момент он будет покраснел и буферизация вывода выключено.
вы можете отключить этот уровень буферизации глобально, установив output_buffering
to Off
в вашем php.ini-файл (или с помощью
php_flag "output_buffering" Off
в конфигурации Apache, если вы используете Apache). Кроме того, вы можете отключить его для одного скрипта, вызвав ob_end_clean()
или ob_end_flush()
в начале скрипта.
буфер записи и буфер веб-сервера
за пределами выходного буфера находится руководство PHP относится к "буферу записи", а также к любой системе буферизации вашего веб-сервера. Если вы используете PHP с Apache через mod_php
, а не с помощью mod_gzip
можно назвать flush()
чтобы смыть их; с другими бэкэндами это тоже может сработать, хотя руководство уклончиво дает гарантии:
описание
void flush ( void )
сбрасывает буферы записи PHP и все, что использует бэкэнд PHP (CGI, веб-сервер и т. д.). Это попытки нажмите текущий выход полностью в браузер с несколькими предостережениями.
flush () возможно, не удастся переопределить схему буферизации вашего веб-сервера, и это не влияет на буферизацию на стороне клиента в браузере. Это также не влияет на механизм буферизации вывода пользовательского пространства PHP. Это означает, что вам придется назвать как помощью ob_flush() и flush () для очистки выходных буферов ob, если вы используете те.
есть также несколько способов, которыми вы можете сделать PHP автоматически вызывать flush()
каждый раз, когда вы echo
что-нибудь (или сделайте что-нибудь еще, что Эхо выводит в тело ответа).
первое-позвонить ob_implicit_flush()
. Обратите внимание, что эта функция обманчиво названа; учитывая ее ob_
префикс, любой разумный человек ожидал бы, что это повлияет на "выходной буфер", как и ob_start
, ob_flush
etc. Однако это не так.; ob_implicit_flush()
, как flush()
, влияет на выходной буфер уровня сервера и никак не взаимодействует с выходным буфером, управляемым другим ob_
функции.
второй-глобально включить неявную промывку, установив implicit_flush
флаг On
в вашем php.ini. Это эквивалентно вызову ob_implicit_flush()
в начале каждого скрипта. Обратите внимание, что руководство советует против этого, загадочно цитируя "серьезные последствия для производительности", некоторые из которых я исследую в этом тангенциально связанный ответ.
вместо отключения буферизации вывода вы можете просто вызвать flush()
после каждой операции чтения. Это позволяет избежать возни с конфигурацией сервера и делает ваш скрипт более портируемым.
буферизация вывода может быть многоуровневой, и у меня были случаи, когда более ранний код сделал несколько уровней. Это очистит их всех.
while (ob_get_level()) ob_end_clean();
// or ob_end_flush() if you want the contents of the buffer.
мы можем дать приведенный ниже код в.файл htaccess для отключения буферизации вывода в PHP
php_flag "output_buffering" off
Я знаю, что этот вопрос немного устарел, но, возвращаясь к этому вопросу, вы можете отключить буферизацию вывода на основе сценария к сценарию, например:
if (ob_get_level())
ob_end_clean();
Это должно выключить буферизацию вывода для любого сценария, который следует за ним.