1: | <?php
|
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: | class XoopsFolderHandler
|
53: | {
|
54: | |
55: | |
56: | |
57: | |
58: | |
59: |
|
60: | public $path;
|
61: |
|
62: | |
63: | |
64: | |
65: | |
66: | |
67: |
|
68: | public $sort = false;
|
69: |
|
70: | |
71: | |
72: | |
73: | |
74: | |
75: |
|
76: | public $mode = '0755';
|
77: |
|
78: | |
79: | |
80: | |
81: | |
82: | |
83: |
|
84: | public $messages = array();
|
85: |
|
86: | |
87: | |
88: | |
89: | |
90: | |
91: |
|
92: | public $errors = array();
|
93: |
|
94: | |
95: | |
96: | |
97: | |
98: | |
99: |
|
100: | public $directories;
|
101: |
|
102: | |
103: | |
104: | |
105: | |
106: | |
107: |
|
108: | public $files;
|
109: |
|
110: | |
111: | |
112: | |
113: | |
114: | |
115: | |
116: |
|
117: | public function __construct($path = false, $create = true, $mode = false)
|
118: | {
|
119: | if (empty($path)) {
|
120: | $path = XOOPS_VAR_PATH . '/caches/xoops_cache';
|
121: | }
|
122: | if ($mode) {
|
123: | $this->mode = intval($mode, 8);
|
124: | }
|
125: | if (!file_exists($path) && $create == true) {
|
126: | $this->create($path, $this->mode);
|
127: | }
|
128: | if (!$this->isAbsolute($path)) {
|
129: | $path = realpath($path);
|
130: | }
|
131: | $this->cd($path);
|
132: | }
|
133: |
|
134: | |
135: | |
136: | |
137: | |
138: | |
139: |
|
140: | public function pwd()
|
141: | {
|
142: | return $this->path;
|
143: | }
|
144: |
|
145: | |
146: | |
147: | |
148: | |
149: | |
150: | |
151: | |
152: |
|
153: | public function cd($path)
|
154: | {
|
155: | $path = $this->realpath($path);
|
156: | if (is_string($path) && is_dir($path) && file_exists($path)) {
|
157: | return $this->path = $path;
|
158: | }
|
159: |
|
160: | return false;
|
161: | }
|
162: |
|
163: | |
164: | |
165: | |
166: | |
167: | |
168: | |
169: | |
170: | |
171: | |
172: |
|
173: | public function read($sort = true, $exceptions = false)
|
174: | {
|
175: | $dirs = $files = array();
|
176: | $dir = opendir($this->path);
|
177: | if ($dir !== false) {
|
178: | while (false !== ($n = readdir($dir))) {
|
179: | $item = false;
|
180: | if (is_array($exceptions)) {
|
181: | if (!in_array($n, $exceptions)) {
|
182: | $item = $n;
|
183: | }
|
184: | } else {
|
185: | if ((!preg_match('/^\\.+$/', $n) && $exceptions === false) || ($exceptions === true && !preg_match('/^\\.(.*)$/', $n))) {
|
186: | $item = $n;
|
187: | }
|
188: | }
|
189: | if ($item !== false) {
|
190: | if (is_dir($this->addPathElement($this->path, $item))) {
|
191: | $dirs[] = $item;
|
192: | } else {
|
193: | $files[] = $item;
|
194: | }
|
195: | }
|
196: | }
|
197: | if ($sort || $this->sort) {
|
198: | sort($dirs);
|
199: | sort($files);
|
200: | }
|
201: | closedir($dir);
|
202: | }
|
203: |
|
204: | return array(
|
205: | $dirs,
|
206: | $files);
|
207: | }
|
208: |
|
209: | |
210: | |
211: | |
212: | |
213: | |
214: | |
215: | |
216: | |
217: |
|
218: | public function find($regexp_pattern = '.*', $sort = false)
|
219: | {
|
220: | $data = $this->read($sort);
|
221: | if (!is_array($data)) {
|
222: | return array();
|
223: | }
|
224: | list($dirs, $files) = $data;
|
225: | $found = array();
|
226: | foreach ($files as $file) {
|
227: | if (preg_match("/^{$regexp_pattern}$/i", $file)) {
|
228: | $found[] = $file;
|
229: | }
|
230: | }
|
231: |
|
232: | return $found;
|
233: | }
|
234: |
|
235: | |
236: | |
237: | |
238: | |
239: | |
240: | |
241: | |
242: | |
243: |
|
244: | public function findRecursive($pattern = '.*', $sort = false)
|
245: | {
|
246: | $startsOn = $this->path;
|
247: | $out = $this->_findRecursive($pattern, $sort);
|
248: | $this->cd($startsOn);
|
249: |
|
250: | return $out;
|
251: | }
|
252: |
|
253: | |
254: | |
255: | |
256: | |
257: | |
258: | |
259: | |
260: | |
261: |
|
262: | public function _findRecursive($pattern, $sort = false)
|
263: | {
|
264: | list($dirs, $files) = $this->read($sort);
|
265: | $found = array();
|
266: | foreach ($files as $file) {
|
267: | if (preg_match("/^{$pattern}$/i", $file)) {
|
268: | $found[] = $this->addPathElement($this->path, $file);
|
269: | }
|
270: | }
|
271: | $start = $this->path;
|
272: | foreach ($dirs as $dir) {
|
273: | $this->cd($this->addPathElement($start, $dir));
|
274: | $newFound = $this->findRecursive($pattern);
|
275: |
|
276: | foreach ($newFound as $item) {
|
277: | $found[] = $item;
|
278: | }
|
279: | }
|
280: |
|
281: | return $found;
|
282: | }
|
283: |
|
284: | |
285: | |
286: | |
287: | |
288: | |
289: | |
290: | |
291: | |
292: |
|
293: | public function isWindowsPath($path)
|
294: | {
|
295: | if (preg_match('/^[A-Z]:\\\\/i', (string)$path)) {
|
296: | return true;
|
297: | }
|
298: |
|
299: | return false;
|
300: | }
|
301: |
|
302: | |
303: | |
304: | |
305: | |
306: | |
307: | |
308: | |
309: | |
310: |
|
311: | public function isAbsolute($path)
|
312: | {
|
313: | $match = preg_match('/^\\//', $path) || preg_match('/^[A-Z]:\\//i', $path);
|
314: |
|
315: | return $match;
|
316: | }
|
317: |
|
318: | |
319: | |
320: | |
321: | |
322: | |
323: | |
324: | |
325: | |
326: |
|
327: | public function normalizePath($path)
|
328: | {
|
329: | if ($this->isWindowsPath($path)) {
|
330: | return '\\';
|
331: | }
|
332: |
|
333: | return '/';
|
334: | }
|
335: |
|
336: | |
337: | |
338: | |
339: | |
340: | |
341: | |
342: | |
343: | |
344: |
|
345: | public function correctSlashFor($path)
|
346: | {
|
347: | if ($this->isWindowsPath($path)) {
|
348: | return '\\';
|
349: | }
|
350: |
|
351: | return '/';
|
352: | }
|
353: |
|
354: | |
355: | |
356: | |
357: | |
358: | |
359: | |
360: | |
361: | |
362: |
|
363: | public function slashTerm($path)
|
364: | {
|
365: | if ($this->isSlashTerm($path)) {
|
366: | return $path;
|
367: | }
|
368: |
|
369: | return $path . $this->correctSlashFor($path);
|
370: | }
|
371: |
|
372: | |
373: | |
374: | |
375: | |
376: | |
377: | |
378: | |
379: | |
380: | |
381: |
|
382: | public function addPathElement($path, $element)
|
383: | {
|
384: | return $this->slashTerm($path) . $element;
|
385: | }
|
386: |
|
387: | |
388: | |
389: | |
390: | |
391: | |
392: | |
393: | |
394: |
|
395: | public function inXoopsPath($path = '')
|
396: | {
|
397: | $dir = substr($this->slashTerm(XOOPS_ROOT_PATH), 0, -1);
|
398: | $newdir = $dir . $path;
|
399: |
|
400: | return $this->inPath($newdir);
|
401: | }
|
402: |
|
403: | |
404: | |
405: | |
406: | |
407: | |
408: | |
409: | |
410: | |
411: |
|
412: | public function inPath($path = '', $reverse = false)
|
413: | {
|
414: | $dir = $this->slashTerm($path);
|
415: | $current = $this->slashTerm($this->pwd());
|
416: | if (!$reverse) {
|
417: | $return = preg_match('/^(.*)' . preg_quote($dir, '/') . '(.*)/', $current);
|
418: | } else {
|
419: | $return = preg_match('/^(.*)' . preg_quote($current, '/') . '(.*)/', $dir);
|
420: | }
|
421: | if ($return == 1) {
|
422: | return true;
|
423: | } else {
|
424: | return false;
|
425: | }
|
426: | }
|
427: |
|
428: | |
429: | |
430: | |
431: | |
432: | |
433: | |
434: | |
435: | |
436: | |
437: | |
438: |
|
439: | public function chmod($path, $mode = false, $recursive = true, $exceptions = array())
|
440: | {
|
441: | if (!$mode) {
|
442: | $mode = $this->mode;
|
443: | }
|
444: | if ($recursive === false && is_dir($path)) {
|
445: | if (chmod($path, intval($mode, 8))) {
|
446: | $this->messages[] = sprintf('%s changed to %s', $path, $mode);
|
447: |
|
448: | return true;
|
449: | } else {
|
450: | $this->errors[] = sprintf('%s NOT changed to %s', $path, $mode);
|
451: |
|
452: | return false;
|
453: | }
|
454: | }
|
455: | if (is_dir($path)) {
|
456: | list($paths) = $this->tree($path);
|
457: | foreach ($paths as $key => $fullpath) {
|
458: | $check = explode('/', $fullpath);
|
459: | $count = count($check);
|
460: |
|
461: | if (in_array($check[$count - 1], $exceptions)) {
|
462: | continue;
|
463: | }
|
464: |
|
465: | if (chmod($fullpath, intval($mode, 8))) {
|
466: | $this->messages[] = sprintf('%s changed to %s', $fullpath, $mode);
|
467: | } else {
|
468: | $this->errors[] = sprintf('%s NOT changed to %s', $fullpath, $mode);
|
469: | }
|
470: | }
|
471: | if (empty($this->errors)) {
|
472: | return true;
|
473: | }
|
474: | }
|
475: |
|
476: | return false;
|
477: | }
|
478: |
|
479: | |
480: | |
481: | |
482: | |
483: | |
484: | |
485: | |
486: | |
487: | |
488: |
|
489: | public function tree($path, $hidden = true, $type = null)
|
490: | {
|
491: | $path = rtrim($path, '/');
|
492: | $this->files = array();
|
493: | $this->directories = array(
|
494: | $path);
|
495: | $directories = array();
|
496: | while (count($this->directories)) {
|
497: | $dir = array_pop($this->directories);
|
498: | $this->_tree($dir, $hidden);
|
499: | $directories[] = $dir;
|
500: | }
|
501: | if ($type === null) {
|
502: | return array(
|
503: | $directories,
|
504: | $this->files);
|
505: | }
|
506: | if ($type === 'dir') {
|
507: | return $directories;
|
508: | }
|
509: |
|
510: | return $this->files;
|
511: | }
|
512: |
|
513: | |
514: | |
515: | |
516: | |
517: | |
518: | |
519: | |
520: | |
521: |
|
522: | public function _tree($path, $hidden)
|
523: | {
|
524: | if (is_dir($path)) {
|
525: | $dirHandle = opendir($path);
|
526: | while (false !== ($item = readdir($dirHandle))) {
|
527: | $found = false;
|
528: | if (($hidden === true && $item !== '.' && $item !== '..') || ($hidden === false && !preg_match('/^\\.(.*)$/', $item))) {
|
529: | $found = $path . '/' . $item;
|
530: | }
|
531: | if ($found !== false) {
|
532: | if (is_dir($found)) {
|
533: | $this->directories[] = $found;
|
534: | } else {
|
535: | $this->files[] = $found;
|
536: | }
|
537: | }
|
538: | }
|
539: | closedir($dirHandle);
|
540: | }
|
541: | }
|
542: |
|
543: | |
544: | |
545: | |
546: | |
547: | |
548: | |
549: | |
550: | |
551: |
|
552: | public function create($pathname, $mode = false)
|
553: | {
|
554: | if (is_dir($pathname) || empty($pathname)) {
|
555: | return true;
|
556: | }
|
557: | if (!$mode) {
|
558: | $mode = $this->mode;
|
559: | }
|
560: | if (is_file($pathname)) {
|
561: | $this->errors[] = sprintf('%s is a file', $pathname);
|
562: |
|
563: | return true;
|
564: | }
|
565: | $nextPathname = substr($pathname, 0, strrpos($pathname, '/'));
|
566: | if ($this->create($nextPathname, $mode)) {
|
567: | if (!file_exists($pathname)) {
|
568: | if (mkdir($pathname, intval($mode, 8))) {
|
569: | $this->messages[] = sprintf('%s created', $pathname);
|
570: |
|
571: | return true;
|
572: | } else {
|
573: | $this->errors[] = sprintf('%s NOT created', $pathname);
|
574: |
|
575: | return false;
|
576: | }
|
577: | }
|
578: | }
|
579: |
|
580: | return true;
|
581: | }
|
582: |
|
583: | |
584: | |
585: | |
586: | |
587: | |
588: |
|
589: | public function dirsize()
|
590: | {
|
591: | $size = 0;
|
592: | $directory = $this->slashTerm($this->path);
|
593: | $stack = array($directory);
|
594: | $count = count($stack);
|
595: | for ($i = 0, $j = $count; $i < $j; ++$i) {
|
596: | if (is_file($stack[$i])) {
|
597: | $size += filesize($stack[$i]);
|
598: | } else {
|
599: | if (is_dir($stack[$i])) {
|
600: | $dir = dir($stack[$i]);
|
601: | if ($dir) {
|
602: | while (false !== ($entry = $dir->read())) {
|
603: | if ($entry === '.' || $entry === '..') {
|
604: | continue;
|
605: | }
|
606: | $add = $stack[$i] . $entry;
|
607: | if (is_dir($stack[$i] . $entry)) {
|
608: | $add = $this->slashTerm($add);
|
609: | }
|
610: | $stack[] = $add;
|
611: | }
|
612: | $dir->close();
|
613: | }
|
614: | }
|
615: | }
|
616: | $j = count($stack);
|
617: | }
|
618: |
|
619: | return $size;
|
620: | }
|
621: |
|
622: | |
623: | |
624: | |
625: | |
626: | |
627: | |
628: | |
629: |
|
630: | public function delete($path)
|
631: | {
|
632: | $path = $this->slashTerm($path);
|
633: | if (is_dir($path) === true) {
|
634: | $files = glob($path . '*', GLOB_NOSORT);
|
635: | $normal_files = glob($path . '*');
|
636: | $hidden_files = glob($path . '\.?*');
|
637: | $files = array_merge($normal_files, $hidden_files);
|
638: | if (is_array($files)) {
|
639: | foreach ($files as $file) {
|
640: | if (preg_match("/(\.|\.\.)$/", $file)) {
|
641: | continue;
|
642: | }
|
643: | if (is_file($file) === true) {
|
644: | if (unlink($file)) {
|
645: | $this->messages[] = sprintf('%s removed', $path);
|
646: | } else {
|
647: | $this->errors[] = sprintf('%s NOT removed', $path);
|
648: | }
|
649: | } else {
|
650: | if (is_dir($file) === true) {
|
651: | if ($this->delete($file) === false) {
|
652: | return false;
|
653: | }
|
654: | }
|
655: | }
|
656: | }
|
657: | }
|
658: | $path = substr($path, 0, strlen($path) - 1);
|
659: | if (rmdir($path) === false) {
|
660: | $this->errors[] = sprintf('%s NOT removed', $path);
|
661: |
|
662: | return false;
|
663: | } else {
|
664: | $this->messages[] = sprintf('%s removed', $path);
|
665: | }
|
666: | }
|
667: |
|
668: | return true;
|
669: | }
|
670: |
|
671: | |
672: | |
673: | |
674: | |
675: | |
676: | |
677: |
|
678: | public function copy($options = array())
|
679: | {
|
680: | $to = null;
|
681: | if (is_string($options)) {
|
682: | $to = $options;
|
683: | $options = array();
|
684: | }
|
685: | $options = array_merge(array(
|
686: | 'to' => $to,
|
687: | 'from' => $this->path,
|
688: | 'mode' => $this->mode,
|
689: | 'skip' => array()), $options);
|
690: |
|
691: | $fromDir = $options['from'];
|
692: | $toDir = $options['to'];
|
693: | $mode = $options['mode'];
|
694: | if (!$this->cd($fromDir)) {
|
695: | $this->errors[] = sprintf('%s not found', $fromDir);
|
696: |
|
697: | return false;
|
698: | }
|
699: | if (!is_dir($toDir)) {
|
700: | mkdir($toDir, $mode);
|
701: | }
|
702: | if (!is_writable($toDir)) {
|
703: | $this->errors[] = sprintf('%s not writable', $toDir);
|
704: |
|
705: | return false;
|
706: | }
|
707: | $exceptions = array_merge(array(
|
708: | '.',
|
709: | '..',
|
710: | '.svn'), $options['skip']);
|
711: | $handle = opendir($fromDir);
|
712: | if ($handle) {
|
713: | while (false !== ($item = readdir($handle))) {
|
714: | if (!in_array($item, $exceptions)) {
|
715: | $from = $this->addPathElement($fromDir, $item);
|
716: | $to = $this->addPathElement($toDir, $item);
|
717: | if (is_file($from)) {
|
718: | if (copy($from, $to)) {
|
719: | chmod($to, intval($mode, 8));
|
720: | touch($to, filemtime($from));
|
721: | $this->messages[] = sprintf('%s copied to %s', $from, $to);
|
722: | } else {
|
723: | $this->errors[] = sprintf('%s NOT copied to %s', $from, $to);
|
724: | }
|
725: | }
|
726: |
|
727: | if (is_dir($from)) {
|
728: | if (!is_dir($to)) {
|
729: | if (mkdir($to, intval($mode, 8)) || is_dir($to)) {
|
730: | chmod($to, intval($mode, 8));
|
731: | $this->messages[] = sprintf('%s created', $to);
|
732: |
|
733: | $options['to'] = $to;
|
734: | $options['from'] = $from;
|
735: |
|
736: | $this->copy($options);
|
737: | } else {
|
738: |
|
739: | if (is_array($this->errors)) {
|
740: | $this->errors[] = sprintf('%s not created', $to);
|
741: | }
|
742: | }
|
743: | }
|
744: | }
|
745: | }
|
746: | }
|
747: | closedir($handle);
|
748: | } else {
|
749: | return false;
|
750: | }
|
751: | if (!empty($this->errors)) {
|
752: | return false;
|
753: | }
|
754: |
|
755: | return true;
|
756: | }
|
757: |
|
758: | |
759: | |
760: | |
761: | |
762: | |
763: | |
764: | |
765: |
|
766: | public function move($options)
|
767: | {
|
768: | $to = null;
|
769: | if (is_string($options)) {
|
770: | $to = $options;
|
771: | $options = (array)$options;
|
772: | }
|
773: | $options = array_merge(array(
|
774: | 'to' => $to,
|
775: | 'from' => $this->path,
|
776: | 'mode' => $this->mode,
|
777: | 'skip' => array()), $options);
|
778: | if ($this->copy($options)) {
|
779: | if ($this->delete($options['from'])) {
|
780: | return $this->cd($options['to']);
|
781: | }
|
782: | }
|
783: |
|
784: | return false;
|
785: | }
|
786: |
|
787: | |
788: | |
789: | |
790: | |
791: | |
792: |
|
793: | public function messages()
|
794: | {
|
795: | return $this->messages;
|
796: | }
|
797: |
|
798: | |
799: | |
800: | |
801: | |
802: | |
803: |
|
804: | public function errors()
|
805: | {
|
806: | return $this->errors;
|
807: | }
|
808: |
|
809: | |
810: | |
811: | |
812: | |
813: | |
814: | |
815: |
|
816: | public function realpath($path)
|
817: | {
|
818: | $path = trim($path);
|
819: | if (strpos($path, '..') === false) {
|
820: | if (!$this->isAbsolute($path)) {
|
821: | $path = $this->addPathElement($this->path, $path);
|
822: | }
|
823: |
|
824: | return $path;
|
825: | }
|
826: | $parts = explode('/', $path);
|
827: | $newparts = array();
|
828: | $newpath = $path[0] === '/' ? '/' : '';
|
829: | while (($part = array_shift($parts)) !== null) {
|
830: | if ($part === '.' || $part == '') {
|
831: | continue;
|
832: | }
|
833: | if ($part === '..') {
|
834: | if (count($newparts) > 0) {
|
835: | array_pop($newparts);
|
836: | continue;
|
837: | } else {
|
838: | return false;
|
839: | }
|
840: | }
|
841: | $newparts[] = $part;
|
842: | }
|
843: | $newpath .= implode('/', $newparts);
|
844: | if ((strlen($path) > 1) && $path[strlen($path) - 1] === '/') {
|
845: | $newpath .= '/';
|
846: | }
|
847: |
|
848: | return $newpath;
|
849: | }
|
850: |
|
851: | |
852: | |
853: | |
854: | |
855: | |
856: | |
857: | |
858: | |
859: |
|
860: | public function isSlashTerm($path)
|
861: | {
|
862: | if (preg_match('/[\/\\\]$/', (string)$path)) {
|
863: | return true;
|
864: | }
|
865: |
|
866: | return false;
|
867: | }
|
868: | }
|
869: | |