Verzeichnisstruktur phpBB-3.2.0
- Veröffentlicht
- 06.01.2017
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
filesystem.php
001 <?php
002 /**
003 *
004 * This file is part of the phpBB Forum Software package.
005 *
006 * @copyright (c) phpBB Limited <https://www.phpbb.com>
007 * @license GNU General Public License, version 2 (GPL-2.0)
008 *
009 * For full copyright and license information, please see
010 * the docs/CREDITS.txt file.
011 *
012 */
013
014 namespace phpbb\filesystem;
015
016 use phpbb\filesystem\exception\filesystem_exception;
017
018 /**
019 * A class with various functions that are related to paths, files and the filesystem
020 */
021 class filesystem implements filesystem_interface
022 {
023 /**
024 * Store some information about file ownership for phpBB's chmod function
025 *
026 * @var array
027 */
028 protected $chmod_info;
029
030 /**
031 * Stores current working directory
032 *
033 * @var string|bool current working directory or false if it cannot be recovered
034 */
035 protected $working_directory;
036
037 /**
038 * Symfony's Filesystem component
039 *
040 * @var \Symfony\Component\Filesystem\Filesystem
041 */
042 protected $symfony_filesystem;
043
044 /**
045 * Constructor
046 */
047 public function __construct()
048 {
049 $this->chmod_info = array();
050 $this->symfony_filesystem = new \Symfony\Component\Filesystem\Filesystem();
051 $this->working_directory = null;
052 }
053
054 /**
055 * {@inheritdoc}
056 */
057 public function chgrp($files, $group, $recursive = false)
058 {
059 try
060 {
061 $this->symfony_filesystem->chgrp($files, $group, $recursive);
062 }
063 catch (\Symfony\Component\Filesystem\Exception\IOException $e)
064 {
065 // Try to recover filename
066 // By the time this is written that is at the end of the message
067 $error = trim($e->getMessage());
068 $file = substr($error, strrpos($error, ' '));
069
070 throw new filesystem_exception('CANNOT_CHANGE_FILE_GROUP', $file, array(), $e);
071 }
072 }
073
074 /**
075 * {@inheritdoc}
076 */
077 public function chmod($files, $perms = null, $recursive = false, $force_chmod_link = false)
078 {
079 if (is_null($perms))
080 {
081 // Default to read permission for compatibility reasons
082 $perms = self::CHMOD_READ;
083 }
084
085 // Check if we got a permission flag
086 if ($perms > self::CHMOD_ALL)
087 {
088 $file_perm = $perms;
089
090 // Extract permissions
091 //$owner = ($file_perm >> 6) & 7; // This will be ignored
092 $group = ($file_perm >> 3) & 7;
093 $other = ($file_perm >> 0) & 7;
094
095 // Does any permissions provided? if so we add execute bit for directories
096 $group = ($group !== 0) ? ($group | self::CHMOD_EXECUTE) : $group;
097 $other = ($other !== 0) ? ($other | self::CHMOD_EXECUTE) : $other;
098
099 // Compute directory permissions
100 $dir_perm = (self::CHMOD_ALL << 6) + ($group << 3) + ($other << 3);
101 }
102 else
103 {
104 // Add execute bit to owner if execute bit is among perms
105 $owner_perm = (self::CHMOD_READ | self::CHMOD_WRITE) | ($perms & self::CHMOD_EXECUTE);
106 $file_perm = ($owner_perm << 6) + ($perms << 3) + ($perms << 0);
107
108 // Compute directory permissions
109 $perm = ($perms !== 0) ? ($perms | self::CHMOD_EXECUTE) : $perms;
110 $dir_perm = (($owner_perm | self::CHMOD_EXECUTE) << 6) + ($perm << 3) + ($perm << 0);
111 }
112
113 // Symfony's filesystem component does not support extra execution flags on directories
114 // so we need to implement it again
115 foreach ($this->to_iterator($files) as $file)
116 {
117 if ($recursive && is_dir($file) && !is_link($file))
118 {
119 $this->chmod(new \FilesystemIterator($file), $perms, true);
120 }
121
122 // Don't chmod links as mostly those require 0777 and that cannot be changed
123 if (is_dir($file) || (is_link($file) && $force_chmod_link))
124 {
125 if (true !== @chmod($file, $dir_perm))
126 {
127 throw new filesystem_exception('CANNOT_CHANGE_FILE_PERMISSIONS', $file, array());
128 }
129 }
130 else if (is_file($file))
131 {
132 if (true !== @chmod($file, $file_perm))
133 {
134 throw new filesystem_exception('CANNOT_CHANGE_FILE_PERMISSIONS', $file, array());
135 }
136 }
137 }
138 }
139
140 /**
141 * {@inheritdoc}
142 */
143 public function chown($files, $user, $recursive = false)
144 {
145 try
146 {
147 $this->symfony_filesystem->chown($files, $user, $recursive);
148 }
149 catch (\Symfony\Component\Filesystem\Exception\IOException $e)
150 {
151 // Try to recover filename
152 // By the time this is written that is at the end of the message
153 $error = trim($e->getMessage());
154 $file = substr($error, strrpos($error, ' '));
155
156 throw new filesystem_exception('CANNOT_CHANGE_FILE_GROUP', $file, array(), $e);
157 }
158 }
159
160 /**
161 * {@inheritdoc}
162 */
163 public function clean_path($path)
164 {
165 $exploded = explode('/', $path);
166 $filtered = array();
167 foreach ($exploded as $part)
168 {
169 if ($part === '.' && !empty($filtered))
170 {
171 continue;
172 }
173
174 if ($part === '..' && !empty($filtered) && $filtered[sizeof($filtered) - 1] !== '.' && $filtered[sizeof($filtered) - 1] !== '..')
175 {
176 array_pop($filtered);
177 }
178 else
179 {
180 $filtered[] = $part;
181 }
182 }
183 $path = implode('/', $filtered);
184 return $path;
185 }
186
187 /**
188 * {@inheritdoc}
189 */
190 public function copy($origin_file, $target_file, $override = false)
191 {
192 try
193 {
194 $this->symfony_filesystem->copy($origin_file, $target_file, $override);
195 }
196 catch (\Symfony\Component\Filesystem\Exception\IOException $e)
197 {
198 throw new filesystem_exception('CANNOT_COPY_FILES', '', array(), $e);
199 }
200 }
201
202 /**
203 * {@inheritdoc}
204 */
205 public function dump_file($filename, $content)
206 {
207 try
208 {
209 $this->symfony_filesystem->dumpFile($filename, $content);
210 }
211 catch (\Symfony\Component\Filesystem\Exception\IOException $e)
212 {
213 throw new filesystem_exception('CANNOT_DUMP_FILE', $filename, array(), $e);
214 }
215 }
216
217 /**
218 * {@inheritdoc}
219 */
220 public function exists($files)
221 {
222 return $this->symfony_filesystem->exists($files);
223 }
224
225 /**
226 * {@inheritdoc}
227 */
228 public function is_absolute_path($path)
229 {
230 return (isset($path[0]) && $path[0] === '/' || preg_match('#^[a-z]:[/\\\]#i', $path)) ? true : false;
231 }
232
233 /**
234 * {@inheritdoc}
235 */
236 public function is_readable($files, $recursive = false)
237 {
238 foreach ($this->to_iterator($files) as $file)
239 {
240 if ($recursive && is_dir($file) && !is_link($file))
241 {
242 if (!$this->is_readable(new \FilesystemIterator($file), true))
243 {
244 return false;
245 }
246 }
247
248 if (!is_readable($file))
249 {
250 return false;
251 }
252 }
253
254 return true;
255 }
256
257 /**
258 * {@inheritdoc}
259 */
260 public function is_writable($files, $recursive = false)
261 {
262 if (defined('PHP_WINDOWS_VERSION_MAJOR') || !function_exists('is_writable'))
263 {
264 foreach ($this->to_iterator($files) as $file)
265 {
266 if ($recursive && is_dir($file) && !is_link($file))
267 {
268 if (!$this->is_writable(new \FilesystemIterator($file), true))
269 {
270 return false;
271 }
272 }
273
274 if (!$this->phpbb_is_writable($file))
275 {
276 return false;
277 }
278 }
279 }
280 else
281 {
282 // use built in is_writable
283 foreach ($this->to_iterator($files) as $file)
284 {
285 if ($recursive && is_dir($file) && !is_link($file))
286 {
287 if (!$this->is_writable(new \FilesystemIterator($file), true))
288 {
289 return false;
290 }
291 }
292
293 if (!is_writable($file))
294 {
295 return false;
296 }
297 }
298 }
299
300 return true;
301 }
302
303 /**
304 * {@inheritdoc}
305 */
306 public function make_path_relative($end_path, $start_path)
307 {
308 return $this->symfony_filesystem->makePathRelative($end_path, $start_path);
309 }
310
311 /**
312 * {@inheritdoc}
313 */
314 public function mirror($origin_dir, $target_dir, \Traversable $iterator = null, $options = array())
315 {
316 try
317 {
318 $this->symfony_filesystem->mirror($origin_dir, $target_dir, $iterator, $options);
319 }
320 catch (\Symfony\Component\Filesystem\Exception\IOException $e)
321 {
322 $msg = $e->getMessage();
323 $filename = substr($msg, strpos($msg, '"'), strrpos($msg, '"'));
324
325 throw new filesystem_exception('CANNOT_MIRROR_DIRECTORY', $filename, array(), $e);
326 }
327 }
328
329 /**
330 * {@inheritdoc}
331 */
332 public function mkdir($dirs, $mode = 0777)
333 {
334 try
335 {
336 $this->symfony_filesystem->mkdir($dirs, $mode);
337 }
338 catch (\Symfony\Component\Filesystem\Exception\IOException $e)
339 {
340 $msg = $e->getMessage();
341 $filename = substr($msg, strpos($msg, '"'), strrpos($msg, '"'));
342
343 throw new filesystem_exception('CANNOT_CREATE_DIRECTORY', $filename, array(), $e);
344 }
345 }
346
347 /**
348 * {@inheritdoc}
349 */
350 public function phpbb_chmod($files, $perms = null, $recursive = false, $force_chmod_link = false)
351 {
352 if (is_null($perms))
353 {
354 // Default to read permission for compatibility reasons
355 $perms = self::CHMOD_READ;
356 }
357
358 if (empty($this->chmod_info))
359 {
360 if (!function_exists('fileowner') || !function_exists('filegroup'))
361 {
362 $this->chmod_info['process'] = false;
363 }
364 else
365 {
366 $common_php_owner = @fileowner(__FILE__);
367 $common_php_group = @filegroup(__FILE__);
368
369 // And the owner and the groups PHP is running under.
370 $php_uid = (function_exists('posic_getuid')) ? @posix_getuid() : false;
371 $php_gids = (function_exists('posix_getgroups')) ? @posix_getgroups() : false;
372
373 // If we are unable to get owner/group, then do not try to set them by guessing
374 if (!$php_uid || empty($php_gids) || !$common_php_owner || !$common_php_group)
375 {
376 $this->chmod_info['process'] = false;
377 }
378 else
379 {
380 $this->chmod_info = array(
381 'process' => true,
382 'common_owner' => $common_php_owner,
383 'common_group' => $common_php_group,
384 'php_uid' => $php_uid,
385 'php_gids' => $php_gids,
386 );
387 }
388 }
389 }
390
391 if ($this->chmod_info['process'])
392 {
393 try
394 {
395 foreach ($this->to_iterator($files) as $file)
396 {
397 $file_uid = @fileowner($file);
398 $file_gid = @filegroup($file);
399
400 // Change owner
401 if ($file_uid !== $this->chmod_info['common_owner'])
402 {
403 $this->chown($file, $this->chmod_info['common_owner'], $recursive);
404 }
405
406 // Change group
407 if ($file_gid !== $this->chmod_info['common_group'])
408 {
409 $this->chgrp($file, $this->chmod_info['common_group'], $recursive);
410 }
411
412 clearstatcache();
413 $file_uid = @fileowner($file);
414 $file_gid = @filegroup($file);
415 }
416 }
417 catch (filesystem_exception $e)
418 {
419 $this->chmod_info['process'] = false;
420 }
421 }
422
423 // Still able to process?
424 if ($this->chmod_info['process'])
425 {
426 if ($file_uid === $this->chmod_info['php_uid'])
427 {
428 $php = 'owner';
429 }
430 else if (in_array($file_gid, $this->chmod_info['php_gids']))
431 {
432 $php = 'group';
433 }
434 else
435 {
436 // Since we are setting the everyone bit anyway, no need to do expensive operations
437 $this->chmod_info['process'] = false;
438 }
439 }
440
441 // We are not able to determine or change something
442 if (!$this->chmod_info['process'])
443 {
444 $php = 'other';
445 }
446
447 switch ($php)
448 {
449 case 'owner':
450 try
451 {
452 $this->chmod($files, $perms, $recursive, $force_chmod_link);
453 clearstatcache();
454 if ($this->is_readable($files) && $this->is_writable($files))
455 {
456 break;
457 }
458 }
459 catch (filesystem_exception $e)
460 {
461 // Do nothing
462 }
463 case 'group':
464 try
465 {
466 $this->chmod($files, $perms, $recursive, $force_chmod_link);
467 clearstatcache();
468 if ((!($perms & self::CHMOD_READ) || $this->is_readable($files, $recursive)) && (!($perms & self::CHMOD_WRITE) || $this->is_writable($files, $recursive)))
469 {
470 break;
471 }
472 }
473 catch (filesystem_exception $e)
474 {
475 // Do nothing
476 }
477 case 'other':
478 default:
479 $this->chmod($files, $perms, $recursive, $force_chmod_link);
480 break;
481 }
482 }
483
484 /**
485 * {@inheritdoc}
486 */
487 public function realpath($path)
488 {
489 if (!function_exists('realpath'))
490 {
491 return $this->phpbb_own_realpath($path);
492 }
493
494 $realpath = realpath($path);
495
496 // Strangely there are provider not disabling realpath but returning strange values. :o
497 // We at least try to cope with them.
498 if ((!$this->is_absolute_path($path) && $realpath === $path) || $realpath === false)
499 {
500 return $this->phpbb_own_realpath($path);
501 }
502
503 // Check for DIRECTORY_SEPARATOR at the end (and remove it!)
504 if (substr($realpath, -1) === DIRECTORY_SEPARATOR)
505 {
506 $realpath = substr($realpath, 0, -1);
507 }
508
509 return $realpath;
510 }
511
512 /**
513 * {@inheritdoc}
514 */
515 public function remove($files)
516 {
517 try
518 {
519 $this->symfony_filesystem->remove($files);
520 }
521 catch (\Symfony\Component\Filesystem\Exception\IOException $e)
522 {
523 // Try to recover filename
524 // By the time this is written that is at the end of the message
525 $error = trim($e->getMessage());
526 $file = substr($error, strrpos($error, ' '));
527
528 throw new filesystem_exception('CANNOT_DELETE_FILES', $file, array(), $e);
529 }
530 }
531
532 /**
533 * {@inheritdoc}
534 */
535 public function rename($origin, $target, $overwrite = false)
536 {
537 try
538 {
539 $this->symfony_filesystem->rename($origin, $target, $overwrite);
540 }
541 catch (\Symfony\Component\Filesystem\Exception\IOException $e)
542 {
543 $msg = $e->getMessage();
544 $filename = substr($msg, strpos($msg, '"'), strrpos($msg, '"'));
545
546 throw new filesystem_exception('CANNOT_RENAME_FILE', $filename, array(), $e);
547 }
548 }
549
550 /**
551 * {@inheritdoc}
552 */
553 public function symlink($origin_dir, $target_dir, $copy_on_windows = false)
554 {
555 try
556 {
557 $this->symfony_filesystem->symlink($origin_dir, $target_dir, $copy_on_windows);
558 }
559 catch (\Symfony\Component\Filesystem\Exception\IOException $e)
560 {
561 throw new filesystem_exception('CANNOT_CREATE_SYMLINK', $origin_dir, array(), $e);
562 }
563 }
564
565 /**
566 * {@inheritdoc}
567 */
568 public function touch($files, $time = null, $access_time = null)
569 {
570 try
571 {
572 $this->symfony_filesystem->touch($files, $time, $access_time);
573 }
574 catch (\Symfony\Component\Filesystem\Exception\IOException $e)
575 {
576 // Try to recover filename
577 // By the time this is written that is at the end of the message
578 $error = trim($e->getMessage());
579 $file = substr($error, strrpos($error, ' '));
580
581 throw new filesystem_exception('CANNOT_TOUCH_FILES', $file, array(), $e);
582 }
583 }
584
585 /**
586 * phpBB's implementation of is_writable
587 *
588 * @todo Investigate if is_writable is still buggy
589 *
590 * @param string $file file/directory to check if writable
591 *
592 * @return bool true if the given path is writable
593 */
594 protected function phpbb_is_writable($file)
595 {
596 if (file_exists($file))
597 {
598 // Canonicalise path to absolute path
599 $file = $this->realpath($file);
600
601 if (is_dir($file))
602 {
603 // Test directory by creating a file inside the directory
604 $result = @tempnam($file, 'i_w');
605
606 if (is_string($result) && file_exists($result))
607 {
608 unlink($result);
609
610 // Ensure the file is actually in the directory (returned realpathed)
611 return (strpos($result, $file) === 0) ? true : false;
612 }
613 }
614 else
615 {
616 $handle = @fopen($file, 'c');
617
618 if (is_resource($handle))
619 {
620 fclose($handle);
621 return true;
622 }
623 }
624 }
625 else
626 {
627 // file does not exist test if we can write to the directory
628 $dir = dirname($file);
629
630 if (file_exists($dir) && is_dir($dir) && $this->phpbb_is_writable($dir))
631 {
632 return true;
633 }
634 }
635
636 return false;
637 }
638
639 /**
640 * Try to resolve real path when PHP's realpath failes to do so
641 *
642 * @param string $path
643 * @return bool|string
644 */
645 protected function phpbb_own_realpath($path)
646 {
647 // Replace all directory separators with '/'
648 $path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
649
650 $is_absolute_path = false;
651 $path_prefix = '';
652
653 if ($this->is_absolute_path($path))
654 {
655 $is_absolute_path = true;
656 }
657 else
658 {
659 // Resolve working directory and store it
660 if (is_null($this->working_directory))
661 {
662 if (function_exists('getcwd'))
663 {
664 $this->working_directory = str_replace(DIRECTORY_SEPARATOR, '/', getcwd());
665 }
666
667 //
668 // From this point on we really just guessing
669 // If chdir were called we screwed
670 //
671 else if (function_exists('debug_backtrace'))
672 {
673 $call_stack = debug_backtrace(0);
674 $this->working_directory = str_replace(DIRECTORY_SEPARATOR, '/', dirname($call_stack[sizeof($call_stack) - 1]['file']));
675 }
676 else
677 {
678 //
679 // Assuming that the working directory is phpBB root
680 // we could use this as a fallback, when phpBB will use controllers
681 // everywhere this will be a safe assumption
682 //
683 //$dir_parts = explode(DIRECTORY_SEPARATOR, __DIR__);
684 //$namespace_parts = explode('\\', trim(__NAMESPACE__, '\\'));
685
686 //$namespace_part_count = sizeof($namespace_parts);
687
688 // Check if we still loading from root
689 //if (array_slice($dir_parts, -$namespace_part_count) === $namespace_parts)
690 //{
691 // $this->working_directory = implode('/', array_slice($dir_parts, 0, -$namespace_part_count));
692 //}
693 //else
694 //{
695 // $this->working_directory = false;
696 //}
697
698 $this->working_directory = false;
699 }
700 }
701
702 if ($this->working_directory !== false)
703 {
704 $is_absolute_path = true;
705 $path = $this->working_directory . '/' . $path;
706 }
707 }
708
709 if ($is_absolute_path)
710 {
711 if (defined('PHP_WINDOWS_VERSION_MAJOR'))
712 {
713 $path_prefix = $path[0] . ':';
714 $path = substr($path, 2);
715 }
716 else
717 {
718 $path_prefix = '';
719 }
720 }
721
722 $resolved_path = $this->resolve_path($path, $path_prefix, $is_absolute_path);
723 if ($resolved_path === false)
724 {
725 return false;
726 }
727
728 if (!@file_exists($resolved_path) || (!@is_dir($resolved_path . '/') && !is_file($resolved_path)))
729 {
730 return false;
731 }
732
733 // Return OS specific directory separators
734 $resolved = str_replace('/', DIRECTORY_SEPARATOR, $resolved_path);
735
736 // Check for DIRECTORY_SEPARATOR at the end (and remove it!)
737 if (substr($resolved, -1) === DIRECTORY_SEPARATOR)
738 {
739 return substr($resolved, 0, -1);
740 }
741
742 return $resolved;
743 }
744
745 /**
746 * Convert file(s) to \Traversable object
747 *
748 * This is the same function as Symfony's toIterator, but that is private
749 * so we cannot use it.
750 *
751 * @param string|array|\Traversable $files filename/list of filenames
752 * @return \Traversable
753 */
754 protected function to_iterator($files)
755 {
756 if (!$files instanceof \Traversable)
757 {
758 $files = new \ArrayObject(is_array($files) ? $files : array($files));
759 }
760
761 return $files;
762 }
763
764 /**
765 * Try to resolve symlinks in path
766 *
767 * @param string $path The path to resolve
768 * @param string $prefix The path prefix (on windows the drive letter)
769 * @param bool $absolute Whether or not the path is absolute
770 * @param bool $return_array Whether or not to return path parts
771 *
772 * @return string|array|bool returns the resolved path or an array of parts of the path if $return_array is true
773 * or false if path cannot be resolved
774 */
775 protected function resolve_path($path, $prefix = '', $absolute = false, $return_array = false)
776 {
777 if ($return_array)
778 {
779 $path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
780 }
781
782 trim ($path, '/');
783 $path_parts = explode('/', $path);
784 $resolved = array();
785 $resolved_path = $prefix;
786 $file_found = false;
787
788 foreach ($path_parts as $path_part)
789 {
790 if ($file_found)
791 {
792 return false;
793 }
794
795 if (empty($path_part) || ($path_part === '.' && ($absolute || !empty($resolved))))
796 {
797 continue;
798 }
799 else if ($absolute && $path_part === '..')
800 {
801 if (empty($resolved))
802 {
803 // No directories above root
804 return false;
805 }
806
807 array_pop($resolved);
808 $resolved_path = false;
809 }
810 else if ($path_part === '..' && !empty($resolved) && !in_array($resolved[sizeof($resolved) - 1], array('.', '..')))
811 {
812 array_pop($resolved);
813 $resolved_path = false;
814 }
815 else
816 {
817 if ($resolved_path === false)
818 {
819 if (empty($resolved))
820 {
821 $resolved_path = ($absolute) ? $prefix . '/' . $path_part : $path_part;
822 }
823 else
824 {
825 $tmp_array = $resolved;
826 if ($absolute)
827 {
828 array_unshift($tmp_array, $prefix);
829 }
830
831 $resolved_path = implode('/', $tmp_array);
832 }
833 }
834
835 $current_path = $resolved_path . '/' . $path_part;
836
837 // Resolve symlinks
838 if (is_link($current_path))
839 {
840 if (!function_exists('readlink'))
841 {
842 return false;
843 }
844
845 $link = readlink($current_path);
846
847 // Is link has an absolute path in it?
848 if ($this->is_absolute_path($link))
849 {
850 if (defined('PHP_WINDOWS_VERSION_MAJOR'))
851 {
852 $prefix = $link[0] . ':';
853 $link = substr($link, 2);
854 }
855 else
856 {
857 $prefix = '';
858 }
859
860 $resolved = $this->resolve_path($link, $prefix, true, true);
861 $absolute = true;
862 }
863 else
864 {
865 $resolved = $this->resolve_path($resolved_path . '/' . $link, $prefix, $absolute, true);
866 }
867
868 if (!$resolved)
869 {
870 return false;
871 }
872
873 $resolved_path = false;
874 }
875 else if (is_dir($current_path . '/'))
876 {
877 $resolved[] = $path_part;
878 $resolved_path = $current_path;
879 }
880 else if (is_file($current_path))
881 {
882 $resolved[] = $path_part;
883 $resolved_path = $current_path;
884 $file_found = true;
885 }
886 else
887 {
888 return false;
889 }
890 }
891 }
892
893 // If at the end of the path there were a .. or .
894 // we need to build the path again.
895 // Only doing this when a string is expected in return
896 if ($resolved_path === false && $return_array === false)
897 {
898 if (empty($resolved))
899 {
900 $resolved_path = ($absolute) ? $prefix . '/' : './';
901 }
902 else
903 {
904 $tmp_array = $resolved;
905 if ($absolute)
906 {
907 array_unshift($tmp_array, $prefix);
908 }
909
910 $resolved_path = implode('/', $tmp_array);
911 }
912 }
913
914 return ($return_array) ? $resolved : $resolved_path;
915 }
916 }
917