w3schools formdata form data jquery ajax file-upload multipartform-data form-data

formdata - send file ajax jquery



Enviando multipart/formdata con jQuery.ajax (12)

Tengo un problema al enviar un archivo a un script PHP del lado del servidor utilizando la función ajax de jQuery. Es posible obtener la Lista de archivos con $(''#fileinput'').attr(''files'') pero ¿cómo es posible enviar estos datos al servidor? La matriz resultante ( $_POST ) en el script php del lado del servidor es 0 ( NULL ) cuando se usa la entrada de archivo.

Sé que es posible (aunque no encontré ninguna solución jQuery hasta ahora, solo código Prototye ( http://webreflection.blogspot.com/2009/03/safari-4-multiple-upload-with-progress.html ) ).

Esto parece ser relativamente nuevo, así que no mencione que la carga de archivos sería imposible a través de XHR / Ajax, porque definitivamente está funcionando.

Necesito la funcionalidad en Safari 5, FF y Chrome estarían bien, pero no son esenciales.

Mi código por ahora es:

$.ajax({ url: ''php/upload.php'', data: $(''#file'').attr(''files''), cache: false, contentType: ''multipart/form-data'', processData: false, type: ''POST'', success: function(data){ alert(data); } });


  1. obtener objeto de formulario por jquery-> $ ("# id") [0]
  2. datos = nuevo FormData ($ ("# id") [0]);
  3. ok, los datos son tus deseos


Acabo de construir esta función basada en alguna información que leí.

Úselo como usar .serialize() , en lugar de eso solo ponga .serializefiles(); .
Trabajando aquí en mis pruebas.

//USAGE: $("#form").serializefiles(); (function($) { $.fn.serializefiles = function() { var obj = $(this); /* ADD FILE TO PARAM AJAX */ var formData = new FormData(); $.each($(obj).find("input[type=''file'']"), function(i, tag) { $.each($(tag)[0].files, function(i, file) { formData.append(tag.name, file); }); }); var params = $(obj).serializeArray(); $.each(params, function (i, val) { formData.append(val.name, val.value); }); return formData; }; })(jQuery);


Comenzando con Safari 5 / Firefox 4, es más fácil usar la clase FormData :

var data = new FormData(); jQuery.each(jQuery(''#file'')[0].files, function(i, file) { data.append(''file-''+i, file); });

Así que ahora tiene un objeto FormData , listo para ser enviado junto con XMLHttpRequest.

jQuery.ajax({ url: ''php/upload.php'', data: data, cache: false, contentType: false, processData: false, method: ''POST'', type: ''POST'', // For jQuery < 1.9 success: function(data){ alert(data); } });

Es imperativo que establezca la opción contentType en false , lo que obliga a jQuery a no agregarle un encabezado Content-Type ; de lo contrario, la cadena de límite no estará presente. Además, debe dejar el indicador processData establecido en falso, de lo contrario, jQuery intentará convertir su FormData en una cadena, que fallará.

Ahora puede recuperar el archivo en PHP usando:

$_FILES[''file-0'']

(Solo hay un archivo, file-0 , a menos que haya especificado el atributo multiple en la entrada del archivo, en cuyo caso, los números se incrementarán con cada archivo).

Usando la emulación de FormData para navegadores antiguos

var opts = { url: ''php/upload.php'', data: data, cache: false, contentType: false, processData: false, method: ''POST'', type: ''POST'', // For jQuery < 1.9 success: function(data){ alert(data); } }; if(data.fake) { // Make sure no text encoding stuff is done by xhr opts.xhr = function() { var xhr = jQuery.ajaxSettings.xhr(); xhr.send = xhr.sendAsBinary; return xhr; } opts.contentType = "multipart/form-data; boundary="+data.boundary; opts.data = data.toString(); } jQuery.ajax(opts);

Crear FormData desde un formulario existente

En lugar de iterar manualmente los archivos, el objeto FormData también se puede crear con el contenido de un objeto de formulario existente:

var data = new FormData(jQuery(''form'')[0]);

Utilice una matriz nativa de PHP en lugar de un contador

Simplemente asigne el mismo nombre a los elementos del archivo y finalice el nombre entre paréntesis:

jQuery.each(jQuery(''#file'')[0].files, function(i, file) { data.append(''file[]'', file); });

$_FILES[''file''] será una matriz que contendrá los campos de carga de archivos para cada archivo cargado. De hecho, recomiendo esto sobre mi solución inicial, ya que es más simple de iterar.


Creo que vale la pena señalar algo relacionado con este problema: si se redirige la url para la llamada ajax, se puede perder el encabezado de tipo de contenido: ''multipart / form-data''.

Por ejemplo, estaba publicando en http://server.com/context?param=x

En la pestaña de red de Chrome vi el encabezado de varias partes correcto para esta solicitud, pero luego un redireccionamiento 302 a http://server.com/context/?param=x (note la barra después del contexto)

Durante la redirección se perdió el encabezado multiparte. Asegúrese de que las solicitudes no se estén redirigiendo si estas soluciones no funcionan para usted.


La clase FormData funciona, sin embargo, en iOS Safari (al menos en el iPhone) no pude usar la solución de Raphael Schweikert tal como está.

Mozilla Dev tiene una buena página sobre la manipulación de objetos FormData .

Entonces, agregue un formulario vacío en algún lugar de su página, especificando el enctype:

<form enctype="multipart/form-data" method="post" name="fileinfo" id="fileinfo"></form>

Luego, crea el objeto FormData como:

var data = new FormData($("#fileinfo"));

y proceder como en el código de Rafael .


Las versiones anteriores de IE no son compatibles con FormData (la lista completa de compatibilidad del navegador para FormData está aquí: https://developer.mozilla.org/en-US/docs/Web/API/FormData ).

Puede usar un complemento de jquery (por ejemplo, http://malsup.com/jquery/form/#code-samples ) o puede usar la solución basada en IFrame para publicar datos de formularios de varias partes a través de ajax: https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript


Mira mi código, hace el trabajo por mí.

$( ''#formId'' ) .submit( function( e ) { $.ajax( { url: ''FormSubmitUrl'', type: ''POST'', data: new FormData( this ), processData: false, contentType: false } ); e.preventDefault(); } );


Si su formulario está definido en su HTML, es más fácil pasar el formulario al constructor que iterar y agregar imágenes.

$(''#my-form'').submit( function(e) { e.preventDefault(); var data = new FormData(this); // <-- ''this'' is your form element $.ajax({ url: ''/my_URL/'', data: data, cache: false, contentType: false, processData: false, type: ''POST'', success: function(data){ ...


Solo quería agregar un poco a la gran respuesta de Rafael. Aquí le indicamos cómo hacer que PHP produzca los mismos $_FILES , independientemente de si usa JavaScript para enviar.

Formulario HTML:

<form enctype="multipart/form-data" action="/test.php" method="post" class="putImages"> <input name="media[]" type="file" multiple/> <input class="button" type="submit" alt="Upload" value="Upload" /> </form>

PHP produce este $_FILES , cuando se envía sin JavaScript:

Array ( [media] => Array ( [name] => Array ( [0] => Galata_Tower.jpg [1] => 518f.jpg ) [type] => Array ( [0] => image/jpeg [1] => image/jpeg ) [tmp_name] => Array ( [0] => /tmp/phpIQaOYo [1] => /tmp/phpJQaOYo ) [error] => Array ( [0] => 0 [1] => 0 ) [size] => Array ( [0] => 258004 [1] => 127884 ) ) )

Si realiza una mejora progresiva, utilizando JS de Raphael para enviar los archivos ...

var data = new FormData($(''input[name^="media"]'')); jQuery.each($(''input[name^="media"]'')[0].files, function(i, file) { data.append(i, file); }); $.ajax({ type: ppiFormMethod, data: data, url: ppiFormActionURL, cache: false, contentType: false, processData: false, success: function(data){ alert(data); } });

... así es como se ve la matriz $_FILES PHP, después de usar ese JavaScript para enviar:

Array ( [0] => Array ( [name] => Galata_Tower.jpg [type] => image/jpeg [tmp_name] => /tmp/phpAQaOYo [error] => 0 [size] => 258004 ) [1] => Array ( [name] => 518f.jpg [type] => image/jpeg [tmp_name] => /tmp/phpBQaOYo [error] => 0 [size] => 127884 ) )

Esa es una buena variedad, y en realidad en lo que algunas personas transforman $_FILES , pero me parece útil trabajar con los mismos $_FILES , independientemente de si se usó JavaScript para enviar. Entonces, aquí hay algunos cambios menores en el JS:

// match anything not a [ or ] regexp = /^[^[/]]+/; var fileInput = $(''.putImages input[type="file"]''); var fileInputName = regexp.exec( fileInput.attr(''name'') ); // make files available var data = new FormData(); jQuery.each($(fileInput)[0].files, function(i, file) { data.append(fileInputName+''[''+i+'']'', file); });

(Edición del 14 de abril de 2017: eliminé el elemento de formulario del constructor de FormData (), que corrigió este código en Safari).

Ese código hace dos cosas.

  1. Recupera el atributo de nombre de input automáticamente, lo que hace que el HTML sea más fácil de mantener. Ahora, mientras la form tenga la clase putImages, todo lo demás se encargará de forma automática. Es decir, la input no necesita tener ningún nombre especial.
  2. El formato de matriz que envía HTML normal es recreado por JavaScript en la línea data.append. Tenga en cuenta los soportes.

Con estos cambios, el envío con JavaScript ahora produce exactamente la misma matriz $_FILES que el envío con HTML simple.


Todas las soluciones anteriores se ven bien y elegantes, pero el objeto FormData () no espera ningún parámetro, pero usa append () después de instanciarlo, como lo que se escribió anteriormente:

formData.append (val.name, val.value);


La respuesta de Devin Venable fue cercana a lo que quería, pero quería una que funcionara en varios formularios y utilizar la acción ya especificada en el formulario para que cada archivo vaya al lugar correcto.

También quería usar el método on () de jQuery para evitar el uso de .ready ().

Eso me llevó a esto: (reemplace formSelector con su selector jQuery)

$(document).on(''submit'', formSelecter, function( e ) { e.preventDefault(); $.ajax( { url: $(this).attr(''action''), type: ''POST'', data: new FormData( this ), processData: false, contentType: false }).done(function( data ) { //do stuff with the data you got back. }); });