c
This commit is contained in:
275
inc/Hura8/System/CDNFileUploadHandle.php
Normal file
275
inc/Hura8/System/CDNFileUploadHandle.php
Normal file
@@ -0,0 +1,275 @@
|
||||
<?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);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user