21 Replies Latest reply on Mar 11, 2008 11:52 PM by BKBK

    Uploaded filename, before CFFile

    elpestybandito Level 1
      Hi,

      I'm doing some form data validation and would like to add rules for files (size and type). Ideally I want to avoid CFFile as the validation shouldn't have anything to do with moving the file anywhere.

      I know that when ColdFusion processes an upload, it stores it in a temporary directory and filename. This is stored in the form field (e.g. form.file = c:\sometempdirectory\blahxxx.tmp) and I can use that to do a GetFileInfo and find out the filesize. Awesome.... except it's called blahxxx.tmp :(

      I want to know the real filename, not the temp filename but I can't find it anywhere. ColdFusion must know it, probably hidden along with its other darkest secrets, as it'll use it when we do a CFFile action="upload". So where is it being hidden? Any ideas?

      I have seen suggestions of using an extra hidden field plus some javascript, but to be honest, I don't like trusting something like that as it's possible to abuse it. I've also gone hunting inside "getPageContext().getRequest()" but not being any good with Java I haven't a clue where to start.

      Please help :)
      Ta,
      Dave
        • 1. Re: Uploaded filename, before CFFile
          bobmoles
          look at #cffile.clientFile# I would start by doing a <cfdump var="#FILE#"> and <cfdump var="#CFFILE#"> Then you can look at all the properties of the two structs and decide what you are actually looking for. CFDump and CFAbort are two of your best friends when you start moving into new waters....
          • 2. Uploaded filename, before CFFile
            elpestybandito Level 1
            Thanks for the reply Bob, but I think you may have missed what I'm trying to do.

            I'll summarise it for everyone...

            Form.cfm

            * Form page has a file field
            * User selects the file "rincewind.txt" and clicks submit.
            * Form action points at save.cfm

            Save.cfm
            * Validation.cfc created and given rules.
            * Validates file size by using GetFileInfo(form.file).
            * Tries to validate file type but form.file ends in .tmp not .txt

            My problem is I want the real filename. There is no CFFile action="upload" in save.cfm so the file / cffile variables do not exist. All I'm currently doing is validation and I don't want my validation component moving files about the place as I'd then have the extra work of cleaning up if they're invalid and letting everything else know it's new location.

            My theory is ColdFusion must hold the original filename somewhere before the CFFile since it'll rename and move the file. CFFile action="upload" can be misleading too, as the file has already been uploaded and stored in a temporary directory by ColdFusion (check out the form variable next time you do an upload), but (oh woe is me) with a tmp extension so I can't validate it. :(
            • 3. Re: Uploaded filename, before CFFile
              Level 7
              elpestybandito wrote:
              > I haven't a clue where to start.
              >
              > Please help :)

              Start by understanding the HTTP request/response client/server process.

              1) A user viewing a form in a browser selects a file to be uploaded and
              submits the form. The browser reads the file from the user's system and
              puts it into the request which then it sends to the web server.

              2) The web server receives the request, takes the file from the request
              and writes it to a temporary location on the server. It then passes the
              request on to ColdFusion telling it where the temporary file is located.

              3) ColdFusion then does what you request it to do with the file
              according the the <cffile...> and other CFML instructions.

              Understanding this process you can see what you ask is impossible and
              does not make sense. You can not process the file name on the server
              before the file is sent because the browser does not send this
              information ahead of the file it sends the entire file, name and all,
              when the form action request is made.

              Your interceptions points are on the client, which requires some kind of
              client side technology such as JavaScript.

              In the web server. Some of which offer some type of scripting
              capabilities that may do what you want.

              In the Application Sever, i.e. ColdFusion. This is the easiest and best
              practice and should always be done. Even if you do a client side option
              , such as JavaScript, you will want to back it up with a Server Side
              solution for just the reason you mentioned. Client side code and be
              messed with and circumvented.


              • 4. Re: Uploaded filename, before CFFile
                Level 7
                elpestybandito wrote:
                > My theory is ColdFusion must hold the original filename somewhere
                > before the CFFile since it'll rename and move the file. CFFile
                > action="upload" can be misleading too, as the file has already been uploaded
                > and stored in a temporary directory by ColdFusion (check out the form variable
                > next time you do an upload), but (oh woe is me) with a tmp extension so I can't
                > validate it. :(
                >
                >

                You do understand the HTTP request/response client/server scenario (many
                people who post questions like this do not). Try investigating the CGI
                scope and the request header/body. I would suspect the file name is
                buried in one or more of those locations. I don't recall off the top of
                my head how one inspects the request head and body, but I suspect Google
                would quickly cough up examples.
                • 5. Re: Uploaded filename, before CFFile
                  elpestybandito Level 1
                  Thanks, I've tried hunting through the CGI scope but using ColdFusion 8 the request body (usually used for the post variables) is always empty. This is due to a setting to stop extremely large uploads from being held in memory.

                  I had thought about hunting through the getPageContext().getRequest() or other areas in that function but since finding out that the contents isn't held I guess it wouldn't be stored in there either.

                  I just feel like there's an extra step that's involved for little reason with file uploads in ColdFusion that could be avoided if there was some access to the original filename.

                  For exampe:
                  * Validating the file extension, as you'd want to know it's a valid file before moving it.
                  * Uploading files to the database. You can do a <cffile action="readbinary" file="#form.file#" variable="blob" /> to get the uploaded file (without bothering with action="upload" at all) and store it in a database. One less step but currently you lose the original filename.

                  I guess that unless someone knows where the real filename is hidden I'll be all out of luck.
                  • 6. Re: Uploaded filename, before CFFile
                    c_wigginton Level 1
                    The following script will capture the user's full path to the file in a hidden field. From there, you can extract out the filename on the form submission before you process the cffile.
                    • 7. Re: Uploaded filename, before CFFile
                      elpestybandito Level 1
                      Thanks c_wigginton, but my plan was to avoid anything client side. Since I didn't want someone to come along, disable JavaScript and enter something in the hidden field that's different from the existing field.

                      • 8. Re: Uploaded filename, before CFFile
                        c_wigginton Level 1
                        I went down your same path awhile ago and couldn't find any alternatives other than client side when using CFFILE. CFFILE prior to CF8 is also memory intensive. You can look at is using something other than CF for the file upload. I've used JavaZoom's upload bean which uses JSP's and POJO's for the upload and works with JRun. The UploadBean provides the ability to obtain the uploaded file name.

                        http://www.javazoom.net/jzservlets/uploadbean/documentation/developerguide.html

                        Having said that, you really need to ask yourself is why are you completely afraid of client side? The key point is you don't have much control anyways from a client perspective on what is getting uploaded prior to the upload event. You can certainly apply filtering through a CFFILE accept attribute, but you can't guarantee the name of the file or what is in the file.

                        For example, you can use a simple copy command to combine a gif images with other file types, the below web link references combination with MP3. The uploaded file will still identify as a gif mime type even though there's hidden data in the file.

                        ref: http://www.raymond.cc/blog/archives/2006/06/26/hide-mp3-audio-inside-gif-picture/

                        So worrying about someone hacking the uploaded file name in a hidden field is moot since they could simply rename the file anything they wanted before selecting it in the browser.

                        As far as turning off JavaScript, you can force JavaScript being enabled by having the submit button being disabled and then enable the button when the document is loaded. jQuery is really nice for this.
                        • 10. Re: Uploaded filename, before CFFile
                          elpestybandito Level 1
                          Thanks for the info c_wigginton, it's certainly true that there are still ways to get around any restrictions I try and place on the file type but I still like to do as much as I can server-side in the way of validation.

                          Azadi, thanks for the link, that's not a bad idea about the file checking that way.

                          In the end I've gone for the following example, I'm using CF8 so it doesn't seem to affect performance from what I can tell. I would be so much easier if I had the original filename another way but I guess this'll have to do.

                          <!--- Retrieve the file information by making a copy --->
                          <cffile action="upload" filefield="form.file" nameconflict="makeUnique" result="info" destination="#GetTempDirectory()#" />
                          <!--- Remove the temp copy --->
                          <cffile action="delete" file="#GetTempDirectory()#\#info.serverFile#" />

                          This way any code that wishes to do a CFFile action="upload" will still work and I get to validate the filename. Seems a bit much overhead but unless Adobe give up the secret of where the name is kept... ;)
                          • 11. Re: Uploaded filename, before CFFile
                            hatethisnamegame
                            function getFileName(tf, tfn)
                            {
                            var f = document.getElementById(tf);
                            var fv = f.value
                            var s = fv.lastIndexOf("\\");
                            var n = fv.substring(s + 1);
                            document.getElementById(tfn).value = n;
                            return true;
                            }

                            In the above:
                            tf is the file field on the form
                            tfn is a hidden field that you save the file name in that you parsed from the file field
                            • 12. Re: Uploaded filename, before CFFile
                              hatethisnamegame Level 1
                              Oh Yes, call the function with the onsubmit on the form
                              • 13. Uploaded filename, before CFFile
                                BKBK Adobe Community Professional & MVP
                                Elpestybandito wrote:
                                I know that when ColdFusion processes an upload, it stores it in a temporary directory and filename. This is stored in the form field (e.g. form.file = c:\sometempdirectory\blahxxx.tmp) and I can use that to do a GetFileInfo and find out the filesize. Awesome.... except it's called blahxxx.tmp :(

                                What you've described is not always the case. That is what happens if you don't specify a full path to a directory as the destination attribute, when you upload the file in the first place. (Or if you, for some bizarre reason, specify Coldfusion's system temp directory as the destination).

                                As an example, create the directory c:\my_uploaded_pics\. When you run the code below, Coldfusion will save the image, including its real name and extension, in your directory. Practically all the information you seek with getFileInfo is contained in the structure cffile.

                                • 14. Re: Uploaded filename, before CFFile
                                  elpestybandito Level 1
                                  Thanks everyone for taking the time to check this topic but I've given up on what I was really after. But I will try to explain it as everyone seems to be mis-understanding what actually happens and what I was after.

                                  Firstly, I didn't want to rely on Client-side JavaScript because that's more open to abuse if not checked on the server-side.

                                  Now imagine I have two files. Form.cfm and Save.cfm. Form.cfm contains just the form with a file upload box, this form submits to Save.cfm.

                                  Now for save.cfm, there seems to be some confusion that the upload doesn't happen until you do cffile action="upload". This is not the case and I'll show this here.

                                  Save.cfm

                                  <cfdump var="#form.upload#" />
                                  <!--- Will display the temporary location of the upload
                                  The variable simple contains a string, nothing special
                                  --->
                                  <cfdump var="#GetFileInfo(form.upload)#" />
                                  <!--- Will display file size and other details --->
                                  <cffile action="read" file="#form.upload#" variable="file" />
                                  <!--- File variable now contains the contents of the upload --->
                                  <cfquery name="qInsertDoc" datasource="aDsn">
                                  INSERT INTO tblDocs (upload)
                                  VALUES (
                                  <cfqueryparam cfsqltype="cf_sql_blob" value="#file#" />
                                  )
                                  </cfquery>

                                  Now, please notice I didn't once use CFFile action="upload" but I still get the file and throw it into the database. More importantly the upload has already taken place and finished before save.cfm is executed. The only difference between doing it this way and doing it the cffile action="upload" way is I can't find out the original filename. All I ever wanted to know was where ColdFusion is hiding that name.

                                  The reason I'm after that, without doing a CFFile action="upload", is this because I didn't want my validation component creating a copy of a file (which is all cffile action="upload" does) just to find out it's original name in order to validate it. And remember I don't want to rely on client-side JavaScript as that can be circumvented.

                                  Thanks
                                  • 15. Re: Uploaded filename, before CFFile
                                    Level 7
                                    Ian Skinner has already explained to you in his post how and why this
                                    happens.

                                    cffile action="upload" DOES NOT upload the file - it merely moves it
                                    from a temp location where the http request has put it to the folder you
                                    specify in the destination attribute of cffile tag.

                                    the file selected in the form's type='file' field get sent to the server
                                    as part of http request. it is not 'taken' from the user's computer by
                                    some process - it is in the http request sent to the server when you hit
                                    'submit' button.

                                    read Ian's post.

                                    Azadi Saryev
                                    Sabai-dee.com
                                    http://www.sabai-dee.com/
                                    • 16. Uploaded filename, before CFFile
                                      elpestybandito Level 1
                                      Azadi, please try to remain civil and read through everything in the post so far before responding.

                                      Looking at your comment you seemed to have the impression that I don't know how file uploads work. I can promise you that I do and if you paid closer attention to my comments you would realise that.

                                      To quote myself "there seems to be some confusion that the upload doesn't happen until you do cffile action="upload". This is not the case and I'll show this here." Doesn't that say that cffile action="upload" isn't responsible for the upload itself?

                                      You pointed me to Ian's comment, how about you read his second comment (that he probably made once he read through my post again and realised I know what's going on).

                                      quote:

                                      Originally posted by: Ian Skinner
                                      You do understand the HTTP request/response client/server scenario (many
                                      people who post questions like this do not). Try investigating the CGI
                                      scope and the request header/body. I would suspect the file name is
                                      buried in one or more of those locations. I don't recall off the top of
                                      my head how one inspects the request head and body, but I suspect Google
                                      would quickly cough up examples.



                                      How about a little list to make things clearer.

                                      * I know CFFile action="upload" is not doing the upload
                                      * I know the server handles the upload and CF stores the file before running the ColdFusion code.
                                      * I know that form.file holds the temporary location and filename of the upload.
                                      * I don't want a client-side method for finding the original name, I prefer server-side for this.
                                      * I do want to know where ColdFusion stores the original filenames of uploads.
                                      * I don't want to use CFFile action="upload" to get at the original filenames.

                                      If you look through that list and my previous comments things should make more sense. I've searched the GetPathContext() function and it's methods but I'm not really sure where to look within it. I've also searched the CGI scope (and it's keys that don't show up in a CFDump) and I've even looked in GetHttpRequestData() but this doesn't return anything in CF8 when there is an upload (to increase performance for large file uploads).

                                      What I do know is that ColdFusion is storing this filename somewhere, because it makes use of it when you ask it to.
                                      • 17. Re: Uploaded filename, before CFFile
                                        Level 7
                                        my apologies, i didn't fully read your last paragraph in your previous
                                        post...

                                        so you probably also know that the original file name is sent with the
                                        http request in the headers?

                                        a simple header sniffing returns something like this after form submit:

                                        Content-Disposition: form-data; name="fileupload"; filename="bg_mfa.png"


                                        i do not, however, know how to get that data on the server side...

                                        Azadi Saryev
                                        Sabai-dee.com
                                        http://www.sabai-dee.com/
                                        • 18. Re: Uploaded filename, before CFFile
                                          elpestybandito Level 1
                                          Thanks Azadi :)

                                          That's exactly what I'm after, just can't find how to access it from ColdFusion. Like I've mention before, it must be there somewhere otherwise ColdFusion wouldn't be able to use the original filename at all.
                                          • 19. Uploaded filename, before CFFile
                                            BKBK Adobe Community Professional & MVP
                                            Elpestybandito wrote:
                                            Now for save.cfm, there seems to be some confusion that the upload doesn't happen until you do cffile action="upload".

                                            That is not where the confusion is. It is well-known that you can upload without using <cffile action="upload">.

                                            I can only speak for myself. What confuses me is why you don't just use <cffile action="upload" destination="#absolutePathToDirectoryYouSpecify#">. It will save the file by its real name, which is what you want, and in the directory you specify.

                                            It might just be -- and I'm guessing -- that Coldfusion will only give you the real name when you use <cffile action="upload">. In any case, you will get more bang for your buck with the cffile structure than with GetFileInfo().

                                            Another point of confusion is that you use <cffile action="read">, which applies mainly to text files. What do you do for images and executables, for example? Toggle between action="read" and action="readBinary"? Then what about MIME types? Permissions?

                                            • 20. Re: Uploaded filename, before CFFile
                                              elpestybandito Level 1
                                              > That is not where the confusion is. It is well-known that you can upload without using <cffile action="upload">.

                                              I have had several replies here and elsewhere where people have thought CfFile action="upload" is responsible or they think I believe it is responsible. That's why I mentioned there appears to be some confusion, as I have kept having to explain what I wish to accomplish.

                                              > What confuses me is why you don't just use <cffile action="upload" destination="#absolutePathToDirectoryYouSpecify#">

                                              I have built a Validation CFC which is provided a set of multiple rules per form field. I already have it validating the file size (GetFileInfo(form.file)) but I didn't want the overhead of creating a copy of the upload (CfFile action="upload") and then removing it, just to find out it's file type. I also wanted the validation CFC to remain independent from any other code and portable between various applications, doing a CFFile action="upload" means I always have to remember that my validation cfc is copying the file somewhere.

                                              Also, when I want to validation multiple file uploads, some possibly large files. There is the overhead of ColdFusion copying each one of these, just to find it's filename.

                                              > Another point of confusion is that you use <cffile action="read">

                                              The example code was based on some I was using for uploading, changing and then saving an RTF file. So I didn't want to open it as a binary, sorry if it appeared wrong.

                                              • 21. Re: Uploaded filename, before CFFile
                                                BKBK Adobe Community Professional & MVP
                                                I didn't want the overhead of creating a copy of the upload (CfFile action="upload") and then removing it, just to find out it's file type.

                                                There will always be the overhead of uploading the file to the server. I believe that that has more to do with HTML. It's the expected behaviour for <input type="File">. So, even without <cffile action="upload">, Coldfusion will upload the file to the temporary directory, giving it an arbitrary name like neotmp9381.tmp. That is default behaviour for Coldfusion.

                                                A possible solution to your problem is to pass the client's file path, including file name, using cfinput's bind attribute. An example follows: