Jak utworzyć i pobrać plik csv ze skryptu php?

89

Jestem początkującym programistą i dużo szukałem w związku z moim pytaniem, ale nie mogłem znaleźć pomocnego rozwiązania lub samouczka na ten temat.

Moim celem jest posiadanie tablicy PHP, a elementy tablicy są wyświetlane na liście na stronie.

Chcę dodać opcję, aby jeśli użytkownik chciał, mógł utworzyć plik CSV z elementami tablicy i pobrać go.

Nie wiem, jak to zrobić. Ja też dużo szukałem. Ale jeszcze nie znalazłem żadnego pomocnego źródła.

Proszę o przesłanie samouczka, rozwiązania lub porady, jak wdrożyć je samodzielnie. Ponieważ jestem nowicjuszem, podaj łatwe do wdrożenia rozwiązania.

Moja tablica wygląda następująco:

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
źródło
2
phpExcel dla pliku CSV to trochę za dużo .. php.net/manual/en/function.fputcsv.php
Damien Pirsy Kwietnia
Pokaż strukturę tablicy, a ja dostanę kod, który zamieni elementy w plik CSV
pół-szybki
@ Half-fast Dodałem strukturę tablicy w poście
user2302780
2
jak dodać tytuł kolumny w pliku csv?
user2302780
możliwy duplikat eksportu do CSV przez PHP
Michal Mau

Odpowiedzi:

200

Możesz użyć wbudowanej funkcji fputcsv () dla swoich tablic, aby wygenerować poprawne linie csv z tablicy, więc będziesz musiał zapętlić i zebrać linie, na przykład:

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

Aby przeglądarki oferowały okno dialogowe „Zapisz jako”, będziesz musiał wysłać takie nagłówki HTTP (więcej informacji o tym nagłówku znajdziesz w rfc ):

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

Kładąc wszystko razem:

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);
}

Możesz go używać w ten sposób:

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"
);

Aktualizacja:
Zamiast tego php://memorymożesz również użyć php://outputdla deskryptora pliku i pozbyć się wyszukiwania i takich:

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);
    }
}   
kompleks857
źródło
2
dlaczego nie echowygenerowane linie CSV bezpośrednio w pętli?
Alex Shesterov
1
@AlexShesterov, głównym powodem jest to, że fputcsv()nie zwraca wygenerowanej linii, potrzebuje deskryptora pliku do zapisu. Możesz przewijać, pisać, czyścić bufor przy każdej iteracji, jeśli masz ograniczoną pamięć. Lub po prostu użyj prawdziwego pliku tymczasowego.
kompleks 857
@ complex857 Jak dodać tytuł kolumny do pliku csv?
user2302780
@ user2302780: Po prostu poprzedzasz swoje dane wierszem nazw kolumn. Możesz użyć kluczy z tablic danych z czymś w rodzaju$data = array_merge(array(array_keys($data[0])), $data);
complex857
1
@JoseRojas, czego można się spodziewać, ponieważ gdy już umieścisz coś na kablu (co oznacza koncepcyjnie wyprowadzanie rzeczy za pomocą php), nie możesz do tego wrócić. Aby użyć, php://outputzobacz drugi zaktualizowany przykład kodu.
kompleks 857
18

Nie mam wystarczającej reputacji, aby odpowiedzieć na rozwiązanie @ complex857. Działa świetnie, ale musiałem dodać; na końcu nagłówka Content-Disposition. Bez tego przeglądarka dodaje dwie kreski na końcu nazwy pliku (np. Zamiast „export.csv” plik zostaje zapisany jako „export.csv--”). Prawdopodobnie próbuje wyczyścić \ r \ n na końcu linii nagłówka.

Prawidłowa linia powinna wyglądać następująco:

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

W przypadku, gdy CSV zawiera znaki UTF-8, musisz zmienić kodowanie na UTF-8, zmieniając wiersz Content-Type:

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

Uważam również, że bardziej eleganckie jest użycie rewind () zamiast fseek ():

rewind($f);

Dzięki za rozwiązanie!

Luxian
źródło
2
Nigdy sam nie doświadczyłem --końca nazw plików, jednak zaktualizowałem odpowiedź (dlaczego nie po prostu prześlij zmianę?)
complex857
14

Spróbuj ... csv download.

<?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
źródło
zepsuje się, jeśli wartość pola zawiera, dlatego wolę tsv (tabulator jest rzadszy niż i możemy go zastąpić czy coś)
oriadam
14

To jest funkcja, której użyłem w moim projekcie i działa zgodnie z oczekiwaniami.

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
źródło
1
Trudno mi było zaimplementować go w hooku wordpress send_headers, ponieważ za każdym razem dodaje cały kod html bieżącej strony do końca pliku csv. Te odpowiedzi bardzo mi pomagają, ale używam ich bez operacji buforowania.
Oleg Apanovich
czysty bufor wyjściowy rozwiązał u mnie problem, że przed użyciem tych wierszy kodu na początku i na końcu powstałego pliku były puste wiersze.
Sharunas Bielskis
8

Użyj poniższego kodu, aby przekonwertować tablicę php na 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
źródło
3

Jeśli twoja struktura tablicy zawsze będzie wielowymiarowa w dokładnie ten sposób, możemy iterować przez elementy takie jak:

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

To jeden ze sposobów ... możesz to zrobić ręcznie, ale w ten sposób jest szybszy i łatwiejszy do zrozumienia i odczytania.

Następnie zarządzałbyś nagłówkami tak, jak robi to complex857, żeby wypluć plik. Możesz następnie usunąć plik za pomocą unlink (), jeśli już go nie potrzebujesz, lub możesz zostawić go na serwerze, jeśli chcesz.

pół szybko
źródło
-2

Użyj następujących,

echo "<script type='text/javascript'> window.location.href = '$file_name'; </script>";
Ashwin Balani
źródło