Web site baker image upload problem - php

Recently I am developing website baker's module. There is one option to upload image. I am using php image upload code but give the following error and image didn't upload.
Warning: move_uploaded_file(http://localhost/wb/media/gallery/mypic.jpg) [function.move-uploaded-file]: failed to open stream: HTTP wrapper does not support writeable connections in C:\wamp\www\wb\modules\hotelmod\save_picture.php on line 84
Warning: move_uploaded_file() [function.move-uploaded-file]: Unable to move 'C:\wamp\tmp\phpBBBD.tmp' to 'http://localhost/wb/media/gallery/mypic.jpg' in C:\wamp\www\wb\modules\hotelmod\save_picture.php on line 84
here's the code that i use:
if (($_FILES["image"]["type"] == "image/jpeg" || $_FILES["image"]["type"] == "image/pjpeg" || $_FILES["image"]["type"] == "image/gif" || $_FILES["image"]["type"] == "image/x-png") && ($_FILES["image"]["size"] < 4000000))
{
// if uploaded image was JPG/JPEG
if($_FILES["image"]["type"] == "image/jpeg" || $_FILES["image"]["type"] == "image/pjpeg"){
$image_source = imagecreatefromjpeg($_FILES["image"]["tmp_name"]);
}
// if uploaded image was GIF
if($_FILES["image"]["type"] == "image/gif"){
$image_source = imagecreatefromgif($_FILES["image"]["tmp_name"]);
}
// BMP doesn't seem to be supported so remove it form above image type test (reject bmps)
// if uploaded image was BMP
if($_FILES["image"]["type"] == "image/bmp"){
$image_source = imagecreatefromwbmp($_FILES["image"]["tmp_name"]);
}
// if uploaded image was PNG
if($_FILES["image"]["type"] == "image/x-png"){
$image_source = imagecreatefrompng($_FILES["image"]["tmp_name"]);
}
$remote_file = WB_URL.'/modules/hotelmod/images/'.$_FILES["image"]["name"];
move_uploaded_file($_FILES['image']['tmp_name'], $remote_file);
}
How can I resolve this? Thanks in advance.

You're probably trying to do something like:
move_uploaded_file($_FILES['somefile']['tmp_name'], 'http://localhost/wb/media/gallery/mypic.jpg');
This is incorrect. Attempting to write to a URL would only trigger yet another HTTP upload, which is what you're already trying to handle.
The destination/target of move_uploaded_files() must be a file system path, something like
/home/sites/yoursite/document_root/images/mypic.jpg
instead.

You're passing a URL to move_uploaded_file(). move_uploaded_file() needs a path. Not a URL. Probably something like (for windows) C:\path\to\save\uploads

You destination must be a file system path, not a URL. Its up to your web server to map URLs to filesystem paths to find the file (but of course your scripts need to know how it does that so you can create links to it).
E.g., you could configure your server to serve http://example.com/uploads/ from /srv/www/example.com/uploads/. Then you'd have your PHP script move the file to /srv/www/example/com/uploads/FOO.png.
Make sure to turn off PHP (and CGI, etc.) in your upload directory for security reasons. E.g., in Apache, you'd do:
<Directory /srv/www/example.com/uploads>
php_admin_flag engine off
</Directory>

Related

Are There Any Security Issues In The Following File Upload Script - PHP

I've looked at a number of the answers to StackOverflow questions on safely uploading images with PHP. I've put this following script together with explainers and wanted to know if this is missing anything. My only/main concern is I can't seem to find much info on stripping out harmful code from the image itself, although this is partly covered in the code.
A couple of SO answers touch on the GD image functionality but they don't really give any good code example cases and because I'm new to php I can't quite seem to wrap my head around how to use this (in terms of creating a new version of the image).
Note: This images in this code go to an '/images' directory, but on the live site they will go into a subdomain called 'images' which is outside the public folder and which will serve static files only (no PHP, Perl etc). The short_open_tag will be turned off in the php.ini file.
The files are selected with a file input type with the name 'profile-image'.
The following code is split into its component parts - the first part is the if/isset statements that check that a submit button called 'submit-profile-image' has been clicked, and the files have been uploaded into memory in the ['tmp_name'] key of the $_FILES superglobal:
if(isset($_POST['submit-profile-image'])) {
$allowed = ['jpeg', 'jpg', 'png'];
if($_FILES['profile-image']['error'] === 0 ) {
// THE DIFFERENT CHECKS IN THE MAIN CODE BELOW GO HERE
} else {
$error[] = "Image failed to load please try again";
}
}
This following code all goes inside the 2nd if statement shown above - I've broken it down to show what it is meant to acheive:
Set variable names of temp upload file and file input name
$profileImageName = $_FILES['profile-image']['name'];
$temp = $_FILES['profile-image']['tmp_name'];
Explode string to split the file name and file extension
$ext = explode('.', $profileImageName);
$ext = strtolower(end($ext));
Completely rename file, and only keep the file extension from the original file:
$file = uniqid('', true) . time() . '.' . $ext;
Sanitize string for extra safety (probably not needed)
$file = filter_var($file, FILTER_SANITIZE_STRING);
$file = strtolower($file);
Check the file extention matches the allowed array of file extensions:
if (!in_array($ext, $allowed)) {
$error[] = "File type must be in the jpg / jpeg or png format";
}
Check MIME type using the getImageSize() function which is more reliable than the 'type' key found in the standard $_FILES superglobal:
$getImageSizeMime = getImageSize($temp);
if(isset($getImageSizeMime['mime']) == false) {
$error[] = "Not a recognised MIME type";
} else {
$getImageSizeMime = $getImageSizeMime['mime'];
}
Make sure the MIME type matches the file extension:
if (in_array($ext, $allowed) != $getImageSizeMime) {
$error[] = "Mime type must be of the jpg / jpeg or png format";
}
Inspect contents of image file itself:
$cleanUpload = file_get_contents($temp) ;
Disallow if file contents contain php or script:
if(preg_match('/(<\?php\s)/', $cleanUpload)) {
$error[] = "Image data cannot contain php script tags";
}
if(preg_match('/script/', $cleanUpload)) {
$error[] = "Image data cannot contain javascript tags";
}
Sanitise file contents of HTML tags
$cleanUpload = filter_var($cleanUpload, FILTER_SANITIZE_STRING);
Move uploaded file if none of the above errors are present
if (!isset($error)) {
if(in_array($ext, $allowed)) {
move_uploaded_file($temp, 'images/' . $file);
}
}
Any input on any security issues missed or any extra checks on the image file itself would be hugely appreciated - particularly on how to duplicated the image to only keep image data using the GD library if possible/necessary? Some of the answers on StackOverflow are very old and seem to feature methods that aren't seen as the most up to date either (which I've avoided in this question).
It would be really good to see if there are any PHP methods for checking image files themselves and removing potentially dangerous code.

