จะสร้างและดาวน์โหลดไฟล์ csv จากสคริปต์ php ได้อย่างไร?


92

ฉันเป็นโปรแกรมเมอร์มือใหม่และฉันค้นหาคำถามมากมายเกี่ยวกับคำถามของฉัน แต่ไม่พบวิธีแก้ปัญหาหรือบทช่วยสอนที่เป็นประโยชน์

เป้าหมายของฉันคือฉันมีอาร์เรย์ PHP และองค์ประกอบอาร์เรย์แสดงอยู่ในรายการบนหน้า

ฉันต้องการเพิ่มตัวเลือกเพื่อที่ว่าหากผู้ใช้ต้องการเขา / เธอสามารถสร้างไฟล์ CSV ที่มีองค์ประกอบอาร์เรย์และดาวน์โหลดได้

ฉันไม่รู้ว่าต้องทำอย่างไร ฉันได้ค้นหามากเกินไป แต่ยังไม่พบแหล่งข้อมูลที่เป็นประโยชน์

โปรดให้คำแนะนำหรือวิธีแก้ปัญหาหรือคำแนะนำเพื่อนำไปใช้ด้วยตัวเอง เนื่องจากฉันเป็นมือใหม่โปรดให้วิธีแก้ปัญหาที่ใช้งานง่าย

อาร์เรย์ของฉันดูเหมือนว่า:

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] => 
        )

)

2
phpExcel สำหรับไฟล์ CSV นั้นมากไปหน่อย .. php.net/manual/en/function.fputcsv.php
Damien Pirsy

แสดงโครงสร้างอาร์เรย์ของคุณและฉันจะให้รหัสเพื่อเปลี่ยนองค์ประกอบให้เป็นไฟล์ csv
ครึ่งเร็ว

@ ครึ่งเร็วฉันได้เพิ่มโครงสร้างอาร์เรย์ในโพสต์แล้ว
user2302780

2
จะเพิ่มชื่อคอลัมน์ในไฟล์ csv ได้อย่างไร
user2302780

คำตอบ:


208

คุณสามารถใช้fputcsv () ในตัวสำหรับอาร์เรย์ของคุณเพื่อสร้างบรรทัด csv ที่ถูกต้องจากอาร์เรย์ของคุณดังนั้นคุณจะต้องวนซ้ำและรวบรวมบรรทัดดังนี้:

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

ในการทำให้เบราว์เซอร์เสนอกล่องโต้ตอบ "บันทึกเป็น" คุณจะต้องส่งส่วนหัว HTTP เช่นนี้ (ดูเพิ่มเติมเกี่ยวกับส่วนหัวนี้ในrfc ):

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

วางมันทั้งหมดเข้าด้วยกัน:

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

และคุณสามารถใช้งานได้ดังนี้:

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

อัปเดต:
แทนที่จะเป็นphp://memoryคุณยังสามารถใช้php://outputสำหรับตัวอธิบายไฟล์และหลีกเลี่ยงการค้นหาและอื่น ๆ :

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

2
ทำไมไม่echoสร้างบรรทัด CSV โดยตรงในลูป
Alex Shesterov

1
@AlexShesterov เหตุผลหลักคือfputcsv()ไม่ส่งคืนบรรทัดที่สร้างขึ้นมันจะต้องมีตัวอธิบายไฟล์เพื่อเขียนถึง คุณสามารถกรอกลับเขียนล้างบัฟเฟอร์ในทุกๆการวนซ้ำแม้ว่าคุณจะมีข้อ จำกัด ด้านหน่วยความจำก็ตาม หรือใช้ไฟล์ชั่วคราวจริงแทน
complex857

@ complex857 ฉันจะเพิ่มชื่อคอลัมน์สำหรับ csv ได้อย่างไร
user2302780

@ user2302780: คุณเพียงนำหน้าข้อมูลของคุณด้วยชื่อคอลัมน์ คุณสามารถใช้คีย์จาก data-arrays ได้เช่น$data = array_merge(array(array_keys($data[0])), $data);
complex857

