Forum Moderators: coopster

Message Too Old, No Replies

flash/php file uploading

         

jiggy1965

9:41 pm on Mar 15, 2010 (gmt 0)

10+ Year Member



I'm developing an flash application where the user can upload an image for an image viewer. Using flash's filereference. Which works, but for the php part I started thinking about three possible problems.

move_uploaded_file($_FILES[’Filedata’][’tmp_name’], "./files/".$_FILES[’Filedata’][’name’]);
chmod("./files/".$_FILES[’Filedata’][’name’], 0777);
echo " ";



First: the filename should be unique to the user currently uploading the image. So when user one uploads 'image01.jpg' and another user uploads 'image01.jpg' during user one's upload, it doesn't overwrite image files. When a user uploads an image, how do I make aboven php script form a filename unique for this user?

Second:When lots of users start using the application and upload their images, the upload directory would fill up quickly. How can I prevent this? Ideally I suppose when a user has uploaded an image and after this image is loaded into a clip with moviecliploader, the uploaded image could automatically be deleted since it is no longer needed. But how can I put that in the Flash's onComplete event?

Another way could be to limit the number of uploaded files to e.g. 10. When a user uploads a file the php script would first check the number of previously uploaded files (by all users). And if more than 10 it would delete the eldest uploaded one. But that might be a file another user uploaded a few minutes ago. Or it would have to delete only the oldest file unique to the current user. But how could I let the php script know which user is currently uploading an image and as a result first delete the eldes file uploaded by that same user?

Third: when a user is finished and leaves the site the uploaded file would remain on the server. Again building up the upload directory. Could I automatically have all these user unique files deleted once the user closes the site?

Readie

9:48 pm on Mar 15, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



You'll have to look into sessions and/or cookies for some of your later points, but a simple way to get unique filenames is to do this:

$someVariableName = date(YmdHis);

Then simply apply that as a prefix for the file name.

Matthew1980

10:01 pm on Mar 15, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Hi there jiggy1965,

Welcome to the forum!

First Issue

1)Create a unique id - couple of arrays then merge/shuffle to make random.


$one = range('a','z');
$two = range('z','a');
$three = array_merge($one, $two);
shuffle($three);
$random_str = 'Img_'.$three[2].$three[4].$three[6].$three[8].$ext;



Note I tend to use a prefix of Img_ so that you have 'uniform' in the db, this will then have a four char random string with the filetype you originally uploaded - thus a filename that in theory won't be duplicate, tweak it as needed though!

2)Retrieve the file extension using something like: $ext = strrchr($_FILES['filedata']['name'], '.');
3)attach that $ext to the end of the randomly created string to "overwrite" the uploaded filename when you process step four..
4)move_uploaded_file($_FILES[’Filedata’][’tmp_name’], "path/to/your/file/".$random_str);

That's the general way to do that anyway, I may have missed a step, but the idea is there ;-p

Cheers,

MRb

jiggy1965

10:14 pm on Mar 15, 2010 (gmt 0)

10+ Year Member



Thanks, that solves the first problem ;-)

Now the other ones. I suppose it could work like this:
1. Flash uploads file to php script
2. php forms a unique file name
3. php echoes that name back to flash
4. Upon filereference.onComplete (file is uploaded), flash communicates to php script two, passing the earlier echoed unique file name
5. php script two deletes that file.

I'm just thinking out loud. Of someone's got a much better sollution I'd like to hear it ;-)

Problem 3: it could happen that a user closes a browser window of navigates to another site before the php script had a change to delete the last uploaded file. I can't really find a way to solve this. The file would remain on the server. Perhaps upon starting the application it would first delete all files older than 5 minutes (since the upload script would delete an uploaded file almost immediately after it has been send back to flash, like in above possible sollution.

Readie

10:34 pm on Mar 15, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



1)Create a unique id - couple of arrays then merge/shuffle to make random

Problem with that is it's only pseudo unique - I know there are potentially thousands of possible names with your method, but probability will always catch up in the end.

using date to get year-month-day-hour-minute-second will always be unique - and if you don't trust that enough you can do date(YmdHisu) for micro seconds too

[edited by: Readie at 10:35 pm (utc) on Mar 15, 2010]

Matthew1980

