[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/minify/lib/Minify/ -> ImportProcessor.php (source)

   1  <?php
   2  /**

   3   * Class Minify_ImportProcessor

   4   * @package Minify

   5   */
   6  
   7  /**

   8   * Linearize a CSS/JS file by including content specified by CSS import

   9   * declarations. In CSS files, relative URIs are fixed.

  10   *

  11   * @imports will be processed regardless of where they appear in the source

  12   * files; i.e. @imports commented out or in string content will still be

  13   * processed!

  14   *

  15   * This has a unit test but should be considered "experimental".

  16   *

  17   * @package Minify

  18   * @author Stephen Clay <steve@mrclay.org>

  19   * @author Simon Schick <simonsimcity@gmail.com>

  20   */
  21  class Minify_ImportProcessor {
  22  
  23      public static $filesIncluded = array();
  24  
  25      public static function process($file)
  26      {
  27          self::$filesIncluded = array();
  28          self::$_isCss = (strtolower(substr($file, -4)) === '.css');
  29          $obj = new Minify_ImportProcessor(dirname($file));
  30          return $obj->_getContent($file);
  31      }
  32  
  33      // allows callback funcs to know the current directory

  34      private $_currentDir = null;
  35  
  36      // allows callback funcs to know the directory of the file that inherits this one

  37      private $_previewsDir = null;
  38  
  39      // allows _importCB to write the fetched content back to the obj

  40      private $_importedContent = '';
  41  
  42      private static $_isCss = null;
  43  
  44      /**

  45       * @param String $currentDir

  46       * @param String $previewsDir Is only used internally

  47       */
  48      private function __construct($currentDir, $previewsDir = "")
  49      {
  50          $this->_currentDir = $currentDir;
  51          $this->_previewsDir = $previewsDir;
  52      }
  53  
  54      private function _getContent($file, $is_imported = false)
  55      {
  56          $file = realpath($file);
  57          if (! $file
  58              || in_array($file, self::$filesIncluded)
  59              || false === ($content = @file_get_contents($file))
  60          ) {
  61              // file missing, already included, or failed read

  62              return '';
  63          }
  64          self::$filesIncluded[] = realpath($file);
  65          $this->_currentDir = dirname($file);
  66  
  67          // remove UTF-8 BOM if present

  68          if (pack("CCC",0xef,0xbb,0xbf) === substr($content, 0, 3)) {
  69              $content = substr($content, 3);
  70          }
  71          // ensure uniform EOLs

  72          $content = str_replace("\r\n", "\n", $content);
  73  
  74          // process @imports

  75          $content = preg_replace_callback(
  76              '/
  77                  @import\\s+
  78                  (?:url\\(\\s*)?      # maybe url(
  79                  [\'"]?               # maybe quote
  80                  (.*?)                # 1 = URI
  81                  [\'"]?               # maybe end quote
  82                  (?:\\s*\\))?         # maybe )
  83                  ([a-zA-Z,\\s]*)?     # 2 = media list
  84                  ;                    # end token

  85              /x'
  86              ,array($this, '_importCB')
  87              ,$content
  88          );
  89  
  90          // You only need to rework the import-path if the script is imported

  91          if (self::$_isCss && $is_imported) {
  92              // rewrite remaining relative URIs

  93              $content = preg_replace_callback(
  94                  '/url\\(\\s*([^\\)\\s]+)\\s*\\)/'
  95                  ,array($this, '_urlCB')
  96                  ,$content
  97              );
  98          }
  99  
 100          return $this->_importedContent . $content;
 101      }
 102  
 103      private function _importCB($m)
 104      {
 105          $url = $m[1];
 106          $mediaList = preg_replace('/\\s+/', '', $m[2]);
 107  
 108          if (strpos($url, '://') > 0) {
 109              // protocol, leave in place for CSS, comment for JS

 110              return self::$_isCss
 111                  ? $m[0]
 112                  : "/* Minify_ImportProcessor will not include remote content */";
 113          }
 114          if ('/' === $url[0]) {
 115              // protocol-relative or root path

 116              $url = ltrim($url, '/');
 117              $file = realpath($_SERVER['DOCUMENT_ROOT']) . DIRECTORY_SEPARATOR
 118                  . strtr($url, '/', DIRECTORY_SEPARATOR);
 119          } else {
 120              // relative to current path

 121              $file = $this->_currentDir . DIRECTORY_SEPARATOR
 122                  . strtr($url, '/', DIRECTORY_SEPARATOR);
 123          }
 124          $obj = new Minify_ImportProcessor(dirname($file), $this->_currentDir);
 125          $content = $obj->_getContent($file, true);
 126          if ('' === $content) {
 127              // failed. leave in place for CSS, comment for JS

 128              return self::$_isCss
 129                  ? $m[0]
 130                  : "/* Minify_ImportProcessor could not fetch '{$file}' */";
 131          }
 132          return (!self::$_isCss || preg_match('@(?:^$|\\ball\\b)@', $mediaList))
 133              ? $content
 134              : "@media {$mediaList} {\n{$content}\n}\n";
 135      }
 136  
 137      private function _urlCB($m)
 138      {
 139          // $m[1] is either quoted or not

 140          $quote = ($m[1][0] === "'" || $m[1][0] === '"')
 141              ? $m[1][0]
 142              : '';
 143          $url = ($quote === '')
 144              ? $m[1]
 145              : substr($m[1], 1, strlen($m[1]) - 2);
 146          if ('/' !== $url[0]) {
 147              if (strpos($url, '//') > 0) {
 148                  // probably starts with protocol, do not alter

 149              } else {
 150                  // prepend path with current dir separator (OS-independent)

 151                  $path = $this->_currentDir
 152                      . DIRECTORY_SEPARATOR . strtr($url, '/', DIRECTORY_SEPARATOR);
 153                  // update the relative path by the directory of the file that imported this one

 154                  $url = self::getPathDiff(realpath($this->_previewsDir), $path);
 155              }
 156          }
 157          return "url({$quote}{$url}{$quote})";
 158      }
 159  
 160      /**

 161       * @param string $from

 162       * @param string $to

 163       * @param string $ps

 164       * @return string

 165       */
 166      private function getPathDiff($from, $to, $ps = DIRECTORY_SEPARATOR)
 167      {
 168          $realFrom = $this->truepath($from);
 169          $realTo = $this->truepath($to);
 170  
 171          $arFrom = explode($ps, rtrim($realFrom, $ps));
 172          $arTo = explode($ps, rtrim($realTo, $ps));
 173          while (count($arFrom) && count($arTo) && ($arFrom[0] == $arTo[0]))
 174          {
 175              array_shift($arFrom);
 176              array_shift($arTo);
 177          }
 178          return str_pad("", count($arFrom) * 3, '..' . $ps) . implode($ps, $arTo);
 179      }
 180  
 181      /**

 182       * This function is to replace PHP's extremely buggy realpath().

 183       * @param string $path The original path, can be relative etc.

 184       * @return string The resolved path, it might not exist.

 185       * @see http://stackoverflow.com/questions/4049856/replace-phps-realpath

 186       */
 187      function truepath($path)
 188      {
 189          // whether $path is unix or not

 190          $unipath = strlen($path) == 0 || $path{0} != '/';
 191          // attempts to detect if path is relative in which case, add cwd

 192          if (strpos($path, ':') === false && $unipath)
 193              $path = $this->_currentDir . DIRECTORY_SEPARATOR . $path;
 194  
 195          // resolve path parts (single dot, double dot and double delimiters)

 196          $path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path);
 197          $parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen');
 198          $absolutes = array();
 199          foreach ($parts as $part) {
 200              if ('.' == $part)
 201                  continue;
 202              if ('..' == $part) {
 203                  array_pop($absolutes);
 204              } else {
 205                  $absolutes[] = $part;
 206              }
 207          }
 208          $path = implode(DIRECTORY_SEPARATOR, $absolutes);
 209          // resolve any symlinks

 210          if (file_exists($path) && linkinfo($path) > 0)
 211              $path = readlink($path);
 212          // put initial separator that could have been lost

 213          $path = !$unipath ? '/' . $path : $path;
 214          return $path;
 215      }
 216  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1