diff --git a/dashboard.php b/dashboard.php index 9317a1f..b011596 100755 --- a/dashboard.php +++ b/dashboard.php @@ -1,6 +1,7 @@ alert('已开启国家条件,请填写允许的国家代码(如 US,GB,CA)。');history.back();"; + exit(); + } + if (!empty($methods)) { ConfigWriter::save($check_name, [ 'methods' => $methods, @@ -889,9 +897,26 @@ $_d = function($name, $default) { return defined($name) ? constant($name) : $def - 指定国家访问真实页(逗号分隔国家代码) - - + + 国家条件
+ 开启后仅允许填写的国家访问真实页;关闭则不做国家拦截。 + + + + + + > + 允许的国家代码(多个使用英文逗号隔开) + + + + 广告策略 ID @@ -1210,6 +1235,16 @@ $_d = function($name, $default) { return defined($name) ? constant($name) : $def $(target).slideToggle(180); }); + function syncCountryCodesRow() { + var on = $('input[name="country_on"]:checked').val() === 'ON'; + $('#countryCodesRow').toggle(on); + if (!on) { + $('input[name="country"]').val(''); + } + } + $(document).on('change', 'input[name="country_on"]', syncCountryCodesRow); + syncCountryCodesRow(); + // 动态添加链接 var linkIdx = 1; $(document).on('click', '#addNewLinkBtn', function() { diff --git a/ip_check.php b/ip_check.php index 7404218..aa939c8 100755 --- a/ip_check.php +++ b/ip_check.php @@ -55,7 +55,7 @@ if (!function_exists('cloak_dbg_record')) { //-----------------------------------------------ip check bof----------------------------------------------- $v_info = new visitorInfo(); - $v_info->get_visitor_Info(COSTM_IP_SCORE, CHECK_KEY, SHOW_SITE_COUNTRY); + $v_info->get_visitor_Info(COSTM_IP_SCORE, CHECK_KEY, CountryAllowlist::resolvedConfig()); $reason = ''; diff --git a/lib/Cloak/CountryAllowlist.php b/lib/Cloak/CountryAllowlist.php index b1d88ad..8723994 100755 --- a/lib/Cloak/CountryAllowlist.php +++ b/lib/Cloak/CountryAllowlist.php @@ -6,18 +6,56 @@ require_once __DIR__ . '/CountryCodeNormalizer.php'; class CountryAllowlist { + /** + * SHOW_SITE_COUNTRY 是否已配置(非空允许列表 = 开启国家条件) + * + * @param string|null $config 默认读取 SHOW_SITE_COUNTRY + */ + public static function isEnabled($config = null) + { + if ($config === null) { + $config = defined('SHOW_SITE_COUNTRY') ? SHOW_SITE_COUNTRY : ''; + } + return self::parse($config) !== []; + } + + /** + * 保存前规范化用户输入:兼容中文逗号/分号、顿号、全角空格及多余空白。 + * + * @param string $config + */ + public static function normalizeInput($config) + { + $config = trim((string) $config); + if ($config === '') { + return ''; + } + + // 全角空格、不间断空格 + $config = preg_replace('/[\x{3000}\x{00A0}]/u', ' ', $config); + + // 常见误输入分隔符统一为英文逗号 + $config = str_replace([',', ';', ';', '、'], ',', $config); + + // 去掉分隔符两侧空白,合并连续逗号 + $config = preg_replace('/\s*,\s*/', ',', $config); + $config = preg_replace('/,+/', ',', $config); + + return trim($config, " \t\n\r,"); + } + /** * @param string $config 逗号分隔国家码,如 US,GB,CA * @return string[] */ public static function parse($config) { - $config = trim((string) $config); + $config = self::normalizeInput($config); if ($config === '') { return []; } - // 支持英文逗号、中文逗号、分号分隔 - $parts = preg_split('/\s*[,,;]\s*/u', $config); + + $parts = explode(',', $config); $out = []; foreach ($parts as $part) { $part = trim($part); @@ -33,10 +71,23 @@ class CountryAllowlist } /** - * 保存配置前规范化国家列表字符串(dashboard 写入用) + * 读取并规范化 SHOW_SITE_COUNTRY(大写 ISO2,逗号分隔) + * + * @param string|null $config 默认 SHOW_SITE_COUNTRY + */ + public static function resolvedConfig($config = null) + { + if ($config === null) { + $config = defined('SHOW_SITE_COUNTRY') ? SHOW_SITE_COUNTRY : ''; + } + return self::formatForConfig($config); + } + + /** + * 保存配置前规范化国家列表字符串(dashboard 写入用,输出大写如 US,GB) * * @param string $config - * @return string 如 BR,CN + * @return string 如 US,GB */ public static function formatForConfig($config) { diff --git a/lib/Cloak/Pipeline/CheckPipeline.php b/lib/Cloak/Pipeline/CheckPipeline.php index aa23427..360dde0 100755 --- a/lib/Cloak/Pipeline/CheckPipeline.php +++ b/lib/Cloak/Pipeline/CheckPipeline.php @@ -2,6 +2,7 @@ require_once __DIR__ . '/../WhitelistGate.php'; require_once __DIR__ . '/../CloakJudgmentCache.php'; require_once __DIR__ . '/../RiskSecondaryGate.php'; +require_once __DIR__ . '/../CountryAllowlist.php'; /** * 流量判定主流水线 @@ -88,11 +89,15 @@ class CheckPipeline return; } - CloakPipelineTimer::stage('GeoIP国家判定'); - include __DIR__ . '/stages/check_country_geoip.inc.php'; - if (!empty($_SESSION['check_result'])) { - CloakPipelineTimer::finish(); - return; + if (CountryAllowlist::isEnabled()) { + CloakPipelineTimer::stage('GeoIP国家判定'); + include __DIR__ . '/stages/check_country_geoip.inc.php'; + if (!empty($_SESSION['check_result'])) { + CloakPipelineTimer::finish(); + return; + } + } elseif ($__cloak_debug_on) { + cloak_dbg_step(__LINE__, 'GeoIP国家判定', 'skip', '未开启国家条件'); } CloakPipelineTimer::stage('广告来源限制'); diff --git a/lib/Cloak/Pipeline/stages/apply_geoip_country_log_only.inc.php b/lib/Cloak/Pipeline/stages/apply_geoip_country_log_only.inc.php index 622492a..89d69d9 100755 --- a/lib/Cloak/Pipeline/stages/apply_geoip_country_log_only.inc.php +++ b/lib/Cloak/Pipeline/stages/apply_geoip_country_log_only.inc.php @@ -1,9 +1,20 @@ v_ip = $ip; diff --git a/lib/Cloak/Pipeline/stages/check_country_geoip.inc.php b/lib/Cloak/Pipeline/stages/check_country_geoip.inc.php index 2b73099..381dd27 100755 --- a/lib/Cloak/Pipeline/stages/check_country_geoip.inc.php +++ b/lib/Cloak/Pipeline/stages/check_country_geoip.inc.php @@ -1,9 +1,11 @@ v_ip = $ip; @@ -53,7 +62,7 @@ if (!CountryAllowlist::isAllowed($countryCode, $allowlist)) { } if (!empty($GLOBALS['__cloak_debug_on'])) { - cloak_dbg_step(__LINE__, 'GeoIP国家判定', 'pass', '国家允许或列表为空', [ + cloak_dbg_step(__LINE__, 'GeoIP国家判定', 'pass', '国家在允许列表内', [ 'ip' => $ip, 'country' => $countryCode, 'allowlist' => $allowlist, diff --git a/lib/Cloak/VisitorSimulationRunner.php b/lib/Cloak/VisitorSimulationRunner.php index 7eb8757..65c547d 100755 --- a/lib/Cloak/VisitorSimulationRunner.php +++ b/lib/Cloak/VisitorSimulationRunner.php @@ -230,7 +230,7 @@ class VisitorSimulationRunner global $v_info, $reason, $config_name; $config_name = $configName; $v_info = new visitorInfo(); - $v_info->get_visitor_Info(COSTM_IP_SCORE, CHECK_KEY, SHOW_SITE_COUNTRY); + $v_info->get_visitor_Info(COSTM_IP_SCORE, CHECK_KEY, CountryAllowlist::resolvedConfig()); $reason = ''; CheckPipeline::run(); diff --git a/lib/CloakAdSourceGuard.php b/lib/CloakAdSourceGuard.php index 073d460..1e8e224 100755 --- a/lib/CloakAdSourceGuard.php +++ b/lib/CloakAdSourceGuard.php @@ -52,9 +52,9 @@ class CloakAdSourceGuard ]; private static $fullTemplates = [ - self::PLATFORM_FB => 'utm_source=facebook&utm_medium=paid_social&utm_campaign={{campaign.name}}&utm_content={{ad.name}}&campaign_id={{campaign.id}}&adset_id={{adset.id}}&ad_id={{ad.id}}&site_source={{site_source_name}}&placement={{placement}}', - self::PLATFORM_GOOGLE => 'utm_source=google&utm_medium=cpc&utm_campaign={campaignid}&utm_content={adgroupid}&utm_term={keyword}&ad_id={creative}&network={network}&placement={placement}', - self::PLATFORM_TIKTOK => 'utm_source=tiktok&utm_medium=video_ad&utm_campaign=__CAMPAIGN_ID__&utm_content=__AID__&adgroup_id=__CID__&placement=__PLACEMENT__', + self::PLATFORM_FB => 'utm_source=facebook&site_source={{site_source_name}}&placement={{placement}}', + self::PLATFORM_GOOGLE => 'utm_source=google&utm_term={keyword}&network={network}&placement={placement}', + self::PLATFORM_TIKTOK => 'utm_source=tiktok&placement=__PLACEMENT__', ]; private static $multiPlatformParams = [ diff --git a/tools/regression_test.php b/tools/regression_test.php index a6d6294..466c829 100755 --- a/tools/regression_test.php +++ b/tools/regression_test.php @@ -286,6 +286,10 @@ $cfDomainOut = shell_exec(escapeshellarg(PHP_BINARY) . ' ' . escapeshellarg($roo $cfDomainJson = json_decode((string) $cfDomainOut, true); reg_assert('Cloudflare 域名自动化 Mock 流转', ($cfDomainJson['ok'] ?? false) === true, (string) $cfDomainOut); +$countryAllowOut = shell_exec(escapeshellarg(PHP_BINARY) . ' ' . escapeshellarg($root . '/tools/verify_country_allowlist.php') . ' 2>/dev/null'); +$countryAllowJson = json_decode((string) $countryAllowOut, true); +reg_assert('国家条件允许列表与 GeoIP 开关', ($countryAllowJson['ok'] ?? false) === true, (string) $countryAllowOut); + $geoOut = shell_exec(escapeshellarg(PHP_BINARY) . ' ' . escapeshellarg($root . '/tools/verify_geoip.php') . ' 2>/dev/null'); $geoJson = json_decode((string) $geoOut, true); if (($geoJson['tests']['db_file_exists'] ?? false) === true) { diff --git a/tools/verify_country_allowlist.php b/tools/verify_country_allowlist.php new file mode 100644 index 0000000..22f2ff8 --- /dev/null +++ b/tools/verify_country_allowlist.php @@ -0,0 +1,43 @@ +#!/usr/bin/env php + $ok, 'tests' => $tests], JSON_UNESCAPED_UNICODE) . "\n"; +exit($ok ? 0 : 1); diff --git a/tools/verify_geoip.php b/tools/verify_geoip.php index 4c54426..ec987a5 100755 --- a/tools/verify_geoip.php +++ b/tools/verify_geoip.php @@ -56,9 +56,16 @@ if ($tests['resolver_available']) { $tests['normalize_name'] = CountryCodeNormalizer::toAlpha2('United States') === 'US'; $tests['allowlist_name'] = CountryAllowlist::isAllowed('United Kingdom', CountryAllowlist::parse('GB,US')); $tests['allowlist_fullwidth_comma'] = CountryAllowlist::isAllowed('BR', CountryAllowlist::parse('BR,CN')); + $tests['allowlist_semicolon'] = CountryAllowlist::isAllowed('GB', CountryAllowlist::parse('US;GB;CA')); $tests['allowlist_country_name'] = CountryAllowlist::isAllowed('BR', CountryAllowlist::parse('Brazil,China')); if (!$tests['normalize_iso2'] || !$tests['normalize_name'] || !$tests['allowlist_name'] - || !$tests['allowlist_fullwidth_comma'] || !$tests['allowlist_country_name']) { + || !$tests['allowlist_fullwidth_comma'] || !$tests['allowlist_semicolon'] || !$tests['allowlist_country_name']) { + $ok = false; + } + + $tests['is_enabled_empty'] = CountryAllowlist::isEnabled('') === false; + $tests['is_enabled_us'] = CountryAllowlist::isEnabled('US,GB') === true; + if (!$tests['is_enabled_empty'] || !$tests['is_enabled_us']) { $ok = false; } }