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>
Community
  • 1
  • 1
Brian Fleishman
  • 1,237
  • 3
  • 21
  • 43
  • 2
    Perhaps this will help you http://stackoverflow.com/questions/5392344/sending-multipart-formdata-with-jquery-ajax – Regular Jo Nov 06 '14 at 17:11
  • 1
    You should be using `cfqueryparam` in your query. NEVER trust user provided data. – Scott Stroz Nov 06 '14 at 17:12
  • 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(,)` 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. – Regular Jo Nov 06 '14 at 17:18
  • 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? – Brian Fleishman Nov 06 '14 at 17:41
  • 1
    @BrianFleishman I thought that maybe the jquery-related tips in the replies such as perhaps contentType and processData – Regular Jo Nov 06 '14 at 17:49
  • @BrianFleishman - It is not a quick task, not matter how you do it, but there are tools like [varScoper](http://varscoper.riaforge.org/) 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](http://stackoverflow.com/questions/2320069/jquery-ajax-file-upload). It explains the new options in greater detail. – Leigh Nov 06 '14 at 19:49
  • 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? – Brian Fleishman Nov 06 '14 at 19:51
  • 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. – Leigh Nov 06 '14 at 21:53

1 Answers1

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>
Community
  • 1
  • 1
Leigh
  • 28,765
  • 10
  • 55
  • 103