<?php

/* 
Filesystem standard class. This class is a file system abstraction layer for handling
all filesytem processes. Standard file and directory access methods.
This class is part of the standard classes library and should only contain 
generic lower level file handling methods that can be used accross any site.

public methods:

GetDirList(path)					return a list of sub directories inside path
DirExists(path)						Check to see if a directory exists. Return true or false. 
GetFileList(path)					GetFileList returns an array of files in a sub directory from the base dir in Alpha order
FileExist(filename, path)			check for file.
OpenFileHandle(filename, true|false) Attempt to create a handle to a file then store the file handle in $oFileHandles return the handle ref name. 
CloseFileHandle(obj_ref)			This will close a filehandle and remove it from the FileHandles array (note: its important to make sure you close open file handles once finished with.
Read(obj_ref)						Read function will suck in the contents of the file handle name passed in with obj_ref.
Write(obj_ref, contents)			Write contents to specificed file handle.
GetFilesize(filename)				Get file size in bytes. 
GetFileModifed						Get last Modifed Date from file.
CreateDir(path, permissions) 		Create a directory with given permssions. Default = 0777.
DeleteDirs(path, 1|0) 				Delete all directories and sub directories in path. Set flag to 1 to delete parent directory.
Rename(path from, path to)			Rename or move a file or folder. 
GetFolderSize(path)					Get folder size. 
GetDirectoryTree(path)				Read directory, with unlimited subdirs and files, it will create an array with files and dirs (tree structure).

Logan Crerar Dec, 2004 
*/

class Filesystem {
	
	var $sBaseDir;
	var $oFileHandles = array();
	var $iHandleIndex = 1;
	var $iHandleCount;
	var $iMaxHandles = 50;
	var $Mount;
	
	// Mount a filesystem root. 
	function Filesystem($sFilesystemDir, $iMaxHandles = 10) {
		
		global $LOG;
		$this->sBaseDir = $sFilesystemDir;
		$this->iMaxHandles = $iMaxHandles;
		if(is_dir($sFilesystemDir)) {
			$this->Mount = true;
			return true;
		} else {
			$this->Mount = false;
			return false;
		}
	}
	
	// GetDirList returns an array of sub directory names from a given path from the base dir.
	function GetDirList($sDirPath, $sBaseDirOverload = "") {
		if(!$sBaseDirOverload) {$sBaseDirOverload = $this->sBaseDir;}
		$this->_CheckMount();
		$aDirList = array();
		$hDir = opendir($sBaseDirOverload . $sDirPath);
		while($sEntry = readdir($hDir)) {
			if(is_dir($sBaseDirOverload . $sDirPath . "/" . $sEntry) && $sEntry != "." && $sEntry != "..") {
				$aDirList[] = $sEntry;
			}
		}
		return $aDirList;
	}
	
	// Check Dir - checks for existance of a directory. 
	function DirExists($sDirPath, $sBaseDirOverload = "") {
		if(!$sBaseDirOverload) {$sBaseDirOverload = $this->sBaseDir;}
		$this->_CheckMount();
		if($hd = opendir($sBaseDirOverload . $sDirPath)) {
			return true;
		} 
		return false; 
	}
	
	// GetFileList returns an array of files in a sub directory from the base dir in Alpha order.
	function GetFileList($sDirPath, $sBaseDirOverride = "", $apend_path = false) {

		$this->_CheckMount();
		
		if($sBaseDirOverride) {
			$sBaseDir = $sBaseDirOverride;
		} else {
			$sBaseDir = $this->sBaseDir;
		}
		$aDirList = array();
		$hDir = opendir($sBaseDir . $sDirPath);
		
		while($sEntry = readdir($hDir)) {
			if(!is_dir($sBaseDir . $sDirPath . "/" . $sEntry) && $sEntry != "." && $sEntry != "..") {
				if($apend_path) {
					$aDirList[] = $sDirPath . "/" . $sEntry;
				} else {
					$aDirList[] = $sEntry;
				}
			}
		}
		natcasesort($aDirList);
		return $aDirList;
	}
	
