Вводная: Помогите разбить URL на переменные: http://name.ru/content/article/1/
Ответ: Получить URL так $url = $_SERVER[REQUEST_URI]; Далее, воспользоваться командой explode
Вариант от Нечто (mod_rewrite и разбор пути средствами PHP):
Правила mod_rewrite:
Благодаря вышеприведенным правилам, вместо виртуального /some/interesting/page/ будет вызван URI /index.php/some/interesting/page, а обращения к реально существующим файлам обрабатываться не будут.
Разбор пути:
<?php // Достаем переменную окружения, содержащую путь; если она не задана, находимся в корне. $URI = (isset($_SERVER[PATH_INFO])) ? $_SERVER[PATH_INFO] : ;
// Разбиваем путь на элементы, фильтруя пустые значения и // восстановливая численную последовательность индексов. // Пустые значения образуются при разбивке путей типа //another///interesting/page///. $URIelements = array_values(array_filter(explode(/, $URI)));
print_r($URIelemets); ?>
Впоследствии элементы запроса можно перебрать на предмет каких-то ключевых системных значений, а также склеить обратно с помощью implode.
Как удобнее хранить данные о разделах сайта Вариант 1 Базовые поля таблицы: id – int – идентификатор страницы title – varchar – заголовок страницы url – varchar – полный URL страницы
Вообщем-то, весь вариант заключается в том, что сохраняются все полные URL для всех существуют страниц, то есть нет страниц с параметром, который может принимать любое значение(числовое, например), либо все допустимые значения строго описаны.
ИТОГО: * Метод прост тем, что не нужны большие усилия для его реализации, достаточно взять пришедший URL и попыпаться выбрать его из базы * Он не может быть использован при большом числе динамического контента(например, лента новостей), так как в таком случае получается довольно большая база и необходимо контролировать все изменения, влекущие к созданию нового URL
Вариант 2 Базовые поля таблицы(pages): id – int – идентификатор страницы url – varchar – URL страницы handler – varchar – файл-обработчик
Довольно распространена ситуация, когда вывод подкатегорий почти не отличается друг от друга. Единственным отличием является группа, к которой принадлежит контент. Например, /news/sport и /news/tv из раздела /news различаются только тем, что, например, в sql-запросе в условии WHERE стоят разные группы(sport и tv, соответственно). Тогда как в /news группы вообще не учитываются. Из-за этого совершенно излишне делать отдельные обработчики для каждого URL, точнее, создание обработчиков сведётся к копированию и изменению 1 запроса(не забывайте про то, что при таком копировании при обнаружении какой-то ошибки вам придётся копировать всё заново).
При таком подходе необходимо добавить в БД 1 запись: url handler /news/ news.php
При загрузке страницы для выбора нужного файла-обработчика действуем по следующей схеме: пытаемся выбрать из БД полный если нет такого URL, то отрезаем от него часть и возвращаемся в п.1 для полученного URL отдаём управление handlerу
ИТОГО: Удобно для хранения страниц с параметрами (дата, номер поиска и т.д.), так как парамеры будут извлечены в отдельный массив Под опредeлённые условиях можно создать отдельный обработчик(например, существует категория новостей, где используется отличный от остальных новостей формат, либо данные хранятся в другой таблице) В случае, если не существует страница, например, /shop, то отобразаится главная страница, что может быть нежелательные, хотя и можно модифицировать код, чтобы при определённых условиях(например, нет страницы в «первом уровне») выдавалась страница с 404 ошибкой
Примеры поиска:
<?php // Удаляем лишние слеши, в начале и конце $url точно будет / $url = preg_replace(#/+#, /, /.$_SERVER[REQUEST_URI]./); $flag = FALSE; // Найдем обработчик? $param = array(); // Массив для параметров
while ($url != / && !$flag) { // Пытаемся выбрать обработчик для страницы $result = mysql_query(SELECT `handler` FROM `pages` WHERE `url`=.$url. LIMIT 1, $db); if (!mysql_num_rows($result)) { $url = substr($url, 0, strlen($url) - 1); // Отрезаем / на конце $url $pos = strrpos($url, /) + 1; $param[] = substr($url, $pos); // Отрезаем параметр $url = substr($url, 0, $pos); // Получаем новый $url } else { $row = mysql_fetch_assoc($result); // Получаем строку $handler = $row[handler]; // Помещяем обработчик в $handler $flag = TRUE; } unset($result); } // Переворачиваем массив с параметрами, чтобы они шли по порядку следования в URL $param = array_reverse($param); ?>
Данный код является ТОЛЬКО примером В итоге мы получаем все параметры в массиве $param, файл-обработчик в $handler.
Вариант 3 Базовые поля таблицы(pages): id – int – идентификатор страницы parent_id – int – родитель handler – varchar – обработчик, занимающийся страницей url – varchar – часть URL между //
Метод заключается в том, что используется древовидная структура и построение дерева происходит в PHP-скрипте.
Допустим, есть URL: /news/sport/smth Выбираем из базы:
Дальше остается только немного обработать результаты выборки.
ИТОГО: * При большой вложенности метод должен быть довольно медленным * Во многом он зависит от реализации * В зависимости от реализации, метод позволяет разбирать структуры подобные такой: <static>/<param>/<static>
Вариант 4
Базовые поля таблицы аналогичны Варианту 3.
Вариант работоспособен, если для хранения разделов будет использоваться Adjacency List. Вариант генерации запроса, не требующего дальнейшего разбора:
$sql1 = t0.id; $sql2 = $sql3 = ; for($i = 1, $c = sizeof($_url); $i < $c; $i++) { $sql1 = IF (t . $i . .id IS NOT NULL, t . $i . .id, . $sql1 . ); $sql2 .= +IF(t . $i . .id IS NULL,0,1); $sql3 .= LEFT JOIN structure t . $i . ON (t . $i . .parent_id = t . ($i-1) . .id AND t . $i . .url = . $this->db->Quote($_url[$i]) . ) ; } $pageId = $this->db->_Query(SELECT . $sql1 . AS id, 1 . $sql2 . AS count FROM structure t0 . $sql3 . WHERE t0.parent_id = 0 AND t0.url = . $this->db->Quote($_url[0])); $this->debug->Trace_R($pageId); ?>
Получаем:
Array ( [id] => 3 [param] => 1 )
Я думаю надо помимо id еще сразу тянуть все нужные данные (название раздела, обработчик и т.д.).
ИТОГО: * Максимальное число вложенностей ограничено засчёт того, что существует максимальное число JOIN в БД * Метод может быть медлительным, так как используется JOIN, при больших объёмах базы и большой вложенности скрипт может вылезти за временное ограничение
Вариант 5 Базовые поля страницы(pages): id – int – идентификатор страницы handler – varchar – обработчик url – varchar – регулярное выражение для URL, соответствующее обработчику
Лирическое отступление: вообще, мне этот метод был навеян pythonовским django, в котором именно при помощи регулярных выражений перечислялась обработка всех допустимых URL. Данный вариант является реализацией части функционала, предоставляемым Django с использованием БД.
Суть метода заключается в том, что в базе хранятся регулярные выражения, которые соответствуют URL. Выборка нужных страниц осуществляется посредством использования MySQLоного REGEXP.
Если немного расширить данный способ, то в PHP при помощи одного preg_match можно получить все параметры. А дальше уж насколько фантазии хватит.
ИТОГО: * Говорят, что регулярные выражения в исполнение My SQL не так уж быстры, а при большом числе страниц, это медлительность может стать катастрофической * Метод позволяет обрабатывать URL, построенных абсолютно любым способом, который можно описать при помощи регулярных выражений
Почти все приведённые варианты(кроме 3 и 5) страдают 1 проблемой: они не могут разбирать URL формата: /<static>/<param>/<static>/<param> и подобные
Добавление слeша в конце Вводная: Нужно добавлять слeш в конце URL, если он отсутствует.
ЧПУ при помощи ошибки 404 и POST данные Вводная: Сегодня стал детально разбираться с ЧПУ через обработку 404 ошибки. Вроде все замечательно работает, но вот я не могу получить данные из $_POST.
Ответ: Суть заключается в использовании директивы Error Document? для перенаправления всех несуществующих запросов на один скрипт. Главный существенный недостаток Error Document? – невозможность перехвата POST-данных! Чтобы получить POST данные формируйте action формы на реально существующий URL. Также, к недостаткам относится то, что засоряется error.log сервера, что мешает выявлению настоящих ошибок, которые необходимо исправить.
ЧПУ при момощи Multi Views? или Force Type? Apache
Вводная: Слышал, что существует способ «скрытия» расширения PHP-файлов при помощи конфигурирования непосредственно Apache.
Ответ: Первым является способ с использованием Mutli Views?. Сам способ заключается в том, что у реальносуществующего файла скрывается расширение. То есть до какого-то момента URL реальный, а после – нет. Он «включается» добавлением в .htaccess или к настройкам сервера:
На самом деле, это более понятно на примере. Допустим, у нас есть файл article.php, лежащий в корне Web-сервера. Тогда запросы вида /article/php_security1, /article/sessions будут обрабатываться скриптом article.php. Далее, уже всё зависит от разбора в скрипте остальной части URL(если требуется).
Второй способ основывается на Force Type?. Способ позволяет добиться аналогичного эффекта при использовании Force Type?. Мы называем файл просто article, а не article.php. И в .htaccess или конфигурации сервера добавляем:
Так что теперь файл article будет интерпретироваться PHP.