7

我正在使用 PHP 使用 fgetcsv() 从 CSV 文件导入数据,它为每一行生成一个数组。最初,我将字符限制设置为 1024,如下所示:

while ($data = fgetcsv($fp, 1024)) {
  // do stuff with the row
}

但是,具有 200 多列的 CSV 在许多行上超过了 1024 的限制。这导致读取的行在一行中间停止,然后对 fgetcsv() 的下一次调用将从上一次停止的地方开始,依此类推,直到达到 EOL。

我已经将此限制提高到 4096,这应该可以解决大多数情况,但我想检查以确保在获取每一行后读取整行。我该怎么做?

我正在考虑检查数组最后一个元素的末尾是否有行尾字符(\n、\r、\r\n),但是这些不会被 fgetcsv() 调用解析出来吗?

4

5 回答 5

10

只需省略长度参数。它在 PHP5 中是可选的。

while ($data = fgetcsv($fp)) {
  // do stuff with the row
}
于 2012-05-24T22:14:35.377 回答
3

只是不要指定限制,fgetcsv() 将尽可能多地捕捉整行。如果您确实指定了限制,那么扫描文件流并确保您没有从中间切开某些东西完全取决于您。

但是,请注意,如果您首先无法控制此 .csv 的生成,则不指定限制可能会有风险。用单行上包含数 TB 数据的恶意 CSV 淹没您的服务器很容易。

于 2012-05-24T22:15:03.063 回答
0

感谢您的建议,但这些解决方案确实没有解决知道我们占了最长线路同时仍然提供限制的问题。我能够通过使用wc -LUNIX 命令 viashell_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
}

这种方法可确保完整读取每一行,并且仍然为非常长的行提供安全网,而无需使用 PHP 逐行遍历整个文件。

于 2012-06-01T16:44:47.657 回答
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;
于 2016-11-22T18:23:19.960 回答
0

fgetcsv()默认情况下用于从 csv 文件中逐行读取,但是当它不以这种方式运行时,您必须检查PHP_EOL操作系统机器上的字符,您只需要去: C:\xampp\php\php.ini 并搜索:

;auto_detect_line_endings = Off

并取消注释并将其激活以:

auto_detect_line_endings = On

重新启动 Apache 并检查 . . . 应该有效

于 2018-11-24T21:02:10.130 回答