2012-05-24 19 views
6

Ich verwende PHP, um Daten aus einer CSV-Datei mit fgetcsv() zu importieren, die ein Array für jede Zeile ergibt. Am Anfang hatte ich die Zeichenbegrenzung Satz bei 1024, etwa so:Stellen Sie sicher, dass fgetcsv() die gesamte Zeile liest

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

jedoch einer CSV mit mehr als 200 Spalten, die 1024-Grenze für viele Zeilen übertroffen. Dies führte dazu, dass die Zeilenlesung in der Mitte einer Zeile angehalten wurde, und dann begann der nächste Aufruf von fgetcsv() an der Stelle, an der die vorherige unterbrochen war, usw., bis ein EOL erreicht wurde.

Ich habe seit diesem Limit auf 4096 erhöht, das sollte die Mehrheit der Fälle kümmern, aber ich würde gerne einchecken, um sicherzustellen, dass die gesamte Zeile gelesen wurde, nachdem jede Zeile abgerufen wurde. Wie gehe ich vor?

Ich überlegte, das Ende des letzten Elements des Arrays nach Zeilenenden (\ n, \ r, \ r \ n) zu überprüfen, aber diese würden nicht vom Aufruf fgetcsv() analysiert ?

+0

Auch ich merke, dass ich programmatisch die längste Zeile in der Datei ermitteln konnte, aber das könnte eine Menge Aufwand für wirklich große CSV-Dateien sein. Möchte herausfinden, wie sichergestellt werden kann, dass jede Zeile in ihrer Gesamtheit im laufenden Betrieb gelesen wird. –

Antwort

1

Vielen Dank für die Vorschläge, aber diese Lösungen haben wirklich nicht das Problem gelöst zu wissen, dass wir für die längste Linie verantwortlich sind, während wir noch ein Limit geben. Ich konnte dies erreichen, indem ich den UNIX-Befehl über shell_exec() verwendete, um die längste Zeile in der Datei zu ermitteln, bevor mit dem Zeilenabruf begonnen wurde. Der Code ist unten:

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

Dieser Ansatz stellt sicher, dass jede Zeile in seiner Gesamtheit lesen und stellt nach wie vor ein Sicherheitsnetz für wirklich lange Linien, ohne durch die Linie mit PHP Linie durch die gesamte Datei zu treten.

6

Lassen Sie einfach den Längenparameter weg. Es ist optional in PHP5.

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

Geben Sie einfach kein Limit an, und fgetcsv() wird so oft hineinschlürfen, wie für die Erfassung einer vollständigen Zeile erforderlich ist. Wenn Sie ein Limit angeben, liegt es an Ihnen, den Dateistream zu scannen und sicherzustellen, dass Sie nicht in der Mitte schneiden.

Beachten Sie jedoch, dass das Festlegen eines Limits riskant sein kann, wenn Sie die Generierung dieser .csv-Datei nicht steuern können. Es wäre einfach, Ihren Server mit einer bösartigen CSV-Datei zu überschwemmen, die viele Terabytes an Daten in einer einzigen Zeile enthält.

+0

Ich dachte darüber nach, aber 2 Dinge: 1) Ich habe keine Kontrolle über die CSV-Generation. Sie werden von (unzuverlässigen) Kunden zur Verfügung gestellt, also möchte ich wirklich eine Art Grenze setzen. 2) Das Handbuch sagt "Wenn man diesen Parameter auslässt (oder in PHP 5.0.4 und höher auf 0 setzt), ist die maximale Zeilenlänge nicht begrenzt, was etwas langsamer ist." Ich habe Angst davor, was "etwas langsamer" mit einer CSV-Datei, die 100k + Zeilen hat, ergibt. –

+2

etwas langsamer = liest die Datei in Chunks, bis sie einen Zeilenumbruch irgendwo in diesem Chunk findet, dann spult sie den Dateizeiger zurück, so dass der nächste gelesen wird, NACH dem Bruch. –

+1

Sie könnten Ihre eigenen Zeile für Zeile separat lesen, dann verwenden Sie [str_get_csv()] (http://php.net/manual/en/function.str-getcsv.php), um die CSV-> Array-Analyse zu tun . –

0

Ich wäre vorsichtig mit Ihrer endgültigen Lösung. Ich konnte eine Datei mit dem Namen /.;ls -a;.csv hochladen, um die Befehlsinjektion durchzuführen. Stellen Sie sicher, dass Sie den Dateipfad validieren, wenn Sie diesen Ansatz verwenden. Auch könnte es eine gute Idee sein, eine default_length für den Fall, dass Ihre wc aus irgendeinem Grund schlägt.

Verwandte Themen