10:34 pm on Mar 15, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Hi there jiggy1965,

[EDIT] Readie, yes, I agree but I was just suggesting a way, as there are many options for doing the same thing in this instance. ;-p

Part 3

One way to solve this would be to create a php file which sole purpose would be to purge that directory/db entries at the same time every night, CRON Jobs, basically you set them up via the control panel on your site, you just need to create the script that would read the upload dir and cycle through each file and delete if file creation time is over a stipulated time frame.

That's just one way that came to mind.

Hope that helps

Cheers,
MRb

jiggy1965

11:20 pm on Mar 15, 2010 (gmt 0)

10+ Year Member



The unique name problem is solved. Also found this piece of code which besides forming a unique name, checks whether by any change this name already exists. And if so tries it again:

// make a unique filename for the uploaded file and check it is not already
// taken... if it is already taken keep trying until we find a vacant one
// sample filename: 1140732936-filename.jpg
$now = time();
while(file_exists($uploadFilename = $uploadsDirectory.$now.'-'.$_FILES[$fieldname]['name']))
{
$now++;
}

The other problems cound be solved in the php upload script itself too. I wouldn't have to add another 'delete file' script too come to think of it. Upon uploading a file I could just let the upload script delete all files older than, let's say, 10 minutes. After uploading and sending the image back to Flash, the file itself could be deleted immediately, but this would need a 2nd 'delete' script. I could just as well let the file remain in the upload directory. Eventually, here after it's 10 minutes old, it would be deleted automatically anyway. At least, if users continue to use the application.

Never heared about cron jobs yet, but sounds interesting. Will read about it.

Matthew1980

8:24 am on Mar 16, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Hi there jiggy1965,

Just as a thought for you, are you checking to see if the filtype's uploaded are only flash, as this method of post is the easiest way to place harmful data onto a site, again, just a thought.


Then check against an array of allowed filetypes, and don't forget that people can name the file extension in both UPPER and lowercase. If the filetye is not in the array, throw an error to say "Filetype is not allowed!"

//Get the filetype eg .swf (including the ".")
$ext = strrchr($_FILES['filedata']['name'], '.');

//accepted tags
$allowed = array(".FLV", ".flv", ".swf", ".SWF");

//Check and flag up error
if (!in_array($ext, $allowed)) {
echo "This filetype is not allowed!";
exit;
}


Hope that makes sense to you ;-p

Cheers,
MRb

Readie

8:51 am on Mar 16, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Because it is possible to have a filetype part-upper and part-lower (though why anyone would ever do that is beyond me) it may be worth modifying Matt's method to use a simple regular expression:

//Get the filetype eg .swf (including the ".")
$ext = strrchr($_FILES['filedata']['name'], '.');

//accepted tags- note the escaped dot (\.) and the i on the end to make it case insensitive
$allowed = array(
'/^\.flv$/i',
'/^\.swf$/i'
);

$count = count($allowed);
$match = 0;
$i = 0;

//loop through all accepted tags and check them against $ext
//stop looping on a match
while($i < $count && $match != 1) {
if(preg_match($allowed[$i], $ext)) {
$match = 1;
$i = $count;
} else {
$i++;
}
}

//Check and flag up error
if ($match != 1) {
echo "This filetype is not allowed!";
exit;
}

jiggy1965

9:10 am on Mar 16, 2010 (gmt 0)

10+ Year Member



No, it's only to allow a jpg file. A possible application could be to let the uploaded jpg serve as a texture for the wallpaper on a house's wall. The process is as follows:

1. Flash lets a user upload a jpg file (and only jpg)
2. This is sent to a php upload script which uploads the file to an upload directory
3. The url of that image is sent back to file, which loads this external file into a movieclip.
4. Since this external file is now loaded into flash as a bitmap, the file itself is useless and could be immediately deleted

So since it can be deleted amost instantly after sending back to flash, I was thinking of starting the php upload script with a for loop which automatically deletes jpg files older than 5 minutes. There wouldn't be much risk of accidentaly deleting other users files I think?

Another way would be to use a for loop which keeps track of the number of files inside the upload directory. To allow a maximum number of files of 20 for example. But then there would be a risk of deleting other users files, if 40 people were uploading a file at the same time for example. The for loop would then only be allowed to keep track of the number of files uploaded by the same user. Which I guess wouldn't a very easy to do?

