Cannot upload image from $_FILES - php

I am doing a simple image upload with PHP, which I have done 100 times before. This time it isn't working. I have both the /tmp and uploads directories set to chmod 777, I have chown'd the directories to apache, I have verified that the $_FILES array is populated:
<input type="file" name="uploadimage" id="uploadimage" />
[uploadimage] => Array(
[name] => dilbert.jpg
[type] => image/jpeg
[tmp_name] => /tmp/phpkuJyyP
[error] => 0
[size] => 731602
)
Here's my code:
$response = array();
$response['path'] = '';
$response['success'] = false;
$response['error'] = '';
$targetDir = "../../../images/uploads/";
$filepath = $targetDir . $_FILES['uploadimage']['name'];
// here just for testing since it won't return below
$response['path'] = $filepath;
if(is_array($_FILES)) {
if(is_uploaded_file($_FILES['uploadimage']['tmp_name'])) {
if(move_uploaded_file($_FILES['uploadimage']['tmp_name'], $filepath)) {
$response['success'] = true;
$response['path'] = $targetDir . $_FILES['uploadimage']['name'];
} else {
$response['error'] = 'File could not be moved';
}
} else {
$response['error'] = 'File not found';
}
} else {
$response['error'] = 'Files array not found';
}
The error I am getting is the innermost one, "File could not be moved"
The path I am getting back in my AJAX call is correct, it should be domain.com/images/uploads/filename.jpg and it is...
I manually uploaded an image to the uploads directory, domain.com/images/uploads/1.jpg and then uploaded that image again witht he uploaded, and it resolves in the UI, because the image was already there, thus I know the path being passed back is accurate.
What else can I try? Images are not ending up in /tmp
Apache errors
PHP Warning: move_uploaded_file(../../../images/uploads/dilbert.jpg):
failed to open stream: No such file or directory in
/var/www/webapp/application/controllers/DocumentController.php
on line 75, referer: http://192.168.1.3/document/
PHP Warning: move_uploaded_file(): Unable to move '/tmp/phpm4Ivrx' to
'../../../images/uploads/dilbert.jpg' in
/var/www/webapp/application/controllers/DocumentController.php
on line 75, referer: http://192.168.1.3/document/
File does not exist:
/var/www/webapp/public/images/uploads/dilbert.jpg, referer:
http://192.168.1.3/document/

Related

Cannot upload image via move_uploaded_file

