1

PHP で、2 つの相対 URL が等しいか比較したいと考えています。問題: URL はパーセント エンコーディングが異なる場合があります。

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

RFC 3986によると、サーバーはこれらの URI を同じように扱う必要があります。でも==比べてしまうとズレてしまうんですよね。

だから私は2つの文字列を受け入れTRUE、それらが同じURIを表す場合に返すPHP関数を探しています(同じ文字のエンコード/デコードされたバリアント、エンコードされた文字の大文字/小文字の16進数、および+%20スペース)、およびFALSEそれらが異なる場合。

これらの文字列にはASCII文字のみが含まれていることを事前に知っています.Unicodeはありません。

4

3 に答える 3

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

URLデコード

于 2010-10-08T21:49:35.583 に答える
0

編集: @webbiedave の応答を見てください。彼の方がはるかに優れています(PHPにそれを行う関数があることさえ知りませんでした..毎日何か新しいことを学びます)

%##これらのパーセントエンコーディングの発生を見つけるには、文字列を解析して一致するものを探す必要があります。次に、それらから数値を取得すると、それを渡してchr()関数を使用して、これらのパーセントエンコーディングの文字を取得できるはずです。文字列を再構築すると、それらを一致させることができるはずです。

これが最も効率的な方法かどうかはわかりませんが、URL が通常それほど長くないことを考えると、パフォーマンスへの影響はそれほど大きくないはずです。

于 2010-10-08T21:50:19.257 に答える
0

ここでのこの問題は webbiedave によって解決されているようですが、私自身の問題がありました。

最初の問題: エンコードされた文字は大文字と小文字を区別しません。したがって、%C3 と %c3 はまったく同じ文字ですが、URI としては異なります。したがって、両方の URI が同じ場所を指しています。

2 番目の問題: folder%20(2) と folder%20%282%29 は両方とも有効に urlencode された URI であり、URI は異なりますが、同じ場所を指しています。

3 番目の問題: URL エンコードされた文字を取り除くと、bla%2Fblubb と bla/blubb のような同じ URI を持つ 2 つの場所ができてしまいます。

それで何をすべきか?2 つの URI を比較するには、それらをすべてのコンポーネントに分割し、すべてのパスとクエリ部分を一度に URL デコードし、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);
}

それはすべきです。そして、はい、それは私が望んでいたよりもかなり複雑です。

于 2018-01-22T17:19:42.077 に答える