基於官方微信公眾平台 PHP SDK 進行二次封裝,整合天氣查詢(K780 API)、有道翻譯、圖靈機器人聊天、自定義選單管理等實用功能。採用類別化設計,支援文本、事件等多種消息類型分發,適合快速構建功能型公眾號。
WechatCallbackapiTest
├── valid() // 簽名驗證(接入驗證)
├── responseMsg() // 主入口:解析 XML → 分發處理器 → 輸出回覆
├── handleText() // 文本消息路由:關鍵詞匹配 → 具體業務
├── handleEvent() // 事件消息:關注/取消關注/選單點擊
├── handleWeather() // 天氣查詢(K780 API)
├── handleTranslation() // 翻譯(有道 API)
├── handleChat() // 聊天機器人(圖靈/小九 API)
├── createMenu/getMenu/deleteMenu // 自定義選單 CRUD
└── checkSignature() // 簽名驗證工具方法
<?php
define('TOKEN', 'your_wechat_token');
$wechatObj = new WechatCallbackapiTest();
$wechatObj->responseMsg();
class WechatCallbackapiTest {
/** 接入驗證 */
public function valid() {
$echoStr = $_GET['echostr'] ?? '';
if ($this->checkSignature()) {
echo $echoStr;
exit;
}
}
/** 主處理入口 */
public function responseMsg() {
$postStr = $GLOBALS['HTTP_RAW_POST_DATA'] ?? file_get_contents('php://input');
if (empty($postStr)) {
echo 'Error: Empty post data';
exit;
}
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
$msgType = trim($postObj->MsgType);
$resultStr = '';
switch ($msgType) {
case 'text':
$resultStr = $this->handleText($postObj);
break;
case 'event':
$resultStr = $this->handleEvent($postObj);
break;
default:
$resultStr = $this->handleDefault($postObj);
}
echo $resultStr;
}
/** 文本消息路由 */
private function handleText($obj) {
$keyword = trim($obj->Content);
if (preg_match('/^天氣\s*(.+)/u', $keyword, $m)) {
$contentStr = $this->handleWeather($m[1]);
} elseif (preg_match('/^翻譯\s*(.+)/u', $keyword, $m)) {
$contentStr = $this->handleTranslation($m[1]);
} else {
$contentStr = $this->handleChat($keyword);
}
return $this->handleStr($obj, $contentStr);
}
/** 天氣查詢:格式「天氣 城市名」 */
private function handleWeather($city) {
$city = trim($city);
if (!$city) return '請輸入:天氣 城市名(例:天氣 北京)';
// 1. 獲取城市 ID 映射
$cityListJson = @file_get_contents('https://api.k780.com:88/?app=weather.city&format=json');
$cityList = json_decode($cityListJson, true)['result'] ?? [];
$cityId = '';
foreach ($cityList as $item) {
if ($item['citynm'] === $city) {
$cityId = $item['weaid'];
break;
}
}
if (!$cityId) return "找不到城市:$city";
// 2. 查詢天氣
$weatherUrl = "https://api.k780.com:88/?app=weather.today&weaid=$cityId&appkey=10638&sign=3736578f099375665f9f141a6326b757&format=json";
$data = json_decode(@file_get_contents($weatherUrl), true);
$r = $data['result'] ?? [];
if (!$r) return '天氣服務暫時不可用';
return "今天是:{$r['days']},{$r['week']},{$r['citynm']}天氣:{$r['weather']}\n" .
"溫度:{$r['temperature']},{$r['wind_direction']} {$r['wind_power']}\n" .
"最低:{$r['temp_low']}°C,最高:{$r['temp_high']}°C";
}
/** 翻譯:格式「翻譯 內容」 */
private function handleTranslation($text) {
$text = trim($text);
if (!$text) return '請輸入:翻譯 內容';
$url = 'https://fanyi.youdao.com/openapi.do?' . http_build_query([
'keyfrom' => 'your_keyfrom',
'key' => 'your_key',
'type' => 'data',
'doctype' => 'json',
'version' => '1.1',
'q' => urlencode($text),
]);
$data = json_decode(@file_get_contents($url), true);
switch ($data['errorCode'] ?? -1) {
case 0: return $data['translation'][0] ?? '翻譯結果為空';
case 20: return '翻譯文本過長(>200字元)';
case 30: return '無法進行有效翻譯';
case 40: return '不支援的語言類型';
case 50: return '無效的 API Key';
default: return '翻譯服務異常';
}
}
/** 聊天機器人:兜底回覆 */
private function handleChat($keyword) {
$curlPost = ['chat' => $keyword];
$ch = curl_init('https://www.xiaojo.com/bot/chata.php');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $curlPost,
CURLOPT_TIMEOUT => 5,
]);
$data = curl_exec($ch);
curl_close($ch);
if ($data) return $data;
// API 失敗時的隨機回覆
$fallbacks = [
'小九今天累了,明天再陪你聊天吧',
'小九睡覺喽~~',
'呼呼~~呼呼~~',
'你話好多啊,不跟你聊了',
'我去喝杯咖啡,稍後回妳',
];
return $fallbacks[array_rand($fallbacks)];
}
/** 事件消息處理 */
private function handleEvent($obj) {
$content = '';
switch ((string)$obj->Event) {
case 'subscribe':
$content = 'Welcome! 感謝關注本公眾號~';
break;
case 'unsubscribe':
$content = '感謝您一直以來的關注,再見!';
break;
case 'CLICK': // 選單點擊事件
$content = '您點擊了選單:' . (string)$obj->EventKey;
break;
default:
$content = '';
}
return $this->handleStr($obj, $content);
}
/** 預設回覆 */
private function handleDefault($obj) {
return $this->handleStr($obj, '收到非文字消息,暫不支援處理');
}
/** 組裝回覆 XML */
private function handleStr($obj, $content, $flag = 0) {
$tpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[%s]]></Content>
<FuncFlag>%d</FuncFlag>
</xml>";
return sprintf($tpl, $obj->FromUserName, $obj->ToUserName, time(), $content, $flag);
}
/** 簽名驗證 */
private function checkSignature() {
$signature = $_GET['signature'] ?? '';
$timestamp = $_GET['timestamp'] ?? '';
$nonce = $_GET['nonce'] ?? '';
$tmpArr = [TOKEN, $timestamp, $nonce];
sort($tmpArr, SORT_STRING);
return sha1(implode($tmpArr)) === $signature;
}
/* ===== 自定義選單管理 ===== */
public function createMenu($menuData, $accessToken) {
$url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=$accessToken";
return $this->httpPostJson($url, $menuData);
}
public function getMenu($accessToken) {
$url = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=$accessToken";
return $this->httpGet($url);
}
public function deleteMenu($accessToken) {
$url = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=$accessToken";
return $this->httpGet($url);
}
private function httpPostJson($url, $data) {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => is_string($data) ? $data : json_encode($data, JSON_UNESCAPED_UNICODE),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
]);
$resp = curl_exec($ch);
curl_close($ch);
return $resp;
}
private function httpGet($url) {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
]);
$resp = curl_exec($ch);
curl_close($ch);
return $resp;
}
}
?>
<?php
// 選單結構(按鈕類型:click/view/miniprogram 等)
$menuData = [
'button' => [
[
'type' => 'click',
'name' => '今日天氣',
'key' => 'WEATHER_TODAY',
],
[
'type' => 'view',
'name' => '官網首頁',
'url' => 'https://www.example.com',
],
[
'name' => '更多服務',
'sub_button' => [
['type' => 'click', 'name' => '在線客服', 'key' => 'CONTACT_SUPPORT'],
['type' => 'click', 'name' => '關於我們', 'key' => 'ABOUT_US'],
],
],
],
];
// 獲取 access_token(需定時刷新快取)
$accessToken = getWechatAccessToken(); // 自行實現
$wechat = new WechatCallbackapiTest();
echo $wechat->createMenu($menuData, $accessToken);
?>
access_token(有效期 7200 秒),提前 200 秒刷新,避免併發重複請求。CURLOPT_SSL_VERIFYPEER,配置 CA 憑證;驗證微信回調 IP 白名單。sendCustomMessage()、sendTemplateMessage() 方法,支援更豐富互動。此 SDK 擴展提供了微信公眾號開發的常用功能骨架,開發者可根據業務需求繼續擴充:素材管理、用戶標籤、數據統計、小程序關聯等,構建完整的微信運營中台。