I am using code below to upload image via drag an drop system. Everything is ok, JS part is working well. But PHP part of code shows me error:
PHP Warning: move_uploaded_file(assets/img/photos/1657614494809.jpg): failed to open stream: No such file or directory in /www_root/_inc/upload.php on line 29, referer: https://smartobchod.sk/bazar/add.php
[Sat Jul 23 12:56:18 2022] [error] [client 78.99.32.1] PHP Warning: move_uploaded_file(): Unable to move '/home/gm016900/tmp/phpKaBL6m' to 'assets/img/photos/1657614494809.jpg' in /www_root/_inc/upload.php on line 29, referer: https://smartobchod.sk/bazar/add.php
EDITED 25.07.2022 (added some security checks)
My PHP code in upload.php is:
<?php
// Get reference to uploaded image
$image_file = $_FILES["file"];
// Get image name
$image_name = $_FILES["file"]["name"];
// Get file size
$image_size = $_FILES["file"]["size"];
// Exit if no file uploaded or image name contains unvalid characters /, \\
if ( ( !strpos($image_name, '/') || !strpos($image_name, '\\') ) && isset($image_file) ) {
$errors = array();
$maxsize = 10485760;
$acceptable = array(
'image/jpeg',
'image/jpg',
'image/gif',
'image/png'
);
} else {
die('No image uploaded.');
}
// Exit if image file is zero bytes or if image size is more then 10 MB
if (getimagesize($image_file["tmp_name"]) <= 0) {
die('Uploaded file has no contents.');
} elseif ($image_size >= $maxsize) {
die('Image is too large. Image must be less than 10 megabytes.');
}
// Exit if is not a valid image file or image has not supported type
$image_type = exif_imagetype($image_file["tmp_name"]);
if (!$image_type) {
die('Uploaded file is not an image.');
} elseif ( !in_array($image_file["type"], $acceptable) ) {
die('Image has not supported type JPG, PNG, GIF.');
} else {
$src = "default.png";
}
// Get file extension based on file type, to prepend a dot we pass true as the second parameter
$image_extension = image_type_to_extension($image_type, true);
// Create a unique image name
$image_name = bin2hex(random_bytes(16)) . $image_extension;
// Location
$relative_location = "/bazar/assets/img/photos/".$image_name;
$absolute_location = dirname(__DIR__, 2).$relative_location;
$return_arr = array();
// transfer file created in tmp folder to location of pictures with name saved in address of $location
// in $image_file is stored $_FILES["file"]["tmp_name"]
if (move_uploaded_file($image_file["tmp_name"], $absolute_location)) {
$src = $relative_location;
$return_arr = array("name" => $image_name,"size" => $image_size, "src"=> $src);
}
echo json_encode($return_arr);
This is sent in header to upload.php:
Content-Disposition: form-data; name="file"; filename="1657614494809.jpg"
Content-Type: image/jpeg
Can you advice me what can be problem?
Here I think your tmp/ folder permission is not proper so it is not able to read that folder or write just check /home/gm016900/tmp permission is should be gm016900 or it may not be created.
Based on your comments, you just need to keep track of relative vs absolute paths.
I wasn't able to test this code, but hopefully you should get the general gist if it fails. Instead of a single $location variable, I'm using two variables $relativeLocation and $absoluteLocation. The latter isn't actually needed, but it makes debugging much easier.
/* Getting file name */
$filename = $_FILES['file']['name'];
/* Getting File size */
$filesize = $_FILES['file']['size'];
/* Location */
$relativeLocation = "assets/img/photos/".$filename;
$absoluteLocation = __DIR__.'/'.$relativeLocation;
$return_arr = array();
/* Upload file */
if (move_uploaded_file($_FILES['file']['tmp_name'], $absoluteLocation)) {
$src = "default.png";
// checking file is image or not
if (is_array(getimagesize($absoluteLocation))) {
$src = $relativeLocation;
}
$return_arr = array("name" => $filename, "size" => $filesize, "src" => $src);
}
echo json_encode($return_arr);
Depending on where your function lives relative to the storage, you might need to go update a directory or two, or possibly go up and then back down:
// Up one directory
$absoluteLocation = dirname(__DIR__).'/'.$relativeLocation;
// Up two directories
$absoluteLocation = dirname(__DIR__, 2).'/'.$relativeLocation;
// Up one directory then over to a sibling directory
$absoluteLocation = dirname(__DIR__).'/files/'.$relativeLocation;
As a personal preference, I always have a constant (or equivalent) in my projects that represents a known location on disk, and if I'm using a router script I define it there. That way, no matter how deep I get in nesting I can build my paths relative to that constant.
I also go one step further and use this library (merged into Symfony here) to avoid string concatenation, not worry about whether something ends with a slash or not, and to be more cross platform. So my actual code looks like:
$absoluteLocation = Path::join(PROJECT_ROOT, 'files', $relativeLocation);
Some people might think that's overkill, but once again it is just a personal preference.

Multiple file upload -- works fine when all documents are uploaded fails when only few are entered

I have this form in which it is required to upload multiple files(upto 10 files). Here's what the html looks like:
<form action="fileupload.php" method="post" enctype="multipart/form-data">
<tr><td><input type="hidden" name="consultant_id" value="<?php echo $consult_id; ?>"></td></tr>
<tr><td>Offer letter:</td><td> Doc: <input type="file" name="myfile[]"></td></tr>
<tr><td>Project acceptance agreement:</td><td> Doc: <input type="file" name="myfile[]"></td></tr>
<tr><td>Employee book:</td><td> Doc: <input type="file" name="myfile[]"></td></tr>
<tr><td>W4 :</td><td> Doc: <input type="file" name="myfile[]"></td></tr>
<tr><td>State W4 :</td><td> Doc: <input type="file" name="myfile[]"></td></tr>
<tr><td><input type="submit" name="submit" value="Upload"> </td></tr>
</form></table>
I want to upload the files to the server and store their respective paths in database(MySql). Now the following php code works awesome when I give input to all file fields(upload all 10 files) but fails when I want to upload only some files(say 5). Here's the code :
<?php
$consultant_id = $_POST['consultant_id'];
echo $consultant_id;
$verified_start_date = $_POST['verified_start_date'];
// Assign valid types
$valid_mime = array(
'application/pdf',
'image/jpeg',
'image/jpg',
);
function upload($files, $dir, $size_limit=1024, $prevent_duplicate=false){
global $valid_mime;
// $files must be given.
if(!isset($files)) return false;
// Look for $valid_mime array.
isset($valid_mime) and is_array($valid_mime) or die('Error in data resources, valid_mime array not found.');
// Make directory if it does not exists. set permission to 0777.
is_dir($dir) and chmod($dir, 0777) or mkdir($dir, 0777, true);
//is_dir($consultant_id) and ($dir, 0777) or mkdir($dir/$consultant_id, 0777, true);
$count = 1;
foreach($files as $file){
$file['error'] === UPLOAD_ERR_OK or die('Error in uploading file(s).');
// Check uploaded-file type.
in_array($file['type'], $valid_mime) or die();
// Set size_limit in KB.
$file['size'] > $size_limit*1024 and die('The uploaded file exceeds the maximum file size.');
$file_extension = strrchr($file['name'], '.');
$filename = basename($file['name'], $file_extension);
$file_path = "{$dir}/{$filename}{$file_extension}";
// Move uploaded-file from php temp folder to desire one.
move_uploaded_file($file["tmp_name"], $file_path);
// Make an array of filepaths
$output[] = $file_path;
}
// Change permission of folder according to security issues.
chmod($dir, 0755);
return $output;
}
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////// Controller Section ////////////////////////////////
// Assign tmp_arr from $_FILES['myfile'] and do die if there is any problem.
$tmp_arr = (isset($_POST['submit']) and isset($_FILES['myfile'])) ? $_FILES['myfile'] : die('Error in posting data.');
// Create an array with desired structure.
for($i=0; $i<count($tmp_arr['name']); $i++){
$files[] = array(
'name' => $tmp_arr['name'][$i],
'type' => $tmp_arr['type'][$i],
'tmp_name' => $tmp_arr['tmp_name'][$i],
'error' => $tmp_arr['error'][$i],
'size' => $tmp_arr['size'][$i],
);
}
// size_limit in KB
$path_arr = upload($files, './public/'.$consultant_id, 1024, true);
?>
I have not mentioned the part where data is entered in database, as I know the problem is somewhere in $tmp_arr['error'][$i] or $file['error'] === UPLOAD_ERR_OK or die('Error in uploading file(s).');
Please take a look.
The problem appears to be that when you have a blank file input, it returns an 'error' value of 4 which means UPLOAD_ERR_NO_FILE. So since the field doesn't match UPLOAD_ERR_OK you immediately stop all code by calling die stopping any files after the first blank from copying over. If the first field was blank, nothing would get get to the move_uploaded_file. If the third out of ten was blank, then the first two files would get copied and when the third was processed it would stop any further files. But you would still just see the error "Error in uploading file(s)."
Edit:
<?php
$consultant_id = $_POST['consultant_id'];
echo $consultant_id;
$verified_start_date = $_POST['verified_start_date'];
// Assign valid types
$valid_mime = array(
'application/pdf',
'image/jpeg',
'image/jpg',
);
function upload($files, $dir, $size_limit=1024, $prevent_duplicate=false){
global $valid_mime;
// $files must be given.
if(!isset($files)) return false;
//please use proper if statements. This is confusing.
//isset($valid_mime) and is_array($valid_mime) or die('Error in data resources, valid_mime array not found.');
// Look for $valid_mime array.
if(!isset($valid_mime) || !is_array($valid_mime)) {
die('Error in data resources, valid_mime array not found.');
}
//please use proper if statements. This is confusing.
// is_dir($dir) and chmod($dir, 0777) or mkdir($dir, 0777, true);
// Make directory if it does not exists. set permission to 0777.
if(!is_dir($dir)) {
mkdir($dir, 0777, true);
} else {
//try to chmod if the directory does exist
chmod($dir, 0777);
}
if(!is_writable($dir)){
die('Error unable to write to specified directory.');
}
foreach($files as $key=>$file){
//switch case on the error code
//you can find a list of these error codes at: http://php.net/manual/en/features.file-upload.errors.php
switch($file['error']){
default:
//triggered if an unknown error happened. Newer php versions might bring new constants.
//log error for this file
$output[$key] = array('error'=>true, 'message'=>'An unknown error occurred');
break;
case UPLOAD_ERR_INI_SIZE:
//log error for this file
$output[$key] = array('error'=>true, 'message'=>'File size exceeds ini setting');
break;
case UPLOAD_ERR_FORM_SIZE:
//log error for this file
$output[$key] = array('error'=>true, 'message'=>'File size exceeds MAX_FILE_SIZE setting');
break;
case UPLOAD_ERR_PARTIAL:
//log error for this file
$output[$key] = array('error'=>true, 'message'=>'File was only partially uploaded');
break;
case UPLOAD_ERR_NO_FILE:
//log error for this file
$output[$key] = array('error'=>true, 'message'=>'File input was blank');
break;
case UPLOAD_ERR_NO_TMP_DIR:
//log error for this file
$output[$key] = array('error'=>true, 'message'=>'Missing temporary folder');
break;
case UPLOAD_ERR_CANT_WRITE:
//log error for this file
$output[$key] = array('error'=>true, 'message'=>'Failed to write file to disk');
break;
case UPLOAD_ERR_OK:
//upload worked fine
// Check uploaded-file type.
if(in_array($file['type'], $valid_mime)){
// Set size_limit in KB.
if($file['size'] <= $size_limit*1024){
//get the file extension.
$file_extension = strrchr($file['name'], '.');
//get the filename
$filename = basename($file['name'], $file_extension);
//full filename and path
$file_path = "{$dir}/{$filename}{$file_extension}";
// Move uploaded-file from php temp folder to desire one.
// function returns true if the move was successful
if(move_uploaded_file($file["tmp_name"], $file_path)){
$output[$key] = array('error'=>false, 'message'=>'File was uploaded successfully', 'file'=>$file_path);
} else {
$output[$key] = array('error'=>true, 'message'=>'Unspecified error when moving the uploaded file');
}
} else {
//log error for this file
$output[$key] = array('error'=>true, 'message'=>'The uploaded file exceeds the maximum file size');
}
} else {
//log error for this file
$output[$key] = array('error'=>true, 'message'=>'Failed to write file to disk');
}
}
}
// Change permission of folder according to security issues.
chmod($dir, 0755);
return $output;
}
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////// Controller Section ////////////////////////////////
// Assign tmp_arr from $_FILES['myfile'] and do die if there is any problem.
$tmp_arr = (isset($_POST['submit']) and isset($_FILES['myfile'])) ? $_FILES['myfile'] : die('Error in posting data.');
// Create an array with desired structure.
for($i=0; $i<count($tmp_arr['name']); $i++){
$files[] = array(
'name' => $tmp_arr['name'][$i],
'type' => $tmp_arr['type'][$i],
'tmp_name' => $tmp_arr['tmp_name'][$i],
'error' => $tmp_arr['error'][$i],
'size' => $tmp_arr['size'][$i],
);
}
// size_limit in KB
$path_arr = upload($files, './public/'.$consultant_id, 1024, true);
If I were doing this, this is the function I would use. If one uploaded file has a problem, it won't stop the remaining files from uploading and translates the 'error' key from $_FILES into a more user friendly message. You could easily loop over the return array and check the boolean 'error' key to see if a specific file has a problem. If 'error' is true, you could echo the message for the user to see. If there was no error, the message 'File was uploaded successfully' can be displayed. The keys from the return array correspond to the same keys found in the array passed in. So $file[0] is the same file as $returnResult[0] for easy reference.

