PHPで相対パスから絶対URL(URI)を作成する

HTMLページをパースしてURLを取り出す処理を書いていたのですが、ページ内のリンクなどが全部絶対URLで記述されていれば非常に楽なのですが、現実としてそうでもなく、ページによっては相対パスで書かれていたりして、正規表現で偏にリンクからURLを抜き出すだけではうまくできませんでした。

そこで少しググってみたら

PHPで相対パスから絶対URL(URI)を作成する|PHPプログラムメモ|プログラムメモ

という記事を発見!おぉ、これは便利!
と思って使わせてもらおうと思ったのですが、いくつかテストしてみて、相対パス処理で不備があるなーと思ったところがあったのでちょっと改良させてもらいました。

37~38行目は正直いらない気がしたのですが、 PHP 5.3 のCLIでWindows上でテストした際に、なぜか \/ (アルファベットのVではなく、\/ ) で出力されたのが気になったので、無駄かもしれないけどあえて記述。
あと $parse の初期化もここまでする必要ないけど、念のためNotice対策を…w

相対パスから絶対URLする関数


<?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;
}
}
<?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;
}
view raw test-code.php hosted with ❤ by GitHub



テストケース


ベース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

最近作ったアプリの話

先日、コナミ社の提供している コナステ のダウンロードコンテンツゲームを1クリックで起動できるアプリを作り、公開した。 Ks Game Launcher  ( Github ) 作った理由として、インストール時に作成されたショートカットをクリックするとブラウザが起動し、ログインし...