connect('127.0.0.1', 6379); } catch (Throwable $e) { error_log("Redis connection failed: " . $e->getMessage()); $redis = null; } } // ───────────────────────────────────────────────────────────────────────────── // 国际访客 IP 检测(Redis 缓存 7 天,避免重复调用外部接口�?// 中国大陆 IP �?不加�?Google Translate,提升国内访问速度 // ───────────────────────────────────────────────────────────────────────────── if (!function_exists('detectIsInternationalVisitor')) { function detectIsInternationalVisitor(?Redis $redis): bool { $acceptLang = $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? ''; if (stripos($acceptLang, 'zh-CN') === 0 || stripos($acceptLang, 'zh-CN,') !== false) { return false; } $ip = ''; foreach (['HTTP_X_REAL_IP', 'HTTP_CF_CONNECTING_IP', 'HTTP_X_FORWARDED_FOR', 'REMOTE_ADDR'] as $key) { if (!empty($_SERVER[$key])) { $ip = trim(explode(',', $_SERVER[$key])[0]); break; } } if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) { return false; } $cacheKey = 'geoip:' . md5($ip); if ($redis) { $cached = @$redis->get($cacheKey); if ($cached !== false && $cached !== null) { return $cached !== 'CN'; } } $country = 'CN'; $ctx = stream_context_create(['http' => ['timeout' => 2, 'ignore_errors' => true]]); $resp = @file_get_contents("http://ip-api.com/json/{$ip}?fields=countryCode", false, $ctx); if ($resp) { $data = json_decode($resp, true); $country = $data['countryCode'] ?? 'CN'; } if ($redis) { @$redis->setex($cacheKey, 604800, $country); } return $country !== 'CN'; } } $isIntlVisitor = detectIsInternationalVisitor($redis); // ----------------------------------------------------------------------------- // ───────────────────────────────────────────────────────────────────────────── // 【修改函数】统一�?重定向至ホーム 逻辑 (�?404 终止) // ───────────────────────────────────────────────────────────────────────────── if (!function_exists('terminateWith404')) { function terminateWith404($logMessage) { // 强制跳转至ホーム,防止违规内容展示 error_log("REDIRECT TO HOME (from blacklist): " . $logMessage); // 清空并关闭输出缓冲区 if (ob_get_level() > 0) { ob_end_clean(); } // 执行 302 重定向到ホーム header("Location: " . rtrim(SYSTEM_HOME_URL, '/') . "/", true, 302); exit(); // 终止脚本 } } // ----------------------------------------------------------------------------- // 【函�?3】动态TDK处理,替换年份占位符 // ----------------------------------------------------------------------------- if (!function_exists('applyDynamicYear')) { function applyDynamicYear($text, $currentYear) { $text = str_replace('[YEAR]', $currentYear, $text); $yearsToReplace = [(string)$currentYear, (string)((int)$currentYear + 1)]; foreach ($yearsToReplace as $year) { $pattern = '/\b(' . preg_quote($year) . ')�?\b/u'; $text = preg_replace($pattern, '[YEAR]', $text); } return str_replace('[YEAR]', $currentYear, $text); } } // --- 问答与文章生成函数已移至 seo/includes/generation_functions.php --- // ───────────────────────────────────────────────────────────────────────────── // 【新方法�?getFilteredRelatedKeywords - 数据库筛选相关关键词 // ───────────────────────────────────────────────────────────────────────────── /** * 从数据库中筛选出包含当前关键词的词汇(长尾词)�? * @param string $keyword 关键�? * @param mysqli $conn MySQLi 数据库连�? * @return array 关键词列�? ["kw1", "kw2", ...] */ if (!function_exists('getFilteredRelatedKeywords')) { function getFilteredRelatedKeywords($keyword, $conn) { if (!$conn) return []; // 【硬性黑名单检查�? global $globalBlacklist; if (isInvalidKeyword($keyword, $globalBlacklist)) { return []; } // 使用 LIKE %关键�? 查找包含当前关键词的长尾�? $searchPattern = '%' . $keyword . '%'; // 限制数量,只查询关键词字段,并排�?is_blacklisted = 0 的词 try { $stmt = $conn->prepare("SELECT keyword FROM search_keywords WHERE keyword LIKE ? AND keyword != ? AND is_blacklisted = 1 LIMIT 15"); $stmt->bind_param("ss", $searchPattern, $keyword); $stmt->execute(); $res = $stmt->get_result(); $keywords = []; while ($row = $res->fetch_assoc()) { // 【强化检查】对每个检索到的关键词都进行硬性黑名单验证 if (!isInvalidKeyword($row['keyword'], $globalBlacklist)) { $keywords[] = $row['keyword']; } } $stmt->close(); } catch (\Throwable $e) { error_log("DB error filtering related keywords for '{$keyword}': " . $e->getMessage()); return []; } // 2. 移除重复�? $filteredKws = array_unique($keywords); return array_values($filteredKws); } } // ───────────────────────────────────────────────────────────────────────────── // 【函�?8】根据关键词生成动态内�?(Q&A 渲染) // ───────────────────────────────────────────────────────────────────────────── if (!function_exists('generateKeywordContent')) { function generateKeywordContent($keyword, $currentYear) { global $conn, $redis; if (empty($keyword)) { return ''; } // ⚠️ 最终的 API 调用和内容生成在这里,必须确保路由逻辑已经执行了所有检查�? $html = ''; // --- 1. Q&A Generation: 调用自动化函数获取问答数?--- $qaData = fetchAndCacheQA($keyword, $conn, $redis); // ... [内容生成?HTML 渲染逻辑保持不变] ... $qaTitle = "「{$keyword}」旅行Q&A"; if (!empty($qaData)) { // 渲染 Q&A 模块 (默认展开) $html .= '
' . $answer . '
'; $html .= '发现大西北最令人动容的风景,开启您的梦幻之�?/p>