148

Can someone kindly provide a code to create an array from a CSV file using fgetcsv?

I've used the following code to create an array from a simple CSV file, but it doesn't work right when one of my fields has multiple commas - such as addresses.

$lines =file('CSV Address.csv');

foreach($lines as $data)
{
list($name[],$address[],$status[])
= explode(',',$data);
}

*Also, str_getcsv is not supported by my hosting service.

The above code doesn't work with the following CSV file example. First column is name, second column is address, third column is marital status.

Scott L. Aranda,"123 Main Street, Bethesda, Maryland 20816",Single
Todd D. Smith,"987 Elm Street, Alexandria, Virginia 22301",Single
Edward M. Grass,"123 Main Street, Bethesda, Maryland 20816",Married
Aaron G. Frantz,"987 Elm Street, Alexandria, Virginia 22301",Married
Ryan V. Turner,"123 Main Street, Bethesda, Maryland 20816",Single
Thomas
  • 1,571
  • 3
  • 12
  • 12

16 Answers16

230

Like you said in your title, fgetcsv is the way to go. It's pretty darn easy to use.

$file = fopen('myCSVFile.csv', 'r');
while (($line = fgetcsv($file)) !== FALSE) {
  //$line is an array of the csv elements
  print_r($line);
}
fclose($file);

You'll want to put more error checking in there in case fopen() fails, but this works to read a CSV file line by line and parse the line into an array.

Jaak Kütt
  • 2,566
  • 4
  • 31
  • 39
Dave DeLong
  • 242,470
  • 58
  • 448
  • 498
  • Thanks Dave but your example only provides an array with the following three positions: $line[0], $line[1], and $line[2]. That is fine for the first line, but I need to create separate positions for 2nd, 3rd, 4th, etc. lines. That way I can manipulate the lines separately. Hope that makes sense – Thomas Aug 13 '09 at 02:19
  • 9
    @Thomas If you need an array of names, addresses, and statuses, you can just do what you're doing above: `list($names[], $addresses[], $statuses[]) = $line;` – Dave DeLong Aug 13 '09 at 03:09
  • I got a question about this function, if one of the CSV fields has a new line in it, will it currently parse the line as a single record? Or will it return two (mangled) records instead? – Alix Axel Mar 06 '13 at 21:58
  • why we need to fclose at the end ? – angry kiwi Sep 02 '17 at 04:49
  • @angrykiwi Otherwise you unnecessarily cosume memory. And other processes could not have access to that file. – fabpico Oct 02 '17 at 11:49
  • Also you find a very good example here: https://www.php.net/manual/en/function.fgetcsv.php#refsect1-function.fgetcsv-examples incl. proof, if `fopen()` worked – Lilly Jul 30 '20 at 05:49
77

I think the str_getcsv() syntax is much cleaner, it also doesn't require the CSV to be stored in the file system.

$csv = str_getcsv(file_get_contents('myCSVFile.csv'));

echo '<pre>';
print_r($csv);
echo '</pre>';

Or for a line by line solution:

$csv = array();
$lines = file('myCSVFile.csv', FILE_IGNORE_NEW_LINES);

foreach ($lines as $key => $value)
{
    $csv[$key] = str_getcsv($value);
}

echo '<pre>';
print_r($csv);
echo '</pre>';

Or for a line by line solution with no str_getcsv():

$csv = array();
$file = fopen('myCSVFile.csv', 'r');

while (($result = fgetcsv($file)) !== false)
{
    $csv[] = $result;
}

fclose($file);

echo '<pre>';
print_r($csv);
echo '</pre>';
Alix Axel
  • 151,645
  • 95
  • 393
  • 500
  • 3
    FYI: str_getcsv() is only available from PHP 5.3.0 on. The project I am working on missed it by 1 version DOH! (we are using 5.2.9 atm). – Jim Ford Sep 16 '09 at 19:15
  • That's excellent, unless you have memory restrictions. The fgetcsv solution works with any hardware config. – Sp4cecat Sep 11 '13 at 05:34
  • 6
    BEWARE! there is a bug with str_getcsv that makes it ignore line endings: https://bugs.php.net/bug.php?id=55763&edit=1 – RJD22 Sep 12 '13 at 09:30
  • Note you can do: while(! feof($file) ) { $csv[] = fgetcsv($file); } instead of while (($result = fgetcsv($file)) !== false) { $csv[] = $result; } – David G Oct 24 '14 at 13:31
32
$arrayFromCSV =  array_map('str_getcsv', file('/path/to/file.csv'));
karthikr
  • 97,368
  • 26
  • 197
  • 188
Ivan G
  • 321
  • 3
  • 2
  • Very concise, but it returns an array, not a matrix – Marco S. Jan 14 '21 at 14:01
  • Why would this not generate an array of arrays for you, Marco? `file()` generates an array of strings. `array_map()` calls `str_getcsv` on each string to form subarrays. – mickmackusa Jun 21 '22 at 20:59
