PHP追加URL到XML文件时,定时任务执行后原有内容被覆盖如何解决
现有代码的核心问题
每次执行定时任务时的操作逻辑天然会覆盖旧内容:
- 直接初始化全新的
DOMDocument实例 - 从头创建空的
<urlset>根节点 - 把本次遍历的1000条URL挂在这个新的空根节点下
- 最后执行
$dom->save($xFile)时,会用内存里这个全新的空结构+本次新数据,完整覆盖本地已有的XML文件,全程没有读取合并旧文件里的已有内容。
另外原代码还存在两个冗余bug: - 加载XML的
simplexml_load_file($xFile)返回结果全程没有被使用,属于无效代码 - 创建
<url>节点后没有把实际URL值写入节点,最终生成的XML只有空壳结构 $page++的计数放在了无校验判断的循环最外层,和实际数据处理进度不匹配,容易出现分页偏移错误
分步修正实现逻辑
1. 匹配你的业务场景拆分处理分支
你的运行逻辑是分多轮处理全量5000条数据,要先判断当前是“新一轮全量任务刚开始”,还是“同一轮任务的中间分页执行”:
- 新一轮刚开始:直接清空旧XML,新建符合站点地图规范的空urlset结构
- 同一轮的中间分页:加载已有XML的内容,把新校验通过的URL追加进去,不覆盖旧节点
2. 代码层面的具体调整点
- 取消每次运行都新建DOM的逻辑,改为根据场景加载已有XML:
- 检测到是任务首轮(缓存存的page值为0),就新建标准urlset结构
- 否则就用
DOMDocument::load()读取已有XML文件的全部内容,拿到已存在的urlset根节点
- 遍历校验通过的新URL时,直接把新建的
<url>节点append到已存在的根节点下,不要重新创建根节点 - 分页计数逻辑修正:把
$page++放到URL校验通过的判断分支里,和实际拉取、处理的偏移量对齐 - 当检测到MySQL拉取的结果为空(也就是全量5000条处理完),再把缓存的page值重置为0,触发下一轮全量刷新时清空旧XML的逻辑
3. 修正后的核心代码片段参考
public function urlcheck() { $xFile = $this->base_path."sitemap/path/urls.xml"; $cache_key = 'valid_urls'; $page = $this->cache->redis->get($cache_key) ?: 0; // 初始化DOM与根节点:分场景处理 $dom = new DOMDocument('1.0','UTF-8'); $dom->formatOutput = true; // 判断是否是新一轮任务(page=0代表从头开始拉取全量数据) if ($page == 0) { // 新建空的标准urlset根节点 $root = $dom->createElement('urlset'); $root->setAttribute('xsi:schemaLocation', 'http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd'); $root->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); $root->setAttribute('xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9'); $dom->appendChild($root); } else { // 同一轮的分页执行,加载已有XML内容 if (file_exists($xFile)) { $dom->load($xFile); $root = $dom->getElementsByTagName('urlset')->item(0); } else { // 异常兜底:文件不存在时按新一轮逻辑新建 $root = $dom->createElement('urlset'); $root->setAttribute('xsi:schemaLocation', 'http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd'); $root->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); $root->setAttribute('xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9'); $dom->appendChild($root); } } // 拉取当前分页的URL数据 $this->load->model('productnew/productnew_es6_m'); $urls= $this->db->query("SELECT url FROM product_data where `active` = 1 limit ".$page.",1000")->result(); foreach($urls as $val) { // 这里放你原来的URL合法性校验逻辑 $is_valid = true; if (!$is_valid) { $page++; continue; } // 校验通过的才追加到XML $url_node = $dom->createElement('url'); $root->appendChild($url_node); $loc = $dom->createElement('loc', $val->url); $url_node->appendChild($loc); $lastmod = $dom->createElement('lastmod', date("Y-m-d")); $url_node->appendChild($lastmod); $page++; } // 保存合并后的完整XML,不会覆盖旧节点 $dom->save($xFile) or die('XML Create Error'); // 拉取结果为空,代表全量5000条处理完,重置page触发下一轮刷新 if(empty($urls)){ $page = 0; } print_r($page); $this->cache->redis->save($cache_key, $page, 432000); }
额外注意细节
- 不要用
file_put_contents直接拼接XML字符串追加,很容易破坏XML的根节点闭合结构,一定要通过DOM对象的节点操作完成合并,保证XML结构合法 - 当5000条数据全量处理完后,下一次任务启动时page=0,就会自动新建空的XML结构,满足“整体刷新”的需求,不需要手动删除旧文件
内容的提问来源于stack exchange,提问作者Jayakiran
相关产品推荐
相关产品推荐

