こんにちは!今回はPHPでURL操作に欠かせない関数「parse_url」について、詳しく解説していきます。
parse_url関数とは?
parse_urlは、URLを構成要素(スキーム、ホスト、パス、クエリなど)に分解してくれる関数です。URLの解析や操作を行う際に非常に便利で、Web開発では頻繁に使用されます。
基本的な使い方
構文
parse_url(string $url, int $component = -1): int|string|array|null|false
パラメータ
- $url: 解析したいURL文字列
- $component: 取得したい特定の構成要素(省略可能)
戻り値
- 配列: すべての構成要素(componentを指定しない場合)
- 文字列/整数: 指定した構成要素の値
- null: 指定した構成要素が存在しない場合
- false: URLが不正な場合
基本的な使用例
<?php
$url = "https://user:pass@example.com:8080/path/to/page?id=123&name=test#section";
$parts = parse_url($url);
print_r($parts);
/*
出力:
Array
(
[scheme] => https
[host] => example.com
[port] => 8080
[user] => user
[pass] => pass
[path] => /path/to/page
[query] => id=123&name=test
[fragment] => section
)
*/
?>
URL構成要素の詳細
取得できる構成要素
| 要素 | 定数 | 説明 | 例 |
|---|---|---|---|
| scheme | PHP_URL_SCHEME | プロトコル | http, https, ftp |
| host | PHP_URL_HOST | ホスト名 | example.com |
| port | PHP_URL_PORT | ポート番号 | 8080, 443 |
| user | PHP_URL_USER | ユーザー名 | username |
| pass | PHP_URL_PASS | パスワード | password |
| path | PHP_URL_PATH | パス | /path/to/page |
| query | PHP_URL_QUERY | クエリ文字列 | id=123&name=test |
| fragment | PHP_URL_FRAGMENT | フラグメント | section |
特定の構成要素だけを取得
<?php
$url = "https://example.com:8080/blog/article?id=100#comments";
// ホスト名だけを取得
$host = parse_url($url, PHP_URL_HOST);
echo $host; // example.com
// パスだけを取得
$path = parse_url($url, PHP_URL_PATH);
echo $path; // /blog/article
// クエリ文字列だけを取得
$query = parse_url($url, PHP_URL_QUERY);
echo $query; // id=100
// ポート番号だけを取得
$port = parse_url($url, PHP_URL_PORT);
echo $port; // 8080
// フラグメントだけを取得
$fragment = parse_url($url, PHP_URL_FRAGMENT);
echo $fragment; // comments
?>
実践的な使用例
例1: ドメイン名を取得
<?php
function getDomain($url) {
$host = parse_url($url, PHP_URL_HOST);
// www.を除去
if (strpos($host, 'www.') === 0) {
$host = substr($host, 4);
}
return $host;
}
echo getDomain("https://www.example.com/page"); // example.com
echo getDomain("http://blog.example.co.jp/"); // blog.example.co.jp
?>
例2: クエリパラメータの取得と解析
<?php
$url = "https://example.com/search?keyword=PHP&category=programming&page=2";
// クエリ文字列を取得
$query = parse_url($url, PHP_URL_QUERY);
// parse_strと組み合わせて配列に変換
parse_str($query, $params);
print_r($params);
/*
Array
(
[keyword] => PHP
[category] => programming
[page] => 2
)
*/
echo "検索キーワード: " . $params['keyword']; // PHP
echo "ページ番号: " . $params['page']; // 2
?>
例3: 相対URLと絶対URLの判定
<?php
function isAbsoluteUrl($url) {
$scheme = parse_url($url, PHP_URL_SCHEME);
return !empty($scheme);
}
echo isAbsoluteUrl("https://example.com/page") ? "絶対URL" : "相対URL"; // 絶対URL
echo isAbsoluteUrl("/page/about") ? "絶対URL" : "相対URL"; // 相対URL
echo isAbsoluteUrl("../images/logo.png") ? "絶対URL" : "相対URL"; // 相対URL
?>
例4: URLの安全性チェック
<?php
function isSecureUrl($url) {
$scheme = parse_url($url, PHP_URL_SCHEME);
return $scheme === 'https';
}
function isTrustedDomain($url, $trustedDomains) {
$host = parse_url($url, PHP_URL_HOST);
return in_array($host, $trustedDomains);
}
$url1 = "https://example.com/page";
$url2 = "http://example.com/page";
echo isSecureUrl($url1) ? "安全な接続" : "安全でない接続"; // 安全な接続
echo isSecureUrl($url2) ? "安全な接続" : "安全でない接続"; // 安全でない接続
$trustedDomains = ['example.com', 'trusted-site.com'];
$externalUrl = "https://unknown-site.com/page";
if (isTrustedDomain($url1, $trustedDomains)) {
echo "信頼できるドメインです";
} else {
echo "外部ドメインです";
}
?>
例5: URLの再構築
<?php
$url = "https://example.com:8080/old-path?id=123#section";
// URLを分解
$parts = parse_url($url);
// パスを変更
$parts['path'] = '/new-path';
// クエリパラメータを追加
parse_str($parts['query'], $queryParams);
$queryParams['new_param'] = 'value';
$parts['query'] = http_build_query($queryParams);
// URLを再構築
function buildUrl($parts) {
$url = '';
if (isset($parts['scheme'])) {
$url .= $parts['scheme'] . '://';
}
if (isset($parts['user'])) {
$url .= $parts['user'];
if (isset($parts['pass'])) {
$url .= ':' . $parts['pass'];
}
$url .= '@';
}
if (isset($parts['host'])) {
$url .= $parts['host'];
}
if (isset($parts['port'])) {
$url .= ':' . $parts['port'];
}
if (isset($parts['path'])) {
$url .= $parts['path'];
}
if (isset($parts['query'])) {
$url .= '?' . $parts['query'];
}
if (isset($parts['fragment'])) {
$url .= '#' . $parts['fragment'];
}
return $url;
}
echo buildUrl($parts);
// https://example.com:8080/new-path?id=123&new_param=value#section
?>
例6: リダイレクト先の検証
<?php
function validateRedirectUrl($redirectUrl, $allowedDomains) {
// URLを解析
$parts = parse_url($redirectUrl);
// 不正なURLチェック
if ($parts === false) {
return false;
}
// 相対URLは許可
if (!isset($parts['host'])) {
return true;
}
// ホワイトリストのドメインチェック
return in_array($parts['host'], $allowedDomains);
}
$allowedDomains = ['example.com', 'subdomain.example.com'];
// テスト
$redirect1 = "https://example.com/dashboard";
$redirect2 = "https://malicious-site.com/phishing";
$redirect3 = "/internal/page";
var_dump(validateRedirectUrl($redirect1, $allowedDomains)); // true
var_dump(validateRedirectUrl($redirect2, $allowedDomains)); // false
var_dump(validateRedirectUrl($redirect3, $allowedDomains)); // true
?>
様々なURL形式の処理
<?php
// HTTPSのURL
$url1 = "https://www.example.com/page";
print_r(parse_url($url1));
// 認証情報付きURL
$url2 = "ftp://user:password@ftp.example.com/files/document.pdf";
print_r(parse_url($url2));
// ポート番号付きURL
$url3 = "http://localhost:3000/api/users";
print_r(parse_url($url3));
// クエリとフラグメント付きURL
$url4 = "https://example.com/article?id=100&lang=ja#section-2";
print_r(parse_url($url4));
// 相対URL(ホスト情報なし)
$url5 = "/path/to/page?param=value";
print_r(parse_url($url5));
/*
Array
(
[path] => /path/to/page
[query] => param=value
)
*/
?>
注意点とベストプラクティス
1. エラーハンドリング
<?php
$invalidUrl = "http:///invalid-url";
$result = parse_url($invalidUrl);
if ($result === false) {
echo "URLの解析に失敗しました";
} else {
print_r($result);
}
// 特定の要素を取得する場合
$host = parse_url($invalidUrl, PHP_URL_HOST);
if ($host === null) {
echo "ホスト名が見つかりません";
} elseif ($host === false) {
echo "URLが不正です";
} else {
echo "ホスト名: " . $host;
}
?>
2. URLエンコーディングの扱い
<?php
// URLエンコードされた文字列
$url = "https://example.com/search?q=PHP%20%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0";
$query = parse_url($url, PHP_URL_QUERY);
echo $query; // q=PHP%20%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0
// デコードする
parse_str($query, $params);
echo $params['q']; // PHP プログラミング
?>
3. セキュリティ上の注意
<?php
// ユーザー入力のURL検証
function sanitizeUrl($url) {
// URLを解析
$parts = parse_url($url);
if ($parts === false) {
return false;
}
// スキームの検証(httpまたはhttpsのみ許可)
if (isset($parts['scheme']) && !in_array($parts['scheme'], ['http', 'https'])) {
return false;
}
return $url;
}
// 危険なスキームをブロック
$dangerousUrl = "javascript:alert('XSS')";
$safeUrl = "https://example.com/page";
var_dump(sanitizeUrl($dangerousUrl)); // false
var_dump(sanitizeUrl($safeUrl)); // https://example.com/page
?>
実用的なヘルパー関数
<?php
class UrlHelper {
// ベースURLを取得
public static function getBaseUrl($url) {
$parts = parse_url($url);
if (!isset($parts['scheme']) || !isset($parts['host'])) {
return null;
}
$baseUrl = $parts['scheme'] . '://' . $parts['host'];
if (isset($parts['port'])) {
$baseUrl .= ':' . $parts['port'];
}
return $baseUrl;
}
// パスとクエリを取得
public static function getPathAndQuery($url) {
$parts = parse_url($url);
$result = isset($parts['path']) ? $parts['path'] : '/';
if (isset($parts['query'])) {
$result .= '?' . $parts['query'];
}
return $result;
}
// URLが同じドメインかチェック
public static function isSameDomain($url1, $url2) {
$host1 = parse_url($url1, PHP_URL_HOST);
$host2 = parse_url($url2, PHP_URL_HOST);
return $host1 === $host2;
}
}
// 使用例
$url = "https://example.com:8080/path/to/page?id=123";
echo UrlHelper::getBaseUrl($url); // https://example.com:8080
echo UrlHelper::getPathAndQuery($url); // /path/to/page?id=123
$url1 = "https://example.com/page1";
$url2 = "https://example.com/page2";
$url3 = "https://other.com/page";
var_dump(UrlHelper::isSameDomain($url1, $url2)); // true
var_dump(UrlHelper::isSameDomain($url1, $url3)); // false
?>
まとめ
parse_url関数は、URLを簡単に解析できる強力な関数です。主なポイントをまとめます:
- 8つの構成要素を取得可能: scheme, host, port, user, pass, path, query, fragment
- 柔軟な使い方: 全要素の取得も、特定要素のみの取得も可能
- エラーハンドリング: false/nullの戻り値に注意
- セキュリティ: ユーザー入力のURL検証に活用
- 他の関数と組み合わせ: parse_str、http_build_queryなどと連携
URLの解析や操作が必要な場面で、parse_urlは非常に便利です。特にリダイレクト処理、API連携、セキュリティチェックなど、実務で頻繁に使用される関数なので、ぜひマスターしてください!
関連記事
parse_str()– クエリ文字列を配列に変換http_build_query()– 配列からクエリ文字列を生成urlencode()/urldecode()– URLエンコード/デコード
