Назад | Перейти на главную страницу

Проверьте, существует ли файл в подкаталоге, и в противном случае перенаправьте все на главный контроллер

Что бы я хотел сделать с mod_rewrite в .htaccess файл под Apache выглядит следующим образом:

Моя попытка решения заключалась в следующем:

<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!)

  1. Поместите index.php в общую папку
  2. Сделайте DocumentRoot общедоступной папкой
  3. Используйте ErrorDocument для перенаправления любого файла, который не найден, в index.php

Если у вас есть причина использовать общую папку, вы можете использовать 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> синтаксис. Итак, сначала мы создаем строку, состоящую из:

  • Исходный URI запроса
  • Жестко запрограммированные разделители, которые мы не ожидаем встретить в URL-адресе ( :: часть).
  • Локальная (для каталога) часть URI, которая 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 намного проще.

Сноски:

  1. Фактически, разрешение относительного пути действительно работает при определенных условиях, как описано в отчет об ошибке для этой проблемы. Просто он работает не так, как ожидалось, и в большинстве распространенных конфигураций не будет работать вообще.
  2. Это странное обратное поведение на самом деле довольно просто: Apache всегда сначала решает RewriteRule и только затем проверьте, позволяют ли условия его применить.
  3. Это, кстати, не сработает, если вы используете Alias или аналогичные методы для сопоставления частей пространства URI сервера с другими местами, не находящимися в корне документа. Документацию для CONTEXT_DOCUMENT_ROOT чтобы выяснить, как обойти эту проблему.

Попробуйте использовать RewriteBase когда вы перемещаете его в подпапку:

RewriteBase /subfolder/
# Rules