-
Bug
-
Resolution: Cannot Reproduce
-
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'))
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.