【问题标题】:Riddle with routing in PHPPHP中的路由之谜
【发布时间】:2017-01-11 21:47:04
【问题描述】:

我用 htaccess 和 PHP 做了简单的路由器。但是这种方式无法在 url 中设置额外的 GET 参数。

.htaccess

RewriteEngine On
[...]
RewriteCond %{REQUEST_URI} !\.(gif|jpg|png)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php?url=$1 [PT,L]
[...]

index.php

[...]
$url = isset($_GET['url']) ? $_GET['url'] : null;
$router = new Router($url);
[...]

然后我正在运行调度程序。例如 url www.site.com/user/regierter 运行class UserController -> registerAction()。但是如果我想添加另一个获取请求,例如: www.site.com/user/regierter?layout=red

如何使发送 url 部分但接受另一个 get 请求成为可能?

【问题讨论】:

标签: php .htaccess url-rewriting routing


【解决方案1】:

您的重写方法不适合这个用例。

简单地使用内部重定向将请求从您的网络服务器获取到 PHP 并让 PHP 处理请求参数会更容易。

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [PT]

这使得 Apache httpd 将 任何 请求(不是文档根目录中存在的文件或目录)重定向到内部的 index.php。这意味着,重定向对最终用户是完全透明的。他们看到www.example.com/foo,而您的网络服务器看到/index.php,而PHP 只看到/foo。这使得无论查询字符串参数如何,都可以在内部处理路由。

$url = $_SERVER['REQUEST_URI'];
$router = new Router($url);

查询字符串中的任何参数仍会在$_GET 中被适当地解析。 $_SERVER['REQUEST_URI'] 包含由您的网络服务器传递给 PHP 的原始请求 URI,以便 PHP 将 www.example.com/foo/bar/?quix=1&quack=2 读取为 /foo/bar/?quix=1&quack=2$_GET['quix'] == 1$_GET['quack'] == 2

因此,就 PHP 所知,原始查询字符串(即 HTTP 请求行)保持不变。此处所做的唯一更改是您的 Web 服务器如何确定是让 PHP 处理请求还是直接从文档根目录提供请求。

现在您的路由器可以直接从$_SERVER['REQUEST_URI'] 提取它需要的所有信息,例如parse_url

因此,如果向 www.site.com/user/register?layout=red 提出请求,var_dump(parse_url($_SERVER['REQUEST_URI'])) 会为您提供类似的信息。

数组(2){ [“路径”]=> 字符串(14)“/用户/注册” [“查询”]=> 字符串(10)“布局=红色” }

$_GET['layout'] 仍然会给你"red"

【讨论】:

  • "您的网络服务器看到 /index.php/foo" - “网络服务器看到”/index.php - 末尾没有 /foo。 (PT 标志只有在服务器上下文中才需要,如果有的话。)
  • 是的,我正在解释网络服务器将如何在 重写规则之后查看请求。这就是为什么我声明内部重定向,而不是外部重定向。
  • 是的,只是网络服务器看到的是/index.php,而不是/index.php/foo,正如您在回答中所说的那样-也许这只是一个错字? (如果您明确地将 URL 路径作为 附加路径信息 附加到 RewriteRule 替换的末尾,它只会变为 /index.php/foo。)
  • @w3dk 啊!确实。那里复制/意大利面失败。感谢您指出。现在修复:)
【解决方案2】:

RewriteRule 标志 PT|passthrough 仅在您的目标 (index.php) 是别名或类似名称时才需要

也就是说,使用 [PT] 标志会导致 RewriteRule 的结果通过 URL 映射传回,因此基于位置的映射,例如 Alias、Redirect 或 ScriptAlias,可能有机会生效。

所以在你的情况下这没有帮助,使用标志 L|last 就足够了。


正如@arkascha 已经提到的,要保留其他获取参数,您必须使用QSA|qsappend 标志

当替换 URI 包含查询字符串时,RewriteRule 的默认行为是丢弃现有的查询字符串,并将其替换为新生成的查询字符串。使用 [QSA] 标志会合并查询字符串。

这意味着你的规则将变成

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php?url=$1 [L,QSA]

这将在您的 PHP 脚本中同时为您提供$_GET['url'] $_GET['layout']

【讨论】:

  • 好答案奥拉夫+1
  • PT 标志在每个目录的上下文中都是隐含的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-18
  • 2011-09-20
  • 1970-01-01
  • 2015-10-31
  • 2011-08-31
  • 2020-10-25
相关资源
最近更新 更多