fgetss() PHP函数的Bug

作者: 虞大胆的叽叽喳喳 | 来源:发表于2018-11-07 17:18 被阅读24次

昨天在工作上遇到一个比较怪异的问题,觉得很有意思,特此记录下,也许你也曾经遇到过该问题。

原系统有一个程序,接收用户上传的 CSV 文件,这个文件共有10万行,每一行就一列,保存的数据是用户的邮箱地址,程序在接收到这个文件后,经过一系列其他逻辑处理,最后将这10万个邮件地址保存到数据库表中,每一个邮件地址一天表记录。

可程序运行结果只能录入5200条数据,为了排查问题,自己脑洞了很多可能遇到的情况,比如是不是文件太大了,是不是邮件地址不合法被丢弃了,经过 N 长时间的断点排查,大概定位到是以下代码产生的问题:

$handle = fopen("./file.csv", "r");
if ($handle) {
    while (!feof($handle)) {
        $buffer = fgetss($handle, 4096);
           
        if ($buffer=="") {
            continue ;
        }
        //存入到数据库表中
        saveData($buffer);
    }
    fclose($handle);
}

程序看上去很简单,之所以录入的数据少了95%,可能是因为有很多条数据($buffer变量)为空,可我将 file.csv 打开一看,觉得数据挺正常的,怎么会有那么多数据为空呢?

仔细观察了下,突然发现 fgetss() 函数,平时从文件句柄读取一行数据用的都是 fgets() 函数,我下意识的将 fgetss() 改为 fgets(),程序居然运行正确了,成功录入了10万条数据。

很明显了,可能就是 fgetss() 函数的锅,打开手册看看这函数是干啥的:

(PHP 4, PHP 5, PHP 7)

fgetss — 从文件指针中读取一行并过滤掉 HTML 标记

和 fgets() 相同,只除了 fgetss() 尝试从读取的文本中去掉任何 HTML 和 PHP 标记。

也就是说该函数在 fgets()函数的基础之上多做了一步工作,就是去除 HTML 和 PHP 标签,肯定是在运行过程中遇到了什么特殊字符,导致读出来的数据为空,可一个大大的问号出现了,难道 95% 的数据有特殊字符?不太可能吧。

我想了个方法,先找出这个字符是啥,改了下代码:

$handle = fopen("./file.csv", "r");
$i = 0  ;
if ($handle) {
    while (!feof($handle)) {
        $buffer = fgetss($handle, 4096);
        $i++ ;
        if ($buffer=="") {
            echo $i . "-" . $debugstr . "\r\n" ;
            continue ;
        }

        $debugstr = $buffer ;
    }
    fclose($handle);
}

程序逻辑就是如果遇到为空的字符,打印上一个字符,得到的结果如下:

5200-yhyy?yj'??
5201-yhyy?yj'??
5202-yhyy?yj'??
...
100000-yhyy?yj'??

也就是说代码遇到了一行特殊字符,导致它后面的数据全部为空了,这个影响就比较大了,如果遇到一行数据处理不成功抛弃即可,但它导致后面的数据读取全为空了,这就是问题的关键所在。我在 file.csv 中找到了这行特殊数据 yhyy?yj'??<@sina.com,至于为什么会出现该问题就不得而知了,然后我在 PHP7 中也测试了下,还是同样的问题,算 PHP 的一个 Bug 吗?

最后也吐槽下 PHP,虽然函数非常多,方便开发,但非常的不结构化,这一点比 Python 差了很多,fgets() 作为一个标准的 C 函数,干它该干的,读取一行数据即可,非要基于 fgets() 再包装一个不伦不类的 fgetss() 函数,显得画蛇添足。


【这篇文章于2018-10-28号发表于公众号,地址https://mp.weixin.qq.com/s/nFgiK-gOva6OxW4s66HosQ,也可以关注我的公众号(ID:yudadanwx,虞大胆的叽叽喳喳)】

相关文章

  • fgetss() PHP函数的Bug

    昨天在工作上遇到一个比较怪异的问题,觉得很有意思,特此记录下,也许你也曾经遇到过该问题。 原系统有一个程序,接收用...

  • docker php镜像中pathinfo() filename

    问题描述 docker PHP 的镜像中,pathinfo函数有bug。basename 和filename,在默...

  • 由FindFirstFile()所引发的PHP解释器的神奇解析行

    由于FindFirstFile()函数处理存在Bug,导致调用了该函数的PHP解释器也引发了一系列的问题。 在实践...

  • php底层rtrim的一个“bug”

    php底层rtrim的一个“bug” 背景 trim系列函数是用于去除字符串中首尾的空格或其他字符。ltrim函数...

  • 关于PHP内置函数的bug

    最近写php的一些项目,总是被内置函数坑害,debug到最后,发现是内置函数的问题。这里简单记录一些内置函数问题的...

  • PHP参考手册

    PHP参考手册 PHP array() 函数 PHP array_change_key_case()函数 PHP ...

  • 从0到1学习网络安全 【PHP基础-PHP 函数】

    PHP 函数 PHP 的真正力量来自它的函数:它拥有超过 1000 个内建的函数。 PHP 用户定义函数 除了内建...

  • PHP中一些函数方法

    php自定义函数之递归函数 php自定义函数之静态变量 php​ 使用系统内置函数 亚麻跌”是PHP学习时间处理的...

  • 九月四号

    PHP函数之内置函数 内置函数指的是PHP默认支持的函数,PHP内置了很多标准的常用的处理函数,包括字符串处理、数...

  • Php03(数据库操作)

    2018年8月10日 1.PHP连接MySQL的常用函数 tip:找了一上午bug导致效率低下的一天。。 mysq...

网友评论

  • helloKimmy:这个代码真的能运行吗?测试用数据,背后可能有干扰源,因为好像是个查询代码。是每回运行到一个地方就截断了么?区别在于,两个指令,一个不查看数据内容,另一个检查数据内容。测试用数据是想用来侵入服务器专门制作的吧?哈哈!

本文标题:fgetss() PHP函数的Bug

本文链接:https://www.haomeiwen.com/subject/nvgvxqtx.html