php - utf-8 字符和 apache2 重写规则的问题

标签 php apache mod-rewrite utf-8

我看到帖子 validating utf-8 in htaccess rewrite rule我认为这很好,但我首先遇到了一个更根本的问题:

我需要扩展以处理查询字符串参数、目录名称、文件名称以及用于向用户显示等的 utf-8 字符。

我用 DefaultCharset utf-8 配置了我的 Apache,如果重要的话还配置了我的 php。我原来的重写规则过滤除了常规 A-Za-z 和下划线和连字符之外的所有内容。它奏效了。其他任何东西都会给你一个 404(这就是我想要的!)现在,似乎一切都匹配,包括我不想要的东西,但是,尽管它似乎匹配但它不会进入查询字符串,除非它是一个普通的 A-Za-z_- 字符串。

我觉得这很令人困惑,因为规则说将您匹配的任何内容放入查询字符串中:

这是原始规则:

RewriteRule ^/puzzle/([A-Za-z_-]+)$ /puzzle.php?g=$1 [NC]

这是修改后的规则:

RewriteRule ^/puzzle/(\w+)$ /puzzle.php?g=$1 [NC]

我做了这个改变,因为我在某处读到\w 与 A-Zetc 中的所有字母字符匹配。只匹配没有口音和东西的那些。

我使用这些规则中的哪一个似乎并不重要:这是发生的事情:

在应用程序中我有这个:

echo $_GET['g'];

如果我给它一个类似 http://mydomain.com/puzzle/USA 的 url它呼应了“美国”并且工作正常。
如果我给它一个类似 http://mydomain.com/puzzle/México 的 url它对此没有回应,并警告我索引 g 未定义,当然也没有获得墨西哥的资源。
如果我给它一个类似 http://mydomain.com/puzzle/fuzzle/buzzle/j.qle 的 url它做同样的事情。
最后一个案例应该是 404!

无论我使用上述哪条规则,它都会执行此操作。我配置了重写日志

   RewriteLogLevel 5
   RewriteLog /opt/local/apache2/logs/puzzles.httpd.rewrite

但它是空的。

这是来自常规访问日志(状态为 200)

[26/May/2010:11:21:42 -0700] "GET /puzzle/M%C3%A9xico HTTP/1.1" 200 342
[26/May/2010:11:21:54 -0700] "GET /puzzle/M/l.foo HTTP/1.1" 200 342

我该怎么做才能将这些 $%#$@(*#@!!! 字符而不是斜杠、点或其他非字母字符放入我的程序中,一旦出现,它会正确解码它们吗??? posix char 类工作得更好吗?还有什么我需要配置的吗?

最佳答案

我建议您激活 MultiViews 而忘记 mod_rewrite。在相关的 Directory/VirtualHost 部分添加到您的 apache 配置:

Options +MultiViews
#should already be set to this, but it doesn't hurt:
AcceptPathInfo Default

不,只要客户端在其 Accept header 中包含相应的 MIME 类型,您始终可以省略扩展名。

现在 /puzzle/whatever 的请求将映射到 /puzzle.php 并且 $_SERVER['PATH_INFO'] 将被填充使用/whatever


如果你想用 mod_rewrite 做它也是可能的。 RewriteRule 的测试字符串未转义(%xx 部分被转换为它们代表的实际字节)。您可以使用 %{REQUEST_URI}%{THE_REQUEST} 获取原始转义字符串(最后一个还包含 HTTP 方法和版本)。

按照惯例,网络浏览器在 URL 中使用 UTF-8 编码。这意味着“México”将被 urlencode 为 M%C2%82xico,而不是 M%82xico,如果浏览器使用 ISO-8859-1,这将是预期的。此外,[a-zA-Z] 将不匹配 é。但是,这应该有效:

RewriteCond %{REQUEST_URI} ^/puzzle/[^/]*$
RewriteRule ^/puzzle/(.*)$ /puzzle.php?q=$1 [B,L]

您需要 B 来转义反向引用,因为您在查询字符串中使用它,其中允许的字符集小于 URI 的其余部分。

您应该注意的是 RewriteRule 不支持 unicode。 .* 以外的任何内容都可能给出(可能)不正确的结果。甚至 [^/] 也可能不起作用,因为 / “字符”(读取:字节)可能是多字节字符序列的一部分。如果 RewriteRule 是 unicode 感知的,那么您使用 \w 的解决方案应该可以工作。

由于您不想匹配子目录,并且 RewriteRule ^/puzzle/[^/]* 不是一个选项,该检查被推迟到 RewriteCond使用(转义的)%{REQUEST_URI}

关于php - utf-8 字符和 apache2 重写规则的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2916194/

相关文章:

php - 探索 PHP 的搜索选项

php - 无法写入新创建的文件

apache - Nginx 对 cms 后端的重写规则

apache - 如何阻止用户通过url访问css文件和图像

.htaccess - 使用 htaccess 具有多个查询字符串的自定义页面 Slug

php - 是否有 "correct"方法可以在实时服务器和开发服务器之间同步数据库?

javascript - 为什么我的 Jquery 事件不会在 focusout() 上触发?

php - 从 Flash 请求 php 文件在 Safari 中挂起

apache - Directus api 和应用程序与前端在同一台服务器上

php - mysqli_connect() : (HY000/2002): Can't connect to local MySQL server through socket