General RewriteRule для многих неопределенных параметров в URL - PullRequest
0 голосов
/ 17 апреля 2010

Я пытаюсь написать правило, которое можно обобщить, так как несколько страниц для передачи значений различны. Прямо сейчас я мог бы сделать:

RewriteRule ^forum/([^/]{1,255})/([\+]{1})/((([a-z]+)([_]{1})([a-zA-Z0-9]+)([/]?))+)$   forum.php?name=$1&$5=$7 [L]

По адресу, например:

Nome+del+Forum/+/page_1/action_do

Должен вернуться:

forum.php?name=Nome+del+Forum&page=1&action=do

Вместо этого используйте только последний параметр (в данном случае action = do ):

forum.php?name=Nome+del+Forum&action=do

Как я могу исправить? Заранее спасибо!

Ответы [ 2 ]

0 голосов
/ 17 апреля 2010

Что-то вроде это ?

И см. Также это для получения дополнительной информации.

Основная информация - эти правила

RewriteCond %{QUERY_STRING} ^(.*)$
RewriteRule ^(.*/)([^/]+)/([^/]+) $1?$2=$3&%1 [L]
RewriteCond %{QUERY_STRING} ^(.*)$
RewriteRule ^([^/]+)/ $1?%1 [L]

перепишет следующее

/mypage/param1/val1/param2/val2/param3/val3/...     --->
/mypage?param1=val1&param2=val2&param3=val3&...

Он принимает первый параметр и вызывает эту страницу. Остальные параметры превращаются в строку запроса.

РЕДАКТИРОВАТЬ больше о том, как работает код.

Первая строка (и третья) просто фиксируют все после "?" чтобы его можно было добавить обратно в конец переписанного URL. Тоже самое можно сделать с помощью флага [QSA], но я предпочитаю это делать явно, так что это видно.

Строка сохраняется в переменной% 1.

Во второй строке используется регулярное выражение для разделения URL на три части.

$ 2 и $ 3 - последние две части пути. $ 1 - это все до этого.

Так вот:

/mypage/param1/val1/param2/val2/param3/val3/param4/val4/param5/val5/

Становится так:

$1                                                        $2      $3
/mypage/param1/val1/param2/val2/param3/val3/param4/val4/  param5  val5

и переписывается так (пробелы добавлены для удобства чтения):

/mypage/param1/val1/param2/val2/param3/val3/param4/val4/ ? param5 = val5

Если в вашем URL используются разделители, отличные от косой черты, вы можете изменить обычный выражение соответственно.

Флаг [L] («последний») запрещает запуск остальных правил. ОДНАКО - и это ключ - mod_rewrite вызывает веб-сервер с новым URL и новый URL отправляется через mod_rewrite снова! Иногда это называется рекурсией mod_rewrite и это именно то, что вы хотите, чтобы это работало.

В следующий раз следующие две части будут удалены с конца и добавлены к строке запроса.

Это: * +1042 *

$1                                           $2      $3     %1
/mypage/param1/val1/param2/val2/param3/val3  param4  val4 ? param5=val5

Становится так:

/mypage/param1/val1/param2/val2/param3/val3 ? param4 = val4 & param5=val5

Это продолжается до тех пор, пока все части URL не будут преобразованы в части строки запроса. Когда это происходит, вторая строка не совпадает но четвертая строка делает. Вот что дает вам ваш последний URL для вызова Программа, которую вы хотите. Ссылки выше показывают ответы на несколько разные варианты которые допускают разные правила для этого.

Также обратите внимание, что есть ограничения на количество раз mod_rewrite можно рекурсировать. Смотрите настройки для MaxRedirects в .htaccess и LimitInternalRecursion в вашем файле Apache Conf.

0 голосов
/ 17 апреля 2010

Самый простой способ, если вы можете указать RewriteMap prg:foo в конфигурации сайта. Обратите внимание, что вы не можете использовать RewriteMap в .htaccess, насколько я знаю.

Если у вас есть доступ к файлу конфигурации сервера, добавьте что-то вроде этого, либо глобально, либо в ваш <VirtualHost>:

RewriteMap forum prg:/path/to/forum-rewriter.pl

Тогда в выбранном вами .htaccess попробуйте:

RewriteRule ^forum/.* ${forum:$0} [QSA]

(В вашей попытке RewriteRule выглядело так, как будто вы хотели найти пути, начинающиеся с forum/, поэтому я здесь и делаю.)

Далее нужно сделать forum-rewriter.pl:

#!/usr/bin/perl

use strict;
use warnings;


$| = 1;
while ($_ = <STDIN>) {
    chomp($_);
    if (s,^forum/([^/]+)(/\+)?(/.*)?,forum.php?name=$1, && $3) {
        my $query_string = $3;
        $query_string =~ s,/([^/_]+)_([^/_]+),&$1=$2,g;
        $_ .= $query_string;
    }
    print "$_\n";
}

Обязательно chmod 755 /path/to/forum-rewriter.pl.

RewriteMap заставит Apache запускать forum-rewriter.pl один раз для каждого процесса httpd во время запуска. Каждый раз, когда шаблон RewriteRule совпадает, он записывает путь к стандартному вводу forum-rewriter.pl. forum-rewriter.pl выполнит свою работу (если есть) на URL и распечатает результат обратно в Apache.

К вашему сведению, это очень легко проверить forum-rewriter.pl. Просто запустите его и начните отправлять ему пути:

$ /tmp/forum-rewriter.pl
forum/Nome+del+Forum/+/page_1/action_do
forum.php?name=Nome+del+Forum&page=1&action=do
forum/Nome+del+Forum/page_1/action_do
forum.php?name=Nome+del+Forum&page=1&action=do
forum/Nome+del+Forum
forum.php?name=Nome+del+Forum
foo
foo

Если вы не можете использовать RewriteMap, я думаю, это возможно с mod_rewrite , но я думаю, что это опасно :

RewriteCond %{ENV:SetForumName} =""
RewriteRule ^forum/([^/]+)(/\+)?(/.*)? /forum.php$3?name=$1 [QSA,E=SetForumName:1]
RewriteCond %{ENV:SetForumName} !=""
RewriteRule ^forum.php/([^/_]+)_([^/_]+)(/.*)? /forum.php$3?$1=$2 [N,QSA]

Это опасно, потому что [N] заставляет Apache перезапустить обработку всех правил перезаписи, когда эта вторая RewriteRule совпадает. Если вы не будете осторожны, вы создадите бесконечный цикл, и Apache выполнит либо 500 запросов, либо карканье. Также обратите внимание на побочный эффект, связанный с установкой переменной окружения SetForumName. Тем не менее, это единственный способ, который я смог найти, чтобы сказать mod_rewrite «заменить all foo_bar в пути на foo=bar в строке запроса».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...