V2ApiBaseController.php 30 KB

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