Crie um arquivo CSV para um usuário em PHP

220

Eu tenho dados em um banco de dados MySQL. Estou enviando ao usuário uma URL para obter seus dados como um arquivo CSV.

Eu tenho o e-mail do link, consulta MySQL, etc. coberto.

Como, quando clicam no link, pop-up para baixar um CVS com o registro do MySQL?

Eu tenho todas as informações para obter o registro já. Eu simplesmente não vejo como o PHP cria o arquivo CSV e permite que eles baixem um arquivo com uma extensão .csv.

d -_- b
fonte

Respostas:

280

Experimentar:

header("Content-type: text/csv");
header("Content-Disposition: attachment; filename=file.csv");
header("Pragma: no-cache");
header("Expires: 0");

echo "record1,record2,record3\n";
die;

etc

Edit: Aqui está um trecho de código que eu uso para codificar opcionalmente os campos CSV:

function maybeEncodeCSVField($string) {
    if(strpos($string, ',') !== false || strpos($string, '"') !== false || strpos($string, "\n") !== false) {
        $string = '"' . str_replace('"', '""', $string) . '"';
    }
    return $string;
}
Oleg Barshay
fonte
11
observe que as regras para CSVs são importantes. Para garantir uma boa exibição, coloque aspas duplas nos campos e não se esqueça de substituir aspas duplas dentro de campos por aspas duplas: `echo '"' .str_replace ('"', '" "', $ record1). '","'. str_replace ....
Mala
46
Apenas para esclarecer, o cabeçalho correto do HTTP Content-Type para CSV é text / csv, não application / csv. Duvido que qualquer navegador moderno se importe de qualquer maneira, mas como existem padrões, é melhor usá-los.
fentie
10
Em geral, siga o RFC 4180 ao gerar arquivos CSV. tools.ietf.org/html/rfc4180
Oleg Barshay
5
@Oleg Barshay: OMG, que RFC é uma obra-prima: "Se aspas duplas forem usadas para delimitar campos, uma aspas dupla aparecendo dentro de um campo deve ser escapada precedendo-a com outra aspas duplas". Outra citação dupla!
aefxx
465
header("Content-Type: text/csv");
header("Content-Disposition: attachment; filename=file.csv");

function outputCSV($data) {
  $output = fopen("php://output", "wb");
  foreach ($data as $row)
    fputcsv($output, $row); // here you can change delimiter/enclosure
  fclose($output);
}

outputCSV(array(
  array("name 1", "age 1", "city 1"),
  array("name 2", "age 2", "city 2"),
  array("name 3", "age 3", "city 3")
));

php: // saída
fputcsv

Andrii Nemchenko
fonte
64
Mais pessoas precisam ver isso e votar. Esta é facilmente a melhor resposta nesta página. O PHP já possui funções internas para formatar o conteúdo CSV. Todos devem usá-los. Grande resposta, @Andrey :)
Maček
2
Pena fputcsv () não funciona corretamente embora :( bugs.php.net/bug.php?id=50686
gou1
4
Bom, mas a outputCSVfunção é desnecessariamente complicada. Você pode foreachterminar $array, enviando seus valores diretamente para fputcsv. Não há necessidade para isso __outputCSVeo array_walk:)foreach($data as $vals) {fputcsv($filehandler,$vals);}
Sygmoral
Estou tendo alguns problemas com caracteres franceses na matriz porque, eventualmente, preciso que o .csv seja aberto no Excel. Engasga com os caracteres acentuados. Coisas como "Prévalence","age 1","city 1" Alguma idéia? Mexer com UTF-8 não ajudou até agora.
Voodoo
1
O delimitador @theosem depende das configurações de exportação do SO ou do Excel. Adicionei observação sobre delimitador.
Andrii Nemchenko
19

Aqui está uma versão aprimorada da função do php.net que @Andrew postou.

function download_csv_results($results, $name = NULL)
{
    if( ! $name)
    {
        $name = md5(uniqid() . microtime(TRUE) . mt_rand()). '.csv';
    }

    header('Content-Type: text/csv');
    header('Content-Disposition: attachment; filename='. $name);
    header('Pragma: no-cache');
    header("Expires: 0");

    $outstream = fopen("php://output", "wb");

    foreach($results as $result)
    {
        fputcsv($outstream, $result);
    }

    fclose($outstream);
}

É realmente fácil de usar e funciona muito bem com os conjuntos de resultados MySQL (i) / PDO.

download_csv_results($results, 'your_name_here.csv');

Lembre-se de exit()depois de ligar para isso se você tiver terminado a página.

Xeoncross
fonte
Como você altera o separador de, para; ?
Rabugento
1
como devemos adicionar um botão para acionar esse evento, para que o usuário possa baixar o arquivo CSV sob demanda?
CanCeylan
Vou ter o erro "SyntaxError: token inesperado ILEGAL" com a linha "fopen (" php: // output "," w ");" Quando eu mudo para "$ fp = fopen ('stats.csv', 'w');" não mostra erro. Mas então é claro que não funciona. Como devo resolver isso?
CanCeylan
@ CanCeylan, essa é uma pergunta em si mesma e preciso de mais detalhes para resolvê-la.
Xeoncross
1
Adicione um fputcsv($outstream, array_keys($results[0]));pouco antes foreachde incluir também os cabeçalhos das colunas.
Justin
16

Além de tudo o que foi dito, você pode precisar adicionar:

header("Content-Transfer-Encoding: UTF-8");

É muito útil ao manipular arquivos com vários idiomas, como nomes de pessoas ou cidades.

Stan
fonte
9

O tópico é um pouco antigo, eu sei, mas para referência futura e para noobs como eu:

Todos os outros aqui explicam como criar o CSV, mas perdem uma parte básica da pergunta: como vincular. Para vincular o download do arquivo CSV, basta vincular o arquivo .php, que por sua vez responde como um arquivo .csv. Os cabeçalhos PHP fazem isso. Isso permite coisas legais, como adicionar variáveis ​​à string de consulta e personalizar a saída:

<a href="my_csv_creator.php?user=23&amp;othervariable=true">Get CSV</a>

my_csv_creator.php pode trabalhar com as variáveis ​​fornecidas na string de consulta e, por exemplo, usar consultas de banco de dados diferentes ou personalizadas, alterar as colunas do CSV, personalizar o nome do arquivo e assim por diante, por exemplo:

User_John_Doe_10_Dec_11.csv
LBJ
fonte
1
Qualquer um que esteja lendo isso seja MUITO cauteloso com essa abordagem. Eu apostaria que as entradas não estão sendo escapadas corretamente e isso pode levar a grandes falhas de segurança em seu aplicativo.
Calumbrodie
Seu método é muito seguro e funciona muito bem. Você pode controlar facilmente o acesso com a sessão e também pode armazenar todas as informações que deseja colocar em um csv em uma sessão var. Em seguida, desative-o como parte do processo de conversão para um csv. Eu apenas sugeriria usar vars de sessão em vez de uma string de consulta.
inorganik
1
Não há brechas de segurança per se com esse método. Contanto que o arquivo php referenciado esteja executando seu trabalho de limpeza e verificação de acesso. Mas realmente não faz sentido mostrar tudo isso aqui. O ponto da postagem é que você pode vincular a qualquer URL que gere o csv.
precisa saber é o seguinte
8

Crie seu arquivo e retorne uma referência a ele com o cabeçalho correto para acionar o Save As - edite o seguinte, conforme necessário. Coloque seus dados CSV em $ csvdata.

$fname = 'myCSV.csv';
$fp = fopen($fname,'wb');
fwrite($fp,$csvdata);
fclose($fp);

header('Content-type: application/csv');
header("Content-Disposition: inline; filename=".$fname);
readfile($fname);
typemismatch
fonte
1
Usar Disposição de Conteúdo "embutida" significa que o navegador deve tentar mostrá-lo sem fazer o download (o IE tende a incorporar uma instância do Excel para isso). "anexo" é o necessário para forçar um download.
Gert van den Berg
5

Aqui está um exemplo de trabalho completo usando o DOP e incluindo cabeçalhos de coluna:

$query = $pdo->prepare('SELECT * FROM test WHERE id=?');
$query->execute(array($id));    
$results = $query->fetchAll(PDO::FETCH_ASSOC);
download_csv_results($results, 'test.csv'); 
exit();


function download_csv_results($results, $name)
{            
    header('Content-Type: text/csv');
    header('Content-Disposition: attachment; filename='. $name);
    header('Pragma: no-cache');
    header("Expires: 0");

    $outstream = fopen("php://output", "wb");    
    fputcsv($outstream, array_keys($results[0]));

    foreach($results as $result)
    {
        fputcsv($outstream, $result);
    }

    fclose($outstream);
}
Justin
fonte
4

Primeiro, crie dados como uma String com vírgula como delimitador (separado por ","). Algo assim

$CSV_string="No,Date,Email,Sender Name,Sender Email \n"; //making string, So "\n" is used for newLine

$rand = rand(1,50); //Make a random int number between 1 to 50.
$file ="export/export".$rand.".csv"; //For avoiding cache in the client and on the server 
                                     //side it is recommended that the file name be different.

file_put_contents($file,$CSV_string);

/* Or try this code if $CSV_string is an array
    fh =fopen($file, 'w');
    fputcsv($fh , $CSV_string , ","  , "\n" ); // "," is delimiter // "\n" is new line.
    fclose($fh);
*/
Behzad Ravanbakhsh
fonte
3

Ei, funciona muito bem .... !!!! Obrigado Peter Mortensen e Connor Burton

<?php
header("Content-type: application/csv");
header("Content-Disposition: attachment; filename=file.csv");
header("Pragma: no-cache");
header("Expires: 0");

ini_set('display_errors',1);
$private=1;
error_reporting(E_ALL ^ E_NOTICE);

mysql_connect("localhost", "user", "pass") or die(mysql_error());
mysql_select_db("db") or die(mysql_error());

$start = $_GET["start"];
$end = $_GET["end"];

$query = "SELECT * FROM customers WHERE created>='{$start} 00:00:00'  AND created<='{$end} 23:59:59'   ORDER BY id";
$select_c = mysql_query($query) or die(mysql_error());

while ($row = mysql_fetch_array($select_c, MYSQL_ASSOC))
{
    $result.="{$row['email']},";
    $result.="\n";
    echo $result;
}

?>

Kaddy
fonte
Você não usar esse código em produção, é vulnerável a injeções de SQL
ntzm
2

Método simples -

$data = array (
    'aaa,bbb,ccc,dddd',
    '123,456,789',
    '"aaa","bbb"');

$fp = fopen('data.csv', 'wb');
foreach($data as $line){
    $val = explode(",",$line);
    fputcsv($fp, $val);
}
fclose($fp);

Portanto, cada linha da $datamatriz irá para uma nova linha do seu arquivo CSV recém-criado. Funciona apenas para o PHP 5 e posterior.

user244641
fonte
2

Você pode simplesmente gravar seus dados em CSV usando a função fputcsv . vamos dar uma olhada no exemplo abaixo. Escreva a matriz da lista no arquivo CSV

$list[] = array("Cars", "Planes", "Ships");
$list[] = array("Car's2", "Planes2", "Ships2");
//define headers for CSV 
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=file_name.csv');
//write data into CSV
$fp = fopen('php://output', 'wb');
//convert data to UTF-8 
fprintf($fp, chr(0xEF).chr(0xBB).chr(0xBF));
foreach ($list as $line) {
    fputcsv($fp, $line);
}
fclose($fp);
Shahbaz
fonte
1

A maneira mais fácil é usar uma classe CSV dedicada como esta:

$csv = new csv();
$csv->load_data(array(
    array('name'=>'John', 'age'=>35),
    array('name'=>'Adrian', 'age'=>23), 
    array('name'=>'William', 'age'=>57) 
));
$csv->send_file('age.csv'); 
Sergiu
fonte
1

Ao invés de:

$query = "SELECT * FROM customers WHERE created>='{$start} 00:00:00'  AND created<='{$end} 23:59:59'   ORDER BY id";
$select_c = mysql_query($query) or die(mysql_error()); 

while ($row = mysql_fetch_array($select_c, MYSQL_ASSOC))
{
    $result.="{$row['email']},";
    $result.="\n";
    echo $result;
}

Usar:

$query = "SELECT * FROM customers WHERE created>='{$start} 00:00:00'  AND created<='{$end} 23:59:59'   ORDER BY id";
$select_c = mysql_query($query) or die(mysql_error()); 

while ($row = mysql_fetch_array($select_c, MYSQL_ASSOC))
{
    echo implode(",", $row)."\n";
}
Joshua
fonte
1

Já veio uma solução muito boa. Estou apenas colocando o código total para que um novato obtenha ajuda total

<?php
extract($_GET); //you can send some parameter by query variable. I have sent table name in *table* variable

header("Content-type: text/csv");
header("Content-Disposition: attachment; filename=$table.csv");
header("Pragma: no-cache");
header("Expires: 0");

require_once("includes/functions.php"); //necessary mysql connection functions here

//first of all I'll get the column name to put title of csv file.
$query = "SHOW columns FROM $table";
$headers = mysql_query($query) or die(mysql_error());
$csv_head = array();
while ($row = mysql_fetch_array($headers, MYSQL_ASSOC))
{
    $csv_head[] =  $row['Field'];
}
echo implode(",", $csv_head)."\n";

//now I'll bring the data.
$query = "SELECT * FROM $table";
$select_c = mysql_query($query) or die(mysql_error()); 

while ($row = mysql_fetch_array($select_c, MYSQL_ASSOC))
{
    foreach ($row as $key => $value) {
            //there may be separator (here I have used comma) inside data. So need to put double quote around such data.
        if(strpos($value, ',') !== false || strpos($value, '"') !== false || strpos($value, "\n") !== false) {
            $row[$key] = '"' . str_replace('"', '""', $value) . '"';
        }
    }
    echo implode(",", $row)."\n";
}

?>

Salvei este código em csv-download.php

Agora veja como eu usei esses dados para baixar o arquivo csv

<a href="csv-download.php?table=tbl_vfm"><img title="Download as Excel" src="images/Excel-logo.gif" alt="Download as Excel" /><a/>

Então, quando clico no link, baixe o arquivo sem me levar à página csv-download.php no navegador.

zahid9i
fonte
0

Para enviá-lo como um CSV e dar o nome do arquivo, use header ():

http://us2.php.net/header

header('Content-type: text/csv');
header('Content-disposition: attachment; filename="myfile.csv"');

No que diz respeito à criação do CSV, você apenas percorre o conjunto de resultados, formata a saída e envia-a, como faria com qualquer outro conteúdo.

Gavin M. Roy
fonte
0

Escrever seu próprio código CSV provavelmente é uma perda de tempo, basta usar um pacote como league / csv - ele lida com todas as coisas difíceis para você, a documentação é boa e é muito estável / confiável:

http://csv.thephpleague.com/

Você precisará usar o compositor. Se você não sabe o que é compositor, eu recomendo que você dê uma olhada: https://getcomposer.org/

John Hunt
fonte
0
<?
    // Connect to database
    $result = mysql_query("select id
    from tablename
    where shid=3");
    list($DBshid) = mysql_fetch_row($result);

    /***********************************
    Write date to CSV file
    ***********************************/

    $_file = 'show.csv';
    $_fp = @fopen( $_file, 'wb' );

    $result = mysql_query("select name,compname,job_title,email_add,phone,url from UserTables where id=3");

    while (list( $Username, $Useremail_add, $Userphone, $Userurl) = mysql_fetch_row($result))
    {
        $_csv_data = $Username.','.$Useremail_add.','.$Userphone.','.$Userurl . "\n";
        @fwrite( $_fp, $_csv_data);
    }
    @fclose( $_fp );
?>
Vish00722
fonte
0

Como escrever no arquivo CSV usando script PHP? Na verdade, eu também estava procurando por isso. É uma tarefa fácil com PHP. fputs (manipulador, conteúdo) - essa função funciona eficientemente para mim. Primeiro, você precisa abrir o arquivo no qual precisa gravar o conteúdo usando fopen ($ CSVFileName, 'wb').

$CSVFileName = test.csv”;
$fp = fopen($CSVFileName, wb’);

//Multiple iterations to append the data using function fputs()
foreach ($csv_post as $temp)
{
    $line = “”;
    $line .= Content 1 . $comma . $temp . $comma . Content 2 . $comma . 16/10/2012″.$comma;
    $line .= \n”;
    fputs($fp, $line);
}
ntzm
fonte
É sempre preferível adicionar o código a si próprio em vez de vincular, pois os links tendem a mudar ou desaparecer ao longo do tempo.
Soutettschkes
Sua resposta é para um tópico muito antigo. Enquanto em 2008 era uma prática padrão criar suas próprias linhas separadas por vírgula, o método correto desde o PHP 5.1.0 seria usar a função fputcsv embutida ( php.net/fputcsv ). Tome cuidado ao ler threads antigos para garantir que as informações contidas neles ainda sejam relevantes.
Luke Mills
-1

Coloque na $outputvariável os dados CSV e ecoe com os cabeçalhos corretos

header("Content-type: application/download\r\n");
header("Content-disposition: filename=filename.csv\r\n\r\n");
header("Content-Transfer-Encoding: ASCII\r\n");
header("Content-length: ".strlen($output)."\r\n");
echo $output;
Lorenzo Massacci
fonte