1. 创建脚本文件 map.sh
nano /root/map.sh
map.sh 脚本内容:
#!/bin/bash
# ============================================================
# map.sh — xBlog 网站地图管理脚本
# 使用方式:bash /root/map.sh
# ============================================================
# ============================
# 配置区域(按需修改)
# ============================
SITE_DIR="/opt/1panel/www/sites/xblog/index" # 网站根目录(宿主机路径)
SITE_DIR_CONTAINER="/www/sites/xblog/index" # 网站根目录(容器内路径)
SITE_URL="https://xblog.itxgo.com" # 博客域名,末尾不加斜杠
SITEMAP_SECRET="xblog_sitemap_2026" # 手动触发密钥
FILE_OWNER="1000:1000" # 网站文件所有者(与其他网站文件保持一致)
PHP_BIN="docker exec php php" # PHP 执行命令(容器环境)
SCRIPT_PATH="$(realpath "$0")" # 本脚本自身路径(卸载时使用)
# ============================
# 派生路径(无需修改)
PHP_SCRIPT="$SITE_DIR/generate_sitemap.php"
ROBOTS_FILE="$SITE_DIR/robots.txt"
SITEMAP_FILE="$SITE_DIR/sitemap.xml"
DB_FILE="$SITE_DIR/blog.db"
# ============================================================
# 颜色输出
# ============================================================
GREEN="\033[0;32m"
RED="\033[0;31m"
YELLOW="\033[1;33m"
CYAN="\033[0;36m"
RESET="\033[0m"
ok() { echo -e "${GREEN}✅ $1${RESET}"; }
err() { echo -e "${RED}❌ $1${RESET}"; }
info() { echo -e "${CYAN}ℹ️ $1${RESET}"; }
warn() { echo -e "${YELLOW}⚠️ $1${RESET}"; }
# ============================================================
# 功能函数
# ============================================================
# 写入 generate_sitemap.php
write_php() {
cat > "$PHP_SCRIPT" << PHPEOF
<?php
/**
* generate_sitemap.php — 网站地图生成脚本
* 由 map.sh 自动生成,请勿手动修改配置项
*/
define('SITEMAP_BASE_URL', '${SITE_URL}');
define('SITEMAP_OUTPUT', __DIR__ . '/sitemap.xml');
define('SITEMAP_SECRET', '${SITEMAP_SECRET}');
function generateSitemap(): int|false
{
\$dbPath = __DIR__ . '/blog.db';
if (!file_exists(\$dbPath)) {
error_log('[Sitemap] 数据库文件不存在: ' . \$dbPath);
return false;
}
try {
\$db = new PDO('sqlite:' . \$dbPath);
\$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
\$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
} catch (PDOException \$e) {
error_log('[Sitemap] 数据库连接失败: ' . \$e->getMessage());
return false;
}
try {
\$stmt = \$db->query("SELECT id, updated_at FROM articles ORDER BY updated_at DESC");
\$articles = \$stmt->fetchAll();
} catch (PDOException \$e) {
error_log('[Sitemap] 文章查询失败: ' . \$e->getMessage());
return false;
}
\$xml = '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
\$xml .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n";
\$xml .= buildUrlEntry(SITEMAP_BASE_URL . '/', date('Y-m-d'), 'daily', '1.0');
foreach (\$articles as \$article) {
\$url = SITEMAP_BASE_URL . '/article.php?id=' . (int)\$article['id'];
\$lastmod = formatSitemapDate(\$article['updated_at']);
\$xml .= buildUrlEntry(\$url, \$lastmod, 'monthly', '0.8');
}
\$xml .= '</urlset>';
\$result = file_put_contents(SITEMAP_OUTPUT, \$xml, LOCK_EX);
if (\$result === false) {
error_log('[Sitemap] 写入 sitemap.xml 失败,请检查目录权限: ' . SITEMAP_OUTPUT);
return false;
}
return count(\$articles);
}
function buildUrlEntry(string \$loc, string \$lastmod, string \$changefreq, string \$priority): string
{
return " <url>\n"
. " <loc>" . htmlspecialchars(\$loc, ENT_XML1 | ENT_QUOTES, 'UTF-8') . "</loc>\n"
. " <lastmod>{\$lastmod}</lastmod>\n"
. " <changefreq>{\$changefreq}</changefreq>\n"
. " <priority>{\$priority}</priority>\n"
. " </url>\n";
}
function formatSitemapDate(?string \$datetime): string
{
if (empty(\$datetime)) return date('Y-m-d');
\$ts = strtotime(\$datetime);
return \$ts ? date('Y-m-d', \$ts) : date('Y-m-d');
}
if (basename(__FILE__) === basename(\$_SERVER['SCRIPT_FILENAME'] ?? '') || php_sapi_name() === 'cli') {
if (php_sapi_name() === 'cli') {
\$ok = generateSitemap();
echo \$ok !== false
? "[Sitemap] 生成成功: " . SITEMAP_OUTPUT . "(共 {\$ok} 篇文章)" . PHP_EOL
: "[Sitemap] 生成失败,请检查错误日志。" . PHP_EOL;
exit(\$ok !== false ? 0 : 1);
}
\$key = \$_GET['key'] ?? '';
if (!hash_equals(SITEMAP_SECRET, \$key)) {
http_response_code(403);
exit('403 Forbidden: 密钥错误');
}
\$ok = generateSitemap();
header('Content-Type: text/plain; charset=utf-8');
echo \$ok !== false
? "✅ sitemap.xml 已生成:" . SITEMAP_OUTPUT . "\n📄 共收录 {\$ok} 篇文章"
: "❌ 生成失败,请查看 PHP 错误日志。";
exit();
}
PHPEOF
}
# 写入 robots.txt
write_robots() {
cat > "$ROBOTS_FILE" << ROBOTEOF
User-agent: *
Allow: /
Disallow: /admin/
Disallow: /uploads/
Disallow: /blog.db
Disallow: /generate_sitemap.php
Disallow: /composer.phar
Sitemap: ${SITE_URL}/sitemap.xml
ROBOTEOF
}
# 检查是否已安装
is_installed() {
[ -f "$PHP_SCRIPT" ]
}
# ============================================================
# 菜单功能:1 安装地图
# ============================================================
do_install() {
echo ""
if is_installed; then
warn "检测到已安装,请使用「2 更新地图」手动刷新,或直接重新安装(将覆盖现有文件)。"
read -rp "是否继续重新安装?[y/N] " confirm
[[ "$confirm" =~ ^[Yy]$ ]] || { info "已取消。"; return; }
fi
# 检查网站目录
if [ ! -d "$SITE_DIR" ]; then
err "网站目录不存在:$SITE_DIR"
info "请检查脚本顶部 SITE_DIR 配置项。"
return 1
fi
# 检查数据库
if [ ! -f "$DB_FILE" ]; then
err "未找到数据库文件:$DB_FILE"
return 1
fi
info "正在写入 generate_sitemap.php ..."
write_php && chown "$FILE_OWNER" "$PHP_SCRIPT" && ok "generate_sitemap.php 已写入" || { err "写入失败,请检查目录权限。"; return 1; }
info "正在写入 robots.txt ..."
write_robots && chown "$FILE_OWNER" "$ROBOTS_FILE" && ok "robots.txt 已写入" || { err "写入失败。"; return 1; }
info "正在生成初始 sitemap.xml ..."
$PHP_BIN "$SITE_DIR_CONTAINER/generate_sitemap.php"
if [ -f "$SITEMAP_FILE" ]; then
chown "$FILE_OWNER" "$SITEMAP_FILE"
ok "sitemap.xml 已生成:$SITEMAP_FILE"
else
err "sitemap.xml 生成失败,请检查 PHP 错误日志。"
fi
echo ""
ok "安装完成!"
info "请在 1panel 面板「计划任务」中添加定时更新任务"
info "Sitemap 地址:${SITE_URL}/sitemap.xml"
}
# ============================================================
# 菜单功能:2 更新地图
# ============================================================
do_update() {
echo ""
if ! is_installed; then
err "尚未安装,请先选择「1 安装地图」。"
return 1
fi
info "正在更新 sitemap.xml ..."
$PHP_BIN "$SITE_DIR_CONTAINER/generate_sitemap.php"
if [ -f "$SITEMAP_FILE" ]; then
ok "sitemap.xml 更新成功"
info "文件路径:$SITEMAP_FILE"
else
err "更新失败,请检查 PHP 错误日志。"
fi
}
# ============================================================
# 菜单功能:3 卸载地图
# ============================================================
do_uninstall_map() {
echo ""
if ! is_installed; then
warn "未检测到已安装的网站地图文件。"
return
fi
warn "将删除以下文件:"
echo " - $PHP_SCRIPT"
echo " - $ROBOTS_FILE"
echo " - $SITEMAP_FILE"
read -rp "确认卸载?[y/N] " confirm
[[ "$confirm" =~ ^[Yy]$ ]] || { info "已取消。"; return; }
[ -f "$PHP_SCRIPT" ] && rm -f "$PHP_SCRIPT" && ok "已删除 generate_sitemap.php"
[ -f "$ROBOTS_FILE" ] && rm -f "$ROBOTS_FILE" && ok "已删除 robots.txt"
[ -f "$SITEMAP_FILE" ] && rm -f "$SITEMAP_FILE" && ok "已删除 sitemap.xml"
echo ""
ok "卸载完成。"
warn "请记得在 1panel 面板「计划任务」中手动删除对应任务。"
}
# ============================================================
# 菜单功能:4 卸载脚本
# ============================================================
do_uninstall_script() {
echo ""
warn "将删除本脚本自身:$SCRIPT_PATH"
if is_installed; then
warn "检测到网站地图仍已安装,建议先执行「3 卸载地图」。"
read -rp "是否同时卸载地图?[y/N] " also_uninstall
[[ "$also_uninstall" =~ ^[Yy]$ ]] && do_uninstall_map
fi
read -rp "确认删除脚本?[y/N] " confirm
[[ "$confirm" =~ ^[Yy]$ ]] || { info "已取消。"; return; }
rm -f "$SCRIPT_PATH"
ok "脚本已删除:$SCRIPT_PATH"
exit 0
}
# ============================================================
# 主菜单
# ============================================================
show_menu() {
echo ""
echo -e "${CYAN}=============================${RESET}"
echo -e "${CYAN} xBlog 网站地图 ${RESET}"
echo -e "${CYAN}=============================${RESET}"
echo " 1. 安装地图"
echo " 2. 更新地图"
echo " 3. 卸载地图"
echo " 4. 卸载脚本"
echo " 5. 使用说明"
echo -e "${CYAN}=============================${RESET}"
echo -n "请选择操作 [1-5],按 q 退出:"
}
# ============================================================
# 菜单功能:5 使用说明
# ============================================================
do_help() {
echo ""
echo -e "${CYAN}=============================${RESET}"
echo -e "${CYAN} 使用说明 ${RESET}"
echo -e "${CYAN}=============================${RESET}"
echo ""
echo -e "${YELLOW}【脚本配置项】${RESET}(位于 map.sh 顶部)"
echo " SITE_DIR 网站根目录路径(宿主机)"
echo " SITE_DIR_CONTAINER 网站根目录路径(容器内)"
echo " SITE_URL 博客域名,末尾不加斜杠"
echo " SITEMAP_SECRET 手动触发更新的密钥"
echo " PHP_BIN PHP 执行命令"
echo ""
echo -e "${YELLOW}【菜单功能】${RESET}"
echo " 1. 安装地图 写入 generate_sitemap.php、robots.txt,"
echo " 并立即生成 sitemap.xml"
echo " 2. 更新地图 立即手动刷新一次 sitemap.xml"
echo " 3. 卸载地图 删除相关文件(需手动删除 1panel 计划任务)"
echo " 4. 卸载脚本 删除本脚本,可选同时卸载地图"
echo ""
echo -e "${YELLOW}【生成的文件】${RESET}(均位于网站根目录)"
echo " generate_sitemap.php 地图生成脚本"
echo " robots.txt 搜索引擎爬取规则"
echo " sitemap.xml 网站地图(自动生成)"
echo ""
echo -e "${YELLOW}【1panel 计划任务】${RESET}"
echo " 在 1panel 面板新建计划任务,类型选「Shell 脚本」,"
echo " 内容填写:"
echo ""
echo -e " ${GREEN}bash $(realpath "$0") update${RESET}"
echo ""
echo -e "${YELLOW}【手动触发更新】${RESET}(浏览器访问)"
echo " ${SITE_URL}/generate_sitemap.php?key=${SITEMAP_SECRET}"
echo ""
echo -e "${YELLOW}【Sitemap 地址】${RESET}"
echo " ${SITE_URL}/sitemap.xml"
echo ""
}
# ============================================================
# 入口
# ============================================================
# 支持直接传参,方便 1panel 计划任务非交互式调用
# 用法:bash /root/map.sh update
if [ "$1" = "update" ]; then
do_update
exit $?
fi
while true; do
show_menu
read -r choice
case "$choice" in
1) do_install ;;
2) do_update ;;
3) do_uninstall_map ;;
4) do_uninstall_script ;;
5) do_help ;;
q|Q) echo ""; info "已退出。"; exit 0 ;;
*) warn "无效输入,请输入 1-5 或 q。" ;;
esac
echo ""
read -rp "按 Enter 返回菜单..." _
done
2. 保存文件
按 Ctrl + X → 确认保存按 Y → 确认文件名按 Enter
3. 赋予执行权限
chmod +x /root/map.sh
4. 运行脚本
bash /root/map.sh
💡 脚本使用说明
配置项
配置文件位于
map.sh顶部,请根据实际环境修改
| 配置项 | 说明 | 示例值 |
|---|---|---|
SITE_DIR |
网站根目录路径(宿主机) | /opt/1panel/www/sites/xblog/index |
SITE_DIR_CONTAINER |
网站根目录路径(容器内) | /www/sites/xblog/index |
SITE_URL |
博客域名(末尾不加斜杠) | https://xblog.itxgo.com |
SITEMAP_SECRET |
手动触发更新的密钥 | xblog_sitemap_2026 |
PHP_BIN |
PHP 执行命令(容器环境) | docker exec php php |
菜单功能
| 选项 | 功能 | 说明 |
|---|---|---|
| 1 | 安装地图 | 自动写入 generate_sitemap.php、robots.txt,并立即生成 sitemap.xml |
| 2 | 更新地图 | 立即手动刷新一次 sitemap.xml |
| 3 | 卸载地图 | 删除相关文件(需手动删除 1Panel 计划任务) |
| 4 | 卸载脚本 | 删除本脚本 map.sh,可选同时卸载地图 |
| 5 | 使用说明 | 显示当前这份帮助文档 |
生成的文件
所有文件均位于网站根目录下:
| 文件 | 用途 |
|---|---|
generate_sitemap.php |
网站地图生成脚本(核心) |
robots.txt |
搜索引擎爬取规则 |
sitemap.xml |
网站地图(自动生成) |
1Panel 计划任务配置
步骤说明
- 登录 1Panel 管理面板
- 进入「计划任务」功能
- 点击「新建计划任务」
- 任务类型选择「Shell 脚本」
- 执行周期按需选择(推荐:每天执行一次)
- 脚本内容填写:
bash /root/map.sh update
🌐 手动触发更新
浏览器访问
https://xblog.itxgo.com/generate_sitemap.php?key=xblog_sitemap_2026
⚠️ 安全提示:
- 请将密钥
xblog_sitemap_2026替换为您实际设置的SITEMAP_SECRET- 建议使用复杂密钥,防止未授权访问
返回结果示例
成功时:
✅ sitemap.xml 已生成:/www/sites/xblog/index/sitemap.xml
📄 共收录 42 篇文章
失败时:
❌ 生成失败,请查看 PHP 错误日志。
🔗 Sitemap 地址
https://xblog.itxgo.com/sitemap.xml
📌 可将此地址提交至搜索引擎(Google Search Console、百度资源平台等)
❓ 常见问题
Q1:生成 sitemap.xml 失败怎么办?
检查以下几点:
- 数据库文件
blog.db是否存在且可读 - 网站根目录是否有写入权限
- PHP 错误日志中是否有详细报错信息
Q2:如何验证 sitemap.xml 是否正确?
# 检查 XML 格式是否合法
curl -s https://xblog.itxgo.com/sitemap.xml | xmllint --format -
Q3:容器环境下 PHP 命令无法执行?
确认 PHP_BIN 配置项是否正确,例如:
# Docker 环境示例
PHP_BIN="docker exec php php"
# 宿主机环境示例
PHP_BIN="php"
📞 技术支持
如有问题,请检查:
- 脚本执行权限:
chmod +x /root/map.sh - PHP 错误日志:通常在
/var/log/或容器内日志目录 - 文件权限:确保网站目录对执行用户可写