1071 lines
39 KiB
PHP
1071 lines
39 KiB
PHP
<?php
|
||
|
||
namespace App\Services;
|
||
use App\Http\Response\CatchError;
|
||
use App\Models\ESTP\User as EstpUser;
|
||
use App\Models\User;
|
||
use App\Models\Wechat;
|
||
use EasyWeChat\Kernel\Support\Str;
|
||
use EasyWeChat\MiniApp\Application;
|
||
use EasyWeChat\Work\Application as WorkApplication;
|
||
use EasyWeChat\OfficialAccount\Application as OfficialApplication;
|
||
use Illuminate\Support\Facades\Cache;
|
||
use Illuminate\Support\Facades\DB;
|
||
use Illuminate\Support\Facades\Log;
|
||
use App\Facades\UploadService;
|
||
use Symfony\Component\Cache\Psr16Cache;
|
||
use WeChatPay\Builder;
|
||
use WeChatPay\Crypto\Rsa;
|
||
use WeChatPay\Formatter;
|
||
use WeChatPay\Util\PemUtil;
|
||
|
||
class WechatService
|
||
{
|
||
use CatchError;
|
||
protected $app, $official_app, $official_access_token, $mp_access_token;
|
||
|
||
public function __construct()
|
||
{
|
||
//小程序
|
||
$config = config('wechat.mini_program');
|
||
$app = new Application($config);
|
||
$this->app = $app;
|
||
//公众号
|
||
$config = config('wechat.official_account.default');
|
||
$official_app = new OfficialApplication($config);
|
||
|
||
// $app->setCache(new Psr16Cache(app('cache.psr6')));
|
||
|
||
|
||
// $access_token_key = "mp_access_token";
|
||
// Log::info("当前access_token: {$app->getAccessToken()->getToken()}");
|
||
// if (config('app.env') == 'production') {
|
||
// if (Cache::has($access_token_key)) {
|
||
// $this->mp_access_token = Cache::get($access_token_key);
|
||
// }else {
|
||
// $app->getAccessToken()->refresh();
|
||
// $this->mp_access_token = $app->getAccessToken()->getToken();
|
||
// Cache::put($access_token_key, $this->mp_access_token, now()->addMinutes(90));
|
||
// }
|
||
// }
|
||
// Log::info("缓存access_token: {$this->mp_access_token}");
|
||
|
||
// $official_app->setCache(new Psr16Cache(app('cache.psr6')));
|
||
// $app->setCache(new Psr16Cache(app('cache.psr6')));
|
||
|
||
|
||
// $access_token_key = "official_access_token";
|
||
// Log::info("当前access_token: {$official_app->getAccessToken()->getToken()}");
|
||
// if (config('app.env') == 'production') {
|
||
// if (Cache::has($access_token_key)) {
|
||
// $this->official_access_token = Cache::get($access_token_key);
|
||
// }else {
|
||
// $official_app->getAccessToken()->refresh();
|
||
// $this->official_access_token = $official_app->getAccessToken()->getToken();
|
||
// Cache::put($access_token_key, $this->official_access_token, now()->addMinutes(90));
|
||
// }
|
||
// }
|
||
// Log::info("缓存access_token: {$this->official_access_token}");
|
||
$this->official_app = $official_app;
|
||
|
||
}
|
||
|
||
public function instance()
|
||
{
|
||
//商户号
|
||
$merchantId = config('wechat.payment.mch_id');
|
||
// 从本地文件中加载「商户API私钥」,「商户API私钥」会用来生成请求的签名
|
||
$merchantPrivateKeyFilePath = 'file://' . config('wechat.payment.private_key');
|
||
$merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);
|
||
|
||
// 「商户API证书」的「证书序列号」
|
||
$merchantCertificateSerial = config('wechat.payment.serial');
|
||
|
||
// 从本地文件中加载「微信支付平台证书」,用来验证微信支付应答的签名
|
||
$platformCertificateFilePath = 'file://' . config('wechat.payment.certificate');
|
||
$platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);
|
||
|
||
// 从「微信支付平台证书」中获取「证书序列号」
|
||
$platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath);
|
||
// 构造一个 APIv3 客户端实例
|
||
$instance = Builder::factory([
|
||
'mchid' => $merchantId,
|
||
'serial' => $merchantCertificateSerial,
|
||
'privateKey' => $merchantPrivateKeyInstance,
|
||
'certs' => [
|
||
$platformCertificateSerial => $platformPublicKeyInstance,
|
||
],
|
||
]);
|
||
return $instance;
|
||
|
||
}
|
||
|
||
public function app()
|
||
{
|
||
return $this->app;
|
||
}
|
||
|
||
/**
|
||
* 公众号
|
||
* @return \EasyWeChat\OfficialAccount\Application
|
||
*/
|
||
public function officialApp()
|
||
{
|
||
return $this->official_app;
|
||
}
|
||
/**
|
||
* 企业微信
|
||
* @return WorkApplication
|
||
*/
|
||
public function workApp($type)
|
||
{
|
||
$work_config = config('wechat.' . $type);
|
||
$work_app = new WorkApplication($work_config);
|
||
return $work_app;
|
||
}
|
||
|
||
|
||
/**
|
||
* 小程序code 换取session 信息
|
||
* @param $code
|
||
* @param string $grant_type
|
||
* @return array
|
||
* @throws \Exception
|
||
*/
|
||
public function codeToSession($code, $grant_type = 'authorization_code')
|
||
{
|
||
try {
|
||
$utils = $this->app->getUtils();
|
||
$response = $utils->codeToSession($code);
|
||
return $response;
|
||
} catch (\Throwable $e) {
|
||
throw new \Exception($e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 小程序code换取手机号信息
|
||
* @param $code
|
||
* @return array|string[]
|
||
* @throws \Exception
|
||
*/
|
||
public function phoneNuber($code)
|
||
{
|
||
try {
|
||
if (env('APP_ENV') == 'local')
|
||
return ['mobile' => '15872844805'];
|
||
$data = ['code' => (string) $code];
|
||
$res = $this->app->getClient()->postJson('wxa/business/getuserphonenumber', $data);
|
||
if ($res->isFailed())
|
||
throw new \Exception($res->getContent());
|
||
$r = json_decode($res->toJson());
|
||
return ['mobile' => $r->phone_info->phoneNumber];
|
||
} catch (\Throwable $e) {
|
||
throw new \Exception($e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 小程序订阅消息列表
|
||
* @return mixed|null
|
||
* @throws \Exception
|
||
*/
|
||
public function templates()
|
||
{
|
||
try {
|
||
$res = $this->app->getClient()->get('wxaapi/newtmpl/gettemplate');
|
||
if ($res->isFailed())
|
||
throw new \Exception($res->getContent());
|
||
return $res['data'] ?? null;
|
||
} catch (\Throwable $e) {
|
||
throw new \Exception($e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 小程序发送订阅消息
|
||
* @param $openid
|
||
* @param $template_id
|
||
* @param $page
|
||
* @param array $data
|
||
* @return bool|int|mixed
|
||
*/
|
||
public function subSend($openid, $template_id, $page, $data = [])
|
||
{
|
||
try {
|
||
if (empty($openid))
|
||
return false;
|
||
$all_data = [
|
||
'template_id' => $template_id,
|
||
'touser' => $openid,
|
||
'page' => $page,
|
||
'data' => $data,
|
||
'miniprogram_state' => (env('APP_ENV') == 'production') ? 'formal' : 'developer',
|
||
'lang' => 'zh_CN',
|
||
];
|
||
$client = $this->app->getClient();
|
||
$response = $client->postJson('cgi-bin/message/subscribe/send', $all_data);
|
||
$all_data['type'] = 'mp';
|
||
if ($response['errcode']) {
|
||
$all_data['err_msg'] = $response['errmsg'];
|
||
$all_data['status'] = 0;
|
||
} else {
|
||
$all_data['err_msg'] = '';
|
||
$all_data['status'] = 1;
|
||
}
|
||
// $this->addTemplateMsgLog($all_data);
|
||
return $response['errcode'] ?? 1;
|
||
} catch (\Throwable $e) {
|
||
$this->getError($e);
|
||
return true;
|
||
}
|
||
}
|
||
|
||
// public function addTemplateMsgLog($data)
|
||
// {
|
||
// $where = $data['type'] == 'mp'?['openid'=>$data['touser']]:['official_openid'=>$data['touser']];
|
||
// $user_id = Wechat::where($where)->value('user_id');
|
||
// $log = new TemplateMsgLog;
|
||
// $log->user_id = $user_id;
|
||
// $log->openid = $data['touser'];
|
||
// $log->type = $data['type'];
|
||
// $log->template_id = $data['template_id'];
|
||
// $log->status = $data['status'];
|
||
// $log->err_msg = $data['err_msg']??'';
|
||
// $log->data = json_encode($data);
|
||
// $log->save();
|
||
// return true;
|
||
// }
|
||
|
||
/**
|
||
* 获取小程序二维码
|
||
* @param $scene
|
||
* @param $page
|
||
* @param string $env_version 正式版为 "release",体验版为 "trial",开发版为 "develop"。默认是正式版。
|
||
* @param int $width
|
||
* @param bool $is_hyaline
|
||
* @return string
|
||
* @throws \EasyWeChat\Kernel\Exceptions\BadResponseException
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
|
||
*/
|
||
public function getMPQrcode($scene, $page, $env_version = 'release', $width = 430, $is_hyaline = true)
|
||
{
|
||
$app = $this->app;
|
||
$response = $app->getClient()->postJson('/wxa/getwxacodeunlimit', [
|
||
'scene' => $scene,
|
||
'page' => $page,
|
||
'width' => $width,
|
||
'is_hyaline' => $is_hyaline,
|
||
'env_version' => $env_version,
|
||
'check_path' => false
|
||
]);
|
||
$file_name = uniqid() . time() . 'qrcode.png';
|
||
$path = storage_path('qrcode/' . $file_name);
|
||
$response->saveAs($path);
|
||
$pic = '';
|
||
if (file_exists($path)) {
|
||
$pic = UploadService::uploadFile($path);
|
||
@unlink($path);
|
||
}
|
||
return $pic;
|
||
}
|
||
|
||
/**
|
||
* 小程序支付
|
||
* @param $trade_no
|
||
* @param $openid
|
||
* @param $total
|
||
* @param $desc
|
||
* @param $callback
|
||
* @return array|false
|
||
*/
|
||
public function mpPay($trade_no, $openid, $total, $desc, $callback, $appId = '', $sub_mchid = '')
|
||
{
|
||
if (config('wechat.payment.debug')) {
|
||
return false;
|
||
}
|
||
$sub_appid = config('wechat.payment.sub_app_id');
|
||
if ($appId) {
|
||
$sub_appid = $appId;
|
||
}
|
||
$resp = $this->instance()
|
||
->chain('v3/pay/partner/transactions/jsapi')
|
||
->post([
|
||
'json' => [
|
||
'sp_mchid' => config('wechat.payment.mch_id'),
|
||
'sp_appid' => config('wechat.payment.sp_appid'),
|
||
'sub_appid' => $sub_appid,
|
||
'sub_mchid' => $sub_mchid ?: config('wechat.payment.sub_merchant_id'),
|
||
'out_trade_no' => $trade_no,
|
||
'description' => $desc,
|
||
'notify_url' => $callback,
|
||
'amount' => [
|
||
'total' => (int) number_format($total * 100, 0, '', ''),
|
||
'currency' => 'CNY'
|
||
],
|
||
'payer' => [
|
||
'sub_openid' => $openid,
|
||
]
|
||
]
|
||
]);
|
||
$res = json_decode($resp->getBody());
|
||
$prepay_id = $res->prepay_id;
|
||
$config = $this->paySign($prepay_id, $sub_appid);
|
||
$config['prepay_id'] = $prepay_id;
|
||
return $config;
|
||
}
|
||
|
||
/**
|
||
* 获取jssdk配置
|
||
* @param $url
|
||
* @return mixed[]
|
||
* @throws \EasyWeChat\Kernel\Exceptions\HttpException
|
||
* @throws \Psr\SimpleCache\InvalidArgumentException
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
|
||
*/
|
||
// public function getOfficialShareConfig($url){
|
||
// $app = $this->officialApp();
|
||
// $config = $app->getUtils()->buildJsSdkConfig($url, ['updateAppMessageShareData','updateTimelineShareData','onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ', 'onMenuShareWeibo', 'onMenuShareQZone', 'openLocation', 'getLocation', 'chooseImage', 'previewImage', 'uploadImage', 'downloadImage', 'openAddress', 'updateAppMessageShareData', 'updateTimelineShareData', 'wx-open-launch-weapp', 'chooseVideo', 'hideMenuItems','showMenuItems'], ['wx-open-launch-weapp'], false);
|
||
// return $config;
|
||
// }
|
||
|
||
public function buildJsSdkConfig($url)
|
||
{
|
||
// $app = $this->officialApp();
|
||
// $api = $app->getClient();
|
||
$token_url = config('app.url') . '/go/api/h5/v1/common/accesstoken/get';
|
||
$params = ['curr_date' => "#" . date("Y-m-d") . "@-"];
|
||
try {
|
||
$res = \App\Facades\HttpService::postData($token_url, $params);
|
||
$access_token = $res['data'];
|
||
} catch (\Exception $e) {
|
||
$access_token = '';
|
||
}
|
||
// $res = $api->get("cgi-bin/ticket/getticket?access_token=$access_token&type=jsapi");
|
||
// if ($res->isFailed()) {
|
||
//
|
||
// }
|
||
// $res = json_decode($res->toJson(),true);
|
||
$ticket_url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" . $access_token . "&type=jsapi";
|
||
$res = \App\Facades\HttpService::getData($ticket_url);
|
||
Log::info("获取微信ticket cgi-bin/ticket/getticket?access_token=$access_token&type=jsapi");
|
||
Log::info($res);
|
||
$ticket = $res['ticket'];
|
||
$nonce = Str::random();
|
||
$timestamp = time();
|
||
$signature = sha1("jsapi_ticket=$ticket&noncestr=$nonce×tamp=$timestamp&url=$url");
|
||
$jsApiList = ['updateAppMessageShareData', 'updateTimelineShareData', 'onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ', 'onMenuShareWeibo', 'onMenuShareQZone', 'openLocation', 'getLocation', 'chooseImage', 'previewImage', 'uploadImage', 'downloadImage', 'openAddress', 'updateAppMessageShareData', 'updateTimelineShareData', 'wx-open-launch-weapp', 'chooseVideo', 'hideMenuItems', 'showMenuItems'];
|
||
$openTagList = ['wx-open-launch-weapp'];
|
||
return [
|
||
'appId' => config('wechat.official_account.default.app_id'),
|
||
'beta' => false,
|
||
'debug' => false,
|
||
'jsApiList' => $jsApiList,
|
||
'nonceStr' => $nonce,
|
||
'openTagList' => $openTagList,
|
||
'signature' => $signature,
|
||
'timestamp' => $timestamp,
|
||
'url' => $url,
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 退款
|
||
* @param $trade_no
|
||
* @param $refund_trade_no
|
||
* @param $total_amount
|
||
* @param $refund_amount
|
||
* @param array $array
|
||
* @return array
|
||
*/
|
||
public function refund($trade_no, $refund_trade_no, $total_amount, $refund_amount, $callback, $sub_mchid = '')
|
||
{
|
||
if (config('wechat.payment.debug')) {
|
||
return ["status" => true, 'msg' => ''];
|
||
}
|
||
if (!$sub_mchid) {
|
||
$sub_mchid = config('wechat.payment.sub_merchant_id');
|
||
}
|
||
try {
|
||
$resp = $this->instance()
|
||
->chain('v3/refund/domestic/refunds')
|
||
->post([
|
||
'json' => [
|
||
'sub_mchid' => $sub_mchid,
|
||
'out_trade_no' => $trade_no,
|
||
'out_refund_no' => $refund_trade_no,
|
||
'notify_url' => $callback,
|
||
'amount' => [
|
||
'total' => (int) number_format($total_amount * 100, 0, '', ''),
|
||
'refund' => (int) number_format($refund_amount * 100, 0, '', ''),
|
||
'currency' => 'CNY'
|
||
],
|
||
]
|
||
]);
|
||
$res = json_decode($resp->getBody());
|
||
Log::info($resp->getBody());
|
||
if ($res->status == 'PROCESSING' || $res->status == "SUCCESS") {
|
||
return ['status' => true, 'msg' => ''];
|
||
}
|
||
return ['status' => false, 'msg' => '打款失败'];
|
||
} catch (\Exception $e) {
|
||
$msg = $e->getMessage();
|
||
Log::info($msg);
|
||
return ['status' => false, 'msg' => $msg];
|
||
}
|
||
|
||
}
|
||
|
||
/**
|
||
* 退款订单查询
|
||
* @param string $refund_trade_no 退款订单号
|
||
*/
|
||
public function orderRefunded($refund_trade_no, $sub_mch_id = null)
|
||
{
|
||
if (config('wechat.payment.debug')) {
|
||
return ['status' => true, 'message' => ""];
|
||
}
|
||
try {
|
||
if (!$sub_mch_id) {
|
||
$sub_mch_id = config('wechat.payment.sub_merchant_id');
|
||
}
|
||
$resp = $this->instance()
|
||
->chain('v3/refund/domestic/refunds/' . $refund_trade_no)
|
||
->get([
|
||
'query' => [
|
||
'sub_mchid' => $sub_mch_id
|
||
],
|
||
'out_refund_no' => $refund_trade_no,
|
||
]);
|
||
$res = json_decode($resp->getBody());
|
||
if ($res->status == 'SUCCESS') {
|
||
return ['status' => true, 'message' => ""];
|
||
}
|
||
return ['status' => false, 'message' => "退款失败"];
|
||
} catch (\Exception $e) {
|
||
Log::debug($refund_trade_no . '订单查询退款异常:' . $e->getMessage());
|
||
return ['status' => false, 'message' => $e->getMessage()];
|
||
}
|
||
}
|
||
/**
|
||
* 小程序-查询订单是否支付
|
||
* @param $trade_no
|
||
* @return bool
|
||
*/
|
||
public function mpPaid($trade_no, $sub_mch_id = '')
|
||
{
|
||
if (config('wechat.payment.debug')) {
|
||
return false;
|
||
}
|
||
if (empty($sub_mch_id)) {
|
||
$sub_mch_id = config('wechat.payment.sub_merchant_id');
|
||
}
|
||
$resp = $this->instance()
|
||
->chain('v3/pay/partner/transactions/out-trade-no/' . $trade_no)
|
||
->get([
|
||
// Query 参数
|
||
'query' => [
|
||
'sp_mchid' => config('wechat.payment.mch_id'),
|
||
'sub_mchid' => $sub_mch_id,
|
||
],
|
||
// 变量名 => 变量值
|
||
'out_trade_no' => $trade_no,
|
||
]);
|
||
Log::info($resp->getBody());
|
||
$res = json_decode($resp->getBody());
|
||
if (empty($res))
|
||
return true;
|
||
if ($res->trade_state == 'NOTPAY' || $res->trade_state == "CLOSED")
|
||
return $res->trade_state_desc;
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* 小程序-支付签名
|
||
* @param $prepay_id
|
||
* @return array
|
||
*/
|
||
public function paySign($prepay_id, $sub_appid)
|
||
{
|
||
$merchantPrivateKeyFilePath = 'file://' . config('wechat.payment.private_key');
|
||
$merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath);
|
||
$params = [
|
||
// 'appId' => config('wechat.mini_program.app_id'),
|
||
'appId' => $sub_appid,
|
||
'timeStamp' => (string) Formatter::timestamp(),
|
||
'nonceStr' => Formatter::nonce(),
|
||
'package' => 'prepay_id=' . $prepay_id,
|
||
];
|
||
$params += [
|
||
'paySign' => Rsa::sign(
|
||
Formatter::joinedByLineFeed(...array_values($params)),
|
||
$merchantPrivateKeyInstance
|
||
),
|
||
'signType' => 'RSA'
|
||
];
|
||
|
||
return $params;
|
||
}
|
||
|
||
public function sendSubscribeMessage($params)
|
||
{
|
||
if (config('app.env') == 'production') {
|
||
|
||
$app = $this->app;
|
||
// $accessToken = $app->getAccessToken();
|
||
// $accessToken->getToken();
|
||
$response = $app->getClient()->postJson('cgi-bin/message/subscribe/send', $params);
|
||
// if ($response['errcode'] && $response['errcode'] != "43101") {
|
||
Log::info($params);
|
||
//todo 发送失败
|
||
// throw new \Exception($response['errmsg']);
|
||
// }
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 公众号-后台服务
|
||
* @return \Psr\Http\Message\ResponseInterface
|
||
* @throws \EasyWeChat\Kernel\Exceptions\BadRequestException
|
||
* @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
|
||
* @throws \EasyWeChat\Kernel\Exceptions\RuntimeException
|
||
* @throws \ReflectionException
|
||
* @throws \Throwable
|
||
*/
|
||
public function server()
|
||
{
|
||
$app = $this->officialApp();
|
||
$server = $app->getServer();
|
||
$server->with(function ($message, \Closure $next) {
|
||
Log::info("api server");
|
||
// 你的自定义逻辑
|
||
// Log::info($message);
|
||
|
||
$openid = $message->FromUserName;
|
||
//获取微信用户信息
|
||
$info = $this->wechatUserByOfficialOpenid($openid);
|
||
Log::info($openid . '用户信息', $info);
|
||
if ($message->MsgType == 'event') {
|
||
if ($message->Event == 'subscribe' || $message->Event == 'unsubscribe') {//关注
|
||
//同步健康信息
|
||
$this->syncSubscribe($info);
|
||
}
|
||
}
|
||
//同步创业家项目关注信息
|
||
// $this->syncEstpSubscribe($info);
|
||
return $next($message);
|
||
});
|
||
|
||
return $server->serve();
|
||
}
|
||
|
||
/**
|
||
* 同步公众号关注
|
||
* @param $info
|
||
*/
|
||
public function syncSubscribe($info)
|
||
{
|
||
$subscribe = $info['subscribe'];
|
||
if ($subscribe) {
|
||
//是否有本地小程序信息信息
|
||
$wechat = Wechat::where(['unionid' => $info['unionid'], 'type' => 'mp'])->first();
|
||
// if (empty($wechat)) return ;
|
||
DB::beginTransaction();
|
||
//是否有本地公众号信息信息
|
||
$official_wechat = Wechat::where('type', 'official')
|
||
->where('openid', $info['openid'])
|
||
->first();
|
||
if (empty($official_wechat))
|
||
return;
|
||
// if (!empty($wechat)){
|
||
// $official_wechat->user_id = $wechat->user_id;
|
||
// }
|
||
$official_wechat->unionid = $info['unionid'];
|
||
$official_wechat->save();
|
||
} else {
|
||
$official_wechat = Wechat::where(['openid' => $info['openid'], 'type' => 'official'])->first();
|
||
if (empty($official_wechat))
|
||
return;
|
||
}
|
||
//同步关注信息
|
||
User::where('id', $official_wechat->user_id)->update(['is_subscribe' => $subscribe]);
|
||
DB::commit();
|
||
}
|
||
|
||
/**
|
||
* 同步创业家项目关注
|
||
* @param $info
|
||
*/
|
||
public function syncEstpSubscribe($info)
|
||
{
|
||
$subscribe = $info['subscribe'];
|
||
if ($subscribe) {
|
||
//关注
|
||
$user = EstpUser::query()->where('unionid', $info['unionid'])->first();
|
||
if ($user) {
|
||
$user['is_subscribe'] = $subscribe;
|
||
$user['openid'] = $info['openid'];
|
||
$user->save();
|
||
}
|
||
|
||
} else {
|
||
//取关
|
||
$user = EstpUser::query()->where('openid', $info['openid'])->first();
|
||
if ($user) {
|
||
$user['is_subscribe'] = $subscribe;
|
||
$user['open_recommend'] = $subscribe;
|
||
$user->save();
|
||
}
|
||
}
|
||
|
||
if ($user) {
|
||
Log::info([
|
||
'msg' => '已更新创业家' . ['取关', '关注'][$subscribe] . '信息',
|
||
'data' => $user->toArray(),
|
||
]);
|
||
}
|
||
|
||
}
|
||
|
||
/**
|
||
* 公众号-通过openid获取用户信息
|
||
* @param $openid
|
||
* @return mixed
|
||
* @throws \EasyWeChat\Kernel\Exceptions\BadResponseException
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
|
||
*/
|
||
public function wechatUserByOfficialOpenid($openid)
|
||
{
|
||
// $app = $this->officialApp();
|
||
// $api = $app->getClient();
|
||
//处理token过期报错
|
||
// $accessToken = $this->official_access_token;
|
||
// $accessToken = $app->getAccessToken()->getToken();
|
||
$url = config('app.url') . '/go/api/h5/v1/common/accesstoken/get';
|
||
$params = ['curr_date' => "#" . date("Y-m-d") . "@-"];
|
||
try {
|
||
$res = \App\Facades\HttpService::postData($url, $params);
|
||
$access_token = $res['data'];
|
||
} catch (\Exception $e) {
|
||
$access_token = '';
|
||
}
|
||
|
||
$url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=$access_token&openid=$openid";
|
||
$res = \App\Facades\HttpService::getData($url);
|
||
return $res;
|
||
// $response = $api->get('/cgi-bin/user/info', [
|
||
// "openid" => $openid,
|
||
// "access_token" => $access_token,
|
||
// ]);
|
||
// if ($response->isFailed()) {
|
||
// throw new \Exception("通过openid获取用户微信信息失败, ".$response->getContent());
|
||
// }
|
||
// $content = $response->toJson();
|
||
// return json_decode($content,true);
|
||
}
|
||
|
||
/**
|
||
* 公众号-发送模板消息
|
||
* @param $param
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
|
||
*/
|
||
public function sendTemplateNotice($param)
|
||
{
|
||
if (config('app.env') == 'production') {
|
||
// $app = $this->officialApp();
|
||
// $api = $app->getClient();
|
||
// $accessToken = $app->getAccessToken()->getToken();
|
||
// $accessToken = $this->official_access_token;
|
||
$url = config('app.url') . '/go/api/h5/v1/common/accesstoken/get';
|
||
$params = ['curr_date' => "#" . date("Y-m-d") . "@-"];
|
||
try {
|
||
$res = \App\Facades\HttpService::postData($url, $params);
|
||
$access_token = $res['data'];
|
||
} catch (\Exception $e) {
|
||
$access_token = '';
|
||
}
|
||
|
||
$url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" . $access_token;
|
||
$res = \App\Facades\HttpService::postData($url, $param);
|
||
// $response = $api->postJson('/cgi-bin/message/template/send?access_token=' . $access_token, $param);
|
||
// if ($response->isFailed()) {
|
||
// $errMsg = $response->toJson();
|
||
// $errMsg = json_decode($errMsg,true);
|
||
// if (isset($errMsg['errcode']) && $errMsg['errcode'] == 40001) {
|
||
// $app->getAccessToken()->refresh();
|
||
// $newResponse = $api->postJson('/cgi-bin/message/template/send', $param);
|
||
// Log::error("sendTemplateNotice1".$newResponse->getContent());
|
||
// throw new \Exception("发送模板消息失败, ".$response->getContent());
|
||
// }
|
||
// Log::error("sendTemplateNotice" . $response->getContent());
|
||
// }
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取公众号二维码
|
||
* @param $param
|
||
* @return mixed
|
||
* @throws \EasyWeChat\Kernel\Exceptions\BadResponseException
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
|
||
*/
|
||
public function getOfficialQrcode($param)
|
||
{
|
||
// $app = $this->officialApp();
|
||
// $api = $app->getClient();
|
||
// $accessToken = $this->official_access_token;
|
||
$url = config('app.url') . '/go/api/h5/v1/common/accesstoken/get';
|
||
$params = ['curr_date' => "#" . date("Y-m-d") . "@-"];
|
||
try {
|
||
$res = \App\Facades\HttpService::postData($url, $params);
|
||
$access_token = $res['data'];
|
||
} catch (\Exception $e) {
|
||
$access_token = '';
|
||
}
|
||
|
||
$url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" . $access_token;
|
||
$res = \App\Facades\HttpService::postData($url, $param);
|
||
return $res;
|
||
// $response = $api->postJson('/cgi-bin/qrcode/create?access_token=' . $access_token, $param);
|
||
// $content = $response->toJson();
|
||
// return json_decode($content,true);
|
||
}
|
||
/**
|
||
* 发送群消息
|
||
* @param $touser
|
||
* @param $msgtype
|
||
* @param $content
|
||
* @param string $toparty
|
||
* @param string $totag
|
||
* @param int $enable_duplicate_check
|
||
* @param int $duplicate_check_interval
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
|
||
*/
|
||
public function sendWorkMessage($touser, $msgtype, $content, $toparty = '', $totag = '', $enable_duplicate_check = 0, $duplicate_check_interval = 1800)
|
||
{
|
||
|
||
$api = $this->workApp('work_application')->getClient();
|
||
|
||
$params = [
|
||
"touser" => $touser,
|
||
'toparty' => $toparty,
|
||
'totag' => $totag,
|
||
"msgtype" => $msgtype,
|
||
"agentid" => 1000008,
|
||
"safe" => 0,
|
||
$msgtype => $content,
|
||
"enable_duplicate_check" => $enable_duplicate_check,
|
||
"duplicate_check_interval" => $duplicate_check_interval
|
||
];
|
||
$response = $api->postJson('/cgi-bin/message/send', $params);
|
||
if ($response->isFailed()) {
|
||
// 出错了,处理异常
|
||
throw new \Exception($response->getContent());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 发送应用消息
|
||
* @param $chatid
|
||
* @param $msgtype
|
||
* @param $content
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
|
||
*/
|
||
public function sendAppChat($chatid, $msgtype, $content)
|
||
{
|
||
$api = $this->workApp('work_application')->getClient();
|
||
// $access_token = $this->workApp()->getAccessToken()->getToken();
|
||
// dd($access_token);
|
||
$params = [
|
||
'chatid' => $chatid,
|
||
'msgtype' => $msgtype,
|
||
'content' => $content,
|
||
'safe' => 0
|
||
];
|
||
$response = $api->postJson("/cgi-bin/appchat/send", $params);
|
||
if ($response->isFailed()) {
|
||
// 出错了,处理异常
|
||
throw new \Exception($response->getContent());
|
||
}
|
||
// dd($response->getContent());
|
||
}
|
||
|
||
/**
|
||
* 微信公众号授权-获取code
|
||
* @param $redirect_uri
|
||
* @return string|void
|
||
* @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
|
||
*/
|
||
public function connectAuth($redirect_uri) //snsapi_userinfo
|
||
{
|
||
$app = $this->officialApp();
|
||
$oauth = $app->getOauth();
|
||
$wechat_user = session('wechat_user');
|
||
$openid = $wechat_user['id'] ?? null;
|
||
if (empty($openid)) {
|
||
session(['intend_url' => $redirect_uri]);
|
||
// Log::info($redirect_uri);
|
||
//生成完整的授权URL
|
||
$redirectUrl = $oauth->redirect($redirect_uri);
|
||
// Log::info($redirectUrl);
|
||
|
||
return $redirectUrl;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 微信公众号授权-获取维信息
|
||
* @param $code
|
||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Session\SessionManager|\Illuminate\Session\Store|mixed|string
|
||
* @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
|
||
*/
|
||
public function connectAuthByCode($code)
|
||
{
|
||
// Log::info("wechat code: ". $code);
|
||
try {
|
||
$app = $this->officialApp();
|
||
$oauth = $app->getOauth();
|
||
|
||
$user = $oauth->userFromCode($code);
|
||
|
||
session(['wechat_user' => $user->toArray()]);
|
||
|
||
$targetUrl = session('intend_url') ?: '/';
|
||
return $targetUrl;
|
||
} catch (\Exception $e) {
|
||
// 获取异常错误信息
|
||
$errorMessage = $e->getMessage();
|
||
// 进行错误处理,例如记录日志或返回给前端
|
||
Log::error("connectAuthByCode error: " . $errorMessage);
|
||
}
|
||
|
||
}
|
||
public function connectWorkAuthByCode($code, $config = 'work_application')
|
||
{
|
||
Log::info("wechat code: " . $code);
|
||
$app = $this->workApp($config);
|
||
|
||
Log::info("缓存测试 " . $code);
|
||
$user = $app->getOAuth()->detailed()->userFromCode($code);
|
||
|
||
// $user = $oauth->userFromCode($code);
|
||
// Log::info($user->toArray());
|
||
//缓存用户信息
|
||
Log::info("缓存用户信息");
|
||
// Log::info($user->toArray());
|
||
session(['work_wechat_user' => $user->toArray()]);
|
||
$targetUrl = session('intend_url') ?: '/';
|
||
return $targetUrl;
|
||
}
|
||
|
||
public function connectWorkAuth($redirect_uri, $config = 'work_application') //snsapi_userinfo
|
||
{
|
||
Log::info("connectWorkAuth " . $redirect_uri);
|
||
session(['intend_url' => $redirect_uri]);
|
||
$app = $this->workApp($config);
|
||
$redirect_uri = $app->getOAuth()->redirect($redirect_uri);
|
||
|
||
return $redirect_uri;
|
||
}
|
||
|
||
/**
|
||
* 获取企业微信jsSDK
|
||
* @param $url
|
||
* @param $type
|
||
* @return array|mixed[]
|
||
* @throws \EasyWeChat\Kernel\Exceptions\HttpException
|
||
* @throws \Psr\SimpleCache\InvalidArgumentException
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
|
||
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
|
||
*/
|
||
public function workJsSdkConfig($url, $type)
|
||
{
|
||
$config = [];
|
||
if ($type == 'work') {
|
||
$utils = $this->workApp('work')->getUtils();
|
||
$config = $utils->buildJsSdkConfig(
|
||
$url,
|
||
[],
|
||
[],
|
||
false,
|
||
);
|
||
// $config['jsapi_ticket'] = $this->workApp('work')->getTicket()->getTicket();
|
||
} elseif ($type == 'app') {
|
||
$utils = $this->workApp('work_application')->getUtils();
|
||
$config = $utils->buildJsSdkAgentConfig(
|
||
config('wechat.work_application.agent_id'),
|
||
$url,
|
||
[],
|
||
[],
|
||
false,
|
||
);
|
||
// $config['jsapi_ticket'] = $this->workApp('work_application')->getTicket()->getAgentTicket(1000003);
|
||
}
|
||
return $config;
|
||
}
|
||
|
||
public function groupChats($cursor = '', $limit = 15, $status_filter = 0, $userid_list = [])
|
||
{
|
||
$api = $this->workApp('work')->getClient();
|
||
$response = $api->postJson('/cgi-bin/externalcontact/groupchat/list', [
|
||
'status_filter' => $status_filter,
|
||
'owner_filter' => [
|
||
'userid_list' => $userid_list
|
||
],
|
||
'cursor' => $cursor,
|
||
'limit' => $limit
|
||
]);
|
||
if ($response->isFailed()) {
|
||
// 出错了,处理异常
|
||
throw new \Exception($response->getContent());
|
||
}
|
||
return json_decode($response->toJson());
|
||
}
|
||
|
||
public function groupChat($chat_id, $need_name = 0)
|
||
{
|
||
try {
|
||
$api = $this->workApp('work')->getClient();
|
||
$response = $api->postJson('/cgi-bin/externalcontact/groupchat/get', [
|
||
'chat_id' => $chat_id,
|
||
'need_name' => $need_name
|
||
]);
|
||
// if ($response->isFailed()) {
|
||
// // 出错了,处理异常
|
||
// throw new \Exception($response->getContent());
|
||
// }
|
||
$res = json_decode($response->toJson());
|
||
return $res;
|
||
|
||
} catch (\Exception $e) {
|
||
$this->getError($e);
|
||
return false;
|
||
}
|
||
|
||
}
|
||
|
||
public function workUserInfo($user_id)
|
||
{
|
||
$api = $this->workApp('work')->getClient();
|
||
$response = $api->get('/cgi-bin/user/get', ['userid' => $user_id]);
|
||
if ($response->isFailed()) {
|
||
// 出错了,处理异常
|
||
throw new \Exception($response->getContent());
|
||
}
|
||
// Log::info($response->toJson());
|
||
|
||
return json_decode($response->toJson());
|
||
}
|
||
|
||
public function test()
|
||
{
|
||
$access = $this->official_app->getAccessToken()->getToken();
|
||
dd($access);
|
||
}
|
||
|
||
|
||
/**
|
||
* 获取小程序 url link
|
||
*/
|
||
public function urlLink($path, $query)
|
||
{
|
||
$data = [
|
||
"path" => $path,
|
||
"query" => $query,
|
||
];
|
||
|
||
$res = $this->app->getClient()->post('wxa/generate_urllink', [
|
||
'json' => $data
|
||
]);
|
||
if ($res->isFailed())
|
||
throw new \Exception($res->getContent());
|
||
$r = json_decode($res->toJson());
|
||
return $r->url_link;
|
||
}
|
||
|
||
public function getUrlLink($url_link)
|
||
{
|
||
$data = [
|
||
'url_link' => $url_link,
|
||
];
|
||
$res = $this->app->getClient()->postJson('wxa/query_urllink', $data);
|
||
if ($res->isFailed())
|
||
throw new \Exception($res->getContent());
|
||
$r = json_decode($res->toJson());
|
||
return $r->url_link_info;
|
||
}
|
||
|
||
public function getUserStep($code, $iv, $encryptedData)
|
||
{
|
||
try {
|
||
$app = $this->app;
|
||
$utils = $app->getUtils();
|
||
$response = $utils->codeToSession($code);
|
||
// 获取解密后的用户数据
|
||
$userInfo = $utils->decryptSession($response['session_key'], $iv, $encryptedData);
|
||
|
||
// 用户的微信步数
|
||
$stepInfoList = $userInfo['stepInfoList'];
|
||
$stepCount = end($stepInfoList); // 获取最近一天的步数
|
||
$stepCount['stepInfoList'] = $stepInfoList;
|
||
return $stepCount;
|
||
} catch (\Throwable $e) {
|
||
throw new \Exception($e->getMessage());
|
||
}
|
||
}
|
||
|
||
public function getMpUrlLink($url, $query = null)
|
||
{
|
||
// $access_token = $this->app->getAccessToken()->getToken();
|
||
$token_url = config('app.url') . '/go/api/mp/v1/common/accesstoken_mp/get';
|
||
$params = ['curr_date' => "#" . date("Y-m-d") . "@-"];
|
||
try {
|
||
$res = \App\Facades\HttpService::postData($token_url, $params);
|
||
$access_token = $res['data'];
|
||
} catch (\Exception $e) {
|
||
$access_token = '';
|
||
}
|
||
$res = $this->app->getClient()->post('wxa/generatescheme?access_token=' . $access_token, [
|
||
'json' => [
|
||
'jump_wxa' => [
|
||
'path' => $url,
|
||
'query' => $query
|
||
],
|
||
"is_expire" => true,
|
||
"expire_time" => time() + 30 * 24 * 60 * 60
|
||
]
|
||
]);
|
||
if ($res->isFailed())
|
||
throw new \Exception($res->getContent());
|
||
$r = json_decode($res->toJson());
|
||
return $r->openlink;
|
||
}
|
||
}
|