Отправляет email-рассылки с помощью сервиса Sendsay

Построй свой сайт на PHP!

  Все выпуски  

Построй свой сайт на PHP!


Информационный Канал Subscribe.Ru

Построй свой сайт на PHP!

искать в
Здравствуйте, уважаемые читатели!
Прежде всего хочу очень сильно извинится за неприятный случай с прошлым выпуском - стоило мне дать в прошлом выпуске ссылку на переведенную мной статью, прямо из-за угла выскочил автор со своим адвокатом, оба-два доселе молчавшие, и попросили меня все следы перевода убрать до углубленного анализа, чего можно, а чего нельзя переводчику и что за это все полагается автору. Неприятно, но ладно. Зато в этот раз я публикую этот самый злополучный перевод, с которым вы можете ознакомится, если не обладали достаточным количесвтом везения, чтобы сделать это раньше. [пиар]. Я очень жду вас на http://phpdevelop.info/, так как если заходить туда каждый день, то можно найти много всяких интересных PHP-проектов. Вы можете также подписаться на rss-заголовки в результате чего все еще больше упрощается. Кроме того, вам, наверное, интересно бы было ознакомится с двумя новыми переводами, а именно: "Трёхзвенная разработка в PHP 5" и "Перегрузка в PHP 5". Обе-две достаточно интересны и полезны, но лично я бы особенно отметил вторую. Впрочем, решать вам. Еще один, уже совсем злостный пиар связан с открытием моей рассылки "КиноЛоги - субъективные заметки о кино". Рассылка все еще "Бронзовая", а подписчиков там ровно один: мне посчастливилось открыть ее тринадцатого числа, а бронзовые рассылки за этот день Subscribe'ом, увы и ах, проанонсированы в его мега-рассылке не были. Так она и висит в каталоге "бронзовых" сокрытой от глаз жемчужиной. ;-) Если вы любите хорошее кино - подписывайтесь, думаю, что не пожалеете. [/пиар]

Реализация Front Controller на PHP

Автор: Эван МакКаллум (Ethan McCallum)

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

К счастью, данный веб-хост разрешал переназначение определенных ключевых директив Apache через .htaccess, что позволило мне подогнать под себя обработку запросов. Добавьте к этом поддержку ОО в PHP, и мое шаблонное решение заняло удобную среднюю нишу в виде приспособленного к моим нуждам Front Controller.

Шаблон проектирования Front Controller описывает способ централизации обработки данных в веб-приложениях. Маршрутизация всех запросов через единственную точку входа предоставляет место для реализации основной логики приложения и, в то же время, ослабляет зависимости между другими компонентами. Все это складывается в сайт, который легче поддерживать и расширять.

В этой статье я поделюсь сокращенной версией контроллера, реализованного мной как средство связи между содержимым и разметкой.

То, что я объясняю здесь, не ограничивается только PHP; шаблон проектирования Front Controller доступен в многих инструментариях для динамической генерации страниц на стороне сервера, таких как mod_perl и Java-сервлеты/JSP. В отличие от этих технологий, реализация Front Controller, предоставленая в этой статье, требует только ограниченной настройки Apache. Ваш веб-хост с поддержкой PHP вероятнее всего поддерживает требуемую конфигурацию.

Код примера был протестирован под Apache 1.3.27 и PHP 4.3.4.

Сначала немного теории

Обычно веб-сервер - это разрекламированный сервис файлов. Клиент запрашивает файл, а сервер извлекает его. Uniform Resource Identifier (URI) (универсальный идентификатор ресурса - прим. переводчика) определяет файл в корневой директории, так что ответ и запрос тесно связаны.

Веб-серверы также могут вместо выдачи необработанных файлов запускать исполняемые файлы, такие как CGI или PHP скрипты. Исполняемые файлы вставляют логику между запросом и ответом, изменяя части последнего (к примеру, чтобы добавить приветствие для конкретного пользователя или получить определенные записи из БД) с каждым вызовом.

Можно направлять все запросы через единственный исполняемый файл, генерируя полностью различные страницы для каждого. В этом случае, исполняемый файл - Front Controller сайта, а сгенерированный ответ - представление. URI и параметры запроса составляют команду, отправляемую контроллеру, который выполняет некоторую логику, чтобы решить, какой результат отправить пользователю.

Центральное расположение контроллера в цикле запрос-ответ делает его подходящим местом для применения основной логики для проверки прав или установки заголовков ответа.

Веб-сайт, управляемый контроллером, в известной степени действует независимо от нижележащего веб-сервера; доступ к файлам, аутентификация и генерация содержимого происходят внутри кода. Вот почему контроллер может иметь доступ к файлам внутри директорий, которые в иных обстаятельствах имеют ограничения, прописанные в .htaccess.

Борцы за частоту языка заметят, что описание содержит сокращения, и в нем втречаются такие действующие лица, как диспетчер, свернутый в главный контроллер. Этот код является отправной точкой и вы можете расширять его по мере своих надобностей.

Прямой и косвенный

Клиенты должны вызывать контроллер либо прямо, либо косвенно. Прямой метод добавляет параметры запроса к URI контроллера:

http://host/controller.php?display=main
http://host/controller.php?display=contact_form
http://host/controller.php?display=privacy_policy

Все внутресайтовые ссылки указывают на /controller.php, но различные параметры запроса изменяют показываемую страницу. Это работает и имеет широкую поддержку среди веб-серверов, но строка параметров может стать весьма громоздкой.

Косвенный метод содержит меньше всего ненужного и выглядит более естетсвенно, но конкретная настройка зависит от используемого веб-сервера. Конфигурационная директива Apache AddHandler ассоциирует исполняемый файл или модуль с путем (таким, как /special) или расширением файла (.site):

http://host/intro/main.site
http://host/intro/contact_form.site
http://host/about/privacy_policy.site

Заметьте, что здесь нет явной ссылки на контроллер. Ассоциирование контроллера с расширением файла .site происходит за кулисами в файлах httpd.conf или .htaccess.

(Скрытый) исполняемый файл здесь - это обработчик содержимого Apache. Когда пользователь запрашивает соответсвующий URI, Apache обходит свой обычный процесс запроса/ответа и передает контроль зарегистрированному обработчику. Затем генерация содержимого для возврата запрашивающему браузеру целиком лежит на обработчике.

В этой статье демонстрируется косвенный метод и используются расширения файлов.

Простой пример

Разъясним моменты, о которых шла речь в предыдущем разделе, при помощи конкретного примера. Рассмотрим следующий код, simple.php:

<p>
Контроллер вызван для URI
<code>
    <?= $_SERVER[ 'REQUEST_URI' ] ?>
</code>
</p>

<ul>
<?php foreach( $_SERVER as $key => $val ){ ?>
    <li>
    <b><?= ${key} ?>:</b>
    <tt><?= ${val} ?></tt>
    </li>
<?php } ?>
</ul>

Представим, что simple.php существует в корневой папке веб-сервера, слушающего адрес localhost:8000.

В .htaccess строки

Action     controller-test /simple.php
AddHandler controller-test .tst

объявляют /simple.php действием controller-test и ассоциируют это действие с расширением .tst. Когда Apache получает запрос, заканчивающийся на .tst, он запустит /simple.php, а не будет пытаться обслужить файл с диска. (Исполняемый файл Action связан с корневой директорией.)

Попробуйте следующее: запросите simple.php, а затем различные .tst-файлы. К примеру:

http://localhost:8000/simple.php
http://localhost:8000/foo.tst
http://localhost:8000/params.tst?p1=one&p2=two
http://localhost:8000/not_here/this_will_fail.tst

Первый URL показывает все параметры запроса и переменные сервера. То же делает и второй URL, несмотря на то, что строка запроса меняется. Здесь был запрошен foo.tst и по причине вызова AddHandler в .htaccess, Apache позволил перехватить управление simple.php. Несмотря на то, что это не показывает ничего в плане эстетики, вывод simple.php показывает изобилие переменных, доступных PHP-скрипту, вызванному как контроллер. (Особенно востроокие могут заметить, что это точно такой же набор переменных, что и доступный при нормальном запуске PHP-скриптов.)

Как и полагается, третий URL не работает. Запрашиваемый ресурс может быть полностью виртуальным, но директории, ведущие к этому ресурсу, должны существовать. Запросы к /not_here/this_will_fail.tst терпят неудачу потому, что директория not_here отсутствует в корневом каталоге.

Также управляемые контроллером ресурс не может быть индексным файлом. Явный запрос index.site будет работать, но по запросу http://localhost:8000/ сервер не попытается запустить /index.site, невзирая на директивы DirectoryIndex.

Эти два ограничения основаны на том, как Apache преобразовывает запросы. Это детально описано в статье Writing Apache Modules with Perl and C.

Как насчет Apache 2.x?

Пользователи Apache 2 обнаружат, что simple.php не работает как обработчик содержимого. Для Apache 2.0.x, AddHander работает только для существующих файлов. В соответствии с отчетами (особенно, Bugzilla bug ID 8431), Apache 1.x неправильно употреблял термин "обработчик", так что это было изменено в 2.x.

Но надежда есть. Соответственно этому рапорту об ошибке, Apache 2.1 может добавить конфигурационную директиву, чтобы смягчить этот запрет, из условия, чтобы AddHandler мог ссылаться на несуществующие файлы, так, как это сделано в Apache 1.x.

Объединяя: обзор сайта-примера

Сайт-пример для этой статьи использует Front Controller для отделения содержимого от разметки. Контроллер преобразует запрашиваемые URI в файлы с содержимым, а затем объединяет содержимое с шаблоном разметки во время запроса.

php_include/classes.php содержит вспомогательные классы, которые упрощают процесс:

SitePage, PageMap и AliasMap могут быть заменены XML-документом; но здесь они для простоты реализованы при помощи обычного кода.

php_include/mappings.php конфигурирует преобразования страницы и напролняет AppConfig определенными значениями. Конечные пользователи могут подгонять под себя настройки сайта, не трогая классов поддержки или кода контроллера.

Controller.php, контроллер, умещается примерно в 30 строк кода, потому что вспомогательные классы делают всю основную работу за за него:

<?php

require_once( 'php_include/classes.php'  );
require_once( 'php_include/mappings.php' );

$daysToCache  = 1.5;
$cacheMaxAge  = ${daysToCache}*24*(60*60);

$layoutFile   = 'php_include/layout_main.php';

$requestedURI = ereg_replace(
    $config->getValue( 'URISuffix' ) .  '$' ,
    "" ,
    $_SERVER["REQUEST_URI"]
);

$page         = $pageMappings->getPage( $requestedURI );

if( is_null( $page ) )
{
    header( 'HTTP/1.0 404 Not Found' );
    $page = $pageMappings->getNotFoundPage();
}

if( ! headers_sent() )
{
    header(
        'Cache-Control: max-age=' . ${cacheMaxAge} . ',
        must-revalidate'
    );
    header(
        'Last-Modified: ' . gmdate('D, d M Y H:i:s' ,
        $page->getLastModified() ) . ' GMT'
    );
}

include( $layoutFile );

?>

Реальный файлы содержимого в директории content - фрагменты HTML-кода без разметки. Функция include() объединяет их с шаблоном разметки. Добавление новой страницы на сайт требует помещения файла с содержимым в директорию content, обновления PageMap и (опционально) обновления AliasMap.

Директории content и php_include ни в коем случае не должны разрешать прямого доступа, так что файлы .htaccess запрещают обычные веб-запросы.

