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