Буферизация вывода и быстрые шаблоны Разрабатывая сайты мы часто сталкиваемся с тем что приходится копировать одни и теже куски HTML на различные страницы. Когда страничек мало это еще терпимо, когда их становится больше 10 это уже раздражает, а когда их количество переваливает за сотню это просто бесит и становится невозможно работать. Как же можно упростить работу с этими кусками? Рассмотрим конкретный пример выводящий на странице текущую дату и время: index.php: Код (PHP): <html> <title>Моя первая страница</title> <body> <table width="100%" height="100%" border=0> <tr valign="middle"> <td align="center">Сегодня: <? echo date('d.m.Y H:i'); ?></td> </tr> </table> </body> </html> Для начала уясним для себя очень простые вещи: 1. Не надо смешивать HTML и PHP код 2. PHP первичен по отношению к HTML т.к. HTML является результатом работы PHP. Исходя из этих правил преобразуем наш пример к нормальному виду: index.php: Код (PHP): <? $title = 'Моя первая страница'; $now = date('d.m.Y H:i'); $HTML = '<html><title>'.$title.'</title><body> <table width="100%" height="100%" border=0><tr valign="middle"><td align="center">Сегодня: '.$now.'</td></tr></table> </body></html>'; print $HTML; ?> Что мы добились этим? Во первых мы разнесли логику и данные. Во вторых сделали наш код читабельным. В третьих мы немного приблизились к пониманию шаблонов. Давайте еще немного поработаем над нашим кодом и освоим первые шаги буферизации. Что такое по сути буфер? Буфер это накопитель, который может по нашему запросу накапливать данные или вернуть накопленные данные. Это пока все, что требуется от буфера на данный момент. Для работы с такого рода объектами использую классы. Напишем первый класс и попробуем его на нашем примере. создадим файл buffer.php: buffer.php: Код (PHP): <? class Buffer { var $buffer; # инициализация function Buffer() { $this->buffer = ""; } # очистка буфера function Clear() { $this->buffer = ""; } # заполнение буфера function Send($str) { $this->buffer .= $str; } # Чтение буфера function Read() { $tmp = $this->buffer; $this->Clear(); return $tmp; } # выдача буфера function Show() { print($this->Read()); } } ?> и применим этот класс к нашему примеру. Для этого еще немного поколдуем с HTML и PHP: index.php: Код (PHP): <? include_once('buffer.inc'); $title = 'Моя первая страница'; $now = date('d.m.Y H:i'); $HTML = new Buffer(); $HTML->Send('<html><title>'.$title.'</title><body> <table width="100%" height="100%" border=0><tr valign="middle"><td align="center">Сегодня: '.$now.'</td></tr></table> </body></html>'); $HTML->Show(); ?> Казалось бы что мы идем по усложнению, хотя это не так. Чуть позже мы увидим, что такой подход дает большие преимущества в создании динамических страниц и генерации HTML любой сложности. Следующим шагом будет быстрая и простая шаблонизация. Все это можно возложить наш класс Buffer. Допишем еще один метод, и посмотрим какой выигрыш нам это даст? Код (PHP): <? class Buffer { ... # шаблонизация или парсинг # замена и подстановка переменных function Parse() { # внимание! использование такого подхода НЕ безопасно # модифицируйте сами этот метод, для работы с массивами. reset($GLOBALS); while(list($name,$val) = each($GLOBALS)) { # выбираем только строки и числа if(is_string($val) OR is_int($val)) { $this->buffer = str_replace('{'.$name.'}',$val,$this->buffer); } } } } ?> и переделаем нашу страницу с учетом того, что мы теперь имеем такой мощный метод как шаблон! Код (PHP): <? include_once('buffer.inc'); $title = 'Моя первая страница'; $now = date('d.m.Y H:i'); $HTML = new Buffer(); $HTML->Send('<html><title>{title}</title><body> <table width="100%" height="100%" border=0><tr valign="middle"><td align="center">Сегодня: {now}</td></tr></table> </body></html>'); $HTML->Parse(); $HTML->Show(); ?> Что изменилось? Измелилось то, что в нашем выводимом HTML появились {title} и {now}, которые наш буфер на моменте шаблонизации заменит на $title и $now. Все бы хорошо, но все равно создается впечатление лишних действий для таких простых вещей и нашей простой странички. Посмотрим не можем лм упростить все это что бы сделать скрипт читаемым, код понятным и коротким. Для этого нам потребуется еще один метод, который позволит загрузить данные не из переменной а из файла. Код (PHP): <? class Buffer { ... # заполнение буфера из файла function SendFile($filename) { if(file_exists($filename)) { $this->buffer .= join('',file($filename)); } } ?> Теперь имея такой мощное средство как работа с файлами вынесем все лишнее и упростим наш скрипт: создадим файл template.html и положим туда наш HTML код. template.html: Код (Text): <html><title>{title}</title><body> <table width="100%" height="100%" border=0><tr valign="middle"><td align="center">Сегодня: {now}</td></tr></table> </body></html> поправим наш код: Код (PHP): <? include_once('buffer.inc'); $title = 'Моя первая страница'; $now = date('d.m.Y H:i'); $HTML = new Buffer(); $HTML->SendFile('template.html'); $HTML->Parse(); $HTML->Show(); ?> Казалось бы это все, что можно выжать из этой странички. Но это не так. Давайте посмотрим на HTML и увидим, что и он состоит из кусков, которые будут переходить от одной страницы к другой не изменяясь. 1. <html><title>{title}</title><body> 2. </body></html> Вынесем их в отдельные файлы и посмотрим как работает наш буффер: header.html: Код (Text): <html><title>{title}</title><body> footer.html: Код (Text): </body></html> template.html: Код (Text): <table width="100%" height="100%" border=0> <tr valign="middle"><td align="center">Сегодня: {now}</td></tr> </table> и изменим наш код: Код (PHP): <? include_once('buffer.inc'); $title = 'Моя первая страница'; $now = date('d.m.Y H:i'); $HTML = new Buffer(); $HTML->SendFile('header.html'); $HTML->SendFile('template.html'); $HTML->SendFile('footer.html'); $HTML->Parse(); $HTML->Show(); ?> Что мы этим добились? Мы добились очень простой и очень важной вещи! А именно: мы разбили наш HTML на куски и умеем собирать их вместе. Это первый шаг к пониманию шаблонизации и буферизации. Теперь для изменения страницы нам не надо перепахивать код, а надо просто изменить наш шаблон! И последним шагом станет написание основного шаблона. main.html: Код (Text): {HEADER} {BODY} {FOOTER} Добавим в коструктор немного красоты, позволяющей нам загружать файл в буффер непосредственно при создании объекта: Код (PHP): <? class Buffer { var $buffer; # инициализация function Buffer($filename='') { $this->buffer = ""; if(!empty($filename)) $this->SendFile($filename); } ... } ?> перепишем наш код к окончательному варианту: Код (PHP): <? error_reporting(E_ALL); include_once('./buffer.inc'); $title = 'Моя первая страница'; $now = date('d.m.Y H:i.s'); // загружаем header И устанавливаем title $HEADER = new Buffer('./header.html'); $HEADER->Parse(); $HEADER = $HEADER->Read(); // загружаем body и устанавливаем now $BODY = new Buffer('./template.html'); $BODY->Parse(); $BODY = $BODY->Read(); // загружаем footer $FOOTER = new Buffer('./footer.html'); $FOOTER = $FOOTER->Read(); // загружаем основной шаблон и выводим его $HTML = new Buffer('./main.html'); $HTML->Parse(); $HTML->Show(); ?> Теперь создание новых страничек будет занимать у нас намного меньше времени потому, что основные части страниц у нас уже готовы и мы будем теперь уделать больше времени наполнению этих страниц, а не тупому копированию. Все это видно на <!-- m --><a class="postlink" href="http://440hz.ru/trash/buffer/">http://440hz.ru/trash/buffer/</a><!-- m --> Скачать архив можно <!-- m --><a class="postlink" href="http://440hz.ru/trash/buffer/buffer.tar.gz">http://440hz.ru/trash/buffer/buffer.tar.gz</a><!-- m -->
440hz при принципиальном подходе твой код потенциально опасен. Пользователь сможет прочесть любую переменную кода оставив где-нить сообщение содержащее {dbpass}. при некоторых условиях оно заменится на пароль от твоей БД (в случае если он там хранится естественно)
svk можно парсеру массив передавать вместо $GLOBALS (что и используется в реальных проектах), да много чего там можно еще наворотить. но в этом случае - да. такой код НЕ безопасен.
440hz именно с массивом обычно и делают. пример - код тогоже phpBB. в нем это $template->assing_vars() если не ошибаюсь. кстати лучше вынеси про небезопасность кода в начало статьи, думаю тут найдется много горе-"программистов" которые будут использовать твой класс в своих страницах
440hz респект тебе огромный за твою статью! В мемориз ее и в закладки! Только ты не написал, самой сложной вещи - как реализовать динамику в шаблонах. Пример с теми же новостями. На одном сайте я нашел способ как это сделать: Код (Text): <html><body> <table> <%loop {array} as {var}%> <tr> <td>{var:news_title}<br>{var:news_text}</td> </tr> <%loop end%> </table> </body></html> Будь добр, подскажи, как это осуществить! Мои познания, пока что, к сожалению, не позволяют мне самому этого сделать.
я для этого использую блоки... PHP: <?php function blocks($telo, $block) { $pos1 = strpos ($telo, "<!-- BEGIN $block -->"); $pos2 = strpos ($telo, "<!-- END $block -->", $pos1); $do = substr($telo, 0, $pos1); $posle = substr($telo, $pos2+(13+strlen($block)), strlen($telo)); $tt = substr($telo, $pos1, $pos2-$pos1); return $tt; } ?>
Красиво, у меня тоже есть статья (набросок статьи) на эту тему, однако она требует сильной редакторской правки, (грамматика у меня хромает) могу дать ссылку в личку кому интересно...
я в свое время отказался от динамики ибо PHP и так шаблонизатор, а навешивать на шаблон еще и логику - это противоречит самому понятию быстрого шаблона. практика показала, что того, что есть с избытком хватает. поверь на слово.
Но вышепреведнный мною пример мне кажется весьма прост и понятен. Вот хочу его реализовать, думаю этого будет достаточно.
у меня в шаблонах реализована логика авторизации/неавторизации пользователя, статус пользователя (админ/не админ). Ну и блоки канешно.... и не скажу что противоречит
D.Lans А чем родной РНР синитаксис сложен ? Код (Text): <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html> <head> <title><?=$title?></title> <meta name="description" content="<?=$description?>"> </head> <body> <h1><?=$title?></h1> <?foreach($news as $item):?> <h2><?=$item['title']?></h2> <p><?=$item['text']?></p> <?endforeach?> </body> </html> По моему не сложнее чем у тебя
ничего не надо туда писать. это один из примеров названия файла шаблона. в первом посте он называется "template.html".