Переписывание URL-адреса на основе каталога в пользовательский запрос

#apache #.htaccess #mod-rewrite #url-rewriting

#apache #.htaccess #мод-переписать #url-переписывание

Вопрос:

Мне нужно переписать каталог на основе URL:

 https://example.com/subdir/gulp-service/category?parent=666amp;name=test
 

для строки запроса:

 ?service=gulp-serviceamp;file=categoryamp;query_string=parent=666amp;name=test
 

.htaccess должно работать https://example.com/subdir/ .
Как написать такой .htaccess ?

Я хочу, чтобы работали 2 URL-адреса:

 https://example.com/subdir/gulp-service
 

и

 https://example.com/subdir/gulp-service/category?parent=666amp;name=test
 

Я написал для службы и файла:

 RewriteEngine On
RewriteRule ^([a-z0-9-] )$ ?service=$1
RewriteRule ^([a-z0-9-] )/([a-z] )$ ?service=$1amp;file=$2
 

в PHP после print_r($_GET) того, как я:

 Array
(
    [service] => mskip-service
    [file] => category
)
 

Как добавить недостающую часть URL-адреса в строку запроса?

Комментарии:

1. Спасибо, что поделились своими усилиями, значит, вы нажали ссылку group.com/subdir/gulp-service/category?parent=666amp;name=test в браузере? Что должно обслуживаться по какой ссылке? Не могли бы вы подробнее рассказать об этом?

2. Какова цель URL-пути? В вашем примере похоже, что это корень документа? Или, возможно, он должен перезаписать тот же URL-путь? ?service=gulp-serviceamp;file=categoryamp;query_string=parent=666amp;name=test — Хотя это выглядит неправильно, поскольку это приведет к query_string / parent=666 и name / test , что не выглядит так, как будто это намерение? Предположительно query_string , параметр URL должен содержать всю строку запроса из первоначального запроса? В этом случае он должен быть %-закодирован как ?service=gulp-serviceamp;file=categoryamp;query_string=parent=666&name=test . (?)

3. Да, конечно, это может быть URL-адрес в кодировке, но как это сделать, чтобы добавить его в строку запроса?

4. Предположительно 666 , и test в parent=666amp;name=test являются переменными? Значение parent всегда числовое? Всегда ли параметры URL (если они вообще присутствуют) parent=<number>amp;name=<something> , или это само по себе может быть переменным? Ваши директивы подразумевают, что сегмент gulp-service пути и сегмент category пути также являются переменными?

Ответ №1:

Предположительно, вам требуется следующее в вашем результирующем $_GET массиве, учитывая ваш второй пример URL:

 Array
(
    [service] => mskip-service
    [file] => category
    [query_string] => parent=666amp;name=test
)
 

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

В противном случае вы получите следующий (нежелательный / искаженный) вывод * 1:

 Array
(
    [service] => mskip-service
    [file] => category
    [query_string] => parent=666
    [name] => test
)
 

Итак, вместо следующего (как в вашем примере):

 ?service=gulp-serviceamp;file=categoryamp;query_string=parent=666amp;name=test
 

Это должен быть URL-адрес, закодированный таким образом в конечной цели:

 ?service=gulp-serviceamp;file=categoryamp;query_string=parent=666&name=test
 

Для этого нет встроенного метода ( escape() функция в выражениях Apache не кодирует = и amp; — два символа, которые нам нужно кодировать!). Однако мы можем эффективно искать / заменять эти символы в строке запроса с помощью внутреннего рекурсивного цикла, прежде чем переписывать конечный запрос.

Я бы также рассмотрел возможность объединения двух правил в одно. Итак, оба ваших примера обрабатываются одним правилом. Единственное предостережение при этом заключается в том, что в первом примере вы получаете пустой file параметр URL. И вы всегда будете получать query_string параметр URL, который может быть пустым, если в первоначальном запросе нет строки запроса.

Вместо этого попробуйте следующее:

 # Manually encode "=" in query string with search/replace
RewriteCond %{QUERY_STRING} (. )=(. )
RewriteRule ^[a-z0-9-] (/[a-z] )?$ $0?%1=%2 [N=20]

# Manually encode "amp;" in query string with search/replace
RewriteCond %{QUERY_STRING} (. )amp;(. )
RewriteRule ^[a-z0-9-] (/[a-z] )?$ $0?%1&%2 [N=20]

# Finally rewrite to desired URL-path
RewriteRule ^([a-z0-9-] )(?:/([a-z] ))?$ ?service=$1amp;file=$2amp;query_string=%{QUERY_STRING} [L]
 

Обратите внимание, что % символы, являющиеся частью последовательности, закодированной в %, должны быть экранированы обратной косой чертой в строке подстановки, чтобы избежать конфликта с %N обратными ссылками.

N Флаг заставляет механизм перезаписи немедленно запускаться заново, используя текущий результат в качестве входных данных. Значение здесь указывает максимальное количество циклов, которые будут выполняться (требуется Apache 2.4.8).

К моменту обработки 3-го правила, которое выполняет требуемую перезапись, исходная строка запроса (т.е. значение QUERY_STRING переменной сервера) уже имело все экземпляры = и amp; заменено на = и & соответственно.


ОБНОВЛЕНИЕ: * 1 Однако, если «искаженный» вывод (как упоминалось выше) «ОК», тогда решение проще. Вам просто нужно 3-е правило сверху:

 # Append the original query string (unencoded)
RewriteRule ^([a-z0-9-] )(?:/([a-z] ))?$ ?service=$1amp;file=$2amp;query_string=%{QUERY_STRING} [L]
 

Затем вы получите вывод:

 Array
(
    [service] => mskip-service
    [file] => category
    [query_string] => parent=666
    [name] => test
)
 

Однако в этом случае на самом деле не было бы никакой необходимости в дополнительном query_string параметре URL (который, возможно, все равно сломан). Вы можете просто объединить (добавить) исходную строку запроса и вручную извлечь необходимые значения. Например:

 # Merge the original query string
RewriteRule ^([a-z0-9-] )(?:/([a-z] ))?$ ?service=$1amp;file=$2 [QSA,L]
 

QSA Флаг добавляет (объединяет) исходную строку запроса.

Для получения следующего вывода, учитывая пример URL:

 Array
(
    [service] => mskip-service
    [file] => category
    [parent] => 666
    [name] => test
)
 

Если вы удалите элементы «service» и «file» из массива, вы сможете восстановить исходную строку запроса из оставшихся пар имя / значение.

(Хотя это может зависеть от того, что серверный скрипт ожидает в качестве входных данных.)