1: <?php
2: /**
3: * This file contains the the static directory handler class.
4: *
5: * @package Core
6: * @subpackage Util
7: * @author Frederic Schneider
8: * @copyright four for business AG <www.4fb.de>
9: * @license http://www.contenido.org/license/LIZENZ.txt
10: * @link http://www.4fb.de
11: * @link http://www.contenido.org
12: */
13: defined('CON_FRAMEWORK') || die('Illegal call: Missing framework initialization - request aborted.');
14:
15: /**
16: * Class for directory handling.
17: * Provides functions for dealing with directories.
18: *
19: * @package Core
20: * @subpackage Util
21: */
22: class cDirHandler {
23:
24: /**
25: * default permissions for new directories
26: *
27: * @see CON-2770
28: * @var int
29: */
30: const DEFAULT_MODE = 0775;
31:
32: /**
33: * Creates a new dir.
34: *
35: * @param string $pathname
36: * the name and path of the new dir
37: * @param bool $recursive [optional]
38: * @return bool
39: * Returns true on success or false on failure.
40: */
41: public static function create($pathname, $recursive = false) {
42: // skip if dir already exists
43: if (self::exists($pathname)) {
44: return true;
45: }
46: // reset umask and store old umask
47: $oldumask = umask(0);
48: // calc mode from setting or default
49: $mode = self::getDefaultPermissions();
50: // create dir with given mode
51: $success = mkdir($pathname, $mode, $recursive);
52: // reset umask to old umask
53: umask($oldumask);
54: // return success
55: return $success;
56: }
57:
58: /**
59: * Removes a dir from the filesystem
60: *
61: * @param string $dirname
62: * The path to the directory
63: *
64: * @return bool
65: * Returns true on success or false on failure.
66: *
67: * @throws cInvalidArgumentException
68: * if the dir with the given dirname does not exist
69: */
70: public static function remove($dirname) {
71: if (!self::exists($dirname)) {
72: throw new cInvalidArgumentException('The directory ' . $dirname . ' could not be accessed because it does not exist.');
73: }
74: return rmdir($dirname);
75: }
76:
77: /**
78: * Moves a dir
79: *
80: * @param string $dirname
81: * The path and name of the directory
82: * @param string $destination
83: * the destination. Note that the dir can also be renamed in the
84: * process of moving it
85: *
86: * @return bool
87: * Returns true on success or false on failure.
88: *
89: * @throws cInvalidArgumentException
90: * if the dir with the given dirname does not exist
91: */
92: public static function move($dirname, $destination) {
93: if (!self::exists($dirname)) {
94: throw new cInvalidArgumentException('The directory ' . $dirname . ' could not be accessed because it does not exist.');
95: }
96:
97: $success = rename($dirname, $destination);
98:
99: if ($success) {
100: self::setDefaultDirPerms($destination);
101: }
102:
103: return $success;
104: }
105:
106: /**
107: * Renames a dir
108: *
109: * @param string $dirname
110: * the name and path of the dir
111: * @param string $new_dirname
112: * the new name of the dir
113: *
114: * @throws cInvalidArgumentException
115: */
116: public static function rename($dirname, $new_dirname) {
117: self::move($dirname, $new_dirname);
118: }
119:
120: /**
121: * Changes the dir permissions
122: *
123: * @param string $dirname
124: * the name and path of the dir
125: * @param int $mode
126: * the new access mode : php chmod needs octal value
127: *
128: * @return bool
129: * Returns true on success or false on failure.
130: *
131: * @throws cInvalidArgumentException
132: * if the dir with the given dirname does not exist
133: */
134: public static function chmod($dirname, $mode) {
135: if (!cFileHandler::exists($dirname)) {
136: throw new cInvalidArgumentException('The directory ' . $dirname . ' could not be accessed because it does not exist.');
137: }
138: // chmod needs octal value for correct execution.
139: $mode = intval($mode, 8);
140: return @chmod($dirname, $mode);
141: }
142:
143: /**
144: * Determines the default permissions for new directories.
145: * These can be configured using the setting "default_perms/directory" in "data/config/<ENV>/config.misc.php".
146: * If no configuration can be found 0775 is assumed.
147: *
148: * @return int
149: */
150: public static function getDefaultPermissions()
151: {
152: $mode = cRegistry::getConfigValue('default_perms', 'directory', self::DEFAULT_MODE);
153:
154: return intval($mode, 8);
155: }
156:
157: /**
158: * Sets the default permissions for the given directory.
159: *
160: * @param string $dirname
161: * the name of the directory
162: *
163: * @return bool
164: * Returns true on success or false on failure.
165: *
166: * @throws cInvalidArgumentException
167: */
168: public static function setDefaultPermissions($dirname)
169: {
170: return self::chmod($dirname, self::getDefaultPermissions());
171: }
172:
173: /**
174: * Sets the default permissions for the given directory.
175: *
176: * @deprecated use setDefaultPermissions() instead
177: * @param string $dirname
178: * the name of the directory
179: *
180: * @return bool
181: * Returns true on success or false on failure.
182: *
183: * @throws cInvalidArgumentException
184: */
185: public static function setDefaultDirPerms($dirname)
186: {
187: return self::setDefaultPermissions($dirname);
188: }
189:
190: /**
191: * Deletes a directory and all of its content.
192: *
193: * @param string $dirname
194: * the name of the directory which should be deleted
195: *
196: * @return bool
197: * Returns true on success or false on failure.
198: *
199: * @throws cInvalidArgumentException
200: * if dirname is empty
201: */
202: public static function recursiveRmdir($dirname) {
203: if ($dirname == '') {
204: throw new cInvalidArgumentException('Directory name must not be empty.');
205: }
206:
207: // make sure $dirname ends with a slash
208: if (cString::getPartOfString($dirname, -1) !== '/') {
209: $dirname .= '/';
210: }
211:
212: foreach (new DirectoryIterator($dirname) as $file) {
213: if ($file != "." && $file != "..") {
214: $file = $dirname . $file;
215: if (is_dir($file)) {
216: self::recursiveRmdir($file);
217: } else {
218: unlink($file);
219: }
220: }
221: }
222:
223: return rmdir($dirname);
224: }
225:
226: /**
227: * Copies a directory and all of its subfolders.
228: *
229: * @param string $dirname
230: * the name and path of the file
231: * @param string $destination
232: * the destination. Note that existing files get overwritten
233: * @param int $mode [optional; default as configured or 0775]
234: * chmod mode
235: *
236: * @return bool
237: * true on success
238: *
239: * @throws cInvalidArgumentException
240: * if the file with the given filename does not exist
241: */
242: public static function recursiveCopy($dirname, $destination, $mode = null) {
243: if (!self::exists($dirname)) {
244: throw new cInvalidArgumentException('The directory ' . $dirname . ' could not be accessed because it does not exist.');
245: }
246:
247: if (is_null($mode)) {
248: $mode = self::getDefaultPermissions();
249: }
250:
251: if (!cFileHandler::exists($destination)) {
252: if (!mkdir($destination)) {
253: return false;
254: }
255: if (!self::chmod($destination, $mode)) {
256: return false;
257: }
258: }
259:
260: foreach ($iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dirname), RecursiveIteratorIterator::SELF_FIRST) as $item) {
261: // workaround for RecursiveDirectoryIterator::SKIP_DOTS, this was
262: // not available in PHP 5.2
263: if ($item->getFilename() == '.' || $item->getFilename() == '..') {
264: continue;
265: }
266:
267: if ($item->isDir()) {
268: if (!mkdir($destination . DIRECTORY_SEPARATOR . $iterator->getSubPathName())) {
269: return false;
270: }
271: if (!self::chmod($destination . DIRECTORY_SEPARATOR . $iterator->getSubPathName(), $mode)) {
272: return false;
273: }
274: } else {
275: if (!copy($item, $destination . DIRECTORY_SEPARATOR . $iterator->getSubPathName())) {
276: return false;
277: }
278: if (!self::chmod($destination . DIRECTORY_SEPARATOR . $iterator->getSubPathName(), $mode)) {
279: return false;
280: }
281: }
282: }
283:
284: return true;
285: }
286:
287: /**
288: * Checks if a directory is empty
289: *
290: * @param string $dir
291: * Name of the directory
292: * @return bool
293: * true if the directory is empty
294: */
295: public static function isDirectoryEmpty($dir) {
296: if (!is_readable($dir)) {
297: return false;
298: }
299: if (is_dir($dir)) {
300: if ($handle = opendir($dir)) {
301: while (false !== ($entry = readdir($handle))) {
302: if ($entry != "." && $entry != "..") {
303: return false;
304: }
305: }
306: }
307: closedir($handle);
308: }
309: return true;
310: }
311:
312: /**
313: * This functions reads the content from given directory.
314: * Optionally options are to read the directory recursive or to list only
315: * directories.
316: *
317: * @param string $dirname
318: * directory
319: * @param bool $recursive [optional]
320: * flag to read recursive
321: * @param bool $dirOnly [optional]
322: * flag to list only directories
323: * @param bool $fileOnly [optional]
324: * flag to list only files if $dirOnly is set to false
325: * @return array|bool
326: * array containing file names as string, false on error
327: */
328: public static function read($dirname, $recursive = false, $dirOnly = false, $fileOnly = false) {
329: if (!self::exists($dirname)) {
330: return false;
331: }
332:
333: $dirContent = array();
334: if ($recursive == false) {
335: $dirHandle = opendir($dirname);
336: $dirContent = array();
337: while (false !== ($file = readdir($dirHandle))) {
338: if (!cFileHandler::fileNameIsDot($file)) {
339:
340: if ($dirOnly == true) { // get only directories
341:
342: if (is_dir($dirname . $file)) {
343: $dirContent[] = $file;
344: }
345: // bugfix: is_dir only checked file name without path, thus returning everything most of the time
346: } else if ($fileOnly === true) { // get only files
347:
348: if (is_file($dirname . $file)) {
349: $dirContent[] = $file;
350: }
351: } else { // get everything
352: $dirContent[] = $file;
353: }
354: }
355: }
356: closedir($dirHandle);
357: } else {
358: $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dirname), RecursiveIteratorIterator::SELF_FIRST);
359: foreach ($objects as $name => $file) {
360:
361: if (!cFileHandler::fileNameIsDot($file)) {
362: $fileName = str_replace("\\", "/", $file->getPathName());
363:
364: if ($dirOnly === true && is_dir($fileName)) {
365: // get only directories
366: $dirContent[] = $fileName;
367:
368: } else if ($fileOnly === true && is_file($fileName)) {
369: // get only files
370: $dirContent[] = $fileName;
371:
372: } else {
373: // get everything
374: $dirContent[] = $fileName;
375:
376: }
377: }
378: }
379: }
380:
381: return $dirContent;
382: }
383:
384: /**
385: * Checks if a directory exists
386: *
387: * @param string $dirname
388: * the name and path of the directory
389: * @return bool
390: * true if the directory exists
391: */
392: public static function exists($dirname) {
393: return is_dir($dirname);
394: }
395:
396: /**
397: * Returns the size of a directory.
398: * AKA the combined filesizes of all files within it.
399: * Note that this function uses filesize(). There could be problems with files
400: * that are larger than 2GiB
401: *
402: * @param string $dirname
403: * The directory name
404: * @param bool $recursive [optional]
405: * true if all the subdirectories should be included in the calculation
406: *
407: * @return int|bool
408: * false in case of an error or the size
409: *
410: * @throws cInvalidArgumentException
411: */
412: public static function getDirectorySize($dirname, $recursive = false) {
413: $ret = 0;
414: $files = self::read($dirname, $recursive, false, true);
415: if ($files === false) {
416: return false;
417: }
418:
419: foreach ($files as $file) {
420: $temp = cFileHandler::info($dirname . $file);
421: $ret += $temp['size'];
422: }
423:
424: return $ret;
425: }
426:
427: /**
428: * Checks if you can create in mother directory a new folder
429: *
430: * @param $dirname
431: * @return bool
432: */
433: public static function isCreatable($dirname) {
434: if (cFileHandler::writeable($dirname) === true) {
435: return true;
436: } else {
437: return false;
438: }
439: }
440: }
441: