Невозможно заставить относительный путь, правила перезаписи и маршруты вести себя так, как я хотел - PullRequest
1 голос
/ 08 ноября 2019

Фон

Я пишу веб-проект на 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

Следующий шаг -переместить приложение полностью за пределы корня документа и использовать псевдоним для внутреннего перенаправления в приложение.

Ответы [ 2 ]

1 голос
/ 11 ноября 2019

Добро пожаловать в Stackoverflow!

Глядя на то, что у вас есть, не похоже, что вам нужно делать то, что вы написали в своем ответе.

, если ваш проект находится в:/usr/local/var/www/app и ваш корневой каталог документов: /usr/local/var/www/app/public

Похоже, вы немного запутались между корневой папкой ваших проектов и сервером HTTP DocumentRoot.

Сервер HTTP DocumentRoot - это папка, которую apache должен обрабатывать в корне. то есть, когда вы переходите на http://myapp.com/index.php, он будет искать в DocumentRoot для index.php.

Предполагая, что вы настроили свой сайт как VirtualHost, как это делает большинство, ваша конфигурация vhost будет выглядеть как-токак это:

<VirtualHost *:80>
    ServerAdmin admin@myapp.local
    DocumentRoot "/usr/local/var/www/app/public"

    <Directory /usr/local/var/www/app>
        AllowOverride all
    </Directory>
    ServerName myapp.local

    ErrorLog "/var/log/myapp.local-error_log"
    CustomLog "/var/log/myapp.local-access_log" common
</VirtualHost>

Тогда в вашем .htaccess файле, который находится в DocumentRoot: /usr/local/var/www/app/public, вы должны иметь:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* /index.php$0 [PT]

Вы также должны использовать предыдущую косую чертув вашем HTML, чтобы ссылаться на файл css, так как / будет гарантировать, что путь относительно вашего DocumentRoot, где находится ваша папка css.

Ключевым моментом здесь является то, что единственныйфайлы, которые должны быть в DocumentRoot, это ваш .htaccess файл, ваш файл index.php и ваши ресурсы. Затем ваше приложение будет ссылаться на код в папке «app», включая файлы с использованием предыдущего оператора каталога ../, в большинстве случаев / frameworks это будет что-то вроде include('../bootstrap.php');.

0 голосов
/ 11 ноября 2019

Что ж, я нашел решение для части 2:

    DocumentRoot "/usr/local/var/www"
    <Directory "/usr/local/var/www">
        RewriteEngine On
        RewriteRule ^$ app/public/ [L]
        RewriteRule (.*) app/public/$1 [L]
    </Directory>

    <Directory "/usr/local/var/www/app/public">
        RewriteEngine On
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule ^ index.php [L]
    </Directory>

Нам нужно иметь правило перезаписи для каждого каталога на корневом уровне, чтобы добавить путь приложения к документу до его оценкидирективы на уровне приложения.

Это не что-то официальное, что я читаю, а скорее то, что я вижу из эксперимента:
Часть пути uri (после применения любых предыдущих правил перезаписи) должна соответствовать той, которая указана вДиректива «Directory» для выполнения. Итак, в начале мы находимся в корне документа, поэтому исполняется директива корневого уровня для каждого каталога. Он добавляет часть app / public перед uri, поэтому теперь путь uri содержит весь путь, ведущий к общедоступному каталогу приложения. Таким образом, директивы приложения для каждого каталога могут быть выполнены.

Часть 3 может быть разрешена аналогичным образом, с добавлением псевдонима. Этот ответ предоставляет пример для него.


Примечание: реализация части 2 не имеет практического значения и ее следует избегать в реальном производстве. Это всего лишь промежуточный шаг, который я предпринял, чтобы решить основную проблему. Только ваша общая папка (та, которая содержит статическое содержимое), если она вообще существует, должна находиться внутри корня документа.

...