HTMLページをパースしてURLを取り出す処理を書いていたのですが、ページ内のリンクなどが全部絶対URLで記述されていれば非常に楽なのですが、現実としてそうでもなく、ページによっては相対パスで書かれていたりして、正規表現で偏にリンクからURLを抜き出すだけではうまくできませんでした。
そこで少しググってみたら
PHPで相対パスから絶対URL(URI)を作成する|PHPプログラムメモ|プログラムメモ
という記事を発見!おぉ、これは便利!
と思って使わせてもらおうと思ったのですが、いくつかテストしてみて、相対パス処理で不備があるなーと思ったところがあったのでちょっと改良させてもらいました。
37~38行目は正直いらない気がしたのですが、 PHP 5.3 のCLIでWindows上でテストした際に、なぜか \/ (アルファベットのVではなく、\ と / ) で出力されたのが気になったので、無駄かもしれないけどあえて記述。
あと $parse の初期化もここまでする必要ないけど、念のためNotice対策を…w
ベースURL
http://example.com/path/to/url
相対パス
こんな感じ
そこで少しググってみたら
PHPで相対パスから絶対URL(URI)を作成する|PHPプログラムメモ|プログラムメモ
という記事を発見!おぉ、これは便利!
と思って使わせてもらおうと思ったのですが、いくつかテストしてみて、相対パス処理で不備があるなーと思ったところがあったのでちょっと改良させてもらいました。
37~38行目は正直いらない気がしたのですが、 PHP 5.3 のCLIでWindows上でテストした際に、なぜか \/ (アルファベットのVではなく、\ と / ) で出力されたのが気になったので、無駄かもしれないけどあえて記述。
あと $parse の初期化もここまでする必要ないけど、念のためNotice対策を…w
相対パスから絶対URLする関数
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* 相対パスから絶対URLを返却する | |
* | |
* @param string $base ベースURL, 絶対URL | |
* @param string $relational_path 相対パス | |
* @return string 相対パスの絶対URL | |
* @link http://logic.stepserver.jp/data/archives/501.html | |
* @link http://blog.anoncom.net/2010/01/08/295.html | |
* @link https://blog.anoncom.net/2010/01/phpurluri.html | |
*/ | |
function createUri( $base = '', $relational_path = '' ) { | |
$parse = array( | |
'scheme' => null, | |
'user' => null, | |
'pass' => null, | |
'host' => null, | |
'port' => null, | |
'path' => null, | |
'query' => null, | |
'fragment' => null, | |
); | |
$parse = parse_url ( $base ); | |
// パス末尾が / で終わるパターン | |
if ( strpos( $parse['path'], '/', ( strlen( $parse['path'] ) - 1 ) ) !== FALSE ) { | |
$parse['path'] .= '.'; // ダミー挿入 | |
} | |
if ( preg_match ( '#^https?\://#', $relational_path ) ) { | |
// 相対パスがURLで指定された場合 | |
return $rel_path; | |
} elseif ( preg_match ( '#^/.*$#', $relational_path ) ) { | |
// ドキュメントルート指定 | |
return $parse['scheme'] . '://' . $parse ['host'] . $relational_path; | |
} else { | |
// 相対パス処理 | |
$basePath = explode ( '/', dirname ( $parse ['path'] ) ); | |
$relPath = explode ( '/', $relational_path ); | |
foreach ( $relPath as $relDirName ) { | |
if ($relDirName == '.') { | |
array_shift ( $basePath ); | |
array_unshift ( $basePath, '' ); | |
} elseif ($relDirName == '..') { | |
array_pop ( $basePath ); | |
if ( count ( $basePath ) == 0 ) { | |
$basePath = array( '' ); | |
} | |
} else { | |
array_push ( $basePath, $relDirName ); | |
} | |
} | |
$path = implode ( '/', $basePath ); | |
return $parse ['scheme'] . '://' . $parse ['host'] . $path; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* テストコード | |
* Testing code | |
*/ | |
$base = 'http://example.com/path/to/url'; | |
$pathes[] = '/'; | |
$pathes[] = '/index.html'; | |
$pathes[] = '/foo/bar/baz/'; | |
$pathes[] = './foo/bar/baz'; | |
$pathes[] = '../../../foo/bar/baz/index.html'; | |
$pathes[] = 'foo/bar/baz.html'; | |
$pathes[] = 'foo/bar/baz/../index.html'; | |
foreach ( $pathes as $path ) { | |
echo createUri($base, $path) . PHP_ROL; | |
} |
テストケース
ベースURL
http://example.com/path/to/url
相対パス
- /
- /index.html
- /foo/bar/baz/
- ./foo/bar/baz
- ../../../foo/bar/baz/index.html
- foo/bar/baz.html
- foo/bar/baz/../index.html
結果
こんな感じ
http://example.com/
http://example.com/index.html
http://example.com/foo/bar/baz/
http://example.com/path/to/foo/bar/baz
http://example.com/foo/bar/baz/index.html
http://example.com/path/to/foo/bar/baz.html
http://example.com/path/to/foo/bar/index.html