split directory - How to extract data from csv file in PHP





fputcsv library (10)


Handy one liner to parse a CSV file into an array

$csv = array_map('str_getcsv', file('data.csv'));

I have a csv file which looks like this

$lines[0] = "text, with commas", "another text", 123, "text",5;
$lines[1] = "some without commas", "another text", 123, "text";
$lines[2] = "some text with commas or no",, 123, "text";

And I would like to have a table:

$t[0] = array("text, with commas", "another text", "123", "text","5");
$t[1] = array("some without commas", "another text", "123", "text");
$t[2] = array("some text, with comma,s or no", NULL , "123", "text");

If I use split($lines[0],",") I'll get "text" ,"with commas" ... Is there any elegant way to do it?







PHP and CSV file - how to detect end of line?

I'd recommend using php's built in csv file reading function fgetcsv() and not create your own: http://php.net/manual/en/function.fgetcsv.php

 if (($handle = fopen($file, "r")) !== FALSE) {
     while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
        $row = implode (",",$data); //puts back together the row from the csv
        echo $row. "\n"; //assuming you want a visual linebreak on console, add the \n
     }
    fclose($handle);
 }  



1.csv:

Name,Gender,Ethnicity,DOB
John,M,British,10/04/49
Simon,M,British,04/03/65

Use file() to read the csv file into an array, then iterate through this array and get all the fields into an array element with explode() and make your new $array

<?php

$file = '1.csv';
$content = file($file);

$array = array();

for($i = 1; $i < count($content); $i++) {
    $line = explode(',', $content[$i]);
    for($j = 0; $j < count($line); $j++) {
        $array[$i][$j + 1] = $line[$j];
    }   
}   

print_r($array);

?>

Output:

Array
(
    [1] => Array
        (
            [1] => John
            [2] => M
            [3] => British
            [4] => 10/04/49

        )

    [2] => Array
        (
            [1] => Simon
            [2] => M
            [3] => British
            [4] => 04/03/65

        )

)

If you want get record:2 and field:4 you can do this:

echo $array[2][4];

Output:

04/03/65



A bit shorter answer since PHP >= 5.3.0:

    $csvFile = file('../somefile.csv');
    $data = [];
    foreach ($csvFile as $line) {
        $data[] = str_getcsv($line);
    }



this function will read a CSV and generate a multi-dimensional array

function fromCSVFile( $file) {
    // open the CVS file
    $handle = @fopen( $file, "r");
    if ( !$handle ) {
        throw new \Exception( "Couldn't open $file!" );
    }

    $result = [];

    // read the first line
    $first = strtolower( fgets( $handle, 4096 ) );
    // get the keys
    $keys = str_getcsv( $first );

    // read until the end of file
    while ( ($buffer = fgets( $handle, 4096 )) !== false ) {

        // read the next entry
        $array = str_getcsv ( $buffer );
        if ( empty( $array ) ) continue;

        $row = [];
        $i=0;

        // replace numeric indexes with keys for each entry
        foreach ( $keys as $key ) {
            $row[ $key ] = $array[ $i ];
            $i++;
        }

        // add relational array to final result
        $result[] = $row;
    }

    fclose( $handle );
    return $result;
}

So if your .CSV file looks like this:

Name,Gender,Ethnicity,DOB
John,M,British,10/04/49
Simon,M,British,04/03/65

You will get this:

(
    [0] => Array
        (
            [name] => John
            [gender] => M
            [ethnicity] => British
            [dob] => 10/04/49
        )

    [1] => Array
        (
            [name] => Simon
            [gender] => M
            [ethnicity] => British
            [dob] => 04/03/65
        )

)



Reading .csv into a PHP array

You already have this kind of implementation in PHP:

$csv = array_map('str_getcsv', file('someCSVfile.csv'));

Explanation:

  • str_getcsv() - Parse a CSV string into an array.
  • file() - Reads entire file into an array.
  • array_map(Function, Array)- Returns an array containing all the elements of the array after applying the callback function to each one.

Example output:

