PHPでsitmap.xmlを生成
PHP Simple HTML DOM Parserを使ってURLを抽出しsitemap.xmlを生成
PHP Simple HTML DOM Parserのダウンロード
PHP Simple HTML DOM Parserからたどり、 PHP Simple HTML DOM Parserに移動し 最新のライブラリ(simple_html_dom.php)をダウンロード。
PHP Simple HTML DOM Parserを使用してリンクを辿り、URLを抽出し、XMLを生成。 仕様としては、(1)ホームのURLを指定する (2)ホームからのリンクを辿る都合上、リンクが切れている場合はURLは辿れない (3)処理に時間がかかるのでタイムアウトしない設定をする。
PHP
/**
* PHPでsitmap.xmlを生成
*
* @param string $url
* @param array $ext : 除外拡張子
* @param array $exception : 除外URL
* @return array
*/
function createSitemap($homeurl, $ext = array(), $exception = array())
{
// ライブラリ読み込み
require_once('simple_html_dom.php');
// ベースURL(http,https)
$arrUrl = @parse_url($homeurl);
$base_url = 'http://' . $arrUrl['host'] . '/';
$base_url_ssl = 'https://' . $arrUrl['host'] . '/';
// 除外拡張子を|で連結
if (! empty($ext)) {
$ext_ptn = implode('|', $ext);
}
$links = array();
$link_url = '';
// チェック待機URLが0になるまで繰り返し
while ($retry < 1) {
// チェックURLを1つ抽出
if (! empty($links)) {
foreach($links as $linksKey => $linksVal){
if ($linksVal == '0') {
$link_url = $linksKey;
break;
}
}
}
if (empty($link_url)) {
// 初回はベースURLを解析
$link_url = $base_url;
}
$html = file_get_html($link_url);
// ディレクトリを抽出
$parts = parse_url($link_url);
$pathinfo = pathinfo($parts['path']);
if (! empty($pathinfo['extension'])) {
$dirname = $pathinfo['dirname'] . '/';
} elseif (! empty($pathinfo['basename'])) {
$dirname = '/' . $pathinfo['basename'] . '/';
} else {
$dirname = '/';
}
// 相対パス用にチェック用のディレクトリを配列に分解
$target_dir = array();
foreach(explode('/', $dirname) as $splitVal) {
if (! empty($splitVal)) {
$target_dir[] = $splitVal;
}
}
if (! empty($html)) {
// チェック済URL
$links[$link_url] = '1';
// <a href=""></a>を抽出
foreach($html->find('a') as $element){
$urls[] = $element->href;
}
// <iframe src="">を抽出
foreach($html->find('iframe') as $element){
$urls[] = $element->src;
}
$urls = array_unique($urls);
foreach($urls as $url){
// http://(またはhttps://)でURLが指定されている場合はベースURLを除去
$base = array($base_url, $base_url_ssl);
$url = str_replace($base, '', $url);
// 外部リンクを除外
if (preg_match('/^https?:/', $url)) {
continue;
}
// mailto:,javascript:などを除外
if (preg_match('/^[^?]+:/', php-sitemap)) {
continue;
}
// #以下を除去
$url = preg_replace('/^(.*)#(.*)/', '$1', $url);
// #除去後空の場合は除外
if ($url == '') {
continue;
}
// 除外拡張子に設定されている拡張子にマッチするURLを除外
if (! empty($ext_ptn)) {
if (preg_match('/\.(' . $ext_ptn . ')$/i', $url)) {
continue;
}
}
// 相対パスを絶対パスに置換
if (! preg_match('/^\/(.*)/', $url)) {
// ./ を除去
$url = preg_replace('/^\.\/(.*)/', '$1', $url);
// ../ を置き換える
if (preg_match('/^(\.\.\/)+(.*)/', $url, $match)) {
// ../の数を取得
$path_count = substr_count($match[0], '../');
// ../の総数だけディレクトリを削る
$individual_dir = $target_dir;
for ($i = 0; $i < $path_count; $i++) {
$individual_dir = array_pop($individual_dir);
}
$url = implode('/', $individual_dir) . $match[2];
} else {
$url = $dirname . $url;
}
}
// 除外URLに設定されているURLを除外
if (! empty($exception)) {
if (array_search($url, $exception) !== FALSE){
continue;
}
}
// /で終わるベースURLと結合させるため、頭の/を除去
$url = preg_replace('/^\/(.*)/', '$1', $url);
$link = $base_url . $url;
if (empty($links[$link])) {
// チェック待機URL
$links[$link] = '0';
}
}
} else {
// 存在しないURL
$links[$link_url] = '2';
}
// 残チェックURLが1つでもあれば繰り返し
$retry = 1;
if (! empty($links)) {
foreach($links as $linksVal){
if ($linksVal == '0') {
$retry = 0;
break;
}
}
}
}
$loc = array();
if (! empty($links)) {
foreach($links as $linksKey => $linksVal){
if ($linksVal == '1') {
$loc[] = $linksKey;
}
}
}
return $loc;
}
チェックURLステイタスが1ではなく、2を抽出すればリンク切れを把握することが可能。
使用例
PHP
$homeurl = 'http://php.o0o0.jp/';
$ext = array('pdf', 'zip', 'csv');
$exception = array('/rss');
$loc = createSitemap($homeurl, $ext, $exception);
$sxe = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><urlset></urlset>');
$sxe->addAttribute('xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9');
foreach($loc as $locKey) {
$urlSxe = ('url');
$urlSxe->addChild('loc', $locKey);
}
echo $sxe->asXML();
exit;
XMLの生成については、PHPでXMLを生成を参照。
sitemap.xmlを作成する際、他のサービスを使っていたのですが、自前でなんとかできないかと思い作成しました。 あらゆるサイトで試した訳ではないのでバグがあるかもしれません。それを踏まえて後で改修するかもしれません。