Flutterwave支付API结合PHP与MySQL:如何将待支付状态更新为成功
原代码存在的问题
- PHP起始标签书写错误,误写为
<php?>,正确语法为<?php,会直接导致代码无法解析 - SQL拼接语法错误:字符串类型的字段值(如
payment_status、tx_ref)未加单引号,会被MySQL识别为列名而非值,直接触发SQL执行错误 - 存在SQL注入风险:直接将接口返回的、可被伪造的字段值拼接到SQL语句中,没有做参数化处理
- 逻辑缺陷:未提前校验Flutterwave返回的
status是否为合法成功状态,也未判断返回的交易字段是否存在,空返回时会触发未定义键的PHP警告 - 跳转失效:执行
header()跳转前已经通过echo输出了内容,会触发headers already sent错误,导致跳转逻辑无法执行 - 冗余代码:重复执行两次
json_decode生成的$res变量没有实际作用,属于无效冗余
正确实现逻辑
核心修正点如下:
- 先校验支付返回的结构合法性,确认Flutterwave返回的交易状态为成功、金额与待支付金额匹配后,再执行数据库更新操作
- 使用MySQL预处理语句执行更新,避免SQL注入和字符串拼接的语法错误
- 移除跳转前的冗余输出,保证header跳转正常执行,跳转后添加
exit终止后续代码运行 - 增加字段存在性判断,避免空返回触发运行时错误
修正后代码示例
<?php // 解析支付返回结果 $responseArray = json_decode($response, true); // 校验返回状态合法性 if (!$responseArray || $responseArray['status'] !== 'success') { exit('非法支付返回结果'); } // 校验交易字段完整性 $transactionData = $responseArray['data'] ?? []; $requiredFields = ['id', 'amount', 'tx_ref']; foreach ($requiredFields as $field) { if (!isset($transactionData[$field])) { exit('交易信息不完整'); } } $payment_id = (int)$transactionData['id']; $paid_amount = (float)$transactionData['amount']; $payment_status = 'success'; // 可统一映射为系统自定义的状态值 $tx_ref = $transactionData['tx_ref']; // 校验支付金额是否与待支付金额匹配 if ($paid_amount < $amountToPay) { exit('支付金额异常'); } // 预处理语句执行更新,避免SQL注入 $updateStmt = $conn->prepare("UPDATE transaction_details SET payment_id = ?, payment_status = ? WHERE tx_ref = ?"); // 绑定参数:i=整数 s=字符串 s=字符串 $updateStmt->bind_param("iss", $payment_id, $payment_status, $tx_ref); if ($updateStmt->execute()) { // 无额外输出,直接执行跳转 header('Location: congratulations.php'); exit; // 终止后续代码执行,避免后续内容干扰跳转 } else { exit('状态更新失败:' . $conn->error); } $updateStmt->close(); $conn->close(); ?>
补充注意事项
- 上述逻辑仅适用于支付完成后前端跳转的回调场景,该场景可靠性较低(用户可能支付后直接关闭页面,跳转请求无法送达),建议额外配置Flutterwave的异步Webhook服务端回调做状态兜底更新,Webhook是Flutterwave服务端主动向你的服务端推送交易结果,可靠性远高于前端跳转回调
- 不要直接存储第三方支付平台返回的原始状态字符串,可统一映射为你系统内部定义的状态枚举(如
pending/success/failed),降低后续业务的兼容成本
内容的提问来源于stack exchange,提问作者Sesugh01
相关产品推荐
相关产品推荐

