2012-05-24 26 views
6

Tôi đang sử dụng PHP để nhập dữ liệu từ tệp CSV sử dụng fgetcsv(), tạo ra một mảng cho mỗi hàng. Ban đầu, tôi đã đặt giới hạn ký tự là 1024, như vậy:Đảm bảo fgetcsv() đọc toàn bộ dòng

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

Tuy nhiên, CSV có hơn 200 cột vượt giới hạn 1024 trên nhiều hàng. Điều này làm cho dòng được đọc dừng ở giữa một hàng, và sau đó cuộc gọi tiếp theo tới fgetcsv() sẽ bắt đầu từ nơi trước đó đã dừng lại và tiếp tục cho đến khi đạt được EOL.

Tôi đã tăng giới hạn này lên 4096, điều này sẽ chăm sóc phần lớn các trường hợp, nhưng tôi muốn kiểm tra để đảm bảo rằng toàn bộ dòng được đọc sau mỗi dòng được tìm nạp. Làm thế nào để tôi đi về điều này?

Tôi đã suy nghĩ để kiểm tra phần cuối của phần tử cuối cùng của mảng cho các ký tự cuối dòng (\ n, \ r, \ r \ n), nhưng sẽ không được phân tích cú pháp này bằng lệnh gọi fgetcsv() ?

+0

Ngoài ra, tôi nhận ra rằng tôi có thể lập trình xác định dòng dài nhất trong tệp, nhưng điều này có thể là rất nhiều chi phí trên các tệp CSV thực sự lớn. Muốn tìm hiểu cách đảm bảo mỗi dòng được đọc toàn bộ khi đang di chuyển. –

Trả lời

1

Cảm ơn bạn đã đề xuất, nhưng các giải pháp này thực sự không giải quyết được vấn đề khi biết rằng chúng tôi tính đến dòng dài nhất trong khi vẫn cung cấp giới hạn. Tôi đã có thể thực hiện điều này bằng cách sử dụng lệnh wc -L UNIX qua shell_exec() để xác định dòng dài nhất trong tệp trước khi bắt đầu tìm nạp dòng. Mã bên dưới:

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

Cách tiếp cận này đảm bảo rằng mọi dòng được đọc toàn bộ và vẫn cung cấp một mạng an toàn cho các dòng thực sự dài mà không cần phải duyệt toàn bộ tệp bằng dòng PHP.

6

Chỉ cần bỏ qua tham số chiều dài. Nó là tùy chọn trong PHP5.

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

Chỉ cần không chỉ định giới hạn và fgetcsv() sẽ slurp càng nhiều càng cần thiết để chụp toàn bộ dòng. Nếu bạn chỉ định giới hạn, thì hoàn toàn tùy thuộc vào BẠN để quét luồng tệp và đảm bảo bạn không cắt gì đó ở giữa.

Tuy nhiên, lưu ý rằng việc không chỉ định giới hạn có thể là nguy hiểm nếu bạn không có quyền kiểm soát việc tạo thế này .csv ngay từ đầu. Thật dễ dàng để đầm lầy máy chủ của bạn bằng một tệp CSV độc hại có nhiều terabyte dữ liệu trên một dòng.

+0

Tôi đã xem xét điều này, nhưng 2 điều: 1) Tôi KHÔNG có quyền kiểm soát việc tạo CSV. Chúng được cung cấp bởi (không đáng tin cậy) khách hàng, vì vậy tôi thực sự muốn áp đặt một số loại giới hạn. 2) Hướng dẫn sử dụng nói "Bỏ qua tham số này (hoặc đặt nó thành 0 trong PHP 5.0.4 trở lên) độ dài dòng tối đa không giới hạn, chậm hơn một chút". Tôi sợ những gì "hơi chậm" sẽ thêm đến với một tập tin CSV có 100k + hàng. –

+2

hơi chậm hơn = đọc tệp theo từng phần cho đến khi tìm thấy dấu ngắt dòng ở đâu đó trong đoạn đó, sau đó tua lại con trỏ tệp để lần đọc tiếp theo được chọn ngay sau khi ngắt. –

+1

Bạn có thể thực hiện đọc riêng từng dòng, sau đó sử dụng [str_get_csv()] (http://php.net/manual/en/function.str-getcsv.php) để thực hiện phân tích cú pháp csv-> mảng . –

0

Tôi sẽ cẩn thận với giải pháp cuối cùng của bạn. Tôi đã có thể tải lên một tệp có tên /.;ls -a;.csv để thực hiện lệnh tiêm. Đảm bảo bạn xác thực đường dẫn tệp nếu bạn sử dụng phương pháp này. Ngoài ra, bạn nên cung cấp default_length trong trường hợp wc của bạn không thành công vì bất kỳ lý do gì.

// 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; 
Các vấn đề liên quan