1、创建公共类 `<?php namespace app\controller;
use support\Request; use support\Cache;
class WechatController { // 公众号 A 的配置 private appSecret = '公众号A的appsecret';
/**
* 获取 access_token(带缓存)
*/
protected function getAccessToken()
{
$cacheKey = 'wechat_access_token_a';
$token = Cache::get($cacheKey);
if (!$token) {
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$this->appId}&secret={$this->appSecret}";
$res = json_decode(file_get_contents($url), true);
if (isset($res['access_token'])) {
$token = $res['access_token'];
Cache::set($cacheKey, $token, 7000);
} else {
// 记录错误日志
return null;
}
}
return $token;
}
/**
* 获取 jsapi_ticket(带缓存)
*/
protected function getJsApiTicket()
{
$cacheKey = 'wechat_jsapi_ticket_a';
$ticket = Cache::get($cacheKey);
if (!$ticket) {
$token = $this->getAccessToken();
if (!$token) {
return null;
}
$url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={$token}&type=jsapi";
$res = json_decode(file_get_contents($url), true);
if (isset($res['ticket'])) {
$ticket = $res['ticket'];
Cache::set($cacheKey, $ticket, 7000);
} else {
return null;
}
}
return $ticket;
}
/**
* 生成签名
* @param string $url 当前页面完整 URL(不含#)
* @return array|null
*/
protected function generateSignature($url)
{
$ticket = $this->getJsApiTicket();
if (!$ticket) {
return null;
}
$timestamp = time();
$nonceStr = $this->createNonceStr();
$string = "jsapi_ticket={$ticket}&noncestr={$nonceStr}×tamp={$timestamp}&url={$url}";
$signature = sha1($string);
return [
'appId' => $this->appId, // 公众号A的appId
'timestamp' => $timestamp,
'nonceStr' => $nonceStr,
'signature' => $signature,
];
}
protected function createNonceStr($length = 16)
{
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$str = '';
for ($i = 0; $i < $length; $i++) {
$str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}
return $str;
}
/**
* 渲染打开小程序的页面(后端输出HTML)
*/
public function openMiniApp(Request $request)
{
// 获取当前页面的完整 URL(用于签名)
$protocol = $request->header('x-forwarded-proto', 'http');
$fullUrl = $protocol . '://' . $request->host() . $request->uri();
$url = explode('#', $fullUrl)[0]; // 去除 # 部分
$signPackage = $this->generateSignature($url);
if (!$signPackage) {
return '签名生成失败';
}
// 返回视图,传递签名数据 以及 客户B的小程序信息
return view('wechat/open_miniapp', [
'signPackage' => $signPackage,
'targetAppId' => 'gh_xxxxxx', // 客户B的小程序原始ID(gh_开头)
'targetPath' => '/pages/index/index', // 目标小程序路径
]);
}
//备用生成签名的方法
public function getJssdkConfig(Request $request)
{ request->get('url'); // 前端传递的当前页面 URL if (!$url) { return json(['code' => 400, 'msg' => 'missing url']); }
// 可选:对 URL 进行简单校验,确保是合法格式
if (!filter_var($url, FILTER_VALIDATE_URL)) {
return json(['code' => 400, 'msg' => 'invalid url']);
}
$ticket = $this->getJsApiTicket(); // 获取 jsapi_ticket
if (!$ticket) {
return json(['code' => 500, 'msg' => 'get ticket failed']);
}
$timestamp = time();
$nonceStr = $this->createNonceStr();
// 注意:参数顺序必须按字典序排序
$string = "jsapi_ticket={$ticket}&noncestr={$nonceStr}×tamp={$timestamp}&url={$url}";
$signature = sha1($string);
return json([
'code' => 0,
'data' => [
'appId' => $this->appId,
'timestamp' => $timestamp,
'nonceStr' => $nonceStr,
'signature' => $signature,
]
]);
} }` 2、这边用于签名的appid和app_secret是公众号的,并且这个公众号是已认证的服务号 3、公众号需要配置域名,在公众号开发设置里,配置jssdk域名