PageRenderTime 150ms CodeModel.GetById 33ms RepoModel.GetById 3ms app.codeStats 0ms

/src/Basset/Filter/UriRewriteFilter.php

https://github.com/yuters/basset
PHP | 222 lines | 126 code | 31 blank | 65 comment | 8 complexity | 0cbb48a0bb68a8e0f03be663a69bf208 MD5 | raw file
  1. <?php namespace Basset\Filter;
  2. use Assetic\Asset\AssetInterface;
  3. use Assetic\Filter\FilterInterface;
  4. /**
  5. * UriRewriteFilter is a rewrite and port of the popular CssUriRewrite class written by Steve Clay.
  6. * Original source can be found by following the links below.
  7. *
  8. * @author Steve Clay
  9. * @link <https://github.com/mrclay/minify>
  10. * @license <https://github.com/mrclay/minify/blob/master/LICENSE.txt>
  11. * @package Minify
  12. * @copyright 2008 Steve Clay / Ryan Grove
  13. */
  14. class UriRewriteFilter implements FilterInterface {
  15. /**
  16. * Applications document root. This is typically the public directory.
  17. *
  18. * @var string
  19. */
  20. protected $documentRoot;
  21. /**
  22. * Root directory of the asset.
  23. *
  24. * @var string
  25. */
  26. protected $assetDirectory;
  27. /**
  28. * Array of symbolic links.
  29. *
  30. * @var array
  31. */
  32. protected $symlinks;
  33. /**
  34. * Create a new UriRewriteFilter instance.
  35. *
  36. * @param string $documentRoot
  37. * @param array $symlinks
  38. * @return void
  39. */
  40. public function __construct($documentRoot = null, $symlinks = array())
  41. {
  42. $this->documentRoot = $this->realPath($documentRoot ?: $_SERVER['DOCUMENT_ROOT']);
  43. $this->symlinks = $symlinks;
  44. }
  45. /**
  46. * Apply filter on file load.
  47. *
  48. * @param Assetic\Asset\AssetInterface $asset
  49. * @return void
  50. */
  51. public function filterLoad(AssetInterface $asset){}
  52. /**
  53. * Apply a filter on file dump.
  54. *
  55. * @param Assetic\Asset\AssetInterface $asset
  56. * @return void
  57. */
  58. public function filterDump(AssetInterface $asset)
  59. {
  60. $this->assetDirectory = $this->realPath($asset->getSourceRoot());
  61. $content = $asset->getContent();
  62. // Spin through the symlinks and normalize them.
  63. foreach ($this->symlinks as $link => $target)
  64. {
  65. if ($link == '//')
  66. {
  67. $link = $this->documentRoot;
  68. }
  69. else
  70. {
  71. $link = str_replace('//', $this->documentRoot.'/', $link);
  72. }
  73. $link = strtr($link, '/', DIRECTORY_SEPARATOR);
  74. $this->symlinks[$link] = $this->realPath($target);
  75. }
  76. $content = $this->trimUrls($content);
  77. $content = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/', array($this, 'processUriCallback'), $content);
  78. $content = preg_replace_callback('/url\\(\\s*([^\\)\\s]+)\\s*\\)/', array($this, 'processUriCallback'), $content);
  79. $asset->setContent($content);
  80. }
  81. /**
  82. * Takes a path and transforms it to a real path.
  83. *
  84. * @param string $path
  85. * @return string
  86. */
  87. protected function realPath($path)
  88. {
  89. if ($realPath = realpath($path))
  90. {
  91. $path = $realPath;
  92. }
  93. return rtrim($path, '/\\');
  94. }
  95. /**
  96. * Trims URLs.
  97. *
  98. * @param string $content
  99. * @return string
  100. */
  101. protected function trimUrls($content)
  102. {
  103. return preg_replace('/url\\(\\s*([^\\)]+?)\\s*\\)/x', 'url($1)', $content);
  104. }
  105. /**
  106. * Processes a regular expression callback, determines the URI and returns the rewritten URIs.
  107. *
  108. * @param array $matches
  109. * @return string
  110. */
  111. protected function processUriCallback($matches)
  112. {
  113. $isImport = $matches[0][0] === '@';
  114. // Determine what the quote character and the URI is, if there is one.
  115. $quoteCharacter = $uri = null;
  116. if ($isImport)
  117. {
  118. $quoteCharater = $matches[1];
  119. $uri = $matches[2];
  120. }
  121. else
  122. {
  123. if ($matches[1][0] === "'" or $matches[1][0] === '"')
  124. {
  125. $quoteCharacter = $matches[1][0];
  126. }
  127. if ( ! $quoteCharacter)
  128. {
  129. $uri = $matches[1];
  130. }
  131. else
  132. {
  133. $uri = substr($matches[1], 1, strlen($matches[1]) - 2);
  134. }
  135. }
  136. // Analyze the URI
  137. if ($uri[0] !== '/' and strpos($uri, '//') === false and strpos($uri, 'data') !== 0)
  138. {
  139. $uri = $this->rewriteRelative($uri);
  140. }
  141. if ($isImport)
  142. {
  143. return "@import {$quoteCharacter}{$uri}{$quoteCharacter}";
  144. }
  145. return "url({$quoteCharacter}{$uri}{$quoteCharacter})";
  146. }
  147. /**
  148. * Rewrites a relative URI.
  149. *
  150. * @param string $uri
  151. * @return string
  152. */
  153. protected function rewriteRelative($uri)
  154. {
  155. $path = strtr($this->assetDirectory, '/', DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.strtr($uri, '/', DIRECTORY_SEPARATOR);
  156. foreach ($this->symlinks as $link => $target)
  157. {
  158. if (strpos($path, $target) === 0)
  159. {
  160. $path = $link.substr($path, strlen($target));
  161. break;
  162. }
  163. }
  164. // Strip the document root from the path.
  165. $path = substr($path, strlen($this->documentRoot));
  166. $uri = strtr($path, '/\\', '//');
  167. $uri = $this->removeDots($uri);
  168. return $uri;
  169. }
  170. /**
  171. * Removes dots from a URI.
  172. *
  173. * @param string $uri
  174. * @return string
  175. */
  176. protected function removeDots($uri)
  177. {
  178. $uri = str_replace('/./', '/', $uri);
  179. do
  180. {
  181. $uri = preg_replace('@/[^/]+/\\.\\./@', '/', $uri, 1, $changed);
  182. }
  183. while ($changed);
  184. return $uri;
  185. }
  186. }