PHP:比较百分比编码不同的 URI

Posted

技术标签:

【中文标题】PHP:比较百分比编码不同的 URI【英文标题】:PHP: comparing URIs which differ in percent-encoding 【发布时间】:2011-04-23 02:42:27 【问题描述】:

php 中,我想比较两个相对 URL 是否相等。问题:URL 的百分比编码可能不同,例如

/dir/file+file/dir/file%20file /dir/file(file)/dir/file%28file%29 /dir/file%5bfile/dir/file%5Bfile

根据RFC 3986,服务器应该同等对待这些URI。但是如果我用==来比较,我会得到一个不匹配的结果。

所以我正在寻找一个 PHP 函数,它将接受两个字符串并返回 TRUE 如果它们表示相同的 URI(在编码中区分相同字符的编码/解码变体、大写/小写十六进制数字字符,+%20 用于空格),FALSE(如果它们不同)。

我事先知道这些字符串中只有 ASCII 字符——没有 unicode。

【问题讨论】:

【参考方案1】:
function uriMatches($uri1, $uri2)

    return urldecode($uri1) == urldecode($uri2);


echo uriMatches('/dir/file+file', '/dir/file%20file');      // TRUE
echo uriMatches('/dir/file(file)', '/dir/file%28file%29');  // TRUE
echo uriMatches('/dir/file%5bfile', '/dir/file%5Bfile');    // TRUE

urldecode

【讨论】:

【参考方案2】:

编辑:请查看@webbiedave 的回复。他的要好得多(我什至不知道 PHP 中有一个函数可以做到这一点.. 每天学习新东西)

您必须解析字符串以查找匹配 %## 的内容,以找到这些百分比编码的出现。然后从中获取数字,您应该能够传递它,以便 chr() 函数获取这些百分比编码的字符。重建字符串,然后你应该能够匹配它们。

不确定这是最有效的方法,但考虑到 URL 通常不会那么长,它应该不会对性能造成太大影响。

【讨论】:

【参考方案3】:

我知道这里的这个问题似乎是由 webbiedave 解决的,但我有自己的问题。

第一个问题:编码字符不区分大小写。所以 %C3 和 %c3 都是完全相同的字符,尽管它们作为 URI 是不同的。所以两个 URI 都指向同一个位置。

第二个问题:folder%20(2) 和 folder%20%282%29 都是有效的 urlencoded URI,它们指向同一个位置,尽管它们是不同的 URI。

第三个问题:如果我去掉 url 编码的字符,我有两个位置具有相同的 URI,例如 bla%2Fblubb 和 bla/blubb。

那该怎么办呢?为了比较两个 URI,我需要对它们进行规范化,将它们拆分为所有组件,对所有路径和查询部分进行一次 urldecode,对它们进行 rawurlencode 并将它们粘合在一起,然后我可以比较它们。

这可能是标准化它的功能:

function normalizeURI($uri) 
    $components = parse_url($uri);
    $normalized = "";
    if ($components['scheme']) 
        $normalized .= $components['scheme'] . ":";
    
    if ($components['host']) 
        $normalized .= "//";
        if ($components['user'])  //this should never happen in URIs, but still probably it's anything can happen thursday
            $normalized .= rawurlencode(urldecode($components['user']));
            if ($components['pass']) 
                $normalized .= ":".rawurlencode(urldecode($components['pass']));
            
            $normalized .= "@";
        
        $normalized .= $components['host'];
        if ($components['port']) 
            $normalized .= ":".$components['port'];
        
    
    if ($components['path']) 
        if ($normalized) 
            $normalized .= "/";
        
        $path = explode("/", $components['path']);
        $path = array_map("urldecode", $path);
        $path = array_map("rawurlencode", $path);
        $normalized .= implode("/", $path);
    
    if ($components['query']) 
        $query = explode("&", $components['query']);
        foreach ($query as $i => $c) 
            $c = explode("=", $c);
            $c = array_map("urldecode", $c);
            $c = array_map("rawurlencode", $c);
            $c = implode("=", $c);
            $query[$i] = $c;
        
        $normalized .= "?".implode("&", $query);
    
    return $normalized;

现在您可以将 webbiedave 的功能更改为:

function uriMatches($uri1, $uri2) 
    return normalizeURI($uri1) === normalizeURI($uri2);

应该可以。是的,它比我想要的要复杂得多。

【讨论】:

以上是关于PHP:比较百分比编码不同的 URI的主要内容,如果未能解决你的问题,请参考以下文章

在 react-router 中使用百分比( % )登录:id

RFC3986 - 哪些 pchars 需要进行百分比编码?

urlbase64 编码规则

URL传参中不能带特殊的字符以及处理方案

如何在 libre office 中设置 URL 编码的超链接?

PHP 比较2组字符串并获得匹配百分比