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

时间:2010-10-08 21:45:18

标签: php url uri rfc3986 percent-encoding

在PHP中,我想比较两个相对URL的相等性。 catch: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(相同的char,大写/小写十六进制数字的编码/解码变体)在编码的字符中,+%20用于空格),FALSE如果它们不同。

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

3 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:0)

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

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

不确定这是最有效的方法,但考虑到URL通常不会那么长,它不应该太过性能损失。

答案 2 :(得分:0)

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

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

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

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

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

这可能是规范它的功能:

scanf

现在你可以改变webbiedave的功能:

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;
}

应该这样做。是的,它比我想要的要复杂得多。