Ob start php что это
Перейти к содержимому

Ob start php что это

  • автор:

Что такое буферизация вывода PHP?

Что такое буферизация вывода PHP? главное изображение

Буферизация вывода — одна из тех концепций в PHP, с которой достаточно часто сталкиваются разработчики, но мало кто задумывается, как она устроена. В статье рассказываем о том, что это за концепция в PHP и зачем ее использовать.

  • PHP буферизация вывода: что это
  • Какие есть функции для работы буферизации вывода PHP
  • Зачем использовать буферизацию PHP
  • Итог

Эта статья — адаптированный перевод материала разработчицы Лары Шенк, опубликованного в ее личном блоге. Повествование ведется от лица автора.

PHP буферизация вывода: что это

Буферизация вывода в PHP — это способ указать, что нужно отдельно сохранить данные перед их отправкой в браузер. То есть данные можно получить, а затем поместить в переменную, работать с ними и уже позже отправлять в браузер.

Как-то раз мне на почту пришел вопрос про плагин Timber — я люблю использовать его при разработке сайтов на WordPress. У меня спросили: «Что делает header.php и footer.php в плагине Timber?». Быстрый ответ на этот вопрос: «Они ничего не делают», потому что они нужны для работы определенных плагинов в WordPress.

Однако я этого не знала, потому что мне никогда не приходилось взаимодействовать с этими файлами во время разработки. Мне стало интересно, и я начала исследовать, из чего состоят эти файлы. Оказалось, что в основном в них находятся функции буферизации PHP ( ob_start , ob_get_contents ).

Давайте представим диалог разработчика с языком программирования PHP (если бы с ним можно было просто поговорить):

Другими словами, PHP отправляет данные в браузер с сервера, как только функция завершается. Например, если вы пишете код: echo «Hi there»; для получения строки «Привет!», она отправляется браузеру сразу после запуска функции с echo .

Однако, если вы запустите функцию echo , когда действует буферизация вывода, сообщение «Привет» будет сохранено в этой невидимой удерживающей ячейке, которая и называется буфером. И она не будет отображаться на странице, пока вы не получите ее содержимое и не отправите его в браузер.

Станьте профессиональным PHP-разработчиком с нуля за 10 месяцев На Хекслете есть профессия «PHP-разработчик». Пройдите ее, чтобы изучить один из самых известных языков программирования, освоить популярные фреймворки и создать большое портфолио с проектами на GitHub.

Какие есть функции для работы буферизации вывода PHP

Существует несколько основных функций для работы буферизации вывода php:

ob_start() запускает буферизацию вывода. Другими словами, она создает буфер (невидимую ячейку), в которой будет храниться весь вывод после ее вызова.

ob_get_contents() собирает все данные, которые находятся в буфере после выполнения команды ob_start . Обычно с помощью этой функции данные из буфера присваивают переменной.

ob_clean() удаляет все из буфера. Обратите внимание, что она ничего не выводит — просто очищает буфер.

ob_flush() выводит содержимое из буфера. Обратите внимание, что она не очищает буфер.

ob_end_clean() очищает буфер и отключает буферизацию вывода.

ob_end_flush() выводит содержимое из буфера и завершает буферизацию вывода. Буфер не стирается.

Самое важное в использовании функций буферизации вывода — это то, где вы их размещаете. Вам нужно запустить буфер с помощью ob_start в нужном месте, и вывести буфер либо на страницу, либо в переменную, прежде чем вы его очистите.

Зачем использовать буферизацию PHP

Возможно вы никогда не будете ее использовать и захотите буферизацию вывода отключить, особенно если вы не являетесь разработчиком плагинов WordPress или не пишете собственные приложения PHP. Для тех, кто не делает ни того, ни другого, я приведу несколько примеров, когда эта концепция все-таки может пригодиться.

Вы когда-нибудь видели такую ошибку?

Warning: Cannot modify header information  headers already sent by (output started at /some/file.php:12) in /some/file.php on line 23 

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

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

И еще один пример: предположим, ваше приложение сохраняет данные для входа пользователя в файлы cookie — в специальный тип HTTP-заголовка. Эти данные должны отправляться в браузер раньше любых других данных сайта или приложения. При этом, в зависимости от того, как устроена ваша программа, код cookie не обязан находиться в самом начале файла.

