PHP:パーセントエンコードが異なるURIを比較します
-
28-09-2019 - |
質問
PHPでは、平等について2つの相対URLを比較したいと考えています。キャッチ:URLはエンコードパーセントが異なる場合があります。
/dir/file+file
vs。/dir/file%20file
/dir/file(file)
vs。/dir/file%28file%29
/dir/file%5bfile
vs。/dir/file%5Bfile
によると RFC 3986, 、サーバーはこれらのURIを同じように処理する必要があります。しかし、私が使用する場合 ==
比較するために、私はミスマッチになります。
だから私は2つの文字列と返品を受け入れるPHP関数を探しています TRUE
それらが同じURIを表している場合(エンコードされたCHARSのエンコード/デコードされたバリアント、エンコードされたCHARの上部/低ケースの16進数、および測定されます。 +
vs。 %20
スペース用)、および FALSE
それらが違う場合。
私は、これらの文字列にあるASCII charのみがあることを事前に知っています - ユニコードはありません。
解決
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
他のヒント
編集: @webbiedaveの応答をご覧ください。彼の方がはるかに優れています(PHPにそれを行う機能があることを知りませんでした。毎日何か新しいことを学びます)
一致するものを探すために文字列を解析する必要があります %##
それらのパーセントエンコーディングの発生を見つけるため。その後、それらから番号を取ると、あなたはそれを渡すことができるはずですので chr() これらのパーセントエンコーディングの特性を取得する機能。文字列を再構築すると、それらを一致させることができるはずです。
それが最も効率的な方法であるかどうかはわかりませんが、URLが通常それほど長くないことを考慮すると、パフォーマンスのヒットはそれほど多くないはずです。
ここでこの問題はWebbiedaveによって解決されているように見えることを知っていますが、私はそれについて私自身の問題を抱えていました。
最初の問題:エンコードされた文字はケース非感受性です。したがって、%C3と%C3は両方ともまったく同じ文字ですが、URIとは異なります。したがって、両方のウリスは同じ場所を指しています。
2番目の問題:フォルダー%20(2)とフォルダー%20%282%29はどちらも有効にurlencoded urisです。
3番目の問題:URLエンコードされた文字を取り除くと、BLA%2FBLUBBやBLA/BLUBBと同じURIを持つ2つの場所があります。
それで、何をすべきか? 2つのURIを比較するには、すべてのコンポーネントでそれらを分割し、すべてのパスとクエリパートを1回分割する方法で両方のURIを正規化する必要があります。
そして、これはそれを正常化する機能かもしれません:
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);
}
それはすべきです。そして、はい、それは私が望んでいたよりも非常に複雑です。