Why won't my upload script work? No errors

My upload form is
<form action="accept-file.php" method="post" enctype="multipart/form-data">
Your Photo: <input type="file" name="photo" size="25" />
<input type="submit" name="submit" value="Submit" />
</form>
And accept-file.php is
<?php
error_reporting(E_ALL);
ini_set('display_errors', '1');
//if they DID upload a file...
if($_FILES['photo']['name'])
{
//if no errors...
if(!$_FILES['photo']['error'])
{
//now is the time to modify the future file name and validate the file
$new_file_name = strtolower($_FILES['photo']['tmp_name']); //rename file
if($_FILES['photo']['size'] > (1024000)) //can't be larger than 1 MB
{
$valid_file = false;
$message = 'Oops! Your file\'s size is to large.';
}
//if the file has passed the test
if($valid_file)
{
//move it to where we want it to be
move_uploaded_file($_FILES['photo']['tmp_name'], 'uploads/'.$new_file_name);
$message = 'Congratulations! Your file was accepted.';
}
}
//if there is an error...
else
{
//set that to be the returned message
$message = 'Ooops! Your upload triggered the following error: '.$_FILES['photo']['error'];
}
}
//you get the following information for each file:
$_FILES['field_name']['name']
$_FILES['field_name']['size']
$_FILES['field_name']['type']
$_FILES['field_name']['tmp_name']
?>
It is copied directly from a tutorial that apparently works ok. As you can see I've ever forced some error reporting at the top, but all I get when I submit the form is a blank screen (browser loads file-accept.php) and the uploaded file does not appear in uploads/ (chmoded to 777).
EDIT:
I am now getting these errors:
Array ( [photo] => Array ( [name] => k3Jb9gv.jpg [type] => image/jpeg [tmp_name] => /tmp/phpzc4fLT [error] => 0 [size] => 384262 ) )
Notice: Undefined index: field_name in .............. on line 38, 39, 40, 41
This line gives you the problems:
$new_file_name = strtolower($_FILES['photo']['tmp_name']);
You should change that to something else like:
$new_file_name = strtolower($_FILES['photo']['name']);
This is because otherwise you filename is the whole temporary url of your file (including directories). That will give you a warning that you are not allowed to upload it there.
Also, you need to set $valid_file to true somewhere, probably before your check for the valid file.
//if they DID upload a file...
if($_FILES['photo']['name'])
{
print_r($_FILES);
//if no errors...
if(!$_FILES['photo']['error'])
{
$valid_file = true;
//now is the time to modify the future file name and validate the file
$new_file_name = strtolower($_FILES['photo']['name']); //rename file
if($_FILES['photo']['size'] > (1024000)) //can't be larger than 1 MB
{
$valid_file = false;
$message = 'Oops! Your file\'s size is to large.';
}
//if the file has passed the test
if($valid_file)
{
//move it to where we want it to be
move_uploaded_file($_FILES['photo']['tmp_name'], 'uploads/'.$new_file_name);
$message = 'Congratulations! Your file was accepted.';
}
}
//if there is an error...
else
{
//set that to be the returned message
$message = 'Ooops! Your upload triggered the following error: '.$_FILES['photo']['error'];
}
}

