复盘微信支付金额不正确问题解决过程——PHP浮点型计算

简介: 问题2017年9月份,商城项目在运行过程中,购买某商品时如果在下单时没有完成付款,而是稍后再从“个人中心-我的订单”发起付款,则无法调起微信支付界面思路其他商品正常,说明导致问题的原因大概率是商品本身只有从会员中心发起的付款存在此问题,说明大...

问题

2017年9月份,商城项目在运行过程中,购买某商品时如果在下单时没有完成付款,而是稍后再从“个人中心-我的订单”发起付款,则无法调起微信支付界面

思路

  • 其他商品正常,说明导致问题的原因大概率是商品本身
  • 只有从会员中心发起的付款存在此问题,说明大概率是会员中心的代码存在问题
  • 需要先观察问题出现时“统一下单”是否能够成功,检查是否是参数问题导致订单无法在微信端创建

观察统一下单返回值

result_code=FAIL
err_code=OUT_TRADE_NO_USED
err_code_des=商户订单号重复

微信官方对于此问题的描述如下:

img_16d20ebe6288936a65a0211fd184a337.png
image.png

出现这个问题的时候建议核查订单号是否重复提交,但实际上在这个使用场景下,我们是“故意”重复提交订单号的。因为从会员中心发起支付的时候订单已经创建了,系统会再次请求微信统一下单接口,即便如此,我们也没有必要每一次请求支付都创建一个新的订单号。

那为什么返回了这个错误

我先给出结论再描述排错过程:

所谓的同一笔交易不能多次提交,实际上指的是在商品描述、标价金额不相同的情况下,用同一个订单号访问了统一下单接口。

img_8ae99fb340ddcaca48e8eeb8e38259fa.png
image.png

这里的错误实际上是因为:从会员中心发起支付时“标价金额”与提交订单时的不相同。

PHP浮点型运算

以下是某位程序员写的微信支付代码:

$total_fee = (int)($order_total * 100);

微信要求金额的单位必须为分,而数据库中订单金额单位是元,所以使用订单金额*100是正确的做法。
订单支付金额的计算非常复杂,所以单位转化为分之后再转化为整型,可以保证微信支付参数不出错,也是正确的做法。

但这里面隐藏了一个问题,还记得我们问题发生的条件必须是“购买某商品时”吗?如果单独购买这个商品的话,订单的金额是19.9。我们可以尝试:

echo (int)(19.9 * 100);
// 结果为1989,而非1990

这就导致了订单创建时给微信的支付数据是1990,而再次支付时却是1980,所以接口返回了“订单号重复”的错误。

为什么会少了1分钱呢?PHP的官方文档中是这么说:


img_4f833f5593e455d3b842eb7fd2a061c5.png
image.png

随后我又实验了很多数字,结果如下:

echo (int)(19.1 * 100);// 1910
echo (int)(19.2 * 100);// 1920
echo (int)(19.3 * 100);// 1930
echo (int)(19.4 * 100);// 1939 注意这里出现了问题
echo (int)(19.5 * 100);// 1950
echo (int)(19.6 * 100);// 1960
echo (int)(19.7 * 100);// 1970
echo (int)(19.8 * 100);// 1980

这个问题的产生,似乎存在规律,例如19.4、18.4和17.4转化后是错误的,而8.4转化后返回了正确的结果。
更有趣的是:

echo (int)((19.8+0.1) * 100);
// 1990 注意此时结果是正确的
var_dump(19.9 == (19.8 + 0.1));
// false

调试过程

实际上这种奇怪的问题排查起来没有什么捷径,无非就是打日志追踪变量,最多也就是细心点罢了。

最终使用了一个比较讨巧的方式解决了这个问题,将代码改为了:

$total_fee = (int)(($order_total + 0.00001) * 100);

至于更加严谨的浮点数计算方法,今后遇到的时候,再研究吧。

目录
相关文章
|
3月前
|
PHP 开发者
PHP计算过去一定时间段内日期范围函数
这个函数为开发者提供了一个快速而简单的方法来获取与当前日期相关的过去时间范围,代码简洁易懂,可复用性高。
142 15
|
3月前
|
消息中间件 人工智能 Java
抖音微信爆款小游戏大全:免费休闲/竞技/益智/PHP+Java全筏开源开发
本文基于2025年最新行业数据,深入解析抖音/微信爆款小游戏的开发逻辑,重点讲解PHP+Java双引擎架构实战,涵盖技术选型、架构设计、性能优化与开源生态,提供完整开源工具链,助力开发者从理论到落地打造高留存、高并发的小游戏产品。
|
3月前
|
小程序 PHP 图形学
热门小游戏源码(Python+PHP)下载-微信小程序游戏源码Unity发实战指南​
本文详解如何结合Python、PHP与Unity开发并部署小游戏至微信小程序。涵盖技术选型、Pygame实战、PHP后端对接、Unity转换适配及性能优化,提供从原型到发布的完整指南,助力开发者快速上手并发布游戏。
|
3月前
|
存储 小程序 Java
热门小程序源码合集:微信抖音小程序源码支持PHP/Java/uni-app完整项目实践指南
小程序已成为企业获客与开发者创业的重要载体。本文详解PHP、Java、uni-app三大技术栈在电商、工具、服务类小程序中的源码应用,提供从开发到部署的全流程指南,并分享选型避坑与商业化落地策略,助力开发者高效构建稳定可扩展项目。
ly~
|
存储 供应链 小程序
除了微信小程序,PHP 还可以用于开发哪些类型的小程序?
除了微信小程序,PHP 还可用于开发多种类型的小程序,包括支付宝小程序、百度智能小程序、抖音小程序、企业内部小程序及行业特定小程序。在电商、生活服务、资讯、工具、娱乐、营销等领域,PHP 能有效管理商品信息、订单处理、支付接口、内容抓取、复杂计算、游戏数据、活动规则等多种业务。同时,在企业内部,PHP 可提升工作效率,实现审批流程、文件共享、生产计划等功能;在医疗和教育等行业,PHP 能管理患者信息、在线问诊、课程资源、成绩查询等重要数据。
ly~
331 6
|
云安全 存储 小程序
PHP微信小程序解决方案PhpMall
PHP微信小程序解决方案PhpMall
263 0
|
JavaScript Java 测试技术
基于微信小程序的家政服务预约系统的+php+vue.js附带文章和源代码设计说明文档ppt
基于微信小程序的家政服务预约系统的+php+vue.js附带文章和源代码设计说明文档ppt
246 3
基于微信小程序的家政服务预约系统的+php+vue.js附带文章和源代码设计说明文档ppt
|
PHP
PHP微信公众号投票活动系统源码
PHP微信公众号投票活动系统源码
409 11
|
PHP 开发工具
php免费用免认证的微信支付宝支付
php免费用免认证的微信支付宝支付
152 5
|
PHP
php使用curl新增微信临时素材(上传图片)
php使用curl新增微信临时素材(上传图片)
433 4