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: * Creates a new dir.
26: *
27: * @param string $pathname
28: * the name and path of the new dir
29: * @param bool $recursive [optional]
30: * @return bool
31: * Returns true on success or false on failure.
32: */
33: public static function create($pathname, $recursive = false) {
34: // skip if dir already exists
35: if (self::exists($pathname)) {
36: return true;
37: }
38: // reset umask and store old umask
39: $oldumask = umask(0);
40: // calc mode from setting or default
41: $mode = cRegistry::getConfigValue('default_perms', 'directory', 0777);
42: // create dir with given mode
43: $success = mkdir($pathname, $mode, $recursive);
44: // reset umask to old umask
45: umask($oldumask);
46: // return success
47: return $success;
48: }
49:
50: /**
51: * Removes a dir from the filesystem
52: *
53: * @param string $dirname
54: * The path to the directory
55: * @throws cInvalidArgumentException
56: * if the dir with the given dirname does not exist
57: * @return bool
58: * Returns true on success or false on failure.
59: */
60: public static function remove($dirname) {
61: if (!self::exists($dirname)) {
62: throw new cInvalidArgumentException('The directory ' . $dirname . ' could not be accessed because it does not exist.');
63: }
64: return rmdir($dirname);
65: }
66:
67: /**
68: * Moves a dir
69: *
70: * @param string $dirname
71: * The path and name of the directory
72: * @param string $destination
73: * the destination. Note that the dir can also be renamed in the
74: * process of moving it
75: * @throws cInvalidArgumentException
76: * if the dir with the given dirname does not exist
77: * @return bool
78: * Returns true on success or false on failure.
79: */
80: public static function move($dirname, $destination) {
81: if (!self::exists($dirname)) {
82: throw new cInvalidArgumentException('The directory ' . $dirname . ' could not be accessed because it does not exist.');
83: }
84:
85: $success = rename($dirname, $destination);
86:
87: if ($success) {
88: self::setDefaultDirPerms($destination);
89: }
90:
91: return $success;
92: }
93:
94: /**
95: * Renames a dir
96: *
97: * @param string $dirname
98: * the name and path of the dir
99: * @param string $new_dirname
100: * the new name of the dir
101: */
102: public static function rename($dirname, $new_dirname) {
103: self::move($dirname, $new_dirname);
104: }
105:
106: /**
107: * Changes the dir permissions
108: *
109: * @param string $dirname
110: * the name and path of the dir
111: * @param int $mode
112: * the new access mode : php chmod needs octal value
113: * @throws cInvalidArgumentException
114: * if the dir with the given dirname does not exist
115: * @return bool
116: * Returns true on success or false on failure.
117: */
118: public static function chmod($dirname, $mode) {
119: if (!cFileHandler::exists($dirname)) {
120: throw new cInvalidArgumentException('The directory ' . $dirname . ' could not be accessed because it does not exist.');
121: }
122: // chmod needs octal value for correct execution.
123: $mode = intval($mode, 8);
124: return @chmod($dirname, $mode);
125: }
126:
127: /**
128: * Sets the default directory permissions on the given directory.
129: *
130: * @param string $dirname
131: * the name of the directory
132: * @return bool
133: * Returns true on success or false on failure.
134: */
135: public static function setDefaultDirPerms($dirname) {
136: $cfg = cRegistry::getConfig();
137: $dirPerms = $cfg['default_perms']['directory'];
138:
139: return self::chmod($dirname, $dirPerms);
140: }
141:
142: /**
143: * Deletes a directory and all of its content.
144: *
145: * @param string $dirname
146: * the name of the directory which should be deleted
147: * @throws cInvalidArgumentException
148: * if dirname is empty
149: * @return bool
150: * Returns true on success or false on failure.
151: */
152: public static function recursiveRmdir($dirname) {
153: if ($dirname == '') {
154: throw new cInvalidArgumentException('Directory name must not be empty.');
155: }
156:
157: // make sure $dirname ends with a slash
158: if (substr($dirname, -1) !== '/') {
159: $dirname .= '/';
160: }
161:
162: foreach (new DirectoryIterator($dirname) as $file) {
163: if ($file != "." && $file != "..") {
164: $file = $dirname . $file;
165: if (is_dir($file)) {
166: self::recursiveRmdir($file);
167: } else {
168: unlink($file);
169: }
170: }
171: }
172:
173: return rmdir($dirname);
174: }
175:
176: /**
177: * Copies a directory and all of its subfolders.
178: *
179: * @param string $dirname
180: * the name and path of the file
181: * @param string $destination
182: * the destination. Note that existing files get overwritten
183: * @param string $chmod [optional; default: 0777]
184: * chmod mode
185: * @throws cInvalidArgumentException
186: * if the file with the given filename does not exist
187: * @return bool
188: * true on success
189: */
190: public static function recursiveCopy($dirname, $destination, $chmod = 0777) {
191: if (!self::exists($dirname)) {
192: throw new cInvalidArgumentException('The directory ' . $dirname . ' could not be accessed because it does not exist.');
193: }
194:
195: if (!cFileHandler::exists($destination)) {
196: if (!mkdir($destination)) {
197: return false;
198: }
199: if (!self::chmod($destination, $chmod)) {
200: return false;
201: }
202: }
203:
204: foreach ($iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dirname), RecursiveIteratorIterator::SELF_FIRST) as $item) {
205: // workaround for RecursiveDirectoryIterator::SKIP_DOTS, this was
206: // not available in PHP 5.2
207: if ($item->getFilename() == '.' || $item->getFilename() == '..') {
208: continue;
209: }
210:
211: if ($item->isDir()) {
212: if (!mkdir($destination . DIRECTORY_SEPARATOR . $iterator->getSubPathName())) {
213: return false;
214: }
215: if (!self::chmod($destination . DIRECTORY_SEPARATOR . $iterator->getSubPathName(), $chmod)) {
216: return false;
217: }
218: } else {
219: if (!copy($item, $destination . DIRECTORY_SEPARATOR . $iterator->getSubPathName())) {
220: return false;
221: }
222: if (!self::chmod($destination . DIRECTORY_SEPARATOR . $iterator->getSubPathName(), $chmod)) {
223: return false;
224: }
225: }
226: }
227:
228: return true;
229: }
230:
231: /**
232: * Checks if a directory is empty
233: *
234: * @param string $dir
235: * Name of the directory
236: * @return bool
237: * true if the directory is empty
238: */
239: public static function isDirectoryEmpty($dir) {
240: if (!is_readable($dir)) {
241: return false;
242: }
243: if (is_dir($dir)) {
244: if ($handle = opendir($dir)) {
245: while (false !== ($entry = readdir($handle))) {
246: if ($entry != "." && $entry != "..") {
247: return false;
248: }
249: }
250: }
251: closedir($handle);
252: }
253: return true;
254: }
255:
256: /**
257: * This functions reads the content from given directory.
258: * Optionally options are to read the directory recursive or to list only
259: * directories.
260: *
261: * @param string $dirName
262: * directory
263: * @param bool $recursive [optional]
264: * flag to read recursive
265: * @param bool $dirOnly [optional]
266: * flag to list only directories
267: * @param bool $fileOnly [optional]
268: * flag to list only files if $dirOnly is set to false
269: * @return array|bool
270: * array containing file names as string, false on error
271: */
272: public static function read($dirname, $recursive = false, $dirOnly = false, $fileOnly = false) {
273: if (!self::exists($dirname)) {
274: return false;
275: }
276:
277: $dirContent = array();
278: if ($recursive == false) {
279: $dirHandle = opendir($dirname);
280: $dirContent = array();
281: while (false !== ($file = readdir($dirHandle))) {
282: if (!cFileHandler::fileNameIsDot($file)) {
283:
284: if ($dirOnly == true) { // get only directories
285:
286: if (is_dir($dirname . $file)) {
287: $dirContent[] = $file;
288: }
289: // bugfix: is_dir only checked file name without path, thus returning everything most of the time
290: } else if ($fileOnly === true) { // get only files
291:
292: if (is_file($dirname . $file)) {
293: $dirContent[] = $file;
294: }
295: } else { // get everything
296: $dirContent[] = $file;
297: }
298: }
299: }
300: closedir($dirHandle);
301: } else {
302: $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dirname), RecursiveIteratorIterator::SELF_FIRST);
303: foreach ($objects as $name => $file) {
304:
305: if (!cFileHandler::fileNameIsDot($file)) {
306: $fileName = str_replace("\\", "/", $file->getPathName());
307:
308: if ($dirOnly === true && is_dir($fileName)) {
309: // get only directories
310: $dirContent[] = $fileName;
311:
312: } else if ($fileOnly === true && is_file($fileName)) {
313: // get only files
314: $dirContent[] = $fileName;
315:
316: } else {
317: // get everything
318: $dirContent[] = $fileName;
319:
320: }
321: }
322: }
323: }
324:
325: return $dirContent;
326: }
327:
328: /**
329: * Checks if a directory exists
330: *
331: * @param string $dirname
332: * the name and path of the directory
333: * @return bool
334: * true if the directory exists
335: */
336: public static function exists($dirname) {
337: return is_dir($dirname);
338: }
339:
340: /**
341: * Returns the size of a directory.
342: * AKA the combined filesizes of all files within it.
343: * Note that this function uses filesize(). There could be problems with files
344: * that are larger than 2GiB
345: *
346: * @param string $dirname
347: * The directory name
348: * @param bool $recursive [optional]
349: * true if all the subdirectories should be included in the calculation
350: * @return int|bool
351: * false in case of an error or the size
352: */
353: public static function getDirectorySize($dirname, $recursive = false) {
354: $ret = 0;
355: $files = self::read($dirname, $recursive, false, true);
356: if ($files === false) {
357: return false;
358: }
359:
360: foreach ($files as $file) {
361: $temp = cFileHandler::info($dirname . $file);
362: $ret += $temp['size'];
363: }
364:
365: return $ret;
366: }
367: }
368: