Upload size before CfFile-Upload

ColdFusion

ColdFusion

Introduction

Uploading files in ColdFusion is dead simple but there are a few quirks that some developers overlook.  One is that does the uploading… it doesn’t!  Any file that’s submitted from a form has already been uploaded to the server before any of your ColdFusion code is executed.  Those submissions are stored as temporary files with temporary names in the ColdFusion temporary directory (wow, that’s a lot of temporaries).  If you look at the contents of your upload form field you’ll see this information:

form.upload = C:\ColdFusion8\runtime\servers\coldfusion\SERVER-INF\temp\wwwroot-tmp\neotmp39336.tmp

Now we know where the upload is being kept.  Why would we want to bother with this?  One reason would be to check the upload size.

“Yeah but I can do that with the information cffile returns! What’s the point Dave!”.  Alright, chill out, I’m getting there.  If the file size is too big, do you really want to bother the server with the task of moving it from one place to another and would you then have to make sure you delete it.  If it’s too big and you leave it in that temporary directory, it’ll be removed anyway when your code has finished.  Seems a lot easier doesn’t it?

Here’s a little example on how to take this approach.  Note that I avoid using “form.upload” for the full path to the file in these examples.  This is because you really shouldn’t trust the use input that much and it’s much safer to get it from GetTempDirectory() instead and add the temp filename on the end.  Keep in mind that apart from that I’ve kept the examples simple which is why I didn’t bother checking if they didn’t upload a file on submit or anything else ;)

CF8/9

<cfset sizeLimit = 1048576 />
<cfif cgi.request_method Eq 'post'>
  fileInfo = GetFileInfo(GetTempDirectory() & GetFileFromPath(form.upload)) />
<cfif fileInfo.size Gt sizeLimit>
    <h2>File size is over the limit!</h2>
  <cfelse>
    <cffile action="upload" fileField="form.upload" destination="#ExpandPath('./')#" nameConflict="overwrite" />
    <h2>File uploaded successfully</h2>
  </cfif>
</cfif>

<form action="upload.cfm" method="post" enctype="multipart/form-data">
<input type="file" name="upload" />

<input type="submit" value="Upload" />
</form>

CF7

Sadly, CF7 doesn’t have the GetFileInfo() function so we’ll have to abuse the CfDirectory tag into getting us the information.

<cfset sizeLimit = 1048576 />
<cfif cgi.request_method Eq 'post'>
  <cfdirectory action="list" name="qFileInfo" directory="#GetTempDirectory()#" filter="#GetFileFromPath(form.upload)#" />
  <cfif qFileInfo.size Gt sizeLimit>
    <h2>File size is over the limit!</h2>
  <cfelse>
    <cffile action="upload" fileField="form.upload" destination="#ExpandPath('./')#" nameConflict="overwrite" />
    <h2>File uploaded successfully</h2>
  </cfif>
</cfif>

<form action="upload.cfm" method="post" enctype="multipart/form-data">
  <input type="file" name="upload" /><br />
  <input type="submit" value="Upload" />
</form>

CF10

It’d be nice if ColdFusion would actually make this kind of information more accessible.  A function like GetUploadInfo() would be fantastic if it returned a structure of form field names, the file sizes, locations and original file name! Sorry, but I really want to know the original filename before using CFFile, for all the same reasons that I like checking the file size.  Maybe I can pester Adobe during the next pre-release program :)

About these ads

