[ Index ]

PHP Cross Reference of Drupal 6 (yi-drupal)

title

Body

[close]

/sites/all/modules/gallery/ -> G2EmbedDiscoveryUtilities.class (source)

   1  <?php
   2  /*
   3   * Gallery - a web based photo album viewer and editor
   4   * Copyright (C) 2000-2006 Bharat Mediratta
   5   *
   6   * This program is free software; you can redistribute it and/or modify
   7   * it under the terms of the GNU General Public License as published by
   8   * the Free Software Foundation; either version 2 of the License, or (at
   9   * your option) any later version.
  10   *
  11   * This program is distributed in the hope that it will be useful, but
  12   * WITHOUT ANY WARRANTY; without even the implied warranty of
  13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14   * General Public License for more details.
  15   *
  16   * You should have received a copy of the GNU General Public License
  17   * along with this program; if not, write to the Free Software
  18   * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA  02110-1301, USA.
  19   */
  20  /**
  21   * @version $Revision: 1.3.2.2 $ $Date: 2007/11/27 18:10:32 $
  22   * @package GalleryCore
  23   * @author Andy Staudacher <ast@gmx.ch>
  24   */
  25  
  26  /**
  27   * A collection of useful G2Embed related utilities to find the correct GalleryEmbed::init 
  28   * parameters
  29   *
  30   * @package GalleryCore
  31   * @subpackage GalleryEmbed
  32   * @static
  33   */
  34  class G2EmbedDiscoveryUtilities {
  35      /**
  36       * Documentation:
  37       * To use GalleryEmbed and its GalleryEmbed::init method to initialize G2, you need:
  38       *   a) the absolute filesystem path to embed.php
  39       *   b) embedUri, the URL of the entry point to your embedding application / embedded G2
  40       *      e.g. http://example.com/ or just / , or http://example.com/index.php?mod=gallery
  41       *   c) g2Uri, the URL path to G2, e.g. http://example.com/gallery2/ or just /gallery2/
  42       *
  43       * Methods to finding out the path to embed.php:
  44       * ============================================
  45       *
  46       *   - It's a good assumption that you can find out or define embedUri easily
  47       *   - g2Uri must be entered by the admin that configures the integration, just copy and paste 
  48       *     the URL of G2
  49       *   - finding out embed.php is a little tricky.
  50       *
  51       *   We offer two methods to get embed.php. Do NOT call them for each request. Call them once
  52       *   when configuring / installing your integration. Else you get a performance penalty.
  53       *
  54       *    1. If you ask the user to enter the g2Uri, you can call:
  55       *        list ($success, $embedPhpPath, $errorString) =
  56       *            G2EmbedDiscoveryUtilities::getG2EmbedPathByG2Uri($g2Uri);
  57       *        if (!$success) {
  58       *            print $errorString;
  59       *            /* Tell the admin to enter the correct input
  60       *        } else {
  61       *            /* embedPhpPath is correct and you can store it in your config for later use 
  62       *        }
  63       *
  64       *    2. If you ask only for the g2Uri, you also need to provide the filesystem path to the
  65       *       entry point (the filesystem path to the file that embedUri points to)
  66       *       list ($success, $embedPhpPath, $errorString) =
  67       *                  G2EmbedDiscoveryUtilities::getG2EmbedPathByG2UriEmbedUriAndLocation(
  68       *                             $g2Uri, $embedUri, dirname(dirname(__FILE__)));
  69       *        if (!$success) {
  70       *            print $errorString;
  71       *            /* Tell the admin to enter the correct input
  72       *        } else {
  73       *            /* embedPhpPath is correct and you can store it in your config for later use 
  74       *        }
  75       *       Disadvantage of this method: it's less reliable. It won't work with Apache Alias,
  76       *                                    or with subdomains, ...
  77       *
  78       *
  79       * Method to normalize the g2Uri and embedUri before using them in GalleryEmbed::init:
  80       * ==================================================================================
  81       *
  82       *   Do NOT call them on each request. Call them once to verify / sanitize user input
  83       *   and then store them in your configuration.
  84       *   - These methods try their best to be tolerant to common user mistakes and return a
  85       *     string that GalleryEmbd::init accepts
  86       *   - You don't have to call these methods before calling the above methods to get
  87       *     embed.php, since it does that already internally
  88       *
  89       *   1. $g2Uri = G2EmbedDiscoveryUtilities::normalizeG2Uri($g2Uri);
  90       *   2. $embedUri = G2EmbedDiscoveryUtilities::normalizeEmbedUri($embedUri);
  91       */
  92  
  93      /**
  94       * The format for g2Uri accepted by GalleryEmbed::init is quite strict and well defined
  95       * missing traling / leading slashes have a meaning.
  96       * This function is more tolerant for incorrect user input and tries to normalize the
  97       * given g2Uri to a value that is probably what the user meant to provide
  98       *
  99       * The returned URI is either a server-relative URI (e.g. /gallery2/) or an absolute URI
 100       * including the schema (e.g. http://example.com/gallery/)
 101       *
 102       * The file / query string part is always removed)
 103       *
 104       * @param string g2Uri
 105       * @return string normalized g2Uri
 106       */
 107      function normalizeG2Uri($g2Uri) {
 108      list ($schemaAndHost, $path, $file, $queryString, $fragment) =
 109          G2EmbedDiscoveryUtilities::_normalizeUri($g2Uri);
 110  
 111      return $schemaAndHost . $path;
 112      }
 113  
 114      /**
 115       * @see normalizeG2Uri
 116       *
 117       * Very similar, but file / query string is kept in the result
 118       */
 119      function normalizeEmbedUri($embedUri) {
 120      list ($schemaAndHost, $path, $file, $queryString, $fragment) =
 121          G2EmbedDiscoveryUtilities::_normalizeUri($embedUri);
 122  
 123      return $schemaAndHost . $path . $file . $queryString . $fragment;
 124      }
 125   
 126      /**
 127       * Find the absolute filesystem path to G2's embed.php when given the g2Uri
 128       *
 129       * Returns false if the g2Uri is wrong. Can also fail if G2 and emApp are
 130       * on different (sub)domains / IPs
 131       *
 132       * @param string the g2Uri, a full URL or a server-relative URI
 133       * @return array boolean success,
 134       *               string filesystem path of embed.php
 135       *               string error string
 136       */
 137      function getG2EmbedPathByG2Uri($g2Uri) {
 138      $g2Uri = trim($g2Uri);
 139      if (empty($g2Uri)) {
 140          return array (false, null, "Bad parameter: the provided g2Uri is empty");
 141      }
 142  
 143      $g2Uri = G2EmbedDiscoveryUtilities::normalizeG2Uri($g2Uri);
 144      
 145      /* Add a schema / host part to the g2Uri if necessary */
 146      if (strpos($g2Uri, 'http') !== 0) {
 147          $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http';
 148          $host = !empty($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '127.0.0.1';
 149          $g2Uri = sprintf('%s://%s%s', $protocol, $host, $g2Uri);
 150      }
 151  
 152      $components = @parse_url($g2Uri);
 153      if (!$components) {
 154          return array(false, null, "Unable to parse normalized URL $g2Uri. Please enter the " .
 155               "full address of your Gallery 2 installation.");
 156      }
 157      $port = empty($components['port']) ? 80 : $components['port'];
 158      if (empty($components['path'])) {
 159          $components['path'] = '/';
 160      }
 161  
 162      $fd = @fsockopen($components['host'], $port, $errno, $errstr, 1);
 163      if (empty($fd)) {
 164          return array(false, null, "Error $errno: '$errstr' retrieving $g2Uri");
 165      }
 166  
 167      $get = $components['path'] . 'embed.php?getEmbedPath=1';
 168  
 169      /* Read the web page into a buffer */    
 170      $ok = fwrite($fd, sprintf("GET %s HTTP/1.0\r\n" .
 171                    "Host: %s\r\n" .
 172                    "\r\n",
 173                    $get,
 174                    $components['host']));
 175      if (!$ok) {
 176          /* Zero bytes written or false was returned */
 177          $errorStr = "Verification of Gallery 2 location failed. fwrite call failed for $g2Uri";
 178          if ($ok === false) {
 179          $errorStr .= "\nreturn value was false";
 180          }
 181          return array(false, null, $errorStr);
 182      }
 183      $ok = fflush($fd);
 184      if (!$ok) {
 185          if (version_compare(phpversion(), '4.2.0', '>=')) {
 186          /* Ignore false returned from fflush on PHP 4.1 */
 187          return array(false, null, "Verification of Gallery 2 location failed. " .
 188                   "fflush call failed for $g2Uri");
 189          }
 190      }
 191  
 192      /*
 193       * Read the response code. fgets stops after newlines.
 194       * The first line contains only the status code (200, 404, etc.).
 195       */
 196      $headers = array();
 197      $response = trim(fgets($fd, 4096));
 198  
 199      /* if the HTTP response code did not begin with a 2 this request was not successful */
 200      if (!preg_match("/^HTTP\/\d+\.\d+\s2\d{2}/", $response)) {
 201          return array(false, null, "URL derived from $g2Uri is invalid");
 202      }
 203  
 204      /* Read the headers. */
 205      while (!feof($fd)) {
 206          $line = trim(fgets($fd, 4096));
 207          if (empty($line)) {
 208          break;
 209          }
 210          /* Normalize the line endings */
 211          $line = str_replace("\r", '', $line);
 212  
 213          list ($key, $value) = explode(':', $line, 2);
 214          $headers[$key] = trim($value);
 215      }
 216  
 217      $embedPhpPath = '';
 218      if (isset($headers['X-G2-EMBED-PATH'])) {
 219          $embedPhpPath = $headers['X-G2-EMBED-PATH'];
 220      } else {
 221          return array(false, null, "Either your server does not support the automated " .
 222               "verification of the Gallery 2 location or the supplied g2Uri " .
 223               "points to a incompatible Gallery 2 version (older than 2.1)");
 224      }
 225      
 226      if (empty($embedPhpPath)) {
 227          return array(false, null, "Correct URL, but the returned " .
 228               "embed.php path is empty (server error?!)");
 229      }
 230  
 231      /* Verify path */
 232      list ($ok, $errorString) = @G2EmbedDiscoveryUtilities::isFileReadable($embedPhpPath);
 233      if (!$ok) {
 234          return array(false, null, $errorString);
 235      } else {
 236          return array(true, $embedPhpPath, null);
 237      }
 238      }
 239  
 240      /**
 241       * Get the absolute filesystem path to embed.php from the given g2Uri, embedUri and the
 242       * absolute filesystem path of the entry point file of your embedding application
 243       *
 244       * Can be unreliable if short URLs are entered or if apache alias / symlinks are used
 245       *
 246       * @param string g2Uri
 247       * @param string embedUri
 248       * @param string the dirname of the location of the entry point of your embedding application
 249       *        e.g. dirname(__FILE__) if your embedUri points right to your wrapper file or if your
 250       *        wrapper file is in the same directory as the entry point to your emApp
 251       *        e.g. dirname(dirname(dirname(__FILE__))) if your wrapper is in a
 252       *        modules/g2integration/wrapper.inc.php file, which is 2 subdirectories deeper than
 253       *        the actual entry point that embedUri is pointing to
 254       * @return array boolean success,
 255       *               string absolute filesystem path to embed.php,
 256       *               string errorString
 257       */
 258      
 259      function getG2EmbedPathByG2UriEmbedUriAndLocation($g2Uri, $embedUri, $dirnameOfEmApp) {
 260      if (empty($dirnameOfEmApp)) {
 261          return array(false, null, 'dirname of embedding application is empty');
 262      }
 263      /* Normalize g2Uri, embedUri */
 264      list ($schemaAndHost, $path, $file, $queryString, $fragment) =
 265          G2EmbedDiscoveryUtilities::_normalizeUri($g2Uri);
 266      $g2Path = $path;
 267      list ($schemaAndHost, $path, $file, $queryString, $fragment) =
 268          G2EmbedDiscoveryUtilities::_normalizeUri($embedUri);
 269      $embedPath = $path;
 270      
 271      /* Normalize path separators */
 272      $dirnameOfEmApp = str_replace(DIRECTORY_SEPARATOR, '/', $dirnameOfEmApp);
 273      /* Remove trailing slash */
 274      if (substr($dirnameOfEmApp, -1) == '/') {
 275          $dirnameOfEmApp = substr($dirnameOfEmApp, 0, strlen($dirnameOfEmApp) - 1);
 276      }
 277      
 278      /*
 279       * Do some directory traversal to translate g2Path + embedPath + dirnameOfEmApp
 280       * to path to embed.php
 281       * path
 282       * Example: g2Path = /baz/bar/gallery2/ , embedPath = /baz/cms/foo/ ,
 283       *          dirnameOfEmApp = /home/john/www/cms/foo/
 284       * 1. Remove as many dirs from the end of dirnameOfEmApp as embedPath has
 285       * 2. append g2Path to dirnameOfEmApp
 286       */
 287      $numberOfSubDirs = count(explode('/', $embedPath));
 288      /* Don't count the one before the leading and after the traling slash */
 289      $numberOfSubDirs -= 2;
 290  
 291      $pathElements = explode('/', $dirnameOfEmApp);
 292      $max = 30; /* prevent infinite loop */
 293      while ($numberOfSubDirs-- > 0 && $max-- > 0) {
 294          array_pop($pathElements);
 295      }
 296  
 297      $embedPhpPath = join('/', $pathElements) . $g2Path . 'embed.php';
 298  
 299      /* Convert / back to platform specific directory separator */
 300      $embedPhpPath = str_replace('/', DIRECTORY_SEPARATOR, $embedPhpPath);
 301  
 302      /* Verify path */
 303      list ($ok, $errorString) = @G2EmbedDiscoveryUtilities::isFileReadable($embedPhpPath);
 304      if (!$ok) {
 305          return array(false, null, $errorString);
 306      } else {
 307          return array(true, $embedPhpPath, null);
 308      }
 309      }
 310  
 311      /**
 312       * Helper function for normalizeG2Uri and normalizeEmbedUri
 313       *
 314       * @access private
 315       */
 316      function _normalizeUri($uri) {
 317      $uri = trim($uri);
 318      if (empty($uri)) {
 319          return array('', '/', '', '', '');
 320      }
 321      $schema = $host = $schemaAndHost = $path = $file = '';
 322      $fragment = $queryString = '';
 323      
 324      /* Normalize path separators */
 325      $uri = str_replace("\\", '/', $uri);
 326      
 327      /*
 328       * With schema (http://) -> easy to identify host
 329       * A single slash:
 330       *     www.example.com/
 331       *     www.example.com/gallery2
 332       *     www.example.com/index.php
 333       *     gallery2/
 334       *     /
 335       *     /gallery2
 336       *     /index.php
 337       *     gallery2/index.php
 338       * Multiple slashes:
 339       *     www.example.com/gallery2/
 340       *     /gallery2/
 341       *     ....
 342       * Problem: Differentiate between host, path and file
 343       *   @files: .php|.html? is recognized as file
 344       *   @host:  (?:\w+:\w+@)[\w\.]*\w+\.\w{2-4}(?::\d+) is most likely a host string
 345       *           localhost or other host strings without a dot are impossible to
 346       *           differentiate from path names ->only http://localhost accepted
 347       *   @path:  everything that is not a file or a host
 348       */
 349  
 350      /* Remove fragment / query string */
 351      if (($pos = strpos($uri, '#')) !== false) {
 352          $fragment = substr($uri, $pos);
 353          $uri = substr($uri, 0, $pos);
 354      }
 355      if (($pos = strpos($uri, '?')) !== false) {
 356          $queryString = substr($uri, $pos);
 357          $uri = substr($uri, 0, $pos);
 358      }
 359  
 360      /* Handle and remove file part */
 361      if (preg_match('{(.*/)?([\w\.]+\.(?:php|html?))$}i', $uri, $matches)) {
 362          $uri = empty($matches[1]) ? '/' : $matches[1];
 363          $file = $matches[2];
 364      }
 365          
 366      /* Get the schema and host for absolute URLs */
 367      if (preg_match('{^(https?://)([^/]+)(.*)$}i', $uri, $matches)) {
 368          $schema = strtolower($matches[1]);
 369          $host = $matches[2];
 370          $schemaAndHost = $schema . $host;
 371          $uri = empty($matches[3]) ? '/' : $matches[3];
 372          $uri = $uri{0} != '/' ? '/' . $uri : $uri;
 373      } else {
 374          /* Get the host string, e.g. from www.example.com/foo or www.example.com */
 375          if (preg_match('{^((?:\w+:\w+@)?[\w\.]*\w+\.\w+(?::\d+)?)(.*)$}', $uri, $matches)) {
 376          $host = $matches[1];
 377          $schema = 'http://';
 378          if ( !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
 379              $schema = 'https://';
 380          }
 381          $schemaAndHost = $schema . $host;;
 382          $uri = empty($matches[2]) ? '/' : $matches[2];
 383          $uri = $uri{0} != '/' ? '/' . $uri : $uri;
 384          }
 385      }
 386  
 387      /* Add leading / trailing slash to path */
 388      $path = $uri{0} != '/' ? '/' . $uri : $uri;
 389      $path .= substr($path, -1) != '/' ? '/' : '';
 390  
 391      return array($schemaAndHost, $path, $file, $queryString, $fragment);
 392      }
 393      
 394      function isFileReadable($path) {
 395      if (@file_exists($path) && @is_readable($path)) {
 396          return array(true, null);
 397      } else if (@G2EmbedDiscoveryUtilities::_isRestrictedByOpenBaseDir($path)) {
 398          return array(false, "file $path is restricted by PHP open_basedir");
 399      } else if (@file_exists($path) && !@is_readable($path)) {
 400          return array(false, "file $path exists but is not readable");
 401      } else {
 402          return array(false, "file $path does not exist");
 403      }
 404      }
 405      
 406      /**
 407       * Return true if the path provided is not allowed by the current open_basedir configuration.
 408       *
 409       * Copied from GalleryPlatform and adjusted to be independent of the G2 framework
 410       *
 411       * @return true if the path is restricted
 412       */
 413      function _isRestrictedByOpenBaseDir($path) {
 414      $slash = DIRECTORY_SEPARATOR;
 415      if (!strncasecmp(PHP_OS, 'win', 3)) {
 416          $separator = ';';
 417          $caseSensitive = false;
 418      } else {
 419          $separator = ':';
 420          $caseSensitive = true;
 421      }
 422  
 423      $openBasedir = @ini_get('open_basedir');
 424      if (empty($openBasedir)) {
 425          return false;
 426      }
 427  
 428      if (($realpath = realpath($path)) === false) {
 429          /*
 430           * PHP's open_basedir will actually take an invalid path, resolve relative
 431           * paths, parse out .. and . and then check against the dir list..
 432           * Here we do an ok job of doing the same, though it isn't perfect.
 433           */
 434          $s = '\\\/';  /* do this by hand because preg_quote() isn't reliable */
 435          if (!preg_match("{^([a-z]+:)?[$s]}i", $path)) {
 436          $path = getcwd() . $slash . $path;
 437          }
 438          for ($realpath = $path, $lastpath = ''; $realpath != $lastpath;) {
 439          $realpath = preg_replace("#[$s]\.([$s]|\$)#", $slash, $lastpath = $realpath);
 440          }
 441  
 442          for ($lastpath = ''; $realpath != $lastpath;) {
 443          $realpath = preg_replace("#[$s][^$s]+[$s]\.\.([$s]|\$)#",
 444                       $slash, $lastpath = $realpath);
 445          }
 446      }
 447  
 448      $function = $caseSensitive ? 'strncmp' : 'strncasecmp';
 449      foreach (explode($separator, $openBasedir) as $baseDir) {
 450          if (($baseDirMatch = realpath($baseDir)) === false) {
 451          $baseDirMatch = $baseDir;
 452          } else if ($baseDir{strlen($baseDir)-1} == $slash) {
 453          /* Realpath will remove a trailing slash.. add it back to avoid prefix match */
 454          $baseDirMatch .= $slash;
 455          }
 456          /* Add slash on path so /dir is accepted if /dir/ is a valid basedir */
 457          if (!$function($baseDirMatch, $realpath . $slash, strlen($baseDirMatch))) {
 458          return false;
 459          }
 460      }
 461  
 462      return true;
 463      }
 464  }
 465  
 466  ?>


Generated: Mon Jul 9 18:01:44 2012 Cross-referenced by PHPXref 0.7