I've put together an example single file upload script that attempts to cover all the things PHP could check for prior to allowing a successful file upload. Is there anything else maybe now available in PHP 7.4+ I could use to make this more secure? For example, I use filter_input
below even though I don't find it in many scripts out there.
Take a look
<?php
# EVALUATE REQUEST METHOD
$REQUEST_METHOD = filter_input(INPUT_SERVER, 'REQUEST_METHOD', FILTER_SANITIZE_ENCODED);
switch ($REQUEST_METHOD) {
# HTTP:POST - PAYLOAD:BLOB
case 'POST':
# POST IMAGE
if(\in_array(@$_FILES["files"], $_FILES) && \count($_FILES) === 1) {
upload();
}
break;
default:
methodInvalid();
break;
}
/**
* Function upload() uploads a single file.
*
*
*/
function upload() {
// Establish the upload file directory
$upload_dir = $_SERVER['DOCUMENT_ROOT'] . '/gui/v1/uploads/submittals/';
// Establish the upload file path
$upload_file = $upload_dir . $_FILES['files']['name'][0];
// Derive the upload file extension
$upload_file_extension = strtolower(pathinfo($upload_file, PATHINFO_EXTENSION));
// Allowed file types
// $allowed_file_extensions = ['pdf', 'jpg', 'jpeg', 'png', 'gif'];
$allowed_file_extensions = ['pdf'];
/**
* Does tmp file exist?
*
*
*/
if (!file_exists($_FILES['files']['tmp_name'][0])) {
# ERROR object
$errorObject = new stdClass();
$errorObject->apiVersion = '1.0';
$errorObject->context = 'upload.submittal';
# ABOUT ERROR object
$aboutError = new stdClass();
$aboutError->code = 'ERR-000';
$aboutError->message = 'Select file to upload.';
# APPEND ABOUT ERROR object TO ERROR object
$errorObject->error = $aboutError;
# RETURN JSON RESPONSE
header('Content-type:application/json;charset=utf-8');
return print(json_encode($errorObject));
}
/**
* Is file extension allowed?
*
*
*/
if (!in_array($upload_file_extension, $allowed_file_extensions)) {
# ERROR object
$errorObject = new stdClass();
$errorObject->apiVersion = '1.0';
$errorObject->context = 'upload.submittal';
# ABOUT ERROR object
$aboutError = new stdClass();
$aboutError->code = 'ERR-000';
$aboutError->message = 'Allowed file formats .pdf';
# APPEND ABOUT ERROR object TO ERROR object
$errorObject->error = $aboutError;
# RETURN JSON RESPONSE
header('Content-type:application/json;charset=utf-8');
return print(json_encode($errorObject));
}
/**
* Is file bigger than 20MB?
*
*
*/
if ($_FILES['files']['size'][0] > 20000000) {
# ERROR object
$errorObject = new stdClass();
$errorObject->apiVersion = '1.0';
$errorObject->context = 'upload.submittal';
# ABOUT ERROR object
$aboutError = new stdClass();
$aboutError->code = 'ERR-000';
$aboutError->message = 'File is too large. File size should be less than 20 megabytes.';
# APPEND ABOUT ERROR object TO ERROR object
$errorObject->error = $aboutError;
# RETURN JSON RESPONSE
header('Content-type:application/json;charset=utf-8');
return print(json_encode($errorObject));
}
/**
* Does file already exist?
*
*
*/
if (file_exists($upload_file)) {
/**
* File overwritten successfuly!
*
*
*/
move_uploaded_file($_FILES['files']['tmp_name'][0], $upload_file);
# SUCCESS object
$successObject = new stdClass();
$successObject->apiVersion = '1.0';
$successObject->context = 'upload.submittal';
$successObject->status = 'OK';
# UPLOAD SUBMITTAL object
$data = new stdClass();
$data->submittalUploaded = true;
# APPEND DATA object TO SUCCESS object
$successObject->data = $data;
# APPEND empty arrays to DATA object
$successObject->data->arr1 = [];
$successObject->data->arr2 = [];
$successObject->data->arr3 = [];
# RETURN JSON RESPONSE
header('Content-type:application/json;charset=utf-8');
return print(json_encode($successObject));
}
/**
* Can file actually be uploaded?
*
*
*/
if (!move_uploaded_file($_FILES['files']['tmp_name'][0], $upload_file)) {
/**
* File upload error!
*
*
*/
# ERROR object
$errorObject = new stdClass();
$errorObject->apiVersion = '1.0';
$errorObject->context = 'upload.submittal';
# ABOUT ERROR object
$aboutError = new stdClass();
$aboutError->code = 'ERR-000';
$aboutError->message = 'File couldn\'t be uploaded.';
# APPEND ABOUT ERROR object TO ERROR object
$errorObject->error = $aboutError;
# RETURN JSON RESPONSE
header('Content-type:application/json;charset=utf-8');
return print(json_encode($errorObject));
} else {
/**
* File uploaded successfuly!
*
*
*/
# SUCCESS object
$successObject = new stdClass();
$successObject->apiVersion = '1.0';
$successObject->context = 'upload.submittal';
$successObject->status = 'OK';
# UPLOAD SUBMITTAL object
$data = new stdClass();
$data->submittalUploaded = true;
# APPEND DATA object TO SUCCESS object
$successObject->data = $data;
# APPEND empty arrays to DATA object
$successObject->data->arr1 = [];
$successObject->data->arr2 = [];
$successObject->data->arr3 = [];
# RETURN JSON RESPONSE
header('Content-type:application/json;charset=utf-8');
return print(json_encode($successObject));
// We could insert URL file path to a database from here...
}
}
/**
* Function methodInvalid() warns about invalid method.
*
*
*/
function methodInvalid() {
# ERROR object
$errorObject = new stdClass();
$errorObject->apiVersion = '1.0';
$errorObject->context = 'uploads';
# ABOUT ERROR object
$aboutError = new stdClass();
$aboutError->code = 'ERR-000';
$aboutError->message = 'Invalid Request. Allowed Methods are POST.';
# APPEND ABOUT ERROR object TO ERROR object
$errorObject->error = $aboutError;
# RETURN JSON RESPONSE
header('Content-type:application/json;charset=utf-8');
return print(json_encode($errorObject));
}
?>