Como criar e baixar um arquivo csv de um script php?

88

Sou um programador novato e pesquisei muito sobre minha dúvida, mas não consegui encontrar uma solução útil ou um tutorial sobre isso.

Meu objetivo é ter uma matriz PHP e os elementos da matriz estão sendo exibidos em uma lista na página.

Quero adicionar uma opção, para que se um usuário quiser, ele / ela pode criar um arquivo CSV com elementos de array e baixá-lo.

Eu não sei fazer isso. Eu também procurei muito. Mas ainda não encontrei nenhum recurso útil.

Forneça algum tutorial, solução ou conselho para implementá-lo sozinho. Como sou um novato, forneça soluções fáceis de implementar.

Minha matriz se parece com:

Array
(
    [0] => Array
        (
            [fs_id] => 4c524d8abfc6ef3b201f489c
            [name] => restaurant
            [lat] => 40.702692
            [lng] => -74.012869
            [address] => new york
            [postalCode] => 
            [city] => NEW YORK
            [state] => ny
            [business_type] => BBQ Joint
            [url] => 
        )

)
user2302780
fonte
2
phpExcel para um arquivo CSV é um pouco demais .. php.net/manual/en/function.fputcsv.php
Damien Pirsy
Mostre sua estrutura de array e forneça algum código para transformar os elementos em um csv
meio rápido
@ meio rápido, adicionei a estrutura de array no post
user2302780
2
como posso adicionar o título da coluna no arquivo csv?
user2302780
possível duplicata de Exportar para CSV via PHP
Michal Mau

Respostas:

198

Você pode usar o fputcsv () embutido para seus arrays para gerar linhas csv corretas de seu array, então você terá que fazer um loop e coletar as linhas, assim:

$f = fopen("tmp.csv", "w");
foreach ($array as $line) {
    fputcsv($f, $line);
}

Para fazer os navegadores oferecerem a caixa de diálogo "Salvar como", você terá que enviar cabeçalhos HTTP como este (veja mais sobre este cabeçalho na rfc ):

header('Content-Disposition: attachment; filename="filename.csv";');

Juntando tudo:

function array_to_csv_download($array, $filename = "export.csv", $delimiter=";") {
    // open raw memory as file so no temp files needed, you might run out of memory though
    $f = fopen('php://memory', 'w'); 
    // loop over the input array
    foreach ($array as $line) { 
        // generate csv lines from the inner arrays
        fputcsv($f, $line, $delimiter); 
    }
    // reset the file pointer to the start of the file
    fseek($f, 0);
    // tell the browser it's going to be a csv file
    header('Content-Type: application/csv');
    // tell the browser we want to save it instead of displaying it
    header('Content-Disposition: attachment; filename="'.$filename.'";');
    // make php send the generated csv lines to the browser
    fpassthru($f);
}

E você pode usá-lo assim:

array_to_csv_download(array(
  array(1,2,3,4), // this array is going to be the first row
  array(1,2,3,4)), // this array is going to be the second row
  "numbers.csv"
);

Atualização:
Em vez de php://memoryvocê também pode usar o php://outputpara o descritor de arquivo e acabar com a busca e tal:

function array_to_csv_download($array, $filename = "export.csv", $delimiter=";") {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename="'.$filename.'";');

    // open the "output" stream
    // see http://www.php.net/manual/en/wrappers.php.php#refsect2-wrappers.php-unknown-unknown-unknown-descriptioq
    $f = fopen('php://output', 'w');

    foreach ($array as $line) {
        fputcsv($f, $line, $delimiter);
    }
}   
complexo857
fonte
2
por que não echoas linhas CSV geradas diretamente no loop?
Alex Shesterov
1
@AlexShesterov, o principal motivo é que fputcsv()não retorna a linha gerada, será necessário um descritor de arquivo para escrever. Você pode retroceder, escrever, limpar o buffer em cada iteração, se você tiver restrição de memória. Ou apenas use um arquivo temporário real.
complexo857 de
@ complex857 como posso adicionar o título da coluna para o csv?
user2302780
@ user2302780: Você apenas prefixa seus dados com uma linha de nomes de colunas. Você pode usar as chaves das matrizes de dados com algo como$data = array_merge(array(array_keys($data[0])), $data);
complex857
1
@JoseRojas isso é esperado, já que uma vez que você coloca algo no ar (o que significa gerar as coisas com php conceitualmente), você não pode voltar atrás. Para usar, php://outputconsulte o segundo exemplo de código atualizado.
complexo857 de
17

