aliroFileManager.php

Go to the documentation of this file.
00001 <?php
00002 
00003 /*******************************************************************************
00004  * Aliro - the modern, accessible content management system
00005  *
00006  * Aliro is open source software, free to use, and licensed under GPL.
00007  * You can find the full licence at http://www.gnu.org/copyleft/gpl.html GNU/GPL
00008  *
00009  * The author freely draws attention to the fact that Aliro derives from Mambo,
00010  * software that is controlled by the Mambo Foundation.  However, this section
00011  * of code is totally new.  If it should contain any fragments that are similar
00012  * to Mambo, please bear in mind (1) there are only so many ways to do things
00013  * and (2) the author of Aliro is also the author and copyright owner for large
00014  * parts of Mambo 4.6.
00015  *
00016  * Tribute should be paid to all the developers who took Mambo to the stage
00017  * it had reached at the time Aliro was created.  It is a feature rich system
00018  * that contains a good deal of innovation.
00019  *
00020  * Your attention is also drawn to the fact that Aliro relies on other items of
00021  * open source software, which is very much in the spirit of open source.  Aliro
00022  * wishes to give credit to those items of code.  Please refer to
00023  * http://aliro.org/credits for details.  The credits are not included within
00024  * the Aliro package simply to avoid providing a marker that allows hackers to
00025  * identify the system.
00026  *
00027  * Copyright in this code is strictly reserved by its author, Martin Brampton.
00028  * If it seems appropriate, the copyright will be vested in the Aliro Organisation
00029  * at a suitable time.
00030  *
00031  * Copyright (c) 2007 Martin Brampton
00032  *
00033  * http://aliro.org
00034  *
00035  * counterpoint@aliro.org
00036  *
00037  * aliroFileManager is the singleton class to insulate Aliro from actual file system
00038  * operations.  This gives the option to elaborate the class to handle issues such as
00039  * coping with safe mode.  The class also provides a utility method "forceCopy" (used
00040  * by the installer) to make a copy happen if at all possible.  Some old methods are
00041  * kept here for backwards compatibility, but they really need review.
00042  *
00043  * aliroDirectory allows the creation of an object that corresponds to a directory in
00044  * the file system, and then provides a number of useful methods to manipulate the
00045  * directory and its contents, including finding out what the contents are.
00046  *
00047  */
00048 
00049 class aliroFileManager {
00050 
00051     private static $instance = __CLASS__;
00052 
00053     private function __construct () {
00054         // Enforce singleton
00055     }
00056 
00057     private function __clone () {
00058         // Enforce singleton
00059     }
00060 
00061     public static function getInstance () {
00062         return is_object(self::$instance) ? self::$instance : (self::$instance = new self::$instance());
00063     }
00064 
00065     function deleteFile ($file) {
00066         if (file_exists($file)) {
00067             @chmod($file, 0644);
00068             return unlink($file);
00069         }
00070         return true;
00071     }
00072 
00073     function deleteDirectory ($dir) {
00074         if (file_exists($dir)) {
00075             if (is_dir($dir)) {
00076                 @chmod($dir, 0755);
00077                 return rmdir($dir);
00078             }
00079             return false;
00080         }
00081         return true;
00082     }
00083 
00084     function setPermissions ($fileSysObject, $mode=null) {
00085         $result = true;
00086         if (file_exists($fileSysObject))  {
00087             if ($mode);
00088             elseif (is_dir($fileSysObject)) $mode = octdec(aliroCore::get('mosConfig_dirperms'));
00089             else $mode = octdec(aliroCore::get('mosConfig_fileperms'));
00090             if ($mode) {
00091                 $origmask = @umask(0);
00092                 $result = @chmod($fileSysObject, $mode);
00093                 @umask($origmask);
00094             }
00095         }
00096         return $result;
00097     }
00098 
00099     function makeDirectory ($dir) {
00100         $result = @mkdir($dir, 0755);
00101         if ($result) $this->setPermissions($dir);
00102         return $result;
00103     }
00104 
00105     public function createDirectory ($dir, $onlyCheck=false) {
00106         if (file_exists($dir)) {
00107             if (is_dir($dir) AND is_writable($dir)) return true;
00108             else return false;
00109         }
00110         list($upDirectory, $count) = $this->containingDirectory($dir);
00111         if ($count > 1 AND !file_exists($upDirectory) AND !($result = $this->createDirectory($upDirectory, $onlyCheck))) return false;
00112         if ($onlyCheck AND isset($result)) return true;
00113         if (!is_dir($upDirectory) OR !is_writable($upDirectory)) return false;
00114         if ($onlyCheck) return true;
00115         else return $this->makeDirectory($dir);
00116     }
00117 
00118     private function containingDirectory ($dir) {
00119         $dirs = preg_split('*[/|\\\]*', $dir);
00120         for ($i = count($dirs)-1; $i >= 0; $i--) {
00121             $text = trim($dirs[$i]);
00122             unset($dirs[$i]);
00123             if ($text) break;
00124         }
00125         $result2 = count($dirs);
00126         $result1 = implode('/',$dirs).($result2 > 1 ? '' : '/');
00127         return array($result1, $result2);
00128     }
00129 
00130     function simpleCopy ($from, $to) {
00131         if (@copy($from, $to)) {
00132             $this->setPermissions($to);
00133             return true;
00134         }
00135         else return false;
00136     }
00137 
00138     function forceCopy ($from, $to, $reportErrors=false) {
00139         if (!file_exists($from)) {
00140             if ($reportErrors) aliroRequest::getInstance()->setErrorMessage (sprintf(T_('Copy requested for %s, but source file not found'), $from), _ALIRO_ERROR_WARN);
00141             return false;
00142         }
00143         $todir = dirname($to);
00144         if (!file_exists($todir)) $this->createDirectory($todir);
00145         if (!file_exists($todir)) {
00146             if ($reportErrors) aliroRequest::getInstance()->setErrorMessage (sprintf(T_('Copy requested for %s, but could not create destination directory'), $from), _ALIRO_ERROR_WARN);
00147             return false;
00148         }
00149         $name = basename($from);
00150         $this->deleteFile($to.$name);
00151         if ($this->simpleCopy ($from, $to)) return true;
00152         elseif ($reportErrors) aliroRequest::getInstance()->setErrorMessage (sprintf(T_('Copy requested for %s, source found but could not copy to %s'), $from, $to), _ALIRO_ERROR_WARN);
00153         return false;
00154     }
00155 
00156     function lightCopy ($from, $to) {
00157         $name = basename($from);
00158         if (file_exists($to.$name)) return false;
00159         $todir = dirname($to);
00160         if (!file_exists($todir)) $this->createDirectory($todir);
00161         if (!file_exists($todir)) return false;
00162         return $this->simpleCopy ($from, $to);
00163     }
00164 
00165     function acceptCopy ($to) {
00166         $todir = dirname($to);
00167         return $this->createDirectory($todir, true);
00168     }
00169 
00170     // Provided for compatibility - not really needed in full
00171     // PHP is happy with paths containing forward or backwards slashes, or even a mixture
00172     // Aliro normally converts all paths to use forward slashes for tidiness
00173     function mosPathName($p_path, $p_addtrailingslash=true) {
00174         if (substr(PHP_OS, 0, 3) == 'WIN')  {
00175             $retval = str_replace( '/', '\\', $p_path );
00176             if ($p_addtrailingslash AND substr( $retval, -1 ) != '\\') $retval .= '\\';
00177             // Remove double \\
00178             $retval = str_replace( '\\\\', '\\', $retval );
00179         }
00180         else {
00181             $retval = str_replace( '\\', '/', $p_path );
00182             if ($p_addtrailingslash AND substr( $retval, -1 ) != '/') $retval .= '/';
00183             // Remove double //
00184             $retval = str_replace('//','/',$retval);
00185         }
00186         return $retval;
00187     }
00188 
00196     function mosChmod($path)
00197     {
00198         $filemode = octdec(aliroCore::get('mosConfig_fileperms'));
00199         $dirmode = octdec(aliroCore::get('mosConfig_dirperms'));
00200         if ($filemode OR $dirmode) return $this->mosChmodRecursive($path, $filemode, $dirmode);
00201         return true;
00202     } // mosChmod
00203 
00211     function mosChmodRecursive($path, $filemode=NULL, $dirmode=NULL) {
00212         $ret = true;
00213         if (is_dir($path)) {
00214             $topdir = new aliroDirectory($path);
00215             $files = $topdir->listFiles ('', 'file', true, true);
00216             $dirs = $topdir->listFiles ('', 'dir', true, true);
00217         }
00218         else {
00219             $files = array($path);
00220             $dirs = array();
00221         }
00222         if (isset($filemode)) foreach ($files as $file) $ret = @chmod($file, $filemode) ? $ret : false;
00223         if (isset($dirmode)) foreach ($dirs as $dir) $ret = @chmod($dir, $dirmode) ? $ret : false;
00224         return $ret;
00225     }
00226     
00227     public function makeUploadSafe ($name, $useRealName=false) {
00228         $tempdir = $this->makeTemp();
00229         $files = array();
00230         $tempfiles = (array) $_FILES[$name]['tmp_name'];
00231         $filenames = (array) $_FILES[$name]['name'];
00232         foreach ($tempfiles as $key=>$temp) {
00233             if ($useRealName) $filename = $filenames[$key];
00234             else $filename = basename($temp);
00235             if (move_uploaded_file($temp, $tempdir.$filename)) {
00236                 $files[$filenames[$key]] = $tempdir.$filename;
00237                 $this->setPermissions($tempdir.$filename);
00238             }
00239         }
00240         return $files;
00241     }
00242 
00243     public function extractArchive ($filename, $extractDir='') {
00244         if (!$extractDir) $extractDir = $this->makeTemp();
00245         if (preg_match( '/\.zip$/i', $filename )) {
00246             $zipfile = new PclZip( $filename );
00247             $ret = $zipfile->extract( PCLZIP_OPT_PATH, $extractDir );
00248             if($ret == 0) {
00249                 aliroRequest::getInstance()->setErrorMessage (sprintf(T_('Installer unrecoverable ZIP error %s in %s'), $zipfile->errorName(true), $filename), _ALIRO_ERROR_FATAL);
00250                 return false;
00251             }
00252         } else {
00253             error_reporting(E_ALL);
00254             $archive = new Archive_Tar( $filename );
00255             $archive->setErrorHandling( PEAR_ERROR_PRINT );
00256 
00257             if (!$archive->extractModify( $extractDir, '' )) {
00258                 aliroRequest::getInstance()->setErrorMessage (sprintf(T_('Installer unrecoverable TAR error in %s'), $filename), _ALIRO_ERROR_FATAL);
00259                 return false;
00260             }
00261             error_reporting(E_ALL|E_STRICT);
00262         }
00263         $this->mosChmodRecursive($extractDir);
00264         return $extractDir;
00265     }
00266     
00267     public function makeTemp () {
00268         $tempDir = criticalInfo::getInstance()->class_base.'/media/'.uniqid('_aliro_temp_').'/';
00269         $this->createDirectory($tempDir);
00270         return $tempDir;
00271     }
00272     
00273 }
00274 
00275 class aliroDirectory {
00276     private $path = '';
00277 
00278     public function __construct ($path) {
00279         $path = str_replace('\\', '/', $path);
00280         $this->path = ('/' == substr($path,-1)) ? $path : $path.'/';
00281     }
00282     
00283     public function getPath () {
00284         return $this->path;
00285     }
00286 
00287     public function listAll ($type='file', $recurse=false, $fullpath=false) {
00288         $results = array();
00289         if ($dir = @opendir($this->path)) {
00290             while ($file = readdir($dir)) {
00291                 if ($file == '.' OR $file == '..') continue;
00292                 if (is_dir($this->path.$file)) {
00293                     if ($recurse) {
00294                         $subdir = new aliroDirectory($this->path.$file);
00295                         $results = array_merge($results, $subdir->listAll($type, $recurse, $fullpath));
00296                         unset($subdir);
00297                     }
00298                     if ($type == 'file') continue;
00299                 }
00300                 elseif ($type == 'dir') continue;
00301                 if ($fullpath) $results[] = $this->path.$file;
00302                 else $results[] = $file;
00303             }
00304             closedir($dir);
00305         }
00306         return $results;
00307     }
00308 
00309     public function soleDir () {
00310         $found = '';
00311         if ($dir = @opendir($this->path)) {
00312             while ($file = readdir($dir)) {
00313                 if ($file == '.' OR $file == '..') continue;
00314                 if (is_dir($this->path.$file)) {
00315                     if ($found) return '';
00316                     else $found = $file;
00317                 }
00318                 else return '';
00319             }
00320             closedir($dir);
00321         }
00322         return $found;
00323     }
00324 
00325     public function deleteAll () {
00326         if (!file_exists($this->path)) return;
00327         $subdirs = $this->listAll ('dir', false, true);
00328         foreach ($subdirs as $subdir) {
00329             $subdirectory = new aliroDirectory($subdir);
00330             $subdirectory->deleteAll();
00331             unset($subdirectory);
00332         }
00333         $this->deleteFiles(false);
00334         aliroFileManager::getInstance()->deleteDirectory($this->path);
00335     }
00336     
00337     public function deleteFiles ($keepstandard=true) {
00338         $filemanager = aliroFileManager::getInstance();
00339         $files = $this->listAll ('file', false, true);
00340         foreach ($files as $file) {
00341             $filename = basename($file);
00342             if (!$keepstandard OR ('index.html' != $filename AND '.' != $filename[0])) $filemanager->deleteFile($file);
00343         }
00344     }
00345 
00346     public function createFresh () {
00347         $this->deleteAll();
00348         $filemanager = aliroFileManager::getInstance();
00349         $filemanager->createDirectory($this->path);
00350         return true;
00351     }
00352 
00353     public function createIfNeeded () {
00354         if (!file_exists($this->path)) {
00355             $filemanager = aliroFileManager::getInstance();
00356             $filemanager->createDirectory($this->path);
00357         }
00358     }
00359 
00360     public function listFiles ($pattern='', $type='file', $recurse=false, $fullpath=false) {
00361         $results = array();
00362         $all = $this->listAll($type, $recurse, $fullpath);
00363         foreach ($all as $file) {
00364             $name = basename($file);
00365             if ($pattern AND !preg_match( "/$pattern/", $name )) continue;
00366             if (($name != 'index.html') AND ($name[0] != '.')) $results[] = $file;
00367         }
00368         return $results;
00369     }
00370 
00371     public function getSize () {
00372         $totalsize = 0;
00373         $files = $this->listFiles();
00374         foreach ($files as $file) $totalsize += filesize($this->path.$file);
00375         return $totalsize;
00376     }
00377     
00378     public function zip ($zipname) {
00379         $zipfile = $this->path.$zipname;
00380         $files = $this->listAll('file', true, true);
00381         $zip = new ZipArchive();
00382         if (!$zip->open($zipfile, ZIPARCHIVE::CREATE)) trigger_error(T_('Unable to open zip file ').$zipfile);
00383         else foreach ($files as $file) $zip->addFile($file,substr($file,strlen($this->path)));
00384         $zip->close();
00385         return $zipfile;
00386     }
00387 
00388 
00389 }

Generated on Wed May 14 13:01:56 2008 for ALIRO by  doxygen 1.5.5