无法使相对路径,重写规则和路由按我预期的方式运行

背景

我正在用不带框架的PHP编写一个Web项目。我使用了各种软件包来编写MVC模式。对于路由部分(我使用了League/Route),我必须在Apache服务器上设置一些重写规则,路由才能正常工作。

公司服务器的设置方式是,所有应用程序代码都位于文档根目录之外,别名用于内部重定向到应用程序。这会在相对路径,路由和URL重写方面带来很多麻烦。

我将把问题分解为几个步骤,并尝试一次理解一个问题。如果要查看我遇到的总体问题,请参阅this question

PART 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。如果单击导航栏上的“ hello 2”,它将成功导航到该页面。

问题:资源引用中的相对路径不起作用: 将为模板中引用的每个资源发出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或twig模板中,其中包含的资源只有在传递给客户端后才会解析):

  • 如果引用具有相对路径的资源的文件位于文档根目录之内,则相对路径会直观地起作用:它相对于当前文件。
  • 如果引用具有相对路径的资源的文件在文档根目录之外(例如,在正在渲染并发送到客户端的模板文件中),则该路径不是相对于当前文件的。它相对于当前URL。也就是说,“ ..”将返回网址中的上一级。这使我无法在这些文件中使用相对路径。

PART 2

现在,我更改服务器设置,以使文档根目录不再位于应用程序内部,而是将应用程序完全置于文档根目录内部。我将app /软链接到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],更改两个重写规则的顺序,希望每个目录首先执行,用自己的指令包装第一个重写规则,等等。这些工作。 由于相同的原因,导航栏上的“ hello 2”选项卡也无法正常工作-完全不处理每个目录的重写规则。

PART 3

下一步是将应用程序完全移到文档根目录之外,并使用别名在内部重定向到该应用程序。

GGsnake 回答:无法使相对路径,重写规则和路由按我预期的方式运行

好吧,我找到了第2部分的解决方案:

daddi $sp,$sp,0x400 #loads the immediate value 0x400 into the $sp register.

在按应用程序级别的按目录指令对它进行评估之前,我们需要在根级别上具有一个按目录重写规则,以将应用程序的路径附加到docroot。

这不是我读过的任何官方文章,而是我从实验中看到的内容:
uri的路径部分(在应用了任何先前的重写规则之后)必须与“目录”指令中指定的路径部分匹配才能执行。因此,从一开始我们就位于文档根目录,因此将执行根目录级别的每目录指令。它在uri之前附加了app / public部分,因此uri路径现在包含通向该应用程序public目录的整个路径。因此,可以执行应用程序的按目录指令。

第3部分可以通过添加别名的类似方式来解决。 This answer提供了一个示例。


注意:第2部分的实现没有实际意义,应在实际生产中避免。这只是我解决最终问题所采取的中间步骤。根本上,只有公用文件夹(包含静态内容的公用文件夹)应该位于文档根目录内。

,

欢迎来到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,则您的虚拟主机配置将如下所示:

<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”文件夹中的代码,这类似于include('../bootstrap.php');

本文链接:https://www.f2er.com/3140359.html

大家都在问