Uploaded image for project: 'phpBB'
  1. phpBB
  2. PHPBB-15168

Unable to run phpbb in virtual directory on IIS with limited access permissions

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Cannot Reproduce
    • Icon: Blocker Blocker
    • None
    • 3.2.0
    • None
    • IIS
      PHP 7.1

      Summary

      phpbb fails to run in a virtual directory on IIS if the Windows user does not have read access to all parent directories.

      Error

      PHP Fatal error: Uncaught InvalidArgumentException: The file "config/production/routing/environment.yml" does not exist (in: ). in C:\home\website\forums\vendor\symfony\config\FileLocator.php:70

      Cause

      phpbb passes './' to phpbb\filesystem\filesystem::realpath (phpbb\filesystem\filesystem.php) in many places (e.g. to the ctor of the FileLocator, to build the route cache etc).
      This function first tries the native realpath function. However, when phpbb is run in a virtual directory on IIS, realpath fails (https://bugs.php.net/bug.php?id=44293).
      According to the php bug report this is the expected behavior.

      Now the filesystem::realpath function fails over to phpbb_own_realpath. In phpbb_own_realpath the working_directory is set and the path is built as following:

      if ($this->working_directory !== false)

      { $is_absolute_path = true; $path = $this->working_directory . '/' . $path; }

      Example:
      path = /home/website/forums/./
      is_absolute_path = true

      Since $is_absolute_path is true and we are on Windows:
      if (defined('PHP_WINDOWS_VERSION_MAJOR'))

      { $path_prefix = $path[0] . ':'; $path = substr($path, 2); }

      Example:
      path = /home/website/forums/.
      path_prefix = C:

      This is now passed to
      $this->resolve_path($path, $path_prefix, $is_absolute_path);
      which fails. The failure happens here:

      else if (is_dir($current_path . '/'))

      { $resolved[] = $path_part; $resolved_path = $current_path; }

      else if (is_file($current_path))

      { $resolved[] = $path_part; $resolved_path = $current_path; $file_found = true; }

      else

      { return false; }

      Example:
      $current_path = c:/home/website
      is_dir for c:/home/website/ fails
      -> the Windows user does not read access to this directory

      is_file for c:/home/website fails
      return false is called

      Issues

      There are multiple issues with the current implementation:

      1. filesystem::resolve_path
      resolve_path should work even if the Windows user does not have read access to the parent directories

      2. filesystem::phpbb_own_realpath
      phpbb_own_realpath should not call resolve_path if the path is '.' or starts with './'

      3. General observation
      There are too many unnecessary calls to realpath. realpath is an expensive call because it requires access to the file system. This can completely be avoided:

      Option 1:
      Set root path of phpbb at the very beginning.
      Example:
      @define('PHPBB_ROOT_PATH', _DIR_);

      Then build all paths relative to the base path using string operations without accessing the file system. file system access is not required because we do not expect
      that sub directores in the phpbb folder are symbolic links etc.

      Option 2:
      chdir to the root phpbb directory at the beginning:
      chdir(_DIR_)
      For example this is how Zend Framework does it
      Then all paths can be relative to the base directory
      I'm in favor of this solution as it has been proven to work and reduces file system access to a minimum.

      Workaround

      My current workaround is to skip resolve_path in filesystem::phpbb_own_realpath for certain cases:

      • path is .
      • path starts with ./

      and then build the $resolved_path directly.

            Marc Marc
            mberchtold mberchtold [X] (Inactive)
            Votes:
            1 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved: