CodeIgniter 中 Sitemap 需手动实现:正确设置 XML 头、分片生成(≤50,000 条/文件)、用 site_url() 动态生成合法 URL、异步 ping 搜索引擎、通过 CLI+Cron 定期生成静态文件。

Sitemap在 CodeIgniter 中不是开箱即用的功能,必须手动构造 XML 响应、控制输出格式、处理 URL 生成逻辑,并解决搜索引擎抓取和更新通知的实际问题。核心难点不在“生成”,而在“正确生成 + 可靠交付 + 持续同步”。
必须显式设置 header 和编码,否则 XML 解析失败
浏览器或爬虫收到非 text/xml 类型响应时,会当作 HTML 或纯文本解析,导致 “StartTag: invalid element name” 这类错误(常见于第一行出现 却被当成 HTML 标签)。
-
header('Content-Type: text/xml; charset=UTF-8')必须在任何输出前调用,不能依赖视图里 echo - 不要用
charset=iso-8859-1—— 中文站点或含 Unicode 字符的 URL 会乱码甚至中断 XML - 避免在控制器中提前
echo、var_dump或开启调试输出(如$this->output->enable_profiler(TRUE)) - 如果用了
base_url()拼接 URL,确保配置中$config['base_url']以http://或https://开头,否则 loc 标签内容非法
单文件超限(>50,000 URL 或 >50MB)时必须拆分并生成 sitemapindex
CodeIgniter 默认不处理分片逻辑,但搜索引擎强制要求:单个 sitemap.xml 最多 50,000 条 ,且文件体积 ≤ 50MB(压缩后)。硬塞 10 万条进一个文件,Google 会静默丢弃后半部分。
- 用
$this->db->limit(50000, $offset)分页查数据,每批生成一个子文件(如sitemap-1.xml、sitemap-2.xml) - 主控制器不直接输出全部 URL,而是先写入
WRITEPATH . 'cache/sitemaps/'下的物理文件(注意目录可写权限) - 另建一个
sitemapindex方法,读取所有已生成的子文件名,输出符合sitemapindex规范的 XML - 子文件 URL 必须是完整可访问路径,例如
https://example.com/sitemap-1.xml,不能是相对路径或未路由的本地路径
自动通知搜索引擎需要手动 ping,没有内置钩子
生成新 sitemap.xml 后,Google/Bing 不会自动发现更新。必须主动向其 ping 接口发送 HTTP GET 请求,且每次只能提交一个 URL。
- 推荐用
file_get_contents()或cURL调用:https://www.google.com/ping?sitemap=https%3A%2F%2Fexample.com%2Fsitemap.xml - 不要在用户请求时实时 ping —— 网络延迟或超时会导致页面卡死;应放在 CLI 命令或 Cron 中异步执行
- 多个搜索引擎要逐个 ping,例如 Bing 的地址是
https://www.bing.com/webmaster/ping.aspx?siteMap=... - 第三方服务如
www.sitemapwriter.com可一次通知多家,但需确认其当前可用性(部分已停更)
URL 动态生成必须匹配实际路由,否则爬虫 404
很多项目直接拼 base_url() . '/article/' . $row['slug'],但若你启用了伪静态路由(如 $route['article/(:any)'] = 'content/view/$1'),而数据库里存的是旧 ID 或未规范化的别名,就会生成无效链接。
- 优先使用
site_url('content/view/' . $row['slug']),它走 CodeIgniter 路由系统,结果与用户访问一致 - 对含中文、空格、特殊符号的 slug,必须用
url_title($row['title'], 'dash', TRUE)生成并存储,不能直接从原始标题截取 - 排除测试环境、后台路径、登录后才可见的内容(如会员中心),这些 URL 不该出现在
sitemap中 - 动态参数 URL(如
/search?q=xxx)禁止加入,搜索引擎明确不索引带问号的地址
实际部署时最容易被忽略的是缓存策略和更新时机:XML 文件本身可以静态化(比如每次生成后写入磁盘),但如果你在控制器里每次都查库+拼 XML,高并发下 DB 压力大且响应慢。真正稳定的方案是——把生成动作抽成 php index.php tools generate_sitemap 命令,再用 Cron 每日凌晨跑一次,既可控,又避开了请求生命周期里的各种干扰。











