修复adjust归因失败
This commit is contained in:
+6
-2
@@ -524,8 +524,12 @@ function dash_build_ad_links($pf, $protocol, $host)
|
|||||||
return [['label' => '落地链接', 'url' => $base]];
|
return [['label' => '落地链接', 'url' => $base]];
|
||||||
}
|
}
|
||||||
|
|
||||||
$spmId = dash_cfg_get($raw, 'CLOAK_AD_SPM_ID');
|
$spmId = dash_cfg_get($raw, 'CLOAK_AD_SPM_ID');
|
||||||
$query = CloakAdSourceGuard::buildAdLinkQuery($enabled, $spmId);
|
$fpUrls = [];
|
||||||
|
if (preg_match("/define\('DB_FP',\s*(array\s*\(.*?\))\s*\)/s", $raw, $fpMatch)) {
|
||||||
|
@eval('$fpUrls = ' . $fpMatch[1] . ';');
|
||||||
|
}
|
||||||
|
$query = CloakAdSourceGuard::buildAdLinkQuery($enabled, $spmId, $fpUrls);
|
||||||
$url = $base . ($query !== '' ? '?' . $query : '');
|
$url = $base . ($query !== '' ? '?' . $query : '');
|
||||||
|
|
||||||
return [['label' => '落地链接', 'url' => $url]];
|
return [['label' => '落地链接', 'url' => $url]];
|
||||||
|
|||||||
@@ -1,133 +1,2 @@
|
|||||||
2026-05-24 20:19:53 | 来源判断 | |false | index | 127.0.0.1 |
|
2026-06-26 15:13:02 | 写入数据库 | false | index | async=1
|
||||||
2026-05-24 20:19:53 | 写入数据库 | false | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('','1031c4dd4b0c','cloaka.test','2026-05-24 20:19:53','127.0.0.1','', 'false','','off','PC','chrome','https://cloaka.test:443/index.php?clk_ts=1779624149&clk_nonce=fe833f043be432f1&clk_sig=f5f6690067758f79c085c18aab3a36cd781224e1abb3e9ee5436f9132538d373','English','https://worldhomenest.store','PC')
|
2026-06-27 15:43:53 | 写入数据库 | false | index | async=1
|
||||||
2026-05-24 20:19:59 | 来源判断 | 缓存|false | index | 127.0.0.1 | https://cloaka.test/dashboard
|
|
||||||
2026-05-24 20:19:59 | 写入数据库 | false | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('','','cloaka.test','2026-05-24 20:19:59','127.0.0.1','US', 'false','缓存','https://cloaka.test/dashboard','PC','chrome','https://cloaka.test:443/index.php?','English','https://worldhomenest.store','PC')
|
|
||||||
2026-05-24 20:25:12 | 来源判断 | |false | index | 127.0.0.1 |
|
|
||||||
2026-05-24 20:25:12 | 写入数据库 | false | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('','a2ea7ffe92a8','cloaka.test','2026-05-24 20:25:12','127.0.0.1','', 'false','','off','PC','chrome','https://cloaka.test:443/index.php?clk_ts=1779625346&clk_nonce=3cfa5dc8e5cf98a7&clk_sig=e02ebad7ce4fa0a4aeda23cb0cae63dbb70479d352b72fc677293f51c9ae66af','English','https://worldhomenest.store','PC')
|
|
||||||
2026-05-24 21:07:53 | 来源判断 | |false | index | 127.0.0.1 |
|
|
||||||
2026-05-24 21:38:24 | 来源判断 | |false | index | 127.0.0.1 |
|
|
||||||
2026-05-24 21:51:28 | 来源判断 | API响应非JSON|false | index | 127.0.0.1 |
|
|
||||||
2026-05-24 21:56:56 | 来源判断 | API请求失败:|false | index | 127.0.0.1 |
|
|
||||||
2026-05-24 21:59:15 | 来源判断 | API请求失败:|false | index | 127.0.0.1 |
|
|
||||||
2026-05-24 22:02:15 | 来源判断 | 黑名单|false | index | 127.0.0.1 |
|
|
||||||
2026-05-24 22:04:28 | 来源判断 | 黑名单|false | index | 127.0.0.1 |
|
|
||||||
2026-05-24 22:04:28 | 写入数据库 | false | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('20251108_emoUAVF6S','4ab064600a83','cloaka.test','2026-05-24 22:04:28','127.0.0.1','-', 'false','黑名单','off','PC','chrome','https://cloaka.test:443/index.php?clk_ts=1779631009&clk_nonce=3cfa5dc8e5cf98a7&clk_sig=3698790e84c74380c19b29b0d9bfd0240a933ba54dc0d16625405b37f096b8a1','English','https://worldhomenest.store','PC')
|
|
||||||
2026-05-24 22:16:41 | 来源判断 | 黑名单|false | index | 127.0.0.1 |
|
|
||||||
2026-05-24 22:31:42 | 来源判断 | 黑名单|false | index | 127.0.0.1 |
|
|
||||||
2026-05-24 22:35:41 | 来源判断 | 来源限制:未命中已开启广告来源(Facebook)|false | index | 127.0.0.1 |
|
|
||||||
2026-05-25 02:48:05 | 来源判断 | 来源限制:未命中已开启广告来源(Facebook)|false | index | 127.0.0.1 |
|
|
||||||
2026-05-25 02:57:31 | 来源判断 | 来源限制:未命中已开启广告来源(Facebook)|false | index | 127.0.0.1 |
|
|
||||||
2026-05-25 02:57:31 | 写入数据库 | false | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('20251108_emoUAVF6S','','cloaka.test','2026-05-25 02:57:31','127.0.0.1','US', 'false','来源限制:未命中已开启广告来源(Facebook)','','PC','chrome','https://cloaka.test/index.php?clk_ts=0&clk_nonce=3cfa5dc8e5cf98a7&clk_sig=954780561396c8b7df3623a21fe1c7a1f362c92e10a540cca4809c2413b9f187','English','https://worldhomenest.store','PC')
|
|
||||||
2026-05-25 03:01:56 | 来源判断 | 来源限制:未命中已开启广告来源(Facebook)|false | index | 127.0.0.1 |
|
|
||||||
2026-05-25 03:01:56 | 写入数据库 | false | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('20251108_emoUAVF6S','','cloaka.test','2026-05-25 03:01:56','127.0.0.1','US','false','来源限制:未命中已开启广告来源(Facebook)','','PC','chrome','https://cloaka.test/index.php?clk_ts=0&clk_nonce=3cfa5dc8e5cf98a7&clk_sig=954780561396c8b7df3623a21fe1c7a1f362c92e10a540cca4809c2413b9f187','English','https://worldhomenest.store','PC')
|
|
||||||
2026-05-25 03:05:20 | 来源判断 | 来源限制:未命中已开启广告来源(Facebook)|false | index | 127.0.0.1 |
|
|
||||||
2026-05-25 03:05:20 | 写入数据库 | false | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('20251108_emoUAVF6S','','cloaka.test','2026-05-25 03:05:20','127.0.0.1','US','false','来源限制:未命中已开启广告来源(Facebook)','','PC','chrome','https://cloaka.test/index.php?clk_ts=0&clk_nonce=3cfa5dc8e5cf98a7&clk_sig=954780561396c8b7df3623a21fe1c7a1f362c92e10a540cca4809c2413b9f187','English','https://worldhomenest.store','PC')
|
|
||||||
2026-05-25 03:33:18 | 来源判断 | 指纹Cookie未写入(已完成前端检测)|false | index | 127.0.0.1 | https://cloaka.test/index?clk_ts=0&clk_nonce=3cfa5dc8e5cf98a7&clk_sig=954780561396c8b7df3623a21fe1c7a1f362c92e10a540cca4809c2413b9f187
|
|
||||||
2026-05-25 03:33:18 | 写入数据库 | false | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('20251108_emoUAVF6S','84f1efe602e2','cloaka.test','2026-05-25 03:33:18','127.0.0.1','US','false','指纹Cookie未写入(已完成前端检测)','https://cloaka.test/index?clk_ts=0&clk_nonce=3cfa5dc8e5cf98a7&clk_sig=954780561396c8b7df3623a21fe1c7a1f362c92e10a540cca4809c2413b9f187','PC','chrome','https://cloaka.test/index.php?clk_ts=0&clk_nonce=3cfa5dc8e5cf98a7&clk_sig=954780561396c8b7df3623a21fe1c7a1f362c92e10a540cca4809c2413b9f187&time=1779651198719','English','https://worldhomenest.store','PC')
|
|
||||||
2026-05-25 03:45:30 | 来源判断 | 指纹Cookie未写入(已完成前端检测)|false | index | 127.0.0.1 | https://cloaka.test/index?clk_ts=0&clk_nonce=3cfa5dc8e5cf98a7&clk_sig=954780561396c8b7df3623a21fe1c7a1f362c92e10a540cca4809c2413b9f187
|
|
||||||
2026-05-25 03:45:30 | 写入数据库 | false | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('20251108_emoUAVF6S','e2f5fc622c3e','cloaka.test','2026-05-25 03:45:30','127.0.0.1','US','false','指纹Cookie未写入(已完成前端检测)','https://cloaka.test/index?clk_ts=0&clk_nonce=3cfa5dc8e5cf98a7&clk_sig=954780561396c8b7df3623a21fe1c7a1f362c92e10a540cca4809c2413b9f187','PC','chrome','https://cloaka.test/index.php?clk_ts=0&clk_nonce=3cfa5dc8e5cf98a7&clk_sig=954780561396c8b7df3623a21fe1c7a1f362c92e10a540cca4809c2413b9f187&time=1779651930890','English','https://worldhomenest.store','PC')
|
|
||||||
2026-05-25 03:57:21 | 来源判断 | 可疑访客:操作系统非IOS或者安卓|false | index | 127.0.0.1 | https://cloaka.test/index?clk_ts=0&clk_nonce=3cfa5dc8e5cf98a7&clk_sig=954780561396c8b7df3623a21fe1c7a1f362c92e10a540cca4809c2413b9f187
|
|
||||||
2026-05-25 03:57:21 | 写入数据库 | false | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('20251108_emoUAVF6S','df32c6c95fb6','cloaka.test','2026-05-25 03:57:21','127.0.0.1','US','false','可疑访客:操作系统非IOS或者安卓','https://cloaka.test/index?clk_ts=0&clk_nonce=3cfa5dc8e5cf98a7&clk_sig=954780561396c8b7df3623a21fe1c7a1f362c92e10a540cca4809c2413b9f187','PC','chrome','https://cloaka.test/index.php?clk_ts=0&clk_nonce=3cfa5dc8e5cf98a7&clk_sig=954780561396c8b7df3623a21fe1c7a1f362c92e10a540cca4809c2413b9f187&time=1779652640867','English','https://worldhomenest.store','PC')
|
|
||||||
2026-05-25 04:05:52 | 来源判断 | 黑名单|false | index | 127.0.0.1 |
|
|
||||||
2026-05-25 04:05:52 | 写入数据库 | false | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('20251108_emoUAVF6S','08c02abd8025','cloaka.test','2026-05-25 04:05:52','127.0.0.1','-','false','黑名单','off','PC','chrome','https://cloaka.test/index.php?clk_ts=0&clk_nonce=3cfa5dc8e5cf98a7&clk_sig=954780561396c8b7df3623a21fe1c7a1f362c92e10a540cca4809c2413b9f187','Chinese','https://worldhomenest.store','PC')
|
|
||||||
2026-05-26 02:02:56 | 写入数据库 | | regression_test | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('reg_test','','reg.test','2026-05-26 02:02:56','127.0.0.1','','false','','','PC','','/','','','')
|
|
||||||
2026-05-26 02:17:38 | 来源判断 | 黑名单|false | index | 127.0.0.1 |
|
|
||||||
2026-05-26 02:17:38 | 写入数据库 | false | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('20251108_emoUAVF6S','025bc6046566','cloaka.test','2026-05-26 02:17:38','127.0.0.1','-','false','黑名单','off','PC','chrome','https://cloaka.test/index.php?','English','https://worldhomenest.store','PC')
|
|
||||||
2026-05-26 02:18:16 | 来源判断 | 黑名单|false | index | 127.0.0.1 |
|
|
||||||
2026-05-26 02:18:16 | 写入数据库 | false | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('20251108_emoUAVF6S','945dddb376ef','cloaka.test','2026-05-26 02:18:16','127.0.0.1','-','false','黑名单','off','PC','chrome','https://cloaka.test/index.php?','English','https://worldhomenest.store','PC')
|
|
||||||
2026-05-26 02:18:35 | 来源判断 | 缓存|false | index | 127.0.0.1 |
|
|
||||||
2026-05-26 02:18:35 | 写入数据库 | false | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('20251108_emoUAVF6S','','cloaka.test','2026-05-26 02:18:35','127.0.0.1','-','false','缓存','','PC','chrome','https://cloaka.test/index.php?','English','https://worldhomenest.store','PC')
|
|
||||||
2026-05-26 02:18:54 | 来源判断 | 黑名单|false | index | 127.0.0.1 |
|
|
||||||
2026-05-26 02:18:54 | 写入数据库 | false | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('20251108_emoUAVF6S','adc58b3764e8','cloaka.test','2026-05-26 02:18:54','127.0.0.1','-','false','黑名单','off','PC','chrome','https://cloaka.test/index.php?','English','https://worldhomenest.store','PC')
|
|
||||||
2026-05-26 02:34:28 | 写入数据库 | | regression_test | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('reg_test','','reg.test','2026-05-26 02:34:28','127.0.0.1','','false','','','PC','','/','','','')
|
|
||||||
2026-05-26 02:36:56 | 写入数据库 | | regression_test | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('reg_test','','reg.test','2026-05-26 02:36:56','127.0.0.1','','false','','','PC','','/','','','')
|
|
||||||
2026-05-26 02:39:07 | 来源判断 | 黑名单|false | index | 127.0.0.1 |
|
|
||||||
2026-05-26 02:39:07 | 写入数据库 | false | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('20251108_emoUAVF6S','fb5ef3770269','cloaka.test','2026-05-26 02:39:07','127.0.0.1','-','false','黑名单','off','PC','chrome','https://cloaka.test/index.php?','English','https://worldhomenest.store','PC')
|
|
||||||
2026-05-26 02:39:27 | 来源判断 | 黑名单|false | index | 127.0.0.1 |
|
|
||||||
2026-05-26 02:39:28 | 写入数据库 | false | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('20251108_emoUAVF6S','3adc7b9b2b81','cloaka.test','2026-05-26 02:39:28','127.0.0.1','-','false','黑名单','off','PC','chrome','https://cloaka.test/index.php?','English','https://worldhomenest.store','PC')
|
|
||||||
2026-05-26 02:43:17 | 来源判断 | 黑名单|false | index | 127.0.0.1 |
|
|
||||||
2026-05-26 02:43:17 | 写入数据库 | false | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('20251108_emoUAVF6S','6d593c89acf1','cloaka.test','2026-05-26 02:43:17','127.0.0.1','-','false','黑名单','off','PC','chrome','https://cloaka.test/index.php?','English','https://worldhomenest.store','PC')
|
|
||||||
2026-05-26 02:44:28 | 来源判断 | API判定通过|true | index | 127.0.0.1 |
|
|
||||||
2026-05-26 02:44:28 | 写入数据库 | true | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('20251108_emoUAVF6S','98af2b462187','cloaka.test','2026-05-26 02:44:28','127.0.0.1','-','true','','off','PC','chrome','https://cloaka.test/index.php?','English','','PC')
|
|
||||||
2026-05-26 02:51:29 | 写入数据库 | | regression_test | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('reg_test','','reg.test','2026-05-26 02:51:29','127.0.0.1','','false','','','PC','','/','','','')
|
|
||||||
2026-05-26 02:52:41 | 来源判断 | API判定通过|true | index | 127.0.0.1 |
|
|
||||||
2026-05-26 02:52:41 | 写入数据库 | true | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('20251108_emoUAVF6S','07cdbefc93dd','cloaka.test','2026-05-26 02:52:41','127.0.0.1','-','true','','off','PC','chrome','https://cloaka.test/index.php?','English','','PC')
|
|
||||||
2026-05-26 02:55:19 | 写入数据库 | | regression_test | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('reg_test','','reg.test','2026-05-26 02:55:19','127.0.0.1','','false','','','PC','','/','','','')
|
|
||||||
2026-05-26 02:56:48 | 来源判断 | API判定通过|true | index | 127.0.0.1 |
|
|
||||||
2026-05-26 02:56:48 | 写入数据库 | true | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('20251108_emoUAVF6S','d9ee1f0cff7e','cloaka.test','2026-05-26 02:56:48','127.0.0.1','-','true','','off','PC','chrome','https://cloaka.test/index.php?','English','','PC')
|
|
||||||
2026-05-26 02:57:49 | 来源判断 | API判定通过|true | index | 127.0.0.1 |
|
|
||||||
2026-05-26 02:57:49 | 写入数据库 | true | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('20251108_emoUAVF6S','a332d9695ae9','cloaka.test','2026-05-26 02:57:49','127.0.0.1','-','true','','off','PC','chrome','https://cloaka.test/index.php?','English','','PC')
|
|
||||||
2026-05-26 02:58:05 | 来源判断 | API判定通过|true | index | 127.0.0.1 |
|
|
||||||
2026-05-26 02:58:05 | 写入数据库 | true | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('20251108_emoUAVF6S','9451a6af27f1','cloaka.test','2026-05-26 02:58:05','127.0.0.1','-','true','','off','PC','chrome','https://cloaka.test/index.php?','English','','PC')
|
|
||||||
2026-05-26 12:09:55 | 写入数据库 | | regression_test | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('reg_test','','reg.test','2026-05-26 12:09:55','127.0.0.1','','false','','','PC','','/','','','')
|
|
||||||
2026-05-26 12:51:31 | 写入数据库 | | regression_test | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('reg_test','','reg.test','2026-05-26 12:51:31','127.0.0.1','','false','','','PC','','/','','','')
|
|
||||||
2026-05-26 12:58:27 | 来源判断 | API判定通过|true | index | 127.0.0.1 |
|
|
||||||
2026-05-26 12:58:27 | 写入数据库 | true | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('20251108_emoUAVF6S','f0f613c783b5','cloaka.test','2026-05-26 12:58:27','127.0.0.1','-','true','','off','PC','chrome','https://cloaka.test/index.php?','English','','PC')
|
|
||||||
2026-05-26 13:01:16 | 写入数据库 | | regression_test | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('reg_test','','reg.test','2026-05-26 13:01:16','127.0.0.1','','false','','','PC','','/','','','')
|
|
||||||
2026-05-26 13:12:07 | 来源判断 | API判定通过|true | index | 127.0.0.1 |
|
|
||||||
2026-05-26 13:12:07 | 写入数据库 | true | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('20251108_emoUAVF6S','0c6370dab8fd','cloaka.test','2026-05-26 13:12:07','127.0.0.1','-','true','','off','PC','chrome','https://cloaka.test/index.php?','English','','PC')
|
|
||||||
2026-06-10 23:05:11 | 写入数据库 | | regression_test | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('reg_test','','reg.test','2026-06-10 23:05:11','127.0.0.1','','false','','','PC','','/','','','')
|
|
||||||
2026-06-10 23:05:59 | 写入数据库 | | regression_test | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('reg_test','','reg.test','2026-06-10 23:05:59','127.0.0.1','','false','','','PC','','/','','','')
|
|
||||||
2026-06-11 00:25:15 | 写入数据库 | | regression_test | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('reg_test','','reg.test','2026-06-11 00:25:15','127.0.0.1','','false','','','PC','','/','','','')
|
|
||||||
2026-06-11 19:28:27 | 写入数据库 | | regression_test | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('reg_test','','reg.test','2026-06-11 19:28:27','127.0.0.1','','false','','','PC','','/','','','')
|
|
||||||
2026-06-11 19:31:05 | 写入数据库 | | regression_test | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('reg_test','','reg.test','2026-06-11 19:31:05','127.0.0.1','','false','','','PC','','/','','','')
|
|
||||||
2026-06-14 00:27:19 | 写入数据库 | | regression_test | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('reg_test','','reg.test','2026-06-14 00:27:19','127.0.0.1','','false','','','PC','','/','','','')
|
|
||||||
2026-06-14 01:29:59 | 写入数据库 | | regression_test | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('reg_test','','reg.test','2026-06-14 01:29:59','127.0.0.1','','false','','','PC','','/','','','')
|
|
||||||
2026-06-14 02:05:06 | 写入数据库 | | regression_test | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('reg_test','','reg.test','2026-06-14 02:05:06','127.0.0.1','','false','','','PC','','/','','','')
|
|
||||||
2026-06-14 02:06:00 | 写入数据库 | | regression_test | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('reg_test','','reg.test','2026-06-14 02:06:00','127.0.0.1','','false','','','PC','','/','','','')
|
|
||||||
2026-06-14 02:28:34 | 来源判断 | 缓存|false | index | 127.0.0.1 |
|
|
||||||
2026-06-14 02:28:34 | 写入数据库 | false | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('20251108_emoUAVF6S','','cloaka.test','2026-06-14 02:28:34','127.0.0.1','-','false','缓存','','PC','chrome','https://cloaka.test/','English','https://worldhomenest.store','PC')
|
|
||||||
2026-06-14 02:30:57 | 来源判断 | 黑名单|false | index | 127.0.0.1 |
|
|
||||||
2026-06-14 02:30:57 | 写入数据库 | false | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('20251108_emoUAVF6S','fa0c6342a353','cloaka.test','2026-06-14 02:30:57','127.0.0.1','-','false','黑名单','off','PC','chrome','https://cloaka.test/','English','https://worldhomenest.store','PC')
|
|
||||||
2026-06-14 03:03:47 | 写入数据库 | | regression_test | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('reg_test','','reg.test','2026-06-14 03:03:47','127.0.0.1','','false','','','PC','','/','','','')
|
|
||||||
2026-06-14 03:04:01 | 写入数据库 | | regression_test | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `fp_url`, `device`) VALUES ('reg_test','','reg.test','2026-06-14 03:04:01','127.0.0.1','','false','','','PC','','/','','','')
|
|
||||||
2026-06-14 03:07:20 | 写入数据库 | | regression_test | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `user_agent`, `http_referer`, `accept_language_raw`, `judge_timing`, `fp_url`, `device`) VALUES ('reg_test','','reg.test','2026-06-14 03:07:20','127.0.0.1','','false','','','PC','','/','','','','','','','')
|
|
||||||
2026-06-14 03:23:32 | 来源判断 | 缓存|true | index | 127.0.0.1 |
|
|
||||||
2026-06-14 03:23:32 | 写入数据库 | true | index | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `user_agent`, `http_referer`, `accept_language_raw`, `judge_timing`, `fp_url`, `device`) VALUES ('20251108_emoUAVF6S','','cloaka.test','2026-06-14 03:23:32','127.0.0.1','-','true','','','PC','chrome','https://cloaka.test/?utm_campaign={campaignid}&adgroup_id=__CID__&ad_spm_id=t0tTw4MJ6r','English','Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36','','en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7','{\"total_ms\":0.12,\"stages\":[{\"name\":\"Session快速路径\",\"ms\":0.04}]}','https://www.google.com/','PC')
|
|
||||||
2026-06-14 11:51:53 | 写入数据库 | | regression_test | INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `client`, `browser`, `page`, `language`, `user_agent`, `http_referer`, `accept_language_raw`, `judge_timing`, `fp_url`, `device`) VALUES ('reg_test','','reg.test','2026-06-14 11:51:53','127.0.0.1','','false','','','PC','','/','','','','','','','')
|
|
||||||
2026-06-14 12:27:29 | 写入数据库 | | regression_test | async=1
|
|
||||||
2026-06-14 12:27:29 | 写入数据库 | | regression_test | async=1
|
|
||||||
2026-06-14 12:30:13 | 写入数据库 | | regression_test | async=1
|
|
||||||
2026-06-14 12:30:13 | 写入数据库 | | regression_test | async=1
|
|
||||||
2026-06-14 12:30:50 | 写入数据库 | | regression_test | async=1
|
|
||||||
2026-06-14 12:30:50 | 写入数据库 | | regression_test | async=1
|
|
||||||
2026-06-14 12:33:28 | 来源判断 | 黑名单|false | index | 127.0.0.1 |
|
|
||||||
2026-06-14 12:33:28 | 写入数据库 | false | index | async=1
|
|
||||||
2026-06-14 15:22:55 | 写入数据库 | | regression_test | async=1
|
|
||||||
2026-06-14 15:22:55 | 写入数据库 | | regression_test | async=1
|
|
||||||
2026-06-14 15:23:23 | 写入数据库 | | regression_test | async=1
|
|
||||||
2026-06-14 15:23:23 | 写入数据库 | | regression_test | async=1
|
|
||||||
2026-06-14 15:47:16 | 来源判断 | 无法识别访客国家|false | index | 127.0.0.1 | https://www.baidu.com/
|
|
||||||
2026-06-14 15:47:16 | 写入数据库 | false | index | async=1
|
|
||||||
2026-06-15 16:45:08 | 来源判断 | 无法识别访客国家|false | index | 127.0.0.1 | https://www.baidu.com/
|
|
||||||
2026-06-15 16:45:08 | 写入数据库 | false | index | async=1
|
|
||||||
2026-06-15 19:13:24 | 来源判断 | 无法识别访客国家|false | index | 127.0.0.1 |
|
|
||||||
2026-06-15 19:13:24 | 写入数据库 | false | index | async=1
|
|
||||||
2026-06-15 20:30:01 | 来源判断 | 无法识别访客国家|false | index | 127.0.0.1 |
|
|
||||||
2026-06-15 20:30:01 | 写入数据库 | false | indBXSXX | async=1
|
|
||||||
2026-06-15 20:30:45 | 来源判断 | 无法识别访客国家|false | index | 127.0.0.1 |
|
|
||||||
2026-06-15 20:30:45 | 写入数据库 | false | indBXSXX | async=1
|
|
||||||
2026-06-15 20:31:04 | 来源判断 | 无法识别访客国家|false | index | 127.0.0.1 |
|
|
||||||
2026-06-15 20:31:04 | 写入数据库 | false | indBXSXX | async=1
|
|
||||||
2026-06-15 20:31:20 | 来源判断 | 无法识别访客国家|false | index | 127.0.0.1 |
|
|
||||||
2026-06-15 20:31:20 | 写入数据库 | false | indBXSXX | async=1
|
|
||||||
2026-06-15 20:31:51 | 来源判断 | 无法识别访客国家|false | indBXSXX | 127.0.0.1 |
|
|
||||||
2026-06-15 20:31:51 | 写入数据库 | false | indBXSXX | async=1
|
|
||||||
2026-06-15 23:59:33 | 写入数据库 | | regression_test | async=1
|
|
||||||
2026-06-15 23:59:33 | 写入数据库 | | regression_test | async=1
|
|
||||||
2026-06-16 03:17:21 | 来源判断 | 无法识别访客国家|false | index | 0.0.0.0 |
|
|
||||||
2026-06-16 03:17:21 | 写入数据库 | false | test | async=1
|
|
||||||
2026-06-16 03:17:42 | 来源判断 | 无法识别访客国家|false | index | 0.0.0.0 |
|
|
||||||
2026-06-16 03:17:42 | 写入数据库 | false | indBXSXX_test | async=1
|
|
||||||
2026-06-16 03:21:38 | 来源判断 | 无法识别访客国家|false | index | 0.0.0.0 |
|
|
||||||
2026-06-16 03:21:38 | 写入数据库 | false | indBXSXX_test | async=1
|
|
||||||
2026-06-20 10:10:20 | 来源判断 | 判定拒绝(安全页)|false | indBXSXX | 127.0.0.1 |
|
|
||||||
2026-06-20 10:10:20 | 写入数据库 | false | indBXSXX | async=1
|
|
||||||
2026-06-20 10:33:43 | 来源判断 | 判定拒绝(安全页)|false | indBXSXX | 127.0.0.1 |
|
|
||||||
2026-06-20 10:33:43 | 写入数据库 | false | indBXSXX | async=1
|
|
||||||
2026-06-20 10:34:34 | 来源判断 | 无法识别访客国家|false | indBXSXX | 127.0.0.1 |
|
|
||||||
2026-06-20 10:34:34 | 写入数据库 | false | indBXSXX | async=1
|
|
||||||
2026-06-20 10:45:40 | 写入数据库 | false | indBXSXX | async=1
|
|
||||||
2026-06-20 10:46:58 | 写入数据库 | false | indBXSXX | async=1
|
|
||||||
2026-06-20 10:47:37 | 写入数据库 | false | indBXSXX | async=1
|
|
||||||
2026-06-22 19:15:55 | 写入数据库 | false | index | async=1
|
|
||||||
|
|||||||
@@ -0,0 +1,266 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Adjust / MMP 归因 URL 合并:宏占位符替换与安全 query 重建
|
||||||
|
*/
|
||||||
|
class AttributionUrlMerger
|
||||||
|
{
|
||||||
|
/** @var string[] */
|
||||||
|
private static $adjustHostSuffixes = [
|
||||||
|
'adjust.com',
|
||||||
|
'go.link',
|
||||||
|
'aindl.com',
|
||||||
|
];
|
||||||
|
|
||||||
|
/** @var string[] 广告平台 click ID,透传到 DB_FP 落地页供 Adjust JS 读取 */
|
||||||
|
private static $passthroughKeys = [
|
||||||
|
'fbclid',
|
||||||
|
'gclid',
|
||||||
|
'wbraid',
|
||||||
|
'gbraid',
|
||||||
|
'ttclid',
|
||||||
|
];
|
||||||
|
|
||||||
|
/** @var string[] cloak 内部参数,不进入最终 Adjust URL */
|
||||||
|
private static $stripKeys = [
|
||||||
|
'ad_spm_id',
|
||||||
|
'time',
|
||||||
|
'utm_source',
|
||||||
|
'utm_medium',
|
||||||
|
'utm_campaign',
|
||||||
|
'utm_term',
|
||||||
|
'utm_content',
|
||||||
|
'site_source',
|
||||||
|
'placement',
|
||||||
|
'campaign_id',
|
||||||
|
'adgroup_id',
|
||||||
|
'network',
|
||||||
|
];
|
||||||
|
|
||||||
|
/** @var array<string,string> Adjust 默认 p1–p6 → Facebook 宏 */
|
||||||
|
private static $defaultMacroParams = [
|
||||||
|
'p1' => '{{campaign.name}}',
|
||||||
|
'p2' => '{{campaign.id}}',
|
||||||
|
'p3' => '{{adset.name}}',
|
||||||
|
'p4' => '{{adset.id}}',
|
||||||
|
'p5' => '{{ad.name}}',
|
||||||
|
'p6' => '{{ad.id}}',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 目标 URL 是否需要归因宏合并
|
||||||
|
*/
|
||||||
|
public static function needsAttributionMerge($targetUrl)
|
||||||
|
{
|
||||||
|
$targetUrl = trim((string) $targetUrl);
|
||||||
|
if ($targetUrl === '') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stripos($targetUrl, '%7B%7B') !== false || stripos($targetUrl, '%7D%7D') !== false) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (preg_match('/\{\{[a-zA-Z0-9_.]+\}\}/', $targetUrl)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parts = parse_url($targetUrl);
|
||||||
|
$host = strtolower((string) ($parts['host'] ?? ''));
|
||||||
|
|
||||||
|
return self::isAdjustHost($host);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从 DB_FP URL 解析需追加到广告链接的宏参数(键名 => Facebook 宏模板)
|
||||||
|
*
|
||||||
|
* @return array<string,string>
|
||||||
|
*/
|
||||||
|
public static function parseAdjustMacroKeys($targetUrl)
|
||||||
|
{
|
||||||
|
$targetUrl = trim((string) $targetUrl);
|
||||||
|
if ($targetUrl === '') {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$parts = parse_url($targetUrl);
|
||||||
|
$query = [];
|
||||||
|
if (!empty($parts['query'])) {
|
||||||
|
parse_str($parts['query'], $query);
|
||||||
|
}
|
||||||
|
|
||||||
|
$keys = [];
|
||||||
|
foreach ($query as $key => $value) {
|
||||||
|
if (!self::isMacroPlaceholder($value)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$macro = self::extractMacroTemplate($value);
|
||||||
|
if ($macro !== '') {
|
||||||
|
$keys[(string) $key] = $macro;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($keys) && self::isAdjustHost(strtolower((string) ($parts['host'] ?? '')))) {
|
||||||
|
return self::$defaultMacroParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将落地页 query 合并进目标 URL,替换宏占位符
|
||||||
|
*
|
||||||
|
* @param array<string,mixed> $incomingQuery
|
||||||
|
*/
|
||||||
|
public static function merge($targetUrl, array $incomingQuery)
|
||||||
|
{
|
||||||
|
$targetUrl = trim((string) $targetUrl);
|
||||||
|
if ($targetUrl === '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$parts = parse_url($targetUrl);
|
||||||
|
if ($parts === false) {
|
||||||
|
return $targetUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
$targetQuery = [];
|
||||||
|
if (!empty($parts['query'])) {
|
||||||
|
parse_str($parts['query'], $targetQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
$merged = [];
|
||||||
|
foreach ($targetQuery as $key => $value) {
|
||||||
|
$key = (string) $key;
|
||||||
|
$value = (string) $value;
|
||||||
|
|
||||||
|
if (self::isMacroPlaceholder($value) && self::hasIncomingValue($incomingQuery, $key)) {
|
||||||
|
$merged[$key] = (string) $incomingQuery[$key];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!self::isMacroPlaceholder($value)) {
|
||||||
|
$merged[$key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (self::$passthroughKeys as $ptKey) {
|
||||||
|
if (!self::hasIncomingValue($incomingQuery, $ptKey)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$merged[$ptKey] = (string) $incomingQuery[$ptKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::buildUrl($parts, $merged);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string,mixed> $query
|
||||||
|
*/
|
||||||
|
private static function buildUrl(array $parts, array $query)
|
||||||
|
{
|
||||||
|
$scheme = $parts['scheme'] ?? 'https';
|
||||||
|
$host = $parts['host'] ?? '';
|
||||||
|
$port = isset($parts['port']) ? ':' . $parts['port'] : '';
|
||||||
|
$path = $parts['path'] ?? '';
|
||||||
|
$frag = isset($parts['fragment']) ? '#' . $parts['fragment'] : '';
|
||||||
|
|
||||||
|
$pairs = [];
|
||||||
|
foreach ($query as $key => $value) {
|
||||||
|
if (in_array((string) $key, self::$stripKeys, true)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$pairs[] = rawurlencode((string) $key) . '=' . rawurlencode((string) $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
$queryStr = implode('&', $pairs);
|
||||||
|
$url = $scheme . '://' . $host . $port . $path;
|
||||||
|
if ($queryStr !== '') {
|
||||||
|
$url .= '?' . $queryStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $url . $frag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $value
|
||||||
|
*/
|
||||||
|
public static function isMacroPlaceholder($value)
|
||||||
|
{
|
||||||
|
$value = trim((string) $value);
|
||||||
|
if ($value === '') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match('/^\{\{[a-zA-Z0-9_.]+\}\}$/', $value)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$decoded = rawurldecode($value);
|
||||||
|
if ($decoded !== $value && preg_match('/^\{\{[a-zA-Z0-9_.]+\}\}$/', $decoded)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (bool) preg_match('/^%7B%7B[a-zA-Z0-9_.]+%7D%7D$/i', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $value
|
||||||
|
*/
|
||||||
|
public static function extractMacroTemplate($value)
|
||||||
|
{
|
||||||
|
$value = trim((string) $value);
|
||||||
|
if ($value === '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match('/^\{\{([a-zA-Z0-9_.]+)\}\}$/', $value, $m)) {
|
||||||
|
return '{{' . $m[1] . '}}';
|
||||||
|
}
|
||||||
|
|
||||||
|
$decoded = rawurldecode($value);
|
||||||
|
if (preg_match('/^\{\{([a-zA-Z0-9_.]+)\}\}$/', $decoded, $m)) {
|
||||||
|
return '{{' . $m[1] . '}}';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match('/^%7B%7B([a-zA-Z0-9_.]+)%7D%7D$/i', $value, $m)) {
|
||||||
|
return '{{' . $m[1] . '}}';
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string,mixed> $incomingQuery
|
||||||
|
*/
|
||||||
|
private static function hasIncomingValue(array $incomingQuery, $key)
|
||||||
|
{
|
||||||
|
if (!array_key_exists($key, $incomingQuery)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$value = $incomingQuery[$key];
|
||||||
|
if ($value === null || $value === '') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (is_array($value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (self::isMacroPlaceholder($value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function isAdjustHost($host)
|
||||||
|
{
|
||||||
|
if ($host === '') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
foreach (self::$adjustHostSuffixes as $suffix) {
|
||||||
|
if ($host === $suffix || substr($host, -strlen('.' . $suffix)) === '.' . $suffix) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
|
require_once __DIR__ . '/AttributionUrlMerger.php';
|
||||||
|
require_once dirname(__DIR__) . '/CloakAdSourceGuard.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 真实页 URL 解析(DB_FP 轮询 + KEEP_PARAMS)
|
* 真实页 URL 解析(DB_FP 轮询 + KEEP_PARAMS / Adjust 归因合并)
|
||||||
*/
|
*/
|
||||||
class FpUrlHelper
|
class FpUrlHelper
|
||||||
{
|
{
|
||||||
@@ -81,8 +84,11 @@ class FpUrlHelper
|
|||||||
setCrossDomainCookie('nt', $now_url, 3600 * 24 + time());
|
setCrossDomainCookie('nt', $now_url, 3600 * 24 + time());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defined('KEEP_PARAMS') && KEEP_PARAMS === 'ON' && !empty($_GET) && $fp_url !== '') {
|
$incomingQuery = CloakAdSourceGuard::buildMergedRequestQuery();
|
||||||
$params = http_build_query($_GET);
|
if ($fp_url !== '' && AttributionUrlMerger::needsAttributionMerge($fp_url)) {
|
||||||
|
$fp_url = AttributionUrlMerger::merge($fp_url, $incomingQuery);
|
||||||
|
} elseif (defined('KEEP_PARAMS') && KEEP_PARAMS === 'ON' && !empty($incomingQuery)) {
|
||||||
|
$params = http_build_query($incomingQuery);
|
||||||
$urlParts = parse_url($fp_url);
|
$urlParts = parse_url($fp_url);
|
||||||
if (isset($urlParts['query'])) {
|
if (isset($urlParts['query'])) {
|
||||||
$fp_url .= '&' . $params;
|
$fp_url .= '&' . $params;
|
||||||
|
|||||||
@@ -35,10 +35,12 @@ class FpPageRenderer
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
if ($show_content == '302') {
|
if ($show_content == '302') {
|
||||||
header('location:' . $fp_url);
|
header('Referrer-Policy: origin-when-cross-origin');
|
||||||
|
header('Location: ' . $fp_url, true, 302);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
if ($show_content == 'js') {
|
if ($show_content == 'js') {
|
||||||
|
$fp_url_js = htmlspecialchars($fp_url, ENT_QUOTES, 'UTF-8');
|
||||||
?>
|
?>
|
||||||
<SCRIPT LANGUAGE="JavaScript">
|
<SCRIPT LANGUAGE="JavaScript">
|
||||||
var time = 1;
|
var time = 1;
|
||||||
@@ -48,7 +50,7 @@ class FpPageRenderer
|
|||||||
timelong ++;
|
timelong ++;
|
||||||
}
|
}
|
||||||
function redirect(){
|
function redirect(){
|
||||||
window.location.href="<?php echo $fp_url; ?>";
|
window.location.href="<?php echo $fp_url_js; ?>";
|
||||||
}
|
}
|
||||||
timer=setInterval('diplaytime()', 300);
|
timer=setInterval('diplaytime()', 300);
|
||||||
timer=setTimeout('redirect()',time * 300);
|
timer=setTimeout('redirect()',time * 300);
|
||||||
|
|||||||
@@ -82,7 +82,8 @@ class RouteResolver
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
if ($redirect_method == '302') {
|
if ($redirect_method == '302') {
|
||||||
header('Location: ' . $zp_url);
|
header('Referrer-Policy: origin-when-cross-origin');
|
||||||
|
header('Location: ' . $zp_url, true, 302);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
if ($redirect_method == 'js') {
|
if ($redirect_method == 'js') {
|
||||||
|
|||||||
@@ -129,11 +129,12 @@ class CloakAdSourceGuard
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $enabledPlatforms PLATFORM_* 常量列表
|
* @param array $enabledPlatforms PLATFORM_* 常量列表
|
||||||
* @param string $spmId
|
* @param string $spmId
|
||||||
|
* @param string|array|null $fpUrls DB_FP 真实页 URL(用于 Adjust 宏检测)
|
||||||
* @return string query 字符串(不含前导 ?)
|
* @return string query 字符串(不含前导 ?)
|
||||||
*/
|
*/
|
||||||
public static function buildAdLinkQuery(array $enabledPlatforms, $spmId)
|
public static function buildAdLinkQuery(array $enabledPlatforms, $spmId, $fpUrls = null)
|
||||||
{
|
{
|
||||||
$spmId = trim((string) $spmId);
|
$spmId = trim((string) $spmId);
|
||||||
if (empty($enabledPlatforms)) {
|
if (empty($enabledPlatforms)) {
|
||||||
@@ -154,6 +155,10 @@ class CloakAdSourceGuard
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (in_array(self::PLATFORM_FB, $enabledPlatforms, true)) {
|
||||||
|
$parts = array_merge($parts, self::buildAdjustMacroQueryParts($fpUrls));
|
||||||
|
}
|
||||||
|
|
||||||
if ($spmId !== '') {
|
if ($spmId !== '') {
|
||||||
$parts[] = 'ad_spm_id=' . rawurlencode($spmId);
|
$parts[] = 'ad_spm_id=' . rawurlencode($spmId);
|
||||||
}
|
}
|
||||||
@@ -161,6 +166,41 @@ class CloakAdSourceGuard
|
|||||||
return implode('&', $parts);
|
return implode('&', $parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DB_FP 为 Adjust 链接时,追加 p1–p6 等 Facebook 宏到广告链接
|
||||||
|
*
|
||||||
|
* @param string|array|null $fpUrls
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
private static function buildAdjustMacroQueryParts($fpUrls)
|
||||||
|
{
|
||||||
|
require_once __DIR__ . '/Cloak/AttributionUrlMerger.php';
|
||||||
|
|
||||||
|
$fpUrl = '';
|
||||||
|
if (is_array($fpUrls)) {
|
||||||
|
foreach ($fpUrls as $url) {
|
||||||
|
$url = trim((string) $url);
|
||||||
|
if ($url !== '') {
|
||||||
|
$fpUrl = $url;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$fpUrl = trim((string) $fpUrls);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($fpUrl === '' || !AttributionUrlMerger::needsAttributionMerge($fpUrl)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$parts = [];
|
||||||
|
foreach (AttributionUrlMerger::parseAdjustMacroKeys($fpUrl) as $key => $macro) {
|
||||||
|
$parts[] = rawurlencode((string) $key) . '=' . $macro;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $parts;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成 10–12 位随机字母数字 ad_spm_id
|
* 生成 10–12 位随机字母数字 ad_spm_id
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -94,9 +94,15 @@ vassert('无平台开启跳过', $r['passed'] && $r['matched_by'] === 'guard_dis
|
|||||||
|
|
||||||
// 链接拼装:单平台
|
// 链接拼装:单平台
|
||||||
$q = CloakAdSourceGuard::buildAdLinkQuery([CloakAdSourceGuard::PLATFORM_FB], $spmId);
|
$q = CloakAdSourceGuard::buildAdLinkQuery([CloakAdSourceGuard::PLATFORM_FB], $spmId);
|
||||||
vassert('单平台 FB 含完整 UTM', strpos($q, 'utm_source=facebook') !== false && strpos($q, 'campaign_id={{campaign.id}}') !== false);
|
vassert('单平台 FB 含完整 UTM', strpos($q, 'utm_source=facebook') !== false);
|
||||||
vassert('单平台含 ad_spm_id', strpos($q, 'ad_spm_id=' . rawurlencode($spmId)) !== false);
|
vassert('单平台含 ad_spm_id', strpos($q, 'ad_spm_id=' . rawurlencode($spmId)) !== false);
|
||||||
|
|
||||||
|
$adjustFp = 'https://aindl.com/v305-8/?p0=1ynqxx65&p1=%7B%7Bcampaign.name%7D%7D&p2=%7B%7Bcampaign.id%7D%7D&p3=%7B%7Badset.name%7D%7D&p4=%7B%7Badset.id%7D%7D&p5=%7B%7Bad.name%7D%7D&p6=%7B%7Bad.id%7D%7D';
|
||||||
|
$qAdjust = CloakAdSourceGuard::buildAdLinkQuery([CloakAdSourceGuard::PLATFORM_FB], $spmId, [$adjustFp]);
|
||||||
|
vassert('Adjust DB_FP 追加 p1 宏', strpos($qAdjust, 'p1={{campaign.name}}') !== false, $qAdjust);
|
||||||
|
vassert('Adjust DB_FP 追加 p6 宏', strpos($qAdjust, 'p6={{ad.id}}') !== false, $qAdjust);
|
||||||
|
vassert('Adjust 广告链接仍含 UTM', strpos($qAdjust, 'utm_source=facebook') !== false);
|
||||||
|
|
||||||
// 链接拼装:多平台
|
// 链接拼装:多平台
|
||||||
$q = CloakAdSourceGuard::buildAdLinkQuery([
|
$q = CloakAdSourceGuard::buildAdLinkQuery([
|
||||||
CloakAdSourceGuard::PLATFORM_FB,
|
CloakAdSourceGuard::PLATFORM_FB,
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Adjust 归因 URL 合并单元验证
|
||||||
|
*
|
||||||
|
* 用法:php tools/verify_attribution_merge.php
|
||||||
|
*/
|
||||||
|
if (PHP_SAPI !== 'cli') {
|
||||||
|
fwrite(STDERR, "请在 CLI 下运行\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once dirname(__DIR__) . '/lib/Cloak/AttributionUrlMerger.php';
|
||||||
|
|
||||||
|
$passed = 0;
|
||||||
|
$failed = 0;
|
||||||
|
|
||||||
|
function vassert($name, $cond, $detail = '')
|
||||||
|
{
|
||||||
|
global $passed, $failed;
|
||||||
|
if ($cond) {
|
||||||
|
$passed++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$failed++;
|
||||||
|
echo "FAIL: {$name}\n";
|
||||||
|
if ($detail !== '') {
|
||||||
|
echo " {$detail}\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$adjustTarget = 'https://aindl.com/v305-8/?p0=1ynqxx65&p1=%7B%7Bcampaign.name%7D%7D&p2=%7B%7Bcampaign.id%7D%7D&p3=%7B%7Badset.name%7D%7D&p4=%7B%7Badset.id%7D%7D&p5=%7B%7Bad.name%7D%7D&p6=%7B%7Bad.id%7D%7D';
|
||||||
|
|
||||||
|
vassert('needsAttributionMerge: 编码宏', AttributionUrlMerger::needsAttributionMerge($adjustTarget));
|
||||||
|
vassert('needsAttributionMerge: 明文宏', AttributionUrlMerger::needsAttributionMerge('https://example.com/?x={{campaign.name}}'));
|
||||||
|
vassert('needsAttributionMerge: Adjust host', AttributionUrlMerger::needsAttributionMerge('https://aindl.com/v305-8/?p0=abc'));
|
||||||
|
vassert('needsAttributionMerge: 普通 URL', !AttributionUrlMerger::needsAttributionMerge('https://www.google.com/'));
|
||||||
|
|
||||||
|
vassert('isMacroPlaceholder: 编码', AttributionUrlMerger::isMacroPlaceholder('%7B%7Bcampaign.name%7D%7D'));
|
||||||
|
vassert('isMacroPlaceholder: 明文', AttributionUrlMerger::isMacroPlaceholder('{{campaign.name}}'));
|
||||||
|
vassert('isMacroPlaceholder: 静态值', !AttributionUrlMerger::isMacroPlaceholder('1ynqxx65'));
|
||||||
|
|
||||||
|
$keys = AttributionUrlMerger::parseAdjustMacroKeys($adjustTarget);
|
||||||
|
vassert('parseAdjustMacroKeys: p1', isset($keys['p1']) && $keys['p1'] === '{{campaign.name}}');
|
||||||
|
vassert('parseAdjustMacroKeys: p6', isset($keys['p6']) && $keys['p6'] === '{{ad.id}}');
|
||||||
|
|
||||||
|
$incoming = [
|
||||||
|
'p1' => 'Summer Sale',
|
||||||
|
'p2' => '120345678',
|
||||||
|
'p3' => 'US Adset',
|
||||||
|
'p4' => '987654',
|
||||||
|
'p5' => 'Creative A',
|
||||||
|
'p6' => '111222',
|
||||||
|
'ad_spm_id' => '6a0HTjW6bd',
|
||||||
|
'time' => '1719491234567',
|
||||||
|
'utm_source'=> 'facebook',
|
||||||
|
'site_source' => 'fb',
|
||||||
|
'placement' => 'feed',
|
||||||
|
'fbclid' => 'IwAR1234567890123456789012',
|
||||||
|
];
|
||||||
|
|
||||||
|
$merged = AttributionUrlMerger::merge($adjustTarget, $incoming);
|
||||||
|
vassert('merge: p0 保留', strpos($merged, 'p0=1ynqxx65') !== false, $merged);
|
||||||
|
vassert('merge: p1 展开', strpos($merged, 'p1=Summer%20Sale') !== false, $merged);
|
||||||
|
vassert('merge: p2 展开', strpos($merged, 'p2=120345678') !== false, $merged);
|
||||||
|
vassert('merge: 无 ad_spm_id', strpos($merged, 'ad_spm_id') === false, $merged);
|
||||||
|
vassert('merge: 无 time', strpos($merged, 'time=') === false, $merged);
|
||||||
|
vassert('merge: 无 utm_source', strpos($merged, 'utm_source') === false, $merged);
|
||||||
|
vassert('merge: 透传 fbclid', strpos($merged, 'fbclid=IwAR1234567890123456789012') !== false, $merged);
|
||||||
|
vassert('merge: 无双重编码', strpos($merged, '%257B') === false, $merged);
|
||||||
|
|
||||||
|
$masterummyTarget = 'https://www.masterummy.online/623-2/?p0=20fm2y6y&p1=%7B%7Bcampaign.name%7D%7D&p2=%7B%7Bcampaign.id%7D%7D&p3=%7B%7Badset.name%7D%7D&p4=%7B%7Badset.id%7D%7D&p5=%7B%7Bad.name%7D%7D&p6=%7B%7Bad.id%7D%7D';
|
||||||
|
$incoming623 = [
|
||||||
|
'p1' => 'IN-master-623-2',
|
||||||
|
'p2' => '120247249921340752',
|
||||||
|
'p3' => '新销量广告组',
|
||||||
|
'p4' => '120247249921360752',
|
||||||
|
'p5' => '2',
|
||||||
|
'p6' => '120247249998390752',
|
||||||
|
'fbclid' => 'IwAR0abcdefghijklmnopqrst',
|
||||||
|
'ad_spm_id' => '6WLT21GWrVKx',
|
||||||
|
];
|
||||||
|
$merged623 = AttributionUrlMerger::merge($masterummyTarget, $incoming623);
|
||||||
|
vassert('623: p1 展开', strpos($merged623, 'p1=IN-master-623-2') !== false, $merged623);
|
||||||
|
vassert('623: p3 中文', strpos($merged623, 'p3=%E6%96%B0%E9%94%80%E9%87%8F%E5%B9%BF%E5%91%8A%E7%BB%84') !== false, $merged623);
|
||||||
|
vassert('623: fbclid 透传', strpos($merged623, 'fbclid=IwAR0abcdefghijklmnopqrst') !== false, $merged623);
|
||||||
|
vassert('623: 无 ad_spm_id', strpos($merged623, 'ad_spm_id') === false, $merged623);
|
||||||
|
|
||||||
|
$plainTarget = 'https://example.com/landing?p1={{campaign.name}}&token=static';
|
||||||
|
$mergedPlain = AttributionUrlMerger::merge($plainTarget, ['p1' => 'My Campaign', 'token' => 'ignored']);
|
||||||
|
vassert('merge: 明文宏替换', strpos($mergedPlain, 'p1=My%20Campaign') !== false, $mergedPlain);
|
||||||
|
vassert('merge: 静态 token 保留', strpos($mergedPlain, 'token=static') !== false, $mergedPlain);
|
||||||
|
|
||||||
|
$clidTarget = 'https://aindl.com/x?p0=abc&fbclid=%7B%7Bfbclid%7D%7D';
|
||||||
|
$mergedClid = AttributionUrlMerger::merge($clidTarget, ['fbclid' => 'realclid123']);
|
||||||
|
vassert('merge: 目标含 fbclid 宏时替换', strpos($mergedClid, 'fbclid=realclid123') !== false, $mergedClid);
|
||||||
|
|
||||||
|
$result = ['ok' => $failed === 0, 'passed' => $passed, 'failed' => $failed];
|
||||||
|
echo json_encode($result, JSON_UNESCAPED_UNICODE) . "\n";
|
||||||
|
exit($failed > 0 ? 1 : 0);
|
||||||
Reference in New Issue
Block a user