【问题标题】:PHP UTF-encoded URL-stringPHP UTF 编码的 URL 字符串
【发布时间】:2010-07-30 02:57:27
【问题描述】:

当我在 Firefox(地址行)中输入 http://www.example.com/?query=Траливали 之类的 URL 时,它会自动编码为 http://www.example.com/?query=%D2%F0%E0%EB%E8%E2%E0%EB%E8

但是像http://www.example.com/#ajax_call?query=Траливали这样的URL没有被转换。

IE8等其他浏览器根本不转换查询。

问题是:如何检测(在 PHP 中)查询是否已编码?怎么解码?

我试过了:

  1. $str = iconv('cp1251', 'utf-8', urldecode($str) );

  2. $str = utf8_decode(urldecode($str));

  3. $str = (urldecode($str));

  4. 来自http://php.net/manual/en/function.urldecode.php 的许多功能 没有任何效果。

测试:

$str = $_GET['str'];

d('%D2%F0%E0%EB%E8%E2%E0%EB%E8' == urldecode('%D2%F0%E0%EB%E8%E2%E0%EB%E8') );

d('%D2%F0%E0%EB%E8%E2%E0%EB%E8' == $str);

d('Траливали' == $str);

d(urldecode($str));

d(utf8_decode(urldecode($str)));

!!! d('%D2%F0%E0%EB%E8%E2%E0%EB%E8' == urlencode($str)); !!!

返回:

[假] [错误的] [错误的] �������� ??? [真]

某种解决方案:http://www.example.com/Траливали/ - 将查询作为 url 部分发送并使用 mod_rewrite 进行解析。

【问题讨论】:

  • 请注意这里有两个步骤:从浏览器到您的脚本,以及从脚本到您的浏览器。如果您想看到您想要的数据,这两个步骤都需要正确完成。所以这取决于你的脚本需要做什么。请参阅我的更新答案以获取一些建议。
  • 关于更新:您是否以相同的编码保存文件? (我假设连接是 utf-8?)尝试测试 d('%...' == rawurlencode($str))
  • 我添加了一些测试,rawurlencode 给出的结果与 urlencode 相同。
  • 刚刚尝试从您的“Траливали”字符串中复制/粘贴,在这里工作就像一个魅力,比较$str == 'Траливали'。您确定您正在以正确的编码保存 php 脚本吗?如果在脚本中输入echo 'Траливали'; 会发生什么?它是否正确显示在屏幕上?
  • 你需要慢慢来,一步一步地评估。查看您的示例网址:您确定“Траливали”在 utf-8 中是“%D2%F0%E0%EB%E8%E2%E0%EB%E8”吗?这里显示为“%D0%A2%D1%80%D0%B0%D0%BB%D0%B8%D0%B2%D0%B0%D0%BB%D0%B8”。会不会是这个问题?

标签: php url utf-8 utf8-decode


【解决方案1】:

在片段无效后,它不会转换为具有 URL 的 query 部分。

RFC 3986 将 URI 定义为由以下部分组成:

     foo://example.com:8042/over/there?name=ferret#nose
     \_/   \______________/\_________/ \_________/ \__/
      |           |            |            |        |
   scheme     authority       path        query   fragment

无法更改顺序。因此,

URL1: http://www.example.com/?query=Траливали#ajax_call

会妥善处理

URL2: http://www.example.com/#ajax_call?query=Траливали

不会。如果我们查看URL2,IE 实际上通过将片段检测为#ajax_call?query=Траливали 来正确处理 URL,而无需查询。片段总是最后并且从不发送到服务器

IE 将正确编码URL1 的查询组件,因为它会将其检测为查询。

对于 PHP 中的解码,%D2 和类似的东西会在 $_GET['query'] 变量中自动解码。之所以没有正确填充$_GET变量是因为在URL2中,没有按标准查询。

另外,最后一件事...在执行'Траливали' == $_GET['query'] 时,只有当您的 PHP 脚本本身以 UTF-8 编码时才会如此。您的文本编辑器应该能够告诉您文件的编码。