	// FileExist check for file.
	function FileExist($sFilename, $sSubDir = "", $fl = false) {
		
		$this->_CheckMount();
		if(!$fl) $sFilename = $this->sBaseDir . $sSubDir . $sFilename;
		if(file_exists($sFilename)) {
			return true;
		}
		return false;
	}
	
	// OpenFileHandle will attempt to create a handle to a file then store the 
	// file handle in $oFileHandles return the handle ref name. 
	function OpenFileHandle($sFilename, $bCreateNewFile = false) {
		if($this->iHandleCount < $this->iMaxHandles) 
			if(!$oFp = $this->_OpenFile($sFilename)) {
				if($bCreateNewFile) {	
					if(!$oFp = $this->_CreateFile($sFilename)) {
						return false;
					}
				} else {
					return false;
				}
			}
			//print_r($oFp);
			$sRef = "fh" . $this->iHandleIndex;
			$this->oFileHandles[$sRef]['obj'] = $oFp;
			$this->oFileHandles[$sRef]['len'] = filesize($this->sBaseDir . $sFilename);
			$this->iHandleIndex++;
			$this->iHandleCount++;
			return $sRef;
	}
	
	// This will close a filehandle and remove it from the FileHandles array.
	// note: its important to ake sure you close open file handles once finished with.
	function CloseFileHandle($sRef) {
		if(!fclose($this->oFileHandles[$sRef]['obj'])) {
			$LOG->LogError("Can't close file handle:" . $sRef, E_USER_WARNING);
			return false;
		}
		unset($this->oFileHandles[$sRef]);
		$this->iHandleCount--;
		return true;
	}
	
	// Read function will suck in the contents of the file handle name passed in 
	// with $sRef.
	function Read($sRef) {
		return fread($this->oFileHandles[$sRef]['obj'], $this->oFileHandles[$sRef]['len']);
	}
	
	// Write contents to specificed file handle.
	function Write($sRef, $sFileContents) {
				
		if(!fwrite($this->oFileHandles[$sRef]['obj'], $sFileContents)) {
			$this->LOG->LogError("Can't write to file handle:" . $sRef, E_USER_WARNING);
			return false;
		}
		return true;
	}
	
	// Get file size in Bytes 
	function GetFilesize($sFilename, $iBaseDirFlag = false) {
		if($iBaseDirFlag) {
			return filesize($sFilename);
		} else {
			return filesize($this->sBaseDir . $sFilename);
		}
	}
		
	// Create a directory with given permssions. 
	function CreateDir($sDirName, $iPerm = 0777) {
		if(!mkdir($this->sBaseDir . $sDirName, "0777"))  {
			$this->LOG->LogError("Can't create directory:" . $this->sBaseDir . $sDirName . " with permissions:" . $sPerm, E_USER_WARNING);
			return false;
		}
		chmod($this->sBaseDir . $sDirName, $iPerm);
		return true;
	}
	
	// Get last Modifed date for file. 
	function GetFileModified($sFilename) {
		// date ("F d Y H:i:s.", filemtime($sFilename));
		return filemtime($sFilename);
	}
		
	function GetFolderCreated($sFilename) {
		return filectime($sFilename);
	}
	
	// Function deletes all files with $ext from directory recursively (inc all sub dirs)
	// @return boolean True on success, False on failure.
	// Use $assoc_ext to delete file of same name but different file extension. 
	// Eg Delete all files *.mpg and associated file of same name but extension .png (to remove video poster images)
	function DeleteFiletypeRecursive($dir_path, $ext, $assoc_ext) {

		// Trim trailing forward slash if exists
		$dir_path = rtrim($dir_path,"/");
		
		// Exit if there's no such directory
    	if(!file_exists($dir_path)) {
        	return false;
    	}

    	// Open the target directory
    	$dir_handle = dir($dir_path);

    	// Take entries in the directory one at a time
    	while(false !== ($entry = $dir_handle->read())) {

        	if($entry == '.' || $entry == '..') {
            	continue;
        	}

        	$abs_name = "$dir_path/$entry";

        	if(is_file($abs_name) && preg_match("/^(.+)\.$ext$/i", $entry, $regs)) {
        	    
        		if(unlink($abs_name)) {
        		    if($assoc_ext) {	
        				$as_path = $dir_path . "/" . $regs[1] . "." . $assoc_ext;
        				if(is_file($as_path)) {
        					unlink($as_path);
        				}
        			}
        			
       	        	continue;
       	     	}
       	     	
      	      	return false;
     	   	}

    	    // Recurse on the children if the current entry happens to be a "directory"
     	   if(is_dir($abs_name) || is_link($abs_name)) {
    	        $this->DeleteFiletypeRecursive($abs_name, $ext, $assoc_ext);
     	   }
    	}
		
    	$dir_handle->close();
    	return true;
	}

