UrlService.php 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: Bear
  5. * Date: 2018/12/3
  6. * Time: 下午4:13
  7. */
  8. namespace app\main\service;
  9. use app\common\library\Redis;
  10. use app\common\model\Referral;
  11. use app\common\utility\WhiteList;
  12. use app\main\constants\AdminConstants;
  13. use app\main\constants\ApiConstants;
  14. use app\main\constants\ErrorCodeConstants;
  15. use app\main\constants\KafkaDotConstants;
  16. use app\main\constants\MarkConstants;
  17. use app\main\constants\MqConstants;
  18. use app\main\constants\OpenPlatformConstants;
  19. use app\main\constants\UrlConstants;
  20. use app\main\constants\UserConstants;
  21. use app\main\helper\ArrayHelper;
  22. use app\main\model\object\AnalysisObject;
  23. use app\main\model\object\DotObject;
  24. use app\main\model\object\UserObject;
  25. use think\Config;
  26. use think\Cookie;
  27. use think\Env;
  28. use think\Request;
  29. /**
  30. * 处理url信息
  31. * Class UrlService
  32. * @package app\main\service
  33. */
  34. class UrlService extends BaseService
  35. {
  36. /**
  37. * @var UrlService
  38. */
  39. protected static $self = NULL;
  40. private $domain;
  41. /**
  42. * @return UrlService
  43. */
  44. public static function instance()
  45. {
  46. if (self::$self == NULL) {
  47. self::$self = new self();
  48. }
  49. return self::$self;
  50. }
  51. /**
  52. * @return Referral
  53. */
  54. public function getReferralModel()
  55. {
  56. return model('Referral');
  57. }
  58. public function checkApiDomain()
  59. {
  60. try{
  61. $channel_id = Request::instance()->get('channel_id');
  62. if(!$channel_id){
  63. $channel_id = Cookie::get('channel_id');
  64. }
  65. UserService::instance()->getRunTimeObject()->channelId = $channel_id;
  66. $host = $this->getSourceDomain();
  67. UserService::instance()->getRunTimeObject()->sourceDomain = $host;
  68. UserService::instance()->getRunTimeObject()->currentPayHost = $host;
  69. $mWeixin = OfficialAccountsService::instance()->getWxpayModel();
  70. $mOphost = OfficialAccountsService::instance()->getOphostModel();
  71. $hosts = $mOphost->getHosts();
  72. LogService::info('API_LOG Source Domain:'.$host);
  73. LogService::info('API_LOG Ophost:'.var_export($hosts,true));
  74. if ($this->checkDomainIsPay()) { //支付域名
  75. UserService::instance()->getRunTimeObject()->urlType = OpenPlatformConstants::URL_TYPE_PAY;
  76. /*
  77. * 动态初始化微信商户服务号参数
  78. */
  79. $arr = Config::get('wechat.http'); // 修正充值API
  80. $arr['base_uri'] = 'https://api.mch.weixin.qq.com/'; // 修正充值API
  81. Config::set('wechat.http', $arr);
  82. $pay_hosts = $mWeixin->getInfoByHost($host);
  83. $payInfo = $mWeixin->getInfo($pay_hosts['platform_id'],$pay_hosts['id']);
  84. Config::set('wechat.app_id', $payInfo['appid']);
  85. Config::set('wechat.secret', $payInfo['secret']);
  86. Config::set('wechat.mch_id', $payInfo['mcid']);
  87. Config::set('wechat.key', $payInfo['apikey']);
  88. Config::set('wechat.platform_id', $payInfo['platform_id']);
  89. LogService::info('API_LOG INIT - PAY Default');
  90. }elseif($appid = $this->checkDomainIsReferral()){
  91. $channelData = AdminService::instance()->getAdminConfigModel()->getAdminInfoByAppId($appid); //$matches[0] appid
  92. if ($channelData) {
  93. UserService::instance()->getRunTimeObject()->agentId = $this->getUserAgentId()->data;
  94. UserService::instance()->getRunTimeObject()->channelId = UserService::instance()->getUserInfo()->channel_id;
  95. UserService::instance()->getRunTimeObject()->adminId = UserService::instance()->getAdminId()->data;
  96. UserService::instance()->getRunTimeObject()->urlType = OpenPlatformConstants::URL_TYPE_SPREAD;
  97. //根据域名获取平台信息
  98. $hostArr = explode(".", $host);
  99. array_shift($hostArr);
  100. $topHost = implode(".", $hostArr);
  101. if($topHost == $channelData['menu_ophost_host']){
  102. $platform_info = OpenPlatformService::instance()->getPlatformModel()->getInfo($channelData['menu_platform_id']);
  103. Config::set('wechat.app_id', $platform_info['appid']);
  104. Config::set('wechat.secret', $platform_info['secret']);
  105. Config::set('wechat.token', $platform_info['token']);
  106. Config::set('wechat.aes_key', $platform_info['aes_key']);
  107. Config::set('wechat.platform_id', $channelData['menu_platform_id']);
  108. }else{
  109. Config::set('wechat.app_id', $channelData['platform_appid']);
  110. Config::set('wechat.secret', $channelData['platform_secret']);
  111. Config::set('wechat.token', $channelData['platform_token']);
  112. Config::set('wechat.aes_key',$channelData['platform_aes_key']);
  113. Config::set('wechat.platform_id', $channelData['platform_id']);
  114. }
  115. LogService::info('API_LOG WeChatAPPID Default');
  116. }
  117. }elseif(in_array($host,$hosts)){
  118. if($ophost = $mOphost->getInfoByHost($host)){
  119. $platformData = OpenPlatformService::instance()->getPlatformModel()->getInfo($ophost['platform_id']);
  120. Config::set('wechat.app_id', $platformData['appid']);
  121. Config::set('wechat.secret', $platformData['secret']);
  122. Config::set('wechat.token', $platformData['token']);
  123. Config::set('wechat.aes_key',$platformData['aes_key']);
  124. Config::set('wechat.platform_id', $ophost['platform_id']);
  125. LogService::info('API_LOG Platform:'.var_export($platformData,true));
  126. } else {
  127. LogService::info('API_LOG 未匹配到域名信息:' . $host . ':' . json_encode($hosts));
  128. }
  129. }
  130. return $this->getReturn();
  131. }catch (\Exception $e){
  132. return $this->getExceptionReturn($e);
  133. }
  134. }
  135. /**
  136. * 删除www.及callback前缀
  137. * @return bool|null|string|string[]
  138. */
  139. public function getSourceDomain()
  140. {
  141. if (!$this->domain) {
  142. $host = get_host_no_port();
  143. $host = preg_replace('/^www\./', '', $host);
  144. $host = preg_replace('/^open\./', '', $host);
  145. $this->domain = preg_replace('/^' . ApiConstants::PAY_CALLBACK_PREFIX . '/', '', $host);
  146. }
  147. return $this->domain;
  148. }
  149. /**
  150. * 域名检查
  151. * @return \app\main\model\object\ReturnObject|UrlService
  152. */
  153. public function checkFrontDomain()
  154. {
  155. if (UrlService::instance()->checkDomainIsPay()) { //支付域名
  156. $result = UrlService::instance()->checkFrontPayHost();
  157. } elseif (UrlService::instance()->checkDomainIsEntry()) { //入口域名
  158. $result = UrlService::instance()->checkFrontEntryHost();
  159. } elseif (UrlService::instance()->checkDomainIsReferral()) { //判断是否为推广域名
  160. $result = UrlService::instance()->checkFrontReferralHost();
  161. }elseif( UrlService::instance()->checkDomainIsShare() ){ //检测是不是分享活动域名
  162. $result = UrlService::instance()->checkShareHost();
  163. } else {
  164. UserService::instance()->getRunTimeObject()->urlType = OpenPlatformConstants::URL_TYPE_ADMIN;
  165. $result = $this->getReturn();
  166. }
  167. return $result;
  168. }
  169. /**
  170. * 检查域名是支付域名
  171. * @return bool
  172. */
  173. public function checkDomainIsPay()
  174. {
  175. $host = $this->getSourceDomain();
  176. $payHosts = OfficialAccountsService::instance()->getWxpayModel()->getHosts();
  177. return in_array($host, $payHosts);
  178. }
  179. /**
  180. * 检查域名是入口域名
  181. * @return bool
  182. */
  183. public function checkDomainIsEntry()
  184. {
  185. $host = get_host_no_port();
  186. $entryHosts = OfficialAccountsService::instance()->getEntryHostModel()->getHosts();
  187. return in_array($host, $entryHosts);
  188. }
  189. /**
  190. * 检查域名是入口域名
  191. * @return bool
  192. */
  193. public function checkDomainIsReferral()
  194. {
  195. $host = get_host_no_port();
  196. if(preg_match("/^wx\w+/i", $host, $matches)){
  197. return $matches[0];
  198. }
  199. if(preg_match("/^px-\w{5}-(wx\w+)-/i", $host, $matches)){
  200. return $matches[1];
  201. }
  202. return "";
  203. }
  204. /**
  205. * @return bool
  206. */
  207. public function checkDomainIsShare()
  208. {
  209. $host = get_host_no_port();
  210. return (bool)strstr(Config::get('site.share_domain'),$host);
  211. }
  212. /**
  213. * 处理支付域名逻辑
  214. * @return \app\main\model\object\ReturnObject
  215. */
  216. public function checkFrontPayHost()
  217. {
  218. UserService::instance()->getRunTimeObject()->urlType = OpenPlatformConstants::URL_TYPE_PAY;
  219. try {
  220. $site = Config::get("site");
  221. $host = get_host_no_port();
  222. //如果是支付域名并且不是Ajax请求清空Cookie,以防JS获取错误参数
  223. if (!Request::instance()->isAjax()) {
  224. foreach ($_COOKIE as $key => $val) {
  225. if (in_array($key, ['user_id', 'openid', 'open_id', 'app_id'])) {
  226. continue;
  227. } else {
  228. Cookie::set($key, null);
  229. }
  230. }
  231. }
  232. //todo user缓存的设置
  233. UserService::instance()->setUserCache(Request::instance()->get('user_id'));
  234. $urlAdminId = UserService::instance()->getAdminId()->data;
  235. $urlChannelId = UserService::instance()->getUserInfo()->channel_id;
  236. if (!$urlAdminId) {
  237. return $this->setData($site['scheme'] . '://' . $site['url_root'])->setCode(ErrorCodeConstants::REDIRECT)->getReturn();
  238. }
  239. $configData = AdminService::instance()->getAdminConfigModel()->getAdminInfoAll($urlChannelId);
  240. //检测支付域名是否一致,如果支付域名不一致,重新跳转到对的支付域名,如果是自定义菜单支付域名时不用跳转
  241. if (!FufenService::instance()->checkTestParams()->data && $configData['wxpay_pay_host'] != $host) {
  242. //为true需要跳转
  243. $isDiyPayHost = true;
  244. if ($configData['menuwxpay_host'] == $host) {
  245. $isDiyPayHost = false;
  246. } else {
  247. if (FufenService::instance()->checkWxpayHostIsFufen($host)->data) {
  248. $isDiyPayHost = false;
  249. }
  250. }
  251. if ($isDiyPayHost) {
  252. $agent_id = $this->getUserAgentId()->data;
  253. if ($agent_id) {
  254. $url = parse_url(get_url_no_port());
  255. if (isset($url['query'])) {
  256. $params = $this->getUrlParams($url['query'] ?? '');
  257. } else {
  258. $params = [];
  259. }
  260. $params['agent_id'] = $agent_id;
  261. if (isset($params['code'])) {
  262. unset($params['code']);
  263. }
  264. $redirectUrl = $site['scheme'] . '://' . $configData['wxpay_pay_host'] . $url['path'] ?? '/';
  265. if (!empty($params)) {
  266. $redirectUrl = $redirectUrl . '?' . http_build_query($params);
  267. }
  268. return $this->setData($redirectUrl)->setCode(ErrorCodeConstants::REDIRECT)->getReturn();
  269. } else {
  270. $redirectUrl = $site['scheme'] . '://' . $configData['wxpay_pay_host'] . get_url_no_port();
  271. $redirect = $this->removeUrlParam('code', $redirectUrl);
  272. return $this->setData($redirect)->setCode(ErrorCodeConstants::REDIRECT)->getReturn();
  273. }
  274. }
  275. }
  276. Cookie::forever('channel_id', $urlChannelId);
  277. UserService::instance()->getRunTimeObject()->adminId = $urlAdminId;
  278. UserService::instance()->getRunTimeObject()->channelId = $urlChannelId;
  279. return $this->getReturn();
  280. } catch (\Exception $e) {
  281. return $this->getExceptionReturn($e);
  282. }
  283. }
  284. /**
  285. * 处理分享活动域名
  286. * @return \app\main\model\object\ReturnObject
  287. */
  288. public function checkShareHost()
  289. {
  290. // UserService::instance()->getRunTimeObject()->urlType = 3;
  291. try {
  292. $site = Config::get("site");
  293. if (!Request::instance()->isAjax()) {
  294. foreach ($_COOKIE as $key => $val) {
  295. if (in_array($key, ['user_id', 'openid', 'open_id', 'app_id'])) {
  296. continue;
  297. } else {
  298. Cookie::set($key, null);
  299. }
  300. }
  301. }
  302. //todo user缓存的设置
  303. UserService::instance()->setUserCache(Request::instance()->get('user_id'));
  304. $urlAdminId = UserService::instance()->getAdminId()->data;
  305. $urlChannelId = UserService::instance()->getUserInfo()->channel_id;
  306. if (!$urlAdminId) {
  307. return $this->setData($site['scheme'] . '://' . $site['url_root'])->setCode(ErrorCodeConstants::REDIRECT)->getReturn();
  308. }
  309. AdminService::instance()->getAdminConfigModel()->getAdminInfoAll($urlChannelId);
  310. Cookie::forever('channel_id', $urlChannelId);
  311. UserService::instance()->getRunTimeObject()->adminId = $urlAdminId;
  312. UserService::instance()->getRunTimeObject()->channelId = $urlChannelId;
  313. return $this->getReturn();
  314. } catch (\Exception $e) {
  315. return $this->getExceptionReturn($e);
  316. }
  317. }
  318. /**
  319. * 入口域名处理方法
  320. * @return \app\main\model\object\ReturnObject
  321. */
  322. public function checkFrontEntryHost()
  323. {
  324. try {
  325. $site = Config::get("site");
  326. $channel_id = Request::instance()->get('channel_id');
  327. if (!$channel_id) { //如果没带渠道商,归到自己渠道商上
  328. //先用kl的测试
  329. $klChannelIds = $site['change_ids'] ?? false;
  330. if ($klChannelIds) {
  331. $arrchange = explode(',', $klChannelIds);
  332. $channel_id = $arrchange[array_rand($arrchange, 1)];
  333. $configData = AdminService::instance()->getAdminConfigModel()->getAdminInfoAll($channel_id);
  334. if (!empty($configData)) {
  335. $redirectUrl = Config::get('site.scheme') . '://' . $configData['appid'] . '.' . $configData['ophost_host'] . get_url_no_port();
  336. $this->setData($redirectUrl)->setCode(ErrorCodeConstants::REDIRECT);
  337. } else {
  338. $this->setData($site['scheme'] . '://' . $site['url_root'])->setCode(ErrorCodeConstants::REDIRECT);
  339. }
  340. }
  341. } else { //如果有channel_id
  342. //获取该渠道商配置信息
  343. $configData = AdminService::instance()->getAdminConfigModel()->getAdminInfoAll($channel_id);
  344. if (!empty($configData)) {
  345. $redirectUrl = Config::get('site.scheme') . '://' . $configData['appid'] . '.' . $configData['ophost_host'] . get_url_no_port();
  346. $this->setData($redirectUrl)->setCode(ErrorCodeConstants::REDIRECT);
  347. } else {
  348. $this->setData($site['scheme'] . '://' . $site['url_root'])->setCode(ErrorCodeConstants::REDIRECT);
  349. }
  350. }
  351. return $this->getReturn();
  352. } catch (\Exception $e) {
  353. return $this->getExceptionReturn($e);
  354. }
  355. }
  356. /**
  357. * 处理推广链接
  358. * @return $this|\app\main\model\object\ReturnObject
  359. */
  360. public function checkFrontReferralHost()
  361. {
  362. UserService::instance()->getRunTimeObject()->urlType = OpenPlatformConstants::URL_TYPE_SPREAD;
  363. $result = UrlService::instance()->unlimitSecondaryDomain();
  364. if ($result->code != ErrorCodeConstants::SUCCESS) {
  365. return $result;
  366. }
  367. $host = get_host_no_port();
  368. $appId = $this->checkDomainIsReferral();
  369. $site = Config::get("site");
  370. try{
  371. if ($appId) {
  372. UserService::instance()->getRunTimeObject()->appId = $appId;
  373. $channelData = AdminService::instance()->getAdminConfigModel()->getAdminInfoByAppId($appId); //得到此渠道的配置信息 adminInfoAll
  374. $admin_id = $channelData['admin_id'];
  375. $hostArr = explode('.', $host);
  376. array_shift($hostArr);
  377. $agent_id = $this->getUserAgentId()->data;
  378. //跳转默认业务域名,如果推广域名和当前渠道商业务域名不一样,如果是自定义菜单域名时不用跳转
  379. if (strpos($host,'px-') !== 0 && implode('.', $hostArr) != $channelData['ophost_host']) {
  380. $isDiyMenu = true;
  381. if (isset($channelData['menuophost']) && $channelData['menuophost'] == implode('.', $hostArr)) {
  382. $isDiyMenu = false;
  383. }
  384. if ($isDiyMenu) {
  385. if ($agent_id) {
  386. $url = parse_url(get_url_no_port());
  387. if (isset($url['query'])) {
  388. $params = $this->getUrlParams($url['query'] ?? '');
  389. } else {
  390. $params = [];
  391. }
  392. $params['agent_id'] = $agent_id;
  393. if (isset($params['code'])) {
  394. unset($params['code']);
  395. }
  396. $redirectUrl = $site['scheme'] . '://' . $appId . '.' . $channelData['ophost_host'] . $url['path'] ?? '/';
  397. if (!empty($params)) {
  398. $redirectUrl = $redirectUrl . '?' . http_build_query($params);
  399. }
  400. $this->setData($redirectUrl)->setCode(ErrorCodeConstants::REDIRECT);
  401. } else {
  402. $redirectUrl = $site['scheme'] . '://' . $appId . '.' . $channelData['ophost_host'] . get_url_no_port();
  403. $this->setData($redirectUrl)->setCode(ErrorCodeConstants::REDIRECT);
  404. }
  405. return $this->getReturn();
  406. }
  407. }
  408. UserService::instance()->getRunTimeObject()->channelId = $admin_id;
  409. UserService::instance()->getRunTimeObject()->adminId = $agent_id ?: $admin_id;
  410. UserService::instance()->getRunTimeObject()->referralId = $this->getUserReferralId()->data;
  411. //设置推广id和代理商id
  412. UrlService::instance()->setUserAgentId((int)Request::instance()->get('agent_id'));
  413. UrlService::instance()->setUserReferralId((int)Request::instance()->get('referral_id'));
  414. } else {
  415. $redirectUrl = $site['scheme'] . '://' . $site['url_root'];
  416. return $this->setData($redirectUrl)->setCode(ErrorCodeConstants::REDIRECT)->getReturn();
  417. }
  418. return $this->getReturn();
  419. }catch (\Exception $e){
  420. return $this->getExceptionReturn($e);
  421. }
  422. }
  423. /**
  424. * 删除URL指定参数
  425. * @param $paramNames
  426. * @param $url
  427. * @return string
  428. */
  429. public function removeUrlParam($paramNames, $url)
  430. {
  431. $paramNames = (array)$paramNames;
  432. $arr = [];
  433. if (strpos($url, "?")) {
  434. $urlInfo = explode("?", $url);
  435. parse_str($urlInfo[1], $arr);
  436. foreach ($paramNames as $name) {
  437. if (array_key_exists($name, $arr)) {
  438. unset($arr[$name]);
  439. }
  440. }
  441. return $urlInfo[0] . "?" . http_build_query($arr);
  442. }
  443. return $url;
  444. }
  445. /**
  446. * 推广链接处理
  447. * @throws \Exception
  448. */
  449. public function processReferral()
  450. {
  451. $urlType = UserService::instance()->getRunTimeObject()->urlType;
  452. $bookId = Request::instance()->get('book_id');
  453. $urlAgentId = $this->getUserAgentId()->data;
  454. $urlChannelId = UserService::instance()->getRunTimeObject()->channelId;
  455. $userId = UserService::instance()->getUserInfo()->id;
  456. $site = Config::get("site");
  457. //书籍屏蔽
  458. if ($bookId && $urlType != OpenPlatformConstants::URL_TYPE_ADMIN) {
  459. $isLimited = BookService::instance()->getBookLimit()->hasLimit($urlAgentId, $urlChannelId, $bookId, $userId);
  460. if ($isLimited) {
  461. return $this->setData(UrlConstants::get_page_404())->setCode(ErrorCodeConstants::REDIRECT)->getReturn();
  462. }
  463. }
  464. /**
  465. * 处理推广链接UV
  466. */
  467. if ($urlType == OpenPlatformConstants::URL_TYPE_SPREAD && ($referral_id = Request::instance()->get('referral_id')) && UserService::instance()->isLogin()) {
  468. //添加推广链接用户白名单
  469. WhiteList::addReferralUser($referral_id, UserService::instance()->getUserInfo()->id);
  470. $dotData = new DotObject();
  471. $dotData->action_type = MqConstants::ROUTING_KEY_REFERRAL_UV;
  472. $dotData->referral_id = $referral_id;
  473. $dotData->user_id = UserService::instance()->getUserInfo()->id;
  474. $dotData->event_time = UserService::instance()->getRunTimeObject()->requestTime;
  475. MqService::instance()->sendMessage($dotData);
  476. $oAna = new AnalysisObject();
  477. $oAna->type = KafkaDotConstants::TYPE_VISIT;
  478. $oAna->event_time = $dotData->event_time;
  479. $oAna->user_from = [
  480. 'referral_id' => $referral_id
  481. ];
  482. KafkaDotService::instance()->sendMsg($userId, $oAna);
  483. }
  484. //推广链接禁用时,跳转到首页
  485. if ($urlType == OpenPlatformConstants::URL_TYPE_SPREAD && Request::instance()->has('referral_id')) {
  486. if ($referral = UrlService::instance()->getReferralModel()->getone((int)Request::instance()->param('referral_id'), false)) {
  487. if (is_array($referral) && isset($referral['state']) && !$referral['state']) {
  488. $redirect = $site['scheme'] . '://' . $_SERVER['HTTP_HOST'] . '/index/index';
  489. return $this->setData($redirect)->setCode(ErrorCodeConstants::REDIRECT)->getReturn();
  490. }
  491. }
  492. }
  493. //如果是302短链,跳转对应域名
  494. if ($urlType == OpenPlatformConstants::URL_TYPE_SPREAD && Request::instance()->has('referral_id') && Request::instance()->has('short_id') && Request::instance()->has('re')) {
  495. if ($referral = UrlService::instance()->getReferralModel()->getone((int)Request::instance()->param('referral_id'), false)) {
  496. if (in_array($referral['type'], [UrlConstants::REFERRAL_READING_PAGE_SPREAD, UrlConstants::REFERRAL_GROUND_PAGE_SPREAD]) && !intval($referral['push'])) { //阅读页与落地页推广时跳,并且是外派
  497. $re_params = Request::instance()->param();
  498. if (isset($re_params['short_id'])) {
  499. unset($re_params['short_id']);
  500. }
  501. if (isset($re_params['re'])) {
  502. unset($re_params['re']);
  503. }
  504. $re_params['user_id'] = UserService::instance()->getUserInfo()->id;
  505. $re_params['open_id'] = UserService::instance()->getUserInfo()->openid;
  506. $redirect = Request::instance()->param('re') . '/index/book/chapter?' . http_build_query($re_params);
  507. return $this->setData($redirect)->setCode(ErrorCodeConstants::REDIRECT)->getReturn();
  508. }
  509. }
  510. }
  511. return $this->getReturn();
  512. }
  513. /**
  514. * 获取URL参数
  515. * @param $query
  516. * @return array
  517. */
  518. function getUrlParams($query)
  519. {
  520. $queryParts = explode('&', $query);
  521. $params = [];
  522. if ($queryParts) {
  523. foreach ($queryParts as $param) {
  524. $item = explode('=', $param);
  525. $params[$item[0]] = $item[1];
  526. }
  527. }
  528. return $params;
  529. }
  530. public function getActionUrl()
  531. {
  532. $moduleName = Request::instance()->module();
  533. $controllerName = strtolower(Request::instance()->controller());
  534. $actionName = strtolower(Request::instance()->action());
  535. $urlAction = $moduleName . '/' . $controllerName . '/' . $actionName; //当前访问模块链接
  536. return UserService::instance()->getRunTimeObject()->urlAction = $urlAction;
  537. }
  538. /**
  539. * 检测action
  540. * @param $list
  541. * @return bool
  542. */
  543. public function checkActionMatch($list)
  544. {
  545. $list = (array)$list;
  546. $action = Request::instance()->action();
  547. return ArrayHelper::match($action, $list);
  548. }
  549. /**
  550. * @param $bookId
  551. * @param $chapterId
  552. * @param string $referralId
  553. * @return bool
  554. * @throws \think\db\exception\DataNotFoundException
  555. * @throws \think\db\exception\ModelNotFoundException
  556. * @throws \think\exception\DbException
  557. */
  558. public function checkIfDaoFen($bookId, $chapterId, $referralId = '')
  559. {
  560. $dofenChapter = Config::get('site.book_guide_chapter_idx');
  561. if($referralId){
  562. $dofenChapter = $this->getReferralModel()->getDaoFenChapterId($referralId);
  563. }
  564. $book = BookService::instance()->getBookModel()->where('id', '=', $bookId)->find();
  565. if($book && $book['attent_chapter_order']){
  566. $dofenChapter = $book['attent_chapter_order'];
  567. }
  568. return $dofenChapter <= $chapterId;
  569. }
  570. public function getPayUrl($redirect, $book_id, $chapter_id){
  571. $admin_info = UserService::instance()->getRunTimeObject()->adminConfig;
  572. $runtime = UserService::instance()->getRunTimeObject();
  573. $params['redirect'] = $redirect;
  574. $params['admin_id'] = $runtime->adminId;
  575. $params['channel_id'] = $runtime->channelId;
  576. if ($user_id = UserService::instance()->getUserInfo()->id) {
  577. $params['user_id'] = $user_id;
  578. } elseif (Cookie::has('visitor')) {
  579. $params['visitor'] = Cookie::get('visitor');
  580. }
  581. if (Cookie::has('referral_id')) {
  582. $params['referral_id'] = Cookie::get('referral_id');
  583. }
  584. $params['book_id'] = $book_id;
  585. $params['chapter_id'] = $chapter_id;
  586. //有菜单支付域名时,跳转菜单支付域名
  587. $menuophost = $admin_info['menuophost'] ?? null;
  588. $menuwxpay_host = $admin_info['menuwxpay_host'] ?? null;
  589. if ($menuophost && $menuwxpay_host && $menuophost == getCurrentOphost()) {
  590. return $this->setData(Config::get('site.scheme') . '://' . $admin_info['menuwxpay_host'] . '/index/recharge/pay?' . http_build_query($params))->getReturn();
  591. } else {
  592. return $this->setData(Config::get('site.scheme') . '://' . $admin_info['wxpay_pay_host'] . '/index/recharge/pay?' . http_build_query($params))->getReturn();
  593. }
  594. }
  595. /**
  596. * 设置代理商ID
  597. * @param $requestAgentId
  598. * @return \app\main\model\object\ReturnObject
  599. */
  600. public function setUserAgentId($requestAgentId)
  601. {
  602. if (!$requestAgentId || !UserService::instance()->isLogin()) {
  603. return $this->getReturn();
  604. }
  605. try {
  606. //登录状态
  607. $channel_id = UserService::instance()->getUserInfo()->channel_id;
  608. $user = UserService::instance()->getUserInfo(true);
  609. $checkBelongs = AdminService::instance()->checkAgentIdBelongsToChannelId($requestAgentId, $channel_id)->data;
  610. if($checkBelongs && $user->agent_id != $requestAgentId){
  611. $update = ['agent_id' => $requestAgentId];
  612. UserService::instance()->update($update, ['id' => $user->id]);
  613. // UserService::instance()->getUserModel()->setConnect($user->id)->update($update, ['id' => $user->id]);
  614. // UserService::instance()->updateRedisUserCache($user->id, $update);
  615. }
  616. } catch (\Exception $e) {
  617. LogService::exception($e);
  618. }
  619. return $this->getReturn();
  620. }
  621. /**
  622. * 设置推广ID
  623. * @param $requestReferralId
  624. * @return \app\main\model\object\ReturnObject
  625. */
  626. public function setUserReferralId($requestReferralId)
  627. {
  628. $user = UserService::instance()->getUserInfo();
  629. if (!$requestReferralId || !UserService::instance()->isLogin() || $requestReferralId == $user->referral_id) {
  630. return $this->getReturn();
  631. }
  632. try {
  633. $update = $this->getUserReferralIdUpdate($requestReferralId)->data;
  634. if ($update) {
  635. UserService::instance()->update($update, ['id' => $user->id]);
  636. // UserService::instance()->getUserModel()->setConnect($user->id)->update($update, ['id' => $user->id]);
  637. // UserService::instance()->updateRedisUserCache($user->id, $update);
  638. }
  639. } catch (\Exception $e) {
  640. return $this->getExceptionReturn($e);
  641. }
  642. return $this->getReturn();
  643. }
  644. /**
  645. * @param $requestReferralId
  646. * @return \app\main\model\object\ReturnObject
  647. */
  648. public function getUserReferralIdUpdate($requestReferralId)
  649. {
  650. $checkBelongs = AdminService::instance()->checkReferralIdBelongsToChannelId($requestReferralId)->data;
  651. $update = [];
  652. if($checkBelongs){
  653. $referral_id_permanent = UserService::instance()->getUserInfo()->referral_id_permanent;
  654. $referral_id = UserService::instance()->getUserInfo()->referral_id;
  655. $update = [];
  656. if ($requestReferralId != $referral_id) {
  657. $update = [
  658. 'referral_id' => $requestReferralId,
  659. ];
  660. }
  661. if ($this->checkCustomExtReferralMatch()->data && !$this->checkCustomExtReferralMatch('', $requestReferralId)->data) {
  662. $update['ext'] = '';
  663. }
  664. $referral_info_request = UrlService::instance()->getReferralModel()->getone($requestReferralId, false);
  665. if ($referral_id_permanent) {
  666. $referral_info_permanent = UrlService::instance()->getReferralModel()->getone($referral_id_permanent, false);
  667. } else {
  668. $referral_info_permanent = false;
  669. }
  670. $referral_info = UrlService::instance()->getReferralModel()->getone($referral_id, false);
  671. //没有推广信息的情况
  672. if(!$referral_info_permanent && !$referral_info){
  673. $update['referral_id_permanent'] = $requestReferralId;
  674. //没有推广信息时处理关注打点
  675. $user = UserService::instance()->getUserInfo();
  676. if ($ext = Request::instance()->param('ext')) {
  677. $ext_data = json_decode($ext, true);
  678. $referral = UrlService::instance()->getReferralModel()->getone($requestReferralId, false);
  679. if ($ext_data['mark'] == MarkConstants::MARK_RESOURCE && ($user->is_subscribe || $user->subscription_extend) && $referral['push'] == UrlConstants::REFERRAL_PUSH_OUT && time() - $user->createtime < 1200) {
  680. $dotData = new DotObject();
  681. //打点信息初始化
  682. $dotData->channel_id = $user->channel_id;
  683. $dotData->user_id = $user->id;
  684. $dotData->event_time = $user->subscribe_time;
  685. if ($user->is_first_unfollow != UserConstants::USER_IS_FIRST_UNFOLLOW_NEVER) {
  686. $dotData->is_first_follow = UserConstants::USER_IS_FIRST_FOLLOW_NO;
  687. } else {
  688. $dotData->is_first_follow = UserConstants::USER_IS_FIRST_FOLLOW_YES;
  689. }
  690. $dotData->action_type = MqConstants::ROUTING_KEY_SUBSCRIBE_REFERER;
  691. $dotData->type = MqConstants::MSG_TYPE_FOLLOW;
  692. $dotData->referral_id = $requestReferralId;
  693. MqService::instance()->sendMessage($dotData);
  694. $oAna = new AnalysisObject();
  695. $oAna->type = KafkaDotConstants::TYPE_SUBSCRIBE;
  696. $oAna->user_from = [
  697. 'referral_id' => $requestReferralId
  698. ];
  699. $oAna->event_time = $user->subscribe_time;
  700. KafkaDotService::instance()->sendMsg($user->id, $oAna);
  701. }
  702. }
  703. }else{
  704. //$checkBelongs判断通过,则推广链接一定存在
  705. $requestGroupId = AdminService::instance()->getAuthGroupAccessModel()->getGroupId($referral_info_request['admin_id']);
  706. $permanentGroupId = false;
  707. if ($referral_info_permanent) {
  708. $permanentGroupId = AdminService::instance()->getAuthGroupAccessModel()->getGroupId($referral_info_permanent['admin_id']);
  709. }
  710. //都是代理商,且代理商不同
  711. if ($referral_info_permanent['admin_id'] != $referral_info_request['admin_id'] && $requestGroupId == AdminConstants::ADMIN_GROUP_ID_AGENT && $permanentGroupId == AdminConstants::ADMIN_GROUP_ID_AGENT) {
  712. $update['referral_id_permanent'] = $requestReferralId;
  713. }
  714. }
  715. }
  716. return $this->setData($update)->getReturn();
  717. }
  718. /**
  719. * 获取推广链接id
  720. * @return \app\main\model\object\ReturnObject
  721. */
  722. public function getUserReferralId()
  723. {
  724. try{
  725. $referralId = 0;
  726. //从用户表获取
  727. if (UserService::instance()->getUserInfo()->referral_id) {
  728. $referralId = UserService::instance()->getUserInfo()->referral_id;
  729. }elseif(Request::instance()->get('referral_id')){
  730. $referralId = Request::instance()->get('referral_id');
  731. }
  732. if ($referralId && UserService::instance()->isLogin()) {
  733. $this->setUserReferralId($referralId);
  734. }
  735. return $this->setData($referralId)->getReturn();
  736. }catch (\Exception $e){
  737. LogService::exception($e);
  738. return $this->setData(0)->getReturn();
  739. }
  740. }
  741. /**
  742. * 获取代理商id
  743. * @return \app\main\model\object\ReturnObject
  744. */
  745. public function getUserAgentId()
  746. {
  747. try {
  748. $agentId = 0;
  749. //从用户表获取
  750. if (UserService::instance()->getUserInfo()->agent_id) {
  751. $agentId = UserService::instance()->getUserInfo()->agent_id;
  752. }elseif(Request::instance()->get('agent_id')){
  753. $agentId = Request::instance()->get('agent_id');
  754. }
  755. if ($agentId && UserService::instance()->isLogin()) {
  756. $channel_id = UserService::instance()->getUserInfo()->channel_id;
  757. if (!AdminService::instance()->checkAgentIdBelongsToChannelId($agentId, $channel_id)->data) {
  758. $agentId = 0;
  759. if (UserService::instance()->isLogin()) {
  760. UserService::instance()->update(['agent_id' => 0]);
  761. // UserService::instance()->getUserModel()->setConnect($user_id)
  762. // ->where('id', $user_id)
  763. // ->update(['agent_id' => 0]);
  764. // UserService::instance()->updateRedisUserCache($user_id, ['agent_id' => 0]);
  765. }
  766. } else {
  767. if (UserService::instance()->getUserInfo()->agent_id != $agentId) {
  768. UserService::instance()->update(['agent_id' => $agentId]);
  769. // $user_id = UserService::instance()->getUserInfo()->id;
  770. // UserService::instance()->getUserModel()->setConnect($user_id)
  771. // ->where('id', $user_id)
  772. // ->update(['agent_id' => $agentId]);
  773. // UserService::instance()->updateRedisUserCache($user_id, ['agent_id' => $agentId]);
  774. }
  775. }
  776. }
  777. return $this->setData($agentId)->getReturn();
  778. } catch (\Exception $e) {
  779. LogService::exception($e);
  780. return $this->setData(0)->getReturn();
  781. }
  782. }
  783. public function delUrlParams($url, $params)
  784. {
  785. $arr = parse_url($url);
  786. $old_params = [];
  787. if (isset($arr['query']) && !empty($arr['query'])) {
  788. $queryParts = explode('&', $arr['query']);
  789. if ($queryParts) {
  790. foreach ($queryParts as $param) {
  791. $item = explode('=', $param);
  792. if (count($item) == 2) {
  793. $old_params[$item[0]] = $item[1];
  794. }
  795. }
  796. }
  797. }
  798. if (is_string($params)) {
  799. if (isset($old_params[$params])) {
  800. unset($old_params[$params]);
  801. }
  802. } elseif (is_array($params)) {
  803. foreach ($params as $item) {
  804. if (isset($old_params[$item])) {
  805. unset($old_params[$item]);
  806. }
  807. }
  808. }
  809. $tmp_url = empty($arr['scheme']) ? 'http' : $arr['scheme'] . '://' . $arr['host'] . $arr['path'];
  810. if (!empty($old_params)) {
  811. $i = 0;
  812. foreach ($old_params as $k => $v) {
  813. $tmp_url = $tmp_url . ($i == 0 ? '?' : '&') . $k . '=' . $v;
  814. $i++;
  815. }
  816. }
  817. return $tmp_url;
  818. }
  819. public function getUrlNoPort($domain = null)
  820. {
  821. $url = Request::instance()->url($domain);
  822. $url = strtolower(preg_replace('/:\d+$/', '', trim($url))); //去除 :端口 结束的
  823. return preg_replace('/:\d+\//', '/', trim($url)); //去除 :端口/
  824. }
  825. /**
  826. * 推广链接域名替换
  827. * @param $channel_id
  828. * @param $url
  829. * @param bool $replaceHost
  830. * @return \app\main\model\object\ReturnObject
  831. */
  832. public function replaceReferralHost($channel_id, $url, $replaceHost = true)
  833. {
  834. $host = AdminService::instance()->getAdminReferralDomain($channel_id)->data;
  835. if ($replaceHost) {
  836. $this->setData(str_replace([$host['menu_ophost_host'], $host['ophost_host']], ['{$ophost}', '{$ophost}'], $url));
  837. } else {
  838. $this->setData(str_replace('{$ophost}', $host['menu_ophost_host'], $url));
  839. }
  840. return $this->getReturn();
  841. }
  842. /**
  843. * 无限二级域名设置
  844. * @return \app\main\model\object\ReturnObject
  845. **/
  846. public function unlimitSecondaryDomain(){
  847. if (!Redis::instance()->get("unlimit_domain")) {
  848. return $this->getReturn();
  849. }
  850. $host=get_host_no_port();
  851. preg_match("/^px-(\w+)-(wx\w+)-(\d+)-(.*?)\.(.*?)$/i", $host, $matches);
  852. $appId = $this->checkDomainIsReferral();
  853. $path=get_url_no_port();
  854. if ($matches) {
  855. $sign = Request::instance()->get('sign');
  856. $cacheSign = Redis::instance()->get("cache:" . $matches[3]);
  857. if ($cacheSign && $cacheSign == $sign) {
  858. Redis::instance()->del("cache:" . $matches[3]);
  859. Cookie::set('user_id', $matches[3]);
  860. }
  861. $userId=UserService::instance()->getUserInfo()->id;
  862. if ($userId) {
  863. $cacheCode = $matches[1];
  864. $openId=UserService::instance()->getUserInfo()->openid;
  865. if (substr(md5($openId), 0, 5) != $matches[4]) {
  866. $url = $this->getUnlimitDomainOriginWxUrl()->data;
  867. return $this->setCode(ErrorCodeConstants::REDIRECT)->setData($url)->getReturn();
  868. }
  869. $redisCacheCode = Redis::instance()->get("DOMAIN:".$userId);
  870. if($redisCacheCode){
  871. if($redisCacheCode == $cacheCode){
  872. Redis::instance()->expire("DOMAIN:".$userId, $this->getUnlimitDomainExpire());
  873. return $this->getReturn();
  874. }else{
  875. $url = $this->getUnlimitDomainOriginWxUrl()->data;
  876. return $this->setCode(ErrorCodeConstants::REDIRECT)->setData($url)->getReturn();
  877. }
  878. }else{
  879. $code = substr(md5(uniqid()), 0, 5);
  880. Redis::instance()->setex("DOMAIN:" . $userId, $this->getUnlimitDomainExpire(), $code);
  881. $preHost = $appId.'.'.$matches[5];
  882. $newUrl = $this->getUnlimitDomain($code, $appId, $userId, $openId,$preHost . $path);
  883. return $this->setData($newUrl)->setCode(ErrorCodeConstants::REDIRECT)->getReturn();
  884. }
  885. } else {
  886. $url = $this->getUnlimitDomainOriginWxUrl()->data;
  887. return $this->setCode(ErrorCodeConstants::REDIRECT)->setData($url)->getReturn();
  888. }
  889. }else {
  890. $userId = UserService::instance()->getUserInfo()->id;
  891. if ($userId) {
  892. if ($userId == UserService::instance()->getUserInfo()->openid) {
  893. Cookie::delete('user_id');
  894. UserService::instance()->getRunTimeObject()->user = new UserObject();
  895. } else {
  896. $cacheCode = Redis::instance()->get("DOMAIN:" . $userId);
  897. if (!$cacheCode) {
  898. $cacheCode = substr(md5(uniqid()), 0, 5);
  899. Redis::instance()->setex("DOMAIN:" . $userId, $this->getUnlimitDomainExpire(), $cacheCode);
  900. }
  901. $openId = UserService::instance()->getUserInfo()->openid;
  902. $sign = md5(time());
  903. Redis::instance()->set("cache:" . $userId, $sign);
  904. if (stripos($path, '?') === false) {
  905. $path .= '?sign=' . $sign;
  906. } else {
  907. $path .= '&sign=' . $sign;
  908. }
  909. $newUrl = $this->getUnlimitDomain($cacheCode, $appId, $userId, $openId, $host . $path);
  910. return $this->setData($newUrl)->setCode(ErrorCodeConstants::REDIRECT)->getReturn();
  911. }
  912. }
  913. }
  914. return $this->getReturn();
  915. }
  916. /**
  917. * 获取无限二级的原始推广链接
  918. * @return \app\main\model\object\ReturnObject
  919. */
  920. public function getUnlimitDomainOriginWxUrl()
  921. {
  922. $url = get_url_no_port(true);
  923. $data = preg_replace("/px-(\w+)-(wx\w+)-(\d+)-(.*?)\.(.*?)$/i", '\2.\5', $url);
  924. return $this->setData($data)->getReturn();
  925. }
  926. /**
  927. * @return mixed 获取无限二级过期时间
  928. */
  929. public function getUnlimitDomainExpire()
  930. {
  931. return Env::get('app.unlimit_domain_expire', 3600);
  932. }
  933. /**
  934. * 获取无限二级链接
  935. * @param $cacheCode
  936. * @param $appId
  937. * @param $userId
  938. * @param $openId
  939. * @param $url
  940. * @return mixed
  941. */
  942. public function getUnlimitDomain($cacheCode, $appId, $userId, $openId, $url)
  943. {
  944. $url = str_replace($appId, 'px-' . $cacheCode . '-' . $appId . '-' . $userId . '-' . substr(md5($openId), 0, 5), $url);
  945. $url = $this->replace2fakeFirstDomain($appId, $url)->data;
  946. return $url;
  947. }
  948. /**
  949. * 虚假顶级域名替换
  950. * @param $appId
  951. * @param $url
  952. * @return \app\main\model\object\ReturnObject
  953. **/
  954. public function replace2fakeFirstDomain($appId, $url)
  955. {
  956. $channelData = AdminService::instance()->getAdminConfigModel()->getAdminInfoByAppId($appId); //得到此渠道的配置信息 adminInfoAll
  957. $host = AdminService::instance()->getAdminReferralDomain($channelData['admin_id'])->data;
  958. if(!$host['fakemenuophost_host'] && !$host['fakeophost_host']){
  959. //默认取Config
  960. $url = Config::get("site.scheme") . '://' . $url;
  961. }else{
  962. if($host['fakemenuophost_host'])
  963. {
  964. //菜单域名
  965. if(false !== strpos($url,$host['menu_ophost_host'])) $url = $host['fakemenuophost_scheme'] . "://" . str_replace($host['menu_ophost_host'],$host['fakemenuophost_host'],$url);
  966. }
  967. if($host['fakeophost_host']) {
  968. //业务域名
  969. if(false !== strpos($url,$host['ophost_host'])) $url = $host['fakeophost_scheme'] . "://" .str_replace($host['ophost_host'],$host['fakeophost_host'],$url);
  970. }
  971. }
  972. return $this->setData($url)->getReturn();
  973. }
  974. /**
  975. * @param $referralId
  976. * @param $ext
  977. * @return \app\main\model\object\ReturnObject
  978. */
  979. public function checkCustomExtReferralMatch($ext = '', $referralId = false)
  980. {
  981. $user = UserService::instance()->getUserInfo();
  982. if (!$referralId) {
  983. $referralId = $user->referral_id;
  984. }
  985. if (!$ext) {
  986. $ext = $user->ext;
  987. }
  988. if ($referralId && CustomService::instance()->checkExtIsCustom($ext)->data) {
  989. $cacheExt = 'RefExt:' . md5($ext);
  990. if ($cache = Redis::instance()->get($cacheExt)) {
  991. return $this->setData($cache == $referralId)->getReturn();
  992. }
  993. }
  994. return $this->setData(false)->getReturn();
  995. }
  996. }