深入解析 php 使用easywechat对接微信服务号和小程序
这EasyWeChat 6.x 是目前 PHP 社区中最好用、最活跃的微信开发 SDK。
EasyWeChat 6.x (由 w7corp 维护) 相较于 5.x 版本,在配置和调用方式上有了很大的变化,它全面拥抱了 Factory (工厂) 模式和依赖注入,代码更现代化。
这里是一份为你准备的、基于 EasyWeChat 6.x 的微信服务号和小程序开发的说明文档与 Demo。
说明文档:EasyWeChat 6.x 对接指南
1. 环境准备 (Prerequisites)
- PHP 版本:
EasyWeChat 6.x要求PHP >= 8.0。 - Composer:用于安装 SDK。
- 微信资质:
- 服务号 (Official Account):已认证的服务号 AppID 和 AppSecret。
- 小程序 (Mini Program):小程序 AppID 和 AppSecret。
- 开放平台 (Open Platform):
- (关键) 如果你希望服务号和小程序下的用户身份是统一的(即获取到相同的
UnionID),你必须将此服务号和此小程序绑定到同一个微信开放平台账号下。
- (关键) 如果你希望服务号和小程序下的用户身份是统一的(即获取到相同的
2. 安装 (Installation)
在你的项目根目录下,使用 Composer 执行:
composer require w7corp/easywechat:^6.0
3. 核心配置 (Configuration)
EasyWeChat 6.x 的核心是 Factory。你需要分别为服务号和小程序创建实例。
最佳实践:创建一个专门的配置文件(例如 config.php)来存放你的密钥,然后在应用中加载它。
示例 config.php (存放密钥)
<?php
// config.php
return [
/**
* 服务号配置
*/
'official_account' => [
'app_id' => '你的服务号AppID',
'secret' => '你的服务号AppSecret',
'token' => '你的服务号Token (用于服务器验证)',
'aes_key' => '你的服务号EncodingAESKey (明文模式可不填)',
],
/**
* 小程序配置
*/
'mini_app' => [
'app_id' => '你的小程序AppID',
'secret' => '你的小程序AppSecret',
],
/**
* 共享配置 (日志、HTTP等)
*/
'common' => [
// 日志配置
'log' => [
'default' => 'daily', // 默认日志驱动
'channels' => [
'daily' => [
'driver' => 'daily',
'path' => __DIR__ . '/logs/wechat.log', // 日志文件路径
'level' => 'debug',
'days' => 7,
],
],
],
// HTTP 客户端配置
'http' => [
'timeout' => 5.0,
'connect_timeout' => 5.0,
// 更多配置...
],
]
];
示例 init.php (应用初始化)
在你的项目入口文件或一个公共的初始化文件(如 init.php)中,引入 Factory 并创建应用实例。
<?php
// init.php
require_once __DIR__ . '/vendor/autoload.php';
use EasyWeChat\Factory;
// 1. 加载配置
$config = require __DIR__ . '/config.php';
// 2. 创建服务号 App 实例
// 合并通用配置
$officialAccountConfig = array_merge($config['common'], $config['official_account']);
$oa = Factory::officialAccount($officialAccountConfig);
// 3. 创建小程序 App 实例
// 合并通用配置
$miniAppConfig = array_merge($config['common'], $config['mini_app']);
$mini = Factory::miniApp($miniAppConfig);
// 4. (可选) 将 $oa 和 $mini 实例存放到全局变量、DI容器或在需要的地方直接返回
// return ['oa' => $oa, 'mini' => $mini];
Demo:文件结构与代码示例
我们基于上述配置,创建以下文件结构来演示几个核心功能:
/your_project
|-- vendor/ (Composer 目录)
|-- logs/ (日志目录,需可写)
|-- config.php (上面写的配置文件)
|-- init.php (上面写的初始化文件)
|
|-- official_account/ (服务号功能)
| |-- oauth_redirect.php (1. 发起网页授权)
| |-- oauth_callback.php (2. 授权回调处理)
| |-- server.php (3. 消息与事件接收)
|
|-- mini_program/ (小程序功能)
| |-- login.php (1. 小程序登录凭证校验)
| |-- decrypt.php (2. 手机号等信息解密)
|
|-- composer.json
[Demo 1] 微信服务号 (Official Account) 功能
功能 1 & 2:网页授权 (OAuth 2.0 获取用户信息)
第1步:发起授权 official_account/oauth_redirect.php
(用户访问这个页面,将自动跳转到微信授权页)
<?php
// official_account/oauth_redirect.php
// 引入初始化文件,获取 $oa 实例
require_once __DIR__ . '/../init.php';
// $oa 已在 init.php 中被创建
// 准备回调地址 (必须是你在服务号后台配置的 "网页授权域名" 下的地址)
$callbackUrl = 'https://your-domain.com/official_account/oauth_callback.php';
// 获取 OAuth 实例
$oauth = $oa->getOauth();
// 1. 发起授权
// scope: snsapi_userinfo (弹框授权,可获取昵称头像)
// scope: snsapi_base (静默授权,只能获取 OpenID)
$response = $oauth->scopes(['snsapi_userinfo'])->redirect($callbackUrl);
// 6.x 版本中,redirect() 返回的是一个 PSR-7 Response 对象
// 我们需要 "发送" 这个响应,它会自动执行 302 跳转
$response->send();
第2步:处理回调 official_account/oauth_callback.php
(用户在微信上同意授权后,会携带 code 跳转回这个页面)
<?php
// official_account/oauth_callback.php
require_once __DIR__ . '/../init.php';
try {
// 获取 OAuth 实例
$oauth = $oa->getOauth();
// 2. 通过 code 换取 AccessToken 和 OpenID
// 注意:这里的 user() 方法会自动处理 $_GET['code']
$user = $oauth->user();
// 3. 获取用户信息
// $user 是一个 EasyWeChat\Oauth\User 对象
$originalData = $user->getOriginal(); // 原始数据
$openId = $user->getId(); // OpenID
$nickname = $user->getNickname(); // 昵称
$avatar = $user->getAvatar(); // 头像
$unionId = $user->getUnionId(); // UnionID (如果已绑定开放平台)
// 业务逻辑:
// 1. 在这里查询你的数据库,看 $openId 或 $unionId 是否已存在
// 2. 如果不存在,创建新用户;如果存在,更新用户信息
// 3. 登录态(Session/JWT)下发
echo "授权成功!<br>";
echo "OpenID: " . $openId . "<br>";
echo "昵称: " . $nickname . "<br>";
echo "头像: <img src='" . $avatar . "' width='100' /><br>";
if ($unionId) {
echo "UnionID: " . $unionId;
}
} catch (\EasyWeChat\Exceptions\HttpException $e) {
echo "授权失败:" . $e->getMessage();
} catch (\Throwable $e) {
echo "系统错误:" . $e->getMessage();
}
功能 3:消息与事件接收 official_account/server.php
(你需要将 https://your-domain.com/official_account/server.php 填入服务号后台的 “服务器配置” URL)
<?php
// official_account/server.php
require_once __DIR__ . '/../init.php';
use EasyWeChat\Messages\Text;
use EasyWeChat\Messages\Image;
try {
// 获取 Server 实例
$server = $oa->getServer();
// 1. 处理文本消息
$server->with(function ($message, $next) {
if ($message->MsgType === 'text') {
// 根据关键词回复
if ($message->Content === '你好') {
return new Text('你也好!');
}
if ($message->Content === '图片') {
// 回复图片 (MediaId 需要提前上传)
// return new Image('MEDIA_ID_HERE');
}
// 默认回复
return new Text('已收到你的消息:' . $message->Content);
}
return $next($message);
});
// 2. 处理事件 (如:关注)
$server->with(function ($message, $next) {
if ($message->MsgType === 'event') {
if ($message->Event === 'subscribe') {
return new Text('感谢你的关注!');
}
if ($message->Event === 'CLICK' && $message->EventKey === 'MENU_KEY_ABOUT_US') {
return new Text('我们是 EasyWeChat 演示团队。');
}
}
return $next($message);
});
// 3. 启动服务,处理请求
$response = $server->serve();
// 4. 发送响应
$response->send();
} catch (\Throwable $e) {
// 记录异常日志,非常重要!
$log = $oa->getLogger();
$log->error('Server Error: ' . $e->getMessage());
}
[Demo 2] 微信小程序 (Mini Program) 功能
功能 1:小程序登录 (code 换 session_key)
(小程序前端 wx.login() 成功后,会带着 code 请求这个接口)
<?php
// mini_program/login.php
require_once __DIR__ . '/../init.php';
// 设置响应头为 JSON
header('Content-Type: application/json');
// 1. 从前端获取 code
$payload = json_decode(file_get_contents('php://input'), true);
$code = $payload['code'] ?? ($_POST['code'] ?? $_GET['code']);
if (empty($code)) {
echo json_encode(['errcode' => 400, 'errmsg' => 'code is required']);
exit;
}
try {
// 2. (推荐) 使用 $mini->get('auth') 获取 auth 实例
$auth = $mini->get('auth');
// 3. 调用 codeToSession (v6 的新方法)
$session = $auth->session($code);
// $session 是一个数组,例如:
// [
// 'openid' => 'OPENID',
// 'session_key' => 'SESSION_KEY',
// 'unionid' => 'UNIONID' (如果已绑定开放平台)
// ]
// 4. 业务逻辑
// (重要) 不要把 session_key 返回给前端!
// 1. 根据 openid 和 unionid 查询或创建用户
// 2. 生成你自己的登录态 (例如 JWT 或 Token)
// 3. 将 Token 和 openid (或 unionid) 返回给前端
// 示例:仅返回 openid 和 unionid
$responseData = [
'errcode' => 0,
'errmsg' => 'ok',
'openid' => $session['openid'],
'unionid' => $session['unionid'] ?? null,
'my_token' => 'YOUR_CUSTOM_LOGIN_TOKEN_HERE', // (这是你生成的Token)
];
echo json_encode($responseData);
} catch (\EasyWeChat\Exceptions\HttpException $e) {
// API 请求失败
echo json_encode(['errcode' => $e->getCode(), 'errmsg' => $e->getMessage()]);
} catch (\Throwable $e) {
// 其他错误
echo json_encode(['errcode' => 500, 'errmsg' => 'server error']);
}
功能 2:解密用户信息 (如手机号)
(小程序前端通过 button open-type="getPhoneNumber" 获取 code、iv 和 encryptedData,然后传给后端)
<?php
// mini_program/decrypt.php
require_once __DIR__ . '/../init.php';
header('Content-Type: application/json');
$payload = json_decode(file_get_contents('php://input'), true);
// 1. 获取前端数据
$code = $payload['code'] ?? null; // 这是 getPhoneNumber 用的 code
$iv = $payload['iv'] ?? null;
$encryptedData = $payload['encrypted_data'] ?? null;
if (empty($code) || empty($iv) || empty($encryptedData)) {
echo json_encode(['errcode' => 400, 'errmsg' => 'missing required parameters']);
exit;
}
try {
// 2. (重要) 解密手机号需要用 session_key
// EasyWeChat v6 提供了快捷方法,它会自动用 code 换 session_key,然后再解密
$utils = $mini->getUtils();
// 3. 解密手机号 (v6.10+ 新增)
$phoneData = $utils->getPhone($code, $encryptedData, $iv);
// $phoneData 示例:
// [
// 'phoneNumber' => '13800138000',
// 'purePhoneNumber' => '13800138000',
// 'countryCode' => '86',
// 'watermark' => [ 'appid' => '...', 'timestamp' => ... ]
// ]
// 业务逻辑:将手机号 $phoneData['purePhoneNumber'] 绑定到对应用户
echo json_encode([
'errcode' => 0,
'errmsg' => 'ok',
'phone_info' => $phoneData,
]);
} catch (\Exception $e) {
echo json_encode(['errcode' => 500, 'errmsg' => '解密失败: ' . $e->getMessage()]);
}
更多推荐



所有评论(0)