Cómo crear una matriz a partir de un archivo CSV usando PHP y la función fgetcsv

106

¿Puede alguien proporcionar amablemente un código para crear una matriz a partir de un archivo CSV usando fgetcsv?

He usado el siguiente código para crear una matriz a partir de un archivo CSV simple, pero no funciona bien cuando uno de mis campos tiene varias comas, como direcciones.

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

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

* Además, str_getcsv no es compatible con mi servicio de alojamiento.

El código anterior no funciona con el siguiente ejemplo de archivo CSV. La primera columna es el nombre, la segunda columna es la dirección, la tercera columna es el estado civil.

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
fuente
2
Atascado con PHP 5.2, ¿eh? Lo siento por ti, estoy en el mismo barco que mi proveedor de hosting.
Adam F
Puede usar este asistente: github.com/rap2hpoutre/csv-to-associative-array
rap-2-h

Respuestas:

179

Como dijiste en tu título, fgetcsv es el camino a seguir. Es bastante fácil de usar.

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

Querrá poner más verificación de errores allí en caso de que fopen()falle, pero esto funciona para leer un archivo CSV línea por línea y analizar la línea en una matriz.

Dave DeLong
fuente
Gracias Dave, pero tu ejemplo solo proporciona una matriz con las siguientes tres posiciones: $ línea [0], $ línea [1] y $ línea [2]. Eso está bien para la primera línea, pero necesito crear posiciones separadas para las líneas 2, 3, 4, etc. De esa forma puedo manipular las líneas por separado. Espero que tenga sentido
Thomas
7
@Thomas Si necesita una variedad de nombres, direcciones y estados, puede hacer lo que está haciendo arriba: list($names[], $addresses[], $statuses[]) = $line;
Dave DeLong
¡Gracias de nuevo Dave! Eso me estaba haciendo tropezar.
Thomas
Tengo una pregunta sobre esta función, si uno de los campos CSV tiene una nueva línea, ¿analizará actualmente la línea como un solo registro? ¿O devolverá dos registros (destrozados) en su lugar?
Alix Axel
¿Por qué tenemos que cerrar al final?
kiwi enojado
55

Creo que la sintaxis str_getcsv () es mucho más limpia, tampoco requiere que el CSV se almacene en el sistema de archivos.

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

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

O para una solución línea por línea:

$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>';

O para una solución línea por línea sin 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
fuente
2
FYI: str_getcsv () solo está disponible desde PHP 5.3.0 en adelante. ¡El proyecto en el que estoy trabajando se perdió por 1 versión DOH! (estamos usando 5.2.9 atm).
Jim Ford
Eso es excelente, a menos que tenga restricciones de memoria. La solución fgetcsv funciona con cualquier configuración de hardware.
Sp4cecat
4
¡TENER CUIDADO! hay un error con str_getcsv que hace que ignore los finales de línea: bugs.php.net/bug.php?id=55763&edit=1
RJD22
Tenga en cuenta que puede hacer: while (! Feof ($ archivo)) {$ csv [] = fgetcsv ($ archivo); } en lugar de while (($ resultado = fgetcsv ($ archivo))! == falso) {$ csv [] = $ resultado; }
David G
23

He creado una función que convertirá una cadena csv en una matriz. La función sabe cómo escapar de los caracteres especiales y funciona con o sin caracteres delimitados.

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

¡Lo probé con su muestra de csv y funciona como se esperaba!

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;
}
knagode
fuente
16
$arrayFromCSV =  array_map('str_getcsv', file('/path/to/file.csv'));
Iván G
fuente
1
Pulgares arriba por la simplicidad
kudlohlavec
14

Pregunta antigua, pero aún relevante para los usuarios de PHP 5.2. str_getcsv está disponible desde PHP 5.3. Escribí una pequeña función que funciona con fgetcsv.

A continuación se muestra mi función de 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;
}

Devoluciones

Comenzar a leer 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
        )
) 
Manu Manjunath
fuente
Por cierto, puede agregar parámetros opcionales a fgetcsv para cambiar el delimitador, el carácter del recinto, etc.
Manu Manjunath
4

Prueba esto..

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
fuente
3

Esta función devolverá una matriz con valores de encabezado como claves de matriz.

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
fuente
3

Para obtener una matriz con las claves correctas, puede intentar esto:

// 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);
ayunarse
fuente
1

Encuentre debajo un enlace a la función de @knagode, mejorado con un parámetro de omisión de filas. 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
fuente
1
En stackoverflow, proporcione más detalles en lugar de proporcionar solo un enlace.
Paul Lo
1

Se me ocurrió este código bastante básico. Creo que podría ser útil para cualquiera.

$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);
grc
fuente
1

Si desea que cada línea esté en una matriz y cada celda de la línea en una matriz:

$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);
Bueno
fuente
0

Prueba este código:

function readCsv($file)
{
    if (($handle = fopen($file, 'r')) !== FALSE) {
        while (($lineArray = fgetcsv($handle, 4000)) !== FALSE) {
            print_r(lineArray);
        }
        fclose($handle);
    }
}
Indrajeet Singh
fuente
1
¿Cuál es la razón para publicar exactamente la misma respuesta aplicada?
pinepain
0
 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
fuente
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;
}
Kamil Sułek
fuente
¿cuál es la pregunta?
SpongePablo
Consulte " Explicación de respuestas totalmente basadas en códigos ". Si bien esto puede ser técnicamente correcto, no explica por qué resuelve el problema o debería ser la respuesta seleccionada. Debemos educar además para ayudar a resolver el problema.
The Tin Man