= 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 "
" . print_r($array, true) . "
"; } /** * 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__