Invio di multipart/formdata con jQuery.ajax

2022-05-31 21:30:26

Ho un problema nell'invio di un file a uno script PHP lato server utilizzando la funzione ajax di jQuery. È possibile ottenere l'elenco dei file con $('#fileinput').attr('files') ma come è possibile inviare questi dati al server? L'array risultante ($_POST) sullo script php lato server è 0 (NULL) quando si utilizza l'input file.

So che è possibile (anche se fino ad ora non ho trovato soluzioni jQuery, solo codice Prototye (http://webreflection.blogspot.com/2009/03/safari-4-multiple-upload-with-progress.html)).

Sembra essere relativamente nuovo, quindi non menzionare che il caricamento di file sarebbe impossibile tramite XHR/Ajax, perché sicuramente funziona.

Ho bisogno della funzionalità in Safari 5, FF e Chrome sarebbero utili ma non essenziali.

Il mio codice per ora è:

$.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

Source
Risposta


612
  • A partire da Safari 5/Firefox 4, è più semplice utilizzare la classe FormData:

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

    Quindi ora hai un oggetto FormData, pronto per essere inviato insieme a 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);
        }
    });
    

    È imperativo impostare l'opzione contentType su false, costringendo jQuery a non aggiungere un'intestazione Content-Type per tu, altrimenti, la stringa limite mancherà. Inoltre, devi lasciare il flag processData impostato su false, altrimenti jQuery tenterà di convertire il tuo FormData in una stringa, che avrà esito negativo.

    Ora puoi recuperare il file in PHP usando:

    $_FILES['file-0']
    

    (C'è un solo file, file-0, a meno che tu non abbia specificato l'attributo multiple nell'input del tuo file, nel qual caso i numeri aumenteranno di ogni file.)

    Utilizzo dell'emulazione FormData per i browser meno recenti

    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);
    

    Crea FormData da un modulo esistente

    Invece di iterare manualmente i file, l'oggetto FormData può anche essere creato con il contenuto di un oggetto modulo esistente:

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

    Utilizza un array nativo PHP invece di un contatore

    Basta nominare gli elementi del tuo file allo stesso modo e terminare il nome tra parentesi:

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

    $_FILES['file'] sarà quindi un array contenente i campi di caricamento del file per ogni file caricato. In realtà lo consiglio rispetto alla mia soluzione iniziale poiché è più semplice ripetere l'iterazione.