26

我正在尝试创建一个简短的 PHP 脚本,该脚本采用 JSON 字符串,将其转换为 CSV 格式(使用fputcsv),并使该 CSV 可作为下载的 .csv 文件使用。我的想法是tmpfile()不用担心 cronjobs 或磁盘空间不足,但我似乎无法让魔法发生。

这是我的尝试,它是来自PHP 文档的readfile转换示例:

$tmp = tmpfile();
$jsonArray = json_decode( $_POST['json'] );
fputcsv($tmp, $jsonArray);

header('Content-Description: File Transfer');
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename='.basename($tmp));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($tmp));

ob_clean();
flush();
readfile($tmp);

我觉得Content-DispositionContent-Transfer-Encoding标题是错误的,但我不知道如何修复它们。例如,basename($tmp)似乎没有返回任何东西,而且我不确定text/csv传输为二进制编码。同样,echo filesize($tmp)也是空白。有没有办法做我在这里尝试的事情?

[编辑]

**以下是我根据接受的答案编写的工作代码:*

$jsonArray = json_decode( $_POST['json'], true );
$tmpName = tempnam(sys_get_temp_dir(), 'data');
$file = fopen($tmpName, 'w');

fputcsv($file, $jsonArray);
fclose($file);

header('Content-Description: File Transfer');
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename=data.csv');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($tmpName));

ob_clean();
flush();
readfile($tmpName);

unlink($tmpName);
4

4 回答 4

8

请注意,它tmpfile()返回一个文件句柄,但您拥有的所有函数都需要一个文件路径(即字符串),而不是句柄 - 特别是basenamefilesizereadfile. 所以这些函数调用都不能正常工作。也basename不会返回文件扩展名。随便叫什么,即

'Content-Disposition: attachment; filename=data.csv'

正如@Joshua Burns 所说,确保您将数组传递给fputcsv或使用assoc参数。

于 2013-03-13T16:25:38.570 回答
3

json_decode()默认情况下将元素转换为对象而不是数组。fputcsv()期望传递的数据是一个数组。

我建议更改:

$jsonArray = json_decode( $_POST['json'] );

到:

$jsonArray = json_decode( $_POST['json'], True );

看看这是否不能解决您的问题。

在尝试解决诸如此类的问题时,我强烈建议您启用display_errors并设置error_reportingE_ALL查看您是否错过了某种错误:

<?php
error_reporting(E_ALL);
ini_set('display_errors', '1');

// Rest of your code here
于 2013-03-13T16:22:00.907 回答
0

首先,检查此字符串,我将其更改为:

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

我曾经遇到过问题,浏览器兼容性:)

于 2013-03-13T16:25:55.057 回答
0

一个问题是tmpfile()返回文件句柄,而filesize将文件名作为参数。
以下行:

header('Content-Length: ' . filesize($tmp));

可能被评估为:

header('Content-Length: 0');

检查所有对 header() 的调用是否在任何输出发生之前执行。

于 2013-03-13T16:35:55.223 回答