PHP / HTML File Upload Not Recognizing Screenshot Images - php

I am building a file upload tool for my website and am running into a strange issue. The html input is set up to accept image/png, image/jpg, image/jpeg, .pdf files and it works fine when I am using it to upload PDFs or images that came from a camera or a design software.
However, when I upload an image (png) that was a screenshot taken on my Mac, the $_FILES has a value for the name attribute, but has no values for the tmp_name, type, error, size attributes. I've tried renaming the file to see if that was the issue, and that doesn't appear to be the problem either.
This is the output I get when I run print_r($_FILES):
Array ( [fileupload] => Array ( [name] => Array ( [0] => Screen Shot 2020-12-23 at 2.10.06 PM.png ) [type] => Array ( [0] => ) [tmp_name] => Array ( [0] => ) [error] => Array ( [0] => 1 ) [size] => Array ( [0] => 0 ) ) )
Warning: mime_content_type(): Empty filename or path in pro_testupload.php on line 87
Warning: getimagesize(): Filename cannot be empty in pro_testupload.php on line 91
Warning: mime_content_type(): Empty filename or path in pro_testupload.php on line 103
Does anyone have any idea about what is going on here? Below is my code:
HTML Code
<form method="POST" action="_process/pro_testupload.php" enctype="multipart/form-data">
<input type="file" id="fileupload" name="fileupload[]" accept="image/png, image/jpg, image/jpeg, .pdf" multiple required>
<button class="btn waves-effect black waves-light" type="submit">Upload</button>
</form>
PHP Code
// -----------------------------------------------------------------
// FILE FORMAT CHECKING FUNCTIONS
// -----------------------------------------------------------------
function check_image($filename) {
// Check mime type using PHPs own built in functions (as client side mime type is vulnerable to exploitation)
$mime_type = mime_content_type($filename);
$allowed_file_types = ['image/png', 'image/jpeg', 'image/jpg'];
// Check the file is actually an image
$check = getimagesize($filename);
// Perform all checks
if (in_array($mime_type, $allowed_file_types) && is_array($check) !== False) {
return True;
} else {
return False;
}
}
function check_pdf($filename) {
// Check mime type using PHPs own built in functions (as client side mime type is vulnerable to exploitation)
$mime_type = mime_content_type($filename);
$allowed_file_types = ['application/pdf'];
// Perform checks
if (in_array($mime_type, $allowed_file_types)) {
return True;
} else {
return False;
}
}
// -----------------------------------------------------------------
// CHECK FILES TO ENSURE THEY MEET REQUIREMENTS
// -----------------------------------------------------------------
if(!empty(array_filter($_FILES['fileupload']['name']))) {
foreach ($_FILES['fileupload']['tmp_name'] as $key => $value) {
if (!(check_image($_FILES['fileupload']['tmp_name'][$key]) || check_pdf($_FILES['fileupload']['tmp_name'][$key]))) {
echo ("The files do not meet the uploaded file requirements");
exit;
}
}
} else {
echo ("There were no files requested to be uploaded.");
exit;
}

Related

Filehandling, move_uploaded_file gives me no response

Got a script I've used several times, using move_uploaded_file. But what I can't figure out is why it do not respond in any way, no error reports, nothing.
<form> using method="post", target="upload" that is an <iframe>
action="file.php" responds to $_FILES
Correct enctype
Filerights is set to 777
Upload folder "uploads" exists
print_r($_FILES['file']) gives me:
Array
(
[name] => 1392930853.png
[type] => image/png
[tmp_name] => /tmp/php0rZdBf
[error] => 0
[size] => 611
)
The code below illustrates my script, and what I've figured out is that the last line with move_uploaded_file is the cause of my problem as it do not respond at all. As I wrote above, no error, no nothing.
Pastebin to script: http://pastebin.com/49m9Siqi
Got a clue what could be the cause of this?
$destination_path = getcwd().'/uploads/';
//echo $destination_path;
// File handling
$counted = count($_FILES['file']['name']);
$counted = $counted-1;
for ($i=0; $i<=$counted; $i++) {
if ($_FILES['file']['error'][$i] == UPLOAD_ERR_OK) {
$md5file = rand() . rand() . md5($_FILES['file']['name'][$i]) . rand() . rand();
if(move_uploaded_file($_FILES['file']['tmp_name'][$i], $destination_path . $md5file . "." . basename($_FILES['file']['type'][$i]))) { echo 'THIS WILL NOT BE ECHOED OUT ON THE PAGE'; }}}
There was a simple error in my form, as I handle my uploaded files like an array I need to create the array first.... Which I forgot to do in my form.
Wrong
<input type="file" name="file">
Correct
<input type="file" name="file[]">

Uploading XML file and parsing it - without temporary files

