URL, декодированный до правила перезаписи htaccess

#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, а затем преобразоваю обратно в ‘/’ перед последующим отображением. Спасибо, мистер Уайт.