	// Delete all directories and sub directories in $path. Set $del = 1 to delete parent directory. 
	function DeleteDirs($path, $del) {   
		$dir = new RecursiveDirectoryIterator($this->sBaseDir . $path);
       	
		//Remove all files
       	foreach(new RecursiveIteratorIterator($dir) as $file) {
       		unlink($file);
       	}

   		//Remove all subdirectories
  		foreach($dir as $subDir) {
       		if(!@rmdir($subDir)) {
           			$this->DeleteDir($subDir);
       		}
      	}
       		
      	//Remove main directory
       	if($del) {
      		rmdir($this->sBaseDir . $path);
       	}
       	
       	return true; 
   	}	
   
   	// Rename or move a file or folder. 
   	function Rename($path_from, $path_to) {
   		rename($this->sBaseDir . $path_from, $this->sBaseDir . $path_to);
   	}
   	 
   	// Get folder size.  
   	function GetFolderSize($path) {
   		$total_size = 0;
    	
   		$files = scandir($path);
    	foreach($files as $t) {
        	if (is_dir($t)) { // In case of folder
            	if ($t<>"." && $t<>"..") { // Exclude self and parent folder
                	$size = foldersize($path . "/" . $t);
                	// print("Dir - $path/$t = $size<br>\n");
                	$total_size += $size;
            	}
        	} else { // In case of file
            	$size = filesize($path . "/" . $t);
            	// print("File - $path/$t = $size<br>\n");
            	$total_size += $size;
        	}
        }   
        return $total_size;
    }

	// Get recursive directory tree as multidimensional array. 
	function GetDirectoryTree($path, $ignore) {
	   	foreach(scandir($path) as $item) {
        	if($item != '.' && $item != '..' && !in_array($item, $ignore))	{
        		// $item = strtolower($item);
            	$entry  = $path.'/'.$item;
				if(is_dir($entry)) {
                	$path_info = pathinfo($entry);
                	$aListArray[$path_info['basename']] = $this->GetDirectoryTree($entry);
            	} elseif(!ereg("index.php$", $entry)) {
                	$path_info = pathinfo($entry);
                	$aListArray[$path_info['basename']] = $path_info['filename'];
            	}
			}
		}
    	return($aListArray);
	}
 
	// Low level function to open a given file for reading and writing.
	function _OpenFile($sFilename) {
		if(!$oFp = fopen($this->sBaseDir . $sFilename, 'r+')) {
			$this->LOG->LogError("Can't open file : " . $this->sBaseDir . $sFilename, E_USER_WARNING);
			return false;
		}
		return $oFp;
	}
	// CreateFile will create a new file and fill with content if supplied.
	function _CreateFile($sFilename) {
		$this->_CheckMount();
		
		if(!$oFp = fopen($this->sBaseDir . $sFilename, 'x')) {
			$this->LOG->LogError("Can't create new - either exists allready or you don't have permissions", E_USER_WARNING);
			return false;
		}
		return $oFp;
	}
	
	// CloseFile will cloe the passed file handle.
	function _CloseFile($oFileHandle) {
		if(!fclose($oFileHandle)) {
			$this->LOG->LogError("Can't close file handle.", E_USER_WARNING);
			return false;
		}
		return true;
	}
		
	function _CheckMount() {
		
		if(!$this->Mount) {
			return false;
		}
	}

}

?>
