支付宝回调验签需用file_get_contents('php://input')获取原始数据并解析,剔除sign/sign_type后字典序排序,urlencode值拼接字符串,再用RSA2公钥验证base64解码后的签名。

支付宝支付回调时,PHP框架需要准确拼接并验签参数,否则无法通过支付宝的签名验证,导致回调失败或被恶意伪造请求攻击。
获取原始POST数据并解析为关联数组
支付宝回调使用 application/x-www-form-urlencoded 编码方式提交数据,但部分框架(如Laravel、ThinkPHP)会自动解析并覆盖 $_POST,丢失原始签名字段顺序。必须用 file_get_contents('php://input') 获取原始数据流再手动解析。
这一步不能依赖 $_POST,因为支付宝要求验签时参数必须按字典序排序且不含 sign 和 sign_type 字段——而框架自动填充的 $_POST 可能已混入其他键,或破坏原始键名大小写(如 notify_id 和 notify_Id 被统一转为小写)。
执行:$raw = file_get_contents('php://input'); → parse_str($raw, $params);
立即学习“PHP免费学习笔记(深入)”;
剔除签名相关字段并按字典序排序
方法一:手动 unset + ksort
unset($params['sign'], $params['sign_type']); → ksort($params);
方法二:array_diff_key + ksort(更安全)
$filtered = array_diff_key($params, ['sign' => '', 'sign_type' => '']); → ksort($filtered);
【注意:必须先 unset 再 ksort,顺序颠倒会导致验签失败】
拼接待签名字符串
第一步:初始化空数组用于收集 key=value 字符串
第二步:遍历 $filtered,对每个键值对做 urlencode 处理(支付宝要求 value 必须 urlencode,key 不需)
第三步:将处理后的字符串 push 进数组,例如 "out_trade_no=" . urlencode($v)
第四步:用 & 符号 implode 拼接所有项,得到最终待签名原文
这一步漏掉 urlencode 或多加空格都会导致签名不匹配。支付宝服务端对 value 的编码要求极其严格,中文、特殊符号、+ 号都必须正确转义。
调用支付宝公钥验签
使用 openssl_get_publickey() 加载支付宝提供的 RSA2 公钥(.pem 格式)→ 调用 openssl_verify() 验证 sign 值与原文是否匹配 → 返回 1 表示验签通过。
如果公钥内容开头不是 -----BEGIN PUBLIC KEY-----,而是以 -----BEGIN RSA PUBLIC KEY----- 开头,必须用 openssl_pkey_get_details() 提取 modulus + publicExponent 手动构造标准 PEM,否则 openssl_verify 会静默失败。
验签前确保 $params['sign'] 是 base64_decode 后的二进制数据,不是原始字符串。



















