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.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

filesystem.php

Zuletzt modifiziert: 09.10.2024, 12:52 - Dateigröße: 20.69 KiB


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