Generación de archivos con JavaScript

Al crear una aplicación web, a menudo es necesario dar a los usuarios la posibilidad de descargar una parte de los datos como un archivo. Podría ser una copia de seguridad de los ajustes de configuración, informes u otra información que se genera dinámicamente.

La solución habitual a este problema sería tener un script de exportación dedicado que seleccione de una base de datos y cree el archivo que necesita. Sin embargo, como demostraremos en este breve tutorial, hay otra forma.

Crearemos un complemento jQuery que, combinado con un simple script php, puede generar todo tipo de archivo de texto y ponerlo a disposición para su descarga. Iniciará la descarga desde su front-end de JavaScript proporcionando solo el contenido del archivo y dejará el resto para el complemento.

El HTML

Comenzaremos por establecer una página HTML simple con un área de texto y un botón de descarga, para que podamos demostrar el funcionamiento del complemento.

index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />

        <title>Generating files with JS &amp; PHP | Tutorialzine Demo</title>

        <!-- Our CSS stylesheet file -->
        <link rel="stylesheet" href="assets/css/styles.css" />

        <!--[if lt IE 9]>
          <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
        <![endif]-->
    </head>

    <body>

        <header>
            <h1>Generating Files with JavaScript</h1>
            <h2><a href="https://tutorialzine.com/2011/05/generating-files-javascript-php/">&laquo; Read and download on Tutorialzine</a></h2>
        </header>

        <form action="./" method="post">
            <textarea></textarea>
            <a href="#" class="blueButton" id="download">Download</a>
        </form>

        <footer>Another cool example: <a href="#" id="downloadPage">download this page.</a> <b>To download the source code, visit <a href="https://tutorialzine.com/2011/05/generating-files-javascript-php/">Tutorialzine.com</a></b></footer>

        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js"></script>
        <script src="assets/js/jquery.generateFile.js"></script>
        <script src="assets/js/script.js"></script>

    </body>
</html>

La página usa el tipo de documento HTML5, ya que estamos usando algunas de las etiquetas definidas por el estándar. Para que funcione en IE, también debemos incluir el script de habilitación de HTML5 en la sección principal.

Antes de la etiqueta del cuerpo de cierre, estamos agregando la biblioteca jQuery, el complemento generateFile escribiremos en un momento, y el script.js archivo que escucha eventos y activa las descargas de archivos.

El PHP

Como probablemente sepa, no es posible generar archivos solo con JavaScript. Existen diferentes soluciones (algunas de ellas incluso se basan en Flash), pero el uso de un script PHP genérico en el backend proporciona un mejor control y facilidad de uso (sin mencionar que funciona en todos los principales navegadores).

Puede ver el script genérico de generación de archivos a continuación:

descargar.php

if(empty($_POST['filename']) || empty($_POST['content'])){
    exit;
}

// Sanitizing the filename:
$filename = preg_replace('/[^a-z0-9\-\_\.]/i','',$_POST['filename']);

// Outputting headers:
header("Cache-Control: ");
header("Content-type: text/plain");
header('Content-Disposition: attachment; filename="'.$filename.'"');

echo $_POST['content'];

Lo que hace este script PHP es simplemente agregar algunos encabezados encima de una declaración de eco. El complemento que estamos creando debe pasar dos parámetros junto con la solicitud POST:filename y contenido . La secuencia de comandos imprimirá el contenido del archivo, mientras establece tres encabezados que forzarán a que aparezca el cuadro de descarga del archivo (en lugar de que su navegador simplemente lo abra).

Para usar el complemento, debe cargar este archivo en algún lugar de su servidor y pasar su URL al complemento que codificaremos a continuación.

JQuery

Como vio en la sección anterior, nuestro complemento debe enviar una solicitud POST a download.php . La elección natural para realizar una solicitud sería mediante AJAX. Sin embargo, hay una deficiencia en el uso de este método:no activa la aparición del cuadro de diálogo de descarga de archivos.

Así que lo que necesitamos es un poco más de la vieja escuela. Crearemos dinámicamente un iframe oculto y escribiremos un formulario en él, que luego enviaremos a través de POST. El atributo de acción del formulario apunta a download.php , por lo que aparecerá el cuadro de diálogo de descarga de archivos, exactamente como lo necesitamos.

Ahora establezcamos el código jQuery que hace esto:

activos/jquery.generateFile.js

(function($){

    // Creating a jQuery plugin:

    $.generateFile = function(options){

        options = options || {};

        if(!options.script || !options.filename || !options.content){
            throw new Error("Please enter all the required config options!");
        }

        // Creating a 1 by 1 px invisible iframe:

        var iframe = $('<iframe>',{
            width:1,
            height:1,
            frameborder:0,
            css:{
                display:'none'
            }
        }).appendTo('body');

        var formHTML = '<form action="" method="post">'+
            '<input type="hidden" name="filename" />'+
            '<input type="hidden" name="content" />'+
            '</form>';

        // Giving IE a chance to build the DOM in
        // the iframe with a short timeout:

        setTimeout(function(){

            // The body element of the iframe document:

            var body = (iframe.prop('contentDocument') !== undefined) ?
                            iframe.prop('contentDocument').body :
                            iframe.prop('document').body;   // IE

            body = $(body);

            // Adding the form to the body:
            body.html(formHTML);

            var form = body.find('form');

            form.attr('action',options.script);
            form.find('input[name=filename]').val(options.filename);
            form.find('input[name=content]').val(options.content);

            // Submitting the form to download.php. This will
            // cause the file download dialog box to appear.

            form.submit();
        },50);
    };

})(jQuery);

En menos de 50 líneas (sin comentarios), el fragmento anterior hace lo que necesitamos. Crea un iframe oculto con un formulario dentro.

Observe el setTimeout() función. Sin él no podemos acceder al elemento de documento del iframe en Internet Explorer. De esta manera, le estamos dando tiempo para construir el DOM y ponerlo a nuestra disposición.

Y aquí está cómo usar este complemento:

activos/script.js

$(document).ready(function(){

    $('#download').click(function(e){

        $.generateFile({
            filename    : 'export.txt',
            content     : $('textarea').val(),
            script      : 'download.php'
        });

        e.preventDefault();
    });

    $('#downloadPage').click(function(e){

        $.generateFile({
            filename    : 'page.html',
            content     : $('html').html(),
            script      : 'download.php'
        });

        e.preventDefault();
    });

});

Al llamar $.generateFile , debe pasar el nombre del archivo (debe ser algo descriptivo), su contenido de texto y la ruta a download.php. Como puede ver en el ejemplo anterior, podemos generar cualquier tipo de archivo, siempre que sea de texto.

¡Con esto, nuestro complemento simple está completo!

Conclusión

Puede usar este código para agregar funciones de exportación a su aplicación web o mejorar ciertas áreas de su sitio con la funcionalidad de descarga. Incluso es posible generar archivos doc y hojas de cálculo si sigue los formatos XML de Microsoft Office. La mejor parte es que todo se hace con JavaScript y puedes combinar fácilmente diferentes fuentes de datos.