[PHP]parse_url関数を完全解説!URLを分解する方法を実例付きで紹介

PHP

こんにちは!今回は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構成要素の詳細

取得できる構成要素

要素定数説明
schemePHP_URL_SCHEMEプロトコルhttp, https, ftp
hostPHP_URL_HOSTホスト名example.com
portPHP_URL_PORTポート番号8080, 443
userPHP_URL_USERユーザー名username
passPHP_URL_PASSパスワードpassword
pathPHP_URL_PATHパス/path/to/page
queryPHP_URL_QUERYクエリ文字列id=123&name=test
fragmentPHP_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エンコード/デコード
タイトルとURLをコピーしました