杰瑞科技汇

PHP如何开发微信公众平台?

微信公众平台 PHP 开发完整教程

目录

  1. 准备工作

    PHP如何开发微信公众平台?-图1
    (图片来源网络,侵删)
    • 1 注册微信公众平台账号
    • 2 获取开发者凭证
    • 3 本地开发环境搭建
    • 4 选择合适的 PHP 框架(可选)
  2. 核心入门:接收与回复消息

    • 1 微信服务器与开发者服务器的通信原理
    • 2 接入(验证)服务器
    • 3 接收和解析用户消息
    • 4 回复用户文本消息
    • 5 回复用户其他类型消息(图文、图片等)
  3. 进阶功能

    • 1 网页授权获取用户信息(OAuth2.0)
    • 2 模板消息推送
    • 3 自定义菜单创建与查询
    • 4 生成带参数的二维码
    • 5 客服接口
  4. 高级实战:微信支付

    • 1 配置微信支付
    • 2 统一下单 API
    • 3 支付结果异步通知
    • 4 查询订单与关闭订单
  5. 开发工具与最佳实践

    PHP如何开发微信公众平台?-图2
    (图片来源网络,侵删)
    • 1 推荐的开发工具
    • 2 代码结构与设计模式
    • 3 常见问题与调试技巧

准备工作

在开始编码之前,我们需要完成一些准备工作。

1 注册微信公众平台账号

  1. 访问 微信公众平台官网
  2. 点击“立即注册”,根据你的需求选择账号类型:
    • 订阅号:适合个人或媒体,主要功能是信息传播。
    • 服务号:适合企业或组织,功能更强大,如微信支付、高级接口等。
    • 小程序:独立于公众号,提供轻量级应用体验。
  3. 按照提示完成注册、邮箱验证、信息登记等流程。服务号需要企业资质,个人只能注册订阅号。

2 获取开发者凭证

注册成功后,登录公众号后台,在 “设置与开发” -> “基本配置” 中找到开发者信息。

  • AppID (开发者ID):公众号的唯一标识。
  • AppSecret (开发者密码):用于获取 Access Token 的密钥,请务必妥善保管,不要泄露

3 本地开发环境搭建

你需要一个本地的 PHP 运行环境。

  • 集成环境包 (推荐新手)

    PHP如何开发微信公众平台?-图3
    (图片来源网络,侵删)
    • XAMPP:支持 Windows, macOS, Linux。
    • WampServer:仅支持 Windows。
    • MAMP:仅支持 macOS。
    • 这些包已经集成了 Apache (Web服务器)、MySQL (数据库) 和 PHP,一键安装即可使用。
  • 手动安装

    • 安装 PHP。
    • 安装 Apache 或 Nginx。
    • 安装 MySQL。
    • 配置环境变量。

安装完成后,可以通过 php -vhttpd -v (或 nginx -v) 命令检查是否安装成功。

4 选择合适的 PHP 框架 (可选)

对于简单的公众号,可以不使用框架,直接写 PHP 脚本,但对于复杂的项目,使用框架能极大提高开发效率和代码质量。

  • Laravel:目前最流行的 PHP 框架,生态完善,文档丰富。
  • ThinkPHP:国内流行的框架,对中文开发者友好,快速开发。
  • Symfony:稳定、灵活,组件化程度高。

本教程将以 原生 PHP 为例讲解核心原理,因为无论使用哪个框架,底层的 API 调用逻辑都是一致的。


核心入门:接收与回复消息

这是公众号开发最核心、最基础的部分。

1 微信服务器与开发者服务器的通信原理

  1. 用户 在公众号里发送消息。
  2. 微信服务器 接收到消息,然后根据你在后台配置的 URL (服务器地址),将消息通过 POST 请求转发给你的 开发者服务器
  3. 你的服务器 (PHP 脚本) 接收并解析这个 POST 请求。
  4. 你的服务器根据消息内容进行处理(如查询数据库、调用 API 等)。
  5. 你的服务器将处理结果按照微信规定的 XML 格式,通过 POST 请求响应给微信服务器。
  6. 微信服务器 再将这个响应结果原样回复给 用户

2 接入(验证)服务器

