Фон
Я пишу веб-проект на PHP без фреймворка. Я использовал различные пакеты для записи в шаблоне MVC. Для части маршрутизации (я использовал Лига / Маршрут ), я должен установить некоторые правила перезаписи на сервере Apache для работы маршрутов.
Сервер компании настроен так, чтобывсе коды приложений находятся за пределами корня документа, а псевдоним используется для внутреннего перенаправления в приложение. Это приводит к большим проблемам с точки зрения относительных путей, маршрутов и перезаписи URL.
Я собираюсь разбить проблемы на шаги и постараюсь понять по одному. Если вы хотите увидеть общую проблему, с которой я столкнулся, обратитесь к этому вопросу
ЧАСТЬ 1
Маршрутизатор сравнивает значение $_SERVER["REQUEST_URI"]
с маршрутами, указанными на рисункеиз какого действия он отображает. Вот маршруты:
$router->map("GET", "/", Hello1Controller::class);
$router->map("GET", "/hello2", Hello2Controller::class);
Вот панель навигации, просто кое-что для демонстрации маршрутизации:
<li><a href="/">Hello 1</a></li>
<li><a href="/hello2">Hello 2</a></li>
Вот правило корня и перезаписи документа в httpd.conf:
DocumentRoot "/usr/local/var/www/app/public"
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /index.php$1 [L]
У меня есть template.twig, расположенный за пределами корня документа (не в публичном каталоге), а внутри template.twig я пытаюсь сослаться на файл css:
<link href="css/style.css" type="text/css" rel="stylesheet"/>
Этот файл CSS находится в public/css/style.css
, поэтому он находится внутри корня документа.
Теперь я пытаюсь получить доступ к https://localhost
, и URL переписывается в /index.php, вызывая фронт-контроллер,Затем фронт-контроллер отображает REQUEST_URI (/) в Hello1Controller, который отображает template.twig. Если мы нажмем «Привет 2» на панели навигации, она успешно перейдет на эту страницу.
ISSUE : относительный путь в ссылке на ресурс не работает: для каждого ресурса, на который есть ссылка в шаблоне, выдается запрос GET. RewriteCond %{REQUEST_FILENAME} !-f
собирается проверить, является ли указанный ресурс файлом или нет. Но %{REQUEST_FILENAME}
оказывается просто относительным путем с /
впереди (я полагаю, что он сделан относительно корня), а не полным путем после его определения. И это, очевидно, не будет файлом, в результате чего правило перезаписи будет применено к обычной ссылке на файл и отправлено на фронт-контроллер. Вы можете увидеть это из журнала:
[rewrite:trace2] init rewrite engine with requested uri /css/style.css, referer: http://localhost/
[rewrite:trace3] applying pattern '^(.*)$' to uri '/css/style.css', referer: http://localhost/
[rewrite:trace4] RewriteCond: input='/css/style.css' pattern='!-f' => matched, referer: http://localhost/
[rewrite:trace2] rewrite '/css/style.css' -> '/index.php/css/style.css', referer: http://localhost/
[rewrite:trace2] local path result: /index.php/css/style.css, referer: http://localhost/
[rewrite:trace2] prefixed with document_root to /usr/local/var/www/app/public/index.php/css/style.css, referer: http://localhost/
И обратите внимание, что запрошенный URI равен "/css/style.css"
, но в коде я использовал относительный путь css/style.css
. Это заставляет меня думать, что относительный путь относительно текущей «позиции» в URL. Не уверен, что это до или после перезаписи, но в этом случае результат одинаков - относительно корня (потому что нет ничего в части пути uri), или index.php (который находится в том же каталоге, что икорень). Оба результата приводят к "/css/style.css"
, который мы видим вместо /usr/local/var/www/app/public/css/style.css
.
Теперь, когда это правило перезаписи применяется в контексте для каждого каталога, оно работает: %{REQUEST_FILENAME}
теперь относительный путьдобавляется к каталогу, что делает его полным путем, ведущим к файлу.
DocumentRoot "/usr/local/var/www/app/public"
<Directory "/usr/local/var/www/app/public">
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ /index.php [L]
</Directory>
(RewriteRule пришлось немного настроить, чтобы hello2 работал. Это не должно влиять на относительный путь)
[rewrite:trace3] [perdir /usr/local/var/www/app/public/] strip per-dir prefix: /usr/local/var/www/app/public/css/style.css -> css/style.css, referer: http://localhost/
[rewrite:trace3] [perdir /usr/local/var/www/app/public/] applying pattern '^(.*)$' to uri 'css/style.css', referer: http://localhost/
[rewrite:trace4] [perdir /usr/local/var/www/app/public/] RewriteCond: input='/usr/local/var/www/app/public/css/style.css' pattern='!-f' => not-matched, referer: http://localhost/
[rewrite:trace1] [perdir /usr/local/var/www/app/public/] pass through /usr/local/var/www/app/public/css/style.css, referer: http://localhost/
Вопрос : Это просто поведение относительного пути по умолчанию в правилах переписывания? для работы с каталогом или .htaccess всегда требуется?
Также вот замечание, которое я сделал относительно относительного пути. Пожалуйста, исправьте меня, если я ошибаюсь:
Относительные пути в коде на стороне клиента (в html, css или шаблонах веток, в которых включенные ресурсы не разрешаются до тех пор, пока не будут переданы на сторону клиента):
- Если файл, ссылающийся на ресурс с относительным путем, находится внутри корня документа, то относительный путь работает интуитивно: он относительно текущего файла.
- Если файл, ссылающийся на ресурсесли относительный путь находится за пределами корня документа (например, в файле шаблона, который обрабатывается и отправляется на клиентскую сторону), то этот путь не относится к текущему файлу. Это относительно текущего URL. То есть «..» вернется на один уровень в URL. Это мешает мне использовать относительный путь в этих файлах.
PART 2
Теперь я изменил настройку сервера, чтобы корень документа больше не находился внутри приложения, а вместо этого приложение полностью находилось внутри корня документа. Я мягко связал приложение / в www /
DocumentRoot "/usr/local/var/www"
RewriteEngine On
RewriteRule ^/?$ /app/public/index.php [L]
<Directory "/usr/local/var/www/app/public">
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ /index.php [L]
</Directory>
Чтобы внутренний перенаправить https://localhost
в мое приложение, я добавил еще одно правило перезаписи. Теперь ссылка на ресурс снова не работает:
[rewrite:trace2] init rewrite engine with requested uri /css/style.css, referer: http://localhost/
[rewrite:trace3] applying pattern '^/?$' to uri '/css/style.css', referer: http://localhost/
[rewrite:trace1] pass through /css/style.css, referer: http://localhost/
[core:trace3] request authorized without authentication by access_checker_ex hook: /css/style.css, referer: http://localhost/
[core:info] AH00128: File does not exist: /usr/local/var/www/css/style.css, referer: http://localhost/
Определение для каждого каталога даже не обрабатывается. Я пробовал разные варианты правил перезаписи, в том числе добавление и удаление [L], изменение порядка двух правил перезаписи, надеясь, что сначала будет выполнено каждое из каталогов, обертывание первого правила перезаписи своей собственной директивой и т. Д. это сработало. Вкладка «Привет 2» на панели навигации также не работает по той же причине - правила перезаписи для каждого каталога вообще не обрабатываются.
PART 3
Следующий шаг -переместить приложение полностью за пределы корня документа и использовать псевдоним для внутреннего перенаправления в приложение.