微信公眾號開發核心在於接收 XML 訊息、解析類型、組裝回覆 XML。本文以 CodeIgniter 3 框架為載體,提供完整控制器實作:Token 驗證、文本/圖片/語音訊息回覆、圖文訊息、隨機笑話查詢資料庫、菜單式關鍵字路由。程式碼結構清晰,可直接部署至 SAE/一般伺服器,適合快速原型與教學參考。
application/controllers/Welcome.php<?php
defined('BASEPATH') OR exit('No direct script access allowed');
define('TOKEN', 'your_token_here'); // 需與微信後台設定一致
class Welcome extends CI_Controller {
public function index()
{
// 1. Token 驗證 (微信伺服器配置時呼叫)
$this->verifySignature();
// 2. 處理用戶訊息
$this->responseMsg();
}
/** 簽名驗證 */
private function verifySignature()
{
$signature = $_GET['signature'] ?? '';
$timestamp = $_GET['timestamp'] ?? '';
$nonce = $_GET['nonce'] ?? '';
$echostr = $_GET['echostr'] ?? '';
$tmpArr = [TOKEN, $timestamp, $nonce];
sort($tmpArr, SORT_STRING);
$tmpStr = sha1(implode($tmpArr));
if ($tmpStr === $signature) {
echo $echostr; // 原樣返回 echostr 完成驗證
exit;
}
}
/** 訊息處理主流程 */
public function responseMsg()
{
$postStr = $GLOBALS['HTTP_RAW_POST_DATA'] ?? file_get_contents('php://input');
if (empty($postStr)) return;
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
$fromUsername = (string)$postObj->FromUserName;
$toUsername = (string)$postObj->ToUserName;
$msgType = (string)$postObj->MsgType;
$time = time();
// 文本訊息模板
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>";
// 圖文訊息模板
$newsTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[news]]></MsgType>
<ArticleCount>2</ArticleCount>
<Articles>
<item>
<Title><![CDATA[%s]]></Title>
<Description><![CDATA[%s]]></Description>
<PicUrl><![CDATA[%s]]></PicUrl>
<Url><![CDATA[%s]]></Url>
</item>
<item>
<Title><![CDATA[%s]]></Title>
<Description><![CDATA[%s]]></Description>
<PicUrl><![CDATA[%s]]></PicUrl>
<Url><![CDATA[%s]]></Url>
</item>
</Articles>
</xml>";
// 圖片回覆模板
$imageTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[image]]></MsgType>
<Image><MediaId><![CDATA[%s]]></MediaId></Image>
</xml>";
switch ($msgType) {
case 'text':
$keyword = trim((string)$postObj->Content);
switch ($keyword) {
case '1': // 隨機笑話
$sql = 'SELECT content FROM jokes ORDER BY RAND() LIMIT 1';
$row = $this->db->query($sql)->row();
$contentStr = $row ? $row->content : '暫無笑話';
break;
case '2': // 顯示 OpenID
$contentStr = 'Your OpenID: ' . $fromUsername;
break;
case '3': // 圖文訊息
$resultStr = sprintf($newsTpl,
$fromUsername, $toUsername, $time,
'百度', '', 'https://www.baidu.com/img/bdlogo.gif', 'https://www.baidu.com',
'Google', '', '', 'https://www.google.com'
);
echo $resultStr;
exit;
case '4':
$contentStr = '功能開發中...';
break;
default: // 選單提示
$contentStr = "回覆數字選擇服務:\n1 隨機笑話\n2 獲取 OpenID\n3 圖文訊息\n4 開發中...";
break;
}
if ($msgType === 'text' && $keyword !== '3') {
echo sprintf($textTpl, $fromUsername, $toUsername, $time, $contentStr);
}
break;
case 'image':
$mediaId = (string)$postObj->MediaId;
echo sprintf($imageTpl, $fromUsername, $toUsername, $time, $mediaId);
break;
case 'voice':
$contentStr = '收到語音,暂不支援識別。';
echo sprintf($textTpl, $fromUsername, $toUsername, $time, $contentStr);
break;
case 'event':
$event = (string)$postObj->Event;
if ($event === 'subscribe') {
$contentStr = '歡迎關注!回覆 1-4 體驗功能。';
echo sprintf($textTpl, $fromUsername, $toUsername, $time, $contentStr);
}
break;
default:
echo 'success';
break;
}
}
}
| 環節 | 說明 | 注意事項 |
|---|---|---|
| Token 驗證 | 微信伺服器配置時發送 GET 請求,需原樣返回 echostr | 驗證通過後才會轉發用戶訊息 |
| 原始資料讀取 | $GLOBALS['HTTP_RAW_POST_DATA'] 或 file_get_contents('php://input') | SAE 環境建議用後者 |
| XML 解析 | simplexml_load_string(..., 'SimpleXMLElement', LIBXML_NOCDATA) | LIBXML_NOCDATA 將 CDATA 直接轉為字串屬性 |
| 回覆格式 | 必須為標準 XML,內容用 CDATA 區塊 | CreateTime 為 Unix 時間戳 |
| 被動回覆時效 | 5 秒內必須回覆,否則微信顯示「該公眾號暫時無法提供服務」 | 耗時操作需改用客服介面/異步隊列 |
| 資料庫查詢 | CI $this->db->query() 返回結果集 | 笑話表需預先建立 |
jokes 表CREATE TABLE `jokes` ( `id` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, `content` TEXT NOT NULL, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
[ ] 微信公眾平台 → 開發 → 基本配置:URL 指向控制器 index(), Token 一致 [ ] 伺服器開放 80/443 埠,支援 HTTP/HTTPS [ ] PHP 開啟 simplexml、pdo_mysql、curl 擴充套件 [ ] CI 配置 database.php 連線資料庫 [ ] 測試:關注公眾號 → 發送 "1" → 應收到隨機笑話 [ ] 開啟開發者模式查看錯誤日誌
微信公眾號開發本質是 XML 進、XML 出 的無狀態 HTTP 介面。掌握 Token 驗證、訊息類型分發、模板組裝、資料庫互動 四大核心,即可快速構建功能豐富的公眾號應用。本範例以 CI 3 為載體,邏輯可無縫移植至任何 PHP 框架或原生 PHP。