I attempted to create a Drupal installation on an internal host, with a base_url (i.e. "subdirectory" type) Apache2 reverse proxy publishing it.

So I had a reverse proxy 'www.example.com/drupal' pointing to a Drupal instance at localhost with base_url 'www.example.com/drupal' set.

During installation, I get the infamous #481758: Fatal error: Call to undefined function field_attach_load() in includes/entity.inc on line 321 during install

However, in this case, it's an easily isolated issue:

Drupal installation and bootstrap rely on $_SERVER['REQUEST_URI'] to be authoritative. In my setup, it isn't, because $_SERVER['REQUEST_URI'] does not include the base_url, because the internal host isn't (and shouldn't really need to be?) aware of it. I'm not sure if I'm going to be told this is a configuration issue, not a bug, but really why should the internal server need to be aware of the base url if it's already hardcoded into settings.php? That should be authoritative, right?

drupal-7.33/includes/install.inc:225:  $uri = preg_replace("/\?.*/", '', $_SERVER['REQUEST_URI']);
drupal-7.33/includes/bootstrap.inc:673:  // When clean URLs are enabled, emulate ?q=foo/bar using REQUEST_URI. It is
drupal-7.33/includes/bootstrap.inc:1621: * Returns the equivalent of Apache's $_SERVER['REQUEST_URI'] variable.
drupal-7.33/includes/bootstrap.inc:1623: * Because $_SERVER['REQUEST_URI'] is only available on Apache, we generate an
drupal-7.33/includes/bootstrap.inc:1627:  if (isset($_SERVER['REQUEST_URI'])) {
drupal-7.33/includes/bootstrap.inc:1628:    $uri = $_SERVER['REQUEST_URI'];
drupal-7.33/includes/bootstrap.inc:2819:  elseif (isset($_SERVER['REQUEST_URI'])) {
drupal-7.33/includes/bootstrap.inc:2821:    // Extract the path from REQUEST_URI.
drupal-7.33/includes/bootstrap.inc:2822:    $request_path = strtok($_SERVER['REQUEST_URI'], '?');
drupal-7.33/includes/bootstrap.inc:2828:    // $_SERVER['REQUEST_URI'] even when it wasn't provided in the URL (some
drupal-7.33/.htaccess:94:  # RewriteRule ^ http%{ENV:protossl}://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
drupal-7.33/.htaccess:100:  # RewriteRule ^ http%{ENV:protossl}://%1%{REQUEST_URI} [L,R=301]
drupal-7.33/.htaccess:116:  RewriteCond %{REQUEST_URI} !=/favicon.ico
drupal-7.33/scripts/dump-database-d6.sh:23:$_SERVER['PHP_SELF']        = $_SERVER['REQUEST_URI'] = '/';
drupal-7.33/scripts/generate-d6-content.sh:23:$_SERVER['PHP_SELF']        = $_SERVER['REQUEST_URI'] = '/';
drupal-7.33/scripts/drupal.sh:67:$_SERVER['PHP_SELF']        = $_SERVER['REQUEST_URI'] = '/';
drupal-7.33/scripts/drupal.sh:118:          $_SERVER['PHP_SELF'] = $_SERVER['REQUEST_URI'] = $path['path'];
drupal-7.33/scripts/generate-d7-content.sh:25:$_SERVER['PHP_SELF']        = $_SERVER['REQUEST_URI'] = '/';
drupal-7.33/scripts/dump-database-d7.sh:23:$_SERVER['PHP_SELF']        = $_SERVER['REQUEST_URI'] = '/';
drupal-7.33/scripts/run-tests.sh:289:  $_SERVER['REQUEST_URI'] = $path .'/';

I could get Drupal to install by hacking core with something like this wrapper around $_SERVER['REQUEST_URI']:

function apache2_request_uri($request_uri) {
  if ($request_uri && isset($GLOBALS['base_url'])) {
    $base_path = parse_url($GLOBALS['base_url'], PHP_URL_PATH);
    if ($base_path && 0 !== strpos($request_uri, $base_path)) {
      return $base_path . $request_uri;
    }
  }
  return $request_uri;
}

This fixes the issue, for me, with Apache2, but is unlikely to address the problem with other web servers, so I'm not sure a patch would be accepted? Can an issue be fixed just for a particular web server?

Comments

lightsurge’s picture

I've discovered that although it's relatively easy to get an existing installation running as above by altering request_uri(), this doesn't work for a new installation.

  • the global $base_url isn't even set yet at the point you need it to be set in order to correct the URI
  • Apparently install.inc overwrites any $base_url you set in your settings.php as part of installation https://api.drupal.org/api/drupal/includes%21install.core.inc/function/i... so that would have to be tackled as well
  • Despite overriding that, and settings.php gets correctly over-written with the right base_url, I get directed back to the form with no error... I think something else must be mucking about with the URI other than the lines grepped above, which messes up the install_state, no idea what though.

Below is as far as I got at a function that would work during install, and it's getting so messy I think I'm going to have to give up on trying to get Drupal to install itself into in this type of setup, and just copy a basic non-base-url existing installation each time, then adding the base_url and patching request_uri() function to get it to work.

function drupal_apache2_request_uri($request_uri = NULL) {
  global $base_url;
  if (!isset($base_url)) {
    if (file_exists(DRUPAL_ROOT . '/' . conf_path() . '/settings.php')) {
      include_once DRUPAL_ROOT . '/' . conf_path() . '/settings.php';
    }
  }
  $base_path = isset($GLOBALS['base_path']) ? $GLOBALS['base_path'] : parse_url($base_url, PHP_URL_PATH);
  $base_path = rtrim($base_path, '/');
  if ($request_uri && $base_path) {
    if (0 !== strpos($request_uri, $base_path)) {
      $request_uri =  $base_path . $request_uri;
    }
  }
  return $request_uri;
}
andypost’s picture

Priority: Normal » Major

1) drupal_settings_initialize() uses $base_url to be used for URL construction
2) forms, dblog are bound to request_uri() uses $_SERVER['REQUEST_URI'] - to get current page address

So here's inconsistency!

Quick solution is to populate $_SERVER['REQUEST_URI'] according $base_url when defined

gaele’s picture

Version: 7.x-dev » 8.0.x-dev
Component: install system » base system
Related issues: +#677958: Invalid REQUEST_URI construnction in request_uri - Fails when using reverse proxy

So the proxy is listening to http://www.example.com/drupal,
the Drupal instance is at http://internal.example.com,
and its $base_url is set at http://www.example.com/drupal.

This will fail on forms where the #action is not set, like the user login page or the search box, or in dblog. There request_uri() is used and $base_url is ignored, resulting in /user instead of /drupal/user:

function system_element_info() {
  // Top level elements.
  $types['form'] = array(
    '#method' => 'post',
    '#action' => request_uri(),
    '#theme_wrappers' => array('form'),
  );

This seems to be still present in D8:

  protected function buildFormAction() {
    // @todo Use <current> instead of the master request in
    //   https://www.drupal.org/node/2505339.
    $request = $this->requestStack->getMasterRequest();
    $request_uri = $request->getRequestUri();

    // Prevent cross site requests via the Form API by using an absolute URL
    // when the request uri starts with multiple slashes..
    if (strpos($request_uri, '//') === 0) {
      $request_uri = $request->getUri();
    }

    // @todo Remove this parsing once these are removed from the request in
    //   https://www.drupal.org/node/2504709.
    $parsed = UrlHelper::parse($request_uri);
    unset($parsed['query'][static::AJAX_FORM_REQUEST], $parsed['query'][MainContentViewSubscriber::WRAPPER_FORMAT]);
    return $parsed['path'] . ($parsed['query'] ? ('?' . UrlHelper::buildQuery($parsed['query'])) : '');
  }
ivanstegic’s picture

Making a note here that $base_url was removed from settings.php in a recent commit

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

catch’s picture

Status: Active » Closed (duplicate)

Closing this as a duplicate of #2753591: Fix mismatch of $base_url with Symfony request object see you over there!

catch’s picture

xjm’s picture

Component: base system » request processing system