WeiXinTool 核心功能模組
- Access Token 管理:快取 (Cache) + 自動刷新,支援多公眾號隔離。
- 素材管理:臨時/永久素材上傳 (圖片/語音/視頻/縮略圖)、圖文素材上傳、獲取素材列表。
- 群發介面:按 OpenID 列表群發、按標籤/分組群發、刪除群發、預覽群發。
- 多客服:輸入 `transfer_customer_service` 將會話轉接人工/機器人客服。
- 用戶管理:獲取用戶列表、用戶詳情、用戶分組 (建立/修改/移動用戶)。
- 通用工具:長鏈接轉短鏈接、語義理解、JS-SDK 簽名、模板訊息發送。
關鍵方法精選
1. 上傳圖文素材 (用於群發)
public function uploadNews(array $articles) {
// $articles = [ ['thumb_media_id'=>'', 'title'=>'', 'content'=>'', 'digest'=>'', ...], ... ]
$url = sprintf(self::UPLOAD_NEWS_URL, $this->access_token);
$post = ['articles' => $articles];
return $this->httpPostJson($url, $post);
}
// 回傳: ['media_id'=>'...', 'type'=>'news', 'created_at'=>...]
2. 群發圖文訊息
public function sendMassNews($mediaId, $toUsers = [], $groupId = null) {
$url = $groupId
? sprintf('https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_token=%s', $this->access_token)
: sprintf('https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token=%s', $this->access_token);
$post = ['mpnews' => ['media_id' => $mediaId], 'msgtype' => 'mpnews'];
if ($groupId) {
$post['filter'] = ['group_id' => $groupId, 'is_to_all' => false];
} else {
$post['touser'] = $toUsers; // OpenID 陣列
}
return $this->httpPostJson($url, $post);
}
3. 多客服接入 (被動回覆)
public static function transferToCustomerService($postObj) {
$xml = "
%s
";
echo sprintf($xml, $postObj->FromUserName, $postObj->ToUserName, time());
}
4. 圖文回覆 (被動/客服主動)
public static function replyNews($articles, $postObj) {
$itemTpl = "-
";
$items = '';
foreach ($articles as $a) {
$items .= sprintf($itemTpl, $a['Title'], $a['Description'], $a['PicUrl'], $a['Url']);
}
$xml = "
%s
%d
{$items}
";
echo sprintf($xml, $postObj->FromUserName, $postObj->ToUserName, time(), count($articles));
}
完整 HTTP 封裝與錯誤碼表
// GET
public static function httpGet($url) {
$ch = curl_init($url);
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER=>true, CURLOPT_SSL_VERIFYPEER=>false, CURLOPT_TIMEOUT=>10]);
$ret = curl_exec($ch);
curl_close($ch);
return $ret;
}
// POST JSON
public static function httpPostJson($url, $data) {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => self::jsonEncode($data), // 自定義 JSON 編碼 (不轉義中文)
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false,
]);
return json_decode(curl_exec($ch), true);
}
// 微信 API 錯誤碼映射 (部分)
public static $errorno = [
-1 => '系統繁忙', 0 => '成功',
40001 => 'AppSecret 錯誤', 40014 => 'access_token 無效',
45009 => '調用頻率超限', 45015 => '回覆超時',
48001 => 'API 功能未授權', 50001 => '用戶未授權該 API',
// ... 完整表見類原始碼
];
使用範例:完整群發流程
$options = [
'appid' => 'wx_xxx', 'appsecret' => 'xxx', 'token' => 'xxx'
];
$wx = new WeiXinTool($options);
// 1. 上傳封面圖
$thumb = $wx->uploadMedia('/path/to/cover.jpg', 'thumb');
if (isset($thumb['errcode'])) die('封面上傳失敗');
// 2. 組裝圖文
$articles = [[
'thumb_media_id' => $thumb['media_id'],
'title' => '新品上市',
'content' => '詳細富文本內容...',
'digest' => '摘要...',
'content_source_url' => 'https://shop.com/detail/123',
]];
// 3. 上傳圖文素材
$news = $wx->uploadNews($articles);
if (isset($news['errcode'])) die('圖文上傳失敗');
// 4. 群發給標籤用戶
$result = $wx->sendMassNews($news['media_id'], [], 102); // group_id=102
print_r($result);
架構建議
- **單例模式**管理 `WeiXinTool` 實例,避免重複獲取 `access_token`。
- **隊列化發送**:群發、模板訊息等耗時操作寫入 Redis/RabbitMQ,Worker 異步處理,避免阻塞 Web 請求。
- **日誌審計**:所有 API 請求/回覆 (含參數、耗時、錯誤碼) 寫入結構化日誌 (ELK/ClickHouse)。
- **熔斷降級**:微信 API 連續失敗達閾值,熔斷並返回本地預設回覆,防止雪崩。