Uploading a file with AJAX and CFFILE [duplicate]
Asked Answered
T

1

7

I have a small form where I would like to upload a file to my CF Server. I have been able to make this work in the past by submitting my CFFORM via a traditional actionpage. However I would like to upload the file using AJAX instead.

I am receiving an error on my processing page as follows: The cffile action="upload" requires forms to use enctype="multipart/form-data" even though I have defined my form as such.

From google'ng around, I think it may be becasue Cffile requres the filefield attribute, but as there is no form object passed to coldfusion. Possible Similar Issue . I don't really like the solution posted though.

Is there anyway I could get around this error?

Here is my AJAX:

<!---Script to upload file link --->     
<cfoutput>
<script>
$(function(){
//Add a new note to a link
$("##upload-file").submit(function(event){
   // prevent native form submission here
   event.preventDefault();
        $.ajax({
            type: "POST",
            data: $('##upload-file').serialize(),
            url: "actionpages/file_upload_action.cfm",
            beforeSend: function(){
                $('.loader').show();
            },
            complete: function(){
                 $('.loader').hide(3000);
            },
            success: function() {
                PopulateFileUploadDiv();
                $("##upload").val('');
                $("##response").append( "File successfully Uploaded." );
              }    
        });
        return false;           
    });
});
</script>
</cfoutput>

My Form:

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

      <input tabindex="0" size="50" type="file" id="upload" name="upload" accept="image/bmp, image/jpg, image/jpeg, image/tiff, image/gif, image/png, text/richtext, text/plain, text/css, text/html, application/rtf, application/msword, application/x-excel, application/zip, multipart/x-zip, audio/wav" value="Upload an additional file" />

      <br />
      <input name="submitForm" id="submitForm" type="submit" value="Attach File To Ticket">

      </form>

Processing Page:

<!---File Upload Logic --->

        <!---CFFile Tag located in template file --->
        <!---CFFile code --->
        <cffile action="upload" filefield="upload" destination="c:\inetpub\wwwroot\ticket-uploads\" accept="image/bmp, image/jpeg, image/jpg, image/tiff, image/gif, image/png, text/richtext, text/plain, text/css, text/html, text/xml, application/x-zip-compressed, application/xml, application/mspowerpoint, application/powerpoint, application/vnd.openxmlformats-officedocument.presentationml.presentation , application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-powerpoint, application/x-mspowerpoint, application/octet-stream, application/pdf, application/rtf, application/msword, application/x-excel, application/zip, multipart/x-zip, audio/wav" nameconflict="makeunique">

       <!---Retrieve Uploaded filename --->
        <cfoutput>
        <cfset Uploaded_File_Name = #cffile.ServerFile#>
        </cfoutput>

        <!--- Add file details to file_uploads table --->
        <cfquery name="uploads" datasource="#datasource#">
        insert into file_uploads (ticket_id, file_path)
        values(#form.ticket_id#, '#Uploaded_File_Name#')
        </cfquery>
Tayib answered 6/11, 2014 at 17:5 Comment(8)
Perhaps this will help you #5392844Crazed
You should be using cfqueryparam in your query. NEVER trust user provided data.Viscometer
Yes, certainly, as Scott said. Use the tag cfqueryparam. All it takes is one mischievous submission to destroy lots of valuable work and data,. change the values line of your query to VALUES(<cfqueryparam cf_sql_type="cf_sql_integer" value="#form.ticket_id#">,<cfqueryparam cf_sql_type="cf_sql_varchar" value="#uploaded_file_name#">) Note the lack of single-quotes. cf_sql_type dictates their presence. However, this has no impact on the problems your having, just stops sql injection. use CFQUERYPARAM for literally every #variable# in every query.Crazed
Yes I agree. I'm slowly going though all my queries and changing them over. I literally have hundreds to change. Not fun. @cfqueryparam - this post has php processing. Are you suggesting the my cffile code would stay the same, I would just use that FormData class?Tayib
@BrianFleishman I thought that maybe the jquery-related tips in the replies such as perhaps contentType and processDataCrazed
@BrianFleishman - It is not a quick task, not matter how you do it, but there are tools like varScoper that make it a little easier. RE: this post has php processing I think you can ignore the PHP stuff, the important part is the js ie sending the file using ajax. You might also find this thread helpful: jQuery Ajax File Upload. It explains the new options in greater detail.Bussey
I looked through the comments and I can't seem to figure out what to implement here. Kind of a newbie to Jquery. Can you provide some suggestions?Tayib
Nothing to do with your question at all, but cfoutput tags are not needed as often as you might think. They are not needed around the cfset. If fact you do not even need the extra variable. You could simply use cffile.ServerFile directly in your cfqueryparam.Bussey
B
6

As @cfqueryparam mentioned in the comments, the key is the javascript code. In particular, the contentType and processData settings. The action page can be written in any server side language.

Just to demonstrate, the example in this thread works fine. At least in newer browsers. Aside from dumping the status to a div, the only thing I changed was the input name. That is because FILE is a keyword in CF.

Upload

<!DOCTYPE html>
<html>
<head>
    <title>Image Upload Form</title>
    <script src="//code.jquery.com/jquery-1.9.1.js"></script>
    <script type="text/javascript">
        function submitForm() {
            console.log("submit event");
            var fd = new FormData(document.getElementById("fileinfo"));
            $.ajax({
              url: "action.cfm",
              type: "POST",
              data: fd,
              enctype: 'multipart/form-data',
              processData: false,  // tell jQuery not to process the data
              contentType: false   // tell jQuery not to set contentType
            }).done(function( response ) {
                // display response in DIV
                $("#output").html( response.toString());
            })
           .fail(function(jqXHR, textStatus, errorMessage) {
                // display error in DIV
                $("#output").html(errorMessage);
            })            
            return false;
        }
    </script>
</head>

<body>
    <form method="post" id="fileinfo" name="fileinfo" onsubmit="return submitForm();">
        <label>Select a file:</label><br>
        <input type="file" name="upload" required />
        <input type="submit" value="Upload" />
    </form>
    <div id="output"></div>
</body>
</html>

action.cfm

<cffile action="upload" filefield="upload" 
    destination="c:/temp/" 
    nameconflict="makeunique"
    result="uploadResult">
<!--- Quick and dirty response dump for DEV/Debugging only --->
<cfoutput>#serializeJSON(uploadResult)#</cfoutput>
Bussey answered 6/11, 2014 at 21:46 Comment(1)
Thanks for the example. I noticed that as well and changed my field name to upload.Tayib

© 2022 - 2024 — McMap. All rights reserved.