Wechat.php 12.5 KB
<?php

namespace app\api\controller;

use addons\third\model\Third;
use addons\wechat\library\Config;
use addons\wechat\model\WechatAutoreply;
use addons\wechat\model\WechatCaptcha;
use addons\wechat\model\WechatContext;
use addons\wechat\model\WechatResponse;
use addons\wechat\model\WechatConfig;

use app\api\model\promoter\PromoterLast;
use app\common\controller\Api;
use app\common\model\User;
use EasyWeChat\Factory;
use addons\wechat\library\Wechat as WechatService;
use fast\Random;
use think\Db;
use think\Exception;
use think\Model;

/**
 * @ApiInternal
 * 微信接口
 */
class Wechat extends Api {

	public $app = null;
	protected $noNeedLogin = ['*'];
	protected $noNeedRight = ['*'];

	public function _initialize() {
		parent::_initialize();
		$this->app = Factory::officialAccount( Config::load() );
	}

	/**
	 * 微信API对接接口
	 */
	public function api() {
		$this->app->server->push( function ( $message ) {
			$wechatService = new WechatService;

			$matches   = null;
			$openid    = $message['FromUserName'];
			$to_openid = $message['ToUserName'];

			$unknownMessage = WechatConfig::getValue( 'default.unknown.message' );
			$unknownMessage = $unknownMessage ? $unknownMessage : "";

//            file_put_contents('xuebo1.txt', print_r(date('Y-m-d H:i:s'), true), FILE_APPEND);
//            file_put_contents('xuebo1.txt', print_r($message, true), FILE_APPEND);
			switch ( $message['MsgType'] ) {
				case 'event': //事件消息
					$event    = $message['Event'];
					$eventkey = $message['EventKey'] ? $message['EventKey'] : $message['Event'];
					//验证码消息
					if ( in_array( $event, ['subscribe', 'SCAN'] ) && preg_match( "/^captcha_([a-zA-Z0-9]+)_([0-9\.]+)/", $eventkey, $matches ) ) {
						return WechatCaptcha::send( $openid, $matches[1], $matches[2] );
					}
					switch ( $event ) {
						case 'subscribe'://添加关注
							$subscribeMessage = WechatConfig::getValue( 'default.subscribe.message' );
							$subscribeMessage = $subscribeMessage ? $subscribeMessage : \config( 'site.follow_wechat' );
							return $subscribeMessage;
						case 'unsubscribe'://取消关注
							return '';
						case 'LOCATION'://获取地理位置
							return '';
						case 'VIEW': //跳转链接,eventkey为链接
							return '';
						case 'SCAN': //扫码

//                          Array
//                          (
//                              [ToUserName] => gh_8a1378fa1ee7
//                              [FromUserName] => or87o6SADyVfOHHWsoWnO9U5XqpI   //扫描者openid
//                              [CreateTime] => 1655281183
//                              [MsgType] => event
//                              [Event] => SCAN
//                              [EventKey] => 2//二维码所属者的用户id
//                              [Ticket] => gQH98DwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyU0luelVXTGVmRUYxMDAwMHcwMzcAAgQKQ6liAwQAAAAA

							//根据扫描者openid查询是否存在用户
//                            file_put_contents('xuebo1.txt', print_r($message, true), FILE_APPEND);

							//扫码者third信息
							$user = db( 'third' )->where( 'openid', $message['FromUserName'] )->find();
							if(!$user) {
//                                if($message['FromUserName'] == 'or87o6RROtVARCqI1dgLQqfUBVqE') {
                                    $user = $this->register_user(['openid'=>$message['FromUserName'],'platform'=>'wechat']);
//                                    file_put_contents('xuebo1.txt', print_r($user, true), FILE_APPEND);
//                                }
                            }

							//↓2022-6-29:不能互为上级关系
							//查询扫码者的信息
							$scan_user_info = db( 'user' )->where( 'id', $user['user_id'] )->find();
							if ( $scan_user_info['is_promoter'] == 1 ) {
								//若扫码者是推广员 is_promoter:是否推广员:1=是,2=否。查询被扫码者信息
								$scand_user_info = db( 'user' )->where( 'id', $message['EventKey'] )->find();
								if ( $scan_user_info['id'] == $scand_user_info['up_user_id'] ) {
									return "已存在上下级关系,不能互相绑定上下级关系!";
								}
							}
							//↑2022-6-29:不能互为上级关系

							//如果扫码者存在,判断是否有上级,绑定上下级
							if ( !empty( $user ) && $user['user_id'] != $message['EventKey'] ) {
								//查询扫码者的上级 up_user_id:0=无上级
								$user_up_id = db( 'user' )->where( 'id', $user['user_id'] )->value( 'up_user_id' );
								//如果没有上级则绑定上级
								if ( $user_up_id == 0 ) {
                                    //↓2022-6-27查询被扫码者上级 :实现后台A->B->C   显示A->B、A->C、B->C......     X,需要改成无限级展示:D绑定C为上级显示AD和CD,E绑定D....以此类推
                                    $ups_user_id = db( 'user' )->where( 'id', $message['EventKey'] )->value( 'up_user_id' );
                                    if($ups_user_id) {
                                        //递归查询所有上级并保存  后台展示,前台仅展示我的下一级的直系成员'is_last'      => 1,
                                        $up_arrays = $this->getParent($ups_user_id);
                                        if($up_arrays) {
                                            $ids = [];
                                            foreach ($up_arrays as $value){
                                                $ids[] = $value['id'];
                                            }
                                            if(in_array($user['id'],$ids)) {
                                                return '邀请人或邀请人的下级中有人是您的下级,无法进行绑定';
                                            }
                                        }
                                    }
									Db::startTrans();
									//绑定上下级
									$promoterModel = new PromoterLast();
									$binding       = $promoterModel->insert( [
										'user_id'      => $message['EventKey'],
										'last_user_id' => $user['user_id'],
										'binding_time' => time(),
										'createtime'   => time()
									] );

									//2022-07-02:解决操作:未绑定上级时申请的推广员,审核中,然后绑定了上级(期间通过扫描二维码方式绑定了上级)。然后审核通过后,上级清空了。
									$aa = Db::name( 'apply_promoter' )->where( 'user_id', $user['user_id'] )->find();
									if ( !empty( $aa ) ) {
										//若扫码绑定时 申请推广信息存在 并且 上级id为0时  更新上级id
										if ( $aa['up_user_id'] == 0 ) {
											Db::name( 'apply_promoter' )->where( 'user_id', $user['user_id'] )->update( ['up_user_id' => $message['EventKey']] );
										}
									}
									//↑2022-07-02:解决操作是未绑定上级时申请的推广员,审核中,然后绑定了上级(期间通过扫描二维码方式绑定了上级)。然后审核通过后,上级清空了。

									//如果被扫码者也有上级:增加被扫码者的上级的下级信息展示,07-04:怎么处理无限级?-》递归
									if ( $ups_user_id ) {
										//查询被扫码者上级id用户信息 并保存
//										$up_up_id = Db::name( 'user' )->where( 'id', $ups_user_id )->value( 'id' );
//										$binding  = $promoterModel->insert( [
//											'user_id'      => $up_up_id,
//											'last_user_id' => $user['user_id'],
//											'is_last'      => 2,
//											'binding_time' => time(),
//											'createtime'   => time()
//										] );
										//递归查询所有上级并保存  后台展示,前台仅展示我的下一级的直系成员'is_last'      => 1,
//										$up_arrays = $this->getParent($ups_user_id);
										if ($up_arrays){
											foreach ($up_arrays as $value){
												$binding  = $promoterModel->insert( [
													'user_id'      => $value['id'],
													'last_user_id' => $user['user_id'],
													'is_last'      => 2,
													'binding_time' => time(),
													'createtime'   => time()
												] );
											}
										}
									}
									//↑2022-6-27查询被扫码者上级 :实现后台A->B->C   显示A->B、A->C、B->C

									$user_update = \db( 'user' )->where( 'id', $user['user_id'] )->update( [
										'up_user_id'   => $message['EventKey'],
										'binding_time' => time(),
									] );
									if ( !$binding || !$user_update ) {
										Db::rollBack();
										return "绑定失败!";
									} else {
										Db::commit();
										return \config( 'site.bind_relation' );
									}
								}
								return \config( 'site.already_bind' );
							}
							return \config( 'site.none_login' );
						default:
							break;
					}

					$wechatResponse = WechatResponse::where( ["eventkey" => $eventkey, 'status' => 'normal'] )->find();
					if ( $wechatResponse ) {
						$responseContent = (array) json_decode( $wechatResponse['content'], true );
						$wechatContext   = WechatContext::where( ['openid' => $openid] )->order( 'id', 'desc' )->find();
						$data            = ['eventkey' => $eventkey, 'command' => '', 'refreshtime' => time(), 'openid' => $openid];
						if ( $wechatContext ) {
							$wechatContext->save( $data );
						} else {
							$wechatContext = WechatContext::create( $data, true );
						}
						$result = $wechatService->response( $this, $openid, '', $responseContent, $wechatContext );
						if ( $result ) {
							return $result;
						}
					}
					return $unknownMessage;
				case 'text': //文字消息
				case 'image': //图片消息
				case 'voice': //语音消息
				case 'video': //视频消息
				case 'location': //坐标消息
				case 'link': //链接消息
				default: //其它消息
					//自动回复处理
					if ( $message['MsgType'] == 'text' ) {
						$autoreply     = null;
						$autoreplyList = WechatAutoreply::where( 'status', 'normal' )->cache( true )->order( 'weigh DESC,id DESC' )->select();
						foreach ( $autoreplyList as $index => $item ) {
							//完全匹配和正则匹配
							if ( $item['text'] == $message['Content'] || ( in_array( mb_substr( $item['text'], 0, 1 ), ['#', '~', '/'] ) && preg_match( $item['text'], $message['Content'], $matches ) ) ) {
								$autoreply = $item;
								break;
							}
						}

						if ( $autoreply ) {
							$wechatResponse = WechatResponse::where( ["eventkey" => $autoreply['eventkey'], 'status' => 'normal'] )->find();
							if ( $wechatResponse ) {
								$responseContent = (array) json_decode( $wechatResponse['content'], true );
								$wechatContext   = WechatContext::where( ['openid' => $openid] )->order( 'id', 'desc' )->find();
								$result          = $wechatService->response( $this, $openid, $message['Content'], $responseContent, $wechatContext, $matches );
								if ( $result ) {
									return $result;
								}
							}
						}
					}
					return $unknownMessage;
			}
			return ""; //SUCCESS
		} );

		$response = $this->app->server->serve();
		// 将响应输出
		$response->send();
		return;
	}

