Files
admin_hura_8/inc/Hura8/System/CDNFileUploadHandle.php

276 lines
8.4 KiB
PHP
Raw Permalink Normal View History

2024-01-29 10:39:53 +07:00
<?php
/**
* Created by Hurasoft
* Date: 28-May-2022
* Time: 1:44 PM
* Description: Use this class in the cdn host to handle the upload of files from Hura8's admin and put the uploaded file in the cdn host's local directory
*/
namespace Hura8\System;
class CDNFileUploadHandle
{
const SECURITY_SALT = 'ahss@3asdaaSDFSD';
//default config
protected $config = [
//1. file settings
"max_file_size" => 2000000,//bytes ~ 1MB
'allowed_file_types' => [
'image' => ['.jpeg', '.jpg', '.gif', '.png'],
'script' => ['.css', '.js'],
],
//2. uploaded by client
'uid' => '',
'token' => '',
'time' => '',
'item_type' => 'product', // product|article|media
'target_path' => '',
'upload_method' => 'content', //file || content
"file_content" => "", //only needed if upload_method = content
"file_name" => "",//only needed if upload_method = content
];
private $tmp_file_prop = null; //array, temporary file's props in tmp folder
private $accepted_file_input_names = [
"file", //<input type=file name="file">
//"qqfile", //name use for files uploaded through FineUploader library
];
private $user_tmp_dir = '';
public function __construct(){
}
protected function createToken($id, $time) {
return sha1(join("-", [$id , $time , static::SECURITY_SALT]));
}
public function start() {
$this->_get_post_info();
if(!$this->validateUser()) {
return $this->set_return_result('error', 'User failed to verify', []);
}
//receive files
$file = $this->receive_file();
//return file-location to upload API to return to client application
return $this->set_return_result('success', 'Upload succeeded', $file );
}
protected function validateUser() {
return ($this->config['token'] == $this->createToken($this->config['uid'], $this->config['time']));
}
protected function _get_post_info() {
$expected_keys = [
'upload_method',
'file_name',
'target_path',
'file_content',
'uid',
'time',
'token',
'item_type',
];
foreach ($expected_keys as $key) {
$this->config[$key] = isset($_POST[$key]) ? $_POST[$key] : null;
}
}
//return boolean
protected function remove_tmp_file() {
$this->deleteDirectory($this->user_tmp_dir);
return true;
}
//return boolean
protected function validate_file() {
//$this->tmp_file_prop
//validate file size
if($this->config['max_file_size'] && $this->config['max_file_size'] < $this->tmp_file_prop['size']) {
return 'Size too large';
}
//validate allowed extension: allow image but upload .docx files
$has_extension = false;
$file_type = '';
foreach ( $this->config['allowed_file_types'] as $group => $group_ext ) {
if(in_array( $this->tmp_file_prop['ext'], $group_ext )) {
$has_extension = true;
$file_type = $group;
break ;
}
}
if( ! $has_extension ) return "File type not allowed";
//validate claimed extension: claim image but not actual image
$full_file_path = $this->tmp_file_prop['tmp_location'] . DIRECTORY_SEPARATOR . $this->tmp_file_prop['name'];
if( $file_type == 'image' && ! v::image()->validate( $full_file_path )) {
return "Not actual image";
}
return '';
}
//return mixed : array $tmp_file_prop or false
protected function receive_file() {
//check upload method
if( $this->config['upload_method'] == 'content' ) {
//upload by content - file created on server
$file_ext = $this->get_ext($this->config['file_name']);
$upload_folder = $this->create_upload_folder() ;
if( ! $this->move_file($upload_folder)) {
return false;
}
return [
"ext" => $file_ext,
"name" => $this->config['file_name'],
"folder" => $upload_folder,
"size" => strlen($this->config['file_content']),
];
} else {
//upload by file
//get list of files to be uploaded
$file_uploaded = null;
foreach ($this->accepted_file_input_names as $_name) {
if(isset($_FILES[$_name])) {
$file_uploaded = $_FILES[$_name];
break;
}
}
if ( ! $file_uploaded ) return false;
//if file name too long, then error
if ( strlen($file_uploaded['name']) > 225 ) return false;
//move file to tmp folder
$file_ext = $this->get_ext($file_uploaded['name']);
$upload_folder = $this->create_upload_folder() ;
if( ! $this->move_file($upload_folder) ){
return false;
}
return [
"ext" => $file_ext,
"name" => $this->config['file_name'],
"folder" => $upload_folder,
"size" => $file_uploaded['size'],
];
}
}
protected function set_return_result($status = 'success', $message = 'Upload success', $content = []) {
return [
"status" => $status,
"message" => $message,
"files" => $content,
];
}
//create upload folder for user: use current date, user id or app id based on $this->config
private function create_upload_folder() {
//$build_folder = [$this->tmp_dir];
/*$user_id = (isset($this->config['user_id'])) ? intval($this->config['user_id']) : null;
if($user_id) {
$build_folder[] = $user_id;
}
$build_folder[] = date("Ymd");*/
//rebuild upload folder
$build_folder = array_filter(explode("/", $this->config['target_path']));
$folder = join("/", $build_folder);
$this->createDir($folder);
return $folder;
}
//get a file's extension
private function get_ext($fileName){
return strtolower(strrchr($fileName, '.'));
}
// check if find is image
private function isImage($fileName) {
return (in_array( $this->get_ext($fileName), ['.jpeg', '.jpg', '.gif', '.png'] ));
}
//for security reason: only allow a-z0-9_- in file name (no other dot . except for the extension)
//example: bad-file.php.js -> bad-filephp.js
private function rename_file($uploaded_file_name, $ext) {
$new_name = preg_replace("/[^a-z0-9_\-]/i", "", str_replace( strrchr($uploaded_file_name, '.'), "", $uploaded_file_name ) ) . $ext;
return strtolower($new_name);
}
private function move_file($folder) {
$new_file = $folder . '/' . $this->config['file_name'];
if( $this->config['upload_method'] == 'content' ) {
// image upload by content
if( $this->isImage($new_file) ) {
//Store in the filesystem.
$fp = fopen($new_file, "w+");
$status = fwrite($fp, $this->config['file_content']);
fclose($fp);
return ($status !== false);
}
// file upload
else if( file_put_contents($new_file, $this->config['file_content'])){
return true;
}
}
return false;
}
protected function createDir($path, $folder_permission = 0750){
if(file_exists($path)) {
return true;
}
return mkdir($path, $folder_permission, true);
}
protected function deleteDirectory($dirPath) {
if (!is_dir($dirPath)) {
return false;
}
$objects = scandir($dirPath);
foreach ($objects as $object) {
if ($object != "." && $object !="..") {
if (filetype($dirPath . DIRECTORY_SEPARATOR . $object) == "dir") {
$this->deleteDirectory($dirPath . DIRECTORY_SEPARATOR . $object);
} else {
unlink($dirPath . DIRECTORY_SEPARATOR . $object);
}
}
}
return rmdir($dirPath);
}
}