微信支付完成后,微信服务器会向商户预先配置的回调地址发送异步通知,商户需要通过PHP编写对应的逻辑来接收并处理这些通知数据,确保订单状态能够正确更新。整个流程包含数据接收、签名校验、数据解析、业务处理、结果响应几个核心步骤,下面逐一说明实现方法。

一、获取回调原始数据
微信支付回调发送的是XML格式的数据,PHP不能直接通过$_POST获取,需要使用输入流读取原始请求内容,具体代码如下:
<?php
// 读取原始回调数据
$raw_data = file_get_contents('php://input');
// 将XML数据转换为数组方便后续处理
function xml_to_array($xml) {
libxml_disable_entity_loader(true);
$values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $values;
}
$callback_data = xml_to_array($raw_data);
?>
二、验证回调签名合法性
接收到数据后,必须先验证签名,确认通知确实来自微信服务器,避免恶意请求伪造数据。签名验证需要用到商户密钥,步骤如下:
- 从回调数据中取出
sign字段,暂时移除 - 将剩余参数按照参数名ASCII码从小到大排序,拼接成键值对字符串
- 拼接商户密钥后做MD5加密,转大写后与回调中的
sign对比
具体实现代码如下:
<?php
// 商户密钥,在微信支付商户平台配置
$merchant_key = 'your_merchant_key_here';
// 验证签名函数
function check_sign($data, $key) {
// 取出sign字段
$sign = $data['sign'];
unset($data['sign']);
// 参数排序
ksort($data);
$string = '';
foreach ($data as $k => $v) {
if ($v != '' && !is_array($v)) {
$string .= $k . '=' . $v . '&';
}
}
// 拼接密钥
$string = $string . 'key=' . $key;
// MD5加密转大写
$check_sign = strtoupper(md5($string));
return $check_sign === $sign;
}
// 执行签名验证
if (!check_sign($callback_data, $merchant_key)) {
// 签名验证失败,返回错误响应
echo array_to_xml(['return_code' => 'FAIL', 'return_msg' => '签名验证失败']);
exit;
}
?>
三、处理业务数据并更新订单
签名验证通过后,就可以处理回调中的业务数据了,核心需要关注return_code和result_code两个字段,只有当两个字段都为SUCCESS时,才表示支付成功。之后可以根据out_trade_no(商户订单号)更新对应订单的状态,代码如下:
<?php
// 判断支付结果
if ($callback_data['return_code'] == 'SUCCESS' && $callback_data['result_code'] == 'SUCCESS') {
$out_trade_no = $callback_data['out_trade_no']; // 商户订单号
$transaction_id = $callback_data['transaction_id']; // 微信支付订单号
$total_fee = $callback_data['total_fee']; // 支付金额,单位为分
// 这里编写你的订单更新逻辑,比如连接数据库修改订单状态为已支付
// 示例:假设使用PDO操作数据库
// $pdo = new PDO('mysql:host=127.0.0.1;dbname=test', 'user', 'pass');
// $sql = "UPDATE orders SET status = 1, transaction_id = ? WHERE out_trade_no = ?";
// $stmt = $pdo->prepare($sql);
// $stmt->execute([$transaction_id, $out_trade_no]);
// 业务处理完成后,返回成功响应给微信服务器,避免微信重复发送通知
$response = [
'return_code' => 'SUCCESS',
'return_msg' => 'OK'
];
echo array_to_xml($response);
} else {
// 支付失败,记录日志
// file_put_contents('pay_callback.log', '支付失败:' . json_encode($callback_data) . PHP_EOL, FILE_APPEND);
echo array_to_xml(['return_code' => 'SUCCESS', 'return_msg' => 'OK']);
}
?>
四、数组转XML的辅助函数
上面的代码中用到了array_to_xml函数,用于将数组转换为微信要求的XML格式响应,实现代码如下:
<?php
function array_to_xml($arr) {
$xml = '<xml>';
foreach ($arr as $key => $val) {
if (is_numeric($val)) {
$xml .= '<' . $key . '>' . $val . '</' . $key . '>';
} else {
$xml .= '<' . $key . '><![CDATA[' . $val . ']]></' . $key . '>';
}
}
$xml .= '</xml>';
return $xml;
}
?>
五、注意事项
- 回调地址必须是可以公网访问的地址,且不能带有参数,微信不支持带参数的回调地址
- 处理回调的业务逻辑需要保证幂等性,避免微信重复发送通知导致订单重复更新
- 响应给微信的XML必须格式正确,否则微信会认为通知接收失败,持续重发通知
- 如果业务处理耗时较长,建议先返回成功响应,再将业务逻辑放到异步队列中处理