20
votes

Consider s CSV file like this

item1,"description 1"
item2,"description 2"
item3,"description 3
description 3 continues on new line"
item4,"description 4"

which should be parsed like this

item1,"description 1"
item2,"description 2"
item3,"description 3 description 3 continues on new line"
item4,"description 4"

Is there a way to parse this CSV in PHP which has multiline values?

4
@goreSplatter, or just use an existing one. - Bart Kiers
@Bart Sorry I left out the other obvious solution. - Linus Kleen
possible duplicate of parse csv file php - outis

4 Answers

11
votes

fgetcsv should be able to properly parse this.
I wouldn't recommend doing this by hand anyway, there are many such gotchas in parsing CSV.

15
votes

Here are some working examples how to do it. I am using fgetcsv:

CSV in string variable $CsvString:

$fp = tmpfile();
fwrite($fp, $CsvString);
rewind($fp); //rewind to process CSV
while (($row = fgetcsv($fp, 0)) !== FALSE) {
    print_r($row);
}

CSV in file:

if (($handle = fopen("test.csv", "r")) !== FALSE) {
  while (($row = fgetcsv($handle, 0, ",")) !== FALSE) {
    print_r($row);
  }
  fclose($handle);
}
10
votes

Based on StanleyD answer, but using a temp memory block (rather than writing to disk) for better performance:

$fp = fopen('php://temp','r+');
fwrite($fp, $CsvString);
rewind($fp); //rewind to process CSV
while (($row = fgetcsv($fp, 0)) !== FALSE) {
    print_r($row);
}
0
votes

Here is a quick and easy solution using the PHP function str_getcsv()

Here is an example:

function parse_csv( $filename_or_text, $delimiter=',', $enclosure='"', $linebreak="\n" )
{
    $return = array();
    
    if(false !== ($csv = (filter_var($filename_or_text, FILTER_VALIDATE_URL) ? file_get_contents($filename_or_text) : $filename_or_text)))
    {
        $csv = trim($csv);
        $csv = mb_convert_encoding($csv, 'UTF-16LE');   
        
        foreach(str_getcsv($csv, $linebreak, $enclosure) as $row){
            $col = str_getcsv($row, $delimiter, $enclosure);
            $col = array_map('trim', $col);
            $return[] = $col;
        }
    }
    else
    {
        throw new \Exception('Can not open the file.');
        $return = false;
    }
    
    return $return;
}

Imagine a situation where you need a function that works with both URL and comma delimited text. This is exactly the function that works like that. Just simply insert a CSV URL or comma separated text and it work nicely.