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

Ob start php что это

  • автор:

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

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

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

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

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

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

Теперь, подключив этот код в начале index.php, или другого файла, к которому обращается сервер при просмотре страниц, мы получим то, что нам нужно.

Меняя контент таким образом, мы не ограничены рамками методов движка. Это бывает весьма ценно. Можно, например, добавить плагин:

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

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

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

ob_start

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

Содержимое этого внутреннего буфера может быть скопировано в строковую переменную, используя ob_get_contents() . Для вывода содержимого внутреннего буфера следует использовать ob_end_flush() . В качестве альтернативы можно использовать ob_end_clean() для уничтожения содержимого буфера.

Некоторые web-сервера (например Apache) изменяют рабочую директорию скрипта, когда вызывается callback-функция. Вы можете вернуть ее назад, используя chdir(dirname($_SERVER['SCRIPT_FILENAME'])) в callback-функции.

Буферы вывода помещаются в стек, то есть допускается вызов ob_start() после вызова другой активной ob_start() . При этом необходимо вызывать ob_end_flush() соответствующее количество раз. Если активны несколько callback-функций, вывод последовательно фильтруется для каждой из них в порядке вложения.

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

Можно задать необязательный параметр output_callback . Эта функция принимает строку в виде аргумента и должна также вернуть строку. Она вызывается при сбросе (отправке) или очистке (с помощью ob_flush() , ob_clean() или подобных функций) или если буфер вывода сбрасывается в браузер по окончанию запроса. При вызове функции output_callback , она получает содержимое буфера и должна вернуть обновленное содержимое для буфера вывода, который будет отправлен браузеру. Если output_callback не является допустимой функцией, то документируемая функция вернет FALSE . Описание функции для этого параметра:

Если output_callback вернет FALSE , то оригинальная информация отправится в браузер без изменений.

Параметр output_callback может быть игнорирован передачей значения NULL .

ob_end_clean() , ob_end_flush() , ob_clean() , ob_flush() и ob_start() не могут вызываться из callback-функций, так как их поведение непредсказуемо. Если вы хотите удалить содержимое буфера, то верните "" (пустую строку) из callback-функции. Вы так же не можете вызывать функции print_r($expression, true) или highlight_file($filename, true) из callback-функций буферизации вывода.

Замечание:

В PHP 4.0.4 функция ob_gzhandler() была введена для облегчения отправки gz-кодированных данных web-браузерам, поддерживающим сжатые web-страницы. ob_gzhandler() определяет тип кодировки содержимого, принимаемый браузером, и возвращает вывод соответствующим образом.

Если передан не обязательный параметр chunk_size , то буфер буден сброшен после любого вывода превышающего или равного по размеру chunk_size . Значение по умолчанию 0 означает, что функция вывода будет вызвана, когда буфер будет закрыт.

До PHP 5.4.0, значение 1 было специальным значением, которое устанавливало параметр chunk_size в 4096.

Параметр flags является битовой маской, которая управляет операциями, которые можно совершать над буфером вывода. По умолчанию она позволяет буферу вывода быть очищенным, сброшенным и удаленным, что равносильно значению PHP_OUTPUT_HANDLER_CLEANABLE | PHP_OUTPUT_HANDLER_FLUSHABLE | PHP_OUTPUT_HANDLER_REMOVABLE , или PHP_OUTPUT_HANDLER_STDFLAGS как сокращение этой комбинации.

Each flag controls access to a set of functions, as described below:

Константа Функции
PHP_OUTPUT_HANDLER_CLEANABLE ob_clean() , ob_end_clean() , и ob_get_clean() .
PHP_OUTPUT_HANDLER_FLUSHABLE ob_end_flush() , ob_flush() , и ob_get_flush() .
PHP_OUTPUT_HANDLER_REMOVABLE ob_end_clean() , ob_end_flush() , и ob_get_flush() .

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

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

Список изменений

Версия Описание
7.0.0 В случае, если ob_start() используется внутри callback-функции буфера вывода, эта функция больше не будет приводить к ошибке E_ERROR , а вместо этого будет вызывать E_RECOVERABLE_ERROR , позволяя сторонним обработчикам ошибок поймать ее.
5.4.0 Третий параметр ob_start() изменен с булева ( boolean ) параметра erase (который при установке в FALSE предотвращал удаление буфера до тех пор, пока не завершалась работа скрипта) на целочисленный ( integer ) параметр flags . К сожалению, это означает появление несовместимости API для кода, который использовал третий параметр до версии PHP 5.4.0. Смотрите пример с флагами, чтобы понять как работать с кодом, чтобы он поддерживал совместимость с обеими версиями.
5.4.0 Параметр chunk_size, установленный в 1, теперь приводит к выводу по 1 байту в выходной буфер.
4.3.2 Функция вернет FALSE в случае, если output_callback не сможет быть выполнена.

