什么是 URL 以及如何设置路由
URL 只是一个由几个部分组成的字符串:
http://example.com/foo?bar=baz
| | | |
| | | +- query
| | +- path
| +- host
+- scheme
URL 可能还具有身份验证信息、端口和片段,但我们将在此尽量保持简单。Kunststube\Router 专门处理路径。方案和查询通常对路由没有影响,主机通常由 Web 服务器处理。
假设使用 Apache Web 服务器进行典型设置,Apache 通常会为您执行“路由”。它接收到如下所示的 HTTP 请求:
GET /foo/bar/baz?some=parameters HTTP/1.1
Web 服务器现在可以自由地以它选择的任何方式响应此请求。大多数 Web 服务器所做的默认操作是将 URL 的路径映射到硬盘上的文件。Web 服务器将首先确定合适的DocumentRoot是什么,即磁盘上已配置为“公共 Web 文件夹”的文件夹。假设 DocumentRoot 是/var/www
. 然后它将连接到该根的请求路径,从而产生/var/www/foo/bar/baz
. 然后它将尝试确定该文件是否存在于磁盘上并将其作为响应提供。如果请求的文件以.php
或 Apache 以其他方式配置为将该文件视为 PHP 文件,它将首先通过 PHP 解释器运行该文件,然后返回其输出。
要使用 PHP 路由器使用我们自己的自定义路由,我们需要拦截 Apache 查找文件以在磁盘上提供服务的过程。这可以在 Apache 配置文件中完成;但是如果您可以访问这些文件,我假设您知道自己在做什么,并且不会详细介绍那里的最佳设置。相反,我将介绍您不能或不想编辑核心 Apache 配置文件而是求助于.htaccess
文件的典型情况。当 Apache 遍历磁盘上的目录结构以找到要服务的正确文件时,它会检查每个目录中是否.htaccess
放置了一个调用的文件。如果找到,它将执行和/或将其中定义的规则合并到文件查找过程中,
您想要实现的是让 Apache “查找”并为任何和所有请求执行一个特定的 PHP 文件,并使原始 URL 可用于该 PHP 文件,以便它可以进行自己的路由。最简单,最肮脏的方法是简单的RewriteRule
:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^(.*)$ index.php?url=/$1 [QSA,L]
</IfModule>
假设您将其放入文件/var/www/.htaccess
中。当 Apache 开始在该目录中查找文件时,它将解析这些重写规则。此时 Apache 正在寻找的路径的“内部状态”是foo/bar/baz
. 的正则表达式^(.*)$
将
RewriteRule
匹配该路径(表达式基本上说“匹配任何东西”),并且该规则将路径重写为
index.php?url=/foo/bar/baz
. 然后将原始some=parameters
文件再次附加到该路径/URL(由于QSA
标志)。然后 Apache 将继续寻找现在重写的路径index.php
。因此,只需将您的代码放入/var/www/index.php
其中,Apache 就会为其启动 PHP 解释器。PHP 将传递 URL 查询部分
?url=/foo/bar/baz&some=parameters
,在 PHP 中可以访问为
$_GET['url']
和$_GET['some']
. 所以完整的设置如下所示:
基本设置
文件/文件夹结构
/var
/www
.htaccess
index.php
/Kunststube
/Router
Router.php
...
.htaccess
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^(.*)$ index.php?url=/$1 [QSA,L]
</IfModule>
索引.php
<?php
require_once 'Kunststube/Router/Router.php';
$r = new Kunststube\Router\Router;
$r->add('/foo');
...
$r->route($_GET['url']);
这就是它的全部。一个基本的重写规则,将每个请求重定向到同一个 PHP 文件,并将原始 URL 作为查询参数附加,然后用于调用路由过程。
警告和调整
对上述设置的一个重要警告是,您的 URL 不能包含名为 的查询参数url
,因为原始查询参数被添加回重写的 URL。URL
/foo/bar?url=baz
将被重写为:
index.php?url=/foo/bar&url=baz
第二个url
参数将替换第一个参数。如果您需要url
在应用程序中使用查询参数,请为您的重写规则选择不同的参数名称。
其次,请注意 Kunststube\Router 期望传递给的 URL
route()
以/
. 您可以在重写过程中添加斜线,如上所示,或者在 PHP 中;只要确保它在那里。
第三,您通常也有不想通过 PHP 路由的文件,例如 CSS 和图像文件。您将希望这些由 Apache 直接提供服务。一个很好的设置是这样的:
/var
/Kunststube
/Router
...
/MyApp
MyScript.php
...
/www
.htaccess
index.php
/css
style.css
...
/img
kitten.jpg
...
将所有实际的 PHP 文件从公共 Web 根目录中取出,只留下公共资产文件和一个最小index.php
文件。调整你的 RewriteRule 看起来像这样:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?url=/$1 [QSA,L]
</IfModule>
RewriteCond
确保RewriteRule
仅当请求的文件实际上不存在时才适用 ( ) !-f
。这意味着对 URL 的请求css/style.css
将按原样通过,因为该文件确实存在并且 Apache 可以直接提供它。对物理上不存在的“虚构”文件的任何请求都将进入
index.php
并可以路由到那里。在里面index.php
,确保使用正确的路由器路径:
require_once '../Kunststube/Router/Router.php';
事实上,更好的做法是在其他地方完全定义您的路线并使用自动加载器来加载所需的文件,但这超出了本文档的范围。