V2BaseController.php 26 KB

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