.htaccess RewriteRule - DOCUMENT_ROOT и RewriteBase - PullRequest
3 голосов
/ 08 ноября 2010

У меня есть подкаталог secure / с несколькими файлами, над которыми я хочу выполнить несколько простых RewriteRules, просто по умолчанию добавив расширение PHP. Мне было трудно заставить их работать, и после некоторых проб и ошибок я наткнулся на следующее.

RewriteEngine On
RewriteBase /secure

# Force PHP extension if not a directory
RewriteCond %{DOCUMENT_ROOT}/secure/%{REQUEST_URI} -d
RewriteRule ^(.*)$ - [L]

RewriteCond %{DOCUMENT_ROOT}/secure/$1.php -f
RewriteRule ^((.*/)*[^./]+)/*$ $1.php [L]

Мое непонимание около %{DOCUMENT_ROOT} и добавление /secure/. Я полагал, что либо %{DOCUMENT_ROOT}, либо использование RewriteBase справится с этим. Тем не менее, каждая из этих частей, кажется, требуется. Я хотел бы знать, почему и что каждый добивается в моем случае.

1 Ответ

11 голосов
/ 08 февраля 2011

Директива RewriteBase используется mod_rewrite исключительно на этапах перенаправления и игнорируется при любой другой обработке.Вопреки тому, что говорится в документации, это часто не нужно, поскольку (как и в вашем случае) довольно часто URL-адрес сопоставляется с подкаталогами в файловой системе за пределами DOCUMENT_ROOT.

Итак, что делаетдиректива делать?Когда ваши правила оцениваются в контексте каждого каталога, как это делается при использовании файла .htaccess, URL передается mod_rewrite очень поздно в цепочке обработки запросов Apache.Это означает, что URL-адрес, возможно, уже был частично переведен в путь файловой системы, поэтому путь в / directory / subdirectory / file мог фактически быть доступен через веб-сервер через / location / subdirectory/file.

Это не кажется большой проблемой, но тот факт, что кусок / location / был потерян, создает проблему для mod_rewrite.Чтобы понять почему, вы должны знать, как mod_rewrite делает возможным перезапись контекста для каждого каталога.

Когда вы выполняете перезапись в файле .htaccess, mod_rewrite повторно вводит измененный запрос в Apache как внутренний редирект, как если бы онбыл URL.Это проблематично, поскольку путь запроса может не соответствовать URL для передачи.Например, если запрос оказался в / directory / subdirectory / file (который, как мы предполагаем, находится за пределами DOCUMENT_ROOT), у нас может быть это правило в / directory / .htaccess :

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* index.php

При этом будет проверен / подкаталог / файл , решено, что это не фактический файл, и переписан его в index.php .В этот момент новый URL должен быть возвращен Apache для внутреннего перенаправления, чтобы завершить перезапись.Поскольку он не имеет контрольной точки, он в конечном итоге отправляет весь путь, то есть отправляет / directory / index.php .Это не то, что вам нужно, так как URL для доступа к этому местоположению на самом деле будет / location / index.php .Вот тут и приходит RewriteBase. Если указать

RewriteBase /location/

в файле .htaccess, префикс каталога / directory / будет заменен на / location / какчасть этой обработки после перезаписи, приводящая к внутреннему перенаправлению на ожидаемый URL / location / index.php .

Это также имеет значение для внешних перенаправлений.Если вы попытаетесь перенаправить извне, используя флаг [R], указав только путь, и путь не будет иметь прямой косой черты, весь каталог будет отправлен обратно клиенту способом, описанным выше, если только он не будет заменен значениемдано в RewriteBase.

Ни одна из этих точек не представляется релевантной вашей ситуации, поэтому вам следует подойти без указания RewriteBase.

Переменная %{DOCUMENT_ROOT} является только значением внутренней ApacheDOCUMENT_ROOT переменная, которая устанавливается в конфигурации вашего сервера / виртуального хоста.Он всегда соответствует каталогу, в который разрешается запрос к / .Для проверок -f и -d требуется полный путь к файловой системе, поэтому %{DOCUMENT_ROOT} необходимо использовать предварительный путь к относительному пути при их использовании.

Для разрешения пути текущего запроса, однако, mod_rewriteпозаботится об этом с помощью переменной %{REQUEST_FILENAME}.Например, предполагая, что файл .htaccess находится в вашем подкаталоге / secure , вы можете изменить свой набор правил следующим образом:

RewriteEngine On

# Force PHP extension if not a directory
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]

RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^.*$ $0.php [L]
...