PHPで相対パスとなっているURLを絶対パスに変換する方法
WEBサイトをクローリングしていると絶対パスで記述されているサイトもあれば、相対パスで書かれているサイトも1ったりします。
そういったサイトのリンクをURL形式に変換するプログラムを作ってみました。
相対パスとなっているURLを絶対パスにしたい
サイトによってリンクの書き方は様々です。例えば下記のようなリンクがよくあります。
■サイトURL
http://example.com/
■サイト内のリンク
http://example.com/about/
/about/
../../about/
./dir1/dir2/
やりたいことは、こういった絶対パスで書かれているURLや相対パスで書かれているURLを絶対パスのURLにすべて統一したいということです。
関数を作って呼び出す
とりあえず関数化してみました。実際に使いながら改良していって変なプログラムになりましたが、問題なく動作しています。
<?php
// アクセスしているURL
$baseUrl = 'http://example.com/dir1/dir2';
//ページ内にあるURL
$linkList = ['../../about',
'/contact',
'./',
'../',
'../../files/test.pdf',
'http://example.com/dir1/',
'http://日本語ドメインの外部サイト.com/',
];
foreach ($linkList as $key => $link){
$url = getNormalizationUrl($baseUrl, $link);
var_dump("【{$key}】Q:{$link}");
var_dump("【{$key}】A:{$url}");
}
function getNormalizationUrl($baseUrl, $link, $isPunycode = TRUE)
{
$baseParse = parse_url($baseUrl);
$linkParse = parse_url($link);
// asciiに変換
if ($isPunycode) {
if (isset($baseParse['host'])) {
$baseParse['host'] = idn_to_ascii($baseParse['host']);
}
if (isset($linkParse['host'])) {
$linkParse['host'] = idn_to_ascii($linkParse['host']);
}
}
$url = null;
if (isset($linkParse['host'])) {
$url = "{$linkParse['scheme']}://{$linkParse['host']}{$linkParse['path']}" .
(isset($linkParse['query']) ? '?' . $linkParse['query'] : '');
;
} elseif (isset($linkParse['path'])) {
if ((in_array(substr($linkParse['path'], 0, 2), ['./','..']))) {
$slashList = explode('/', $linkParse['path']);
$basePath = isset($baseParse['path']) ? $baseParse['path'] : '';
// 拡張子が存在すればファイル名と判断し削除する
if (pathinfo($basePath, PATHINFO_EXTENSION)) {
// ファイル名を除く
$basePath = pathinfo($basePath, PATHINFO_DIRNAME);
}
foreach ($slashList as $val) {
if ($val == '..') {
$basePath = dirname($basePath);
}
if (in_array($basePath, ['/','\\'])) {
$basePath = '';
break;
}
}
$url = $baseParse['scheme'] . '://' . $baseParse['host'] . $basePath . '/' . str_replace(['../','./'],
'', $link);
} elseif (substr($linkParse['path'], 0, 1) == '/') {
$url = $baseParse['scheme'] . '://' . $baseParse['host'] . $link;
} else {
$basePath = isset($baseParse['path']) ? $baseParse['path'] : '';
if (pathinfo($basePath, PATHINFO_EXTENSION)) {
$basePath = pathinfo($basePath, PATHINFO_DIRNAME);
}
$url = $baseParse['scheme'] . '://' . str_replace("//", "/", $baseParse['host'] . '/' . $basePath . '/' .
$link);
}
}
return $url;
}
?>
実行結果は下記になります。
string(22) "【0】Q:../../about"
string(35) "【0】A:http://example.com/about"
string(19) "【1】Q:/contact"
string(37) "【1】A:http://example.com/contact"
string(13) "【2】Q:./"
string(40) "【2】A:http://example.com/dir1/dir2/"
string(14) "【3】Q:../"
string(35) "【3】A:http://example.com/dir1/"
string(31) "【4】Q:../../files/test.pdf"
string(44) "【4】A:http://example.com/files/test.pdf"
string(35) "【5】Q:http://example.com/dir1/"
string(35) "【5】A:http://example.com/dir1/"
string(62) "【6】Q:http://日本語ドメインの外部サイト.com/"
string(62) "【6】A:http://xn--u9jwfb1eyeb2ouf2669ay00a16cdy1mgdra.com/"
相対パスでのリンクに関しては現在のアクセスしているURLを下にURLを生成して返却します。
URLでのリンクの場合は、処理をせずそのまま返却しています。
日本語ドメインなどのURLに関しては、英字の文字列に変換して返却しています。
まとめ
現時点でこの関数でURLを正規化して1日50万ページを解析しています。今のところエラーもなく動作しているので大丈夫と思われます。
といいつつ、使用する際は自己責任のもと使用してください。
コメント
コメントを残す