Примеры

Пример #1 Пример callback-функции, определенной пользователем

function callback ( $buffer )
<
// заменить все яблоки апельсинами
return ( str_replace ( «яблоки» , «апельсины» , $buffer ));
>

ob_start

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

Содержимое этого внутреннего буфера может быть скопировано в строковую переменную, используя ob_get_contents() . Для вывода содержимого внутреннего буфера следует использовать ob_end_flush() . В качестве альтернативы можно использовать ob_end_clean() для очистки содержимого буфера.

Некоторые веб-серверы (например, Apache) изменяют рабочую директорию скрипта при вызове callback-функции. Вы можете вернуть её назад, используя chdir(dirname($_SERVER['SCRIPT_FILENAME'])) в callback-функции.

Буферы вывода помещаются в стек, то есть допускается вызов ob_start() после вызова другой активной ob_start() . При этом необходимо вызывать ob_end_flush() соответствующее количество раз. Если активны несколько callback-функций, вывод последовательно фильтруется для каждой из них в порядке вложения.

Если буферизация вывода всё ещё активна, когда скрипт завершает работу, PHP автоматически выводит содержимое.

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

Можно задать необязательный параметр callback . Эта функция принимает строку в виде аргумента и должна также вернуть строку. Она вызывается при сбросе (отправке) или очистке (с помощью ob_flush() , ob_clean() или подобных функций) или если буфер вывода сбрасывается в браузер по окончанию запроса. При вызове функции callback , она получает содержимое буфера и, как ожидается, должна вернуть обновлённое содержимое для буфера вывода, которое будет отправлено браузеру. Если callback не является допустимой функцией, то эта функция вернёт false . Описание функции для этого параметра:

Если callback вернёт false , то оригинальная информация отправится в браузер без изменений.

Параметр callback может быть игнорирован передачей значения null .

ob_end_clean() , ob_end_flush() , ob_clean() , ob_flush() и ob_start() не могут вызываться из callback-функций, так как их поведение непредсказуемо. Если вы хотите удалить содержимое буфера, то верните "" (пустую строку) из callback-функции. Вы также не можете использовать функции буферизации вывода, такие как print_r($expression, true) или highlight_file($filename, true) из callback-функции.

Замечание:

Функция ob_gzhandler() была введена для облегчения отправки gz-кодированных данных браузерам, поддерживающим сжатые веб-страницы. ob_gzhandler() определяет тип кодировки содержимого, принимаемый браузером, и возвращает вывод соответствующим образом.

Если передан необязательный параметр chunk_size , то буфер буден сброшен после любого вывода, превышающего или равного по размеру chunk_size . Значение по умолчанию 0 означает, что функция вывода будет вызвана, когда буфер будет закрыт.

Параметр flags является битовой маской, которая управляет операциями, которые можно совершать над буфером вывода. По умолчанию она позволяет буферу вывода быть очищенным, сброшенным и удалённым, что равносильно значению PHP_OUTPUT_HANDLER_CLEANABLE | PHP_OUTPUT_HANDLER_FLUSHABLE | PHP_OUTPUT_HANDLER_REMOVABLE или PHP_OUTPUT_HANDLER_STDFLAGS как сокращение этой комбинации.

Каждый флаг управляет доступом к набору функций, как описано ниже:

Константа Функции
PHP_OUTPUT_HANDLER_CLEANABLE ob_clean() , ob_end_clean() и ob_get_clean() .
PHP_OUTPUT_HANDLER_FLUSHABLE ob_end_flush() , ob_flush() и ob_get_flush() .
PHP_OUTPUT_HANDLER_REMOVABLE ob_end_clean() , ob_end_flush() и ob_get_flush() .

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

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

Примеры

Пример #1 Пример callback-функции, определённой пользователем

function callback ( $buffer )
<
// заменить все яблоки апельсинами
return ( str_replace ( «яблоки» , «апельсины» , $buffer ));
>

Результат выполнения данного примера:

Пример #2 Создание нестираемого буфера вывода

ob_start ( null , 0 , PHP_OUTPUT_HANDLER_STDFLAGS ^ PHP_OUTPUT_HANDLER_REMOVABLE );

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

  • ob_get_contents() — Возвращает содержимое буфера вывода
  • ob_end_clean() — Очистить (стереть) буфер вывода и отключить буферизацию вывода
  • ob_end_flush() — Сбросить (отправить) буфер вывод и отключить буферизацию вывода
  • ob_implicit_flush() — Включение/выключение неявного сброса
  • ob_gzhandler() — callback-функция, используемая для gzip-сжатия буфера вывода при вызове ob_start
  • ob_iconv_handler() — Преобразует символы из текущей кодировки в кодировку выходного буфера
  • mb_output_handler() — Callback-функция, преобразующая кодировку символов в выходном буфере
  • ob_tidyhandler() — Функция обратного вызова ob_start для восстановление буфера

