I've built a website with a HTML form/ PHP upload for image files, it works well when its running on XAMPP on my local computer but when i've uploaded it to 000webhost most of the time it says invalid file and only sometimes will the images successfully upload. I've tried turning up the max execution time in the php configuration but that doesn't seem to have fixed it. The files i've tried to upload are smaller than the max file size in the php config and have worked on my test machine perfectly.
I find it odd that it works sometimes and doesn't other times and don't really know what to try.
EDIT:
Here is the form
Filename:
if ((($_FILES["file"]["type"] == "image/gif")
|| ($_FILES["file"]["type"] == "image/jpeg")
|| ($_FILES["file"]["type"] == "image/pjpeg")
|| ($_FILES["file"]["type"] == "image/png")))
{
if ($_FILES["file"]["error"] > 0)
{
echo "Return Code: " . $_FILES["file"]["error"] . "<br />";
}
else
{
echo "Upload: " . $_FILES["file"]["name"] . "<br />";
echo "Type: " . $_FILES["file"]["type"] . "<br />";
echo "Size: " . ($_FILES["file"]["size"] / 1024) . " Kb<br />";
echo "Temp file: " . $_FILES["file"]["tmp_name"] . "<br />";
move_uploaded_file($_FILES["file"]["tmp_name"],
"churchimages/pauls.jpeg");
echo "Stored in: " . "churchimages/pauls.jpeg";
}
}
else
{
echo "Invalid file";//This is the section I am seeing
}
Your file type detection is relying on $_FILES["file"]["type"], which is sent by the browser and highly unreliable.
A much better way to detect whether an uploaded file is an image is getimagesize().
$info = getimagesize($_FILES["file"]["tmp_name"]);
$allowed_types = array(IMG_GIF, IMG_JPEG, IMG_PNG);
if (in_array($info[2], $allowed_types))
{ .... do stuff ... }
You should check if the upload actually succeeded FIRST, before doing any of the other operations:
if ($_FILES['file']['error'] === UPLOAD_ERR_OK) {
... handle upload...
if (!move_uploaded_file(...)) { // <--important. ALWAYS check if the move worked.
die("File move failed. Data is lost");
}
} else {
die("Upload failed with code " . $_FILES['file']['error']);
}
IN the case where an upload did not occur, then the ['type'] field would not be set, and just saying "invalid file" would be useless - there is no file at all.
As Pekka's pointed out, you should use other methods of determining file type. The ['type'] data in $_FILES is user-provided, and is trivial to forge.
Make sure that you're defining an absolute path for the uploaded files rather than a relative one.
I have had this issue today.. very sad. took about an hour to repair.
Idea: checking for $_FILES["file"]["type"] == "image/gif" at the top of the script is what failed for me. It seems the browser was populating a "BLANK DATA" instead of "image/gif" so my initial check failed each time with "invalid file type"
Question: It seems the browsers are not properly sending across the file type from the tmp directory?
My FIX: remove the file type check.... as stated above it is very unreliable...
Check the PHP file permissions. in ooowebhost you can find it in chmod. change to '777'. otherwise, the file doesn't have permissions to execute/write
Related
//uploadForm.html
<html>
<body>
<form action="upload_file.php" method="post" enctype="multipart/form-data">
<label for="browseFile">Filename : </label>
<input type="file" name="file" id="browseFile"><br>
<input type="submit" name="submit" value="Submit">
</body>
</html>
//upload_file.php
<?php
$allowedExt = array("png","jpg");
$temp = explode(".",$_FILES["file"]["name"]);
$extension = end($temp);
echo "uploading...";
if((($_FILES["file"]["type"]=="image/png") || ($_FILES["file"]["type"]=="image/jpg")) && ($_FILES["file"]["size"] < 1000000))
{
echo "success";
if($_FILES["file"]["error"] > 0)
{
echo "error in uploading" . $_FILES["file"]["error"]."<br>";
}
else
{
echo "<p>uploaded successfully</p>";
}
}
else
echo "invalid file" ;
echo $_FILES["file"]["name"]."stored in ".$_FILES["file"]["tmp_name"]."<br>";
move_uploaded_file($_FILES["file"]["tmp_name"],"uploads/".$_FILES["file"]["name"]);
echo "moved Successfully";
?>
When I try to echo the temp directory name , it is blank . The uploaded files are missing .
I dont get it in the MAMP/htdocs folder neither in /tmp/ directory .
I dont have uploads directory in /MAMP/htdocs/ .Wont the program create a directory if it does not exist ?
In your final instructions, you have $_FILES['name']['tmp_name'] instead of $_FILES['file']['tmp_name'].
By the way, you have a few errors in your script:
Even if someone uploads an invalid file, you show them an error message, but you still move it to the final place.
$_FILES["file"]["type"] is a value sent by the browser (ie: the client). A malicious attacker may sent you any kind of file and disguise it as a image/png, and you are trusting it. You cannot trust this value. Instead, you could use getimagesize, which returns you an array that has the mime type of the image (and is detected by the server (ie: by you). To detect the mime-type of non-images, you can use FileInfo, concretely finfo_file.
Also, the php script will not create your uploads folder if it does not exist, and instead will show an error (and do nothing). You must create this folder first, and make sure that the user running your php script (usually the same that is running your http server) has write permissions on that directory.
edit: You don't see any uploaded file in your temp directory because (quoting http://www.php.net/manual/en/features.file-upload.post-method.php):
The file will be deleted from the temporary directory at the end of
the request if it has not been moved away or renamed.
$allowedExt = array("png","jpg");
echo $temp = explode(".",$_FILES["file"]["name"]);
$extension = end($temp);
echo "uploading...";
if ($_FILES["file"]["error"] > 0)
{
echo "Error: " . $_FILES["file"]["error"] . "<br>";
}
else
{
move_uploaded_file($_FILES["file"]["tmp_name"],
"upload/" . $_FILES["file"]["name"]);
echo "Stored in: " . "upload/" . $_FILES["file"]["name"];
}
$_FILES["name"]["tmp_name"] does not exist, it should be $_FILES["file"]["tmp_name"]
I've built this webform wizard, consisting of several PHP pages. In this several pages users can fill in the form and the data gets temporarily stored in a session and at the last page the sessions are used to store all the data in the MYSQL database. Everything works fine with the exception of the uploaded file. Here is my code:
HTML: wizard_page2
<form name="registratieformulier" method="post" enctype="multipart/form-data" action="sw3.php">
<tr><td>Foto winkel uploaden: </td><td><input type="file" name="uploadfoto"/></td></tr><br /><br />
<tr><td><strong>Omschrijving van winkel:</strong></td> </tr><br />
<tr><textarea cols="50" rows="7" name="omschrijvingwinkel"></textarea></tr>
<input name="pkbedrijven" value="<?php echo($pkbedrijven); ?>" type="hidden" />
<input type="submit" name="stuurfoto" value="Verzenden" />
</form>
PHP: wizard_last_page
$_FILES['uploadfoto']['name'] = $_SESSION["naamfoto"];
$_FILES['uploadfoto']['tmp_name'] = $_SESSION["tijdelijk"];
$bn = $_SESSION["wn"];
$target_path = "../../winkels/$bn/";
$target_path = $target_path . basename( $_FILES['uploadfoto']['name']);
move_uploaded_file($_FILES['uploadfoto']['tmp_name'], $target_path)or die("There was an error uploading the file, please try again!");
$foto_path = "http://mywebsite.nl/winkels/$bn/".basename($_FILES['uploadfoto']['name']);
$omschrijving = $_SESSION["omschrijving"];
$add = "UPDATE winkelprofiel SET winkelomschrijving='$omschrijving', winkelfoto='$foto_path' WHERE fkBedrijvenID=$pkbedrijven ";
$query_upload = mysql_query($add) or die("De winkelfoto en omschrijving konden niet worden opgeslagen");
The $_FILES array only holds information about the file that has been uploaded in this request. If you do not save that file elsewhere within the same request, it will be removed by PHP at the end of the request. You cannot simply save $_FILES['uploadfoto']['tmp_name'] into the session and expect the file to still be there later, because it won't be. There's also no point in assigning the values in $_SESSION back into $_FILES, it won't bring the file back.
What you need to do:
if the upload was successful, move $_FILES['uploadfoto']['tmp_name'] somewhere else immediately
save the location you have moved it to into $_SESSION
do something with that file in $_SESSION at the end of your multi-page process (no need for $_FILES anymore at all)
have some mechanism in place to remove old uploaded files, in case the user abandons the session and the file never gets used
I think that the problem is, the file located at $_FILES['uploadfoto']['tmp_name'] will only be available when it is uploaded. Even you store the value in session, the file won't be there when you come to wizard_last_page. You need to handle uploaded files right away in the POST request.
So you need to move the file to $target_path or any certain temporary place when it's uploaded, then store the $target_path in the session so you can access to the file later on wizard_last_page.
Well, you can upload the file in one temporary location first. Then on the last page, once you submit the form, you can transfer the file to the desired location and then delete the temporary one.
$_SESSION['file'] = $_FILES["file"]["name"];
if (file_exists("uploads/" . $_FILES["file"]["name"]))
{
echo $_FILES["file"]["name"] . " already exists. ";
}
else
{
move_uploaded_file($_FILES["file"]["tmp_name"],"uploads/temp/" . $_FILES["file"]["name"]);
};
//This for the last page.
$file = file_get_contents("uploads/temp/".$_SESSION['file']);
file_put_contents("uploads/".$_SESSION['file'], $file);
I disagree with the accepted answer. There is a way to store all the images in the session array variable. You can use the "file_get_contents" function for storing the image.
Have a look at this:
$_SESSION['imgArrayFile'][] = $_FILES['file']; //Your file informations
$_SESSION['imgArrayName'][] = $_POST["ImgNewNamePlacowki"]; //new name for img
$_SESSION['ImgArrayAlt'][] = $_POST["ImgAltPlacowki"]; // alt tags if you use them
$_SESSION['obj_image_session'][] = file_get_contents($_FILES['file']['tmp_name']);
//above "file_get_contents" function - store image as a long string.
Regardless of what other think about using it for this purpose it can do the job for you.
There are several issues with storing large amounts of data in a session but if you images are small enough and you are aware of your settings limitation, then you will be just fine.
Save your file with
$file= $destination."/".$filename; //images/new.jpg
$fp=fopen($file,"w");
fwrite($fp,$_SESSION['obj_image_session'][$index]);
EXAMPLE FROM MY (WORKING) PROJECT:
<?php
//$galery_img_folder = "your/new/image/destination";
foreach($_SESSION['imgArrayFile'] as $index => $name){
if($_SESSION['imgArrayName'][$index]!=""
&& $_SESSION['ImgArrayAlt'][$index]!=""
&& $_SESSION['obj_image_session'][$index]!=""
){
$allowedExts = array("gif", "jpeg", "jpg", "png");
$temp = explode(".", $_SESSION['imgArrayFile'][$index]["name"]);
$extension = end($temp);
if ((($_SESSION['imgArrayFile'][$index]["type"] == "image/gif")
|| ($_SESSION['imgArrayFile'][$index]["type"] == "image/jpeg")
|| ($_SESSION['imgArrayFile'][$index]["type"] == "image/jpg")
|| ($_SESSION['imgArrayFile'][$index]["type"] == "image/pjpeg")
|| ($_SESSION['imgArrayFile'][$index]["type"] == "image/x-png")
|| ($_SESSION['imgArrayFile'][$index]["type"] == "image/png"))
&& ($_SESSION['imgArrayFile'][$index]["size"] < 104857600)
&& in_array($extension, $allowedExts))
{
if(isset($_SESSION['imgArrayName'][$index]) && $_SESSION['imgArrayName'][$index]!=""){
$rename = $_SESSION['imgArrayName'][$index];
$rename = $rename.".".end($temp);
}
if ($_SESSION['imgArrayFile'][$index]["error"] > 0)
{
echo "Return Error Code: " . $_SESSION['imgArrayFile'][$index]["error"] . "<br>";
}
else
{
$size = display_filesize($_SESSION['imgArrayFile'][$index]["size"]);
echo "Upload: " . $_SESSION['imgArrayFile'][$index]["name"] . "<br>";
echo "Type: " . $_SESSION['imgArrayFile'][$index]["type"] . "<br>";
echo "Size: " . ($size) . "<br>";
echo "Temp file: " . $_SESSION['imgArrayFile'][$index]["tmp_name"] . "<br>";
if (file_exists($galery_img_folder."/".$rename))
{
$error[] = ''.$rename.' <span class="error" id="error"> this name exsists </span>';
}
else
{
$_FILES["file"]["tmp_name"]=$_SESSION['imgArrayFile'][$index]["tmp_name"];
move_uploaded_file($_FILES["file"]["tmp_name"], $galery_img_folder."/".$rename);
//now make use of the file_get_content variables
$file= $galery_img_folder."/".$rename;
$fp=fopen($file,"w");
fwrite($fp,$_SESSION['obj_image_session'][$index]);
}
}
}
}
else
{
$error[] = '<span class="error" id="error"> Niewłaściwy plik </span>';
$maxsixe = display_filesize(104857600);
echo "Size: " . ($maxsixe) . "<br>";
}
}
}//end foreach ! ! !
}//end dodawanie zdjecia
?>
Of course you will have to make some small modifications to make it work with your project, but my point was to show you that it's possible.
Have a great day and happy coding !
I want to implement PHP uploading Progress Bar and My idea is to get the size of $_FILES['file']['tmp'] after each second.
But what is problem here, when a file is uploading there exist no file in temp directory set in php.ini but file successfully uploaded and when i try to get size of $_FILES['file']['tmp'] it show error warning.
<br />
<b>Warning</b>: filesize() [<a href='function.filesize'>function.filesize</a>]: stat failed for D:\Program Files\webserver\temp\phpDD05.tmp in <b>D:\Program Files\webserver\www\test\upload\uploading.php</b> on line <b>5</b><br />
which mean i think file not exist. How we can converge this idea to success for uploading with progress bar
You can try something like this to see if there's an error, then grab the file size if there are no errors.
<?php
if ($_FILES["file"]["error"] > 0)
{
echo "Error: " . $_FILES["file"]["error"] . "<br />";
}
else
{
echo "Upload: " . $_FILES["file"]["name"] . "<br />";
echo "Size: " . ($_FILES["file"]["size"] / 1024) . " Kb<br />";
}
?>
What does that do for you?
File is incapsulated in the POST request, so you need something outside your form that uploads the file and something that monitors periodically the file. I suggest some already made solutions like ajax upload progress bar or similar
I have this script for uploading a image and content from a form, it works in one project but not the other. I have spent a good few hours trying to debug it, I am hoping someone could point out the issue I might be having. Where there are comments is where I have tried to debug. The first error I got was the "echo invalid file" at the beginning of the last comment. With these specific areas commented out the upload name and type that I am supposed to be grabbing from the form is not being echoed, I am thinking this is where the error is occurring, but can't quite seem to find it. Thanks.
<?php
include("../includes/connect.php");
/*
if ((($_FILES["file"]["type"] == "image/gif")
|| ($_FILES["file"]["type"] == "image/jpeg")
|| ($_FILES["file"]["type"] == "image/pjpeg"))
&& ($_FILES["file"]["size"] < 2000000))
{
*/
if ($_FILES["file"]["error"] > 0)
{
echo "Return Code: " . $_FILES["file"]["error"] . "<br />";
}
else
{
echo "Upload: " . $_FILES["file"]["name"] . "<br />";
echo "Type: " . $_FILES["file"]["type"] . "<br />";
echo "Size: " . ($_FILES["file"]["size"] / 1024) . " Kb<br />";
echo "Temp file: " . $_FILES["file"]["tmp_name"] . "<br />";
/* GRAB FORM DATA */
$title = $_POST['title'];
$date = $_POST['date'];
$content = $_POST['content'];
$imageName1 = $_FILES["file"]["name"];
echo $title;
echo "<br/>";
echo $date;
echo "<br/>";
echo $content;
echo "<br/>";
echo $imageName1;
$sql = "INSERT INTO blog (title,date,content,image)VALUES(
\"$title\",
\"$date\",
\"$content\",
\"$imageName1\"
)";
$results = mysql_query($sql)or die(mysql_error());
echo "<br/>";
if (file_exists("../images/blog/" . $_FILES["file"]["name"]))
{
echo $_FILES["file"]["name"] . " already exists. ";
}
else
{
move_uploaded_file($_FILES["file"]["tmp_name"],
"../images/blog/" . $_FILES["file"]["name"]);
echo "Stored in: " . "../images/blog/" . $_FILES["file"]["name"];
}
}
/*
}
else
{
echo "Invalid file" . "<br/>";
echo "Type: " . $_FILES["file"]["type"] . "<br />";
}
*/
//lets create a thumbnail of this uploaded image.
/*
$fileName = $_FILES["file"]["name"];
createThumb($fileName,310,"../images/blog/thumbs/");
function createThumb($thisFileName, $thisThumbWidth, $thisThumbDest){
$thisOriginalFilePath = "../images/blog/". $thisFileName;
list($width, $height) = getimagesize($thisOriginalFilePath);
$imgRatio =$width/$height;
$thisThumbHeight = $thisThumbWidth/$imgRatio;
$thumb = imagecreatetruecolor($thisThumbWidth,$thisThumbHeight);
$source = imagecreatefromjpeg($thisOriginalFilePath);
imagecopyresampled($thumb, $source, 0, 0, 0, 0, $thisThumbWidth,$thisThumbHeight, $width, $height);
$newFileName = $thisThumbDest.$thisFileName;
imagejpeg($thumb,$newFileName, 80);
echo "<p><img src=\"$newFileName\" /></p>";
//header("location: http://www.google.ca");
}
*/
?>
Perhaps you forgot to add enctype="multipart/form-data" method="post" to your HTML form, or have no <input type="file" name="file" id="file" value=""/> in your HTML.
Here's some problems with your script:
The 'error' value in the $_FILES array is not just a boolean, it will tell you if an upload succeeded, or why it failed. The error codes are defined here.
The 'type' value is supplied by the remote client. It's NOT determined by the web server or PHP. As such, doing mime-type verification based on that value is a major hole: it's trivial to forge the supplied type value. Best to use a server-side method, like fileinfo, to determine the actual mime type.
You blindly insert the form data into your insertion query, which leaves you wide open to SQL injection attacks. At least pass the data through mysql_real_escape_string() before building your query, or better yet, use PDO and parameterized queries
You're storing the files with the original client-provided name. You at least check if the filename's already in use, preventing upload collisions/overwriting, but there's also the case where the client's operating system/file system allows characters in filenames that the server's OS/FS do not, which could lead to subtle file "vanished" bugs, or overwriting entirely different files because the invalid characters were filtered out or translated to something else. Since you're using a database to store information about the upload, you can store the original filename in that table, and use the table's primary key (an auto_increment int, right?) as the filename.
Not really a problem, but in terms of efficiency, there's no need to use getimagesize() in your thumb creation function. GD has imagesx() and imagesy() which get the pixel size from a GD image handle. getimagesize() is independent of GD, so you're opening and parsing the source image twice. Again, it's not really a problem, but on a busy site, opening the image only once could be a decent cpu time and memory usage savings.
The error was in the html form file, I had added a name="something" beside the method="post" and enctype="multi/form-data" obviously this was not liked. Thanks RC for pointing me in the right direction. I am not quite sure why I did this.
$_FILES["file"]["error"] is not just a flag.
It has error codes.
Explained in the manual
Is this totally safe or not? I would like a totally safe file uploading script for my new project. Here is the one I found:
<?php
if ((($_FILES["file"]["type"] == "image/gif")
|| ($_FILES["file"]["type"] == "image/jpeg")
|| ($_FILES["file"]["type"] == "image/pjpeg"))
&& ($_FILES["file"]["size"] < 20000))
{
if ($_FILES["file"]["error"] > 0)
{
echo "Return Code: " . $_FILES["file"]["error"] . "<br />";
}
else
{
echo "Upload: " . $_FILES["file"]["name"] . "<br />";
echo "Type: " . $_FILES["file"]["type"] . "<br />";
echo "Size: " . ($_FILES["file"]["size"] / 1024) . " Kb<br />";
echo "Temp file: " . $_FILES["file"]["tmp_name"] . "<br />";
if (file_exists("upload/" . $_FILES["file"]["name"]))
{
echo $_FILES["file"]["name"] . " already exists. ";
}
else
{
move_uploaded_file($_FILES["file"]["tmp_name"],
"upload/" . $_FILES["file"]["name"]);
echo "Stored in: " . "upload/" . $_FILES["file"]["name"];
}
}
}
else
{
echo "Invalid file";
}
?>
You can't trust the $_FILES["file"]["type"] for mime types. That information is sent by the browser so it could be faked. It's best to check mime types with mime_content_type or Fileinfo.
One thing to be aware of is MIME Type Detection in Internet Explorer, which can turn your images into a security risk.
Even if a file has the right extension, and is served with an image mime type, if the file itself contains tokens like <html>, <body>, etc, IE (7 and older) may still interpret it as HTML, opening up a possible XSS exploit.
The files with viruses are still going to get through.
Looks ok to me.
Unless files are scanned, there is no totally 100% safe way to do file uploading. Remember, PHP is a scripting language, not a security program language. So it is as safe as you make it. That said, besides limiting the size and type, the only other thing you might be able to do is check for weird file names - weird being what you define for your application.
If you can use a third party service to scan your files (as yahoo scans attatchments for viruses) for virus, that would make the application better, but I don't know of any off the top of my head.
This might be the over-pedantic ramblings of a security analyst, but you should validate all those fields, using regular expressions for example. And the content as well. Otherwise you just can't be sure. One could quite easily trick that code into accepting a file as being an 'image/gif' then embed a script in it that a particular Apache handler might choose to treat as a valid command! (maybe not by default, but when you install a 'cool new Apache module' in the future...)
If you want a 'totally' secure script: Validate EVERYTHING to make sure everything is exactly how you want it and nothing more or less.