Files
Clemens Schwaighofer c53eea0b42 All CSS used are prefixed with afus-, uuid v4 for each upload group
Set uuid v4 for each upload group as ".uploadQueueUid"
Add max upload files as ".uploadQueueMax"
Change to upload files to ".uploadQueueOpen" (from ".uploadQueueMax")

Extract retrun message from two types for messages that could come
from the server
2024-09-17 15:50:39 +09:00

341 lines
9.5 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_crc' => 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_crc = 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'];
$file_crc = hash('sha256', file_get_contents($folder . $file_uid) ?: '');
// 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_crc' => $file_crc,
'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__