/home/smartonegroup/public_html/system/system/autoload/Upload.php
<?php
/**
* Simple PHP upload class
*
* @author Aivis Silins
*/
class Upload {
/**
* @var array<string, mixed>|mixed|mixed[]
*/
public $file_post;
/**
* Default directory persmissions (destination dir)
*/
protected $default_permissions = 0750;
/**
* File post array
*
* @var array
*/
protected $files_post = array();
/**
* Destination directory
*
* @var string
*/
protected $destination;
/**
* Fileinfo
*
* @var object
*/
protected $finfo;
/**
* Data about file
*
* @var array
*/
public $file = array();
/**
* Max. file size
*
* @var int
*/
protected $max_file_size;
/**
* Allowed mime types
*
* @var array
*/
protected $mimes = array();
/**
* External callback object
*
* @var obejct
*/
protected $external_callback_object;
/**
* External callback methods
*
* @var array
*/
protected $external_callback_methods = array();
/**
* Temp path
*
* @var string
*/
protected $tmp_name;
/**
* Validation errors
*
* @var array
*/
protected $validation_errors = array();
/**
* Filename (new)
*
* @var string
*/
protected $filename;
/**
* Internal callbacks (filesize check, mime, etc)
*
* @var array
*/
private $callbacks = array();
/**
* Root dir
*
* @var string
*/
protected $root;
/**
* Return upload object
*
* $destination = 'path/to/your/file/destination/folder';
*
* @param string $destination
* @param string $root
* @return Upload
*/
public static function factory($destination, $root = false) {
return new Upload($destination, $root);
}
/**
* Define ROOT constant and set & create destination path
*
* @param string $destination
* @param string $root
*/
public function __construct($destination, $root = false) {
$this->root = $root !== '' && $root !== '0' ? $root : $_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR;
// set & create destination path
if (!$this->set_destination($destination)) {
throw new Exception('Upload: Can\'t create destination. '.$this->root . $this->destination);
}
//create finfo object
$this->finfo = new finfo();
}
/**
* Set target filename
*
* @param string $filename
*/
public function set_filename($filename) {
$this->filename = $filename;
}
/**
* Check & Save file
*
* Return data about current upload
*
* @return array
*/
public function upload($filename = '') {
if ($this->check()) {
$this->save();
}
// return state data
return $this->get_state();
}
/**
* Save file on server
*
* Return state data
*
* @return array
*/
public function save() {
$this->save_file();
return $this->get_state();
}
/**
* Validate file (execute callbacks)
*
* Returns TRUE if validation successful
*
* @return bool
*/
public function check() {
//execute callbacks (check filesize, mime, also external callbacks
$this->validate();
//add error messages
$this->file['errors'] = $this->get_errors();
//change file validation status
$this->file['status'] = empty($this->validation_errors);
return $this->file['status'];
}
/**
* Get current state data
*
* @return array
*/
public function get_state() {
return $this->file;
}
/**
* Save file on server
*/
protected function save_file() {
//create & set new filename
if(empty($this->filename)){
$this->create_new_filename();
}
//set filename
$this->file['filename'] = $this->filename;
//set full path
$this->file['full_path'] = $this->root . $this->destination . $this->filename;
$this->file['path'] = $this->destination . $this->filename;
$status = move_uploaded_file($this->tmp_name, $this->file['full_path']);
//checks whether upload successful
if (!$status) {
throw new Exception('Upload: Can\'t upload file.');
}
//done
$this->file['status'] = true;
}
/**
* Set data about file
*/
protected function set_file_data() {
$file_size = $this->get_file_size();
$this->file = array(
'status' => false,
'destination' => $this->destination,
'size_in_bytes' => $file_size,
'size_in_mb' => $this->bytes_to_mb($file_size),
'mime' => $this->get_file_mime(),
'original_filename' => $this->file_post['name'],
'tmp_name' => $this->file_post['tmp_name'],
'post_data' => $this->file_post,
);
}
/**
* Set validation error
*
* @param string $message
*/
public function set_error($message) {
$this->validation_errors[] = $message;
}
/**
* Return validation errors
*
* @return array
*/
public function get_errors() {
return $this->validation_errors;
}
/**
* Set external callback methods
*
* @param object $instance_of_callback_object
* @param array $callback_methods
*/
public function callbacks($instance_of_callback_object, $callback_methods) {
if (empty($instance_of_callback_object)) {
throw new Exception('Upload: $instance_of_callback_object can\'t be empty.');
}
if (!is_array($callback_methods)) {
throw new Exception('Upload: $callback_methods data type need to be array.');
}
$this->external_callback_object = $instance_of_callback_object;
$this->external_callback_methods = $callback_methods;
}
/**
* Execute callbacks
*/
protected function validate() {
//get curent errors
$errors = $this->get_errors();
if (empty($errors)) {
//set data about current file
$this->set_file_data();
//execute internal callbacks
$this->execute_callbacks($this->callbacks, $this);
//execute external callbacks
$this->execute_callbacks($this->external_callback_methods, $this->external_callback_object);
}
}
/**
* Execute callbacks
*/
protected function execute_callbacks($callbacks, $object) {
foreach($callbacks as $method) {
$object->$method($this);
}
}
/**
* File mime type validation callback
*
* @param obejct $object
*/
protected function check_mime_type($object) {
if (!empty($object->mimes) && !in_array($object->file['mime'], $object->mimes)) {
$object->set_error('Mime type not allowed.');
}
}
/**
* Set allowed mime types
*
* @param array $mimes
*/
public function set_allowed_mime_types($mimes) {
$this->mimes = $mimes;
//if mime types is set -> set callback
$this->callbacks[] = 'check_mime_type';
}
/**
* File size validation callback
*
* @param object $object
*/
protected function check_file_size($object) {
if (!empty($object->max_file_size)) {
$file_size_in_mb = $this->bytes_to_mb($object->file['size_in_bytes']);
if ($object->max_file_size <= $file_size_in_mb) {
$object->set_error('File is too big.');
}
}
}
/**
* Set max. file size
*
* @param int $size
*/
public function set_max_file_size($size) {
$this->max_file_size = $size;
//if max file size is set -> set callback
$this->callbacks[] = 'check_file_size';
}
/**
* Set File array to object
*
* @param array $file
*/
public function file($file) {
$this->set_file_array($file);
}
/**
* Set file array
*
* @param array $file
*/
protected function set_file_array($file) {
//checks whether file array is valid
if (!$this->check_file_array($file)) {
//file not selected or some bigger problems (broken files array)
$this->set_error('Please select file.');
}
//set file data
$this->file_post = $file;
//set tmp path
$this->tmp_name = $file['tmp_name'];
}
/**
* Checks whether Files post array is valid
*
* @return bool
*/
protected function check_file_array($file) {
return isset($file['error'])
&& !empty($file['name'])
&& !empty($file['type'])
&& !empty($file['tmp_name'])
&& !empty($file['size']);
}
/**
* Get file mime type
*
* @return string
*/
protected function get_file_mime() {
return $this->finfo->file($this->tmp_name, FILEINFO_MIME_TYPE);
}
/**
* Get file size
*
* @return int
*/
protected function get_file_size() {
return filesize($this->tmp_name);
}
/**
* Set destination path (return TRUE on success)
*
* @param string $destination
* @return bool
*/
protected function set_destination($destination) {
$this->destination = $destination . DIRECTORY_SEPARATOR;
return $this->destination_exist() ? TRUE : $this->create_destination();
}
/**
* Checks whether destination folder exists
*
* @return bool
*/
protected function destination_exist() {
return is_writable($this->root . $this->destination);
}
/**
* Create path to destination
*
* @param string $dir
* @return bool
*/
protected function create_destination() {
return mkdir($this->root . $this->destination, $this->default_permissions, true);
}
/**
* Set unique filename
*
* @return string
*/
protected function create_new_filename() {
$filename = sha1(mt_rand(1, 9999) . $this->destination . uniqid()) . time();
$this->set_filename($filename);
}
/**
* Convert bytes to mb.
*
* @param int $bytes
* @return int
*/
protected function bytes_to_mb($bytes) {
return round(($bytes / 1048576), 2);
}
} // end of Upload