User Contributed Notes 39 notes

You can use PHP to generate a static HTML page. Useful if you have a complex script that, for performance reasons, you do not want site visitors to run repeatedly on demand. A «cron» job can execute the PHP script to create the HTML page. For example:

<?php // CREATE index.html
ob_start ();
/* PERFORM COMLEX QUERY, ECHO RESULTS, ETC. */
$page = ob_get_contents ();
ob_end_clean ();
$cwd = getcwd ();
$file = » $cwd » . ‘/’ . «index.html» ;
@ chmod ( $file , 0755 );
$fw = fopen ( $file , «w» );
fputs ( $fw , $page , strlen ( $page ));
fclose ( $fw );
die();
?>

Output Buffering even works in nested scopes or might be applied in recursive structures. thought this might save someone a little time guessing and testing 🙂

ob_start (); // start output buffer 1
echo «a» ; // fill ob1

ob_start (); // start output buffer 2
echo «b» ; // fill ob2
$s1 = ob_get_contents (); // read ob2 («b»)
ob_end_flush (); // flush ob2 to ob1

echo «c» ; // continue filling ob1
$s2 = ob_get_contents (); // read ob1 («a» . «b» . «c»)
ob_end_flush (); // flush ob1 to browser

// echoes «b» followed by «abc», as supposed to:
echo «<HR> $s1 <HR> $s2 <HR>» ;

. at least works on Apache 1.3.28

ob_start() opens a buffer in which all output is stored. So every time you do an echo, the output of that is added to the buffer. When the script finishes running, or you call ob_flush(), that stored output is sent to the browser (and gzipped first if you use ob_gzhandler, which means it downloads faster).

The most common reason to use ob_start is as a way to collect data that would otherwise be sent to the browser.

These are two usages of ob_start():

1-Well, you have more control over the output. Trivial example: say you want to show the user an error message, but the script has already sent some HTML to the browser. It’ll look ugly, with a half-rendered page and then an error message. Using the output buffering functions, you can simply delete the buffer and sebuffer and send only the error message, which means it looks all nice and neat buffer and send
2-The reason output buffering was invented was to create a seamless transfer, from: php engine -> apache -> operating system -> web user

If you make sure each of those use the same buffer size, the system will use less writes, use less system resources and be able to handle more traffic.

With Regards, Hossein

When used in constructor part of class it have to be prefixed by «self::» or by classname, else PHP fails to create buffer.

$bo = ob_start («self::callback_ob») ;
.
>

In case of an error the contents of the output buffer are shown along with the error message. If it is really important that this does never happen, you can do the following (but this also eats up the error message):

function switchableOutputHandler ( $buffer ) <
global $outputbufferOutput ;

if ( $outputbufferOutput )
return $buffer ;
else
return «» ;
>

function internob_start () <
global $outputbufferOutput ;

$outputbufferOutput = FALSE ;
return ob_start ( «switchableOutputHandler» );
>

function internob_get_clean () <
global $outputbufferOutput ;

$outputbufferOutput = TRUE ;
$result = ob_get_clean ();
$outputbufferOutput = FALSE ;
return $result ;
>

?>

You can then use internob_start() and internob_get_clean() instead of ob_start() and ob_get_clean(). Other functions can be replaced accordingly.

Just a word of warning to those like myself who are upgrading from 5.3. I have a piece of code that used to work:

<?php
if ( ! ob_start ( ! DEBUGMODE ? ‘ob_gzhandler’ : » ) ) <
ob_start ();
>
?>

Which is not working anymore (I get an error like: Warning: ob_start(): function » not found or invalid function name).

It’s easily fixed though, just changed the » to a null, like this:

<?php
if ( ! ob_start ( ! DEBUGMODE ? ‘ob_gzhandler’ : null ) ) <
ob_start ();
>
?>

Which preserves the code intention but works 🙂

