WebScript.Ru
C:\   главная  ::   о сайте  ::  каталог скриптов  ::  гнездо  ::  форум  ::   авторам  :: Новостройки ::   ХОСТИНГ  ::

|| разделы::
|| поиск по сайту::

|| реклама::
|| новости почтой::
Рассылки Subscribe.Ru ::



Новости сайта WebScript.Ru
Популярные статьи

Hot 5 Stories

|| рекомендуем::




Использование Output Buffering в PHP


Прислал: Dmitry Vereschaka [ 02.07.2003 @ 18:53 ]
Раздел:: [ Статьи по PHP ]


В моей первой статье было несколько интересных моментов, о которых хотелось упомянуть, однако не хотелось акцентировать внимание, потому что это уводило в сторону от основного содержимого. Но теперь, когда эти моменты являются темой для отдельной статьи, просто необходимо остановиться на них подробнее ;)

Коротко суть проблемы можно изложить так: очень часто те данные, которые вы получаете, например, из базы данных, должны фигурировать в тексте HTML-страницы гораздо ранее того участка программы, который занимается добычей этих данных. Например, заголовок страницы, задаваемый тэгом <title>, зачастую является содержимым какого-либо поля таблицы БД, а блок программы, который обращается к БД, расположен гораздо позже вывода заголовка страницы.

Что делать? Ответ простой - читать документацию. На функции ob_*, начиная с ob_start()
Оказывается, что в PHP есть возможность не сразу выдавать результат работы скрипта браузеру, а сохранять в специальном месте, именуемом Output Buffer (буфер вывода). При этом в PHP есть функции, которые позволяют изменять его содержимое. Еще одним аргументом за ob_start() в самом начале программы является возможность установки различных HTTP-заголовков, например, cookies, в произвольном месте скрипта, а не в самом его начале.

Кстати, в PHP есть возможность "сжать" (заархивировать) результат работы вашего скрипта, дабы уменьшить количество трафика, гуляющего по сети - для этого нужно вызвать функцию ob_start с параметром "ob_gzhandler": ob_start("ob_gzhandler"); Естественно, если браузер не поддерживает сжатый контент - ваша страница будет передана ему без изменений.

А теперь давайте от слов перейдём к конкретным примерам:

Внимание! Здесь и далее предполагается, что в самом начале скрипта включается буферизация вывода:

<?
ob_start();
?>

