【问题标题】:PHP - Streaming CSV Files to BrowserPHP - 将 CSV 文件流式传输到浏览器
【发布时间】:2016-08-02 05:05:44
【问题描述】:

我无法将 CSV 文件直接下载到我的浏览器,而无需将文件存储在我的服务器上的某个位置。我找到了一个教程 (https://www.perpetual-beta.org/weblog/php-stream-file-direct.html),但我似乎无法使用它!

这是我的主要功能:

public function exportRecord($id) {
    $contest = (string) $this->getContest($id);
    $entries = (array) $this->getEntries($id);

    $filename = sprintf('%1$s-%2$s-%3$s', str_replace(' ', '', $contest['name']), date('Ymd'), date('His'));
    $output = fopen('php://output', 'w');

    ob_start();

    $header = array(
        'First Name',
        'Last Name',
        'Address',
        'City',
        'State',
        'Zip',
        'Phone',
        'Email',
        'Item Purchased',
        'Partner Name',
        'Partner #',
        'Date Entered',
        'Subscribe'
    );

    fputcsv($output, $header);

    foreach ($entries as $entry) {
        fputcsv($output, $entry);
    }

    $string = ob_get_clean();

    header('Pragma: public');
    header('Expires: 0');
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header('Cache-Control: private', false);
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="' . $filename . '.csv";');
    header('Content-Transfer-Encoding: binary');

    exit($string);
}

我正在调用以下两个函数,它们只是对我的数据库进行查询...

private function getContest($id) {
    $query = sprintf(
        'SELECT name ' .
        'FROM contests ' .
        'WHERE id = %s;',
        $id
    );

    $result = $this->mysql->query($query);
    $response = '';

    if ($result) {
        while ($row = mysqli_fetch_assoc($result)) {
            $response = $row;
        }
    } else {
        echo $this->mysql->error;
    }

    return $response;
}

private function getEntries($id) {
    $query = sprintf(
        'SELECT firstName, ' .
            'lastName, ' .
            'CONCAT(address1, ", ", address2), ' .
            'city, ' .
            'state, ' .
            'zip, ' .
            'phone, ' .
            'email, ' .
            'itemPurchased, ' .
            'partnerName, ' .
            'partnerNum, ' .
            'dateEntered, ' .
            'subscribe ' .
        'FROM entries ' .
        'WHERE contestID = %s;',
        $id
    );

    $result = $this->mysql->query($query);
    $response = '';

    if ($result) {
        while ($row = mysqli_fetch_assoc($result)) {
            $response[] = $row;
        }
    } else {
        echo $this->mysql->error;
    }

    return $response;
}

感谢您提供的任何帮助/建议!这是一个屏幕截图,只是为了让您了解问题所在: 谢谢!

【问题讨论】:

  • 您使用的是什么类型的浏览器,究竟是什么?我最近通过这种方法发现了Safari的问题。
  • 我应该提到这一点!对不起。我正在使用最新版本的 Chrome 和 Firefox。我也在 IE9 上试过。
  • 好的,还有 2 个问题。 1 ) 你试过error_reporting(E_ALL); ini_set('display_errors', '1'); 来检查是否有错误吗? (将其放在顶部)- 2 ) 你得到 any 结果了吗? $string 是否显示任何内容?究竟是什么不工作?
  • 我的 $string 输出看起来不错 - 但它没有作为 CSV 文件下载。 ""名字","姓氏",地址,城市,州,邮编,电话,电子邮件,"购买的物品","合作伙伴名称","合作伙伴 #","输入日期",订阅 Homer,Simpson,"123 Fake Street, Apartment B",Springfield,PA,12345,215-666-9876,hjsimpson@duff.com,JA12345,"Some Partner",987654321,"2015-01-01 00:00:00", Steve,French ,"123 Mustard Tiger Dr,",Springfield,CA,76543,215-777-9876,stevefrench@trailerparkboys.com,JA12345,"一些合作伙伴",987654321,"2015-01-01 00:00:00","
  • 你能帮我添加header("Content-Length: " . filesize($string));吗?我听说这句话在某些情况下会有所不同。

标签: php csv download export-to-csv


【解决方案1】:

您在 Jonathan Hollin 的示例中遗漏了几个步骤。您需要开始输出缓冲,您必须写出缓冲区并正确设置标题。这可能需要一些修改,但我尝试将示例调整为您在此问题中提供的内容:

<?php
public function exportRecord($id) {
    $contest = (array) $this->getContest($id);
    $entries = (array) $this->getEntries($id);

    $filename = sprintf('%1$s-%2$s-%3$s', str_replace(' ', '', $contest['name']), date('Ymd'), date('His'));

    $header = array(
        'First Name',
        'Last Name',
        'Address',
        'City',
        'State',
        'Zip',
        'Phone',
        'Email',
        'Item Purchased',
        'Partner Name',
        'Partner #',
        'Date Entered',
        'Subscribe'
    );

    export_csv($header, $entries, $filename);
}

private function export_csv($header, $data, $filename) {
    // No point in creating the export file on the file-system. We'll stream
    // it straight to the browser. Much nicer.

    // Open the output stream
    $fh = fopen('php://output', 'w');

    // Start output buffering (to capture stream contents)
    ob_start();

    // CSV Header
    if(is_array($header)){
        fputcsv($fh, $header);
    }

    // CSV Data
    foreach ($data as $row) {
        fputcsv($fh, $row);
    }

    // Get the contents of the output buffer
    $string = ob_get_clean();

    // Output CSV-specific headers
    header('Pragma: public');
    header('Expires: 0');
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header('Cache-Control: private', false);
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="' . $filename . '.csv";');
    header('Content-Transfer-Encoding: binary');

    // Stream the CSV data
    exit($string);
}

【讨论】:

  • 感谢您的建议!我更新了我的代码并在 Chrome 和 Firefox 中进行了尝试......它仍然无法正常工作。检查页面时,我的网络选项卡中有输出 ($string)。我上传了一张图片。
  • 确保所有标题都已设置(尤其是 Content-Disposition 和 Content-Type)。我再次对此进行了测试,并且在 csv 输出流方面一切看起来都很好。看起来您正在将数组转换为字符串,这超出了此问题的范围。我建议创建一个简化的样本以更清楚地说明问题。 [链接]css-tricks.com/reduced-test-cases
【解决方案2】:

我最终用 JS 来做这件事。

                    } else if (action == 'export') {
                    if (result.data !== false) {
                        var data = encodeURIComponent(result.data);
                        var contest = result.contest.trim();
                        var filename = contest + '.csv';
                        var dataUri = 'data:text/csv;charset=utf-8,' + data;
                        var link = document.createElement('a');

                        link.setAttribute('href', dataUri);
                        link.setAttribute('download', filename);
                        document.body.appendChild(link);
                        link.click();

                        showMessage('Export successfully created!', 'success');
                    } else {
                        showMessage('There are no entries for this contest! Nothing to export...', 'error');
                    }
                }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-11
    • 2013-04-18
    • 2010-09-14
    • 1970-01-01
    • 2012-02-17
    • 2013-05-26
    • 2015-06-08
    • 2015-04-21
    相关资源
    最近更新 更多