2012-05-24 11 views
6

Sto utilizzando PHP per importare i dati da un file CSV utilizzando fgetcsv(), che produce un array per ogni riga. Inizialmente, avevo il set limite di caratteri a 1024, in questo modo:Assicurarsi che fgetcsv() legga l'intera riga

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

Tuttavia, un CSV con oltre 200 colonne superato il limite di 1024 più righe. Ciò ha causato l'interruzione della lettura della riga nel mezzo di una riga, quindi la chiamata successiva a fgetcsv() iniziava da dove era stata interrotta la precedente e così via fino al raggiungimento di un EOL.

Ho quindi aumentato questo limite a 4096, che dovrebbe occuparsi della maggior parte dei casi, ma vorrei inserire un controllo per essere sicuro che l'intera riga sia stata letta dopo che ogni riga è stata recuperata. Come faccio a fare questo?

Stavo pensando di controllare la fine dell'ultimo elemento dell'array per i caratteri di fine riga (\ n, \ r, \ r \ n), ma non sarebbe analizzato dalla chiamata fgetcsv() ?

+0

Inoltre, mi rendo conto che potrei determinare a livello di codice la riga più lunga nel file, ma questo potrebbe essere un sovraccarico su file CSV veramente grandi. Vorrei capire come garantire che ogni riga sia letta nella sua interezza al volo. –

risposta

1

Grazie per i suggerimenti, ma queste soluzioni in realtà non hanno risolto il problema di sapere che rappresentiamo la linea più lunga pur continuando a fornire un limite. Sono stato in grado di farlo utilizzando il comando wc -L UNIX tramite shell_exec() per determinare la riga più lunga nel file prima di iniziare il recupero riga. Il codice è qui sotto:

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

Questo approccio assicura che ogni linea viene letta nella sua interezza e fornisce ancora una rete di sicurezza per linee veramente lunghi senza uscire attraverso l'intero file con linea PHP per riga.

6

Basta omettere il parametro lunghezza. È facoltativo in PHP5.

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

Basta non specificare un limite e fgetcsv() si insinuerà quanto necessario per acquisire una linea completa. Se specifichi un limite, è interamente a VOI scansionare il flusso di file e assicurarti di non affettare qualcosa nel mezzo.

Tuttavia, notare che non specificare un limite può essere rischioso se non si ha il controllo sulla generazione di questo .csv in primo luogo. Sarebbe facile inondare il tuo server con un CSV dannoso che ha molti terabyte di dati su una singola riga.

+0

Ho considerato questo, ma 2 cose: 1) NON ho il controllo sulla generazione CSV. Sono forniti da (inaffidabili) clienti, quindi voglio davvero imporre una sorta di limite. 2) Il manuale dice "Omettendo questo parametro (o impostandolo su 0 in PHP 5.0.4 e successivi) la lunghezza massima della linea non è limitata, che è leggermente più lento." Ho paura di cosa "leggermente più lento" si sommerà con un file CSV che ha 100k + righe. –

+2

un po 'più lento = legge il file in blocchi finché non trova un linebreak da qualche parte in quel blocco, quindi riavvolge il puntatore del file in modo che la prossima lettura venga ripresa subito dopo l'interruzione. –

+1

È POSSIBILE eseguire la lettura riga per riga separatamente, quindi utilizzare [str_get_csv()] (http://php.net/manual/en/function.str-getcsv.php) per eseguire l'analisi csv-> array . –

0

Farei attenzione alla soluzione finale. Sono stato in grado di caricare un file denominato /.;ls -a;.csv per eseguire l'iniezione di comandi. Assicurati di convalidare il percorso del file se usi questo approccio. Inoltre, potrebbe essere una buona idea fornire un default_length nel caso in cui il tuo wc non riesca per qualsiasi motivo.

Problemi correlati