With PHP 5 I would like to upload an XML file via a web form and parse it using SimpleXML.
I've tried few SimpleXML examples and they work fine at my CentOS 6 Linux server.
However, I don't have any experience with handling uploaded files in PHP yet.
Should I use the $_FILES and do I always have to use a temporary file or can it be done completely in memory?
From PHP Cookbook I've copied this example:
<html>
<body>
<?php if ($_SERVER['REQUEST_METHOD'] == 'GET') { ?>
<form method="post" action="<?php echo $_SERVER['SCRIPT_NAME'] ?>"
enctype="multipart/form-data">
<input type="file" name="doc"/>
<input type="submit" value="Send File"/>
</form>
<?php } else {
if (isset($_FILES['doc']) &&
($_FILES['doc']['error'] == UPLOAD_ERR_OK)) {
$oldPath = $_FILES['doc']['tmp_name'];
$newPath = '/tmp/' . basename($_FILES['doc']['name']);
if (move_uploaded_file($oldPath, $newPath)) {
print "File moved from $oldPath to $newPath";
} else {
print "Couldn't move $oldPath to $newPath";
}
} else {
print "No valid file uploaded.";
}
}
?>
</body>
</html>
It works fine and for the print_r statement added by me the following output is printed:
Array
(
[document] => Array
(
[name] => my_file.xml
[type] => text/xml
[tmp_name] => /tmp/phpRD9cYI
[error] => 0
[size] => 1610252
)
)
And I can see the /tmp/my_file.xml file.
My question is though if I can skip the creation of temporary files?
I don't like them because:
They are sometimes security issue
They have to be cleaned up (by a cronjob?)
Their names might collide (probably seldom case unless it's 1)
UPDATE: Also, I don't understand, why can't I read the file at $oldPath? It is not found there and I have to call the move_uploaded_file() and then read the $newPath...
You don't need to save/move the file in a new folder,
if (isset($_FILES['doc']) && ($_FILES['doc']['error'] == UPLOAD_ERR_OK)) {
$xml = simplexml_load_file($_FILES['doc']['tmp_name']);
}
The tempfile generated will be automatically removed when the PHP script finishes. Hope this helps.

Can't move/fine APC Uploaded file

As a bit of a follow up to Javascript form won't submit (to view the code I am using visit that link) I am now encountering a problem that I cannot find the file that has been uploaded.
I have added $files = apc_fetch('files_'.$_POST['APC_UPLOAD_PROGRESS']); to the top of my page and this is the output of print_r($files);
Array
(
[theFile] => Array
(
[name] => tt1.mp4
[type] => video/mp4
[tmp_name] => /tmp/php2BEvy7
[error] => 0
[size] => 1050290
)
)
However when I try to run the following code:
if (file_exists($files['theFile']['tmp_name'])) {
$webinarType = strcmp($files['theFile']['type'], 'video/mp4');
if($webinarType == 0) {
$webinarFile = $fileTitle;
$webinarTempName = $files['theFile']['tmp_name'];
} else {
echo 'Webinar must be .mp4';
}
} else {
echo "No File";
}
I get the No File output.
I have ssh'd into the server and the file is not in /tmp/, /path/to/public_html/tmp/ or path/to/file/tmp/ all of which exist.
I have tried to use move_uploaded_file() but as this is executed on all file inputs I can't get the tmp_name dynamically due to my limited knowledge of javascript.
tl;dr version; Where is my file gone and how can I find it?
NOTE; This form did work before the APC intevention and I am running wordpress in case that affects anything.
Fixed this one on my own as well.
In the progress.php file (found on the other question) I modified the elseif statement with this:
elseif(($s_progressId = $_POST['APC_UPLOAD_PROGRESS']) || ($s_progressId = $_GET['APC_UPLOAD_PROGRESS']))
{
// If the file has finished uploading add content to APC cache
$realpath = realpath($PHP_SELF);
$uploaddir = $realpath . '/tmp/';
foreach ($_FILES as $file) {
if(!empty($file['name'])) {
$uploaded_file = $file['name'];
$moveme = $uploaddir.$uploaded_file;
move_uploaded_file($file['tmp_name'], $moveme);
}
}
apc_store('files_'.$s_progressId, $_FILES);
die();
}
That way I could iterate through the $_FILES array without knowing the name of the input. I noticed that it loops through a couple of times hence the if(!empty()) however in hindsight it's probably best practice anyway.

PHP - Upload multiple images

I need to upload multiple images via form. I thought that I will do it with no problem, but I have one.
When I try to do foreach and get image by image it is not acting like I hoped it will.
HTML
<form method="post" action="" enctype="multipart/form-data" id="frmImgUpload">
<input name="fileImage[]" type="file" multiple="true" />
<br />
<input name="btnSubmit" type="submit" value="Upload" />
</form>
PHP
<?php
if ($_POST)
{
echo "<pre>";
foreach ($_FILES['fileImage'] as $file)
{
print_r($file);
die(); // I want it to print first image content and then die to test this out...
//imgUpload($file) - I already have working function that uploads one image
}
}
What I expected from it to print out first image, instead it prints names of all the images.
Example
Array
(
[0] => 002.jpg
[1] => 003.jpg
[2] => 004.jpg
[3] => 005.jpg
)
What I want it to output
Array
(
[name] => 002.jpg
[type] => image/jpeg
[tmp_name] => php68A5.tmp
[error] => 0
[size] => 359227
)
So how can I select image by image in the loop so I can upload them all?
Okey I found solution and this is how I did it, probably not the best way but it works.
foreach ($_FILES['fileImage']['name'] as $f)
{
$file['name'] = $_FILES['fileImage']['name'][$i];
$file['type'] = $_FILES['fileImage']['type'][$i];
$file['tmp_name'] = $_FILES['fileImage']['tmp_name'][$i];
$file['error'] = $_FILES['fileImage']['error'][$i];
$file['size'] = $_FILES['fileImage']['size'][$i];
imgUpload($file);
$i++;
}
that array is formed in another way
it's something line this:
array (
'name' => array (
[0] => 'yourimagename',
[1] => 'yourimagename2',
....
),
'tmp_file' => array (
....
that shoud do it :
foreach ($_FILES['fileImage']['name'] as $file)
{
print_r($file);
die(); // I want it to print first image content and then die to test this out...
//imgUpload($file) - I already have working function that uploads one image
}
You are basically asking of how to rebuild the $_FILES array to access subitems of them as one array.
$index = 0;
$field = 'fileImage';
$keys = array_keys($_FILES[$field]);
$file = array();
foreach($keys as $key)
{
$file[$key] = $_FILES[$field][$key][$index];
}
print_r($file);
change $index to the value you need to pick a specific file.

Get Renamed File Names of JavaScript Forms in CodeIgniter

I have a multiple image upload form, and the following code is working well for uploading. I need to save file names to database to the database, but I cannot figure out how to do that properly.
uploadform.php:
echo form_open_multipart('gallery/upload');
<input type="file" name="photo" size="50" />
<input type="file" name="thumb" size="50" />
<input type="submit" value="Upload" />
</form>
gallery_model.php
function multiple_upload($upload_dir = 'uploads/', $config = array())
{
/* Upload */
$CI =& get_instance();
$files = array();
if(empty($config))
{
$config['upload_path'] = realpath($upload_dir);
$config['allowed_types'] = 'gif|jpg|jpeg|jpe|png';
$config['max_size'] = '2048';
}
$CI->load->library('upload', $config);
$errors = FALSE;
foreach($_FILES as $key => $value)
{
if( ! empty($value['name']))
{
if( ! $CI->upload->do_upload($key))
{
$data['upload_message'] = $CI->upload->display_errors(ERR_OPEN, ERR_CLOSE); // ERR_OPEN and ERR_CLOSE are error delimiters defined in a config file
$CI->load->vars($data);
$errors = TRUE;
}
else
{
// Build a file array from all uploaded files
$files[] = $CI->upload->data();
}
}
}
// There was errors, we have to delete the uploaded files
if($errors)
{
foreach($files as $key => $file)
{
#unlink($file['full_path']);
}
}
elseif(empty($files) AND empty($data['upload_message']))
{
$CI->lang->load('upload');
$data['upload_message'] = ERR_OPEN.$CI->lang->line('upload_no_file_selected').ERR_CLOSE;
$CI->load->vars($data);
}
else
{
return $files;
}
/* -------------------------------
Insert to database */
// problem is here, i need file names to add db.
// if there is already same names file at the folder, it rename file itself. so in such case, I need renamed file name :/
}
}
You should keep your model for database operations only. All the upload processing and file moving has to be done in the controller. The model has to insert the record about the photo in the database and that's about it.
And as a response to your question do a print_r($files) and see what it contains. It should have the original filenames. It'll probably be something like artmania said above: $files[0]['file_name']. You should be able to loop through your $files array with a foreach construct like this:
foreach($files as $file) {
$file_name = $file['file_name'];
}
You can get all the other data about the file in the same way. The CodeIgniter manual says about $this->upload->data():
This is a helper function that returns
an array containing all of the data
related to the file you uploaded. Here
is the array prototype:
Array
(
[file_name] => mypic.jpg
[file_type] => image/jpeg
[file_path] => /path/to/your/upload/
[full_path] => /path/to/your/upload/jpg.jpg
[raw_name] => mypic
[orig_name] => mypic.jpg
[file_ext] => .jpg
[file_size] => 22.2
[is_image] => 1
[image_width] => 800
[image_height] => 600
[image_type] => jpeg
[image_size_str] => width="800" height="200"
)
Fore more info check out the manual.

Categories