#php #apache #.htaccess #mod-rewrite
#php #apache #.htaccess #мод-перезапись
Вопрос:
У меня есть следующее правило перезаписи в .htaccess :-
RewriteRule ^.*/-y.* /handleurl.php [L]
Его цель — отображать соответствующие страницы в зависимости от значений в URL, например:
example.com/books/BookA/-y?act=x
будет отображаться страница bookA
переменная, содержащая название книги, кодируется таким образом, что …
example.com/books/Book B/-y?act=x
становится example.com/books/book B/-y?act=x
… это нормально (оно декодируется в handleurl.php
)
однако, если книга вызывается Book A/B
, у меня есть…
example.com/books/Book A/B/-y?act=x
который становится example.com/books/Book A/B/-y?act=x
Похоже, что htaccess декодирует это перед правилом перезаписи, поэтому правило перезаписи видит слишком много элементов в URL-адресе, обозначенном /
.
Есть ли какой-либо способ заставить правило перезаписи игнорировать закодированное /
по назначению?
Я видел предыдущий ответ на аналогичный вопрос, но мне нужно только /
игнорировать, а не другие закодированные символы.
Ответ №1:
Похоже, что htaccess декодирует это перед правилом перезаписи, поэтому правило перезаписи видит слишком много элементов в URL-адресе, обозначенном
/
Проблема не в этом. Независимо от того, декодирован URL-путь /books/Book A/B/-y
или нет, здесь нет никакой разницы * 1. Оба будут соответствовать (довольно щедрому) регулярному ^.*/-y.*
выражению в RewriteRule
шаблоне.
(* 1 Но да, URL-путь, соответствующий RewriteRule
шаблону, декодируется URL, т.е. %-декодируется.)
Проблема, вероятно, заключается в том, что Apache (по умолчанию) отклоняет — с помощью 404 — любой URL, содержащий %-кодированную косую черту ie. /
(или обратная косая
черта) в части URL-пути URL. Это функция безопасности, которая в противном случае «потенциально может разрешить небезопасные пути» (источник).
Однако это можно переопределить с AllowEncodedSlashes
помощью директивы. Но эта директива может использоваться только в контексте сервера или виртуального хоста. Он не может быть использован в .htaccess
.
Вам либо нужно AllowEncodedSlashes On
разрешить кодированные косые черты, которые также декодируются, как и для других символов. Или установите AllowEncodedSlashes NoDecode
для разрешения кодированных косых черт, но не декодируйте их — что предпочтительнее и, вероятно, то, что вы ожидаете.
В сторону #1:
RewriteRule ^.*/-y.* /handleurl.php [L]
Регулярное выражение ^.*/-y.*
является очень общим, возможно, слишком общим. Это то же самое, что и просто /-y
. Чему .*
-y
должно соответствовать после? Из ваших примеров URL-адресов похоже -y
, что он всегда находится в конце URL-пути, поэтому его можно привязать, например. /-y$
. И если URL, который вам нужно сопоставить, всегда начинается /books/
, то, возможно, это также следует включить в регулярное выражение?
В сторону #2:
… название книги кодируется таким образом, что …
example.com/books/Book B/-y?act=x
становитсяexample.com/books/book B/-y?act=x
… что нормально (оно декодируется в handleurl.php )
Это не строго «URL-кодированный», вы преобразовали пробел в a
в URL-пути. Это
допустимая «кодировка URL» для пробела, когда используется только в строке запроса. A
в URL-пути является литералом
(и будет отображаться поисковыми системами как таковой). В URL-пути пробел будет кодироваться как URL
. (Возможно, вы использовали неправильные функции кодирования PHP, например. urlencode()
вместо rawurlencode()
?)
Конечно, вы можете конвертировать / кодировать URL-адрес, однако вы хотите создать более читаемый URL-адрес — при условии, что он действителен.
Комментарии:
1. Мистер Уайт, спасибо. Я явно лаял не на то дерево. Сообщение Not Found [url], которое я получал, было, я думаю, как вы предлагаете, из-за того, что Apache не нравится кодировка / . Я удаляю этот бит кодировки, и он работает (хотя следующая программа завершается сбоем с дополнительным / — но это из-за плохого дизайна, который я теперь могу исправить. Я также постараюсь улучшить и упростить правила перезаписи в соответствии с вашими заметками.
Ответ №2:
Правило перезаписи никогда не было проблемой. Я думаю, что Apache не понравилось закодированное ‘/’ и тот факт, что программа обработки URL-адресов ниже по потоку использовала ‘/’ в качестве разделителя при идентификации отдельных элементов url. Я должен решить: 1) хочу ли я разрешить ‘/’ в переменных, составляющих элементы свободного URL, и 2) если да, то как передать его, не нарушая Apache, и как впоследствии удалить URL. Возможно, я преобразоваю ‘/’ в ‘~’ в пользу URL, а затем преобразоваю обратно в ‘/’ перед последующим отображением. Спасибо, мистер Уайт.