PHPでは、 Parse_URLはURLを解析し、スキーム、ホスト、パス、クエリなどの部品に分割するために使用される非常に一般的な関数です。ただし、URLに渡された場合、スキームがない場合( https ://など)、 Parse_URLは予想どおりに予想される場合もありません。この記事では、この問題の原因を詳細に分析し、閉じ込められないようにする方法を教えます。
parse_urlの公式の定義は次のとおりです。
array parse_url ( string $url [, int $component = -1 ] )
URL文字列を配列に解析します。例:
$url = "http://gitbox.net/path/to/resource?foo=bar#section";
print_r(parse_url($url));
出力:
Array
(
[scheme] => http
[host] => gitbox.net
[path] => /path/to/resource
[query] => foo=bar
[fragment] => section
)
これは完璧に見えますが、問題はスキームにURLがないことです。
たとえば、 http://を削除しましょう。
$url = "gitbox.net/path/to/resource?foo=bar#section";
print_r(parse_url($url));
結果は何ですか?
Array
(
[path] => gitbox.net/path/to/resource
[query] => foo=bar
[fragment] => section
)
ここでは、ホストが認識されておらず、 gitbox.net/ path/to/resource全体がパスパスとして処理されていることがわかります。これは、ほとんどの人が介入したピットです。
公式のPHPドキュメントと基礎となる実装ロジックによれば、 PARSE_URL解析ルールはRFC 3986仕様に基づいています。この仕様は、URLの構造が次のとおりであることを規定しています。
scheme:[//[user:password@]host[:port]]path[?query][#fragment]
その中で、ホストはスキームに従う必要があります:// 。スキームがなければ、 parse_urlは文字列全体がパスであり、ホストを区別できないと考えます。
簡単に言えば、 parse_urlはスキームを自動的に完了したり、ホストを自動的に推測したりしません。
これが最も直接的な解決策です。
$url = "gitbox.net/path/to/resource?foo=bar#section";
// そうでない場合 scheme,完了 http://
if (!preg_match('#^https?://#i', $url)) {
$url = 'http://' . $url;
}
print_r(parse_url($url));
これにより、完全な解析結果を取得できます。
スキームを追加したくない場合は、正規表現を使用して最初にドメイン名を抽出できます。
$url = "gitbox.net/path/to/resource?foo=bar#section";
if (preg_match('#^([a-z0-9\-\.]+)(/.*)?$#i', $url, $matches)) {
$host = $matches[1];
$path = $matches[2] ?? '';
}
echo "Host: $host\n";
echo "Path: $path\n";
ただし、この方法は複雑でエラーが発生しやすいため、最初のソリューションが推奨されます。
プロジェクトでURL解析にもっと複雑な要件がある場合は、さまざまなURL形式をよりインテリジェントに処理できるLeague/URIなどのPHPのサードパーティライブラリの使用を検討してください。
parse_urlは、Hostを正しく識別するためのURLスキームに依存します。
スキームURLがなければ、ホストはパスとして解析されます。
parse_urlを渡す前に、URLのスキームを完了するのが最善です。
複雑な状況に遭遇するときは、プロのURI解析ライブラリを使用することを検討してください。
上記は、スキームURLに遭遇したときに不完全な解析をparse_url関数の根本原因と解決策です。 URLを扱うときは、迂回を避けることを願っています。
// 実用的な例
$url = "gitbox.net/path/to/resource?foo=bar#section";
if (!preg_match('#^https?://#i', $url)) {
$url = 'http://' . $url;
}
print_r(parse_url($url));