PHP如何解析urlencode格式webhook内容取值并更新数据库
问题根因
代码无法获取参数的核心错误是用json_decode()解析URL编码格式的表单数据:你收到的webhook推送是标准的application/x-www-form-urlencoded格式(即key=value&key2=value2的URL编码结构),不是JSON格式,json_decode()处理这类内容会返回null,自然读不到任何字段值。
另外提前手动调用urldecode()处理原始输入是多余操作,后续解析函数会自动完成URL解码,手动提前解码反而可能在参数值包含&、=这类特殊字符时出现解析错误。
修复方案
直接使用PHP内置的parse_str()函数解析原始POST输入即可,该函数会自动完成URL解码,将所有参数解析为关联数组,不需要额外做转义处理。
修正后的完整代码如下:
<?php if ($_SERVER['REQUEST_METHOD'] == 'POST') { require_once 'dbcon/v20/dbcon.php'; // 读取原始POST输入,无需提前做urldecode处理 $rawInput = file_get_contents("php://input"); // 解析urlencoded格式内容为关联数组 parse_str($rawInput, $evt); // 基础参数校验,避免缺字段时抛出PHP警告 if (!isset($evt['Status'], $evt['MsgId'], $evt['remoteid'])) { http_response_code(400); exit("Invalid request payload"); } http_response_code(200); switch ($evt['Status']) { case 0: // waiting 待发送状态,可按需补充业务逻辑 break; case 1: // in progress 发送中状态,可按需补充业务逻辑 break; case 2: // sent 已发送 $msgid = $evt['MsgId']; $sentdate = $evt['SendDateTime']; $remoteid = $evt['remoteid']; $status = "Sent"; $uph = $mydbcon->prepare("UPDATE sms_send SET sent_date=?, status=? WHERE ticket=? AND remoteid=?"); $uph->bind_param('ssss', $sentdate, $status, $msgid, $remoteid); $uph->execute(); $uph->close(); // 释放预处理句柄,避免资源浪费 break; case 3: // delivered 已送达 $msgid = $evt['MsgId']; $sentdate = $evt['SendDateTime']; $deliverydate = $evt['DeliveryDateTime'] ?? ''; // 兼容字段为空的情况 $remoteid = $evt['remoteid']; $status = "Delivered"; $uph = $mydbcon->prepare("UPDATE sms_send SET sent_date=?, delivery_date=?, status=? WHERE ticket=? AND remoteid=?"); $uph->bind_param('sssss', $sentdate, $deliverydate, $status, $msgid, $remoteid); $uph->execute(); $uph->close(); break; case 4: // refused 发送被拒,可按需补充业务逻辑 break; case 6: // not delivered 未送达,可按需补充业务逻辑 break; } exit(); } ?>
补充说明
- 对于标准的
application/x-www-form-urlencoded格式POST请求,你也可以直接通过$_POST全局变量获取对应参数,PHP会自动完成解析;手动读取php://input后用parse_str解析的方式兼容性更强,不受服务端特殊配置影响。 - 调试阶段可以在解析完参数后加
file_put_contents("test.txt", print_r($evt, true));,将解析后的完整数组写入文件,确认所有字段都能正常获取,调试完成后删除该行即可。 - 数据库预处理语句执行完成后建议调用
close()释放句柄,减少数据库连接资源占用。
内容的提问来源于stack exchange,提问作者Louis Web Solutions
相关产品推荐
相关产品推荐

