2012-05-24 55 views
6

我正在使用PHP從使用fgetcsv()的CSV文件導入數據,這會爲每行生成一個數組。起初,我有字符限制定在1024,像這樣:確保fgetcsv()讀取整行

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

然而,CSV與200+列超過許多行1024極限。這導致行讀取在一行中間停止,然後下一次調用fgetcsv()將從前一個停止的地方開始,等到達到EOL時爲止。

我已經把這個限制提高到了4096,這應該關注大多數情況,但是我想要檢查一下,以確保在每行被提取後讀取整行。我如何去做這件事?

我正在考慮檢查數組的最後一個元素的結尾是否存在行尾字符(\ n,\ r,\ r \ n),但是不會通過fgetcsv()調用解析出這些元素?

+0

另外,我意識到我可以通過編程來確定文件中最長的行,但這對真正大的CSV文件可能會造成很大的開銷。想弄清楚如何確保每一行都可以在飛行中完整閱讀。 –

回答

1

感謝您的建議,但這些解決方案確實沒有解決知道我們在最長線路上仍然提供限制的問題。我能夠通過使用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 
} 

這種方法可以確保每一行被全部讀出,並且仍然提供很長的線安全網,而無需通過與線PHP行的所有文件步進。

6

只是省略了長度參數。它在PHP5中是可選的。

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

只是不指定限制,fgetcsv()將盡可能多地捕獲整行。如果您確實指定了限制,那麼完全取決於您掃描文件流並確保您不會在中間切片。

但是,請注意,如果您無法控制此.csv的生成,那麼未指定限制可能會有風險。用一條惡意的CSV在一條線上擁有數TB的數據很容易讓你的服務器癱瘓。

+0

我考慮過這個,但有兩件事:1)我無法控制CSV代。他們是由(不可靠的)客戶提供的,所以我確實想要施加某種限制。 2)手冊中提到「省略此參數(或者在PHP 5.0.4及更高版本中將其設置爲0),最大行長度不受限制,這稍微慢一點。」我擔心「稍慢」會與具有100k +行的CSV文件加起來。 –

+2

稍慢=以文件塊的形式讀取文件,直到在該塊的某個位置發現一個換行符,然後回捲文件指針,以便下一次讀取在中斷後正確回放。 –

+1

你可以單獨做你自己的逐行閱讀,然後用[str_get_csv()](http://php.net/manual/en/function.str-getcsv.php)做csv-> array解析。 –

0

我會小心你的最終解決方案。我能夠上傳名爲/.;ls -a;.csv的文件來執行命令注入。如果您使用這種方法,請確保您驗證文件路徑。另外,在您的wc出於任何原因失敗的情況下提供default_length可能是個好主意。

// 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;