Переписывание произвольного количества сегментов пути для запроса параметров

У меня есть это правило .htaccess:

RewriteRule viewshoplatest/(.*)/(.*)/(.*)/(.*)/(.*)/(.*)/(.*)/(.*)/(.*)/(.*)/(.*)/(.*)/(.*)/(.*)/(.*)/(.*)/$ /viewshoplatest.php?$1=$2&$3=$4&$5=$6&$7=$8&$9=$10&$11=$12&$13=$14&$15=$16

Он должен отобразить такой URL:

http://www.veepiz.com/viewshoplatest/start/10/end/10/filter/0/ownerid/0/sortby/date/sortdir/DESC/cat/0/scat/0/

:

http://www.veepiz.com/viewshoplatest.php?start=0&end=10&filter=0&ownerid=0&sortby=date&sortdir=DESC&cat=0&scat=0

Когда я нажимаю ссылку и печатаю переменные $_GET, я получаю следующее:

Array ( [start] => 10 [end] => 10 [filter] => 0 [ownerid] => 0 [sortby] => start0 [start1] => start2 [start3] => start4 [start5] => start6 )

Любые идеи относительно того, почему он плохо себя ведет?


Хорошо, я исправил это, переписав правило на

RewriteRule viewshoplatest/start/(.*)/end/(.*)/filter/(.*)/ownerid/(.*)/sortby/(.*)/sortdir/(.*)/cat/(.*)/scat/(.*)/$ /viewshoplatest.php?start=$1&end=$2&filter=$3&ownerid=$4&sortby=$5&sortdir=$6&cat=$7&scat=$8

Ответ 1

Прежде всего: вы не должны использовать .*, если вы можете быть более конкретным, например, в этом случае [^/]+. Потому что множественный .* может привести к огромному возврату назад. Итак:

RewriteRule ^viewshoplatest/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/$ /viewshoplatest.php?$1=$2&$3=$4&$5=$6&$7=$8&$9=$10&$11=$12&$13=$14&$15=$16

Вы можете использовать взятый как RegexBuddy, чтобы увидеть разницу в том, как обрабатываются эти регулярные выражения.

Но так как mod_rewrite позволяет ссылаться только на первые девять групп (см. Tims answer), вы можете использовать итеративный подход и обрабатывать по одному параметру за раз:

RewriteRule ^viewshoplatest/([^/]+)/([^/]+)/([^/]+/[^/]+/.*)$ /viewshoplatest/$3?$1=$2 [QSA,N]
RewriteRule ^viewshoplatest/([^/]+)/([^/]+)/([^/]*)/?$ /viewshoplatest.php?$1=$2&$3 [QSA,L]

Первое правило будет обрабатывать одну пару пара за раз (кроме последней пары), добавив ее к уже существующим (см. флаг QSA), а затем перезапустить процесс перезаписи без увеличения внутреннего счетчика рекурсии (см. флаг N), Второе правило затем перепишет последнюю пару пара (или просто имя) и закончит итерацию.

Но так как использование флага N может быть опасным, так как это может вызвать бесконечную рекурсию, вы также можете использовать PHP для анализа запрошенного пути:

$_SERVER['REQUEST_URI_PATH'] = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$segments = implode('/', trim($_SERVER['REQUEST_URI_PATH'], '/'));
array_shift($segments); // remove path prefix "/viewshoplatest"
for ($i=0, $n=count($segments); $i<$n; ) {
    $_GET[rawurldecode($segments[$i++])] = ($i < $n) ? rawurldecode($segments[$i++]) : null;
}

Теперь вам просто нужно это правило, чтобы передать запрос через:

RewriteRule ^viewshoplatest(/|$) /viewshoplatest.php [L]

Ответ 2

Просто чтобы узнать, что вы узнали, вы можете определить только девять групп, которые будут использоваться в качестве обратных ссылок, поэтому обычно лучше переписать строку script sans-query и провести проверку script REQUEST_URI в случаях, когда у вас будет много данных для разбора.

Из документация:

Обратные ссылки - это идентификаторы формы $N (N = 0..9), которая будет заменяется содержанием Nth группа сопоставленного шаблона

$0 - это весь сопоставленный шаблон, который дает вам остальные девять чисел для работы. Любое большее число рассматривается как обратная ссылка, за которой следуют некоторые буквальные числовые символы.