Wechat.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. <?php
  2. namespace addons\wechat\library;
  3. use addons\signin\model\Signin;
  4. use addons\third\model\Third;
  5. use app\common\model\User;
  6. use EasyWeChat\Kernel\Messages\News;
  7. use EasyWeChat\Kernel\Messages\NewsItem;
  8. use fast\Date;
  9. use fast\Http;
  10. use fast\Random;
  11. use think\Session;
  12. use think\Config;
  13. /**
  14. * 微信服务类
  15. */
  16. class Wechat
  17. {
  18. public static function appConfig()
  19. {
  20. return array(
  21. 'signin' => array(
  22. 'name' => '签到送积分',
  23. 'config' => array()
  24. ),
  25. 'blog' => array(
  26. 'name' => '关联博客',
  27. 'config' => array(
  28. array(
  29. 'type' => 'text',
  30. 'caption' => '日志ID',
  31. 'field' => 'post_id',
  32. 'rule' => '',
  33. 'extend' => 'class="form-control selectpage" data-source="blog/post/index" data-field="title"',
  34. 'options' => '',
  35. ),
  36. array(
  37. 'type' => 'radio',
  38. 'caption' => '开启搜索日志',
  39. 'field' => 'searchpost',
  40. 'rule' => '',
  41. 'extend' => '',
  42. 'options' => [
  43. '1' => '是',
  44. '0' => '否',
  45. ],
  46. ),
  47. array(
  48. 'type' => 'text',
  49. 'caption' => '正则搜索匹配索引',
  50. 'field' => 'searchregexindex',
  51. 'rule' => '',
  52. 'defaultvalue' => '1',
  53. 'extend' => '',
  54. 'options' => [],
  55. )
  56. )
  57. ),
  58. 'cms' => array(
  59. 'name' => '关联CMS',
  60. 'config' => array(
  61. array(
  62. 'type' => 'text',
  63. 'caption' => '文章ID',
  64. 'field' => 'archives_id',
  65. 'rule' => '',
  66. 'extend' => 'class="form-control selectpage" data-source="cms/archives/index" data-field="title"',
  67. 'options' => ''
  68. ),
  69. array(
  70. 'type' => 'text',
  71. 'caption' => '单页ID',
  72. 'field' => 'page_id',
  73. 'rule' => '',
  74. 'extend' => 'class="form-control selectpage" data-source="cms/page/index" data-field="title"',
  75. 'options' => ''
  76. ),
  77. array(
  78. 'type' => 'text',
  79. 'caption' => '专题ID',
  80. 'field' => 'special_id',
  81. 'rule' => '',
  82. 'extend' => 'class="form-control selectpage" data-source="cms/special/index" data-field="title"',
  83. 'options' => ''
  84. ),
  85. array(
  86. 'type' => 'radio',
  87. 'caption' => '开启搜索文章',
  88. 'field' => 'searcharchives',
  89. 'rule' => '',
  90. 'extend' => '',
  91. 'options' => [
  92. '1' => '是',
  93. '0' => '否',
  94. ],
  95. ),
  96. array(
  97. 'type' => 'radio',
  98. 'caption' => '开启搜索单页',
  99. 'field' => 'searchpage',
  100. 'rule' => '',
  101. 'extend' => '',
  102. 'options' => [
  103. '1' => '是',
  104. '0' => '否',
  105. ],
  106. ),
  107. array(
  108. 'type' => 'radio',
  109. 'caption' => '开启搜索专题',
  110. 'field' => 'searchspecial',
  111. 'rule' => '',
  112. 'extend' => '',
  113. 'options' => [
  114. '1' => '是',
  115. '0' => '否',
  116. ],
  117. ),
  118. array(
  119. 'type' => 'text',
  120. 'caption' => '正则搜索匹配索引',
  121. 'field' => 'searchregexindex',
  122. 'rule' => '',
  123. 'defaultvalue' => '1',
  124. 'extend' => '',
  125. 'options' => [],
  126. )
  127. )
  128. ),
  129. 'ask' => array(
  130. 'name' => '关联问答',
  131. 'config' => array(
  132. array(
  133. 'type' => 'text',
  134. 'caption' => '问题ID',
  135. 'field' => 'question_id',
  136. 'extend' => 'class="form-control selectpage" data-source="ask/question/index" data-field="title"',
  137. 'options' => ''
  138. ),
  139. array(
  140. 'type' => 'text',
  141. 'caption' => '文章ID',
  142. 'field' => 'article_id',
  143. 'extend' => 'class="form-control selectpage" data-source="ask/article/index" data-field="title"',
  144. 'options' => ''
  145. ),
  146. array(
  147. 'type' => 'radio',
  148. 'caption' => '开启搜索问题',
  149. 'field' => 'searchquestion',
  150. 'rule' => '',
  151. 'extend' => '',
  152. 'options' => [
  153. '1' => '是',
  154. '0' => '否',
  155. ],
  156. ),
  157. array(
  158. 'type' => 'radio',
  159. 'caption' => '开启搜索文章',
  160. 'field' => 'searcharticle',
  161. 'rule' => '',
  162. 'extend' => '',
  163. 'options' => [
  164. '1' => '是',
  165. '0' => '否',
  166. ],
  167. ),
  168. array(
  169. 'type' => 'text',
  170. 'caption' => '正则搜索匹配索引',
  171. 'field' => 'searchregexindex',
  172. 'rule' => '',
  173. 'defaultvalue' => '1',
  174. 'extend' => '',
  175. 'options' => [],
  176. )
  177. )
  178. ),
  179. 'vote' => array(
  180. 'name' => '关联投票',
  181. 'config' => array(
  182. array(
  183. 'type' => 'text',
  184. 'caption' => '投票主题ID',
  185. 'field' => 'subject_id',
  186. 'extend' => 'class="form-control selectpage" data-source="vote/subject/index" data-field="title"',
  187. 'rule' => '',
  188. 'options' => ''
  189. ),
  190. array(
  191. 'type' => 'text',
  192. 'caption' => '参赛人员ID',
  193. 'field' => 'player_id',
  194. 'rule' => '',
  195. 'extend' => 'class="form-control selectpage" data-source="vote/player/index" data-field="nickname"',
  196. 'options' => ''
  197. ),
  198. array(
  199. 'type' => 'radio',
  200. 'caption' => '开启搜索主题',
  201. 'field' => 'searchsubject',
  202. 'rule' => '',
  203. 'extend' => '',
  204. 'options' => [
  205. '1' => '是',
  206. '0' => '否',
  207. ],
  208. ),
  209. array(
  210. 'type' => 'radio',
  211. 'caption' => '开启搜索参赛人员',
  212. 'field' => 'searchplayer',
  213. 'rule' => '',
  214. 'extend' => '',
  215. 'options' => [
  216. '1' => '是',
  217. '0' => '否',
  218. ],
  219. ),
  220. array(
  221. 'type' => 'text',
  222. 'caption' => '正则搜索匹配索引',
  223. 'field' => 'searchregexindex',
  224. 'rule' => '',
  225. 'defaultvalue' => '1',
  226. 'extend' => '',
  227. 'options' => [],
  228. )
  229. )
  230. ),
  231. );
  232. }
  233. /**
  234. * 应用交互
  235. * @return array|bool|mixed|string
  236. */
  237. public function response($obj, $openid, $message, $content, $context, $matches = null)
  238. {
  239. $response = false;
  240. if (isset($content['app'])) {
  241. $entry = null;
  242. $keyword = isset($content['searchregexindex']) && $content['searchregexindex'] > -1 && $matches && isset($matches[$content['searchregexindex']])
  243. ? $matches[$content['searchregexindex']] : $message;
  244. switch ($content['app']) {
  245. case 'signin':
  246. $signinInfo = get_addon_info('signin');
  247. if (!$signinInfo || !$signinInfo['state']) {
  248. return "请先在后台管理安装并启用《会员签到》插件";
  249. }
  250. $thirdInfo = get_addon_info('third');
  251. if (!$thirdInfo || !$thirdInfo['state']) {
  252. return "请先在后台管理安装并启用《第三方登录》插件";
  253. }
  254. $user = self::getUserByOpenid($openid);
  255. if (!$user) {
  256. return "请先在会员中心绑定微信登录,<a href='" . addon_url('third/index/connect', [':platform' => 'wechat'], true, true) . "'>点击这里绑定</a>";
  257. }
  258. $config = get_addon_config('signin');
  259. $signdata = $config['signinscore'];
  260. $lastdata = Signin::where('user_id', $user->id)->order('id', 'desc')->find();
  261. $successions = $lastdata && $lastdata['createtime'] > Date::unixtime('day', -1) ? $lastdata['successions'] : 0;
  262. $signin = Signin::where('user_id', $user->id)->whereTime('createtime', 'today')->find();
  263. if ($signin) {
  264. return '今天已签到,请明天再来!';
  265. } else {
  266. $successions++;
  267. Signin::create(['user_id' => $user->id, 'successions' => $successions, 'createtime' => time()]);
  268. $score = isset($signdata['s' . $successions]) ? $signdata['s' . $successions] : $signdata['sn'];
  269. $user->setInc('score', $score);
  270. User::score($score, $user->id, "连续签到{$successions}天");
  271. return '签到成功!连续签到' . $successions . '天!获得' . $score . '积分,';
  272. }
  273. break;
  274. case 'blog':
  275. $blogInfo = get_addon_info('blog');
  276. if (!$blogInfo || !$blogInfo['state']) {
  277. return "请先在后台管理安装并启用《简单博客》插件";
  278. }
  279. $entry = \addons\blog\model\Post::get($content['post_id']);
  280. if ($entry) {
  281. $entry['image'] = $entry['thumb'];
  282. }
  283. if (!$entry && $content['searchpost']) {
  284. $entry = \addons\blog\model\Post::where("title|description", 'like', "%{$keyword}%")->where('status', 'normal')->find();
  285. }
  286. if (!$entry) {
  287. return "未搜索到任何匹配信息$keyword" . json_encode($matches);
  288. }
  289. break;
  290. case 'cms':
  291. $cmsInfo = get_addon_info('cms');
  292. if (!$cmsInfo || !$cmsInfo['state']) {
  293. return "请先在后台管理安装并启用《CMS内容管理系统》插件";
  294. }
  295. if (isset($content['archives_id']) && $content['archives_id']) {
  296. $entry = \addons\cms\model\Archives::get($content['archives_id']);
  297. } elseif (isset($content['page_id']) && $content['page_id']) {
  298. $entry = \addons\cms\model\Page::get($content['page_id']);
  299. } elseif (isset($content['special_id']) && $content['special_id']) {
  300. $entry = \addons\cms\model\Special::get($content['special_id']);
  301. }
  302. if (!$entry && $content['searcharchives']) {
  303. $entry = \addons\cms\model\Archives::where("title|description", 'like', "%{$keyword}%")->where('status', 'normal')->find();
  304. }
  305. if (!$entry && $content['searchpage']) {
  306. $entry = \addons\cms\model\Page::where("title|description", 'like', "%{$keyword}%")->where('status', 'normal')->find();
  307. }
  308. if (!$entry && $content['searchspecial']) {
  309. $entry = \addons\cms\model\Special::where("title|description", 'like', "%{$keyword}%")->where('status', 'normal')->find();
  310. }
  311. if (!$entry) {
  312. return "未搜索到任何匹配信息";
  313. }
  314. break;
  315. case 'ask':
  316. $blogInfo = get_addon_info('ask');
  317. if (!$blogInfo || !$blogInfo['state']) {
  318. return "请先在后台管理安装并启用《知识付费问答》插件";
  319. }
  320. if (isset($content['question_id']) && $content['question_id']) {
  321. $entry = \addons\ask\model\Question::get($content['question_id']);
  322. } elseif (isset($content['article_id']) && $content['article_id']) {
  323. $entry = \addons\ask\model\Article::get($content['article_id']);
  324. }
  325. if (!$entry && $content['searchquestion']) {
  326. $entry = \addons\ask\model\Question::where("title", 'like', "%{$keyword}%")->where('status', 'normal')->find();
  327. }
  328. if (!$entry && $content['searcharticle']) {
  329. $entry = \addons\ask\model\Article::where("title|description", 'like', "%{$keyword}%")->where('status', 'normal')->find();
  330. }
  331. if (!$entry) {
  332. return "未搜索到任何匹配信息";
  333. }
  334. break;
  335. case 'vote':
  336. $blogInfo = get_addon_info('vote');
  337. if (!$blogInfo || !$blogInfo['state']) {
  338. return "请先在后台管理安装并启用《在线投票系统》插件";
  339. }
  340. if (isset($content['subject_id']) && $content['subject_id']) {
  341. $entry = \addons\vote\model\Subject::all($content['subject_id']);
  342. } elseif (isset($content['player_id']) && $content['player_id']) {
  343. $entry = \addons\vote\model\Player::all($content['player_id']);
  344. }
  345. if (!$entry && $content['searchsubject']) {
  346. $entry = \addons\vote\model\Subject::where("title|description", 'like', "%{$keyword}%")->where('status', 'normal')->find();
  347. }
  348. if (!$entry && $content['searchplayer']) {
  349. $entry = \addons\vote\model\Player::where("nickname", 'like', "%{$keyword}%")->where('status', 'normal')->find();
  350. }
  351. if (!$entry) {
  352. return "未搜索到任何匹配信息";
  353. }
  354. break;
  355. default:
  356. break;
  357. }
  358. if (isset($entry) && $entry) {
  359. $items = [
  360. new NewsItem([
  361. 'title' => isset($entry['title']) ? $entry['title'] : (isset($entry['nickname']) ? $entry['nickname'] : ''),
  362. 'description' => isset($entry['description']) ? $entry['description'] : '',
  363. 'url' => $entry['fullurl'],
  364. 'image' => cdnurl($entry['image'], true),
  365. ]),
  366. ];
  367. $news = new News($items);
  368. $response[] = $news;
  369. }
  370. } else {
  371. $response = isset($content['content']) ? $content['content'] : $response;
  372. }
  373. return $response;
  374. }
  375. /**
  376. * 获取Token
  377. */
  378. public static function getAccessToken()
  379. {
  380. $token = Session::get('wechat_access_token');
  381. if (!$token) {
  382. $config = get_addon_config('wechat');
  383. $params = [
  384. 'grant_type' => 'client_credential',
  385. 'appid' => $config['app_id'],
  386. 'secret' => $config['secret'],
  387. ];
  388. $url = "https://api.weixin.qq.com/cgi-bin/token";
  389. $result = Http::sendRequest($url, $params, 'GET');
  390. if ($result['ret']) {
  391. $msg = (array)json_decode($result['msg'], true);
  392. if (isset($msg['access_token'])) {
  393. $token = $msg['access_token'];
  394. Session::set('wechat_access_token', $token, $msg['expires_in'] - 1);
  395. }
  396. }
  397. }
  398. return $token;
  399. }
  400. /**
  401. * 根据Openid获取用户信息
  402. * @param string $openid 微信OpenID
  403. * @return User|null
  404. */
  405. public static function getUserByOpenid($openid)
  406. {
  407. $third = Third::where('platform', 'wechat')->where('openid', $openid)->find();
  408. if ($third && $third->user_id) {
  409. return User::get($third->user_id);
  410. }
  411. return null;
  412. }
  413. }