Como criar um array a partir de um arquivo CSV usando PHP e a função fgetcsv

106

Alguém pode gentilmente fornecer um código para criar uma matriz a partir de um arquivo CSV usando fgetcsv?

Usei o código a seguir para criar uma matriz a partir de um arquivo CSV simples, mas ele não funciona direito quando um dos meus campos tem várias vírgulas - como endereços.

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

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

* Além disso, str_getcsv não é compatível com meu serviço de hospedagem.

O código acima não funciona com o seguinte exemplo de arquivo CSV. A primeira coluna é o nome, a segunda coluna é o endereço, a terceira coluna é o 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
fonte
2
Preso no PHP 5.2 eh? Sinto por você, estou no mesmo barco que meu provedor de hospedagem.
Adam F
Você pode usar este auxiliar: github.com/rap2hpoutre/csv-to-associative-array
rap-2-h

Respostas:

179

Como você disse no título, fgetcsv é o caminho a percorrer. É muito 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);

Você vai querer colocar mais verificação de erro lá no caso de fopen()falha, mas isso funciona para ler um arquivo CSV linha por linha e analisar a linha em um array.

Dave DeLong
fonte
Obrigado Dave, mas seu exemplo fornece apenas um array com as três posições a seguir: $ line [0], $ line [1] e $ line [2]. Isso é bom para a primeira linha, mas preciso criar posições separadas para as linhas 2, 3, 4, etc. Dessa forma, posso manipular as linhas separadamente. Espero que faça sentido
Thomas
7
@Thomas Se você precisa de uma matriz de nomes, endereços e status, pode simplesmente fazer o que está fazendo acima: list($names[], $addresses[], $statuses[]) = $line;
Dave DeLong
Obrigado novamente Dave! Isso estava me enganando.
Thomas
Tenho uma pergunta sobre esta função, se um dos campos CSV tiver uma nova linha, ele irá analisar a linha como um único registro? Ou retornará dois registros (mutilados)?
Alix Axel
por que precisamos fechar no final?
kiwi zangado,
55

Acho que a sintaxe str_getcsv () é muito mais limpa, também não requer que o CSV seja armazenado no sistema de arquivos.

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

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

Ou para uma solução linha a linha:

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

Ou para uma solução linha por linha sem 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
fonte
2
FYI: str_getcsv () está disponível apenas a partir do PHP 5.3.0. O projeto no qual estou trabalhando perdeu por 1 versão DOH! (estamos usando 5,2,9 atm).
Jim Ford,
Isso é excelente, a menos que você tenha restrições de memória. A solução fgetcsv funciona com qualquer configuração de hardware.
Sp4cecat
4
CUIDADO! há um bug com str_getcsv que o faz ignorar terminações de linha: bugs.php.net/bug.php?id=55763&edit=1
RJD22
Observe que você pode fazer: while (! Feof ($ file)) {$ csv [] = fgetcsv ($ file); } em vez de while (($ result = fgetcsv ($ file))! == false) {$ csv [] = $ result; }
David G
23

Eu criei uma função que irá converter uma string csv em uma matriz. A função sabe como escapar caracteres especiais e funciona com ou sem caracteres de inclusão.

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

Eu tentei com sua amostra csv e funcionou conforme o esperado!

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
fonte
16
$arrayFromCSV =  array_map('str_getcsv', file('/path/to/file.csv'));
Ivan G
fonte
1
Perfeito para a simplicidade
kudlohlavec
14

Pergunta antiga, mas ainda relevante para usuários de PHP 5.2. str_getcsv está disponível no PHP 5.3. Escrevi uma pequena função que funciona com o próprio fgetcsv.

Abaixo está minha função em 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;
}

Devoluções

Comece a ler 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
fonte
A propósito, você pode adicionar parâmetros opcionais a fgetcsv para alterar o delimitador, o caractere de invólucro etc.
Manu Manjunath
4

Experimente isso ..

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

Esta função retornará array com valores de cabeçalho como chaves de array.

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

Para obter uma matriz com as chaves certas, você pode tentar isto:

// 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
fonte
1

Por favor, encontre abaixo um link para a função de @knagode, aprimorado com um parâmetro de pular linhas. 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
fonte
1
No stackoverflow, elabore mais em vez de fornecer apenas um link.
Paul Lo
1

Eu vim com esse código bem básico. Acho que pode ser útil para qualquer pessoa.

$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
fonte
1

Se você quiser que cada linha esteja em uma matriz e cada célula da linha em uma 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);
Para o bem
fonte
0

Experimente 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
fonte
1
Qual é a razão para postar exatamente a mesma resposta do questionador 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
fonte
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
fonte
Qual é a questão?
SpongePablo
Consulte " Explicando respostas inteiramente baseadas em código ". Embora isso possa ser tecnicamente correto, não explica por que resolve o problema ou deve ser a resposta selecionada. Devemos educar além de ajudar a resolver o problema.
The Tin Man