Intereting Posts
Как отправить октет / поток типа BLOB типа на сервер с помощью AJAX? дезинфицирующее средство для строки для имени файла Как искать значение из ввода mysqli в базе данных PHP: как кодировать бесконечности или числа NaN для JSON? Временные метки Laravel для отображения миллисекунд test, если массив содержит значение, используя PHPUnit Разметка страницы, чтобы показать максимальное значение и ограничить остальные Python эквивалент запроса PHP curl Как получить код для проверки правильности комбинации имени пользователя и пароля? Недопустимый номер параметра: количество связанных переменных не совпадает с числом токенов в Доктрине Отключение SMTP-сервера PHPMailer GoDaddy Изменить язык по ссылке Laravel Mail отправляет электронную почту, но возвращает false Каков надлежащий способ использования, включая скобки или без скобок в php Websocket – клиент не получает данные

Как отключить буферизацию вывода в 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.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); 

Версия tl; dr

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

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

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

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

         php_flag "output_buffering" Off 
    • или просто для сценария, о котором вы заботитесь, либо …

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

    • вызов 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 в Off в файле php.ini (или используя

 php_flag "output_buffering" Off 

в вашем Apache config, если вы используете 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 (), чтобы очистить выходные выходные буферы, если вы их используете.

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

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

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

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

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

 php_flag "output_buffering" off 

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

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

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

 if (ob_get_level()) ob_end_clean(); 

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