Пример 1: автоматическая подсветка переменных.
Предположим, у вас на сайте есть статьи, посвященные PHP. Естественно, они должны содержать и примеры кода на PHP ;) Однако, если весь ваш код будет набран шрифтом одного цвета, то читать этот код будет немного затруднительно. Так давайте раскрасим код! Пусть все имена переменных будут синего цвета. А комментарии - красного (будем считать, что комментарии начинаются c //). Для этого в самом конце скрипта добавляем следующий код:

<?
$x=ob_get_contents(); // получаем содержимое output buffer
ob_clean(); // очищаем его
$x=preg_replace("/(\\$[\\w]+)/si","<font color=\"blue\">\\1</font>",$x);
// заменяем всё, что начинается со знака $ и продолжается более, 
// чем одним алфавитно-цифровым символом
// на то же самое, но обрамлённое тэгами <font> синего цвета
$x=preg_replace("/(?<!:)(\\/\\/[^\\r\\n]+)[\\r\\n]/si","<font color=\"red\">\\1</font>",$x);
// заменяем комментарии на самих себя, но делаем их красного цвета
// (?<!:) нужно, чтобы случайно не поменять ссылки - //webscript.ru, например.
echo $x;  // результат на лицо, то есть в браузер ;)
?>
Естественно, вышеприведённый пример не является идеальным - например, если в вашем тексте встретится код JavaScript, в котором нечаянно окажется комментарий, то работать он перестанет. Однако, с небольшой модификацией, именно этот пример раскрасил, хоть и не идеально, эту статью.

Пример 2: автоматическое распознавание URL и генерация ссылок.
Предположим, у вас на сайте есть гостевая книга или форум, и какой-либо посетитель решил разместить ссылку на свой ресурс. Дабы не утруждать пользователя изучением HTML, было бы удобно сделать так, чтобы все URL, указанные пользователем, автоматически обрамлялись в соответствующие ссылки на языке HTML. Например:

//php.net => <a href="//php.net">php.net</a>
ftp://ftp.chg.ru => <a href="ftp://ftp.chg.ru">ftp.chg.ru</a>
Так же было бы полезно преобразовывать следующие строки:
www.webscript.ru => <a href="//www.webscript.ru">www.webscript.ru</a>
ftp.chg.ru => <a href="//ftp.chg.ru">ftp.chg.ru</a>
Приступим:

в самом конце вашего скрипта надо дописать следующий код:

<?
$x=ob_get_contents();
ob_clean();
$x=preg_replace("/(?<!\\/)(www\\.[\\S]+)/si",'<a href="//\\1">\\1</a>',$x);
// меняем всё, что начинается с www, но не следует после /, на <a href="//www...">www...</a>
// тут используется "важный" regexp - (?<!\\/) - без него уже существующие ссылки типа 
// <a href="//www..."> тоже бы подверглись преобразованию... 
//результат получается не совсем желательным
$x=preg_replace("/(?<!\\/)(ftp\\.[\\S]+)/si",'<a href="ftp://\\1">\\1</a>',$x);
// аналогично поступаем с ftp...
$x=preg_replace("/(?<!\")(http2|ftp):\\/\\/(\\S+)/si",'<a href="\\1://\\2">\\2</a>',$x);
// здесь мы обрабатываем строки вида (http2|ftp)://что-нибудь, заменяя эту последовательность 
// соответствующими тэгами HTML
echo $x;
?>

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

<?
$links=array(
"новости"=>array("url"=>"/news","synonyms"=>"в разделе новостей,последние новости,новости сайта"),
"голосования"=>array("url"=>"/votes","synonyms"=>"раздел голосований,проголосуй")
);
// массив links - это описание соответствий названий разделов и их URL
// естественно, что на вашем сайте он создаётся из БД
// кроме того, для каждого раздела полезно иметь список синонимов
// а то php не силён в падежах, склонениях, спряжениях и т.д.
setlocale(LC_ALL,"ru");
// полезно включить локаль, а то PHP не сможет отличить прописные буквы
// русского языка от их "братьев меньших" ;)
$x=ob_get_contents();
ob_clean();
foreach ($links as $word=>$description) {
$synonyms=split(",",$description['synonyms']);
// берем список синонимов и помещаем их в массив 
$synonyms[]=$word;
// слово есть синоним самого себя
foreach ($synonyms as $replace) {
$x=preg_replace("/(\\W)($replace)(\\W)/is", "\\1<a href=\"".$description['url']."\">\\2</a>\\3",$x);
// заменяем все вхождения синонима на ссылку на соответствующий раздел
// сохраняя при этом старое название
}
}
echo $x;
?>
Естественно, приведённый выше пример нельзя считать окончательным - например, если у вас где-нибудь в синонимах встретится какой-то из символов, имеющих специальное значение в perl regular expressions, например, скобки, то результатом выполнения этого кусочка программы могут стать сообщения об ошибках на ваших страницах. Кроме того, приведённое выше регулярное выражение не учитывает, что название раздела уже может являться ссылкой либо её частью, и, соответственно, испортит её.

Но, тем не менее, эта технология, с некоторыми дополнениями, спасает автора этих строк от написания ссылок на разделы своего сайта. Кроме того, именно с использованием output buffering становится очень простым реализация достаточно сложных вещей - например, экспорт данных в excel можно реализовать, написав буквально пару операторов (подсказка: excel умеет импортировать HTML, ну а как отрезать дизайн от экспортируемой таблицы вы, наверное, уже догадались).


 :::::  yUAC пишет 03.07.2003 @ 13:39 
Вообще говоря, это далеко не самый лучший способ использовать буферизацию вывода, например вообще ничего не было сказано про очень частые ошибки с Header("Location: ..."), когда заголовки и кукисы ставятся после вывода на экран, и возникает ошибка...

Что именно буферизация вывода позволяет делать нормальные системы шаблонов, ЧПУ "на лету", проставление размеров картинок тоже "на лету", ну в конце концов просто для того, чтобы подключить модуль на сайте и запихнуть в шаблон то, что он вывел... В общем, как с ООП, область применения гораздо шире, чем здесь описано...
 :::::  ThE0ReTiС пишет 03.07.2003 @ 17:08 
вообще-то для проставления размеров и ЧПУ буферизация совершенно не нужна.
И для подключения модулей...
Это собачий хвост.
Размеры можно поставить на этапе отдавания результирующего кода клиенту
и все остальное сделать в этот же момент.
а для подсветки кода в РНР вообще есть специальные функции, так что там даже регулярки излшество...
Чего-то не внушает доверия автор...
Хотя и сам таким когда-то был
 :::::  ActiveX пишет 15.07.2003 @ 00:25 
Странно, может быть я чего не так понял, но почему-то вот такая штучка выводит и то, что содержит echo, и потом тоже самое, когда я это извлекаю из буфера. Как убрать "преждевреммный" вывод?
----------
<?php
ob_start();
echo "Some text to test";
?>
<html>
<head><title>test</title></head>
<body><h1>
<?php
$c=ob_get_contents();
ob_end_clean();
echo $c;
?>
</h1></body>
</htmд>
----------
В итоге будет выведен "Some text to test" перед началом всего HTML-кода и потом так же будет выведен уже в тэгах <h1>
 :::::  Dmitry Vereschaka пишет 15.07.2003 @ 12:02 
Не совсем понятно, чего ты хочешь добиться, но, быть может,
если ты перед echo $c напишешь $c=preg_replace('/^(.*)(<html>.*$)/si','\2',$c); ,
то всё, что было выведено до <html> будет уничтожено. А если ты напишешь
$c=preg_replace('/^(.*)(<html>.*$)/si','\2\1',$c); , то всё, что было до <html> переместится после <h1>
 :::::  ActiveX пишет 17.07.2003 @ 09:17 
Нет, это немного не то.
Мне нужно добиться того эффекта, что бы в первом блоке <?php ... ?> не было вообще никакого вывода, а был он лишь только в втором блоке, где я применяю ф-ю ob_get_contents() и on_end_clean(), а на деле у меня все скрипт выводит (при просмотре HTML-кода сгенеренной страницы):
-------------
Some text to test<html>
<head><title>test</title></head>
<body><h1>Some text to test</h1></body>
</html>
-------------
Как мне избавиться от самой первой надписи "Some text to test"?
 :::::  Manowar пишет 29.07.2003 @ 11:22 
Что тут можно сказать, переходите на темплетные технологие и проблемы с хидерами, куками и прочей .. отпадут сами собой. И вообще, я считаю, что возможность встраивание пхп кода внутрь хтмл это скорее недостаток, чем преймущество. Давайте не будем смешивать мухи с котлетами...
 :::::  Neo пишет 01.08.2003 @ 02:33 
Хм. очень интересно. Никогда о таком не слышал. Надо будет попробывать, потом комментарии расширю!
 :::::  Design & Programming from ADC пишет 01.10.2003 @ 00:56 
Необязательно буферизацию юзать, она ненадежна. Лучше уж такие фичи как подсветка использовать в гостевых, но не на сайтах, например смотри: если стоит
www.нечто.com<br> то это бр тоже отабразится в баре, а посему когда большой доклад или статья или научная публикация, тебе прийдется больше часа рыскать в коде, когда можно постаить просто
<a href='''>
Юзайте наздоровье! Не все простое гениально!

теоретик
какие функи. шоу сорс? мдя... далеко пойдешь. и куда ее сунуть. ифреймом чели. нюню.
 :::::  Алекс пишет 01.10.2003 @ 19:54 
Впечатлило...
 :::::  Яков Альперин пишет 16.04.2004 @ 07:45 
Есть такая задача, как обратный URL-rewriting. Т.е. как сделать так, чтобы с юзера могло приходить /статья_1.html вместо /mods/resource/view.php?rid=1 , знают все. А вот как сделать, чтобы все URL-ы в проекте вдруг поменялись на эту форму записи - так это буфер и есть.
 :::::  Бондарев Александр пишет 24.06.2004 @ 15:29 
Странное применение такой полезной штуки...

Я ob_ постоянно использую, но совсем для других целей.. В первую очередь для отправки грамотных HTTP заголовков. В самом начале кода создается функция, принимающая буфер. При вызове эта функция во-первых, перебирает все подключенные файлы и выводит Last-Modified с датой последнего изменения самого свежего из подключенных файлов, а во-вторых считает длину буфера и выводит Content-Length.
Имя:
Email:
URL

Введите сумму двух чисел девять и шесть (девять+шесть=?)
Запомнить мою информацию

* Html запрещен* Ваш E-mail опубликован не будет.

Copyright © 2000-2001 WebScript.Ru nas@webscript.ru
Design © 2001 by Parallax Design Studio (aka Spectator.ru)
Все торговые марки и авторские права на эту страницу принадлежат их соответствующим владельцам.
Сгенерировано за: 0.0454130