Envío de datos multiparte/formularios con jQuery.ajax

Resuelto zoku asked hace 13 años • 14 respuestas

Tengo un problema al enviar un archivo a un script PHP del lado del servidor usando la función ajax de jQuery. Es posible obtener la lista de archivos, $('#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 utiliza la entrada del 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 menciones 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);
    }
});
zoku avatar Mar 22 '11 20:03 zoku
Aceptado

A partir de Safari 5/Firefox 4, es más fácil usar la FormDataclase:

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

Ahora tiene un FormDataobjeto, 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 contentTypeopción en false, lo que obligará a jQuery a no agregar un Content-Typeencabezado; de lo contrario, faltará la cadena de límite. Además, debe dejar el processDataindicador establecido en falso; de lo contrario, jQuery intentará convertirlo FormDataen una cadena, lo cual fallará.

Ahora puedes recuperar el archivo en PHP usando:

$_FILES['file-0']

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

Usando la emulación FormData para navegadores más 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 a partir de 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 nombre los elementos de su archivo de la misma manera y termine el nombre entre paréntesis:

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

$_FILES['file']Entonces habrá una matriz que contiene los campos de carga de archivos para cada archivo cargado. De hecho, recomiendo esto en lugar de mi solución inicial, ya que es más sencillo de iterar.

Raphael Schweikert avatar May 12 '2011 09:05 Raphael Schweikert

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();
  } );
Asad Ullah avatar Aug 30 '2014 06:08 Asad Ullah