Подтвердить что ты не робот

Как отключить буферизацию вывода в PHP

Я написал простое реле script, которое подключается к веб-камере и считывает из сокета и выводит эти данные с помощью функции печати. Данные представляют собой данные 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.0\r\n\r\n");

//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);
4b9b3361

Ответ 1

tl; dr версия

Сделайте две вещи:

  • Отключите буфер вывода пользовательского пространства, либо...

    • В глобальном масштабе, либо...

      • Отключение output_buffering в вашем php.ini или
      • Отключение output_buffering в вашей конфигурации Apache с помощью

        php_flag "output_buffering" Off
        
    • или только для script, о котором вы заботитесь, либо...

      • вызов ob_end_flush() или
      • вызов ob_end_clean()
  • Также отключите буфер вывода на уровне сервера как можно больше:

    • вызов ob_implicit_flush() в начале вашего script или
    • вызов flush() после каждого оператора echo или другого оператора, который добавляет вывод в тело ответа

Более длинная версия

Смутно, есть два уровня буферизации, которые могут быть релевантными, и документация по PHP плохо справляется с различием между ними.

Выходной буфер

Первый уровень обычно упоминается документами PHP как "выходной буфер". Этот уровень буферизации влияет только на вывод в тело ответа HTTP, а не на заголовки. Вы можете включить буферизацию вывода с помощью ob_start() и отключить ее с помощью ob_end_flush() или ob_end_clean(). Вы также можете запустить все свои сценарии с буферизацией вывода с использованием параметра output_buffering в php.ini.

Значение по умолчанию для производственных версий php.ini составляет 4096, что означает, что первые 4096 байтов вывода будут буферизованы в выходном буфере, после чего он будет сброшен, а выходная буферизация отключена.

Вы можете отключить этот уровень буферизации глобально, установив output_buffering в Off в ваш файл php.ini(или используя

php_flag "output_buffering" Off

в вашей конфигурации Apache, если вы используете Apache). Кроме того, вы можете отключить его для одного script, вызывая ob_end_clean() или ob_end_flush() в начале script.

Буфер записи и буфер веб-сервера

Помимо выходного буфера, это то, что руководство PHP называет как "буфер записи", плюс любая система буферизации, которую имеет ваш веб-сервер. Если вы используете PHP с Apache через mod_php и не используете mod_gzip, вы можете вызвать flush(), чтобы очистить их; с другими бэкендами, это тоже может сработать, хотя руководство сдержанно дает заверения:

Описание

void flush ( void )

Сбрасывает буферы записи PHP и любые внутренние ресурсы PHP (CGI, веб-сервер и т.д.). Это пытается вытолкнуть текущий вывод полностью в браузер с несколькими оговорками.

flush(), возможно, не сможет переопределить схему буферизации вашего веб-сервера и не влияет на буферизацию на стороне клиента в браузере. Он также не влияет на механизм буферизации вывода пользовательского пространства PHP. Это означает, что вам нужно будет вызвать ob_flush() и flush(), чтобы очистить выходные выходные буферы, если вы используя их.

Существует также несколько способов, с помощью которых PHP может автоматически вызывать flush() каждый раз, когда вы echo что-либо (или делать что-либо еще, что выводит результат на тело ответа).

Первое - вызвать ob_implicit_flush(). Обратите внимание, что эта функция обманчиво названа; учитывая его префикс ob_, любой разумный человек ожидал бы, что он повлияет на "выходной буфер", как и на ob_start, ob_flush и т.д. Однако это не так; ob_implicit_flush(), как и flush(), влияет на выходной буфер на уровне сервера и никак не взаимодействует с выходным буфером, управляемым другими функциями ob_.

Второй - глобально включить неявную промывку, установив флаг implicit_flush в On в php.ini. Это эквивалентно вызову ob_implicit_flush() в начале каждого script. Обратите внимание, что руководство советует против этого, критически ссылаясь на "серьезные последствия для производительности", некоторые из которых я рассматриваю в этом касательном ответе.

Ответ 2

Вместо отключения буферизации вывода вы можете просто вызвать flush() после каждой операции чтения. Это позволяет избежать проблем с конфигурацией сервера и сделать ваш script более портативным.

Ответ 3

Буферизация вывода может быть многоуровневой, и у меня были случаи, когда более ранний код делал несколько уровней. Это очистит их всех.

while (ob_get_level()) ob_end_clean(); 
// or ob_end_flush() if you want the contents of the buffer.

Ответ 4

Мы можем предоставить приведенный ниже код в файле .htaccess для отключения буферизации вывода в PHP

php_flag "output_buffering" off

Ответ 5

Я знаю, что этот вопрос немного устарел, но, вернувшись к этому вопросу, вы можете отключить буферизацию вывода на основе script до script, например:

if (ob_get_level())
   ob_end_clean();

Это должно отключить всю буферизацию вывода для любого script, следующего за ней.