我使用PHP使用fgetcsv()从CSV文件导入数据,这会为每行生成一个数组。最初,我将字符限制设置为1024,如下所示:
while ($data = fgetcsv($fp, 1024)) {
// do stuff with the row
}
但是,200多列的CSV在许多行上超过1024限制。这导致行读取停止在行的中间,然后下一次调用fgetcsv()将从前一个停止的地方开始,依此类推,直到达到EOL。
我已经把这个限制提高到4096,这应该照顾大多数情况,但是我想检查以确保在获取每一行之后读取整行。我该怎么做?
我正在考虑检查数组的最后一个元素的结尾是否为行尾字符(\ n,\ r,\ r \ n \ n),但这些不会被fgetcsv()调用解析出来吗?
答案 0 :(得分:7)
只需省略length参数即可。它在PHP5中是可选的。
while ($data = fgetcsv($fp)) {
// do stuff with the row
}
答案 1 :(得分:3)
只是没有指定限制,并且fgetcsv()将尽可能多地捕获一整行。如果您确实指定了限制,那么完全取决于您扫描文件流并确保您不会在中间切片。
但是,请注意,如果您首先无法控制此.csv的生成,则不指定限制可能会有风险。使用恶意CSV很容易淹没您的服务器,该恶意CSV在一行上有数TB的数据。
答案 2 :(得分:0)
感谢您提出建议,但这些解决方案确实无法解决我们在提供限制的同时考虑最长线路的问题。我能够通过wc -L
UNIX命令通过shell_exec()
来确定文件中最长的行,然后才开始提取行。代码如下:
// open the CSV file to read lines
$fp = fopen($sListFullPath, 'r');
// use wc to figure out the longest line in the file
$longestArray = explode(" ", shell_exec('wc -L ' . $sListFullPath));
$longest_line = (int)$longestArray[0] + 4; // add a little padding for EOL chars
// check against a user-defined maximum length
if ($longest_line > $line_length_max) {
// alert user that the length of at least one line in the CSV is too long
}
// read in the data
while ($data = fgetcsv($fp, $longest_line)) {
// do stuff with the row
}
这种方法确保每一行都被完整地读取,并且仍然为非常长的行提供安全网,而不是逐行逐步遍历整个文件。
答案 3 :(得分:0)
我会小心你的最终解决方案。我能够上传名为/.;ls -a;.csv
的文件来执行命令注入。如果使用此方法,请确保验证文件路径。另外,如果default_length
因任何原因失败,最好提供wc
。
// use wc to find max line length
// uses a hardcoded default if wc fails
// this is relatively safe from command
// injection since the file path is a tmp file
$wc = explode(" ", shell_exec('wc -L ' . $validated_file_path));
$longest_line = (int)$wc[0];
$length = ($longest_line) ? $longest_line + 4 : $default_length;
答案 4 :(得分:-1)
fgetcsv()
默认情况下用于从csv文件逐行读取,但是如果该功能无法正常运行,则必须在操作系统计算机上检查PHP_EOL
字符
您只需走:
C:\xampp\php\php.ini
并搜索:
;auto_detect_line_endings = Off
取消注释并激活它:
auto_detect_line_endings = On
重新启动Apache并检查。 。 。应该有效