微信公众号PHP对接需重点解决签名验证、XML解析和access_token管理三大问题:签名须按规则排序拼接并SHA1校验;XML需用php://input读取且禁用实体加载;access_token应存Redis并加锁刷新;图文消息PicUrl必须HTTPS。

微信公众号 PHP 对接不是配个 URL 和 Token 就能通,卡在签名验证、XML 解析、access_token 管理这三个地方,漏一个就收不到消息或调不了接口。
signature 校验失败的常见写法和修正
微信 GET 请求带 signature、timestamp、nonce、echostr 四个参数,你必须用后台配置的 token 参与拼接并 SHA1 加密比对。很多人直接拿 $_GET['signature'] 跟硬编码字符串比,或者排序错、哈希函数用错。
- 排序必须用
sort($arr, SORT_STRING),不能用asort(会保留键名,导致拼接顺序错乱) - 拼接必须是
implode('', $arr),中间不能有空格、换行、BOM - SHA1 必须用
sha1($str),不能用hash('sha1', $str)(后者默认二进制输出,要加true参数才等效) - 调试时务必
var_dump($tmpStr, $_GET['signature'])并肉眼比对——微信不报错,只静默丢弃请求 - 验证通过后必须
echo $echostr并立刻exit,后续任何输出(包括空白符)都会让微信解析失败
接收和回复 XML 消息时的安全与格式要点
微信所有用户消息都走 POST 的 raw XML,$_POST 始终为空是正常现象;直接用 simplexml_load_string 解析未过滤的 XML 会触发 XXE 攻击,且中文不转义会导致 XML 解析失败。
- 读取必须用
file_get_contents('php://input'),这是唯一可靠方式 - 解析前必须调用
libxml_disable_entity_loader(true),否则存在 XXE 风险 - 回复 XML 中的
ToUserName和FromUserName必须互换,否则用户收不到 -
CreateTime字段必须是字符串类型的时间戳((string)time()),不能是整型 - 中文内容必须用
htmlspecialchars($content, ENT_QUOTES, 'UTF-8')转义,否则微信当空响应 - HTTP 响应头必须显式设置
Content-Type: text/xml; charset=utf-8
access_token 存 Redis 的正确姿势
access_token 有效期 7200 秒,调用量有限(2000 次/天),不能每次请求都重拉;存文件易被并发写坏,存 session 完全无效(不同请求 session 不共享)。
立即学习“PHP免费学习笔记(深入)”;
- 推荐用 Redis:
$redis->setex('wx_access_token', 7200, $token),天然带过期,避免竞态 - 获取时先查缓存,命中则直接用;未命中再调用
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=xxx&secret=xxx - 刷新时需加分布式锁(如 Redis SETNX),否则多个进程并发刷新会覆盖旧 token
- 微信返回的
expires_in是相对秒数,不是绝对时间戳,别存成 Unix 时间戳去比对 - 不要把
access_token拼在 URL 里做 curl 请求——URL 长度受限且易被日志泄露
图文消息回复的字段完整性要求
发图文消息时,MsgType 设为 news,ArticleCount 表示条数,但每条 item 内的四个字段缺一不可,否则微信静默丢弃整条消息。
- 每个
item必须包含Title、Description、PicUrl、Url -
PicUrl必须是可公开访问的 HTTPS 地址(HTTP 会被微信拦截) -
Url必须能被微信服务器 GET 访问(不能 403/404/跳转登录页) - 最多支持 8 条,
ArticleCount必须与实际item数量一致 - 所有字段值都要用
htmlspecialchars(..., ENT_QUOTES, 'UTF-8')转义,尤其是含 HTML 符号的标题或描述
最常被忽略的是:签名验证阶段的排序和拼接细节、XML 解析前的 libxml_disable_entity_loader(true)、以及图文消息中 PicUrl 的 HTTPS 强制要求——这三处出问题,微信既不提示也不报错,只沉默丢包。



















