【问题标题】:How Do I Use Apache RewriteMap with PHP?如何在 PHP 中使用 Apache RewriteMap?
【发布时间】:2023-03-11 18:04:01
【问题描述】:

我一直在研究使用RewriteMap 来动态处理一系列 URL 重写,而我想做的是使用 PHP 脚本来生成适当的重写条件和规则——但我只能'让它工作。

我已经在带有 WebHost Manager 和 cPanel 的 Linux 服务器上运行 Apache。

我将以下内容添加到 WHM > Apache Configuration > Include Editor > PreVirtual Host Include > All Versions:

RewriteMap myrules "prg:/usr/lib/php /path/to/my/script.php"

我更新了配置文件,Apache 重启正常。

现在我想调用我从 .htaccess 文件中定义的 RewriteMap 来执行重写,但这就是我卡住的地方,一切似乎都坏了。

我想获取传入的域,对照地图检查它,然后返回关联的 domain:user_name 值。比如:

RewriteCond %{HTTP_HOST} ^(www\.)?${myrules:%{HTTP_HOST}}\.com$ [NC]
RewriteRule ^(.*)$ http://mywebsite.com/user/${myrules:%{HTTP_HOST}}/$1 [NC,P,L]

因此,举例来说,如果我的地图有 johnsmith.com:john-smith,那么传入 URL johnsmith.com 将代理 mywebsite.com/user/john-smith/ 上的内容。

首先,我很确定上面的条件/规则都是错误的。

把它弄对是我的首要任务。

其次,如何使用 RewriteMap 定义的 PHP 脚本输出我的地图?

任何帮助将不胜感激!

【问题讨论】:

  • 不要这样做。你有prg:例如here,但先阅读cmets :)
  • HTTP_HOST 是您的服务器的主机名,而不是客户端的名称。有一些 REMOTE_* 变量,但我不确定这些值的可靠性。
  • 请参阅prg: External Rewriting Program 以获取有关 Perl 小示例的说明。
  • @dusan.bajic 那里的 cmets 似乎建议进行重定向。不幸的是,我不能只是重定向,我需要代理。

标签: php apache .htaccess mod-rewrite url-rewriting


【解决方案1】:

johnsmith.com 是否首先解析到您的服务器?如果 johnsmith.com 和 mywebsite.com 由同一台服务器处理,则无需代理请求。

我认为你的规则应该更像这样:

RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+\.com)$ [NC]
RewriteRule ^.*$ http://mywebsite.com/user/${myrules:%1}/$0 [NC,P,L]
# or
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+\.com)$ [NC]
RewriteRule ^ - [E=MAPTO:${myrules:%1}]
RewriteCond %{ENV:MAPTO} !=""
RewriteRule ^.*$ http://mywebsite.com/user/%{ENV:MAPTO}/$0 [NC,P,L]

注意事项:

  • $0 是 RewriteRule 的模式匹配的整个字符串(如果 .htaccess 在 DocumentRoot 中,$0%{REQUEST_URI} 是相同的)
  • %1 是最后一个 RewriteCond 的第一个捕获括号匹配的字符串(因此,没有潜在前缀“www.”的 Host 标头的值)

在第二组规则中,第一条规则将“RewriteMap 调用”的结果放入名为 MAPTO 的环境变量中。第二个,旨在忽略未知/未映射的主机(MAPTO 值为空字符串)。

还有一个说明性的 PHP 代码作为 RewriteMap:

<?php
$map = [
    'foo.com' => 'bar',
    'johnsmith.com' => 'john-smith',
];

if (!defined('STDOUT'))
    define('STDOUT', fopen('php://stdout', 'w'));
if (!defined('STDIN'))
    define('STDIN', fopen('php://stdin', 'r'));
set_file_buffer(STDOUT, 0);
while (!feof(STDIN)) {
    $input = rtrim(fgets(STDIN), "\n");
    fputs(STDOUT, (array_key_exists($input, $map) ? $map[$input] : 'NULL') . "\n");
}

注意:'NULL' 值是 Apache 期望知道一个值何时未映射到另一个值的字符串。它允许您在 Apache 级别定义自己的默认值。例如:要将“root”作为后备,请使用以下语法:${myrules:%1|root}

【讨论】:

  • 感谢您提供的精彩示例!你能解释一下第二个规则集中发生了什么吗?另外,我希望能够匹配我的地图中的完整主机,例如 johnsmith.com 或 johnsmith.net 或 sandbox.johnsmith.org。
  • @HWD 实际上,我的代码示例中缺少域扩展名以符合规则。我还编辑了我的答案以添加更多信息。
  • 你的重写条件似乎只匹配.com——其他扩展呢?很好的帮助,谢谢。
  • @HWD 我保留了您的初始设计,其中包含“.com”扩展名。但是,如果您希望匹配任何域,而不需要潜在的“www”。前缀,你可以改用^(?:www\.)?(.+)
  • 我相信 PHP 代码给了我错误。 STDOUT/STDIN 似乎以字符串而不是资源的形式返回。
猜你喜欢
  • 1970-01-01
  • 2013-07-06
  • 1970-01-01
  • 2011-10-03
  • 2021-01-08
  • 2023-03-19
  • 1970-01-01
  • 2018-09-30
  • 1970-01-01
相关资源
最近更新 更多