【讨论】:

  • 是的,确实如此。谢谢你这么好的回复。但是将fragment 用于ajax 地址是一种常见的做法。它是问题的根源,而不是解决方案。
  • @topright: 这是解决方案。我不是说要一起删除片段,我是说你的片段应该永远是最后一个。重写您的链接以尊重这一点。 PHP 不处理 fragment 之后的 query,因为它不希望它在那里(根据 RFC3986,这是非法的)。 IE 甚至懒得尝试对其进行编码,因为它需要一个片段(仅限于 ASCII 字符)。
  • @topright #ajax_call?query=Траливали 表示该片段由文本ajax_call?query=Траливали 组成。片段未发送到服务器。换句话说,您在 URL 中 # 之后放置的任何内容都不会发送到服务器
  • 不相信我?试一试...echo $_SERVER['REQUEST_URI']; 会为您提供 Apache 所看到的完全一致的请求。您会很快注意到该片段丢失了。还要检查你的日志......不会有碎片。
  • @topright:看,现在问题很清楚了,我敢打赌,问题出在你的 JavaScript Fragment-To-Query 代码中......你能发布那段代码吗?
【解决方案2】:
rawurldecode($_GET['query']);

但这实际上应该已经由 php 完成了;-)

edit 你在说“没有用” - 你在尝试什么?如果文本没有按照您的意愿出现在屏幕上,例如当您echo $_GET['query']; 时,您的问题可能是您为发送回浏览器的页面指定的编码。

包括一行

header("Content-Type: text/html; charset=utf-8");

看看有没有帮助。

【讨论】:

  • 请展示整个脚本并向我们展示究竟是什么失败了。
  • 我在帖子中添加了一些测试。
【解决方案3】:

不幸的是,片段是如何编码的,browser-dependent

是否通过应用 RFC 强制的 URL 转义规则对片段 ID(哈希)进行编码?
MSIE:没有
Firefox:部分
野生动物园:是的
歌剧:没有
铬:没有
安卓:是的

关于浏览器在将国际(阅读:非ASCII)字符转换为%nn转义序列之前使用什么编码来编码的问题,“大多数浏览器通过默认发送UTF-8数据来处理这个问题手动在 URL 栏中输入的文本,并在所有后续链接上使用页面编码。” (相同的source)。

【讨论】:

  • 片段的编码方式并不重要,它只是在客户端处理。
  • @那是怎么回事?对于 javascript "á" != "%C3%A1"
【解决方案4】:

您可以为此使用UTF8::autoconvert_request()

查看http://code.google.com/p/php5-utf8/ 了解更多信息。

【讨论】:

    【解决方案5】:

    网址仅限于某些 ascii 字符。非 url 友好的字符应该是 url 编码的(你看到的 %hh 编码)。某些浏览器可能会自动对出现在 addr 行的 url 进行编码。

    【讨论】:

    • -1:在查询中传递 UTF-8 没有问题。多字节字符将被简单地编码为两个字节,然后将被正确解码。
    • 但是浏览器还在后台对url进行编码。服务器应该会看到一个格式正确的 url,webapp 将能够对其进行解码。
    • 浏览器不需要理解字符集来进行 URL 编码。它只是读取 8 个字节并将其转换为十六进制值。任何不考虑 printable ascii 的字符都由用户代理根据 RFC3986 进行编码。
    【解决方案6】:

    答案很简单:字符串编码总是。正如 HTTP 标准中所述。
    什么是 firefox 显示 - 没关系。

    另外,由于 PHP 自动解码查询字符串,也不需要解码。

    请注意,'%D2%F0%E0%EB%E8%E2%E0%EB%E8' 是单字节编码,因此,您的页面可能在 1251 中。至少 HTTP 标头对浏览器说.
    而 AJAX 总是使用 utf-8。

    因此,您只需对页面使用单一编码 (utf-8),或者将 ajax 调用与常规调用区分开来。

    至于片段 - 不要使用片段值将其发送到服务器。有一个 JS 变量,然后使用它两次 - 设置一个片段并使用 JSON 发送到服务器。

    【讨论】:

      【解决方案7】:

      RFC 1738 规定只有字母数字、特殊字符 $-_.+!*'()," 和保留字符 ;/?:@=& 在 URL 中是未编码的。其他一切都由 HTTP 客户端(即 Web 浏览器)编码。无论 PHP 是否自动解码查询字符串,您都可以使用 rawurldecode()。双重解码没有危险。

      【讨论】:

        猜你喜欢
        • 2023-04-11
        • 1970-01-01
        • 2011-12-08
        • 1970-01-01
        • 2016-05-16
        • 1970-01-01
        • 2014-06-09
        • 2013-06-17
        • 1970-01-01
        相关资源
        最近更新 更多