Não tenho reputação suficiente para responder à solução @ complex857. Funciona muito bem, mas eu tenho que adicionar; no final do cabeçalho Content-Disposition. Sem ele, o navegador adiciona dois travessões no final do nome do arquivo (por exemplo, em vez de "export.csv", o arquivo é salvo como "export.csv--"). Provavelmente, ele tenta limpar \ r \ n no final da linha do cabeçalho.

A linha correta deve ser semelhante a esta:

header('Content-Disposition: attachment;filename="'.$filename.'";');

Caso o CSV contenha caracteres UTF-8, você deve alterar a codificação para UTF-8 alterando a linha Content-Type:

header('Content-Type: application/csv; charset=UTF-8');

Além disso, acho mais elegante usar rewind () em vez de fseek ():

rewind($f);

Obrigado pela sua solução!

Luxian
fonte
2
Eu mesmo nunca experimentei o --no final dos nomes de arquivo, no entanto, atualizei a resposta (por que não apenas enviar uma edição?)
complexo857
13

Tente ... download csv.

<?php 
mysql_connect('hostname', 'username', 'password');
mysql_select_db('dbname');
$qry = mysql_query("SELECT * FROM tablename");
$data = "";
while($row = mysql_fetch_array($qry)) {
  $data .= $row['field1'].",".$row['field2'].",".$row['field3'].",".$row['field4']."\n";
}

header('Content-Type: application/csv');
header('Content-Disposition: attachment; filename="filename.csv"');
echo $data; exit();
?>
Indrajeet Singh
fonte
irá quebrar se um valor de campo contiver, é por isso que eu prefiro tsv (tab é mais raro do que, e podemos substituí-lo ou algo assim)
oriadam
11

Essa é a função que usei no meu projeto e funciona conforme o esperado.

function array_csv_download( $array, $filename = "export.csv", $delimiter=";" )
{
    header( 'Content-Type: application/csv' );
    header( 'Content-Disposition: attachment; filename="' . $filename . '";' );

    // clean output buffer
    ob_end_clean();

    $handle = fopen( 'php://output', 'w' );

    // use keys as column titles
    fputcsv( $handle, array_keys( $array['0'] ) );

    foreach ( $array as $value ) {
        fputcsv( $handle, $value , $delimiter );
    }

    fclose( $handle );

    // flush buffer
    ob_flush();

    // use exit to get rid of unexpected output afterward
    exit();
}
Sajidur Rahman
fonte
1
Eu tive dificuldade em tentar implementá-lo no gancho send_headers do wordpress, porque toda vez que ele adicionava todo o html da página atual ao final do arquivo csv. Essas respostas me surpreendem muito, mas eu as uso sem operações de buffer.
Oleg Apanovich
O buffer de saída limpo resolveu para mim o problema de que antes do uso dessas linhas de código no início e no final do arquivo formado havia linhas vazias.
Sharunas Bielskis
8

Use o código abaixo para converter uma matriz php em CSV

<?php
   $ROW=db_export_data();//Will return a php array
   header("Content-type: application/csv");
   header("Content-Disposition: attachment; filename=test.csv");
   $fp = fopen('php://output', 'w');

   foreach ($ROW as $row) {
        fputcsv($fp, $row);
   }
   fclose($fp);
Kiran Reddy
fonte
3

Se sua estrutura de array sempre será multidimensional dessa maneira exata, podemos iterar por meio de elementos como:

$fh = fopen('somefile.csv', 'w') or die('Cannot open the file');

for( $i=0; $i<count($arr); $i++ ){
    $str = implode( ',', $arr[$i] );
    fwrite( $fh, $str );
    fwrite( $fh, "\n" );
}
fclose($fh);

Essa é uma maneira de fazer ... você poderia fazer manualmente, mas desta forma é mais rápida e fácil de entender e ler.

Então, você administraria seus cabeçalhos, algo que complex857 está fazendo para cuspir o arquivo. Em seguida, você pode excluir o arquivo usando unlink () se não precisar mais dele ou pode deixá-lo no servidor, se desejar.

meio rápido
fonte
0

Use o seguinte,

echo "<script type='text/javascript'> window.location.href = '$file_name'; </script>";
Ashwin Balani
fonte