:标题/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 '';
// 站长提示开关(后台可关):关闭时统一隐藏带 st-tip 标记的辅助文案
if ((setting_get('show_st_tips', '1')) !== '1') {
echo '';
}
echo '' . "\n";
}
/** 昼夜切换浮动按钮 + 返回顶部按钮(全站页面右下角) */
function layout_theme_fab(): void
{
echo '' . "\n";
echo '' . "\n";
}
/** 站内 logo 图片(内容区使用,同 favicon) */
function layout_logo_img(string $cls = 'logo', string $alt = 'logo'): void
{
global $P;
echo '
';
}
/** 全站页脚 */
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 '
';
}
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();
}