创巨圆微信服务商管理平台
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.
 
 
 
 
cjy-mp-company/app/common/service/wechat/OpenPlatform.php

266 lines
11 KiB

<?php
namespace app\common\service\wechat;
use app\admin\model\Authorizers;
use app\common\model\WxcallbackBiz;
use app\common\model\WxcallbackComponent;
use app\common\service\BaseServices;
use EasyWeChat\Factory;
use EasyWeChat\OpenPlatform\Application;
use support\Log;
use support\Cache;
use Symfony\Component\HttpFoundation\HeaderBag;
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Db;
use Tinywan\ExceptionHandler\Exception\BadRequestHttpException;
class OpenPlatform extends BaseServices {
public Application $app;
private $platform_id;
/**
* @throws DataNotFoundException
* @throws ModelNotFoundException
* @throws DbException
* @throws BadRequestHttpException
*/
public function __construct($platform_id)
{
$this->platform_id = $platform_id;
$platform = $this->getPlatformParams($platform_id);
$this->app = Factory::openPlatform([
'app_id' => $platform['app_id'],
'secret' => $platform['secret'],
'token' => $platform['token'],
'aes_key' => $platform['aes_key'],
'debug' => true,
'log' => [
'default' => env('APP_DEBUG') ? 'dev' : 'prod', // 默认使用的 channel,生产环境可以改为下面的 prod
'channels' => [
// 测试环境
'dev' => [
'driver' => 'single',
'path' => runtime_path("logs/wechat-" . date('Y-m-d') . ".log"),
'level' => 'debug',
],
// 生产环境
'prod' => [
'driver' => 'daily',
'path' => runtime_path("logs/wechat-" . date('Y-m-d') . ".log"),
'level' => 'info',
],
],
],
]);
}
/**
* 处理开放平台消息
* @param $request
* @param string $appid
* @return false|string
*/
public function handle($request, string $appid = '')
{
// https://zhuanlan.zhihu.com/p/659727799 授权事件、消息与事件通知
try {
$symfony_request = new SymfonyRequest($request->get(), $request->post(), [], $request->cookie(), [], [], $request->rawBody());
$symfony_request->headers = new HeaderBag($request->header());
$this->app->rebind('request', $symfony_request);
// 授权事件
$this->app->server->push(function ($message) {
if (isset($message['InfoType'])) {
// 授权事件 日志记录
$this->addComponentCallBackRecord($message);
switch ($message['InfoType']) {
case 'notify_third_fastregisterbetaapp':
// 过滤掉重复请求
$key = 'wechat_mp_' . md5(json_encode($message));
if (Cache::has($key)) {
Log::info('收到重复注册试用小程序请求,已过滤');
return 'success';
} else {
Cache::set($key, '', 10);
}
FastRegisterApp::callback($message);
return 'success';
case 'authorized':
case 'updateauthorized':
$this->addAuthorizerInfo($message);
break;
case 'unauthorized':
$this->delAuthorizerInfo($message);
break;
default:
break;
}
}
return 'success';
});
// 消息与事件通知 日志记录
$message = $this->app->server->getMessage();
if (isset($message['Event'])) {
$this->addWxcallbackBizRecord($message, $appid);
}
$response = $this->app->server->serve();
return $response->getContent();
} catch (\Exception $e){
Log::error($e->getMessage());
return $e->getMessage();
}
}
/**
* 重新获取授权账号列表
* @param $platform_id
* @throws BadRequestHttpException
*/
public function refresh($platform_id)
{
try {
Db::startTrans();
$model = new Authorizers();
$model->where('platform_id', $platform_id)->delete();
$list = $this->app->getAuthorizers();
$insert_data = [];
foreach ($list['list'] as $item) {
$program = $this->app->getAuthorizer($item['authorizer_appid']);
$program_authorizer_info = $program['authorizer_info'];
$program_authorization_info = $program['authorization_info'];
$insert_data[] = [
'platform_id' => $platform_id,
'appid' => $item['authorizer_appid'] ?? '',
'refreshtoken' => $program_authorization_info['authorizer_refresh_token'],
'auth_time' => $item['auth_time'] ?? '',
'app_type' => isset($program_authorizer_info['MiniProgramInfo']),
'nick_name' => $program_authorizer_info['nick_name'] ?? '',
'user_name' => $program_authorizer_info['user_name'] ?? '',
'head_img' => $program_authorizer_info['head_img'] ?? '',
'qrcode_url' => $program_authorizer_info['qrcode_url'] ?? '',
'principal_name' => $program_authorizer_info['principal_name'] ?? '',
'register_type' => $program_authorizer_info['register_type'] ?? '',
'verify_info' => $program_authorizer_info['verify_type_info']['id'] ?? '',
'service_type' => $program_authorizer_info['service_type_info']['id'] ?? '',
'account_status' => $program_authorizer_info['account_status'] ?? '',
'is_phone' => $program_authorizer_info['basic_config']['is_phone_configured'] ?? '',
'is_email' => $program_authorizer_info['basic_config']['is_email_configured'] ?? '',
'func_info' => $program_authorization_info['func_info'] ? json_encode($program_authorization_info['func_info'], JSON_UNESCAPED_UNICODE) : '',
'json_data' => json_encode($program, true),
];
}
$model->saveAll($insert_data);
Db::commit();
} catch (\Exception $e) {
Db::rollback();
throw new BadRequestHttpException($e->getMessage());
}
}
/**
* 保存小程序信息
* */
public function addAuthorizerInfo($data)
{
$program = $this->app->getAuthorizer($data['AuthorizerAppid']);
$program_authorizer_info = $program['authorizer_info'];
$program_authorization_info = $program['authorization_info'];
// 有时候平台不返回refresh_token,需要根据code手动去获取refresh_token
// 刷新令牌authorizer_refresh_token是需要一直保存的?有有效期这个说法吗?
// https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/2.0/troubleshooting/TroubleShooting.html
if (!$program_authorization_info['authorizer_refresh_token']){
$program_authorization_info = $this->app->handleAuthorize($data['AuthorizationCode']);
$program_authorization_info = $program_authorization_info['authorization_info'];
}
$insert_data = [
'platform_id' => $this->platform_id,
'appid' => $program_authorization_info['authorizer_appid'] ?? '',
'refreshtoken' => $program_authorization_info['authorizer_refresh_token'] ?? '',
'auth_time' => time(),
'app_type' => isset($program_authorizer_info['MiniProgramInfo']),
'nick_name' => $program_authorizer_info['nick_name'] ?? '',
'user_name' => $program_authorizer_info['user_name'] ?? '',
'head_img' => $program_authorizer_info['head_img'] ?? '',
'qrcode_url' => $program_authorizer_info['qrcode_url'] ?? '',
'principal_name' => $program_authorizer_info['principal_name'] ?? '',
'register_type' => $program_authorizer_info['register_type'] ?? '',
'verify_info' => $program_authorizer_info['verify_type_info']['id'] ?? '',
'service_type' => $program_authorizer_info['service_type_info']['id'] ?? '',
'account_status' => $program_authorizer_info['account_status'] ?? '',
'is_phone' => $program_authorizer_info['basic_config']['is_phone_configured'] ?? '',
'is_email' => $program_authorizer_info['basic_config']['is_email_configured'] ?? '',
'func_info' => $program_authorization_info['func_info'] ? json_encode($program_authorization_info['func_info'], JSON_UNESCAPED_UNICODE) : '',
'json_data' => json_encode($program, true),
];
$row = Authorizers::find(['appid' => $insert_data['appid']]);
if ($row){
Authorizers::update($insert_data, ['appid' => $insert_data['appid']]);
}else{
Authorizers::create($insert_data);
}
}
/**
* 删除小程序授权信息
* @return void
*/
public function delAuthorizerInfo($data){
Authorizers::destroy(['appid' => $data['AuthorizerAppid']]);
}
public function getTemplate()
{
return $this->app->code_template->list();
}
private function addComponentCallBackRecord($data)
{
$row = [
'appid' => $data['AppId'],
'authorizer_appid' => $data['AuthorizerAppid'] ?? null,
'infotype' => $data['InfoType'],
'postbody' => json_encode($data),
'receivetime' => $data['CreateTime']
];
WxcallbackComponent::create($row);
}
private function addWxcallbackBizRecord($data, $appid)
{
$row = [
'appid' => $appid,
'tousername' => $data['ToUserName'],
'msgtype' => $data['MsgType'],
'event' => $data['Event'],
'postbody' => json_encode($data),
'receivetime' => $data['CreateTime']
];
WxcallbackBiz::create($row);
}
public function getPcAuthorizerUrl()
{
$pre_code = $this->app->createPreAuthorizationCode();
$callback = env('SITE_URL') . '/auth/callback';
$pc_url = $this->app->getPreAuthorizationUrl($callback, $pre_code);
$mobile_url = $this->app->getMobilePreAuthorizationUrl($callback, $pre_code);
return [
'pc_url' => urlencode($pc_url),
'mobile_url' => urlencode($mobile_url)
];
}
/**
* 注册试用小程序
* @param $name
* @param $openid
* @return mixed
*/
public function fastRegisterBetaApp($name, $openid)
{
return $this->app->httpPostJson('wxa/component/fastregisterbetaweapp', compact('name', 'openid'));
}
}