最近製作網站的 sitemap ,要求每個 txt 檔案包含不超過 5w 條 url 。包括 www 站 與 m 站,http 與 https ,即要同時製作四份 sitemap ,並每日自動更新。
CREATE TABLE `z_sitemaps` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`txt_area` enum('m','www') NOT NULL DEFAULT 'www',
`txt_order` int(10) unsigned NOT NULL COMMENT '檔名稱 1.txt 2.txt ..',
`url_sum` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '包含的url數量',
`complete` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '是否填充完畢',
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
<?php
namespace App\Library\Other;
use DB;
/**
* 整理 sitemap 檔案
* 製作 sitemap xml 地圖
*/
class Sitemap {
private $max_num; // 單個sitemap最大url個數
private $area; // www | m
private $https_dir; // 存放路徑
private $sync_xml_dir; // sitemap xml地圖
// 規範:所有dir路徑必須以/結尾
public function __construct(string $area){
$this->max_num = 49900;
$this->area = in_array($area, ['www','m']) ? $area : 'www';
$this->https_dir = public_path().'/sitemaps/'.$area.'/https/';
$this->sync_xml_dir = public_path().'/sitemaps/';
}
/*
* @param $urls url陣列
* @return 所放入的檔案路徑,多個檔案以;分隔
*/
public function createSitemap(array $urls){
$count = count($urls);
if($count > $this->max_num){return false;}
$sitemap = $this->searchSitemap();
$expect_num = 49900 - $sitemap->url_sum;
$put_files = [];
// 檔案數量小於期望值直接填充
if($count <= $expect_num){
$file_name = $this->fillSitemap($sitemap, $urls);
$put_files[] = $file_name;
}else{
// 先將未填滿的sitemap檔案填滿
$slice_arr = array_slice($urls, 0, $expect_num);
$file_name = $this->fillSitemap($sitemap, $slice_arr);
$put_files[] = $file_name;
// 再將剩餘的新增到新檔案
$remain = array_slice($urls,$expect_num);
$sitemap = $this->newSitemap();
$file_name = $this->fillSitemap($sitemap, $remain);
$put_files[] = $file_name;
}
return implode(';', $put_files);
}
/*
* 查詢尚未填充完畢的sitemap檔案
* @return 一條表記錄
*/
public function searchSitemap(){
$sitemap = DB::table('z_sitemaps')->where('txt_area',$this->area)->where('complete',0)->where('url_sum','<',$this->max_num)->orderBy('id','desc')->first();
return $sitemap ? $sitemap : $this->newSitemap();
}
/*
* 建立空sitemap檔案
* @return 一條資料記錄
*/
public function newSitemap(){
// 最大檔名
$max_order = DB::table('z_sitemaps')->where('txt_area',$this->area)->max('txt_order');
// 最大檔名+1 則是下一個檔名
if(!$max_order){ $max_order = 1;} else { $max_order = $max_order + 1;}
// public/sitemaps/{www|m}/https/1.txt
$file_name = $this->getSitemapFilename($max_order);
// 建立空檔案
file_put_contents($file_name, '');
// 同時新增表記錄對應檔名
$sitemap_id = DB::table('z_sitemaps')->insertGetId([
'txt_area' => $this->area,
'txt_order' => $max_order,
'created_at' => date('Y-m-d H:i:s', time()),
]);
return DB::table('z_sitemaps')->where('id',$sitemap_id)->first();
}
/*
* @param $sitemap 一條表記錄
* @param $urls url陣列
* @return 已儲存的sitemap檔案地址
*/
public function fillSitemap($sitemap, array $urls){
$count = count($urls);
$url_list = implode("\n", $urls)."\n";
$file_name = $this->getSitemapFilename($sitemap->txt_order);
$rs = file_put_contents($file_name, $url_list, FILE_APPEND);
$current = $sitemap->url_sum + $count;
$is_complete = $current >= $this->max_num ? 1 : 0;
DB::table('z_sitemaps')->where('id',$sitemap->id)->update([
'url_sum' => $current,
'updated_at' => date('Y-m-d H:i:s', time()),
'complete' => $is_complete,
]);
// 同時生成 http 格式
$this->syncHttpsToHttp($file_name);
return $file_name;
}
// 檔案真實路徑
public function getSitemapFilename($txt_order){
return $this->https_dir.$txt_order.'.txt';
}
// 同步https目錄中的sitemap檔案到http目錄
// 注意:https目錄與http目錄必須是同級目錄
public function syncHttpsToHttp($file_name)
{
$str = file_get_contents($file_name);
if($str){
$http_str = str_replace('https','http',$str);
$http_dir_path = str_replace('https', 'http', $file_name);
file_put_contents($http_dir_path, $http_str);
}
}
//生成sitemap地圖 XML格式
public function sitemapXml($is_http=0)
{
$area = $this->area;
$http = $is_http ? 'http' : 'https';
$strxml = '<sitemapindex></sitemapindex>';
$xmlobj = new \SimpleXMLElement($strxml);
$sitemaps = DB::table('z_sitemaps')->where('txt_area',$area)->orderBy('id','desc')->get();
foreach ($sitemaps as $v) {
$loc = 'https://xxxx.com/sitemaps/'.$http.'/'.$v->txt_order.'.txt';
$lastmod = $v->updated_at;
$sitemap = $xmlobj->addChild('sitemap');
$sitemap->addChild('loc',$loc);
$sitemap->addChild('lastmod',$lastmod);
}
$file_path = '...';
$xmlobj->asXML($file_path);
}
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結