You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
yanzong/app/common/library/wxserver/Server.php

482 lines
18 KiB

<?php
declare (strict_types=1);
namespace app\common\library\wxserver;
use app\common\model\WxserverAccount;
use cores\exception\BaseException;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Cache;
use think\facade\Db;
class Server
{
const APPID = 'wxc03d95d3597e348a';
const SECRET = 'e2720e31673906be6e92afd377b927ba';
const TOKEN = 'obUzmSA4MvMjOblZ5NCpgecTZYaGtAg6';//消息校验Token
const KEY = '2tujZuThOCzcuoBcBmeqMPjL6phcsv2dY7pgwYJwdtX'; //消息加解密Key
protected WxBizMsgCrypt $crypt;
public function __construct()
{
$this->crypt = new WxBizMsgCrypt(self::TOKEN, self::KEY, self::APPID);
}
/**
* @notes:保存Ticket
* @param string $xml
* @return mixed|string
* @author: wanghousheng
*/
public function getVerifyTicket(string $xml)
{
$ticket = '';
$xmlData = $this->crypt->fromXml($xml);
if (!empty($xmlData['Encrypt'])) {
//解密
$encryptXml = $this->crypt->decryptMsg($xmlData['Encrypt']);
$data = $this->crypt->fromXml($encryptXml);
if (!empty($data['ComponentVerifyTicket'])) {
$ticket = $data['ComponentVerifyTicket'];
Cache::set('component_verify_ticket', $ticket);
}
}
return $ticket;
}
public function getStableAccessToken()
{
$url = 'https://api.weixin.qq.com/cgi-bin/stable_token';
$data['grant_type'] = 'client_credential';
$data['appid'] = self::APPID;
$data['secret'] = self::SECRET;
$result = $this->curlPost($url, json_encode($data), 10);
$result = json_decode($result, true);
if (!empty($result['access_token'])) {
return $result['access_token'];
}
}
/**
* @notes:获取令牌
* @return mixed|string
* @author: wanghousheng
*/
public function getComponentAccessToken()
{
if (Cache::has('wxserver_component_access_token')) {
return Cache::get('wxserver_component_access_token');
}
$url = 'https://api.weixin.qq.com/cgi-bin/component/api_component_token';
$ticket = Cache::get('component_verify_ticket');
if (!empty($ticket)) {
$data = [];
$data['component_appid'] = self::APPID;
$data['component_appsecret'] = self::SECRET;
$data['component_verify_ticket'] = $ticket;
$result = $this->curlPost($url, json_encode($data), 10);
$result = json_decode($result, true);
if (!empty($result['component_access_token'])) {
Cache::set('wxserver_component_access_token', $result['component_access_token'], 6200);
return $result['component_access_token'];
}
}
return '';
}
/**
* @notes:生成H5授权链接
* @param string $redirect_uri //授权后重定向的回调链接地址
* @param string $biz_appid //业务公众号appid
* @return string
* @author: wanghousheng
*/
public function jumpH5Url(string $redirect_uri, string $biz_appid = ''): string
{
$url = '';
$auth_code = $this->getPreAuthCode();
if ($auth_code) {
$url = "https://open.weixin.qq.com/wxaopen/safe/bindcomponent?action=bindcomponent&no_scan=1";
$url .= "&component_appid=" . self::APPID . "&pre_auth_code=" . $auth_code . "&redirect_uri=" . $redirect_uri;
$url .= '&auth_type=3&biz_appid=' . $biz_appid . "#wechat_redirect";
}
return $url;
}
/**
* @notes:获取预授权码
* @return false|mixed
* @author: wanghousheng
*/
public function getPreAuthCode()
{
$token = $this->getComponentAccessToken();
if ($token) {
$url = 'https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?component_access_token=' . $token;
$data['component_appid'] = self::APPID;
$result = $this->curlPost($url, json_encode($data));
$result = json_decode($result, true);
if ($result && !empty($result['pre_auth_code'])) {
return $result['pre_auth_code'];
}
}
return false;
}
/**
* @notes:发布版本
* @param $appid
* @param $template_id
* @return true|void
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException|BaseException
* @author: wanghousheng
*/
public function commit($appid, $template_id)
{
$version = '';
$desc = '';
$model = new WxserverAccount();
$info = $model->where(['appid' => $appid])->find();
if (!empty($info)) {
$info = $info->toArray();
$access_token = $this->authorizerAccessToken($appid, $info['refresh_token']);
//获取模板
$templatelist = $this->getTemplatelist();
if ($templatelist) {
foreach ($templatelist as $value) {
if (!empty($value['user_version']) && !empty($value['user_desc']) && $value['template_id'] == $template_id) {
$version = $value['user_version'];
$desc = $value['user_desc'];
break;
}
}
}
if ($version == '' || $desc == '') {
throwError('模板不存在');
}
$data['template_id'] = $template_id;
$data['user_version'] = $version;
$data['user_desc'] = $desc;
$ext_json['extAppid'] = $appid;
$ext_json['ext']['store_id'] = $info['store_id'];
$ext_json['window'] = [];
$data['ext_json'] = json_encode($ext_json);
$url = 'https://api.weixin.qq.com/wxa/commit?access_token=' . $access_token;
$result = $this->curlPost($url, json_encode($data));
$result = json_decode($result, true);
if ($result && !empty($result['errmsg']) && $result['errmsg'] == 'ok') {
$model->update(['version' => $version . $desc], ['id' => $info['id']]);
return true;
}
}
}
/**
* @notes:获取/刷新接口调用令牌
* @param $appid
* @param $refresh_token
* @return false|mixed
* @author: wanghousheng
*/
public function authorizerAccessToken($appid, $refresh_token)
{
if (Cache::has($appid . '_authorizer_access_token')) {
return Cache::get($appid . '_authorizer_access_token');
}
$token = $this->getComponentAccessToken();
if ($token) {
$url = 'https://api.weixin.qq.com/cgi-bin/component/api_authorizer_token?component_access_token=' . $token;
$data['component_appid'] = self::APPID;
$data['authorizer_appid'] = $appid;
$data['authorizer_refresh_token'] = $refresh_token;
$result = $this->curlPost($url, json_encode($data));
$result = json_decode($result, true);
if ($result && !empty($result['authorizer_access_token'])) {
Cache::set($appid . '_authorizer_access_token', $result['authorizer_access_token'], 6200);
return $result['authorizer_access_token'];
}
}
return false;
}
private function getAuditStatusText($status): string
{
$status = intval($status);
switch ($status) {
case 0:
$text = '未提交审核';
break;
case 1:
$text = '审核中';
break;
case 2:
$text = '审核驳回';
break;
case 3:
$text = '审核通过';
break;
case 4:
$text = '提审中';
break;
case 5:
$text = '提审失败';
break;
default:
$text = '未知';
break;
}
return $text;
}
/**
* @notes:获取草稿箱列表
* @return array|mixed
* @author: wanghousheng
*/
public function getTemplatedraftlist($type)
{
if (!$type && Cache::has('wx_server_drafttemplatelist')) {
return Cache::get('wx_server_drafttemplatelist');
}
$token = $this->getComponentAccessToken();
$list = [];
if ($token) {
$url = 'https://api.weixin.qq.com/wxa/gettemplatedraftlist?access_token=' . $token;
$result = $this->curlGet($url);
$result = json_decode($result, true);
if ($result && !empty($result['draft_list'])) {
$draft_list = $result['draft_list'];
foreach ($draft_list as $value) {
$list[] = [
'create_time' => date('Y-m-d H:i:s', $value['create_time']),
'user_version' => $value['user_version'],
'user_desc' => $value['user_desc'],
'id' => $value['draft_id'],
];
}
Cache::set('wx_server_drafttemplatelist', $list, 7200);
}
}
return $list;
}
/**
* @notes:添加草稿箱到模板中
* @param $draft_id
* @return bool
* @author: wanghousheng
*/
public function addTotemplate($draft_id): bool
{
$templateList = [];
if (Cache::has('wx_server_templatelist')) {
$templateList = Cache::get('wx_server_templatelist');
}
if ($templateList) {
$draft_ids = array_column($templateList, 'draft_id');
if (in_array($draft_id, $draft_ids)) {
return true;
}
}
$token = $this->getComponentAccessToken();
if ($token) {
$url = 'https://api.weixin.qq.com/wxa/addtotemplate?access_token=' . $token;
$data['draft_id'] = $draft_id;
$data['template_type'] = 1;
$res = $this->curlPost($url, json_encode($data));
$res = json_decode($res, true);
if ($res && !empty($res['errmsg']) && $res['errmsg'] == 'ok') {
Cache::delete('wx_server_templatelist');
return true;
}
}
return false;
}
/**
* @notes:删除模板
* @param $template_id
* @return bool
* @author: wanghousheng
*/
public function deleTetemplate($template_id): bool
{
$token = $this->getComponentAccessToken();
if ($token) {
$url = 'https://api.weixin.qq.com/wxa/deletetemplate?access_token=' . $token;
$data['template_id'] = $template_id;
$res = $this->curlPost($url, json_encode($data));
$res = json_decode($res, true);
if ($res && !empty($res['errmsg']) && $res['errmsg'] == 'ok') {
Cache::delete('wx_server_templatelist');
return true;
}
}
return false;
}
/**
* @notes:代码模板列表
* @param int $type
* @return array
* @author: wanghousheng
*/
public function getTemplatelist(int $type = 0): array
{
if (!$type && Cache::has('wx_server_templatelist')) {
return Cache::get('wx_server_templatelist');
}
$token = $this->getComponentAccessToken();
$list = [];
if ($token) {
$url = 'https://api.weixin.qq.com/wxa/gettemplatelist?access_token=' . $token . '&template_type=1';
$result = $this->curlGet($url);
$result = json_decode($result, true);
if ($result && !empty($result['template_list'])) {
$template_list = $result['template_list'];
foreach ($template_list as $value) {
$list[] = [
'create_time' => date('Y-m-d H:i:s', $value['create_time']),
'user_version' => $value['user_version'],
'user_desc' => $value['user_desc'],
'template_id' => $value['template_id'],
'audit_status' => $value['audit_status'],
'audit_status_text' => $this->getAuditStatusText($value['audit_status']),
'reason' => !empty($value['reason']) ? $value['reason'] : '',
'draft_id' => $value['draft_id'],
];
}
Cache::set('wx_server_templatelist', $list, 7200);
}
}
return $list;
}
/**
* @notes:获取授权信息
* @param $authorization_code
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @author: wanghousheng
*/
public function authorizationInfo($authorization_code)
{
$url = 'https://api.weixin.qq.com/cgi-bin/component/api_query_auth?component_access_token=' . $this->getComponentAccessToken();
$data = [];
$data['component_appid'] = self::APPID;
$data['authorization_code'] = $authorization_code;
$result = $this->curlPost($url, json_encode($data));
$result = json_decode($result, true);
if ($result && !empty($result['authorization_info']) && !empty($result['authorization_info']['authorizer_appid'])) {
$url = 'https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_info?component_access_token=' . $this->getComponentAccessToken();
$data = [];
$data['component_appid'] = self::APPID;
$data['authorizer_appid'] = $result['authorization_info']['authorizer_appid'];
$res = $this->curlPost($url, json_encode($data));
$res = json_decode($res, true);
if ($res && !empty($res['authorizer_info']) && !empty($res['authorization_info'])) {
$authorizer_info = $res['authorizer_info'];
$authorization_info = $res['authorization_info'];
$insert_data['appid'] = $authorization_info['authorizer_appid'];
$model = new WxserverAccount();
$account_info = $model->where(['appid' => $insert_data['appid']])->find();
if (!empty($account_info)) {
return;
}
$insert_data['access_token'] = $result['authorization_info']['authorizer_access_token'];
$insert_data['refresh_token'] = $authorization_info['authorizer_refresh_token'];
$insert_data['nick_name'] = $authorizer_info['nick_name'];
$insert_data['head_image'] = $authorizer_info['head_img'];
$insert_data['user_name'] = $authorizer_info['user_name'];
$insert_data['qrcode_image'] = $authorizer_info['qrcode_url'];
$insert_data['principal_name'] = $authorizer_info['principal_name'];
$insert_data['signature'] = $authorizer_info['signature'];
$insert_data['store_id'] = $this->getStoreId($authorization_info['authorizer_appid']);
$insert_data['create_time'] = time();
$insert_data['update_time'] = time();
$model->insertGetId($insert_data);
}
}
}
/**
* @notes:获取店铺ID
* @param $appid
* @return int|mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @author: wanghousheng
*/
public function getStoreId($appid)
{
$list = Db::table('yoshop_wxapp_setting')->where(['key' => 'basic'])->select();
if (!$list->isEmpty()) {
$list = $list->toArray();
foreach ($list as $value) {
if ($value['values']) {
$item = json_decode($value['values'], true);
if (!empty($item['app_id']) && $item['app_id'] == $appid) {
return $value['store_id'];
}
}
}
}
return 0;
}
private function curlPost($url, $post_data, $timeout = 5)
{
$ch = curl_init();
if (stripos($url, 'https://') !== false) {
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSLVERSION, 1);
}
if (is_string($post_data)) {
$strPOST = $post_data;
} else {
$aPOST = array();
foreach ($post_data as $key => $val) {
$aPOST[] = $key . '=' . urlencode($val);
}
$strPOST = join('&', $aPOST);
}
curl_setopt($ch, CURLOPT_HTTP_VERSION, 1);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $strPOST);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
$result = curl_exec($ch);
$aStatus = curl_getinfo($ch);
curl_close($ch);
if (intval($aStatus['http_code']) == 200) {
return $result;
} else {
return false;
}
}
protected function curlGet(string $url, array $data = [])
{
if (!empty($data)) {
$url = $url . '?' . http_build_query($data);
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
}