И тут как раз вступает в действие буферизация вывода, которая позволяет сказать: «Привет, PHP! Я скажу, когда нужно отправить вывод сайта после того, как будут обработаны cookie-файлы». В ином случае вы просто столкнетесь с ошибкой, про которую я писала чуть выше.

Обратите внимание, что появление этой ошибки может указывать и на использование плохих практик написания кода с точки зрения структуры вашего приложения. Например, такая ошибка может выпадать из-за конфликтов с другими плагинами.

Итог

При использовании плагинов или фреймворков мы постоянно встречаемся с кодом, про который вообще ничего не знаем — как он работает и даже для чего нужен. Мы просто знаем, как его использовать, и делаем это. Однако иногда все-таки нужно понять, что это за код и зачем он вообще нужен. В случае с буферизацией вывода PHP все точно так же. Сохраните себе эту статью, чтобы вернуться к материалу, если возникнут трудности с буферизацией.

Использование ob_start при поддержке проектов на php

Сегодня я бы хотел познакомить начинающих вебмастеров с разнообразными изящными способами использования буферизации вывода в php. Опытные вебмастера для себя здесь врят ли найдут что-то полезное. Хотя — кто знает?

Как вы все знаете, буферизацией вывода в php управляет набор функций, начинающихся на «ob_». Самая главная из них — ob_start. При запуске она собирает последующий вывод, то есть всевозможные print(), echo и прочее, что потом отдастся посетителю в форме html-странички. И если перед тем, как выводить, мы запустили буферизацию, то с этой, почти готовой уже, страничкой, можно будет напоследок что-нибудь сотворить.

Например, мы хотим отфильтровать все ссылки на посторонние сайты.

На нашем, древнем как топор австралопитека, форуме, роится великое множество спамеров, заманивающих посетителя в места, заполненные развратом, однорукими бандитами и политической агитацией. Можно было бы использовать js со слежением, но мы хотим вместо этого изменить все эти ссылки так:

Способ может быть и не самый эффективный, но действенный. Мы написали redirect.php с фильтром и черным листом, и теперь нам надо преобразовывать все ссылки на тысячах страниц форума. С помощью ob_start и парочки регулярных выражений мы сделаем это всего в несколько строк:

