0

I keep running into an issue getting the file(s) added in AJAX so that the server ajax function can process the data. How can I get the $_FILES to be passed the same as with the default action (built into form elements)?

HTML Form

<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" >Import</button>
</form>

JavaScript

    jQuery(document).ready(function($) {
    //This is already setup and sent from the server side, and is
    // is used to prevent unauthorized users from uploading data.
    var importnonce = "3x4mpl3f4k3n0nc3"; 

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

        // CHECK FOR ANY ERRORS HERE.
        // IF ERRORS EXIST, RETURN FALSE TO END OPERATIONS.

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

        // Issue occures here. PHP gets a string '[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("Haven't entered server side yet.");
            },
            dataFilter: function(data, type) {
                // Used to parse data, and possibly check for errors.
                console.log("JSON string echoed back from server side.");
            },
            success: function(data, textStatus, jqXHR) {
                console.log("Back from server-side!");
                // Checking errors that may have been caught on the server side that
                // normally wouldn't display in the error Ajax function.
                if (data.msg != 'success') {
                    alert(data.error);
                }
            },
            error: function(jqXHR, textStatus, errorThrown) {
                console.log("A JS error has occurred.");
            },
            complete: function(jqXHR, textStatus) {
                console.log("Ajax is finished.");
            }
        });

        return false;
    });
});

PHP Server/Handler

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

        $rtnData = new stdClass();
        $rtnData->msg = 'success'; //For signifying Server errors
        $rtnData->error = ''; //For displaying custom error messages or using the try/catch method

        //Do Stuff
        foreach ($_FILES as $key => $value) {
            //GET FILE CONTENT
            $file_array[$key] = json_decode(file_get_contents($value['tmp_name']));
        }

        // Do more stuff with file(s).

        // Add stuff to $rtnData.

        echo json_encode($rtnData);
    }
}
?>
3

I haven't tried but i think you need to add FormData object directly as data parameter. Something like this

    var ajaxData = new FormData();

    ajaxData.append( 'action', 'ajax_handler_import' );
    ajaxData.append( '_ajax_nonce', importNonce );
    // or maybe skip the nonce for now

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

The rest of your code goes as it is

2
  • Sorry I haven't replied sooner...I was trying to finish out a project, and figured I'd come back when I have more knowledge on the subject. Thanks for providing the solution, I didn't know adding the FormData object to an object would mess it up, and I was running out of ideas. Figures it would be a simple problem xP. The lesson learned here: stay away from mixed objects. – EkoJR Dec 1 '12 at 9:44
  • Not to mention this won't work on IE9 and below IE versions. – Arda Nov 3 '15 at 15:32
1

Ajax in the traditional sense is XMLHttpRequest, which does not allow you encode and send local files to a server.

The common ways of doing uploading through "ajax" means, is to either use a Flash swf to handle the uploading on the same page, or to use a form that has a target of an invisible 1x1 iframe.

Here is a very similar question with a good answer to see how you can do that

2
  • Yea, I was going through that Q/A recently. Unfortunately, I'm not familiar with flash, and I've been trying to avoid adding plugins if at all possible. I've mainly been trying to follow WordPress Ajax method, but by what I've found, just passing it to ajax is restricted/limited by the browsers. Mainly refering to this Q/A led me to FormData Objects which says is possible if the browser used has it. – EkoJR Nov 2 '12 at 8:45
  • It turns out that you can use your own methods for passing file data over to an AJAX function instead of relying on a JS plugin. For the most part, FormData Objects (as mentioned above), handles this with XMLHttpRequest Level 2 operations (as I currently understand it), and is supported by all major browsers now. I figured it would be a matter of time after HTML5 came out. However, using plUpload is a possible recommendation for large file data. – EkoJR Dec 1 '12 at 9:54
1

Here's the solution that I was able to find, and I actually see quite a few common mistakes that were made.

  • Files weren't being appended properly in JS.
  • AJAX dataFilter: function() could be replaced with dataType: 'json'.
  • JS submit doesn't need to return false to stop the form action.
    • Could be replace with event.stopPropagation() & e.preventDefault().
    • Add an empty form action in HTML.
  • PHP function for AJAX wasn't ending with 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" >Import</button>
</form>

JavaScript

jQuery(document).ready(function($){
    // PHP files could echo an Nonce. This however localizes scripts.
    var importNonce = localizedData.import_nonce;

    $('#form_import').submit( function( event ) {
        event.stopPropagation(); // Stop stuff happening
        event.preventDefault(); // Totally stop stuff happening

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

        // For EACH file, append to formData.
        // NOTE: Just appending all of importFiles doesn't transition well to 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', // This replaces dataFilter: function() && JSON.parse( data ).
            processData: false, // Don't process the files
            contentType: false, // Set content type to false as jQuery will tell the server its a query string request


            beforeSend: function( jqXHR, settings ){
                // (OPTIONAL) Alt. AJAX concept.
                // Removes the old IFrame if any.
                var element = document.getElementById('import_IF');
                if ( element !== null ){
                    element.parentNode.removeChild( element );
                }
                // END (OPTIONAL).
            },
            success: function( data, textStatus, jqXHR ) {
                console.log( 'Return from PHP AJAX function/method.' );

                // Do stuff with data.values

                // (OPTIONAL) Alt. AJAX concept.
                // Required for downloading 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);
                // END (OPTIONAL).
            },
            complete: function(jqXHR, textStatus){
                console.log( 'AJAX is complete.' );

                // (OPTIONAL) Alt. AJAX concept.
                // Clean up IFrame.
                var element = document.getElementById('import_IF');
                if ( element !== null ){
                    element.parentNode.removeChild( element );
                }
                // END (OPTIONAL).
            }
        });// End AJAX.
    });// End .submit().
});

PHP

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

    public funtion 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();
        // Do Stuff with new data.
        update_option( 'example_database', $new_data );

        // (OPTIONAL) Add data to return to AJAX Success
        $rtn_data = array(
            'action'               => 'apl_import',
            '_ajax_nonce'          => wp_create_nonce( 'alt_ajax' ),
        );
        echo json_encode( $rtn_data );
        // END (OPTIONAL).

        die();
    }
}
?>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.