Link to home
Start Free TrialLog in
Avatar of bradderick
bradderickFlag for Australia

asked on

Users uploading pictures

Hi all,

Two part question that is linked:


In building the auction system of my current website I was wondering if I could get some advice on how to upload pictures.

Each user that puts up an auction will be able to upload up to 3 pictures, totalling no more than 100k.

The upload will be done in the auction creation process on one of the steps of a wizard.

The pictures will not be stored inside a database but on the hard drive of the web hoster. So we would need to somehow generate a dynamic path for each photo in both the auction detail page (view section) and during the upload (creation section) process as well. I don't want to create a new directory for each user (as there could be 10k users) and neither do I want to create one picture directory and have 10-30 thousand files in it.

If possible, I would like the code to generate a new directory every 250 pictures or so. That will keep it reasonably managable.

Also code needs to verify that the user is actually uploading a jpg file as that pretty much gets around uploading viruses.

Could you also please take into account that the photos will then be removed as each auction will only last for 30 days max.


As well, if possible I would like to know if there is an easyish way to make thumbnails appear on the auction detail page that then link to the big picture. Some javascript maybe? Is there a way to create thumbnails without actually storing smaller versions of the pictures on the server and if not, what technique will automate the creation of the stored thumbnails.


Before I go researching all the different file upload processes I would like to get some detailed opinions (and code if possible) as to the best way to go about the above please.

Cheers,
Brad
Avatar of jg4smile
jg4smile

This is pretty simple in ColdFusion. let me see if I can break the problems down...

1. User a user code (maybe the last 4 digits of SSN, or some other user identifyer in the file name of the pictures). Additionally, you could track this in a database, but it seems that you do not want a lot of DB development involve.

2. The CFFILE tag will return file information from a directory as if it is a query from a database. You could check the RecordCount property after performing a CFFILE action="read". If recordcount >=250 then CFFILE action="create" and create a directory.

3. Use JavaScript to verify that the file type is JPG...or at least to verify that the file extension is JPG or even other graphic file extensions. Because this is an auction site, not send the correct file type is the responsibility of your subscribers. Checking for the correct extension should suffice. I know this is a major concern, but if someone loads a virus with a JPG extension, it does not have an opportunity to execute.