i get the permissions denied error while uploading an image on the local xampp server

the htdocs folder in xampp has the 777 permissions, i can copy alter any file manually there but uploading a file into a subfolder gives an error. my code is:
<?php
define ('MAX_FILE_SIZE', 1024 * 50);
if (array_key_exists('submit', $_POST)) {
// define constant for upload folder
define('UPLOAD_DIR', '/opt/lampp/htdocs/properties/');
// replace any spaces in original filename with underscores
$file = str_replace(' ', '_', $_FILES['image']['name']);
// create an array of permitted MIME types
$permitted = array('image/gif', 'image/jpeg', 'image/pjpeg','image/png');
// upload if file is OK
if (in_array($_FILES['image']['type'], $permitted)
&& $_FILES['image']['size'] > 0
&& $_FILES['image']['size'] <= MAX_FILE_SIZE) {
switch($_FILES['image']['error']) {
case 0:
// check if a file of the same name has been uploaded
if (!file_exists(UPLOAD_DIR . $file)) {
// move the file to the upload folder and rename it
$success = move_uploaded_file($_FILES['image']['tmp_name'], UPLOAD_DIR $file);
} else {
$result = 'A file of the same name already exists.';
}
if ($success) {
$result = "$file uploaded successfully.";
} else {
$result = "Error uploading $file. Please try again.";
}
break;
case 3:
case 6:
case 7:
case 8:
$result = "Error uploading $file. Please try again.";
break;
case 4:
$result = "You didn't select a file to be uploaded.";
}
} else {
$result = "$file is either too big or not an image.";
}
}
?>
the error i get is:
Warning: move_uploaded_file(/opt/lampp/htdocs/properties/Cover.jpg): failed to open stream: Permission denied in /opt/lampp/htdocs/listprop.php on line 82
check is safe_mode is on in your php.ini
If only the xampp folder is writable that doesn't help, you need the sub-folders writable too.
Second, just asking
define('UPLOAD_DIR', '/opt/lampp/htdocs/properties/');
where lampp is shouldn't that be xampp? just asking (that can cause move problems too)

