javascript download file from url
Descargar en navegador con solicitud ajax (7)
Estoy trabajando con AngularJS y estoy tratando de generar un PDF en php. Esto es lo que tengo en mi controller.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");
});
};
En mi archivo php tengo lo siguiente para crear un PDF con la biblioteca 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'');
}
Pero la solicitud está respondiendo esto en lugar de abrir un diálogo de guardar para guardar mi pdf.
% PDF-1.3 3 0 obj <> endobj 4 0 obj <> secuencia x3Rðâ2Ð35W (çr QÐw3T04Ó30PISp êZ * [¤ (hx¤æää + çå¤ (j * dÔ7W endstream endobj 1 0 obj <endobj 5 0 obj <endobj 2 0 obj << / ProcSet [/ PDF / Text / ImageB / ImageC / ImageI] / Font << / F1 5 0 R> / XObject <<>> endobj 6 0 obj << / Producer (FPDF 1.7) / CreationDate (D: 20150611094522 )> endobj 7 0 obj << / Tipo / Catálogo / Páginas 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 remolque << / Tamaño 8 / Root 7 0 R / Info 6 0 R> startxref 644 %% EOF
He usado la biblioteca de PHPExcel y esto funcionó:
$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'');
¿Ahora cómo puedo hacer que esto funcione para mi PDF?
ACTUALIZAR:
He editado mi código a esto:
$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);
El archivo se guarda localmente pero la descarga no funciona. No tengo mi diálogo para guardar el pdf. ¿Qué estoy haciendo mal?
ACTUALIZACIÓN 2
Ahora he intentado cambiar application-download
de la application/pdf
en la application/pdf
. Guarda el archivo localmente pero no aparece el cuadro de diálogo de descarga.
La respuesta se ve así (cuando reviso Network in Chrome):
% PDF-1.3 3 0 obj <> endobj 4 0 obj <> secuencia x3Rðâ2Ð35W (çr QÐw3T04Ó30PISp êZ * [¤ (hx¤æää + çå¤ (j * dÔ7W endstream endobj 1 0 obj <endobj 5 0 obj <endobj 2 0 obj << / ProcSet [/ PDF / Text / ImageB / ImageC / ImageI] / Font << / F1 5 0 R> / XObject <<>> endobj 6 0 obj << / Producer (FPDF 1.7) / CreationDate (D: 20150617090832 )> endobj 7 0 obj << / Tipo / Catálogo / Páginas 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 remolque << / Tamaño 8 / Root 7 0 R / Info 6 0 R> startxref 644 %% EOF
Con ajax no es posible.
En cambio, lo que puedes hacer es golpear tu acción mediante el envío de formularios de JavaScript.
por ejemplo, document.getElementById(formID).action= actionName
.
document.getElementById(formID).submit();
Aquí formID es la identificación de su formulario y actionName
será ''/download-pdf''
como usted ha especificado.
En tu clase de acción: establece encabezados de respuesta
getResponse().setContentType("application/pdf");
getResponse().setHeader("Content-Disposition", " attachment; filename= "+"pdffile.pdf");
Esto hará que su archivo se descargue con filename = pdffile.pdf.
Déjame sugerirte una cosa.
Solo con AJAX, no puedes descargar ningún archivo. Primero debe crear un archivo .zip con una llamada ajax y luego de obtener esa ruta de archivo debe abrir ese archivo con cualquier comando.
Aquí un ejemplo que funciona para mí: :)
$http.post(''www.abc.com/zipcreate'', {''id'': id}).then(function (zipurl) {
$window.location = zipurl;
});
Sin duda, funciona. Trata una vez. :)
EDITAR:
O puedes usar
$window.location = ''abc.com/link'';
en ''abc.com/link'': use el siguiente código:
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=".$name);
header("Pragma: no-cache");
header("Expires: 0");
readfile($file);
exit;
Obtendrá su archivo en la lista de descargas.
De acuerdo con la documentation , puede establecer el 2do parámetro como D
:
$pdf->Output(''Order123.pdf'', ''D'');
Si quiere manejar todos los detalles usted mismo usando un archivo guardado, así es como he presentado los archivos PDF al navegador para su descarga desde 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);
Actualizar:
Por favor, verifique que el archivo PDF se está realizando en realidad. ¿El proceso del servidor web tiene acceso de escritura a esa ruta? ¿Se está incluyendo FPDF correctamente? Hice esto en una máquina virtual de prueba y presentó un archivo 1.pdf
para su descarga, que se abrió y contenía "¡Hola mundo!":
<?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);
?>
Envíe el documento a un destino determinado: navegador, archivo o cadena. En el caso de un navegador, el complemento se puede usar (si está presente) o se puede forzar una descarga (cuadro de diálogo "Guardar como").
El método primero llama a Close () si es necesario para terminar el documento.
Parámetros
nombre:
El nombre del archivo. Si no se especifica, el documento se enviará al navegador (destino I) con el nombre doc.pdf.
dest
Destino donde enviar el documento. Puede tomar uno de los siguientes valores:
- I: enviar el archivo en línea al navegador. El complemento se usa si está disponible. El nombre dado por nombre se usa cuando se selecciona la opción "Guardar como" en el enlace que genera el PDF.
- D: enviar al navegador y forzar la descarga de un archivo con el nombre dado por nombre.
- F: guardar en un archivo local con el nombre indicado por nombre (puede incluir una ruta).
- S: devuelve el documento como una cadena. nombre es ignorado
Esto no es posible con (solo) AJAX.
Aquí puede usar dos técnicas principales, ambas sin usar JavaScript para realizar la descarga real. La idea general es que redirija el navegador a un recurso que proporcionará el documento deseado; si está redirigiendo a una descarga, no abandonará la página, sino que mostrará el cuadro de diálogo Guardar. Un tema similar se discute en esta pregunta .
GET Request
location.href = ''/download-pdf?fid='' + encodeURIComponent($routeParams.fid);
Ajuste su script del lado del servidor para usar $_GET[''fid'']
.
Solicitud POST
El servidor crea un recurso y responde con una URL donde se puede encontrar el recurso:
$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");
});
Ajuste la secuencia de comandos del lado del servidor para devolver una respuesta JSON apropiada después de crear el nuevo recurso.
ACTUALIZAR
El método de uso de FileSaver.js tampoco funciona, parece que no hay forma de invocar forzosamente el diálogo Guardar como nativo a través de JavaScript solo, con la excepción de saveAs execCommand
para IE. Comprobar ¿ExecCommand SaveAs funciona en Firefox?
Incluye github.com/eligrey/FileSaver.js como dependencia en tu proyecto
Cambie la función downloadPDF
siguiente manera
$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");
});
};
El objeto Blob
funcionará en el navegador más moderno, pero hay soporte limitado para IE <10, compruebe https://github.com/eligrey/FileSaver.js#supported-browsers para detectar polyfills
Elimine también Content-Disposition: attachment
y Content-Type: application-download
encabezados de Content-Type: application-download
ya que no queremos que el navegador gestione de forma nativa el proceso de descarga.
Aquí hay una demostración funcional http://plnkr.co/edit/9r1tehQ94t5vkqZfZuQC?p=preview , muestra la solicitud GET a un PDF
header(''Content-Type: application/octet-stream'');
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=/"" . basename($file_url) . "/"");
O usando 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");
});
};
O crea un elemento con atributo de 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");
});
};