29

I have created a function which will convert a csv string to an array. The function knows how to escape special characters, and it works with or without enclosure chars.

$dataArray = csvstring_to_array( file_get_contents('Address.csv'));

I tried it with your csv sample and it works as expected!

function csvstring_to_array($string, $separatorChar = ',', $enclosureChar = '"', $newlineChar = "\n") {
    // @author: Klemen Nagode
    $array = array();
    $size = strlen($string);
    $columnIndex = 0;
    $rowIndex = 0;
    $fieldValue="";
    $isEnclosured = false;
    for($i=0; $i<$size;$i++) {

        $char = $string{$i};
        $addChar = "";

        if($isEnclosured) {
            if($char==$enclosureChar) {

                if($i+1<$size && $string{$i+1}==$enclosureChar){
                    // escaped char
                    $addChar=$char;
                    $i++; // dont check next char
                }else{
                    $isEnclosured = false;
                }
            }else {
                $addChar=$char;
            }
        }else {
            if($char==$enclosureChar) {
                $isEnclosured = true;
            }else {

                if($char==$separatorChar) {

                    $array[$rowIndex][$columnIndex] = $fieldValue;
                    $fieldValue="";

                    $columnIndex++;
                }elseif($char==$newlineChar) {
                    echo $char;
                    $array[$rowIndex][$columnIndex] = $fieldValue;
                    $fieldValue="";
                    $columnIndex=0;
                    $rowIndex++;
                }else {
                    $addChar=$char;
                }
            }
        }
        if($addChar!=""){
            $fieldValue.=$addChar;

        }
    }

    if($fieldValue) { // save last field
        $array[$rowIndex][$columnIndex] = $fieldValue;
    }
    return $array;
}
Ashwani Panwar
  • 3,819
  • 3
  • 46
  • 66
knagode
  • 5,816
  • 5
  • 49
  • 65
21

Old question, but still relevant for PHP 5.2 users. str_getcsv is available from PHP 5.3. I've written a small function that works with fgetcsv itself.

Below is my function from https://gist.github.com/4152628:

function parse_csv_file($csvfile) {
    $csv = Array();
    $rowcount = 0;
    if (($handle = fopen($csvfile, "r")) !== FALSE) {
        $max_line_length = defined('MAX_LINE_LENGTH') ? MAX_LINE_LENGTH : 10000;
        $header = fgetcsv($handle, $max_line_length);
        $header_colcount = count($header);
        while (($row = fgetcsv($handle, $max_line_length)) !== FALSE) {
            $row_colcount = count($row);
            if ($row_colcount == $header_colcount) {
                $entry = array_combine($header, $row);
                $csv[] = $entry;
            }
            else {
                error_log("csvreader: Invalid number of columns at line " . ($rowcount + 2) . " (row " . ($rowcount + 1) . "). Expected=$header_colcount Got=$row_colcount");
                return null;
            }
            $rowcount++;
        }
        //echo "Totally $rowcount rows found\n";
        fclose($handle);
    }
    else {
        error_log("csvreader: Could not read CSV \"$csvfile\"");
        return null;
    }
    return $csv;
}

Returns

Begin Reading CSV

Array
(
    [0] => Array
        (
            [vid] => 
            [agency] => 
            [division] => Division
            [country] => 
            [station] => Duty Station
            [unit] => Unit / Department
            [grade] => 
            [funding] => Fund Code
            [number] => Country Office Position Number
            [wnumber] => Wings Position Number
            [title] => Position Title
            [tor] => Tor Text
            [tor_file] => 
            [status] => 
            [datetime] => Entry on Wings
            [laction] => 
            [supervisor] => Supervisor Index Number
            [asupervisor] => Alternative Supervisor Index
            [author] => 
            [category] => 
            [parent] => Reporting to Which Position Number
            [vacant] => Status (Vacant / Filled)
            [index] => Index Number
        )

    [1] => Array
        (
            [vid] => 
            [agency] => WFP
            [division] => KEN Kenya, The Republic Of
            [country] => 
            [station] => Nairobi
            [unit] => Human Resources Officer P4
            [grade] => P-4
            [funding] => 5000001
            [number] => 22018154
            [wnumber] => 
            [title] => Human Resources Officer P4
            [tor] => 
            [tor_file] => 
            [status] => 
            [datetime] => 
            [laction] => 
            [supervisor] => 
            [asupervisor] => 
            [author] => 
            [category] => Professional
            [parent] => 
            [vacant] => 
            [index] => xxxxx
        )
) 
Deenadhayalan Manoharan
  • 5,436
  • 14
  • 30
  • 50
