Что бы я хотел сделать с mod_rewrite
в .htaccess
файл под Apache выглядит следующим образом:
foo.txt
или foo/bar
, получен, проверьте, существует ли такой файл в public
подкаталог, например public/foo.txt
или public/foo/bar
. Если это так, просто отобразите этот файл.index.php
Моя попытка решения заключалась в следующем:
<IfModule mod_rewrite.c>
RewriteEngine On
# Don't rewrite requests for files in the 'public' directory
RewriteRule ^(public)($|/) - [L]
# For all other files first check if they exist in 'public'
RewriteCond %{DOCUMENT_ROOT}/public%{REQUEST_URI} -f
RewriteRule ^ public%{REQUEST_URI} [L]
# Let 'index.php' handle everything else
RewriteRule . index.php [L]
</IfModule>
К сожалению, есть серьезный недостаток: он не работает в подкаталогах, т.е. когда .htaccess
а все остальные файлы перемещаются из /
к /sub/
. В идеале он работал бы в произвольный вложенные папки, конечно.
Кто-нибудь может помочь? Как я могу исправить .htaccess
чтобы устранить этот недостаток?
Не похоже, что вы хотите получить доступ к чему-либо за пределами папки / public? Если так, мне это кажется простым и без каких-либо переписываний (надеюсь, что на самом деле нет никаких причин, по которым вы хотеть использовать mod_rewrite
!)
Если у вас есть причина использовать общую папку, вы можете использовать mod_rewrite
для перенаправления чего-либо, кроме index.php, в public / something, и по-прежнему использовать ErrorDocument для перенаправления на index.php.
Этот набор правил мне подходит. Я пропустил проверку путей, начинающихся с / public.
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}/public%{REQUEST_URI} -f
RewriteRule ^/(.*) /public/$1 [L]
RewriteRule . /index.html [L]
Если /public
не находится в корне вашего документа, вы можете заменить% {DOCUMENT_ROOT} на путь на диске к каталогу / public. В CONTEXT_DOCUMENT_ROOT
может содержать путь к файлу в каталоге содержимого для .htaccess
файл Если у вас нет такого же файла в /public/public
как в /public
, то RewriteCond
не будет совпадать. Я избежал этой проблемы, используя свой эквивалент /public
как мой docroot. Если ты не можешь поставить index.php
в /public
, ты можешь использовать Alias
чтобы получить к нему доступ, где он есть.
Ваш подход предполагает переписывание всех совпадений. Альтернативный набор правил с использованием ../public
в качестве корня вашего документа будет:
Псевдоним /index.php /var/www/index.php RewriteCond% {REQUEST_FILENAME}! -F RewriteCond% {REQUEST_FILENAME}! -D RewriteRule. /index.php [L]
Вы также можете обработать отсутствующие файлы с помощью настраиваемой страницы ошибки 404.
У меня была аналогичная проблема, когда я хочу распространять веб-приложение, которое ведет себя так, как вы описываете: в определенном каталоге есть куча статических файлов, к которым можно получить доступ, как если бы они находились в корне веб-приложения (т.е. /images/pic.png
получить изображение в public/images/pic.png
), а все остальное отображается в сценарий контроллера.
Первая проблема, с которой я столкнулся, заключается в том, что -f
в RewriteCond
не работает с относительным путем - т.е. если строка "TestPattern" может быть разрешена в файл относительно каталога, в котором указано условие (используя .htaccess
), -f
по-прежнему будет возвращать "не соответствует"(1).
Поэтому нам нужно попытаться «понять», какой префикс для каталога используется .htaccess
файл находится в, и mod_rewrite
фактически решает эту проблему для нас и гарантирует, что RewriteRule
всегда оценивается относительно префикса каталога .htaccess
файл, но, к сожалению, он никоим образом не раскрывает эту информацию, RewriteCond
может получить доступ (они действительно должны позволить нам это).
При этом, очевидно, есть несколько странных вещей, которые вы можете сделать с RewriteCond
чтобы заставить CondPattern выявить взаимосвязь между %{REQUEST_URI}
и RewriteRule
ввод - читать ответы на этот вопрос за все странные вещи, которых вы можете достичь.
Но сокращая эти уловки только до проблемы (получение -f
чтобы соответствовать правильному пути относительно .htaccess, независимо от того, где он может быть) мы получаем эту довольно простую вещь:
RewriteEngine On
RewriteCond %{REQUEST_URI}::$1 ^(.*?/)(.*)::\2
RewriteCond %{DOCUMENT_ROOT}%1static/%2 -f
RewriteRule ^(.*)$ static/$1 [END]
RewriteRule . index.php [END,QSA]
Регулярное выражение в RewriteCond
очень ограничен тем, что не разрешается для переменных и захваченного текста, но может использовать обратные ссылки на себя с помощью \<number>
синтаксис. Итак, сначала мы создаем строку, состоящую из:
::
часть).RewriteRule
будет соответствовать - это $1
часть: RewriteCond
может посмотреть на группу захвата цели RewriteRule
(2), поэтому мы фиксируем весь ввод.Затем мы применяем регулярное выражение, объясняющее связь между этим URI запроса и RewriteRule
input - URI запроса состоит из двух частей (первая и вторая записи), где первая заканчивается на /
а второй идентичен тому, что появляется после ::
разделитель - \2
просто ссылается на второй захват в том же регулярном выражении и говорит, что он должен быть идентичным.
В результате мы разбили URI запроса на две группы захвата - первая - это префикс локального каталога, который mod_rewrite
наслаждается конфиденциально, а второй - это локальный путь в этом каталоге, который мы хотим проверить. Второе условие использует %<number>
чтобы ссылаться на эти снимки, создавая абсолютный путь под корнем документа(3). Обратите внимание, что %1
фиксирует как начальную, так и конечную косую черту префикса URI.
Наконец, обратите внимание, что я использую END
флаг вместо L
(последний), так как он быстрее и существует mod_rewrite
немедленно. Это позволяет мне отказаться от строки с RewriteRule … - [L]
который существует только для того, чтобы остановить поведение L
это фактически не останавливает обработку: он просто возвращается к началу или правилам перезаписи с новым URL-адресом. END
намного проще.
RewriteRule
и только затем проверьте, позволяют ли условия его применить.Alias
или аналогичные методы для сопоставления частей пространства URI сервера с другими местами, не находящимися в корне документа. Документацию для CONTEXT_DOCUMENT_ROOT
чтобы выяснить, как обойти эту проблему.Попробуйте использовать RewriteBase
когда вы перемещаете его в подпапку:
RewriteBase /subfolder/
# Rules