PHP模拟POST请求需严格按服务端规则生成签名,常见坑包括键名排序、编码差异、时间戳精度、密钥处理等;签名须字节级一致,且需确认签名位置(Header/Body/URL),验签时应使用php://input并检查BOM、空格、密钥真实性。

PHP 模拟 POST 请求时,如果服务端要求参数签名(如 HMAC-SHA256、MD5 拼接、时间戳+nonce 等),光用 curl 发数据是不够的——签名错一个字符、少一个参数、时间偏差超 30 秒,都会返回 401 Unauthorized 或 invalid signature。
签名生成必须和服务器完全一致
签名不是“差不多对”,而是字节级严格匹配。常见坑包括:
-
json_encode()默认不排序键名,而签名常要求按 key 字典序拼接; - 空格、换行、URL 编码方式不一致(比如服务端用
rawurlencode(),你用了urlencode()); - 时间戳用的是
time()(秒级),但服务端校验的是毫秒或 UTC 时间; - 密钥参与计算前被意外 trim() 或 base64_decode() 过。
建议先用服务端提供的签名样例(含原始参数、密钥、期望签名值),在 PHP 里逐行比对中间结果,而不是直接发请求。
curl POST 时别漏掉签名头或签名字段
签名可能放在 HTTP Header(如 X-Signature)、URL 查询参数(?sign=xxx),或作为 POST body 的一个字段(如 {"data":{...},"sign":"xxx"})。确认清楚再写:
立即学习“PHP免费学习笔记(深入)”;
- Header 方式:用
curl_setopt($ch, CURLOPT_HTTPHEADER, [...])加入; - Body 字段方式:若用
json_encode()提交,确保sign是顶层字段且类型为 string; - GET 参数方式:用
http_build_query()拼完再手动追加&sign=xxx,注意不要重复 urlencode。
示例(Header 签名):
$headers = [
'Content-Type: application/json',
'X-Timestamp: ' . $timestamp,
'X-Nonce: ' . $nonce,
'X-Signature: ' . $sign
];
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
PHP 里验证签名失败?先检查这三件事
如果你是接收方(即 PHP 要验签),失败通常不是算法问题,而是输入源没对齐:
- 原始数据来源是否干净?
$_POST会被 PHP 自动解析并丢弃原始 body,验签必须用file_get_contents('php://input'); - 是否忽略了不可见字符?比如前端传了带 BOM 的 JSON,或参数里混入了全角空格;
- 密钥是否被配置文件自动 trim() 或转义?建议用
var_dump($secret)看实际长度和内容。
验签逻辑务必和文档/服务端代码逐行对照,尤其注意大小写(如 sha256_hmac 和 hash_hmac('sha256', ...) 结果一致,但拼接顺序不能反)。
签名逻辑看似简单,真正卡住人的永远是那些“应该一样但其实不一样”的细节——参数顺序、编码边界、时钟同步、body 原始性。动手前,先拿到服务端的明确签名规则原文,比对着写,比凭经验猜快得多。











