sitemap 檔案填充示例程式碼

php_yt發表於2020-11-14

最近製作網站的 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 協議》,轉載必須註明作者和本文連結
focus

相關文章