123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- <?php
- namespace app\common\library\xmwechat\offiaccount;
- use app\admin\model\xmwechat\offiaccount\Autoreply;
- use app\admin\model\xmwechat\offiaccount\Material;
- use app\common\library\xmwechat\SingletonTrait;
- use app\common\library\xmwechat\WechatService;
- use EasyWeChat\Kernel\Exceptions\BadRequestException;
- use EasyWeChat\Kernel\Exceptions\InvalidArgumentException;
- use EasyWeChat\Kernel\Exceptions\RuntimeException;
- use EasyWeChat\OfficialAccount\Application;
- use Psr\Http\Message\ResponseInterface;
- use think\db\exception\DataNotFoundException;
- use think\db\exception\DbException;
- use think\db\exception\ModelNotFoundException;
- use think\exception\HttpResponseException;
- use think\facade\Log;
- use think\Response;
- use think\facade\Request;
- use think\facade\Db;
- /**
- * 消息推送
- */
- class MessageService extends WechatService
- {
- protected ?Application $app;
- protected string $accessToken;
- use SingletonTrait;
- protected HttpClientInterface $httpClient;
- public function __construct()
- {
-
- parent::__construct();
- if (empty($this->offiAccountConfig['app_id']) || empty($this->offiAccountConfig['secret'])) {
- $this->result('请配置公众号appid或secret');
- }
- $this->app = new Application([
- 'app_id' => $this->offiAccountConfig['app_id'],
- 'secret' => $this->offiAccountConfig['secret'],
- 'token' => $this->offiAccountConfig['server_token'],
- 'aes_key' => $this->offiAccountConfig['encoding_aes_key'],
- ]);
- $accessToken = $this->app->getAccessToken();
- $this->accessToken = $accessToken->getToken();
- // file_put_contents(dirname(__FILE__) . '/Token.txt',$this->accessToken);
- }
- /**
- * 微信开发文档 https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_event_pushes.html
- * @return ResponseInterface
- * @throws InvalidArgumentException
- * @throws BadRequestException
- * @throws RuntimeException
- * @throws \ReflectionException
- * @throws \Throwable
- * @author jsjxsz
- */
- public function messageServe(): ResponseInterface
- {
-
- $server = $this->app->getServer();
- // 自定义菜单click事件
- // {"ToUserName":"gh_3fd79f90b5af","FromUserName":"oluKa548P2NdCeiEbvlAomQxLKfM","CreateTime":"1693377845","MsgType":"event","Event":"CLICK","EventKey":"fq99mlqge3"}
- $server->addEventListener('CLICK', function ($message) {
- Log::info('event-message-CLICK' . json_encode($message,JSON_UNESCAPED_UNICODE));
- $eventKey = $message['EventKey'];
- return $this->getReplyContentByEvent('click', $eventKey);
- });
- // 订阅事件
- // {"ToUserName":"gh_3fd79f90b5af","FromUserName":"oluKa548P2NdCeiEbvlAomQxLKfM","CreateTime":"1693377844","MsgType":"event","Event":"subscribe","EventKey":""}
- $server->addEventListener('subscribe', function ($message) {
- // 发起 GET 请求
- $url='https://api.weixin.qq.com/cgi-bin/user/info?access_token='.$this->accessToken.'&openid='.$message['FromUserName'].'&lang=zh_CN';
- $options = [
- 'http' => [
- 'method' => 'GET',
- 'header' => 'Content-type: application/x-www-form-urlencoded\r\n',
- ],
- ];
- $context = stream_context_create($options);
- $response = file_get_contents($url, false, $context);
- $response=json_decode($response, true);
- Db::name('oauth_log')->where('uuid', $response['unionid'])->update(['opid' => $response['openid'],'opid_status' => '1']);
- Log::info('event-message-subscribe' . json_encode($message,JSON_UNESCAPED_UNICODE));
- return $this->getReplyContentByEvent('subscribe');
- });
- //解除绑定
- $server->addEventListener('unsubscribe', function ($message) {
- Db::name('oauth_log')->where('opid', $message['FromUserName'])->update(['opid' => null,'opid_status' => null]);
-
- // Log::info('接收普通消息text-message' . json_encode($message,JSON_UNESCAPED_UNICODE));
- // return $this->getReplyContentByMessage($message['Content']);
- });
-
- // 接收普通消息
- $server->addMessageListener('text', function ($message) {
- Log::info('接收普通消息text-message' . json_encode($message,JSON_UNESCAPED_UNICODE));
- return $this->getReplyContentByMessage($message['Content']);
- });
- return $server->serve();
- }
- /**
- * 事件消息回复内容
- * @param $event
- * @return array|string
- * @throws DataNotFoundException
- * @throws DbException
- * @throws ModelNotFoundException
- * @author jsjxsz
- */
- public function getReplyContentByEvent($event, $eventKey = ''): array|string
- {
-
- if ($event == 'subscribe') {
- // 订阅事件回复内容
- $autoreply = Autoreply::where('type', 'follow')->where('status', 1)->find();
- if ($autoreply['msg_type'] == 'text') {
- return htmlspecialchars_decode($autoreply['reply_content']);
- } elseif ($autoreply['msg_type'] == 'image') {
- $content = json_decode($autoreply['reply_content'], true);
- return [
- 'MsgType' => 'image',
- 'Image' => [
- 'MediaId' => $content['media_id'],
- ],
- ];
- } elseif ($autoreply['msg_type'] == 'voice') {
- $content = json_decode($autoreply['reply_content'], true);
- return [
- 'MsgType' => 'voice',
- 'Voice' => [
- 'MediaId' => $content['media_id'],
- ],
- ];
- } elseif ($autoreply['msg_type'] == 'video') {
- $content = json_decode($autoreply['reply_content'], true);
- return [
- 'MsgType' => 'video',
- 'Video' => [
- 'MediaId' => $content['media_id'],
- 'Title' => $content['name'],
- 'Description' => $content['description'],
- ],
- ];
- } elseif ($autoreply['msg_type'] == 'news') {
- $content = json_decode($autoreply['reply_content'], true);
- return [
- 'MsgType' => 'news',
- 'Articles' => [
- 'item' => [
- 'Title' => $content['title'],
- 'Description' => $content['digest'],
- 'PicUrl' => $content['show_cover_pic'],
- 'Url' => $content['url'],
- ]
- ],
- ];
- } else {
- return $this->getDefaultReply();
- }
- } else if ($event == 'click') {
- $content = Material::where('event_key', $eventKey)->value('content');
- return htmlspecialchars_decode($content);
- } else {
- return $this->getDefaultReply();
- }
- }
- // 普通消息获取回复内容
- public function getReplyContentByMessage($content)
- {
- $autoreply = Autoreply::where('keyword', $content)->where('status', 1)->find();
- if (!empty($autoreply)) {
- $msg_type = $autoreply['msg_type'];
- if ($msg_type == 'text') {
- return htmlspecialchars_decode($autoreply['reply_content']);
- } elseif ($msg_type == 'image') {
- $content = json_decode($autoreply['reply_content'], true);
- return [
- 'MsgType' => 'image',
- 'Image' => [
- 'MediaId' => $content['media_id'],
- ],
- ];
- } elseif ($msg_type == 'voice') {
- $content = json_decode($autoreply['reply_content'], true);
- return [
- 'MsgType' => 'voice',
- 'Voice' => [
- 'MediaId' => $content['media_id'],
- ],
- ];
- } elseif ($msg_type == 'video') {
- $content = json_decode($autoreply['reply_content'], true);
- return [
- 'MsgType' => 'video',
- 'Video' => [
- 'MediaId' => $content['media_id'],
- 'Title' => $content['name'],
- 'Description' => $content['description'],
- ],
- ];
- } elseif ($msg_type == 'news') {
- $content = json_decode($autoreply['reply_content'], true);
- return [
- 'MsgType' => 'news',
- 'Articles' => [
- 'item' => [
- 'Title' => $content['title'],
- 'Description' => $content['digest'],
- 'PicUrl' => $content['show_cover_pic'],
- 'Url' => $content['url'],
- ]
- ],
- ];
- } else {
- return $this->getDefaultReply();
- }
- } else {
- return $this->getDefaultReply();
- }
- }
- /**
- * 默认回复
- * @return mixed
- * @author jsjxsz
- */
- public function getDefaultReply(): mixed
- {
- $content = Autoreply::where('type', 'default')->where('status', 1)->value('reply_content');
- return htmlspecialchars_decode($content);
- }
- /**
- * @param array $params
- * @return bool
- * @author jsjxsz
- */
- public function checkSignature(array $params): bool
- {
- $offiAccount = config('xmwechat')['offiAccount'];
- $server_token = $offiAccount['server_token'];
- $tmpArr = array($server_token, $params['timestamp'], $params['nonce']);
- sort($tmpArr, SORT_STRING);
- $tmpStr = implode($tmpArr);
- $tmpStr = sha1($tmpStr);
- if ($tmpStr == $params['signature']) {
- return true;
- } else {
- return false;
- }
- }
- }
|