必须用 domdocument 而非字符串拼接:因后者易导致 xml 结构损坏、日期格式错误(缺 t/时区)、特殊字符未转义、bom/空白干扰首行、命名空间缺失或重复,引发 google search console 报“无效 xml”或“无法解析”。

直接用 DOMDocument 生成,别拼字符串,否则 Google Search Console 会报“无效的 XML”或“无法解析日期”。
为什么不能用 echo 或字符串拼接生成 sitemap.xml
看似一行 echo "<url><loc>$url</loc></url>" 就能搞定,但实际踩坑极多:
-
&、、中文路径等不转义,XML 直接结构损坏 -
lastmod写成date('Y-m-d')缺少T和时区,Google 忽略该字段 - PHP 文件开头有 BOM 或空白(比如
include了带输出的配置),导致 XML 声明不在首行 - 没设
xmlns属性,或重复设置,整个文件被判定为无效 - 用
file_put_contents($file, $dom->saveXML())写入,可能多出 BOM 或换行,搜索引擎拒收
DOMDocument 构建 sitemap.xml 的关键顺序
顺序错一点,save() 就可能写空文件或格式错乱。必须按这个流程来:
- 初始化:
$dom = new DOMDocument('1.0', 'UTF-8');—— 缺少编码参数,中文lastmod或注释会乱码 - 创建根节点:
$urlset = $dom->createElement('urlset'); - 立刻设置命名空间:
$urlset->setAttribute('xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9');—— 必须在appendChild之前 - 挂载根:
$dom->appendChild($urlset); - 循环添加
url节点时,对每个loc值调用htmlspecialchars($full_url, ENT_XML1)——ENT_QUOTES不够安全,会漏掉 XML 特殊字符 - 所有节点加完后,再设
$dom->formatOutput = true;—— 提前设无效,缩进不会生效 - 最后写入:
$dom->save('/path/sitemap.xml');—— 不要用saveXML()+file_put_contents
数据库 URL 和时间字段怎么安全对接
从 MySQL 或 PDO 查出来的数据,不能直接塞进 XML:
-
loc必须是完整绝对地址:'https://example.com' . $row['slug'],不是/article/123 -
lastmod推荐用(new DateTime($row['updated_at']))->format(DateTime::ATOM)—— 比strtotime() + date()更稳,自动带时区偏移 -
priority和changefreq别硬编码,按页面类型区分:首页1.0/daily,文章页0.8/weekly,分类页0.6/monthly - 单个 sitemap.xml 最好不超过 5 万条 URL;超量需拆分,并用
sitemapindex.xml管理
生产环境必须加的缓存与触发机制
每次访问都查库 + 渲染,等于自己发起 DoS 攻击:
- 不要让
sitemap.php每次响应都执行全量生成;改用定时任务(如 cron)每小时/每天跑一次,写死到sitemap.xml - 如果必须动态响应(比如调试期),至少加
header('Cache-Control: public, max-age=3600');,避免搜索引擎频繁重抓 - 用
.htaccess伪静态把sitemap.php映射成sitemap.xml,但注意:真实文件名仍是sitemap.php,别让 PHP 输出前有任何输出(包括空格、BOM、echo) - 生成后务必用
curl -I https://yoursite.com/sitemap.xml检查Content-Type: application/xml; charset=utf-8是否正确返回
最容易被忽略的是 ENT_XML1 和 DateTime::ATOM 这两个参数细节 —— 它们不报错,但会让搜索引擎静默丢弃部分 URL 或整份文件。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











