<?php
/* $Id: $ */
/**
*
* Class Upload
*
* This class has the purpose of ease and secure the upload of files for SWFUpload and other applications.
*
* This script is based on the upload_save.php code of SWFUpload widget
*
* @author Cristiano Gois <cristianogois@gmail.com>
* @version 1.8
* @copyright Freeware
* @package Upload
* @since 03/2011
**/
class Upload{
private $file_name;
private $tmp_name;
private $file_extension;
private $succeed_files_track;
private $fail_files_track;
private $max_file_size_in_bytes;
private $save_path;
private $upload_name;
private $file_perm;
private $valid_chars_regex;
private $extension_whitelist;
private $errors;
private $errtype; // returning type of method formatErrorMsg. // 0: String; 1: JSON
const MAX_FILENAME_LENGTH = 260;
/**
* Constructor
*
* @access public
**/
public function __construct($filename="", $save_path="./", $file_ext="", $upload_name="Filedata"){
$path_info = pathinfo($_FILES[$upload_name]['name']);
$this->file_name = ((!isset($filename) || trim($filename)==='')) ?
basename($_FILES[$upload_name]['name'], '.'.$path_info["extension"]) : $filename;
$this->tmp_name = $_FILES[$upload_name]["tmp_name"];
$this->file_extension = (empty($file_ext)) ? $path_info["extension"] : $file_ext;
$this->succeed_files_track = array();
$this->fail_files_track = array();
$this->save_path = $save_path;
$this->upload_name = $upload_name;
$this->file_perm = 0755; // don't use single quotes or double quotes
$this->max_file_size_in_bytes = 10485760; // 10MB in bytes
$this->valid_chars_regex = '.A-Z0-9_ !@#$%^&()+={}\[\]\',~`-'; // Characters allowed in the file name (in a Regular Expression format)
$this->extension_whitelist = array("jpg", "png", "jpeg", "pdf"); // Allowed file extensions
$this->errors = array( 0=>"There is no error, the file uploaded with success",
1=>"The uploaded file exceeds the upload_max_filesize directive in php.ini",
2=>"The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form",
3=>"The uploaded file was only partially uploaded",
4=>"No file was uploaded",
6=>"Missing a temporary folder"
);
$this->errtype = 0; // 0: String; 1: JSON
}
// override magic method to retrieve properties
public function __get($field){
if($field == 'filename'){
return $this->file_name;
}else if($field == 'fullname'){
return $this->file_name.".".$this->file_extension;
}else{
return $this->$field;
}
}
// override magic method to set properties
public function __set($field, $value){
$this->$field = $value;
}
public function getPostMaxSize(){
return trim(ini_get('post_max_size'));
}
/*
* Create directory structure
*/
public function createDirectoryStructure(){
$path = $this->save_path;
return is_dir($path) || @mkdir($path, (int)$this->file_perm, TRUE);
}
/*
* Save file
* uses createDiretoryStructure(), getPostMaxSize()
* @todo rearrange the conditionals to avoid the 'return $bool' repetition
*/
public function save($force=false, $overwrite=false){
$upload_name = $this->upload_name;
$file_name = $this->file_name;
$file_ext = $this->file_extension;
$save_path = $this->save_path;
$full_name = $this->fullname;
$file_path = $save_path."/".$full_name;
$bool = false;
$unit = strtoupper(substr($this->getPostMaxSize(), -1));
$multiplier = ($unit == 'M' ? 1048576 : ($unit == 'K' ? 1024 : ($unit == 'G' ? 1073741824 : 1)));
if((int)$_SERVER['CONTENT_LENGTH'] > $multiplier*(int)$this->getPostMaxSize() && $this->getPostMaxSize()) {
// header("HTTP/1.1 500 Internal Server Error"); // This will trigger an uploadError event in SWFUpload
$this->formatErrorMsg(2, "POST exceeded maximum allowed size");
return $bool;
}
// Validate the upload
if(!isset($_FILES[$upload_name])){
print $this->formatErrorMsg (4, "No upload found in \$_FILES for $upload_name");
return $bool;
}else if(isset($_FILES[$upload_name]["error"]) && $_FILES[$upload_name]["error"] != 0){
$this->formatErrorMsg($_FILES[$upload_name]["error"], $this->errors[$_FILES[$upload_name]["error"]]);
return $bool;
}else if(!isset($_FILES[$upload_name]["tmp_name"]) || !@is_uploaded_file($_FILES[$upload_name]["tmp_name"])){
$this->formatErrorMsg(7, "Upload failed is_uploaded_file test");
return $bool;
}else if(!isset($_FILES[$upload_name]['name'])){
$this->formatErrorMsg(8, "File has no name");
return $bool;
}
clearstatcache();
// Validate the file size (Warning: the largest files supported by this code is 2GB)
$file_size = @filesize($_FILES[$upload_name]["tmp_name"]);
if (!$file_size || $file_size > $this->max_file_size_in_bytes) {
//header("HTTP/1.1 500 Internal Server Error");
$this->formatErrorMsg (2, "File exceeds the maximum allowed size");
return $bool;
}
if ($file_size <= 0) {
$this->formatErrorMsg(9, "File size outside allowed lower bound");
return $bool;
}
// Validate file extension
$is_valid_extension = false;
foreach ($this->extension_whitelist as $extension) {
if (strcasecmp($file_ext, $extension) == 0) {
$is_valid_extension = true;
break;
}
}
if (!$is_valid_extension) {
$this->formatErrorMsg(10, "Invalid file extension: $file_ext");
return $bool;
}
// Validate file name (for our purposes we'll just remove invalid characters)
$file_name = preg_replace('/[^'.$this->valid_chars_regex.']|\.+$/i', "", $file_name);
if (strlen($file_name) == 0 || strlen($file_name) > self::MAX_FILENAME_LENGTH) {
$this->formatErrorMsg(11, "Invalid file name");
return $bool;
}
// Validate that we won't overwrite an existing file
if (file_exists($file_path) && !$overwrite) {
$this->formatErrorMsg (12, "File with this name already exists");
return $bool;
}
if($force){
if(!$this->createDirectoryStructure()){
$this->formatErrorMsg (13, "Destination folder does not exist and could not be created");
return $bool;
}
}
if(!@move_uploaded_file($_FILES[$upload_name]["tmp_name"], $file_path)){
$this->formatErrorMsg (14, "File could not be saved");
return $bool;
}else{
move_uploaded_file($file_path, "./".$full_name);
$bool = true;
}
return $bool;
}
/**
* Error handling
*
* @access public
**/
public function formatErrorMsg($errno, $errstr){
if($this->errtype == 0){ //plain text
print $errstr;
}else if($this->errtype == 1){ // JSON Format
print "{ \"errno\": $errno, \"errmsg\": \"$errstr\" }";
}
}
/**
* Deconstructor
*
* @access public
**/
public function __destruct() {}
}
?>
|