339 lines
11 KiB
PHP
339 lines
11 KiB
PHP
<?php
|
|
|
|
namespace Extend\Wechat;
|
|
|
|
use App\Constants\HttpEnumCode;
|
|
use App\Exception\BusinessException;
|
|
use EasyWeChat\Kernel\Exceptions\BadResponseException;
|
|
use EasyWeChat\Kernel\Exceptions\InvalidArgumentException;
|
|
use EasyWeChat\Kernel\HttpClient\AccessTokenAwareClient;
|
|
use EasyWeChat\MiniApp\Application;
|
|
use Hyperf\Utils\ApplicationContext;
|
|
use Psr\Container\ContainerExceptionInterface;
|
|
use Psr\Container\NotFoundExceptionInterface;
|
|
use Psr\SimpleCache\CacheInterface;
|
|
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
|
|
use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
|
|
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
|
|
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
|
|
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
|
|
|
/**
|
|
* 微信类
|
|
*/
|
|
class Wechat
|
|
{
|
|
|
|
protected Application $app;
|
|
|
|
protected array $config;// 系统配置
|
|
|
|
/**
|
|
* @param string $user_type
|
|
*/
|
|
public function __construct(string $user_type)
|
|
{
|
|
if ($user_type == 1){
|
|
$this->config = config("we_chat.applets.patient");
|
|
}elseif ($user_type == 2){
|
|
$this->config = config("we_chat.applets.doctor");
|
|
}elseif ($user_type == 3){
|
|
$this->config = config("we_chat.applets.pharmacist");
|
|
}
|
|
|
|
if (empty($this->config)){
|
|
throw new BusinessException("系统配置错误", HttpEnumCode::SERVER_ERROR);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取wechat类
|
|
* @param string $appId
|
|
* @param string $appSecret
|
|
* @throws ContainerExceptionInterface
|
|
* @throws NotFoundExceptionInterface
|
|
*/
|
|
public function createApp(string $appId, string $appSecret): void
|
|
{
|
|
$config = array(
|
|
"app_id" => $appId,
|
|
"secret" => $appSecret,
|
|
"http" => [
|
|
'throw' => false, // 状态码非 200、300 时是否抛出异常,默认为开启
|
|
'timeout' => 5.0,
|
|
// 'base_uri' => 'https://api.weixin.qq.com/', // 如果你在国外想要覆盖默认的 url 的时候才使用,根据不同的模块配置不同的 uri
|
|
|
|
'retry' => true, // 使用默认重试配置
|
|
// 'retry' => [
|
|
// // 仅以下状态码重试
|
|
// 'http_codes' => [429, 500]
|
|
// // 最大重试次数
|
|
// 'max_retries' => 3,
|
|
// // 请求间隔 (毫秒)
|
|
// 'delay' => 1000,
|
|
// // 如果设置,每次重试的等待时间都会增加这个系数
|
|
// // (例如. 首次:1000ms; 第二次: 3 * 1000ms; etc.)
|
|
// 'multiplier' => 3
|
|
// ],
|
|
]
|
|
);
|
|
|
|
try {
|
|
// 获取WeChat客户端
|
|
$this->app = new Application($config);
|
|
|
|
// 替换缓存
|
|
$this->app->setCache(ApplicationContext::getContainer()->get(CacheInterface::class));
|
|
|
|
} catch (InvalidArgumentException $e) {
|
|
throw new BusinessException('实例化EasyWeChat类失败:' . $e->getMessage(), HttpEnumCode::SERVER_ERROR);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* 获取wechat客户端
|
|
* @param string $appId
|
|
* @param string $appSecret
|
|
* @return AccessTokenAwareClient
|
|
*/
|
|
public function createClient(string $appId, string $appSecret): AccessTokenAwareClient
|
|
{
|
|
try {
|
|
// 获取WeChat客户端
|
|
$this->createApp($appId, $appSecret);
|
|
|
|
return $this->app->getClient();
|
|
|
|
} catch (NotFoundExceptionInterface|ContainerExceptionInterface $e) {
|
|
throw new BusinessException('实例化EasyWeChat类失败:' . $e->getMessage(), HttpEnumCode::SERVER_ERROR);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 根据 jsCode 获取用户 session 信息
|
|
* @param string $code code
|
|
* @return array
|
|
* @throws ClientExceptionInterface
|
|
* @throws ContainerExceptionInterface
|
|
* @throws DecodingExceptionInterface
|
|
* @throws NotFoundExceptionInterface
|
|
* @throws RedirectionExceptionInterface
|
|
* @throws ServerExceptionInterface
|
|
* @throws TransportExceptionInterface
|
|
*/
|
|
public function codeToSession(string $code): array
|
|
{
|
|
try {
|
|
$this->createApp($this->config['app_id'],$this->config['secret']);
|
|
$utils = $this->app->getUtils();
|
|
return $utils->codeToSession($code);
|
|
} catch (\Exception $e) {
|
|
throw new BusinessException($e->getMessage(), HttpEnumCode::SERVER_ERROR);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 解密微信会话信息
|
|
* @param string $sessionKey 会话密钥
|
|
* @param string $iv 加密算法的初始向量
|
|
* @param string $encryptedData 用户信息的加密数据
|
|
* @return array
|
|
* @throws ContainerExceptionInterface
|
|
* @throws NotFoundExceptionInterface
|
|
*/
|
|
public function decryptSession(string $sessionKey, string $iv, string $encryptedData): array
|
|
{
|
|
try {
|
|
$this->createApp($this->config['app_id'],$this->config['secret']);
|
|
|
|
$utils = $this->app->getUtils();
|
|
return $utils->decryptSession($sessionKey, $iv, $encryptedData);
|
|
} catch (\Exception $e) {
|
|
throw new BusinessException($e->getMessage(), HttpEnumCode::SERVER_ERROR);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取 access_token
|
|
* @return string
|
|
* @throws ContainerExceptionInterface
|
|
* @throws NotFoundExceptionInterface
|
|
*/
|
|
public function getAccessToken(): string
|
|
{
|
|
try {
|
|
$this->createApp($this->config['app_id'],$this->config['secret']);
|
|
|
|
$accessToken = $this->app->getAccessToken();
|
|
return $accessToken->getToken();
|
|
} catch (\Exception $e) {
|
|
throw new BusinessException($e->getMessage(), HttpEnumCode::SERVER_ERROR);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取手机号
|
|
* @param string $code
|
|
* @return array
|
|
* @throws ClientExceptionInterface
|
|
* @throws DecodingExceptionInterface
|
|
* @throws RedirectionExceptionInterface
|
|
* @throws ServerExceptionInterface
|
|
* @throws TransportExceptionInterface|BadResponseException
|
|
*/
|
|
public function getPhone(string $code): array
|
|
{
|
|
try {
|
|
$this->createApp($this->config['app_id'],$this->config['secret']);
|
|
|
|
$client = $this->createClient($this->config['app_id'],$this->config['secret']);
|
|
|
|
$options = [
|
|
"code" => $code,
|
|
];
|
|
|
|
$response = $client->postJson('wxa/business/getuserphonenumber', $options);
|
|
|
|
if ($response->isFailed()) {
|
|
// 出错了,处理异常
|
|
$result = $response->toArray();
|
|
if(empty($result)){
|
|
// 返回值为空
|
|
return [];
|
|
}
|
|
if (isset($result['errcode'])){
|
|
if ($result['errcode'] == "40029"){
|
|
// code过期
|
|
return [];
|
|
// throw new BusinessException( HttpEnumCode::getMessage(HttpEnumCode::GET_WX_ERROR),HttpEnumCode::GET_WX_ERROR);
|
|
}
|
|
}
|
|
return [];
|
|
}
|
|
|
|
return $response->toArray(false);
|
|
} catch (\Exception $e) {
|
|
throw new BusinessException($e->getMessage(), HttpEnumCode::SERVER_ERROR);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取分享二维码
|
|
* @throws NotFoundExceptionInterface
|
|
* @throws RedirectionExceptionInterface
|
|
* @throws ContainerExceptionInterface
|
|
* @throws DecodingExceptionInterface
|
|
* @throws ClientExceptionInterface
|
|
* @throws TransportExceptionInterface
|
|
* @throws ServerExceptionInterface
|
|
*/
|
|
public function getUnlimitedQRCode(array $options): array|string
|
|
{
|
|
try {
|
|
$this->createApp($this->config['app_id'], $this->config['secret']);
|
|
|
|
$client = $this->createClient($this->config['app_id'], $this->config['secret']);
|
|
|
|
$response = $client->postJson('wxa/getwxacodeunlimit', $options);
|
|
|
|
if ($response->isFailed()) {
|
|
// 出错了,处理异常
|
|
$result = $response->toArray();
|
|
if(empty($result)){
|
|
// 返回值为空
|
|
return [];
|
|
}
|
|
if (isset($result['errcode'])){
|
|
throw new BusinessException();
|
|
}
|
|
return [];
|
|
}
|
|
|
|
return $response->getContent(true);
|
|
|
|
} catch (\Exception $e) {
|
|
throw new BusinessException($e->getMessage(), HttpEnumCode::SERVER_ERROR);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取当前账号下订阅消息个人模版列表
|
|
* @return array|string
|
|
* @throws ClientExceptionInterface
|
|
* @throws ContainerExceptionInterface
|
|
* @throws DecodingExceptionInterface
|
|
* @throws NotFoundExceptionInterface
|
|
* @throws RedirectionExceptionInterface
|
|
* @throws ServerExceptionInterface
|
|
* @throws TransportExceptionInterface
|
|
*/
|
|
public function getTemplate(): array|string
|
|
{
|
|
try {
|
|
$this->createApp($this->config['app_id'], $this->config['secret']);
|
|
|
|
$client = $this->createClient($this->config['app_id'], $this->config['secret']);
|
|
|
|
$options = [];
|
|
$response = $client->get('wxaapi/newtmpl/gettemplate', $options);
|
|
if ($response->isFailed()) {
|
|
// 出错了,处理异常
|
|
$result = $response->toArray();
|
|
if(empty($result)){
|
|
// 返回值为空
|
|
return [];
|
|
}
|
|
if (isset($result['errcode'])){
|
|
throw new BusinessException();
|
|
}
|
|
return [];
|
|
}
|
|
|
|
return $response->getContent(false);
|
|
} catch (\Exception $e) {
|
|
throw new BusinessException($e->getMessage(), HttpEnumCode::SERVER_ERROR);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 发送订阅消息
|
|
* @throws NotFoundExceptionInterface
|
|
* @throws RedirectionExceptionInterface
|
|
* @throws ContainerExceptionInterface
|
|
* @throws DecodingExceptionInterface
|
|
* @throws ClientExceptionInterface
|
|
* @throws TransportExceptionInterface
|
|
* @throws ServerExceptionInterface
|
|
*/
|
|
public function sendSubscribeMessage(array $options): array|string
|
|
{
|
|
try {
|
|
$this->createApp($this->config['app_id'], $this->config['secret']);
|
|
|
|
$client = $this->createClient($this->config['app_id'], $this->config['secret']);
|
|
|
|
$response = $client->postJson('cgi-bin/message/subscribe/send', $options);
|
|
|
|
if ($response->isFailed()) {
|
|
// 出错了,处理异常
|
|
$result = $response->toArray();
|
|
if(empty($result)){
|
|
// 返回值为空
|
|
throw new BusinessException("返回值为空");
|
|
}
|
|
if (isset($result['errcode'])){
|
|
if ($result['errcode'] == 43101){
|
|
throw new BusinessException("用户拒绝接收消息");
|
|
}
|
|
throw new BusinessException($result['errmsg']);
|
|
}
|
|
throw new BusinessException();
|
|
}
|
|
|
|
return $response->getContent(false);
|
|
} catch (\Exception $e) {
|
|
throw new BusinessException($e->getMessage(), HttpEnumCode::SERVER_ERROR);
|
|
}
|
|
}
|
|
} |