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

Inconsistent realpath() results -> problems with redirect() and extract_current_page()

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • None
    • 3.0.RC7
    • Other
    • None
    • PHP Environment:
      Database:

      THE PROBLEM

      The problem as seen initially was that some local phpBBrc7 modifications (for a purely local authentication method) failed on Windows, though they worked fine on Linux.

      However, investigation found that the underlying cause (depending on how far you trace it back) is incorrect results from the standard phpBB redirect() and extract_current_page() functions, or failure to ensure consistent handling of inconsistent results returned by the PHP realpath() function (varying between versions or between Linux and Windows, yielding paths either with or without trailing "/"), leading to the incorrect results.

      Additionally, while it's possible that none of the redirect() calls in unmodified phpBB3rc7 trigger the problem, a variant of the problem DOES arise for some ACP functionality, and the redirect() problem can be demonstrated trivially by adding one line (to use redirect() and log the result) to otherwise-unmodified phpBB3rc7.

      My development's purely Linux-based; to investigate the problem on Windows I used the XAMPP Apache/PHP/MySQL etc., package for Windows from http://www.apachefriends.org/en/xampp.html, on Windows XP. That includes PHP 5.2.4 with Apache 2.2.6. The original problem report was for the same PHP version but with Windows 2003 Server and Apache 2.0.59.

      I am not in a position to investigate whether the difference in behaviour is Linux versus Windows or PHP 2.0.59 versus 5.2.4 (or maybe a bit of both).

      HOW TO REPRODUCE THE PROBLEM

      On Windows with PHP 5.2.4, at least, with unmodified phpBB3rc7:

      (1) For the redirect() problem, with phpBB3rc7 installed e.g. with URL path /phpBB3

      insert

      error_log("redirect returned " . redirect("{$phpbb_root_path}ucamlogin.$phpEx",true));

      near the top of adm/index.html - e.g.immediately after the session management calls, access the ACP, and then look at the error log.

      In configurations with the problem, the log should show that the target URL derived by redirect() is e.g. http://localhost/../ucamlogin.php - when it should be http://localhost/phpBB3/ucamlogin.php.

      (2) For the ACP problem, just log in to the ACP and then on the initial (General) page select the "Run now" button for "Purge the cache" (maybe other options, that's the one where I encountered the problem). Then click the Yes button on the confirmation page. Although it doesn't appear to use redirect(), that similarly ends up at the wrong URL (with the phpBB3 root directory's name omitted from the URL path).

      WHY IT HAPPENS

      If the realpath() function returns paths with a trailing "/", that confuses the code which attempts to match various paths and deduce which parts correspond to phpBB root, the current directory relative to that, etc.

      Empirically, in my test systems, realpath() in the Windows case returns paths with a trailing "/" whereas on Linux it's omitted - though I can't tell if that's a difference between PHP versions or because realpath()'s handling of Windows paths is inconsistent with the handling for Linux).

      Among the consequences, the line

      $root_dirs = explode('/', str_replace('
      ', '/', phpbb_realpath($phpbb_root_path)));

      in redirect() ends up with a null final array entry (due to the trailing "/"), causing

      $dir = str_repeat('../', sizeof($root_dirs)) . implode('/', $page_dirs);

      to insert one more "../" component than it should (because sizeof($root_dirs) is made one greater than the number of real root path elements by the trailing null component). Additionally, the "adm" or whatever) subdirectory name gets lost due to similar problems with
      manipulating $page_dirs in extract_current_page().

      WORKAROUNDS

      NB The "Force server URL settings" in the ACP General / Server settings page does NOT solve this problem, as it avoids only one of the two places where the underlying problem arises.

      Option 1: in redirect(), arrange to drop the final element of the $root_dirs array if it is a null string: after

      $root_dirs = explode('/', str_replace('
      ', '/', phpbb_realpath($phpbb_root_path)));

      add

      if (sizeof($root_dirs) and $root_dirs[sizeof($root_dirs)-1] == '') {
      array_pop($root_dirs);
      }

      and similarly in extract_current_page() for the assignment to $page_dirs there.

      The fix in extract_current_page() was sufficient to fix the ACP cache-purging problem, but both changes were needed to fix the redirection problem.

      Option 2:

      As suggested in

      http://www.phpbb.com/community/viewtopic.php?f=46&t=578410#p3184328

      (which I only found after investigating the problem in detail and developing the "option 1" solution), arrange for phpBB's realpath() implementation to be used in all cases, rather than using PHP's realpath() function (which is currently used conditionally, if it is available).

      Option 3:

      Untested, but using the PHP realpath() function and modifying the phpbb_realpath() wrapper function to strip trailing "/"s also ought to work. Presumably the "cleanest" solution, especially if PHP versions that lack realpath() but are new enough to run phpBB3 are rare or non-existent.

      Options 2 and 3 seem more risky (since they may affect other code which relies on the current - though inconsistent - behaviour). Then again, maybe option 1 is more risky because it works around the underlying realpath() problem in some cases, but not others, which could cause new inconsistencies! It's not clear to me which is the right/best solution.

            Acyd Burn Meik Sievertsen [X] (Inactive)
            john line john line
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved: