Frontend.php 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. <?php
  2. namespace app\common\controller;
  3. use app\common\constants\BigData;
  4. use app\common\library\Ip;
  5. use app\common\library\Redis;
  6. use app\common\library\Ua;
  7. use app\common\library\WeChatObject;
  8. use app\common\model\AdminConfig;
  9. use app\common\service\BlacklistService;
  10. use app\common\service\BookService;
  11. use app\common\service\CampaignService;
  12. use app\common\service\LogService;
  13. use app\main\constants\AdConstants;
  14. use app\main\constants\CacheConstants;
  15. use app\main\constants\CampaignConstants;
  16. use app\main\constants\ErrorCodeConstants;
  17. use app\main\constants\KafkaDotConstants;
  18. use app\main\constants\MarkConstants;
  19. use app\main\constants\OpenPlatformConstants;
  20. use app\main\constants\UcCacheConstants;
  21. use app\main\constants\UrlConstants;
  22. use app\main\constants\UserConstants;
  23. use app\main\model\object\AnalysisObject;
  24. use app\main\model\object\UserObject;
  25. use app\main\service\ActivityService;
  26. use app\main\service\AdminService;
  27. use app\main\service\AppGuideService;
  28. use app\main\service\ClientAppService;
  29. use app\main\service\CustomService;
  30. use app\main\service\ExportFansService;
  31. use app\main\service\GdtMpApiService;
  32. use app\main\service\GdtService;
  33. use app\main\service\KafkaDotService;
  34. use app\main\service\OfficialAccountsEventService;
  35. use app\main\service\OpenPlatformService;
  36. use app\main\service\SmartPushDotService;
  37. use app\main\service\SubscripService;
  38. use app\main\service\ToutiaoNotifyService;
  39. use app\main\service\UcNotifyService;
  40. use app\main\service\UrlService;
  41. use app\main\service\UserService;
  42. use app\main\service\UserSilentService;
  43. use think\Config;
  44. use think\Controller;
  45. use think\Cookie;
  46. use think\exception\HttpException;
  47. use think\Hook;
  48. use think\Lang;
  49. use think\Log;
  50. use think\Request;
  51. use function GuzzleHttp\Psr7\parse_query;
  52. use app\common\service\UserVipExtendService;
  53. class Frontend extends Controller
  54. {
  55. /**
  56. * 前台用户系统
  57. * @var UserService | UserObject
  58. */
  59. protected $user = null;
  60. /**
  61. * 当前url访问类型 0未识别 1后台首页 2支付页 3推广页
  62. * @var int
  63. */
  64. protected $urlType = 0;
  65. /**
  66. * 当前访问链接隶属于哪个渠道商/代理商
  67. * @var null
  68. */
  69. protected $urlAdminId = null;
  70. protected $urlChannelId = null;
  71. protected $urlAgentId = null;
  72. protected $appid = null;
  73. /**
  74. * 布局模板
  75. * @var string
  76. */
  77. protected $layout = 'layout';
  78. /**
  79. * redis单例对象
  80. */
  81. protected $redis;
  82. /**
  83. * @var AdminConfig
  84. */
  85. protected $adminconfig;
  86. protected $groupId;
  87. /**
  88. * @var int 当前请求时间戳
  89. */
  90. protected $time = null;
  91. /**
  92. * @throws \Exception
  93. * @throws \think\Exception
  94. * @throws \think\db\exception\DataNotFoundException
  95. * @throws \think\db\exception\ModelNotFoundException
  96. * @throws \think\exception\DbException
  97. */
  98. public function _initialize()
  99. {
  100. //初始化基础变量
  101. $dycode = '';
  102. $prefix_dycode = '';
  103. $this->assign('prefix_dycode', $prefix_dycode);
  104. $this->assign('dycode', $dycode);
  105. //前端域名屏蔽
  106. $blacklistService = new BlacklistService();
  107. $blacklistService -> checkDomain($this->request);
  108. $time = $this->request->server('REQUEST_TIME');
  109. UserService::instance()->getRunTimeObject()->requestTime = $time;
  110. //登录前打点用户信息
  111. Log::info('OS:' . Ua::getOs() . ' UA:' . Ua::getUa() . ' NetType:' . Ua::getNetType() . ' IP:' . Ip::ip() . ' [' . Ip::str() . '] user_id:' . Cookie::get('user_id') . ' openid:' . Cookie::get('openid') . ' channel_id:' . Cookie::get('channel_id') . ' agent_id:' . Cookie::get('agent_id') . ' referral_id:' . Cookie::get('referral_id') . ' REMOTE_ADDR:' . (isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '') . ' HTTP_X_FORWARDED_FOR:' . (isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : ''));
  112. //渠道是否开启了广告功能
  113. $isAdPick = model("ChannelSpecialManage")->isWhite("ad_pick", Cookie::get('channel_id'));
  114. $this->assign('isAdPick', $isAdPick);
  115. $this->assign('g_os', Ua::getOs());
  116. $this->assign('openinstall_appkey', Config::get('site.openinstall_appkey')??''); //openinstall appkey
  117. //config('site.url_agent', 'm{0}.mp.koread.cn'); //测试用,上线删除
  118. $this->assign('log_host', Config::get('site.loghost')); //设置打点域名
  119. $this->assign('log_iframe_host', Config::get('site.logiframehost')??''); //设置打点域名
  120. $this->redis = Redis::instance();
  121. $this->assign('ad_latest_version', $this->redis->get(AdConstants::AD_LATEST_VERSION)); // 最新广告版本号
  122. //移除HTML标签
  123. $this->request->filter('strip_tags');
  124. $actionUrl = UrlService::instance()->getActionUrl();
  125. //传递APK下载地址
  126. $appGuideInfo = AppGuideService::instance()->getAppGuideInfo(Cookie::get('channel_id'));
  127. if($appGuideInfo && !empty($appGuideInfo['app_url'])){
  128. $apk_url = $appGuideInfo['app_url'];
  129. }else{
  130. $apk_url = Config::get('site.default_apk_url');
  131. }
  132. $this->assign('apk_url', $apk_url);
  133. $user_silent_data = [];
  134. // 判断是否为推广短链
  135. if (!in_array($actionUrl, OpenPlatformConstants::$ignoreUrlArr)) {
  136. /**
  137. * 配置项处理
  138. */
  139. $site = Config::get("site");
  140. $result = UrlService::instance()->checkFrontDomain();
  141. if ($result) {
  142. if ($result->code == ErrorCodeConstants::REDIRECT) {
  143. $this->redirect($result->data);
  144. }
  145. if ($result->code == ErrorCodeConstants::EXCEPTION){
  146. throw new HttpException(400, '异常错误,请重试');
  147. }
  148. }
  149. if (UserService::instance()->getRunTimeObject()->urlType == OpenPlatformConstants::URL_TYPE_ADMIN) {
  150. $this->layout = 'index_default';
  151. }
  152. $urlChannelId = UserService::instance()->getRunTimeObject()->channelId;
  153. //渠道信息
  154. $adminConfig = AdminService::instance()->getAdminConfigModel()->getAdminInfoAll($urlChannelId);
  155. UserService::instance()->getRunTimeObject()->adminConfig = $adminConfig;
  156. /**
  157. * 浏览器环境
  158. */
  159. if (!Config::get('app_debug') && !Ua::isWeiXin()) {
  160. if (UserService::instance()->getRunTimeObject()->urlType == OpenPlatformConstants::URL_TYPE_PAY) { //充值域名
  161. $this->redirect($site['scheme'] . '://' . $site['url_root']);
  162. } elseif (UserService::instance()->getRunTimeObject()->urlType == OpenPlatformConstants::URL_TYPE_SPREAD) { //推广域名 浏览器环境下显示二维码
  163. $this->view->assign('chapter', $adminConfig);
  164. $this->view->assign('isWeChat',Ua::isWeiXin());
  165. exit($this->view->fetch('index@layout/browser'));
  166. }
  167. }
  168. //动态初始化微信参数
  169. OpenPlatformService::instance()->initWxParams();
  170. //用户新建&登录
  171. $loginResult = UserService::instance()->frontUserLogin();
  172. if ($loginResult->code == ErrorCodeConstants::REDIRECT) {
  173. $this->assign('jumpUrl', $loginResult->data);
  174. exit($this->view->fetch('index@layout/jumpurl'));
  175. }
  176. //禁用用户,禁止访问
  177. if (UserService::instance()->isLogin()) {
  178. $user = UserService::instance()->getUserInfo();
  179. //更新porlardb用户拓展表ua字段ext_b: iOS=1,非iOS=2
  180. switch (Ua::getOs()){
  181. case 'iOS':
  182. $userUaVal = 2;
  183. break;
  184. default:
  185. $userUaVal = 1;
  186. break;
  187. }
  188. if (!Request::instance()->isAjax()) {
  189. UserVipExtendService::instance()->updateUserOs($user->id,$userUaVal);
  190. }
  191. if ((time() - (int)$user->subscribe_time) < CacheConstants::TOUTIAO_SUB_WINDOW) {
  192. //客户端缓存,支持橘子建站回传需求
  193. $clientCache = CacheConstants::getUserClientCache($user->id);
  194. if (!Redis::instance()->exists($clientCache)) {
  195. Redis::instance()->hMSet($clientCache, ['ip' => Ip::ip(), 'ua' => $_SERVER['HTTP_USER_AGENT']]);
  196. Redis::instance()->expire($clientCache, 86400);
  197. }
  198. if (!Redis::instance()->hGet($clientCache, 'reg')) {
  199. $type = ToutiaoNotifyService::instance()::ORANGE_EVENT_TYPE_NEW;
  200. ToutiaoNotifyService::instance()->OrangeNotify($adminConfig, $user, $type);
  201. Redis::instance()->hSet($clientCache, 'reg', 1);
  202. }
  203. if ($user->is_subscribe || $user->subscription_extend) {
  204. if ($link = ToutiaoNotifyService::instance()->checkCache(Ip::ip(), $_SERVER['HTTP_USER_AGENT'] ?? '', $adminConfig['appid'])->data) {
  205. //头条回传
  206. LogService::info('REF:'.$link);
  207. //添加支付缓存
  208. $cachePay = CacheConstants::getGuideWxPay($user->id);
  209. $expire = 86400;
  210. Redis::instance()->set($cachePay, $link, $expire);
  211. ToutiaoNotifyService::instance()->notify($link, $user->id);
  212. }
  213. if ($link = UcNotifyService::instance()->checkCache(Ip::ip(), $_SERVER['HTTP_USER_AGENT'] ?? '', $adminConfig['appid'])->data) {
  214. //uc回传
  215. LogService::info('UCREF:'.$link);
  216. //添加支付缓存
  217. $cachePay = UcCacheConstants::getGuideWxPay($user->id);
  218. $expire = 86400;
  219. Redis::instance()->set($cachePay, $link, $expire);
  220. UcNotifyService::instance()->notify($user, $link);
  221. }
  222. /* //gdt follow回传
  223. $gdtReportKey = 'GDTFR:'.$user->id;
  224. if (!Redis::instance()->exists($gdtReportKey)) {
  225. //不存在回传
  226. LogService::info("GDTEF:u:".$user->id . ':c:'.$adminConfig['admin_id']);
  227. GdtMpApiService::instance()->follow($adminConfig, ['url' => '', 'appid' => $adminConfig['appid'], 'openid' => $user->openid]);
  228. Redis::instance()->set($gdtReportKey, $user->id, CacheConstants::TOUTIAO_SUB_WINDOW);
  229. }*/
  230. }
  231. }
  232. //更新老用户活跃人数
  233. if (date('Ymd') != date('Ymd', UserService::instance()->getUserInfo()->createtime)) {
  234. $channelId = AdminService::instance()->getAdminExtendModel()->getChannelId(UserService::instance()->getUserInfo()->channel_id);
  235. $activeOld = CacheConstants::getOldUserActiveCacheKey($channelId);
  236. Redis::instance()->pfAdd($activeOld, UserService::instance()->getUserInfo()->id);
  237. Redis::instance()->expire($activeOld, 86400);
  238. }
  239. // 生成微信动态码,APP使用
  240. $prefix_dycode = ClientAppService::instance()->makeUserRegisterCode(UserService::instance()->getUserInfo()->channel_id, UserService::instance()->getUserInfo()->openid, true);
  241. $dycode = ClientAppService::instance()->makeUserRegisterCode(UserService::instance()->getUserInfo()->channel_id, UserService::instance()->getUserInfo()->openid);
  242. $this->assign('prefix_dycode', $prefix_dycode);
  243. $this->assign('dycode', $dycode);
  244. $ext = $this->request->param('ext');
  245. //打点MQ
  246. if($ext && json_decode($ext)){
  247. Cookie::set('ext', $ext);
  248. $update = ['ext' => $ext];
  249. if (UrlService::instance()->checkCustomExtReferralMatch()->data && !UrlService::instance()->checkCustomExtReferralMatch($ext)->data) {
  250. $update['referral_id'] = '';
  251. }
  252. $ext_data = json_decode($ext, true);
  253. $oAna = new AnalysisObject();
  254. $oAna->user_from = [
  255. "mark" => $ext_data['mark'], // 用于区分 客服消息、模板消息、书单、智能推送、自定义二维码 等
  256. "push_id" => $ext_data['push_id'] ?? 0,
  257. "push_idx" => $ext_data['push_idx'] ?? BigData::DEFAULT_PUSH_IDX,
  258. "push_time" => $ext_data['push_time'] ?? time(), // 10位时间戳
  259. ];
  260. $oAna->type = [KafkaDotConstants::TYPE_VISIT];
  261. $oAna->event_time = $time;
  262. //关注时间小于2小时对ext加关注
  263. if ($ext_data['mark'] == MarkConstants::MARK_REPLY_PRE_RESOURCE && time() - UserService::instance()->getUserInfo()->subscribe_time < 7200 && !UserService::instance()->getUserInfo()->ext) {
  264. $oAna->type[] = KafkaDotConstants::TYPE_SUBSCRIBE;
  265. $dotData = SmartPushDotService::instance()->generateSubData(
  266. $ext_data['mark'],
  267. $ext_data['push_id'] ?? 0,
  268. $ext_data['push_time'] ?? time(),
  269. UserService::instance()->getUserInfo()->id
  270. );
  271. SmartPushDotService::instance()->dotSmartPushInfo($dotData);
  272. }
  273. KafkaDotService::instance()->sendMsg(UserService::instance()->getUserInfo()->id, $oAna);
  274. UserService::instance()->update($update);
  275. $dotData = SmartPushDotService::instance()->generateDotData(
  276. $ext_data['mark'],
  277. $ext_data['push_id'] ?? 0,
  278. $ext_data['push_idx'] ?? BigData::DEFAULT_PUSH_IDX,
  279. $ext_data['push_time'] ?? time(),
  280. time(),
  281. array_merge(['type' => 1, 'user_id' => UserService::instance()->getUserInfo()->id], $ext_data)
  282. );
  283. SmartPushDotService::instance()->dotSmartPushInfo($dotData);
  284. if (CustomService::instance()->checkExtIsCustom($ext)->data) {
  285. //是客服消息
  286. UserService::instance()->setOtherDataToRedis(UserService::instance()->getUserInfo()->id, ['last_custom_id' => $ext_data['push_id']]);
  287. }
  288. }
  289. $state = UserService::instance()->getUserInfo()->state;
  290. if ($state == UserConstants::USER_STATE_DISABLE) {
  291. $this->redirect(UrlConstants::get_page_404());
  292. }
  293. }
  294. else {
  295. if (UserService::instance()->getRunTimeObject()->urlType == OpenPlatformConstants::URL_TYPE_SPREAD) {
  296. throw new HttpException(400, '异常错误,请重试');
  297. }
  298. }
  299. $this->assign('prefix_dycode', $prefix_dycode);
  300. $this->assign('dycode', $dycode);
  301. //region 处理静默关注逻辑
  302. $silent_default_channel = Config::get('site.silent_default_channel');
  303. // $silentFlag 校验渠道是否开启静默授权
  304. $silentFlag = UserSilentService::instance()->silentChannel(Cookie::get('channel_id'));
  305. LogService::info('F:silent:静默关注逻辑:channel_id:' . Cookie::get('channel_id')
  306. . ",user_id:" . Cookie::get('user_id')
  307. . ",openid:" . Cookie::get('openid')
  308. . ',istwice:' . $this->request->param('istwice')
  309. . ',silent_default_channel:' . Config::get('site.silent_default_channel')
  310. . ',silentFlag:' . $silentFlag);
  311. $istwice = $this->request->param('istwice') ?? 0;
  312. if ( !$this->request->isAjax() && Ua::isWeiXin() && Cookie::get('channel_id') && !empty($silent_default_channel) && $silentFlag && ($istwice || ( !$istwice && $silent_default_channel != Cookie::get('channel_id') ))) {
  313. LogService::info('F:silent:静默关注逻辑:Go' );
  314. $adminConfigInfo = model('AdminConfig')->getAdminInfoAll(Cookie::get('channel_id'));
  315. //解析请求域名
  316. $domainParse = parse_url($this->request->domain());
  317. // $isologous 渠道业务域名与当前请求域名是否相同(仅充值等业务,不进行该逻辑判断)
  318. $isologous = false;
  319. if ($adminConfigInfo) {
  320. $tmp_host = $adminConfigInfo['appid'] . "." . $adminConfigInfo['ophost_host'];
  321. LogService::info('F:silent:业务域名:' . $tmp_host);
  322. LogService::info('F:silent:请求域名:' . $domainParse['host']);
  323. if ($adminConfigInfo['ophost_host'] && $adminConfigInfo['appid'] && $tmp_host == $domainParse['host']) {
  324. $isologous = true;
  325. }
  326. }
  327. if ($isologous) {
  328. LogService::info('F:silent:$isologous:渠道业务域名与当前请求域名相同');
  329. } else {
  330. LogService::info('F:silent:$isologous:渠道业务域名与当前请求域名不同');
  331. }
  332. // 是否已经存储了关联的静默数据 TRUE | FALSE
  333. $has_user_silent = UserSilentService::instance()->getSilentData(Cookie::get('user_id'), Cookie::get('channel_id'), Cookie::get('openid'), $silent_default_channel);
  334. if ($has_user_silent) {
  335. LogService::info("F:silent:用户静默授权信息已经收集了");
  336. } else {
  337. LogService::info("F:silent:用户静默授权信息还没有收集");
  338. }
  339. if ( !$has_user_silent && $isologous ) {
  340. // 通过参数判断是否已经做了静默授权
  341. $has_silent = $this->request->param('has_silent') ? 1 : 2;
  342. LogService::info("F:silent:FullUrl:" . $this->request->domain() . $this->request->url());
  343. LogService::info("F:silent:has_silent:" . $has_silent);
  344. LogService::info("F:silent:has_silent:baseUrl:".$this->request->baseUrl());
  345. LogService::info("F:silent:has_silent:url:".$this->request->url());
  346. $silentHost = UserSilentService::instance()->getSlientChannelHost();
  347. $silentUrl = 'http://'.$silentHost . $this->request->url();
  348. $adminInfo = model('AdminConfig')->getAdminInfoAll($silent_default_channel);
  349. $wechat = new WeChatObject($adminInfo);
  350. $officialAccount = $wechat->getOfficialAccount();
  351. if ($has_silent == 2 && $domainParse['host'] != $silentHost) {
  352. $silentParams = [
  353. 'user_id' => UserService::instance()->getUserInfo()->id,
  354. 'channel_id' => UserService::instance()->getUserInfo()->channel_id,
  355. 'openid' => UserService::instance()->getUserInfo()->openid,
  356. 'istwice' => 1,
  357. 'jumpurl' => del_url_params(UserSilentService::instance()->refactorUrl($this->request->url(true)),'code')
  358. ];
  359. LogService::info("F:silent:redirectSilentUrl01:" . $silentUrl);
  360. if (strpos($silentUrl, '?')) {
  361. $silentUrl .= '&' . http_build_query($silentParams);
  362. } else {
  363. $silentUrl .= '?' . http_build_query($silentParams);
  364. }
  365. //删除CODE
  366. $silentUrl = del_url_params($silentUrl, 'code');
  367. LogService::info("F:silent:redirectSilentUrl02:" . $silentUrl);
  368. $response = $officialAccount->oauth->scopes(['snsapi_base'])->redirect($silentUrl);
  369. $this->assign('jumpUrl', $response->getTargetUrl());
  370. LogService::info("F:silent:JumpURL:" . $response->getTargetUrl());
  371. exit($this->view->fetch('index@layout/jumpurl_silent'));
  372. } else {
  373. LogService::info("F:silent:FullUrl2:" . $this->request->domain() . $this->request->url());
  374. if ($this->request->has('code') && UserService::instance()->isLogin()) {
  375. LogService::info("F:silent:准备存储数据:code:" . $this->request->param('code'));
  376. /*$user = $officialAccount->oauth->user();
  377. $tri_openid = $user->getId();*/
  378. $tri_openid = UserService::instance()->getUserInfo()->openid;
  379. LogService::info("F:silent:saveSilentData1:" . $this->request->param('user_id') . ":" . $this->request->param('channel_id') . ":" . $this->request->param('openid'));
  380. $user_id = $this->request->param('user_id');
  381. $channel_id = $this->request->param('channel_id');
  382. $openid = $this->request->param('openid');
  383. $user_silent_data = UserSilentService::instance()->saveSilentData($user_id, $channel_id, $openid, $silent_default_channel, $tri_openid);
  384. }
  385. if ($this->request->param('jumpurl')) {
  386. LogService::info("F:silent:Redirect:" . $this->request->param('jumpurl'));
  387. $this->redirect(del_url_params($this->request->param('jumpurl'), 'code'));
  388. }
  389. }
  390. }
  391. } else {
  392. LogService::info('F:silent:静默关注逻辑:NOt Go');
  393. }
  394. //判断有没有需要转移的渠道
  395. $isTransfer = Cookie::get('IST:' . UserService::instance()->getUserInfo()->id);
  396. if (empty($isTransfer)) {
  397. LogService::info("F:silent:isTransfer:UID:" . UserService::instance()->getUserInfo()->id . ":Cookie:" . $isTransfer);
  398. if ($user_transfer_row = Redis::instance()->hGetAll('STU:' . UserService::instance()->getUserInfo()->channel_id)) {
  399. if ($user_transfer_row['endtime'] <= time()) {
  400. $uttl = 0;
  401. } else {
  402. $uttl = $user_transfer_row['endtime'] - time();
  403. }
  404. //判断是否转移过
  405. $isTransfer = Redis::instance()->get('IST:' . UserService::instance()->getUserInfo()->id);
  406. if (empty($isTransfer)) {
  407. LogService::info("F:silent:isTransfer:UID:" . UserService::instance()->getUserInfo()->id . ":Redis:" . $isTransfer);
  408. $whereist['uid'] = ['eq', UserService::instance()->getUserInfo()->id];
  409. $whereist['from_cid'] = ['eq', $user_transfer_row['send_channel_id']];
  410. $whereist['to_cid'] = ['eq', UserService::instance()->getUserInfo()->channel_id];
  411. $isTransferRow = model('ChannelUserTransferRecord')->where($whereist)->count();
  412. if (!empty($isTransferRow)) {
  413. LogService::info("F:silent:isTransfer:UID:" . UserService::instance()->getUserInfo()->id . ":isTransferRow:" . json_encode($isTransferRow, JSON_UNESCAPED_UNICODE));
  414. $isTransfer = 1;
  415. Redis::instance()->setex('IST:' . UserService::instance()->getUserInfo()->id, $uttl, 1);//ttl:5d
  416. Cookie::set('IST:' . UserService::instance()->getUserInfo()->id, 1, $uttl);//ttl:5d
  417. }
  418. }
  419. if (empty($isTransfer)) {
  420. //去转移
  421. $transfered = UserSilentService::instance()->channelFansTransfer(
  422. $user_silent_data,
  423. UserService::instance()->getUserInfo()->id,
  424. UserService::instance()->getUserInfo()->channel_id,
  425. UserService::instance()->getUserInfo()->openid,
  426. $user_transfer_row['send_channel_id']
  427. );
  428. if ($transfered) {
  429. LogService::info("F:silent:isTransfer:UID:" . UserService::instance()->getUserInfo()->id . ":transfered:" . $transfered);
  430. Redis::instance()->setex('IST:' . UserService::instance()->getUserInfo()->id, $uttl, 1);//ttl:5d
  431. Cookie::set('IST:' . UserService::instance()->getUserInfo()->id, 1, $uttl);//ttl:5d
  432. }
  433. }
  434. }
  435. }
  436. //endregion
  437. $this->assign('user_id', UserService::instance()->getUserInfo()->id);
  438. //处理推广链接
  439. $referral_result = UrlService::instance()->processReferral();
  440. if ($referral_result->code == ErrorCodeConstants::REDIRECT) {
  441. $this->redirect($referral_result->data);
  442. }
  443. $moduleName = Request::instance()->module();
  444. $controllerName = strtolower(Request::instance()->controller());
  445. $actionName = strtolower(Request::instance()->action());
  446. // 配置信息
  447. $config = [
  448. 'site' => array_intersect_key($site, array_flip(['name', 'cdnurl', 'version', 'timezone', 'languages'])),
  449. 'modulename' => $moduleName,
  450. 'controllername' => $controllerName,
  451. 'actionname' => $actionName,
  452. 'jsname' => 'frontend/' . str_replace('.', '/', $controllerName),
  453. 'moduleurl' => rtrim(url("/{$moduleName}", '', false), '/'),
  454. ];
  455. // 配置信息后
  456. Hook::listen("config_init", $config);
  457. $this->assign('site', $site);
  458. $this->assign('config', $config);
  459. $isAddBackDom = 0;
  460. if (in_array(
  461. $actionUrl,
  462. [
  463. 'index/user/recent',
  464. 'index/book/info',
  465. 'index/book/chapter',
  466. 'index/index/index'
  467. ]
  468. )
  469. ) {
  470. $isAddBackDom = 1;
  471. }
  472. $this->assign('isAddBackDom', $isAddBackDom);
  473. /**
  474. * 如果有使用模板布局
  475. */
  476. if ($this->layout) {
  477. $this->view->engine->layout('layout/' . $this->layout);
  478. }
  479. //设置参数
  480. $this->user = UserService::instance();
  481. $this->adminconfig = UserService::instance()->getRunTimeObject()->adminConfig;
  482. $this->urlType = UserService::instance()->getRunTimeObject()->urlType;
  483. $this->urlAgentId = UserService::instance()->getRunTimeObject()->agentId;
  484. $this->urlAdminId = UserService::instance()->getRunTimeObject()->adminId;
  485. $this->urlChannelId = UserService::instance()->getRunTimeObject()->channelId;
  486. $this->appid = UserService::instance()->getRunTimeObject()->appId;
  487. $this->time = UserService::instance()->getRunTimeObject()->requestTime;
  488. }
  489. }
  490. /**
  491. * 获取URL参数
  492. * @param $query
  493. * @return array
  494. */
  495. function getUrlParams($query)
  496. {
  497. $queryParts = explode('&', $query);
  498. $params = [];
  499. if ($queryParts) {
  500. foreach ($queryParts as $param) {
  501. $item = explode('=', $param);
  502. $params[$item[0]] = $item[1];
  503. }
  504. }
  505. return $params;
  506. }
  507. /**
  508. * 删除URL指定参数
  509. * @param $paramNames
  510. * @param $url
  511. * @return string
  512. */
  513. protected function removeUrlParam($paramNames, $url)
  514. {
  515. if (is_string($paramNames)) {
  516. $paramNames = [$paramNames];
  517. }
  518. $baseUrl = $url;
  519. $arr = [];
  520. if (strpos($url, "?") !== false) {
  521. $urlInfo = explode("?", $url);
  522. $baseUrl = $urlInfo[1];
  523. parse_str($baseUrl, $arr);
  524. }
  525. foreach ($arr as $name => $v) {
  526. if (in_array($name, $paramNames)) {
  527. unset($arr[$name]);
  528. }
  529. }
  530. return $urlInfo[0] . "?" . http_build_query($arr);
  531. }
  532. /**
  533. * 加载语言文件
  534. * @param string $name
  535. */
  536. protected function loadlang($name)
  537. {
  538. Lang::load(APP_PATH . $this->request->module() . '/lang/' . Lang::detect() . '/' . str_replace('.', '/', $name) . '.php');
  539. }
  540. /**
  541. * 渲染配置信息
  542. * @param mixed $name 键名或数组
  543. * @param mixed $value 值
  544. */
  545. protected function assignconfig($name, $value = '')
  546. {
  547. $this->view->config = array_merge($this->view->config ? $this->view->config : [], is_array($name) ? $name : [$name => $value]);
  548. }
  549. /**
  550. * 关注回复资源继续阅读
  551. * @param $responseModel
  552. * @param $adminConfig
  553. * @return array
  554. */
  555. protected function getContinueTipData($responseModel, $adminConfig)
  556. {
  557. $push_time = time();
  558. $replace = [];
  559. $appid = $adminConfig['appid'];
  560. $content = UrlService::instance()->replaceReferralHost(
  561. $adminConfig['admin_id'],
  562. $responseModel->content,
  563. false
  564. )->data;
  565. switch ($responseModel->type) {
  566. case "text":
  567. $mark = MarkConstants::MARK_RESOURCE;
  568. preg_match_all("<a href=['\"](.*?)['\"]>", $content, $match);
  569. if ($match) {
  570. foreach ($match[1] as $index => $item) {
  571. $push_idx = $index + 1;
  572. $parse = parse_url($item);
  573. $host = $parse['host'] ?? '';
  574. $path = $parse['path'] ?? '';
  575. if (preg_match('/^' . $appid . '/', $host)) {
  576. if (array_key_exists('query', $parse)) {
  577. $query = parse_query($parse['query']);
  578. if (!empty($query)) {
  579. if (array_key_exists('book_id', $query)) {
  580. $push_id = $query['book_id'];
  581. $replace = [
  582. 'book_id' => $query['book_id'],
  583. 'url' => $item .= '&' . OfficialAccountsEventService::instance()->processExt($mark, $push_id, $push_idx, $push_time),
  584. ];
  585. break;
  586. } elseif (array_key_exists('t', $query)) {
  587. $push_id = $query['t'];
  588. $replace = [
  589. 'book_id' => '',
  590. 'url' => $item .= '&' . OfficialAccountsEventService::instance()->processExt($mark, $push_id, $push_idx, $push_time),
  591. 'referral_id' => $query['t'],
  592. ];
  593. break;
  594. }
  595. }
  596. }
  597. if (!empty($path)) {
  598. $path = explode('/', $parse['path']);
  599. if ($keyIndex = array_search('t', $path)) {
  600. $push_id = $path[$keyIndex+1];
  601. $replace = [
  602. 'book_id' => '',
  603. 'url' => $item .= '?' . OfficialAccountsEventService::instance()->processExt($mark, $push_id, $push_idx, $push_time),
  604. 'referral_id' => $push_id,
  605. ];
  606. break;
  607. }
  608. }
  609. }
  610. }
  611. }
  612. break;
  613. case "news":
  614. $mark = MarkConstants::MARK_RESOURCE;
  615. $items = json_decode($content, true);
  616. foreach ($items as $index => $item) {
  617. $push_idx = $index + 1;
  618. $parse = parse_url($item['url']);
  619. $path = $parse['path'] ?? '';
  620. if (array_key_exists('query', $parse)) {
  621. $query = parse_query($parse['query']);
  622. if (array_key_exists('book_id', $query)) {
  623. $push_id = $query['book_id'];
  624. $replace = [
  625. 'book_id' => $query['book_id'],
  626. 'url' => $item['url'] .= '&' . OfficialAccountsEventService::instance()->processExt($mark, $push_id, $push_idx, $push_time),
  627. 'referral_id' => ''
  628. ];
  629. break;
  630. } elseif (array_key_exists('t', $query)) {
  631. $push_id = $query['t'];
  632. $replace = [
  633. 'book_id' => '',
  634. 'url' => $item['url'] .= '&' . OfficialAccountsEventService::instance()->processExt($mark, $push_id, $push_idx, $push_time),
  635. 'referral_id' => $query['t'],
  636. ];
  637. break;
  638. } else {
  639. continue;
  640. }
  641. }
  642. if (!empty($path)) {
  643. $path = explode('/', $parse['path']);
  644. if ($keyIndex = array_search('t', $path)) {
  645. $push_id = $path[$keyIndex+1];
  646. $replace = [
  647. 'book_id' => '',
  648. 'url' => $item['url'] .= '?' . OfficialAccountsEventService::instance()->processExt($mark, $push_id, $push_idx, $push_time),
  649. 'referral_id' => $push_id,
  650. ];
  651. break;
  652. }
  653. }
  654. }
  655. break;
  656. }
  657. if (!empty($replace)) {
  658. //查询小说标题
  659. if (isset($replace['referral_id']) && $replace['referral_id']) {
  660. $referralinfo = model('referral')->getone($replace['referral_id'], false);
  661. if (empty($referralinfo) || !$referralinfo['book_id']) {
  662. return [];
  663. }
  664. $replace['book_id'] = $referralinfo['book_id'];
  665. }
  666. $bookinfo = BookService::instance()->getBookModel()->BookInfo($replace['book_id']);
  667. $replace['book_name'] = $bookinfo['name'];
  668. $replace['image'] = $bookinfo['image'];
  669. $replace['description'] = $bookinfo['description'];
  670. }
  671. return $replace;
  672. }
  673. }