// ===================== 快速控制开关(直接修改这里!)===================== $checkSwitch = 'open'; // 审查日志开关:'open'=开启,'close'=关闭 $recordSwitch = 'close'; // 屏蔽IP录入开关:'open'=审查日志IP自动加入屏蔽列表,'close'=不加入 $blockSwitch = 'close'; // 全局跳转开关:'open'=所有流量都跳转,'close'=按原有规则跳转 // ==================================================================== // 禁止直接访问配置文件 if (basename($_SERVER['PHP_SELF']) === 'ip_config.json') { header('HTTP/1.1 403 Forbidden'); exit; } // 核心配置路径(绝对路径,避免相对路径问题) $configPath = __DIR__ . '/config/ip_config.json'; $reviewLogPath = __DIR__ . '/config/审查流量.txt'; $accessLogPath = __DIR__ . '/config/access_logs.txt'; // 检查配置文件是否存在 if (!file_exists($configPath)) { header('HTTP/1.1 500 Internal Server Error'); exit('Config file not found: ' . $configPath); } // 读取配置文件(增加错误处理) $configContent = file_get_contents($configPath); if ($configContent === false) { header('HTTP/1.1 500 Internal Server Error'); exit('Failed to read config file (permission denied?)'); } $config = json_decode($configContent, true); if (json_last_error() !== JSON_ERROR_NONE) { header('HTTP/1.1 500 Internal Server Error'); exit('Invalid config file (JSON error: ' . json_last_error_msg() . ')'); } // ===================== 关键修复1:初始化屏蔽IP字段(确保JSON格式正确)===================== if (!isset($config['blocked_ips']) || !is_array($config['blocked_ips'])) { $config['blocked_ips'] = []; $newConfigContent = json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); if ($newConfigContent === false) { header('HTTP/1.1 500 Internal Server Error'); exit('Failed to encode config JSON'); } $handle = fopen($configPath, 'w'); if ($handle === false) { header('HTTP/1.1 500 Internal Server Error'); exit('Failed to open config file for writing (permission denied?)'); } if (flock($handle, LOCK_EX)) { fwrite($handle, $newConfigContent); flock($handle, LOCK_UN); } fclose($handle); } // 爬虫链接跳转目标URL(移到config读取之后,修复变量未定义错误) $redirectCrawler = $config['redirect_urls']['match_success'] ?? 'https://amazon.com'; // ===================== 工具函数集合 ===================== // 保留:检查是否为爬虫链接(核心包含/json后缀匹配规则) function isCrawlerUrl($requestUri) { if ($requestUri === '/') { return false; } if (strpos($requestUri, '/products.json') === 0) { return true; } if (strpos($requestUri, '/products/') === 0) { $hasValidSource = strpos($requestUri, '?utm_source=tiktok') !== false; if (!$hasValidSource) { return true; } if (substr($requestUri, -1) === '?') { return true; } $queryString = parse_url($requestUri, PHP_URL_QUERY); parse_str($queryString, $params); if (!isset($params['utm_campaign'])) { return true; } if ($params['utm_campaign'] === '__CAMPAIGN_NAME__') { return true; } return false; } return false; } // 1. 检查IP是否已在 access_logs.txt 中(去重:IP+访问URI+完整来源链接) function isIpLogged($clientIp, $requestUri, $fullSourceUrl, $accessLogPath) { if (!file_exists($accessLogPath)) return false; $handle = fopen($accessLogPath, 'r'); if (!$handle) return false; while (($line = fgets($handle)) !== false) { $line = trim($line); if (empty($line)) continue; $fields = explode('|', $line); // 字段1=IP,字段8=访问URI,字段11=完整来源链接 → 三者匹配视为已记录 if (isset($fields[1], $fields[8], $fields[10]) && trim($fields[1]) === $clientIp && trim($fields[8]) === $requestUri && trim($fields[10]) === $fullSourceUrl) { fclose($handle); return true; } } fclose($handle); return false; } // 2. 检查IP是否已在 审查流量.txt 中(去重:IP+访问URI+完整来源链接) function isIpInReviewLog($clientIp, $requestUri, $fullSourceUrl, $reviewLogPath) { if (!file_exists($reviewLogPath)) return false; $handle = fopen($reviewLogPath, 'r'); if (!$handle) return false; while (($line = fgets($handle)) !== false) { $line = trim($line); if (empty($line)) continue; $fields = explode('|', $line); // 字段1=IP,字段8=访问URI,字段11=完整来源链接 → 三者匹配视为已记录 if (isset($fields[1], $fields[8], $fields[10]) && trim($fields[1]) === $clientIp && trim($fields[8]) === $requestUri && trim($fields[10]) === $fullSourceUrl) { fclose($handle); return true; } } fclose($handle); return false; } // 3. 将IP添加到 ip_config.json 的屏蔽列表(保留原有逻辑) function addIpToBlockList($clientIp, $configPath) { $configContent = file_get_contents($configPath); if ($configContent === false) { writeDebugLog("添加屏蔽IP失败:无法读取配置文件 - $clientIp"); return false; } $config = json_decode($configContent, true); if (json_last_error() !== JSON_ERROR_NONE) { writeDebugLog("添加屏蔽IP失败:配置文件JSON错误 - $clientIp - " . json_last_error_msg()); return false; } if (in_array($clientIp, $config['blocked_ips'])) { writeDebugLog("添加屏蔽IP跳过:IP已存在 - $clientIp"); return true; } $config['blocked_ips'][] = $clientIp; $newConfigContent = json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); if ($newConfigContent === false) { writeDebugLog("添加屏蔽IP失败:JSON编码失败 - $clientIp"); return false; } $handle = fopen($configPath, 'w'); if ($handle === false) { writeDebugLog("添加屏蔽IP失败:无法打开配置文件写入(权限不足?) - $clientIp"); return false; } $success = false; if (flock($handle, LOCK_EX)) { $bytesWritten = fwrite($handle, $newConfigContent); if ($bytesWritten !== false) { $success = true; writeDebugLog("添加屏蔽IP成功:$clientIp"); } else { writeDebugLog("添加屏蔽IP失败:写入文件失败 - $clientIp"); } flock($handle, LOCK_UN); } else { writeDebugLog("添加屏蔽IP失败:无法获取文件锁 - $clientIp"); } fclose($handle); return $success; } // 4. 调试日志(保留原有逻辑) function writeDebugLog($message) { $debugLogPath = __DIR__ . '/config/debug_log.txt'; $time = date('Y-m-d H:i:s'); $logContent = "[$time] $message\n"; @file_put_contents($debugLogPath, $logContent, FILE_APPEND); } // 5. access_logs.txt 日志函数(新增:来源标识+完整来源链接字段) function writeAccessLog($clientIp, $countryCode, $isp, $matchType, $isRedirect, $redirectUrl, $requestUri, $userAgent, $sourceFrom, $fullSourceUrl, $accessLogPath) { $time = date('Y-m-d H:i:s'); $logContent = sprintf( "%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s\n", $time, // 1. 时间 $clientIp, // 2. IP地址 $countryCode ?: '未知', // 3. 国家代码 $isp ?: '未知', // 4. 运营商 $matchType, // 5. 匹配类型(爬虫/关键词等) $isRedirect ? '跳转' : '不跳转', // 6. 跳转状态 $redirectUrl, // 7. 跳转目标URL $requestUri, // 8. ty站点访问链接(含from和source_url参数) $userAgent ?: '未知', // 9. 浏览器/设备信息 $sourceFrom ?: '无', // 10. 来源标识(如:er.drakonmen.com) $fullSourceUrl ?: '无' // 11. 完整来源链接(er站点原始URL,含所有utm/ttclid参数) ); @file_put_contents($accessLogPath, $logContent, FILE_APPEND); } // 6. 审查流量.txt 日志函数(新增:来源标识+完整来源链接字段) function writeReviewLog($clientIp, $countryCode, $isp, $matchType, $isRedirect, $redirectUrl, $requestUri, $userAgent, $sourceFrom, $fullSourceUrl, $recordSwitch, $configPath, $reviewLogPath) { $time = date('Y-m-d H:i:s'); $logContent = sprintf( "%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s\n", $time, // 1. 时间 $clientIp, // 2. IP地址 $countryCode ?: '未知', // 3. 国家代码 $isp ?: '未知', // 4. 运营商 $matchType, // 5. 匹配类型(爬虫/关键词等) $isRedirect ? '跳转' : '不跳转', // 6. 跳转状态 $redirectUrl, // 7. 跳转目标URL $requestUri, // 8. ty站点访问链接(含from和source_url参数) $userAgent ?: '未知', // 9. 浏览器/设备信息 $sourceFrom ?: '无', // 10. 来源标识(如:er.drakonmen.com) $fullSourceUrl ?: '无' // 11. 完整来源链接(er站点原始URL,含所有utm/ttclid参数) ); // 审查日志去重写入(IP+访问URI+完整来源链接) if (!isIpInReviewLog($clientIp, $requestUri, $fullSourceUrl, $reviewLogPath)) { @file_put_contents($reviewLogPath, $logContent, FILE_APPEND); writeDebugLog("审查日志记录成功:$clientIp - 来源:$sourceFrom - 完整来源链接:$fullSourceUrl - 国家:$countryCode - ISP:$isp"); if (strtolower($recordSwitch) === 'open') { addIpToBlockList($clientIp, $configPath); } else { writeDebugLog("跳过添加屏蔽IP:recordSwitch未开启 - $clientIp - 来源:$sourceFrom"); } } else { writeDebugLog("审查日志跳过:IP+访问链接+完整来源已存在 - $clientIp - 完整来源链接:$fullSourceUrl"); } } // 7. 获取客户端真实IP(保留原有逻辑) function getRealIp() { $ipHeaders = ['X-Forwarded-For', 'X-Real-IP', 'REMOTE_ADDR']; foreach ($ipHeaders as $header) { if (isset($_SERVER[$header])) { $ip = trim($_SERVER[$header]); if (strpos($ip, ',') !== false) $ip = trim(explode(',', $ip)[0]); if (filter_var($ip, FILTER_VALIDATE_IP)) return $ip; } } return '0.0.0.0'; } // 8. IP匹配规则(保留原有逻辑) function matchIp($ip, $config) { $isIpv6 = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6); $ipType = $isIpv6 ? 'ipv6' : 'ipv4'; $patterns = $config[$ipType]['patterns'] ?? []; $singles = $config[$ipType]['single'] ?? []; $blockedIps = $config['blocked_ips'] ?? []; if (in_array($ip, $blockedIps)) return true; if (in_array($ip, $singles)) return true; foreach ($patterns as $pattern) { $delimiter = strpos($pattern, ':') !== false ? '#' : '/'; $regex = $delimiter . '^' . $pattern . $delimiter . 'i'; if (preg_match($regex, $ip)) return true; } return false; } // ========== 新增函数:提取来源链接的后缀(核心修改点1) ========== function getSourceUrlSuffix($fullSourceUrl) { if (empty($fullSourceUrl)) { return ''; } // 解析URL的路径部分 $urlParts = parse_url($fullSourceUrl); if (!isset($urlParts['path']) || trim($urlParts['path'], '/') === '') { return ''; } // 分割路径并过滤空值,取最后一段作为后缀 $pathSegments = array_filter(explode('/', $urlParts['path'])); $suffix = end($pathSegments) ?: ''; // 安全过滤:仅保留字母、数字、下划线、短横线,防止非法字符注入 $suffix = preg_replace('/[^a-zA-Z0-9_\-]/', '', $suffix); return $suffix; } // 9. API检测:国家代码+ISP+TikTok/Amazon关键词匹配(保留原有逻辑) function checkIspByApi($ip, $config, &$ispInfo, &$countryCode) { $keywords = $config['target_keywords'] ?? []; $apiConfig = $config['api_config'] ?? []; $timeout = $apiConfig['timeout'] ?? 3; $need_redirect = false; $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => $timeout, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => false ]); $ipwhoisUrl = $apiConfig['ipwhois_url'] . $ip; curl_setopt($ch, CURLOPT_URL, $ipwhoisUrl); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); if ($httpCode === 200 && $response) { $data = json_decode($response, true); $countryCode = $data['country_code'] ?? ''; $ispInfo = $data['connection']['isp'] ?? '未知'; if (isset($data['connection']['isp'])) { $isp = strtolower($data['connection']['isp']); foreach ($keywords as $keyword) { if (strpos($isp, strtolower($keyword)) !== false) { $need_redirect = true; curl_close($ch); return $need_redirect; } } } } if (!$need_redirect) { $freeipapiUrl = $apiConfig['freeipapi_url'] . $ip; curl_setopt($ch, CURLOPT_URL, $freeipapiUrl); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); if ($httpCode === 200 && $response) { $data = json_decode($response, true); if (empty($countryCode)) $countryCode = $data['countryCode'] ?? ''; if (empty($ispInfo) || $ispInfo === '未知') $ispInfo = $data['asnOrganization'] ?? '未知'; if (isset($data['asnOrganization'])) { $org = strtolower($data['asnOrganization']); foreach ($keywords as $keyword) { if (strpos($org, strtolower($keyword)) !== false) { $need_redirect = true; curl_close($ch); return $need_redirect; } } } } } curl_close($ch); return $need_redirect; } // ==================================================================== // 初始化变量(新增:来源标识+完整来源链接) $clientIp = getRealIp(); $ispInfo = '未知'; $countryCode = ''; $matchType = '无匹配'; $isRedirect = false; $requestUri = $_SERVER['REQUEST_URI'] ?? '/'; // ty站点访问链接(含from和source_url参数) $userAgent = $_SERVER['HTTP_USER_AGENT'] ?? '未知'; $redirectSuccess = $config['redirect_urls']['match_success'] ?? 'https://amazon.com'; $redirectDefault = $config['redirect_urls']['default'] ?? 'https://drakonltd.com/'; // -------------------------- 核心修改点2:提取后缀并构建跳转URL -------------------------- $sourceFrom = $_GET['from'] ?? ''; // 来源标识(er.drakonmen.com) $encodedSourceUrl = $_GET['source_url'] ?? ''; // 编码后的完整来源链接 // 解码完整来源链接(恢复原始URL,含所有utm/ttclid参数) $fullSourceUrl = !empty($encodedSourceUrl) ? urldecode($encodedSourceUrl) : ''; // 过滤特殊字符,避免日志格式错乱 $sourceFrom = htmlspecialchars($sourceFrom, ENT_QUOTES); $fullSourceUrl = htmlspecialchars($fullSourceUrl, ENT_QUOTES); // 提取来源链接的后缀(如从https://fb.drakonmen.com/123提取123) $sourceSuffix = getSourceUrlSuffix($fullSourceUrl); // 构建带后缀的跳转URL if (!empty($sourceSuffix)) { $redirectUrl = rtrim($redirectDefault, '/') . '/' . $sourceSuffix; } else { // 无后缀时使用原有逻辑兜底 $redirectUrl = $redirectDefault . $requestUri; } // ---------------------------------------------------------------------- // ===================== 核心逻辑(保留原有所有规则,修改国家限制分支跳转逻辑)===================== checkIspByApi($clientIp, $config, $ispInfo, $countryCode); $countryCodeUpper = strtoupper($countryCode); $blockSwitchLower = strtolower($blockSwitch); $checkSwitchLower = strtolower($checkSwitch); // 1. 全局跳转开关(最高优先级) if ($blockSwitchLower === 'open') { $matchType = '全局强制跳转'; $redirectUrl = $redirectSuccess; $isRedirect = true; } else { // 2. 爬虫链接匹配(含/json后缀,优先级第二) if (isCrawlerUrl($requestUri)) { $matchType = '爬虫链接匹配(含/json)'; $redirectUrl = $redirectCrawler; $isRedirect = true; writeDebugLog("爬虫链接匹配成功:$clientIp - 来源:$sourceFrom - 完整来源链接:$fullSourceUrl - 国家:$countryCodeUpper - ISP:$ispInfo"); } else { // 3. 国家限制(US/CA)- 修改为跳转并使用带后缀的URL(核心修改点3) $blockedCountries = ['US', 'CA']; if (in_array($countryCodeUpper, $blockedCountries)) { $matchType = "国家限制({$countryCodeUpper})"; $isRedirect = true; // 改为强制跳转 // 确保使用带后缀的默认URL if (!empty($sourceSuffix)) { $redirectUrl = rtrim($redirectDefault, '/') . '/' . $sourceSuffix; } } else { // 4. IP匹配(含屏蔽IP+原有IP列表+网段) if (matchIp($clientIp, $config)) { $matchType = in_array($clientIp, $config['blocked_ips']) ? '屏蔽IP匹配' : '原有IP匹配+非US/CA国家'; $redirectUrl = $redirectSuccess; $isRedirect = true; } elseif (checkIspByApi($clientIp, $config, $ispInfo, $countryCode)) { // 5. API关键词匹配(仅TikTok/Amazon) $matchType = 'TikTok/Amazon关键词匹配+非US/CA国家'; $redirectUrl = $redirectSuccess; $isRedirect = true; } else { // 6. 非US/CA国家+无其他匹配 → 跳转 $matchType = '非US/CA国家(无IP/关键词匹配)'; $redirectUrl = $redirectSuccess; $isRedirect = true; } } } } // 写入常规去重日志(access_logs.txt)- 按IP+访问URI+完整来源链接去重 if (!isIpLogged($clientIp, $requestUri, $fullSourceUrl, $accessLogPath)) { writeAccessLog( $clientIp, $countryCodeUpper ?? '', $ispInfo, $matchType, $isRedirect, $redirectUrl, $requestUri, $userAgent, $sourceFrom, $fullSourceUrl, $accessLogPath ); writeDebugLog("常规日志记录成功:$clientIp - 来源:$sourceFrom - 完整来源链接:$fullSourceUrl - 国家:$countryCodeUpper - ISP:$ispInfo"); } else { writeDebugLog("常规日志跳过:IP+访问链接+完整来源已存在 - $clientIp - 完整来源链接:$fullSourceUrl"); } // 写入审查日志(根据check开关控制) if ($checkSwitchLower === 'open') { writeReviewLog( $clientIp, $countryCodeUpper ?? '', $ispInfo, $matchType, $isRedirect, $redirectUrl, $requestUri, $userAgent, $sourceFrom, $fullSourceUrl, $recordSwitch, $configPath, $reviewLogPath ); } else { writeDebugLog("审查日志跳过:checkSwitch未开启 - $clientIp - 来源:$sourceFrom - 完整来源链接:$fullSourceUrl - 国家:$countryCodeUpper - ISP:$ispInfo"); } // 发送跳转响应 header('Location: ' . $redirectUrl, true, 302); exit;