4. Use CFSCHEDULE to add a task to check the Photos folder(s) and delete anything where datediff(d,now(),#filemodified#) > 30.

5. Use javascript or CF to pull the image sizes. I would take those sizes and run some factor formulas to create the thumbnails at the optimal size (e.x. If the photo size is 300px x 400px and my thumb size needs to be 30 width...300/400 = 30/x >> 300x=1200 >> x=40 >> <img src="image.gif" width="30" height="#x#">.

If I were developing this app, I would create a couple reusable routines.
* Gather all directories under the PHOTOS folder.
* Get a list of all files (filenames) and also use recordcount to return the total number of photos.


-----
solutions...not answers
ASKER CERTIFIED SOLUTION
Avatar of anandkp
anandkp
Flag of India image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of bradderick

ASKER

Hi Guys,

Ok so, i misled you a little bit about the database. I don't want to STORE images inside the database but there is a table called ClassifiedsPictures that has a 'PictureLink' column that is a url that will store a link to a particular image on the hard drive.

The table, ClassifiedsPictures, is linked with a foreign key to the Classifieds table so that each classified can have multiple picutre links.

Elaborating slightly on the first point of creating pictures named with the user's username (won't know users SSN), i thought you could search a directory to see if that user had any pictures and if so get the next number and if not, create from number one.

So what I have so far in the form code is:
<INPUT TYPE="file" NAME="picture1" VALUE="SESSION.ClasAdd.PictureLink1">
<INPUT TYPE="file" NAME="picture2" VALUE="SESSION.ClasAdd.PictureLink2">
<INPUT TYPE="file" NAME="picture3" VALUE="SESSION.ClasAdd.PictureLink3">

I've got nothing yet on the processing page.

I'm not too sure how the code you have given me works anand, would you mind putting in some further explanation?

jg4smile, you have given me some great suggestions, could you elaborate on the code for the process page to upload a photo, perhaps using the method I talked about above to generate a dynamic name, and to store it in lets say the 'photo' directory as it would be cleaned up every 30 days so one directory would probably be alright.

Would you mind answering a question about cfschedule as well. Can anyone use cfschedule? what i mean is, we are going to be using webhosting rather than our own server in the beginning and from what i understand cfschedule interacts quite closely with the cf administrator. Is it still possible to use cfschedule if one does not have access to the cf administrator?
 

Cheers,
Brad
I agree completely with what anand said here:

1. Changing direcotry paths wld lead to - more coding & processing wrt the path of images


you are writing code for this... the computer doesn't care what images are in which dir... why should you?  if you are writing a program to take care of this (which you are) why would you care what the program sees for dirs?  if you are doing it yourself, then fine, separate the dirs.. but there is no reason to separate the dirs, since this will just make it harder on you, and the program...



regarding "Elaborating slightly on the first point of creating pictures named with the user's username (won't know users SSN), i thought you could search a directory to see if that user had any pictures and if so get the next number and if not, create from number one. " 

just keep and check that info in the db.  there is no way to tell from the file info which user uploaded it, unless perhaps you do different dirs for each user, or you have an os that tells you which user created which file, and each user will have differing permissions on your os tied to thier web login id (which i SERIOUSLY doubt).

cfschedule, i beleive can be one of the tags that is restricted in cfadmin... if it is not, you should have no problem, as there is a <cfschedule> tag you can use... if you can't use it, then you can always include the check on every page (or on every page, only to be done at certain times) and the user's accessing the code will do the clean up for you... if the slow down in performance is not acceptable, just build an admin section where you clean it yourself once a day, or month, or whenever you feel like it...
Hi guys,

Well I would really appreciate some code to help me out with the cffile uploading functions.

From you you've said it seems like if a picture only lasts for 30 days anyway and then is cleaned up when the classified is archived one directory would not be a problem.

Substand, when i was talking about username naming what I meant was say you have two users, Hal and Jem. Hal is a new user and uploads a classified with two pictures,

The system searches for pics named Hal[number].jpg and finding none creates
Hal0001.jpg

For his second upload, the system searches and finding hal[0001] it creates Hal0002.jpg

Then Jem uploads a classified with one picture. He is a power user and has already uploaded 14 pictures in the last month so the system finds the biggest one as
Jem0014.jpg and so the uploaded picture is automatically called Jem0015.jpg.

As far as which pictures relate to which classifieds, it is easy to tell because, as i said above, there is a table dedicated to storing exactly this information, as well as a link to the picture (which may be obsolete now, it was there if you had multiple directories like, "/photos/700-900/" etc).

So if we were to say that the directory for the pictures was called /photos/ what would some code be for cffile, with the necessary checks to ensure, its not over 100k total and it is a jpeg.

Cheers,
Brad
Hi guys,

Well I have done a bit of searching around and it looks like i have found a custom tag that could do some of what I want to do. Have a look at:

http://www.cfdev.com/products/productdetail.cfm/id/6

It is a tag called

<cf_AutoResize>

I haven't tried using it as yet but I wanted to run past you the install instructions down the bottom of the page. It says:

Installing <cf_autoresize>:

1. Unzip autoresize.zip into a temporary directory.
2. Copy autoresize.cfm into your custom tags directory, usually C:\cfusion\customtags.
3. Copy image.dll into your cfx directory, usually C:\cfusion\cfx.
4. Register image.dll as a cfx tag in Cold Fusion administrator, through the Extensions>>CFX Tags area.
5. Copy CF_autoresize.vtm into your homesite or cold fusion studio directory, usually C:\Program Files\Allaire\ColdFusion Studio4 (homesite 4.0)\Extensions\TagDefs\Custom
6. Delete the temporary directory holding the unzipped files.

Now, if I am running my site of a shared hosting solution where I don't have access to cf administrator is there a way i can still use this tag as it sounds like a great solution.

The only thing the tag doesn't do is have a selection to change the name of the file being uploaded (unless one of the same exists). Is it possible to upload using cffile and then use cf_autoresize to dynamically generate thumbnails?

Cheers,
Brad
I dont know - as i havent experimented much with this tag !

like i said before - ive used my own java code to do the resizing for me & the code for uploading [along with rename & filesize check] - is given above in my previous comment !

K'Rgds
Anand
Hi anand,

After i copied your code into dreamweaver it made it a lot easier to read with all the pretty colours!

I'm a little unsure about the cftry section.

    <CFTRY>
        <CFFILE ACTION="UPLOAD" FILEFIELD="New_FieldName" DESTINATION="#FilePath#" NAMECONFLICT="MakeUnique" ACCEPT="image/jpg">
       
          <CFIF ISDEFINED('Rename')><!--- Rename ! --->
           <CFSET FILEEXT = LISTLAST(FILE.SERVERFILE,'.')>
           <CFIF FILE.FileSize LT 30><!--- Size chk --->              
               <CFFILE ACTION="RENAME" SOURCE="#FilePath##FILE.SERVERFILE#" DESTINATION="#FilePath##NewFileName#.#FILEEXT#">
               <CFSET New_FieldName = "#NewFileName#.#FILEEXT#">              
           <CFELSE>
               <CFTHROW>
           </CFIF>
               
       <CFELSE>
                     <!--- keep original name as it is --->
           <CFSET New_FieldName = #FILE.SERVERFILE#>
       </CFIF>  
              
I don't understand what <CFIF ISDEFINED('Rename')><!--- Rename ! ---> does?

Also, does this line, <CFSET FILEEXT = LISTLAST(FILE.SERVERFILE,'.')>, get the fileextension by just getting whats after the '.'? if so, what if the user has named their file my.favourite.image.jpeg?

I am struggling a bit with the variables in the code you gave me.

It seems that it will upload a picture and rename it to the users name, can we set an increment in there so that if they don't have any pictures it will be username01.jpg and if they already have 4 photos it will be username05.jpg?

Also, is there a way to dynamically generate a thumbnail? i tried just forcing the width of the img to be x but it seems to pixelate the picture pretty badly.

Cheers,
Brad
OK answeres to ur questions :)