.htaccess в корневом каталоге содержит различные настройки Apache. Так как виртуальные ресурсы не могут быть индексными документами, RedirectMatch перенаправляет запросы корневого URI на /main/index.site. (измените хост и порт для того, чтобы заставить пример работать на вашем сайте.) Директивы AddHandler ассоциируют Controller.php с запросами, заканчивающимися на .site. Директивы ErrorDocument преобразуют коды статуса HTTP к управляемым контроллером страницам.

Директории-заглушки main и errors позволяют нам вызывать управляемые контроллером ресурсы с путями директорий, для логического группирования. (Вернитесь к описанию того, как Apache обрабатывает несуществующие директории.)

Процесс запроса

Когда сайт получает запрос на файл, управляемый контроллером:

  1. Контроллер загружает свои вспомогательные классы и файл преобразований, который создает $config, конфигурационный объект для всего приложения.
  2. Контроллер вырезает настраиваемое расширение файла (как объявлено в mappings.php) из запрашиваемого URI и достает подходящий объект SitePage из PageMap.
  3. Если файл с содержимым присутствует и доступен для чтения, переменная $page будет содержать объект SitePage. Иначе $page указывает на назначенную страницу ошибки 404.
  4. Контроллер устанавливат заголовки (в данном случае, дату Last-Modified) и передает управление шаблону разметки.
  5. Шаблон разметки (php_include/layout_main.php) использует $config для установки цвета фона полосы заголовка и достает имя файла с содержимым из $page.
  6. Вызов include() вставляет страницу содержимого в центр шаблона для завершения представления. Сервер интерпретирует страницы содержимого как PHP-документы, так что они могут содержать любую допустимую PHP-логику.

Теперь сервер может вернуть завершенный HTML-документ клиентскому браузеру.

А мне это подходит?

Немногие техники подходят каждому. Если обновления вашего сайта затрагивают добавление новых страниц налету, то нагрузка от поддержки таблицы преобразований может сыграть против вас. Однако, если динамичная природа вашего сайта зависит от чего-то вне необработанных страниц (например, базы данных) или если ваши обновления затрагивают внимательно спланированные перемещения, то техника Front Controller может принести вам пользу в долгосрочной перспективе.

Заключение

Front Controller, показанный в этой статье, отделяет запрос от ответа, разметку от содержимого и страницы содержимого друг от друга. Такое разделение предлагает заметную гибкость, как по сравнению с HTML-страницами, так и дублирующимися построенными на include() страницами шаблонов.

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

Для получения большей информации по шаблону проектирования Front Controller, отправляем к текстам, перечисленным в разделе Ресурсы.

Ресурсы

  • Код примера включает simple.php, полный сайт-пример и минимальный конфигурационный файл Apache httpd.conf для демонстрации требований к веб-хосту.
  • Patterns of Enterprise Application Architecture (Fowler)
  • Core J2EE Patterns (Alur, Crupi, Malks)
  • Writing Apache Modules with Perl and C (Stein, MacEachern)
  • Некоторые концепции в этой статье (включая PageMap и Util::aliasLink()) были навеяны Java RequestDispatcher и расширением Tiles Jakarta Struts framework.

Об авторе

Эван МакКаллум (Ethan McCallum) превратился из любознательного ребенка в любознательного взрослого, направляя свою страсть к технологии в карьеру. Как свободный (freelance) консультант, он занимается Unix/Linux, C++ и Java. Эван также является автором "Compile Time", колонки в Linux Magazine о разработке Linux-приложений.

 
Copyright © 2004-2005 Построй свой сайт на PHP!
Перепечатка возможна только с сохранением авторства.
Выпуск #10: 2005-06-28

Subscribe.Ru
Поддержка подписчиков
Другие рассылки этой тематики
Другие рассылки этого автора
Подписан адрес:
Код этой рассылки: comp.soft.prog.phpdev
Отписаться
Вспомнить пароль

В избранное