PHP: Буферизация вывода
Индекс материала |
---|
PHP: Буферизация вывода |
Повторное использование буферов |
Чтение буферов вывода |
Сжатие выходных данных |
Все страницы |
Буферизация вывода в PHP это довольно полезная штука, если уметь ею пользоваться. Скажите сколько раз вы видели ошибки типа:
Warning: Cannot modify header information - headers already sent by (output started at ...)
Как правило подобное случается, если вы хотите отправить куки, или выполнить операции, которые способствуют их отправке, или иные операции способствующие отправке заголовков, например запуск сессии или применение функции header или подобных. Или ваш файл в кодировке юникод и в самом его начале притаилась BOM - метка порядка байтов. Это подлющая штука есть неразрывный пробел с нулевой шириной. Смотрим под заголовком "Порядок байтов".
Всё очень просто: По - умолчанию никакой буферизации вывода нет ( если, конечно вы не нашаманили в файле php.ini и не присвоили директиве output_buffering значение On ) и PHP отсылает данные юзеру, сразу, как только они готовы. Согласно протоколу HTTP, сервер в ответ на запрос пользователя, должен сначала отправить ему служебные заголовки, а уже после, тело страницы. А тут внезапно, в коде вы опять пытаетесь заставить его отправить HTTP - заголовки, вызывая, скажем функцию session_start() - после удачной авторизации... Ясен пень - повторная отправка заголовков запрещена, HTTP - протокол так не работает! Но что ж делать то? Если после вывода на странице, нужно ещё и сессию стартануть и кУку поставить? - Вспоминаем про буферизацию вывода.
Возможности при буферизации
Используя буферизацию вывода мы можем:
- Посылать cookie из любого места в скрипте.
- Стартовать сессию в любой момент.
- Сжимать данные, перед отправкой их пользователю.
Сжатие дополнительно нагружает процессор, тем не менее объем трафика на одну страницу уменьшится примерно процентов на сорок, а это значит, что сервер потратит меньше времени на пересылку данных по сети. Величина сжатия зависит от многих факторов, например картинки сжимаются хуже чем текст.
Что происходит при буферизации?
При буферизации вывода, механизм PHP складывает в стопку весь вывод скрипта, паралельно формируя пакет HTTP - заголовков, в том числе, добавляя туда и заголовки "cookie" и любые другие, которые получатся в результате работы вашего скрипта. А потом, когда скрипт отработал он берёт и отправляет всё это клиенту в правильном порядке: сначала заголовки, а потом страницу - результат работы скрипта.
Как включить буферизацию вывода?
Первый способ это если сервак ваш, или у вас просто есть доступ к файлу php.ini ( как я писал выше ) ищем в нём директиву output_buffering и присваиваем ей значение On. Это включит буферизацию для всех скриптов.
Второй способ это использовать функцию ob_start() в скрипте, вывод которого нам нужно буферизовать. Этот способ предпочтительней - вы получите большую гибкость/контроль в работе, а так же лучшую переносимость.
На мой взгляд довольно удобно рассматривать буферизацию вывода, в виде неких контейнеров - буферов. Так проще понять их работу.
Итак, открыть такой контейнер - буфер можно лишь одной функцией ob_start(), а вот закрыть этот самый буфер можно двумя функциями: ob_end_flush() и ob_end_clean()
- ob_end_flush()
Закрывает буфер и отправляет данные.
- ob_end_clean()
Закрывает буфер без отправки данных.
Все содержимое, которое выводиться в тот момент, когда буфер открыт попадает в буфер и никуда не отсылается. Например:
ob_start(); echo '<p>первый буфер </p>'; ob_end_flush(); ob_start(); echo '<p>второй буфер </p>'; ob_end_сlean(); ob_start(); echo '<p>третий буфер </p>';
Этот скрипт выведет результат:
<p>первый буфер </p> <p>третий буфер </p>
Разберемся что произошло. Мы создали три буфера. Строки 1-3 - это первый. Он закрыт функцией ob_end_flush() - его вывод мы можем наблюдать в результате.
Второй буфер - это строки 5-7. Он закрыт с помощью функции ob_end_clean() - поэтому его вывод пропал безследно.
И третий буфер - это строки 9-10. Он у нас не закрыт никак! - Шозанах? - спросите вы ..? Всё просто - по окончанию сценария, PHP автоматом закрывает все буферы так, как будто они были закрыты функцией ob_end_flush().
Информация копипастерам
Внимание! Копирование контента с сайта, возможно только с разрешения администратора. Т.е. Меня! Я скорее всего разрешу Вам это сделать, в обмен на живую ссылку, на статью оригинал.