微信公众平台 PHP 开发完整教程
目录
-
准备工作
(图片来源网络,侵删)- 1 注册微信公众平台账号
- 2 获取开发者凭证
- 3 本地开发环境搭建
- 4 选择合适的 PHP 框架(可选)
-
核心入门:接收与回复消息
- 1 微信服务器与开发者服务器的通信原理
- 2 接入(验证)服务器
- 3 接收和解析用户消息
- 4 回复用户文本消息
- 5 回复用户其他类型消息(图文、图片等)
-
进阶功能
- 1 网页授权获取用户信息(OAuth2.0)
- 2 模板消息推送
- 3 自定义菜单创建与查询
- 4 生成带参数的二维码
- 5 客服接口
-
高级实战:微信支付
- 1 配置微信支付
- 2 统一下单 API
- 3 支付结果异步通知
- 4 查询订单与关闭订单
-
开发工具与最佳实践
(图片来源网络,侵删)- 1 推荐的开发工具
- 2 代码结构与设计模式
- 3 常见问题与调试技巧
准备工作
在开始编码之前,我们需要完成一些准备工作。
1 注册微信公众平台账号
- 访问 微信公众平台官网。
- 点击“立即注册”,根据你的需求选择账号类型:
- 订阅号:适合个人或媒体,主要功能是信息传播。
- 服务号:适合企业或组织,功能更强大,如微信支付、高级接口等。
- 小程序:独立于公众号,提供轻量级应用体验。
- 按照提示完成注册、邮箱验证、信息登记等流程。服务号需要企业资质,个人只能注册订阅号。
2 获取开发者凭证
注册成功后,登录公众号后台,在 “设置与开发” -> “基本配置” 中找到开发者信息。
- AppID (开发者ID):公众号的唯一标识。
- AppSecret (开发者密码):用于获取 Access Token 的密钥,请务必妥善保管,不要泄露。
3 本地开发环境搭建
你需要一个本地的 PHP 运行环境。
-
集成环境包 (推荐新手):
(图片来源网络,侵删)- XAMPP:支持 Windows, macOS, Linux。
- WampServer:仅支持 Windows。
- MAMP:仅支持 macOS。
- 这些包已经集成了 Apache (Web服务器)、MySQL (数据库) 和 PHP,一键安装即可使用。
-
手动安装:
- 安装 PHP。
- 安装 Apache 或 Nginx。
- 安装 MySQL。
- 配置环境变量。
安装完成后,可以通过 php -v 和 httpd -v (或 nginx -v) 命令检查是否安装成功。
4 选择合适的 PHP 框架 (可选)
对于简单的公众号,可以不使用框架,直接写 PHP 脚本,但对于复杂的项目,使用框架能极大提高开发效率和代码质量。
- Laravel:目前最流行的 PHP 框架,生态完善,文档丰富。
- ThinkPHP:国内流行的框架,对中文开发者友好,快速开发。
- Symfony:稳定、灵活,组件化程度高。
本教程将以 原生 PHP 为例讲解核心原理,因为无论使用哪个框架,底层的 API 调用逻辑都是一致的。
核心入门:接收与回复消息
这是公众号开发最核心、最基础的部分。
1 微信服务器与开发者服务器的通信原理
- 用户 在公众号里发送消息。
- 微信服务器 接收到消息,然后根据你在后台配置的 URL (服务器地址),将消息通过
POST请求转发给你的 开发者服务器。 - 你的服务器 (PHP 脚本) 接收并解析这个
POST请求。 - 你的服务器根据消息内容进行处理(如查询数据库、调用 API 等)。
- 你的服务器将处理结果按照微信规定的 XML 格式,通过
POST请求响应给微信服务器。 - 微信服务器 再将这个响应结果原样回复给 用户。
2 接入(验证)服务器
在后台配置 URL 之前,你需要先写一个脚本来验证服务器地址的有效性。
验证逻辑:
- 微信服务器会向你配置的 URL 发送一个
GET请求。 - 请求中包含四个参数:
signature,timestamp,nonce,echostr。 - 你的服务器需要:
a. 将
token(你在后台配置的)、timestamp、nonce三个参数进行字典序排序。 b. 将排序后的三个参数字符串拼接成一个字符串,并进行SHA1加密。 c. 将加密后的字符串与signature进行对比。 d. 如果一致,说明请求来自微信,请原样返回echostr参数内容。 e. 如果不一致,则不是来自微信,返回空。
server.php (验证脚本)
<?php
// 你的 Token,必须与公众号后台配置的完全一致
define("TOKEN", "your_token_here");
$wechatObj = new wechatCallbackapiTest();
// 如果是验证请求,则执行验证
if (isset($_GET['echostr'])) {
$wechatObj->valid();
} else {
// 否则,处理接收到的消息
$wechatObj->responseMsg();
}
class wechatCallbackapiTest
{
public function valid()
{
$signature = $_GET["signature"];
$timestamp = $_GET["timestamp"];
$nonce = $_GET["nonce"];
$token = TOKEN;
$tmpArr = array($token, $timestamp, $nonce);
sort($tmpArr, SORT_STRING);
$tmpStr = implode($tmpArr);
$tmpStr = sha1($tmpStr);
if ($tmpStr == $signature) {
echo $_GET["echostr"];
exit;
}
}
// ... 后续会添加 responseMsg 方法
}
操作步骤:
- 将上面的代码保存为
server.php。 - 将
server.php放到你 Web 服务器的根目录(如htdocs或www)。 - 在本地
hosts文件中添加0.0.1 your-test-domain.com(mp.localtest.me)。 - 在公众号后台 “设置与开发” -> “基本配置” -> “服务器配置” 中:
- URL 填写
http://your-test-domain.com/server.php。 - Token 填写
your_token_here。 - 消息加解密方式选择“明文模式”(开发阶段最简单)。
- 点击“提交”,如果提示成功,说明接入成功。
- URL 填写
3 接收和解析用户消息
当用户发送消息后,微信服务器会向你的 server.php 发送一个 POST 请求,请求体是 XML 格式的数据。
server.php (修改以接收消息)
// ... 前面的 valid() 方法保持不变 ...
public function responseMsg()
{
// 1. 获取微信推送过来的 POST 数据 (XML)
$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
// 2. 兼容性更好的写法
// $postStr = file_get_contents('php://input');
// empty() 判断变量是否为空
if (!empty($postStr)) {
// 3. 简单的日志记录 (推荐)
// $this->logger("Rcv\n".$postStr);
// 4. 解析 XML
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
$fromUsername = $postObj->FromUserName; // 发送者 OpenID
$toUsername = $postObj->ToUserName; // 公众号原始ID
$keyword = trim($postObj->Content); // 用户发送的消息内容
$msgType = $postObj->MsgType; // 消息类型 (text, image, event等)
// 5. 根据消息类型进行处理
if ($msgType == 'text') {
// 回复文本消息
$this->handleText($fromUsername, $toUsername, $keyword);
} else if ($msgType == 'event') {
// 处理事件推送,如关注、点击菜单等
$this->handleEvent($fromUsername, $toUsername, $postObj);
}
} else {
echo "";
exit;
}
}
private function handleText($from, $to, $keyword)
{
// 这里是业务逻辑,比如根据关键词回复不同内容
$content = "你发送的是: " . $keyword;
$this->sendText($from, $to, $content);
}
private function handleEvent($from, $to, $postObj)
{
$event = $postObj->Event;
if ($event == 'subscribe') {
// 用户关注事件
$content = "欢迎关注我们的公众号!";
$this->sendText($from, $to, $content);
}
// 可以添加其他事件处理,如 CLICK, SCAN 等
}
// 发送文本消息的通用方法
private function sendText($from, $to, $content)
{
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>";
$result = sprintf($textTpl, $from, $to, time(), $content);
echo $result;
exit;
}
当你关注公众号或发送文本消息时,你的服务器就会收到数据并做出相应回复。
4 回复用户其他类型消息
回复其他类型的消息(如图文、图片)只需要修改 XML 模板即可。
回复图文消息示例
// 在 handleText 或其他方法中调用
private function sendNews($from, $to)
{
$articles = [
[
'Title' => '欢迎来到我们的世界',
'Description' => '这是一个描述,点击查看详情。',
'PicUrl' => 'http://your-domain.com/images/news1.jpg',
'Url' => 'http://your-domain.com/news/1'
],
[
'Title' => '另一篇精彩文章',
'Description' => '这是另一篇描述,也很精彩。',
'PicUrl' => 'http://your-domain.com/images/news2.jpg',
'Url' => 'http://your-domain.com/news/2'
]
];
$itemTpl = "<item>
<Title><![CDATA[%s]]></Title>
<Description><![CDATA[%s]]></Description>
<PicUrl><![CDATA[%s]]></PicUrl>
<Url><![CDATA[%s]]></Url>
</item>";
$items = '';
foreach ($articles as $a) {
$items .= sprintf($itemTpl, $a['Title'], $a['Description'], $a['PicUrl'], $a['Url']);
}
$newsTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[news]]></MsgType>
<ArticleCount>%d</ArticleCount>
<Articles>
%s
</Articles>
</xml>";
$result = sprintf($newsTpl, $from, $to, time(), count($articles), $items);
echo $result;
exit;
}
进阶功能
1 网页授权获取用户信息 (OAuth2.0)
当用户在公众号内点击一个链接时,你希望获取他的基本信息(如昵称、头像),这时就需要使用网页授权。
流程:
- 用户点击你的链接。
- 你的链接重定向到微信授权页面。
- 用户同意授权。
- 微信重定向回你指定的回调 URL,并带上
code。 - 你的服务器用
code换取access_token和openid。 - 用
access_token获取用户信息。
PHP 实现
// 在某个页面中,a.php
<a href="https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect">点击获取用户信息</a>
// REDIRECT_URI 需要 urlencode,urlencode('http://your-domain.com/callback.php')
// scope=snsapi_userinfo 表示需要获取用户信息,snsapi_base 只获取 openid
// callback.php
<?php
$appid = 'your_appid';
$secret = 'your_secret';
$code = $_GET['code'];
// 1. 获取 access_token
$url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={$appid}&secret={$secret}&code={$code}&grant_type=authorization_code";
$res = $this->https_request($url);
$token_info = json_decode($res, true);
// 2. 获取用户信息
if (isset($token_info['access_token'])) {
$access_token = $token_info['access_token'];
$openid = $token_info['openid'];
$user_info_url = "https://api.weixin.qq.com/sns/userinfo?access_token={$access_token}&openid={$openid}&lang=zh_CN";
$user_info = json_decode($this->https_request($user_info_url), true);
// $user_info 就包含了用户的 nickname, headimgurl, sex 等信息
// var_dump($user_info);
} else {
echo "获取失败";
}
// 通用的 HTTP 请求函数
private function https_request($url, $data = null)
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
if (!empty($data)) {
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
2 模板消息推送
模板消息用于在特定场景下给用户发送服务通知,如订单支付成功、预约提醒等。
步骤:
- 在公众号后台“模板消息”中找到并启用一个模板。
- 记录下模板 ID。
- 你的服务器调用
https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN接口。
PHP 实现
// 1. 获取 access_token (有效期2小时,需要缓存)
$access_token = $this->getAccessToken(); // 需要自己实现一个获取并缓存 access_token 的方法
$template_id = 'YOUR_TEMPLATE_ID'; // 你启用的模板ID
$touser = 'USER_OPENID'; // 用户的openid
$url = 'http://www.qq.com'; // 点击模板消息后跳转的URL
// 模板数据,格式必须严格按微信文档来
$data = [
'first' => ['value' => '您的订单已支付成功', 'color' => '#173177'],
'keyword1' => ['value' => '20250815', 'color' => '#173177'],
'keyword2' => ['value' => '微信支付', 'color' => '#173177'],
'remark' => ['value' => '感谢您的购买!', 'color' => '#173177']
];
$post_data = json_encode([
'touser' => $touser,
'template_id' => $template_id,
'url' => $url,
'data' => $data
]);
$url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={$access_token}";
$res = $this->https_request($url, $post_data);
$result = json_decode($res, true);
if ($result['errcode'] == 0) {
echo "发送成功";
} else {
echo "发送失败: " . $result['errmsg'];
}
3 自定义菜单创建与查询
可以通过 API 动态创建菜单,而不用在后台手动配置。
PHP 实现
// 获取 access_token
$access_token = $this->getAccessToken();
// 菜单结构 (参考微信官方文档)
$menu_data = [
'button' => [
[
'type' => 'click',
'name' => '今日歌曲',
'key' => 'V1001_TODAY_MUSIC'
],
[
'type' => 'view',
'name' => '搜索',
'url' => 'http://www.soso.com/'
],
[
'name' => '菜单',
'sub_button' => [
[
'type' => 'view',
'name' => '绑定账号',
'url' => 'http://your-domain.com/bind.php'
],
[
'type' => 'click',
'name' => '赞一下我们',
'key' => 'V1001_GOOD'
]
]
]
]
];
$post_data = json_encode($menu_data, JSON_UNESCAPED_UNICODE); // 防止中文被转义
$url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token={$access_token}";
$res = $this->https_request($url, $post_data);
$result = json_decode($res, true);
if ($result['errcode'] == 0) {
echo "菜单创建成功";
} else {
echo "菜单创建失败: " . $result['errmsg'];
}
4 生成带参数的二维码
用于识别用户来源、场景等。
- 临时二维码:
expire_seconds指定有效期,最大1800秒。 - 永久二维码:
scene_id必须为数字,最大100000。
PHP 实现 (创建临时二维码)
$access_token = $this->getAccessToken();
// 创建临时二维码
$post_data = json_encode([
'expire_seconds' => 60,
'action_name' => 'QR_SCENE',
'action_info' => [
'scene' => [
'scene_id' => 123 // 场景值ID
]
]
]);
$url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token={$access_token}";
$res = $this->https_request($url, $post_data);
$result = json_decode($res, true);
if (isset($result['ticket'])) {
$ticket = $result['ticket'];
$expire_seconds = $result['expire_seconds'];
// ticket 需要 URL Encode
$qrcode_url = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" . urlencode($ticket);
echo "二维码URL: " . $qrcode_url;
echo "<br>有效期: " . $expire_seconds . " 秒";
// 可以将 $ticket 和场景值存入数据库,用于用户扫描后的识别
}
当用户扫描这个二维码时,公众号会收到一个 SCAN 事件推送,事件中会包含你设置的 scene_id,从而识别用户来源。
高级实战:微信支付
微信支付流程相对复杂,这里只概述核心步骤。
1 配置微信支付
- 在公众号后台“微信支付”中开通。
- 获取 商户号 (mch_id)、API密钥 (api_key)。
- 下载 支付证书 (apiclient_cert.pem, apiclient_key.pem),并放在服务器安全位置。
2 统一下单 API
这是发起支付的关键步骤。
- 构造请求数据包(XML格式),包含商品信息、金额、回调地址等。
- 对请求进行签名:这是最关键的一步,将所有参数(除 sign 外)按字典序排序,拼接,再用你的
api_key进行 MD5 加密,得到sign。 - 将 XML 数据包发送到统一下单接口:
https://api.mch.weixin.qq.com/pay/unifiedorder。 - 解析返回结果,如果成功,会返回
prepay_id。 - 再次签名,生成最终需要传递给微信 JSAPI 的参数。
3 支付结果异步通知
用户支付成功后,微信服务器会向你在统一下单时指定的 notify_url 发送一个 POST 请求(XML格式)。
你的服务器需要:
- 接收通知。
- 验证签名(非常重要!防止伪造)。
- 验证业务参数(如订单号、金额)。
- 处理业务逻辑(如更新订单状态为“已支付”)。
- 回复微信服务器
<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>,表示已收到通知。
开发工具与最佳实践
1 推荐的开发工具
- Postman / Apifox:用于测试 API 接口,可以模拟发送
POST请求和 XML 数据。 - Ngrok:将本地服务器暴露到公网,方便在公众号后台配置本地开发环境。
- 日志工具:强烈建议将所有接收到的微信消息和 API 调用记录到日志文件中,便于排查问题。
2 代码结构与设计模式
- 使用 Composer:管理依赖,如 Guzzle (HTTP 客户端), EasyWeChat (强大的微信 SDK)。
- 使用 SDK:对于复杂功能,推荐使用成熟的第三方 SDK,如 overtrue/wechat,它能帮你处理所有繁琐的签名、XML解析、API调用等细节,让你专注于业务逻辑。
- MVC 模式:将接收消息、处理逻辑、回复消息分离,使代码更清晰。
3 常见问题与调试技巧
- Token 验证失败:检查
server.php中的TOKEN是否与后台一致,检查服务器是否可以正常访问server.php。 - 签名错误:检查 API 调用时参数是否完整、排序是否正确、
key是否正确。 - 无法接收消息:检查服务器是否可以接收来自微信服务器的
POST请求(防火墙、服务器配置)。 - 调试方法:
- 打印日志:将接收到的 XML 和发送的 XML 都打印到日志文件。
- 使用
file_get_contents('php://input'):比$GLOBALS["HTTP_RAW_POST_DATA"]更可靠。 - 使用 Ngrok:确保微信能访问到你本地的开发环境。
微信公众平台 PHP 开发,核心在于理解其 事件驱动 和 请求-响应 的机制,从简单的消息回复开始,逐步学习使用各种高级接口,对于初学者,建议先用原生 PHP 理解底层逻辑,然后在实际项目中使用成熟的 SDK 来提高效率。
希望这份教程能帮助你顺利开启公众号开发之旅!