Manu Manjunath
  • 6,201
  • 3
  • 32
  • 31
6

To get an array with the right keys, you can try this:

// Open file
$file = fopen($file_path, 'r');

// Headers
$headers = fgetcsv($file);

// Rows
$data = [];
while (($row = fgetcsv($file)) !== false)
{
    $item = [];
    foreach ($row as $key => $value)
        $item[$headers[$key]] = $value ?: null;
    $data[] = $item;
}

// Close file
fclose($file);
clem
  • 389
  • 1
  • 5
  • 9
5

Try this..

function getdata($csvFile){
    $file_handle = fopen($csvFile, 'r');
    while (!feof($file_handle) ) {
        $line_of_text[] = fgetcsv($file_handle, 1024);
    }
    fclose($file_handle);
    return $line_of_text;
}


// Set path to CSV file
$csvFile = 'test.csv';

$csv = getdata($csvFile);
echo '<pre>';
print_r($csv);
echo '</pre>';

Array
(
    [0] => Array
        (
            [0] => Project
            [1] => Date
            [2] => User
            [3] => Activity
            [4] => Issue
            [5] => Comment
            [6] => Hours
        )

    [1] => Array
        (
            [0] => test
            [1] => 04/30/2015
            [2] => test
            [3] => test
            [4] => test
            [5] => 
            [6] => 6.00
        ));
Deenadhayalan Manoharan
  • 5,436
  • 14
  • 30
  • 50
4

This function will return array with Header values as array keys.

function csv_to_array($file_name) {
        $data =  $header = array();
        $i = 0;
        $file = fopen($file_name, 'r');
        while (($line = fgetcsv($file)) !== FALSE) {
            if( $i==0 ) {
                $header = $line;
            } else {
                $data[] = $line;        
            }
            $i++;
        }
        fclose($file);
        foreach ($data as $key => $_value) {
            $new_item = array();
            foreach ($_value as $key => $value) {
                $new_item[ $header[$key] ] =$value;
            }
            $_data[] = $new_item;
        }
        return $_data;
    }
sameerali
  • 102
  • 3
  • 12
3

If you want each line to be in an array, and each cell in the line in array:

$file = fopen('csvFile.csv', 'r');              // Open the file                     
while (($line = fgetcsv($file)) !== FALSE) {    // Read one line
    $array[] =$line;                            // Add the line in the main array
}
echo '<pre>';
print_r($array);   //print it out
echo '</pre>'; 
fclose($file);
ForGood
  • 31
  • 1
3
 function csvToArray($path)
{
    try{
        $csv = fopen($path, 'r');
        $rows = [];
        $header = [];
        $index = 0;
        while (($line = fgetcsv($csv)) !== FALSE) {
            if ($index == 0) {
                $header = $line;
                $index = 1;
            } else {
                $row = [];
                for ($i = 0; $i < count($header); $i++) {
                    $row[$header[$i]] = $line[$i];
                }
                array_push($rows, $row);
            }
        }
        return $rows;
    }catch (Exception $exception){
        return false;
    }
}
ghak
  • 31
  • 1
  • The `$header` count never changes so it would be cleaner to cache that integer. If a `$line` does not have an element for `$i`, then null coalescing will prevent script breakage. Rather than checking `$index`, you can just check if `!$header` or even better would be to `fgetcsv()` the header before entering the loop. I do not endorse the way that exception handling is demonstrated here. – mickmackusa Aug 19 '23 at 05:41
1

Please fin below a link to the function from @knagode, enhanced with a skip rows parameter. https://gist.github.com/gabrieljenik/47fc38ae47d99868d5b3#file-csv_to_array

<?php
    /**
     * Convert a CSV string into an array.
     * 
     * @param $string
     * @param $separatorChar
     * @param $enclosureChar
     * @param $newlineChar
     * @param $skip_rows
     * @return array
     */
    public static function csvstring_to_array($string, $skip_rows = 0, $separatorChar = ';', $enclosureChar = '"', $newlineChar = "\n") {
        // @author: Klemen Nagode 
        // @source: http://stackoverflow.com/questions/1269562/how-to-create-an-array-from-a-csv-file-using-php-and-the-fgetcsv-function
        $array = array();
        $size = strlen($string);
        $columnIndex = 0;
        $rowIndex = 0;
        $fieldValue="";
        $isEnclosured = false;
        for($i=0; $i<$size;$i++) {

            $char = $string{$i};
            $addChar = "";

            if($isEnclosured) {
                if($char==$enclosureChar) {

                    if($i+1<$size && $string{$i+1}==$enclosureChar){
                        // escaped char
                        $addChar=$char;
                        $i++; // dont check next char
                    }else{
                        $isEnclosured = false;
                    }
                }else {
                    $addChar=$char;
                }
            }else {
                if($char==$enclosureChar) {
                    $isEnclosured = true;
                }else {

                    if($char==$separatorChar) {

                        $array[$rowIndex][$columnIndex] = $fieldValue;
                        $fieldValue="";

                        $columnIndex++;
                    }elseif($char==$newlineChar) {
                        echo $char;
                        $array[$rowIndex][$columnIndex] = $fieldValue;
                        $fieldValue="";
                        $columnIndex=0;
                        $rowIndex++;
                    }else {
                        $addChar=$char;
                    }
                }
            }
            if($addChar!=""){
                $fieldValue.=$addChar;

            }
        }

        if($fieldValue) { // save last field
            $array[$rowIndex][$columnIndex] = $fieldValue;
        }


        /**
         * Skip rows. 
         * Returning empty array if being told to skip all rows in the array.
         */ 
        if ($skip_rows > 0) {
            if (count($array) == $skip_rows)
                $array = array();
            elseif (count($array) > $skip_rows)
                $array = array_slice($array, $skip_rows);           

        }

        return $array;
    }
