首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 微信 JSSDK 自定義分享完整實現:從簽名生成到前端配置

     編輯:PHP 綜合知識

微信公眾號網頁自定義分享(標題/描述/圖片/鏈接)是運營剛需。本文完整講解 JSSDK 簽名算法、access_token/jsapi_ticket 緩存策略、前端 wx.config 注入與分享接口調用,附生產級 PHP 封裝類與前端代碼。

核心流程時序圖

  1. 後端:獲取 access_token(7200s 有效,全局緩存)
  2. 後端:用 access_token 換取 jsapi_ticket(7200s 有效,全局緩存)
  3. 後端:構造簽名字符串 jsapi_ticket=...&noncestr=...×tamp=...&url=... → SHA1 簽名
  4. 後端:將 appId, timestamp, nonceStr, signature 傳給前端模板
  5. 前端:引入 jweixin-1.0.0.js → wx.config({...}) 驗證
  6. 前端:wx.ready 中調用 onMenuShareTimeline/AppMessage/QQ/Weibo 設置分享內容

後端 PHP 完整實現(含緩存優化)

class WechatJSSDK {
    private $appId, $appSecret;
    private $cache; // Redis/Memcached 實例

    public function __construct($appId, $appSecret, $cache) {
        $this->appId = $appId;
        $this->appSecret = $appSecret;
        $this->cache = $cache;
    }

    // 獲取 access_token(緩存 7000s)
    private function getAccessToken() {
        $key = 'wx_access_token_' . $this->appId;
        if ($token = $this->cache->get($key)) return $token;
        $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$this->appId}&secret={$this->appSecret}";
        $res = json_decode(httpGet($url), true);
        if (isset($res['access_token'])) {
            $this->cache->set($key, $res['access_token'], 7000);
            return $res['access_token'];
        }
        throw new Exception('AccessToken獲取失敗: ' . ($res['errmsg'] ?? '未知'));
    }

    // 獲取 jsapi_ticket(緩存 7000s)
    private function getJsapiTicket() {
        $key = 'wx_jsapi_ticket_' . $this->appId;
        if ($ticket = $this->cache->get($key)) return $ticket;
        $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" . $this->getAccessToken() . "&type=jsapi";
        $res = json_decode(httpGet($url), true);
        if (isset($res['ticket'])) {
            $this->cache->set($key, $res['ticket'], 7000);
            return $res['ticket'];
        }
        throw new Exception('JsapiTicket獲取失敗: ' . ($res['errmsg'] ?? '未知'));
    }

    // 核心:生成簽名配置陣列
    public function getSignPackage($url = null) {
        $url = $url ?? 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
        // 去除 # 及後面部分
        if (($pos = strpos($url, '#')) !== false) $url = substr($url, 0, $pos);

        $jsapiTicket = $this->getJsapiTicket();
        $nonceStr    = $this->randomStr(16);
        $timestamp   = time();
        $string      = "jsapi_ticket={$jsapiTicket}&noncestr={$nonceStr}×tamp={$timestamp}&url={$url}";
        $signature   = sha1($string);

        return [
            'appId'     => $this->appId,
            'nonceStr'  => $nonceStr,
            'timestamp' => $timestamp,
            'signature' => $signature,
            'rawString' => $string, // 調試用
        ];
    }

    private function randomStr($len = 16) {
        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $str = '';
        for ($i = 0; $i < $len; $i++) $str .= $chars[mt_rand(0, strlen($chars) - 1)];
        return $str;
    }
}

控制器調用示例

$jssdk = new WechatJSSDK('APPID', 'SECRET', $redis);
$signPackage = $jssdk->getSignPackage();
// 分配給模板引擎
$view->assign('signPackage', $signPackage);

前端模板完整代碼

<script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
<script>
wx.config({
    debug: false, // 生產關閉
    appId: '<?= $signPackage['appId'] ?>',
    timestamp: '<?= $signPackage['timestamp'] ?>',
    nonceStr: '<?= $signPackage['nonceStr'] ?>',
    signature: '<?= $signPackage['signature'] ?>',
    jsApiList: [
        'onMenuShareTimeline', 'onMenuShareAppMessage',
        'onMenuShareQQ', 'onMenuShareWeibo',
        'updateAppMessageShareData', 'updateTimelineShareData' // 1.4.0+ 新接口
    ]
});

wx.ready(function() {
    const shareData = {
        title: '自定義分享標題',
        desc: '自定義分享描述',
        link: location.href.split('#')[0], // 必須與簽名 URL 一致
        imgUrl: 'https://your.com/share.jpg',
        success: () => console.log('分享成功'),
        cancel: () => console.log('用戶取消')
    };

    // 兼容舊版接口(逐漸棄用)
    wx.onMenuShareTimeline(shareData);
    wx.onMenuShareAppMessage(shareData);
    wx.onMenuShareQQ(shareData);
    wx.onMenuShareWeibo(shareData);

    // 新版接口(推薦)
    wx.updateAppMessageShareData(shareData);
    wx.updateTimelineShareData(shareData);
});

wx.error(function(res) {
    console.error('JSSDK驗證失敗:', res);
    // 可上報日誌分析
});
</script>

十大避坑指南(血淚總結)

#坑點解決方案
1簽名 URL 與當前頁 URL 不一致簽名用 location.href.split('#')[0],前端分享 link 必須完全一致
2access_token / jsapi_ticket 未緩存必須全局緩存 7000s,否則高併發觸發微信頻控封禁
3nonceStr/timestamp 前後端不一致簽名用的參數必須原樣傳給 wx.config
4未配置 JS 接口安全域名公眾平台 → 設置 → 功能設置 → JS接口安全域名(無需協議頭)
5測試環境域名不在安全域名用內網穿透映射到已備案域名,或配置測試號
6分享圖片無法加載圖片必須 HTTPS、<300KB、建議 300x300px、域名需在安全域名下
7iOS 微信分享到朋友圈無圖/無描述必須設置 updateTimelineShareData,舊接口 onMenuShareTimeline 不支援 desc
8頁面動態路由導致 URL 變化SPA 頁面路由切換需重新獲取簽名並 wx.config
9企業微信/服務號/訂閱號權限差異認證服務號/企業微信才有全部分享接口,訂閱號受限
10簽名算法大小寫/排序錯誤參數按 ASCII 碼升序拼接,key 小寫,值不編碼,SHA1 大寫輸出

調試技巧

  • 開啟 debug: true,控制台會輸出具體錯誤碼
  • 對比後端生成的 rawString 與前端 wx.config 參數是否完全一致
  • 使用微信開發者工具「公眾號網頁調試」模式

將上述邏輯封裝為 Composer 包或框架組件,即可在任何項目中一行代碼接入微信分享,徹底告別「分享出去是默認標題」的尷尬。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved