Доброго времени суток.
Eсть ссылки типа:
index.php?page=art
index.php?page=art&subpage=pic
index.php?page=art&subpage=pic&sub2page=pic2преобразовать в человеческий вид не составляет труда:
/art.html
/art/pic.html
/art/pic/pic2.htmlВопрос заключается вот в чем:
заранее не известна вложенность страниц. Как можно понять выше, структура может быть
/art->element1
/art->el1->el2->el3 ... ->elnдля последнего варианта, когда не известна конкретная вложенность страниц, возможно ли написать какое-либо универсальное правило, которое будет динамически строить ссылки вида /art/el1/.../eln.html ?
> index.php?page=art
> index.php?page=art&subpage=pic
> index.php?page=art&subpage=pic&sub2page=pic2
>
> /art.html
> /art/pic.html
> /art/pic/pic2.htmlКак вариант можно заменять строки вида "&sub[цифры]page=" на "/".
>Как вариант можно заменять строки вида "&sub[цифры]page=" на "/".Ой, что за глюки! Имелась в виду строка вида "& sub [цифры] page=" без пробелов.
>>Как вариант можно заменять строки вида "&sub[цифры]page=" на "/".
>Эм, да, этот вариант можно рассмотреть :)
Но, вопрос закрывать рано.Вот к примеру, как я предполагаю переписывать урлы:
для первого уровня вложенности:
RewriteRule ^([a-z0-9]+)/([a-z0-9]+).html$ index.php?page=$1&subpage=$2
тобишь вводим: /art/pic.html
получаем: index.php?page=art&subpage=picТ.к. в адресной строке уже будет ЧПУшный урл, полагаю, то нам надо наоборот "/" превращать в "&sub[цифры]page=". В предыдущем RewriteRule четко задана вложенность, т.е. встречается только 1 "/". Как нам этим правилом пройтись ПО ВСЕМУ урлу в поисках "/", заменяя на "&sub[цифры]page=", еще и вместо [цифры] подставляя порядковый номер?
А, да, конечно, надо же менять наоборот :) С этим сложнее. Предлагаю немного пересмотреть схему и вместо параметров sub[цифры]page использовать массив subpage примерно так:index.php?subpage[]=art&subpage[]=pic&subpage[]=pic2
Тогда скрипт PHP получит массив $_GET["subpage"] = array("art", "pic", "pic2"), что на мой взгляд гораздо удобнее как для RewriteRule, так и для дальнейшего разбора.
>А, да, конечно, надо же менять наоборот :) С этим сложнее. Предлагаю
>немного пересмотреть схему и вместо параметров sub[цифры]page использовать массив subpage примерно
>так:
>
> index.php?subpage[]=art&subpage[]=pic&subpage[]=pic2
>
>Тогда скрипт PHP получит массив $_GET["subpage"] = array("art", "pic", "pic2"), что на
>мой взгляд гораздо удобнее как для RewriteRule, так и для дальнейшего
>разбора.Тоже интересная идея :) Но опять таки для строительства такой ссылки, в RewriteRule нужно четко указывать структуру линка, т.е. количество вложенных "разделов". А оно у нас изменчиво, и зависит от того, как встанут звезды :)
Отсюда немного видоизмененный предыдущий вопрос: как нам этим правилом пройтись ПО ВСЕМУ урлу в поисках "/", заменяя на "&sub[]page="?
Вчера под вечер была еще идейка решения проблемы: при добавлении нового раздела просто дописывать в .htaccess соответствующее правило. Но надо бы рассмотреть альтернативные варианты.
Я тут подумал, а что, собственно, париться? Можно же сделать это по-простому:RewriteCond %{REQUEST_URI} \.html$
RewriteRule ^(.*)$ index.php?path=$1&%{QUERY_STRING}Тогда при запросе /art/pic/pic2.html?qq=ww&ee=rr будет вызван index.php?path=art/pic/pic2.html&qq=ww&ee=rr. Дальше на PHP простейший анализ:
$subpage = explode('/', substr($_GET['path'], -5))
И всё.
>RewriteCond %{REQUEST_URI} \.html$
>RewriteRule ^(.*)$ index.php?path=$1&%{QUERY_STRING}
>
>Тогда при запросе /art/pic/pic2.html?qq=ww&ee=rr будет вызван index.php?path=art/pic/pic2.html&qq=ww&ee=rr. Дальше на PHP простейший анализ:
>
>$subpage = explode('/', substr($_GET['path'], -5))Да, умно :) Принимать всего одну переменную и ее разбирать... Тут отдельная благодарность, скорее всего этот вариант и реализую.
Можно поразвлекаться еще немного. Следующий вопрос не стоит как "обязательный" вариант, но теоретически было бы полезно подумать над еще одним вариантом реализации.
На том же примере. С вложенностью "категорий" вроде разобрались.А что если нужно в php-скрипте анализировать связку переменных. Т.е., к примеру, нам нужно проверять переменную 'cat', которая должна быть равна 'art' (index.php?cat=art), потом перменную 'act' с значением 'pic' (index.php?act=pic) и т.д.
Т.е. получаемый урл должен быть вида index.php?cat=art&act=pic.
Вводимый урл: /art/pic/
В вышестоящем примере мы просто получим массив со значениями 'art' и 'pic'.
Т.к. заведомо вложенность категорий не известна, мы не можем на абум в скрипте присвоить соответствующим перменным (cat и act) значения из полученного массива (art и pic).
Как быть тут с более менее оптимальным вариантом?Как я сказал, можно при добавлении новой категории средствами пхп дописывать в .htaccess новое правило, в котором будет строиться конечный урл вида index.php?cat=$1&act=$2 .
Не нравится то, что постоянно прийдется писать новые правила. А если категорий будет много? :) На каждую по правилу - не оптимально.
>>RewriteCond %{REQUEST_URI} \.html$
>>RewriteRule ^(.*)$ index.php?path=$1&%{QUERY_STRING}
>>
>>Тогда при запросе /art/pic/pic2.html?qq=ww&ee=rr будет вызван index.php?path=art/pic/pic2.html&qq=ww&ee=rr. Дальше на PHP простейший анализ:
>>
>>$subpage = explode('/', substr($_GET['path'], -5))
>Кой-чего родил. Тут конечно все зависит от конкретный требований, но в принципе можно и обойтись вышеизложенным вариантом.
Получаем из урла список категорий. И в порядке их следования получаем ихние ID в базе данных.
1-й ($cat1_id = ): select id from cat where name = '$subpage[1]' (т.к. корневая категория всегда будет с уникальным именем)
2-й: select id from cat where name = '$subpage[1]' and parent = '$cat1_id' (т.к. уже вторая категория в таблице может повторятся. Тобишь может быть /art/pic/ и /pass/pic).
Ну и дальше до конечной страницы :)
Блин, такое впечатление, что я изобретаю велосипед :)P.S.
>>$subpage = explode('/', substr($_GET['path'], -5))Эта фигня не правильна. В $subpage у нас будет только '.html' :) Проверено.
Проще брать все: $subpage = explode('/', $_GET['path'])
, а потом просто удалять '.html': unset($subpage[последний_элемент]);Собственно. Покритикуй(те) :)
Да, ошибся маленько, нужно так:$subpage = explode('/', substr($_GET['path'], 0, -5))
Если нужно /art/pic преобразовать в переменные $cat="art" $act="pic", то после этого можно указать
$cat = array_shift($subpage); $act = array_shift($subpage);
или что-то в этом роде в зависимости от логики программы. Оставшиеся элементы будут в массиве $subpage. Или я что-то про твои "категории" не понял - тогда растолкуй, что хочешь получить в итоге, потому что дальше колдовство с БД совсем непонятно.
>[оверквотинг удален]
>
>Если нужно /art/pic преобразовать в переменные $cat="art" $act="pic", то после этого можно
>указать
>
>$cat = array_shift($subpage); $act = array_shift($subpage);
>
>или что-то в этом роде в зависимости от логики программы. Оставшиеся элементы
>будут в массиве $subpage. Или я что-то про твои "категории" не
>понял - тогда растолкуй, что хочешь получить в итоге, потому что
>дальше колдовство с БД совсем непонятно.Что касается "катгорий": цель - дать возможность через панель управления создавать неограниченное количество каталогов (тут я понимаю "категория" как "каталог" в урле), подкаталогов, и страниц в них :)
В принципе за основу возьму explode('/', substr($_GET['path'], 0, -5)) , а дальше уже будет видно, как работать в конкретных условиях.
Спасибо за "беседу" и помощь :)
Еще вот столкнулся с проблемкой. Суть такова:
Есть адреса, к примеру:
/files/cat1/
/company/about/
Как мы уже тут говорили, реальный передаваемый адрес будет, к примеру: index.php?path=/files/cat1/ . Его разбираем и дальше, тут не интересно.Что нужно: передавать ссылки типа index.php?name=[название_первого_каталога]&path=...
т.е., к примеру: index.php?name=files&path=/files/cat1/
Это я планировал сделать в .htaccess. Пишу правила:
RewriteCond %{REQUEST_URI} ^/(files)/?
RewriteRule ^(.*)$ index.php?name2=%1&path2=$1&%{QUERY_STRING} [L]
RewriteRule ^(.*)$ index.php?name=content&path=$1&%{QUERY_STRING} [L]
Как должно быть (думаю): в следствии первого RewriteRule, следующего после RewriteCond апдрес получается index.php?name2=files&path... и преобразование урлов заканчивается.
Если RewriteCond не сработал, выполняется последний урл.Что мы получаем на практике. На первых приведенных примерах адресов:
В случае /company/about/ - все работает как положено. name имеет знчение content и на этом все заканчивается. Имеем что планировали
print_r($_GET):
[name] => content
[path] => company/about/
В случае /files/cat1/ - не имеем что надо.
print_r($_GET):
[name] => content
[path] => index.php
[name2] => files
[path2] => files/cat1/
схавало оба правила, получилось черти что. Более того, если поменять /files/ на что-то другое, нонсенс:
/filesFailed/cat1/
print_r($_GET):
[name] => content
[path] => index.php
[name2] => files
[path2] => filesFailed/cat1/
В name2 почему-то вопхнулось только первая часть названия каталога. Однако в RewriteCond у нас явно указано "files" и ничего более.В чем может быть загвоздка? :)
> RewriteCond %{REQUEST_URI} ^/(files)/?...
>В name2 почему-то вопхнулось только первая часть названия каталога. Однако в RewriteCond
>у нас явно указано "files" и ничего более.А "/?" ни о чём не говорит?
Лично у меня нет никакого желания разбираться в хитросплетениях работы mod_rewrite, поэтому я решил эту задачу за 10 минут на PHP, почти ничего к "реврайту" не добавляя. Вот моё решение:
.htaccess
----------------------------------------------------------------
RewriteEngine on
RewriteBase <мой путь>RewriteCond %{REQUEST_URI} (\.html|/)$
RewriteRule ^(.*)$ index.php?path=$1&%{QUERY_STRING}
----------------------------------------------------------------index.php
----------------------------------------------------------------
<?phpheader("Content-type: text/plain; charset=UTF-8");
echo '_GET = '; print_r($_GET);
$cats = array('files', 'content', 'foo', 'bar');
$defaultCat = 'content';$path = ltrim($_GET['path'], '/');
if (preg_match('/\.html$/', $path)) {
$type = 'html';
$path = substr($path, 0, -5);
} elseif (preg_match('/\/$/', $path)) {
$type = 'dir';
$path = substr($path, 0, -1);
} else {
die("Oops! I don't understand this path: $path");
}$subpage = explode('/', $path);
if (in_array($subpage[0], $cats)) {
$cat = array_shift($subpage);
} else {
$cat = $defaultCat;
}echo "type = $type\ncat = $cat\nsubpage = "; print_r($subpage);
?>
----------------------------------------------------------------Ввожу http://<мой домен>/<мой путь>/files/qq/ww.html?foo=bar, получаю:
_GET = Array
(
[path] => files/qq/ww.html
[foo] => bar
)
type = html
cat = files
subpage = Array
(
[0] => qq
[1] => ww
)Ввожу http://<мой домен>/<мой путь>/filesFailed/qq/ww/ee/?foo=bar
_GET = Array
(
[path] => filesFailed/qq/ww/ee/
[foo] => bar
)
type = dir
cat = content
subpage = Array
(
[0] => filesFailed
[1] => qq
[2] => ww
[3] => ee
)В общем - старик Оккам и принцип KISS рулят, как обычно :)
P.S. Люблю иногда такие задачки порешать...
>> RewriteCond %{REQUEST_URI} ^/(files)/?
>
>...
>>В name2 почему-то вопхнулось только первая часть названия каталога. Однако в RewriteCond
>>у нас явно указано "files" и ничего более.
>
>А "/?" ни о чём не говорит?
>Конечно же говорит. Это позволяет одинаково работать путям с последним слешем и без него:
/files и /files/
Допустим, если>Лично у меня нет никакого желания разбираться в хитросплетениях работы mod_rewrite, поэтому
Жаль, на самом деле интересная весчь. Искренне хочется врулить, почему же таки мой вариант не работает как надо. В теории вроде бы все ок :)
>я решил эту задачу за 10 минут на PHP, почти ничего
>к "реврайту" не добавляя. Вот моё решение:
>Если уже решать это на PHP, мне кажется есть более компактное простое решение. Просто из адреса /files/cat1/ или /company/about/ берем название первого "каталога", и смотрим, если не "files", то name=content. А если "files" (и другие интересующие) - значит name=[название].
Однако хочется разрулить именно с модРеврайтом :)
>>> RewriteCond %{REQUEST_URI} ^/(files)/?
>>А "/?" ни о чём не говорит?
>
>Конечно же говорит. Это позволяет одинаково работать путям с последним слешем и
>без него:
>/files и /files/А мне оно говорит, что под этот шаблон попадает и /files и /filesFailed и /files_что_угодно. Вообще здесь ^/(files)/? эквивалентно ^/(files) - угадай почему :)
>Жаль, на самом деле интересная весчь. Искренне хочется врулить, почему же таки
>мой вариант не работает как надо. В теории вроде бы все
>ок :)Вещь интересная, но времени мало :(
>Если уже решать это на PHP, мне кажется есть более компактное простое
>решение. Просто из адреса /files/cat1/ или /company/about/ берем название первого "каталога",
>и смотрим, если не "files", то name=content. А если "files" (и
>другие интересующие) - значит name=[название].Так у меня ровно это и есть.
>Однако хочется разрулить именно с модРеврайтом :)
Попробуй. Если получится, буду рад за тебя.
>
>А "/?" ни о чём не говорит?
>С этим разобрался. Прийдется явно указывать последний слеш...
Спасибо :)