in_array() vs if else on file uploading in php

Description :
I have given the interface to the user where he/she can upload pdf,doc,docx,img files perfectly.
Every thing is done except I have a confusion on one little piece of code. So before knowing any reason why its done I cant just write it in my php.
While uploading any file at first we do check the type of file before taking any further actions.
Now there are two ways by which we can check one is
$ext = end(explode(".",$_FILES['upload'][name]));
if(in_array($ext,$array_name_of_all_allowed_extensions))
OR
if($_FILES['upload']['type'] == "application/pdf")
{
//any action
}
but every where I see the code for uploading the file is as
$allowedExts = array("pdf", "doc", "docx");
$extension = end(explode(".", $_FILES["file"]["name"]));
if ((($_FILES["file"]["type"] == "application/pdf")
|| ($_FILES["file"]["type"] == "application/msword"))
&& ($_FILES["file"]["size"] < 20000000)
&& in_array($extension, $allowedExts))
{
if ($_FILES["file"]["error"] > 0)
{
echo "Return Code: " . $_FILES["file"]["error"] . "<br>";
}
every one seems to be using the both .. the if condition for the type and in_array() as well.
Can any one tell me why is that. I mean using any one of them in_array() preferred should do the job
Is this understandable :
$ext = end(explode(".",$_FILES['upload'][name]));
if(in_array($ext,$array_name_of_all_allowed_extensions))
the above piece of code my fellow programmer is to check the extension of the file user uploaded it can be any weird extension that you don't your web app to upload so you define an array that only the files that end with ".jpeg , .jpg , .pdf" etc are allowed to be uploaded
if ((($_FILES["file"]["type"] == "application/pdf")
this above line of code checks the type of uploaded file that whether it is the type you allow or not
you can write .exe at the end of any pdf file and it will update the name of the file to mypdf.exe how ever the type of the file will still remain pdf document and it will open as regular as it should ... So checking through if is just a little work that the file being uploaded has a correct name and not been tampered with ...
Its entirely your choice otherwise if you make an array of the allowed file type and then use in_array() that is enough too ... hope that helps :) ile that whether

How do you dynamically set the upload target path when using an AJAX based file uploader?

I'm trying to implement Valum's file uploader (improved by Ben Colon https://github.com/bencolon/file-uploader) and I'm running into a problem. Previously, my upload.php had the upload target set in accordance to certain input fields. See here:
//Directory where files are stored
if ($grade == '9')
{
$target = "storage/g9/";
}
elseif ($grade == '10')
{
$target = "storage/g10/";
}
elseif ($grade == '11')
{
$target = "storage/g11/";
}
elseif ($grade == '12')
{
$target = "storage/g12/";
}
$target = $target . $_POST['snumber'] . "." . $extension;
move_uploaded_file($_FILES['upload']['tmp_name'], $target);
Now, with an AJAX based file uploader it starts uploading before you even hit submit so PHP doesn't get a chance to pickup the input fields to decide what the upload path is going to be, it can only go to a predefined one. To see how the AJAX file uploader does it, view their PHP on GitHub. How do I make it so the upload path changes depending on the user input fields?
I believe PHP needs to know where to save the file as soon as you start uploading it. But, you can move the file once it's finished uploading, via PHP's rename() function.
There's also move_uploaded_file() (although I've never used it myself).

File Uploading and Security

I'm currently writing an upload class for uploading images. I do extension checks to verify that the uploaded images are of the supported types, and the photos are always chmod(0664) when the uploaded file is copied to it's resting place. Is this relatively safe? I don't know much about image encoding, but even if someone went through the trouble of somehow tricking my extension check, the file could never be ran on the server anyways unless there was a security hole elsewhere and the attackers were already into my file system, correct? Here's my extension check:
function validate_ext() { //Function validates that the files extension matches the list of allowed extensions
$extension = $this->get_ext($this->theFile);
$ext_array = $this->extensions;
if (in_array($extension, $ext_array)) { //Check if file's ext is in the list of allowed exts
return true;
echo "ext found";
} else {
$this->error[] = "That file type is not supported. The supported file types are: ".$this->extString;
return false;
}
}
And here's the function that copies the uploaded file to it's final resting place.
if ($_FILES[$this->uploadName]['error'] === UPLOAD_ERR_OK){
$newfile = $this->uploadDir.$this->theFile;
if (!move_uploaded_file($this->tempFile, $newfile)) {
$this->error[] = "The file could not be moved to the new directory. Check permissions and folder paths.";
die($this->error_text());
}else{
$this->error[] = "The file ".$this->originalName." was successfully uploaded.";
if ($this->renameFile == true){
$this->error[] = $this->originalName." was renamed to ".$this->theFile;
}
chmod($newfile , $this->fileperm);
}
}else{
$this->error[] = $this->file_upload_error_message($_FILES[$this->uploadName]['error']);
die($this->error_text());
}
Reading the extension really isnt a good way to check file type. You should read the file mime type... granted that can be faked too, but its more of a hassle to fake.
In Linux world, as long as u gave the file non-executable permission, the file cannot execute. Whether it's .jpeg or it's .bash. That's true the other way around too, .jpeg with an executable permission could be executed too (if the content of that .jpeg file is executable file, not image content).
You can use getimagesize() to check the file itself.

Checking filetypes when uploading, and browser dependency issues

I'm building a php file uploader and I've some issues with security. For example I don't want to allow ".php" file uploads. As I know the only way to check the file type is with $_FILES['file']['type'] and the value of it is browser dependent.
I check with multiple browsers and found that when selecting a regular .php file different browsers return these values:
firefox: application/x-download
chrome: text/plain
safari: text/plain
IE: text/plain
opera: application/octet-stream
I've also tried the same experiment with the regular .txt files and all browses return text/plain as the mime type.
So here's the problem, If I want to allow the .txt file upload what should I do to prevent .php file uploads?
Don’t rely on the information the client sends. Even the media type the client sends can be forged.
If you don’t want to allow PHP files, just don’t allow files with the file extension .php or change it to .txt:
if (strtolower(strrchr($_FILES['file']['name'], '.')) == '.php') {
// has file extension .php
}
Use the following function:
function Mime($path)
{
$result = false;
if (is_file($path) === true)
{
if (function_exists('finfo_open') === true)
{
$finfo = finfo_open(FILEINFO_MIME_TYPE);
if (is_resource($finfo) === true)
{
$result = finfo_file($finfo, $path);
}
finfo_close($finfo);
}
else if (function_exists('mime_content_type') === true)
{
$result = preg_replace('~^(.+);.*$~', '$1', mime_content_type($path));
}
else if (function_exists('exif_imagetype') === true)
{
$result = image_type_to_mime_type(exif_imagetype($path));
}
}
return $result;
}
This will return the proper mime type of any file.
Try the following. It is FAR from fool proof but its a quick check. it will block anything labeled .php (as it is on the client machine) so if they have something like 'do_evil.php.txt' it will allow it BUT (read the code notes)
$file_ext = substr($_FILES['userfile']['name'], -3);
if($file_ext == 'php') {
//REJECT FILE
}
else {
// allow upload and once the file has been upload to the temp directory
// have a peice of code move the file to the final location and rename
// the file and specify a new file extension, using $file_ext as the extension
// so even if the file was 'do_evil.php.txt' when it comes to rest at the
// final location it will be 'do_evil.txt' and thus treated by the server as a
// text file and not PHP
}
I have used the above in the past with descent results. It is by no means bullet proof, but it should at least help. i think i might have some code lying around that does all of that, if you need it ill go looking for it but no promises i can find it

Categories