:标题/favicon/主题防闪烁/公共样式 */ function layout_head(string $title = ''): void { global $P; $site = setting_get('site_name', '知识导航站'); $logo = site_logo_rel(); $fullTitle = ($title !== '' ? $title . ' - ' : '') . $site; $prefix = $P; echo ''; echo ''; echo ''; // 主题防闪烁:在任何样式加载前应用 echo ''; echo '' . he($fullTitle) . ''; echo ''; echo ''; echo '' . "\n"; } /** 昼夜切换浮动按钮 */ function layout_theme_fab(): void { echo '' . "\n"; } /** 站内 logo 图片(内容区使用,同 favicon) */ function layout_logo_img(string $cls = 'logo', string $alt = 'logo'): void { global $P; echo '' . he($alt) . ''; } /** 全站页脚 */ function layout_footer(): void { global $P; $site = setting_get('site_name', '知识导航站'); $icp = setting_get('icp_no', ''); $gongan = setting_get('gongan_no', ''); $gonganLink = setting_get('gongan_link', ''); $copyright = setting_get('copyright', ''); $extra = setting_get('footer_text', ''); echo '' . "\n"; } /** 读取首页展示的名言(quota.txt 随机一行) */ function home_quote(): string { $file = DATA_DIR . '/quota.txt'; $lines = []; if (is_file($file)) { $raw = @file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); if (is_array($raw)) { foreach ($raw as $ln) { $ln = trim($ln); if ($ln !== '' && strpos($ln, '#') !== 0) { $lines[] = $ln; } } } } if (!$lines) { return '知识就是力量。'; } return $lines[array_rand($lines)]; } /** 图标值是否属于图片(dataURL / http / 常见图片扩展 / 相对路径) */ function icon_is_image(string $raw): bool { $v = trim($raw); if ($v === '') { return false; } if (preg_match('/^data:image\//i', $v) || preg_match('#^https?://#i', $v)) { return true; } if (preg_match('/\.(png|jpe?g|gif|svg|webp)(\?|#|$)/i', $v)) { return true; } return $v[0] === '/' || strpos($v, './') === 0 || strpos($v, '../') === 0; } /** 渲染图标:图片返回 ,否则返回转义文本(供前台/后台预览复用) */ function site_icon(?string $raw, string $alt = 'icon'): string { $v = trim((string)$raw); if ($v === '') { return ''; } if (icon_is_image($v)) { return '' . he($alt) . ''; } return he($v); } /** 默认 CDN IPv4 段库(每行:CIDR + 空格 + 厂商名;# 开头为注释,由后台可覆盖) */ function default_cdn_ranges(): string { return implode("\n", [ '# 内置默认:Cloudflare 官方 IPv4 段(可在后台“CDN IP 段库”补充其它厂商)', '103.21.244.0/22 Cloudflare', '103.22.200.0/22 Cloudflare', '103.31.4.0/22 Cloudflare', '104.16.0.0/13 Cloudflare', '104.24.0.0/14 Cloudflare', '108.162.192.0/18 Cloudflare', '131.0.72.0/22 Cloudflare', '141.101.64.0/18 Cloudflare', '162.158.0.0/15 Cloudflare', '172.64.0.0/13 Cloudflare', '173.245.48.0/20 Cloudflare', '188.114.96.0/20 Cloudflare', '190.93.240.0/20 Cloudflare', '197.234.240.0/22 Cloudflare', '198.41.128.0/17 Cloudflare', ]); } /** 当前生效的 CDN 段库文本(后台配置优先,为空回退默认内置列表) */ function cdn_ranges_text(): string { $v = setting_get('cdn_ranges', ''); return $v !== '' ? $v : default_cdn_ranges(); } /** 默认搜索引擎列表(后台未配置时的兜底) */ function default_search_engines(): array { return [ ['key' => 'bing', 'name' => 'Bing', 'icon' => 'B', 'url' => 'https://www.bing.com/search?q={kw}'], ['key' => 'baidu', 'name' => '百度', 'icon' => '度', 'url' => 'https://www.baidu.com/s?wd={kw}'], ['key' => 'github', 'name' => 'GitHub', 'icon' => 'G', 'url' => 'https://github.com/search?q={kw}'], ['key' => 'google', 'name' => 'Google', 'icon' => 'G', 'url' => 'https://www.google.com/search?q={kw}'], ]; } /** 读取当前生效的搜索引擎列表(优先后台配置,无效或为空回退默认) */ function search_engines(): array { $raw = setting_get('search_engines', ''); if ($raw === '') { return default_search_engines(); } $arr = json_decode($raw, true); if (!is_array($arr) || count($arr) === 0) { return default_search_engines(); } $out = []; foreach ($arr as $i => $e) { if (!is_array($e)) continue; $name = trim((string)($e['name'] ?? '')); $url = trim((string)($e['url'] ?? '')); $icon = trim((string)($e['icon'] ?? '')); if ($name === '' || $url === '' || strpos($url, '{kw}') === false) continue; $key = trim((string)($e['key'] ?? '')); if ($key === '') { $key = 'e' . ((int)$i + 1); } $out[] = ['key' => $key, 'name' => $name, 'icon' => ($icon !== '' ? $icon : 'S'), 'url' => $url]; } return $out !== [] ? $out : default_search_engines(); }