Method keeps returning false when it should return true?

I have a method that checks if a thumbnail is validate for uploading. For some reason it is returning false in the calling program.
The image file definitely meets the requirements that I set for it in terms of correct size, dimensions, file type and there are no errors in the file.
This is the print_r() of the Image file:
imageArray ( [file] => Array ( [name] => juliensbook2slide.jpg [type] => image/jpeg [tmp_name] => C:\Users\chris\AppData\Local\Temp\php5A99.tmp [error] => 0 [size] => 20590 ) )
Here is the method code:
public function checkThumb(){
$this->temp_dir = $_FILES['file']['tmp_name'];
$this->image_type = $_FILES['file']['type'];
$this->image_size = $_FILES['file']['size'];
$this->image_name = $_FILES['file']['name'];
$this->image_error = $_FILES['file']['error'];
#$this->image_dimensions = getimagesize($this->temp_dir);
$this->image_width = $this->image_dimensions[0]; // Image width
$this->image_height = $this->image_dimensions[1]; // Image height
$this->path = '';
$this->error = '';
if(!empty($this->image_name) && $this->image_error == 0){
$this->path = 'img/thumb_/'.$this->random_name. $_FILES['file']['name'];
if(in_array($this->image_type, $this->allowed_type)){
if($this->image_size <= $this->max_size){
if(($this->image_width < $this->max_width) && $this->image_height < $this->max_height){
return true;
}else{
return $error = 'ERROR: Image dimension must be no larger than 4050x4050';
}
}else{
return $error = 'ERROR: Image size must be no larger than 5MB';
}
}else{
return $error = 'ERROR: image must be .jpg, .gif, .png only.';
}
}else {
return false;
}
}
and here is the code where it is not moving the uploaded image because it is returning false:
if($register->checkThumb){
//send image to permanent image directory
$register->moveUploadedImage();
//if the thumbnail failed validation put the error message in variable
}else if(is_string($register->checkThumb())){
$message = $register->checkThumb();
}
print_r($_FILES);
//put record of user into database
$register->convertSex();
$register->insertIntoDB($thumb);
}
So why is it returning false?
You weren't calling the method. There were no round brackets after the method name. So basically you were checking if a property named checkThumb is set.
As in $register->checkThumb vs. $register->checkThumb().
This should work:
if($register->checkThumb()){ //send image to permanent image directory
$register->moveUploadedImage();
} //if the thumbnail failed validation put the error message in variable
else if(is_string($register->checkThumb())) {
$message = $register->checkThumb();
}
But i would recommend not calling the same method 3 times so I'd use the following:
$checked_thumb = $register->checkThumb();
if($checked_thumb){ //send image to permanent image directory
$register->moveUploadedImage();
} //if the thumbnail failed validation put the error message in variable
else if(is_string($checked_thumb)) {
$message = $checked_thumb;
}

Categories