When a script ends, all buffered output is flushed (this is not a bug: http://bugs.php.net/bug.php?id=42334&thanks=4). What happens when the script throws an error (and thus ends) in the middle of an output buffer? The script spits out everything in the buffer before printing the error!

Here is the simplest solution I have been able to find. Put it at the beginning of the error handling function to clear all buffered data and print only the error:

$handlers = ob_list_handlers();
while ( ! empty($handlers) ) <
ob_end_clean();
$handlers = ob_list_handlers();
>

My callback is stored in a function class, and using ob_start (‘Class::callback’) wasn’t working. Not wanting to instantiate the class (no need, it’s a function class) I tried this and it worked a charm:

ob_start (array (Class, ‘callback’));

Careful with while using functions that change headers of a page; that change will not be undone when ending output buffering.

If you for instance have a class that generates an image and sets the appropriate headers, they will still be in place after the end of ob.

For instance:
<?php
ob_start ();
myClass :: renderPng (); //header(«Content-Type: image/png»); in here
$pngString = ob_get_contents ();
ob_end_clean ();
?>

will put the image bytes into $pngString, and set the content type to image/png. Though the image will not be sent to the client, the png header is still in place; if you do html output here, the browser will most likely display «image error, cannot be viewed», at least firefox does.

You need to set the correct image type (text/html) manually in this case.

When you rely on URL rewriting to pass the PHP session ID you should be careful with ob_get_contents(), as this might disable URL rewriting completely.

Example:
ob_start();
session_start();
echo ‘<a href=».»>self link</a>’;
$data = ob_get_contents();
ob_end_clean();
echo $data;

In the example above, URL rewriting will never occur. In fact, rewriting would occur if you ended the buffering envelope using ob_end_flush(). It seems to me that rewriting occurs in the very same buffering envelope where the session gets started, not at the final output stage.

If you need a scenario like the one above, using an «inner envelope» will help:

ob_start();
ob_start(); // add the inner buffering envelope
session_start();
echo ‘<a href=».»>self link</a>’;
ob_end_flush(); // closing the inner envelope will activate URL rewriting
$data = ob_get_contents();
ob_end_clean();
echo $data;

In case you’re interested or believe like me that this is rather a design flaw instead of a feature, please visit bug #35933 (http://bugs.php.net/bug.php?id=35933) and comment on it.

If ob_start does not seem to be working for you, note that with Apache 2 the flush() function causes PHP to send headers regardless of whether ob_start had been called before flush.

will cause Apache 2 to send whatever headers may be stacked up — which means you can’t use a header(location:xxx) after the flush. To fix, remove the flush(). Spent several hours discovering this. Apache 1.x didn’t work this way.

Way to make all stdout and stderr write to a log
from *inside* a php script.
You simply need to make sure to call elog() every
once in awhile to get output.
It’s a nice way to «daemonize» a script w.r.t. its logging.

// This allows us to capture all stdout and stderr (and error_log() calls)
// to this logfile.
// The «collected output» will be flushed anytime «elog()» is used.
ini_set(«error_log», «/var/log/script.log»);
ob_start();

function elog($str)
<
// get anything written to stdout or stderr that did *NOT* use elog()
// and write it now.
$writeme = ob_get_contents();
if ($writeme)
<
error_log($writeme);
ob_end_clean();
ob_start();
>
// now write message this method was called with
error_log($str);
>

Some web hosting servers (mine do, at least) have in their php.ini the following setting:
output_handler = ob_gzhandler

This proved problematic for php-scripts which returns an image or a binary file in general, since there is no way to determine the content length of the compressed file.

Since I spent a lot of time scouring the net searching for a work-around (.htaccess-modifications were out of the picture for various reasons), I found this to work nicely to cancel out the ob_gzhandler specified in the php.ini:

<?php
while ( ob_get_level ())
ob_end_clean ();
header ( «Content-Encoding: None» , true );
?>

Put this at the top of the script before anything else is written to the page, and the script result will not be compressed.

In extension to the compress() function posted below, here’s a nifty little class that improves the idea a bit. Basically, running that compress() function for all your CSS for every single page load is clearly far less than optimal, especially since the styles will change only infrequently at the very worst.

With this class you can simply specify an array of your CSS file names and call dump_style(). The contents of each file are saved in compress()’d form in a cache file that is only recreated when the corresponding source CSS changes.

It’s intended for PHP5, but will work identically if you just un-OOP everything and possibly define file_put_contents.

$CSS_FILES = array(
‘_general.css’
);

$css_cache = new CSSCache ( $CSS_FILES );
$css_cache -> dump_style ();

class CSSCache <
private $filenames = array();
private $cwd ;

public function __construct ( $i_filename_arr ) <
if (! is_array ( $i_filename_arr ))
$i_filename_arr = array( $i_filename_arr );

$this -> filenames = $i_filename_arr ;
$this -> cwd = getcwd () . DIRECTORY_SEPARATOR ;

if ( $this -> style_changed ())
$expire = — 72000 ;
else
$expire = 3200 ;

header ( ‘Content-Type: text/css; charset: UTF-8’ );
header ( ‘Cache-Control: must-revalidate’ );
header ( ‘Expires: ‘ . gmdate ( ‘D, d M Y H:i:s’ , time () + $expire ) . ‘ GMT’ );
>

public function dump_style () <
ob_start ( ‘ob_gzhandler’ );

foreach ( $this -> filenames as $filename )
$this -> dump_cache_contents ( $filename );

private function get_cache_name ( $filename , $wildcard = FALSE ) <
$stat = stat ( $filename );
return $this -> cwd . ‘.’ . $filename . ‘.’ .
( $wildcard ? ‘*’ : ( $stat [ ‘size’ ] . ‘-‘ . $stat [ ‘mtime’ ])) . ‘.cache’ ;
>

private function style_changed () <
foreach ( $this -> filenames as $filename )
if (! is_file ( $this -> get_cache_name ( $filename )))
return TRUE ;
return FALSE ;
>

private function compress ( $buffer ) <
$buffer = preg_replace ( ‘!/\*[^*]*\*+([^/][^*]*\*+)*/!’ , » , $buffer );
$buffer = str_replace (array( «\r\n» , «\r» , «\n» , «\t» , ‘ ‘ ), » , $buffer );
$buffer = str_replace ( ‘ < ' , '<' , $buffer );
$buffer = str_replace ( ‘ >’ , ‘>’ , $buffer );
$buffer = str_replace ( ‘; ‘ , ‘;’ , $buffer );
$buffer = str_replace ( ‘, ‘ , ‘,’ , $buffer );
$buffer = str_replace ( ‘ <' , '<' , $buffer );
$buffer = str_replace ( ‘> ‘ , ‘>’ , $buffer );
$buffer = str_replace ( ‘: ‘ , ‘:’ , $buffer );
$buffer = str_replace ( ‘ ,’ , ‘,’ , $buffer );
$buffer = str_replace ( ‘ ;’ , ‘;’ , $buffer );
return $buffer ;
>

private function dump_cache_contents ( $filename ) <
$current_cache = $this -> get_cache_name ( $filename );

// the cache exists — just dump it
if ( is_file ( $current_cache )) <
include( $current_cache );
return;
>

// remove any old, lingering caches for this file
if ( $dead_files = glob ( $this -> get_cache_name ( $filename , TRUE ), GLOB_NOESCAPE ))
foreach ( $dead_files as $dead_file )
unlink ( $dead_file );

$compressed = $this -> compress ( file_get_contents ( $filename ));
file_put_contents ( $current_cache , $compressed );

When a fatal error is thrown, PHP will output the current buffer of Output-Control without postprocessing before printing the error message. If you are working with several output control levels, this might not result in the desired behavior.

You can use an output callback handler to handle this and discard the output.

Therefore, use ob_start(«ob_error_handler») in connection with the following:

function ob_error_handler($str) <
$error = error_get_last();
if ($error && $error[«type»] == E_USER_ERROR || $error[«type»] == E_ERROR) <
return ini_get(«error_prepend_string»).
«\nFatal error: $error[message] in $error[file] on line $error[line]\n».
ini_get(«error_append_string»);
>
return $str;
>

With ob callback: note that the second parameter sent to your method won’t help you differentiate between flush calls and calls to ob_clean, but the buffer contents is sent in both cases, so you end up parsing data that isn’t going to be used. Also, note that the constant PHP_OUTPUT_HANDLER_START is never actually sent, rather the integer «3» turns up on first flush:
<?php

function ob_handler ( $string , $flag ) <
static $input = array();
$done = false ;
switch( $flag ) <
case PHP_OUTPUT_HANDLER_START :
$flag_sent = «PHP_OUTPUT_HANDLER_START ( $flag )» ;
break;
case PHP_OUTPUT_HANDLER_CONT :
$flag_sent = «PHP_OUTPUT_HANDLER_CONT ( $flag )» ;
break;
case PHP_OUTPUT_HANDLER_END :
$done = true ;
$flag_sent = «PHP_OUTPUT_HANDLER_END ( $flag )» ;
break;
default:
$flag_sent = «Flag is not a constant ( $flag )» ;
>
$input [] = » $flag_sent : $string <br />» ;
$output = » $string <br />» ;
if(! $done ) return $output ;
// print_r($input, 1) causes an error and var_export just doesn’t work
$output .= ‘<br />’ ;
foreach( $input as $k => $v ) $output .= » $k : $v » ;
return $output ;
>

echo ‘flush’ ;
ob_flush ();

echo ‘flush 2’ ;
ob_flush ();

echo ‘clean’ ;
ob_clean ();

echo ‘flush 3’ ;
ob_flush ();

echo ‘end flush’ ;
ob_end_flush ();
?>

flush
flush 2
flush 3
end flush

0: Flag is not a constant (3): flush
1: PHP_OUTPUT_HANDLER_CONT (2): flush 2
2: PHP_OUTPUT_HANDLER_CONT (2): clean
3: PHP_OUTPUT_HANDLER_CONT (2): flush 3
4: PHP_OUTPUT_HANDLER_END (4): end flush

I suppose the START flag problem *may* be a bug but I’m not able to upgrade before reporting since I must have the same version as my server (I’m on PHP 5.2.6). If anyone has 5.2.11 or other stable version feel free to test/report as you see fit.

Following clement dot ayme at st dot com ‘s remark :

In my experience it seems that the output IS buffered, but ALSO sent to the standard output !

Under certain freak conditions, when an error ocours perfoming an action on an object that cannot be done (either because the object does not exist or the method does not exist) inside of an ob_start() the script will exit and print everything the current function generates before the error, but nothing else, including no error message.

I am at a loss to why no error message appears and am trying to get a working example for the developers that is simpler than my whole program!

So if you are using ob_start() and you get no output, check your objects. you have made a mistake on them somewhere. The only trouble is you will not know where as there is no error!!

There is no start flag problem. One just has to notice that the second parameter is not a mode but consists of bitwise-OR’ed flags.

<?php
function ob_handler ( $string , $flags ) <
static $input = array();
if ( $flags & PHP_OUTPUT_HANDLER_START )
$flags_sent [] = «PHP_OUTPUT_HANDLER_START» ;
if ( $flags & PHP_OUTPUT_HANDLER_CONT )
$flags_sent [] = «PHP_OUTPUT_HANDLER_CONT» ;
if ( $flags & PHP_OUTPUT_HANDLER_END )
$flags_sent [] = «PHP_OUTPUT_HANDLER_END» ;
$input [] = implode ( ‘ | ‘ , $flags_sent ) . » ( $flags ): $string <br />» ;
$output = » $string <br />» ;
if ( $flags & PHP_OUTPUT_HANDLER_END ) <
$output .= ‘<br />’ ;
foreach( $input as $k => $v ) $output .= » $k : $v » ;
>
return $output ;
>

echo ‘flush’ ;
ob_flush ();

echo ‘flush 2’ ;
ob_flush ();

echo ‘clean’ ;
ob_clean ();

echo ‘flush 3’ ;
ob_flush ();

echo ‘end flush’ ;
ob_end_flush ();
?>

flush
flush 2
flush 3
end flush

0: PHP_OUTPUT_HANDLER_START | PHP_OUTPUT_HANDLER_CONT (3): flush
1: PHP_OUTPUT_HANDLER_CONT (2): flush 2
2: PHP_OUTPUT_HANDLER_CONT (2): clean
3: PHP_OUTPUT_HANDLER_CONT (2): flush 3
4: PHP_OUTPUT_HANDLER_END (4): end flush

If you want to run code in the middle of a string that you made, but you want to wait the printing.
(so if you want to allow php in bb-code style, and you want to execute it in order, and print everything in order. )

phpRun($code) <
ob_start();
exec($code);
$output = ob_get_contents();
ob_end_clean();
return $output;
>

$str = str_replace(«]\n», «]», $str);
$match = array(‘#\[php\](.*?)\[\/php\]#se’);
$replace = array( phpRun( stripslashes(‘$1’) ) );
$str= preg_replace($match, $replace, $str);

This concerns the default values used for ob_start().

Note that I could verify that ob_start() and ob_start(null,0) are not always equivalent.

It seems that with ob_start() the output buffer is open with current default parameters of your configuration if they have been explicitly defined.

So, if you have set $chunk_size to any value previously and send data larger than $chunk_size the data will be automatically flushed by blocks of $chunk_size.

If you explicitely define $chunk_size=0, later, when you will use any function as $my_ob_dataoutput=ob_get_clean(); you will get back the whole content of your output (quite unlimited with $chunk_size=0).

I discover this because my var $my_ob_dataoutput was truncated. Using «ob_get_status (true)» function, I could verify that an error (in a lower level or by default out of my control) was setting previously the $chunk_size of ob at 4096.
I changed «ob_start()» for «ob_start(null,0)» and everything became OK.

I think it’s worth noting that while you can’t call any output functions such as echo or print from within a callback function, you can still send headers (presumably including cookies, haven’t checked). Of course this only works in the first callback, like so:

function myCallback ( $buffer , $flags ) <
if ( $flags & PHP_OUTPUT_HANDLER_START ) <
header ( ‘Server: LastMinuteHeaderServer’ );
>
>

ob_start ( ‘myCallback’ );
echo «Hello World!» ;
ob_end_flush ();

?>

Not the most inspiring example, but in this case the code is able to sneak a last-minute header in before the headers part of the response is sent. This can be handy if you want to avoid replacing header values that are uncertain.

For example if your code may return an image, but you don’t want to set content type until you’re sure that the image can be sent successfully, you can use the callback to leave the decision right until the very last moment, by which point you’re hopefully sure of what’s being sent in the HTTP body.

Be very careful when returning false from your callback function!

Despite what the documentation says, this is *not* the same as returning the supplied $buffer value, unmodified. In the context of a ‘clean’ operation (e.g. ob_clean()) this will result in your callback function being disabled and skipped for any subsequent output.

The answer is to ensure you always return a string value from your callback. This is likely a bug, and it may get fixed at some point, but it applies to all versions since PHP 5.4 up to the current version (8.1 at time of writing). Note that it was not an issue on PHP 5.3 and below.

Some more detail can be seen on this Stack Overflow question: https://stackoverflow.com/questions/69845122/

A demonstration of the issue has been set up in this fiddle: https://3v4l.org/66cai

I usually create my pages in four parts — variable initialisation, import header (using the variables just declared to configure), main body (mostly non-PHP), import footer. I wondered about making the main body examinable by another PHP script if the main page was included into it. I found I could control output of the main body by ending the header with an unclosed function which finishes at the start of the footer, thus enclosing the main body. Output buffering can then be used to read this into a variable. As a demonstration of how this can be used to control the order of output look at this example:

// Callback to process buffered output
function capture ( $buffer )
<
$GLOBALS [ ‘output’ ] .= $buffer ;
return «C » ;
>

// Calls the printE() function with output capture
function captureE ()
<
ob_start ( «capture» );
printE ();
ob_end_flush ();
>
?>

A
<?php
// Output ‘E’ (the main body in the example scenario)
function printE ()
< // (End header after this line) ?>
E
<?php // (Start footer with this line)
>
?>
B
<?php captureE (); ?>
D
<?php print $output ; ?>
F
<?php printE (); ?>
G

The output is A B C D E F E G.

For the application I mentioned above there are two points to note:
— The page when executed alone must output its main body but the inspection script should suppress this, perhaps by means of a variable set before the page is included and then checked for in the footer output lines.
— Because the main body is now inside a function it has a different namespace, thus changes may be required to prevent code breaking (e.g. use of globals, handling of functions defined within the main body).

These are handy. First one has been mentioned before.

ob_start( array( ‘lib_class’, ‘parse_output’ ) );
ob_start( array( $this, ‘parse_output’ ) );

Note: $this is NOT a reference. Anything the callback saves or logs disappears in the clone ob_start works with.
It does enable the callback to work with the attributes of $this, like $this->ar_tpl_value or whatever your style is.

The manual says:
«If the optional parameter chunk_size is passed, the callback function is called on every first newline after chunk_size bytes of output. The output_callback parameter may be bypassed by passing a NULL value.»
This doesn’t work with my 4.3.11. Might be the Zend optimizer though. Daren’t turn it off to go see.

If you’re trying to include a php file inside a loop by require_once (in example, a dinamic email template) and change the value of some variables (in example, url to unsuscribe, different for each user), you should use

$usermail = array( «email1» , «email2» , . );

for( $i = 0 ; $i < $MAX ; $i ++)
<
$usermail_unsuscribe = $usermail [ $i ];
ob_start ();
include( «email_template.php» );
ob_clean ();
>
?>

Otherwise $usermail_unsuscribe will get only «email1» value.

Make sure the editor you use does not add the UTF8/UTF16 BOM at the start of the scripts if you want to use ob_start(«ob_gzhandler»);

If those three characters are present, browsers like Firefox won’t be able to decode the pages and will report:

Content Encoding Error

The page you are trying to view cannot be shown because it uses an invalid or unsupported form of compression.

The page you are trying to view cannot be shown because it uses an invalid or unsupported form of compression.

Google Chrome will simply report «Error 2 (net::ERR_FAILED): Unknown error.»

With the ob_start command commented out, the page is successfully load and the browser will usually detect the BOM and not show it on the page, so everything’s hard to debug.

Note that since PHP 5.1.x, all objects have their destructors called before the output buffer callback function executes. Thus, globalised objects will not be available as expected in the function.

This is stated to be intended behaviour, per http://bugs.php.net/bug.php?id=40104

Here’s a nifty function I use daily. Essentially: include a PHP file — but render its output to a variable, rather than to the buffer. It’s also set up to load the script with a variable set, and automagically loads globals into the script’s namespace, making it an effective templating scheme. It also has error handling, so that you’re not flying blind when using output buffering.

<?php
$GLOBALS [ ‘BufferedErrors’ ]=Array();
function errorParse ( $errno , $errstr , $errfile , $errline , $errcontext ) <
$errorTypes = Array(
E_ERROR => ‘Fatal Error’ ,
E_WARNING => ‘Warning’ ,
E_PARSE => ‘Parse Error’ ,
E_NOTICE => ‘Notice’ ,
E_CORE_ERROR => ‘Fatal Core Error’ ,
E_CORE_WARNING => ‘Core Warning’ ,
E_COMPILE_ERROR => ‘Compilation Error’ ,
E_COMPILE_WARNING => ‘Compilation Warning’ ,
E_USER_ERROR => ‘Triggered Error’ ,
E_USER_WARNING => ‘Triggered Warning’ ,
E_USER_NOTICE => ‘Triggered Notice’ ,
E_STRICT => ‘Deprecation Notice’ ,
E_RECOVERABLE_ERROR => ‘Catchable Fatal Error’
);
$ret =(object)Array(
‘number’ => $errno ,
‘message’ => $errstr ,
‘file’ => $errfile ,
‘line’ => $errline ,
‘context’ => $errcontext ,
‘type’ => $errorTypes [ $errno ]
);
$GLOBALS [ ‘BufferedErrors’ ][]= $ret ;
return false ;
>
function parse ( $fileToInclude , $argumentsToFile = false ) <
$bufferedErrorStack = $GLOBALS [ ‘BufferedErrors’ ];
set_error_handler ( ‘errorParse’ , error_reporting ());
$GLOBALS [ ‘BufferedErrors’ ]=Array();

if (! file_exists ( $fileToInclude ))
return » ;
if ( $argumentsToFile === false )
$argumentsToFile = Array();
$argumentsToFile = array_merge ( $GLOBALS , $argumentsToFile );
foreach ( $argumentsToFile as $variableName => $variableValue )
$ $variableName = $variableValue ;
ob_start ();
include( $fileToInclude );
$ret = ob_get_contents ();
ob_end_clean ();

restore_error_handler ();
$errors = $GLOBALS [ ‘BufferedErrors’ ];
$GLOBALS [ ‘BufferedErrors’ ] = $bufferedErrorStack ;
if ( count ( $errors )> 0 ) <
$ret .= ‘<ul >’ ;
foreach ( $errors as $error )
$ret .=
‘<li>’ .
‘<b>’ . $error -> type . ‘</b>: ‘ .
$error -> message .
‘<blockquote>’ .
‘<i>file</i>: ‘ . $error -> file . ‘<br />’ .
‘<i>line</i>: ‘ . $error -> line .
‘</blockquote>’ .
‘</li>’ ;
$ret .= ‘</ul>’ ;
>
return $ret ;
>

Referring to dan at roteloftet dot com’s comment:

RFC 2616 (HTTP) specifies a «transparent» Content-Encoding, «identity» (§ 3.5), that nicely suits what you tried to do with the (invalid) «None». So this equally working, and it’s also RFC-compliant:

<?php
header ( ‘Content-Encoding: identity’ , true );
?>

simple code to make phpsession $_GET nice for Valid XHTML 1.0 Transitional 🙂

function callback($buffer)
<
$buffer = str_replace(«&PHPSESSID», «&amp;PHPSESSID», $buffer);
return $buffer;
>

When using a callback with ob_start(), functions like ob_get_contents() don’t make use of it, use ob_end_flush() instead.

nb: not tested with every ob_* functions, just ob_get_contents() and ob_end_flush()

This function dynamically changes title of HTML page:

function change_title($new_title) <
$output = ob_get_contents();
ob_end_clean();

$output = preg_replace(«/<title>(.*?)<\/title>/», «<title>$new_title</title>», $output);
echo $output;
>

Example:
ob_start();
// . some output
change_title(‘NEW TITLE!’);

If you’re using Apache (1.3x or 2.0), you might consider adding automatic compression capability to your delivered pages.

I assume you all know how to build compression classes and use them in your programs, but none has yet to offer the speed and robustness of a binary-compiled module. Furthermore, such modules also log the «compressable» hit in the web log file, thus allowing your favorite web anaysing program to show you reports of bandwidth saved.

Having said that, you might consider the following two modules for Apache:

Что такое буферизация вывода 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. Для тех, кто не делает ни того, ни другого, я приведу несколько примеров, когда эта концепция все-таки может пригодиться.

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

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

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

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

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

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

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

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

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