V2ApiBaseController.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  1. <?php
  2. /**
  3. * V2ApiBaseController.php UTF-8
  4. * V2版本接口校验
  5. *
  6. * @date : 2018/1/15 21:35
  7. *
  8. * @license 这不是一个自由软件,未经授权不许任何使用和传播。
  9. * @author : wuyonghong <wyh@huosdk.com>
  10. * @version : HUOSDK 8.0
  11. */
  12. namespace box\common\controller;
  13. use huo\controller\agent\Agent;
  14. use huo\controller\common\CommonFunc;
  15. use huo\controller\common\HuoCookie;
  16. use huo\controller\common\HuoSession;
  17. use huo\controller\game\GameCache;
  18. use huo\controller\member\Member;
  19. use huo\controller\member\MemCache;
  20. use huo\controller\request\Channel;
  21. use huo\controller\request\Crash;
  22. use huo\controller\request\Device;
  23. use huo\controller\request\Event;
  24. use huo\controller\request\Game;
  25. use huo\controller\request\Mem;
  26. use huo\controller\request\Order;
  27. use huo\controller\request\Role;
  28. use huo\logic\game\GameLogic;
  29. use huo\model\game\GameModel;
  30. use huoCheck\HuoApiV2;
  31. use huolib\constant\CommonConst;
  32. use huolib\constant\DeviceTypeConst;
  33. use huolib\constant\FormatConst;
  34. use huolib\constant\GameConst;
  35. use huolib\status\CommonStatus;
  36. use huolib\status\MemberStatus;
  37. use huolib\status\OrderStatus;
  38. use think\Config;
  39. use think\Controller;
  40. use think\Db;
  41. use think\exception\HttpResponseException;
  42. use think\exception\ValidateException;
  43. use think\Loader;
  44. use think\Response;
  45. use think\View;
  46. class V2ApiBaseController extends Controller {
  47. //token
  48. protected $token = '';
  49. //设备类型
  50. protected $device_type = '';
  51. //用户 id
  52. protected $mem_id = 0;
  53. // 语言
  54. protected $lang = 'en';
  55. //用户
  56. protected $user;
  57. /* 返回类型 */
  58. protected $response_type = 'json';
  59. //用户类型
  60. protected $user_type;
  61. protected $allowed_device_types = ['mobile', 'android', 'iphone', 'ipad', 'web', 'pc', 'mac', 'wxapp', 'mp'];
  62. /**
  63. * @var \think\Request Request实例
  64. */
  65. protected $request;
  66. // 验证失败是否抛出异常
  67. protected $fail_exception = false;
  68. // 是否批量验证
  69. protected $batch_validate = false;
  70. protected $rq_data = [];
  71. protected $sess_config
  72. = [
  73. 'id' => '',
  74. 'prefix' => '',
  75. 'type' => '',
  76. 'expire' => CommonConst::CONST_DAY_SECONDS
  77. ];
  78. const USER_AGENT = 'BOX_USER_AGENT';
  79. /**
  80. * 前置操作方法列表
  81. *
  82. * @var array $before_action_list
  83. * @access protected
  84. */
  85. protected $before_action_list = [];
  86. // 初始化
  87. private function _initLang() {
  88. $_lang = $this->request->header('HS-Lang/s', 'en-us');
  89. $this->lang = $_lang;
  90. config('default_lang', $this->lang);
  91. }
  92. /**
  93. * 获取设备类型
  94. *
  95. * @return string
  96. */
  97. public function getDeviceType() {
  98. if ($this->request->isWeixin()) {
  99. return DeviceTypeConst::DEVICE_TYPE_WEIXIN;
  100. }
  101. if ($this->request->isMobile()) {
  102. return DeviceTypeConst::DEVICE_TYPE_WAP;
  103. }
  104. return DeviceTypeConst::DEVICE_TYPE_PC;
  105. }
  106. /**
  107. *
  108. */
  109. private function _initUser() {
  110. $_token = HuoCookie::getMemToken();
  111. if (empty($_token)) {
  112. $_token = $this->request->param('token/s', '');
  113. }
  114. $_game_data = get_val($this->rq_data, 'game', []);
  115. $_device_type = get_val($_game_data, 'mp_id');
  116. $_wx_param['wx_app_id'] = $this->request->param('wx_app_id/s', '');
  117. if (!empty($_wx_param['wx_app_id'])) {
  118. $this->device_type = $_wx_param['wx_app_id'];
  119. } elseif (!empty($_device_type)) {
  120. $this->device_type = $_device_type;
  121. } else {
  122. $this->device_type = DeviceTypeConst::DEVICE_TYPE_MP;
  123. }
  124. $_mem_id = $this->getMemIdByToken($_token, $this->device_type);
  125. if (!empty($_mem_id)) {
  126. $this->mem_id = $_mem_id;
  127. }
  128. if (APP_DEBUG) {
  129. /* 调试环境直接登陆 */
  130. $_mem_id = $this->request->param('debug_mem_id/s', 0);
  131. if (!empty($_mem_id)) {
  132. $this->mem_id = $_mem_id;
  133. }
  134. }
  135. }
  136. protected function _initialize() {
  137. $this->response_type = $this->request->param('format/s', FormatConst::FORMAT_HTML);
  138. if (FormatConst::FORMAT_HTML == $this->response_type) {
  139. $this->_initializeView();
  140. $_site = $this->request->domain();
  141. $_agent_id = (new Agent())->getAgentIdBySite($_site);
  142. if (empty($_agent_id)) {
  143. $_agent_id = $this->request->request('agent_id', 0);
  144. }
  145. if (empty($_agent_id)) {
  146. $_agent_id = (new HuoSession($this->mem_id))->getAgentId();
  147. } else {
  148. (new HuoSession($this->mem_id))->setAgentId($_agent_id);
  149. }
  150. $siteInfo = cmf_get_site_info($_agent_id);
  151. View::share('site_info', $siteInfo);
  152. View::share('agent_id', $_agent_id);
  153. View::share('agent_site', $_site);
  154. View::share('h5i_site', H5ISITE);
  155. View::share('static_site', STATICSITE);
  156. }
  157. Config::set('default_return_type', $this->response_type);
  158. $this->_initLang();
  159. $this->checkParam();
  160. // 用户验证初始化
  161. $this->_initUser();
  162. /* 记录请求数据 */
  163. if ($this->request->isOptions()) {
  164. $this->success();
  165. }
  166. }
  167. /**
  168. * 前置操作
  169. *
  170. * @access protected
  171. *
  172. * @param string $method 前置操作方法名
  173. * @param array $options 调用参数 ['only'=>[...]] 或者['except'=>[...]]
  174. */
  175. protected function beforeAction($method, $options = []) {
  176. if (isset($options['only'])) {
  177. if (is_string($options['only'])) {
  178. $options['only'] = explode(',', $options['only']);
  179. }
  180. if (!in_array($this->request->action(), $options['only'])) {
  181. return;
  182. }
  183. } elseif (isset($options['except'])) {
  184. if (is_string($options['except'])) {
  185. $options['except'] = explode(',', $options['except']);
  186. }
  187. if (in_array($this->request->action(), $options['except'])) {
  188. return;
  189. }
  190. }
  191. call_user_func([$this, $method]);
  192. }
  193. /**
  194. * @param $token
  195. * @param $device_type
  196. *
  197. * @return array|bool|false|\PDOStatement|string|\think\Model
  198. */
  199. public function getMemIdByToken($token, $device_type) {
  200. if (empty($token)) {
  201. return 0;
  202. }
  203. $_path = 'mp/wx/login';
  204. $_is_up = $_path == request()->path() ? true : false;
  205. $_mem_id = (new Member())->getMemIdByToken($token, $device_type, $_is_up);
  206. if (empty($_mem_id)) {
  207. return 0;
  208. }
  209. return $_mem_id;
  210. }
  211. /**
  212. * 返回数据
  213. *
  214. * @param array $data
  215. */
  216. protected function returnData($data = []) {
  217. $_msg = $data['msg'];
  218. $_code = $data['code'];
  219. $_data = $data['data'];
  220. if (CommonStatus::NO_ERROR != $_code) {
  221. $this->error($_msg, $_data, $_code);
  222. }
  223. $this->success($_msg, $_data, $_code);
  224. }
  225. /**
  226. * 操作错误跳转的快捷方法
  227. *
  228. * @access protected
  229. *
  230. * @param mixed $msg 提示信息,若要指定错误码,可以传数组,格式为['code'=>您的错误码,'msg'=>'您的错误消息']
  231. * @param mixed $data 返回的数据
  232. * @param int $code
  233. *
  234. * @param array $header 发送的Header信息
  235. *
  236. * @param null $url
  237. * @param int $wait
  238. *
  239. * @return void
  240. */
  241. protected function error($msg = '', $data = '', $code = 400, array $header = [], $url = null, $wait = 3) {
  242. $type = $this->getResponseType();
  243. if ('html' == $type) {
  244. parent::error($msg, $data, $code, $header, $url, $wait);
  245. }
  246. if (empty($data)) {
  247. $data = null;
  248. }
  249. $result = [
  250. 'code' => $code,
  251. 'msg' => $msg,
  252. 'data' => $data,
  253. ];
  254. \think\Log::write($result, 'debug', true);
  255. $header['Access-Control-Allow-Origin'] = '*';
  256. $header['Access-Control-Allow-Headers'] = 'X-Requested-With,Content-Type,HS-Device-Type,HS-Token,HS-Lang';
  257. $header['Access-Control-Allow-Methods'] = 'GET,POST,PATCH,PUT,DELETE,OPTIONS';
  258. $response = Response::create($result, $type)->header($header);
  259. throw new HttpResponseException($response);
  260. }
  261. /**
  262. * 获取当前的response 输出类型
  263. *
  264. * @access protected
  265. * @return string
  266. */
  267. protected function getResponseType() {
  268. return $this->response_type;
  269. }
  270. /**
  271. * 获取当前登录用户的id
  272. *
  273. * @return int
  274. */
  275. public function getMemId() {
  276. if (empty($this->mem_id)) {
  277. $this->error(lang('NO_LOGIN'), '', 1002);
  278. }
  279. // $this->mem_id = rand(1, 10);
  280. return $this->mem_id;
  281. }
  282. /**
  283. * 设置验证失败后是否抛出异常
  284. *
  285. * @access protected
  286. *
  287. * @param bool $fail 是否抛出异常
  288. *
  289. * @return $this
  290. */
  291. protected function validateFailException($fail = true) {
  292. $this->fail_exception = $fail;
  293. return $this;
  294. }
  295. /**
  296. * 验证数据
  297. *
  298. * @access protected
  299. *
  300. * @param array $data 数据
  301. * @param string|array $validate 验证器名或者验证规则数组
  302. * @param array $message 提示信息
  303. * @param bool $batch 是否批量验证
  304. * @param mixed $callback 回调方法(闭包)
  305. *
  306. * @return array|string|true
  307. * @throws ValidateException
  308. */
  309. protected function validate($data, $validate, $message = [], $batch = false, $callback = null) {
  310. if (is_array($validate)) {
  311. $_valid_class = Loader::validate();
  312. $_valid_class->rule($validate);
  313. } else {
  314. if (strpos($validate, '.')) {
  315. // 支持场景
  316. list($validate, $scene) = explode('.', $validate);
  317. }
  318. $_valid_class = Loader::validate($validate);
  319. if (!empty($scene)) {
  320. $_valid_class->scene($scene);
  321. }
  322. }
  323. // 是否批量验证
  324. if ($batch || $this->batch_validate) {
  325. $_valid_class->batch(true);
  326. }
  327. if (is_array($message)) {
  328. $_valid_class->message($message);
  329. }
  330. if ($callback && is_callable($callback)) {
  331. call_user_func_array($callback, [$_valid_class, &$data]);
  332. }
  333. if (!$_valid_class->check($data)) {
  334. if ($this->fail_exception) {
  335. throw new ValidateException($_valid_class->getError());
  336. } else {
  337. return $_valid_class->getError();
  338. }
  339. } else {
  340. return true;
  341. }
  342. }
  343. /**
  344. * 操作成功跳转的快捷方法
  345. *
  346. * @access protected
  347. *
  348. * @param mixed $msg 提示信息
  349. * @param mixed $data 返回的数据
  350. * @param array $header 发送的Header信息
  351. *
  352. * @param int $code 返回码
  353. *
  354. * @return void
  355. */
  356. protected function success($msg = '', $data = '', $code = 200, array $header = [], $url = null, $wait = 3) {
  357. $type = $this->getResponseType();
  358. if ('html' == $type) {
  359. parent::success($msg, $data, $code, $header, $url, $wait);
  360. }
  361. if (empty($data)) {
  362. $data = null;
  363. }
  364. $result = [
  365. 'code' => $code,
  366. 'msg' => $msg,
  367. 'data' => $data,
  368. ];
  369. $header['Access-Control-Allow-Origin'] = '*';
  370. $header['Access-Control-Allow-Headers'] = 'X-Requested-With,Content-Type,HS-Device-Type,HS-Token,HS-Lang';
  371. $header['Access-Control-Allow-Methods'] = 'GET,POST,PATCH,PUT,DELETE,OPTIONS';
  372. $response = Response::create($result, $type)->header($header);
  373. throw new HttpResponseException($response);
  374. }
  375. protected function checkParam() {
  376. $_is_json = false;
  377. $_params = $_REQUEST;
  378. $this->rq_data = $this->getParam($_params, $_is_json);
  379. if (empty($this->rq_data)) {
  380. $this->rq_data = [];
  381. }
  382. // $this->checkSign();
  383. // $this->checkTime();
  384. }
  385. /**
  386. * 获取请求参数
  387. *
  388. * @param mixed $param
  389. * @param bool $is_json
  390. *
  391. * @return bool|mixed|string
  392. */
  393. public function getParam($param, $is_json = false) {
  394. if (empty($param)) {
  395. return '';
  396. }
  397. if ($is_json) {
  398. $_param = json_decode($param, true);
  399. if (JSON_ERROR_NONE != json_last_error()) {
  400. return false;
  401. }
  402. } else {
  403. foreach ($param as $_k => $_v) {
  404. if (strpos($_k, '-')) {
  405. list($_k1, $_k2) = explode('-', $_k);
  406. if (is_array($_k2)) {
  407. return false;
  408. }
  409. $_param[$_k1][$_k2] = $_v;
  410. } else {
  411. $_param[$_k] = $_v;
  412. }
  413. }
  414. }
  415. if (empty($_param)) {
  416. return false;
  417. }
  418. return $_param;
  419. }
  420. /**
  421. * @return bool|string
  422. */
  423. protected function getKey() {
  424. switch ($this->device_type) {
  425. case DeviceTypeConst::DEVICE_TYPE_IOSSDK:
  426. case DeviceTypeConst::DEVICE_TYPE_ANDSDK:
  427. case DeviceTypeConst::DEVICE_TYPE_IOSAPP:
  428. case DeviceTypeConst::DEVICE_TYPE_IOSH5APP:
  429. case DeviceTypeConst::DEVICE_TYPE_ANDAPP:
  430. case DeviceTypeConst::DEVICE_TYPE_ANDH5APP:
  431. $_key = $this->getAppKey();
  432. break;
  433. case DeviceTypeConst::DEVICE_TYPE_IOSAPPLESDK:
  434. $_key = $this->getAppKey(true);
  435. break;
  436. default:
  437. $_key = $this->token;
  438. }
  439. return $_key;
  440. }
  441. protected function getAppKey($is_iosapplesdk = false) {
  442. $_gl_class = new GameLogic();
  443. $_app_id = get_val($this->rq_data, 'app_id');
  444. if (empty($_app_id) && false == $is_iosapplesdk) {
  445. return false;
  446. }
  447. $_client_id = get_val($this->rq_data, 'client_id');
  448. if (empty($_client_id) && false == $is_iosapplesdk) {
  449. return false;
  450. }
  451. $_client_key = $_gl_class->getVersionKey($_app_id, $_client_id);
  452. if (empty($_client_key) && false == $is_iosapplesdk) {
  453. return false;
  454. }
  455. $_public_key_file = GLOBAL_CONF_PATH.'extra/key/rsa_public_key.pem';
  456. if (!file_exists($_public_key_file)) {
  457. return false;
  458. } else {
  459. $_key_content = file_get_contents($_public_key_file);
  460. }
  461. // 以下为了初始化公钥,保证公钥不管是带格式还是不带格式都可以通过验证。
  462. $_key_content = str_replace("-----BEGIN PUBLIC KEY-----", "", $_key_content);
  463. $_key_content = str_replace("-----END PUBLIC KEY-----", "", $_key_content);
  464. $_key_content = str_replace("\r\n", "", $_key_content);
  465. $_key_content = str_replace("\n", "", $_key_content);
  466. // Log::error('------pubic_key-----'.$_key_content);
  467. if (empty($_key_content)) {
  468. return false;
  469. }
  470. if (true == $is_iosapplesdk) {
  471. return $_key_content;
  472. }
  473. return $_client_key.'&'.$_key_content;
  474. }
  475. /**
  476. * 校验签名
  477. */
  478. protected function checkSign() {
  479. $_ignore_sign = [ //忽略签名的接口数组
  480. 'v8/app/getPluginList'
  481. ];
  482. $_path = $this->request->path();
  483. if (in_array($_path, $_ignore_sign)) {
  484. return true;
  485. }
  486. if (empty($this->device_type) || FormatConst::FORMAT_HTML == $this->response_type) {
  487. return true;
  488. }
  489. $_haV2 = new HuoApiV2();
  490. //获取client_key
  491. $_key = $this->getKey();
  492. $_haV2->setKey($_key);
  493. $_rs = $_haV2->check($_path, $this->rq_data, $this->request->method());
  494. if (true != $_rs) {
  495. $this->error(OrderStatus::getMsg(OrderStatus::SIGN_ERROR), '', OrderStatus::SIGN_ERROR);
  496. }
  497. }
  498. /**
  499. * 校验请求事件
  500. */
  501. protected function checkTime() {
  502. $_ts = get_val($this->rq_data, 'ts', 0);
  503. if (abs($_ts - time()) < 5) {
  504. $this->error('time is error');
  505. }
  506. }
  507. /**
  508. * 设置玩家入参
  509. *
  510. * @param bool $is_reg
  511. *
  512. * @return Mem
  513. */
  514. public function setMemData($is_reg = false) {
  515. $_mem = new Mem();
  516. $_mem->setData(get_val($this->rq_data, 'mem'));
  517. $_app_id = get_val($this->rq_data, 'app_id', 0);
  518. $_mg_mem_id = (new HuoSession($this->mem_id, $_app_id))->getMgMemId();
  519. if (false == $is_reg) {
  520. $_mem_id = $this->mem_id;
  521. if (!empty($_mem_id)) {
  522. $_mem->setMemId($_mem_id);
  523. $_mem->setMgMemId($_mg_mem_id);
  524. $_mem_data = MemCache::ins()->getInfoById($_mem_id);
  525. $_mem->setAgentId($_mem_data['agent_id']);
  526. }
  527. }
  528. return $_mem;
  529. }
  530. /**
  531. * @return Order
  532. */
  533. public function setOrderData() {
  534. $_order = new Order();
  535. $_order->setData(get_val($this->rq_data, 'order', []));
  536. return $_order;
  537. }
  538. /**
  539. * @return Role
  540. */
  541. public function setRoleData() {
  542. $_role = new Role();
  543. $_role->setData(get_val($this->rq_data, 'role', []));
  544. return $_role;
  545. }
  546. /**
  547. * @return Crash
  548. */
  549. public function setCrashData() {
  550. $_crash = new Crash();
  551. $_crash->setData(get_val($this->rq_data, 'crash', []));
  552. return $_crash;
  553. }
  554. /**
  555. * @return Device
  556. */
  557. public function setDeviceData() {
  558. $_device = new Device();
  559. $_device->setData(get_val($this->rq_data, 'device', []));
  560. $_device->setDeviceType($this->device_type);
  561. $_device->setIp($this->request->ip());
  562. if (isset($this->rq_data['open_cnt'])) {
  563. $_device->setOpenCnt($this->rq_data['open_cnt']);
  564. // (new HuoSession($this->mem_id))->setOpenCnt($this->rq_data['open_cnt']);
  565. } else {
  566. // $_open_cnt = (new HuoSession($this->mem_id))->getOpenCnt();
  567. if (empty($_open_cnt)) {
  568. $_open_cnt = 0;
  569. }
  570. $_device->setOpenCnt($_open_cnt);
  571. }
  572. $_device->setFromDevice($this->device_type);
  573. switch ($this->device_type) {
  574. case DeviceTypeConst::DEVICE_TYPE_IOSSDK:
  575. case DeviceTypeConst::DEVICE_TYPE_IOSAPP:
  576. case DeviceTypeConst::DEVICE_TYPE_IOSH5APP:
  577. $_device->setFrom(GameConst::GAME_IOS);
  578. break;
  579. case DeviceTypeConst::DEVICE_TYPE_IOSAPPLESDK:
  580. $_device->setFrom(GameConst::GAME_IOS_SWITCH);
  581. break;
  582. case DeviceTypeConst::DEVICE_TYPE_ANDSDK:
  583. case DeviceTypeConst::DEVICE_TYPE_ANDAPP:
  584. case DeviceTypeConst::DEVICE_TYPE_ANDH5APP:
  585. $_device->setFrom(GameConst::GAME_ANDROID);
  586. break;
  587. case DeviceTypeConst::DEVICE_TYPE_SAFARI:
  588. case DeviceTypeConst::DEVICE_TYPE_ANDBROWSER:
  589. case DeviceTypeConst::DEVICE_TYPE_WEIXIN:
  590. case DeviceTypeConst::DEVICE_TYPE_PC:
  591. case DeviceTypeConst::DEVICE_TYPE_WAP:
  592. $_device->setFrom(GameConst::GAME_H5);
  593. break;
  594. default:
  595. $_device->setFrom(GameConst::GAME_H5);
  596. }
  597. return $_device;
  598. }
  599. /**
  600. * @return Game
  601. */
  602. public function setGameData() {
  603. $_game = new Game();
  604. $_game->setData(get_val($this->rq_data, 'game', []));
  605. switch ($this->device_type) {
  606. case DeviceTypeConst::DEVICE_TYPE_IOSAPPLESDK:
  607. $_game->setAppleId(get_val($this->rq_data, 'apple_id', 0));
  608. $_app_id = (new GameModel())->getAppIdByAppleId($_game->getAppleId());
  609. if (empty($_app_id)) {
  610. $this->error('AppleId 错误');
  611. }
  612. $_game->setHAppId($_app_id);
  613. $this->rq_data['app_id'] = $_app_id;
  614. break;
  615. case DeviceTypeConst::DEVICE_TYPE_IOSSDK:
  616. break;
  617. case DeviceTypeConst::DEVICE_TYPE_IOSAPP:
  618. case DeviceTypeConst::DEVICE_TYPE_IOSH5APP:
  619. case DeviceTypeConst::DEVICE_TYPE_SAFARI:
  620. default:
  621. $_game->setHAppId(get_val($this->rq_data, 'app_id', 0));
  622. }
  623. if ($_game->getHAppId() !== 0) {
  624. $_game_data = (new GameCache())->getInfoByAppId($_game->getHAppId());
  625. if (empty($_game_data)) {
  626. $this->error('游戏参数错误');
  627. }
  628. }
  629. return $_game;
  630. }
  631. /**
  632. * @return Channel
  633. *
  634. */
  635. public function setChannelData() {
  636. $_channel = new Channel();
  637. $_channel->setData(get_val($this->rq_data, 'agent', []));
  638. $_device_data = get_val($this->rq_data, 'device', []);
  639. $_device_id = get_val($_device_data, 'device_id', '');
  640. /* 计算AgentId */
  641. $_agent_id = Commonfunc::getAgentId(
  642. 0,
  643. $_channel->getAgentGame(),
  644. $_channel->getAgentId(),
  645. $_device_id
  646. );
  647. $_channel->setAgentId($_agent_id);
  648. return $_channel;
  649. }
  650. /**
  651. * @return Event
  652. */
  653. public function setEventData() {
  654. $_event = new Event();
  655. $_event->setData(get_val($this->rq_data, 'event', []));
  656. return $_event;
  657. }
  658. public function _initializeView() {
  659. $cmfThemePath = config('cmf_theme_path');
  660. $cmfDefaultTheme = cmf_get_current_theme();
  661. $themePath = "{$cmfThemePath}{$cmfDefaultTheme}";
  662. $root = cmf_get_root();
  663. //使cdn设置生效
  664. $cdnSettings = cmf_get_option('cdn_settings');
  665. if (empty($cdnSettings['cdn_static_root'])) {
  666. $viewReplaceStr = [
  667. '__ROOT__' => $root,
  668. '__TMPL__' => "{$root}/{$themePath}",
  669. '__STATIC__' => "{$root}/static",
  670. '__WEB_ROOT__' => $root
  671. ];
  672. } else {
  673. $cdnStaticRoot = rtrim($cdnSettings['cdn_static_root'], '/');
  674. $viewReplaceStr = [
  675. '__ROOT__' => $root,
  676. '__TMPL__' => "{$cdnStaticRoot}/{$themePath}",
  677. '__STATIC__' => "{$cdnStaticRoot}/static",
  678. '__WEB_ROOT__' => $cdnStaticRoot
  679. ];
  680. }
  681. $viewReplaceStr = array_merge(config('view_replace_str'), $viewReplaceStr);
  682. config('template.view_base', "{$themePath}/");
  683. config('view_replace_str', $viewReplaceStr);
  684. $themeErrorTmpl = "{$themePath}/error.html";
  685. if (file_exists_case($themeErrorTmpl)) {
  686. config('dispatch_error_tmpl', $themeErrorTmpl);
  687. }
  688. $themeSuccessTmpl = "{$themePath}/success.html";
  689. if (file_exists_case($themeSuccessTmpl)) {
  690. config('dispatch_success_tmpl', $themeSuccessTmpl);
  691. }
  692. }
  693. /**
  694. * 加载模板输出
  695. *
  696. * @access protected
  697. *
  698. * @param string $template 模板文件名
  699. * @param array $vars 模板输出变量
  700. * @param array $replace 模板替换
  701. * @param array $config 模板参数
  702. *
  703. * @return mixed
  704. */
  705. protected function fetch($template = '', $vars = [], $replace = [], $config = []) {
  706. $template = $this->parseTemplate($template);
  707. $more = $this->getThemeFileMore($template);
  708. $this->assign('theme_vars', $more['vars']);
  709. $this->assign('theme_widgets', $more['widgets']);
  710. return parent::fetch($template, $vars, $replace, $config);
  711. }
  712. /**
  713. * 自动定位模板文件
  714. *
  715. * @access private
  716. *
  717. * @param string $template 模板文件规则
  718. *
  719. * @return string
  720. */
  721. private function parseTemplate($template) {
  722. // 分析模板文件规则
  723. $request = $this->request;
  724. // 获取视图根目录
  725. if (strpos($template, '@')) {
  726. // 跨模块调用
  727. list($module, $template) = explode('@', $template);
  728. }
  729. $viewBase = config('template.view_base');
  730. if ($viewBase) {
  731. // 基础视图目录
  732. $module = isset($module) ? $module : $request->module();
  733. $path = $viewBase.($module ? $module.DS : '');
  734. } else {
  735. $path = isset($module) ? APP_PATH.$module.DS.'view'.DS : config('template.view_path');
  736. }
  737. $depr = config('template.view_depr');
  738. if (0 !== strpos($template, '/')) {
  739. $template = str_replace(['/', ':'], $depr, $template);
  740. $controller = cmf_parse_name($request->controller());
  741. if ($controller) {
  742. if ('' == $template) {
  743. // 如果模板文件名为空 按照默认规则定位
  744. $template = str_replace('.', DS, $controller).$depr.$request->action();
  745. } elseif (false === strpos($template, $depr)) {
  746. $template = str_replace('.', DS, $controller).$depr.$template;
  747. }
  748. }
  749. } else {
  750. $template = str_replace(['/', ':'], $depr, substr($template, 1));
  751. }
  752. return $path.ltrim($template, '/').'.'.ltrim(config('template.view_suffix'), '.');
  753. }
  754. /**
  755. * 获取模板文件变量
  756. *
  757. * @param string $file
  758. * @param string $theme
  759. *
  760. * @return array
  761. */
  762. private function getThemeFileMore($file, $theme = "") {
  763. //TODO 增加缓存
  764. $theme = empty($theme) ? cmf_get_current_theme() : $theme;
  765. $themePath = config('cmf_theme_path');
  766. $file = str_replace('\\', '/', $file);
  767. $file = str_replace('//', '/', $file);
  768. $file = str_replace(['.html', '.php', $themePath.$theme."/"], '', $file);
  769. $files = Db::name('theme_file')->field('more')->where(['theme' => $theme])->where(
  770. function ($query) use ($file) {
  771. $query->where(['is_public' => 1])->whereOr(['file' => $file]);
  772. }
  773. )->select();
  774. $vars = [];
  775. $widgets = [];
  776. foreach ($files as $file) {
  777. $oldMore = json_decode($file['more'], true);
  778. if (!empty($oldMore['vars'])) {
  779. foreach ($oldMore['vars'] as $varName => $var) {
  780. $vars[$varName] = $var['value'];
  781. }
  782. }
  783. if (!empty($oldMore['widgets'])) {
  784. foreach ($oldMore['widgets'] as $widgetName => $widget) {
  785. $widgetVars = [];
  786. if (!empty($widget['vars'])) {
  787. foreach ($widget['vars'] as $varName => $var) {
  788. $widgetVars[$varName] = $var['value'];
  789. }
  790. }
  791. $widget['vars'] = $widgetVars;
  792. $widgets[$widgetName] = $widget;
  793. }
  794. }
  795. }
  796. return ['vars' => $vars, 'widgets' => $widgets];
  797. }
  798. /**
  799. * 检查是否登陆
  800. *
  801. * @param int $mem_id
  802. */
  803. public function checkLogin($mem_id = 0) {
  804. $_mem_id = $mem_id;
  805. if (empty($_mem_id)) {
  806. $_mem_id = $this->mem_id;
  807. }
  808. if (empty($_mem_id)) {
  809. $_code = MemberStatus::LOGIN_IS_OUT;
  810. $this->error(lang(MemberStatus::getMsg($_code)), [], $_code);
  811. }
  812. }
  813. }