/application/library/Thirdpart/Minify/lib/Minify/Source/Factory.php

https://gitlab.com/flyhope/Hiblog · PHP · 179 lines · 111 code · 21 blank · 47 comment · 19 complexity · d662974229737c97866aba0300516db0 MD5 · raw file

  1. <?php
  2. class Minify_Source_Factory {
  3. /**
  4. * @var array
  5. */
  6. protected $options;
  7. /**
  8. * @var callable[]
  9. */
  10. protected $handlers = array();
  11. /**
  12. * @var Minify_Env
  13. */
  14. protected $env;
  15. /**
  16. * @param Minify_Env $env
  17. * @param array $options
  18. *
  19. * noMinPattern : Pattern matched against basename of the filepath (if present). If the pattern
  20. * matches, Minify will try to avoid re-compressing the resource.
  21. *
  22. * fileChecker : Callable responsible for verifying the existence of the file.
  23. *
  24. * resolveDocRoot : If true, a leading "//" will be replaced with the document root.
  25. *
  26. * checkAllowDirs : If true, the filepath will be verified to be within one of the directories
  27. * specified by allowDirs.
  28. *
  29. * allowDirs : Directory paths in which sources can be served.
  30. *
  31. * uploaderHoursBehind : How many hours behind are the file modification times of uploaded files?
  32. * If you upload files from Windows to a non-Windows server, Windows may report
  33. * incorrect mtimes for the files. Immediately after modifying and uploading a
  34. * file, use the touch command to update the mtime on the server. If the mtime
  35. * jumps ahead by a number of hours, set this variable to that number. If the mtime
  36. * moves back, this should not be needed.
  37. *
  38. * @param Minify_CacheInterface $cache Optional cache for handling .less files.
  39. *
  40. */
  41. public function __construct(Minify_Env $env, array $options = array(), Minify_CacheInterface $cache = null)
  42. {
  43. $this->env = $env;
  44. $this->options = array_merge(array(
  45. 'noMinPattern' => '@[-\\.]min\\.(?:[a-zA-Z]+)$@i', // matched against basename
  46. 'fileChecker' => array($this, 'checkIsFile'),
  47. 'resolveDocRoot' => true,
  48. 'checkAllowDirs' => true,
  49. 'allowDirs' => array('//'),
  50. 'uploaderHoursBehind' => 0,
  51. ), $options);
  52. // resolve // in allowDirs
  53. $docRoot = $env->getDocRoot();
  54. foreach ($this->options['allowDirs'] as $i => $dir) {
  55. if (0 === strpos($dir, '//')) {
  56. $this->options['allowDirs'][$i] = $docRoot . substr($dir, 1);
  57. }
  58. }
  59. if ($this->options['fileChecker'] && !is_callable($this->options['fileChecker'])) {
  60. throw new InvalidArgumentException("fileChecker option is not callable");
  61. }
  62. $this->setHandler('~\.less$~i', function ($spec) use ($cache) {
  63. return new Minify_LessCssSource($spec, $cache);
  64. });
  65. $this->setHandler('~\.(js|css)$~i', function ($spec) {
  66. return new Minify_Source($spec);
  67. });
  68. }
  69. /**
  70. * @param string $basenamePattern A pattern tested against basename. E.g. "~\.css$~"
  71. * @param callable $handler Function that recieves a $spec array and returns a Minify_SourceInterface
  72. */
  73. public function setHandler($basenamePattern, $handler)
  74. {
  75. $this->handlers[$basenamePattern] = $handler;
  76. }
  77. /**
  78. * @param string $file
  79. * @return string
  80. *
  81. * @throws Minify_Source_FactoryException
  82. */
  83. public function checkIsFile($file)
  84. {
  85. $realpath = realpath($file);
  86. if (!$realpath) {
  87. throw new Minify_Source_FactoryException("File failed realpath(): $file");
  88. }
  89. $basename = basename($file);
  90. if (0 === strpos($basename, '.')) {
  91. throw new Minify_Source_FactoryException("Filename starts with period (may be hidden): $basename");
  92. }
  93. if (!is_file($realpath) || !is_readable($realpath)) {
  94. throw new Minify_Source_FactoryException("Not a file or isn't readable: $file");
  95. }
  96. return $realpath;
  97. }
  98. /**
  99. * @param mixed $spec
  100. *
  101. * @return Minify_SourceInterface
  102. *
  103. * @throws Minify_Source_FactoryException
  104. */
  105. public function makeSource($spec)
  106. {
  107. $source = null;
  108. if ($spec instanceof Minify_SourceInterface) {
  109. $source = $spec;
  110. }
  111. if (empty($spec['filepath'])) {
  112. // not much we can check
  113. return new Minify_Source($spec);
  114. }
  115. if ($this->options['resolveDocRoot'] && 0 === strpos($spec['filepath'], '//')) {
  116. $spec['filepath'] = $this->env->getDocRoot() . substr($spec['filepath'], 1);
  117. }
  118. if (!empty($this->options['fileChecker'])) {
  119. $spec['filepath'] = call_user_func($this->options['fileChecker'], $spec['filepath']);
  120. }
  121. if ($this->options['checkAllowDirs']) {
  122. foreach ((array)$this->options['allowDirs'] as $allowDir) {
  123. if (strpos($spec['filepath'], realpath($allowDir)) !== 0) {
  124. throw new Minify_Source_FactoryException("File '{$spec['filepath']}' is outside \$allowDirs."
  125. . " If the path is resolved via an alias/symlink, look into the \$min_symlinks option.");
  126. }
  127. }
  128. }
  129. $basename = basename($spec['filepath']);
  130. if ($this->options['noMinPattern'] && preg_match($this->options['noMinPattern'], $basename)) {
  131. if (preg_match('~\.(css|less)$~i', $basename)) {
  132. $spec['minifyOptions']['compress'] = false;
  133. // we still want URI rewriting to work for CSS
  134. } else {
  135. $spec['minifier'] = '';
  136. }
  137. }
  138. $hoursBehind = $this->options['uploaderHoursBehind'];
  139. if ($hoursBehind != 0) {
  140. $spec['uploaderHoursBehind'] = $hoursBehind;
  141. }
  142. foreach ($this->handlers as $basenamePattern => $handler) {
  143. if (preg_match($basenamePattern, $basename)) {
  144. $source = call_user_func($handler, $spec);
  145. break;
  146. }
  147. }
  148. if (!$source) {
  149. throw new Minify_Source_FactoryException("Handler not found for file: $basename");
  150. }
  151. return $source;
  152. }
  153. }