//CSV
NAME,CLASS,ROOM
Sally,2018,312
Belinda,2017,148

//OUTPUT:
Array(
       [0] => Array([0] => NAME,    [1] => CLASS, [2] => ROOM), 
       [1] => Array([0] => Sally,   [1] => 2018,  [2] => 312),
       [2] => Array([0] => Belinda, [1] => 2017,  [2] => 148)
)

Associative keys

Two quick functions to parse with associative keys - both based on the array_map method:

METHOD 1: running twice

function assoc_getcsv($csv_path) {
    $r = array_map('str_getcsv', file($csv_path));
    foreach( $r as $k => $d ) { $r[$k] = array_combine($r[0], $r[$k]); }
    return array_values(array_slice($r,1));
}  

METHOD 2: running once

function assoc_getcsv($csv_path) {
    $f = array();
    function parse_csv_assoc($str,&$f){ 
        if (empty($f)) { $f = str_getcsv($str); }
        return array_combine($f, str_getcsv($str));         
    }
    return array_values(array_slice(array_map('parse_csv_assoc', file($csv_path), $f),1));
} 

Example output:

//CSV
NAME,CLASS,ROOM
Sally,2018,312
Belinda,2017,148

//OUTPUT:
Array(
       [0] => Array([NAME] => Sally,   [CLASS] => 2018,  [ROOM] => 312),
       [1] => Array([NAME] => Belinda, [CLASS] => 2017,  [ROOM] => 148)
)



How I solved this issue:

In the XLS file, before exporting the file into CSV, I added in the end of sheet one more column with the char '.




here is also a simple method to get read csv file.

$sfp = fopen('/path/to/source.csv','r'); 
$dfp = fopen('/path/to/destination.csv','w'); 
while ($row = fgetcsv($sfp,10000,",","")) { 
 $goodstuff = ""; 
 $goodstuff = str_replace("¦",",",$row[2]); 
 $goodstuff .= "\n"; 
 fwrite($dfp,$goodstuff); 
} 
fclose($sfp); 
fclose($dfp);



NOTE FOR PHP 7

To update on this answer as it has gained some popularity: This answer no longer applies as of PHP 7. As explained in the "Backward incompatible changes", in PHP 7 foreach works on copy of the array, so any changes on the array itself are not reflected on foreach loop. More details at the link.

Explanation (quote from php.net):

The first form loops over the array given by array_expression. On each iteration, the value of the current element is assigned to $value and the internal array pointer is advanced by one (so on the next iteration, you'll be looking at the next element).

So, in your first example you only have one element in the array, and when the pointer is moved the next element does not exist, so after you add new element foreach ends because it already "decided" that it it as the last element.

In your second example, you start with two elements, and foreach loop is not at the last element so it evaluates the array on the next iteration and thus realises that there is new element in the array.

I believe that this is all consequence of On each iteration part of the explanation in the documentation, which probably means that foreach does all logic before it calls the code in {}.

Test case

If you run this:

<?
    $array = Array(
        'foo' => 1,
        'bar' => 2
    );
    foreach($array as $k=>&$v) {
        $array['baz']=3;
        echo $v." ";
    }
    print_r($array);
?>

You will get this output:

1 2 3 Array
(
    [foo] => 1
    [bar] => 2
    [baz] => 3
)

Which means that it accepted the modification and went through it because it was modified "in time". But if you do this:

<?
    $array = Array(
        'foo' => 1,
        'bar' => 2
    );
    foreach($array as $k=>&$v) {
        if ($k=='bar') {
            $array['baz']=3;
        }
        echo $v." ";
    }
    print_r($array);
?>

You will get:

1 2 Array
(
    [foo] => 1
    [bar] => 2
    [baz] => 3
)

Which means that array was modified, but since we modified it when the foreach already was at the last element of the array, it "decided" not to loop anymore, and even though we added new element, we added it "too late" and it was not looped through.

Detailed explanation can be read at How does PHP 'foreach' actually work? which explains the internals behind this behaviour.







php csv split