fgetss PHP函数的Bug

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

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

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

程序看上去很简单,之所以录入的数据少了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% 的数据有特殊字符?不太可能吧。

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

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

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

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

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181031G0T7ZF00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券