麻烦utf-8字符&apache2重写规则

我看到在htaccess重写规则中validationutf-8的post,我认为这很好,但是我有一个更基本的问题:

我需要扩展处理utf-8字符查询string参数,目录名称,文件,并用于显示给用户等。

我用DefaultCharset UTF-8configuration我的Apache,也是我的PHP,如果重要的话。 我原来的重写规则过滤了除了普通的A-ZA-Z和下划线和连字符以外的所有内容。 它的工作。 其他任何东西都会给你一个404(这是我想要的!)现在,但是,似乎所有的匹配,包括我不想要的东西,但是,虽然它似乎匹配不查询string,除非它是一个常规的A-Za-z_-string。

我觉得这很容易混淆,因为规则说把你匹配的任何东西放到查询string中:

这是原来的规则:

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!

而且,无论我使用上述哪个规则,都是这样做的。 我configuration了一个重写日志

  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 

我可以做些什么来获得这些$%#$ @(*#@ !!!字符,但不是斜杠,点或其他非alpha到我的程序中,一旦有,它会解码他们正确posix char类工作更好吗?还有什么我需要configuration?

上…

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

有人纠正我,如果我错了,但不是这意味着得到请求要求子目录简单地绕过这条规则?

另外,解决这个问题的一个懒惰的方法也是在'%'字符中进行分组。 据我所知,所有你允许使用的是任何URL路径是URL编码。 其实,看: http : //www.blooberry.com/indexdot/html/topics/urlencoding.htm

我相信有更先进和更好的方法来做到这一点,但这应该解决你的眼前的问题。

这是对驱逐舰答案的回应,但是太长了。

我用URL编码unicode因为它很容易解码显示。 所以也许这是最基本的问题。 最后我只是在php中使用url_encode来做到这一点,但我想我会尝试一个在线的只是为了测试的东西:我去http://www.opinionatedgeek.com/dotnet/tools/urlencode/Encode.aspx和试图编码墨西哥,它出来M%c3%a9xico。 我去了你指出的网站,试了一下,它出来M%E9xico不同! 这是什么? 我想我会不得不接受任何PHP功能实际上给我。 但是这两个都有9个,这意味着我必须接受数字以及%。 这是我必须包括的吗?

我希望请求真正的子目录符合这个规则,如果这是你的意思绕过它,我宁愿他们实际上在子目录中呈现静态页面。 这就是为什么我真的想排除/我以为我做了什么。 但似乎匹配任何之后的/包括嵌套的子目录,并去puzzle.php文件。

