¿Cómo puedo subir archivos de forma asincrónica?

2914

Me gustaría subir un archivo de forma asincrónica con jQuery.

$(document).ready(function () {
    $("#uploadbutton").click(function () {
        var filename = $("#file").val();

        $.ajax({
            type: "POST",
            url: "addFile.do",
            enctype: 'multipart/form-data',
            data: {
                file: filename
            },
            success: function () {
                alert("Data Uploaded: ");
            }
        });
    });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<span>File</span>
<input type="file" id="file" name="file" size="10"/>
<input id="uploadbutton" type="button" value="Upload"/>

En lugar de cargar el archivo, solo obtengo el nombre del archivo. ¿Qué puedo hacer para solucionar este problema?

Sergio del Amo
fuente
Hay varios complementos listos para cargar archivos para jQuery. Hacer este tipo de hacks de carga no es una experiencia agradable, por lo que la gente disfruta usando soluciones ya hechas. He aquí algunos de ellos: - jQuery cargador de archivos - archivos múltiples Subir Plugin - Mini de múltiples archivos Subir - jQuery Carga de archivos Puede buscar más proyectos en la NGP (usando "jquery-plugin" como la palabra clave) o en Github.
Alegre
72
solo está obteniendo el nombre del archivo porque su nombre de archivo var está obteniendo el valor de $ ('# archivo'), no el archivo que se encuentra en la entrada
Jimmy
21
Aquí hay uno bueno: http://blueimp.github.io/jQuery-File-Upload/ - Carga de HTML5 ajax - Respaldo elegante a iframes para navegadores no compatibles - Carga asíncrona de varios archivos Lo hemos usado y funciona muy bien. ( Documentación aquí )
Ashish Panery
3
Compruebe también esto: stackoverflow.com/questions/6974684/… , aquí explica cómo lograrlo a través de jQuery
Chococroc
2
@Jimmy ¿Cómo podría obtener el archivo que se encuentra en la entrada?
alex

Respuestas:

2519

Con HTML5 puede realizar cargas de archivos con Ajax y jQuery. No solo eso, puede hacer validaciones de archivos (nombre, tamaño y tipo MIME) o manejar el evento de progreso con la etiqueta de progreso HTML5 (o un div). Recientemente tuve que hacer un cargador de archivos, pero no quería usar Flash ni Iframes o complementos y después de investigar un poco, encontré la solución.

El HTML:

<form enctype="multipart/form-data">
    <input name="file" type="file" />
    <input type="button" value="Upload" />
</form>
<progress></progress>

Primero, puede hacer alguna validación si lo desea. Por ejemplo, en el .on('change')caso del archivo:

$(':file').on('change', function () {
  var file = this.files[0];

  if (file.size > 1024) {
    alert('max upload size is 1k');
  }

  // Also see .name, .type
});

Ahora $.ajax()envíe con el clic del botón:

$(':button').on('click', function () {
  $.ajax({
    // Your server script to process the upload
    url: 'upload.php',
    type: 'POST',

    // Form data
    data: new FormData($('form')[0]),

    // Tell jQuery not to process data or worry about content-type
    // You *must* include these options!
    cache: false,
    contentType: false,
    processData: false,

    // Custom XMLHttpRequest
    xhr: function () {
      var myXhr = $.ajaxSettings.xhr();
      if (myXhr.upload) {
        // For handling the progress of the upload
        myXhr.upload.addEventListener('progress', function (e) {
          if (e.lengthComputable) {
            $('progress').attr({
              value: e.loaded,
              max: e.total,
            });
          }
        }, false);
      }
      return myXhr;
    }
  });
});

Como puede ver, con la carga de archivos HTML5 (y algunas investigaciones) no solo se hace posible, sino que es muy fácil. Pruébelo con Google Chrome, ya que algunos de los componentes HTML5 de los ejemplos no están disponibles en todos los navegadores.

olanod
fuente
14
¿Puedo usar $ _FILES en upload.php?
Alessandro Cosentino
71
Esto debería funcionar en Internet Explorer, pero solo en la Versión 10. ( caniuse.com/xhr2 )
Tyler
18
Hola, agradezco que PHP sea su lenguaje de elección ... pero me pregunto si sabe si esto también funciona en ASP.NET MVC. Soy un desarrollador de .NET y he intentado utilizar su ejemplo simple para cargar algunos archivos AJAX, pero del lado del servidor no obtengo el archivo que publiqué a través de AJAX. Estoy usando la última versión de Chrome.
Shumii
25
Es FormData quien hace toda la magia aquí. Asegúrese de revisar estos documentos: cubre todas sus preguntas sobre múltiples archivos y campos.
Encarnado el
44
Solo para que alguien más no pase horas ... name="file"es muy importante en la <input>etiqueta del archivo si vas a usar los datos en PHP (y probablemente en otros lugares). Creé un formulario dinámicamente usando javascript, por lo que no necesitaba el atributo de nombre, pero descubrí de la manera difícil que lo necesita para recuperar el lado del servidor de datos.
Kivak Wolf
273

Actualización 2019: todavía depende de los navegadores que use su demografía.

Una cosa importante a entender con la "nueva" fileAPI HTML5 es que no fue compatible hasta IE 10 . Si el mercado específico al que apunta tiene una propensión superior a la media hacia versiones anteriores de Windows, es posible que no tenga acceso a él.

A partir de 2017, aproximadamente el 5% de los navegadores son uno de IE 6, 7, 8 o 9. Si te diriges a una gran corporación (por ejemplo, esta es una herramienta B2B, o algo que estás entregando para entrenamiento) ese número puede dispararse . En 2016, traté con una empresa que usa IE8 en más del 60% de sus máquinas.

Es 2019 a partir de esta edición, casi 11 años después de mi respuesta inicial. IE9 y versiones inferiores están en todo el mundo alrededor de la marca del 1%, pero todavía hay grupos de mayor uso.

Lo importante de esto, cualquiera que sea la función, es verificar qué navegador usan sus usuarios . Si no lo hace, aprenderá una lección rápida y dolorosa de por qué "funciona para mí" no es lo suficientemente bueno como para entregarlo a un cliente. caniuse es una herramienta útil, pero tenga en cuenta de dónde obtienen sus datos demográficos. Es posible que no se alineen con los tuyos. Esto nunca es más cierto que los entornos empresariales.

Mi respuesta de 2008 sigue.


Sin embargo, hay métodos viables que no son JS de carga de archivos. Puede crear un iframe en la página (que oculta con CSS) y luego orientar su formulario para publicar en ese iframe. La página principal no necesita moverse.

Es una publicación "real", por lo que no es totalmente interactiva. Si necesita estado, necesita algo del lado del servidor para procesarlo. Esto varía enormemente dependiendo de su servidor. ASP.NET tiene mejores mecanismos. PHP plain falla, pero puede usar modificaciones de Perl o Apache para solucionarlo.

Si necesita cargar múltiples archivos, es mejor hacer cada archivo de uno en uno (para superar los límites máximos de carga de archivos). Publique el primer formulario en el iframe, controle su progreso utilizando lo anterior y cuando haya terminado, publique el segundo formulario en el iframe, y así sucesivamente.

O use una solución Java / Flash. Son mucho más flexibles en lo que pueden hacer con sus publicaciones ...

Oli
fuente
142
Para el registro, ahora es posible realizar cargas de archivos AJAX puras si el navegador admite la API de archivos - developer.mozilla.org/en/using_files_from_web_applications
meleyal
la solución de iframe es bastante simple y fácil de usar
Matthew Lock
Esta es una respuesta bastante antigua, pero fue un poco engañosa. IE soportó XHR de forma nativa desde IE7, y lo soportó a través de ActiveX desde IE5. w3schools.com/ajax/ajax_xmlhttprequest_create.asp . La forma práctica de hacer esto fue apuntar a componentes flash (shockwave) o implementar un control Flash / ActiveX (Silverlight). Si puede originar una solicitud y manejar la respuesta a través de javascript, es ajax ... aunque, dicho esto, ajax es sinónimo de xhr, pero no describe el mecanismo / componentes subrayados que entregan / intercambian la carga útil.
Brett Caswell
44
@BrettCaswell No estaba diciendo que AJAX / XHR no fuera posible, solo que no era posible publicar un archivo con ellos en versiones antiguas, pero permanentes, de IE. Eso fue y sigue siendo completamente cierto.
Oli
Esta no es la forma, esta es una opinión de UX, válida tal vez.
Nimjox
112

Recomiendo usar el complemento Fine Uploader para este propósito. Tu JavaScriptcódigo sería:

$(document).ready(function() {
  $("#uploadbutton").jsupload({
    action: "addFile.do",
    onComplete: function(response){
      alert( "server response: " + response);
    }
  });
});
Shiladitya
fuente
Utiliza JSON, por lo que para la versión anterior de PHP no será posible su uso.
Lorenzo Manucci
Parece mucho más limpio que Ajax File Upload, donde necesito incluir una gran pieza de código solo para usar la maldita cosa.
ripper234
La URL más nueva para la versión 2 ahora es valums-file-uploader.github.com/file-uploader
Simon East
35
"Este complemento es de código abierto bajo GNU GPL 2 o posterior y GNU LGPL 2 o posterior". Por lo tanto, siempre que no distribuya la copia o una versión modificada, no tiene que abrir su proyecto.
Trantor Liu
¿Me estoy perdiendo de algo? Parece que esta biblioteca ya no usa jquery, por lo que no admite la sintaxis de la respuesta.
James McCormack
102

Nota: Esta respuesta está desactualizada, ahora es posible cargar archivos usando XHR.


No puede cargar archivos usando XMLHttpRequest (Ajax). Puede simular el efecto usando un iframe o Flash. El excelente jQuery Form Plugin que publica sus archivos a través de un iframe para obtener el efecto.

Mattias
fuente
1
Sí, puede PUBLICAR en un iframe y capturar el archivo allí. Sin embargo, tengo una experiencia muy limitada con esto, por lo que realmente no puedo comentarlo.
Mattias
15
Pequeña observación: en las últimas versiones de Chrome y Firefox es posible, stackoverflow.com/questions/4856917/…
Alleo
No es compatible con IE9 y menos
Radmation
96

Terminando para futuros lectores.

Carga asincrónica de archivos

Con HTML5

Puede cargar archivos con jQuery utilizando el $.ajax()método si FormData y File API son compatibles (ambas características HTML5).

También puede enviar archivos sin FormData, pero de cualquier manera la API de archivos debe estar presente para procesar archivos de tal manera que puedan enviarse con XMLHttpRequest (Ajax).

$.ajax({
  url: 'file/destination.html', 
  type: 'POST',
  data: new FormData($('#formWithFiles')[0]), // The form with the file inputs.
  processData: false,
  contentType: false                    // Using FormData, no need to process data.
}).done(function(){
  console.log("Success: Files sent!");
}).fail(function(){
  console.log("An error occurred, the files couldn't be sent!");
});

Para ver un ejemplo rápido y puro de JavaScript ( sin jQuery ), consulte " Envío de archivos con un objeto FormData ".

Retroceder

Cuando no se admite HTML5 (sin API de archivo ), la única otra solución de JavaScript pura (sin Flash ni ningún otro complemento del navegador) es la técnica de iframe oculta , que permite emular una solicitud asincrónica sin usar el objeto XMLHttpRequest .

Consiste en establecer un iframe como el objetivo del formulario con las entradas del archivo. Cuando el usuario envía una solicitud, los archivos se cargan pero la respuesta se muestra dentro del iframe en lugar de volver a representar la página principal. Ocultar el iframe hace que todo el proceso sea transparente para el usuario y emula una solicitud asincrónica.

Si se hace correctamente, debería funcionar prácticamente en cualquier navegador, pero tiene algunas advertencias sobre cómo obtener la respuesta del iframe.

En este caso, puede preferir usar un complemento de envoltura como Bifröst que usa la técnica de iframe pero también proporciona un transporte jQuery Ajax que permite enviar archivos con el $.ajax()método de esta manera:

$.ajax({
  url: 'file/destination.html', 
  type: 'POST',
  // Set the transport to use (iframe means to use Bifröst)
  // and the expected data type (json in this case).
  dataType: 'iframe json',                                
  fileInputs: $('input[type="file"]'),  // The file inputs containing the files to send.
  data: { msg: 'Some extra data you might need.'}
}).done(function(){
  console.log("Success: Files sent!");
}).fail(function(){
  console.log("An error occurred, the files couldn't be sent!");
});

Complementos

Bifröst es solo un pequeño contenedor que agrega soporte de respaldo al método ajax de jQuery, pero muchos de los complementos mencionados anteriormente como jQuery Form Plugin o jQuery File Upload incluyen toda la pila de HTML5 a diferentes fallbacks y algunas características útiles para facilitar el proceso. Dependiendo de sus necesidades y requisitos, es posible que desee considerar una implementación simple o cualquiera de estos complementos.

404
fuente
3
Una cosa a tener en cuenta, basada en la documentación: también debe enviar contentType: false. Cuando no envié esto con Chrome, el tipo de contenido del formulario fue invalidado por jQuery.
ceniza
Buena respuesta. Algunas sugerencias de mejora: elimine las partes del código no relacionadas con la respuesta, por ejemplo, las devoluciones de llamada .done()y .fail(). Además, un ejemplo sin el uso de FormDatay una lista de pros / contras sería increíble.
Zero3
Recibí este error:TypeError: Argument 1 of FormData.constructor does not implement interface HTMLFormElement.
candlejack
85

Este complemento jQuery de carga de archivos AJAX carga el archivo en algún momento y pasa la respuesta a una devolución de llamada, nada más.

  • No depende de HTML específico, solo dale un <input type="file">
  • No requiere que su servidor responda de ninguna manera particular
  • No importa cuántos archivos use o dónde se encuentren en la página

- Use tan poco como -

$('#one-specific-file').ajaxfileupload({
  'action': '/upload.php'
});

- o tanto como -

$('input[type="file"]').ajaxfileupload({
  'action': '/upload.php',
  'params': {
    'extra': 'info'
  },
  'onComplete': function(response) {
    console.log('custom handler for file:');
    alert(JSON.stringify(response));
  },
  'onStart': function() {
    if(weWantedTo) return false; // cancels upload
  },
  'onCancel': function() {
    console.log('no file selected');
  }
});
Jordan Feldstein
fuente
1
@ user840250 jQuery 1.9.1?
Jordan Feldstein
62

He estado usando el siguiente script para cargar imágenes que funciona bien.

HTML

<input id="file" type="file" name="file"/>
<div id="response"></div>

JavaScript

jQuery('document').ready(function(){
    var input = document.getElementById("file");
    var formdata = false;
    if (window.FormData) {
        formdata = new FormData();
    }
    input.addEventListener("change", function (evt) {
        var i = 0, len = this.files.length, img, reader, file;

        for ( ; i < len; i++ ) {
            file = this.files[i];

            if (!!file.type.match(/image.*/)) {
                if ( window.FileReader ) {
                    reader = new FileReader();
                    reader.onloadend = function (e) {
                        //showUploadedItem(e.target.result, file.fileName);
                    };
                    reader.readAsDataURL(file);
                }

                if (formdata) {
                    formdata.append("image", file);
                    formdata.append("extra",'extra-data');
                }

                if (formdata) {
                    jQuery('div#response').html('<br /><img src="ajax-loader.gif"/>');

                    jQuery.ajax({
                        url: "upload.php",
                        type: "POST",
                        data: formdata,
                        processData: false,
                        contentType: false,
                        success: function (res) {
                         jQuery('div#response').html("Successfully uploaded");
                        }
                    });
                }
            }
            else
            {
                alert('Not a vaild image!');
            }
        }

    }, false);
});

Explicación

Utilizo la respuesta divpara mostrar la animación de carga y la respuesta después de que se realiza la carga.

La mejor parte es que puede enviar datos adicionales como identificadores, etc. con el archivo cuando utiliza este script. Lo he mencionado extra-datacomo en el guión.

En el nivel de PHP, esto funcionará como carga de archivos normal. los datos adicionales se pueden recuperar como $_POSTdatos.

Aquí no estás usando un complemento y esas cosas. Puedes cambiar el código como quieras. No estás codificando ciegamente aquí. Esta es la funcionalidad principal de cualquier carga de archivos jQuery. En realidad Javascript.

Techie
fuente
55
-1 para usar jQuery y no usar su motor de selección y controladores de eventos. addEventListenerNo es un navegador cruzado.
Mark
3
Porque no tendría sentido agregar una respuesta separada que se basaría principalmente en esta, con solo unos pocos cambios. En cambio, esta respuesta debe corregirse.
Mark
2
@RainFromHeaven, por favor, ¿puedes editar la respuesta? No sé cómo hacerlo en el navegador cruzado.
Thiago Negri
2
Todavía no funciona en IE 9 y versiones anteriores. Muchos usuarios aún usan esas versiones de IE.
Pierre
1
¿Alguien puede explicar cómo se puede hacer que esto funcione en asp.net? ¿Utilizo webmethod? Si es así, ¿cómo se vería?
SamuraiJack
49

Puedes hacerlo en JavaScript vainilla con bastante facilidad. Aquí hay un fragmento de mi proyecto actual:

var xhr = new XMLHttpRequest();
xhr.upload.onprogress = function(e) {
    var percent = (e.position/ e.totalSize);
    // Render a pretty progress bar
};
xhr.onreadystatechange = function(e) {
    if(this.readyState === 4) {
        // Handle file upload complete
    }
};
xhr.open('POST', '/upload', true);
xhr.setRequestHeader('X-FileName',file.name); // Pass the filename along
xhr.send(file);
mpen
fuente
3
@ Gary: Lo siento, debería haber publicado ese bit también. Estaba usando la nueva funcionalidad de arrastrar y soltar en HTML5; Puede encontrar un ejemplo aquí: html5demos.com/file-api#view-source - simplemente haga clic en "ver código fuente". Esencialmente, dentro del ondropevento que puede hacervar file = e.dataTransfer.files[0]
mpen
Tal vez la pregunta se ha editado desde entonces, pero algunas personas en una discusión que abrí piensan que una respuesta vainilla de JS está fuera de tema si OP solicita una solución jQuery (siempre que exista una) y esas respuestas pertenecen a una pregunta separada.
Andy
44
@Andy Bueno, no estoy de acuerdo, y parece que otros 34 también. Si puede usar jQuery, entonces ciertamente puede usar JavaScript. En cualquier caso, este es un sitio de la comunidad, no es solo OP lo que estoy tratando de ayudar aquí. Todos son libres de elegir / usar la respuesta que más les guste. Algunas personas simplemente gravitan hacia jQuery porque piensan que será mucho más fácil / menos líneas de código, cuando realmente no necesitan la sobrecarga de una biblioteca adicional.
mpen
47

Puedes subir simplemente con jQuery .ajax().

HTML:

<form id="upload-form">
    <div>
        <label for="file">File:</label>
        <input type="file" id="file" name="file" />
        <progress class="progress" value="0" max="100"></progress>
    </div>
    <hr />
    <input type="submit" value="Submit" />
</form>

CSS

.progress { display: none; }

Javascript:

$(document).ready(function(ev) {
    $("#upload-form").on('submit', (function(ev) {
        ev.preventDefault();
        $.ajax({
            xhr: function() {
                var progress = $('.progress'),
                    xhr = $.ajaxSettings.xhr();

                progress.show();

                xhr.upload.onprogress = function(ev) {
                    if (ev.lengthComputable) {
                        var percentComplete = parseInt((ev.loaded / ev.total) * 100);
                        progress.val(percentComplete);
                        if (percentComplete === 100) {
                            progress.hide().val(0);
                        }
                    }
                };

                return xhr;
            },
            url: 'upload.php',
            type: 'POST',
            data: new FormData(this),
            contentType: false,
            cache: false,
            processData: false,
            success: function(data, status, xhr) {
                // ...
            },
            error: function(xhr, status, error) {
                // ...
            }
       });
    }));
});
Zayn Ali
fuente
1
@RaydenBlack solo jQuery.
Zayn Ali
¿Cómo obtener el progreso de carga?
Ali Sherafat
44

La forma más simple y robusta que he hecho en el pasado es simplemente apuntar a una etiqueta iFrame oculta con su formulario; luego se enviará dentro del iframe sin volver a cargar la página.

Es decir, si no desea utilizar un complemento, JavaScript o cualquier otra forma de "magia" que no sea HTML. Por supuesto, puedes combinar esto con JavaScript o lo que tienes ...

<form target="iframe" action="" method="post" enctype="multipart/form-data">
    <input name="file" type="file" />
    <input type="button" value="Upload" />
</form>

<iframe name="iframe" id="iframe" style="display:none" ></iframe>

También puede leer el contenido del iframe onLoadpara errores del servidor o respuestas exitosas y luego enviarlo al usuario.

Chrome, iFrames y onLoad

-note- solo necesita seguir leyendo si está interesado en cómo configurar un bloqueador de UI al cargar / descargar

Actualmente, Chrome no activa el evento onLoad para el iframe cuando se usa para transferir archivos. Firefox, IE y Edge activan el evento de carga para las transferencias de archivos.

La única solución que encontré que funciona para Chrome fue usar una cookie.

Para hacer eso básicamente cuando se inicia la carga / descarga:

  • [Lado del cliente] Inicie un intervalo para buscar la existencia de una cookie
  • [Lado del servidor] Haga lo que necesite con los datos del archivo
  • [Lado del servidor] Establecer cookie para el intervalo del lado del cliente
  • [Cliente] El intervalo ve la cookie y la usa como el evento onLoad. Por ejemplo, puede iniciar un bloqueador de UI y luego onLoad (o cuando se hace una cookie) elimina el bloqueador de UI.

Usar una cookie para esto es feo pero funciona.

Hice un complemento jQuery para manejar este problema para Chrome al descargar, puedes encontrar aquí

https://github.com/ArtisticPhoenix/jQuery-Plugins/blob/master/iDownloader.js

El mismo principio básico se aplica también a la carga.

Para usar el descargador (incluya el JS, obviamente)

 $('body').iDownloader({
     "onComplete" : function(){
          $('#uiBlocker').css('display', 'none'); //hide ui blocker on complete
     }
 });

 $('somebuttion').click( function(){
      $('#uiBlocker').css('display', 'block'); //block the UI
      $('body').iDownloader('download', 'htttp://example.com/location/of/download');
 });

Y en el lado del servidor, justo antes de transferir los datos del archivo, cree la cookie

 setcookie('iDownloader', true, time() + 30, "/");

El complemento verá la cookie y luego activará la onCompletedevolución de llamada.

Fénix Artístico
fuente
3
Me encanta. Si tan solo alguien pudiera mencionar los posibles problemas con esta brillante solución. Realmente no entiendo por qué las personas escriben mal y usan estas complejas bibliotecas y complementos cuando existe la solución.
Yevgeniy Afanasyev
1
Bueno, supongo que la razón sería mostrar información de progreso mientras se carga.
Prakhar Mishra
32

Una solución que encontré fue tener como <form>objetivo un iFrame oculto. El iFrame puede ejecutar JS para mostrar al usuario que está completo (en la carga de la página).

Darryl Hein
fuente
1
Estoy interesado en esta respuesta, ¿tiene una demostración a la que pueda vincular?
lfender6445
32

He escrito esto en un entorno Rails . Solo se trata de cinco líneas de JavaScript, si utiliza el ligero plugin jQuery-form.

El desafío es lograr que la carga AJAX funcione, ya que el estándar remote_form_forno comprende el envío de formularios de varias partes. No va a enviar los datos del archivo que Rails busca con la solicitud AJAX.

Ahí es donde entra en juego el complemento jQuery-form.

Aquí está el código de Rails para ello:

<% remote_form_for(:image_form, 
                   :url => { :controller => "blogs", :action => :create_asset }, 
                   :html => { :method => :post, 
                              :id => 'uploadForm', :multipart => true }) 
                                                                        do |f| %>
 Upload a file: <%= f.file_field :uploaded_data %>
<% end %>

Aquí está el JavaScript asociado:

$('#uploadForm input').change(function(){
 $(this).parent().ajaxSubmit({
  beforeSubmit: function(a,f,o) {
   o.dataType = 'json';
  },
  complete: function(XMLHttpRequest, textStatus) {
   // XMLHttpRequest.responseText will contain the URL of the uploaded image.
   // Put it in an image element you create, or do with it what you will.
   // For example, if you have an image elemtn with id "my_image", then
   //  $('#my_image').attr('src', XMLHttpRequest.responseText);
   // Will set that image tag to display the uploaded image.
  },
 });
});

Y aquí está la acción del controlador Rails, bastante vainilla:

 @image = Image.new(params[:image_form])
 @image.save
 render :text => @image.public_filename

He estado usando esto durante las últimas semanas con Bloggity, y ha funcionado como un campeón.

wbharding
fuente
31

Simple Ajax Uploader es otra opción:

https://github.com/LPology/Simple-Ajax-Uploader

  • Cross-browser: funciona en IE7 +, Firefox, Chrome, Safari, Opera
  • Admite cargas múltiples y simultáneas, incluso en navegadores que no son HTML5
  • Sin flash ni CSS externo: solo un archivo Javascript de 5 KB
  • Opcional, soporte incorporado para barras de progreso completamente entre navegadores (usando la extensión APC de PHP)
  • Flexible y altamente personalizable: use cualquier elemento como botón de carga, diseñe sus propios indicadores de progreso
  • No se requieren formularios, solo proporcione un elemento que sirva como botón de carga
  • Licencia MIT: uso gratuito en proyectos comerciales

Ejemplo de uso:

var uploader = new ss.SimpleUpload({
    button: $('#uploadBtn'), // upload button
    url: '/uploadhandler', // URL of server-side upload handler
    name: 'userfile', // parameter name of the uploaded file
    onSubmit: function() {
        this.setProgressBar( $('#progressBar') ); // designate elem as our progress bar
    },
    onComplete: function(file, response) {
        // do whatever after upload is finished
    }
});
usuario1091949
fuente
2
Este parece ser el más prometedor hasta el momento, ¡me tienes en IE7+! Probándolo ahora. Gracias
Pierre
25

jQuery Uploadify es otro buen complemento que he usado antes para cargar archivos. El código JavaScript es tan simple como el siguiente: código. Sin embargo, la nueva versión no funciona en Internet Explorer.

$('#file_upload').uploadify({
    'swf': '/public/js/uploadify.swf',
    'uploader': '/Upload.ashx?formGuid=' + $('#formGuid').val(),
    'cancelImg': '/public/images/uploadify-cancel.png',
    'multi': true,
    'onQueueComplete': function (queueData) {
        // ...
    },
    'onUploadStart': function (file) {
        // ...
    }
});

He buscado mucho y he encontrado otra solución para cargar archivos sin ningún complemento y solo con ajax. La solución es la siguiente:

$(document).ready(function () {
    $('#btn_Upload').live('click', AjaxFileUpload);
});

function AjaxFileUpload() {
    var fileInput = document.getElementById("#Uploader");
    var file = fileInput.files[0];
    var fd = new FormData();
    fd.append("files", file);
    var xhr = new XMLHttpRequest();
    xhr.open("POST", 'Uploader.ashx');
    xhr.onreadystatechange = function () {
        if (xhr.readyState == 4) {
             alert('success');
        }
        else if (uploadResult == 'success')
            alert('error');
    };
    xhr.send(fd);
}
farnoush resa
fuente
2
Uploadify ha estado muerto por años. Ya no se admite ni se mantiene.
Ray Nicholus
24

Aquí hay otra solución de cómo cargar archivos ( sin ningún complemento )

Usando Javascripts simples y AJAX (con barra de progreso)

Parte HTML

<form id="upload_form" enctype="multipart/form-data" method="post">
    <input type="file" name="file1" id="file1"><br>
    <input type="button" value="Upload File" onclick="uploadFile()">
    <progress id="progressBar" value="0" max="100" style="width:300px;"></progress>
    <h3 id="status"></h3>
    <p id="loaded_n_total"></p>
</form>

Parte JS

function _(el){
    return document.getElementById(el);
}
function uploadFile(){
    var file = _("file1").files[0];
    // alert(file.name+" | "+file.size+" | "+file.type);
    var formdata = new FormData();
    formdata.append("file1", file);
    var ajax = new XMLHttpRequest();
    ajax.upload.addEventListener("progress", progressHandler, false);
    ajax.addEventListener("load", completeHandler, false);
    ajax.addEventListener("error", errorHandler, false);
    ajax.addEventListener("abort", abortHandler, false);
    ajax.open("POST", "file_upload_parser.php");
    ajax.send(formdata);
}
function progressHandler(event){
    _("loaded_n_total").innerHTML = "Uploaded "+event.loaded+" bytes of "+event.total;
    var percent = (event.loaded / event.total) * 100;
    _("progressBar").value = Math.round(percent);
    _("status").innerHTML = Math.round(percent)+"% uploaded... please wait";
}
function completeHandler(event){
    _("status").innerHTML = event.target.responseText;
    _("progressBar").value = 0;
}
function errorHandler(event){
    _("status").innerHTML = "Upload Failed";
}
function abortHandler(event){
    _("status").innerHTML = "Upload Aborted";
}

Parte PHP

<?php
$fileName = $_FILES["file1"]["name"]; // The file name
$fileTmpLoc = $_FILES["file1"]["tmp_name"]; // File in the PHP tmp folder
$fileType = $_FILES["file1"]["type"]; // The type of file it is
$fileSize = $_FILES["file1"]["size"]; // File size in bytes
$fileErrorMsg = $_FILES["file1"]["error"]; // 0 for false... and 1 for true
if (!$fileTmpLoc) { // if file not chosen
    echo "ERROR: Please browse for a file before clicking the upload button.";
    exit();
}
if(move_uploaded_file($fileTmpLoc, "test_uploads/$fileName")){ // assuming the directory name 'test_uploads'
    echo "$fileName upload is complete";
} else {
    echo "move_uploaded_file function failed";
}
?>

Aquí está la aplicación EJEMPLO

Siddhartha Chowdhury
fuente
19
var formData=new FormData();
formData.append("fieldname","value");
formData.append("image",$('[name="filename"]')[0].files[0]);

$.ajax({
    url:"page.php",
    data:formData,
    type: 'POST',
    dataType:"JSON",
    cache: false,
    contentType: false,
    processData: false,
    success:function(data){ }
});

Puede usar datos de formulario para publicar todos sus valores, incluidas las imágenes.

Vivek Aasaithambi
fuente
66
Nota: cache: falsees redundante en una POSTsolicitud ya que POST nunca se almacena en caché.
Se fue la codificación del
@Vivek Aasaithambi, recibí este error:TypeError: Argument 1 of FormData.constructor does not implement interface HTMLFormElement.
candlejack
15

Para cargar el archivo de forma asincrónica con Jquery, utilice los siguientes pasos:

paso 1 En su proyecto, abra el administrador de Nuget y agregue el paquete (jquery fileupload (solo necesita escribirlo en el cuadro de búsqueda, aparecerá y lo instalará)) URL: https://github.com/blueimp/jQuery-File- Subir

Paso 2 Agregue los siguientes scripts en los archivos HTML, que ya se agregaron al proyecto ejecutando el paquete anterior:

jquery.ui.widget.js

jquery.iframe-transport.js

jquery.fileupload.js

Paso 3 Escriba el control de carga de archivos según el código siguiente:

<input id="upload" name="upload" type="file" />

paso 4 escribe un método js como uploadFile como se muestra a continuación:

 function uploadFile(element) {

            $(element).fileupload({

                dataType: 'json',
                url: '../DocumentUpload/upload',
                autoUpload: true,
                add: function (e, data) {           
                  // write code for implementing, while selecting a file. 
                  // data represents the file data. 
                  //below code triggers the action in mvc controller
                  data.formData =
                                    {
                                     files: data.files[0]
                                    };
                  data.submit();
                },
                done: function (e, data) {          
                   // after file uploaded
                },
                progress: function (e, data) {

                   // progress
                },
                fail: function (e, data) {

                   //fail operation
                },
                stop: function () {

                  code for cancel operation
                }
            });

        };

Paso 5 En la función Listo, carga el archivo del elemento para iniciar el proceso como se muestra a continuación:

$(document).ready(function()
{
    uploadFile($('#upload'));

});

Paso 6 Escriba el controlador MVC y la acción de la siguiente manera:

public class DocumentUploadController : Controller
    {       

        [System.Web.Mvc.HttpPost]
        public JsonResult upload(ICollection<HttpPostedFileBase> files)
        {
            bool result = false;

            if (files != null || files.Count > 0)
            {
                try
                {
                    foreach (HttpPostedFileBase file in files)
                    {
                        if (file.ContentLength == 0)
                            throw new Exception("Zero length file!");                       
                        else 
                            //code for saving a file

                    }
                }
                catch (Exception)
                {
                    result = false;
                }
            }


            return new JsonResult()
                {
                    Data=result
                };


        }

    }
ashish
fuente
14

Un enfoque moderno sin Jquery es usar el objeto FileList del que obtiene <input type="file">cuando el usuario selecciona un archivo (s) y luego usar Fetch para publicar FileList envuelto alrededor de un objeto FormData .

// The input DOM element // <input type="file">
const inputElement = document.querySelector('input[type=file]');

// Listen for a file submit from user
inputElement.addEventListener('change', () => {
    const data = new FormData();
    data.append('file', inputElement.files[0]);
    data.append('imageName', 'flower');

    // You can then post it to your server.
    // Fetch can accept an object of type FormData on its  body
    fetch('/uploadImage', {
        method: 'POST',
        body: data
    });
});
Alister
fuente
Aparentemente no es compatible con IE
Marco Demaio
11

Puede ver una solución resuelta con una demostración funcional aquí que le permite obtener una vista previa y enviar archivos de formulario al servidor. Para su caso, debe usar Ajax para facilitar la carga del archivo al servidor:

<from action="" id="formContent" method="post" enctype="multipart/form-data">
    <span>File</span>
    <input type="file" id="file" name="file" size="10"/>
    <input id="uploadbutton" type="button" value="Upload"/>
</form>

Los datos que se envían son datos de formulario. En su jQuery, use una función de envío de formulario en lugar de hacer clic en un botón para enviar el archivo de formulario como se muestra a continuación.

$(document).ready(function () {
   $("#formContent").submit(function(e){

     e.preventDefault();
     var formdata = new FormData(this);

 $.ajax({
     url: "ajax_upload_image.php",
     type: "POST",
     data: formdata,
     mimeTypes:"multipart/form-data",
     contentType: false,
     cache: false,
     processData: false,
     success: function(){

     alert("successfully submitted");

     });
   });
});

Ver más detalles

Daniel Nyamasyo
fuente
11

Muestra: si usa jQuery, puede hacer que sea fácil cargar un archivo. Este es un pequeño y fuerte complemento de jQuery, http://jquery.malsup.com/form/ .

Ejemplo

var $bar   = $('.ProgressBar');
$('.Form').ajaxForm({
  dataType: 'json',

  beforeSend: function(xhr) {
    var percentVal = '0%';
    $bar.width(percentVal);
  },

  uploadProgress: function(event, position, total, percentComplete) {
    var percentVal = percentComplete + '%';
    $bar.width(percentVal)
  },

  success: function(response) {
    // Response
  }
});

Espero que sea de ayuda

MEAbid
fuente
10

Puedes usar

$(function() {
    $("#file_upload_1").uploadify({
        height        : 30,
        swf           : '/uploadify/uploadify.swf',
        uploader      : '/uploadify/uploadify.php',
        width         : 120
    });
});

Manifestación

Amit
fuente
9

Convierta el archivo a base64 utilizando | ReadAsDataURL () de HTML5 o algún codificador de base64 . Violín aquí

var reader = new FileReader();

        reader.onload = function(readerEvt) {
            var binaryString = readerEvt.target.result;
            document.getElementById("base64textarea").value = btoa(binaryString);
        };

        reader.readAsBinaryString(file);

Luego para recuperar:

window.open("data:application/octet-stream;base64," + base64);
tnt-rox
fuente
9

Puede pasar parámetros adicionales junto con el nombre del archivo al realizar una carga asincrónica utilizando XMLHttpRequest (sin dependencia de flash e iframe). Agregue el valor del parámetro adicional con FormData y envíe la solicitud de carga.


var formData = new FormData();
formData.append('parameter1', 'value1');
formData.append('parameter2', 'value2'); 
formData.append('file', $('input[type=file]')[0].files[0]);

$.ajax({
    url: 'post back url',
    data: formData,
// other attributes of AJAX
});

Además, la carga de archivos Syncfusion JavaScript UI proporciona una solución para este escenario simplemente usando el argumento de evento. puede encontrar documentación aquí y más detalles sobre este control aquí ingrese la descripción del enlace aquí

Karthik Ravichandran
fuente
8

Busque Manejar el proceso de carga de un archivo, asincrónicamente aquí: https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications

Muestra del enlace

<?php
if (isset($_FILES['myFile'])) {
    // Example:
    move_uploaded_file($_FILES['myFile']['tmp_name'], "uploads/" . $_FILES['myFile']['name']);
    exit;
}
?><!DOCTYPE html>
<html>
<head>
    <title>dnd binary upload</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <script type="text/javascript">
        function sendFile(file) {
            var uri = "/index.php";
            var xhr = new XMLHttpRequest();
            var fd = new FormData();

            xhr.open("POST", uri, true);
            xhr.onreadystatechange = function() {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    // Handle response.
                    alert(xhr.responseText); // handle response.
                }
            };
            fd.append('myFile', file);
            // Initiate a multipart/form-data upload
            xhr.send(fd);
        }

        window.onload = function() {
            var dropzone = document.getElementById("dropzone");
            dropzone.ondragover = dropzone.ondragenter = function(event) {
                event.stopPropagation();
                event.preventDefault();
            }

            dropzone.ondrop = function(event) {
                event.stopPropagation();
                event.preventDefault();

                var filesArray = event.dataTransfer.files;
                for (var i=0; i<filesArray.length; i++) {
                    sendFile(filesArray[i]);
                }
            }
        }
    </script>
</head>
<body>
    <div>
        <div id="dropzone" style="margin:30px; width:500px; height:300px; border:1px dotted grey;">Drag & drop your file here...</div>
    </div>
</body>
</html>
Allende
fuente
7

Esta es mi solución

<form enctype="multipart/form-data">    

    <div class="form-group">
        <label class="control-label col-md-2" for="apta_Description">Description</label>
        <div class="col-md-10">
            <input class="form-control text-box single-line" id="apta_Description" name="apta_Description" type="text" value="">
        </div>
    </div>

    <input name="file" type="file" />
    <input type="button" value="Upload" />
</form>

y el js

<script>

    $(':button').click(function () {
        var formData = new FormData($('form')[0]);
        $.ajax({
            url: '@Url.Action("Save", "Home")',  
            type: 'POST',                
            success: completeHandler,
            data: formData,
            cache: false,
            contentType: false,
            processData: false
        });
    });    

    function completeHandler() {
        alert(":)");
    }    
</script>

Controlador

[HttpPost]
public ActionResult Save(string apta_Description, HttpPostedFileBase file)
{
    [...]
}
Erick Langford Xenes
fuente
2
Parece que has mezclado algún tipo de marco en tu respuesta. Como mínimo, debe mencionar para qué marco es utilizable su respuesta. Mejor aún, elimine todos los elementos del marco y presente solo una respuesta a la pregunta planteada.
Zero3
2
¿Entonces hay un marco de mvc llamado "mvc"? y usa la sintaxis csharpish? eso es cruel.
nonchip
6

Usando HTML5 y JavaScript , cargar asíncrono es bastante fácil, creo la lógica de carga junto con su html, esto no funciona completamente ya que necesita la API, pero demuestre cómo funciona, si tiene el punto final llamado /uploaddesde la raíz de su sitio web, este código debería funcionar para usted:

const asyncFileUpload = () => {
  const fileInput = document.getElementById("file");
  const file = fileInput.files[0];
  const uri = "/upload";
  const xhr = new XMLHttpRequest();
  xhr.upload.onprogress = e => {
    const percentage = e.loaded / e.total;
    console.log(percentage);
  };
  xhr.onreadystatechange = e => {
    if (xhr.readyState === 4 && xhr.status === 200) {
      console.log("file uploaded");
    }
  };
  xhr.open("POST", uri, true);
  xhr.setRequestHeader("X-FileName", file.name);
  xhr.send(file);
}
<form>
  <span>File</span>
  <input type="file" id="file" name="file" size="10" />
  <input onclick="asyncFileUpload()" id="upload" type="button" value="Upload" />
</form>

También alguna información adicional sobre XMLHttpReques:

El objeto XMLHttpRequest

Todos los navegadores modernos admiten el objeto XMLHttpRequest. El objeto XMLHttpRequest se puede usar para intercambiar datos con un servidor web detrás de escena. Esto significa que es posible actualizar partes de una página web sin tener que volver a cargar toda la página.


Crear un objeto XMLHttpRequest

Todos los navegadores modernos (Chrome, Firefox, IE7 +, Edge, Safari, Opera) tienen un objeto XMLHttpRequest incorporado.

Sintaxis para crear un objeto XMLHttpRequest:

variable = nuevo XMLHttpRequest ();


Acceso a través de dominios

Por razones de seguridad, los navegadores modernos no permiten el acceso a través de dominios.

Esto significa que tanto la página web como el archivo XML que intenta cargar deben estar ubicados en el mismo servidor.

Los ejemplos en W3Schools abren todos los archivos XML ubicados en el dominio W3Schools.

Si desea utilizar el ejemplo anterior en una de sus propias páginas web, los archivos XML que cargue deben ubicarse en su propio servidor.

Para más detalles, puedes seguir leyendo aquí ...

Alireza
fuente
5

Puede usar la nueva API Fetch por JavaScript. Me gusta esto:

function uploadButtonCLicked(){
    var input = document.querySelector('input[type="file"]')

    fetch('/url', {
      method: 'POST',
      body: input.files[0]
    }).then(res => res.json())   // you can do something with response
      .catch(error => console.error('Error:', error))
      .then(response => console.log('Success:', response));
}                               

Ventaja: Fetch API es compatible de forma nativa con todos los navegadores modernos, por lo que no tiene que importar nada. Además, tenga en cuenta que fetch () devuelve una Promesa que luego se maneja mediante el uso .then(..code to handle response..)asíncrono.

Barba Negra
fuente
4

Puede realizar cargas de archivos múltiples asincrónicos utilizando JavaScript o jQuery y sin utilizar ningún complemento. También puede mostrar el progreso en tiempo real de la carga de archivos en el control de progreso. Me he encontrado con 2 buenos enlaces:

  1. Función de carga de archivos Mulitple basada en formularios web ASP.NET con barra de progreso
  2. Carga de archivos múltiples basada en ASP.NET MVC realizada en jQuery

El lenguaje del lado del servidor es C #, pero puede hacer algunas modificaciones para que funcione con otro lenguaje como PHP.

Carga de archivos ASP.NET Core MVC:

En la vista crear control de carga de archivos en html:

<form method="post" asp-action="Add" enctype="multipart/form-data">
    <input type="file" multiple name="mediaUpload" />
    <button type="submit">Submit</button>
</form>

Ahora cree un método de acción en su controlador:

[HttpPost]
public async Task<IActionResult> Add(IFormFile[] mediaUpload)
{
    //looping through all the files
    foreach (IFormFile file in mediaUpload)
    {
        //saving the files
        string path = Path.Combine(hostingEnvironment.WebRootPath, "some-folder-path"); 
        using (var stream = new FileStream(path, FileMode.Create))
        {
            await file.CopyToAsync(stream);
        }
    }
}

La variable hostingEnvironment es de tipo IHostingEnvironment que se puede inyectar al controlador mediante inyección de dependencia, como:

private IHostingEnvironment hostingEnvironment;
public MediaController(IHostingEnvironment environment)
{
    hostingEnvironment = environment;
}
Joe Clinton
fuente
¿Podría incluir la esencia de la solución en su respuesta, ya que de lo contrario podría resultar inútil si el sitio web vinculado cambia o se desconecta?
Dima Kozhevin
4

Para PHP, busque https://developer.hyvor.com/php/image-upload-ajax-php-mysql

HTML

<html>
<head>
    <title>Image Upload with AJAX, PHP and MYSQL</title>
</head>
<body>
<form onsubmit="submitForm(event);">
    <input type="file" name="image" id="image-selecter" accept="image/*">
    <input type="submit" name="submit" value="Upload Image">
</form>
<div id="uploading-text" style="display:none;">Uploading...</div>
<img id="preview">
</body>
</html>

JAVASCRIPT

var previewImage = document.getElementById("preview"),  
    uploadingText = document.getElementById("uploading-text");

function submitForm(event) {
    // prevent default form submission
    event.preventDefault();
    uploadImage();
}

function uploadImage() {
    var imageSelecter = document.getElementById("image-selecter"),
        file = imageSelecter.files[0];
    if (!file) 
        return alert("Please select a file");
    // clear the previous image
    previewImage.removeAttribute("src");
    // show uploading text
    uploadingText.style.display = "block";
    // create form data and append the file
    var formData = new FormData();
    formData.append("image", file);
    // do the ajax part
    var ajax = new XMLHttpRequest();
    ajax.onreadystatechange = function() {
        if (this.readyState === 4 && this.status === 200) {
            var json = JSON.parse(this.responseText);
            if (!json || json.status !== true) 
                return uploadError(json.error);

            showImage(json.url);
        }
    }
    ajax.open("POST", "upload.php", true);
    ajax.send(formData); // send the form data
}

PHP

<?php
$host = 'localhost';
$user = 'user';
$password = 'password';
$database = 'database';
$mysqli = new mysqli($host, $user, $password, $database);


 try {
    if (empty($_FILES['image'])) {
        throw new Exception('Image file is missing');
    }
    $image = $_FILES['image'];
    // check INI error
    if ($image['error'] !== 0) {
        if ($image['error'] === 1) 
            throw new Exception('Max upload size exceeded');

        throw new Exception('Image uploading error: INI Error');
    }
    // check if the file exists
    if (!file_exists($image['tmp_name']))
        throw new Exception('Image file is missing in the server');
    $maxFileSize = 2 * 10e6; // in bytes
    if ($image['size'] > $maxFileSize)
        throw new Exception('Max size limit exceeded'); 
    // check if uploaded file is an image
    $imageData = getimagesize($image['tmp_name']);
    if (!$imageData) 
        throw new Exception('Invalid image');
    $mimeType = $imageData['mime'];
    // validate mime type
    $allowedMimeTypes = ['image/jpeg', 'image/png', 'image/gif'];
    if (!in_array($mimeType, $allowedMimeTypes)) 
        throw new Exception('Only JPEG, PNG and GIFs are allowed');

    // nice! it's a valid image
    // get file extension (ex: jpg, png) not (.jpg)
    $fileExtention = strtolower(pathinfo($image['name'] ,PATHINFO_EXTENSION));
    // create random name for your image
    $fileName = round(microtime(true)) . mt_rand() . '.' . $fileExtention; // anyfilename.jpg
    // Create the path starting from DOCUMENT ROOT of your website
    $path = '/examples/image-upload/images/' . $fileName;
    // file path in the computer - where to save it 
    $destination = $_SERVER['DOCUMENT_ROOT'] . $path;

    if (!move_uploaded_file($image['tmp_name'], $destination))
        throw new Exception('Error in moving the uploaded file');

    // create the url
    $protocol = stripos($_SERVER['SERVER_PROTOCOL'],'https') === true ? 'https://' : 'http://';
    $domain = $protocol . $_SERVER['SERVER_NAME'];
    $url = $domain . $path;
    $stmt = $mysqli -> prepare('INSERT INTO image_uploads (url) VALUES (?)');
    if (
        $stmt &&
        $stmt -> bind_param('s', $url) &&
        $stmt -> execute()
    ) {
        exit(
            json_encode(
                array(
                    'status' => true,
                    'url' => $url
                )
            )
        );
    } else 
        throw new Exception('Error in saving into the database');

} catch (Exception $e) {
    exit(json_encode(
        array (
            'status' => false,
            'error' => $e -> getMessage()
        )
    ));
}
Supun Kavinda
fuente
4

También podría considerar usar algo como https://uppy.io .

Realiza la carga de archivos sin navegar fuera de la página y ofrece algunas bonificaciones como arrastrar y soltar, reanudar las cargas en caso de fallas del navegador / redes inestables e importar desde, por ejemplo, Instagram. Es de código abierto y no depende de jQuery / React / Angular / Vue, pero se puede usar con él. Descargo de responsabilidad: como su creador soy parcial;)

kvz
fuente
El enlace de arriba está muerto. Aquí está el github: github.com/transloadit/uppy
Chris Charles
uppy.io ¿Las páginas de CloudFlare + GitHub están respaldadas y están listas para mí? Todavía es útil tener el enlace de repositorio directo también :)
kvz