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