<?php

// name: UD - UploadDownload class
// file: UD.class.php

class UD { 

	var $rootDir;
	var $allowedExtensions;
	var $readOnlyFiles = false;
	var $readOnlyDirs = false;
	
	var $maxFileSize;
	var $uploadedFiles;
	var $maxRecursionDirs;
	var $restrictedDirs = Array();
	
	var $fileContent;
		
	var $createImageThumb = false;
	var $thumbDirName = "_thumb";
	var $thumbImageExtension = Array("jpg", "jpeg", "gif", "png");
	var $thumbHeight = 100;
	var $thumbWidth = 100;
	var $thumbKeepAspectRation = true;
	var $forceJpgConversion = false;
	
	var $_recursionDirs;
	var $_err;
	
	static $_PL_OS_SEP;
	static $_CUR_OS;
	
	function __construct($rDir=false){
	
		if(!$rDir){
			$dir = $_SERVER['DOCUMENT_ROOT'];
		}
		
		// set constants
		self::$_PL_OS_SEP = "/";
		self::$_CUR_OS = substr( php_uname(), 0, 7 ) == "Windows" ? "win" : "_nix" ;
		
		// set main properties
		$this->rootDir = $this->_addSlash($rDir);
		$this->allowedExtensions = array();
		$this->readOnlyFiles = false;
		$this->maxFileSize = 0;
		$this->uploadedFiles = array();
		
		// initialize Error Message
		$this->_initErrorMsg();
		
	} // UD function end

	# ----------------------------------------------------------
	
	function getFoldersAndFiles($fileDir="", $numericArray=false, $dateFormat="d-m-Y h:m:i"){
	
		$FaF =  array();
		$pathToDir = $this->_addRootPathToFolder($fileDir);

		//echo $pathToDir;
		
		if (!is_dir($pathToDir)){

			return -1;
		}
					
		if (!($dh = opendir($pathToDir))) 
			return -2;
		
		$i=0;
		while (($file = readdir($dh)) !== false) { 

			$F[name] = $file;
			
			// remove '.' and '..' if root

			if($F[name]=='.' || $F[name]=='..')
				continue;
			
			/*if($pathToDir == $this->_addSlash($this->rootDir) && ($F[name]=='.' || $F[name]=='..'))
				continue;*/
				
			$F[type] = filetype($pathToDir.$file);
			
			// if read only files
			if($this->readOnlyFiles && $F[type]=="dir")
				continue;
		
			// if read only dirs
			if($this->readOnlyDirs && $F[type]!="dir")
				continue;


			// filter restricted
				
			if(in_array($F[name], $this->restrictedDirs) && $F[type]=="dir")
				continue;

					
			// get extension	
			if($F[type]=='file'){
				$F[extension] = $this->_getExtension($file); 
			}
			else if($F[type]=='dir'){
				unset($F[extension]);
			}
				
			// filter files
			if($F[type]=="file"){
				if(count($this->allowedExtensions)>0){
					if(in_array($F[extension], $this->allowedExtensions) == FALSE)
						continue;
				}
			}
			
			$F[chmod] = $this->_getPermision($pathToDir.$file);
			$F[size] = filesize($pathToDir.$file);
			$F[type] = filetype($pathToDir.$file);
		
			$_stats = stat( $pathToDir.$file );
			$F[date] = date($dateFormat, $_stats['ctime']);
			
			if($numericArray==true){
			 	$A = array();
			 	$A[0] = $F[name];
			 	$A[2] = $F[size];
			 	$A[3] = $F[date];
			 	$A[4] = $F[chmod];
			 	if($F[type]=="dir"){
			 		$A[1] = $F[type];
			 	}else{
			 		$A[1] = $F[extension];
			 	}

				$FaF[$i]=$A;
			}else{
				$FaF[$i]=$F;
			}
			$i++;
		} 
		closedir($dh); 
	
		
	
		return $FaF;
		
	} // getFoldersAndFiles  function end
	
	# ----------------------------------------------------------
	function getFileInfo($filePath, $dateFormat="d-m-Y h:m:i"){
	
		if(!file_exists($filePath)) return false;
	
		clearstatcache();
		
		$path_parts = pathinfo($filePath);
		$F = (object) array();
		$F->name = $path_parts['basename'];
		if (!is_dir($filePath)) 
			$F->extension = $path_parts['extension'];
		$F->type = (is_dir($filePath) ? "dir" : "file");
		$F->size = filesize($filePath);
		$_stats = stat($filePath);
		$F->date = date($dateFormat, $_stats['mtime']);
		
		return 	$F;
	}
	# ----------------------------------------------------------
	function readFile($fileDir){
		
		$pathToFile = $this->_addRootPathToFile($fileDir);

		readfile($pathToFile);
		
		die;
	}
	# ----------------------------------------------------------
	
	
	function getFileContent($fileDir){
	
		$this->fileContent = "";
		
		$pathToFile = $this->_addRootPathToFile($fileDir);
		
		if(!is_file($pathToFile)){
			return -16; 
		}
		
		if(filesize($pathToFile)==0){
			return "";
		}
	
		$fp = fopen($pathToFile,"r", true);
		$this->fileContent = fread($fp, filesize($pathToFile));
		fclose($fp);
		
	
		
		# return file contents
		return (string) $this->fileContent;
		
	} 

	function downloadFile($fileDir){
		
		$pathToFile = $this->_addRootPathToFile($fileDir);

		header("Content-type: application/force-download");
		header("Content-Disposition: attachment; filename=".$this->_getFileName($pathToFile));
		@readfile($pathToFile);
		exit;
	}

	function getImage($fileDir){
		$pathToFile = $this->_addRootPathToFile($fileDir);
		header('Content-Type: image/'.$this->_getExtension($pathToFile));
		header("Content-Length: " . (string)(filesize($pathToFile)) );
		echo $this->getFileContent($fileDir);
		exit;
	}
		
	# ----------------------------------------------------------
	// TO DO error ids
	function saveFileContent($filePath, $fileContent){
	
		$pathToFile = $this->_addRootPathToFile($filePath);
		
		/*if(!is_file($pathToFile)){
			return -16; 
		}*/
		
		$fp = fopen($pathToFile,"w", true);
		//print_r($fileContent);
		fwrite($fp, $fileContent);
		fclose($fp);
	
		# return file contents
		return true;
		
	} 
	
	# ----------------------------------------------------------
	
	function deleteFolder($fileDir=""){

		$pathToDir = $this->_addRootPathToFolder($fileDir);

		if($pathToDir == $this->rootDir){
			return -4; 
		}
		
		if(!is_dir($pathToDir)){
			return -1; 
		} 
		
		if(!$this->_is_emtpy_dir($pathToDir)){
		 	return -9; 
		}
	
		if(@rmdir($pathToDir)===false){
			return -3;
		}
		
		return true;
		
	}
	
		# ----------------------------------------------------------
	
	function deleteFile($fileDir){

		$pathToFile = $this->_addRootPathToFile($fileDir);
		
		if(!is_file($pathToFile)){
			return -16; 
		} 
			
		if(@unlink($pathToFile)===false){
			return -17;
		}
		
		return true;
		
	}
	
		# ----------------------------------------------------------
	
	function renameFile($pathToFile, $newFilePath){
		
		$pathToFile = $this->_addRootPathToFile($pathToFile);
		$newFilePath = $this->_addRootPathToFile($newFilePath);
		
		if(!is_file($pathToFile)){
			return -16; 
		} 

		if(is_dir($newFilePath)){
			return -18; 
		} 
		
		if (!in_array($this->_getExtension($newFilePath), $this->allowedExtensions) && !empty($this->allowedExtensions)){
			return -20;
		}
		
		if(@rename($pathToFile, $newFilePath)===false){
			return -19;
		}
			
		
		return true;
		
	}
	
	# ----------------------------------------------------------
	
	function renameFolder($pathToDir, $newDirPath){
		
		$pathToDir = $this->_addRootPathToFolder($pathToDir);
		$newDirPath = $this->_addRootPathToFolder($newDirPath);
		
		if($pathToDir == $this->rootDir){
			return -8; 
		}
		
		if(!is_dir($pathToDir)){
			return -1; 
		} 
		
		if(is_dir($newDirPath)){
			return -5; 
		} 
		
		if(@rename($pathToDir, $newDirPath)===false){
			return -6;
		}
		
		return true;
		
	}
	
	# ----------------------------------------------------------
	
	function createFile($filePath, $fileContent, $chmod=0644){
		
		$filePath = $this->_addRootPathToFolder($filePath);
			
		if(is_file($filePath)){
			return -18; 
		} 
		
		if(!$fp=fopen($filePath,"w") ){
			return -023;
		}
		if(!empty($fileContent))
			fwrite($fp, $fileContent);
		
		fclose($fp);

		//chmod($filePath, $chmod);

		return true;
		
	}
	
	function createFileAP($absFilePath, $fileContent, $chmod=0644){
			
		if(is_file($absFilePath)){
			return -18; 
		} 
		
		if(!$fp=fopen($absFilePath,"w") ){
			return -023;
		}
		if(!empty($fileContent))
			fwrite($fp, $fileContent);
		
		fclose($fp);

		//chmod($filePath, $chmod);

		return true;
		
	}
	
	function addFolder($newDirPath, $chmod=0755){
		
		$newDirPath = $this->_addRootPathToFolder($newDirPath);
			
		if(is_dir($newDirPath)){
			return -5; 
		} 
		
		if(mkdir($newDirPath)===false){
			return -7;
		}
		
		chmod($newDirPath, $chmod);
		
		return true;
		
	}
	
	# ----------------------------------------------------------
	
	function uploadFiles($fileDir, $imageQuality=75){
		
		$pathToDir = $this->_addRootPathToFolder($fileDir);
		
		if (!is_dir($pathToDir)){
			return -1;
		}
		
		$i=-1;
		foreach ($_FILES as $varName => $file) {
			
			$i++;
			$fileName = $file['name'];

			if (empty($fileName)) 	{
			$this->uploadedFiles[$i]['status']=-15;
			continue;
			}

			$i=count($this->uploadedFiles);
			$this->uploadedFiles[$i]['name'] = $fileName;

		   if (!is_uploaded_file($file['tmp_name'])) {
	    	$this->uploadedFiles[$i]['status']=-14;
				continue;
			}
    	
			if ($file['size'] > $this->maxFileSize && $this->maxFileSize!=0){ 
		    $this->uploadedFiles[$i]['status']=-11;
		    continue;
			}

			if (!in_array($this->_getExtension($fileName), $this->allowedExtensions) && !empty($this->allowedExtensions)){
		    $this->uploadedFiles[$i]['status']=-12;
		    continue;
			}

			$_fpath = str_replace("//","/",$pathToDir.$fileName);
			
			if (!move_uploaded_file($file['tmp_name'], $_fpath)){	
			$this->uploadedFiles[$i]['status']=-13;
			continue;
			}
			
			chmod($_fpath, 0777);
			
			// convert to jpg image
			if($this->forceJpgConversion){
				$fileName = $this->convertToJpg(str_replace("//","/",$pathToDir.$fileName), $imageQuality);
				if($fileName===false){
					$this->uploadedFiles[$i]['status'] = -30;
					continue;
				}
				$this->uploadedFiles[$i]['name'] = $fileName;
			}

						
			$this->uploadedFiles[$i]['status']=1;
			
			// create thumbnails
			if($this->createImageThumb && in_array($this->_getExtension($fileName), $this->thumbImageExtension)){
				$this->addFolder($fileDir."/".$this->thumbDirName);
				$this->createThumbnail($pathToDir.$fileName, $pathToDir.$this->thumbDirName."/".$fileName, $this->thumbWidth, $this->thumbHeight, $this->thumbKeepAspectRation);
			}
			
		}
		
		return true;
		
	} // uploadFiles function end
	
	# ----------------------------------------------------------
	
	function getTreeArray($relPath="/"){
		$this->_getTreeArray($relPath, $this->_recursionDirs);
		return $this->_recursionDirs;
	}
	
	# ----------------------------------------------------------
		
	function convertToJpg($filePath, $imageQuality){
			
		$extenzion = $this->_getExtension($filePath);

		if($extenzion == "jpg" || $extenzion == "jpeg")
			$im = imagecreatefromjpeg($filePath);
		else if($extenzion == "gif")
			$im = imagecreatefromgif($filePath);
		else if($extenzion == "png")
			$im = imagecreatefrompng($filePath);
		else 
			return false;

		$newFilePath = substr($filePath, 0,strrpos($filePath, ".")) . ".jpg";
		
		
		imageJPEG($im, $newFilePath, $imageQuality);

		chmod($newFilePath, 0777);
		
		if($this->_getExtensionCS($filePath)!="jpg")
			@unlink($filePath);
		
		$newFileName = substr($newFilePath, strrpos($filePath, "/")+1);
		
		return $newFileName;
	}
	
	# ----------------------------------------------------------
	
	function createThumbnail($filePath, $thumbFilePath, $maxWidth, $maxHeigth, $keepAspectRatio=false){
		
		
		$heigth = $maxHeigth;
		$width = $maxWidth;

		$extenzion = $this->_getExtension($filePath);

		if($extenzion == "jpg" || $extenzion == "jpeg")
			$im = imagecreatefromjpeg($filePath);
		else if($extenzion == "gif")
			$im = imagecreatefromgif($filePath);
		else if($extenzion == "png")
			$im = imagecreatefrompng($filePath);
		else 
			return false;
			
		$imWidth	= imagesx($im);
		$imHeigth = imagesy($im);
		
		if($imHeigth<=$maxHeigth && $imWidth<=$maxWidth){
			$heigth = $imHeigth;
			$width = $imWidth;
		}
		else{
			if($keepAspectRatio){
				if(($imWidth/$maxWidth)>($imHeigth/$maxHeigth)){
					$heigth = round($imHeigth/($imWidth/$maxWidth));
				}
				else{
					$width = round($imWidth/($imHeigth/$maxHeigth));
				}
			}
		}
	
		$imThumb = ImageCreateTrueColor($width,$heigth);
	
		@imagecopyresized ($imThumb, $im, 0, 0, 0, 0, $width, $heigth, $imWidth, $imHeigth);
		
		if($extenzion == "jpg" || $extenzion == "jpeg")
				imageJPEG($imThumb, $thumbFilePath, 70);
		if($extenzion == "gif")
				imageGIF($imThumb, $thumbFilePath);
		if($extenzion == "png")
				imagePNG($imThumb, $thumbFilePath);
		else
			return false;
			
		chmod($thumbFilePath, 0777);
		
		return true;
		
	}
	
	# ----------------------------------------------------------
	
	function getErrorMsg($e){

		$id = $this->getErrorID($e);

		return $this->_err["$id"];
			
	} // getErrorMsg function end
	
	# ----------------------------------------------------------
	
	function getErrorID($e){
		
		$e=abs($e);
		strlen($e)==1 ? $id="00".$e : (strlen($e)==2 ? $id="0".$e : true);
		
		return $id;
		
	} // getErrorID function end
	
	function formatSize($bytes){
		
		if($bytes/1024 < 1 )
			return $bytes;
		
		if($bytes/(1024*1024) < 1 ){
			return round($bytes/(1024)) . "K";
		}
		
		if($bytes/(1024*1024*1024) < 1 ){
			return round($bytes/(1024*1024)) . "M";
		}
		
		if($bytes/(1024*1024*1024*1024) < 1 ){
			return round($bytes/(1024*1024*1024)) . "G";
		}
	}
	
	
	function copy($file, $newfile, $force=true){
		if (!file_exists($file)) {
			return -16;
		}
		if($force==false){
			if (file_exists($newfile)) {
				return -21;
			}
		}
		if (!@copy($file, $newfile)) {
	    	return -22;
		}
		return true;
	}
	function move($file, $newfile, $force=true){
		if(!($success=$this->copy($file, $newfile, $force))){
			return $success;
		}
		return $this->deleteFile($file);
	}
	


	////////////////////////////////////////////////////////////
	# ----------------------------------------------------------
	// Private
	# ----------------------------------------------------------
	
	function _is_emtpy_dir($dirname){

		$result=true;    
		$handle = opendir($dirname);
		while( ( $name = readdir($handle)) !== false){
			if ($name!= "." && $name !=".."){
				$result=false;      
				break;             
			}
		}
		closedir($handle);
		
		return $result;
		
	}

		
	function _getPermision($file){
		
		$chmod = fileperms($file);
		$chmod = sprintf('%o', $chmod);
		$chmod = substr($chmod,-3); 
		
		return $chmod;
		
	} // _getPermision function end
	
	# ----------------------------------------------------------
	
	function _addSlash($dir){

		if(empty($dir))
			return "";
		
		if(substr($dir,-1)!="/")
			$dir.="/";
		
		$dir = str_replace("//","/",$dir);	
		
		return $dir;
		
	} // _addSlash function end
	
	# ----------------------------------------------------------
	
	function _addRootPathToFile($fileDir){
			
		return $fileDir;
			
		$pathToFile = $this->_addSlash($this->rootDir) . $fileDir;
		$pathToFile = str_replace("//","/",$pathToFile);
		
		return $pathToFile;
	}
	
	function _addRootPathToFolder($folderDir){
			
		$pathToDir = $this->_addSlash($this->rootDir) . $this->_addSlash($folderDir);
		$pathToDir = str_replace("//","/",$pathToDir);
		
		return $pathToDir;
	}
	
	
	# ----------------------------------------------------------	
	function getFileName($path){
		return self::_getFileName($path);
	} // strrpos function end
	# ----------------------------------------------------------
	
	function _getFileName($path){
		
		$pos = strrpos($path, "/"); 
		if ($pos === false) { 
			return "";	
		} 	
		
		$name = substr($path, $pos+1);
		
		return $name;
		
	} // strrpos function end
	
	# ----------------------------------------------------------
		
	function _getExtensionCS($file){

		$pos = strrpos($file, "."); 
		if ($pos === false) { 
			return "";	
		} 	
		
		$extension = substr($file, $pos+1);
		
		return $extension;
		
	} // _getExtension function end
	
	# ----------------------------------------------------------
	
	function _getExtension($file){

		$file = $this->_getExtensionCS($file);
		
		$extension = strtolower($file);
		
		return $extension;
		
	} // _getExtension function end

	# ----------------------------------------------------------

	function getExtension($file){
		
		return $this->_getExtension($file);
		
	} // getExtension function end
	# ----------------------------------------------------------
	
	function getFilenameParts($fileName){

		$parts = Array("name"=>"", "extension"=>"", "dot"=>"");
		
		$pos = strrpos($fileName, "."); 
		if ($pos === false) { 
			$parts["name"] = $fileName;
			return $parts;
		} 	
		$parts["name"] = substr($fileName, 0,$pos);
		$parts["dot"] = ".";
		$parts["extension"] = substr($fileName, $pos+1);

		return  $parts;
		
	}
		
	# ----------------------------------------------------------
	
	function _initErrorMsg(){
		
		$this->_err = array();
		
		$this->_err["001"] = "It's not directory";
		$this->_err["002"] = "Error opening directory";
		$this->_err["003"] = "Direcroty not empty or you havnot permision to delete it";
		$this->_err["004"] = "You can't delete root directory";
		$this->_err["005"] = "Directory with that name exist";
		$this->_err["006"] = "Can't rename directory to that name";
		$this->_err["007"] = "Can't create directory with that name";
		$this->_err["008"] = "You can't rename root directory";
		$this->_err["009"] = "Directory is not empty";
				
		$this->_err["011"] = "File size limit owerflow";
		$this->_err["012"] = "Extenzion of original file name is restricted";
		$this->_err["013"] = "Can't move file";
		$this->_err["014"] = "File is not uploaded to server";
		$this->_err["015"] = "Empty filename";
		$this->_err["016"] = "It's not file";
		$this->_err["017"] = "Can't delete file";
		$this->_err["018"] = "File with that name exist";
		$this->_err["019"] = "Can't rename file to that name";
		$this->_err["020"] = "Restricted extension of file";
		$this->_err["021"] = "Cannot copy file because file with the same name exist";
		$this->_err["022"] = "File copying failed";
		$this->_err["023"] = "Can't create file";
			
		$this->_err["030"] = "Can't convert to jpg image";
		
		return $this->_err;
	} // _initErrorMsg function end

	
	function _getTreeArray($relPath, $arr, $aktinst = 0){
		
		$ff = $this->getFoldersAndFiles($relPath);
		
		if($ff<0) return;
		
		$arr = $ff;
		
		while (list($key, $val) = each($ff)){
			if ($val['type']=="dir" and $val['name']!="." and $val['name']!=".."){
				$_relPath = $relPath;
				
				$_relPath .= str_replace("//","/","/".$val['name']."/");
				$absPath = $this->_addRootPathToFolder($_relPath) ;
				
				if (is_dir($absPath) && ($aktinst < $this->maxRecursionDirs || $this->maxRecursionDirs == 0)){ 
					$arr[$key][folders] = array();
					$this->_getTreeArray($_relPath, $arr[$key][folders],$aktinst+1); 
				}
			}
		}
		
	}


	// ------------------------------------------------------------
	// New methodr sor paths managament and security check
	// ------------------------------------------------------------
	
	static function checkCurrentOS( $_OS )
	{
	   if ( strcmp( $_OS, self::$_CUR_OS ) == 0 ) {
	       return true;
	   }
	   return false;
	}
	
	static function isRelative( $_dir )
	{
		if ( self::checkCurrentOS( "win" ) ) {
			return ( preg_match( "/^\w+:/", $_dir ) <= 0 );
		}
		else {
	    	return ( preg_match( "/^\//", $_dir ) <= 0 );
		}
	}
	
	static function unifyPath( $_path )
	{
	   if ( self::checkCurrentOS( "win" ) ) {
	       return str_replace( "\\", self::$_PL_OS_SEP, $_path );
	   }
	   return $_path;
	}
	
	static function getRealpath( $_path )
	{
	   /*
	     * This is the starting point of the system root.
	     * Left empty for UNIX based and Mac.
	     * For Windows this is drive letter and semicolon.
	     */
	   $__path = $_path;
	   if ( self::isRelative( $_path ) ) {
	       $__curdir = self::unifyPath( realpath( "." ) . self::$_PL_OS_SEP );
	       $__path = $__curdir . $__path;
	   }
	   $__startPoint = "";
	   if ( self::checkCurrentOS( "win" ) ) {
	       list( $__startPoint, $__path ) = explode( ":", $__path, 2 );
	       $__startPoint .= ":".self::$_PL_OS_SEP;
	   }
	   # From now processing is the same for WIndows and Unix, and hopefully for others.
	   $__realparts = array( );
	   $__parts = explode( self::$_PL_OS_SEP, $__path );
	   for ( $i = 0; $i < count( $__parts ); $i++ ) {
	       if ( strlen( $__parts[ $i ] ) == 0 || $__parts[ $i ] == "." ) {
	           continue;
	       }
	       if ( $__parts[ $i ] == ".." ) {
	           if ( count( $__realparts ) > 0 ) {
	               array_pop( $__realparts );
	           }
	       }
	       else {
	           array_push( $__realparts, $__parts[ $i ] );
	       }
	   }
	  
       if ( self::checkCurrentOS( "win" ) ) 
         return $__startPoint . implode( self::$_PL_OS_SEP, $__realparts );
		else
		 return $__startPoint . self::$_PL_OS_SEP . implode( self::$_PL_OS_SEP, $__realparts );
	}

	
} // UD class end

?>