diff --git a/.htaccess b/.htaccess index ca10d364e0..cab4556788 100644 --- a/.htaccess +++ b/.htaccess @@ -136,11 +136,12 @@ DirectoryIndex index.php # uncomment the following line: # RewriteBase / - # Rewrite URLs of the form 'x' to the form 'index.php?q=x'. + # Pass all requests not referring directly to files in the filesystem to + # index.php. Clean URLs are handled in drupal_environment_initialize(). RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_URI} !=/favicon.ico - RewriteRule ^(.*)$ index.php?q=$1 [L,QSA] + RewriteRule ^ index.php [L] # Various header fixes. diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index d1bcedfa71..bea9c53247 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -433,8 +433,8 @@ function conf_init() { // $_SERVER['SCRIPT_NAME'] can, in contrast to $_SERVER['PHP_SELF'], not // be modified by a visitor. - if ($dir = trim(dirname($_SERVER['SCRIPT_NAME']), '\,/')) { - $base_path = "/$dir"; + if ($dir = rtrim(dirname($_SERVER['SCRIPT_NAME']), '\/')) { + $base_path = $dir; $base_url .= $base_path; $base_path .= '/'; } @@ -1138,6 +1138,19 @@ function _drupal_bootstrap($phase) { case DRUPAL_BOOTSTRAP_CONFIGURATION: drupal_unset_globals(); + + // When clean URLs are enabled, emulate ?q=foo/bar using REQUEST_URI. It is + // not possible to append the query string using mod_rewrite without the B + // flag (this was added in Apache 2.2.8), because mod_rewrite unescapes the + // path before passing it on to PHP. This is a problem when the path contains + // e.g. "&" or "%" that have special meanings in URLs and must be encoded. + $_GET['q'] = request_path(); + + // The D7 patch we're backporting does not sync $_REQUEST['q'], however some contrib modules use this + // instead of $_GET['q'] - eg: globalredirect, imagecache_customactions. + // This is added to maintain support. + $_REQUEST['q'] = $_GET['q']; + // PHP's built-in phar:// stream wrapper is not sufficiently secure. Override // it with a more secure one, which requires PHP 5.3.3. For lower versions, // unregister the built-in one without replacing it. Sites needing phar @@ -1367,6 +1380,50 @@ function language_default($property = NULL) { return $property ? $language->$property : $language; } +/** + * Returns the requested URL path of the page being viewed. + * + * Examples: + * - http://example.com/node/306 returns "node/306". + * - http://example.com/drupalfolder/node/306 returns "node/306" while + * base_path() returns "/drupalfolder/". + * - http://example.com/path/alias (which is a path alias for node/306) returns + * "path/alias" as opposed to the internal path. + * + * @return + * The requested Drupal URL path. + * + * @see current_path() + */ +function request_path() { + static $path; + + if (isset($path)) { + return $path; + } + + if (isset($_GET['q'])) { + // This is a request with a ?q=foo/bar query string. $_GET['q'] is + // overwritten in drupal_path_initialize(), but request_path() is called + // very early in the bootstrap process, so the original value is saved in + // $path and returned in later calls. + $path = $_GET['q']; + } + elseif (isset($_SERVER['REQUEST_URI'])) { + // This is a request using a clean URL. Extract the path from REQUEST_URI. + $request_path = strtok($_SERVER['REQUEST_URI'], '?'); + $base_path_len = strlen(rtrim(dirname($_SERVER['SCRIPT_NAME']), '\/')); + // Unescape and strip $base_path prefix, leaving q without a leading slash. + $path = substr(urldecode($request_path), $base_path_len + 1); + } + else { + // This is the front page. + $path = ''; + } + + return $path; +} + /** * If Drupal is behind a reverse proxy, we use the X-Forwarded-For header * instead of $_SERVER['REMOTE_ADDR'], which would be the IP address diff --git a/includes/common.inc b/includes/common.inc index 0c6af87217..44cc553f50 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -2691,35 +2691,18 @@ function drupal_json($var = NULL) { } /** - * Wrapper around urlencode() which avoids Apache quirks. - * - * Should be used when placing arbitrary data in an URL. Note that Drupal paths - * are urlencoded() when passed through url() and do not require urlencoding() - * of individual components. - * - * Notes: - * - For esthetic reasons, we do not escape slashes. This also avoids a 'feature' - * in Apache where it 404s on any path containing '%2F'. - * - mod_rewrite unescapes %-encoded ampersands, hashes, and slashes when clean - * URLs are used, which are interpreted as delimiters by PHP. These - * characters are double escaped so PHP will still see the encoded version. - * - With clean URLs, Apache changes '//' to '/', so every second slash is - * double escaped. - * - This function should only be used on paths, not on query string arguments, - * otherwise unwanted double encoding will occur. + * Encodes a Drupal path for use in a URL. * - * @param $text - * String to encode + * For aesthetic reasons slashes are not escaped. + * + * Note that url() takes care of calling this function, so a path passed to that + * function should not be encoded in advance. + * + * @param $path + * The Drupal path to encode. */ function drupal_urlencode($text) { - if (variable_get('clean_url', '0')) { - return str_replace(array('%2F', '%26', '%23', '//'), - array('/', '%2526', '%2523', '/%252F'), - rawurlencode($text)); - } - else { - return str_replace('%2F', '/', rawurlencode($text)); - } + return str_replace('%2F', '/', rawurlencode($text)); } /** diff --git a/includes/file.inc b/includes/file.inc index 32371f4fb5..3697292331 100644 --- a/includes/file.inc +++ b/includes/file.inc @@ -521,6 +521,10 @@ function file_unmunge_filename($filename) { * @return */ function file_create_filename($basename, $directory) { + // Strip control characters (ASCII value < 32). Though these are allowed in + // some filesystems, not many applications handle them well. + $basename = preg_replace('/[\x00-\x1F]/u', '_', $basename); + $dest = $directory .'/'. $basename; if (file_exists($dest)) { diff --git a/misc/drupal.js b/misc/drupal.js index 182f069d8b..fa314bbcda 100644 --- a/misc/drupal.js +++ b/misc/drupal.js @@ -348,8 +348,7 @@ Drupal.unfreezeHeight = function () { */ Drupal.encodeURIComponent = function (item, uri) { uri = uri || location.href; - item = encodeURIComponent(item).replace(/%2F/g, '/'); - return (uri.indexOf('?q=') != -1) ? item : item.replace(/%26/g, '%2526').replace(/%23/g, '%2523').replace(/\/\//g, '/%252F'); + return encodeURIComponent(item).replace(/%2F/g, '/'); }; /**