...

View Full Version : PHP File Upload that sends email to person of choice depending on upload directory.



_Aerospace_Eng_
04-28-2006, 12:43 AM
I recently code this for a user on the forums. Basically its a file upload script that will email a person depending on which directory was chosen. I think I've put in sufficient error checking. Once the file is uploaded successfully it redirects the user to a page and outputs that the file was uploaded to so and so directory. If any one sees any problems with it let me know please. One thing you should know if you use this script is that you should NOT allow it to be viewable to the public because you server could be filled up with junk. This should be used in a members only type area on your site. With that said here is the code. I commented it pretty well so it should be easy to follow. The directories you are uploading to must be chmodded to 777 for this script to work properly.

uploader.php

<?php
$error = ""; // Set a variable that will be used for errors
$sendTo = ""; // Set a variable that will be used for emailing
if(isset($_POST['upload']) && $_POST['upload'] == 'Upload File') // Form is submitted
{
$whereto = $_POST['where']; // Gets post value from select menu
$whatfile = $_FILES['uploadedfile']['name']; // Gets file value from file upload input
$subject = "File uploaded to ". $whereto ." directory"; // This is the subject that will appear in the email
$from = "Upload form <noreply@yourdomain.com>";
if(empty($whereto)) // Checks to see if $whereto is empty, if so echo error
{
$error = "You need to choose a directory.<br />";
}
if($whatfile == NULL) // Checks to see if file input field is empty, if so throw an error
{
$error .= "You need to choose a file.";
}
if(!empty($whereto) && $whatfile != NULL) //if no errors so far then continue uploading
{
$target_path = "$whereto/"; // The directory the file will be placed

/* Add the original filename to our target path. Result is "uploads/filename.extension" */
$target_path = $target_path . basename($whatfile);
if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path))
{
header("Location: index.php?to=$whereto"); // Directs user back to page of choice
}
else
{
/* if there was a problem then throw an error */
$error .= "There was an error uploading the file, please try again!";
}
if(empty($error))
{
if($whereto == "uploads1") // Change $sentTo depending on the directory chosen
{
$sendTo = "Jim <jim@yourdomain.com>"; // Change this to an email address of your own
}
if($whereto == "uploads2")
{
$sendTo = "Kim <kim@yourdomain.com>"; // Change this to an email address of your own
}
/* The below will be what is shown in the email */
$body = "You have received the following from the web based upload form:\r\n";
$body .= "---------------------------------------------------------------\r\n";
$body .= "Subject: File uploaded to ". $whereto ." directory\r\n";
$body .= "File name: ". $whatfile ."\r\n";
$body .= "Upload directory: ". $whereto ."\r\n";
$body .= "Uploader's IP address: ". $_SERVER['REMOTE_ADDR'] ."\r\n";
$body .= "---------------------------------------------------------------\r\n";

/* headers used to show from field in email client */
$headers = 'From: '.$from."\r\n" .
'Reply-To: '.$from;

/* this actually sends the mail */
mail($sendTo, $subject, $body, $headers);
}
}
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>File Upload</title>
</head>

<body>
<div>
<?php
if(!empty($error))
{
echo $error;
}
?>
</div>
<form enctype="multipart/form-data" action="<?php echo $_SERVER['SCRIPT_NAME']?>" method="POST">
<input type="hidden" name="MAX_FILE_SIZE" value="100000" />
Choose a file to upload: <input name="uploadedfile" type="file" /><br />
<select name="where">
<option value="">Choose a directory</option>
<option value="uploads1">uploads1</option>
<option value="uploads2">uploads2</option>
</select>
<input type="submit" name="upload" value="Upload File" />
</form>
</body>
</html>

index.php

<?php
$directory = $_GET['to']; // This checks the url getting the value for the to=
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Index Page</title>
</head>

<body>
<?php
if(!empty($directory)) // if to=something then echo that the file was uploaded in so and so directory
{
echo "Your file has been uploaded to the ". $directory ." directory.";
}
?>
</body>
</html>

fci
04-28-2006, 04:41 AM
I do not recommend the usage of empty() since it allows some ambiguity, if you want to look for an empty string, actually check for it $str=="" (someone could send in an array for $whereto which I believe would allow someone to see errors on the page which could reveal limited information about the server/file/error/blah).
also, your $whereto does not appear to be properly sanitized which may not make a difference but someone could do some http splitting when you do header(...).

