为什么PHP在fclose()之后继续输出到CSV文件?

时间:2014-04-14 09:34:06

标签: php fclose

在网页上,我使用以下代码将一些数据写入CSV文件,最后以fclose()结束;

header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename='.$filename);
$out = fopen('php://output', 'w');
fputcsv($out, $cvs_cols);
fclose($out);
echo "HELLO WORLD"; // sneaks into CSV!?

为什么" HELLO WORLD"当它已经fclose()时进入CSV下载文件?我想输出要在浏览器中显示的页面的其余HTML。我怎么能这样做?

4 个答案:

答案 0 :(得分:5)

1个HTTP请求后跟随1个响应。您无法同时发送内容类型text/csv和内容类型text/html(可能是SPDY,但不是纯HTTP)。

fclose关闭文件描述符,但不关闭浏览器的输出。

您还应该设置Content-Length标题并输入文件大小。

Mark Ba​​ker已经在评论中提出了最重要的观点:

echo并写信给php://output会将内容放入同一个信息流:STDOUT。其他选择是将CSV写入内存(但如果您不使用它则无意义)或文件。详细了解这些流:http://www.php.net/manual/en/features.commandline.io-streams.php

可能的解决方案:

您需要2个HTTP请求。 1对于下载,另一个用于HTML。最流行的方式是首先使用HTML响应并放入类似

的内容
<meta http-equiv="refresh"
      content="3; URL=http://yourserver.com/download.php?id=pdf&amp;id=123" />

3秒后开始下载。

答案 1 :(得分:4)

(尚未)“CSV文件”。

您正在做的是将数据流发送到客户端,并告诉客户端此流的Content-Type text/csvfilename $filename。然后,客户端可以选择将其另存为CSV文件,或者只在浏览器中显示。

此代码:

$out = fopen('php://output', 'w');
fputcsv($out, $cvs_cols);
fclose($out);

有效地执行echo $cvs_cols会做的事情(用一些额外的东西来格式化csv输出)。

因此,当调用echo "HELLO WORLD";时,它会在与$cvs_cols变量的内容相同的数据流中发送。

当您致电fopen('php://output', 'w')时,您正在为php://output创建第二个文件句柄,因为默认情况下会创建一个文件句柄以从echo等调用输出。所以当您调用{{1}时你只关闭第二个文件句柄。

答案 2 :(得分:1)

使用

ob_clean():ob_clean - 清理(擦除)输出缓冲区

flush():flush - 刷新输出缓冲区(flush

ob_start();

header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename='.$filename);
$out = fopen('php://output', 'w');
fputcsv($out, $cvs_cols);
fclose($out);

ob_end_clean();   //    the buffer and never prints or returns anything.


echo "HELLO WORLD"; // sneaks into CSV!?

答案 3 :(得分:0)

这里有一个非常老的线程,但是为了解决这个问题,我只添加了一个简单的exit();。命令。因此,一个按钮使用查询字符串'action = export_csv'调用同一页面,然后使用exit()运行该操作。在最后一行,希望能有所帮助。

<a href="?action=export_csv">Export CSV</a>

然后页面上的“操作”为:

if(isset($_GET['action']) && $_GET['action']=='export_csv'){
    // output headers so that the file is downloaded rather than displayed
    header('Content-Type: text/csv; charset=utf-8');
    header('Content-Disposition: attachment; filename=email-responses.csv');

    // create a file pointer connected to the output stream
    $output = fopen('php://output', 'w');

    // output the column headings
    fputcsv($output, array('Email address'));

    $db = new PDO('mysql:host=hostname_mysql;dbname=database_mysql;charset=UTF8', username_mysql, password_mysql);
    $query = "SELECT XXX FROM XXXX";
    $result = $db->query($query);
    $data = $result->fetchAll(PDO::FETCH_ASSOC);
    // loop over the rows, outputting them
    foreach($data as $row){
        fputcsv($output, $row);
    }
    fclose($output);
    exit();
}