Mini formulario de subida de archivos en AJAX

En este tutorial vamos a crear un formulario de subida de archivos en AJAX, que permitirá a los visitantes subir archivos desde sus navegadores arrastrándolos y soltándolos al elemento, o bién, seleccionándolos de forma individual. Para este propósito, vamos a combinar el poderoso jQuery File Upload Plugin con la ordenada jQuery Knob para desarrollar una interfaz CSS3/JS pulida y elegante.

El HTML

Como de costumbre, vamos a empezar con el documento básico de HTML5:

<!DOCTYPE html>
<html>

    <head>
        <meta charset="utf-8"/>
        <title>Mini Ajax File Upload Form</title>

        <!-- Google web fonts -->
        <link href="http://fonts.googleapis.com/css?family=PT+Sans+Narrow:400,700" rel='stylesheet' />

        <!-- The main CSS file -->
        <link href="assets/css/style.css" rel="stylesheet" />
    </head>

    <body>

        <form id="upload" method="post" action="upload.php" enctype="multipart/form-data">
            <div id="drop">
                Drop Here

                <a>Browse</a>
                <input type="file" name="upl" multiple />
            </div>

            <ul>
                <!-- The file uploads will be shown here -->
            </ul>

        </form>

        <!-- JavaScript Includes -->
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
        <script src="assets/js/jquery.knob.js"></script>

        <!-- jQuery File Upload Dependencies -->
        <script src="assets/js/jquery.ui.widget.js"></script>
        <script src="assets/js/jquery.iframe-transport.js"></script>
        <script src="assets/js/jquery.fileupload.js"></script>

        <!-- Our main JS file -->
        <script src="assets/js/script.js"></script>

    </body>
</html>

En el head del documento, he incluido dos fuentes de Google Web Fonts, y antes del cierre del body, he incluido una serie de librerías de JavaScript. Estas son, la librería jQuery, el plugin jQuery Knob y las dependencias para el jQuery File Upload Plugin.

El elemento principal de la página es el formulario #upload. Dentro está el div #drop (que soporta drag&drop) y una lista desordenada. Esta lista tendrá un elemento li para cada uno de los archivos transferidos. Puedes ver el markup generado por la subida de un fichero a continuación:

<li class="working">
    <input type="text" value="0" data-width="48" data-height="48" data-fgColor="#0788a5" data-readOnly="1" data-bgColor="#3e4043" />
    <p>Sunset.jpg <i>145 KB</i></p>
    <span></span>
</li>

El input del fragmento anterior se oculta con CSS. Su único propósito es inicializar el plugin jQuery Knob, que mostrará un precio canvas basado en el control knob. El input contiene un número de atributos data- * que modifican la apariencia del knob. Más tarde, cuando recibamos el progreso de la subida de archivos, vamos a actualizar el valor de este input, lo que hará que el knob se vuelva a regenerar. El span mantiene el icono a la derecha; esto puede ser una marca de verificación o una cruz roja.

El jQuery

Un visitante tiene dos maneras de subir un archivo mediante este formulario:

  • Soltándolos en el div #drop (válido en todos los navegadores excepto IE)
  • Haciendo clic en el botón Examinar. Esto simulará un clic en el input oculto, que hará que muestre la ventana de exploración de archivos del sistema. Observa que el file input tiene el parámetro múltiple, lo permite subir más de un archivo seleccionado en un momento dado

El comportamiento por defecto del plugin es colocar los archivos en una cola, pero vamos a hacer que los archivos se carguen automáticamente cuando se suelten/seleccionen, lo que hará que la experiencia sea más sencilla. Aqui está el JS utilizado:

assets/js/script.js

$(function(){

    var ul = $('#upload ul');

    $('#drop a').click(function(){
        // Simulate a click on the file input button
        // to show the file browser dialog
        $(this).parent().find('input').click();
    });

    // Initialize the jQuery File Upload plugin
    $('#upload').fileupload({

        // This element will accept file drag/drop uploading
        dropZone: $('#drop'),

        // This function is called when a file is added to the queue;
        // either via the browse button, or via drag/drop:
        add: function (e, data) {

            var tpl = $('<li class="working"><input type="text" value="0" data-width="48" data-height="48"'+
                ' data-fgColor="#0788a5" data-readOnly="1" data-bgColor="#3e4043" /><p></p><span></span></li>');

            // Append the file name and file size
            tpl.find('p').text(data.files[0].name)
                         .append('<i>' + formatFileSize(data.files[0].size) + '</i>');

            // Add the HTML to the UL element
            data.context = tpl.appendTo(ul);

            // Initialize the knob plugin
            tpl.find('input').knob();

            // Listen for clicks on the cancel icon
            tpl.find('span').click(function(){

                if(tpl.hasClass('working')){
                    jqXHR.abort();
                }

                tpl.fadeOut(function(){
                    tpl.remove();
                });

            });

            // Automatically upload the file once it is added to the queue
            var jqXHR = data.submit();
        },

        progress: function(e, data){

            // Calculate the completion percentage of the upload
            var progress = parseInt(data.loaded / data.total * 100, 10);

            // Update the hidden input field and trigger a change
            // so that the jQuery knob plugin knows to update the dial
            data.context.find('input').val(progress).change();

            if(progress == 100){
                data.context.removeClass('working');
            }
        },

        fail:function(e, data){
            // Something has gone wrong!
            data.context.addClass('error');
        }

    });

    // Prevent the default action when a file is dropped on the window
    $(document).on('drop dragover', function (e) {
        e.preventDefault();
    });

    // Helper function that formats the file sizes
    function formatFileSize(bytes) {
        if (typeof bytes !== 'number') {
            return '';
        }

        if (bytes >= 1000000000) {
            return (bytes / 1000000000).toFixed(2) + ' GB';
        }

        if (bytes >= 1000000) {
            return (bytes / 1000000).toFixed(2) + ' MB';
        }

        return (bytes / 1000).toFixed(2) + ' KB';
    }

});

La librería Jquery File Upload viene con su propia interfaz que puedes utilizar sin problemas. Como necesitamos una interfaz totalmente personalizada, vamos a utilizar la versión básica del plugin, que no incluye interfaz. Para que funcione, pasamos un número de opciones de configuración/callbacks. En el código anterior, estos son:

  • dropZone
  • add
  • progress
  • fall

La propiedad data.context se preserva entre las llamadas de los métodos al plugin. De esta manera sabemos que elemento LI debemos actualizar en el progreso.

El PHP

jQuery File Upload también cuenta con un potente script PHP para la manipulación de la carga de archivos que puedes poner en tu servidor, pero para este tutorial, vamos a construir el nuestro propio. Las subidas de archivos enviados por el plugin son prácticamente iguales que una subida normal - se puede acceder a la información a través del array $ _FILES:

// A list of permitted file extensions
$allowed = array('png', 'jpg', 'gif','zip');

if(isset($_FILES['upl']) && $_FILES['upl']['error'] == 0){

	$extension = pathinfo($_FILES['upl']['name'], PATHINFO_EXTENSION);

	if(!in_array(strtolower($extension), $allowed)){
		echo '{"status":"error"}';
		exit;
	}

	if(move_uploaded_file($_FILES['upl']['tmp_name'], 'uploads/'.$_FILES['upl']['name'])){
		echo '{"status":"success"}';
		exit;
	}
}

echo '{"status":"error"}';
exit;

 

 

 

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP