| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446 |
- <?php
- namespace api\modules\v1\forms\user;
- use common\enums\StatusEnum;
- use common\events\user\UserLoginEvent;
- use common\events\user\UserRegisterEvent;
- use common\helpers\ArrayHelper;
- use common\helpers\sms\Sms;
- use common\helpers\StringHelper;
- use common\models\base\User;
- use common\models\user\UserInfo;
- use common\traits\ErrorTrait;
- use yii\base\Model;
- use Alipay\EasySDK\Kernel\Factory;
- use Alipay\EasySDK\Kernel\Util\ResponseChecker;
- use Alipay\EasySDK\Kernel\Config;
- use Exception;
- use Yii;
- class AlipayMiniForm extends Model
- {
- use ErrorTrait;
- public $mall_id;
- public $config=[];
- public function __construct($mall_id)
- {
- $this->mall_id = $mall_id;
- $this->config = \Yii::$app->services->setting->mall->get($mall_id, 'alipay_mini');
- $option = $this->getOptions();
- Factory::setOptions($option);
- }
- private function getOptions()
- {
- $options = new Config();
- $options->protocol = 'https';
- $options->gatewayHost = 'openapi.alipay.com';
- $options->signType = 'RSA2';
- $options->appId = $this->config['app_id'];
- // 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中
- $options->merchantPrivateKey = $this->config['merchantPrivateKey'];
- if ($this->config['is_use_cert']) {
- $options->alipayCertPath = dirname(Yii::$app->basePath).'/'.$this->config['alipayCertPath'];
- $options->alipayRootCertPath = dirname(Yii::$app->basePath).'/'.$this->config['alipayRootCertPath'];
- $options->merchantCertPath = dirname(Yii::$app->basePath).'/'.$this->config['merchantCertPath'];
- } else {
- //注:如果采用非证书模式,则无需赋值上面的三个证书路径,改为赋值如下的支付宝公钥字符串即可
- $options->alipayPublicKey = file_get_contents(dirname(Yii::$app->basePath).'/'.$this->config['alipayCertPath']);
- }
- //可设置异步通知接收服务地址(可选)
- $options->notifyUrl = '';
- //可设置AES密钥,调用AES加解密相关接口时需要(可选)
- $options->encryptKey = $this->config['encryptKey'];
- return $options;
- }
- /**
- *
- * @param $code
- * @throws \Exception
- * @return array|bool
- */
- public function authorize($code, $parent_id){
- $option = $this->getOptions();
- Yii::error('authorize option:'.json_encode($option));
- Factory::setOptions($option);
- try {
- $result = Factory::base()->oauth()->getToken($code);
- Yii::error('authorize result:'.json_encode($result));
- $responseChecker = new ResponseChecker();
- //3. 处理响应或异常
- if (!$responseChecker->success($result)) {
- $this->setError($result->msg.",".$result->subMsg);
- return false;
- }
- $return_data['openid'] = $result->userId; //支付宝的会员ID
- $return_data['access_token'] = '';
- //支付宝用户id
- $user_info = $this->checkIsAuthorized($result->userId);
- if(!$user_info){
- if(!$result->accessToken) throw new Exception('授权失败');
- $user_info = $this->getUserInfoShare($result->accessToken, $parent_id);
- if (empty($user_info)) {
- $this->setError($this->getError());
- return false;
- }
- }
- if($user_info){
- if($user_info['user_id'] > 0){
- //支付宝的会员ID已存在用户表中
- $user = \common\models\user\User::findOne($user_info['user_id']);
- \Yii::$app->user->login($user);
- $res = \Yii::$app->services->apiAccessToken->getAccessToken($user, 'api');
- $return_data['access_token'] = $res['access_token'];
- // 触发登录成功事件,事务提交完成后触发
- $event = new UserLoginEvent($user['mall_id']);
- \Yii::$app->services->events->dispatch($event, ['mall_id' => $user['mall_id'], 'nickname' => $user['nickname'], 'user_id' => $user['id'], 'platform' =>$user['platform'], 'ip' => ArrayHelper::get_client_ip()], $event->listeners);
- }
- }
- return $return_data;
- } catch (Exception $e) {
- $this->setError('请求失败:'.$e->getMessage());
- return false;
- }
- }
- /**
- * 通过token获取支付宝会员信息
- * @param $token
- * @return array|bool|mixed|void
- * @throws \yii\base\Exception
- * @throws \yii\db\Exception
- */
- public function getUserInfoShare($token, $parent_id)
- {
- //设置系统参数(OpenAPI中非biz_content里的参数)
- $textParams = array(
- 'auth_token' => $token
- );
- //设置业务参数(OpenAPI中biz_content里的参数)
- $extendParams =[];
- $bizParams = [];
- $result = Factory::util()->generic()->execute("alipay.user.info.share",$textParams, $bizParams);
- $responseChecker = new ResponseChecker();
- //3. 处理响应或异常
- if (!$responseChecker->success($result)) {
- $this->setError($result->msg.",".$result->subMsg);
- return false;
- }
- Yii::error('httpBody:'.$result->httpBody);
- $bodyJson = json_decode($result->httpBody, true);
- $user_info = [];
- if($bodyJson['alipay_user_info_share_response']){
- //avatar nick_name user_id 暂时没看到mobile
- $platform_data = $bodyJson['alipay_user_info_share_response'];
- $model = UserInfo::setData([
- 'user_id' => 0,
- 'unionid' => '',
- 'openid' => $bodyJson['alipay_user_info_share_response']['user_id'] ?? 0,
- 'platform' => \common\models\user\User::PLATFORM_MP_ALI,
- 'mall_id' => $this->mall_id,
- 'platform_data' => $bodyJson['alipay_user_info_share_response']
- ]);
- if(!$model) throw new Exception(UserInfo::getStaticError());
- $user_info_id = $model->id;
- //后台设置支付宝小程序是否有授权手机号的能力
- $can_auth_phone = $this->config['can_auth_phone'] ?? false;
- if(!$can_auth_phone){
- //直接注册用户
- $password = StringHelper::random(6,true);
- $params['password'] = \Yii::$app->getSecurity()->generatePasswordHash($password);
- $params["username"] = $platform_data['nick_name'] ? (string)$platform_data['nick_name'] : '';
- $params["openid"] = $platform_data["user_id"]; //支付宝open_id
- $params["unionid"] = '';
- $params["nickname"] = $platform_data['nick_name'] ? (string)$platform_data['nick_name'] : '';
- $params["headimgurl"] = $platform_data["avatar"] ?? '';
- $params["avatar_url"] = $platform_data["avatar"] ?? '';
- $params['platform'] = \common\models\user\User::PLATFORM_MP_ALI;
- $params['last_login_at'] = time();
- $params['mall_id'] = $this->mall_id;
- $params['parent_id'] = $parent_id ?? 0; // 直推人
- $user = \common\models\user\User::setData($params);
- if ($user == false) throw new Exception(User::getStaticError());
- // 小程序授权手机触发注册事件
- $event = new UserRegisterEvent($params['mall_id']);
- $data = ['user_id' => $user->id, 'platform' => $user->platform];
- \Yii::$app->services->events->dispatch($event, $data, $event->listeners);
- if(!UserInfo::updateAll(['user_id' => $user->id ],['id' => $user_info_id])) throw new Exception('update error');
- // $model->user_id = $user->id;
- // $res = $model->save();
- // if ($res == false) throw new Exception(UserInfo::getStaticError());
- }
- $user_info = UserInfo::getOne([['id' => $model->id]],true);
- }
- return $user_info;
- }
- /**
- * @desc:授权
- * @Author: hua
- * @Date: 2021/10/25
- * @Time: 11:21
- * @Copyright: copyright (c) 2021 广东七件事集团
- * @param $params
- * @return array|false
- */
- public function checkIsAuthorized($alipay_user_id,$is_array = true)
- {
- $where = [['mall_id' => $this->mall_id], ['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]]];
- $where[] = ['openid' => $alipay_user_id];
- $where[] = ['platform' => \common\models\user\User::PLATFORM_MP_ALI];
- $user_info = UserInfo::getOne($where,$is_array);
- return $user_info;
- }
- /**
- * 支付宝encryptedData 解密
- * @param $encryptedData
- * @return false|void
- * @throws
- */
- public function decryptData($encryptedData)
- {
- Yii::error('$encryptedData:'.$encryptedData);
- $result = Factory::util()->aes()->decrypt($encryptedData);
- Yii::error('decryptData:'.$result);
- $result = json_decode($result);
- $responseChecker = new ResponseChecker();
- //3. 处理响应或异常
- if (!$responseChecker->success($result)) {
- $this->setError($result->msg,",".$result->subMsg);
- return false;
- }
- if(!$result->mobile){
- $this->setError('支付宝小程序权限:获取不到会员手机号');
- return false;
- }
- $mobile = $result->mobile;
- return $mobile;
- }
- public function authorizedMobilePhone($params)
- {
- try{
- $mobile = $this->decryptData($params['encryptData']);
- if(!$mobile){
- throw new Exception($this->getError());
- }
- $where = [['mobile' => $mobile], ['mall_id' => $this->mall_id], ['status' => [StatusEnum::DISABLED, StatusEnum::ENABLED]]];
- $user = \common\models\user\User::getOne($where);
- $user_info = $this->checkIsAuthorized($params['openid'],false);
- $platform_data = json_decode($user_info->platform_data, true);
- if (!empty($user)) {
- $res = UserInfo::findOne(['mall_id' => $this->mall_id, 'user_id' => $user->id,'platform'=>$user_info->platform,'status'=>StatusEnum::ENABLED]);
- if (!empty($res)) throw new \yii\db\Exception('该手机号码已经被注册');
- $user_info->user_id = $user->id;
- $res = $user_info->save();
- if ($res == false) throw new Exception(UserInfo::getStaticError());
- $user->nickname = $platform_data['nick_name'] ? (string)$platform_data['nick_name'] : '';
- $user->avatar_url = $platform_data['avatar'] ?? '';
- $user->platform = $user_info->platform;
- $res = $user->save();
- if ($res == false) throw new Exception(\common\models\user\User::getStaticError());
- }else{
- if($user_info && $user_info->user_id > 0){
- //存在用户,直接修改用户的手机号
- $user = \common\models\user\User::findOne(['id' => $user_info->user_id]);
- $user->mobile = $mobile;
- $user->nickname = $platform_data['nick_name'] ? (string)$platform_data['nick_name'] : '';
- $user->avatar_url = $platform_data['avatar'] ?? '';
- $user->platform = $user_info->platform;
- $res = $user->save();
- if ($res == false) throw new Exception('手机号修改失败');
- }else{
- $password = substr($mobile,-6,6);
- $params['password'] = \Yii::$app->getSecurity()->generatePasswordHash($password);
- $params["username"] = $mobile;
- $params["openid"] = $platform_data["user_id"];
- $params["unionid"] = $platform_data["unionid"] ?? '';
- $params["nickname"] = $platform_data['nick_name'] ? (string)$platform_data['nick_name'] : '';
- $params["headimgurl"] = $platform_data["avatar"] ?? '';
- $params["avatar_url"] = $platform_data["avatar"] ?? '';
- $params['platform'] = $user_info->platform;
- $params['last_login_at'] = time();
- $params['mall_id'] = $this->mall_id;
- $params['mobile'] = $mobile;
- $user = \common\models\user\User::setData($params);
- if ($user == false) throw new \yii\db\Exception(User::getStaticError());
- $user_info->user_id = $user->id;
- $res = $user_info->save();
- if ($res == false) throw new Exception(UserInfo::getStaticError());
- }
- // 小程序授权手机触发注册事件
- $event = new UserRegisterEvent($this->mall_id);
- $data = ['user_id' => $user->id, 'platform' => $user->platform];
- \Yii::$app->services->events->dispatch($event, $data, $event->listeners);
- }
- \Yii::$app->user->login($user);
- // 触发登录成功事件,事务提交完成后触发
- $event = new UserLoginEvent($user->mall_id);
- \Yii::$app->services->events->dispatch($event, ['mall_id' => $user->mall_id, 'nickname' => $user->nickname, 'user_id' => $user->id, 'platform' => $user->platform, 'ip' => ArrayHelper::get_client_ip()], $event->listeners);
- return \Yii::$app->services->apiAccessToken->getAccessToken($user, 'api');
- }catch(Exception $e){
- $this->setError($e->getMessage());
- Yii::error('authorizedMobilePhone error:'.$e->getMessage());
- return false;
- }
- }
- /**
- * 获取小程序二维码链接
- * @param $url
- * @param $query
- * @param $desc
- * @return bool|string
- * @throws Exception
- */
- public function qrcode($url,$query,$desc)
- {
- $desc = $desc ?: '海报分享';
- $result = Factory::base()->qrcode()->create($url,$query,$desc);
- $responseChecker = new ResponseChecker();
- //3. 处理响应或异常
- if (!$responseChecker->success($result)) {
- \Yii::error($result->msg.",".$result->subMsg);
- $this->setError($result->msg.",".$result->subMsg);
- return false;
- }
- return $result->qrCodeUrl;
- }
- public function bindMobileBySms($openid,$mobile,$captcha)
- {
- try{
- //手机验证码验证
- if (YII_ENV == 'prod') {
- //短信验证码
- if (!Sms::checkValidateCode($mobile, $captcha,Sms::SMS_TYPE_MOBILE_BIND)) throw new \Exception('验证码不正确');
- }
- //查询user_info
- $user_info = $this->checkIsAuthorized($openid,false);
- if(!$user_info) throw new Exception('查询不到授权信息');
- $where = [['mobile' => $mobile], ['mall_id' => $this->mall_id], ['status' => [StatusEnum::DISABLED, StatusEnum::ENABLED]]];
- $user = \common\models\user\User::getOne($where);
- $user_info = $this->checkIsAuthorized($openid,false);
- $platform_data = json_decode($user_info->platform_data, true);
- if (!empty($user)) {
- $res = UserInfo::findOne(['mall_id' => $this->mall_id, 'user_id' => $user->id, 'platform' => $user_info->platform, 'status' => StatusEnum::ENABLED]);
- if (!empty($res)) throw new \Exception('该手机号码已经被注册');
- $user_info->user_id = $user->id;
- $res = $user_info->save();
- if ($res == false) throw new Exception(UserInfo::getStaticError());
- $user->nickname = $platform_data['nick_name'] ? (string)$platform_data['nick_name'] : '';
- $user->avatar_url = $platform_data['avatar'] ?? '';
- $user->platform = $user_info->platform;
- $res = $user->save();
- if ($res == false) throw new Exception(\common\models\user\User::getStaticError());
- }else{
- if($user_info->user_id > 0){
- //查询对应用户信息
- $user = User::find()->where(['id' => $user_info->user_id,'mall_id' => $this->mall_id,'status' => StatusEnum::ENABLED])->one();
- if($user->mobile) throw new Exception('该用户已绑定手机号');
- $user->mobile = $mobile;
- $user->platform = $user_info->platform;
- $res = $user->save();
- if (!$res) throw new Exception('手机号修改失败');
- }else{
- $platform_data = json_decode($user_info->platform_data, true);
- $password = substr($mobile,-6,6);
- $params['password'] = \Yii::$app->getSecurity()->generatePasswordHash($password);
- $params["username"] = $mobile;
- $params["openid"] = $platform_data["user_id"];
- $params["unionid"] = $platform_data["unionid"] ?? '';
- $params["nickname"] = $platform_data['nick_name'] ? (string)$platform_data['nick_name'] : '';
- $params["headimgurl"] = $platform_data["avatar"] ?? '';
- $params["avatar_url"] = $platform_data["avatar"] ?? '';
- $params['platform'] = $user_info->platform;
- $params['last_login_at'] = time();
- $params['mall_id'] = $this->mall_id;
- $params['mobile'] = $mobile;
- $user = \common\models\user\User::setData($params);
- if (!$user) throw new \Exception(\common\models\base\User::getStaticError());
- $user_info->user_id = $user->id;
- $res = $user_info->save();
- if (!$res) throw new Exception(UserInfo::getStaticError());
- // 小程序授权手机触发注册事件
- $event = new UserRegisterEvent($this->mall_id);
- $data = ['user_id' => $user->id, 'platform' => $user->platform];
- \Yii::$app->services->events->dispatch($event, $data, $event->listeners);
- }
- }
- //支付宝的会员ID已存在用户表中
- $user = \common\models\user\User::findOne($user_info->user_id);
- \Yii::$app->user->login($user);
- $res = \Yii::$app->services->apiAccessToken->getAccessToken($user, 'api');
- $return_data['access_token'] = $res['access_token'];
- // 触发登录成功事件,事务提交完成后触发
- $event = new UserLoginEvent($user['mall_id']);
- \Yii::$app->services->events->dispatch($event, ['mall_id' => $user['mall_id'], 'nickname' => $user['nickname'], 'user_id' => $user['id'], 'platform' =>$user['platform'], 'ip' => ArrayHelper::get_client_ip()], $event->listeners);
- return $return_data;
- }catch (Exception $e){
- $this->setError($e->getMessage());
- return false;
- }
- }
- }
|