(note: I haven't had the chance to test these but.. yeah).

Nightfire
04-28-2006, 04:51 AM
^ Someone as paranoid as me.

Anything involving file uploading is worth being over paranoid about.

fci
04-28-2006, 04:59 AM
^ Someone as paranoid as me.

Anything involving file uploading is worth being over paranoid about.

mmmm.. the code also isn't using is_uploaded_file()..

I'd say its preferable to be paranoid all the time.. although I would say it is about being 'security conscious' ..

ralph l mayo
04-28-2006, 06:44 AM
You use basename but then don't include any restriction on $_POST['where']? So if $_POST['where'] == '/etc' and $_FILES[]['name'] == 'passwd', unless I'm missing something, you better hope all your permissions are secure?

OTOH, is_uploaded_file is implied by move_uploaded_file, so don't worry about that. I just don't think there's any easy way to sanitize a user supplied directory, I'd rather drop it all in ./upload/ or something and know the area of effect is restricted.

Also, is this arbitrary file upload ending up somewhere inside document root? So I can upload blah.php == <?php eval($_GET['f']); ?>? If so it can be used to get a remote shell as apache's user and probably to elevate to root by a determined hacker.

_Aerospace_Eng_
04-28-2006, 06:56 AM
I do not recommend the usage of empty() since it allows some ambiguity, if you want to look for an empty string, actually check for it $str=="" (someone could send in an array for $whereto which I believe would allow someone to see errors on the page which could reveal limited information about the server/file/error/blah).
also, your $whereto does not appear to be properly sanitized which may not make a difference but someone could do some http splitting when you do header(...).

(note: I haven't had the chance to test these but.. yeah).
Okay I'll take that into account.

You use basename but then don't include any restriction on $_POST['where']? So if $_POST['where'] == '/etc' and $_FILES[]['name'] == 'passwd', unless I'm missing something, you better hope all your permissions are secure?

OTOH, is_uploaded_file is implied by move_uploaded_file, so don't worry about that. I just don't think there's any easy way to sanitize a user supplied directory, I'd rather drop it all in ./upload/ or something and know the area of effect is restricted.

Also, is this arbitrary file upload ending up somewhere inside document root? So I can upload blah.php == <?php eval($_GET['f']); ?>? If so it can be used to get a remote shell as apache's user and probably to elevate to root by a determined hacker.
I did recommend that the directory be password protected but I see what you are getting at. I wasn't really sure what the user wanted to do with the file. This could be implemented by using the absolute path of the server.

So would this be okay in checking the upload directories?

<?php
$error = ""; // Set a variable that will be used for errors
$sendTo = ""; // Set a variable that will be used for emailing
if(isset($_POST['upload']) && $_POST['upload'] == 'Upload File') // Form is submitted
{
$whereto = $_POST['where']; // Gets post value from select menu
$whatfile = $_FILES['uploadedfile']['name']; // Gets file value from file upload input
$subject = "File uploaded to ". $whereto ." directory"; // This is the subject that will appear in the email
$from = "Upload form <noreply@yourdomain.com>";
if($whereto == "") // Checks to see if $whereto is empty, if so echo error
{
$error = "You need to choose a directory.<br />";
}
if($whatfile == NULL) // Checks to see if file input field is empty, if so throw an error
{
$error .= "You need to choose a file.";
}
if($whereto != "" && $whatfile != NULL && $whereto == "uploads1" || $whereto == "uploads2") //if no errors so far then continue uploading
{
$target_path = "$whereto/"; // The directory the file will be placed

/* Add the original filename to our target path. Result is "uploads/filename.extension" */
$target_path = $target_path . basename($whatfile);
if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path))
{
header("Location: index.php?to=$whereto"); // Directs user back to page of choice
}
else
{
/* if there was a problem then throw an error */
$error .= "There was an error uploading the file, please try again!";
}
if($error == "")
{
if($whereto == "uploads1") // Change $sentTo depending on the directory chosen
{
$sendTo = "Jim <jim@yourdomain.com>"; // Change this to an email address of your own
}
if($whereto == "uploads2")
{
$sendTo = "Kim <kim@yourdomain.com>"; // Change this to an email address of your own
}
/* The below will be what is shown in the email */
$body = "You have received the following from the web based upload form:\r\n";
$body .= "---------------------------------------------------------------\r\n";
$body .= "Subject: File uploaded to ". $whereto ." directory\r\n";
$body .= "File name: ". $whatfile ."\r\n";
$body .= "Upload directory: ". $whereto ."\r\n";
$body .= "Uploader's IP address: ". $_SERVER['REMOTE_ADDR'] ."\r\n";
$body .= "---------------------------------------------------------------\r\n";

/* headers used to show from field in email client */
$headers = 'From: '.$from."\r\n" .
'Reply-To: '.$from;

/* this actually sends the mail */
mail($sendTo, $subject, $body, $headers);
}
}
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>File Upload</title>
</head>

<body>
<div>
<?php
if(!empty($error))
{
echo $error;
}
?>
</div>
<form enctype="multipart/form-data" action="<?php echo $_SERVER['SCRIPT_NAME']?>" method="POST">
<input type="hidden" name="MAX_FILE_SIZE" value="100000" />
Choose a file to upload: <input name="uploadedfile" type="file" /><br />
<select name="where">
<option value="">Choose a directory</option>
<option value="uploads1">uploads1</option>
<option value="uploads2">uploads2</option>
</select>
<input type="submit" name="upload" value="Upload File" />
</form>
</body>
</html>
or is there a more efficient way of doing this?

fci
04-28-2006, 01:13 PM
what ralph is getting is that someone can upload a PHP file which would be publically accessible.. which means you should be theoretically be checking against an allowed extensions array.
and.. a more aesthetically pleasing way to check for a valid directory would be to use an array of directories then using in_array() (fewer ||'s).



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum