[ Index ]

PHP Cross Reference of phpBB-3.3.0-deutsch

title

Body

[close]

/phpbb/filesystem/ -> filesystem.php (source)

   1  <?php
   2  /**
   3   *
   4   * This file is part of the phpBB Forum Software package.
   5   *
   6   * @copyright (c) phpBB Limited <https://www.phpbb.com>
   7   * @license GNU General Public License, version 2 (GPL-2.0)
   8   *
   9   * For full copyright and license information, please see
  10   * the docs/CREDITS.txt file.
  11   *
  12   */
  13  
  14  namespace phpbb\filesystem;
  15  
  16  use phpbb\filesystem\exception\filesystem_exception;
  17  
  18  /**
  19   * A class with various functions that are related to paths, files and the filesystem
  20   */
  21  class filesystem implements filesystem_interface
  22  {
  23      /**
  24       * Store some information about file ownership for phpBB's chmod function
  25       *
  26       * @var array
  27       */
  28      protected $chmod_info;
  29  
  30      /**
  31       * Stores current working directory
  32       *
  33       * @var string|bool        current working directory or false if it cannot be recovered
  34       */
  35      protected $working_directory;
  36  
  37      /**
  38       * Symfony's Filesystem component
  39       *
  40       * @var \Symfony\Component\Filesystem\Filesystem
  41       */
  42      protected $symfony_filesystem;
  43  
  44      /**
  45       * Constructor
  46       */
  47  	public function __construct()
  48      {
  49          $this->chmod_info            = array();
  50          $this->symfony_filesystem    = new \Symfony\Component\Filesystem\Filesystem();
  51          $this->working_directory    = null;
  52      }
  53  
  54      /**
  55       * {@inheritdoc}
  56       */
  57  	public function chgrp($files, $group, $recursive = false)
  58      {
  59          try
  60          {
  61              $this->symfony_filesystem->chgrp($files, $group, $recursive);
  62          }
  63          catch (\Symfony\Component\Filesystem\Exception\IOException $e)
  64          {
  65              // Try to recover filename
  66              // By the time this is written that is at the end of the message
  67              $error = trim($e->getMessage());
  68              $file = substr($error, strrpos($error, ' '));
  69  
  70              throw new filesystem_exception('FILESYSTEM_CANNOT_CHANGE_FILE_GROUP', $file, array(), $e);
  71          }
  72      }
  73  
  74      /**
  75       * {@inheritdoc}
  76       */
  77  	public function chmod($files, $perms = null, $recursive = false, $force_chmod_link = false)
  78      {
  79          if (is_null($perms))
  80          {
  81              // Default to read permission for compatibility reasons
  82              $perms = self::CHMOD_READ;
  83          }
  84  
  85          // Check if we got a permission flag
  86          if ($perms > self::CHMOD_ALL)
  87          {
  88              $file_perm = $perms;
  89  
  90              // Extract permissions
  91              //$owner = ($file_perm >> 6) & 7; // This will be ignored
  92              $group = ($file_perm >> 3) & 7;
  93              $other = ($file_perm >> 0) & 7;
  94  
  95              // Does any permissions provided? if so we add execute bit for directories
  96              $group = ($group !== 0) ? ($group | self::CHMOD_EXECUTE) : $group;
  97              $other = ($other !== 0) ? ($other | self::CHMOD_EXECUTE) : $other;
  98  
  99              // 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('FILESYSTEM_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('FILESYSTEM_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('FILESYSTEM_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[count($filtered) - 1] !== '.' && $filtered[count($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('FILESYSTEM_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('FILESYSTEM_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('FILESYSTEM_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('FILESYSTEM_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('posix_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('FILESYSTEM_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('FILESYSTEM_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('FILESYSTEM_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('FILESYSTEM_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[count($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 = count($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[count($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  }


Generated: Tue Apr 7 19:44:41 2020 Cross-referenced by PHPXref 0.7.1