	protected function register_user($values)
    {
        $auth = \app\common\library\Auth::instance();
        // 先随机一个用户名,随后再变更为u+数字id
        $username = Random::alnum(20);
        $password = Random::alnum(6);
        $domain   = request()->host();

        Db::startTrans();
        try {
            // 默认注册一个会员
            $result = $auth->register($username, $password, $username . '@' . $domain, '', []);
            if (!$result) {
                throw new Exception($auth->getError());
            }
            $user   = $auth->getUser();
            $fields = ['username' => '', 'email' => 'u' . $user->id . '@' . $domain];
            $fields['nickname'] = $username;
            $fields['avatar'] = '';
            // 更新会员资料
            $user = User::get($user->id);
            $user->save($fields);

            // 保存第三方信息
            $values['user_id'] = $user->id;
            Third::create($values, true);
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            $auth->logout();
            return false;
        }
        return Third::get(['user_id'=>$user->id])->toArray();
    }

	/**
	 * 递归查询所有上级
	 *
	 */
	public function getParent( $pid, $array = [] ) {
		static $level = 1;
		$is_parent = Db::name( 'user' )->field('id,up_user_id')->where( ['id' => $pid] )->find();

		$array[] = $is_parent;
		if ( $is_parent['up_user_id'] ) {
			$level ++;
			return $this->getParent( $is_parent['up_user_id'], $array );
		}
		return $array;
	}
}