Version: current

      1 <?php
      2 /**
      3  * A collection of static methods for manipulating the filesystem.
      4  * @package sapphire
      5  * @subpackage filesystem
      6  */
      7 class Filesystem extends Object {
      8
      9     public static $file_create_mask = 02775;
     10
     11     public static $folder_create_mask = 02775;
     12
     13     protected static $cache_folderModTime;
     14
     15     /**
     16      * Create a folder, recursively
     17      */
     18     static function makeFolder($folder) {
     19         if(!file_exists($base = dirname($folder))) self::makeFolder($base);
     20         if(!file_exists($folder)) mkdir($folder, Filesystem::$folder_create_mask);
     21     }
     22
     23     /**
     24      * Remove a directory and all subdirectories and files
     25      * @param $contentsOnly If this is true then the contents of the folder will be removed but not the folder itself
     26      */
     27     static function removeFolder( $folder, $contentsOnly = false ) {
     28
     29         // remove a file encountered by a recursive call.
     30         if( !is_dir( $folder ) || is_link($folder) )
     31             unlink( $folder );
     32         else {
     33
     34             $dir = opendir( $folder );
     35
     36             while( $file = readdir( $dir ) )
     37                 if( !preg_match( '/\.{1,2}$/', $file ) )
     38                     self::removeFolder( $folder.'/'.$file );
     39
     40             closedir($dir);
     41
     42             if(!$contentsOnly) rmdir($folder);
     43         }
     44     }
     45
     46     /**
     47      * Cleanup function to reset all the Filename fields.  Visit File/fixfiles to call.
     48      */
     49     public function fixfiles() {
     50         if(!Permission::check('ADMIN')) return Security::permissionFailure($this);
     51
     52         $files = DataObject::get("File");
     53         foreach($files as $file) {
     54             $file->resetFilename();
     55             echo "<li>", $file->Filename;
     56             $file->write();
     57         }
     58         echo "<p>Done!";
     59     }
     60
     61     /*
     62      * Return the most recent modification time of anything in the folder.
     63      * @param $folder The folder, relative to the site root
     64      * @param $extensionList An option array of file extensions to limit the search to
     65      */
     66     static function folderModTime($folder, $extensionList = null, $recursiveCall = false) {
     67         //$cacheID = $folder . ',' . implode(',', $extensionList);
     68         //if(!$recursiveCall && self::$cache_folderModTime[$cacheID]) return self::$cache_folderModTime[$cacheID];
     69
     70         $modTime = 0;
     71         if(!Filesystem::isAbsolute($folder)) $folder = Director::baseFolder() . '/' . $folder;
     72
     73         $items = scandir($folder);
     74         foreach($items as $item) {
     75             if($item[0] != '.') {
     76                 // Recurse into folders
     77                 if(is_dir("$folder/$item")) {
     78                     $modTime = max($modTime, self::folderModTime("$folder/$item", $extensionList, true));
     79
     80                 // Check files
     81                 } else {
     82                     if($extensionList) $extension = strtolower(substr($item,strrpos($item,'.')+1));
     83                     if(!$extensionList || in_array($extension, $extensionList)) {
     84                         $modTime = max($modTime, filemtime("$folder/$item"));
     85                     }
     86                 }
     87             }
     88         }
     89
     90         //if(!$recursiveCall) self::$cache_folderModTime[$cacheID] = $modTime;
     91         return $modTime;
     92     }
     93
     94     /**
     95      * Returns true if the given filename is an absolute file reference.
     96      * Works on Linux and Windows
     97      */
     98     static function isAbsolute($filename) {
     99         if($_ENV['OS'] == "Windows_NT" || $_SERVER['WINDIR']) return $filename[1] == ':' && $filename[2] == '/';
    100         else return $filename[0] == '/';
    101     }
    102
    103     /**
    104      * This function ensures the file table is correct with the files in the assets folder.
    105      *
    106      * If a Folder record ID is given, all of that folder's children will be synchronised.
    107      * If the given Folder ID isn't found, or not specified at all, then everything will
    108      * be synchronised from the root folder (singleton Folder).
    109      *
    110      * @param int $folderID Folder ID to sync along with all it's children
    111      */
    112     static function sync($folderID = null) {
    113         $folder = DataObject::get_by_id('Folder', (int) $folderID);
    114         if(!($folder && $folder->exists())) $folder = singleton('Folder');
    115
    116         $results = $folder->syncChildren();
    117         $finished = false;
    118         while(!$finished) {
    119             $orphans = DB::query("SELECT \"C\".\"ID\" FROM \"File\" AS \"C\"
    120                 LEFT JOIN \"File\" AS \"P\" ON \"C\".\"ParentID\" = \"P\".\"ID\"
    121                 WHERE \"P\".\"ID\" IS NULL AND \"C\".\"ParentID\" > 0");
    122             $finished = true;
    123             if($orphans) foreach($orphans as $orphan) {
    124                 $finished = false;
    125                 // Delete the database record but leave the filesystem alone
    126                 $file = DataObject::get_by_id("File", $orphan['ID']);
    127                 $file->deleteDatabaseOnly();
    128                 unset($file);
    129             }
    130         }
    131
    132         // Update the image tracking of all pages
    133         if(class_exists('Subsite')) Subsite::$disable_subsite_filter = true;
    134         foreach(DataObject::get("SiteTree") as $page) {
    135             // syncLinkTracking is called by SiteTree::onBeforeWrite()
    136             $page->write();
    137         }
    138         if(class_exists('Subsite')) Subsite::$disable_subsite_filter = false;
    139
    140         return _t(
    141             'Filesystem.SYNCRESULTS',
    142             sprintf('Sync complete: %s items created, %d items deleted', (int) $results['added'], (int) $results['deleted'])
    143         );
    144     }
    145
    146 }
    147
    148 ?>

[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the Silverstripe Forums to ask development related questions. -