11 thoughts on “Upload size before CfFile-Upload

  1. Andrew Scott

    Hmm, I don’t think you have read the documentation to well.

    ColdFusion on every cffile upload has all the information in the scope cffile. And guess what the size is there for you to see, and I am going by memory but it has been there since it was introduced in ColdFusion 3

    Reply
    1. misterdai Post author

      Hmm, I don’t think you have read my blog post to well.

      Sorry couldn’t resist. If you read my post you’ll spot that I’m doing this to avoid using cffile when I don’t have to. I know cffile will give me all the information I want, but it also moves the file. Maybe it’s because I came from PHP to ColdFusion but I want to know what’s going on before I move a file somewhere, as I’ll only have to delete it if it isn’t suitable.

      I think we all know cffile will tell you this, but by then you’ve already moved the file haven’t you? Seems less intensive to just use GetFileInfo and then ignore it if it’s beyond your imposed limit.

      Reply
        1. misterdai Post author

          PHP gives you the information via $_FILES right from the first line of your code. It contains the following lovely, useful information: file name (original), type (mime), size (bytes), tmp_name (on server), error (code if something went wrong). You can then use a function called “move_uploaded_file($tmp_name, $new_name)” to put the uploaded file where you want.

          ColdFusion however feels like it works backwards slightly. It hides all this upload information until you do the equilvalent of “move_uploaded_file” with “cffile action=upload”. All I’m showing in this blog post is how to get at some of that information, before you actually go and start moving some file, that you might not even want, around your server.

          Your question, “Why ask CF for something it already does?” because I want it before I move a file. If CF had a GetUploadInfo function, I’d be a happy chappy!

          Think of it this way, if you were eating dinner and didn’t have a knife, would you put the whole chicken in your mouth first and then decide it’s too big? Or would you look at it, realise it’s too big and ask for a knife next time?

        2. misterdai Post author

          Andrew, sorry if I’ve upset you as I see someone has voted down my comments and voted up yours. I may have appear frustrated as you seemed to dismiss my points without trying to understand them.

          My sole purpose of this post was to find a way to get file information about the upload, without worrying about moving a possibly large or invalid file to somewhere on the server. I have seen mention of attacks formed around uploads since in ColdFusion you’d have to move the file to another directory (what cffile action=upload does) before you see information about it, find out it’s invalid and delete it. During that brief amount of time, the attacker would be constantly requesting the uploaded file (possibly a .cfm file), giving them a small chance of executing code between the movement process and the deletion.

          A workaround to this would have been to move the file twice, once to a non-web accessible location where the file can then be validated. Then again to the final destination, if it’s valid.

          I wanted to avoid any movements of the file if it’s invalid. Preferring to see the information first before moving it around the server and avoiding any additional overhead.

          To this end, I’ve created a function that will dig out the original name as well as the file size.

          http://misterdai.wordpress.com/2010/06/23/form-scope-hidden-upload-details/

          I can also confirm that the powers that be at Adobe have agreed to add this as a feature to CF10.

  2. Seth

    I have been looking for the same information before CFFile is executed. I want the original filename. Why, because users are dumb and don’t follow the rules. They upload files that have characters like “:” in the filename. The windows filesystem is unable to accept a file with a “:” in the name and throws an error. I would rather check the filename prior to CFFILE and process it without throwing errors.

    Reply
  3. Andrew Scott

    I think you dont understand and it maybe that CF 10 might look at an alternative way of doing this, but at the end of the day you need to understand that every langauge is different. You might be Used to it one way that doesnt mean that what you are looking for, cant be done either.

    So you might wish to read the docs before such a post!

    Reply
    1. misterdai Post author

      Fine… I’ll bite. Seems like you’ve been trying to bait me for a more bullish response by voting down my comments and repeatedly telling me to read the docs. I especially enjoyed the exclamation mark. I’m half thinking you’re just doing this on purpose ;)

      Trust me, I’ve read the docs. Here’s what happens for a file to be uploaded in ColdFusion….
      1. User submits an upload via a form to the server.
      2. Web server receives request, passes it onto ColdFusion.
      3. ColdFusion accepts the request, stores the uploaded file in a temporary directory with a unique temporary name (*.tmp).
      4. ColdFusion then starts processing the requested .cfm file.
      5. CfFile is used. In the process, it moves & renames the file from the temporary directory to the destination provided to the tag.
      6. CfFile returns a structure containing information about the file (name, size, extension etc…).

      Agreed? I just want to check because I have previously encountered developers who think that the upload doesn’t actually happen until the cffile tag is executed. I’m guessing you’re smarter than that and understand that the upload is happily sitting in the temporary directory on the server before the .cfm template has started being executed. Maybe if the action had been called “moveUploadedFile” instead of “upload” there wouldn’t be any confusion.

      My issue. I’d like to know the details of that file, without moving it. If CfFile gave me that information, without forcing me to specify a destination directory I’d be a happy man and wouldn’t have bothered with this post. The file is already on the server, why force me to move it somewhere just to find it’s size and name? As Ben Nadel pointed out on my other post I linked to, it has been used as an attack vector.

      What’s wrong with wanting to be provided the information before taking action? Adobe seem to agree, they’ve accepted the idea. CF10 won’t be doing away with CfFile action=”upload” as my whole post is not about replacing it, it’s about providing some information so you can decide if you want to “move” the file or just ignore it.

      Now, if you still think I should read the docs you’re obviously not bothering to even try and understand my posts and release that I know exactly what CfFile action=”upload” does. I know languages are different as well, that’s not my problem either. My problem is I like having all the information to hand, before making a decision. ColdFusion knows the original file name and can easily find out the size, I think it’d be beneficial to developers if it’d share that information, before forcing us to move the file.

      So… how about you and I just agree to disagree? You’re happy to let CfFile move the uploaded file somewhere and then find out the information to see if the file is valid. I’d prefer it if I had that information first, so I can see if it’s valid before moving the uploaded file, because I might not want to move it.

      I don’t think there’s any need to belittle me and imply I don’t know what the CfFile tag is doing. Why not just say that you’re happy to move files around your server without knowing what they are, until after you’ve moved them? Nothing wrong with that, especially if you’re moving them to a non-web accessible directory first. Heck, I’ll even buy you a beer and talk this out if we ever end up at the same CF conference as each other.

      Reply
  4. thekillertipsMisty

    Hi Guys, Just read your Post and Comments.
    Just wanna post this:

    Why this is not the right way of doing it:

    The trick is simple: CGI.CONTENT_LENGTH
    Stop the upload before it begins!

    Upload

    #URL.NOTE#

    Source File Name:

    Reply
    1. misterdai Post author

      Nice idea but the by the time your ColdFusion code starts executing, the upload has already finished. So when you check CGI.ContentLength, the upload is already present on your server in a temporary location. My workaround is simply to avoid having to move the file (which is all CFFile Upload actually does) if it’s file extension isn’t to your liking.

      Hope that makes sense :)

      Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s