- 好友
- 0
- 精华
- 0
- 积分
- 13
- 阅读权限
- 200
- 注册时间
- 2026-5-15
- 最后登录
- 2026-7-2
管理员
- UID
- 1
|
楼主 |
发表于 2026-5-22 19:35:17
|
显示全部楼层
2026-5-22,更新网站地图的页头页尾及部分细节显示样式
- <?php
- /**
- * Discuz! Sitemap HTML 生成计划任务(静默模式)
- * 文件路径: source/include/cron/sitemap_builder.php
- *
- * 功能:定时生成 Sitemap.html,供用户浏览网站结构
- * 特点:无任何输出,仅记录日志,符合 Discuz! Cron 规范
- *
- * @author Your Name
- * @version 2.4
- * @license GPL v3
- */
- // 防止直接访问,只能通过Discuz系统调用
- if (!defined('IN_DISCUZ')) {
- exit('Access Denied');
- }
- // 静默运行,禁止任何输出
- error_reporting(0);
- ini_set('display_errors', 0);
- // ==================== 【关键配置区】====================
- // 🔒 版块显示控制配置
- // 1. $hidden_groups: 不在网站地图中显示的版块(分区),但其帖子仍会显示
- // 2. $excluded_from_posts: 不显示其帖子的版块,但版块本身可能仍显示在地图中
- // 版块控制配置
- $hidden_groups = [1]; // ←←← 在地图中不显示的版块ID(分区),但其帖子仍会显示
- $excluded_from_posts = [0]; // ←←← 不显示其帖子的版块ID,但版块本身可能仍显示在地图中
- $config = [
- 'html_filename' => 'Sitemap.html',
- 'update_interval' => 58, // 最短更新间隔(分钟),建议每天一次
- 'batch_size' => 200, // 每批次处理的数量
- 'max_threads' => 1000, // 最大处理帖子数
- 'memory_limit' => '256M', // 内存限制
- 'max_execution_time' => 300, // 最大执行时间(秒)
- 'charset' => 'utf-8'
- ];
- // ================================================
- // 设置资源限制
- @ini_set('memory_limit', $config['memory_limit']);
- @set_time_limit($config['max_execution_time']);
- // 获取站点时区
- $site_timezone = $_G['setting']['timeoffset'] ?? 8;// 默认为北京时间(UTC+8)
- // 强制设置PHP时区以确保一致性
- $timezone_map = [
- -12 => 'Pacific/Kwajalein', -11 => 'Pacific/Midway', -10 => 'Pacific/Honolulu',
- -9 => 'America/Anchorage', -8 => 'America/Los_Angeles', -7 => 'America/Denver',
- -6 => 'America/Chicago', -5 => 'America/New_York', -4 => 'America/Halifax',
- -3 => 'America/Sao_Paulo', -2 => 'Atlantic/South_Georgia', -1 => 'Atlantic/Azores',
- 0 => 'UTC', 1 => 'Europe/London', 2 => 'Europe/Paris', 3 => 'Europe/Moscow',
- 4 => 'Asia/Baku', 5 => 'Asia/Karachi', 6 => 'Asia/Dhaka', 7 => 'Asia/Jakarta',
- 8 => 'Asia/Shanghai', 9 => 'Asia/Tokyo', 10 => 'Australia/Brisbane',
- 11 => 'Pacific/Noumea', 12 => 'Pacific/Auckland'
- ];
- date_default_timezone_set($timezone_map[$site_timezone] ?? 'Asia/Shanghai');
- $html_filepath = DISCUZ_ROOT . '/' . $config['html_filename'];
- $web_root = rtrim($_G['siteurl'], '/') . '/';
- $site_name = htmlspecialchars($_G['setting']['sitename'] ?? 'Discuz Forum', ENT_QUOTES, $config['charset']);
- // 检查是否在更新冷却期内,防止频繁生成
- if (file_exists($html_filepath)) {
- $last_modified = filemtime($html_filepath);
- if ((time() - $last_modified) < ($config['update_interval'] * 60)) {
- runlog('sitemap_html', 'Skipped: within update interval.');
- return TRUE;
- }
- }
- // 构建版块排除条件
- $exclude_groups_sql = '';
- $exclude_posts_sql = '';
- if (!empty($hidden_groups)) {
- $group_ids = array_map('intval', array_filter($hidden_groups));
- if (!empty($group_ids)) {
- $exclude_groups_sql = " AND fid NOT IN (" . implode(',', $group_ids) . ") ";
- }
- }
- if (!empty($excluded_from_posts)) {
- $post_exclude_ids = array_map('intval', array_filter($excluded_from_posts));
- if (!empty($post_exclude_ids)) {
- $exclude_posts_sql = " AND fid NOT IN (" . implode(',', $post_exclude_ids) . ") ";
- }
- }
- // === 修复:获取所有分区(包括status=2的隐藏分区),但排除在$hidden_groups中的版块 ===
- $groups_data = []; // 存储分区信息(即城市版块)
- $gids_for_thread = []; // 存储分区ID用于帖子查询
- // 获取所有公开的分区(包括隐藏分区),但排除$hidden_groups中的
- $query_groups = DB::query("
- SELECT fid as gid, name
- FROM " . DB::table('forum_forum') . "
- WHERE type='group'
- {$exclude_groups_sql}
- ORDER BY displayorder
- ");
- while ($group = DB::fetch($query_groups)) {
- $groups_data[] = $group;
- $gids_for_thread[] = (int) $group['gid'];
- }
- $public_group_count = count($groups_data);
- // === 修复:帖子查询逻辑 - 分区版块不显示但其帖子仍显示 ===
- $thread_fid_condition = '';
- // 获取所有版块,排除$excluded_from_posts中的版块,但保留属于隐藏分区的版块的帖子
- $query_fids = DB::query("
- SELECT fid
- FROM " . DB::table('forum_forum') . "
- WHERE status='1' AND type='forum'
- AND fid NOT IN (" . implode(',', array_map('intval', $excluded_from_posts)) . ")
- ");
- $fids_to_include = [];
- while ($fid_row = DB::fetch($query_fids)) {
- $fids_to_include[] = (int) $fid_row['fid'];
- }
- if (!empty($fids_to_include)) {
- $thread_fid_condition = "AND fid IN (" . implode(',', $fids_to_include) . ")";
- } else {
- $thread_fid_condition = "AND 1=0"; // 无符合条件的版块,则不查任何帖子
- }
- // 获取帖子总数(仅排除$excluded_from_posts中的版块,不考虑$hidden_groups对帖子的影响)
- $total_result = DB::fetch_first(
- "SELECT COUNT(*) AS total FROM " . DB::table('forum_thread') .
- " WHERE displayorder >= 0 AND lastpost > 0 {$thread_fid_condition}"
- );
- $total_threads = (int)$total_result['total'];
- // 若无有效内容,提前退出
- if ($total_threads <= 0 && $public_group_count <= 0) {
- runlog('sitemap_html', 'No valid threads or groups found for Sitemap.html.');
- return TRUE;
- }
- // 分批读取数据(含 subject)
- $threads_data = [];
- $offset = 0;
- $processed = 0;
- do {
- $query = DB::query(
- "SELECT tid, lastpost, subject, replies, fid FROM " . DB::table('forum_thread') .
- " WHERE displayorder >= 0 AND lastpost > 0 {$thread_fid_condition} " .
- "ORDER BY lastpost DESC LIMIT {$offset}, {$config['batch_size']}"
- );
- $batch_count = 0;
- while ($thread = DB::fetch($query)) {
- // 确保 subject 安全
- $thread['subject'] = dhtmlspecialchars($thread['subject']);
- $threads_data[] = $thread;
- $batch_count++;
- $processed++;
- if ($processed >= $config['max_threads']) break;
- }
- $offset += $config['batch_size'];
- if ($batch_count < $config['batch_size']) break;
- if ($processed >= $config['max_threads']) break;
- } while ($batch_count == $config['batch_size']);
- if (empty($threads_data) && empty($groups_data)) {
- runlog('sitemap_html', 'No thread or group data retrieved for HTML sitemap.');
- return TRUE;
- }
- // 开始写入 HTML
- $html_file = @fopen($html_filepath, 'w');
- if (!$html_file) {
- runlog('sitemap_html', 'Failed to open HTML file for writing: ' . $html_filepath);
- return FALSE;
- }
- $generation_time = date('Y-m-d H:i:s');
- // HTML 头部
- $html_header = '<!DOCTYPE html>
- <html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN">
- <head>
- <meta charset="' . $config['charset'] . '">
- <title>网站地图 - ' . $site_name . '</title>
- <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
- <meta name="robots" content="noindex,follow">
- <style>
- /* 原有样式 */
- body{
- font-family: Arial, sans-serif;
- margin: 0;
- padding: 0;
- background: #f5f5f5;
- line-height: 1.4; /* 调整行高 */
- }
- .container{
- max-width: 100%;
- width: 100%;
- margin: 0 auto;
- background: #fff;
- padding: 15px;
- box-sizing: border-box;
- }
- @media (min-width: 768px) {
- .container {
- max-width: 1200px;
- padding: 30px;
- border-radius: 8px;
- box-shadow: 0 2px 10px rgba(0,0,0,0.1);
- margin: 20px auto;
- }
- }
- h1{
- text-align: center;
- color: #333;
- margin-top: 0;
- font-size: 1.8rem;
- display: none; /* 隐藏主标题 */
- }
- @media (min-width: 768px) {
- h1 {
- font-size: 2.2rem;
- }
- }
- h2{
- color: #007cba;
- margin-top: 30px;
- font-size: 1.4rem;
- line-height: 1.4; /* 调整行高 */
- }
- @media (min-width: 768px) {
- h2 {
- font-size: 1.6rem;
- }
- }
- h3{
- color: #555;
- margin-top: 20px;
- margin-bottom: 10px;
- font-size: 1.2rem;
- line-height: 1.4; /* 调整行高 */
- }
- ul{
- list-style: none;
- padding: 0;
- margin: 0;
- }
- li{
- margin: 5px 0; /* 减小间距 */
- padding: 8px 12px; /* 减小内边距 */
- background: #f9f9f9;
- border-left: 4px solid #007cba;
- border-radius: 4px;
- word-wrap: break-word;
- overflow-wrap: break-word;
- line-height: 1.4; /* 调整行高 */
- }
- a{
- color: #007cba;
- text-decoration: none;
- font-weight: bold;
- word-break: break-all;
- display: inline; /* 改为inline以便时间和链接在同一行 */
- }
- a:hover{
- text-decoration: underline;
- }
- .timestamp{
- color: #666;
- font-size: 0.85em;
- margin-left: 8px; /* 减小间距 */
- display: inline; /* 与链接同行 */
- }
- @media (min-width: 768px) {
- .timestamp {
- margin-left: 10px;
- }
- }
- .hot{
- border-left-color: #ff6b6b;
- background: #fff5f5;
- }
- .recent{
- border-left-color: #4ecdc4;
- }
- .stats{
- background: #e8f4fd;
- padding: 12px;
- border-radius: 5px;
- margin: 20px 0;
- font-size: 0.9rem;
- line-height: 1.4; /* 调整行高 */
- }
- @media (min-width: 768px) {
- .stats {
- font-size: 1rem;
- }
- }
- /* 修复换行问题:确保统计信息在一行显示 */
- .stats p {
- margin: 6px 0; /* 减小间距 */
- white-space: nowrap; /* 防止内容换行 */
- overflow: hidden; /* 隐藏溢出内容 */
- text-overflow: ellipsis; /* 超出部分显示省略号 */
- }
- /* 针对链接的特殊处理 */
- .stats a {
- display: inline !important; /* 确保链接为行内元素 */
- white-space: nowrap; /* 防止链接文字换行 */
- }
- .group-section{
- margin-bottom: 30px;
- }
- .footer-text{
- margin-top: 40px;
- text-align: center;
- color: #666;
- font-size: 0.85rem;
- padding: 20px 0 10px;
- line-height: 1.4; /* 调整行高 */
- }
- @media (min-width: 768px) {
- .footer-text {
- font-size: 0.9rem;
- }
- }
- /* 提示信息样式 */
- .city-hint {
- color: #666;
- font-style: italic;
- margin-top: -10px;
- margin-bottom: 15px;
- font-size: 0.9em;
- display: inline-block; /* 改为行内块元素 */
- line-height: 1.4; /* 调整行高 */
- }
- /* 便民诉求链接样式 */
- .city-hint a {
- display: inline; /* 确保链接为行内元素 */
- white-space: nowrap; /* 防止链接换行 */
- }
- /* 修复帖子列表布局 - 调整为紧凑样式 */
- .thread-item {
- display: inline; /* 与时间在同一行 */
- }
- .thread-title {
- display: inline; /* 与时间在同一行 */
- }
- .thread-timestamp {
- white-space: nowrap; /* 时间不换行 */
- color: #666;
- font-size: 0.85em;
- }
- /* 页头样式 */
- .header {
- background: #0033FF; /* 修改为指定颜色 */
- border-bottom: 1px solid #e5e5e5;
- padding: 15px 0;
- box-shadow: 0 2px 4px rgba(0,0,0,0.05);
- }
- .header-content {
- max-width: 1200px;
- margin: 0 auto;
- padding: 0 20px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- flex-wrap: wrap;
- }
- .logo-area {
- display: flex;
- align-items: center;
- gap: 15px;
- }
- .logo {
- font-size: 1.8rem;
- font-weight: bold;
- text-decoration: none;
- color: #ffffff; /* 白色文字 */
- }
- .site-name {
- font-size: 1.2rem;
- color: #ffffff; /* 白色文字 */
- }
- .nav-main {
- display: flex;
- gap: 25px;
- list-style: none;
- margin: 0;
- padding: 0;
- align-items: center;
- justify-content: flex-start; /* 导航居左显示 */
- }
- .nav-main a {
- color: #ffffff; /* 白色导航文字 */
- text-decoration: none;
- font-weight: 500;
- padding: 8px 12px;
- border-radius: 4px;
- transition: all 0.3s ease;
- }
- .nav-main a:hover {
- background-color: #0022cc; /* 深蓝色悬停效果 */
- color: #ffffff;
- }
- /* 页脚样式 */
- .footer {
- background: #2c3e50;
- color: #ecf0f1;
- padding: 10px 0 5px; /* 进一步减少上下内边距 */
- margin-top: 15px; /* 减少页脚与内容的距离 */
- }
- .footer-content {
- max-width: 1200px;
- margin: 0 auto;
- padding: 0 20px;
- }
- .footer-top {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
- gap: 20px; /* 减少间距 */
- margin-bottom: 10px; /* 减少底部外边距 */
- }
- .footer-column h4 {
- color: #ecf0f1;
- margin-bottom: 10px; /* 减少底部外边距 */
- font-size: 1.1rem;
- }
- .footer-column ul {
- list-style: none;
- padding: 0;
- margin: 0;
- }
- .footer-column li {
- margin-bottom: 5px; /* 减少底部外边距 */
- }
- .footer-column a {
- color: #bdc3c7;
- text-decoration: none;
- transition: color 0.3s ease;
- }
- .footer-column a:hover {
- color: #3498db;
- }
- .footer-bottom {
- padding-top: 5px; /* 最小化上内边距,只保留一行文字的空间 */
- text-align: center;
- border-top: none; /* 确保没有顶部边框 */
- }
- .copyright {
- color: #95a5a6;
- font-size: 0.9rem;
- line-height: 1.4; /* 进一步调整行高 */
- margin: 0; /* 移除默认外边距 */
- }
- .copyright p {
- margin: 3px 0; /* 最小化段落间距 */
- }
- .copyright a {
- color: #3498db;
- text-decoration: none;
- }
- .copyright a:hover {
- text-decoration: underline;
- }
- /* 响应式设计 */
- @media (max-width: 768px) {
- .header-content {
- flex-direction: column;
- gap: 15px;
- text-align: center;
- }
- .nav-main {
- flex-wrap: wrap;
- justify-content: flex-start; /* 移动端也保持居左 */
- gap: 10px;
- }
- .footer-top {
- grid-template-columns: 1fr;
- gap: 15px; /* 移动端进一步减少间距 */
- }
- .logo-area {
- display: flex;
- flex-direction: row;
- }
- .footer-bottom {
- padding-top: 4px; /* 移动端进一步减少上内边距 */
- }
- }
- </style>
- </head>
- <body>
- <!-- 页头 -->
- <header class="header">
- <div class="header-content">
- <div class="logo-area">
- <a href="/" class="logo">' . $site_name . '</a>
- <span class="site-name">网站地图</span>
- </div>
- </div>
- </header>
- <div class="container">';
- fwrite($html_file, $html_header);
- // 首页
- fwrite($html_file, "<div style="display: flex; align-items: center; gap: 20px;">\n");
- fwrite($html_file, " <h2 style="margin:0;">首页</h2>\n");
- fwrite($html_file, " <ul style="display: flex; gap: 15px; list-style: none; padding: 0; margin: 0;">\n");
- // 导航链接
- fwrite($html_file, " <li><a href="" . htmlspecialchars($web_root, ENT_QUOTES, $config['charset']) . "">{$site_name}</a></li>\n");
- fwrite($html_file, " <li><a href="2-1.html">便民诉求</a></li>\n");
- fwrite($html_file, " </ul>\n");
- fwrite($html_file, "</div>\n");
- // === 修复:显示分区列表(即城市版块),包括隐藏分区,使用静态链接格式 gid-1.html ===
- if (!empty($groups_data)) {
- fwrite($html_file, "<h2>城市版块</h2>\n");
- fwrite($html_file, "<div class="city-hint">如果没有您的城市,请到<a href="2-1.html" target="_blank">便民诉求</a>发帖申请!</div>\n<ul>\n");
- foreach ($groups_data as $group) {
- // 使用静态链接格式 gid-1.html
- $group_url = $web_root . $group['gid'] . '-1.html';
-
- $entry = "\t<li>\n" .
- "\t\t<a href="" . htmlspecialchars($group_url, ENT_QUOTES, $config['charset']) . "" target="_blank">" . htmlspecialchars($group['name'], ENT_QUOTES, $config['charset']) . "</a>\n" .
- "\t</li>\n";
- fwrite($html_file, $entry);
- }
- fwrite($html_file, "</ul>\n");
- }
- // === 修复结束 ===
- // 帖子列表
- fwrite($html_file, "<h2>最新帖子</h2>\n<ul>\n");
- foreach ($threads_data as $thread) {
- $url = $web_root . $thread['tid'] . '-1-1.html';
- $update_time = date('Y-m-d H:i', $thread['lastpost']);
- $hours = (time() - $thread['lastpost']) / 3600;
- $classes = [];
- if ($thread['replies'] > 50) $classes[] = 'hot';
- if ($hours < 24) $classes[] = 'recent';
- $class_attr = $classes ? ' class="' . implode(' ', $classes) . '"' : '';
- $entry = "\t<li{$class_attr}>\n" .
- "\t\t<div class="thread-item">\n" .
- "\t\t\t<a href="" . htmlspecialchars($url, ENT_QUOTES, $config['charset']) . "" target="_blank" class="thread-title">" . $thread['subject'] . "</a>\n" .
- "\t\t\t<span class="timestamp">({$update_time})</span>\n" .
- "\t\t</div>\n" .
- "\t</li>\n";
- fwrite($html_file, $entry);
- }
- fwrite($html_file, "</ul>\n");
- // === 移动:统计信息移到帖子下方 ===
- fwrite($html_file, "<div class="stats">\n");
- fwrite($html_file, "\t<p>本地图由系统自动生成,仅用于帮助用户导航</p>\n");
- fwrite($html_file, "\t<p>生成时间:" . $generation_time . "</p>\n");
- fwrite($html_file, "\t<p>收录城市版块(分区):" . $public_group_count . " 个</p>\n");
- fwrite($html_file, "\t<p>收录帖子(排除特定版块帖子):" . $processed . " / " . $total_threads . " 条</p>\n");
- fwrite($html_file, "\t<p><strong>XML格式:</strong><a href="Sitemap.xml" target="_blank">点击打开</a></p>\n");
- fwrite($html_file, "</div>\n");
- // === 移动结束 ===
- // 尾部
- $html_footer = '
- </div>
- <!-- 页脚 -->
- <footer class="footer">
- <div class="footer-content">
- <div class="footer-bottom">
- <div class="copyright">
- <p>客服:<a href="mailto:kefu@zgbm.com">kefu@zgbm.com</a></p>
- <p>© ' . date('Y') . ' ' . $site_name . '</p>
- </div>
- </div>
- </div>
- </footer>
-
- <script>
- // 页面加载完成后的初始化
- document.addEventListener("DOMContentLoaded", function() {
- console.log("网站地图页面加载完成");
- });
- </script>
- </body>
- </html>';
- fwrite($html_file, $html_footer);
- fclose($html_file);
- @chmod($html_filepath, 0644);
- // 更新日志内容
- runlog('sitemap_html', "Success: Generated Sitemap.html with {$public_group_count} city-groups and {$processed}/{$total_threads} threads. Hidden groups: [" . implode(',', $hidden_groups) . "], Excluded post fids: [" . implode(',', $excluded_from_posts) . "]");
- return TRUE;
- ?>
复制代码
|
|