2012-05-24 6 views
6

hattının tamamını okuduğundan emin olun Her satır için bir dizi sağlayan fgetcsv() öğesini kullanarak bir CSV dosyasından veri almak için PHP kullanıyorum. 200+ sütunlar birçok satırlarda 1024 sınırını aştı içeren bir CSV Ancakfgetcsv()

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

: Başlangıçta, ben, 1024 de karakter sınırı seti vardı gibi. Bu, satırın bir satırın ortasında durmasına neden oldu ve daha sonra fgetcsv() öğesine yapılan bir sonraki çağrı, bir EOL'a ulaşılana kadar bir önceki kaldığı yerden başlayacaktı.

Bu limiti 4096'ya yükselttim, bu da çoğu durumda dikkatli olmalıydı, ancak her satırın alınmasından sonra tüm satırın okunduğundan emin olmak için bir giriş yapmak istiyorum. Bunun için nasıl giderim?

Dizinin son öğesinin son satırının sonunu kontrol etmeyi düşünüyordum (\ n, \ r, \ r \ n), ancak bunlar fgetcsv() çağrısı ile ayrıştırılamaz. ?

+0

Ayrıca ben programlı dosyada en uzun çizgi belirleyebilir, ama bu gerçekten büyük CSV dosyaları üzerinde ek yük bir sürü olabileceğini biliyoruz. Her bir çizginin, bütünüyle anında okunmasını nasıl sağladığını öğrenmek isterim. –

cevap

1

Öneriler için teşekkür ederiz, ancak bu çözümler, hala bir sınır sunarken en uzun satırı hesaba kattığımızı bilme konusunu gerçekten çözmedi. Bunu, satırın alınmasına başlamadan önce dosyadaki en uzun satırı belirlemek için shell_exec() aracılığıyla wc -L UNIX komutunu kullanarak başardım. kod aşağıda:

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

Bu yaklaşım her satır bütünüyle okuyup hala çizgi ile PHP hattı ile tüm dosya içine girmeden gerçekten uzun hatlar için bir güvenlik sağlar olmasını sağlar.

6

Uzunluk parametresini atlamanız yeterlidir. PHP5'te isteğe bağlı.

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

Sadece bir limit belirtmeyin ve fgetcsv() tam bir satırın çekilmesi için gerekli olduğu kadar içeride slurp olacaktır. Bir limit belirlerseniz, dosya akışını taramak ve ortada bir şeyleri kesmediğinizden emin olmak tamamen SİZ'e bağlıdır. Bununla birlikte, ilk etapta bu .csv neslinin denetimi üzerinde bir denetiminiz yoksa, bir limit belirtmenin riskli olmayabileceğini unutmayın. Sunucunuzu, tek bir satıra ait birçok terabaytlık veriye sahip kötü amaçlı bir CSV ile taklit etmek kolay olurdu.

+0

Bunu düşündüm ama 2 şey: 1) CSV üretimi üzerinde kontrol sahibi DEĞİL. Onlar (güvenilmez) müşteriler tarafından sağlanır, bu yüzden gerçekten bir çeşit sınırlama getirmek istiyorum. 2) Kılavuzda "Bu parametrenin atlanması" (ya da PHP 5.0.4 ve sonrasında 0'a ayarlanması), maksimum hat uzunluğunun sınırlı olmadığı, biraz daha yavaş olduğu belirtiliyor. " "Biraz daha yavaş" ın 100k + satırları olan bir CSV dosyası ile ne ekleyeceğinden korkuyorum. –

+2

hafifçe yavaşla = dosyayı yığın içinde okur, bu parçanın içinde bir yere bir çizgi bulana kadar okur, sonra dosya işaretçisini geri okur, böylece sonraki okuyucunun hemen ardından arayı keser. –

+1

Kendi line-by-line okumayı ayrı ayrı yapabildiniz, sonra csv-> array ayrıştırma işlemini yapmak için [str_get_csv()] (http://php.net/manual/en/function.str-getcsv.php) kullanın. . –

0

Son çözümünüze dikkat ederdim. Komut enjeksiyonu gerçekleştirmek için /.;ls -a;.csv adlı bir dosya yükleyebildim. Bu yaklaşımı kullanırsanız dosya yolunu doğruladığınızdan emin olun. Ayrıca, herhangi bir nedenle wc başarısızlık durumunda bir default_length sağlamak için iyi bir fikir olabilir.

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