from javascript php ajax angularjs fpdf

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"); }); };

demo plnkr