24

I have csv values like this:

$csv_data = "test,this,thing
             hi,there,this
             is,cool,dude
             have,fun";

I want to take an entire CSV string and read it into a multidemensional array so that I get:

array(
   array(
      'test' => 'hi',
      'this' => 'there',
      'thing' => 'this'
   ),
   array(
      'test' => 'is',
      'this' => 'cool',
      'thing' => 'dude'
   ),
   array(
      'test' => 'have',
      'this' => 'fun',
      'thing' => ''
   )
);

I want an output like that, take note that the CSV value is dynamic.

6
  • Should the last line of the CSV data have another comma? Doesn't seem like valid CSV data if rows don't all have the same number of columns. Or does the code need to account for that varying number of columns? Commented Dec 2, 2011 at 7:58
  • its like, the first row would be the keys of an array then other are its value. on the 'thing' => '' part, that is correct. Commented Dec 2, 2011 at 8:02
  • I get that, but the last line of CSV data is have,fun, which only has two columns, not three like the other lines. Do we need to account for rows that have the wrong number of columns like that? Commented Dec 2, 2011 at 8:05
  • Okay, I've updated my answer to reflect either scenario (same or differing number of columns). Commented Dec 2, 2011 at 8:15
  • 3
    This is one of the strangest instances of "closed" that I've seen. This is a very general, useful question of how to parse CSV strings into an array. I have more or less this same problem, which is how I got here. Commented Jan 11, 2016 at 22:47

3 Answers 3

39

Assuming every row in the CSV data has the same number of columns, this should work.

$lines = explode("\n", $csv_data);
$head = str_getcsv(array_shift($lines));

$array = array();
foreach ($lines as $line) {
    $array[] = array_combine($head, str_getcsv($line));
}

If lines have a variable number of columns (as in your example, where the last line has 2 columns instead of 3), use this loop instead:

foreach ($lines as $line) {
    $row = array_pad(str_getcsv($line), count($head), '');
    $array[] = array_combine($head, $row);
}
Sign up to request clarification or add additional context in comments.

3 Comments

And what about csv data that contains \n in single Fields. The usual notation in csv is to enclosuer such fields with quotes, e.g. "some value\nin a field". So, those \n have to be ignored while parsing. Your explode approach will cut them off.
@ChrisPillen While not one of the asker's requirements, that's a valid point. What do you think the best remedy for that would be? Save the CSV data to a tmpfile() and parse it back out using fgetcsv()? Should I add an example of that to my answer?
@Wiseguy You could use regex to parse the data, but using a temp file and fgetcsv() would be the simpler and much cleaner.
7

Here is a complete solution:

$lines = explode("\n", $csv_data);
$formatting = explode(",", $lines[0]);
unset($lines[0]);
$results = array();
foreach ( $lines as $line ) {
   $parsedLine = str_getcsv( $line, ',' );
   $result = array();
   foreach ( $formatting as $index => $caption ) {
      if(isset($parsedLine[$index])) {
         $result[$formatting[$index]] = trim($parsedLine[$index]);
      } else {
         $result[$formatting[$index]] = '';
      }
   }
   $results[] = $result;
}

So what are we doing here?

  • First, your CSV data is split into array of lines with explode
  • Since the first row in your CSV describes data format, it must be separated from the actual data rows (explode and unset)
  • For storing the results, we initialize a new array ($results)
  • Foreach is used to iterate through the data line by line. For each line:
    • Line is parsed with PHP's str_getcsv
    • An empty result array is initialized
    • Each line is inspected in the light of the format. Cells are added and missing columns are padded with empty strings.

3 Comments

It's not outputting correctly that I desired, thanks \for your answer :)
It was much more complex problem I thought. Check the revised answer. Detailed explanation will follow.
Explanation added. Given your description this should answer the question.
2

Here is a very clean and simple solution:

function parse_row($row) {
  return array_map('trim', explode(',', $row));
}

$rows   = str_getcsv($csv_data, "\n");
$keys   = parse_row(array_shift($rows));
$result = array();

foreach ($rows as $row) {
  $row = parse_row($row);
  $row = array_pad($row, 3, NULL);

  $result[] = array_combine($keys, $row);
}

Comments

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.