Как создать сайт? — модульный сайт

В наше время сложно представить себе какой ни будь динамический проект, в том числе и профильный, без модульной структуры. Такой подход позволяет решить ряд проблем, которые неизбежны в любом другом случае. Начиная с ЧПУ и заканчивая удобством по расширению его функционала. В данной статье я хочу предложить вашему вниманию одно из простейших модульных решений по созданию сайта с динамическим обработчиком ЧПУ на PHP. По сути именно так построены все мои сайты.

Содержание:

Обработчик ЧПУ на PHP

Для создания php-обработчика я использую index.php – файл, который загружается по умолчанию при обращении к сайту.

Начинается он у меня с подключения внешних модулей, например:

  • config.php – файл с настройки, обычно в виде констант;
  • functions.php – файл с общим набором функций;
  • core.php – файл с функциями для конкретного сайта;
  • и т.д.

Затем идёт получение и очистка переменной furl, которая содержит ЧПУ. Выглядит это так:

$furl = isset($_REQUEST['furl']) ? trim($_REQUEST['furl'], '/\\') : '';

Здесь я убираю слэш (/) и/или косую черту (\) по краям строки, т.к. эти символы создают дополнительные проблемы при обработке ЧПУ.

Далее идёт разбор и обработка ЧПУ, с использованием регулярных выражений. Обычный набор условий. Но начинается всё со следующих строк:

$section = '404';
if ( empty($furl) ) {
  $section = 'default';

Как вы видите, здесь я использую переменную $section, которая содержит имя подключаемого (в дальнейшем) php-скрипта. Например, если значение $furl окажется пустым, то вызывается файл default.php, что соответствует главной странице. По идее, можете назвать его и index.php, просто у меня так повелось, чтобы не спутать с другими index.php.

В качестве примера, приведу ещё пару условий, для обработки ЧПУ категорий с разбиением по страницам.

} elseif ( preg_match('/^category$/', $furl) ) {
  $section = 'categories';
} elseif ( preg_match('/^category\/([a-z0-9\-]{1,50})$/', $furl, $m) ) {
  $section = 'category';
  $slug = (string) $m['1'];
  $page = 1;
} elseif ( preg_match('/^category\/([a-z0-9\-]{1,50})\/([0-9]{1,11})$/', $furl, $m) ) {
  $section = 'category';
  $slug = (string) $m['1'];
  $page = (int) $m['2'];
  if ( $page == 1 ) moved_permanently(@SITE_URL .'category/'. $slug .'/');

Каждое многоуровневое ЧПУ лучше разбирать именно в порядке иерархии, от малого до полного.

  • И так, первое условие проверяет: если ЧПУ состоит только из подстроки: category – в качестве значения переменной $section задается: categories – т.е. вывод списка категорий на отдельной странице.
  • Затем рассматривается случай с указанием после префикса: category/ – чанга конкретной категории, т.е. уникального его названия в ЧПУ. Например: category/name – здесь в качестве чанга выступает значение: name. Примечательно, что в самом регулярном выражение указывается допустимый набор символов (он в квадратных скобках: [a-z0-9\-]) и длины строки (это в фигурных скобках: {1,50}).

    Извлеченные из значения $furl подстроки передаются переменной $m в виде массива. Так для получения первой подстроки я обращаюсь к $m['1']. Как вы видите, такой вариант ЧПУ у меня является первой страницей из списка, потому переменной $page я задаю отсутствующее в ЧПУ значение 1.

  • Последнее условие приведенного примера учитывает и вызываемую страницу. Её номер находится в $m['2']. В случае если указана первая страница, для исключения дублей, делается 301 редирект на правильный URL-адрес.

Как вы наверное уже заметили, по умолчанию, значением переменной $section является строка: 404 – что соответствует php-файлу 404.php. Впрочем, здесь я использую свою функцию page_not_found(), что позволяет минимизировать нагрузки и решать проблему с не найденными страницами куда как проще. Так в конце набора условий по обработке ЧПУ у меня идет вот такая строка:

if ( $section == '404' ) page_not_found();

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

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

$section_file = ABSPATH .'includes/sections/'. $section .'.php';
if ( !file_exists($section_file) ) die('Section file: '. $section_file .' - not exists.');

Т.к. я использую шаблонизатор Smarty, далее у меня идет проверка на необходимость его подключения на основе значения переменной $section, ведь не все секции в нем нуждаются.

Осталось лишь подключить саму секцию, например:

define('INDEX_ACCESS', 1);
include_once($section_file);

Для чего нужна константа INDEX_ACCESS? Она служит маркером для проверки того, что файл секции не вызывается напрямую. Для этого в начале каждого такого php-файла я вставляю следующую строку:

if ( !defined('INDEX_ACCESS') ) die('Access denied.');

Структура сайта

Безусловно, приведенный пример это простейший вариант. Если есть разбиение на модули, будет не лишним внести дополнительный чанг для модуля в ЧПУ или что-то в этом роде. Тем не менее, для большинства небольших проектов, предложенной модульной структуры более чем достаточно. Тем более что и она не исключает работы с модулями.

Нам осталось лишь дополнить общую картину используемой мной структурой сайта. Здесь я почерпнул идею у WordPress. Получилось достаточно просто и понятно. Возможно, что предложенная структура сайта поможет сэкономить вам время.

  • admin/ – у меня директория закрывается паролем серверными средствами. Разбирать её содержание я не буду, это тема для отдельной статьи.
  • content/ – директория содержит содержание сайта:
    • cache/ – кэш страниц,
    • css/ – CSS-файлы с таблицами стилей, у меня их много и их я подключаю в шаблон по необходимости,
    • data/ – промежуточные данные, вроде SQLite баз данных,
    • fonts/ – для шрифтов, если таковые нужны,
    • images/ – картинки,
    • templates/ – шаблоны,
    • templates_c/ – скомпилированные шаблоны.
  • includes/ – подключаемые элементы, в самой директории содержатся основной набор php-файлов: functions.php (общий набор функций), core.php (функции для конкретного сайта) и т.д.
    • js/ – JavaScript файлы.
    • sections/ – php-файлы секций сайта.
    • smarty/ – библиотека шаблонизатора Smarty.

В корневой паке содержатся: .htaccess, config.php, index.php и т.п.

Очень сложно совместить не совместимое, но при желании вполне возможно. Должен отметить, что несмотря на удобство модульного решения, самым сложным является совмещение отдельных кусочков в одно целое. Особенно это становится очевидным, когда над проектом работает несколько человек. Для всего этого должен быть отдельный человек. В противном случае будет как у меня: много попыток и лишь единичные результаты. Тем не менее, если моя статья вам была полезна, буду очень рад. На этом у меня всё. Спасибо за внимание. Удачи!

Короткая ссылка: http://goo.gl/HMwV2p

Максим
Максим комментирует...

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

Недавно я собирался сделать одно веб-приложение на Java. В процессе изысканий стал разбираться с кучей всяких фреймворков J2EE portlet-enabled JSR-compliant MVC role-based CMS web service application container и т.д. В конце концов, я написал всё как умею и оно работает.

Как говорится: казалось бы, зачем убийце убивать убийцу убийцы, но Донцову уже было не остановить… - а значит нужно вовремя остановиться и убедиться, что мы не топчемся на одном месте, усложняя задачу тем, что должно было её упростить.

Константин Кирилюк
Константин Кирилюк комментирует...

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