Как создать сайт? — модульный сайт
В наше время сложно представить себе какой ни будь динамический проект, в том числе и профильный, без модульной структуры. Такой подход позволяет решить ряд проблем, которые неизбежны в любом другом случае. Начиная с ЧПУ и заканчивая удобством по расширению его функционала. В данной статье я хочу предложить вашему вниманию одно из простейших модульных решений по созданию сайта с динамическим обработчиком ЧПУ на PHP. По сути именно так построены все мои сайты.
Содержание:
- Настройка динамического ЧПУ в .htaccess
- Обработчик ЧПУ на 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