Files
JavaScript.ajax-file-upload/test/backend.php

337 lines
9.3 KiB
PHP

<?php // phpcs:ignore PSR1.Files.SideEffects
header("Content-Type: application/json; charset=UTF-8");
session_start();
define('DS', DIRECTORY_SEPARATOR);
define('DIR', __DIR__ . DS);
define('LOG', 'log' . DS);
// run id
DEFINE('RUNUID', session_id());
function logWrite(string $message): void
{
global $fh;
if (!$fh) {
$fh = fopen(DIR . LOG . 'backend.' . date("Y-m-d") . '.log', 'a');
}
fwrite($fh, '{' . RUNUID . '} [' . printTime() . '] ' . $message . "\n");
}
function logHandleClose(): void
{
global $fh;
if ($fh) {
fclose($fh);
}
}
function printTime(): string
{
$set_microtime = 4;
list($microtime, $timestamp) = explode(' ', microtime());
$string = date("Y-m-d H:i:s", $timestamp);
// if microtime flag is -1 no round, if 0, no microtime, if >= 1, round that size
$string .= substr(number_format(round($microtime, $set_microtime), $set_microtime), 1);
return $string;
}
function errMsg(string $level, string $message): void
{
global $error_string;
$error_string[] = [
'level' => $level,
'str' => $message
];
}
/**
* [printAr description]
* @param array $array [description]
* @return string [description]
*/
function printAr(array $array): string
{
return "<pre>" . print_r($array, true) . "</pre>";
}
/**
* helper function for PHP file upload error messgaes to messge string
* @param int $error_code integer _FILE upload error code
* @return string message string, translated
*/
function fileUploadErrorMessage(int $error_code): string
{
switch ($error_code) {
case UPLOAD_ERR_INI_SIZE:
$message = 'The uploaded file exceeds the upload_max_filesize directive in php.ini';
break;
case UPLOAD_ERR_FORM_SIZE:
$message = 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form';
break;
case UPLOAD_ERR_PARTIAL:
$message = 'The uploaded file was only partially uploaded';
break;
case UPLOAD_ERR_NO_FILE:
$message = 'No file was uploaded';
break;
case UPLOAD_ERR_NO_TMP_DIR:
$message = 'Missing a temporary folder';
break;
case UPLOAD_ERR_CANT_WRITE:
$message = 'Failed to write file to disk';
break;
case UPLOAD_ERR_EXTENSION:
$message = 'File upload stopped by extension';
break;
default:
$message = 'Unknown upload error';
break;
}
return $message;
}
/**
* creates psuedo random uuid v4
* Code take from class here:
* https://www.php.net/manual/en/function.uniqid.php#94959
* @return string pseudo random uuid v4
*/
function uuidv4(): string
{
return sprintf(
'%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
// 32 bits for "time_low"
mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
// 16 bits for "time_mid"
mt_rand(0, 0xffff),
// 16 bits for "time_hi_and_version",
// four most significant bits holds version number 4
mt_rand(0, 0x0fff) | 0x4000,
// 16 bits, 8 bits for "clk_seq_hi_res",
// 8 bits for "clk_seq_low",
// two most significant bits holds zero and one for variant DCE1.1
mt_rand(0, 0x3fff) | 0x8000,
// 48 bits for "node"
mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0xffff)
);
}
/**
* @param string|int|float $bytes bytes as string int or pure int
* @return string converted byte number (float) with suffix
*/
function humanReadableByteFormat($bytes): string
{
// if not numeric, return as is
if (is_numeric($bytes)) {
// space before name
$space = true;
// use sprintf instead of round
$adjust = true;
// use SI 1000 mod and not 1024 mod
$si = false;
// si or normal
$unit = $si ? 1000 : 1024;
// always positive
$abs_bytes = $bytes == PHP_INT_MIN ? PHP_INT_MAX : abs($bytes);
// smaller than unit is always B
if ($abs_bytes < $unit) {
return $bytes . 'B';
}
// labels in order of size [Y, Z]
$labels = array('', 'K', 'M', 'G', 'T', 'P', 'E');
// exp position calculation
$exp = floor(log($abs_bytes, $unit));
// avoid printing out anything larger than max labels
if ($exp >= count($labels)) {
$exp = count($labels) - 1;
}
// deviation calculation
$dev = pow($unit, $exp) * ($unit - 0.05);
// shift the exp +1 for on the border units
if (
$exp < 6 &&
$abs_bytes > ($dev - (((int)$dev & 0xfff) == 0xd00 ? 52 : 0))
) {
$exp++;
}
// label name, including leading space if flagged
$pre = ($space ? ' ' : '') . ($labels[$exp] ?? '>E') . ($si ? 'i' : '') . 'B';
$bytes_calc = $abs_bytes / pow($unit, $exp);
if ($adjust) {
return sprintf("%.2f%s", $bytes_calc, $pre);
} else {
return round($bytes_calc, 2) . $pre;
}
} else {
// if anything other return as string
return (string)$bytes;
}
}
$error = false;
$status = 'error';
$error_string = [];
$ajax_data = [];
$folder = DIR . 'uploaded' . DS;
logWrite(print_r($_POST, true));
// backend receiver calls
if (isset($_POST['action'])) {
// action switch statement
switch ($_POST['action']) {
case 'chainAction':
$ajax_data['chain'] = 'Just A chain action: ' . ($_POST['chain'] ?? '-');
$status = 'ok';
errMsg($status, 'Successful chained action');
break;
// list current files
case 'fileList':
$ajax_data['reference_id'] = uniqid();
if (is_dir($folder)) {
$file_array = [];
// sorted by date
$files = glob($folder . DIRECTORY_SEPARATOR . '*');
// oldest top
usort($files, function ($x, $y) {
return filemtime($x) > filemtime($y) ? 1 : -1;
});
foreach ($files as $file) {
$file_array[] = [
'name' => basename($file),
'create_date' => date("Y-m-d H:i:s", filemtime($file)),
'size' => humanReadableByteFormat((int)filesize($file))
];
}
$ajax_data['file_list'] = $file_array;
$status = 'ok';
if (!count($file_array)) {
$status = 'warn';
$ajax_data['info'] = 'No files uploaded yet';
}
} else {
$error = true;
errMsg($status, 'Uploaded folder not found');
}
break;
// for simple single file upload
case 'fileUpload':
// has a target name (file prefix flag)
$upload_name = $_POST['uploadName'];
// $this->debug('FILE UPLOAD', 'ALL FILES: '.$this->printAr($_FILES));
// errMsg('debug', 'Called for: ' . $upload_name . ' with data: '
// . (isset($_FILES[$upload_name]) ? printAr($_FILES[$upload_name]) : 'NOT FOUND'));
// return string & array init
$file_upload_message = [];
// do we have an upload actually
if (
isset($_FILES[$upload_name]['error']) &&
$_FILES[$upload_name]['error'] == UPLOAD_ERR_OK
) {
// set status to success post all checks
$status = 'success';
// strip out -file from upload name for search
$_upload_name = str_replace('-file', '', $upload_name);
$mime_type = null;
$ajax_data = [
'msg' => [],
'file_uid' => null,
'file_url' => null,
'file_name' => null,
'file_size' => null,
'file_size_raw' => null,
'file_type' => null,
];
// check mime type for file and do check if we have a "valid_files" settings
$finfo = new \finfo(FILEINFO_MIME_TYPE);
$mime_type = $finfo->file($_FILES[$upload_name]['tmp_name']);
if (!in_array($mime_type, ['text/csv', 'text/plain', 'text/x-php'])) {
$file_upload_message[] = 'File type must be CSV or PHP: ' . $mime_type;
$ajax_data['msg'] = $file_upload_message;
$ajax_data['error'] = 'File type must be CSV or PHP: ' . $mime_type;
$status = 'error';
}
// ON ERROR set status = 'error';
// file type ok and file size ok, we commence actualy upload
if ($status == 'success') {
// basic file id data
$file_uid = null;
$file_url = null;
$file_name = null;
$file_size = null;
$file_size_raw = null;
$file_upload_message[] = 'File upload successful';
// internal file id
$file_uid = uuidv4();
// move file to tmp location and return new name
move_uploaded_file(
$_FILES[$upload_name]['tmp_name'],
$folder . $file_uid
);
$file_name = $_FILES[$upload_name]['name'];
$file_size = humanReadableByteFormat($_FILES[$upload_name]['size']);
$file_size_raw = $_FILES[$upload_name]['size'];
// correct the image rotation
// $this->correctImageOrientation(BASE.TMP.$file_uid);
// make a copy to layout/cache/images for file url
// as a thumbnail in defined size
// $file_url = $this->form_base_path
// . $this->createThumbnailSimple(BASE.TMP.$file_uid, THUMB_WIDTH, THUMB_HEIGHT);
// write back data for frontend processing
$ajax_data = [
'msg' => $file_upload_message,
'file_uid' => $file_uid,
'file_url' => $file_url,
'file_name' => $file_name,
'file_size' => $file_size,
'file_size_raw' => $file_size_raw,
'file_type' => $mime_type,
];
} else {
$info_msg = 'File uploaded and check failed';
errMsg($status, $info_msg);
$ajax_data['msg'][] = $info_msg;
}
} else {
$info_msg = isset($_FILES[$upload_name]) ?
'File upload filed: ' . fileUploadErrorMessage($_FILES[$upload_name]['error']) :
'General file upload error';
errMsg($status, $info_msg);
$ajax_data = [
'msg' => [
$info_msg
]
];
}
break;
default:
$error = true;
errMsg($status, 'Abnormal action');
break;
}
} else {
$error = true;
errMsg($status, 'No action set');
}
$data = [
'status' => $status,
'msg' => $error_string,
'action' => $_POST['action'] ?? null,
'content' => $ajax_data
];
// print the JSON data out to the browsers
$output = json_encode($data);
print $output;
// __END__