PHP7 serialize_precision 配置不当导致 json_encode() 浮点小数溢出错误
https://blog.csdn.net/moliyiran/article/details/81179825
感谢 @地狱星星:
原因已找到, 该现象只出现在PHP 7.1+版本上
建议使用默认值 serialize_precision = -1 即可
参考: https://wiki.php.net/rfc/prec...
----------------------------------------------------------------------------------
事情是这样的,项目里发现一个奇怪的现象,json_encode一个带浮点价格的数据, 出现溢出, 比如:
- <?php
- echo json_encode(277.2);
- // 输出结果为: 277.199999999999989
这明显是不能接受的, 数据虽然很接近, 但毕竟已经变更了
下意识地认为这是php的一个bug, 不能准确地json序列化一个浮点小数
这个问题google了半天竟然也无果, 然后我跟同事说, 你们json_encode数据里有小数的时候, 记得先number_format()转化成字符串.
自己又写了个fix方法, 遍历数据, 把is_float()的数据都用number_format()转化了
- function json_encode_pre($d, $depth=128, $level=0){
- if($level>$depth) return $d;
- if(is_array($d)){
- foreach ($d as $i => $v) { $d[$i] = json_encode_pre($v, $depth, $level+1); }
- return $d;
- }
- if(is_float($d)){
- # 测试发现number_format有效数字低于18(保守取16)时,不会溢出
- $p = 16 - strlen(intval($d));
- $f = number_format($d, $p);
- if($p>1){ $f = preg_replace('/0+$/','', $d); }
- return $d;
- }
- return $d;
- }
- echo number_format(277.2, 14); // 当18位有效数字处理(277.2已有4位有效数字)
- // 277.199999999999989
- echo number_format(277.2, 12); // 当16位
- // 277.2000000000000
- echo json_encode(json_encode_pre(277.2));
- // "277.2"
看到这结果时, 便猜测是有效数字位数的问题导致了溢出, PHP怎么会有这么蠢的设计呢?这是我当时的想法.
然后想着是不是能从源码下手, 于是查了下php源码, 发现这段代码:
- static inline void php_json_encode_double(smart_str *buf, double d, int options) /* {{{ */
- {
- size_t len;
- char num[PHP_DOUBLE_MAX_LENGTH];
- php_gcvt(d, (int)PG(serialize_precision), '.', 'e', num);
- len = strlen(num);
- if (options & PHP_JSON_PRESERVE_ZERO_FRACTION && strchr(num, '.') == NULL && len < PHP_DOUBLE_MAX_LENGTH - 2) {
- num[len++] = '.';
- num[len++] = '0';
- num[len] = '\0';
- }
- smart_str_appendl(buf, num, len);
- }
是的, 竟然发现了配置项serialize_precision, 这个配置我当初的理解是serialize()方法用的, 而我当初尝试修改过配置项precision, 然并卵, 原来json_encode会用到serialize_precision, 于是修改php.ini, 把它设为16, 原来是17还是18忘了.
- <?php
- echo json_encode(277.2);
- // 输出结果为: 277.2
如果你想重现我的问题, 很简单, 把serialize_precision设为20或更大, 至于这个有效数字最大值是多少才不会溢出, 我还不知道跟什么有关系, 希望能有大神指点了.
我是通过改配置数值, 出现溢出的值再减去2来用的.
附上配置项说明, 从官方说明上看, 很难想像是跟json_encode是有关系的.
- ; php.ini
- ; When floats & doubles are serialized store serialize_precision significant
- ; digits after the floating point. The default value ensures that when floats
- ; are decoded with unserialize, the data will remain the same.
- serialize_precision = 16
- ; The number of significant digits displayed in floating point numbers.
- ; http://php.net/precision
- precision = 16
另外源码里有个json_encode的选项JSON_PRESERVE_ZERO_FRACTION, 这个的意思是如果是个是个整数, 是否保留小数点和0, 来看测试结果:
- <?php
- echo json_encode(277.0);
- // 277
- echo json_encode(277.0, JSON_PRESERVE_ZERO_FRACTION);
- // 277.0
PHP7 serialize_precision 配置不当导致 json_encode() 浮点小数溢出错误的更多相关文章
- SELinux配置不当导致vsftpd系统用户不能登陆
1.测试是否是SELinux配置不当导致的: setenforce 0 再次登陆ftp,正常,说明是SELinux配置不当导致.还原配置 setenforce 1 2.查看配置: getsebool ...
- SELinux配置不当导致httpd无法在非80端口启动
检测是否为selinux导致httpd启动失败,若setenforce 0以后就可以启动,就表示selinux配置不当. 首先本机要支持semanage命令,安装方法网上有. semanage po ...
- NFS配置不当导致的那些事儿
NFS(Network File System):是FreeBSD支持的文件系统中的一种,它允许网络中的计算机之间通过TCP/IP网络共享资源: NFS配置:(声明:以下NFS实验是在RedHat7上 ...
- MySQL配置不当导致Sonarqube出错的一次经历:Packet for query is too large (16990374 > 13421568)
公司里部署了Jenkins + Sonarqube对项目代码进行构建和代码质量扫描. 某个大型项目报告项目构建失败.进jenkins看,该项目构建日志中的报错信息是这样的: 通过错误堆栈中的信息可以判 ...
- 配置不当导致无法加载odoo-10.0模块
启动odoo-bin时出错 2017-01-05 06:38:51,046 5480 INFO ? odoo: Odoo version 10.02017-01-05 06:38:51,046 548 ...
- nginx配置不当导致的目录遍历下载漏洞-“百度杯”CTF比赛 2017 二月场
题目:http://98fe42cede6c4f1c9ec3f55c0f542d06b680d580b5bf41d4.game.ichunqiu.com/login.php 题目内容: 网站要上线了, ...
- nginx 配置不当导致目录遍历下载漏洞
今天做百度杯的时候发现一个题很有意思. 点进题目,发现了一个js重定向到login.php,抓包发现请求的header中cookie=0,做过这种类似的题目,o==false,在请求头里面将cooki ...
- Nginx配置不当可能导致的安全问题
Nginx配置不当可能导致的安全问题 Auther: Spark1e目前很多网站使用了nginx或者tenginx(淘宝基于Nginx研发的web服务器)来做反向代理和静态服务器,ningx的配置文件 ...
- 痞子衡嵌入式:系统时钟配置不当会导致i.MXRT1xxx系列下OTFAD加密启动失败
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是系统时钟配置不当会导致i.MXRT1xxx系列下OTFAD加密启动失败问题. 我们知道,i.MXRT1xxx家族早期型号(RT1050/ ...
随机推荐
- Random类产生随机数
Random 类作为JAVA中用于产生的随机数 ,new Random(10) :10是种子数. 注意:Random 的一个特点是:相同种子数的Random对象,对应相同次数生成的随机数字是完全相 ...
- 洛谷 P1280 尼克的任务题解
题目链接:https://www.luogu.org/problem/P1280 题目描述 尼克每天上班之前都连接上英特网,接收他的上司发来的邮件,这些邮件包含了尼克主管的部门当天要完成的全部任务,每 ...
- Dubbo源码分析(2):ServiceBean
ServiceBean时序图
- python 类 双下划线解析
__getattr__用法:说明:这是python里的一个内建函数,当调用的属性或者方法不存在时,该方法会被调用调用不存在的属性调用不存在的方法
- php获取本地化时间戳函数
在实际的工作中我们还需要经常用到指定某个时间生成. 例如:需要找到昨天到今天此时此刻的注册用户. 那么我们需要做两件事情: 1.得到当前的时间unix时间戳.用time()函数就可以直接搞定大理石平台 ...
- windows下命令行切换目录
1.切换目录 C:\Users\MACHENIKE> cd H:/www C:\Users\MACHENIKE>H: H:\www> 2.查看目录文件 H:\www>dir
- 本地存储API
一.定义 随着互联网的快速发展,基于网页的应用越来越普遍,同时也变得越来越复杂,为了满足各种各样的需求,会经常在本地存储大量的数据,HTML5规范提出了相关解决方案 本地存储设置读取方便,容量较大,s ...
- 博客系统的使用(typecho、WordPress等等)
一.下载,解压,安装 二.Apache配置虚拟主机,(host文件修改) 三.开启php.ini中pdo类型的扩展适配数据库 四.按照指示页面配置 五.操作控制面板和blog前台
- AtCoder Grand Contest 011题解
传送门 \(A\) 直接按时间排序之后贪心就可以了 const int N=1e5+5; int a[N],q[N],c,k,h,t,n,res; inline int min(R int x,R i ...
- [golang] 抓包注入分析
视频信息 Packet Capture, Analysis, and Injection with Goby John Leonat GopherCon 2016 https://www.youtub ...