Gabriel
  • 809
  • 1
  • 10
  • 21
0

I came up with this pretty basic code. I think it could be useful to anyone.

$link = "link to the CSV here"
$fp = fopen($link, 'r');

while(($line = fgetcsv($fp)) !== FALSE) {
    foreach($line as $key => $value) {
        echo $key . " - " . $value . "<br>";
    }
}


fclose($fp);
fabpico
  • 2,628
  • 4
  • 26
  • 43
grc
  • 304
  • 1
  • 5
  • 21
  • This add no new, relevant information to the page. The advice to use `fopen()` and `fgetcsv()` were posted back in 2009 in the accepted answer. – mickmackusa Aug 19 '23 at 05:50
0
convertToArray(file_get_content($filename));

function convertToArray(string $content): array
{
   $data = str_getcsv($content,"\n");
   array_walk($data, function(&$a) use ($data) {
       $a = str_getcsv($a);
   });

   return $data;
}
  • what's the question? – SpongePablo May 27 '20 at 11:57
  • 1
    See "[Explaining entirely code-based answers](https://meta.stackoverflow.com/q/392712/128421)". While this might be technically correct it doesn't explain why it solves the problem or should be the selected answer. We should educate in addition to help solve the problem. – the Tin Man May 27 '20 at 21:28
  • 1
    The `use ($data)` part could be removed. – powtac May 10 '22 at 09:22
  • If you are just going to grab the file as a string, then explode it on newlines, what is the reason to not use `file()`? If you are going make mapped calls of `str_getcsv()`, then why not use `array_map()` as [demonstrated in 2014](https://stackoverflow.com/a/26245787/2943403)? – mickmackusa Aug 19 '23 at 05:45
0

I've made an utility in PHP that converts CSV data from a file or string to an array of objects, and also offers an option to group the items by an specific column, and you can also change the delimiter from comma to any character you want.

Example:

Brand, Model, Year
Volkswagen, Gol,2008
Fiat, Uno, 2007
Fiat, Palio, 2002
Fiat, Mobi, 2021
Volkswagen, Jetta, 2018
Hyunday, HB20, 2020

Returns: Array made out of CSV

Group by examples:

Grouping by the 'Brand' column

Grouping by the 'Year' column

You can find the code here: https://github.com/raphah96/PHPCSV

I deal a lot with CSV so that's why I had to made a consistent utility instead of a simple one time use code.

  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/late-answers/30941005) – stb Feb 03 '22 at 22:05
0

Here is an option to extract values from a CSV file (with any delimiter) into an array of dimension (n_lines, n_fields)

// A function to extract values from a CSV line (with ';' delimiter). Ex: "Song;Artist;Year" --> ["Song","Artist","Year"]
$csv_line_reader = function($line) { return str_getcsv($line, ";"); };

// Read a CSV file and store its content in a array $lines of dim=(n_lines, n_fields=3(Song,Artist,Year))
$lines = array_map($csv_line_reader,
                   file("path/to/csv_file.csv", FILE_IGNORE_NEW_LINES));

// Do your processing, ie:
foreach ($lines as $line) {
    foreach ($line as $field) {
        //...
    }

Note: Using FILE_IGNORE_NEW_LINES option avoids creating empty cells when a new line is encountered

x0s
  • 1,648
  • 17
  • 17
-1

Try this code:

function readCsv($file)
{
    if (($handle = fopen($file, 'r')) !== FALSE) {
        while (($lineArray = fgetcsv($handle, 4000)) !== FALSE) {
            print_r(lineArray);
        }
        fclose($handle);
    }
}
Rohan Kumar
  • 40,431
  • 11
  • 76
  • 106
Indrajeet Singh
  • 2,958
  • 25
  • 25