Как загрузить временный файл
Я пытаюсь создать короткий PHP script, который берет строку 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-Disposition
и Content-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);
Ответы
Ответ 1
Обратите внимание, что tmpfile()
возвращает дескриптор файла, но для всех функций вам нужен путь к файлу (т.е. строка), а не дескриптор - особенно basename
, filesize
и readfile
. Поэтому ни один из этих вызовов функций не будет работать корректно. Также basename
также не будет возвращать расширение файла. Просто назовите его, как хотите, т.е.
'Content-Disposition: attachment; filename=data.csv'
Как говорит @Joshua Burns, убедитесь, что вы передаете массив в fputcsv
или используете параметр assoc
.
Ответ 2
json_decode()
по умолчанию переводит элементы в объекты, а не в массивы. fputcsv()
ожидает, что данные передаются как массив.
Я бы рекомендовал изменить:
$jsonArray = json_decode( $_POST['json'] );
To:
$jsonArray = json_decode( $_POST['json'], True );
И посмотрите, не устранит ли эта проблема.
При попытке решить такие проблемы я настоятельно рекомендую включить display_errors
и установить error_reporting
на E_ALL
, чтобы увидеть, есть ли какая-то ошибка, которую вы пропускаете:
<?php
error_reporting(E_ALL);
ini_set('display_errors', '1');
// Rest of your code here
Ответ 3
Во-первых, проверьте эту строку, я бы изменил ее на:
header('Content-Disposition: attachment; filename="'.basename($tmp).'"');
У меня была проблема с ним один раз с совместимостью с браузером:)
Ответ 4
Одна из проблем заключается в том, что tmpfile() возвращает дескриптор файла, а filesize принимает имя файла как параметр.
Следующая строка:
header('Content-Length: ' . filesize($tmp));
вероятно, оценивается как:
header('Content-Length: 0');
Убедитесь, что все вызовы header() выполняются до того, как произойдет какой-либо вывод.