Readie

9:28 am on Mar 16, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Well, I can personally see a fairly easy way to do this:

jpeg only
Since jpg, jpeg, jpe, jfif are all viable versions of jpeg - you can adjust my above method for those 4 file types (simply create/alter the allowed file types array

OR

If you want to force .jpg only:

if(preg_match('/^\.jpg$/i', $ext)) {
$match = 1;
} else {
$match = 0;
}


Limit files
Save the current time and the file name in a MySQL database for every upload, so use date(YmdHis)

Everytime a user loads the page - look in the MySQL database for this:

$now = date(YmdHis)
$prev = ($now - (60 * 5))

$sql = 'SELECT * FROM uploads WHERE upload_time <= ' . $prev;
$result = mysql_query($sql);
$rows = mysql_num_rows($result);

for($i = 0; $i < $rows; $i++) {
$file = mysql_result($result, $i, "file_name");
$ftime = mysql_result($result, $i, "upload_time");
unlink('path/to/file/' . $file);
$sql = 'DELETE FROM uploads WHERE file_name = "' . $file . '" AND upload_time = "' . $ftime . '"';
mysql_query($sql);
}

Matthew1980

11:07 am on Mar 16, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Hi there,

If there is only one filetype, all as you would need to do effetively is check one $var against another? Then again, this is just down to preference of method at the end of the day ;-p either/either


//Get the filetype eg .swf (including the ".")
$ext = strrchr($_FILES['filedata']['name'], '.');

//Check and flag up error
if ($ext != ".jpeg" || ".JPEG" || ".jpg" || ".JPG") {
echo "This filetype is not allowed!";
exit;
}


I like the limit files 'function' though :)

It doesnt matter how long the file is there for, as long as the user can place the file on the server, and then potentially access/execute it there is always a danger there, at least I hope the upload dir is outside of the root of the domain, then of course it can't be navigated to.

Good luck with the project anyway,

Cheers,
MRb

IgorLialiakin

3:42 pm on May 23, 2010 (gmt 0)

10+ Year Member



hi there!
Thnx God I found this topic on the net. You know, I have run into the same problem and still am stumbled solving it. Please help. I don't understand how using fileref.upload("upload.php") method one can get back from PHP script new path to the uploaded picture. And how should th PHP script look like if i want simply check with the rule that if the name "pic1.jpg" already exists then PHP simply adds lets say "1" to the file name -> "pic11.jpg" and returns back to the flash.
I appreciate your help very much
Thank you,
Igor.

IgorLialiakin

4:01 pm on May 23, 2010 (gmt 0)

10+ Year Member



What i mean: I did like you say here:

<?php

if(!is_dir("./files")) mkdir("./files", 0755);

$ext = strrchr($_FILES['filedata']['name'], '.');
$one = range('a','z');
$two = range('z','a');
$three = array_merge($one, $two);
shuffle($three);
$random_str = 'Img_'.$three[2].$three[4].$three[6].$three[8].$ext;
move_uploaded_file($_FILES[’Filedata’][’tmp_name’], "./files/".$random_str);

chmod("./files/".$_FILES['Filedata']['name'], 0777);

echo "&value1=linktratratra";
?>

But it wont upload :(

rocknbil

5:20 pm on May 23, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



the filename should be unique to the user currently uploading the image.


Not necessarily, as it relates to the next question:

When lots of users start using the application and upload their images, the upload directory would fill up quickly. How can I prevent this?


You need some method of creating a user directory.

/uploads/fddR34345ffsd

This will fix BOTH problems. You can randomly create user directories (checking that the don't already exist, and re-iterating your rand until it is unique) or devise some scheme by which you can identify the directory by a unique field, such as user ID or user name. Don't just use user ID, it's too "sniffable."

Then you can apply any scheme you want in the user's uploaded directory, rand, time, or even a readable filename from $_FILES['photo']['name] ("day_at_the_beach.jpg").

It will only take a small tweaking of the Flash AS to get it to play along nicely. Might not even need to be tweaked, if you're passing the image path as a variable to the Flash, it will do whatever you tell it to.