今日も適当ダイアリー

PHP や Javascript や Symfony、BEAR.Sunday などのWeb周りのことを中心に。それ以外のことも気まぐれに投稿します。

相対パスから絶対URL(http://〜〜)への変換

とあるURLの相対パス(./ とか ../../hoge/ とか)から絶対URL(http://〜〜)の情報を取得したいような場合、PHPではそのような関数などはないため、自力でなんとか解決しなければなりません。

自分のために作ったけど、自分のための備忘録代わりに投稿しておきます。

ソースは以下の通り。

<?php
$baseURL = 'http://www.example.com/hoge/fuga/';
$relativePath = './../foo/test.php';

echo getAbsURL($baseURL, $relativePath);

// ベースURL と 相対パス情報から、絶対パス(http(s)://〜〜)を返す
function getAbsURL($baseURL, $relativePath) {
    if ($relativePath == '') {
        // 相対パスが空の場合は、baseURLをそのまま返す
        return $baseURL;
    }

    if (preg_match('@^https?://@iD', $relativePath)) {
        // 相対パスが http(s):// から始まる場合は、そのまま返す
        return $relativePath;
    }

    // baseURL の分解
    if (!preg_match('@^(https?://[^/]+)/?(.*)$@iD',
        $baseURL, $tmpMatches)) {
        // http(s)://〜〜から始まらない場合
        if ($baseURL[0] != '/') {
            return false;
        }

        $tmpMatches = array(
            $baseURL,
            '',
            substr($baseURL, 1)
        );
    }

    $base = $tmpMatches[1];     // e.g. http://www.example.com
    $tmpPath = $tmpMatches[2];  // e.g. hoge/fuga/index.php
    $path = array();

    if (preg_match('@^/@iD', $relativePath)) {
        // 相対パスが/から始まる場合
        return $base . $relativePath;
    }

    // baseURLパス情報にディレクトリが含まれていれば
    // baseURLのパス情報をディレクトリ情報のみに
    if (strlen($tmpPath) > 0 && strpos($tmpPath, '/') !== false) {
        if ($tmpPath[strlen($tmpPath) - 1] == '/') {
            // 最後が / なら/を削除
            $tmpPath = substr($tmpPath, 0, -1);
        } else {
            // 最後が / ではない(ファイル名)の場合、/ までを削除
            $tmpPath = substr($tmpPath, 0, strrpos($tmpPath, '/'));
        }

        // ディレクトリ名毎に配列にする
        $path = explode('/', $tmpPath);
    }

    // 相対パス情報をディレクトリ毎に配列にする
    $relativePath = explode('/', $relativePath);

    // 相対パスディレクトリ毎に
    foreach($relativePath as $dir) {
        if ($dir == '.') {
            // /./ は処理をスキップ
            continue;
        }

        if (preg_match('@^\.+$@iD', $dir)) {
            // /../ /.../ などなら、ディレクトリを上にたどる
            for ($i=1; $i < strlen($dir); $i++) {
                array_pop($path);
            }
            continue;
        }

        // .以外のディレクトリ名の場合は、そのまま追加
        $path[] = $dir;
    }

    // パスを/で結合
    $path = implode('/', $path);
    return $base . '/' . $path;
}

以上。