在后台配置 URL 之前,你需要先写一个脚本来验证服务器地址的有效性。

验证逻辑

  1. 微信服务器会向你配置的 URL 发送一个 GET 请求。
  2. 请求中包含四个参数:signature, timestamp, nonce, echostr
  3. 你的服务器需要: a. 将 token (你在后台配置的)、timestampnonce 三个参数进行字典序排序。 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 方法
}

操作步骤

  1. 将上面的代码保存为 server.php
  2. server.php 放到你 Web 服务器的根目录(如 htdocswww)。
  3. 在本地 hosts 文件中添加 0.0.1 your-test-domain.com (mp.localtest.me)。
  4. 在公众号后台 “设置与开发” -> “基本配置” -> “服务器配置” 中:
    • URL 填写 http://your-test-domain.com/server.php
    • Token 填写 your_token_here
    • 消息加解密方式选择“明文模式”(开发阶段最简单)。
    • 点击“提交”,如果提示成功,说明接入成功。

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)

当用户在公众号内点击一个链接时,你希望获取他的基本信息(如昵称、头像),这时就需要使用网页授权。

流程

  1. 用户点击你的链接。
  2. 你的链接重定向到微信授权页面。
  3. 用户同意授权。
  4. 微信重定向回你指定的回调 URL,并带上 code
  5. 你的服务器用 code 换取 access_tokenopenid
  6. 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 模板消息推送

模板消息用于在特定场景下给用户发送服务通知,如订单支付成功、预约提醒等。

步骤

  1. 在公众号后台“模板消息”中找到并启用一个模板。
  2. 记录下模板 ID。
  3. 你的服务器调用 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 生成带参数的二维码

用于识别用户来源、场景等。

  1. 临时二维码expire_seconds 指定有效期,最大1800秒。
  2. 永久二维码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 配置微信支付

  1. 在公众号后台“微信支付”中开通。
  2. 获取 商户号 (mch_id)API密钥 (api_key)
  3. 下载 支付证书 (apiclient_cert.pem, apiclient_key.pem),并放在服务器安全位置。

2 统一下单 API

这是发起支付的关键步骤。

  1. 构造请求数据包(XML格式),包含商品信息、金额、回调地址等。
  2. 对请求进行签名:这是最关键的一步,将所有参数(除 sign 外)按字典序排序,拼接,再用你的 api_key 进行 MD5 加密,得到 sign
  3. 将 XML 数据包发送到统一下单接口:https://api.mch.weixin.qq.com/pay/unifiedorder
  4. 解析返回结果,如果成功,会返回 prepay_id
  5. 再次签名,生成最终需要传递给微信 JSAPI 的参数。

3 支付结果异步通知

用户支付成功后,微信服务器会向你在统一下单时指定的 notify_url 发送一个 POST 请求(XML格式)。 你的服务器需要:

  1. 接收通知。
  2. 验证签名(非常重要!防止伪造)。
  3. 验证业务参数(如订单号、金额)。
  4. 处理业务逻辑(如更新订单状态为“已支付”)。
  5. 回复微信服务器 <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 常见问题与调试技巧

  1. Token 验证失败:检查 server.php 中的 TOKEN 是否与后台一致,检查服务器是否可以正常访问 server.php
  2. 签名错误:检查 API 调用时参数是否完整、排序是否正确、key 是否正确。
  3. 无法接收消息:检查服务器是否可以接收来自微信服务器的 POST 请求(防火墙、服务器配置)。
  4. 调试方法
    • 打印日志:将接收到的 XML 和发送的 XML 都打印到日志文件。
    • 使用 file_get_contents('php://input'):比 $GLOBALS["HTTP_RAW_POST_DATA"] 更可靠。
    • 使用 Ngrok:确保微信能访问到你本地的开发环境。

微信公众平台 PHP 开发,核心在于理解其 事件驱动请求-响应 的机制,从简单的消息回复开始,逐步学习使用各种高级接口,对于初学者,建议先用原生 PHP 理解底层逻辑,然后在实际项目中使用成熟的 SDK 来提高效率。

希望这份教程能帮助你顺利开启公众号开发之旅!

分享:
扫描分享到社交APP
上一篇
下一篇