1. CFTRY is basically to have a server chk incase user has left the file field blank - or has entered a wrong path on his machine [by typing it out & not selecting via the BROWSE button]

2. so in an event of failure on size or image type - the CFCATCH wld be called & appropriate action can be taken !

3. <CFIF ISDEFINED('Rename')> - is used to chk if the u want to rename the file with a different name - this new name can be generated dynacmically based on ur requirement - just use the new name [generated by whatever ur code is & paste that variable inside by code]

eg :
<CFFILE ACTION="RENAME" SOURCE="#FilePath##FILE.SERVERFILE#" DESTINATION="#FilePath##NewFileName#.#FILEEXT#">
              <CFSET New_FieldName = "#BradsNewName_ComingFromSomewhere#.#FILEEXT#">              
          <CFELSE>
              <CFTHROW>
          </CFIF>

this will rename the image to the value of variable "#BradsNewName_ComingFromSomewhere#"

4. FileExt - is a variable set to get the extension of the file - this is only used incase u wanna rename the file - else it goes in with the serverfilename :)

5. yes u can set an increment value for ur newname - liek i mentioned in [3] above - the newname for the image can be ne-thing u want it to be !

6. for thumbnail - ive used a .jar file - that does the job for me ... scaling images to the pixels perfectly ... [if u want i cld email it to u]

K'Rgds
Anand
It looks good. I'm going to have a bit of a play around with it I think. I need to work on how to get that generator, ie on how to check if there is username*.jpeg and if so find out what number username[999].jpg is and then increment it by one and then output it.

Cheers,
Brad
Haven't heard from you as yet anand?

Cheers,
Brad
yeah i know - just got cought up a bit

its on the way !
Not a problem anand! Real life has to come first :)

I'm just goin through it now, would you be able tell me specifically what this is:

"NewStyleID\","99","141","245","350"

The first one is the directory, what are the last four? I guess one would be width and one height?

Cheers,
Brad

Is there anyway to check a filesize BEFORE the upload process has gone ahead? As I think i would like to have a 100k limit total. So that someone could upload one 100k file, 2 50k files or 3 33k files.

To do this i could theoretically check filesizes before uploading, add them and see if it is <=100 or is this only possible after upload?

Because if it possible only after upload then theoretically if someone was malicious they could upload a 100meg file over and over and over. It would be deleted as it totalled over 100k but only after it had been uploaded. Is there a way around this?

Cheers,
Brad

Also, i'm raising the points for this question as it has gone on quite some time.
yeah ur right - one is width & the other is height
i was resizing it in 2 sizes - one medium & other thumbnail

try removing one & see if it works - just pass "NewStyleID\","99","141"

abt checking teh file size before upload - I DONT think thats possible ... ive tried  alot & i guess there were many questins regarding this on this forum - but i didnt see an answere to this ! - unfortunately its not possible

K'Rgds
Anand
Ok well taking another tack for the upload, is there a way to get out how long it is taking in real time? and if timetaken > 60mins then abort?

Cheers,
Rob
the time taken will depend on n number of issues

1. net connection
2. bandwidth
3. image format
4. server status
5. peak / non peak hours
6. ....

so it really wont make sense trying to achieve what ur asking for

though there is something called as content.length - & u cld make sure that the filesize is atleast less than XXX.KB before being uploaded

K'Rgds
Anand
So there is a way to check the length of content before uploading?

Would you mind giving me a code example on how to use content.length?

Cheers,
Brad
that was CONTENT_LENGTH & not CONTENT.LENGTH

sorry for the mistype !
How To Limit File Upload Sizes

There was some discussion a while back on a possible vulnerability in CFMX. I was worried that a denial of service attack would be possible by uploading a single very large file. My fear was that the ColdFusion server was buffering files in RAM before writing them out to the file system, however I was relieved when two people from the ColdFusion team confirmed that the files were written directly to disk and not buffered in RAM. In other words, the input stream from the request is written directly to a file output stream (without being buffered more than just a few K), which means you cannot cause the JVM to run out of memory by uploading a file. Very good implementation.

The next question, however, was whether or not it was possible to create a DOS attack by making the server run out of disk space. Could someone upload enough gigabytes of data to fill an entire partition? Shouldn't there be a way to guard against this type of issue?

Fortunately, there is. On the advice of Laurent Rouquette, I confirmed this morning that you can use the variable cgi.CONTENT_LENGTH to decide if you want to allow a file to be uploaded or not. The code below only allows files less than 25,000 bytes to be saved:

<cfif cgi.CONTENT_LENGTH lt 25000>
    <cffile action="upload"
            fileField="testFile"
            destination="/tmp"
            nameConflict="overwrite" />
</cfif>

Note that the file will still be uploaded and saved in a temporary location, but if the cffile tag does not get executed, the temp file will simply be deleted after the upload is complete.

I recommend that anyone who has an application that allows files to be uploaded use this technique as an extra level of security. Remember, though, that the content length of the request contains all the information in the request, so allow a little extra space for other data, as well.

K'Rgds
Anand
Cheers for finding that for me buddy!

I'm in the process of writing my upload.cfm file now with your code from above. I'm gonna close this question as it has gone on for ages and I think you definitely deserve the points!

If I have any other queries about the upload code I will post a new Q

Thanks again all for the help,

Cheers,
Brad
its just that at this point - i am way tooooooooo busy ... so cldnt run thru my resources quickly enough

sorry abt the delay bro !

Cheers
Anand
Don't sweat on the delay! I appreciate you getting it for me, however long it takes.

Cheers,
Brad