27

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?

3
  • @goreSplatter, or just use an existing one. Commented Jan 19, 2011 at 8:18
  • @Bart Sorry I left out the other obvious solution. Commented Jan 19, 2011 at 8:21
  • possible duplicate of parse csv file php Commented Dec 26, 2011 at 7:36

4 Answers 4

20

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);
}
Sign up to request clarification or add additional context in comments.

1 Comment

Excellent answer. I have CSV's uploaded by the user with \r line endings (I have no idea why), and had to strreplace prior to parsing CSV. Since str_getcsv doesn't handle multiple lines, and some rows have new lines in them, this (while hackish, putting stuff in a temp file just to make PHP parse it) works.
14

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);
}

Comments

13

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.

4 Comments

The problem is I was using fgets read line from file then str_getcsv to parse string instead of using only fgetcsv. It was working fine with single line columns but not multiline ones. Even tough PHP.net says fgetcsv "Gets line from file" seems that "line" here is not actual line in plain text file but the whole actual row with all multiline data.
I came along the same issue today and made a little test, that proofs your statement about lines referring to csv-rows and not to actual file-lines.
I was hoping to use str_getcsv as it doesn't have to load the entire file into memory, just the row that is being red. fgetcsv does work with multiline CSV fields, but str_getcsv apparently does not.
@Erfan fgetcsv also only reads one line at a time from an open file handle…!?
-1

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.

1 Comment

No multiline, see @Erfan

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.