Also note that uploaded files only exist in a temporary place on the server and need to be moved using rename so that they exist in a location on the server that is accessible.
I didn’t see that in your code until I scrolled further down it.
if (is_uploaded_file($sorted_files[$count]['tmp_name']))
if(!move_uploaded_file($tmp_name, 'uploads/'.$uploadFilename))
$errorMessage = "Error uploading file - check destination is writeable.";
then output error messages or try a routine that uses chmod() to try changing the permissions of that folder that the file is going to and then reverting them back to previous values.
You might want to consider rejigging your code so that any upload errors are discovered earlier because you are echoing a load of information that really is not needed, all the user is interested in is if the file goes up to the server and your back end only needs to know that it is a file type that is accepted, you may not want the user knowing where the file is actually going to so if it was a malicious attack and someone uploads a PHP script then calls it or uploads an EXE file and then gets it to run or people download it and run it, etc. Consider security aspects of your server and the end users.
ok, did some reworking of the code, let me know if it looks ok
//run the function to get only the selected files (out of the 6 possible)
get_files();
foreach ($sorted_files as $file) {
if ($file == '') {
continue;
}
$Type = $file["type"];
$Name = $file["name"];
$tmp_name = $file["tmp_name"];
$Error = $file["error"];
$Size = $file["size"];
// first we check to see f en error code happened on the file
if($Error > 0){
echo 'An error ocurred when uploading.';
}
// then we check the extension
if(($Type != 'image/png') && ($Type != 'image/gif') && ($Type != 'image/jpeg') && ($Type != 'image/bmp'))
{
echo 'Unsupported filetype uploaded.';
}
// Then we check its size
if($Size > 102400){
echo 'File uploaded exceeds maximum upload size.';
}
if alls good, we rename it to give it a unique name
$now = time();
while(file_exists($uploadFilename = $now.'-'.$Name))
{
$now++;
}
// lastly we move the renamed file into my directory
if(!move_uploaded_file($tmp_name, 'uploads/'.$uploadFilename)){
echo 'Error uploading file - check destination is writeable.';
}
}
This seems pretty good but I really dont understand the functkion
function get_files($_FILES) {
$files = $_FILES['file'];
$file_count=count($files);
$count=0;
while ( $count <> $file_count-1 ) {
$files[$count]['name']=$files['name'][$count];
$files[$count]['type']=$files['type'][$count];
$files[$count]['tmp_name']=$files['tmp_name'][$count];
$files[$count]['error']=$files['error'][$count];
$files[$count]['size']=$files['size'][$count];
if (!is_uploaded_file($sorted_files[$count]['tmp_name'])) {
unset($sorted_files[$count]);
}
$count++;
}
return $sorted_files;
}
Simplest way to look at this is a very basic image upload form.
filename: form.php
<?php
// get some orientation going on...
$dirSelf = str_replace(basename($_SERVER['PHP_SELF']), '', $_SERVER['PHP_SELF']);
// generate the name of the upload processing script.
$handler = 'http://' . $_SERVER['HTTP_HOST'] . $dirSelf . 'processor.php';
// set a maximum file size allowed, this can also be set from use of the php ini function
$max_file_size = 1000000; // size in bytes
?><!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>Upload form</title>
</head>
<body>
<form id="Upload" action="<?php echo $handler; ?>" enctype="multipart/form-data" method="post">
<h1>Upload form</h1>
<input type="hidden" name="MAX_FILE_SIZE" value="<?php echo $max_file_size ?>">
<p><label for="file">Select File:</label>
<input id="file" type="file" name="ulf"></p>
<p><input id="submit" type="submit" name="submit" value="Submit"></p>
</form>
</body>
</html>
filename: processor.php
<?php
// make a note of the current working directory, relative to root.
$dirSelf = str_replace(basename($_SERVER['PHP_SELF']), '', $_SERVER['PHP_SELF']);
// make a note of the directory that will recieve the uploaded file
$uploadsDir = $_SERVER['DOCUMENT_ROOT'] . $dirSelf . 'upload/';
// make a note of the location of the upload form in case we need it
$uploadForm = 'http://' . $_SERVER['HTTP_HOST'] . $dirSelf . 'form.php';
// make a note of the location of the success page
$uploadSuccess = 'http://' . $_SERVER['HTTP_HOST'] . $dirSelf . 'success.php';
// fieldname used within the file <input> of the HTML form
$fieldname = 'ulf'; // name of the field on the upload form.
// inital security check was the upload form was actually submitted?
isset($_POST['submit']) or header("Location: {$uploadForm}");
// any uploading errors
($_FILES[$fieldname]['error'] == 0) or header("Location: {$uploadForm}");
// check that the file was a HTTP upload
@is_uploaded_file($_FILES[$fieldname]['tmp_name']) or header("Location: {$uploadForm}");
// we are only accepting images...
@getimagesize($_FILES[$fieldname]['tmp_name']) or header("Location: {$uploadForm}");
// the file name
$uploadFilename = $uploadsDir.$_FILES[$fieldname]['name'];
// move the file
@move_uploaded_file($_FILES[$fieldname]['tmp_name'], $uploadFilename) or die("receiving directory insuffiecient permission");
// we did it!
header("Location: {$uploadSuccess}");
?>
filename: success.php
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
<title>Successful upload</title>
</head>
<body>
<h1>File upload</h1>
<p>Your file upload was successful, Thank you.</p>
</body>
</html>
Breaking the script down…
form.php will deal with the file selection
processor.php will do the legwork of checking that the form was used and that processor.php was not called directly and that the file being uploaded is an image and so on
success.php will be displayed if the file was uploaded successfully.
So going by that example, you should be able to get a working form, granted its a nofrills format but we are not here for pretty forms, just the facts.
I hope this helps you get a working form and you understand that this is as about as basic you can get and that you would need to have a few quirks added for people who might upload a file of the same name and changes that need to be made if you are accepting other file types like rar and zip files for example, you would need to employ the services of the is_executable() function to guard against executable file types like shell scripts, exe files and so on.
With a multiple file upload then you need to have a processor.php script like
<?php
// make a note of the current working directory, relative to root.
$dirSelf = str_replace(basename($_SERVER['PHP_SELF']), '', $_SERVER['PHP_SELF']);
// make a note of the directory that will recieve the uploaded file
$uploadsDir = $_SERVER['DOCUMENT_ROOT'] . $dirSelf . 'upload/';
// make a note of the location of the upload form in case we need it
$uploadForm = 'http://' . $_SERVER['HTTP_HOST'] . $dirSelf . 'form.php';
// make a note of the location of the success page
$uploadSuccess = 'http://' . $_SERVER['HTTP_HOST'] . $dirSelf . 'success.php';
// fieldname used within the file <input> of the HTML form
$fieldname = 'ulf'; // name of the field on the upload form.
// inital security check was the upload form was actually submitted?
isset($_POST['submit']) or header("Location: {$uploadForm}");
// were files uploaded, if so then store the active $_FILES keys
$keys = array();
foreach($_FILES[$fieldname]['name'] as $key => $filename)
if(!empty($filename))
$keys[] = $key;
// check at least one file was uploaded
count($active_keys) or header("Location: {$uploadForm}");
// check for uploading errors
foreach($keys as $key)
($_FILES[$fieldname]['error'][$key] == 0) or header("Location: {$uploadForm}");
// check that the file(s) are a HTTP upload
foreach($keys as $key)
@is_uploaded_file($_FILES[$fieldname]['tmp_name'][$key]) or header("Location: {$uploadForm}");
// validation... since this is an image upload script we
// should run a check to make sure the upload is an image
foreach($keys as $key)
@getimagesize($_FILES[$fieldname]['tmp_name'][$key]) or header("Location: {$uploadForm}");
// now let's move the file to its final and allocate it with the new filename
foreach($keys as $key)
@move_uploaded_file($_FILES[$fieldname]['tmp_name'][$key], $uploadFilename[$key]) or header("Location: {$uploadForm}");
header("Location: {$uploadSuccess}");
?>
In your script you appear to be missing the additional array dimension because the multiple files add an extra element to the $_FILES array.
function get_files($_FILES) {
$files = $_FILES['file'];
$file_count=count($files);
$count=0;
while ( $count <> $file_count-1 ) {
$files[$count]['name']=$files['name'][$count];
$files[$count]['type']=$files['type'][$count];
$files[$count]['tmp_name']=$files['tmp_name'][$count];
$files[$count]['error']=$files['error'][$count];
$files[$count]['size']=$files['size'][$count];
if (!is_uploaded_file($sorted_files[$count]['tmp_name'])) {
unset($sorted_files[$count]);
}
$count++;
}
return $sorted_files;
}
Lots of things going on here that can be simplified or are just plain wrong.
The function expects a parameter $_FILES but you call it without a parameter. Remove the parameter, or actually pass $_FILES to it.
The function doesn’t check if files are uploaded at all, it just assumes they are
$files = $_FILES[‘file’] is quite useless, you could just as well work with $_FILES[‘file’] directly. In fact, it would be easier.
$sorted_files is not initialised, which results in an E_NOTICE warning – which you seem to have turned off. I recommend you turn those on, it makes life a lot easier in the long run.
The loop would be a lot better with a for here instead of a while
function get_files() {
if (empty($_FILES['file'])) return false;
$sorted_files = array();
for ($i = 0; $i < count($_FILES['file']); $i++) {
if (!is_uploaded_file($_FILES['file']['tmp_name'][$i])) {
continue;
}
foreach (array('name', 'type', 'tmp_name', 'error', 'size') as $field) {
$sorted_files[$i][$field] = $_FILES['file'][$field][$i];
}
}
return $sorted_files;
}
Shows that both methods (with a tweak to the while condition in method 2) work fine, no matter if all fives are uploaded, just 1 or none. Both methods check if a file has been uploaded or not. imho, method 2 is better as it elimiates the need for a loop within a loop, which is something I personally prefer to avoid wherever possible.
Ah, but you’re cheating, because the original function is
function get_da_files($_FILES)
which does raise errors (different errors on different PHP versions). See http://3v4l.org/6g3CU
(The error you get in PHP>=5.4 is the most correct one IMHO)
Off Topic:
If you want to show any and all errors, you can do set error_reporting to -1
The Check destination is writable… Are you on a windows based system? If so, go to your folder where the images are to be uploaded and right click on the folder then select properties and ensure that the “Read Only” box has nothing in it, it will either be ticked or have a coloured box, it needs to be clear of any property and click “Apply” then “Ok”
If you are on a Linux system then the process is a whole new game and its been that long that I have use Linux that I will let someone who knows Linux comment BUT the permissions in Linux for folder permissions is a lot more simpler in PHP with the issue of a permissions change using chmod() function from memory chmod( filename , 0664) where filename is the path to the folder and the number is an Octal value that MUST have a leading zero, the 0664 is read / write for owner and read for everyone else and i believe that files of an executable type can’t be run as they don’t have permission with that setting.