From bc0507a511ab5b96105e73f625b6c31f7e010f6d Mon Sep 17 00:00:00 2001
From: Bob Vincent <bobvin@pillars.net>
Date: Tue, 24 May 2011 15:38:54 -0400
Subject: [PATCH] Issue #1113588 by pillarsdotnet: Provide url_to_path()
 function by re-factoring and re-using code from existing
 conf_path() function.

---
 includes/bootstrap.inc |   29 +++++++++++++++-
 includes/common.inc    |   84 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 111 insertions(+), 2 deletions(-)

diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc
index 7d000343a58896e317dbc40420c5d3b007d7e468..57253191e5a03750b4f35aa22fbf431a4849740a 100644
--- a/includes/bootstrap.inc
+++ b/includes/bootstrap.inc
@@ -549,6 +549,31 @@ function conf_path($require_settings = TRUE, $reset = FALSE) {
     return $conf;
   }
 
+  $script_name = $_SERVER['SCRIPT_NAME'];
+  if (!$script_name) {
+    $script_name = $_SERVER['SCRIPT_FILENAME'];
+  }
+  $http_host = $_SERVER['HTTP_HOST'];
+  $conf = find_conf_path($script_name, $http_host, $require_settings);
+  return $conf;
+}
+
+/**
+ * Find the appropriate configuration directory for a given host and path.
+ *
+ * @param $http_host
+ *   The hostname and optional port number, e.g. "www.example.com" or
+ *   "www.example.com:8080".
+ *
+ * @param $script_name
+ *   The part of the url following the hostname, including the leading slash.
+ *
+ * @return
+ *   The path of the matching configuration directory.
+ *
+ * @see conf_path()
+ */
+function find_conf_path($http_host, $script_name, $require_settings = TRUE) {
   $confdir = 'sites';
 
   $sites = array();
@@ -557,8 +582,8 @@ function conf_path($require_settings = TRUE, $reset = FALSE) {
     include(DRUPAL_ROOT . '/' . $confdir . '/sites.php');
   }
 
-  $uri = explode('/', $_SERVER['SCRIPT_NAME'] ? $_SERVER['SCRIPT_NAME'] : $_SERVER['SCRIPT_FILENAME']);
-  $server = explode('.', implode('.', array_reverse(explode(':', rtrim($_SERVER['HTTP_HOST'], '.')))));
+  $uri = explode('/', $script_name);
+  $server = explode('.', implode('.', array_reverse(explode(':', rtrim($http_host, '.')))));
   for ($i = count($uri) - 1; $i > 0; $i--) {
     for ($j = count($server); $j > 0; $j--) {
       $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
diff --git a/includes/common.inc b/includes/common.inc
index 0c6c9eb2be8f4020d820fe3d37380db584fb0957..04ac4a4b51e7c7308715e0f483ad5d6fb4de436e 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -2203,6 +2203,90 @@ function url_is_external($path) {
 }
 
 /**
+ * Returns the local relative path corresponding to a given URL, if possible.
+ *
+ * Finds the configuration directory matching the given URL, and compares it
+ * to the current configuration directory. Returns a path relative to the drupal
+ * install if they match, and FALSE if they don't.
+ *
+ * In a properly-configured multisite installation, this function helps answer
+ * the question, "Could this URL match a file or path within the current site?
+ *
+ * Whether the URL does in fact resolve to this site, or at all, cannot be
+ * determined within Drupal itself.  This is only a sanity check.
+ *
+ * @param $url
+ *   The internal path or external URL being linked to, such as
+ *   "drupal/node/34" or "http://example.com/drupal/foo".
+ * @return
+ *   FALSE if $url contains a host/port/path that does not match the current
+ *   site, or else a drupal path such as "node/34" or "foo".
+ *
+ * @see conf_path(), find_conf_path()
+ */
+function url_to_path($url) {
+  global $base_path;
+  $local = &drupal_static('__FUNCTION__', array());
+  $base_len = strlen($base_path);
+
+  $parts = parse_url($url);
+  $http_host = isset($parts['host']) ? $parts['host'] : $_SERVER['HTTP_HOST'];
+  if (isset($parts['port'])) {
+    $http_host .= ':' . $parts['port'];
+  }
+  $script_name = '/';
+  if (isset($parts['path'])) {
+    $script_name .= ltrim($parts['path'], '/');
+  }
+  $path = $http_host . $script_name;
+  if (!isset($local[$path])) {
+    $local[$path] = FALSE;
+    // Check whether the current conf_path() matches the url's conf_path.
+    if (conf_path() === find_conf_path($http_host, $script_name)) {
+      // Check whether the current $base_path is included in the url path.
+      if (!strncmp($script_name, $base_path, $base_len)) {
+        // If both match, the file could be local to the current site.
+        $local[$path] = TRUE;
+      }
+    }
+  }
+  return $local[$path] ? substr($script_name, $base_len) : FALSE;
+}
+
+/**
+ * Returns an absolute local path corresponding to a given URL, if possible.
+ *
+ * For example, when looking for image URLs within an email message body for
+ * possible conversion to inline attachments, the following code might be used:
+ * @code
+ *   if ( !url_is_external($url)
+ *     && ($path = url_to_realpath($url))
+ *     && is_file($path) ) {
+ *     // Attach $path and replace $url.
+ *     ...
+ *   }
+ * @endcode
+ *
+ * @param $url
+ *   The internal path or external URL being linked to, such as
+ *   "sites/example.com/files/logo.png" or
+ *   "http://example.com/logo.png".
+ * @return
+ *   FALSE if $url contains a host/port/path that does not match the current
+ *   site, or else an absolute local path to an existing file such as
+ *   "/path/to/drupal/sites/example.com/files/logo.png".
+ *
+ * @see url_to_path()
+ */
+function url_to_realpath($url) {
+  $path = url_to_path($url);
+  if ($path) {
+    return realpath(DRUPAL_ROOT . '/' . $path);
+  }
+  return FALSE;
+}
+
+/**
  * Format an attribute string for a HTTP header.
  *
  * @param $attributes
-- 
1.7.5.4

