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

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

  • Если запрос на любой файл или путь , например, foo.txt или foo / bar , получено, проверьте, существует ли такой файл в подкаталоге public , например public / foo.txt или public / foo / bar . Если это так, просто отобразите этот файл.
  • В противном случае я хотел бы сделать с mod_rewrite в файле .htaccess под Apache:

    • Если запрос любого файла или пути, например ] foo.txt или foo / bar , проверьте, существует ли такой файл в подкаталоге public , например public / foo.txt или public / foo / bar . Если это так, просто отобразите этот файл.
    • В противном случае я хотел бы сделать с mod_rewrite в файле .htaccess под Apache:

      • Если запрос любого файла или пути, например ] foo.txt или foo / bar , проверьте, существует ли такой файл в подкаталоге public , например public / foo.txt или public / foo / bar . Если это так, просто отобразите этот файл.
      • В противном случае txt или public / foo / bar . Если это так, просто отобразите этот файл.
      • В противном случае 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 , чтобы устранить этот недостаток?

0
задан 14 June 2016 в 17:37
4 ответа

У меня была похожая проблема, когда я хотел распространить веб-приложение, которое ведет себя так, как вы описываете: в определенном каталоге есть куча статических файлов, к которым можно получить доступ, как если бы они находились в корне веб-приложения (т. Е. Попытка /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 очень ограничено тем, что оно не разрешается для переменных и захваченного текста, но оно может использовать обратные ссылки на себя, используя синтаксис . Поэтому мы сначала создаем строку, состоящую из:

  • Исходный URI запроса
  • Жестко запрограммированный разделитель, который мы не ожидаем увидеть в URL-адресе (часть ::).
  • Локальная (для каждого каталога) часть URI, с которой будет соответствовать RewriteRule - это часть $1: RewriteCond может посмотреть на группу захвата целевого объекта RewriteRule(2), поэтому мы захватываем весь ввод.

Затем мы применяем регулярное выражение, которое объясняет связь между URI этого запроса и входом RewriteRule - URI запроса состоит из двух частей (первая и вторая записи) где первый заканчивается разделителем /, а второй идентичен тому, что появляется после разделителя ::2 просто ссылается на второй захват в том же regexp и говорит, что он должен быть идентичным.

В результате мы разбили URI запроса на две группы захвата - первая - это локальный префикс для каждого каталога, которым mod_rewrite пользуется конфиденциально, а вторая - локальный путь в этом каталоге, который мы хотим проверить. Второе условие использует % для обозначения этих захватов, строящих абсолютный путь под корнем документа(3). Обратите внимание, что %1 захватывает как начальную, так и конечную косую черту префикса URI.

Наконец, обратите внимание, что я использую флаг END вместо L (последний), так как он быстрее и существует mod_rewrite немедленно. Это позволяет мне опустить строку с RewriteRule ... - [Л] , который существует только для того, чтобы остановить поведение L, которое фактически не прекращает обработку: оно просто возвращается к началу или переписывает правила с новым URL-адресом. END намного проще.

Сноски:

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

Кажется, вы не хотите получить доступ к чему-либо за пределами папки / public? Если так, мне это кажется простым и без каких-либо переписываний (я надеюсь, что нет никаких причин, по которым вы действительно хотите, чтобы использовал mod_rewrite !)

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

Если у вас есть причина использовать общую папку, вы можете использовать mod_rewrite для перенаправления чего-либо, кроме index.php, в public / something, и по-прежнему использовать ErrorDocument для перенаправления на index.php.

4
ответ дан 4 December 2019 в 11:15

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

RewriteBase /subfolder/
# Rules
0
ответ дан 4 December 2019 в 11:15

Этот набор правил мне подходит. Я пропустил проверку путей, которые запускают /public.[1233 visible. Если / public не находится в корневом каталоге вашего документа, вы можете заменить% {DOCUMENT_ROOT} на путь на диске к каталогу / public. CONTEXT_DOCUMENT_ROOT может содержать путь к каталогу содержимого для файла .htaccess Если у вас нет того же файла в / public / public , что и в / public , RewriteCond не будет соответствовать. Я избежал этой проблемы, используя свой эквивалент / public в качестве корневого документа. Если вы не можете поместить index.php в / public , вы можете использовать Псевдоним , чтобы получить к нему доступ, где он находится.

Ваш подход предполагает переписывание всего Матчи. Альтернативный набор правил, использующий ../ public в качестве корня вашего документа, будет:

Псевдоним /index.php /var/www/index.php RewriteCond% {REQUEST_FILENAME}! -F RewriteCond% {REQUEST_FILENAME}! -D RewriteRule. /index.php [L]

Вы также можете обработать отсутствующие файлы с помощью специальной страницы ошибки 404.

2
ответ дан 4 December 2019 в 11:15

Теги

Похожие вопросы