微信接入验证失败主因是签名排序拼接错误,需严格按token、timestamp、nonce字符串字典序排序并trim清理,xml解析须用libxml_nocdata,event值须严格比较且注意大小写与前缀。

验证失败:sha1() 排序和拼接顺序错一个字符就白忙
PHP 8.5 本身对微信接入没兼容性问题,但验证环节极其敏感——sort($tmpArr, SORT_STRING) 必须显式指定 SORT_STRING,否则 PHP 8.4+ 默认行为可能因数组元素类型隐式变化导致排序结果不一致。微信要求的是纯字符串字典序,不是数值排序。
常见错误现象:Verification failed. 日志里看到计算出的 $tmpStr 和 $_GET['signature'] 差一位;或本地测试通、上线就挂(常因服务器时区/HTTP代理改写了 GET 参数)。
-
TOKEN必须和公众号后台「服务器配置」里填的一模一样,大小写、空格、不可见字符全算 - 三个参数参与排序:
TOKEN、$_GET['timestamp']、$_GET['nonce']——不能漏掉TOKEN,也不能多加echostr - 拼接前用
trim()清理每个变量,避免换行或 BOM 头污染字符串 - 验证通过后务必
exit,否则后续代码可能输出额外空白,破坏echostr原样返回
收不到消息?php://input 被 Nginx/Apache 吃掉了
PHP 8.5 默认禁用 $HTTP_RAW_POST_DATA,必须用 file_get_contents('php://input') 读取 XML。但很多生产环境的 Web 服务器配置会提前解析或截断原始体,导致你拿到空字符串。
使用场景:用户发“你好”,你的接口没进任何分支,file_get_contents('php://input') 返回空,simplexml_load_string() 报 Warning 或直接失败。
立即学习“PHP免费学习笔记(深入)”;
- Nginx 需确认未开启
client_max_body_size限制过小,或fastcgi_pass未透传原始 body - Apache 下检查是否启用了
mod_security或其他 WAF 规则拦截了 XML POST - 调试时先加一行:
file_put_contents('/tmp/wx-raw.log', file_get_contents('php://input'), FILE_APPEND);看原始数据是否到达 PHP 层 - XML 解析必须加
LIBXML_NOCDATA标志,否则带 CDATA 的图文内容会丢失
图文回复报错“invalid xml”:字段名大小写和嵌套层级不能错
微信对图文消息 XML 的结构校验极严。MsgType 必须是 news(小写),ArticleCount 必须是整数字符串,Articles 下每个 item 必须完整包含 Title、Description、PicUrl、Url 四个节点——缺一不可,顺序不限,但标签名必须首字母大写且严格匹配文档。
参数差异:PicUrl 必须是公网可直连的 HTTPS 地址(微信会主动抓取缩略图),Url 同样需 HTTPS,且不能是 localhost 或内网地址;Description 超过 200 字会被截断,但不会报错。
-
item节点必须在Articles内,不能直接放在xml根下 - 所有文本内容必须用
包裹,否则特殊符号(如&、)会导致 XML 解析失败 - 最多 8 条图文,
ArticleCount值必须与实际item数量一致,否则部分条目被忽略 - 别用
json_encode()拼 XML——手写模板最稳,例如:$xml = "<xml>...</xml>";
菜单事件没响应?Event 值区分大小写且含隐藏状态
用户点击自定义菜单触发的是 event 类型消息,但 $postObj->Event 的值不是 “CLICK”,而是全大写的 CLICK(注意不是小写)。更隐蔽的是,扫码菜单的 Event 是 SCAN,但首次关注扫码还会附带 EventKey 带前缀 qrscene_,而后续扫码是纯 key。
性能影响:每次处理事件都去查数据库配菜单逻辑?别这么做。把常用菜单响应逻辑硬编码或缓存在 apcu 里,避免 IO 成为瓶颈。
-
Event值必须用===严格比较,避免类型转换误判 -
EventKey可能为空(比如默认菜单),需先isset($postObj->EventKey)判断 - 测试时用微信「开发者工具」里的「接口调试工具」手动发 XML,比真人点菜单快十倍
- 别忽略
subscribe事件的EventKey——带参数关注的场景越来越常见
CDATA、或者 EventKey 多了个下划线。细节不补全,再新的 PHP 也跑不通。