1
@JoseRojas ที่คาดว่าจะได้รับเมื่อคุณใส่อะไรบางอย่างทับเส้นลวด (สิ่งที่ส่งออกสิ่งต่าง ๆ ด้วย php หมายถึงแนวคิด) คุณไม่สามารถย้อนกลับไปได้ หากต้องการใช้php://outputดูตัวอย่างโค้ดที่อัปเดตครั้งที่สอง
complex857

18

ฉันไม่มีชื่อเสียงมากพอที่จะตอบกลับโซลูชัน @ complex857 มันใช้งานได้ดี แต่ฉันต้องเพิ่ม; ที่ส่วนท้ายของส่วนหัวการจัดการเนื้อหา หากไม่มีเบราว์เซอร์จะเพิ่มสองขีดที่ท้ายชื่อไฟล์ (เช่นแทนที่จะเป็น "export.csv" ไฟล์จะถูกบันทึกเป็น "export.csv--") อาจจะพยายามฆ่าเชื้อ \ r \ n ที่ส่วนท้ายของบรรทัดส่วนหัว

เส้นที่ถูกต้องควรมีลักษณะดังนี้:

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

ในกรณีที่ CSV มีอักขระ UTF-8 อยู่คุณต้องเปลี่ยนการเข้ารหัสเป็น UTF-8 โดยเปลี่ยนบรรทัด Content-Type:

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

นอกจากนี้ฉันพบว่าการใช้ rewind () แทน fseek ():

rewind($f);

ขอบคุณสำหรับการแก้ปัญหาของคุณ!


2
ฉันไม่เคยพบกับ--ท้ายชื่อไฟล์ด้วยตัวเอง แต่ฉันได้อัปเดตคำตอบแล้ว (ทำไมไม่ส่งการแก้ไขล่ะ)
complex857

14

ลอง ... ดาวน์โหลด 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();
?>

จะแตกหากมีค่าฟิลด์นั่นคือเหตุผลที่ฉันชอบ tsv (แท็บหายากมากกว่าและเราสามารถแทนที่หรือบางอย่างได้)
oriadam

14

นั่นคือฟังก์ชันที่ฉันใช้สำหรับโปรเจ็กต์ของฉันและทำงานได้ตามที่คาดไว้

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

1
ฉันมีช่วงเวลาที่ยากลำบากในการพยายามใช้งานใน wordpress send_headers hook เพราะทุกครั้งที่เพิ่ม html ของหน้าปัจจุบันทั้งหมดที่ท้ายไฟล์ csv คำตอบเหล่านี้ทำให้ฉันชะงักมาก แต่ฉันใช้มันโดยไม่ต้องใช้บัฟเฟอร์
Oleg Apanovich

บัฟเฟอร์เอาต์พุตที่สะอาดช่วยแก้ปัญหาให้ฉันได้ว่าก่อนที่จะใช้แถวรหัสเหล่านี้ในตอนต้นและตอนท้ายของไฟล์ที่สร้างเป็นแถวว่าง
Sharunas Bielskis

8

ใช้โค้ดด้านล่างเพื่อแปลงอาร์เรย์ php เป็น 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);

3

หากโครงสร้างอาร์เรย์ของคุณจะเป็นแบบหลายมิติเสมอไปเราสามารถวนซ้ำองค์ประกอบต่างๆเช่นนี้ได้:

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

นั่นเป็นวิธีหนึ่งที่ทำได้ ... คุณสามารถทำได้ด้วยตนเอง แต่วิธีนี้ง่ายกว่าและเข้าใจและอ่านง่ายกว่า

จากนั้นคุณจะจัดการส่วนหัวของคุณในสิ่งที่ complex857 ทำเพื่อคายไฟล์ออกมา จากนั้นคุณสามารถลบไฟล์โดยใช้การยกเลิกการเชื่อมโยง ()หากคุณไม่ต้องการใช้งานอีกต่อไปหรือคุณสามารถปล่อยทิ้งไว้บนเซิร์ฟเวอร์ได้หากต้องการ


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.