这是我的尝试,但没有快乐:我用这个规则:重写规则^ / puzzle /([A-Za-z0-9 _% – ] +)$ /puzzle.php?g=$1 [NC]将%和0-9添加到组中。 我需要逃避%或什么? 我读到只有\需要在方括号内转义。 我希望这就是你的意思。 这些将是唯一的附加字符,你会通过编码任何可能的Unicode字符串? 然后我通过了2个不同的网址编码墨西哥版本。对于M%E9xico我现在得到404和这个消息:请求的URL /难题/墨西哥在这台服务器上没有被发现。 对于M%c3%a9xico我现在得到这个消息404:在这台服务器上找不到请求的网址/拼图/México。 对于不存在的子目录,它现在应该给404。 所以现在只是重写规则不起作用。 这是进步。 同时重写日志开始得到它的东西:这是一些。 我会谷歌如何阅读这些日志:

 kidd108d-mac3:logs tpdick$ cat puzzles.httpd.rewrite ::1 - - [26/May/2010:15:54:37 --0700] [puzzles.net/sid#886b00][rid#904858/initial] (2) init rewrite engine with requested uri /puzzle/M?xico ::1 - - [26/May/2010:15:54:37 --0700] [puzzles.net/sid#886b00][rid#904858/initial] (3) applying pattern '^/puzzle/([A-Za-z0-9_%-]+)$' to uri '/puzzle/M?xico' ::1 - - [26/May/2010:15:54:37 --0700] [puzzles.net/sid#886b00][rid#904858/initial] (1) pass through /puzzle/M?xico ::1 - - [26/May/2010:15:54:37 --0700] [puzzles.net/sid#886b00][rid#910858/subreq] (3) [perdir /Users/tpdick/Sites/puzzles/] add path info postfix: /Users/tpdick/Sites/puzzles/puzzle.php -> /Users/tpdick/Sites/puzzles/puzzle.php/M?xico ::1 - - [26/May/2010:15:54:37 --0700] [puzzles.net/sid#886b00][rid#910858/subreq] (3) [perdir /Users/tpdick/Sites/puzzles/] strip per-dir prefix: /Users/tpdick/Sites/puzzles/puzzle.php/M?xico -> puzzle.php/M?xico ::1 - - [26/May/2010:15:54:37 --0700] [puzzles.net/sid#886b00][rid#910858/subreq] (3) [perdir /Users/tpdick/Sites/puzzles/] applying pattern '^(.*)/GeoP-Test/puzzle/(.*)$' to uri 'puzzle.php/M?xico' ::1 - - [26/May/2010:15:54:37 --0700] [puzzles.net/sid#886b00][rid#910858/subreq] (1) [perdir /Users/tpdick/Sites/puzzles/] pass through /Users/tpdick/Sites/puzzles/puzzle.php ::1 - - [26/May/2010:15:54:37 --0700] [puzzles.net/sid#886b00][rid#904858/initial] (3) [perdir /Users/tpdick/Sites/puzzles/] add path info postfix: /Users/tpdick/Sites/puzzles/puzzle.php -> /Users/tpdick/Sites/puzzles/puzzle.php/M?xico ::1 - - [26/May/2010:15:54:37 --0700] [puzzles.net/sid#886b00][rid#904858/initial] (3) [perdir /Users/tpdick/Sites/puzzles/] strip per-dir prefix: /Users/tpdick::1 - - [26/May/2010:15:54:37 --0700] [puzzles.net/sid#886b00][rid#904858/initial] (2) init rewrite engine with requested uri /puzzle/México ::1 - - [26/May/2010:15:54:37 --0700] [puzzles.net/sid#886b00][rid#904858/initial] (3) applying pattern '^/puzzle/([A-Za-z0-9_%-]+)$' to uri '/puzzle/México' ::1 - - [26/May/2010:15:54:37 --0700] [puzzles.net/sid#886b00][rid#904858/initial] (1) pass through /puzzle/México ::1 - - [26/May/2010:15:54:37 --0700] [puzzles.net/sid#886b00][rid#910858/subreq] (3) [perdir /Users/tpdick/Sites/puzzles/] add path info postfix: /Users/tpdick/Sites/puzzles/puzzle.php -> /Users/tpdick/Sites/puzzles/puzzle.php/México ::1 - - [26/May/2010:15:54:37 --0700] [puzzles.net/sid#886b00][rid#910858/subreq] (3) [perdir /Users/tpdick/Sites/puzzles/] strip per-dir prefix: /Users/tpdick/Sites/puzzles/puzzle.php/México -> puzzle.php/México ::1 - - [26/May/2010:15:54:37 --0700] [puzzles.net/sid#886b00][rid#910858/subreq] (3) [perdir /Users/tpdick/Sites/puzzles/] applying pattern '^(.*)/GeoP-Test/puzzle/(.*)$' to uri 'puzzle.php/México' ::1 - - [26/May/2010:15:54:37 --0700] [puzzles.net/sid#886b00][rid#910858/subreq] (1) [perdir /Users/tpdick/Sites/puzzles/] pass through /Users/tpdick/Sites/puzzles/puzzle.php ::1 - - [26/May/2010:15:54:37 --0700] [puzzles.net/sid#886b00][rid#904858/initial] (3) [perdir /Users/tpdick/Sites/puzzles/] add path info postfix: /Users/tpdick/Sites/puzzles/puzzle.php -> /Users/tpdick/Sites/puzzles/puzzle.php/México 

怎么办??

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

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

不,只要客户端在其Accept头中包含通讯员MIME类型,就可以随时忽略这些扩展名。

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


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

按照惯例,Web浏览器在URL中使用UTF-8编码。 这意味着“墨西哥”将被编码为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/[^/]*不是一个选项,那么这个检查会被推迟到使用(转义) %{REQUEST_URI}RewriteCond

该解决方案基于: http : //www.dracos.co.uk/code/apache-rewrite-problem/

试试这个重写规则:

 AddDefaultCharset UTF-8 RewriteEngine On RewriteCond %{THE_REQUEST} /puzzle/([^?\ /]+) RewriteRule ^puzzle/(.*)$ puzzle.php/%1 [L] 

如何获取查询参数:

 <?php // Get query param $g = substr($_SERVER['PATH_INFO'], 1); echo "<p>g: $g</p>"; // Test if '/' is present in URL for 404's $g2 = substr($_SERVER['REQUEST_URI'], 8); if (strpos($g2, '/') === false) { // do stuff } else { // Send 404 header here echo "<p>404</p>"; } ?> 

有了这个解决方案,你必须从PHP发送404。

使用CodeIgniter和utf-8越南语(TiếngViệt)文件.htaccess:

 RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.+[az,AZ,0-9,ễ].+)$ index.php/$1 [L] 

当url有'ễn',那么错误=> RewriteRule有'ễ'

测试它([^/]+)它可能适合你