Come Importare/Caricare File con jQuery AJAX?

1 nov 2012, 15:08:14
Visualizzazioni: 66.2K
Voti: 0

Continuo a incontrare un problema nell'aggiungere i file tramite AJAX in modo che la funzione ajax del server possa elaborare i dati. Come posso far passare $_FILES allo stesso modo della action predefinita (incorporata negli elementi del form)?

Form HTML

<form id="frmImport" name="frmImport" method="post" enctype="multipart/form-data" >
    <input id="file_import" name="importData" type="file" />
    <br/>
    <button id="btn_import" type="submit" >Importa</button>
</form>

JavaScript

    jQuery(document).ready(function($) {
    // Questo è già configurato e inviato dal lato server, e viene
    // utilizzato per impedire agli utenti non autorizzati di caricare dati.
    var importnonce = "3x4mpl3f4k3n0nc3"; 

    $('#frmImport').submit(function(e) {
        e.preventDefault();

        // CONTROLLA SE CI SONO ERRORI QUI.
        // SE ESISTONO ERRORI, RITORNA FALSE PER TERMINARE LE OPERAZIONI.

        var formData = new FormData();
        formData.append('action', 'ajax_handler_import');
        formData.append('_ajax_nonce', importNonce);

        // Il problema si verifica qui. PHP riceve una stringa '[object FormData]'.
        var importFiles = $('#file_import')[0].files;
        formData.append('uploadFiles', importFiles);

        jQuery.ajax({
            url: ajaxurl,
            type: 'POST',
            cache: false,
            contentType: false,
            processData: false,

            data: formData,

            beforeSend: function(jqXHR, settings) {
                console.log("Non ancora entrato lato server.");
            },
            dataFilter: function(data, type) {
                // Utilizzato per analizzare i dati e possibilmente controllare gli errori.
                console.log("Stringa JSON restituita dal lato server.");
            },
            success: function(data, textStatus, jqXHR) {
                console.log("Ritorno dal lato server!");
                // Controllo degli errori che potrebbero essere stati rilevati sul lato server
                // che normalmente non verrebbero visualizzati nella funzione Ajax di errore.
                if (data.msg != 'success') {
                    alert(data.error);
                }
            },
            error: function(jqXHR, textStatus, errorThrown) {
                console.log("Si è verificato un errore JS.");
            },
            complete: function(jqXHR, textStatus) {
                console.log("Ajax è terminato.");
            }
        });

        return false;
    });
});

PHP Server/Handler

<?php
class server {
    function ajax_import_handler() {
        check_ajax_referer("ajax_handler_import");

        $rtnData = new stdClass();
        $rtnData->msg = 'success'; // Per segnalare errori del Server
        $rtnData->error = ''; // Per visualizzare messaggi di errore personalizzati o utilizzare il metodo try/catch

        // Esegui operazioni
        foreach ($_FILES as $key => $value) {
            // OTTIENI IL CONTENUTO DEL FILE
            $file_array[$key] = json_decode(file_get_contents($value['tmp_name']));
        }

        // Esegui altre operazioni con i file.

        // Aggiungi elementi a $rtnData.

        echo json_encode($rtnData);
    }
}
?>
0
Tutte le risposte alla domanda 3
2

Non ho provato ma penso che tu debba aggiungere l'oggetto FormData direttamente come parametro data. Qualcosa come questo:

    var ajaxData = new FormData();

    ajaxData.append( 'action', 'ajax_handler_import' );
    ajaxData.append( '_ajax_nonce', importNonce );
    // oppure forse salta il nonce per ora

    jQuery.each($('#fileImportData')[0].files, function(i, file) {
        ajaxData.append('file-'+i, file);
    });

Il resto del tuo codice rimane come è

1 nov 2012 15:33:21
Commenti

Scusa se non ho risposto prima... Stavo cercando di finire un progetto e ho pensato di tornare quando avrò più conoscenza sull'argomento. Grazie per aver fornito la soluzione, non sapevo che aggiungere l'oggetto FormData a un oggetto potesse causare problemi, e stavo finendo le idee. Immaginavo fosse un problema semplice xP. La lezione imparata qui: evita oggetti misti.

EkoJR EkoJR
1 dic 2012 11:44:29

Per non parlare del fatto che questo non funzionerà su IE9 e versioni precedenti di IE.

Arda Arda
3 nov 2015 17:32:49
2

Ajax nel senso tradizionale è XMLHttpRequest, che non consente di codificare e inviare file locali a un server.

I modi comuni per effettuare il caricamento tramite mezzi "ajax", sono utilizzare un file Flash swf per gestire il caricamento sulla stessa pagina, oppure utilizzare un modulo che ha come target un iframe invisibile 1x1.

Ecco una domanda molto simile con una buona risposta per vedere come puoi farlo

1 nov 2012 15:51:04
Commenti

Sì, stavo esaminando quel Q/A di recente. Sfortunatamente, non ho familiarità con Flash e ho cercato di evitare l'aggiunta di plugin quando possibile. Ho principalmente seguito il metodo Ajax di WordPress, ma da quello che ho scoperto, passare semplicemente i dati ad Ajax è limitato/ristretto dai browser. Principalmente riferendomi a questo Q/A mi ha portato agli oggetti FormData che dicono essere possibili se il browser utilizzato li supporta.

EkoJR EkoJR
2 nov 2012 10:45:07

Si scopre che puoi utilizzare i tuoi metodi per passare i dati dei file a una funzione AJAX invece di affidarti a un plugin JS. Per la maggior parte, gli oggetti FormData (come menzionato sopra), gestiscono questo con operazioni XMLHttpRequest Level 2 (per come lo capisco attualmente), ed è supportato da tutti i principali browser ora. Immaginavo che sarebbe stata questione di tempo dopo l'uscita di HTML5. Tuttavia, l'uso di plUpload è una possibile raccomandazione per file di grandi dimensioni.

EkoJR EkoJR
1 dic 2012 11:54:53
0

Ecco la soluzione che sono riuscito a trovare, e in realtà vedo diversi errori comuni che sono stati commessi.

  • I file non venivano aggiunti correttamente in JS.
  • L'AJAX dataFilter: function() poteva essere sostituito con dataType: 'json'.
  • Il submit JS non ha bisogno di restituire false per fermare l'azione del form.
    • Poteva essere sostituito con event.stopPropagation() e e.preventDefault().
    • Aggiungere un'azione vuota al form in HTML.
  • La funzione PHP per AJAX non terminava con die().

HTML

<form id="form_import" name="form_import" method="post" enctype="multipart/form-data" action >
    <input id="file_import" name="import_data" type="file" />
    <br/>
    <button id="btn_import" type="submit" >Importa</button>
</form>

JavaScript

jQuery(document).ready(function($){
    // I file PHP potrebbero restituire un Nonce. Questo però localizza gli script.
    var importNonce = localizedData.import_nonce;

    $('#form_import').submit( function( event ) {
        event.stopPropagation(); // Ferma le azioni predefinite
        event.preventDefault(); // Blocca completamente le azioni predefinite

        var formData = new FormData();
        var importFiles = $('#file_import')[0].files;

        // Per OGNI file, aggiungi a formData.
        // NOTA: Aggiungere semplicemente tutti i importFiles non si traduce bene in PHP.
        jQuery.each( importFiles, function( index, value ) {
            var name = 'file_' + index;
            formData.append( name, value )
        });

        formData.append( 'action', 'ajax_file_import' );
        formData.append( '_ajax_nonce', importNonce );

        jQuery.ajax({
            url: ajaxurl,
            type: 'POST',
            data: formData,
            cache: false,
            dataType: 'json', // Questo sostituisce dataFilter: function() && JSON.parse( data ).
            processData: false, // Non elaborare i file
            contentType: false, // Imposta il content type a false poiché jQuery dirà al server che è una richiesta di query string


            beforeSend: function( jqXHR, settings ){
                // (OPZIONALE) Concetto alternativo AJAX.
                // Rimuove il vecchio IFrame se presente.
                var element = document.getElementById('import_IF');
                if ( element !== null ){
                    element.parentNode.removeChild( element );
                }
                // FINE (OPZIONALE).
            },
            success: function( data, textStatus, jqXHR ) {
                console.log( 'Risposta dalla funzione/metodo PHP AJAX.' );

                // Fai qualcosa con data.values

                // (OPZIONALE) Concetto alternativo AJAX.
                // Necessario per il download in AJAX.
                var paramStr = '';
                paramStr += '?_ajax_nonce=' + data._ajax_nonce;
                paramStr += '&action='      + data.action;
                paramStr += '&filename='    + data.filename;

                var elemIF = document.createElement("iframe");
                elemIF.id = 'import_IF'
                elemIF.style.display = "none";
                elemIF.src = ajaxurl + paramStr;

                document.body.appendChild(elemIF);
                elemIF.parentNode.removeChild(elemIF);
                // FINE (OPZIONALE).
            },
            complete: function(jqXHR, textStatus){
                console.log( 'AJAX completato.' );

                // (OPZIONALE) Concetto alternativo AJAX.
                // Pulizia IFrame.
                var element = document.getElementById('import_IF');
                if ( element !== null ){
                    element.parentNode.removeChild( element );
                }
                // FINE (OPZIONALE).
            }
        });// Fine AJAX.
    });// Fine .submit().
});

PHP

<?php
class server {
    public function __construct() {
        // Esempio per aggiungere script.
        add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_example' ) );
        add_action( 'wp_ajax_ajax_file_import', array( $this, 'ajax_import_example' ) );
    }

    public function enqueue_example() {
        wp_register_script(
            'example-js',
            FILE_URL,
            array(),
            VERSION,
            false
        );
        wp_enqueue_script( 'example-js' );

        $data = array(
            'import_nonce'  => wp_create_nonce( 'ajax_file_import_nonce' ),
        );

        wp_localize_script( 'example-js', 'localizedData', $data );
    }

    public function ajax_import_example() {
        check_ajax_referer( 'ajax_file_import_nonce' );

        $raw_content = array();
        $i = 0;
        while ( isset( $_FILES[ 'file_' . $i ] ) ) {
            $file_arr = $_FILES[ 'file_' . $i ];
            $file_content = file_get_contents( $file_arr['tmp_name'] );
            $raw_content[]  = json_decode( $file_content );
            $i++;
        }

        $new_data = array();
        // Fai qualcosa con i nuovi dati.
        update_option( 'example_database', $new_data );

        // (OPZIONALE) Aggiungi dati da restituire ad AJAX Success
        $rtn_data = array(
            'action'               => 'apl_import',
            '_ajax_nonce'          => wp_create_nonce( 'alt_ajax' ),
        );
        echo json_encode( $rtn_data );
        // FINE (OPZIONALE).

        die();
    }
}
?>
2 lug 2017 10:41:15