function f_callback($buffer)< $buffer = preg_replace('#http://(www.)?myoldforum\.ru/#','/',$buffer); $buffer = preg_replace('#href="http://([^"]*)"#','#href php">function generate_plugin() < /*что-то генерируем*/ >function f_callback($buffer)< /*. */ $buffer = str_replace ('',generate_plugin(),$buffer); /*. */ return $buffer; > ob_start('f_callback'); 

Теперь, там, где мы добавили в контент появится то, что мы хотели получить. Одно из применений — вставка виджета js на страницу сайта. Например, яндекс-карты. Обычно это не составляет никакого труда, но иногда криво написанный редактор страниц сайта экранирует кавычки и фигурные скобки, ломая виджет. Как видим, эта проблема легко решается.

Набор инструментов php для работы с буффером вывода богат, и не ограничивается одним лишь ob_start. Вышеописанные приемы в некоторых случаях излишне ресурсоемки и громоздки, поскольку оперируют со всей страницей. Мы можем обработать только ее часть, создав в шаблоне оболочку вокруг генерации чего-то, в дебри чего нам не хочется лезть, но что обязательно нужно поправить:

Должно быть, вы уже заметили все эти обороты: «не хочется лезть», «древний, как стул тиранозавра», «криво написанный редактор»… В идеальном мире оболочки вокруг буфера вывода не нужны. Все что можно сделать с помощью ob_start, теоретически можно было бы сделать и без него. Этот прием иной раз вносит путанницу в код проекта, многие видят его смысл лишь в том, что бы отдать вывод в ob_gzhandler для сжатия, и считают его применение в иных случаях опасным. Но часто без управления выводом просто не обойтись.

Особенно если не хочется копать вглубь.

Предопределённые константы

Перечисленные ниже константы всегда доступны как часть ядра PHP.

Флаги состояния, передаваемые обработчику вывода

Следующие флаги передаются как часть битовой маски во второй параметр ( phase ) обработчика вывода, установленного функцией ob_start() :

PHP_OUTPUT_HANDLER_START ( int )

Указывает, что буферизация вывода началась.

PHP_OUTPUT_HANDLER_WRITE ( int )

Указывает, что буфер вывода очищается и в нём есть данные для вывода.

PHP_OUTPUT_HANDLER_FLUSH ( int )

Означает, что буфер был сброшен (очищен и выведен).

PHP_OUTPUT_HANDLER_CLEAN ( int )

Означает, что буфер был очищен.

PHP_OUTPUT_HANDLER_FINAL ( int )

Означает, что это последняя операция буферизации.

PHP_OUTPUT_HANDLER_CONT ( int )

Означает, что буфер был очищен, но буферизация вывода будет продолжена.

Это синоним для PHP_OUTPUT_HANDLER_WRITE .

PHP_OUTPUT_HANDLER_END ( int )

Означает, что буферизация вывода завершена.

Это синоним для PHP_OUTPUT_HANDLER_FINAL .

Флаги управления буфером вывода

Следующие флаги передают в виде битовой маски в третий параметр ( flags ) обработчика вывода, установленного функцией ob_start() :

PHP_OUTPUT_HANDLER_CLEANABLE ( int )

Определяет, может ли буфер вывода, созданный функцией ob_start() , быть очищен функцией ob_clean() . Это флаг не управляет поведением функций ob_end_clean() или ob_get_clean() .

PHP_OUTPUT_HANDLER_FLUSHABLE ( int )

Определяет, может ли буфер вывода, созданный функцией ob_start() , быть сброшен (выведен и очищен) функцией ob_flush() . Это флаг не управляет поведением функций ob_end_flush() или ob_get_flush() .

PHP_OUTPUT_HANDLER_REMOVABLE ( int )

Определяет, может ли буфер вывода, созданный функцией ob_start() , быть удалён до завершения скрипта или при вызове функций ob_end_clean() , ob_end_flush() , ob_get_clean() или ob_get_flush() .

PHP_OUTPUT_HANDLER_STDFLAGS ( int )

Значение по умолчанию для флагов буфера вывода. Равняется PHP_OUTPUT_HANDLER_CLEANABLE | PHP_OUTPUT_HANDLER_FLUSHABLE | PHP_OUTPUT_HANDLER_REMOVABLE .

Флаги статуса обработчика вывода

Следующие флаги — часть битовой маски ключа flags массива, возвращаемого функцией ob_get_status() :

PHP_OUTPUT_HANDLER_STARTED ( int )

Означает, что был вызван обработчик вывода.

PHP_OUTPUT_HANDLER_DISABLED ( int )

Указывает, что обработчик вывода выключен. Этот флаг будет установлен, когда обработчик вывода вернёт false , завершается с ошибкой при обработке буфера или он был установлен до вызова обработчика вывода.

PHP_OUTPUT_HANDLER_PROCESSED ( int )

Указывает, что обработчик вывода успешно обработал буфер.

User Contributed Notes

There are no user contributed notes for this page.

  • Контроль вывода
    • Введение
    • Установка и настройка
    • Предопределённые константы
    • Буферизация вывода
    • Сброс (отправка) системных буферов
    • Пользовательские буферы вывода
    • Примеры
    • Функции контроля вывода

    ob_end_clean

    Функция вызывает обработчик вывода (с флагами PHP_OUTPUT_HANDLER_CLEAN и PHP_OUTPUT_HANDLER_FINAL ), стирает возвращённое им значение и содержимое активного буфера вывода, а затем отключает активный буфер вывода.

    Функция ob_end_clean() завершится неудачно, если активный буфер вывода был запущен без флага PHP_OUTPUT_HANDLER_REMOVABLE .

    Функция ob_end_clean() удалит содержимое активного буфера вывода, даже если она была запущена без флага PHP_OUTPUT_HANDLER_CLEANABLE .

    Список параметров

    У этой функции нет параметров.

    Возвращаемые значения

    Возвращает true в случае успешного выполнения или false в случае возникновения ошибки.

    Ошибки

    Если функция завершается неудачно, она выдаёт ошибку уровня E_NOTICE .

    Примеры

    Следующий пример показывает простой способ избавиться содержимого активного буфера вывода:

    Пример #1 Пример использования функции ob_end_clean()

    ob_start ();
    echo ‘Текст, который не отобразится.’ ;
    ob_end_clean ();
    ?>

    Смотрите также

    • ob_start() — Включает буферизацию вывода
    • ob_get_contents() — Возвращает содержимое буфера вывода
    • ob_clean() — Очищает (стирает) содержимое активного буфера вывода
    • ob_get_clean() — Получает содержимое активного буфера вывода и выключает его
    • ob_end_flush() — Сбрасывает (отправляет) возвращаемое значение активного обработчика вывода и отключает активный буфер вывода

    User Contributed Notes 12 notes

    19 years ago

    Note that if you started called ob_start with a callback, that callback will still be called even if you discard the OB with ob_end_clean.

    Because there is no way of removing the callback from the OB once you’ve set it, the only way to stop the callback function from having any effect is to do something like:

    $ignore_callback = false ;
    ob_start ( ‘my_callback’ );
    .
    if( $need_to_abort ) $ignore_callback = true ;
    ob_end_clean ();
    .
    >

    12 years ago

    Take note that if you change zlib output compression setting in between ob_start and ob_end_clean or ob_end_flush, you will get an error: ob_end_flush() failed to delete buffer zlib output compression

    ini_set ( ‘zlib.output_compression’ , ‘1’ );

    ?>

    ob_end_clean(); in this example will throw the error.

    3 years ago

    If there is no confidence about output buffering (enabled or not),
    you may try these guards:

    while ( ob_get_level () !== 0 ) ob_end_clean ();
    >

    while ( ob_get_length () !== false ) ob_end_clean ();
    >

    20 years ago

    You might want to prevent your script from executing if the client already has the latest version.
    You can do it like so:

    $mtime=filemtime($_SERVER[«SCRIPT_FILENAME»])-date(«Z»);
    $gmt_mtime = date(‘D, d M Y H:i:s’, $mtime) . ‘ GMT’;

    if(isset($headers[«If-Modified-Since»])) if ($headers[«If-Modified-Since»] == $gmt_mtime) header(«HTTP/1.1 304 Not Modified»);
    ob_end_clean();
    exit;
    >
    >

    $size=ob_get_length();
    header(«Last-Modified: «.$gmt_mtime);
    header(«Content-Length: $size»);
    ob_end_flush();

    Instead of checking the If-Modified-Since-Header against the date of the last modification of the script, you can of course query a database or take any other date that is somehow related to the modification of the result of your script.

    You can for instance use this technique to generate images dynamically. If the user indicates he already has a version of the image by the If-Modified-Since-Header, there’s no need to generate it and let the server finally discard it because the server only then interpretes the If-Modified-Since-Header.
    This saves server load and shortens response-times.

    17 years ago

    Keep in mind that mrfritz379’s example (#49800) is just an example. You can achieve that example’s result in a more efficient manner without using output buffering functions:

    echo «

    Search running. Please be patient. . .»;
    $output = «

    FileList:

    \n»;
    if (is_dir($dir)) $dh = opendir($dir);

    while (($fd = readdir($dh)) != false) echo » .»;
    $output .= $fd;
    >
    >
    echo «
    Search Complete!

    \n»;
    echo $output;

    In addition to John Smith’s comment (#42939), ob_gzhandler() may still set the HTTP header «Content-Encoding» to «gzip» or «deflate» even if you call ob_end_clean(). This will cause a problem in the following situation:

    1. Call ob_gzhandler().
    2. Echo «Some content»;
    3. Call ob_end_clean().
    4. Echo «New content»;

    In the above case, the browser may receive the «Content-Encoding: gzip» HTTP header and attempts to decompress the uncompressed «New content». The browser will fail.

    In the following situation, this behaviour will go unnoticed:

    1. Call ob_gzhandler().
    2. Echo «Some content»;
    3. Call ob_end_clean().
    4. Call ob_gzhandler().
    5. Echo «New content»;

    This is because the second ob_gzhandler() will mask the absence of the first ob_gzhandler().

    A solution would be to write a wrapper, like John Smith did, for the ob_gzhandler().

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *