Загрузить в браузере с помощью ajax request
Я работаю с AngularJS, и я пытаюсь создать PDF файл в php. Это то, что у меня есть в моем контроллере .js:
$scope.downloadPDF = function(){
$http.post('/download-pdf', { fid: $routeParams.fid })
.success(function(data, status, headers, config){
console.log("success");
})
.error(function(data, status, headers, config){
console.log("error");
});
};
В моем php файле у меня есть следующее, чтобы создать PDF файл с библиотекой FPDF:
function download_pdf()
{
$id = $_POST['fid'];
$pdf = new FPDF();
$pdf->AddPage();
$pdf->SetFont('Arial','B',16);
$pdf->Cell(40,10,'Hello World!');
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename=' . $id . '.pdf');
$pdf->Output('Order123.pdf', 'D');
}
Но запрос отвечает на это вместо того, чтобы открывать диалог сохранения, чтобы сохранить мой pdf.
% PDF-1.3 3 0 obj < > endobj 4 0 obj < > поток x3Rðâ2Ð35W (Сr QÐw3T04Ó30PISp Ez * [¤ (hx¤æää + çå¤ (J * dÔ7W endstream endobj 1 0 obj < endobj 5 0 obj < endobj 2 0 obj & Л; < /ProcSet [/PDF/Text/ImageB/ImageC/ImageI] /Font < /F 1 5 0 R > /XObject < → endobj 6 0 obj & Л; < /Производитель (FPDF 1.7) /CreationDate (D: 20150611094522) > endobj 7 0 obj & Л; < /Тип/Каталог /Страницы 1 0 R > endobj Xref 0 8 0000000000 65535 f 0000000228 00000 n 0000000416 00000 n 0000000009 00000 n 0000000087 00000 n 0000000315 00000 n 0000000520 00000 n 0000000595 00000 n прицеп & Л; < /Размер 8 /Корень 7 0 R /Инфо 6 0 R > startxref 644 %% EOF
Я использовал библиотеку PHPExcel, и это сработало:
$objWriter = PHPExcel_IOFactory::createWriter($ea, 'Excel2007');
// We'll be outputting an excel file
header('Content-type: application/vnd.ms-excel');
// It will be called Submission on [date_now].xls
header('Content-Disposition: attachment; filename="' . $filename . '.xls' . '"');
// Write file to the browser
$objWriter->save('php://output');
Теперь, как я могу сделать эту работу для моего PDF?
UPDATE:
Я редактировал свой код:
$pdf = new FPDF();
$pdf->AddPage();
$pdf->SetFont('Arial','B',16);
$pdf->Cell(40,10,'Hello World!');
$filename = DXS_VKGROUP_PLUGIN_LIB_DIR . 'uploads/' . $_POST['fid'] . '.pdf';
$pdf->Output($filename, 'F'); // Save file locally
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Content-Type: application-download');
header('Content-Length: ' . filesize($filename));
header('Content-Transfer-Encoding: binary');
header('Content-Disposition: attachment; filename="' . $filename . '"');
$handle = fopen($filename, 'rb');
fpassthru($handle);
fclose($handle);
Файл сохраняется локально, но загрузка не работает. Он не получает моего диалога, чтобы сохранить PDF. Что я делаю неправильно?
ОБНОВЛЕНИЕ 2
Теперь я попытался изменить application-download
в application/pdf
. Он сохраняет файл локально, но я не получаю диалоговое окно загрузки.
Ответ выглядит следующим образом (когда я проверяю сеть в Chrome):
% PDF-1.3 3 0 obj < > endobj 4 0 obj < > поток x3Rðâ2Ð35W (Сr QÐw3T04Ó30PISp Ez * [¤ (hx¤æää + çå¤ (J * dÔ7W endstream endobj 1 0 obj < endobj 5 0 obj < endobj 2 0 obj & Л; < /ProcSet [/PDF/Text/ImageB/ImageC/ImageI] /Font < /F 1 5 0 R > /XObject < → endobj 6 0 obj & Л; < /Производитель (FPDF 1.7) /CreationDate (D: 20150617090832) > endobj 7 0 obj & Л; < /Тип/Каталог /Страницы 1 0 R > endobj Xref 0 8 0000000000 65535 f 0000000228 00000 n 0000000416 00000 n 0000000009 00000 n 0000000087 00000 n 0000000315 00000 n 0000000520 00000 n 0000000595 00000 n прицеп & Л; < /Размер 8 /Корень 7 0 R /Инфо 6 0 R > startxref 644 %% EOF
Ответы
Ответ 1
ОБНОВЛЕНИЕ
Метод использования FileSaver.js также не работает, похоже, не существует способа принудительно вызвать собственный диалог "Сохранить как" с помощью JavaScript, но единственным исключением является saveAs execCommand
для IE. Проверить Работает ли execCommand SaveAs в Firefox?
Включить FileSaver.js как зависимость в вашем проекте
Измените функцию downloadPDF
следующим образом
$scope.downloadPDF = function() {
$http.post('/download-pdf', {
fid: $routeParams.fid
}, {
responseType: 'arraybuffer'
})
.success(function(data, status, headers, config) {
// Convert response data to Blob
var file = new Blob([data], {
type: 'application/pdf'
});
// Call the File Saver method to save the above Blob,this will show Save As dialog
saveAs(file, "test.pdf");
})
.error(function(data, status, headers, config) {
console.log("error");
});
};
Объект Blob
будет работать в большинстве современных браузеров, но существует ограниченная поддержка IE < 10, проверьте https://github.com/eligrey/FileSaver.js#supported-browsers для polyfills
Также удалите заголовки Content-Disposition: attachment
и Content-Type: application-download
, так как мы не хотим, чтобы браузер обрабатывал процесс загрузки
Вот рабочая демонстрация http://plnkr.co/edit/9r1tehQ94t5vkqZfZuQC?p=preview, она показывает запрос GET для PDF
Ответ 2
Позвольте мне предложить вам одну вещь.
Только AJAX вы не можете скачать любой файл. Вам нужно сначала создать ZIP файл с помощью ajax-вызова, и после этого, получив этот путь к файлу, вы должны открыть этот файл с помощью любой команды.
Вот один пример, который работает для меня::)
$http.post('www.abc.com/zipcreate', {'id': id}).then(function (zipurl) {
$window.location = zipurl;
});
Конечно, это работает. Попробуйте один раз.:)
EDIT:
Или вы можете использовать
$window.location = 'abc.com/link';
в 'abc.com/link':
используйте ниже код:
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=".$name);
header("Pragma: no-cache");
header("Expires: 0");
readfile($file);
exit;
Вы получите свой файл в списке загрузки.
Ответ 3
В соответствии с документацией вы можете установить второй параметр D
:
$pdf->Output('Order123.pdf', 'D');
Если вы хотите обрабатывать все детали самостоятельно с помощью сохраненного файла, так я представил PDF файлы для браузера для загрузки с PHP:
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Content-Type: application-download');
header('Content-Length: ' . filesize('file.pdf'));
header('Content-Transfer-Encoding: binary');
header('Content-Disposition: attachment; filename="file.pdf"');
$handle = fopen('file.pdf', 'rb');
fpassthru($handle);
fclose($handle);
Update:
Убедитесь, что файл PDF действительно выполнен. Имеет ли процесс веб-сервера доступ на запись к этому пути? Правильно ли включен FPDF? Я сделал это на тестовой виртуальной машине и представил файл 1.pdf
для загрузки, который открылся и содержал "Hello World!":
<?php
require('/var/www/html/fpdf17/fpdf.php');
$_POST = array('fid' => '1');
$pdf = new FPDF();
$pdf->AddPage();
$pdf->SetFont('Arial', 'B', 16);
$pdf->Cell(40, 10, 'Hello World!');
$filename = '/tmp/' . $_POST['fid'] . '.pdf';
$pdf->Output($filename, 'F'); // Save file locally
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Content-Type: application-download');
header('Content-Length: ' . filesize($filename));
header('Content-Transfer-Encoding: binary');
header('Content-Disposition: attachment; filename="' . basename($filename) . '"');
$handle = fopen($filename, 'rb');
fpassthru($handle);
fclose($handle);
unlink($filename);
?>
Ответ 4
С ajax это невозможно.
Вместо этого вы можете сделать это, нажав ваше действие через форму javascript.
например, document.getElementById(formID).action= actionName
.
document.getElementById(formID).submit();
Здесь formID - это ваш идентификатор формы, а actionName
будет '/download-pdf'
, как вы указали.
В вашем классе действий - установите заголовки ответов
getResponse().setContentType("application/pdf");
getResponse().setHeader("Content-Disposition", " attachment; filename= "+"pdffile.pdf");
Это приведет к загрузке файла с именем файла = pdffile.pdf.
Ответ 5
Это невозможно с (только) AJAX.
Существует два основных метода, которые вы можете использовать здесь: оба без использования JavaScript для фактической загрузки. Общая идея заключается в том, что вы перенаправляете браузер на ресурс, который предоставит желаемый документ; если вы перенаправляетесь на скачивание, он не покидает страницу, но вместо этого отображает диалог "Сохранить". Аналогичная тема обсуждается в этом вопросе.
Запрос GET
location.href = '/download-pdf?fid=' + encodeURIComponent($routeParams.fid);
Откорректируйте серверную сторону script для использования $_GET['fid']
.
Запрос POST
Сервер создает ресурс и отвечает URL-адресом, в котором можно найти ресурс:
$http.post('/download-pdf', { fid: $routeParams.fid })
.success(function(data, status, headers, config) {
// follow location provided by server
location.href = data.redirect_url;
console.log("success");
})
.error(function(data, status, headers, config){
console.log("error");
});
Отрегулируйте серверную сторону script, чтобы вернуть соответствующий ответ JSON после создания нового ресурса.
Ответ 6
header('Content-Type: application/octet-stream');
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=\"" . basename($file_url) . "\"");
Или используя BLOB:
$scope.downloadPDF = function() {
$http.post('/download-pdf', {
fid: $routeParams.fid
}, {
responseType: 'arraybuffer'
})
.success(function(data, status, headers, config) {
var file = new Blob([data], {
type: 'application/pdf'
});
var url = URL.createObjectURL(blob);
window.location.href = url;
})
.error(function(data, status, headers, config) {
console.log("error");
});
};
Или создайте элемент с атрибутом download
:
$scope.downloadPDF = function() {
$http.get('http://46.101.139.188/demo.pdf', {
}, {
responseType: 'arraybuffer'
})
.success(function(data, status, headers, config) {
var file = new Blob([data], {
type: 'application/pdf'
});
var url = URL.createObjectURL(file);
var a = document.createElement('a');
a.setAttribute('download', 'download');
a.setAttribute('href', url);
var event = new MouseEvent('click', {
'view': window,
'bubbles': true,
'cancelable': true
});
a.dispatchEvent(event);
})
.error(function(data, status, headers, config) {
console.log("error");
});
};
демонстрация plnkr
Ответ 7
Отправьте документ в указанное место назначения: браузер, файл или строка. В случае браузера можно использовать подключаемый модуль (если он есть) или загрузить (диалоговое окно "Сохранить как" ).
Сначала метод вызывает Close(), чтобы завершить документ.
Параметры
имя:
Имя файла. Если не указано, документ будет отправлен в браузер (пункт назначения I) с именем doc.pdf.
Dest
Назначение, куда отправить документ. Он может принимать одно из следующих значений:
- I: отправьте файл встроенным в браузер. Плагин используется, если
доступный. Имя, указанное именем, используется, когда вы выбираете "Сохранить
как "на ссылке, генерирующей PDF.
- D: отправить в браузер и принудительно загрузить файл с указанным именем
по имени.
- F: сохранить в локальный файл с именем, указанным по имени (может
укажите путь).
- S: возвращает документ как строку. имя игнорируется.