mirror of
				https://github.com/getgrav/grav.git
				synced 2025-10-31 10:25:59 +01:00 
			
		
		
		
	initial commit of new asset pipeline work + user agent handling
This commit is contained in:
		
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -7,6 +7,8 @@ composer.lock | |||||||
| # Grav Specific | # Grav Specific | ||||||
| cache/* | cache/* | ||||||
| !cache/.* | !cache/.* | ||||||
|  | assets/* | ||||||
|  | !assets/.* | ||||||
| logs/* | logs/* | ||||||
| !logs/.* | !logs/.* | ||||||
| images/* | images/* | ||||||
|   | |||||||
| @@ -20,6 +20,8 @@ | |||||||
|         "doctrine/cache": "1.4.*@dev", |         "doctrine/cache": "1.4.*@dev", | ||||||
|         "tracy/tracy": "dev-master", |         "tracy/tracy": "dev-master", | ||||||
|         "gregwar/image": "dev-master", |         "gregwar/image": "dev-master", | ||||||
|         "ircmaxell/password-compat": "1.0.*" |         "ircmaxell/password-compat": "1.0.*", | ||||||
|  |         "mrclay/minify": "dev-master", | ||||||
|  |         "ornicar/php-user-agent": "1.0.*@dev" | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -35,6 +35,7 @@ try { | |||||||
|     $registry->store('Twig', new Twig); |     $registry->store('Twig', new Twig); | ||||||
|     $registry->store('Pages', new Page\Pages); |     $registry->store('Pages', new Page\Pages); | ||||||
|     $registry->store('Taxonomy', new Taxonomy); |     $registry->store('Taxonomy', new Taxonomy); | ||||||
|  |     $registry->store('Assets', new Assets); | ||||||
|  |  | ||||||
|     $grav->process(); |     $grav->process(); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -31,6 +31,13 @@ twig: | |||||||
|   auto_reload: true                     # Refresh cache on changes |   auto_reload: true                     # Refresh cache on changes | ||||||
|   autoescape: false                     # Autoescape Twig vars |   autoescape: false                     # Autoescape Twig vars | ||||||
|  |  | ||||||
|  | assets:                                 # Configuration for Assets Manager (JS, CSS) | ||||||
|  |   css_pipeline: false                   # The CSS pipeline is the unification of multiple CSS resources into one file | ||||||
|  |   css_minify: true                      # Minify the CSS during pipelining | ||||||
|  |   css_rewrite: true                     # Rewrite any CSS relative URLs during pipelining | ||||||
|  |   js_pipeline: false                    # The JS pipeline is the unification of multiple JS resources into one file | ||||||
|  |   js_minify: true                       # Minify the JS during pipelining | ||||||
|  |  | ||||||
| debugger: | debugger: | ||||||
|   enabled: true                         # Enable Grav debugger |   enabled: true                         # Enable Grav debugger | ||||||
|   max_depth: 10                         # How many nested levels to display for objects or arrays |   max_depth: 10                         # How many nested levels to display for objects or arrays | ||||||
|   | |||||||
| @@ -12,6 +12,7 @@ if (!defined('ROOT_DIR')) { | |||||||
| define('USER_PATH', 'user/'); | define('USER_PATH', 'user/'); | ||||||
| define('USER_DIR', ROOT_DIR . USER_PATH); | define('USER_DIR', ROOT_DIR . USER_PATH); | ||||||
| define('SYSTEM_DIR', ROOT_DIR .'system/'); | define('SYSTEM_DIR', ROOT_DIR .'system/'); | ||||||
|  | define('ASSETS_DIR', ROOT_DIR . 'assets/'); | ||||||
| define('CACHE_DIR', ROOT_DIR .'cache/'); | define('CACHE_DIR', ROOT_DIR .'cache/'); | ||||||
| define('IMAGES_DIR', ROOT_DIR . 'images/'); | define('IMAGES_DIR', ROOT_DIR . 'images/'); | ||||||
| define('LOG_DIR', ROOT_DIR .'logs/'); | define('LOG_DIR', ROOT_DIR .'logs/'); | ||||||
|   | |||||||
							
								
								
									
										682
									
								
								system/src/Grav/Common/Assets.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										682
									
								
								system/src/Grav/Common/Assets.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,682 @@ | |||||||
|  | <?php | ||||||
|  | namespace Grav\Common; | ||||||
|  |  | ||||||
|  | use \Tracy\Debugger; | ||||||
|  | use Closure; | ||||||
|  | use Exception; | ||||||
|  | use FilesystemIterator; | ||||||
|  | use RecursiveDirectoryIterator; | ||||||
|  | use RecursiveIteratorIterator; | ||||||
|  | use RegexIterator; | ||||||
|  |  | ||||||
|  | define('CSS_ASSET', true); | ||||||
|  | define('JS_ASSET', false); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * The Wrapper object for handling JS, CSS assets | ||||||
|  |  * | ||||||
|  |  * Based on stolz/assets package modified for use with Grav | ||||||
|  |  * | ||||||
|  |  * | ||||||
|  |  * @author RocketTheme | ||||||
|  |  * @license MIT | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | class Assets | ||||||
|  | { | ||||||
|  |     /** @const Regex to match CSS and JavaScript files */ | ||||||
|  |     const DEFAULT_REGEX = '/.\.(css|js)$/i'; | ||||||
|  |  | ||||||
|  |     /** @const Regex to match CSS files */ | ||||||
|  |     const CSS_REGEX = '/.\.css$/i'; | ||||||
|  |  | ||||||
|  |     /** @const Regex to match JavaScript files */ | ||||||
|  |     const JS_REGEX = '/.\.js$/i'; | ||||||
|  |  | ||||||
|  |     /** @const Regex to match CSS urls */ | ||||||
|  |     const CSS_URL_REGEX = '{url\([\'\"]((?!http|//).*?)[\'\"]\)}'; | ||||||
|  |  | ||||||
|  |     /** @const Regex to match CSS sourcemap comments */ | ||||||
|  |     const CSS_SOURCEMAP_REGEX = '{\/\*# (.*) \*\/}'; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Closure used by the pipeline to fetch assets. | ||||||
|  |      * | ||||||
|  |      * Useful when file_get_contents() function is not available in your PHP | ||||||
|  |      * instalation or when you want to apply any kind of preprocessing to | ||||||
|  |      * your assets before they get pipelined. | ||||||
|  |      * | ||||||
|  |      * The closure will receive as the only parameter a string with the path/URL of the asset and | ||||||
|  |      * it should return the content of the asset file as a string. | ||||||
|  |      * @var Closure | ||||||
|  |      */ | ||||||
|  |     protected $fetch_command; | ||||||
|  |  | ||||||
|  |     protected $css_pipeline = false; | ||||||
|  |     protected $js_pipeline = false; | ||||||
|  |  | ||||||
|  |     protected $collections = array(); | ||||||
|  |     protected $css = array(); | ||||||
|  |     protected $js = array(); | ||||||
|  |  | ||||||
|  |     protected $config; | ||||||
|  |     protected $theme_url; | ||||||
|  |     protected $base_url; | ||||||
|  |  | ||||||
|  |     protected $css_minify = true; | ||||||
|  |     protected $css_rewrite = true; | ||||||
|  |     protected $js_minify = true; | ||||||
|  |  | ||||||
|  |     protected $css_no_pipeline = array(); | ||||||
|  |     protected $js_no_pipeline = array(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     public function __construct(array $options = array()) | ||||||
|  |     { | ||||||
|  |         // Forward config options | ||||||
|  |         if($options) | ||||||
|  |             $this->config($options); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function init() | ||||||
|  |     { | ||||||
|  |         // $this->config = $config; | ||||||
|  |  | ||||||
|  |         $this->config = Registry::get('Config'); | ||||||
|  |         $base_url = $this->config->get('system.base_url_relative'); | ||||||
|  |         $theme = $this->config->get('system.pages.theme'); | ||||||
|  |         $asset_config = (array)$this->config->get('system.assets'); | ||||||
|  |  | ||||||
|  |         $this->config($asset_config); | ||||||
|  |         $this->base_url = $base_url; | ||||||
|  |         $this->theme_url = $base_url .'/'. USER_PATH . basename(THEMES_DIR) .'/'. $theme; | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set up configuration options. | ||||||
|  |      * | ||||||
|  |      * All the class properties except 'js' and 'css' are accepted here. | ||||||
|  |      * Also, an extra option 'autoload' may be passed containing an array of | ||||||
|  |      * assets and/or collections that will be automatically added on startup. | ||||||
|  |      * | ||||||
|  |      * @param  array $options Configurable options. | ||||||
|  |      * @return Manager | ||||||
|  |      * @throws Exception | ||||||
|  |      */ | ||||||
|  |     public function config(array $config) | ||||||
|  |     { | ||||||
|  |         // Set pipeline modes | ||||||
|  |         if(isset($config['css_pipeline'])) | ||||||
|  |             $this->css_pipeline = $config['css_pipeline']; | ||||||
|  |  | ||||||
|  |         if(isset($config['js_pipeline'])) | ||||||
|  |             $this->js_pipeline = $config['js_pipeline']; | ||||||
|  |  | ||||||
|  |         // Pipeline requires public dir | ||||||
|  |         if(($this->js_pipeline || $this->css_pipeline) && ! is_dir(ASSETS_DIR)) | ||||||
|  |             throw new Exception('Assets: Public dir not found'); | ||||||
|  |  | ||||||
|  |         // Set custom pipeline fetch command | ||||||
|  |         if(isset($config['fetch_command']) and ($config['fetch_command'] instanceof Closure)) | ||||||
|  |             $this->fetch_command = $config['fetch_command']; | ||||||
|  |  | ||||||
|  |         // Set CSS Minify state | ||||||
|  |         if(isset($config['css_minify'])) | ||||||
|  |             $this->css_minify = $config['css_minify']; | ||||||
|  |  | ||||||
|  |         if(isset($config['css_rewrite'])) | ||||||
|  |             $this->css_rewrite = $config['css_rewrite']; | ||||||
|  |  | ||||||
|  |         // Set JS Minify state | ||||||
|  |         if(isset($config['js_minify'])) | ||||||
|  |             $this->js_minify = $config['js_minify']; | ||||||
|  |  | ||||||
|  |         // Set collections | ||||||
|  |         if(isset($config['collections']) and is_array($config['collections'])) | ||||||
|  |             $this->collections = $config['collections']; | ||||||
|  |  | ||||||
|  |         // Autoload assets | ||||||
|  |         if(isset($config['autoload']) and is_array($config['autoload'])) | ||||||
|  |         { | ||||||
|  |             foreach($config['autoload'] as $asset) | ||||||
|  |             { | ||||||
|  |                 $this->add($asset); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Add an asset or a collection of assets. | ||||||
|  |      * | ||||||
|  |      * It automatically detects the asset type (JavaScript, CSS or collection). | ||||||
|  |      * You may add more than one asset passing an array as argument. | ||||||
|  |      * | ||||||
|  |      * @param  mixed   $asset | ||||||
|  |      * @param  int     $priority the priority, bigger comes first | ||||||
|  |      * @param  bool    $pipeline false if this should not be pipelined | ||||||
|  |      * @return Manager | ||||||
|  |      */ | ||||||
|  |     public function add($asset, $priority = 10, $pipeline = true) | ||||||
|  |     { | ||||||
|  |         // More than one asset | ||||||
|  |         if(is_array($asset)) | ||||||
|  |         { | ||||||
|  |             foreach($asset as $a) | ||||||
|  |                 $this->add($a, $priority, $pipeline); | ||||||
|  |         } | ||||||
|  |         // Collection | ||||||
|  |         elseif(isset($this->collections[$asset])) | ||||||
|  |         { | ||||||
|  |             $this->add($this->collections[$asset], $priority, $pipeline); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             // JavaScript or CSS | ||||||
|  |             $info = pathinfo($asset); | ||||||
|  |             if(isset($info['extension'])) | ||||||
|  |             { | ||||||
|  |                 $ext = strtolower($info['extension']); | ||||||
|  |                 if($ext === 'css') | ||||||
|  |                     $this->addCss($asset, $priority, $pipeline); | ||||||
|  |                 elseif($ext === 'js') | ||||||
|  |                     $this->addJs($asset, $priority, $pipeline); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Add a CSS asset. | ||||||
|  |      * | ||||||
|  |      * It checks for duplicates. | ||||||
|  |      * You may add more than one asset passing an array as argument. | ||||||
|  |      * | ||||||
|  |      * @param  mixed   $asset | ||||||
|  |      * @param  int     $priority the priority, bigger comes first | ||||||
|  |      * @param  bool    $pipeline false if this should not be pipelined | ||||||
|  |      * @return Manager | ||||||
|  |      */ | ||||||
|  |     public function addCss($asset, $priority = 10, $pipeline = true) | ||||||
|  |     { | ||||||
|  |         if(is_array($asset)) | ||||||
|  |         { | ||||||
|  |             foreach($asset as $a) | ||||||
|  |                 $this->addCss($a, $priority, $pipeline); | ||||||
|  |  | ||||||
|  |             return $this; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if( ! $this->isRemoteLink($asset)) | ||||||
|  |             $asset = $this->buildLocalLink($asset); | ||||||
|  |  | ||||||
|  |         if( ! in_array($asset, $this->css)) | ||||||
|  |             $this->css[] = ['asset'=>$asset, 'priority'=>$priority, 'pipeline'=>$pipeline]; | ||||||
|  |  | ||||||
|  |         return $this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Add a JavaScript asset. | ||||||
|  |      * | ||||||
|  |      * It checks for duplicates. | ||||||
|  |      * You may add more than one asset passing an array as argument. | ||||||
|  |      * | ||||||
|  |      * @param  mixed   $asset | ||||||
|  |      * @param  int     $priority the priority, bigger comes first | ||||||
|  |      * @param  bool    $pipeline false if this should not be pipelined | ||||||
|  |      * @return Manager | ||||||
|  |      */ | ||||||
|  |     public function addJs($asset, $priority = 10, $pipeline = true) | ||||||
|  |     { | ||||||
|  |         if(is_array($asset)) | ||||||
|  |         { | ||||||
|  |             foreach($asset as $a) | ||||||
|  |                 $this->addJs($a, $priority, $pipeline); | ||||||
|  |  | ||||||
|  |             return $this; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if( ! $this->isRemoteLink($asset)) | ||||||
|  |             $asset = $this->buildLocalLink($asset); | ||||||
|  |  | ||||||
|  |         if( ! in_array($asset, $this->js)) | ||||||
|  |             $this->js[] = ['asset'=>$asset, 'priority'=>$priority, 'pipeline'=>$pipeline]; | ||||||
|  |  | ||||||
|  |         return $this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Build the CSS link tags. | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public function css() | ||||||
|  |     { | ||||||
|  |         if( ! $this->css) | ||||||
|  |             return null; | ||||||
|  |  | ||||||
|  |         // Sort array by priorities (larger priority first) | ||||||
|  |         usort($this->css, function ($a, $b) {return $a['priority'] - $b['priority'];}); | ||||||
|  |         $this->css = array_reverse($this->css); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         $output = ''; | ||||||
|  |         if($this->css_pipeline) { | ||||||
|  |             $output .= '<link type="text/css" rel="stylesheet" href="'.$this->pipeline(CSS_ASSET).'" />'."\n"; | ||||||
|  |  | ||||||
|  |             foreach ($this->css_no_pipeline as $file) { | ||||||
|  |                 $output .= '<link type="text/css" rel="stylesheet" href="'.$file['asset'].'" />'."\n"; | ||||||
|  |             } | ||||||
|  |             return $output; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         foreach($this->css as $file) | ||||||
|  |             $output .= '<link type="text/css" rel="stylesheet" href="'.$file['asset'].'" />'."\n"; | ||||||
|  |  | ||||||
|  |         return $output; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Build the JavaScript script tags. | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public function js() | ||||||
|  |     { | ||||||
|  |         if( ! $this->js) | ||||||
|  |             return null; | ||||||
|  |  | ||||||
|  |         // Sort array by priorities (larger priority first) | ||||||
|  |         usort($this->js, function ($a, $b) {return $a['priority'] - $b['priority'];}); | ||||||
|  |         $this->js = array_reverse($this->js); | ||||||
|  |  | ||||||
|  |         $output = ''; | ||||||
|  |         if($this->js_pipeline) { | ||||||
|  |             $output .= '<script type="text/javascript" src="'.$this->pipeline(JS_ASSET).'"></script>'."\n"; | ||||||
|  |             foreach ($this->js_no_pipeline as $file) { | ||||||
|  |                 $output .= '<script type="text/javascript" src="'.$file['asset'].'"></script>'."\n"; | ||||||
|  |             } | ||||||
|  |             return $output; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         foreach($this->js as $file) | ||||||
|  |             $output .= '<script type="text/javascript" src="'.$file['asset'].'"></script>'."\n"; | ||||||
|  |  | ||||||
|  |         return $output; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Add/replace collection. | ||||||
|  |      * | ||||||
|  |      * @param  string  $collectionName | ||||||
|  |      * @param  array   $assets | ||||||
|  |      * @return Manager | ||||||
|  |      */ | ||||||
|  |     public function registerCollection($collectionName, Array $assets) | ||||||
|  |     { | ||||||
|  |         $this->collections[$collectionName] = $assets; | ||||||
|  |  | ||||||
|  |         return $this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Reset all assets. | ||||||
|  |      * | ||||||
|  |      * @return Manager | ||||||
|  |      */ | ||||||
|  |     public function reset() | ||||||
|  |     { | ||||||
|  |         return $this->resetCss()->resetJs(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Reset CSS assets. | ||||||
|  |      * | ||||||
|  |      * @return Manager | ||||||
|  |      */ | ||||||
|  |     public function resetCss() | ||||||
|  |     { | ||||||
|  |         $this->css = array(); | ||||||
|  |  | ||||||
|  |         return $this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Reset JavaScript assets. | ||||||
|  |      * | ||||||
|  |      * @return Manager | ||||||
|  |      */ | ||||||
|  |     public function resetJs() | ||||||
|  |     { | ||||||
|  |         $this->js = array(); | ||||||
|  |  | ||||||
|  |         return $this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Minifiy and concatenate CSS / JS files. | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     protected function pipeline($css = true) | ||||||
|  |     { | ||||||
|  |         $cache = Registry::get('Cache'); | ||||||
|  |         $key = '?'.$cache->getKey(); | ||||||
|  |  | ||||||
|  |         if ($css) { | ||||||
|  |             $file = md5(json_encode($this->css) . $this->js_minify . $this->css_minify . $this->css_rewrite) . '.css'; | ||||||
|  |             foreach ($this->css as $id => $asset) { | ||||||
|  |                 if (!$asset['pipeline']) { | ||||||
|  |                     $this->css_no_pipeline[] = $asset; | ||||||
|  |                     unset($this->css[$id]); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             $file = md5(json_encode($this->js) . $this->js_minify . $this->css_minify . $this->css_rewrite) . '.js'; | ||||||
|  |             foreach ($this->js as $id => $asset) { | ||||||
|  |                 if (!$asset['pipeline']) { | ||||||
|  |                     $this->js_no_pipeline[] = $asset; | ||||||
|  |                     unset($this->js[$id]); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $relative_path = "{$this->base_url}/".basename(ASSETS_DIR)."/{$file}"; | ||||||
|  |         $absolute_path = ASSETS_DIR.$file; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         // If pipeline exist return it | ||||||
|  |         if(file_exists($absolute_path)) | ||||||
|  |             return $relative_path . $key; | ||||||
|  |  | ||||||
|  |         // Concatenate files | ||||||
|  |         if ($css) { | ||||||
|  |             $buffer = $this->gatherLinks($this->css, CSS_ASSET); | ||||||
|  |             if ($this->css_minify) { | ||||||
|  |                 $min = new \CSSmin(); | ||||||
|  |                 $buffer = $min->run($buffer); | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             $buffer = $this->gatherLinks($this->js, JS_ASSET); | ||||||
|  |             if ($this->js_minify) { | ||||||
|  |                 $buffer = \JSMin::minify($buffer); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Write file | ||||||
|  |         file_put_contents($absolute_path, $buffer); | ||||||
|  |  | ||||||
|  |         return $relative_path . $key; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Download and concatenate the content of several links. | ||||||
|  |      * | ||||||
|  |      * @param  array  $links | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     protected function gatherLinks(array $links, $css = true) | ||||||
|  |     { | ||||||
|  |         $buffer = ''; | ||||||
|  |         $local = true; | ||||||
|  |  | ||||||
|  |         foreach($links as $asset) | ||||||
|  |         { | ||||||
|  |             $link = $asset['asset']; | ||||||
|  |  | ||||||
|  |             if($this->isRemoteLink($link)) { | ||||||
|  |                 $local = false; | ||||||
|  |                 if('//' === substr($link, 0, 2)) | ||||||
|  |                     $link = 'http:' . $link; | ||||||
|  |             } else { | ||||||
|  |                 $relative_path = str_replace($this->base_url.'/', '', $link); | ||||||
|  |                 $relative_dir = dirname ($relative_path); | ||||||
|  |                 $link = ROOT_DIR . $relative_path; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             $file = ($this->fetch_command instanceof Closure) ? $this->fetch_command->__invoke($link) : file_get_contents($link); | ||||||
|  |             $buffer .= $file; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // If this is CSS + the file is local + rewrite enabled | ||||||
|  |         if ($css && $local && $this->css_rewrite) { | ||||||
|  |             $buffer = $this->cssRewrite($buffer, $relative_dir); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Pull out @imports and move to top | ||||||
|  |         if ($css) { | ||||||
|  |             $buffer = $this->moveImports($buffer); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $buffer; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function moveImports($file) | ||||||
|  |     { | ||||||
|  |         $this->imports = array(); | ||||||
|  |  | ||||||
|  |         $file = preg_replace_callback('{@import(.*);}', | ||||||
|  |             function($matches) { | ||||||
|  |                 $this->imports[] = $matches[0]; | ||||||
|  |                 return ''; | ||||||
|  |             }, | ||||||
|  |             $file | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         return implode("\n", $this->imports) . "\n\n" . $file; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Finds relative CSS urls() and rewrites the URL with an absolute one | ||||||
|  |      * @param  string $file          the css source file | ||||||
|  |      * @param  string $relative_path relative path to the css file | ||||||
|  |      * @return [type]                [description] | ||||||
|  |      */ | ||||||
|  |     protected function cssRewrite($file, $relative_path) | ||||||
|  |     { | ||||||
|  |  | ||||||
|  |         // Strip any sourcemap comments | ||||||
|  |         $file = preg_replace(self::CSS_SOURCEMAP_REGEX, '', $file); | ||||||
|  |  | ||||||
|  |         // Find any css url() elements, grab the URLs and calculate an absolute path | ||||||
|  |         // Then replace the old url with the new one | ||||||
|  |         $file = preg_replace_callback(self::CSS_URL_REGEX, | ||||||
|  |                 function($matches) use ($relative_path) { | ||||||
|  |  | ||||||
|  |                     $old_url = $matches[1]; | ||||||
|  |                     $newpath = array(); | ||||||
|  |                     $paths = explode('/', $old_url); | ||||||
|  |  | ||||||
|  |                     foreach ($paths as $path) { | ||||||
|  |                         if ($path == '..') { | ||||||
|  |                             $relative_path = dirname($relative_path); | ||||||
|  |                         } else { | ||||||
|  |                             $newpath[] = $path; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     $new_url = $this->base_url . '/' . $relative_path . '/' . implode('/', $newpath); | ||||||
|  |  | ||||||
|  |                     return str_replace($old_url, $new_url, $matches[0]); | ||||||
|  |                 }, | ||||||
|  |                 $file | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         return $file; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function buildLocalLink($asset) | ||||||
|  |     { | ||||||
|  |  | ||||||
|  |         $matches = $this->assetIsGravPackage($asset); | ||||||
|  |         $base_url = $this->config->get('system.base_url_relative'); | ||||||
|  |  | ||||||
|  |         if($matches === false) | ||||||
|  |             return $base_url . '/' . $asset; | ||||||
|  |  | ||||||
|  |         if($matches[1] == 'theme') { | ||||||
|  |             return $this->theme_url . '/' . $matches[2] . '/' . $matches[3]; | ||||||
|  |         } elseif ($matches[1] == 'plugin') { | ||||||
|  |             return $base_url . '/user/plugins/' . $matches[2] . '/' . $matches[3]; | ||||||
|  |         } else { | ||||||
|  |             return $base_url . '/' . $asset; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function assetIsGravPackage($asset) | ||||||
|  |     { | ||||||
|  |         if(preg_match('{^@([a-z]+)/(.*?):(.*)$}', $asset, $matches)) | ||||||
|  |             return $matches; | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Determine whether a link is local or remote. | ||||||
|  |      * | ||||||
|  |      * Undestands both "http://" and "https://" as well as protocol agnostic links "//" | ||||||
|  |      * | ||||||
|  |      * @param  string $link | ||||||
|  |      * @return bool | ||||||
|  |      */ | ||||||
|  |     protected function isRemoteLink($link) | ||||||
|  |     { | ||||||
|  |         return ('http://' === substr($link, 0, 7) or 'https://' === substr($link, 0, 8) or '//' === substr($link, 0, 2)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get all CSS assets already added. | ||||||
|  |      * | ||||||
|  |      * @return array | ||||||
|  |      */ | ||||||
|  |     public function getCss() | ||||||
|  |     { | ||||||
|  |         return $this->css; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get all JavaScript assets already added. | ||||||
|  |      * | ||||||
|  |      * @return array | ||||||
|  |      */ | ||||||
|  |     public function getJs() | ||||||
|  |     { | ||||||
|  |         return $this->js; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Add all assets matching $pattern within $directory. | ||||||
|  |      * | ||||||
|  |      * @param  string $directory Relative to $this->public_dir | ||||||
|  |      * @param  string $pattern (regex) | ||||||
|  |      * @return Manager | ||||||
|  |      * @throws Exception | ||||||
|  |      */ | ||||||
|  |     public function addDir($directory, $pattern = self::DEFAULT_REGEX) | ||||||
|  |     { | ||||||
|  |         // Check if public_dir exists | ||||||
|  |         if( ! is_dir(ASSETS_DIR)) | ||||||
|  |             throw new Exception('Assets: Public dir not found'); | ||||||
|  |  | ||||||
|  |         // Get files | ||||||
|  |         $files = $this->rglob(ASSETS_DIR . DIRECTORY_SEPARATOR . $directory, $pattern, ASSETS_DIR); | ||||||
|  |  | ||||||
|  |         // No luck? Nothing to do | ||||||
|  |         if( ! $files) | ||||||
|  |             return $this; | ||||||
|  |  | ||||||
|  |         // Add CSS files | ||||||
|  |         if($pattern === self::CSS_REGEX) | ||||||
|  |         { | ||||||
|  |             $this->css = array_unique(array_merge($this->css, $files)); | ||||||
|  |             return $this; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Add JavaScript files | ||||||
|  |         if($pattern === self::JS_REGEX) | ||||||
|  |         { | ||||||
|  |             $this->js = array_unique(array_merge($this->js, $files)); | ||||||
|  |             return $this; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Unknown pattern. We must poll to know the extension :( | ||||||
|  |         foreach($files as $asset) | ||||||
|  |         { | ||||||
|  |             $info = pathinfo($asset); | ||||||
|  |             if(isset($info['extension'])) | ||||||
|  |             { | ||||||
|  |                 $ext = strtolower($info['extension']); | ||||||
|  |                 if($ext === 'css' and ! in_array($asset, $this->css)) | ||||||
|  |                     $this->css[] = $asset; | ||||||
|  |                 elseif($ext === 'js' and ! in_array($asset, $this->js)) | ||||||
|  |                     $this->js[] = $asset; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Add all CSS assets within $directory (relative to public dir). | ||||||
|  |      * | ||||||
|  |      * @param  string $directory Relative to $this->public_dir | ||||||
|  |      * @return Manager | ||||||
|  |      */ | ||||||
|  |     public function addDirCss($directory) | ||||||
|  |     { | ||||||
|  |         return $this->addDir($directory, self::CSS_REGEX); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Add all JavaScript assets within $directory. | ||||||
|  |      * | ||||||
|  |      * @param  string $directory Relative to $this->public_dir | ||||||
|  |      * @return Manager | ||||||
|  |      */ | ||||||
|  |     public function addDirJs($directory) | ||||||
|  |     { | ||||||
|  |         return $this->addDir($directory, self::JS_REGEX); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Recursively get files matching $pattern within $directory. | ||||||
|  |      * | ||||||
|  |      * @param  string $directory | ||||||
|  |      * @param  string $pattern (regex) | ||||||
|  |      * @param  string $ltrim Will be trimed from the left of the file path | ||||||
|  |      * @return array | ||||||
|  |      */ | ||||||
|  |     protected function rglob($directory, $pattern, $ltrim = null) | ||||||
|  |     { | ||||||
|  |         $iterator = new RegexIterator(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory, FilesystemIterator::SKIP_DOTS)), $pattern); | ||||||
|  |         $offset = strlen($ltrim); | ||||||
|  |         $files = array(); | ||||||
|  |  | ||||||
|  |         foreach($iterator as $file) | ||||||
|  |             $files[] = substr($file->getPathname(), $offset); | ||||||
|  |  | ||||||
|  |         return $files; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var Config | ||||||
|  |      */ | ||||||
|  |     protected function priorityCompare($a, $b) | ||||||
|  |     { | ||||||
|  |         return $a ['priority'] - $b ['priority']; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function __toString() { | ||||||
|  |         return ''; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -66,6 +66,11 @@ class Grav extends Getters | |||||||
|      */ |      */ | ||||||
|     protected $twig; |     protected $twig; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var  Assets | ||||||
|  |      */ | ||||||
|  |     protected $assets; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * @var Taxonomy |      * @var Taxonomy | ||||||
|      */ |      */ | ||||||
| @@ -79,6 +84,9 @@ class Grav extends Getters | |||||||
|         // Get the Configuration settings and caching |         // Get the Configuration settings and caching | ||||||
|         $this->config = Registry::get('Config'); |         $this->config = Registry::get('Config'); | ||||||
|  |  | ||||||
|  |         // Get User Agent | ||||||
|  |         $this->user_agent = new \phpUserAgent(); | ||||||
|  |  | ||||||
|         Debugger::$logDirectory = $this->config->get('system.debugger.log.enabled') ? LOG_DIR : null; |         Debugger::$logDirectory = $this->config->get('system.debugger.log.enabled') ? LOG_DIR : null; | ||||||
|         Debugger::$maxDepth = $this->config->get('system.debugger.max_depth'); |         Debugger::$maxDepth = $this->config->get('system.debugger.max_depth'); | ||||||
|  |  | ||||||
| @@ -103,6 +111,11 @@ class Grav extends Getters | |||||||
|         $themes = new Themes(); |         $themes = new Themes(); | ||||||
|         $this->plugins['Theme'] = $themes->load(); |         $this->plugins['Theme'] = $themes->load(); | ||||||
|  |  | ||||||
|  |         // Get assets and fire event to hook onto | ||||||
|  |         $this->assets = Registry::get('Assets'); | ||||||
|  |         $this->assets->init(); | ||||||
|  |         $this->fireEvent('onAfterGetAssets'); | ||||||
|  |  | ||||||
|         // Get twig object |         // Get twig object | ||||||
|         $this->twig = Registry::get('Twig'); |         $this->twig = Registry::get('Twig'); | ||||||
|         $this->twig->init(); |         $this->twig->init(); | ||||||
|   | |||||||
| @@ -28,6 +28,11 @@ class Twig | |||||||
|      */ |      */ | ||||||
|     protected $config; |     protected $config; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var Useragent | ||||||
|  |      */ | ||||||
|  |     protected $user_agent; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * @var Uri |      * @var Uri | ||||||
|      */ |      */ | ||||||
| @@ -69,9 +74,10 @@ class Twig | |||||||
|             // get Grav and Config |             // get Grav and Config | ||||||
|             $this->grav = Registry::get('Grav'); |             $this->grav = Registry::get('Grav'); | ||||||
|             $this->config = $this->grav->config; |             $this->config = $this->grav->config; | ||||||
|  |             $this->user_agent = $this->grav->user_agent; | ||||||
|             $this->uri = Registry::get('Uri'); |             $this->uri = Registry::get('Uri'); | ||||||
|             $this->taxonomy = Registry::get('Taxonomy'); |             $this->taxonomy = Registry::get('Taxonomy'); | ||||||
|  |             $this->assets = Registry::get('Assets'); | ||||||
|  |  | ||||||
|             $this->twig_paths = array(THEMES_DIR . $this->config->get('system.pages.theme') . '/templates'); |             $this->twig_paths = array(THEMES_DIR . $this->config->get('system.pages.theme') . '/templates'); | ||||||
|             $this->grav->fireEvent('onAfterTwigTemplatesPaths'); |             $this->grav->fireEvent('onAfterTwigTemplatesPaths'); | ||||||
| @@ -114,9 +120,9 @@ class Twig | |||||||
|                 'theme_dir' => THEMES_DIR . $theme, |                 'theme_dir' => THEMES_DIR . $theme, | ||||||
|                 'theme_url' => $themeUrl, |                 'theme_url' => $themeUrl, | ||||||
|                 'site' => $this->config->get('site'), |                 'site' => $this->config->get('site'), | ||||||
|                 'stylesheets' => array(), |                 'assets' => $this->assets, | ||||||
|                 'scripts' => array(), |  | ||||||
|                 'taxonomy' => $this->taxonomy, |                 'taxonomy' => $this->taxonomy, | ||||||
|  |                 'user_agent' => $this->user_agent, | ||||||
|             ); |             ); | ||||||
|  |  | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -57,6 +57,26 @@ class CleanCommand extends Command { | |||||||
|         'vendor/ircmaxell/password-compat/version-test.php', |         'vendor/ircmaxell/password-compat/version-test.php', | ||||||
|         'vendor/ircmaxell/password-compat/.travis.yml', |         'vendor/ircmaxell/password-compat/.travis.yml', | ||||||
|         'vendor/ircmaxell/password-compat/test', |         'vendor/ircmaxell/password-compat/test', | ||||||
|  |         'vendor/mrclay/minify/.editorconfig', | ||||||
|  |         'vendor/mrclay/minify/.git', | ||||||
|  |         'vendor/mrclay/minify/.gitignore', | ||||||
|  |         'vendor/mrclay/minify/composer.json', | ||||||
|  |         'vendor/mrclay/minify/min_extras', | ||||||
|  |         'vendor/mrclay/minify/min_unit_tests', | ||||||
|  |         'vendor/mrclay/minify/min/.htaccess', | ||||||
|  |         'vendor/mrclay/minify/min/builder', | ||||||
|  |         'vendor/mrclay/minify/min/config-test.php', | ||||||
|  |         'vendor/mrclay/minify/min/config.php', | ||||||
|  |         'vendor/mrclay/minify/min/groupsConfig.php', | ||||||
|  |         'vendor/mrclay/minify/min/index.php', | ||||||
|  |         'vendor/mrclay/minify/min/quick-test.css', | ||||||
|  |         'vendor/mrclay/minify/min/quick-test.js', | ||||||
|  |         'vendor/mrclay/minify/min/utils.php', | ||||||
|  |         'vendor/ornicar/php-user-agent/.git', | ||||||
|  |         'vendor/ornicar/php-user-agent/.gitignore', | ||||||
|  |         'vendor/ornicar/php-user-agent/composer.json', | ||||||
|  |         'vendor/ornicar/php-user-agent/prove.php', | ||||||
|  |         'vendor/ornicar/php-user-agent/test', | ||||||
|         'vendor/symfony/console/Symfony/Component/Console/composer.json', |         'vendor/symfony/console/Symfony/Component/Console/composer.json', | ||||||
|         'vendor/symfony/console/Symfony/Component/Console/phpunit.xml.dist', |         'vendor/symfony/console/Symfony/Component/Console/phpunit.xml.dist', | ||||||
|         'vendor/symfony/console/Symfony/Component/Console/.gitignore', |         'vendor/symfony/console/Symfony/Component/Console/.gitignore', | ||||||
|   | |||||||
| @@ -13,7 +13,8 @@ class ClearCacheCommand extends Command { | |||||||
|  |  | ||||||
|     protected $paths_to_remove = [ |     protected $paths_to_remove = [ | ||||||
|         'cache', |         'cache', | ||||||
|         'images' |         'images', | ||||||
|  |         'assets' | ||||||
|     ]; |     ]; | ||||||
|  |  | ||||||
|     protected function configure() { |     protected function configure() { | ||||||
|   | |||||||
| @@ -23,6 +23,13 @@ twig: | |||||||
|   auto_reload: true |   auto_reload: true | ||||||
|   autoescape: false |   autoescape: false | ||||||
|  |  | ||||||
|  | assets: | ||||||
|  |   css_pipeline: false | ||||||
|  |   css_minify: true | ||||||
|  |   css_rewrite: true | ||||||
|  |   js_pipeline: false | ||||||
|  |   js_minify: true | ||||||
|  |  | ||||||
| debugger: | debugger: | ||||||
|   enabled: true |   enabled: true | ||||||
|   max_depth: 10 |   max_depth: 10 | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								vendor/autoload.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/autoload.php
									
									
									
									
										vendored
									
									
								
							| @@ -4,4 +4,4 @@ | |||||||
|  |  | ||||||
| require_once __DIR__ . '/composer' . '/autoload_real.php'; | require_once __DIR__ . '/composer' . '/autoload_real.php'; | ||||||
|  |  | ||||||
| return ComposerAutoloaderInit59d31b9205a8126f2a856995d42bb492::getLoader(); | return ComposerAutoloaderInit70d1fc134524e0edbf7795cd92686187::getLoader(); | ||||||
|   | |||||||
							
								
								
									
										50
									
								
								vendor/composer/autoload_classmap.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										50
									
								
								vendor/composer/autoload_classmap.php
									
									
									
									
										vendored
									
									
								
							| @@ -6,6 +6,56 @@ $vendorDir = dirname(dirname(__FILE__)); | |||||||
| $baseDir = dirname($vendorDir); | $baseDir = dirname($vendorDir); | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|  |     'CSSmin' => $vendorDir . '/mrclay/minify/min/lib/CSSmin.php', | ||||||
|  |     'DooDigestAuth' => $vendorDir . '/mrclay/minify/min/lib/DooDigestAuth.php', | ||||||
|  |     'FirePHP' => $vendorDir . '/mrclay/minify/min/lib/FirePHP.php', | ||||||
|  |     'HTTP_ConditionalGet' => $vendorDir . '/mrclay/minify/min/lib/HTTP/ConditionalGet.php', | ||||||
|  |     'HTTP_Encoder' => $vendorDir . '/mrclay/minify/min/lib/HTTP/Encoder.php', | ||||||
|  |     'JSCompilerContext' => $vendorDir . '/mrclay/minify/min/lib/JSMinPlus.php', | ||||||
|  |     'JSMin' => $vendorDir . '/mrclay/minify/min/lib/JSMin.php', | ||||||
|  |     'JSMinPlus' => $vendorDir . '/mrclay/minify/min/lib/JSMinPlus.php', | ||||||
|  |     'JSMin_UnterminatedCommentException' => $vendorDir . '/mrclay/minify/min/lib/JSMin.php', | ||||||
|  |     'JSMin_UnterminatedRegExpException' => $vendorDir . '/mrclay/minify/min/lib/JSMin.php', | ||||||
|  |     'JSMin_UnterminatedStringException' => $vendorDir . '/mrclay/minify/min/lib/JSMin.php', | ||||||
|  |     'JSNode' => $vendorDir . '/mrclay/minify/min/lib/JSMinPlus.php', | ||||||
|  |     'JSParser' => $vendorDir . '/mrclay/minify/min/lib/JSMinPlus.php', | ||||||
|  |     'JSToken' => $vendorDir . '/mrclay/minify/min/lib/JSMinPlus.php', | ||||||
|  |     'JSTokenizer' => $vendorDir . '/mrclay/minify/min/lib/JSMinPlus.php', | ||||||
|  |     'Minify' => $vendorDir . '/mrclay/minify/min/lib/Minify.php', | ||||||
|  |     'Minify_Build' => $vendorDir . '/mrclay/minify/min/lib/Minify/Build.php', | ||||||
|  |     'Minify_CSS' => $vendorDir . '/mrclay/minify/min/lib/Minify/CSS.php', | ||||||
|  |     'Minify_CSS_Compressor' => $vendorDir . '/mrclay/minify/min/lib/Minify/CSS/Compressor.php', | ||||||
|  |     'Minify_CSS_UriRewriter' => $vendorDir . '/mrclay/minify/min/lib/Minify/CSS/UriRewriter.php', | ||||||
|  |     'Minify_CSSmin' => $vendorDir . '/mrclay/minify/min/lib/Minify/CSSmin.php', | ||||||
|  |     'Minify_Cache_APC' => $vendorDir . '/mrclay/minify/min/lib/Minify/Cache/APC.php', | ||||||
|  |     'Minify_Cache_File' => $vendorDir . '/mrclay/minify/min/lib/Minify/Cache/File.php', | ||||||
|  |     'Minify_Cache_Memcache' => $vendorDir . '/mrclay/minify/min/lib/Minify/Cache/Memcache.php', | ||||||
|  |     'Minify_Cache_XCache' => $vendorDir . '/mrclay/minify/min/lib/Minify/Cache/XCache.php', | ||||||
|  |     'Minify_Cache_ZendPlatform' => $vendorDir . '/mrclay/minify/min/lib/Minify/Cache/ZendPlatform.php', | ||||||
|  |     'Minify_ClosureCompiler' => $vendorDir . '/mrclay/minify/min/lib/Minify/ClosureCompiler.php', | ||||||
|  |     'Minify_ClosureCompiler_Exception' => $vendorDir . '/mrclay/minify/min/lib/Minify/ClosureCompiler.php', | ||||||
|  |     'Minify_CommentPreserver' => $vendorDir . '/mrclay/minify/min/lib/Minify/CommentPreserver.php', | ||||||
|  |     'Minify_Controller_Base' => $vendorDir . '/mrclay/minify/min/lib/Minify/Controller/Base.php', | ||||||
|  |     'Minify_Controller_Files' => $vendorDir . '/mrclay/minify/min/lib/Minify/Controller/Files.php', | ||||||
|  |     'Minify_Controller_Groups' => $vendorDir . '/mrclay/minify/min/lib/Minify/Controller/Groups.php', | ||||||
|  |     'Minify_Controller_MinApp' => $vendorDir . '/mrclay/minify/min/lib/Minify/Controller/MinApp.php', | ||||||
|  |     'Minify_Controller_Page' => $vendorDir . '/mrclay/minify/min/lib/Minify/Controller/Page.php', | ||||||
|  |     'Minify_Controller_Version1' => $vendorDir . '/mrclay/minify/min/lib/Minify/Controller/Version1.php', | ||||||
|  |     'Minify_DebugDetector' => $vendorDir . '/mrclay/minify/min/lib/Minify/DebugDetector.php', | ||||||
|  |     'Minify_HTML' => $vendorDir . '/mrclay/minify/min/lib/Minify/HTML.php', | ||||||
|  |     'Minify_HTML_Helper' => $vendorDir . '/mrclay/minify/min/lib/Minify/HTML/Helper.php', | ||||||
|  |     'Minify_ImportProcessor' => $vendorDir . '/mrclay/minify/min/lib/Minify/ImportProcessor.php', | ||||||
|  |     'Minify_JS_ClosureCompiler' => $vendorDir . '/mrclay/minify/min/lib/Minify/JS/ClosureCompiler.php', | ||||||
|  |     'Minify_JS_ClosureCompiler_Exception' => $vendorDir . '/mrclay/minify/min/lib/Minify/JS/ClosureCompiler.php', | ||||||
|  |     'Minify_Lines' => $vendorDir . '/mrclay/minify/min/lib/Minify/Lines.php', | ||||||
|  |     'Minify_Loader' => $vendorDir . '/mrclay/minify/min/lib/Minify/Loader.php', | ||||||
|  |     'Minify_Logger' => $vendorDir . '/mrclay/minify/min/lib/Minify/Logger.php', | ||||||
|  |     'Minify_Packer' => $vendorDir . '/mrclay/minify/min/lib/Minify/Packer.php', | ||||||
|  |     'Minify_Source' => $vendorDir . '/mrclay/minify/min/lib/Minify/Source.php', | ||||||
|  |     'Minify_YUICompressor' => $vendorDir . '/mrclay/minify/min/lib/Minify/YUICompressor.php', | ||||||
|  |     'Minify_YUI_CssCompressor' => $vendorDir . '/mrclay/minify/min/lib/Minify/YUI/CssCompressor.php', | ||||||
|  |     'MrClay\\Cli' => $vendorDir . '/mrclay/minify/min/lib/MrClay/Cli.php', | ||||||
|  |     'MrClay\\Cli\\Arg' => $vendorDir . '/mrclay/minify/min/lib/MrClay/Cli/Arg.php', | ||||||
|     'Tracy\\Bar' => $vendorDir . '/tracy/tracy/src/Tracy/Bar.php', |     'Tracy\\Bar' => $vendorDir . '/tracy/tracy/src/Tracy/Bar.php', | ||||||
|     'Tracy\\BlueScreen' => $vendorDir . '/tracy/tracy/src/Tracy/BlueScreen.php', |     'Tracy\\BlueScreen' => $vendorDir . '/tracy/tracy/src/Tracy/BlueScreen.php', | ||||||
|     'Tracy\\Debugger' => $vendorDir . '/tracy/tracy/src/Tracy/Debugger.php', |     'Tracy\\Debugger' => $vendorDir . '/tracy/tracy/src/Tracy/Debugger.php', | ||||||
|   | |||||||
							
								
								
									
										4
									
								
								vendor/composer/autoload_files.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/composer/autoload_files.php
									
									
									
									
										vendored
									
									
								
							| @@ -6,6 +6,8 @@ $vendorDir = dirname(dirname(__FILE__)); | |||||||
| $baseDir = dirname($vendorDir); | $baseDir = dirname($vendorDir); | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     $vendorDir . '/tracy/tracy/src/shortcuts.php', |  | ||||||
|     $vendorDir . '/ircmaxell/password-compat/lib/password.php', |     $vendorDir . '/ircmaxell/password-compat/lib/password.php', | ||||||
|  |     $vendorDir . '/tracy/tracy/src/shortcuts.php', | ||||||
|  |     $vendorDir . '/ornicar/php-user-agent/lib/phpUserAgent.php', | ||||||
|  |     $vendorDir . '/ornicar/php-user-agent/lib/phpUserAgentStringParser.php', | ||||||
| ); | ); | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								vendor/composer/autoload_real.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								vendor/composer/autoload_real.php
									
									
									
									
										vendored
									
									
								
							| @@ -2,7 +2,7 @@ | |||||||
|  |  | ||||||
| // autoload_real.php @generated by Composer | // autoload_real.php @generated by Composer | ||||||
|  |  | ||||||
| class ComposerAutoloaderInit59d31b9205a8126f2a856995d42bb492 | class ComposerAutoloaderInit70d1fc134524e0edbf7795cd92686187 | ||||||
| { | { | ||||||
|     private static $loader; |     private static $loader; | ||||||
|  |  | ||||||
| @@ -19,9 +19,9 @@ class ComposerAutoloaderInit59d31b9205a8126f2a856995d42bb492 | |||||||
|             return self::$loader; |             return self::$loader; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         spl_autoload_register(array('ComposerAutoloaderInit59d31b9205a8126f2a856995d42bb492', 'loadClassLoader'), true, true); |         spl_autoload_register(array('ComposerAutoloaderInit70d1fc134524e0edbf7795cd92686187', 'loadClassLoader'), true, true); | ||||||
|         self::$loader = $loader = new \Composer\Autoload\ClassLoader(); |         self::$loader = $loader = new \Composer\Autoload\ClassLoader(); | ||||||
|         spl_autoload_unregister(array('ComposerAutoloaderInit59d31b9205a8126f2a856995d42bb492', 'loadClassLoader')); |         spl_autoload_unregister(array('ComposerAutoloaderInit70d1fc134524e0edbf7795cd92686187', 'loadClassLoader')); | ||||||
|  |  | ||||||
|         $map = require __DIR__ . '/autoload_namespaces.php'; |         $map = require __DIR__ . '/autoload_namespaces.php'; | ||||||
|         foreach ($map as $namespace => $path) { |         foreach ($map as $namespace => $path) { | ||||||
| @@ -42,14 +42,14 @@ class ComposerAutoloaderInit59d31b9205a8126f2a856995d42bb492 | |||||||
|  |  | ||||||
|         $includeFiles = require __DIR__ . '/autoload_files.php'; |         $includeFiles = require __DIR__ . '/autoload_files.php'; | ||||||
|         foreach ($includeFiles as $file) { |         foreach ($includeFiles as $file) { | ||||||
|             composerRequire59d31b9205a8126f2a856995d42bb492($file); |             composerRequire70d1fc134524e0edbf7795cd92686187($file); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return $loader; |         return $loader; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| function composerRequire59d31b9205a8126f2a856995d42bb492($file) | function composerRequire70d1fc134524e0edbf7795cd92686187($file) | ||||||
| { | { | ||||||
|     require $file; |     require $file; | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										407
									
								
								vendor/composer/installed.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										407
									
								
								vendor/composer/installed.json
									
									
									
									
										vendored
									
									
								
							| @@ -1,45 +1,4 @@ | |||||||
| [ | [ | ||||||
|     { |  | ||||||
|         "name": "erusev/parsedown", |  | ||||||
|         "version": "dev-master", |  | ||||||
|         "version_normalized": "9999999-dev", |  | ||||||
|         "source": { |  | ||||||
|             "type": "git", |  | ||||||
|             "url": "https://github.com/erusev/parsedown.git", |  | ||||||
|             "reference": "e33ac1c56ea591f21b9cf2fa74356ef708d4e130" |  | ||||||
|         }, |  | ||||||
|         "dist": { |  | ||||||
|             "type": "zip", |  | ||||||
|             "url": "https://api.github.com/repos/erusev/parsedown/zipball/e33ac1c56ea591f21b9cf2fa74356ef708d4e130", |  | ||||||
|             "reference": "e33ac1c56ea591f21b9cf2fa74356ef708d4e130", |  | ||||||
|             "shasum": "" |  | ||||||
|         }, |  | ||||||
|         "time": "2014-06-18 09:27:25", |  | ||||||
|         "type": "library", |  | ||||||
|         "installation-source": "source", |  | ||||||
|         "autoload": { |  | ||||||
|             "psr-0": { |  | ||||||
|                 "Parsedown": "" |  | ||||||
|             } |  | ||||||
|         }, |  | ||||||
|         "notification-url": "https://packagist.org/downloads/", |  | ||||||
|         "license": [ |  | ||||||
|             "MIT" |  | ||||||
|         ], |  | ||||||
|         "authors": [ |  | ||||||
|             { |  | ||||||
|                 "name": "Emanuil Rusev", |  | ||||||
|                 "email": "hello@erusev.com", |  | ||||||
|                 "homepage": "http://erusev.com" |  | ||||||
|             } |  | ||||||
|         ], |  | ||||||
|         "description": "Parser for Markdown.", |  | ||||||
|         "homepage": "http://parsedown.org", |  | ||||||
|         "keywords": [ |  | ||||||
|             "markdown", |  | ||||||
|             "parser" |  | ||||||
|         ] |  | ||||||
|     }, |  | ||||||
|     { |     { | ||||||
|         "name": "doctrine/cache", |         "name": "doctrine/cache", | ||||||
|         "version": "dev-master", |         "version": "dev-master", | ||||||
| @@ -111,67 +70,6 @@ | |||||||
|             "caching" |             "caching" | ||||||
|         ] |         ] | ||||||
|     }, |     }, | ||||||
|     { |  | ||||||
|         "name": "tracy/tracy", |  | ||||||
|         "version": "dev-master", |  | ||||||
|         "version_normalized": "9999999-dev", |  | ||||||
|         "source": { |  | ||||||
|             "type": "git", |  | ||||||
|             "url": "https://github.com/nette/tracy.git", |  | ||||||
|             "reference": "1250ac4907947b28ec66d6e00a337dadaddaad4c" |  | ||||||
|         }, |  | ||||||
|         "dist": { |  | ||||||
|             "type": "zip", |  | ||||||
|             "url": "https://api.github.com/repos/nette/tracy/zipball/1250ac4907947b28ec66d6e00a337dadaddaad4c", |  | ||||||
|             "reference": "1250ac4907947b28ec66d6e00a337dadaddaad4c", |  | ||||||
|             "shasum": "" |  | ||||||
|         }, |  | ||||||
|         "require": { |  | ||||||
|             "php": ">=5.3.1" |  | ||||||
|         }, |  | ||||||
|         "require-dev": { |  | ||||||
|             "nette/tester": "~1.0" |  | ||||||
|         }, |  | ||||||
|         "time": "2014-08-07 17:19:48", |  | ||||||
|         "type": "library", |  | ||||||
|         "extra": { |  | ||||||
|             "branch-alias": { |  | ||||||
|                 "dev-master": "2.3-dev" |  | ||||||
|             } |  | ||||||
|         }, |  | ||||||
|         "installation-source": "source", |  | ||||||
|         "autoload": { |  | ||||||
|             "classmap": [ |  | ||||||
|                 "src/Tracy" |  | ||||||
|             ], |  | ||||||
|             "files": [ |  | ||||||
|                 "src/shortcuts.php" |  | ||||||
|             ] |  | ||||||
|         }, |  | ||||||
|         "notification-url": "https://packagist.org/downloads/", |  | ||||||
|         "license": [ |  | ||||||
|             "BSD-3-Clause", |  | ||||||
|             "GPL-2.0", |  | ||||||
|             "GPL-3.0" |  | ||||||
|         ], |  | ||||||
|         "authors": [ |  | ||||||
|             { |  | ||||||
|                 "name": "David Grudl", |  | ||||||
|                 "homepage": "http://davidgrudl.com" |  | ||||||
|             }, |  | ||||||
|             { |  | ||||||
|                 "name": "Nette Community", |  | ||||||
|                 "homepage": "http://nette.org/contributors" |  | ||||||
|             } |  | ||||||
|         ], |  | ||||||
|         "description": "Tracy: useful PHP debugger", |  | ||||||
|         "homepage": "http://tracy.nette.org", |  | ||||||
|         "keywords": [ |  | ||||||
|             "debug", |  | ||||||
|             "debugger", |  | ||||||
|             "nette" |  | ||||||
|         ] |  | ||||||
|     }, |  | ||||||
|     { |     { | ||||||
|         "name": "gregwar/cache", |         "name": "gregwar/cache", | ||||||
|         "version": "v1.0.9", |         "version": "v1.0.9", | ||||||
| @@ -373,63 +271,6 @@ | |||||||
|         "description": "Symfony Yaml Component", |         "description": "Symfony Yaml Component", | ||||||
|         "homepage": "http://symfony.com" |         "homepage": "http://symfony.com" | ||||||
|     }, |     }, | ||||||
|     { |  | ||||||
|         "name": "symfony/console", |  | ||||||
|         "version": "2.5.x-dev", |  | ||||||
|         "version_normalized": "2.5.9999999.9999999-dev", |  | ||||||
|         "target-dir": "Symfony/Component/Console", |  | ||||||
|         "source": { |  | ||||||
|             "type": "git", |  | ||||||
|             "url": "https://github.com/symfony/Console.git", |  | ||||||
|             "reference": "cd2d1e4bac2206b337326b0140ff475fe9ad5f63" |  | ||||||
|         }, |  | ||||||
|         "dist": { |  | ||||||
|             "type": "zip", |  | ||||||
|             "url": "https://api.github.com/repos/symfony/Console/zipball/cd2d1e4bac2206b337326b0140ff475fe9ad5f63", |  | ||||||
|             "reference": "cd2d1e4bac2206b337326b0140ff475fe9ad5f63", |  | ||||||
|             "shasum": "" |  | ||||||
|         }, |  | ||||||
|         "require": { |  | ||||||
|             "php": ">=5.3.3" |  | ||||||
|         }, |  | ||||||
|         "require-dev": { |  | ||||||
|             "psr/log": "~1.0", |  | ||||||
|             "symfony/event-dispatcher": "~2.1" |  | ||||||
|         }, |  | ||||||
|         "suggest": { |  | ||||||
|             "psr/log": "For using the console logger", |  | ||||||
|             "symfony/event-dispatcher": "" |  | ||||||
|         }, |  | ||||||
|         "time": "2014-08-05 09:00:40", |  | ||||||
|         "type": "library", |  | ||||||
|         "extra": { |  | ||||||
|             "branch-alias": { |  | ||||||
|                 "dev-master": "2.5-dev" |  | ||||||
|             } |  | ||||||
|         }, |  | ||||||
|         "installation-source": "source", |  | ||||||
|         "autoload": { |  | ||||||
|             "psr-0": { |  | ||||||
|                 "Symfony\\Component\\Console\\": "" |  | ||||||
|             } |  | ||||||
|         }, |  | ||||||
|         "notification-url": "https://packagist.org/downloads/", |  | ||||||
|         "license": [ |  | ||||||
|             "MIT" |  | ||||||
|         ], |  | ||||||
|         "authors": [ |  | ||||||
|             { |  | ||||||
|                 "name": "Symfony Community", |  | ||||||
|                 "homepage": "http://symfony.com/contributors" |  | ||||||
|             }, |  | ||||||
|             { |  | ||||||
|                 "name": "Fabien Potencier", |  | ||||||
|                 "email": "fabien@symfony.com" |  | ||||||
|             } |  | ||||||
|         ], |  | ||||||
|         "description": "Symfony Console Component", |  | ||||||
|         "homepage": "http://symfony.com" |  | ||||||
|     }, |  | ||||||
|     { |     { | ||||||
|         "name": "ircmaxell/password-compat", |         "name": "ircmaxell/password-compat", | ||||||
|         "version": "1.0.3", |         "version": "1.0.3", | ||||||
| @@ -470,5 +311,253 @@ | |||||||
|             "hashing", |             "hashing", | ||||||
|             "password" |             "password" | ||||||
|         ] |         ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "name": "erusev/parsedown", | ||||||
|  |         "version": "dev-master", | ||||||
|  |         "version_normalized": "9999999-dev", | ||||||
|  |         "source": { | ||||||
|  |             "type": "git", | ||||||
|  |             "url": "https://github.com/erusev/parsedown.git", | ||||||
|  |             "reference": "9437766539f6f88e748e7b6183ea31f78e154df5" | ||||||
|  |         }, | ||||||
|  |         "dist": { | ||||||
|  |             "type": "zip", | ||||||
|  |             "url": "https://api.github.com/repos/erusev/parsedown/zipball/9437766539f6f88e748e7b6183ea31f78e154df5", | ||||||
|  |             "reference": "9437766539f6f88e748e7b6183ea31f78e154df5", | ||||||
|  |             "shasum": "" | ||||||
|  |         }, | ||||||
|  |         "time": "2014-08-13 22:27:48", | ||||||
|  |         "type": "library", | ||||||
|  |         "installation-source": "source", | ||||||
|  |         "autoload": { | ||||||
|  |             "psr-0": { | ||||||
|  |                 "Parsedown": "" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "notification-url": "https://packagist.org/downloads/", | ||||||
|  |         "license": [ | ||||||
|  |             "MIT" | ||||||
|  |         ], | ||||||
|  |         "authors": [ | ||||||
|  |             { | ||||||
|  |                 "name": "Emanuil Rusev", | ||||||
|  |                 "email": "hello@erusev.com", | ||||||
|  |                 "homepage": "http://erusev.com" | ||||||
|  |             } | ||||||
|  |         ], | ||||||
|  |         "description": "Parser for Markdown.", | ||||||
|  |         "homepage": "http://parsedown.org", | ||||||
|  |         "keywords": [ | ||||||
|  |             "markdown", | ||||||
|  |             "parser" | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "name": "tracy/tracy", | ||||||
|  |         "version": "dev-master", | ||||||
|  |         "version_normalized": "9999999-dev", | ||||||
|  |         "source": { | ||||||
|  |             "type": "git", | ||||||
|  |             "url": "https://github.com/nette/tracy.git", | ||||||
|  |             "reference": "e432452e0a68b2e5adfba2061eba412f51dbab4c" | ||||||
|  |         }, | ||||||
|  |         "dist": { | ||||||
|  |             "type": "zip", | ||||||
|  |             "url": "https://api.github.com/repos/nette/tracy/zipball/e432452e0a68b2e5adfba2061eba412f51dbab4c", | ||||||
|  |             "reference": "e432452e0a68b2e5adfba2061eba412f51dbab4c", | ||||||
|  |             "shasum": "" | ||||||
|  |         }, | ||||||
|  |         "require": { | ||||||
|  |             "php": ">=5.3.1" | ||||||
|  |         }, | ||||||
|  |         "require-dev": { | ||||||
|  |             "nette/tester": "~1.0" | ||||||
|  |         }, | ||||||
|  |         "time": "2014-08-14 17:58:22", | ||||||
|  |         "type": "library", | ||||||
|  |         "extra": { | ||||||
|  |             "branch-alias": { | ||||||
|  |                 "dev-master": "2.3-dev" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "installation-source": "source", | ||||||
|  |         "autoload": { | ||||||
|  |             "classmap": [ | ||||||
|  |                 "src/Tracy" | ||||||
|  |             ], | ||||||
|  |             "files": [ | ||||||
|  |                 "src/shortcuts.php" | ||||||
|  |             ] | ||||||
|  |         }, | ||||||
|  |         "notification-url": "https://packagist.org/downloads/", | ||||||
|  |         "license": [ | ||||||
|  |             "BSD-3-Clause", | ||||||
|  |             "GPL-2.0", | ||||||
|  |             "GPL-3.0" | ||||||
|  |         ], | ||||||
|  |         "authors": [ | ||||||
|  |             { | ||||||
|  |                 "name": "David Grudl", | ||||||
|  |                 "homepage": "http://davidgrudl.com" | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "name": "Nette Community", | ||||||
|  |                 "homepage": "http://nette.org/contributors" | ||||||
|  |             } | ||||||
|  |         ], | ||||||
|  |         "description": "Tracy: useful PHP debugger", | ||||||
|  |         "homepage": "http://tracy.nette.org", | ||||||
|  |         "keywords": [ | ||||||
|  |             "debug", | ||||||
|  |             "debugger", | ||||||
|  |             "nette" | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "name": "symfony/console", | ||||||
|  |         "version": "2.5.x-dev", | ||||||
|  |         "version_normalized": "2.5.9999999.9999999-dev", | ||||||
|  |         "target-dir": "Symfony/Component/Console", | ||||||
|  |         "source": { | ||||||
|  |             "type": "git", | ||||||
|  |             "url": "https://github.com/symfony/Console.git", | ||||||
|  |             "reference": "748beed2a1e73179c3f5154d33fe6ae100c1aeb1" | ||||||
|  |         }, | ||||||
|  |         "dist": { | ||||||
|  |             "type": "zip", | ||||||
|  |             "url": "https://api.github.com/repos/symfony/Console/zipball/748beed2a1e73179c3f5154d33fe6ae100c1aeb1", | ||||||
|  |             "reference": "748beed2a1e73179c3f5154d33fe6ae100c1aeb1", | ||||||
|  |             "shasum": "" | ||||||
|  |         }, | ||||||
|  |         "require": { | ||||||
|  |             "php": ">=5.3.3" | ||||||
|  |         }, | ||||||
|  |         "require-dev": { | ||||||
|  |             "psr/log": "~1.0", | ||||||
|  |             "symfony/event-dispatcher": "~2.1" | ||||||
|  |         }, | ||||||
|  |         "suggest": { | ||||||
|  |             "psr/log": "For using the console logger", | ||||||
|  |             "symfony/event-dispatcher": "" | ||||||
|  |         }, | ||||||
|  |         "time": "2014-08-14 16:10:54", | ||||||
|  |         "type": "library", | ||||||
|  |         "extra": { | ||||||
|  |             "branch-alias": { | ||||||
|  |                 "dev-master": "2.5-dev" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "installation-source": "source", | ||||||
|  |         "autoload": { | ||||||
|  |             "psr-0": { | ||||||
|  |                 "Symfony\\Component\\Console\\": "" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "notification-url": "https://packagist.org/downloads/", | ||||||
|  |         "license": [ | ||||||
|  |             "MIT" | ||||||
|  |         ], | ||||||
|  |         "authors": [ | ||||||
|  |             { | ||||||
|  |                 "name": "Symfony Community", | ||||||
|  |                 "homepage": "http://symfony.com/contributors" | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "name": "Fabien Potencier", | ||||||
|  |                 "email": "fabien@symfony.com" | ||||||
|  |             } | ||||||
|  |         ], | ||||||
|  |         "description": "Symfony Console Component", | ||||||
|  |         "homepage": "http://symfony.com" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "name": "mrclay/minify", | ||||||
|  |         "version": "dev-master", | ||||||
|  |         "version_normalized": "9999999-dev", | ||||||
|  |         "source": { | ||||||
|  |             "type": "git", | ||||||
|  |             "url": "https://github.com/mrclay/minify.git", | ||||||
|  |             "reference": "fb3931f8cd54a637b2a42170c3a9a1c4da9e69a9" | ||||||
|  |         }, | ||||||
|  |         "dist": { | ||||||
|  |             "type": "zip", | ||||||
|  |             "url": "https://api.github.com/repos/mrclay/minify/zipball/fb3931f8cd54a637b2a42170c3a9a1c4da9e69a9", | ||||||
|  |             "reference": "fb3931f8cd54a637b2a42170c3a9a1c4da9e69a9", | ||||||
|  |             "shasum": "" | ||||||
|  |         }, | ||||||
|  |         "require": { | ||||||
|  |             "ext-pcre": "*", | ||||||
|  |             "php": ">=5.2.1" | ||||||
|  |         }, | ||||||
|  |         "time": "2014-04-03 23:53:48", | ||||||
|  |         "type": "library", | ||||||
|  |         "installation-source": "source", | ||||||
|  |         "autoload": { | ||||||
|  |             "classmap": [ | ||||||
|  |                 "min/lib/" | ||||||
|  |             ] | ||||||
|  |         }, | ||||||
|  |         "notification-url": "https://packagist.org/downloads/", | ||||||
|  |         "license": [ | ||||||
|  |             "BSD-3-Clause" | ||||||
|  |         ], | ||||||
|  |         "authors": [ | ||||||
|  |             { | ||||||
|  |                 "name": "Steve Clay", | ||||||
|  |                 "email": "steve@mrclay.org", | ||||||
|  |                 "homepage": "http://www.mrclay.org/", | ||||||
|  |                 "role": "Developer" | ||||||
|  |             } | ||||||
|  |         ], | ||||||
|  |         "description": "Minify is a PHP5 app that helps you follow several rules for client-side performance. It combines multiple CSS or Javascript files, removes unnecessary whitespace and comments, and serves them with gzip encoding and optimal client-side cache headers", | ||||||
|  |         "homepage": "http://code.google.com/p/minify/" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "name": "ornicar/php-user-agent", | ||||||
|  |         "version": "dev-master", | ||||||
|  |         "version_normalized": "9999999-dev", | ||||||
|  |         "source": { | ||||||
|  |             "type": "git", | ||||||
|  |             "url": "https://github.com/ornicar/php-user-agent.git", | ||||||
|  |             "reference": "91f648fc5080ac1e8a8b51bcd90867b6ddeaf633" | ||||||
|  |         }, | ||||||
|  |         "dist": { | ||||||
|  |             "type": "zip", | ||||||
|  |             "url": "https://api.github.com/repos/ornicar/php-user-agent/zipball/91f648fc5080ac1e8a8b51bcd90867b6ddeaf633", | ||||||
|  |             "reference": "91f648fc5080ac1e8a8b51bcd90867b6ddeaf633", | ||||||
|  |             "shasum": "" | ||||||
|  |         }, | ||||||
|  |         "require": { | ||||||
|  |             "php": ">=5.3.0" | ||||||
|  |         }, | ||||||
|  |         "time": "2013-07-09 13:04:43", | ||||||
|  |         "type": "library", | ||||||
|  |         "extra": { | ||||||
|  |             "branch-alias": { | ||||||
|  |                 "dev-master": "1.0-dev" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "installation-source": "source", | ||||||
|  |         "autoload": { | ||||||
|  |             "files": [ | ||||||
|  |                 "lib/phpUserAgent.php", | ||||||
|  |                 "lib/phpUserAgentStringParser.php" | ||||||
|  |             ] | ||||||
|  |         }, | ||||||
|  |         "notification-url": "https://packagist.org/downloads/", | ||||||
|  |         "license": [ | ||||||
|  |             "MIT" | ||||||
|  |         ], | ||||||
|  |         "authors": [ | ||||||
|  |             { | ||||||
|  |                 "name": "Thibault Duplessis", | ||||||
|  |                 "email": "thibault.duplessis@gmail.com", | ||||||
|  |                 "homepage": "http://ornicar.github.com" | ||||||
|  |             } | ||||||
|  |         ], | ||||||
|  |         "keywords": [ | ||||||
|  |             "user-agent" | ||||||
|  |         ] | ||||||
|     } |     } | ||||||
| ] | ] | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								vendor/erusev/parsedown/Parsedown.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/erusev/parsedown/Parsedown.php
									
									
									
									
										vendored
									
									
								
							| @@ -619,7 +619,7 @@ class Parsedown | |||||||
|  |  | ||||||
|     protected function identifyMarkup($Line) |     protected function identifyMarkup($Line) | ||||||
|     { |     { | ||||||
|         if (preg_match('/^<(\w[\w\d]*)(?:[ ][^>\/]*)?(\/?)[ ]*>/', $Line['text'], $matches)) |         if (preg_match('/^<(\w[\w\d]*)(?:[ ][^>]*)?(\/?)[ ]*>/', $Line['text'], $matches)) | ||||||
|         { |         { | ||||||
|             if (in_array($matches[1], $this->textLevelElements)) |             if (in_array($matches[1], $this->textLevelElements)) | ||||||
|             { |             { | ||||||
|   | |||||||
							
								
								
									
										141
									
								
								vendor/mrclay/minify/HISTORY.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								vendor/mrclay/minify/HISTORY.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,141 @@ | |||||||
|  | Minify Release History | ||||||
|  |  | ||||||
|  | (master) | ||||||
|  |     * Builder styled with Bootstrap (thanks to help from acidvertigo) | ||||||
|  |  | ||||||
|  | Version 2.2.0 | ||||||
|  |     * Fix handling of RegEx in certain situations in JSMin | ||||||
|  |       * Thanks to Vovan-VE for reporting this | ||||||
|  |     * Update composer.json with support info | ||||||
|  |     * Add ability to set ClosureCompiler URL | ||||||
|  |       * Thanks Elan Ruusamäe for the pull request | ||||||
|  |     * Better report of temp directory errors | ||||||
|  |       * Also thanks to Elan Ruusamäe for anatoher pull request | ||||||
|  |     * Updated CSSmin and added Minify_CSSmin wrapper | ||||||
|  |     * Fix windows issue associated with long cache filenames | ||||||
|  |     * Fix issue with web-based tool | ||||||
|  |     * Fix bug in JSMin exceptions | ||||||
|  |     * Fix "about:blank" bug in CSS_UriRewriter | ||||||
|  |     * Cite is no longer a block element in HTML minification | ||||||
|  |     * Allow for definition of custom config locations outside of the min directory | ||||||
|  |       * Thanks Sam Bauers for the pull request | ||||||
|  |     * Allow option for overriding the maximum byte size POST limit for ClosureCompiler and other additions | ||||||
|  |       * Thanks Joscha Feth for the code | ||||||
|  |     * Fixes to file-relative URL identification in UriRewriter | ||||||
|  |     * Allow far-future expiration and file versioning with the "v" querystirng parameter in addition to existing method | ||||||
|  |     * Lots of general code tidy ups | ||||||
|  |  | ||||||
|  | Version 2.1.7 | ||||||
|  |     * Fixes arbitrary file inclusion vulnerability on some systems | ||||||
|  |       * Thanks to Matt Mecham for reporting this | ||||||
|  |  | ||||||
|  | Version 2.1.6 | ||||||
|  |     * JSMin fixes | ||||||
|  |     * Prevents some Closure Compiler API failures | ||||||
|  |     * Uses autoloading for all class loading | ||||||
|  |     * Multiple group support in HTML Helper | ||||||
|  |     * Cache adaptor for XCache | ||||||
|  |     * Allow setting stack-size in YUI Compressor wrapper | ||||||
|  |     * Adds jsCleanComments option to HTML minifier | ||||||
|  |     * Upgrades CSSmin | ||||||
|  |     * CLI script more portable | ||||||
|  |     * Adds composer.json | ||||||
|  |  | ||||||
|  | Version 2.1.5 | ||||||
|  |     * Removed XSS vulnerability | ||||||
|  |     * Disabled builder bby default | ||||||
|  |     * command line tools to minify and rewrite URIs in CSS | ||||||
|  |     * upgrade (optional) JSMin+ library | ||||||
|  |     * more efficient JS minification when using CC/YUIC | ||||||
|  |     * Closure Compiler uses cURL when allow_url_fopen is off | ||||||
|  |     * Missing file notices when using groups | ||||||
|  |  | ||||||
|  | Version 2.1.4 | ||||||
|  |     * Option to minify JS with Closure Compiler API w/ JSMin failover | ||||||
|  |     * Cookie/bookmarklet-based debug mode. No HTML editing! | ||||||
|  |     * Allows 1 file to be missing w/o complete failure | ||||||
|  |     * Combine multiple groups and files in single URI | ||||||
|  |     * More useful HTML helpers for writing versioned URIs | ||||||
|  |     * More detailed error logging, including minifier exceptions | ||||||
|  |     * Builder offers more helpful messages/PHP environment warnings | ||||||
|  |     * Bypass minification based on filename pattern. e.g. foo.min.js / foo-min.css | ||||||
|  |     * JSMin won't choke on common Closure compiler syntaxes (i+ ++j) | ||||||
|  |     * Better caching in IE6 | ||||||
|  |     * Cache ids are influenced by group/file names | ||||||
|  |     * Debug mode for Javascript doesn't break on common XPath strings (Prototype 1.6) | ||||||
|  |     * Removed annoying maxFiles limit | ||||||
|  |     * mbstring.func_overload usage is safer | ||||||
|  |  | ||||||
|  | Version 2.1.3 | ||||||
|  |     * HTTP fixes | ||||||
|  |       * ETag generation now valid (different when gzipped) | ||||||
|  |       * Vary header always sent when Accept-Encoding is sniffed | ||||||
|  |       * Cache-Control no longer has "must-revalidate" due to webkit bug | ||||||
|  |         See: http://mrclay.org/index.php/2009/02/24/safari-4-beta-cache-controlmust-revalidate-bug/ | ||||||
|  |       * Dropped deflate encoding. Browser and proxy support could be buggy. | ||||||
|  |         See: http://stackoverflow.com/questions/883841/ | ||||||
|  |     * File cache now works w/o setting $min_cachePath | ||||||
|  |     * Allow setting contentType in Minify_Source objects | ||||||
|  |     * No more 5.3 deprecation warnings: split() removed | ||||||
|  |  | ||||||
|  | Version 2.1.2 | ||||||
|  |     * Javascript fixes | ||||||
|  |       * Debug mode no longer confused by "*/*" in strings/RegExps (jQuery) | ||||||
|  |       * quote characters inside RegExp literals no longer cause exception | ||||||
|  |       * files ending in single-line comments no longer cause code loss | ||||||
|  |     * CSS: data: URLs no longer mangled | ||||||
|  |     * Optional error logging to Firefox's FirePHP extension | ||||||
|  |     * Unit tests to check for common DOCUMENT_ROOT problems | ||||||
|  |       * DOCUMENT_ROOT no longer overwritten on IIS servers | ||||||
|  |     * Builder app doesn't fail on systems without gzdeflate() | ||||||
|  |     * APC caching class included | ||||||
|  |  | ||||||
|  | Version 2.1.1 | ||||||
|  |     * Bug fix release | ||||||
|  |     * Detection and workarounds for zlib.output_compression and non-PHP encoding modules | ||||||
|  |     * Zlib not required (mod_rewrite, et.al., can still be used for encoding) | ||||||
|  |     * HTML : More IE conditional comments preserved | ||||||
|  |     * Minify_groupUri() utility fixed | ||||||
|  |  | ||||||
|  | Version 2.1.0 | ||||||
|  |     * "min" default application for quick deployment | ||||||
|  |     * Minify URI Builder app & bookmarklet for quickly creating minify URIs | ||||||
|  |     * Relative URIs in CSS file are fixed automatically by default | ||||||
|  |     * "debug" mode for revealing original line #s in combined files | ||||||
|  |     * Better IIS support | ||||||
|  |     * Improved minifier classes: | ||||||
|  |       * JS: preserves IE conditional comments | ||||||
|  |       * CSS: smaller output, preserves more hacks and valid CSS syntax,  | ||||||
|  |              shorter line lengths, other bug fixes | ||||||
|  |       * HTML: smaller output, shorter line lengths, other bug fixes | ||||||
|  |     * Default Cache-Control: max-age of 30 minutes | ||||||
|  |     * Conditional GETs supported even when max-age sent | ||||||
|  |     * Experimental memcache cache class (default is files) | ||||||
|  |     * Minify_Cache_File has flock()s (by default) | ||||||
|  |     * Workaround for Windows mtime reporting bug | ||||||
|  |  | ||||||
|  | Version 2.0.2 beta (2008-06-24) | ||||||
|  |     * Fast new cache system. Cached files served almost 3x as fast. | ||||||
|  |     * Dropped support of compress encoding (though HTTP_Encoder still supports it) | ||||||
|  |  | ||||||
|  | Version 2.0.1 (2008-05-31) | ||||||
|  |     * E_STRICT compliance (Cache_Lite_File). | ||||||
|  |  | ||||||
|  | Version 2.0.0 (2008-05-22) | ||||||
|  |     * Complete code overhaul. Minify is now a PEAR-style class and toolkit  | ||||||
|  |       for building customized minifying file servers. | ||||||
|  |     * Content-Encoding: deflate/gzip/compress, based on request headers | ||||||
|  |     * Expanded CSS and HTML minifiers with test cases | ||||||
|  |     * Easily plug-in 3rd-party minifiers (like Packer) | ||||||
|  |     * Plug-able front end controller allows changing the way files are chosen | ||||||
|  |     * Compression & encoding modules lazy-loaded as needed (304 responses use  | ||||||
|  |       use minimal code) | ||||||
|  |     * Separate utility classes for HTTP encoding and cache control  | ||||||
|  |  | ||||||
|  | Version 1.0.1 (2007-05-05) | ||||||
|  |     * Fixed various problems resolving pathnames when hosted on an NFS mount. | ||||||
|  |     * Fixed 'undefined constant' notice. | ||||||
|  |     * Replaced old JSMin library with a much faster custom implementation. | ||||||
|  |  | ||||||
|  | Version 1.0.0 (2007-05-02) | ||||||
|  |     * First release. | ||||||
							
								
								
									
										26
									
								
								vendor/mrclay/minify/LICENSE.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								vendor/mrclay/minify/LICENSE.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | |||||||
|  | Copyright (c) 2008 Ryan Grove <ryan@wonko.com> | ||||||
|  | Copyright (c) 2008 Steve Clay <steve@mrclay.org> | ||||||
|  | All rights reserved. | ||||||
|  |  | ||||||
|  | Redistribution and use in source and binary forms, with or without | ||||||
|  | modification, are permitted provided that the following conditions are met: | ||||||
|  |  | ||||||
|  |   * Redistributions of source code must retain the above copyright notice, | ||||||
|  |     this list of conditions and the following disclaimer. | ||||||
|  |   * Redistributions in binary form must reproduce the above copyright notice, | ||||||
|  |     this list of conditions and the following disclaimer in the documentation | ||||||
|  |     and/or other materials provided with the distribution. | ||||||
|  |   * Neither the name of this project nor the names of its contributors may be | ||||||
|  |     used to endorse or promote products derived from this software without | ||||||
|  |     specific prior written permission. | ||||||
|  |  | ||||||
|  | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||||||
|  | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||||
|  | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||||
|  | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | ||||||
|  | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||||
|  | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||||
|  | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||||||
|  | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||||
|  | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
							
								
								
									
										181
									
								
								vendor/mrclay/minify/MIN.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								vendor/mrclay/minify/MIN.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,181 @@ | |||||||
|  | The files in the /min/ directory represent the default Minify setup designed to ease | ||||||
|  | integration with your site. This app will combine and minify your Javascript or | ||||||
|  | CSS files and serve them with HTTP compression and cache headers. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | RECOMMENDED | ||||||
|  |  | ||||||
|  | It's recommended to edit /min/config.php to set $min_cachePath to a writeable | ||||||
|  | (by PHP) directory on your system. This will improve performance. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | GETTING STARTED | ||||||
|  |  | ||||||
|  | The quickest way to get started is to use the Minify URI Builder application | ||||||
|  | on your website: http://example.com/min/builder/ | ||||||
|  |  | ||||||
|  |  | ||||||
|  | MINIFYING A SINGLE FILE | ||||||
|  |  | ||||||
|  | Let's say you want to serve this file: | ||||||
|  |   http://example.com/wp-content/themes/default/default.css | ||||||
|  |  | ||||||
|  | Here's the "Minify URL" for this file: | ||||||
|  |   http://example.com/min/?f=wp-content/themes/default/default.css | ||||||
|  |  | ||||||
|  | In other words, the "f" argument is set to the file path from root without the | ||||||
|  | initial "/". As CSS files may contain relative URIs, Minify will automatically | ||||||
|  | "fix" these by rewriting them as root relative. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | COMBINING MULTIPLE FILES IN ONE DOWNLOAD | ||||||
|  |  | ||||||
|  | Separate the paths given to "f" with commas. | ||||||
|  |  | ||||||
|  | Let's say you have CSS files at these URLs: | ||||||
|  |   http://example.com/scripts/jquery-1.2.6.js | ||||||
|  |   http://example.com/scripts/site.js | ||||||
|  |  | ||||||
|  | You can combine these files through Minify by requesting this URL: | ||||||
|  |   http://example.com/min/?f=scripts/jquery-1.2.6.js,scripts/site.js | ||||||
|  |  | ||||||
|  |  | ||||||
|  | SIMPLIFYING URLS WITH A BASE PATH | ||||||
|  |  | ||||||
|  | If you're combining files that share the same ancestor directory, you can use | ||||||
|  | the "b" argument to set the base directory for the "f" argument. Do not include | ||||||
|  | the leading or trailing "/" characters. | ||||||
|  |  | ||||||
|  | E.g., the following URLs will serve the exact same content: | ||||||
|  |   http://example.com/min/?f=scripts/jquery-1.2.6.js,scripts/site.js,scripts/home.js | ||||||
|  |   http://example.com/min/?b=scripts&f=jquery-1.2.6.js,site.js,home.js | ||||||
|  |  | ||||||
|  |  | ||||||
|  | MINIFY URLS IN HTML | ||||||
|  |  | ||||||
|  | In HTML files, don't forget to replace any "&" characters with "&". | ||||||
|  |  | ||||||
|  |  | ||||||
|  | SPECIFYING ALLOWED DIRECTORIES | ||||||
|  |  | ||||||
|  | By default, Minify will serve any *.css/*.js files within the DOCUMENT_ROOT. If | ||||||
|  | you'd prefer to limit Minify's access to certain directories, set the | ||||||
|  | $min_serveOptions['minApp']['allowDirs'] array in config.php. E.g. to limit | ||||||
|  | to the /js and /themes/default directories, use: | ||||||
|  |  | ||||||
|  | $min_serveOptions['minApp']['allowDirs'] = array('//js', '//themes/default'); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | GROUPS: NICER URLS | ||||||
|  |  | ||||||
|  | For nicer URLs, edit groupsConfig.php to pre-specify groups of files | ||||||
|  | to be combined under preset keys. E.g., here's an example configuration in | ||||||
|  | groupsConfig.php: | ||||||
|  |  | ||||||
|  | return array( | ||||||
|  |     'js' => array('//js/Class.js', '//js/email.js') | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | This pre-selects the following files to be combined under the key "js": | ||||||
|  |   http://example.com/js/Class.js | ||||||
|  |   http://example.com/js/email.js | ||||||
|  |  | ||||||
|  | You can now serve these files with this simple URL: | ||||||
|  |   http://example.com/min/?g=js | ||||||
|  |  | ||||||
|  |  | ||||||
|  | GROUPS: SPECIFYING FILES OUTSIDE THE DOC_ROOT | ||||||
|  |  | ||||||
|  | In the groupsConfig.php array, the "//" in the file paths is a shortcut for | ||||||
|  | the DOCUMENT_ROOT, but you can also specify paths from the root of the filesystem | ||||||
|  | or relative to the DOC_ROOT: | ||||||
|  |  | ||||||
|  | return array( | ||||||
|  |     'js' => array( | ||||||
|  |         '//js/file.js'            // file within DOC_ROOT | ||||||
|  |         ,'//../file.js'           // file in parent directory of DOC_ROOT | ||||||
|  |         ,'C:/Users/Steve/file.js' // file anywhere on filesystem | ||||||
|  |     ) | ||||||
|  | ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | COMBINE MULTIPLE GROUPS AND FILES IN ONE URL | ||||||
|  |  | ||||||
|  | E.g.: http://example.com/min/?g=js&f=more/scripts.js | ||||||
|  |  | ||||||
|  | Separate group keys with commas: | ||||||
|  |   http://example.com/min/?g=baseCss,css1&f=moreStyles.css | ||||||
|  |  | ||||||
|  |  | ||||||
|  | FAR-FUTURE EXPIRES HEADERS | ||||||
|  |  | ||||||
|  | Minify can send far-future (one year) Expires headers. To enable this you must | ||||||
|  | add a number or the parameter "v" to the querystring (e.g. /min/?g=js&1234 or | ||||||
|  | /min/?g=js&v=1234) and alter it whenever a source file is changed. If you have a | ||||||
|  | build process you can use a build/source control revision number. | ||||||
|  |  | ||||||
|  | You can alternately use the utility function Minify_getUri() to get a "versioned" | ||||||
|  | Minify URI for use in your HTML. E.g.: | ||||||
|  |  | ||||||
|  | <?php | ||||||
|  | require $_SERVER['DOCUMENT_ROOT'] . '/min/utils.php'; | ||||||
|  |  | ||||||
|  | $jsUri = Minify_getUri('js'); // a key in groupsConfig.php | ||||||
|  | echo "<script src='{$jsUri}'></script>"; | ||||||
|  |  | ||||||
|  | $cssUri = Minify_getUri(array( | ||||||
|  |      '//css/styles1.css' | ||||||
|  |     ,'//css/styles2.css' | ||||||
|  | )); // a list of files | ||||||
|  | echo "<link rel=stylesheet href='{$cssUri}'>"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | STORING CONFIG FILES OUTSIDE THE MINIFY DIRECTORY | ||||||
|  |  | ||||||
|  | It is possible to store config files (min/config.php, min/config-test.php, | ||||||
|  | min/groupsConfig.php) in a custom directory outside the Minify directory. This is | ||||||
|  | useful if you wish to include Minify as an external dependency inside another | ||||||
|  | project via SVN external or Git submodule inclusion. | ||||||
|  |  | ||||||
|  | For example, let's assume you have a Minify directory "min" in your site root. Then | ||||||
|  | you could create a new directory called "min-configs" in the site root. Copy any | ||||||
|  | config files you wish to modify to "min-configs", and modify as desired. | ||||||
|  |  | ||||||
|  | Then create a new file, for example "min.php" in your site root. The contents of | ||||||
|  | this file could look like this: | ||||||
|  |  | ||||||
|  | <?php | ||||||
|  | $customConfigDirectory = dirname(__FILE__) . '/min-configs'; | ||||||
|  | $min_customConfigPaths = array( | ||||||
|  |     'base'   => $customConfigDirectory . '/config.php', | ||||||
|  |     'test'   => $customConfigDirectory . '/config-test.php', | ||||||
|  |     'groups' => $customConfigDirectory . '/groupsConfig.php' | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | include_once 'min/index.php'; | ||||||
|  |  | ||||||
|  | You would then reference min.php in your JS and CSS links instead of min/index.php. | ||||||
|  |  | ||||||
|  | This method will affect those using the Minify_getUri() function. You will need | ||||||
|  | to add options to calls to that function, e.g.: | ||||||
|  |  | ||||||
|  | <?php | ||||||
|  | require $_SERVER['DOCUMENT_ROOT'] . '/min/utils.php'; | ||||||
|  |  | ||||||
|  | $jsUri = Minify_getUri('//js/file.js', array('minAppUri' => '/min.php')); | ||||||
|  | echo "<script src='{$jsUri}'></script>"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | DEBUG MODE | ||||||
|  |  | ||||||
|  | In debug mode, instead of compressing files, Minify sends combined files with | ||||||
|  | comments prepended to each line to show the line number in the original source | ||||||
|  | file. To enable this, set $min_allowDebugFlag to true in config.php and append | ||||||
|  | "&debug=1" to your URIs. E.g. /min/?f=script1.js,script2.js&debug=1 | ||||||
|  |  | ||||||
|  | Known issue: files with comment-like strings/regexps can cause problems in this mode. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | QUESTIONS? | ||||||
|  |  | ||||||
|  | http://groups.google.com/group/minify | ||||||
							
								
								
									
										68
									
								
								vendor/mrclay/minify/README.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								vendor/mrclay/minify/README.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | |||||||
|  | WELCOME TO MINIFY! | ||||||
|  |  | ||||||
|  | Minify is an HTTP content server. It compresses sources of content  | ||||||
|  | (usually files), combines the result and serves it with appropriate  | ||||||
|  | HTTP headers. These headers can allow clients to perform conditional  | ||||||
|  | GETs (serving content only when clients do not have a valid cache)  | ||||||
|  | and tell clients to cache the file for a period of time.  | ||||||
|  | More info: http://code.google.com/p/minify/ | ||||||
|  |  | ||||||
|  |  | ||||||
|  | WORDPRESS USER? | ||||||
|  |  | ||||||
|  | These WP plugins integrate Minify into WordPress's style and script hooks to | ||||||
|  | get you set up faster. | ||||||
|  |   http://wordpress.org/extend/plugins/bwp-minify/ | ||||||
|  |   http://wordpress.org/extend/plugins/w3-total-cache/ | ||||||
|  |  | ||||||
|  |  | ||||||
|  | INSTALLATION | ||||||
|  |  | ||||||
|  | Place the /min/ directory as a child of your DOCUMENT_ROOT | ||||||
|  | directory: i.e. you will have: /home/example/www/min | ||||||
|  |  | ||||||
|  | You can see verify that it is working by visiting these two URLs: | ||||||
|  |   http://example.org/min/?f=min/quick-test.js | ||||||
|  |   http://example.org/min/?f=min/quick-test.css | ||||||
|  |  | ||||||
|  | If your server supports mod_rewrite, this URL should also work: | ||||||
|  |   http://example.org/min/f=min/quick-test.js | ||||||
|  |  | ||||||
|  | CONFIGURATION & USAGE | ||||||
|  |  | ||||||
|  | See the MIN.txt file and http://code.google.com/p/minify/wiki/UserGuide | ||||||
|  |  | ||||||
|  | Minify also comes with a URI Builder application that can help you write URLs | ||||||
|  | for use with Minify or configure groups of files. See here for details: | ||||||
|  |   http://code.google.com/p/minify/wiki/BuilderApp | ||||||
|  |  | ||||||
|  | The cookbook also provides some more advanced options for minification: | ||||||
|  |   http://code.google.com/p/minify/wiki/CookBook | ||||||
|  |  | ||||||
|  | UPGRADING | ||||||
|  |  | ||||||
|  | See UPGRADING.txt for instructions. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | UNIT TESTING: | ||||||
|  |  | ||||||
|  | 1. Place the /min_unit_tests/ directory as a child of your DOCUMENT_ROOT  | ||||||
|  | directory: i.e. you will have: /home/example/www/min_unit_tests | ||||||
|  |  | ||||||
|  | 2. To run unit tests, access: http://example.org/min_unit_tests/test_all.php | ||||||
|  |  | ||||||
|  | (If you wish, the other test_*.php files can be run to test individual | ||||||
|  | components with more verbose output.) | ||||||
|  |  | ||||||
|  | 3. Remove /min_unit_tests/ from your DOCUMENT_ROOT when you are done. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | FILE ENCODINGS | ||||||
|  |  | ||||||
|  | Minify *should* work fine with files encoded in UTF-8 or other 8-bit  | ||||||
|  | encodings like ISO 8859/Windows-1252. By default Minify appends | ||||||
|  | ";charset=utf-8" to the Content-Type headers it sends.  | ||||||
|  |  | ||||||
|  | Leading UTF-8 BOMs are stripped from all sources to prevent  | ||||||
|  | duplication in output files, and files are converted to Unix newlines. | ||||||
|  |  | ||||||
							
								
								
									
										28
									
								
								vendor/mrclay/minify/UPGRADING.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								vendor/mrclay/minify/UPGRADING.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | |||||||
|  | Minify Upgrade Guide | ||||||
|  |  | ||||||
|  | UPGRADING FROM 2.1.* | ||||||
|  |  | ||||||
|  | 1. Rename the following files: | ||||||
|  |  | ||||||
|  |     /min/config.php       --> /min/old_config.php | ||||||
|  |     /min/groupsConfig.php --> /min/old_groupsConfig.php | ||||||
|  |  | ||||||
|  | 2. Overwrite all files in /min (and /min_unit_tests) with those from this zip. | ||||||
|  |  | ||||||
|  | 3. Delete /min/groupsConfig.php | ||||||
|  |  | ||||||
|  | 4. Rename /min/old_groupsConfig.php --> /min/groupsConfig.php | ||||||
|  |  | ||||||
|  | 5. Merge your settings in old_config.php into config.php. | ||||||
|  |  | ||||||
|  | 6. (optional) Delete /min/old_config.php. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | INSTALLING FRESH | ||||||
|  |  | ||||||
|  | See README.txt for instructions on installing this app for the first time. | ||||||
|  |     | ||||||
|  |  | ||||||
|  | SUPPORT | ||||||
|  |  | ||||||
|  | Send a message to http://groups.google.com/group/minify | ||||||
							
								
								
									
										775
									
								
								vendor/mrclay/minify/min/lib/CSSmin.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										775
									
								
								vendor/mrclay/minify/min/lib/CSSmin.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,775 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | /*! | ||||||
|  |  * cssmin.php 2.4.8-2 | ||||||
|  |  * Author: Tubal Martin - http://tubalmartin.me/ | ||||||
|  |  * Repo: https://github.com/tubalmartin/YUI-CSS-compressor-PHP-port | ||||||
|  |  * | ||||||
|  |  * This is a PHP port of the CSS minification tool distributed with YUICompressor, | ||||||
|  |  * itself a port of the cssmin utility by Isaac Schlueter - http://foohack.com/ | ||||||
|  |  * Permission is hereby granted to use the PHP version under the same | ||||||
|  |  * conditions as the YUICompressor. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /*! | ||||||
|  |  * YUI Compressor | ||||||
|  |  * http://developer.yahoo.com/yui/compressor/ | ||||||
|  |  * Author: Julien Lecomte - http://www.julienlecomte.net/ | ||||||
|  |  * Copyright (c) 2013 Yahoo! Inc. All rights reserved. | ||||||
|  |  * The copyrights embodied in the content of this file are licensed | ||||||
|  |  * by Yahoo! Inc. under the BSD (revised) open source license. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | class CSSmin | ||||||
|  | { | ||||||
|  |     const NL = '___YUICSSMIN_PRESERVED_NL___'; | ||||||
|  |     const TOKEN = '___YUICSSMIN_PRESERVED_TOKEN_'; | ||||||
|  |     const COMMENT = '___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_'; | ||||||
|  |     const CLASSCOLON = '___YUICSSMIN_PSEUDOCLASSCOLON___'; | ||||||
|  |     const QUERY_FRACTION = '___YUICSSMIN_QUERY_FRACTION___'; | ||||||
|  |  | ||||||
|  |     private $comments; | ||||||
|  |     private $preserved_tokens; | ||||||
|  |     private $memory_limit; | ||||||
|  |     private $max_execution_time; | ||||||
|  |     private $pcre_backtrack_limit; | ||||||
|  |     private $pcre_recursion_limit; | ||||||
|  |     private $raise_php_limits; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param bool|int $raise_php_limits | ||||||
|  |      * If true, PHP settings will be raised if needed | ||||||
|  |      */ | ||||||
|  |     public function __construct($raise_php_limits = TRUE) | ||||||
|  |     { | ||||||
|  |         // Set suggested PHP limits | ||||||
|  |         $this->memory_limit = 128 * 1048576; // 128MB in bytes | ||||||
|  |         $this->max_execution_time = 60; // 1 min | ||||||
|  |         $this->pcre_backtrack_limit = 1000 * 1000; | ||||||
|  |         $this->pcre_recursion_limit =  500 * 1000; | ||||||
|  |  | ||||||
|  |         $this->raise_php_limits = (bool) $raise_php_limits; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Minify a string of CSS | ||||||
|  |      * @param string $css | ||||||
|  |      * @param int|bool $linebreak_pos | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public function run($css = '', $linebreak_pos = FALSE) | ||||||
|  |     { | ||||||
|  |         if (empty($css)) { | ||||||
|  |             return ''; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($this->raise_php_limits) { | ||||||
|  |             $this->do_raise_php_limits(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->comments = array(); | ||||||
|  |         $this->preserved_tokens = array(); | ||||||
|  |  | ||||||
|  |         $start_index = 0; | ||||||
|  |         $length = strlen($css); | ||||||
|  |  | ||||||
|  |         $css = $this->extract_data_urls($css); | ||||||
|  |  | ||||||
|  |         // collect all comment blocks... | ||||||
|  |         while (($start_index = $this->index_of($css, '/*', $start_index)) >= 0) { | ||||||
|  |             $end_index = $this->index_of($css, '*/', $start_index + 2); | ||||||
|  |             if ($end_index < 0) { | ||||||
|  |                 $end_index = $length; | ||||||
|  |             } | ||||||
|  |             $comment_found = $this->str_slice($css, $start_index + 2, $end_index); | ||||||
|  |             $this->comments[] = $comment_found; | ||||||
|  |             $comment_preserve_string = self::COMMENT . (count($this->comments) - 1) . '___'; | ||||||
|  |             $css = $this->str_slice($css, 0, $start_index + 2) . $comment_preserve_string . $this->str_slice($css, $end_index); | ||||||
|  |             // Set correct start_index: Fixes issue #2528130 | ||||||
|  |             $start_index = $end_index + 2 + strlen($comment_preserve_string) - strlen($comment_found); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // preserve strings so their content doesn't get accidentally minified | ||||||
|  |         $css = preg_replace_callback('/(?:"(?:[^\\\\"]|\\\\.|\\\\)*")|'."(?:'(?:[^\\\\']|\\\\.|\\\\)*')/S", array($this, 'replace_string'), $css); | ||||||
|  |  | ||||||
|  |         // Let's divide css code in chunks of 5.000 chars aprox. | ||||||
|  |         // Reason: PHP's PCRE functions like preg_replace have a "backtrack limit" | ||||||
|  |         // of 100.000 chars by default (php < 5.3.7) so if we're dealing with really | ||||||
|  |         // long strings and a (sub)pattern matches a number of chars greater than | ||||||
|  |         // the backtrack limit number (i.e. /(.*)/s) PCRE functions may fail silently | ||||||
|  |         // returning NULL and $css would be empty. | ||||||
|  |         $charset = ''; | ||||||
|  |         $charset_regexp = '/(@charset)( [^;]+;)/i'; | ||||||
|  |         $css_chunks = array(); | ||||||
|  |         $css_chunk_length = 5000; // aprox size, not exact | ||||||
|  |         $start_index = 0; | ||||||
|  |         $i = $css_chunk_length; // save initial iterations | ||||||
|  |         $l = strlen($css); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         // if the number of characters is 25000 or less, do not chunk | ||||||
|  |         if ($l <= $css_chunk_length) { | ||||||
|  |             $css_chunks[] = $css; | ||||||
|  |         } else { | ||||||
|  |             // chunk css code securely | ||||||
|  |             while ($i < $l) { | ||||||
|  |                 $i += 50; // save iterations | ||||||
|  |                 if ($l - $start_index <= $css_chunk_length || $i >= $l) { | ||||||
|  |                     $css_chunks[] = $this->str_slice($css, $start_index); | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |                 if ($css[$i - 1] === '}' && $i - $start_index > $css_chunk_length) { | ||||||
|  |                     // If there are two ending curly braces }} separated or not by spaces, | ||||||
|  |                     // join them in the same chunk (i.e. @media blocks) | ||||||
|  |                     $next_chunk = substr($css, $i); | ||||||
|  |                     if (preg_match('/^\s*\}/', $next_chunk)) { | ||||||
|  |                         $i = $i + $this->index_of($next_chunk, '}') + 1; | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     $css_chunks[] = $this->str_slice($css, $start_index, $i); | ||||||
|  |                     $start_index = $i; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Minify each chunk | ||||||
|  |         for ($i = 0, $n = count($css_chunks); $i < $n; $i++) { | ||||||
|  |             $css_chunks[$i] = $this->minify($css_chunks[$i], $linebreak_pos); | ||||||
|  |             // Keep the first @charset at-rule found | ||||||
|  |             if (empty($charset) && preg_match($charset_regexp, $css_chunks[$i], $matches)) { | ||||||
|  |                 $charset = strtolower($matches[1]) . $matches[2]; | ||||||
|  |             } | ||||||
|  |             // Delete all @charset at-rules | ||||||
|  |             $css_chunks[$i] = preg_replace($charset_regexp, '', $css_chunks[$i]); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Update the first chunk and push the charset to the top of the file. | ||||||
|  |         $css_chunks[0] = $charset . $css_chunks[0]; | ||||||
|  |  | ||||||
|  |         return implode('', $css_chunks); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Sets the memory limit for this script | ||||||
|  |      * @param int|string $limit | ||||||
|  |      */ | ||||||
|  |     public function set_memory_limit($limit) | ||||||
|  |     { | ||||||
|  |         $this->memory_limit = $this->normalize_int($limit); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Sets the maximum execution time for this script | ||||||
|  |      * @param int|string $seconds | ||||||
|  |      */ | ||||||
|  |     public function set_max_execution_time($seconds) | ||||||
|  |     { | ||||||
|  |         $this->max_execution_time = (int) $seconds; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Sets the PCRE backtrack limit for this script | ||||||
|  |      * @param int $limit | ||||||
|  |      */ | ||||||
|  |     public function set_pcre_backtrack_limit($limit) | ||||||
|  |     { | ||||||
|  |         $this->pcre_backtrack_limit = (int) $limit; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Sets the PCRE recursion limit for this script | ||||||
|  |      * @param int $limit | ||||||
|  |      */ | ||||||
|  |     public function set_pcre_recursion_limit($limit) | ||||||
|  |     { | ||||||
|  |         $this->pcre_recursion_limit = (int) $limit; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Try to configure PHP to use at least the suggested minimum settings | ||||||
|  |      */ | ||||||
|  |     private function do_raise_php_limits() | ||||||
|  |     { | ||||||
|  |         $php_limits = array( | ||||||
|  |             'memory_limit' => $this->memory_limit, | ||||||
|  |             'max_execution_time' => $this->max_execution_time, | ||||||
|  |             'pcre.backtrack_limit' => $this->pcre_backtrack_limit, | ||||||
|  |             'pcre.recursion_limit' =>  $this->pcre_recursion_limit | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         // If current settings are higher respect them. | ||||||
|  |         foreach ($php_limits as $name => $suggested) { | ||||||
|  |             $current = $this->normalize_int(ini_get($name)); | ||||||
|  |             // memory_limit exception: allow -1 for "no memory limit". | ||||||
|  |             if ($current > -1 && ($suggested == -1 || $current < $suggested)) { | ||||||
|  |                 ini_set($name, $suggested); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Does bulk of the minification | ||||||
|  |      * @param string $css | ||||||
|  |      * @param int|bool $linebreak_pos | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     private function minify($css, $linebreak_pos) | ||||||
|  |     { | ||||||
|  |         // strings are safe, now wrestle the comments | ||||||
|  |         for ($i = 0, $max = count($this->comments); $i < $max; $i++) { | ||||||
|  |  | ||||||
|  |             $token = $this->comments[$i]; | ||||||
|  |             $placeholder = '/' . self::COMMENT . $i . '___/'; | ||||||
|  |  | ||||||
|  |             // ! in the first position of the comment means preserve | ||||||
|  |             // so push to the preserved tokens keeping the ! | ||||||
|  |             if (substr($token, 0, 1) === '!') { | ||||||
|  |                 $this->preserved_tokens[] = $token; | ||||||
|  |                 $token_tring = self::TOKEN . (count($this->preserved_tokens) - 1) . '___'; | ||||||
|  |                 $css = preg_replace($placeholder, $token_tring, $css, 1); | ||||||
|  |                 // Preserve new lines for /*! important comments | ||||||
|  |                 $css = preg_replace('/\s*[\n\r\f]+\s*(\/\*'. $token_tring .')/S', self::NL.'$1', $css); | ||||||
|  |                 $css = preg_replace('/('. $token_tring .'\*\/)\s*[\n\r\f]+\s*/', '$1'.self::NL, $css); | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // \ in the last position looks like hack for Mac/IE5 | ||||||
|  |             // shorten that to /*\*/ and the next one to /**/ | ||||||
|  |             if (substr($token, (strlen($token) - 1), 1) === '\\') { | ||||||
|  |                 $this->preserved_tokens[] = '\\'; | ||||||
|  |                 $css = preg_replace($placeholder,  self::TOKEN . (count($this->preserved_tokens) - 1) . '___', $css, 1); | ||||||
|  |                 $i = $i + 1; // attn: advancing the loop | ||||||
|  |                 $this->preserved_tokens[] = ''; | ||||||
|  |                 $css = preg_replace('/' . self::COMMENT . $i . '___/',  self::TOKEN . (count($this->preserved_tokens) - 1) . '___', $css, 1); | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // keep empty comments after child selectors (IE7 hack) | ||||||
|  |             // e.g. html >/**/ body | ||||||
|  |             if (strlen($token) === 0) { | ||||||
|  |                 $start_index = $this->index_of($css, $this->str_slice($placeholder, 1, -1)); | ||||||
|  |                 if ($start_index > 2) { | ||||||
|  |                     if (substr($css, $start_index - 3, 1) === '>') { | ||||||
|  |                         $this->preserved_tokens[] = ''; | ||||||
|  |                         $css = preg_replace($placeholder,  self::TOKEN . (count($this->preserved_tokens) - 1) . '___', $css, 1); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // in all other cases kill the comment | ||||||
|  |             $css = preg_replace('/\/\*' . $this->str_slice($placeholder, 1, -1) . '\*\//', '', $css, 1); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         // Normalize all whitespace strings to single spaces. Easier to work with that way. | ||||||
|  |         $css = preg_replace('/\s+/', ' ', $css); | ||||||
|  |  | ||||||
|  | 		// Fix IE7 issue on matrix filters which browser accept whitespaces between Matrix parameters | ||||||
|  | 		$css = preg_replace_callback('/\s*filter\:\s*progid:DXImageTransform\.Microsoft\.Matrix\(([^\)]+)\)/', array($this, 'preserve_old_IE_specific_matrix_definition'), $css); | ||||||
|  |  | ||||||
|  |         // Shorten & preserve calculations calc(...) since spaces are important | ||||||
|  |         $css = preg_replace_callback('/calc(\(((?:[^\(\)]+|(?1))*)\))/i', array($this, 'replace_calc'), $css); | ||||||
|  |  | ||||||
|  |         // Replace positive sign from numbers preceded by : or a white-space before the leading space is removed | ||||||
|  |         // +1.2em to 1.2em, +.8px to .8px, +2% to 2% | ||||||
|  |         $css = preg_replace('/((?<!\\\\)\:|\s)\+(\.?\d+)/S', '$1$2', $css); | ||||||
|  |  | ||||||
|  |         // Remove leading zeros from integer and float numbers preceded by : or a white-space | ||||||
|  |         // 000.6 to .6, -0.8 to -.8, 0050 to 50, -01.05 to -1.05 | ||||||
|  |         $css = preg_replace('/((?<!\\\\)\:|\s)(\-?)0+(\.?\d+)/S', '$1$2$3', $css); | ||||||
|  |  | ||||||
|  |         // Remove trailing zeros from float numbers preceded by : or a white-space | ||||||
|  |         // -6.0100em to -6.01em, .0100 to .01, 1.200px to 1.2px | ||||||
|  |         $css = preg_replace('/((?<!\\\\)\:|\s)(\-?)(\d?\.\d+?)0+([^\d])/S', '$1$2$3$4', $css); | ||||||
|  |  | ||||||
|  |         // Remove trailing .0 -> -9.0 to -9 | ||||||
|  |         $css = preg_replace('/((?<!\\\\)\:|\s)(\-?\d+)\.0([^\d])/S', '$1$2$3', $css); | ||||||
|  |  | ||||||
|  |         // Replace 0 length numbers with 0 | ||||||
|  |         $css = preg_replace('/((?<!\\\\)\:|\s)\-?\.?0+([^\d])/S', '${1}0$2', $css); | ||||||
|  |  | ||||||
|  |         // Remove the spaces before the things that should not have spaces before them. | ||||||
|  |         // But, be careful not to turn "p :link {...}" into "p:link{...}" | ||||||
|  |         // Swap out any pseudo-class colons with the token, and then swap back. | ||||||
|  |         $css = preg_replace_callback('/(?:^|\})(?:(?:[^\{\:])+\:)+(?:[^\{]*\{)/', array($this, 'replace_colon'), $css); | ||||||
|  |  | ||||||
|  |         // Remove spaces before the things that should not have spaces before them. | ||||||
|  |         $css = preg_replace('/\s+([\!\{\}\;\:\>\+\(\)\]\~\=,])/', '$1', $css); | ||||||
|  |  | ||||||
|  |         // Restore spaces for !important | ||||||
|  |         $css = preg_replace('/\!important/i', ' !important', $css); | ||||||
|  |  | ||||||
|  |         // bring back the colon | ||||||
|  |         $css = preg_replace('/' . self::CLASSCOLON . '/', ':', $css); | ||||||
|  |  | ||||||
|  |         // retain space for special IE6 cases | ||||||
|  |         $css = preg_replace_callback('/\:first\-(line|letter)(\{|,)/i', array($this, 'lowercase_pseudo_first'), $css); | ||||||
|  |  | ||||||
|  |         // no space after the end of a preserved comment | ||||||
|  |         $css = preg_replace('/\*\/ /', '*/', $css); | ||||||
|  |  | ||||||
|  |         // lowercase some popular @directives | ||||||
|  |         $css = preg_replace_callback('/@(font-face|import|(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?keyframe|media|page|namespace)/i', array($this, 'lowercase_directives'), $css); | ||||||
|  |  | ||||||
|  |         // lowercase some more common pseudo-elements | ||||||
|  |         $css = preg_replace_callback('/:(active|after|before|checked|disabled|empty|enabled|first-(?:child|of-type)|focus|hover|last-(?:child|of-type)|link|only-(?:child|of-type)|root|:selection|target|visited)/i', array($this, 'lowercase_pseudo_elements'), $css); | ||||||
|  |  | ||||||
|  |         // lowercase some more common functions | ||||||
|  |         $css = preg_replace_callback('/:(lang|not|nth-child|nth-last-child|nth-last-of-type|nth-of-type|(?:-(?:moz|webkit)-)?any)\(/i', array($this, 'lowercase_common_functions'), $css); | ||||||
|  |  | ||||||
|  |         // lower case some common function that can be values | ||||||
|  |         // NOTE: rgb() isn't useful as we replace with #hex later, as well as and() is already done for us | ||||||
|  |         $css = preg_replace_callback('/([:,\( ]\s*)(attr|color-stop|from|rgba|to|url|(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?(?:calc|max|min|(?:repeating-)?(?:linear|radial)-gradient)|-webkit-gradient)/iS', array($this, 'lowercase_common_functions_values'), $css); | ||||||
|  |  | ||||||
|  |         // Put the space back in some cases, to support stuff like | ||||||
|  |         // @media screen and (-webkit-min-device-pixel-ratio:0){ | ||||||
|  |         $css = preg_replace('/\band\(/i', 'and (', $css); | ||||||
|  |  | ||||||
|  |         // Remove the spaces after the things that should not have spaces after them. | ||||||
|  |         $css = preg_replace('/([\!\{\}\:;\>\+\(\[\~\=,])\s+/S', '$1', $css); | ||||||
|  |  | ||||||
|  |         // remove unnecessary semicolons | ||||||
|  |         $css = preg_replace('/;+\}/', '}', $css); | ||||||
|  |  | ||||||
|  |         // Fix for issue: #2528146 | ||||||
|  |         // Restore semicolon if the last property is prefixed with a `*` (lte IE7 hack) | ||||||
|  |         // to avoid issues on Symbian S60 3.x browsers. | ||||||
|  |         $css = preg_replace('/(\*[a-z0-9\-]+\s*\:[^;\}]+)(\})/', '$1;$2', $css); | ||||||
|  |  | ||||||
|  |         // Replace 0 length units 0(px,em,%) with 0. | ||||||
|  |         $css = preg_replace('/(^|[^0-9])(?:0?\.)?0(?:em|ex|ch|rem|vw|vh|vm|vmin|cm|mm|in|px|pt|pc|%|deg|g?rad|m?s|k?hz)/iS', '${1}0', $css); | ||||||
|  |  | ||||||
|  | 		// 0% step in a keyframe? restore the % unit | ||||||
|  | 		$css = preg_replace_callback('/(@[a-z\-]*?keyframes[^\{]*?\{)(.*?\}\s*\})/iS', array($this, 'replace_keyframe_zero'), $css); | ||||||
|  |  | ||||||
|  |         // Replace 0 0; or 0 0 0; or 0 0 0 0; with 0. | ||||||
|  |         $css = preg_replace('/\:0(?: 0){1,3}(;|\}| \!)/', ':0$1', $css); | ||||||
|  |  | ||||||
|  |         // Fix for issue: #2528142 | ||||||
|  |         // Replace text-shadow:0; with text-shadow:0 0 0; | ||||||
|  |         $css = preg_replace('/(text-shadow\:0)(;|\}| \!)/i', '$1 0 0$2', $css); | ||||||
|  |  | ||||||
|  |         // Replace background-position:0; with background-position:0 0; | ||||||
|  |         // same for transform-origin | ||||||
|  |         // Changing -webkit-mask-position: 0 0 to just a single 0 will result in the second parameter defaulting to 50% (center) | ||||||
|  |         $css = preg_replace('/(background\-position|webkit-mask-position|(?:webkit|moz|o|ms|)\-?transform\-origin)\:0(;|\}| \!)/iS', '$1:0 0$2', $css); | ||||||
|  |  | ||||||
|  |         // Shorten colors from rgb(51,102,153) to #336699, rgb(100%,0%,0%) to #ff0000 (sRGB color space) | ||||||
|  |         // Shorten colors from hsl(0, 100%, 50%) to #ff0000 (sRGB color space) | ||||||
|  |         // This makes it more likely that it'll get further compressed in the next step. | ||||||
|  |         $css = preg_replace_callback('/rgb\s*\(\s*([0-9,\s\-\.\%]+)\s*\)(.{1})/i', array($this, 'rgb_to_hex'), $css); | ||||||
|  |         $css = preg_replace_callback('/hsl\s*\(\s*([0-9,\s\-\.\%]+)\s*\)(.{1})/i', array($this, 'hsl_to_hex'), $css); | ||||||
|  |  | ||||||
|  |         // Shorten colors from #AABBCC to #ABC or short color name. | ||||||
|  |         $css = $this->compress_hex_colors($css); | ||||||
|  |  | ||||||
|  |         // border: none to border:0, outline: none to outline:0 | ||||||
|  |         $css = preg_replace('/(border\-?(?:top|right|bottom|left|)|outline)\:none(;|\}| \!)/iS', '$1:0$2', $css); | ||||||
|  |  | ||||||
|  |         // shorter opacity IE filter | ||||||
|  |         $css = preg_replace('/progid\:DXImageTransform\.Microsoft\.Alpha\(Opacity\=/i', 'alpha(opacity=', $css); | ||||||
|  |  | ||||||
|  |         // Find a fraction that is used for Opera's -o-device-pixel-ratio query | ||||||
|  |         // Add token to add the "\" back in later | ||||||
|  |         $css = preg_replace('/\(([a-z\-]+):([0-9]+)\/([0-9]+)\)/i', '($1:$2'. self::QUERY_FRACTION .'$3)', $css); | ||||||
|  |  | ||||||
|  |         // Remove empty rules. | ||||||
|  |         $css = preg_replace('/[^\};\{\/]+\{\}/S', '', $css); | ||||||
|  |  | ||||||
|  |         // Add "/" back to fix Opera -o-device-pixel-ratio query | ||||||
|  |         $css = preg_replace('/'. self::QUERY_FRACTION .'/', '/', $css); | ||||||
|  |  | ||||||
|  | 		// Replace multiple semi-colons in a row by a single one | ||||||
|  |         // See SF bug #1980989 | ||||||
|  |         $css = preg_replace('/;;+/', ';', $css); | ||||||
|  |  | ||||||
|  |         // Restore new lines for /*! important comments | ||||||
|  |         $css = preg_replace('/'. self::NL .'/', "\n", $css); | ||||||
|  |  | ||||||
|  |         // Lowercase all uppercase properties | ||||||
|  |         $css = preg_replace_callback('/(\{|\;)([A-Z\-]+)(\:)/', array($this, 'lowercase_properties'), $css); | ||||||
|  |  | ||||||
|  |         // Some source control tools don't like it when files containing lines longer | ||||||
|  |         // than, say 8000 characters, are checked in. The linebreak option is used in | ||||||
|  |         // that case to split long lines after a specific column. | ||||||
|  |         if ($linebreak_pos !== FALSE && (int) $linebreak_pos >= 0) { | ||||||
|  |             $linebreak_pos = (int) $linebreak_pos; | ||||||
|  |             $start_index = $i = 0; | ||||||
|  |             while ($i < strlen($css)) { | ||||||
|  |                 $i++; | ||||||
|  |                 if ($css[$i - 1] === '}' && $i - $start_index > $linebreak_pos) { | ||||||
|  |                     $css = $this->str_slice($css, 0, $i) . "\n" . $this->str_slice($css, $i); | ||||||
|  |                     $start_index = $i; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // restore preserved comments and strings in reverse order | ||||||
|  |         for ($i = count($this->preserved_tokens) - 1; $i >= 0; $i--) { | ||||||
|  |             $css = preg_replace('/' . self::TOKEN . $i . '___/', $this->preserved_tokens[$i], $css, 1); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Trim the final string (for any leading or trailing white spaces) | ||||||
|  |         return trim($css); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Utility method to replace all data urls with tokens before we start | ||||||
|  |      * compressing, to avoid performance issues running some of the subsequent | ||||||
|  |      * regexes against large strings chunks. | ||||||
|  |      * | ||||||
|  |      * @param string $css | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     private function extract_data_urls($css) | ||||||
|  |     { | ||||||
|  |         // Leave data urls alone to increase parse performance. | ||||||
|  |         $max_index = strlen($css) - 1; | ||||||
|  |         $append_index = $index = $last_index = $offset = 0; | ||||||
|  |         $sb = array(); | ||||||
|  |         $pattern = '/url\(\s*(["\']?)data\:/i'; | ||||||
|  |  | ||||||
|  |         // Since we need to account for non-base64 data urls, we need to handle | ||||||
|  |         // ' and ) being part of the data string. Hence switching to indexOf, | ||||||
|  |         // to determine whether or not we have matching string terminators and | ||||||
|  |         // handling sb appends directly, instead of using matcher.append* methods. | ||||||
|  |  | ||||||
|  |         while (preg_match($pattern, $css, $m, 0, $offset)) { | ||||||
|  |             $index = $this->index_of($css, $m[0], $offset); | ||||||
|  |             $last_index = $index + strlen($m[0]); | ||||||
|  |             $start_index = $index + 4; // "url(".length() | ||||||
|  |             $end_index = $last_index - 1; | ||||||
|  |             $terminator = $m[1]; // ', " or empty (not quoted) | ||||||
|  |             $found_terminator = FALSE; | ||||||
|  |  | ||||||
|  |             if (strlen($terminator) === 0) { | ||||||
|  |                 $terminator = ')'; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             while ($found_terminator === FALSE && $end_index+1 <= $max_index) { | ||||||
|  |                 $end_index = $this->index_of($css, $terminator, $end_index + 1); | ||||||
|  |  | ||||||
|  |                 // endIndex == 0 doesn't really apply here | ||||||
|  |                 if ($end_index > 0 && substr($css, $end_index - 1, 1) !== '\\') { | ||||||
|  |                     $found_terminator = TRUE; | ||||||
|  |                     if (')' != $terminator) { | ||||||
|  |                         $end_index = $this->index_of($css, ')', $end_index); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // Enough searching, start moving stuff over to the buffer | ||||||
|  |             $sb[] = $this->str_slice($css, $append_index, $index); | ||||||
|  |  | ||||||
|  |             if ($found_terminator) { | ||||||
|  |                 $token = $this->str_slice($css, $start_index, $end_index); | ||||||
|  |                 $token = preg_replace('/\s+/', '', $token); | ||||||
|  |                 $this->preserved_tokens[] = $token; | ||||||
|  |  | ||||||
|  |                 $preserver = 'url(' . self::TOKEN . (count($this->preserved_tokens) - 1) . '___)'; | ||||||
|  |                 $sb[] = $preserver; | ||||||
|  |  | ||||||
|  |                 $append_index = $end_index + 1; | ||||||
|  |             } else { | ||||||
|  |                 // No end terminator found, re-add the whole match. Should we throw/warn here? | ||||||
|  |                 $sb[] = $this->str_slice($css, $index, $last_index); | ||||||
|  |                 $append_index = $last_index; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             $offset = $last_index; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $sb[] = $this->str_slice($css, $append_index); | ||||||
|  |  | ||||||
|  |         return implode('', $sb); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Utility method to compress hex color values of the form #AABBCC to #ABC or short color name. | ||||||
|  |      * | ||||||
|  |      * DOES NOT compress CSS ID selectors which match the above pattern (which would break things). | ||||||
|  |      * e.g. #AddressForm { ... } | ||||||
|  |      * | ||||||
|  |      * DOES NOT compress IE filters, which have hex color values (which would break things). | ||||||
|  |      * e.g. filter: chroma(color="#FFFFFF"); | ||||||
|  |      * | ||||||
|  |      * DOES NOT compress invalid hex values. | ||||||
|  |      * e.g. background-color: #aabbccdd | ||||||
|  |      * | ||||||
|  |      * @param string $css | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     private function compress_hex_colors($css) | ||||||
|  |     { | ||||||
|  |         // Look for hex colors inside { ... } (to avoid IDs) and which don't have a =, or a " in front of them (to avoid filters) | ||||||
|  |         $pattern = '/(\=\s*?["\']?)?#([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])(\}|[^0-9a-f{][^{]*?\})/iS'; | ||||||
|  |         $_index = $index = $last_index = $offset = 0; | ||||||
|  |         $sb = array(); | ||||||
|  |         // See: http://ajaxmin.codeplex.com/wikipage?title=CSS%20Colors | ||||||
|  |         $short_safe = array( | ||||||
|  |             '#808080' => 'gray', | ||||||
|  |             '#008000' => 'green', | ||||||
|  |             '#800000' => 'maroon', | ||||||
|  |             '#000080' => 'navy', | ||||||
|  |             '#808000' => 'olive', | ||||||
|  |             '#ffa500' => 'orange', | ||||||
|  |             '#800080' => 'purple', | ||||||
|  |             '#c0c0c0' => 'silver', | ||||||
|  |             '#008080' => 'teal', | ||||||
|  |             '#f00' => 'red' | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         while (preg_match($pattern, $css, $m, 0, $offset)) { | ||||||
|  |             $index = $this->index_of($css, $m[0], $offset); | ||||||
|  |             $last_index = $index + strlen($m[0]); | ||||||
|  |             $is_filter = $m[1] !== null && $m[1] !== ''; | ||||||
|  |  | ||||||
|  |             $sb[] = $this->str_slice($css, $_index, $index); | ||||||
|  |  | ||||||
|  |             if ($is_filter) { | ||||||
|  |                 // Restore, maintain case, otherwise filter will break | ||||||
|  |                 $sb[] = $m[1] . '#' . $m[2] . $m[3] . $m[4] . $m[5] . $m[6] . $m[7]; | ||||||
|  |             } else { | ||||||
|  |                 if (strtolower($m[2]) == strtolower($m[3]) && | ||||||
|  |                     strtolower($m[4]) == strtolower($m[5]) && | ||||||
|  |                     strtolower($m[6]) == strtolower($m[7])) { | ||||||
|  |                     // Compress. | ||||||
|  |                     $hex = '#' . strtolower($m[3] . $m[5] . $m[7]); | ||||||
|  |                 } else { | ||||||
|  |                     // Non compressible color, restore but lower case. | ||||||
|  |                     $hex = '#' . strtolower($m[2] . $m[3] . $m[4] . $m[5] . $m[6] . $m[7]); | ||||||
|  |                 } | ||||||
|  |                 // replace Hex colors to short safe color names | ||||||
|  |                 $sb[] = array_key_exists($hex, $short_safe) ? $short_safe[$hex] : $hex; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             $_index = $offset = $last_index - strlen($m[8]); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $sb[] = $this->str_slice($css, $_index); | ||||||
|  |  | ||||||
|  |         return implode('', $sb); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* CALLBACKS | ||||||
|  |      * --------------------------------------------------------------------------------------------- | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     private function replace_string($matches) | ||||||
|  |     { | ||||||
|  |         $match = $matches[0]; | ||||||
|  |         $quote = substr($match, 0, 1); | ||||||
|  |         // Must use addcslashes in PHP to avoid parsing of backslashes | ||||||
|  |         $match = addcslashes($this->str_slice($match, 1, -1), '\\'); | ||||||
|  |  | ||||||
|  |         // maybe the string contains a comment-like substring? | ||||||
|  |         // one, maybe more? put'em back then | ||||||
|  |         if (($pos = $this->index_of($match, self::COMMENT)) >= 0) { | ||||||
|  |             for ($i = 0, $max = count($this->comments); $i < $max; $i++) { | ||||||
|  |                 $match = preg_replace('/' . self::COMMENT . $i . '___/', $this->comments[$i], $match, 1); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // minify alpha opacity in filter strings | ||||||
|  |         $match = preg_replace('/progid\:DXImageTransform\.Microsoft\.Alpha\(Opacity\=/i', 'alpha(opacity=', $match); | ||||||
|  |  | ||||||
|  |         $this->preserved_tokens[] = $match; | ||||||
|  |         return $quote . self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . $quote; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function replace_colon($matches) | ||||||
|  |     { | ||||||
|  |         return preg_replace('/\:/', self::CLASSCOLON, $matches[0]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function replace_calc($matches) | ||||||
|  |     { | ||||||
|  |         $this->preserved_tokens[] = trim(preg_replace('/\s*([\*\/\(\),])\s*/', '$1', $matches[2])); | ||||||
|  |         return 'calc('. self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . ')'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | 	private function preserve_old_IE_specific_matrix_definition($matches) | ||||||
|  | 	{ | ||||||
|  | 		$this->preserved_tokens[] = $matches[1]; | ||||||
|  | 		return 'filter:progid:DXImageTransform.Microsoft.Matrix(' . self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . ')'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | 	private function replace_keyframe_zero($matches) | ||||||
|  |     { | ||||||
|  |         return $matches[1] . preg_replace('/0\s*,/', '0%,', preg_replace('/\s*0\s*\{/', '0%{', $matches[2])); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function rgb_to_hex($matches) | ||||||
|  |     { | ||||||
|  |         // Support for percentage values rgb(100%, 0%, 45%); | ||||||
|  |         if ($this->index_of($matches[1], '%') >= 0){ | ||||||
|  |             $rgbcolors = explode(',', str_replace('%', '', $matches[1])); | ||||||
|  |             for ($i = 0; $i < count($rgbcolors); $i++) { | ||||||
|  |                 $rgbcolors[$i] = $this->round_number(floatval($rgbcolors[$i]) * 2.55); | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             $rgbcolors = explode(',', $matches[1]); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Values outside the sRGB color space should be clipped (0-255) | ||||||
|  |         for ($i = 0; $i < count($rgbcolors); $i++) { | ||||||
|  |             $rgbcolors[$i] = $this->clamp_number(intval($rgbcolors[$i], 10), 0, 255); | ||||||
|  |             $rgbcolors[$i] = sprintf("%02x", $rgbcolors[$i]); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Fix for issue #2528093 | ||||||
|  |         if (!preg_match('/[\s\,\);\}]/', $matches[2])){ | ||||||
|  |             $matches[2] = ' ' . $matches[2]; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return '#' . implode('', $rgbcolors) . $matches[2]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function hsl_to_hex($matches) | ||||||
|  |     { | ||||||
|  |         $values = explode(',', str_replace('%', '', $matches[1])); | ||||||
|  |         $h = floatval($values[0]); | ||||||
|  |         $s = floatval($values[1]); | ||||||
|  |         $l = floatval($values[2]); | ||||||
|  |  | ||||||
|  |         // Wrap and clamp, then fraction! | ||||||
|  |         $h = ((($h % 360) + 360) % 360) / 360; | ||||||
|  |         $s = $this->clamp_number($s, 0, 100) / 100; | ||||||
|  |         $l = $this->clamp_number($l, 0, 100) / 100; | ||||||
|  |  | ||||||
|  |         if ($s == 0) { | ||||||
|  |             $r = $g = $b = $this->round_number(255 * $l); | ||||||
|  |         } else { | ||||||
|  |             $v2 = $l < 0.5 ? $l * (1 + $s) : ($l + $s) - ($s * $l); | ||||||
|  |             $v1 = (2 * $l) - $v2; | ||||||
|  |             $r = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h + (1/3))); | ||||||
|  |             $g = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h)); | ||||||
|  |             $b = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h - (1/3))); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $this->rgb_to_hex(array('', $r.','.$g.','.$b, $matches[2])); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function lowercase_pseudo_first($matches) | ||||||
|  |     { | ||||||
|  |         return ':first-'. strtolower($matches[1]) .' '. $matches[2]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function lowercase_directives($matches) | ||||||
|  |     { | ||||||
|  |         return '@'. strtolower($matches[1]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function lowercase_pseudo_elements($matches) | ||||||
|  |     { | ||||||
|  |         return ':'. strtolower($matches[1]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function lowercase_common_functions($matches) | ||||||
|  |     { | ||||||
|  |         return ':'. strtolower($matches[1]) .'('; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function lowercase_common_functions_values($matches) | ||||||
|  |     { | ||||||
|  |         return $matches[1] . strtolower($matches[2]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function lowercase_properties($matches) | ||||||
|  |     { | ||||||
|  |         return $matches[1].strtolower($matches[2]).$matches[3]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* HELPERS | ||||||
|  |      * --------------------------------------------------------------------------------------------- | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     private function hue_to_rgb($v1, $v2, $vh) | ||||||
|  |     { | ||||||
|  |         $vh = $vh < 0 ? $vh + 1 : ($vh > 1 ? $vh - 1 : $vh); | ||||||
|  |         if ($vh * 6 < 1) return $v1 + ($v2 - $v1) * 6 * $vh; | ||||||
|  |         if ($vh * 2 < 1) return $v2; | ||||||
|  |         if ($vh * 3 < 2) return $v1 + ($v2 - $v1) * ((2/3) - $vh) * 6; | ||||||
|  |         return $v1; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function round_number($n) | ||||||
|  |     { | ||||||
|  |         return intval(floor(floatval($n) + 0.5), 10); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function clamp_number($n, $min, $max) | ||||||
|  |     { | ||||||
|  |         return min(max($n, $min), $max); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * PHP port of Javascript's "indexOf" function for strings only | ||||||
|  |      * Author: Tubal Martin http://blog.margenn.com | ||||||
|  |      * | ||||||
|  |      * @param string $haystack | ||||||
|  |      * @param string $needle | ||||||
|  |      * @param int    $offset index (optional) | ||||||
|  |      * @return int | ||||||
|  |      */ | ||||||
|  |     private function index_of($haystack, $needle, $offset = 0) | ||||||
|  |     { | ||||||
|  |         $index = strpos($haystack, $needle, $offset); | ||||||
|  |  | ||||||
|  |         return ($index !== FALSE) ? $index : -1; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * PHP port of Javascript's "slice" function for strings only | ||||||
|  |      * Author: Tubal Martin http://blog.margenn.com | ||||||
|  |      * Tests: http://margenn.com/tubal/str_slice/ | ||||||
|  |      * | ||||||
|  |      * @param string   $str | ||||||
|  |      * @param int      $start index | ||||||
|  |      * @param int|bool $end index (optional) | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     private function str_slice($str, $start = 0, $end = FALSE) | ||||||
|  |     { | ||||||
|  |         if ($end !== FALSE && ($start < 0 || $end <= 0)) { | ||||||
|  |             $max = strlen($str); | ||||||
|  |  | ||||||
|  |             if ($start < 0) { | ||||||
|  |                 if (($start = $max + $start) < 0) { | ||||||
|  |                     return ''; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if ($end < 0) { | ||||||
|  |                 if (($end = $max + $end) < 0) { | ||||||
|  |                     return ''; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if ($end <= $start) { | ||||||
|  |                 return ''; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $slice = ($end === FALSE) ? substr($str, $start) : substr($str, $start, $end - $start); | ||||||
|  |         return ($slice === FALSE) ? '' : $slice; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Convert strings like "64M" or "30" to int values | ||||||
|  |      * @param mixed $size | ||||||
|  |      * @return int | ||||||
|  |      */ | ||||||
|  |     private function normalize_int($size) | ||||||
|  |     { | ||||||
|  |         if (is_string($size)) { | ||||||
|  |             switch (substr($size, -1)) { | ||||||
|  |                 case 'M': case 'm': return $size * 1048576; | ||||||
|  |                 case 'K': case 'k': return $size * 1024; | ||||||
|  |                 case 'G': case 'g': return $size * 1073741824; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return (int) $size; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										121
									
								
								vendor/mrclay/minify/min/lib/DooDigestAuth.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								vendor/mrclay/minify/min/lib/DooDigestAuth.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * DooDigestAuth class file. | ||||||
|  |  * | ||||||
|  |  * @author Leng Sheng Hong <darkredz@gmail.com> | ||||||
|  |  * @link http://www.doophp.com/ | ||||||
|  |  * @copyright Copyright © 2009 Leng Sheng Hong | ||||||
|  |  * @license http://www.doophp.com/license | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Handles HTTP digest authentication | ||||||
|  |  * | ||||||
|  |  * <p>HTTP digest authentication can be used with the URI router. | ||||||
|  |  * HTTP digest is much more recommended over the use of HTTP Basic auth which doesn't provide any encryption. | ||||||
|  |  * If you are running PHP on Apache in CGI/FastCGI mode, you would need to | ||||||
|  |  * add the following line to your .htaccess for digest auth to work correctly.</p> | ||||||
|  |  * <code>RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]</code> | ||||||
|  |  * | ||||||
|  |  * <p>This class is tested under Apache 2.2 and Cherokee web server. It should work in both mod_php and cgi mode.</p> | ||||||
|  |  * | ||||||
|  |  * @author Leng Sheng Hong <darkredz@gmail.com> | ||||||
|  |  * @version $Id: DooDigestAuth.php 1000 2009-07-7 18:27:22 | ||||||
|  |  * @package doo.auth | ||||||
|  |  * @since 1.0 | ||||||
|  |  */ | ||||||
|  | class DooDigestAuth{ | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Authenticate against a list of username and passwords. | ||||||
|  |      * | ||||||
|  |      * <p>HTTP Digest Authentication doesn't work with PHP in CGI mode, | ||||||
|  |      * you have to add this into your .htaccess <code>RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]</code></p> | ||||||
|  |      * | ||||||
|  |      * @param string $realm Name of the authentication session | ||||||
|  |      * @param array $users An assoc array of username and password: array('uname1'=>'pwd1', 'uname2'=>'pwd2') | ||||||
|  |      * @param string $fail_msg Message to be displayed if the User cancel the login | ||||||
|  |      * @param string $fail_url URL to be redirect if the User cancel the login | ||||||
|  |      * @return string The username if login success. | ||||||
|  |      */ | ||||||
|  |     public static function http_auth($realm, $users, $fail_msg=NULL, $fail_url=NULL){ | ||||||
|  |         $realm = "Restricted area - $realm"; | ||||||
|  |  | ||||||
|  |         //user => password | ||||||
|  |         //$users = array('admin' => '1234', 'guest' => 'guest'); | ||||||
|  |         if(!empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && strpos($_SERVER['REDIRECT_HTTP_AUTHORIZATION'], 'Digest')===0){ | ||||||
|  |             $_SERVER['PHP_AUTH_DIGEST'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (empty($_SERVER['PHP_AUTH_DIGEST'])) { | ||||||
|  |             header('WWW-Authenticate: Digest realm="'.$realm. | ||||||
|  |                    '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"'); | ||||||
|  |             header('HTTP/1.1 401 Unauthorized'); | ||||||
|  |             if($fail_msg!=NULL) | ||||||
|  |                 die($fail_msg); | ||||||
|  |             if($fail_url!=NULL) | ||||||
|  |                 die("<script>window.location.href = '$fail_url'</script>"); | ||||||
|  |             exit; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // analyze the PHP_AUTH_DIGEST variable | ||||||
|  |         if (!($data = self::http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) || !isset($users[$data['username']])){ | ||||||
|  |             header('WWW-Authenticate: Digest realm="'.$realm. | ||||||
|  |                    '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"'); | ||||||
|  |             header('HTTP/1.1 401 Unauthorized'); | ||||||
|  |             if($fail_msg!=NULL) | ||||||
|  |                 die($fail_msg); | ||||||
|  |             if($fail_url!=NULL) | ||||||
|  |                 die("<script>window.location.href = '$fail_url'</script>"); | ||||||
|  |             exit; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // generate the valid response | ||||||
|  |         $A1 = md5($data['username'] . ':' . $realm . ':' . $users[$data['username']]); | ||||||
|  |         $A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']); | ||||||
|  |         $valid_response = md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2); | ||||||
|  |  | ||||||
|  |         if ($data['response'] != $valid_response){ | ||||||
|  |             header('HTTP/1.1 401 Unauthorized'); | ||||||
|  |             header('WWW-Authenticate: Digest realm="'.$realm. | ||||||
|  |                    '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"'); | ||||||
|  |             if($fail_msg!=NULL) | ||||||
|  |                 die($fail_msg); | ||||||
|  |             if($fail_url!=NULL) | ||||||
|  |                 die("<script>window.location.href = '$fail_url'</script>"); | ||||||
|  |             exit; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // ok, valid username & password | ||||||
|  |         return $data['username']; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Method to parse the http auth header, works with IE. | ||||||
|  |      * | ||||||
|  |      * Internet Explorer returns a qop="xxxxxxxxxxx" in the header instead of qop=xxxxxxxxxxx as most browsers do. | ||||||
|  |      * | ||||||
|  |      * @param string $txt header string to parse | ||||||
|  |      * @return array An assoc array of the digest auth session | ||||||
|  |      */ | ||||||
|  |     private static function http_digest_parse($txt) | ||||||
|  |     { | ||||||
|  |         $res = preg_match("/username=\"([^\"]+)\"/i", $txt, $match); | ||||||
|  |         $data['username'] = (isset($match[1]))?$match[1]:null; | ||||||
|  |         $res = preg_match('/nonce=\"([^\"]+)\"/i', $txt, $match); | ||||||
|  |         $data['nonce'] = $match[1]; | ||||||
|  |         $res = preg_match('/nc=([0-9]+)/i', $txt, $match); | ||||||
|  |         $data['nc'] = $match[1]; | ||||||
|  |         $res = preg_match('/cnonce=\"([^\"]+)\"/i', $txt, $match); | ||||||
|  |         $data['cnonce'] = $match[1]; | ||||||
|  |         $res = preg_match('/qop=([^,]+)/i', $txt, $match); | ||||||
|  |         $data['qop'] = str_replace('"','',$match[1]); | ||||||
|  |         $res = preg_match('/uri=\"([^\"]+)\"/i', $txt, $match); | ||||||
|  |         $data['uri'] = $match[1]; | ||||||
|  |         $res = preg_match('/response=\"([^\"]+)\"/i', $txt, $match); | ||||||
|  |         $data['response'] = $match[1]; | ||||||
|  |         return $data; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										1370
									
								
								vendor/mrclay/minify/min/lib/FirePHP.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1370
									
								
								vendor/mrclay/minify/min/lib/FirePHP.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										366
									
								
								vendor/mrclay/minify/min/lib/HTTP/ConditionalGet.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										366
									
								
								vendor/mrclay/minify/min/lib/HTTP/ConditionalGet.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,366 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class HTTP_ConditionalGet   | ||||||
|  |  * @package Minify | ||||||
|  |  * @subpackage HTTP | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Implement conditional GET via a timestamp or hash of content | ||||||
|  |  * | ||||||
|  |  * E.g. Content from DB with update time: | ||||||
|  |  * <code> | ||||||
|  |  * list($updateTime, $content) = getDbUpdateAndContent(); | ||||||
|  |  * $cg = new HTTP_ConditionalGet(array( | ||||||
|  |  *     'lastModifiedTime' => $updateTime | ||||||
|  |  *     ,'isPublic' => true | ||||||
|  |  * )); | ||||||
|  |  * $cg->sendHeaders(); | ||||||
|  |  * if ($cg->cacheIsValid) { | ||||||
|  |  *     exit(); | ||||||
|  |  * } | ||||||
|  |  * echo $content; | ||||||
|  |  * </code> | ||||||
|  |  *  | ||||||
|  |  * E.g. Shortcut for the above | ||||||
|  |  * <code> | ||||||
|  |  * HTTP_ConditionalGet::check($updateTime, true); // exits if client has cache | ||||||
|  |  * echo $content; | ||||||
|  |  * </code> | ||||||
|  |  * | ||||||
|  |  * E.g. Content from DB with no update time: | ||||||
|  |  * <code> | ||||||
|  |  * $content = getContentFromDB(); | ||||||
|  |  * $cg = new HTTP_ConditionalGet(array( | ||||||
|  |  *     'contentHash' => md5($content) | ||||||
|  |  * )); | ||||||
|  |  * $cg->sendHeaders(); | ||||||
|  |  * if ($cg->cacheIsValid) { | ||||||
|  |  *     exit(); | ||||||
|  |  * } | ||||||
|  |  * echo $content; | ||||||
|  |  * </code> | ||||||
|  |  *  | ||||||
|  |  * E.g. Static content with some static includes: | ||||||
|  |  * <code> | ||||||
|  |  * // before content | ||||||
|  |  * $cg = new HTTP_ConditionalGet(array( | ||||||
|  |  *     'lastUpdateTime' => max( | ||||||
|  |  *         filemtime(__FILE__) | ||||||
|  |  *         ,filemtime('/path/to/header.inc') | ||||||
|  |  *         ,filemtime('/path/to/footer.inc') | ||||||
|  |  *     ) | ||||||
|  |  * )); | ||||||
|  |  * $cg->sendHeaders(); | ||||||
|  |  * if ($cg->cacheIsValid) { | ||||||
|  |  *     exit(); | ||||||
|  |  * } | ||||||
|  |  * </code> | ||||||
|  |  * @package Minify | ||||||
|  |  * @subpackage HTTP | ||||||
|  |  * @author Stephen Clay <steve@mrclay.org> | ||||||
|  |  */ | ||||||
|  | class HTTP_ConditionalGet { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Does the client have a valid copy of the requested resource? | ||||||
|  |      *  | ||||||
|  |      * You'll want to check this after instantiating the object. If true, do | ||||||
|  |      * not send content, just call sendHeaders() if you haven't already. | ||||||
|  |      * | ||||||
|  |      * @var bool | ||||||
|  |      */ | ||||||
|  |     public $cacheIsValid = null; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param array $spec options | ||||||
|  |      *  | ||||||
|  |      * 'isPublic': (bool) if false, the Cache-Control header will contain | ||||||
|  |      * "private", allowing only browser caching. (default false) | ||||||
|  |      *  | ||||||
|  |      * 'lastModifiedTime': (int) if given, both ETag AND Last-Modified headers | ||||||
|  |      * will be sent with content. This is recommended. | ||||||
|  |      * | ||||||
|  |      * 'encoding': (string) if set, the header "Vary: Accept-Encoding" will | ||||||
|  |      * always be sent and a truncated version of the encoding will be appended | ||||||
|  |      * to the ETag. E.g. "pub123456;gz". This will also trigger a more lenient  | ||||||
|  |      * checking of the client's If-None-Match header, as the encoding portion of | ||||||
|  |      * the ETag will be stripped before comparison. | ||||||
|  |      *  | ||||||
|  |      * 'contentHash': (string) if given, only the ETag header can be sent with | ||||||
|  |      * content (only HTTP1.1 clients can conditionally GET). The given string  | ||||||
|  |      * should be short with no quote characters and always change when the  | ||||||
|  |      * resource changes (recommend md5()). This is not needed/used if  | ||||||
|  |      * lastModifiedTime is given. | ||||||
|  |      *  | ||||||
|  |      * 'eTag': (string) if given, this will be used as the ETag header rather | ||||||
|  |      * than values based on lastModifiedTime or contentHash. Also the encoding | ||||||
|  |      * string will not be appended to the given value as described above. | ||||||
|  |      *  | ||||||
|  |      * 'invalidate': (bool) if true, the client cache will be considered invalid | ||||||
|  |      * without testing. Effectively this disables conditional GET.  | ||||||
|  |      * (default false) | ||||||
|  |      *  | ||||||
|  |      * 'maxAge': (int) if given, this will set the Cache-Control max-age in  | ||||||
|  |      * seconds, and also set the Expires header to the equivalent GMT date.  | ||||||
|  |      * After the max-age period has passed, the browser will again send a  | ||||||
|  |      * conditional GET to revalidate its cache. | ||||||
|  |      */ | ||||||
|  |     public function __construct($spec) | ||||||
|  |     { | ||||||
|  |         $scope = (isset($spec['isPublic']) && $spec['isPublic']) | ||||||
|  |             ? 'public' | ||||||
|  |             : 'private'; | ||||||
|  |         $maxAge = 0; | ||||||
|  |         // backwards compatibility (can be removed later) | ||||||
|  |         if (isset($spec['setExpires'])  | ||||||
|  |             && is_numeric($spec['setExpires']) | ||||||
|  |             && ! isset($spec['maxAge'])) { | ||||||
|  |             $spec['maxAge'] = $spec['setExpires'] - $_SERVER['REQUEST_TIME']; | ||||||
|  |         } | ||||||
|  |         if (isset($spec['maxAge'])) { | ||||||
|  |             $maxAge = $spec['maxAge']; | ||||||
|  |             $this->_headers['Expires'] = self::gmtDate( | ||||||
|  |                 $_SERVER['REQUEST_TIME'] + $spec['maxAge']  | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |         $etagAppend = ''; | ||||||
|  |         if (isset($spec['encoding'])) { | ||||||
|  |             $this->_stripEtag = true; | ||||||
|  |             $this->_headers['Vary'] = 'Accept-Encoding'; | ||||||
|  |             if ('' !== $spec['encoding']) { | ||||||
|  |                 if (0 === strpos($spec['encoding'], 'x-')) { | ||||||
|  |                     $spec['encoding'] = substr($spec['encoding'], 2); | ||||||
|  |                 } | ||||||
|  |                 $etagAppend = ';' . substr($spec['encoding'], 0, 2); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (isset($spec['lastModifiedTime'])) { | ||||||
|  |             $this->_setLastModified($spec['lastModifiedTime']); | ||||||
|  |             if (isset($spec['eTag'])) { // Use it | ||||||
|  |                 $this->_setEtag($spec['eTag'], $scope); | ||||||
|  |             } else { // base both headers on time | ||||||
|  |                 $this->_setEtag($spec['lastModifiedTime'] . $etagAppend, $scope); | ||||||
|  |             } | ||||||
|  |         } elseif (isset($spec['eTag'])) { // Use it | ||||||
|  |             $this->_setEtag($spec['eTag'], $scope); | ||||||
|  |         } elseif (isset($spec['contentHash'])) { // Use the hash as the ETag | ||||||
|  |             $this->_setEtag($spec['contentHash'] . $etagAppend, $scope); | ||||||
|  |         } | ||||||
|  |         $privacy = ($scope === 'private') | ||||||
|  |             ? ', private' | ||||||
|  |             : ''; | ||||||
|  |         $this->_headers['Cache-Control'] = "max-age={$maxAge}{$privacy}"; | ||||||
|  |         // invalidate cache if disabled, otherwise check | ||||||
|  |         $this->cacheIsValid = (isset($spec['invalidate']) && $spec['invalidate']) | ||||||
|  |             ? false | ||||||
|  |             : $this->_isCacheValid(); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Get array of output headers to be sent | ||||||
|  |      *  | ||||||
|  |      * In the case of 304 responses, this array will only contain the response | ||||||
|  |      * code header: array('_responseCode' => 'HTTP/1.0 304 Not Modified') | ||||||
|  |      *  | ||||||
|  |      * Otherwise something like:  | ||||||
|  |      * <code> | ||||||
|  |      * array( | ||||||
|  |      *     'Cache-Control' => 'max-age=0, public' | ||||||
|  |      *     ,'ETag' => '"foobar"' | ||||||
|  |      * ) | ||||||
|  |      * </code> | ||||||
|  |      * | ||||||
|  |      * @return array  | ||||||
|  |      */ | ||||||
|  |     public function getHeaders() | ||||||
|  |     { | ||||||
|  |         return $this->_headers; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set the Content-Length header in bytes | ||||||
|  |      *  | ||||||
|  |      * With most PHP configs, as long as you don't flush() output, this method | ||||||
|  |      * is not needed and PHP will buffer all output and set Content-Length for  | ||||||
|  |      * you. Otherwise you'll want to call this to let the client know up front. | ||||||
|  |      *  | ||||||
|  |      * @param int $bytes | ||||||
|  |      *  | ||||||
|  |      * @return int copy of input $bytes | ||||||
|  |      */ | ||||||
|  |     public function setContentLength($bytes) | ||||||
|  |     { | ||||||
|  |         return $this->_headers['Content-Length'] = $bytes; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Send headers | ||||||
|  |      *  | ||||||
|  |      * @see getHeaders() | ||||||
|  |      *  | ||||||
|  |      * Note this doesn't "clear" the headers. Calling sendHeaders() will | ||||||
|  |      * call header() again (but probably have not effect) and getHeaders() will | ||||||
|  |      * still return the headers. | ||||||
|  |      * | ||||||
|  |      * @return null | ||||||
|  |      */ | ||||||
|  |     public function sendHeaders() | ||||||
|  |     { | ||||||
|  |         $headers = $this->_headers; | ||||||
|  |         if (array_key_exists('_responseCode', $headers)) { | ||||||
|  |             // FastCGI environments require 3rd arg to header() to be set | ||||||
|  |             list(, $code) = explode(' ', $headers['_responseCode'], 3); | ||||||
|  |             header($headers['_responseCode'], true, $code); | ||||||
|  |             unset($headers['_responseCode']); | ||||||
|  |         } | ||||||
|  |         foreach ($headers as $name => $val) { | ||||||
|  |             header($name . ': ' . $val); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Exit if the client's cache is valid for this resource | ||||||
|  |      * | ||||||
|  |      * This is a convenience method for common use of the class | ||||||
|  |      * | ||||||
|  |      * @param int $lastModifiedTime if given, both ETag AND Last-Modified headers | ||||||
|  |      * will be sent with content. This is recommended. | ||||||
|  |      * | ||||||
|  |      * @param bool $isPublic (default false) if true, the Cache-Control header  | ||||||
|  |      * will contain "public", allowing proxies to cache the content. Otherwise  | ||||||
|  |      * "private" will be sent, allowing only browser caching. | ||||||
|  |      * | ||||||
|  |      * @param array $options (default empty) additional options for constructor | ||||||
|  |      */ | ||||||
|  |     public static function check($lastModifiedTime = null, $isPublic = false, $options = array()) | ||||||
|  |     { | ||||||
|  |         if (null !== $lastModifiedTime) { | ||||||
|  |             $options['lastModifiedTime'] = (int)$lastModifiedTime; | ||||||
|  |         } | ||||||
|  |         $options['isPublic'] = (bool)$isPublic; | ||||||
|  |         $cg = new HTTP_ConditionalGet($options); | ||||||
|  |         $cg->sendHeaders(); | ||||||
|  |         if ($cg->cacheIsValid) { | ||||||
|  |             exit(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Get a GMT formatted date for use in HTTP headers | ||||||
|  |      *  | ||||||
|  |      * <code> | ||||||
|  |      * header('Expires: ' . HTTP_ConditionalGet::gmtdate($time)); | ||||||
|  |      * </code>   | ||||||
|  |      * | ||||||
|  |      * @param int $time unix timestamp | ||||||
|  |      *  | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public static function gmtDate($time) | ||||||
|  |     { | ||||||
|  |         return gmdate('D, d M Y H:i:s \G\M\T', $time); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     protected $_headers = array(); | ||||||
|  |     protected $_lmTime = null; | ||||||
|  |     protected $_etag = null; | ||||||
|  |     protected $_stripEtag = false; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param string $hash | ||||||
|  |      * | ||||||
|  |      * @param string $scope | ||||||
|  |      */ | ||||||
|  |     protected function _setEtag($hash, $scope) | ||||||
|  |     { | ||||||
|  |         $this->_etag = '"' . substr($scope, 0, 3) . $hash . '"'; | ||||||
|  |         $this->_headers['ETag'] = $this->_etag; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param int $time | ||||||
|  |      */ | ||||||
|  |     protected function _setLastModified($time) | ||||||
|  |     { | ||||||
|  |         $this->_lmTime = (int)$time; | ||||||
|  |         $this->_headers['Last-Modified'] = self::gmtDate($time); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Determine validity of client cache and queue 304 header if valid | ||||||
|  |      * | ||||||
|  |      * @return bool | ||||||
|  |      */ | ||||||
|  |     protected function _isCacheValid() | ||||||
|  |     { | ||||||
|  |         if (null === $this->_etag) { | ||||||
|  |             // lmTime is copied to ETag, so this condition implies that the | ||||||
|  |             // server sent neither ETag nor Last-Modified, so the client can't  | ||||||
|  |             // possibly has a valid cache. | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         $isValid = ($this->resourceMatchedEtag() || $this->resourceNotModified()); | ||||||
|  |         if ($isValid) { | ||||||
|  |             $this->_headers['_responseCode'] = 'HTTP/1.0 304 Not Modified'; | ||||||
|  |         } | ||||||
|  |         return $isValid; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @return bool | ||||||
|  |      */ | ||||||
|  |     protected function resourceMatchedEtag() | ||||||
|  |     { | ||||||
|  |         if (!isset($_SERVER['HTTP_IF_NONE_MATCH'])) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         $clientEtagList = get_magic_quotes_gpc() | ||||||
|  |             ? stripslashes($_SERVER['HTTP_IF_NONE_MATCH']) | ||||||
|  |             : $_SERVER['HTTP_IF_NONE_MATCH']; | ||||||
|  |         $clientEtags = explode(',', $clientEtagList); | ||||||
|  |          | ||||||
|  |         $compareTo = $this->normalizeEtag($this->_etag); | ||||||
|  |         foreach ($clientEtags as $clientEtag) { | ||||||
|  |             if ($this->normalizeEtag($clientEtag) === $compareTo) { | ||||||
|  |                 // respond with the client's matched ETag, even if it's not what | ||||||
|  |                 // we would've sent by default | ||||||
|  |                 $this->_headers['ETag'] = trim($clientEtag); | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param string $etag | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     protected function normalizeEtag($etag) { | ||||||
|  |         $etag = trim($etag); | ||||||
|  |         return $this->_stripEtag | ||||||
|  |             ? preg_replace('/;\\w\\w"$/', '"', $etag) | ||||||
|  |             : $etag; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @return bool | ||||||
|  |      */ | ||||||
|  |     protected function resourceNotModified() | ||||||
|  |     { | ||||||
|  |         if (!isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         // strip off IE's extra data (semicolon) | ||||||
|  |         list($ifModifiedSince) = explode(';', $_SERVER['HTTP_IF_MODIFIED_SINCE'], 2); | ||||||
|  |         if (strtotime($ifModifiedSince) >= $this->_lmTime) { | ||||||
|  |             // Apache 2.2's behavior. If there was no ETag match, send the  | ||||||
|  |             // non-encoded version of the ETag value. | ||||||
|  |             $this->_headers['ETag'] = $this->normalizeEtag($this->_etag); | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										335
									
								
								vendor/mrclay/minify/min/lib/HTTP/Encoder.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										335
									
								
								vendor/mrclay/minify/min/lib/HTTP/Encoder.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,335 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class HTTP_Encoder   | ||||||
|  |  * @package Minify | ||||||
|  |  * @subpackage HTTP | ||||||
|  |  */ | ||||||
|  |   | ||||||
|  | /** | ||||||
|  |  * Encode and send gzipped/deflated content | ||||||
|  |  * | ||||||
|  |  * The "Vary: Accept-Encoding" header is sent. If the client allows encoding,  | ||||||
|  |  * Content-Encoding and Content-Length are added. | ||||||
|  |  * | ||||||
|  |  * <code> | ||||||
|  |  * // Send a CSS file, compressed if possible | ||||||
|  |  * $he = new HTTP_Encoder(array( | ||||||
|  |  *     'content' => file_get_contents($cssFile) | ||||||
|  |  *     ,'type' => 'text/css' | ||||||
|  |  * )); | ||||||
|  |  * $he->encode(); | ||||||
|  |  * $he->sendAll(); | ||||||
|  |  * </code> | ||||||
|  |  * | ||||||
|  |  * <code> | ||||||
|  |  * // Shortcut to encoding output | ||||||
|  |  * header('Content-Type: text/css'); // needed if not HTML | ||||||
|  |  * HTTP_Encoder::output($css); | ||||||
|  |  * </code> | ||||||
|  |  *  | ||||||
|  |  * <code> | ||||||
|  |  * // Just sniff for the accepted encoding | ||||||
|  |  * $encoding = HTTP_Encoder::getAcceptedEncoding(); | ||||||
|  |  * </code> | ||||||
|  |  * | ||||||
|  |  * For more control over headers, use getHeaders() and getData() and send your | ||||||
|  |  * own output. | ||||||
|  |  *  | ||||||
|  |  * Note: If you don't need header mgmt, use PHP's native gzencode, gzdeflate,  | ||||||
|  |  * and gzcompress functions for gzip, deflate, and compress-encoding | ||||||
|  |  * respectively. | ||||||
|  |  *  | ||||||
|  |  * @package Minify | ||||||
|  |  * @subpackage HTTP | ||||||
|  |  * @author Stephen Clay <steve@mrclay.org> | ||||||
|  |  */ | ||||||
|  | class HTTP_Encoder { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Should the encoder allow HTTP encoding to IE6?  | ||||||
|  |      *  | ||||||
|  |      * If you have many IE6 users and the bandwidth savings is worth troubling  | ||||||
|  |      * some of them, set this to true. | ||||||
|  |      *  | ||||||
|  |      * By default, encoding is only offered to IE7+. When this is true, | ||||||
|  |      * getAcceptedEncoding() will return an encoding for IE6 if its user agent | ||||||
|  |      * string contains "SV1". This has been documented in many places as "safe", | ||||||
|  |      * but there seem to be remaining, intermittent encoding bugs in patched  | ||||||
|  |      * IE6 on the wild web. | ||||||
|  |      *  | ||||||
|  |      * @var bool | ||||||
|  |      */ | ||||||
|  |     public static $encodeToIe6 = true; | ||||||
|  |      | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Default compression level for zlib operations | ||||||
|  |      *  | ||||||
|  |      * This level is used if encode() is not given a $compressionLevel | ||||||
|  |      *  | ||||||
|  |      * @var int | ||||||
|  |      */ | ||||||
|  |     public static $compressionLevel = 6; | ||||||
|  |      | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get an HTTP Encoder object | ||||||
|  |      *  | ||||||
|  |      * @param array $spec options | ||||||
|  |      *  | ||||||
|  |      * 'content': (string required) content to be encoded | ||||||
|  |      *  | ||||||
|  |      * 'type': (string) if set, the Content-Type header will have this value. | ||||||
|  |      *  | ||||||
|  |      * 'method: (string) only set this if you are forcing a particular encoding | ||||||
|  |      * method. If not set, the best method will be chosen by getAcceptedEncoding() | ||||||
|  |      * The available methods are 'gzip', 'deflate', 'compress', and '' (no | ||||||
|  |      * encoding) | ||||||
|  |      */ | ||||||
|  |     public function __construct($spec)  | ||||||
|  |     { | ||||||
|  |         $this->_useMbStrlen = (function_exists('mb_strlen') | ||||||
|  |                                && (ini_get('mbstring.func_overload') !== '') | ||||||
|  |                                && ((int)ini_get('mbstring.func_overload') & 2)); | ||||||
|  |         $this->_content = $spec['content']; | ||||||
|  |         $this->_headers['Content-Length'] = $this->_useMbStrlen | ||||||
|  |             ? (string)mb_strlen($this->_content, '8bit') | ||||||
|  |             : (string)strlen($this->_content); | ||||||
|  |         if (isset($spec['type'])) { | ||||||
|  |             $this->_headers['Content-Type'] = $spec['type']; | ||||||
|  |         } | ||||||
|  |         if (isset($spec['method']) | ||||||
|  |             && in_array($spec['method'], array('gzip', 'deflate', 'compress', ''))) | ||||||
|  |         { | ||||||
|  |             $this->_encodeMethod = array($spec['method'], $spec['method']); | ||||||
|  |         } else { | ||||||
|  |             $this->_encodeMethod = self::getAcceptedEncoding(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get content in current form | ||||||
|  |      *  | ||||||
|  |      * Call after encode() for encoded content. | ||||||
|  |      *  | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public function getContent()  | ||||||
|  |     { | ||||||
|  |         return $this->_content; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Get array of output headers to be sent | ||||||
|  |      *  | ||||||
|  |      * E.g. | ||||||
|  |      * <code> | ||||||
|  |      * array( | ||||||
|  |      *     'Content-Length' => '615' | ||||||
|  |      *     ,'Content-Encoding' => 'x-gzip' | ||||||
|  |      *     ,'Vary' => 'Accept-Encoding' | ||||||
|  |      * ) | ||||||
|  |      * </code> | ||||||
|  |      * | ||||||
|  |      * @return array  | ||||||
|  |      */ | ||||||
|  |     public function getHeaders() | ||||||
|  |     { | ||||||
|  |         return $this->_headers; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Send output headers | ||||||
|  |      *  | ||||||
|  |      * You must call this before headers are sent and it probably cannot be | ||||||
|  |      * used in conjunction with zlib output buffering / mod_gzip. Errors are | ||||||
|  |      * not handled purposefully. | ||||||
|  |      *  | ||||||
|  |      * @see getHeaders() | ||||||
|  |      */ | ||||||
|  |     public function sendHeaders() | ||||||
|  |     { | ||||||
|  |         foreach ($this->_headers as $name => $val) { | ||||||
|  |             header($name . ': ' . $val); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Send output headers and content | ||||||
|  |      *  | ||||||
|  |      * A shortcut for sendHeaders() and echo getContent() | ||||||
|  |      * | ||||||
|  |      * You must call this before headers are sent and it probably cannot be | ||||||
|  |      * used in conjunction with zlib output buffering / mod_gzip. Errors are | ||||||
|  |      * not handled purposefully. | ||||||
|  |      */ | ||||||
|  |     public function sendAll() | ||||||
|  |     { | ||||||
|  |         $this->sendHeaders(); | ||||||
|  |         echo $this->_content; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Determine the client's best encoding method from the HTTP Accept-Encoding  | ||||||
|  |      * header. | ||||||
|  |      *  | ||||||
|  |      * If no Accept-Encoding header is set, or the browser is IE before v6 SP2, | ||||||
|  |      * this will return ('', ''), the "identity" encoding. | ||||||
|  |      *  | ||||||
|  |      * A syntax-aware scan is done of the Accept-Encoding, so the method must | ||||||
|  |      * be non 0. The methods are favored in order of gzip, deflate, then  | ||||||
|  |      * compress. Deflate is always smallest and generally faster, but is  | ||||||
|  |      * rarely sent by servers, so client support could be buggier. | ||||||
|  |      *  | ||||||
|  |      * @param bool $allowCompress allow the older compress encoding | ||||||
|  |      *  | ||||||
|  |      * @param bool $allowDeflate allow the more recent deflate encoding | ||||||
|  |      *  | ||||||
|  |      * @return array two values, 1st is the actual encoding method, 2nd is the | ||||||
|  |      * alias of that method to use in the Content-Encoding header (some browsers | ||||||
|  |      * call gzip "x-gzip" etc.) | ||||||
|  |      */ | ||||||
|  |     public static function getAcceptedEncoding($allowCompress = true, $allowDeflate = true) | ||||||
|  |     { | ||||||
|  |         // @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html | ||||||
|  |          | ||||||
|  |         if (! isset($_SERVER['HTTP_ACCEPT_ENCODING']) | ||||||
|  |             || self::isBuggyIe()) | ||||||
|  |         { | ||||||
|  |             return array('', ''); | ||||||
|  |         } | ||||||
|  |         $ae = $_SERVER['HTTP_ACCEPT_ENCODING']; | ||||||
|  |         // gzip checks (quick) | ||||||
|  |         if (0 === strpos($ae, 'gzip,')             // most browsers | ||||||
|  |             || 0 === strpos($ae, 'deflate, gzip,') // opera | ||||||
|  |         ) { | ||||||
|  |             return array('gzip', 'gzip'); | ||||||
|  |         } | ||||||
|  |         // gzip checks (slow) | ||||||
|  |         if (preg_match( | ||||||
|  |                 '@(?:^|,)\\s*((?:x-)?gzip)\\s*(?:$|,|;\\s*q=(?:0\\.|1))@' | ||||||
|  |                 ,$ae | ||||||
|  |                 ,$m)) { | ||||||
|  |             return array('gzip', $m[1]); | ||||||
|  |         } | ||||||
|  |         if ($allowDeflate) { | ||||||
|  |             // deflate checks     | ||||||
|  |             $aeRev = strrev($ae); | ||||||
|  |             if (0 === strpos($aeRev, 'etalfed ,') // ie, webkit | ||||||
|  |                 || 0 === strpos($aeRev, 'etalfed,') // gecko | ||||||
|  |                 || 0 === strpos($ae, 'deflate,') // opera | ||||||
|  |                 // slow parsing | ||||||
|  |                 || preg_match( | ||||||
|  |                     '@(?:^|,)\\s*deflate\\s*(?:$|,|;\\s*q=(?:0\\.|1))@', $ae)) { | ||||||
|  |                 return array('deflate', 'deflate'); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if ($allowCompress && preg_match( | ||||||
|  |                 '@(?:^|,)\\s*((?:x-)?compress)\\s*(?:$|,|;\\s*q=(?:0\\.|1))@' | ||||||
|  |                 ,$ae | ||||||
|  |                 ,$m)) { | ||||||
|  |             return array('compress', $m[1]); | ||||||
|  |         } | ||||||
|  |         return array('', ''); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Encode (compress) the content | ||||||
|  |      *  | ||||||
|  |      * If the encode method is '' (none) or compression level is 0, or the 'zlib' | ||||||
|  |      * extension isn't loaded, we return false. | ||||||
|  |      *  | ||||||
|  |      * Then the appropriate gz_* function is called to compress the content. If | ||||||
|  |      * this fails, false is returned. | ||||||
|  |      *  | ||||||
|  |      * The header "Vary: Accept-Encoding" is added. If encoding is successful,  | ||||||
|  |      * the Content-Length header is updated, and Content-Encoding is also added. | ||||||
|  |      *  | ||||||
|  |      * @param int $compressionLevel given to zlib functions. If not given, the | ||||||
|  |      * class default will be used. | ||||||
|  |      *  | ||||||
|  |      * @return bool success true if the content was actually compressed | ||||||
|  |      */ | ||||||
|  |     public function encode($compressionLevel = null) | ||||||
|  |     { | ||||||
|  |         if (! self::isBuggyIe()) { | ||||||
|  |             $this->_headers['Vary'] = 'Accept-Encoding'; | ||||||
|  |         } | ||||||
|  |         if (null === $compressionLevel) { | ||||||
|  |             $compressionLevel = self::$compressionLevel; | ||||||
|  |         } | ||||||
|  |         if ('' === $this->_encodeMethod[0] | ||||||
|  |             || ($compressionLevel == 0) | ||||||
|  |             || !extension_loaded('zlib')) | ||||||
|  |         { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         if ($this->_encodeMethod[0] === 'deflate') { | ||||||
|  |             $encoded = gzdeflate($this->_content, $compressionLevel); | ||||||
|  |         } elseif ($this->_encodeMethod[0] === 'gzip') { | ||||||
|  |             $encoded = gzencode($this->_content, $compressionLevel); | ||||||
|  |         } else { | ||||||
|  |             $encoded = gzcompress($this->_content, $compressionLevel); | ||||||
|  |         } | ||||||
|  |         if (false === $encoded) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         $this->_headers['Content-Length'] = $this->_useMbStrlen | ||||||
|  |             ? (string)mb_strlen($encoded, '8bit') | ||||||
|  |             : (string)strlen($encoded); | ||||||
|  |         $this->_headers['Content-Encoding'] = $this->_encodeMethod[1]; | ||||||
|  |         $this->_content = $encoded; | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Encode and send appropriate headers and content | ||||||
|  |      * | ||||||
|  |      * This is a convenience method for common use of the class | ||||||
|  |      *  | ||||||
|  |      * @param string $content | ||||||
|  |      *  | ||||||
|  |      * @param int $compressionLevel given to zlib functions. If not given, the | ||||||
|  |      * class default will be used. | ||||||
|  |      *  | ||||||
|  |      * @return bool success true if the content was actually compressed | ||||||
|  |      */ | ||||||
|  |     public static function output($content, $compressionLevel = null) | ||||||
|  |     { | ||||||
|  |         if (null === $compressionLevel) { | ||||||
|  |             $compressionLevel = self::$compressionLevel; | ||||||
|  |         } | ||||||
|  |         $he = new HTTP_Encoder(array('content' => $content)); | ||||||
|  |         $ret = $he->encode($compressionLevel); | ||||||
|  |         $he->sendAll(); | ||||||
|  |         return $ret; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Is the browser an IE version earlier than 6 SP2? | ||||||
|  |      * | ||||||
|  |      * @return bool | ||||||
|  |      */ | ||||||
|  |     public static function isBuggyIe() | ||||||
|  |     { | ||||||
|  |         if (empty($_SERVER['HTTP_USER_AGENT'])) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         $ua = $_SERVER['HTTP_USER_AGENT']; | ||||||
|  |         // quick escape for non-IEs | ||||||
|  |         if (0 !== strpos($ua, 'Mozilla/4.0 (compatible; MSIE ') | ||||||
|  |             || false !== strpos($ua, 'Opera')) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         // no regex = faaast | ||||||
|  |         $version = (float)substr($ua, 30); | ||||||
|  |         return self::$encodeToIe6 | ||||||
|  |             ? ($version < 6 || ($version == 6 && false === strpos($ua, 'SV1'))) | ||||||
|  |             : ($version < 7); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     protected $_content = ''; | ||||||
|  |     protected $_headers = array(); | ||||||
|  |     protected $_encodeMethod = array('', ''); | ||||||
|  |     protected $_useMbStrlen = false; | ||||||
|  | } | ||||||
							
								
								
									
										449
									
								
								vendor/mrclay/minify/min/lib/JSMin.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										449
									
								
								vendor/mrclay/minify/min/lib/JSMin.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,449 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * JSMin.php - modified PHP implementation of Douglas Crockford's JSMin. | ||||||
|  |  * | ||||||
|  |  * <code> | ||||||
|  |  * $minifiedJs = JSMin::minify($js); | ||||||
|  |  * </code> | ||||||
|  |  * | ||||||
|  |  * This is a modified port of jsmin.c. Improvements: | ||||||
|  |  * | ||||||
|  |  * Does not choke on some regexp literals containing quote characters. E.g. /'/ | ||||||
|  |  * | ||||||
|  |  * Spaces are preserved after some add/sub operators, so they are not mistakenly | ||||||
|  |  * converted to post-inc/dec. E.g. a + ++b -> a+ ++b | ||||||
|  |  * | ||||||
|  |  * Preserves multi-line comments that begin with /*! | ||||||
|  |  * | ||||||
|  |  * PHP 5 or higher is required. | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted to use this version of the library under the | ||||||
|  |  * same terms as jsmin.c, which has the following license: | ||||||
|  |  * | ||||||
|  |  * -- | ||||||
|  |  * Copyright (c) 2002 Douglas Crockford  (www.crockford.com) | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy of | ||||||
|  |  * this software and associated documentation files (the "Software"), to deal in | ||||||
|  |  * the Software without restriction, including without limitation the rights to | ||||||
|  |  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | ||||||
|  |  * of the Software, and to permit persons to whom the Software is furnished to do | ||||||
|  |  * so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in all | ||||||
|  |  * copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * The Software shall be used for Good, not Evil. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  |  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  |  * SOFTWARE. | ||||||
|  |  * -- | ||||||
|  |  * | ||||||
|  |  * @package JSMin | ||||||
|  |  * @author Ryan Grove <ryan@wonko.com> (PHP port) | ||||||
|  |  * @author Steve Clay <steve@mrclay.org> (modifications + cleanup) | ||||||
|  |  * @author Andrea Giammarchi <http://www.3site.eu> (spaceBeforeRegExp) | ||||||
|  |  * @copyright 2002 Douglas Crockford <douglas@crockford.com> (jsmin.c) | ||||||
|  |  * @copyright 2008 Ryan Grove <ryan@wonko.com> (PHP port) | ||||||
|  |  * @license http://opensource.org/licenses/mit-license.php MIT License | ||||||
|  |  * @link http://code.google.com/p/jsmin-php/ | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | class JSMin { | ||||||
|  |     const ORD_LF            = 10; | ||||||
|  |     const ORD_SPACE         = 32; | ||||||
|  |     const ACTION_KEEP_A     = 1; | ||||||
|  |     const ACTION_DELETE_A   = 2; | ||||||
|  |     const ACTION_DELETE_A_B = 3; | ||||||
|  |  | ||||||
|  |     protected $a           = "\n"; | ||||||
|  |     protected $b           = ''; | ||||||
|  |     protected $input       = ''; | ||||||
|  |     protected $inputIndex  = 0; | ||||||
|  |     protected $inputLength = 0; | ||||||
|  |     protected $lookAhead   = null; | ||||||
|  |     protected $output      = ''; | ||||||
|  |     protected $lastByteOut  = ''; | ||||||
|  |     protected $keptComment = ''; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Minify Javascript. | ||||||
|  |      * | ||||||
|  |      * @param string $js Javascript to be minified | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public static function minify($js) | ||||||
|  |     { | ||||||
|  |         $jsmin = new JSMin($js); | ||||||
|  |         return $jsmin->min(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param string $input | ||||||
|  |      */ | ||||||
|  |     public function __construct($input) | ||||||
|  |     { | ||||||
|  |         $this->input = $input; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Perform minification, return result | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public function min() | ||||||
|  |     { | ||||||
|  |         if ($this->output !== '') { // min already run | ||||||
|  |             return $this->output; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $mbIntEnc = null; | ||||||
|  |         if (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) { | ||||||
|  |             $mbIntEnc = mb_internal_encoding(); | ||||||
|  |             mb_internal_encoding('8bit'); | ||||||
|  |         } | ||||||
|  |         $this->input = str_replace("\r\n", "\n", $this->input); | ||||||
|  |         $this->inputLength = strlen($this->input); | ||||||
|  |  | ||||||
|  |         $this->action(self::ACTION_DELETE_A_B); | ||||||
|  |  | ||||||
|  |         while ($this->a !== null) { | ||||||
|  |             // determine next command | ||||||
|  |             $command = self::ACTION_KEEP_A; // default | ||||||
|  |             if ($this->a === ' ') { | ||||||
|  |                 if (($this->lastByteOut === '+' || $this->lastByteOut === '-') | ||||||
|  |                         && ($this->b === $this->lastByteOut)) { | ||||||
|  |                     // Don't delete this space. If we do, the addition/subtraction | ||||||
|  |                     // could be parsed as a post-increment | ||||||
|  |                 } elseif (! $this->isAlphaNum($this->b)) { | ||||||
|  |                     $command = self::ACTION_DELETE_A; | ||||||
|  |                 } | ||||||
|  |             } elseif ($this->a === "\n") { | ||||||
|  |                 if ($this->b === ' ') { | ||||||
|  |                     $command = self::ACTION_DELETE_A_B; | ||||||
|  |  | ||||||
|  |                     // in case of mbstring.func_overload & 2, must check for null b, | ||||||
|  |                     // otherwise mb_strpos will give WARNING | ||||||
|  |                 } elseif ($this->b === null | ||||||
|  |                           || (false === strpos('{[(+-!~', $this->b) | ||||||
|  |                               && ! $this->isAlphaNum($this->b))) { | ||||||
|  |                     $command = self::ACTION_DELETE_A; | ||||||
|  |                 } | ||||||
|  |             } elseif (! $this->isAlphaNum($this->a)) { | ||||||
|  |                 if ($this->b === ' ' | ||||||
|  |                     || ($this->b === "\n" | ||||||
|  |                         && (false === strpos('}])+-"\'', $this->a)))) { | ||||||
|  |                     $command = self::ACTION_DELETE_A_B; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             $this->action($command); | ||||||
|  |         } | ||||||
|  |         $this->output = trim($this->output); | ||||||
|  |  | ||||||
|  |         if ($mbIntEnc !== null) { | ||||||
|  |             mb_internal_encoding($mbIntEnc); | ||||||
|  |         } | ||||||
|  |         return $this->output; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * ACTION_KEEP_A = Output A. Copy B to A. Get the next B. | ||||||
|  |      * ACTION_DELETE_A = Copy B to A. Get the next B. | ||||||
|  |      * ACTION_DELETE_A_B = Get the next B. | ||||||
|  |      * | ||||||
|  |      * @param int $command | ||||||
|  |      * @throws JSMin_UnterminatedRegExpException|JSMin_UnterminatedStringException | ||||||
|  |      */ | ||||||
|  |     protected function action($command) | ||||||
|  |     { | ||||||
|  |         // make sure we don't compress "a + ++b" to "a+++b", etc. | ||||||
|  |         if ($command === self::ACTION_DELETE_A_B | ||||||
|  |             && $this->b === ' ' | ||||||
|  |             && ($this->a === '+' || $this->a === '-')) { | ||||||
|  |             // Note: we're at an addition/substraction operator; the inputIndex | ||||||
|  |             // will certainly be a valid index | ||||||
|  |             if ($this->input[$this->inputIndex] === $this->a) { | ||||||
|  |                 // This is "+ +" or "- -". Don't delete the space. | ||||||
|  |                 $command = self::ACTION_KEEP_A; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         switch ($command) { | ||||||
|  |             case self::ACTION_KEEP_A: // 1 | ||||||
|  |                 $this->output .= $this->a; | ||||||
|  |  | ||||||
|  |                 if ($this->keptComment) { | ||||||
|  |                     $this->output = rtrim($this->output, "\n"); | ||||||
|  |                     $this->output .= $this->keptComment; | ||||||
|  |                     $this->keptComment = ''; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 $this->lastByteOut = $this->a; | ||||||
|  |  | ||||||
|  |                 // fallthrough intentional | ||||||
|  |             case self::ACTION_DELETE_A: // 2 | ||||||
|  |                 $this->a = $this->b; | ||||||
|  |                 if ($this->a === "'" || $this->a === '"') { // string literal | ||||||
|  |                     $str = $this->a; // in case needed for exception | ||||||
|  |                     for(;;) { | ||||||
|  |                         $this->output .= $this->a; | ||||||
|  |                         $this->lastByteOut = $this->a; | ||||||
|  |  | ||||||
|  |                         $this->a = $this->get(); | ||||||
|  |                         if ($this->a === $this->b) { // end quote | ||||||
|  |                             break; | ||||||
|  |                         } | ||||||
|  |                         if ($this->isEOF($this->a)) { | ||||||
|  |                             $byte = $this->inputIndex - 1; | ||||||
|  |                             throw new JSMin_UnterminatedStringException( | ||||||
|  |                                 "JSMin: Unterminated String at byte {$byte}: {$str}"); | ||||||
|  |                         } | ||||||
|  |                         $str .= $this->a; | ||||||
|  |                         if ($this->a === '\\') { | ||||||
|  |                             $this->output .= $this->a; | ||||||
|  |                             $this->lastByteOut = $this->a; | ||||||
|  |  | ||||||
|  |                             $this->a       = $this->get(); | ||||||
|  |                             $str .= $this->a; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 // fallthrough intentional | ||||||
|  |             case self::ACTION_DELETE_A_B: // 3 | ||||||
|  |                 $this->b = $this->next(); | ||||||
|  |                 if ($this->b === '/' && $this->isRegexpLiteral()) { | ||||||
|  |                     $this->output .= $this->a . $this->b; | ||||||
|  |                     $pattern = '/'; // keep entire pattern in case we need to report it in the exception | ||||||
|  |                     for(;;) { | ||||||
|  |                         $this->a = $this->get(); | ||||||
|  |                         $pattern .= $this->a; | ||||||
|  |                         if ($this->a === '[') { | ||||||
|  |                             for(;;) { | ||||||
|  |                                 $this->output .= $this->a; | ||||||
|  |                                 $this->a = $this->get(); | ||||||
|  |                                 $pattern .= $this->a; | ||||||
|  |                                 if ($this->a === ']') { | ||||||
|  |                                     break; | ||||||
|  |                                 } | ||||||
|  |                                 if ($this->a === '\\') { | ||||||
|  |                                     $this->output .= $this->a; | ||||||
|  |                                     $this->a = $this->get(); | ||||||
|  |                                     $pattern .= $this->a; | ||||||
|  |                                 } | ||||||
|  |                                 if ($this->isEOF($this->a)) { | ||||||
|  |                                     throw new JSMin_UnterminatedRegExpException( | ||||||
|  |                                         "JSMin: Unterminated set in RegExp at byte " | ||||||
|  |                                             . $this->inputIndex .": {$pattern}"); | ||||||
|  |                                 } | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |  | ||||||
|  |                         if ($this->a === '/') { // end pattern | ||||||
|  |                             break; // while (true) | ||||||
|  |                         } elseif ($this->a === '\\') { | ||||||
|  |                             $this->output .= $this->a; | ||||||
|  |                             $this->a = $this->get(); | ||||||
|  |                             $pattern .= $this->a; | ||||||
|  |                         } elseif ($this->isEOF($this->a)) { | ||||||
|  |                             $byte = $this->inputIndex - 1; | ||||||
|  |                             throw new JSMin_UnterminatedRegExpException( | ||||||
|  |                                 "JSMin: Unterminated RegExp at byte {$byte}: {$pattern}"); | ||||||
|  |                         } | ||||||
|  |                         $this->output .= $this->a; | ||||||
|  |                         $this->lastByteOut = $this->a; | ||||||
|  |                     } | ||||||
|  |                     $this->b = $this->next(); | ||||||
|  |                 } | ||||||
|  |             // end case ACTION_DELETE_A_B | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @return bool | ||||||
|  |      */ | ||||||
|  |     protected function isRegexpLiteral() | ||||||
|  |     { | ||||||
|  |         if (false !== strpos("(,=:[!&|?+-~*{;", $this->a)) { | ||||||
|  |             // we obviously aren't dividing | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  | 		// we have to check for a preceding keyword, and we don't need to pattern | ||||||
|  | 		// match over the whole output. | ||||||
|  | 		$recentOutput = substr($this->output, -10); | ||||||
|  |  | ||||||
|  | 		// check if return/typeof directly precede a pattern without a space | ||||||
|  | 		foreach (array('return', 'typeof') as $keyword) { | ||||||
|  |             if ($this->a !== substr($keyword, -1)) { | ||||||
|  |                 // certainly wasn't keyword | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |             if (preg_match("~(^|[\\s\\S])" . substr($keyword, 0, -1) . "$~", $recentOutput, $m)) { | ||||||
|  |                 if ($m[1] === '' || !$this->isAlphaNum($m[1])) { | ||||||
|  |                     return true; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  | 		// check all keywords | ||||||
|  | 		if ($this->a === ' ' || $this->a === "\n") { | ||||||
|  | 			if (preg_match('~(^|[\\s\\S])(?:case|else|in|return|typeof)$~', $recentOutput, $m)) { | ||||||
|  | 				if ($m[1] === '' || !$this->isAlphaNum($m[1])) { | ||||||
|  | 					return true; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Return the next character from stdin. Watch out for lookahead. If the character is a control character, | ||||||
|  |      * translate it to a space or linefeed. | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     protected function get() | ||||||
|  |     { | ||||||
|  |         $c = $this->lookAhead; | ||||||
|  |         $this->lookAhead = null; | ||||||
|  |         if ($c === null) { | ||||||
|  |             // getc(stdin) | ||||||
|  |             if ($this->inputIndex < $this->inputLength) { | ||||||
|  |                 $c = $this->input[$this->inputIndex]; | ||||||
|  |                 $this->inputIndex += 1; | ||||||
|  |             } else { | ||||||
|  |                 $c = null; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (ord($c) >= self::ORD_SPACE || $c === "\n" || $c === null) { | ||||||
|  |             return $c; | ||||||
|  |         } | ||||||
|  |         if ($c === "\r") { | ||||||
|  |             return "\n"; | ||||||
|  |         } | ||||||
|  |         return ' '; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Does $a indicate end of input? | ||||||
|  |      * | ||||||
|  |      * @param string $a | ||||||
|  |      * @return bool | ||||||
|  |      */ | ||||||
|  |     protected function isEOF($a) | ||||||
|  |     { | ||||||
|  |         return ord($a) <= self::ORD_LF; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get next char (without getting it). If is ctrl character, translate to a space or newline. | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     protected function peek() | ||||||
|  |     { | ||||||
|  |         $this->lookAhead = $this->get(); | ||||||
|  |         return $this->lookAhead; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Return true if the character is a letter, digit, underscore, dollar sign, or non-ASCII character. | ||||||
|  |      * | ||||||
|  |      * @param string $c | ||||||
|  |      * | ||||||
|  |      * @return bool | ||||||
|  |      */ | ||||||
|  |     protected function isAlphaNum($c) | ||||||
|  |     { | ||||||
|  |         return (preg_match('/^[a-z0-9A-Z_\\$\\\\]$/', $c) || ord($c) > 126); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Consume a single line comment from input (possibly retaining it) | ||||||
|  |      */ | ||||||
|  |     protected function consumeSingleLineComment() | ||||||
|  |     { | ||||||
|  |         $comment = ''; | ||||||
|  |         while (true) { | ||||||
|  |             $get = $this->get(); | ||||||
|  |             $comment .= $get; | ||||||
|  |             if (ord($get) <= self::ORD_LF) { // end of line reached | ||||||
|  |                 // if IE conditional comment | ||||||
|  |                 if (preg_match('/^\\/@(?:cc_on|if|elif|else|end)\\b/', $comment)) { | ||||||
|  |                     $this->keptComment .= "/{$comment}"; | ||||||
|  |                 } | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Consume a multiple line comment from input (possibly retaining it) | ||||||
|  |      * | ||||||
|  |      * @throws JSMin_UnterminatedCommentException | ||||||
|  |      */ | ||||||
|  |     protected function consumeMultipleLineComment() | ||||||
|  |     { | ||||||
|  |         $this->get(); | ||||||
|  |         $comment = ''; | ||||||
|  |         for(;;) { | ||||||
|  |             $get = $this->get(); | ||||||
|  |             if ($get === '*') { | ||||||
|  |                 if ($this->peek() === '/') { // end of comment reached | ||||||
|  |                     $this->get(); | ||||||
|  |                     if (0 === strpos($comment, '!')) { | ||||||
|  |                         // preserved by YUI Compressor | ||||||
|  |                         if (!$this->keptComment) { | ||||||
|  |                             // don't prepend a newline if two comments right after one another | ||||||
|  |                             $this->keptComment = "\n"; | ||||||
|  |                         } | ||||||
|  |                         $this->keptComment .= "/*!" . substr($comment, 1) . "*/\n"; | ||||||
|  |                     } else if (preg_match('/^@(?:cc_on|if|elif|else|end)\\b/', $comment)) { | ||||||
|  |                         // IE conditional | ||||||
|  |                         $this->keptComment .= "/*{$comment}*/"; | ||||||
|  |                     } | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |             } elseif ($get === null) { | ||||||
|  |                 throw new JSMin_UnterminatedCommentException( | ||||||
|  |                     "JSMin: Unterminated comment at byte {$this->inputIndex}: /*{$comment}"); | ||||||
|  |             } | ||||||
|  |             $comment .= $get; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get the next character, skipping over comments. Some comments may be preserved. | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     protected function next() | ||||||
|  |     { | ||||||
|  |         $get = $this->get(); | ||||||
|  |         if ($get === '/') { | ||||||
|  |             switch ($this->peek()) { | ||||||
|  |                 case '/': | ||||||
|  |                     $this->consumeSingleLineComment(); | ||||||
|  |                     $get = "\n"; | ||||||
|  |                     break; | ||||||
|  |                 case '*': | ||||||
|  |                     $this->consumeMultipleLineComment(); | ||||||
|  |                     $get = ' '; | ||||||
|  |                     break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return $get; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class JSMin_UnterminatedStringException extends Exception {} | ||||||
|  | class JSMin_UnterminatedCommentException extends Exception {} | ||||||
|  | class JSMin_UnterminatedRegExpException extends Exception {} | ||||||
							
								
								
									
										2086
									
								
								vendor/mrclay/minify/min/lib/JSMinPlus.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2086
									
								
								vendor/mrclay/minify/min/lib/JSMinPlus.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										608
									
								
								vendor/mrclay/minify/min/lib/Minify.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										608
									
								
								vendor/mrclay/minify/min/lib/Minify.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,608 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify   | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |   | ||||||
|  | /** | ||||||
|  |  * Minify - Combines, minifies, and caches JavaScript and CSS files on demand. | ||||||
|  |  * | ||||||
|  |  * See README for usage instructions (for now). | ||||||
|  |  * | ||||||
|  |  * This library was inspired by {@link mailto:flashkot@mail.ru jscsscomp by Maxim Martynyuk} | ||||||
|  |  * and by the article {@link http://www.hunlock.com/blogs/Supercharged_Javascript "Supercharged JavaScript" by Patrick Hunlock}. | ||||||
|  |  * | ||||||
|  |  * Requires PHP 5.1.0. | ||||||
|  |  * Tested on PHP 5.1.6. | ||||||
|  |  * | ||||||
|  |  * @package Minify | ||||||
|  |  * @author Ryan Grove <ryan@wonko.com> | ||||||
|  |  * @author Stephen Clay <steve@mrclay.org> | ||||||
|  |  * @copyright 2008 Ryan Grove, Stephen Clay. All rights reserved. | ||||||
|  |  * @license http://opensource.org/licenses/bsd-license.php  New BSD License | ||||||
|  |  * @link http://code.google.com/p/minify/ | ||||||
|  |  */ | ||||||
|  | class Minify { | ||||||
|  |      | ||||||
|  |     const VERSION = '2.2.0'; | ||||||
|  |     const TYPE_CSS = 'text/css'; | ||||||
|  |     const TYPE_HTML = 'text/html'; | ||||||
|  |     // there is some debate over the ideal JS Content-Type, but this is the | ||||||
|  |     // Apache default and what Yahoo! uses.. | ||||||
|  |     const TYPE_JS = 'application/x-javascript'; | ||||||
|  |     const URL_DEBUG = 'http://code.google.com/p/minify/wiki/Debugging'; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * How many hours behind are the file modification times of uploaded files? | ||||||
|  |      *  | ||||||
|  |      * If you upload files from Windows to a non-Windows server, Windows may report | ||||||
|  |      * incorrect mtimes for the files. Immediately after modifying and uploading a  | ||||||
|  |      * file, use the touch command to update the mtime on the server. If the mtime  | ||||||
|  |      * jumps ahead by a number of hours, set this variable to that number. If the mtime  | ||||||
|  |      * moves back, this should not be needed. | ||||||
|  |      * | ||||||
|  |      * @var int $uploaderHoursBehind | ||||||
|  |      */ | ||||||
|  |     public static $uploaderHoursBehind = 0; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * If this string is not empty AND the serve() option 'bubbleCssImports' is | ||||||
|  |      * NOT set, then serve() will check CSS files for @import declarations that | ||||||
|  |      * appear too late in the combined stylesheet. If found, serve() will prepend | ||||||
|  |      * the output with this warning. | ||||||
|  |      * | ||||||
|  |      * @var string $importWarning | ||||||
|  |      */ | ||||||
|  |     public static $importWarning = "/* See http://code.google.com/p/minify/wiki/CommonProblems#@imports_can_appear_in_invalid_locations_in_combined_CSS_files */\n"; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Has the DOCUMENT_ROOT been set in user code? | ||||||
|  |      *  | ||||||
|  |      * @var bool | ||||||
|  |      */ | ||||||
|  |     public static $isDocRootSet = false; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Specify a cache object (with identical interface as Minify_Cache_File) or | ||||||
|  |      * a path to use with Minify_Cache_File. | ||||||
|  |      *  | ||||||
|  |      * If not called, Minify will not use a cache and, for each 200 response, will  | ||||||
|  |      * need to recombine files, minify and encode the output. | ||||||
|  |      * | ||||||
|  |      * @param mixed $cache object with identical interface as Minify_Cache_File or | ||||||
|  |      * a directory path, or null to disable caching. (default = '') | ||||||
|  |      *  | ||||||
|  |      * @param bool $fileLocking (default = true) This only applies if the first | ||||||
|  |      * parameter is a string. | ||||||
|  |      * | ||||||
|  |      * @return null | ||||||
|  |      */ | ||||||
|  |     public static function setCache($cache = '', $fileLocking = true) | ||||||
|  |     { | ||||||
|  |         if (is_string($cache)) { | ||||||
|  |             self::$_cache = new Minify_Cache_File($cache, $fileLocking); | ||||||
|  |         } else { | ||||||
|  |             self::$_cache = $cache; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Serve a request for a minified file.  | ||||||
|  |      *  | ||||||
|  |      * Here are the available options and defaults in the base controller: | ||||||
|  |      *  | ||||||
|  |      * 'isPublic' : send "public" instead of "private" in Cache-Control  | ||||||
|  |      * headers, allowing shared caches to cache the output. (default true) | ||||||
|  |      *  | ||||||
|  |      * 'quiet' : set to true to have serve() return an array rather than sending | ||||||
|  |      * any headers/output (default false) | ||||||
|  |      *  | ||||||
|  |      * 'encodeOutput' : set to false to disable content encoding, and not send | ||||||
|  |      * the Vary header (default true) | ||||||
|  |      *  | ||||||
|  |      * 'encodeMethod' : generally you should let this be determined by  | ||||||
|  |      * HTTP_Encoder (leave null), but you can force a particular encoding | ||||||
|  |      * to be returned, by setting this to 'gzip' or '' (no encoding) | ||||||
|  |      *  | ||||||
|  |      * 'encodeLevel' : level of encoding compression (0 to 9, default 9) | ||||||
|  |      *  | ||||||
|  |      * 'contentTypeCharset' : appended to the Content-Type header sent. Set to a falsey | ||||||
|  |      * value to remove. (default 'utf-8')   | ||||||
|  |      *  | ||||||
|  |      * 'maxAge' : set this to the number of seconds the client should use its cache | ||||||
|  |      * before revalidating with the server. This sets Cache-Control: max-age and the | ||||||
|  |      * Expires header. Unlike the old 'setExpires' setting, this setting will NOT | ||||||
|  |      * prevent conditional GETs. Note this has nothing to do with server-side caching. | ||||||
|  |      *  | ||||||
|  |      * 'rewriteCssUris' : If true, serve() will automatically set the 'currentDir' | ||||||
|  |      * minifier option to enable URI rewriting in CSS files (default true) | ||||||
|  |      *  | ||||||
|  |      * 'bubbleCssImports' : If true, all @import declarations in combined CSS | ||||||
|  |      * files will be move to the top. Note this may alter effective CSS values | ||||||
|  |      * due to a change in order. (default false) | ||||||
|  |      *  | ||||||
|  |      * 'debug' : set to true to minify all sources with the 'Lines' controller, which | ||||||
|  |      * eases the debugging of combined files. This also prevents 304 responses. | ||||||
|  |      * @see Minify_Lines::minify() | ||||||
|  |      *  | ||||||
|  |      * 'minifiers' : to override Minify's default choice of minifier function for  | ||||||
|  |      * a particular content-type, specify your callback under the key of the  | ||||||
|  |      * content-type: | ||||||
|  |      * <code> | ||||||
|  |      * // call customCssMinifier($css) for all CSS minification | ||||||
|  |      * $options['minifiers'][Minify::TYPE_CSS] = 'customCssMinifier'; | ||||||
|  |      *  | ||||||
|  |      * // don't minify Javascript at all | ||||||
|  |      * $options['minifiers'][Minify::TYPE_JS] = ''; | ||||||
|  |      * </code> | ||||||
|  |      *  | ||||||
|  |      * 'minifierOptions' : to send options to the minifier function, specify your options | ||||||
|  |      * under the key of the content-type. E.g. To send the CSS minifier an option:  | ||||||
|  |      * <code> | ||||||
|  |      * // give CSS minifier array('optionName' => 'optionValue') as 2nd argument  | ||||||
|  |      * $options['minifierOptions'][Minify::TYPE_CSS]['optionName'] = 'optionValue'; | ||||||
|  |      * </code> | ||||||
|  |      *  | ||||||
|  |      * 'contentType' : (optional) this is only needed if your file extension is not  | ||||||
|  |      * js/css/html. The given content-type will be sent regardless of source file | ||||||
|  |      * extension, so this should not be used in a Groups config with other | ||||||
|  |      * Javascript/CSS files. | ||||||
|  |      *  | ||||||
|  |      * Any controller options are documented in that controller's setupSources() method. | ||||||
|  |      *  | ||||||
|  |      * @param mixed $controller instance of subclass of Minify_Controller_Base or string | ||||||
|  |      * name of controller. E.g. 'Files' | ||||||
|  |      *  | ||||||
|  |      * @param array $options controller/serve options | ||||||
|  |      *  | ||||||
|  |      * @return null|array if the 'quiet' option is set to true, an array | ||||||
|  |      * with keys "success" (bool), "statusCode" (int), "content" (string), and | ||||||
|  |      * "headers" (array). | ||||||
|  |      * | ||||||
|  |      * @throws Exception | ||||||
|  |      */ | ||||||
|  |     public static function serve($controller, $options = array()) | ||||||
|  |     { | ||||||
|  |         if (! self::$isDocRootSet && 0 === stripos(PHP_OS, 'win')) { | ||||||
|  |             self::setDocRoot(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (is_string($controller)) { | ||||||
|  |             // make $controller into object | ||||||
|  |             $class = 'Minify_Controller_' . $controller; | ||||||
|  |             $controller = new $class(); | ||||||
|  |             /* @var Minify_Controller_Base $controller */ | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // set up controller sources and mix remaining options with | ||||||
|  |         // controller defaults | ||||||
|  |         $options = $controller->setupSources($options); | ||||||
|  |         $options = $controller->analyzeSources($options); | ||||||
|  |         self::$_options = $controller->mixInDefaultOptions($options); | ||||||
|  |          | ||||||
|  |         // check request validity | ||||||
|  |         if (! $controller->sources) { | ||||||
|  |             // invalid request! | ||||||
|  |             if (! self::$_options['quiet']) { | ||||||
|  |                 self::_errorExit(self::$_options['badRequestHeader'], self::URL_DEBUG); | ||||||
|  |             } else { | ||||||
|  |                 list(,$statusCode) = explode(' ', self::$_options['badRequestHeader']); | ||||||
|  |                 return array( | ||||||
|  |                     'success' => false | ||||||
|  |                     ,'statusCode' => (int)$statusCode | ||||||
|  |                     ,'content' => '' | ||||||
|  |                     ,'headers' => array() | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         self::$_controller = $controller; | ||||||
|  |          | ||||||
|  |         if (self::$_options['debug']) { | ||||||
|  |             self::_setupDebug($controller->sources); | ||||||
|  |             self::$_options['maxAge'] = 0; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // determine encoding | ||||||
|  |         if (self::$_options['encodeOutput']) { | ||||||
|  |             $sendVary = true; | ||||||
|  |             if (self::$_options['encodeMethod'] !== null) { | ||||||
|  |                 // controller specifically requested this | ||||||
|  |                 $contentEncoding = self::$_options['encodeMethod']; | ||||||
|  |             } else { | ||||||
|  |                 // sniff request header | ||||||
|  |                 // depending on what the client accepts, $contentEncoding may be | ||||||
|  |                 // 'x-gzip' while our internal encodeMethod is 'gzip'. Calling | ||||||
|  |                 // getAcceptedEncoding(false, false) leaves out compress and deflate as options. | ||||||
|  |                 list(self::$_options['encodeMethod'], $contentEncoding) = HTTP_Encoder::getAcceptedEncoding(false, false); | ||||||
|  |                 $sendVary = ! HTTP_Encoder::isBuggyIe(); | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             self::$_options['encodeMethod'] = ''; // identity (no encoding) | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // check client cache | ||||||
|  |         $cgOptions = array( | ||||||
|  |             'lastModifiedTime' => self::$_options['lastModifiedTime'] | ||||||
|  |             ,'isPublic' => self::$_options['isPublic'] | ||||||
|  |             ,'encoding' => self::$_options['encodeMethod'] | ||||||
|  |         ); | ||||||
|  |         if (self::$_options['maxAge'] > 0) { | ||||||
|  |             $cgOptions['maxAge'] = self::$_options['maxAge']; | ||||||
|  |         } elseif (self::$_options['debug']) { | ||||||
|  |             $cgOptions['invalidate'] = true; | ||||||
|  |         } | ||||||
|  |         $cg = new HTTP_ConditionalGet($cgOptions); | ||||||
|  |         if ($cg->cacheIsValid) { | ||||||
|  |             // client's cache is valid | ||||||
|  |             if (! self::$_options['quiet']) { | ||||||
|  |                 $cg->sendHeaders(); | ||||||
|  |                 return; | ||||||
|  |             } else { | ||||||
|  |                 return array( | ||||||
|  |                     'success' => true | ||||||
|  |                     ,'statusCode' => 304 | ||||||
|  |                     ,'content' => '' | ||||||
|  |                     ,'headers' => $cg->getHeaders() | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             // client will need output | ||||||
|  |             $headers = $cg->getHeaders(); | ||||||
|  |             unset($cg); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         if (self::$_options['contentType'] === self::TYPE_CSS | ||||||
|  |             && self::$_options['rewriteCssUris']) { | ||||||
|  |             foreach($controller->sources as $key => $source) { | ||||||
|  |                 if ($source->filepath  | ||||||
|  |                     && !isset($source->minifyOptions['currentDir']) | ||||||
|  |                     && !isset($source->minifyOptions['prependRelativePath']) | ||||||
|  |                 ) { | ||||||
|  |                     $source->minifyOptions['currentDir'] = dirname($source->filepath); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // check server cache | ||||||
|  |         if (null !== self::$_cache && ! self::$_options['debug']) { | ||||||
|  |             // using cache | ||||||
|  |             // the goal is to use only the cache methods to sniff the length and  | ||||||
|  |             // output the content, as they do not require ever loading the file into | ||||||
|  |             // memory. | ||||||
|  |             $cacheId = self::_getCacheId(); | ||||||
|  |             $fullCacheId = (self::$_options['encodeMethod']) | ||||||
|  |                 ? $cacheId . '.gz' | ||||||
|  |                 : $cacheId; | ||||||
|  |             // check cache for valid entry | ||||||
|  |             $cacheIsReady = self::$_cache->isValid($fullCacheId, self::$_options['lastModifiedTime']);  | ||||||
|  |             if ($cacheIsReady) { | ||||||
|  |                 $cacheContentLength = self::$_cache->getSize($fullCacheId);     | ||||||
|  |             } else { | ||||||
|  |                 // generate & cache content | ||||||
|  |                 try { | ||||||
|  |                     $content = self::_combineMinify(); | ||||||
|  |                 } catch (Exception $e) { | ||||||
|  |                     self::$_controller->log($e->getMessage()); | ||||||
|  |                     if (! self::$_options['quiet']) { | ||||||
|  |                         self::_errorExit(self::$_options['errorHeader'], self::URL_DEBUG); | ||||||
|  |                     } | ||||||
|  |                     throw $e; | ||||||
|  |                 } | ||||||
|  |                 self::$_cache->store($cacheId, $content); | ||||||
|  |                 if (function_exists('gzencode') && self::$_options['encodeMethod']) { | ||||||
|  |                     self::$_cache->store($cacheId . '.gz', gzencode($content, self::$_options['encodeLevel'])); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             // no cache | ||||||
|  |             $cacheIsReady = false; | ||||||
|  |             try { | ||||||
|  |                 $content = self::_combineMinify(); | ||||||
|  |             } catch (Exception $e) { | ||||||
|  |                 self::$_controller->log($e->getMessage()); | ||||||
|  |                 if (! self::$_options['quiet']) { | ||||||
|  |                     self::_errorExit(self::$_options['errorHeader'], self::URL_DEBUG); | ||||||
|  |                 } | ||||||
|  |                 throw $e; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (! $cacheIsReady && self::$_options['encodeMethod']) { | ||||||
|  |             // still need to encode | ||||||
|  |             $content = gzencode($content, self::$_options['encodeLevel']); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // add headers | ||||||
|  |         $headers['Content-Length'] = $cacheIsReady | ||||||
|  |             ? $cacheContentLength | ||||||
|  |             : ((function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) | ||||||
|  |                 ? mb_strlen($content, '8bit') | ||||||
|  |                 : strlen($content) | ||||||
|  |             ); | ||||||
|  |         $headers['Content-Type'] = self::$_options['contentTypeCharset'] | ||||||
|  |             ? self::$_options['contentType'] . '; charset=' . self::$_options['contentTypeCharset'] | ||||||
|  |             : self::$_options['contentType']; | ||||||
|  |         if (self::$_options['encodeMethod'] !== '') { | ||||||
|  |             $headers['Content-Encoding'] = $contentEncoding; | ||||||
|  |         } | ||||||
|  |         if (self::$_options['encodeOutput'] && $sendVary) { | ||||||
|  |             $headers['Vary'] = 'Accept-Encoding'; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (! self::$_options['quiet']) { | ||||||
|  |             // output headers & content | ||||||
|  |             foreach ($headers as $name => $val) { | ||||||
|  |                 header($name . ': ' . $val); | ||||||
|  |             } | ||||||
|  |             if ($cacheIsReady) { | ||||||
|  |                 self::$_cache->display($fullCacheId); | ||||||
|  |             } else { | ||||||
|  |                 echo $content; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             return array( | ||||||
|  |                 'success' => true | ||||||
|  |                 ,'statusCode' => 200 | ||||||
|  |                 ,'content' => $cacheIsReady | ||||||
|  |                     ? self::$_cache->fetch($fullCacheId) | ||||||
|  |                     : $content | ||||||
|  |                 ,'headers' => $headers | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Return combined minified content for a set of sources | ||||||
|  |      * | ||||||
|  |      * No internal caching will be used and the content will not be HTTP encoded. | ||||||
|  |      *  | ||||||
|  |      * @param array $sources array of filepaths and/or Minify_Source objects | ||||||
|  |      *  | ||||||
|  |      * @param array $options (optional) array of options for serve. By default | ||||||
|  |      * these are already set: quiet = true, encodeMethod = '', lastModifiedTime = 0. | ||||||
|  |      *  | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public static function combine($sources, $options = array()) | ||||||
|  |     { | ||||||
|  |         $cache = self::$_cache; | ||||||
|  |         self::$_cache = null; | ||||||
|  |         $options = array_merge(array( | ||||||
|  |             'files' => (array)$sources | ||||||
|  |             ,'quiet' => true | ||||||
|  |             ,'encodeMethod' => '' | ||||||
|  |             ,'lastModifiedTime' => 0 | ||||||
|  |         ), $options); | ||||||
|  |         $out = self::serve('Files', $options); | ||||||
|  |         self::$_cache = $cache; | ||||||
|  |         return $out['content']; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Set $_SERVER['DOCUMENT_ROOT']. On IIS, the value is created from SCRIPT_FILENAME and SCRIPT_NAME. | ||||||
|  |      *  | ||||||
|  |      * @param string $docRoot value to use for DOCUMENT_ROOT | ||||||
|  |      */ | ||||||
|  |     public static function setDocRoot($docRoot = '') | ||||||
|  |     { | ||||||
|  |         self::$isDocRootSet = true; | ||||||
|  |         if ($docRoot) { | ||||||
|  |             $_SERVER['DOCUMENT_ROOT'] = $docRoot; | ||||||
|  |         } elseif (isset($_SERVER['SERVER_SOFTWARE']) | ||||||
|  |                   && 0 === strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS/')) { | ||||||
|  |             $_SERVER['DOCUMENT_ROOT'] = substr( | ||||||
|  |                 $_SERVER['SCRIPT_FILENAME'] | ||||||
|  |                 ,0 | ||||||
|  |                 ,strlen($_SERVER['SCRIPT_FILENAME']) - strlen($_SERVER['SCRIPT_NAME'])); | ||||||
|  |             $_SERVER['DOCUMENT_ROOT'] = rtrim($_SERVER['DOCUMENT_ROOT'], '\\'); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Any Minify_Cache_* object or null (i.e. no server cache is used) | ||||||
|  |      * | ||||||
|  |      * @var Minify_Cache_File | ||||||
|  |      */ | ||||||
|  |     private static $_cache = null; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Active controller for current request | ||||||
|  |      * | ||||||
|  |      * @var Minify_Controller_Base | ||||||
|  |      */ | ||||||
|  |     protected static $_controller = null; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Options for current request | ||||||
|  |      * | ||||||
|  |      * @var array | ||||||
|  |      */ | ||||||
|  |     protected static $_options = null; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param string $header | ||||||
|  |      * | ||||||
|  |      * @param string $url | ||||||
|  |      */ | ||||||
|  |     protected static function _errorExit($header, $url) | ||||||
|  |     { | ||||||
|  |         $url = htmlspecialchars($url, ENT_QUOTES); | ||||||
|  |         list(,$h1) = explode(' ', $header, 2); | ||||||
|  |         $h1 = htmlspecialchars($h1); | ||||||
|  |         // FastCGI environments require 3rd arg to header() to be set | ||||||
|  |         list(, $code) = explode(' ', $header, 3); | ||||||
|  |         header($header, true, $code); | ||||||
|  |         header('Content-Type: text/html; charset=utf-8'); | ||||||
|  |         echo "<h1>$h1</h1>"; | ||||||
|  |         echo "<p>Please see <a href='$url'>$url</a>.</p>"; | ||||||
|  |         exit(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set up sources to use Minify_Lines | ||||||
|  |      * | ||||||
|  |      * @param Minify_Source[] $sources Minify_Source instances | ||||||
|  |      */ | ||||||
|  |     protected static function _setupDebug($sources) | ||||||
|  |     { | ||||||
|  |         foreach ($sources as $source) { | ||||||
|  |             $source->minifier = array('Minify_Lines', 'minify'); | ||||||
|  |             $id = $source->getId(); | ||||||
|  |             $source->minifyOptions = array( | ||||||
|  |                 'id' => (is_file($id) ? basename($id) : $id) | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Combines sources and minifies the result. | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      * | ||||||
|  |      * @throws Exception | ||||||
|  |      */ | ||||||
|  |     protected static function _combineMinify() | ||||||
|  |     { | ||||||
|  |         $type = self::$_options['contentType']; // ease readability | ||||||
|  |          | ||||||
|  |         // when combining scripts, make sure all statements separated and | ||||||
|  |         // trailing single line comment is terminated | ||||||
|  |         $implodeSeparator = ($type === self::TYPE_JS) | ||||||
|  |             ? "\n;" | ||||||
|  |             : ''; | ||||||
|  |         // allow the user to pass a particular array of options to each | ||||||
|  |         // minifier (designated by type). source objects may still override | ||||||
|  |         // these | ||||||
|  |         $defaultOptions = isset(self::$_options['minifierOptions'][$type]) | ||||||
|  |             ? self::$_options['minifierOptions'][$type] | ||||||
|  |             : array(); | ||||||
|  |         // if minifier not set, default is no minification. source objects | ||||||
|  |         // may still override this | ||||||
|  |         $defaultMinifier = isset(self::$_options['minifiers'][$type]) | ||||||
|  |             ? self::$_options['minifiers'][$type] | ||||||
|  |             : false; | ||||||
|  |  | ||||||
|  |         // process groups of sources with identical minifiers/options | ||||||
|  |         $content = array(); | ||||||
|  |         $i = 0; | ||||||
|  |         $l = count(self::$_controller->sources); | ||||||
|  |         $groupToProcessTogether = array(); | ||||||
|  |         $lastMinifier = null; | ||||||
|  |         $lastOptions = null; | ||||||
|  |         do { | ||||||
|  |             // get next source | ||||||
|  |             $source = null; | ||||||
|  |             if ($i < $l) { | ||||||
|  |                 $source = self::$_controller->sources[$i]; | ||||||
|  |                 /* @var Minify_Source $source */ | ||||||
|  |                 $sourceContent = $source->getContent(); | ||||||
|  |  | ||||||
|  |                 // allow the source to override our minifier and options | ||||||
|  |                 $minifier = (null !== $source->minifier) | ||||||
|  |                     ? $source->minifier | ||||||
|  |                     : $defaultMinifier; | ||||||
|  |                 $options = (null !== $source->minifyOptions) | ||||||
|  |                     ? array_merge($defaultOptions, $source->minifyOptions) | ||||||
|  |                     : $defaultOptions; | ||||||
|  |             } | ||||||
|  |             // do we need to process our group right now? | ||||||
|  |             if ($i > 0                               // yes, we have at least the first group populated | ||||||
|  |                 && ( | ||||||
|  |                     ! $source                        // yes, we ran out of sources | ||||||
|  |                     || $type === self::TYPE_CSS      // yes, to process CSS individually (avoiding PCRE bugs/limits) | ||||||
|  |                     || $minifier !== $lastMinifier   // yes, minifier changed | ||||||
|  |                     || $options !== $lastOptions)    // yes, options changed | ||||||
|  |                 ) | ||||||
|  |             { | ||||||
|  |                 // minify previous sources with last settings | ||||||
|  |                 $imploded = implode($implodeSeparator, $groupToProcessTogether); | ||||||
|  |                 $groupToProcessTogether = array(); | ||||||
|  |                 if ($lastMinifier) { | ||||||
|  |                     try { | ||||||
|  |                         $content[] = call_user_func($lastMinifier, $imploded, $lastOptions); | ||||||
|  |                     } catch (Exception $e) { | ||||||
|  |                         throw new Exception("Exception in minifier: " . $e->getMessage()); | ||||||
|  |                     } | ||||||
|  |                 } else { | ||||||
|  |                     $content[] = $imploded; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             // add content to the group | ||||||
|  |             if ($source) { | ||||||
|  |                 $groupToProcessTogether[] = $sourceContent; | ||||||
|  |                 $lastMinifier = $minifier; | ||||||
|  |                 $lastOptions = $options; | ||||||
|  |             } | ||||||
|  |             $i++; | ||||||
|  |         } while ($source); | ||||||
|  |  | ||||||
|  |         $content = implode($implodeSeparator, $content); | ||||||
|  |          | ||||||
|  |         if ($type === self::TYPE_CSS && false !== strpos($content, '@import')) { | ||||||
|  |             $content = self::_handleCssImports($content); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // do any post-processing (esp. for editing build URIs) | ||||||
|  |         if (self::$_options['postprocessorRequire']) { | ||||||
|  |             require_once self::$_options['postprocessorRequire']; | ||||||
|  |         } | ||||||
|  |         if (self::$_options['postprocessor']) { | ||||||
|  |             $content = call_user_func(self::$_options['postprocessor'], $content, $type); | ||||||
|  |         } | ||||||
|  |         return $content; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Make a unique cache id for for this request. | ||||||
|  |      *  | ||||||
|  |      * Any settings that could affect output are taken into consideration   | ||||||
|  |      * | ||||||
|  |      * @param string $prefix | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     protected static function _getCacheId($prefix = 'minify') | ||||||
|  |     { | ||||||
|  |         $name = preg_replace('/[^a-zA-Z0-9\\.=_,]/', '', self::$_controller->selectionId); | ||||||
|  |         $name = preg_replace('/\\.+/', '.', $name); | ||||||
|  |         $name = substr($name, 0, 100 - 34 - strlen($prefix)); | ||||||
|  |         $md5 = md5(serialize(array( | ||||||
|  |             Minify_Source::getDigest(self::$_controller->sources) | ||||||
|  |             ,self::$_options['minifiers']  | ||||||
|  |             ,self::$_options['minifierOptions'] | ||||||
|  |             ,self::$_options['postprocessor'] | ||||||
|  |             ,self::$_options['bubbleCssImports'] | ||||||
|  |             ,self::VERSION | ||||||
|  |         ))); | ||||||
|  |         return "{$prefix}_{$name}_{$md5}"; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Bubble CSS @imports to the top or prepend a warning if an import is detected not at the top. | ||||||
|  |      * | ||||||
|  |      * @param string $css | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     protected static function _handleCssImports($css) | ||||||
|  |     { | ||||||
|  |         if (self::$_options['bubbleCssImports']) { | ||||||
|  |             // bubble CSS imports | ||||||
|  |             preg_match_all('/@import.*?;/', $css, $imports); | ||||||
|  |             $css = implode('', $imports[0]) . preg_replace('/@import.*?;/', '', $css); | ||||||
|  |         } else if ('' !== self::$importWarning) { | ||||||
|  |             // remove comments so we don't mistake { in a comment as a block | ||||||
|  |             $noCommentCss = preg_replace('@/\\*[\\s\\S]*?\\*/@', '', $css); | ||||||
|  |             $lastImportPos = strrpos($noCommentCss, '@import'); | ||||||
|  |             $firstBlockPos = strpos($noCommentCss, '{'); | ||||||
|  |             if (false !== $lastImportPos | ||||||
|  |                 && false !== $firstBlockPos | ||||||
|  |                 && $firstBlockPos < $lastImportPos | ||||||
|  |             ) { | ||||||
|  |                 // { appears before @import : prepend warning | ||||||
|  |                 $css = self::$importWarning . $css; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return $css; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										101
									
								
								vendor/mrclay/minify/min/lib/Minify/Build.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								vendor/mrclay/minify/min/lib/Minify/Build.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_Build   | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Maintain a single last modification time for a group of Minify sources to | ||||||
|  |  * allow use of far off Expires headers in Minify. | ||||||
|  |  *  | ||||||
|  |  * <code> | ||||||
|  |  * // in config file | ||||||
|  |  * $groupSources = array( | ||||||
|  |  *   'js' => array('file1.js', 'file2.js') | ||||||
|  |  *   ,'css' => array('file1.css', 'file2.css', 'file3.css') | ||||||
|  |  * ) | ||||||
|  |  *  | ||||||
|  |  * // during HTML generation | ||||||
|  |  * $jsBuild = new Minify_Build($groupSources['js']); | ||||||
|  |  * $cssBuild = new Minify_Build($groupSources['css']); | ||||||
|  |  *  | ||||||
|  |  * $script = "<script type='text/javascript' src='" | ||||||
|  |  *     . $jsBuild->uri('/min.php/js') . "'></script>"; | ||||||
|  |  * $link = "<link rel='stylesheet' type='text/css' href='" | ||||||
|  |  *     . $cssBuild->uri('/min.php/css') . "'>"; | ||||||
|  |  *  | ||||||
|  |  * // in min.php | ||||||
|  |  * Minify::serve('Groups', array( | ||||||
|  |  *   'groups' => $groupSources | ||||||
|  |  *   ,'setExpires' => (time() + 86400 * 365) | ||||||
|  |  * )); | ||||||
|  |  * </code> | ||||||
|  |  *  | ||||||
|  |  * @package Minify | ||||||
|  |  * @author Stephen Clay <steve@mrclay.org> | ||||||
|  |  */ | ||||||
|  | class Minify_Build { | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Last modification time of all files in the build | ||||||
|  |      *  | ||||||
|  |      * @var int  | ||||||
|  |      */ | ||||||
|  |     public $lastModified = 0; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * String to use as ampersand in uri(). Set this to '&' if | ||||||
|  |      * you are not HTML-escaping URIs. | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public static $ampersand = '&'; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Get a time-stamped URI | ||||||
|  |      *  | ||||||
|  |      * <code> | ||||||
|  |      * echo $b->uri('/site.js'); | ||||||
|  |      * // outputs "/site.js?1678242" | ||||||
|  |      *  | ||||||
|  |      * echo $b->uri('/scriptaculous.js?load=effects'); | ||||||
|  |      * // outputs "/scriptaculous.js?load=effects&1678242" | ||||||
|  |      * </code> | ||||||
|  |      * | ||||||
|  |      * @param string $uri | ||||||
|  |      * @param boolean $forceAmpersand (default = false) Force the use of ampersand to  | ||||||
|  |      * append the timestamp to the URI. | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public function uri($uri, $forceAmpersand = false) { | ||||||
|  |         $sep = ($forceAmpersand || strpos($uri, '?') !== false) | ||||||
|  |             ? self::$ampersand | ||||||
|  |             : '?'; | ||||||
|  |         return "{$uri}{$sep}{$this->lastModified}"; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  |      * Create a build object | ||||||
|  |      *  | ||||||
|  |      * @param array $sources array of Minify_Source objects and/or file paths | ||||||
|  |      *  | ||||||
|  |      * @return null | ||||||
|  |      */ | ||||||
|  |     public function __construct($sources)  | ||||||
|  |     { | ||||||
|  |         $max = 0; | ||||||
|  |         foreach ((array)$sources as $source) { | ||||||
|  |             if ($source instanceof Minify_Source) { | ||||||
|  |                 $max = max($max, $source->lastModified); | ||||||
|  |             } elseif (is_string($source)) { | ||||||
|  |                 if (0 === strpos($source, '//')) { | ||||||
|  |                     $source = $_SERVER['DOCUMENT_ROOT'] . substr($source, 1); | ||||||
|  |                 } | ||||||
|  |                 if (is_file($source)) { | ||||||
|  |                     $max = max($max, filemtime($source)); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         $this->lastModified = $max; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										99
									
								
								vendor/mrclay/minify/min/lib/Minify/CSS.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								vendor/mrclay/minify/min/lib/Minify/CSS.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,99 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_CSS   | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Minify CSS | ||||||
|  |  * | ||||||
|  |  * This class uses Minify_CSS_Compressor and Minify_CSS_UriRewriter to  | ||||||
|  |  * minify CSS and rewrite relative URIs. | ||||||
|  |  *  | ||||||
|  |  * @package Minify | ||||||
|  |  * @author Stephen Clay <steve@mrclay.org> | ||||||
|  |  * @author http://code.google.com/u/1stvamp/ (Issue 64 patch) | ||||||
|  |  */ | ||||||
|  | class Minify_CSS { | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Minify a CSS string | ||||||
|  |      *  | ||||||
|  |      * @param string $css | ||||||
|  |      *  | ||||||
|  |      * @param array $options available options: | ||||||
|  |      *  | ||||||
|  |      * 'preserveComments': (default true) multi-line comments that begin | ||||||
|  |      * with "/*!" will be preserved with newlines before and after to | ||||||
|  |      * enhance readability. | ||||||
|  |      * | ||||||
|  |      * 'removeCharsets': (default true) remove all @charset at-rules | ||||||
|  |      *  | ||||||
|  |      * 'prependRelativePath': (default null) if given, this string will be | ||||||
|  |      * prepended to all relative URIs in import/url declarations | ||||||
|  |      *  | ||||||
|  |      * 'currentDir': (default null) if given, this is assumed to be the | ||||||
|  |      * directory of the current CSS file. Using this, minify will rewrite | ||||||
|  |      * all relative URIs in import/url declarations to correctly point to | ||||||
|  |      * the desired files. For this to work, the files *must* exist and be | ||||||
|  |      * visible by the PHP process. | ||||||
|  |      * | ||||||
|  |      * 'symlinks': (default = array()) If the CSS file is stored in  | ||||||
|  |      * a symlink-ed directory, provide an array of link paths to | ||||||
|  |      * target paths, where the link paths are within the document root. Because  | ||||||
|  |      * paths need to be normalized for this to work, use "//" to substitute  | ||||||
|  |      * the doc root in the link paths (the array keys). E.g.: | ||||||
|  |      * <code> | ||||||
|  |      * array('//symlink' => '/real/target/path') // unix | ||||||
|  |      * array('//static' => 'D:\\staticStorage')  // Windows | ||||||
|  |      * </code> | ||||||
|  |      * | ||||||
|  |      * 'docRoot': (default = $_SERVER['DOCUMENT_ROOT']) | ||||||
|  |      * see Minify_CSS_UriRewriter::rewrite | ||||||
|  |      *  | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public static function minify($css, $options = array())  | ||||||
|  |     { | ||||||
|  |         $options = array_merge(array( | ||||||
|  |             'compress' => true, | ||||||
|  |             'removeCharsets' => true, | ||||||
|  |             'preserveComments' => true, | ||||||
|  |             'currentDir' => null, | ||||||
|  |             'docRoot' => $_SERVER['DOCUMENT_ROOT'], | ||||||
|  |             'prependRelativePath' => null, | ||||||
|  |             'symlinks' => array(), | ||||||
|  |         ), $options); | ||||||
|  |          | ||||||
|  |         if ($options['removeCharsets']) { | ||||||
|  |             $css = preg_replace('/@charset[^;]+;\\s*/', '', $css); | ||||||
|  |         } | ||||||
|  |         if ($options['compress']) { | ||||||
|  |             if (! $options['preserveComments']) { | ||||||
|  |                 $css = Minify_CSS_Compressor::process($css, $options); | ||||||
|  |             } else { | ||||||
|  |                 $css = Minify_CommentPreserver::process( | ||||||
|  |                     $css | ||||||
|  |                     ,array('Minify_CSS_Compressor', 'process') | ||||||
|  |                     ,array($options) | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (! $options['currentDir'] && ! $options['prependRelativePath']) { | ||||||
|  |             return $css; | ||||||
|  |         } | ||||||
|  |         if ($options['currentDir']) { | ||||||
|  |             return Minify_CSS_UriRewriter::rewrite( | ||||||
|  |                 $css | ||||||
|  |                 ,$options['currentDir'] | ||||||
|  |                 ,$options['docRoot'] | ||||||
|  |                 ,$options['symlinks'] | ||||||
|  |             );   | ||||||
|  |         } else { | ||||||
|  |             return Minify_CSS_UriRewriter::prepend( | ||||||
|  |                 $css | ||||||
|  |                 ,$options['prependRelativePath'] | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										249
									
								
								vendor/mrclay/minify/min/lib/Minify/CSS/Compressor.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										249
									
								
								vendor/mrclay/minify/min/lib/Minify/CSS/Compressor.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,249 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_CSS_Compressor  | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Compress CSS | ||||||
|  |  * | ||||||
|  |  * This is a heavy regex-based removal of whitespace, unnecessary | ||||||
|  |  * comments and tokens, and some CSS value minimization, where practical. | ||||||
|  |  * Many steps have been taken to avoid breaking comment-based hacks,  | ||||||
|  |  * including the ie5/mac filter (and its inversion), but expect tricky | ||||||
|  |  * hacks involving comment tokens in 'content' value strings to break | ||||||
|  |  * minimization badly. A test suite is available. | ||||||
|  |  *  | ||||||
|  |  * @package Minify | ||||||
|  |  * @author Stephen Clay <steve@mrclay.org> | ||||||
|  |  * @author http://code.google.com/u/1stvamp/ (Issue 64 patch) | ||||||
|  |  */ | ||||||
|  | class Minify_CSS_Compressor { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Minify a CSS string | ||||||
|  |      *  | ||||||
|  |      * @param string $css | ||||||
|  |      *  | ||||||
|  |      * @param array $options (currently ignored) | ||||||
|  |      *  | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public static function process($css, $options = array()) | ||||||
|  |     { | ||||||
|  |         $obj = new Minify_CSS_Compressor($options); | ||||||
|  |         return $obj->_process($css); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * @var array | ||||||
|  |      */ | ||||||
|  |     protected $_options = null; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Are we "in" a hack? I.e. are some browsers targetted until the next comment? | ||||||
|  |      * | ||||||
|  |      * @var bool | ||||||
|  |      */ | ||||||
|  |     protected $_inHack = false; | ||||||
|  |      | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Constructor | ||||||
|  |      *  | ||||||
|  |      * @param array $options (currently ignored) | ||||||
|  |      */ | ||||||
|  |     private function __construct($options) { | ||||||
|  |         $this->_options = $options; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Minify a CSS string | ||||||
|  |      *  | ||||||
|  |      * @param string $css | ||||||
|  |      *  | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     protected function _process($css) | ||||||
|  |     { | ||||||
|  |         $css = str_replace("\r\n", "\n", $css); | ||||||
|  |          | ||||||
|  |         // preserve empty comment after '>' | ||||||
|  |         // http://www.webdevout.net/css-hacks#in_css-selectors | ||||||
|  |         $css = preg_replace('@>/\\*\\s*\\*/@', '>/*keep*/', $css); | ||||||
|  |          | ||||||
|  |         // preserve empty comment between property and value | ||||||
|  |         // http://css-discuss.incutio.com/?page=BoxModelHack | ||||||
|  |         $css = preg_replace('@/\\*\\s*\\*/\\s*:@', '/*keep*/:', $css); | ||||||
|  |         $css = preg_replace('@:\\s*/\\*\\s*\\*/@', ':/*keep*/', $css); | ||||||
|  |          | ||||||
|  |         // apply callback to all valid comments (and strip out surrounding ws | ||||||
|  |         $css = preg_replace_callback('@\\s*/\\*([\\s\\S]*?)\\*/\\s*@' | ||||||
|  |             ,array($this, '_commentCB'), $css); | ||||||
|  |  | ||||||
|  |         // remove ws around { } and last semicolon in declaration block | ||||||
|  |         $css = preg_replace('/\\s*{\\s*/', '{', $css); | ||||||
|  |         $css = preg_replace('/;?\\s*}\\s*/', '}', $css); | ||||||
|  |          | ||||||
|  |         // remove ws surrounding semicolons | ||||||
|  |         $css = preg_replace('/\\s*;\\s*/', ';', $css); | ||||||
|  |          | ||||||
|  |         // remove ws around urls | ||||||
|  |         $css = preg_replace('/ | ||||||
|  |                 url\\(      # url( | ||||||
|  |                 \\s* | ||||||
|  |                 ([^\\)]+?)  # 1 = the URL (really just a bunch of non right parenthesis) | ||||||
|  |                 \\s* | ||||||
|  |                 \\)         # ) | ||||||
|  |             /x', 'url($1)', $css); | ||||||
|  |          | ||||||
|  |         // remove ws between rules and colons | ||||||
|  |         $css = preg_replace('/ | ||||||
|  |                 \\s* | ||||||
|  |                 ([{;])              # 1 = beginning of block or rule separator  | ||||||
|  |                 \\s* | ||||||
|  |                 ([\\*_]?[\\w\\-]+)  # 2 = property (and maybe IE filter) | ||||||
|  |                 \\s* | ||||||
|  |                 : | ||||||
|  |                 \\s* | ||||||
|  |                 (\\b|[#\'"-])        # 3 = first character of a value | ||||||
|  |             /x', '$1$2:$3', $css); | ||||||
|  |          | ||||||
|  |         // remove ws in selectors | ||||||
|  |         $css = preg_replace_callback('/ | ||||||
|  |                 (?:              # non-capture | ||||||
|  |                     \\s* | ||||||
|  |                     [^~>+,\\s]+  # selector part | ||||||
|  |                     \\s* | ||||||
|  |                     [,>+~]       # combinators | ||||||
|  |                 )+ | ||||||
|  |                 \\s* | ||||||
|  |                 [^~>+,\\s]+      # selector part | ||||||
|  |                 {                # open declaration block | ||||||
|  |             /x' | ||||||
|  |             ,array($this, '_selectorsCB'), $css); | ||||||
|  |          | ||||||
|  |         // minimize hex colors | ||||||
|  |         $css = preg_replace('/([^=])#([a-f\\d])\\2([a-f\\d])\\3([a-f\\d])\\4([\\s;\\}])/i' | ||||||
|  |             , '$1#$2$3$4$5', $css); | ||||||
|  |          | ||||||
|  |         // remove spaces between font families | ||||||
|  |         $css = preg_replace_callback('/font-family:([^;}]+)([;}])/' | ||||||
|  |             ,array($this, '_fontFamilyCB'), $css); | ||||||
|  |          | ||||||
|  |         $css = preg_replace('/@import\\s+url/', '@import url', $css); | ||||||
|  |          | ||||||
|  |         // replace any ws involving newlines with a single newline | ||||||
|  |         $css = preg_replace('/[ \\t]*\\n+\\s*/', "\n", $css); | ||||||
|  |          | ||||||
|  |         // separate common descendent selectors w/ newlines (to limit line lengths) | ||||||
|  |         $css = preg_replace('/([\\w#\\.\\*]+)\\s+([\\w#\\.\\*]+){/', "$1\n$2{", $css); | ||||||
|  |          | ||||||
|  |         // Use newline after 1st numeric value (to limit line lengths). | ||||||
|  |         $css = preg_replace('/ | ||||||
|  |             ((?:padding|margin|border|outline):\\d+(?:px|em)?) # 1 = prop : 1st numeric value | ||||||
|  |             \\s+ | ||||||
|  |             /x' | ||||||
|  |             ,"$1\n", $css); | ||||||
|  |          | ||||||
|  |         // prevent triggering IE6 bug: http://www.crankygeek.com/ie6pebug/ | ||||||
|  |         $css = preg_replace('/:first-l(etter|ine)\\{/', ':first-l$1 {', $css); | ||||||
|  |              | ||||||
|  |         return trim($css); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Replace what looks like a set of selectors   | ||||||
|  |      * | ||||||
|  |      * @param array $m regex matches | ||||||
|  |      *  | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     protected function _selectorsCB($m) | ||||||
|  |     { | ||||||
|  |         // remove ws around the combinators | ||||||
|  |         return preg_replace('/\\s*([,>+~])\\s*/', '$1', $m[0]); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Process a comment and return a replacement | ||||||
|  |      *  | ||||||
|  |      * @param array $m regex matches | ||||||
|  |      *  | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     protected function _commentCB($m) | ||||||
|  |     { | ||||||
|  |         $hasSurroundingWs = (trim($m[0]) !== $m[1]); | ||||||
|  |         $m = $m[1];  | ||||||
|  |         // $m is the comment content w/o the surrounding tokens,  | ||||||
|  |         // but the return value will replace the entire comment. | ||||||
|  |         if ($m === 'keep') { | ||||||
|  |             return '/**/'; | ||||||
|  |         } | ||||||
|  |         if ($m === '" "') { | ||||||
|  |             // component of http://tantek.com/CSS/Examples/midpass.html | ||||||
|  |             return '/*" "*/'; | ||||||
|  |         } | ||||||
|  |         if (preg_match('@";\\}\\s*\\}/\\*\\s+@', $m)) { | ||||||
|  |             // component of http://tantek.com/CSS/Examples/midpass.html | ||||||
|  |             return '/*";}}/* */'; | ||||||
|  |         } | ||||||
|  |         if ($this->_inHack) { | ||||||
|  |             // inversion: feeding only to one browser | ||||||
|  |             if (preg_match('@ | ||||||
|  |                     ^/               # comment started like /*/ | ||||||
|  |                     \\s* | ||||||
|  |                     (\\S[\\s\\S]+?)  # has at least some non-ws content | ||||||
|  |                     \\s* | ||||||
|  |                     /\\*             # ends like /*/ or /**/ | ||||||
|  |                 @x', $m, $n)) { | ||||||
|  |                 // end hack mode after this comment, but preserve the hack and comment content | ||||||
|  |                 $this->_inHack = false; | ||||||
|  |                 return "/*/{$n[1]}/**/"; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (substr($m, -1) === '\\') { // comment ends like \*/ | ||||||
|  |             // begin hack mode and preserve hack | ||||||
|  |             $this->_inHack = true; | ||||||
|  |             return '/*\\*/'; | ||||||
|  |         } | ||||||
|  |         if ($m !== '' && $m[0] === '/') { // comment looks like /*/ foo */ | ||||||
|  |             // begin hack mode and preserve hack | ||||||
|  |             $this->_inHack = true; | ||||||
|  |             return '/*/*/'; | ||||||
|  |         } | ||||||
|  |         if ($this->_inHack) { | ||||||
|  |             // a regular comment ends hack mode but should be preserved | ||||||
|  |             $this->_inHack = false; | ||||||
|  |             return '/**/'; | ||||||
|  |         } | ||||||
|  |         // Issue 107: if there's any surrounding whitespace, it may be important, so  | ||||||
|  |         // replace the comment with a single space | ||||||
|  |         return $hasSurroundingWs // remove all other comments | ||||||
|  |             ? ' ' | ||||||
|  |             : ''; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Process a font-family listing and return a replacement | ||||||
|  |      *  | ||||||
|  |      * @param array $m regex matches | ||||||
|  |      *  | ||||||
|  |      * @return string    | ||||||
|  |      */ | ||||||
|  |     protected function _fontFamilyCB($m) | ||||||
|  |     { | ||||||
|  |         // Issue 210: must not eliminate WS between words in unquoted families | ||||||
|  |         $pieces = preg_split('/(\'[^\']+\'|"[^"]+")/', $m[1], null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); | ||||||
|  |         $out = 'font-family:'; | ||||||
|  |         while (null !== ($piece = array_shift($pieces))) { | ||||||
|  |             if ($piece[0] !== '"' && $piece[0] !== "'") { | ||||||
|  |                 $piece = preg_replace('/\\s+/', ' ', $piece); | ||||||
|  |                 $piece = preg_replace('/\\s?,\\s?/', ',', $piece); | ||||||
|  |             } | ||||||
|  |             $out .= $piece; | ||||||
|  |         } | ||||||
|  |         return $out . $m[2]; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										307
									
								
								vendor/mrclay/minify/min/lib/Minify/CSS/UriRewriter.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										307
									
								
								vendor/mrclay/minify/min/lib/Minify/CSS/UriRewriter.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,307 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_CSS_UriRewriter   | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Rewrite file-relative URIs as root-relative in CSS files | ||||||
|  |  * | ||||||
|  |  * @package Minify | ||||||
|  |  * @author Stephen Clay <steve@mrclay.org> | ||||||
|  |  */ | ||||||
|  | class Minify_CSS_UriRewriter { | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * rewrite() and rewriteRelative() append debugging information here | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public static $debugText = ''; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * In CSS content, rewrite file relative URIs as root relative | ||||||
|  |      *  | ||||||
|  |      * @param string $css | ||||||
|  |      *  | ||||||
|  |      * @param string $currentDir The directory of the current CSS file. | ||||||
|  |      *  | ||||||
|  |      * @param string $docRoot The document root of the web site in which  | ||||||
|  |      * the CSS file resides (default = $_SERVER['DOCUMENT_ROOT']). | ||||||
|  |      *  | ||||||
|  |      * @param array $symlinks (default = array()) If the CSS file is stored in  | ||||||
|  |      * a symlink-ed directory, provide an array of link paths to | ||||||
|  |      * target paths, where the link paths are within the document root. Because  | ||||||
|  |      * paths need to be normalized for this to work, use "//" to substitute  | ||||||
|  |      * the doc root in the link paths (the array keys). E.g.: | ||||||
|  |      * <code> | ||||||
|  |      * array('//symlink' => '/real/target/path') // unix | ||||||
|  |      * array('//static' => 'D:\\staticStorage')  // Windows | ||||||
|  |      * </code> | ||||||
|  |      *  | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public static function rewrite($css, $currentDir, $docRoot = null, $symlinks = array())  | ||||||
|  |     { | ||||||
|  |         self::$_docRoot = self::_realpath( | ||||||
|  |             $docRoot ? $docRoot : $_SERVER['DOCUMENT_ROOT'] | ||||||
|  |         ); | ||||||
|  |         self::$_currentDir = self::_realpath($currentDir); | ||||||
|  |         self::$_symlinks = array(); | ||||||
|  |          | ||||||
|  |         // normalize symlinks | ||||||
|  |         foreach ($symlinks as $link => $target) { | ||||||
|  |             $link = ($link === '//') | ||||||
|  |                 ? self::$_docRoot | ||||||
|  |                 : str_replace('//', self::$_docRoot . '/', $link); | ||||||
|  |             $link = strtr($link, '/', DIRECTORY_SEPARATOR); | ||||||
|  |             self::$_symlinks[$link] = self::_realpath($target); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         self::$debugText .= "docRoot    : " . self::$_docRoot . "\n" | ||||||
|  |                           . "currentDir : " . self::$_currentDir . "\n"; | ||||||
|  |         if (self::$_symlinks) { | ||||||
|  |             self::$debugText .= "symlinks : " . var_export(self::$_symlinks, 1) . "\n"; | ||||||
|  |         } | ||||||
|  |         self::$debugText .= "\n"; | ||||||
|  |          | ||||||
|  |         $css = self::_trimUrls($css); | ||||||
|  |          | ||||||
|  |         // rewrite | ||||||
|  |         $css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/' | ||||||
|  |             ,array(self::$className, '_processUriCB'), $css); | ||||||
|  |         $css = preg_replace_callback('/url\\(\\s*([\'"](.*?)[\'"]|[^\\)\\s]+)\\s*\\)/' | ||||||
|  |             ,array(self::$className, '_processUriCB'), $css); | ||||||
|  |  | ||||||
|  |         return $css; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * In CSS content, prepend a path to relative URIs | ||||||
|  |      *  | ||||||
|  |      * @param string $css | ||||||
|  |      *  | ||||||
|  |      * @param string $path The path to prepend. | ||||||
|  |      *  | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public static function prepend($css, $path) | ||||||
|  |     { | ||||||
|  |         self::$_prependPath = $path; | ||||||
|  |          | ||||||
|  |         $css = self::_trimUrls($css); | ||||||
|  |          | ||||||
|  |         // append | ||||||
|  |         $css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/' | ||||||
|  |             ,array(self::$className, '_processUriCB'), $css); | ||||||
|  |         $css = preg_replace_callback('/url\\(\\s*([\'"](.*?)[\'"]|[^\\)\\s]+)\\s*\\)/' | ||||||
|  |             ,array(self::$className, '_processUriCB'), $css); | ||||||
|  |  | ||||||
|  |         self::$_prependPath = null; | ||||||
|  |         return $css; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Get a root relative URI from a file relative URI | ||||||
|  |      * | ||||||
|  |      * <code> | ||||||
|  |      * Minify_CSS_UriRewriter::rewriteRelative( | ||||||
|  |      *       '../img/hello.gif' | ||||||
|  |      *     , '/home/user/www/css'  // path of CSS file | ||||||
|  |      *     , '/home/user/www'      // doc root | ||||||
|  |      * ); | ||||||
|  |      * // returns '/img/hello.gif' | ||||||
|  |      *  | ||||||
|  |      * // example where static files are stored in a symlinked directory | ||||||
|  |      * Minify_CSS_UriRewriter::rewriteRelative( | ||||||
|  |      *       'hello.gif' | ||||||
|  |      *     , '/var/staticFiles/theme' | ||||||
|  |      *     , '/home/user/www' | ||||||
|  |      *     , array('/home/user/www/static' => '/var/staticFiles') | ||||||
|  |      * ); | ||||||
|  |      * // returns '/static/theme/hello.gif' | ||||||
|  |      * </code> | ||||||
|  |      *  | ||||||
|  |      * @param string $uri file relative URI | ||||||
|  |      *  | ||||||
|  |      * @param string $realCurrentDir realpath of the current file's directory. | ||||||
|  |      *  | ||||||
|  |      * @param string $realDocRoot realpath of the site document root. | ||||||
|  |      *  | ||||||
|  |      * @param array $symlinks (default = array()) If the file is stored in  | ||||||
|  |      * a symlink-ed directory, provide an array of link paths to | ||||||
|  |      * real target paths, where the link paths "appear" to be within the document  | ||||||
|  |      * root. E.g.: | ||||||
|  |      * <code> | ||||||
|  |      * array('/home/foo/www/not/real/path' => '/real/target/path') // unix | ||||||
|  |      * array('C:\\htdocs\\not\\real' => 'D:\\real\\target\\path')  // Windows | ||||||
|  |      * </code> | ||||||
|  |      *  | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public static function rewriteRelative($uri, $realCurrentDir, $realDocRoot, $symlinks = array()) | ||||||
|  |     { | ||||||
|  |         // prepend path with current dir separator (OS-independent) | ||||||
|  |         $path = strtr($realCurrentDir, '/', DIRECTORY_SEPARATOR)   | ||||||
|  |             . DIRECTORY_SEPARATOR . strtr($uri, '/', DIRECTORY_SEPARATOR); | ||||||
|  |          | ||||||
|  |         self::$debugText .= "file-relative URI  : {$uri}\n" | ||||||
|  |                           . "path prepended     : {$path}\n"; | ||||||
|  |          | ||||||
|  |         // "unresolve" a symlink back to doc root | ||||||
|  |         foreach ($symlinks as $link => $target) { | ||||||
|  |             if (0 === strpos($path, $target)) { | ||||||
|  |                 // replace $target with $link | ||||||
|  |                 $path = $link . substr($path, strlen($target)); | ||||||
|  |                  | ||||||
|  |                 self::$debugText .= "symlink unresolved : {$path}\n"; | ||||||
|  |                  | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         // strip doc root | ||||||
|  |         $path = substr($path, strlen($realDocRoot)); | ||||||
|  |          | ||||||
|  |         self::$debugText .= "docroot stripped   : {$path}\n"; | ||||||
|  |          | ||||||
|  |         // fix to root-relative URI | ||||||
|  |         $uri = strtr($path, '/\\', '//'); | ||||||
|  |         $uri = self::removeDots($uri); | ||||||
|  |        | ||||||
|  |         self::$debugText .= "traversals removed : {$uri}\n\n"; | ||||||
|  |          | ||||||
|  |         return $uri; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Remove instances of "./" and "../" where possible from a root-relative URI | ||||||
|  |      * | ||||||
|  |      * @param string $uri | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public static function removeDots($uri) | ||||||
|  |     { | ||||||
|  |         $uri = str_replace('/./', '/', $uri); | ||||||
|  |         // inspired by patch from Oleg Cherniy | ||||||
|  |         do { | ||||||
|  |             $uri = preg_replace('@/[^/]+/\\.\\./@', '/', $uri, 1, $changed); | ||||||
|  |         } while ($changed); | ||||||
|  |         return $uri; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Defines which class to call as part of callbacks, change this | ||||||
|  |      * if you extend Minify_CSS_UriRewriter | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     protected static $className = 'Minify_CSS_UriRewriter'; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get realpath with any trailing slash removed. If realpath() fails, | ||||||
|  |      * just remove the trailing slash. | ||||||
|  |      *  | ||||||
|  |      * @param string $path | ||||||
|  |      *  | ||||||
|  |      * @return mixed path with no trailing slash | ||||||
|  |      */ | ||||||
|  |     protected static function _realpath($path) | ||||||
|  |     { | ||||||
|  |         $realPath = realpath($path); | ||||||
|  |         if ($realPath !== false) { | ||||||
|  |             $path = $realPath; | ||||||
|  |         } | ||||||
|  |         return rtrim($path, '/\\'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Directory of this stylesheet | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     private static $_currentDir = ''; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * DOC_ROOT | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     private static $_docRoot = ''; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * directory replacements to map symlink targets back to their | ||||||
|  |      * source (within the document root) E.g. '/var/www/symlink' => '/var/realpath' | ||||||
|  |      * | ||||||
|  |      * @var array | ||||||
|  |      */ | ||||||
|  |     private static $_symlinks = array(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Path to prepend | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     private static $_prependPath = null; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param string $css | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     private static function _trimUrls($css) | ||||||
|  |     { | ||||||
|  |         return preg_replace('/ | ||||||
|  |             url\\(      # url( | ||||||
|  |             \\s* | ||||||
|  |             ([^\\)]+?)  # 1 = URI (assuming does not contain ")") | ||||||
|  |             \\s* | ||||||
|  |             \\)         # ) | ||||||
|  |         /x', 'url($1)', $css); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param array $m | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     private static function _processUriCB($m) | ||||||
|  |     { | ||||||
|  |         // $m matched either '/@import\\s+([\'"])(.*?)[\'"]/' or '/url\\(\\s*([^\\)\\s]+)\\s*\\)/' | ||||||
|  |         $isImport = ($m[0][0] === '@'); | ||||||
|  |         // determine URI and the quote character (if any) | ||||||
|  |         if ($isImport) { | ||||||
|  |             $quoteChar = $m[1]; | ||||||
|  |             $uri = $m[2]; | ||||||
|  |         } else { | ||||||
|  |             // $m[1] is either quoted or not | ||||||
|  |             $quoteChar = ($m[1][0] === "'" || $m[1][0] === '"') | ||||||
|  |                 ? $m[1][0] | ||||||
|  |                 : ''; | ||||||
|  |             $uri = ($quoteChar === '') | ||||||
|  |                 ? $m[1] | ||||||
|  |                 : substr($m[1], 1, strlen($m[1]) - 2); | ||||||
|  |         } | ||||||
|  |         // if not root/scheme relative and not starts with scheme | ||||||
|  |         if (!preg_match('~^(/|[a-z]+\:)~', $uri)) { | ||||||
|  |             // URI is file-relative: rewrite depending on options | ||||||
|  |             if (self::$_prependPath === null) { | ||||||
|  |                 $uri = self::rewriteRelative($uri, self::$_currentDir, self::$_docRoot, self::$_symlinks); | ||||||
|  |             } else { | ||||||
|  |                 $uri = self::$_prependPath . $uri; | ||||||
|  |                 if ($uri[0] === '/') { | ||||||
|  |                     $root = ''; | ||||||
|  |                     $rootRelative = $uri; | ||||||
|  |                     $uri = $root . self::removeDots($rootRelative); | ||||||
|  |                 } elseif (preg_match('@^((https?\:)?//([^/]+))/@', $uri, $m) && (false !== strpos($m[3], '.'))) { | ||||||
|  |                     $root = $m[1]; | ||||||
|  |                     $rootRelative = substr($uri, strlen($root)); | ||||||
|  |                     $uri = $root . self::removeDots($rootRelative); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return $isImport | ||||||
|  |             ? "@import {$quoteChar}{$uri}{$quoteChar}" | ||||||
|  |             : "url({$quoteChar}{$uri}{$quoteChar})"; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										85
									
								
								vendor/mrclay/minify/min/lib/Minify/CSSmin.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								vendor/mrclay/minify/min/lib/Minify/CSSmin.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,85 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_CSSmin | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Wrapper for CSSmin | ||||||
|  |  * | ||||||
|  |  * This class uses CSSmin and Minify_CSS_UriRewriter to minify CSS and rewrite relative URIs. | ||||||
|  |  *  | ||||||
|  |  * @package Minify | ||||||
|  |  * @author Stephen Clay <steve@mrclay.org> | ||||||
|  |  */ | ||||||
|  | class Minify_CSSmin { | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Minify a CSS string | ||||||
|  |      *  | ||||||
|  |      * @param string $css | ||||||
|  |      *  | ||||||
|  |      * @param array $options available options: | ||||||
|  |      *  | ||||||
|  |      * 'removeCharsets': (default true) remove all @charset at-rules | ||||||
|  |      * | ||||||
|  |      * 'prependRelativePath': (default null) if given, this string will be | ||||||
|  |      * prepended to all relative URIs in import/url declarations | ||||||
|  |      *  | ||||||
|  |      * 'currentDir': (default null) if given, this is assumed to be the | ||||||
|  |      * directory of the current CSS file. Using this, minify will rewrite | ||||||
|  |      * all relative URIs in import/url declarations to correctly point to | ||||||
|  |      * the desired files. For this to work, the files *must* exist and be | ||||||
|  |      * visible by the PHP process. | ||||||
|  |      * | ||||||
|  |      * 'symlinks': (default = array()) If the CSS file is stored in  | ||||||
|  |      * a symlink-ed directory, provide an array of link paths to | ||||||
|  |      * target paths, where the link paths are within the document root. Because  | ||||||
|  |      * paths need to be normalized for this to work, use "//" to substitute  | ||||||
|  |      * the doc root in the link paths (the array keys). E.g.: | ||||||
|  |      * <code> | ||||||
|  |      * array('//symlink' => '/real/target/path') // unix | ||||||
|  |      * array('//static' => 'D:\\staticStorage')  // Windows | ||||||
|  |      * </code> | ||||||
|  |      * | ||||||
|  |      * 'docRoot': (default = $_SERVER['DOCUMENT_ROOT']) | ||||||
|  |      * see Minify_CSS_UriRewriter::rewrite | ||||||
|  |      *  | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public static function minify($css, $options = array())  | ||||||
|  |     { | ||||||
|  |         $options = array_merge(array( | ||||||
|  |             'compress' => true, | ||||||
|  |             'removeCharsets' => true, | ||||||
|  |             'currentDir' => null, | ||||||
|  |             'docRoot' => $_SERVER['DOCUMENT_ROOT'], | ||||||
|  |             'prependRelativePath' => null, | ||||||
|  |             'symlinks' => array(), | ||||||
|  |         ), $options); | ||||||
|  |          | ||||||
|  |         if ($options['removeCharsets']) { | ||||||
|  |             $css = preg_replace('/@charset[^;]+;\\s*/', '', $css); | ||||||
|  |         } | ||||||
|  |         if ($options['compress']) { | ||||||
|  |             $obj = new CSSmin(); | ||||||
|  |             $css = $obj->run($css); | ||||||
|  |         } | ||||||
|  |         if (! $options['currentDir'] && ! $options['prependRelativePath']) { | ||||||
|  |             return $css; | ||||||
|  |         } | ||||||
|  |         if ($options['currentDir']) { | ||||||
|  |             return Minify_CSS_UriRewriter::rewrite( | ||||||
|  |                 $css | ||||||
|  |                 ,$options['currentDir'] | ||||||
|  |                 ,$options['docRoot'] | ||||||
|  |                 ,$options['symlinks'] | ||||||
|  |             );   | ||||||
|  |         } else { | ||||||
|  |             return Minify_CSS_UriRewriter::prepend( | ||||||
|  |                 $css | ||||||
|  |                 ,$options['prependRelativePath'] | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										133
									
								
								vendor/mrclay/minify/min/lib/Minify/Cache/APC.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								vendor/mrclay/minify/min/lib/Minify/Cache/APC.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,133 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_Cache_APC | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * APC-based cache class for Minify | ||||||
|  |  *  | ||||||
|  |  * <code> | ||||||
|  |  * Minify::setCache(new Minify_Cache_APC()); | ||||||
|  |  * </code> | ||||||
|  |  *  | ||||||
|  |  * @package Minify | ||||||
|  |  * @author Chris Edwards | ||||||
|  |  **/ | ||||||
|  | class Minify_Cache_APC { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Create a Minify_Cache_APC object, to be passed to | ||||||
|  |      * Minify::setCache(). | ||||||
|  |      * | ||||||
|  |      * | ||||||
|  |      * @param int $expire seconds until expiration (default = 0 | ||||||
|  |      * meaning the item will not get an expiration date) | ||||||
|  |      * | ||||||
|  |      * @return null | ||||||
|  |      */ | ||||||
|  |     public function __construct($expire = 0) | ||||||
|  |     { | ||||||
|  |         $this->_exp = $expire; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Write data to cache. | ||||||
|  |      * | ||||||
|  |      * @param string $id cache id | ||||||
|  |      * | ||||||
|  |      * @param string $data | ||||||
|  |      * | ||||||
|  |      * @return bool success | ||||||
|  |      */ | ||||||
|  |     public function store($id, $data) | ||||||
|  |     { | ||||||
|  |         return apc_store($id, "{$_SERVER['REQUEST_TIME']}|{$data}", $this->_exp); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get the size of a cache entry | ||||||
|  |      * | ||||||
|  |      * @param string $id cache id | ||||||
|  |      * | ||||||
|  |      * @return int size in bytes | ||||||
|  |      */ | ||||||
|  |     public function getSize($id) | ||||||
|  |     { | ||||||
|  |         if (! $this->_fetch($id)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         return (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) | ||||||
|  |             ? mb_strlen($this->_data, '8bit') | ||||||
|  |             : strlen($this->_data); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Does a valid cache entry exist? | ||||||
|  |      * | ||||||
|  |      * @param string $id cache id | ||||||
|  |      * | ||||||
|  |      * @param int $srcMtime mtime of the original source file(s) | ||||||
|  |      * | ||||||
|  |      * @return bool exists | ||||||
|  |      */ | ||||||
|  |     public function isValid($id, $srcMtime) | ||||||
|  |     { | ||||||
|  |         return ($this->_fetch($id) && ($this->_lm >= $srcMtime)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Send the cached content to output | ||||||
|  |      * | ||||||
|  |      * @param string $id cache id | ||||||
|  |      */ | ||||||
|  |     public function display($id) | ||||||
|  |     { | ||||||
|  |         echo $this->_fetch($id) | ||||||
|  |             ? $this->_data | ||||||
|  |             : ''; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Fetch the cached content | ||||||
|  |      * | ||||||
|  |      * @param string $id cache id | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public function fetch($id) | ||||||
|  |     { | ||||||
|  |         return $this->_fetch($id) | ||||||
|  |             ? $this->_data | ||||||
|  |             : ''; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private $_exp = null; | ||||||
|  |  | ||||||
|  |     // cache of most recently fetched id | ||||||
|  |     private $_lm = null; | ||||||
|  |     private $_data = null; | ||||||
|  |     private $_id = null; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Fetch data and timestamp from apc, store in instance | ||||||
|  |      * | ||||||
|  |      * @param string $id | ||||||
|  |      * | ||||||
|  |      * @return bool success | ||||||
|  |      */ | ||||||
|  |     private function _fetch($id) | ||||||
|  |     { | ||||||
|  |         if ($this->_id === $id) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         $ret = apc_fetch($id); | ||||||
|  |         if (false === $ret) { | ||||||
|  |             $this->_id = null; | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         list($this->_lm, $this->_data) = explode('|', $ret, 2); | ||||||
|  |         $this->_id = $id; | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										197
									
								
								vendor/mrclay/minify/min/lib/Minify/Cache/File.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								vendor/mrclay/minify/min/lib/Minify/Cache/File.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,197 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_Cache_File   | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | class Minify_Cache_File { | ||||||
|  |      | ||||||
|  |     public function __construct($path = '', $fileLocking = false) | ||||||
|  |     { | ||||||
|  |         if (! $path) { | ||||||
|  |             $path = self::tmp(); | ||||||
|  |         } | ||||||
|  |         $this->_locking = $fileLocking; | ||||||
|  |         $this->_path = $path; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Write data to cache. | ||||||
|  |      * | ||||||
|  |      * @param string $id cache id (e.g. a filename) | ||||||
|  |      *  | ||||||
|  |      * @param string $data | ||||||
|  |      *  | ||||||
|  |      * @return bool success | ||||||
|  |      */ | ||||||
|  |     public function store($id, $data) | ||||||
|  |     { | ||||||
|  |         $flag = $this->_locking | ||||||
|  |             ? LOCK_EX | ||||||
|  |             : null; | ||||||
|  |         $file = $this->_path . '/' . $id; | ||||||
|  |         if (! @file_put_contents($file, $data, $flag)) { | ||||||
|  |             $this->_log("Minify_Cache_File: Write failed to '$file'"); | ||||||
|  |         } | ||||||
|  |         // write control | ||||||
|  |         if ($data !== $this->fetch($id)) { | ||||||
|  |             @unlink($file); | ||||||
|  |             $this->_log("Minify_Cache_File: Post-write read failed for '$file'"); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Get the size of a cache entry | ||||||
|  |      * | ||||||
|  |      * @param string $id cache id (e.g. a filename) | ||||||
|  |      *  | ||||||
|  |      * @return int size in bytes | ||||||
|  |      */ | ||||||
|  |     public function getSize($id) | ||||||
|  |     { | ||||||
|  |         return filesize($this->_path . '/' . $id); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Does a valid cache entry exist? | ||||||
|  |      * | ||||||
|  |      * @param string $id cache id (e.g. a filename) | ||||||
|  |      *  | ||||||
|  |      * @param int $srcMtime mtime of the original source file(s) | ||||||
|  |      *  | ||||||
|  |      * @return bool exists | ||||||
|  |      */ | ||||||
|  |     public function isValid($id, $srcMtime) | ||||||
|  |     { | ||||||
|  |         $file = $this->_path . '/' . $id; | ||||||
|  |         return (is_file($file) && (filemtime($file) >= $srcMtime)); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Send the cached content to output | ||||||
|  |      * | ||||||
|  |      * @param string $id cache id (e.g. a filename) | ||||||
|  |      */ | ||||||
|  |     public function display($id) | ||||||
|  |     { | ||||||
|  |         if ($this->_locking) { | ||||||
|  |             $fp = fopen($this->_path . '/' . $id, 'rb'); | ||||||
|  |             flock($fp, LOCK_SH); | ||||||
|  |             fpassthru($fp); | ||||||
|  |             flock($fp, LOCK_UN); | ||||||
|  |             fclose($fp); | ||||||
|  |         } else { | ||||||
|  |             readfile($this->_path . '/' . $id);             | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  | 	/** | ||||||
|  |      * Fetch the cached content | ||||||
|  |      * | ||||||
|  |      * @param string $id cache id (e.g. a filename) | ||||||
|  |      *  | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public function fetch($id) | ||||||
|  |     { | ||||||
|  |         if ($this->_locking) { | ||||||
|  |             $fp = fopen($this->_path . '/' . $id, 'rb'); | ||||||
|  |             if (!$fp) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |             flock($fp, LOCK_SH); | ||||||
|  |             $ret = stream_get_contents($fp); | ||||||
|  |             flock($fp, LOCK_UN); | ||||||
|  |             fclose($fp); | ||||||
|  |             return $ret; | ||||||
|  |         } else { | ||||||
|  |             return file_get_contents($this->_path . '/' . $id); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Fetch the cache path used | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public function getPath() | ||||||
|  |     { | ||||||
|  |         return $this->_path; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get a usable temp directory | ||||||
|  |      * | ||||||
|  |      * Adapted from Solar/Dir.php | ||||||
|  |      * @author Paul M. Jones <pmjones@solarphp.com> | ||||||
|  |      * @license http://opensource.org/licenses/bsd-license.php BSD | ||||||
|  |      * @link http://solarphp.com/trac/core/browser/trunk/Solar/Dir.php | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public static function tmp() | ||||||
|  |     { | ||||||
|  |         static $tmp = null; | ||||||
|  |         if (! $tmp) { | ||||||
|  |             $tmp = function_exists('sys_get_temp_dir') | ||||||
|  |                 ? sys_get_temp_dir() | ||||||
|  |                 : self::_tmp(); | ||||||
|  |             $tmp = rtrim($tmp, DIRECTORY_SEPARATOR); | ||||||
|  |         } | ||||||
|  |         return $tmp; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns the OS-specific directory for temporary files | ||||||
|  |      * | ||||||
|  |      * @author Paul M. Jones <pmjones@solarphp.com> | ||||||
|  |      * @license http://opensource.org/licenses/bsd-license.php BSD | ||||||
|  |      * @link http://solarphp.com/trac/core/browser/trunk/Solar/Dir.php | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     protected static function _tmp() | ||||||
|  |     { | ||||||
|  |         // non-Windows system? | ||||||
|  |         if (strtolower(substr(PHP_OS, 0, 3)) != 'win') { | ||||||
|  |             $tmp = empty($_ENV['TMPDIR']) ? getenv('TMPDIR') : $_ENV['TMPDIR']; | ||||||
|  |             if ($tmp) { | ||||||
|  |                 return $tmp; | ||||||
|  |             } else { | ||||||
|  |                 return '/tmp'; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         // Windows 'TEMP' | ||||||
|  |         $tmp = empty($_ENV['TEMP']) ? getenv('TEMP') : $_ENV['TEMP']; | ||||||
|  |         if ($tmp) { | ||||||
|  |             return $tmp; | ||||||
|  |         } | ||||||
|  |         // Windows 'TMP' | ||||||
|  |         $tmp = empty($_ENV['TMP']) ? getenv('TMP') : $_ENV['TMP']; | ||||||
|  |         if ($tmp) { | ||||||
|  |             return $tmp; | ||||||
|  |         } | ||||||
|  |         // Windows 'windir' | ||||||
|  |         $tmp = empty($_ENV['windir']) ? getenv('windir') : $_ENV['windir']; | ||||||
|  |         if ($tmp) { | ||||||
|  |             return $tmp; | ||||||
|  |         } | ||||||
|  |         // final fallback for Windows | ||||||
|  |         return getenv('SystemRoot') . '\\temp'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Send message to the Minify logger | ||||||
|  |      * @param string $msg | ||||||
|  |      * @return null | ||||||
|  |      */ | ||||||
|  |     protected function _log($msg) | ||||||
|  |     { | ||||||
|  |         Minify_Logger::log($msg); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     private $_path = null; | ||||||
|  |     private $_locking = null; | ||||||
|  | } | ||||||
							
								
								
									
										140
									
								
								vendor/mrclay/minify/min/lib/Minify/Cache/Memcache.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								vendor/mrclay/minify/min/lib/Minify/Cache/Memcache.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,140 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_Cache_Memcache | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Memcache-based cache class for Minify | ||||||
|  |  *  | ||||||
|  |  * <code> | ||||||
|  |  * // fall back to disk caching if memcache can't connect | ||||||
|  |  * $memcache = new Memcache; | ||||||
|  |  * if ($memcache->connect('localhost', 11211)) { | ||||||
|  |  *     Minify::setCache(new Minify_Cache_Memcache($memcache)); | ||||||
|  |  * } else { | ||||||
|  |  *     Minify::setCache(); | ||||||
|  |  * } | ||||||
|  |  * </code> | ||||||
|  |  **/ | ||||||
|  | class Minify_Cache_Memcache { | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Create a Minify_Cache_Memcache object, to be passed to  | ||||||
|  |      * Minify::setCache(). | ||||||
|  |      * | ||||||
|  |      * @param Memcache $memcache already-connected instance | ||||||
|  |      *  | ||||||
|  |      * @param int $expire seconds until expiration (default = 0 | ||||||
|  |      * meaning the item will not get an expiration date) | ||||||
|  |      *  | ||||||
|  |      * @return null | ||||||
|  |      */ | ||||||
|  |     public function __construct($memcache, $expire = 0) | ||||||
|  |     { | ||||||
|  |         $this->_mc = $memcache; | ||||||
|  |         $this->_exp = $expire; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Write data to cache. | ||||||
|  |      * | ||||||
|  |      * @param string $id cache id | ||||||
|  |      *  | ||||||
|  |      * @param string $data | ||||||
|  |      *  | ||||||
|  |      * @return bool success | ||||||
|  |      */ | ||||||
|  |     public function store($id, $data) | ||||||
|  |     { | ||||||
|  |         return $this->_mc->set($id, "{$_SERVER['REQUEST_TIME']}|{$data}", 0, $this->_exp); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Get the size of a cache entry | ||||||
|  |      * | ||||||
|  |      * @param string $id cache id | ||||||
|  |      *  | ||||||
|  |      * @return int size in bytes | ||||||
|  |      */ | ||||||
|  |     public function getSize($id) | ||||||
|  |     { | ||||||
|  |         if (! $this->_fetch($id)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         return (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) | ||||||
|  |             ? mb_strlen($this->_data, '8bit') | ||||||
|  |             : strlen($this->_data); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Does a valid cache entry exist? | ||||||
|  |      * | ||||||
|  |      * @param string $id cache id | ||||||
|  |      *  | ||||||
|  |      * @param int $srcMtime mtime of the original source file(s) | ||||||
|  |      *  | ||||||
|  |      * @return bool exists | ||||||
|  |      */ | ||||||
|  |     public function isValid($id, $srcMtime) | ||||||
|  |     { | ||||||
|  |         return ($this->_fetch($id) && ($this->_lm >= $srcMtime)); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Send the cached content to output | ||||||
|  |      * | ||||||
|  |      * @param string $id cache id | ||||||
|  |      */ | ||||||
|  |     public function display($id) | ||||||
|  |     { | ||||||
|  |         echo $this->_fetch($id) | ||||||
|  |             ? $this->_data | ||||||
|  |             : ''; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  | 	/** | ||||||
|  |      * Fetch the cached content | ||||||
|  |      * | ||||||
|  |      * @param string $id cache id | ||||||
|  |      *  | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public function fetch($id) | ||||||
|  |     { | ||||||
|  |         return $this->_fetch($id) | ||||||
|  |             ? $this->_data | ||||||
|  |             : ''; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     private $_mc = null; | ||||||
|  |     private $_exp = null; | ||||||
|  |      | ||||||
|  |     // cache of most recently fetched id | ||||||
|  |     private $_lm = null; | ||||||
|  |     private $_data = null; | ||||||
|  |     private $_id = null; | ||||||
|  |      | ||||||
|  | 	/** | ||||||
|  |      * Fetch data and timestamp from memcache, store in instance | ||||||
|  |      *  | ||||||
|  |      * @param string $id | ||||||
|  |      *  | ||||||
|  |      * @return bool success | ||||||
|  |      */ | ||||||
|  |     private function _fetch($id) | ||||||
|  |     { | ||||||
|  |         if ($this->_id === $id) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         $ret = $this->_mc->get($id); | ||||||
|  |         if (false === $ret) { | ||||||
|  |             $this->_id = null; | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         list($this->_lm, $this->_data) = explode('|', $ret, 2); | ||||||
|  |         $this->_id = $id; | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										126
									
								
								vendor/mrclay/minify/min/lib/Minify/Cache/XCache.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								vendor/mrclay/minify/min/lib/Minify/Cache/XCache.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,126 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_Cache_XCache | ||||||
|  |  * | ||||||
|  |  * @link http://xcache.lighttpd.net/ | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * XCache-based cache class for Minify | ||||||
|  |  * {@see http://xcache.lighttpd.net/wiki/XcacheApi XCache API} | ||||||
|  |  * | ||||||
|  |  * <code> | ||||||
|  |  * Minify::setCache(new Minify_Cache_XCache()); | ||||||
|  |  * </code> | ||||||
|  |  * | ||||||
|  |  * @package Minify | ||||||
|  |  * @author Elan Ruusamäe <glen@delfi.ee> | ||||||
|  |  **/ | ||||||
|  | class Minify_Cache_XCache { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Create a Minify_Cache_XCache object, to be passed to | ||||||
|  |      * Minify::setCache(). | ||||||
|  |      * | ||||||
|  |      * @param int $expire seconds until expiration (default = 0 | ||||||
|  |      * meaning the item will not get an expiration date) | ||||||
|  |      */ | ||||||
|  |     public function __construct($expire = 0) | ||||||
|  |     { | ||||||
|  |         $this->_exp = $expire; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Write data to cache. | ||||||
|  |      * | ||||||
|  |      * @param string $id cache id | ||||||
|  |      * @param string $data | ||||||
|  |      * @return bool success | ||||||
|  |      */ | ||||||
|  |     public function store($id, $data) | ||||||
|  |     { | ||||||
|  |         return xcache_set($id, "{$_SERVER['REQUEST_TIME']}|{$data}", $this->_exp); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get the size of a cache entry | ||||||
|  |      * | ||||||
|  |      * @param string $id cache id | ||||||
|  |      * @return int size in bytes | ||||||
|  |      */ | ||||||
|  |     public function getSize($id) | ||||||
|  |     { | ||||||
|  |         if (! $this->_fetch($id)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         return (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) | ||||||
|  |             ? mb_strlen($this->_data, '8bit') | ||||||
|  |             : strlen($this->_data); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Does a valid cache entry exist? | ||||||
|  |      * | ||||||
|  |      * @param string $id cache id | ||||||
|  |      * @param int $srcMtime mtime of the original source file(s) | ||||||
|  |      * @return bool exists | ||||||
|  |      */ | ||||||
|  |     public function isValid($id, $srcMtime) | ||||||
|  |     { | ||||||
|  |         return ($this->_fetch($id) && ($this->_lm >= $srcMtime)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Send the cached content to output | ||||||
|  |      * | ||||||
|  |      * @param string $id cache id | ||||||
|  |      */ | ||||||
|  |     public function display($id) | ||||||
|  |     { | ||||||
|  |         echo $this->_fetch($id) | ||||||
|  |             ? $this->_data | ||||||
|  |             : ''; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Fetch the cached content | ||||||
|  |      * | ||||||
|  |      * @param string $id cache id | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public function fetch($id) | ||||||
|  |     { | ||||||
|  |         return $this->_fetch($id) | ||||||
|  |             ? $this->_data | ||||||
|  |             : ''; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private $_exp = null; | ||||||
|  |  | ||||||
|  |     // cache of most recently fetched id | ||||||
|  |     private $_lm = null; | ||||||
|  |     private $_data = null; | ||||||
|  |     private $_id = null; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Fetch data and timestamp from xcache, store in instance | ||||||
|  |      * | ||||||
|  |      * @param string $id | ||||||
|  |      * @return bool success | ||||||
|  |      */ | ||||||
|  |     private function _fetch($id) | ||||||
|  |     { | ||||||
|  |         if ($this->_id === $id) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         $ret = xcache_get($id); | ||||||
|  |         if (false === $ret) { | ||||||
|  |             $this->_id = null; | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         list($this->_lm, $this->_data) = explode('|', $ret, 2); | ||||||
|  |         $this->_id = $id; | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										142
									
								
								vendor/mrclay/minify/min/lib/Minify/Cache/ZendPlatform.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								vendor/mrclay/minify/min/lib/Minify/Cache/ZendPlatform.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,142 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_Cache_ZendPlatform | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * ZendPlatform-based cache class for Minify | ||||||
|  |  * | ||||||
|  |  * Based on Minify_Cache_APC, uses output_cache_get/put (currently deprecated) | ||||||
|  |  *  | ||||||
|  |  * <code> | ||||||
|  |  * Minify::setCache(new Minify_Cache_ZendPlatform()); | ||||||
|  |  * </code> | ||||||
|  |  * | ||||||
|  |  * @package Minify | ||||||
|  |  * @author Patrick van Dissel | ||||||
|  |  */ | ||||||
|  | class Minify_Cache_ZendPlatform { | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Create a Minify_Cache_ZendPlatform object, to be passed to | ||||||
|  |      * Minify::setCache(). | ||||||
|  |      * | ||||||
|  |      * @param int $expire seconds until expiration (default = 0 | ||||||
|  |      * meaning the item will not get an expiration date) | ||||||
|  |      * | ||||||
|  |      * @return null | ||||||
|  |      */ | ||||||
|  |     public function __construct($expire = 0) | ||||||
|  |     { | ||||||
|  |         $this->_exp = $expire; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Write data to cache. | ||||||
|  |      * | ||||||
|  |      * @param string $id cache id | ||||||
|  |      * | ||||||
|  |      * @param string $data | ||||||
|  |      * | ||||||
|  |      * @return bool success | ||||||
|  |      */ | ||||||
|  |     public function store($id, $data) | ||||||
|  |     { | ||||||
|  |         return output_cache_put($id, "{$_SERVER['REQUEST_TIME']}|{$data}"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get the size of a cache entry | ||||||
|  |      * | ||||||
|  |      * @param string $id cache id | ||||||
|  |      * | ||||||
|  |      * @return int size in bytes | ||||||
|  |      */ | ||||||
|  |     public function getSize($id) | ||||||
|  |     { | ||||||
|  |         return $this->_fetch($id) | ||||||
|  |             ? strlen($this->_data) | ||||||
|  |             : false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Does a valid cache entry exist? | ||||||
|  |      * | ||||||
|  |      * @param string $id cache id | ||||||
|  |      * | ||||||
|  |      * @param int $srcMtime mtime of the original source file(s) | ||||||
|  |      * | ||||||
|  |      * @return bool exists | ||||||
|  |      */ | ||||||
|  |     public function isValid($id, $srcMtime) | ||||||
|  |     { | ||||||
|  |         $ret = ($this->_fetch($id) && ($this->_lm >= $srcMtime)); | ||||||
|  |         return $ret; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Send the cached content to output | ||||||
|  |      * | ||||||
|  |      * @param string $id cache id | ||||||
|  |      */ | ||||||
|  |     public function display($id) | ||||||
|  |     { | ||||||
|  |         echo $this->_fetch($id) | ||||||
|  |             ? $this->_data | ||||||
|  |             : ''; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Fetch the cached content | ||||||
|  |      * | ||||||
|  |      * @param string $id cache id | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public function fetch($id) | ||||||
|  |     { | ||||||
|  |         return $this->_fetch($id) | ||||||
|  |             ? $this->_data | ||||||
|  |             : ''; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     private $_exp = null; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     // cache of most recently fetched id | ||||||
|  |     private $_lm = null; | ||||||
|  |     private $_data = null; | ||||||
|  |     private $_id = null; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Fetch data and timestamp from ZendPlatform, store in instance | ||||||
|  |      * | ||||||
|  |      * @param string $id | ||||||
|  |      * | ||||||
|  |      * @return bool success | ||||||
|  |      */ | ||||||
|  |     private function _fetch($id) | ||||||
|  |     { | ||||||
|  |         if ($this->_id === $id) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         $ret = output_cache_get($id, $this->_exp); | ||||||
|  |         if (false === $ret) { | ||||||
|  |             $this->_id = null; | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         list($this->_lm, $this->_data) = explode('|', $ret, 2); | ||||||
|  |         $this->_id = $id; | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										139
									
								
								vendor/mrclay/minify/min/lib/Minify/ClosureCompiler.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								vendor/mrclay/minify/min/lib/Minify/ClosureCompiler.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,139 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_ClosureCompiler | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Compress Javascript using the Closure Compiler | ||||||
|  |  * | ||||||
|  |  * You must set $jarFile and $tempDir before calling the minify functions. | ||||||
|  |  * Also, depending on your shell's environment, you may need to specify | ||||||
|  |  * the full path to java in $javaExecutable or use putenv() to setup the | ||||||
|  |  * Java environment. | ||||||
|  |  * | ||||||
|  |  * <code> | ||||||
|  |  * Minify_ClosureCompiler::$jarFile = '/path/to/closure-compiler-20120123.jar'; | ||||||
|  |  * Minify_ClosureCompiler::$tempDir = '/tmp'; | ||||||
|  |  * $code = Minify_ClosureCompiler::minify( | ||||||
|  |  *   $code, | ||||||
|  |  *   array('compilation_level' => 'SIMPLE_OPTIMIZATIONS') | ||||||
|  |  * ); | ||||||
|  |  * | ||||||
|  |  * --compilation_level WHITESPACE_ONLY, SIMPLE_OPTIMIZATIONS, ADVANCED_OPTIMIZATIONS | ||||||
|  |  * | ||||||
|  |  * </code> | ||||||
|  |  * | ||||||
|  |  * @todo unit tests, $options docs | ||||||
|  |  * @todo more options support (or should just passthru them all?) | ||||||
|  |  * | ||||||
|  |  * @package Minify | ||||||
|  |  * @author Stephen Clay <steve@mrclay.org> | ||||||
|  |  * @author Elan Ruusamäe <glen@delfi.ee> | ||||||
|  |  */ | ||||||
|  | class Minify_ClosureCompiler { | ||||||
|  |  | ||||||
|  |     const OPTION_CHARSET = 'charset'; | ||||||
|  |     const OPTION_COMPILATION_LEVEL = 'compilation_level'; | ||||||
|  |  | ||||||
|  |     public static $isDebug = false; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Filepath of the Closure Compiler jar file. This must be set before | ||||||
|  |      * calling minifyJs(). | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public static $jarFile = null; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Writable temp directory. This must be set before calling minifyJs(). | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public static $tempDir = null; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Filepath of "java" executable (may be needed if not in shell's PATH) | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public static $javaExecutable = 'java'; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Minify a Javascript string | ||||||
|  |      * | ||||||
|  |      * @param string $js | ||||||
|  |      * | ||||||
|  |      * @param array $options (verbose is ignored) | ||||||
|  |      * | ||||||
|  |      * @see https://code.google.com/p/closure-compiler/source/browse/trunk/README | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      * | ||||||
|  |      * @throws Minify_ClosureCompiler_Exception | ||||||
|  |      */ | ||||||
|  |     public static function minify($js, $options = array()) | ||||||
|  |     { | ||||||
|  |         self::_prepare(); | ||||||
|  |         if (! ($tmpFile = tempnam(self::$tempDir, 'cc_'))) { | ||||||
|  |             throw new Minify_ClosureCompiler_Exception('Minify_ClosureCompiler : could not create temp file in "'.self::$tempDir.'".'); | ||||||
|  |         } | ||||||
|  |         file_put_contents($tmpFile, $js); | ||||||
|  |         $cmd = self::_getCmd($options, $tmpFile); | ||||||
|  |         exec($cmd, $output, $result_code); | ||||||
|  |         unlink($tmpFile); | ||||||
|  |         if ($result_code != 0) { | ||||||
|  |             $message = 'Minify_ClosureCompiler : Closure Compiler execution failed.'; | ||||||
|  |             if (self::$isDebug) {  | ||||||
|  |                 exec($cmd . ' 2>&1', $error); | ||||||
|  |                 if ($error) { | ||||||
|  |                     $message .= "\nReason:\n" . join("\n", $error); | ||||||
|  |                 } | ||||||
|  |             }  | ||||||
|  |             throw new Minify_ClosureCompiler_Exception($message); | ||||||
|  |         } | ||||||
|  |         return implode("\n", $output); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private static function _getCmd($userOptions, $tmpFile) | ||||||
|  |     { | ||||||
|  |         $o = array_merge( | ||||||
|  |             array( | ||||||
|  |                 self::OPTION_CHARSET => 'utf-8', | ||||||
|  |                 self::OPTION_COMPILATION_LEVEL => 'SIMPLE_OPTIMIZATIONS', | ||||||
|  |             ), | ||||||
|  |             $userOptions | ||||||
|  |         ); | ||||||
|  |         $charsetOption = $o[self::OPTION_CHARSET]; | ||||||
|  |         $cmd = self::$javaExecutable . ' -jar ' . escapeshellarg(self::$jarFile) | ||||||
|  |              . (preg_match('/^[\\da-zA-Z0-9\\-]+$/', $charsetOption) | ||||||
|  |                 ? " --charset {$charsetOption}" | ||||||
|  |                 : ''); | ||||||
|  |  | ||||||
|  |         foreach (array(self::OPTION_COMPILATION_LEVEL) as $opt) { | ||||||
|  |             if ($o[$opt]) { | ||||||
|  |                 $cmd .= " --{$opt} ". escapeshellarg($o[$opt]); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return $cmd . ' ' . escapeshellarg($tmpFile); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private static function _prepare() | ||||||
|  |     { | ||||||
|  |         if (! is_file(self::$jarFile)) { | ||||||
|  |             throw new Minify_ClosureCompiler_Exception('Minify_ClosureCompiler : $jarFile('.self::$jarFile.') is not a valid file.'); | ||||||
|  |         } | ||||||
|  |         if (! is_readable(self::$jarFile)) { | ||||||
|  |             throw new Minify_ClosureCompiler_Exception('Minify_ClosureCompiler : $jarFile('.self::$jarFile.') is not readable.'); | ||||||
|  |         } | ||||||
|  |         if (! is_dir(self::$tempDir)) { | ||||||
|  |             throw new Minify_ClosureCompiler_Exception('Minify_ClosureCompiler : $tempDir('.self::$tempDir.') is not a valid direcotry.'); | ||||||
|  |         } | ||||||
|  |         if (! is_writable(self::$tempDir)) { | ||||||
|  |             throw new Minify_ClosureCompiler_Exception('Minify_ClosureCompiler : $tempDir('.self::$tempDir.') is not writable.'); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class Minify_ClosureCompiler_Exception extends Exception {} | ||||||
							
								
								
									
										89
									
								
								vendor/mrclay/minify/min/lib/Minify/CommentPreserver.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								vendor/mrclay/minify/min/lib/Minify/CommentPreserver.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,89 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_CommentPreserver  | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Process a string in pieces preserving C-style comments that begin with "/*!" | ||||||
|  |  *  | ||||||
|  |  * @package Minify | ||||||
|  |  * @author Stephen Clay <steve@mrclay.org> | ||||||
|  |  */ | ||||||
|  | class Minify_CommentPreserver { | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * String to be prepended to each preserved comment | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public static $prepend = "\n"; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * String to be appended to each preserved comment | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public static $append = "\n"; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Process a string outside of C-style comments that begin with "/*!" | ||||||
|  |      * | ||||||
|  |      * On each non-empty string outside these comments, the given processor  | ||||||
|  |      * function will be called. The comments will be surrounded by  | ||||||
|  |      * Minify_CommentPreserver::$preprend and Minify_CommentPreserver::$append. | ||||||
|  |      *  | ||||||
|  |      * @param string $content | ||||||
|  |      * @param callback $processor function | ||||||
|  |      * @param array $args array of extra arguments to pass to the processor  | ||||||
|  |      * function (default = array()) | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public static function process($content, $processor, $args = array()) | ||||||
|  |     { | ||||||
|  |         $ret = ''; | ||||||
|  |         while (true) { | ||||||
|  |             list($beforeComment, $comment, $afterComment) = self::_nextComment($content); | ||||||
|  |             if ('' !== $beforeComment) { | ||||||
|  |                 $callArgs = $args; | ||||||
|  |                 array_unshift($callArgs, $beforeComment); | ||||||
|  |                 $ret .= call_user_func_array($processor, $callArgs);     | ||||||
|  |             } | ||||||
|  |             if (false === $comment) { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             $ret .= $comment; | ||||||
|  |             $content = $afterComment; | ||||||
|  |         } | ||||||
|  |         return $ret; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Extract comments that YUI Compressor preserves. | ||||||
|  |      *  | ||||||
|  |      * @param string $in input | ||||||
|  |      *  | ||||||
|  |      * @return array 3 elements are returned. If a YUI comment is found, the | ||||||
|  |      * 2nd element is the comment and the 1st and 3rd are the surrounding | ||||||
|  |      * strings. If no comment is found, the entire string is returned as the  | ||||||
|  |      * 1st element and the other two are false. | ||||||
|  |      */ | ||||||
|  |     private static function _nextComment($in) | ||||||
|  |     { | ||||||
|  |         if ( | ||||||
|  |             false === ($start = strpos($in, '/*!')) | ||||||
|  |             || false === ($end = strpos($in, '*/', $start + 3)) | ||||||
|  |         ) { | ||||||
|  |             return array($in, false, false); | ||||||
|  |         } | ||||||
|  |         $ret = array( | ||||||
|  |             substr($in, 0, $start) | ||||||
|  |             ,self::$prepend . '/*!' . substr($in, $start + 3, $end - $start - 1) . self::$append | ||||||
|  |         ); | ||||||
|  |         $endChars = (strlen($in) - $end - 2); | ||||||
|  |         $ret[] = (0 === $endChars) | ||||||
|  |             ? '' | ||||||
|  |             : substr($in, -$endChars); | ||||||
|  |         return $ret; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										222
									
								
								vendor/mrclay/minify/min/lib/Minify/Controller/Base.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										222
									
								
								vendor/mrclay/minify/min/lib/Minify/Controller/Base.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,222 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_Controller_Base   | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Base class for Minify controller | ||||||
|  |  *  | ||||||
|  |  * The controller class validates a request and uses it to create sources | ||||||
|  |  * for minification and set options like contentType. It's also responsible | ||||||
|  |  * for loading minifier code upon request. | ||||||
|  |  *  | ||||||
|  |  * @package Minify | ||||||
|  |  * @author Stephen Clay <steve@mrclay.org> | ||||||
|  |  */ | ||||||
|  | abstract class Minify_Controller_Base { | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Setup controller sources and set an needed options for Minify::source | ||||||
|  |      *  | ||||||
|  |      * You must override this method in your subclass controller to set  | ||||||
|  |      * $this->sources. If the request is NOT valid, make sure $this->sources  | ||||||
|  |      * is left an empty array. Then strip any controller-specific options from  | ||||||
|  |      * $options and return it. To serve files, $this->sources must be an array of | ||||||
|  |      * Minify_Source objects. | ||||||
|  |      *  | ||||||
|  |      * @param array $options controller and Minify options | ||||||
|  |      *  | ||||||
|  |      * @return array $options Minify::serve options | ||||||
|  |      */ | ||||||
|  |     abstract public function setupSources($options); | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Get default Minify options for this controller. | ||||||
|  |      *  | ||||||
|  |      * Override in subclass to change defaults | ||||||
|  |      * | ||||||
|  |      * @return array options for Minify | ||||||
|  |      */ | ||||||
|  |     public function getDefaultMinifyOptions() { | ||||||
|  |         return array( | ||||||
|  |             'isPublic' => true | ||||||
|  |             ,'encodeOutput' => function_exists('gzdeflate') | ||||||
|  |             ,'encodeMethod' => null // determine later | ||||||
|  |             ,'encodeLevel' => 9 | ||||||
|  |             ,'minifierOptions' => array() // no minifier options | ||||||
|  |             ,'contentTypeCharset' => 'utf-8' | ||||||
|  |             ,'maxAge' => 1800 // 30 minutes | ||||||
|  |             ,'rewriteCssUris' => true | ||||||
|  |             ,'bubbleCssImports' => false | ||||||
|  |             ,'quiet' => false // serve() will send headers and output | ||||||
|  |             ,'debug' => false | ||||||
|  |              | ||||||
|  |             // if you override these, the response codes MUST be directly after | ||||||
|  |             // the first space. | ||||||
|  |             ,'badRequestHeader' => 'HTTP/1.0 400 Bad Request' | ||||||
|  |             ,'errorHeader'      => 'HTTP/1.0 500 Internal Server Error' | ||||||
|  |              | ||||||
|  |             // callback function to see/modify content of all sources | ||||||
|  |             ,'postprocessor' => null | ||||||
|  |             // file to require to load preprocessor | ||||||
|  |             ,'postprocessorRequire' => null | ||||||
|  |         ); | ||||||
|  |     }   | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get default minifiers for this controller. | ||||||
|  |      *  | ||||||
|  |      * Override in subclass to change defaults | ||||||
|  |      * | ||||||
|  |      * @return array minifier callbacks for common types | ||||||
|  |      */ | ||||||
|  |     public function getDefaultMinifers() { | ||||||
|  |         $ret[Minify::TYPE_JS] = array('JSMin', 'minify'); | ||||||
|  |         $ret[Minify::TYPE_CSS] = array('Minify_CSS', 'minify'); | ||||||
|  |         $ret[Minify::TYPE_HTML] = array('Minify_HTML', 'minify'); | ||||||
|  |         return $ret; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Is a user-given file within an allowable directory, existing, | ||||||
|  |      * and having an extension js/css/html/txt ? | ||||||
|  |      *  | ||||||
|  |      * This is a convenience function for controllers that have to accept | ||||||
|  |      * user-given paths | ||||||
|  |      * | ||||||
|  |      * @param string $file full file path (already processed by realpath()) | ||||||
|  |      *  | ||||||
|  |      * @param array $safeDirs directories where files are safe to serve. Files can also | ||||||
|  |      * be in subdirectories of these directories. | ||||||
|  |      *  | ||||||
|  |      * @return bool file is safe | ||||||
|  |      * | ||||||
|  |      * @deprecated use checkAllowDirs, checkNotHidden instead | ||||||
|  |      */ | ||||||
|  |     public static function _fileIsSafe($file, $safeDirs) | ||||||
|  |     { | ||||||
|  |         $pathOk = false; | ||||||
|  |         foreach ((array)$safeDirs as $safeDir) { | ||||||
|  |             if (strpos($file, $safeDir) === 0) { | ||||||
|  |                 $pathOk = true; | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         $base = basename($file); | ||||||
|  |         if (! $pathOk || ! is_file($file) || $base[0] === '.') { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         list($revExt) = explode('.', strrev($base)); | ||||||
|  |         return in_array(strrev($revExt), array('js', 'css', 'html', 'txt')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param string $file | ||||||
|  |      * @param array $allowDirs | ||||||
|  |      * @param string $uri | ||||||
|  |      * @return bool | ||||||
|  |      * @throws Exception | ||||||
|  |      */ | ||||||
|  |     public static function checkAllowDirs($file, $allowDirs, $uri) | ||||||
|  |     { | ||||||
|  |         foreach ((array)$allowDirs as $allowDir) { | ||||||
|  |             if (strpos($file, $allowDir) === 0) { | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         throw new Exception("File '$file' is outside \$allowDirs. If the path is" | ||||||
|  |             . " resolved via an alias/symlink, look into the \$min_symlinks option." | ||||||
|  |             . " E.g. \$min_symlinks['/" . dirname($uri) . "'] = '" . dirname($file) . "';"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param string $file | ||||||
|  |      * @throws Exception | ||||||
|  |      */ | ||||||
|  |     public static function checkNotHidden($file) | ||||||
|  |     { | ||||||
|  |         $b = basename($file); | ||||||
|  |         if (0 === strpos($b, '.')) { | ||||||
|  |             throw new Exception("Filename '$b' starts with period (may be hidden)"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * instances of Minify_Source, which provide content and any individual minification needs. | ||||||
|  |      * | ||||||
|  |      * @var array | ||||||
|  |      *  | ||||||
|  |      * @see Minify_Source | ||||||
|  |      */ | ||||||
|  |     public $sources = array(); | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Short name to place inside cache id | ||||||
|  |      * | ||||||
|  |      * The setupSources() method may choose to set this, making it easier to | ||||||
|  |      * recognize a particular set of sources/settings in the cache folder. It | ||||||
|  |      * will be filtered and truncated to make the final cache id <= 250 bytes. | ||||||
|  |      *  | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public $selectionId = ''; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Mix in default controller options with user-given options | ||||||
|  |      *  | ||||||
|  |      * @param array $options user options | ||||||
|  |      *  | ||||||
|  |      * @return array mixed options | ||||||
|  |      */ | ||||||
|  |     public final function mixInDefaultOptions($options) | ||||||
|  |     { | ||||||
|  |         $ret = array_merge( | ||||||
|  |             $this->getDefaultMinifyOptions(), $options | ||||||
|  |         ); | ||||||
|  |         if (! isset($options['minifiers'])) { | ||||||
|  |             $options['minifiers'] = array(); | ||||||
|  |         } | ||||||
|  |         $ret['minifiers'] = array_merge( | ||||||
|  |             $this->getDefaultMinifers(), $options['minifiers'] | ||||||
|  |         ); | ||||||
|  |         return $ret; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Analyze sources (if there are any) and set $options 'contentType'  | ||||||
|  |      * and 'lastModifiedTime' if they already aren't. | ||||||
|  |      *  | ||||||
|  |      * @param array $options options for Minify | ||||||
|  |      *  | ||||||
|  |      * @return array options for Minify | ||||||
|  |      */ | ||||||
|  |     public final function analyzeSources($options = array())  | ||||||
|  |     { | ||||||
|  |         if ($this->sources) { | ||||||
|  |             if (! isset($options['contentType'])) { | ||||||
|  |                 $options['contentType'] = Minify_Source::getContentType($this->sources); | ||||||
|  |             } | ||||||
|  |             // last modified is needed for caching, even if setExpires is set | ||||||
|  |             if (! isset($options['lastModifiedTime'])) { | ||||||
|  |                 $max = 0; | ||||||
|  |                 foreach ($this->sources as $source) { | ||||||
|  |                     $max = max($source->lastModified, $max); | ||||||
|  |                 } | ||||||
|  |                 $options['lastModifiedTime'] = $max; | ||||||
|  |             }     | ||||||
|  |         } | ||||||
|  |         return $options; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Send message to the Minify logger | ||||||
|  |      * | ||||||
|  |      * @param string $msg | ||||||
|  |      * | ||||||
|  |      * @return null | ||||||
|  |      */ | ||||||
|  |     public function log($msg) { | ||||||
|  |         Minify_Logger::log($msg); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										76
									
								
								vendor/mrclay/minify/min/lib/Minify/Controller/Files.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								vendor/mrclay/minify/min/lib/Minify/Controller/Files.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_Controller_Files   | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Controller class for minifying a set of files | ||||||
|  |  *  | ||||||
|  |  * E.g. the following would serve the minified Javascript for a site | ||||||
|  |  * <code> | ||||||
|  |  * Minify::serve('Files', array( | ||||||
|  |  *     'files' => array( | ||||||
|  |  *         '//js/jquery.js' | ||||||
|  |  *         ,'//js/plugins.js' | ||||||
|  |  *         ,'/home/username/file.js' | ||||||
|  |  *     ) | ||||||
|  |  * )); | ||||||
|  |  * </code> | ||||||
|  |  *  | ||||||
|  |  * As a shortcut, the controller will replace "//" at the beginning | ||||||
|  |  * of a filename with $_SERVER['DOCUMENT_ROOT'] . '/'. | ||||||
|  |  * | ||||||
|  |  * @package Minify | ||||||
|  |  * @author Stephen Clay <steve@mrclay.org> | ||||||
|  |  */ | ||||||
|  | class Minify_Controller_Files extends Minify_Controller_Base { | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Set up file sources | ||||||
|  |      *  | ||||||
|  |      * @param array $options controller and Minify options | ||||||
|  |      * @return array Minify options | ||||||
|  |      *  | ||||||
|  |      * Controller options: | ||||||
|  |      *  | ||||||
|  |      * 'files': (required) array of complete file paths, or a single path | ||||||
|  |      */ | ||||||
|  |     public function setupSources($options) { | ||||||
|  |         // strip controller options | ||||||
|  |          | ||||||
|  |         $files = $options['files']; | ||||||
|  |         // if $files is a single object, casting will break it | ||||||
|  |         if (is_object($files)) { | ||||||
|  |             $files = array($files); | ||||||
|  |         } elseif (! is_array($files)) { | ||||||
|  |             $files = (array)$files; | ||||||
|  |         } | ||||||
|  |         unset($options['files']); | ||||||
|  |          | ||||||
|  |         $sources = array(); | ||||||
|  |         foreach ($files as $file) { | ||||||
|  |             if ($file instanceof Minify_Source) { | ||||||
|  |                 $sources[] = $file; | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |             if (0 === strpos($file, '//')) { | ||||||
|  |                 $file = $_SERVER['DOCUMENT_ROOT'] . substr($file, 1); | ||||||
|  |             } | ||||||
|  |             $realPath = realpath($file); | ||||||
|  |             if (is_file($realPath)) { | ||||||
|  |                 $sources[] = new Minify_Source(array( | ||||||
|  |                     'filepath' => $realPath | ||||||
|  |                 ));     | ||||||
|  |             } else { | ||||||
|  |                 $this->log("The path \"{$file}\" could not be found (or was not a file)"); | ||||||
|  |                 return $options; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if ($sources) { | ||||||
|  |             $this->sources = $sources; | ||||||
|  |         } | ||||||
|  |         return $options; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										91
									
								
								vendor/mrclay/minify/min/lib/Minify/Controller/Groups.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								vendor/mrclay/minify/min/lib/Minify/Controller/Groups.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_Controller_Groups   | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Controller class for serving predetermined groups of minimized sets, selected | ||||||
|  |  * by PATH_INFO | ||||||
|  |  *  | ||||||
|  |  * <code> | ||||||
|  |  * Minify::serve('Groups', array(  | ||||||
|  |  *     'groups' => array( | ||||||
|  |  *         'css' => array('//css/type.css', '//css/layout.css') | ||||||
|  |  *        ,'js' => array('//js/jquery.js', '//js/site.js') | ||||||
|  |  *     ) | ||||||
|  |  * )); | ||||||
|  |  * </code> | ||||||
|  |  *  | ||||||
|  |  * If the above code were placed in /serve.php, it would enable the URLs | ||||||
|  |  * /serve.php/js and /serve.php/css | ||||||
|  |  *  | ||||||
|  |  * As a shortcut, the controller will replace "//" at the beginning | ||||||
|  |  * of a filename with $_SERVER['DOCUMENT_ROOT'] . '/'. | ||||||
|  |  *  | ||||||
|  |  * @package Minify | ||||||
|  |  * @author Stephen Clay <steve@mrclay.org> | ||||||
|  |  */ | ||||||
|  | class Minify_Controller_Groups extends Minify_Controller_Base { | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Set up groups of files as sources | ||||||
|  |      *  | ||||||
|  |      * @param array $options controller and Minify options | ||||||
|  |      * | ||||||
|  |      * 'groups': (required) array mapping PATH_INFO strings to arrays | ||||||
|  |      * of complete file paths. @see Minify_Controller_Groups | ||||||
|  |      * | ||||||
|  |      * @return array Minify options | ||||||
|  |      */ | ||||||
|  |     public function setupSources($options) { | ||||||
|  |         // strip controller options | ||||||
|  |         $groups = $options['groups']; | ||||||
|  |         unset($options['groups']); | ||||||
|  |          | ||||||
|  |         // mod_fcgid places PATH_INFO in ORIG_PATH_INFO | ||||||
|  |         $pi = isset($_SERVER['ORIG_PATH_INFO']) | ||||||
|  |             ? substr($_SERVER['ORIG_PATH_INFO'], 1)  | ||||||
|  |             : (isset($_SERVER['PATH_INFO']) | ||||||
|  |                 ? substr($_SERVER['PATH_INFO'], 1)  | ||||||
|  |                 : false | ||||||
|  |             ); | ||||||
|  |         if (false === $pi || ! isset($groups[$pi])) { | ||||||
|  |             // no PATH_INFO or not a valid group | ||||||
|  |             $this->log("Missing PATH_INFO or no group set for \"$pi\""); | ||||||
|  |             return $options; | ||||||
|  |         } | ||||||
|  |         $sources = array(); | ||||||
|  |          | ||||||
|  |         $files = $groups[$pi]; | ||||||
|  |         // if $files is a single object, casting will break it | ||||||
|  |         if (is_object($files)) { | ||||||
|  |             $files = array($files); | ||||||
|  |         } elseif (! is_array($files)) { | ||||||
|  |             $files = (array)$files; | ||||||
|  |         } | ||||||
|  |         foreach ($files as $file) { | ||||||
|  |             if ($file instanceof Minify_Source) { | ||||||
|  |                 $sources[] = $file; | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |             if (0 === strpos($file, '//')) { | ||||||
|  |                 $file = $_SERVER['DOCUMENT_ROOT'] . substr($file, 1); | ||||||
|  |             } | ||||||
|  |             $realPath = realpath($file); | ||||||
|  |             if (is_file($realPath)) { | ||||||
|  |                 $sources[] = new Minify_Source(array( | ||||||
|  |                     'filepath' => $realPath | ||||||
|  |                 ));     | ||||||
|  |             } else { | ||||||
|  |                 $this->log("The path \"{$file}\" could not be found (or was not a file)"); | ||||||
|  |                 return $options; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if ($sources) { | ||||||
|  |             $this->sources = $sources; | ||||||
|  |         } | ||||||
|  |         return $options; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										238
									
								
								vendor/mrclay/minify/min/lib/Minify/Controller/MinApp.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										238
									
								
								vendor/mrclay/minify/min/lib/Minify/Controller/MinApp.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,238 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_Controller_MinApp   | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Controller class for requests to /min/index.php | ||||||
|  |  *  | ||||||
|  |  * @package Minify | ||||||
|  |  * @author Stephen Clay <steve@mrclay.org> | ||||||
|  |  */ | ||||||
|  | class Minify_Controller_MinApp extends Minify_Controller_Base { | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Set up groups of files as sources | ||||||
|  |      *  | ||||||
|  |      * @param array $options controller and Minify options | ||||||
|  |      * | ||||||
|  |      * @return array Minify options | ||||||
|  |      */ | ||||||
|  |     public function setupSources($options) { | ||||||
|  |         // PHP insecure by default: realpath() and other FS functions can't handle null bytes. | ||||||
|  |         foreach (array('g', 'b', 'f') as $key) { | ||||||
|  |             if (isset($_GET[$key])) { | ||||||
|  |                 $_GET[$key] = str_replace("\x00", '', (string)$_GET[$key]); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // filter controller options | ||||||
|  |         $cOptions = array_merge( | ||||||
|  |             array( | ||||||
|  |                 'allowDirs' => '//' | ||||||
|  |                 ,'groupsOnly' => false | ||||||
|  |                 ,'groups' => array() | ||||||
|  |                 ,'noMinPattern' => '@[-\\.]min\\.(?:js|css)$@i' // matched against basename | ||||||
|  |             ) | ||||||
|  |             ,(isset($options['minApp']) ? $options['minApp'] : array()) | ||||||
|  |         ); | ||||||
|  |         unset($options['minApp']); | ||||||
|  |         $sources = array(); | ||||||
|  |         $this->selectionId = ''; | ||||||
|  |         $firstMissingResource = null; | ||||||
|  |         if (isset($_GET['g'])) { | ||||||
|  |             // add group(s) | ||||||
|  |             $this->selectionId .= 'g=' . $_GET['g']; | ||||||
|  |             $keys = explode(',', $_GET['g']); | ||||||
|  |             if ($keys != array_unique($keys)) { | ||||||
|  |                 $this->log("Duplicate group key found."); | ||||||
|  |                 return $options; | ||||||
|  |             } | ||||||
|  |             $keys = explode(',', $_GET['g']); | ||||||
|  |             foreach ($keys as $key) { | ||||||
|  |                 if (! isset($cOptions['groups'][$key])) { | ||||||
|  |                     $this->log("A group configuration for \"{$key}\" was not found"); | ||||||
|  |                     return $options; | ||||||
|  |                 } | ||||||
|  |                 $files = $cOptions['groups'][$key]; | ||||||
|  |                 // if $files is a single object, casting will break it | ||||||
|  |                 if (is_object($files)) { | ||||||
|  |                     $files = array($files); | ||||||
|  |                 } elseif (! is_array($files)) { | ||||||
|  |                     $files = (array)$files; | ||||||
|  |                 } | ||||||
|  |                 foreach ($files as $file) { | ||||||
|  |                     if ($file instanceof Minify_Source) { | ||||||
|  |                         $sources[] = $file; | ||||||
|  |                         continue; | ||||||
|  |                     } | ||||||
|  |                     if (0 === strpos($file, '//')) { | ||||||
|  |                         $file = $_SERVER['DOCUMENT_ROOT'] . substr($file, 1); | ||||||
|  |                     } | ||||||
|  |                     $realpath = realpath($file); | ||||||
|  |                     if ($realpath && is_file($realpath)) { | ||||||
|  |                         $sources[] = $this->_getFileSource($realpath, $cOptions); | ||||||
|  |                     } else { | ||||||
|  |                         $this->log("The path \"{$file}\" (realpath \"{$realpath}\") could not be found (or was not a file)"); | ||||||
|  |                         if (null === $firstMissingResource) { | ||||||
|  |                             $firstMissingResource = basename($file); | ||||||
|  |                             continue; | ||||||
|  |                         } else { | ||||||
|  |                             $secondMissingResource = basename($file); | ||||||
|  |                             $this->log("More than one file was missing: '$firstMissingResource', '$secondMissingResource'"); | ||||||
|  |                             return $options; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 if ($sources) { | ||||||
|  |                     try { | ||||||
|  |                         $this->checkType($sources[0]); | ||||||
|  |                     } catch (Exception $e) { | ||||||
|  |                         $this->log($e->getMessage()); | ||||||
|  |                         return $options; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (! $cOptions['groupsOnly'] && isset($_GET['f'])) { | ||||||
|  |             // try user files | ||||||
|  |             // The following restrictions are to limit the URLs that minify will | ||||||
|  |             // respond to. | ||||||
|  |             if (// verify at least one file, files are single comma separated,  | ||||||
|  |                 // and are all same extension | ||||||
|  |                 ! preg_match('/^[^,]+\\.(css|js)(?:,[^,]+\\.\\1)*$/', $_GET['f'], $m) | ||||||
|  |                 // no "//" | ||||||
|  |                 || strpos($_GET['f'], '//') !== false | ||||||
|  |                 // no "\" | ||||||
|  |                 || strpos($_GET['f'], '\\') !== false | ||||||
|  |             ) { | ||||||
|  |                 $this->log("GET param 'f' was invalid"); | ||||||
|  |                 return $options; | ||||||
|  |             } | ||||||
|  |             $ext = ".{$m[1]}"; | ||||||
|  |             try { | ||||||
|  |                 $this->checkType($m[1]); | ||||||
|  |             } catch (Exception $e) { | ||||||
|  |                 $this->log($e->getMessage()); | ||||||
|  |                 return $options; | ||||||
|  |             } | ||||||
|  |             $files = explode(',', $_GET['f']); | ||||||
|  |             if ($files != array_unique($files)) { | ||||||
|  |                 $this->log("Duplicate files were specified"); | ||||||
|  |                 return $options; | ||||||
|  |             } | ||||||
|  |             if (isset($_GET['b'])) { | ||||||
|  |                 // check for validity | ||||||
|  |                 if (preg_match('@^[^/]+(?:/[^/]+)*$@', $_GET['b']) | ||||||
|  |                     && false === strpos($_GET['b'], '..') | ||||||
|  |                     && $_GET['b'] !== '.') { | ||||||
|  |                     // valid base | ||||||
|  |                     $base = "/{$_GET['b']}/";        | ||||||
|  |                 } else { | ||||||
|  |                     $this->log("GET param 'b' was invalid"); | ||||||
|  |                     return $options; | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 $base = '/'; | ||||||
|  |             } | ||||||
|  |             $allowDirs = array(); | ||||||
|  |             foreach ((array)$cOptions['allowDirs'] as $allowDir) { | ||||||
|  |                 $allowDirs[] = realpath(str_replace('//', $_SERVER['DOCUMENT_ROOT'] . '/', $allowDir)); | ||||||
|  |             } | ||||||
|  |             $basenames = array(); // just for cache id | ||||||
|  |             foreach ($files as $file) { | ||||||
|  |                 $uri = $base . $file; | ||||||
|  |                 $path = $_SERVER['DOCUMENT_ROOT'] . $uri; | ||||||
|  |                 $realpath = realpath($path); | ||||||
|  |                 if (false === $realpath || ! is_file($realpath)) { | ||||||
|  |                     $this->log("The path \"{$path}\" (realpath \"{$realpath}\") could not be found (or was not a file)"); | ||||||
|  |                     if (null === $firstMissingResource) { | ||||||
|  |                         $firstMissingResource = $uri; | ||||||
|  |                         continue; | ||||||
|  |                     } else { | ||||||
|  |                         $secondMissingResource = $uri; | ||||||
|  |                         $this->log("More than one file was missing: '$firstMissingResource', '$secondMissingResource`'"); | ||||||
|  |                         return $options; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 try { | ||||||
|  |                     parent::checkNotHidden($realpath); | ||||||
|  |                     parent::checkAllowDirs($realpath, $allowDirs, $uri); | ||||||
|  |                 } catch (Exception $e) { | ||||||
|  |                     $this->log($e->getMessage()); | ||||||
|  |                     return $options; | ||||||
|  |                 } | ||||||
|  |                 $sources[] = $this->_getFileSource($realpath, $cOptions); | ||||||
|  |                 $basenames[] = basename($realpath, $ext); | ||||||
|  |             } | ||||||
|  |             if ($this->selectionId) { | ||||||
|  |                 $this->selectionId .= '_f='; | ||||||
|  |             } | ||||||
|  |             $this->selectionId .= implode(',', $basenames) . $ext; | ||||||
|  |         } | ||||||
|  |         if ($sources) { | ||||||
|  |             if (null !== $firstMissingResource) { | ||||||
|  |                 array_unshift($sources, new Minify_Source(array( | ||||||
|  |                     'id' => 'missingFile' | ||||||
|  |                     // should not cause cache invalidation | ||||||
|  |                     ,'lastModified' => 0 | ||||||
|  |                     // due to caching, filename is unreliable. | ||||||
|  |                     ,'content' => "/* Minify: at least one missing file. See " . Minify::URL_DEBUG . " */\n" | ||||||
|  |                     ,'minifier' => '' | ||||||
|  |                 ))); | ||||||
|  |             } | ||||||
|  |             $this->sources = $sources; | ||||||
|  |         } else { | ||||||
|  |             $this->log("No sources to serve"); | ||||||
|  |         } | ||||||
|  |         return $options; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param string $file | ||||||
|  |      * | ||||||
|  |      * @param array $cOptions | ||||||
|  |      * | ||||||
|  |      * @return Minify_Source | ||||||
|  |      */ | ||||||
|  |     protected function _getFileSource($file, $cOptions) | ||||||
|  |     { | ||||||
|  |         $spec['filepath'] = $file; | ||||||
|  |         if ($cOptions['noMinPattern'] && preg_match($cOptions['noMinPattern'], basename($file))) { | ||||||
|  |             if (preg_match('~\.css$~i', $file)) { | ||||||
|  |                 $spec['minifyOptions']['compress'] = false; | ||||||
|  |             } else { | ||||||
|  |                 $spec['minifier'] = ''; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return new Minify_Source($spec); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected $_type = null; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Make sure that only source files of a single type are registered | ||||||
|  |      * | ||||||
|  |      * @param string $sourceOrExt | ||||||
|  |      * | ||||||
|  |      * @throws Exception | ||||||
|  |      */ | ||||||
|  |     public function checkType($sourceOrExt) | ||||||
|  |     { | ||||||
|  |         if ($sourceOrExt === 'js') { | ||||||
|  |             $type = Minify::TYPE_JS; | ||||||
|  |         } elseif ($sourceOrExt === 'css') { | ||||||
|  |             $type = Minify::TYPE_CSS; | ||||||
|  |         } elseif ($sourceOrExt->contentType !== null) { | ||||||
|  |             $type = $sourceOrExt->contentType; | ||||||
|  |         } else { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         if ($this->_type === null) { | ||||||
|  |             $this->_type = $type; | ||||||
|  |         } elseif ($this->_type !== $type) { | ||||||
|  |             throw new Exception('Content-Type mismatch'); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										68
									
								
								vendor/mrclay/minify/min/lib/Minify/Controller/Page.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								vendor/mrclay/minify/min/lib/Minify/Controller/Page.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_Controller_Page   | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Controller class for serving a single HTML page | ||||||
|  |  *  | ||||||
|  |  * @link http://code.google.com/p/minify/source/browse/trunk/web/examples/1/index.php#59 | ||||||
|  |  * @package Minify | ||||||
|  |  * @author Stephen Clay <steve@mrclay.org> | ||||||
|  |  */ | ||||||
|  | class Minify_Controller_Page extends Minify_Controller_Base { | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Set up source of HTML content | ||||||
|  |      *  | ||||||
|  |      * @param array $options controller and Minify options | ||||||
|  |      * @return array Minify options | ||||||
|  |      *  | ||||||
|  |      * Controller options: | ||||||
|  |      *  | ||||||
|  |      * 'content': (required) HTML markup | ||||||
|  |      *  | ||||||
|  |      * 'id': (required) id of page (string for use in server-side caching) | ||||||
|  |      *  | ||||||
|  |      * 'lastModifiedTime': timestamp of when this content changed. This | ||||||
|  |      * is recommended to allow both server and client-side caching. | ||||||
|  |      *  | ||||||
|  |      * 'minifyAll': should all CSS and Javascript blocks be individually  | ||||||
|  |      * minified? (default false)  | ||||||
|  |      * | ||||||
|  |      * @todo Add 'file' option to read HTML file. | ||||||
|  |      */ | ||||||
|  |     public function setupSources($options) { | ||||||
|  |         if (isset($options['file'])) { | ||||||
|  |             $sourceSpec = array( | ||||||
|  |                 'filepath' => $options['file'] | ||||||
|  |             ); | ||||||
|  |             $f = $options['file']; | ||||||
|  |         } else { | ||||||
|  |             // strip controller options | ||||||
|  |             $sourceSpec = array( | ||||||
|  |                 'content' => $options['content'] | ||||||
|  |                 ,'id' => $options['id'] | ||||||
|  |             ); | ||||||
|  |             $f = $options['id']; | ||||||
|  |             unset($options['content'], $options['id']); | ||||||
|  |         } | ||||||
|  |         // something like "builder,index.php" or "directory,file.html" | ||||||
|  |         $this->selectionId = strtr(substr($f, 1 + strlen(dirname(dirname($f)))), '/\\', ',,'); | ||||||
|  |  | ||||||
|  |         if (isset($options['minifyAll'])) { | ||||||
|  |             // this will be the 2nd argument passed to Minify_HTML::minify() | ||||||
|  |             $sourceSpec['minifyOptions'] = array( | ||||||
|  |                 'cssMinifier' => array('Minify_CSS', 'minify') | ||||||
|  |                 ,'jsMinifier' => array('JSMin', 'minify') | ||||||
|  |             ); | ||||||
|  |             unset($options['minifyAll']); | ||||||
|  |         } | ||||||
|  |         $this->sources[] = new Minify_Source($sourceSpec); | ||||||
|  |          | ||||||
|  |         $options['contentType'] = Minify::TYPE_HTML; | ||||||
|  |         return $options; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										119
									
								
								vendor/mrclay/minify/min/lib/Minify/Controller/Version1.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								vendor/mrclay/minify/min/lib/Minify/Controller/Version1.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,119 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_Controller_Version1   | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Controller class for emulating version 1 of minify.php (mostly a proof-of-concept) | ||||||
|  |  *  | ||||||
|  |  * <code> | ||||||
|  |  * Minify::serve('Version1'); | ||||||
|  |  * </code> | ||||||
|  |  *  | ||||||
|  |  * @package Minify | ||||||
|  |  * @author Stephen Clay <steve@mrclay.org> | ||||||
|  |  */ | ||||||
|  | class Minify_Controller_Version1 extends Minify_Controller_Base { | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Set up groups of files as sources | ||||||
|  |      *  | ||||||
|  |      * @param array $options controller and Minify options | ||||||
|  |      * @return array Minify options | ||||||
|  |      *  | ||||||
|  |      */ | ||||||
|  |     public function setupSources($options) { | ||||||
|  |         // PHP insecure by default: realpath() and other FS functions can't handle null bytes. | ||||||
|  |         if (isset($_GET['files'])) { | ||||||
|  |             $_GET['files'] = str_replace("\x00", '', (string)$_GET['files']); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         self::_setupDefines(); | ||||||
|  |         if (MINIFY_USE_CACHE) { | ||||||
|  |             $cacheDir = defined('MINIFY_CACHE_DIR') | ||||||
|  |                 ? MINIFY_CACHE_DIR | ||||||
|  |                 : ''; | ||||||
|  |             Minify::setCache($cacheDir); | ||||||
|  |         } | ||||||
|  |         $options['badRequestHeader'] = 'HTTP/1.0 404 Not Found'; | ||||||
|  |         $options['contentTypeCharset'] = MINIFY_ENCODING; | ||||||
|  |  | ||||||
|  |         // The following restrictions are to limit the URLs that minify will | ||||||
|  |         // respond to. Ideally there should be only one way to reference a file. | ||||||
|  |         if (! isset($_GET['files']) | ||||||
|  |             // verify at least one file, files are single comma separated,  | ||||||
|  |             // and are all same extension | ||||||
|  |             || ! preg_match('/^[^,]+\\.(css|js)(,[^,]+\\.\\1)*$/', $_GET['files'], $m) | ||||||
|  |             // no "//" (makes URL rewriting easier) | ||||||
|  |             || strpos($_GET['files'], '//') !== false | ||||||
|  |             // no "\" | ||||||
|  |             || strpos($_GET['files'], '\\') !== false | ||||||
|  |             // no "./" | ||||||
|  |             || preg_match('/(?:^|[^\\.])\\.\\//', $_GET['files']) | ||||||
|  |         ) { | ||||||
|  |             return $options; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $files = explode(',', $_GET['files']); | ||||||
|  |         if (count($files) > MINIFY_MAX_FILES) { | ||||||
|  |             return $options; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // strings for prepending to relative/absolute paths | ||||||
|  |         $prependRelPaths = dirname($_SERVER['SCRIPT_FILENAME']) | ||||||
|  |             . DIRECTORY_SEPARATOR; | ||||||
|  |         $prependAbsPaths = $_SERVER['DOCUMENT_ROOT']; | ||||||
|  |          | ||||||
|  |         $goodFiles = array(); | ||||||
|  |         $hasBadSource = false; | ||||||
|  |          | ||||||
|  |         $allowDirs = isset($options['allowDirs']) | ||||||
|  |             ? $options['allowDirs'] | ||||||
|  |             : MINIFY_BASE_DIR; | ||||||
|  |          | ||||||
|  |         foreach ($files as $file) { | ||||||
|  |             // prepend appropriate string for abs/rel paths | ||||||
|  |             $file = ($file[0] === '/' ? $prependAbsPaths : $prependRelPaths) . $file; | ||||||
|  |             // make sure a real file! | ||||||
|  |             $file = realpath($file); | ||||||
|  |             // don't allow unsafe or duplicate files | ||||||
|  |             if (parent::_fileIsSafe($file, $allowDirs)  | ||||||
|  |                 && !in_array($file, $goodFiles))  | ||||||
|  |             { | ||||||
|  |                 $goodFiles[] = $file; | ||||||
|  |                 $srcOptions = array( | ||||||
|  |                     'filepath' => $file | ||||||
|  |                 ); | ||||||
|  |                 $this->sources[] = new Minify_Source($srcOptions); | ||||||
|  |             } else { | ||||||
|  |                 $hasBadSource = true; | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if ($hasBadSource) { | ||||||
|  |             $this->sources = array(); | ||||||
|  |         } | ||||||
|  |         if (! MINIFY_REWRITE_CSS_URLS) { | ||||||
|  |             $options['rewriteCssUris'] = false; | ||||||
|  |         } | ||||||
|  |         return $options; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     private static function _setupDefines() | ||||||
|  |     { | ||||||
|  |         $defaults = array( | ||||||
|  |             'MINIFY_BASE_DIR' => realpath($_SERVER['DOCUMENT_ROOT']) | ||||||
|  |             ,'MINIFY_ENCODING' => 'utf-8' | ||||||
|  |             ,'MINIFY_MAX_FILES' => 16 | ||||||
|  |             ,'MINIFY_REWRITE_CSS_URLS' => true | ||||||
|  |             ,'MINIFY_USE_CACHE' => true | ||||||
|  |         ); | ||||||
|  |         foreach ($defaults as $const => $val) { | ||||||
|  |             if (! defined($const)) { | ||||||
|  |                 define($const, $val); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										26
									
								
								vendor/mrclay/minify/min/lib/Minify/DebugDetector.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								vendor/mrclay/minify/min/lib/Minify/DebugDetector.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Detect whether request should be debugged | ||||||
|  |  * | ||||||
|  |  * @package Minify | ||||||
|  |  * @author Stephen Clay <steve@mrclay.org> | ||||||
|  |  */ | ||||||
|  | class Minify_DebugDetector { | ||||||
|  |     public static function shouldDebugRequest($cookie, $get, $requestUri) | ||||||
|  |     { | ||||||
|  |         if (isset($get['debug'])) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         if (! empty($cookie['minifyDebug'])) { | ||||||
|  |             foreach (preg_split('/\\s+/', $cookie['minifyDebug']) as $debugUri) { | ||||||
|  |                 $pattern = '@' . preg_quote($debugUri, '@') . '@i'; | ||||||
|  |                 $pattern = str_replace(array('\\*', '\\?'), array('.*', '.'), $pattern); | ||||||
|  |                 if (preg_match($pattern, $requestUri)) { | ||||||
|  |                     return true; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										255
									
								
								vendor/mrclay/minify/min/lib/Minify/HTML.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										255
									
								
								vendor/mrclay/minify/min/lib/Minify/HTML.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,255 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_HTML | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Compress HTML | ||||||
|  |  * | ||||||
|  |  * This is a heavy regex-based removal of whitespace, unnecessary comments and | ||||||
|  |  * tokens. IE conditional comments are preserved. There are also options to have | ||||||
|  |  * STYLE and SCRIPT blocks compressed by callback functions. | ||||||
|  |  * | ||||||
|  |  * A test suite is available. | ||||||
|  |  * | ||||||
|  |  * @package Minify | ||||||
|  |  * @author Stephen Clay <steve@mrclay.org> | ||||||
|  |  */ | ||||||
|  | class Minify_HTML { | ||||||
|  |     /** | ||||||
|  |      * @var boolean | ||||||
|  |      */ | ||||||
|  |     protected $_jsCleanComments = true; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * "Minify" an HTML page | ||||||
|  |      * | ||||||
|  |      * @param string $html | ||||||
|  |      * | ||||||
|  |      * @param array $options | ||||||
|  |      * | ||||||
|  |      * 'cssMinifier' : (optional) callback function to process content of STYLE | ||||||
|  |      * elements. | ||||||
|  |      * | ||||||
|  |      * 'jsMinifier' : (optional) callback function to process content of SCRIPT | ||||||
|  |      * elements. Note: the type attribute is ignored. | ||||||
|  |      * | ||||||
|  |      * 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If | ||||||
|  |      * unset, minify will sniff for an XHTML doctype. | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public static function minify($html, $options = array()) { | ||||||
|  |         $min = new self($html, $options); | ||||||
|  |         return $min->process(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Create a minifier object | ||||||
|  |      * | ||||||
|  |      * @param string $html | ||||||
|  |      * | ||||||
|  |      * @param array $options | ||||||
|  |      * | ||||||
|  |      * 'cssMinifier' : (optional) callback function to process content of STYLE | ||||||
|  |      * elements. | ||||||
|  |      * | ||||||
|  |      * 'jsMinifier' : (optional) callback function to process content of SCRIPT | ||||||
|  |      * elements. Note: the type attribute is ignored. | ||||||
|  |      * | ||||||
|  |      * 'jsCleanComments' : (optional) whether to remove HTML comments beginning and end of script block | ||||||
|  |      * | ||||||
|  |      * 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If | ||||||
|  |      * unset, minify will sniff for an XHTML doctype. | ||||||
|  |      */ | ||||||
|  |     public function __construct($html, $options = array()) | ||||||
|  |     { | ||||||
|  |         $this->_html = str_replace("\r\n", "\n", trim($html)); | ||||||
|  |         if (isset($options['xhtml'])) { | ||||||
|  |             $this->_isXhtml = (bool)$options['xhtml']; | ||||||
|  |         } | ||||||
|  |         if (isset($options['cssMinifier'])) { | ||||||
|  |             $this->_cssMinifier = $options['cssMinifier']; | ||||||
|  |         } | ||||||
|  |         if (isset($options['jsMinifier'])) { | ||||||
|  |             $this->_jsMinifier = $options['jsMinifier']; | ||||||
|  |         } | ||||||
|  |         if (isset($options['jsCleanComments'])) { | ||||||
|  |             $this->_jsCleanComments = (bool)$options['jsCleanComments']; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Minify the markeup given in the constructor | ||||||
|  |      *  | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public function process() | ||||||
|  |     { | ||||||
|  |         if ($this->_isXhtml === null) { | ||||||
|  |             $this->_isXhtml = (false !== strpos($this->_html, '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML')); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         $this->_replacementHash = 'MINIFYHTML' . md5($_SERVER['REQUEST_TIME']); | ||||||
|  |         $this->_placeholders = array(); | ||||||
|  |          | ||||||
|  |         // replace SCRIPTs (and minify) with placeholders | ||||||
|  |         $this->_html = preg_replace_callback( | ||||||
|  |             '/(\\s*)<script(\\b[^>]*?>)([\\s\\S]*?)<\\/script>(\\s*)/i' | ||||||
|  |             ,array($this, '_removeScriptCB') | ||||||
|  |             ,$this->_html); | ||||||
|  |          | ||||||
|  |         // replace STYLEs (and minify) with placeholders | ||||||
|  |         $this->_html = preg_replace_callback( | ||||||
|  |             '/\\s*<style(\\b[^>]*>)([\\s\\S]*?)<\\/style>\\s*/i' | ||||||
|  |             ,array($this, '_removeStyleCB') | ||||||
|  |             ,$this->_html); | ||||||
|  |          | ||||||
|  |         // remove HTML comments (not containing IE conditional comments). | ||||||
|  |         $this->_html = preg_replace_callback( | ||||||
|  |             '/<!--([\\s\\S]*?)-->/' | ||||||
|  |             ,array($this, '_commentCB') | ||||||
|  |             ,$this->_html); | ||||||
|  |          | ||||||
|  |         // replace PREs with placeholders | ||||||
|  |         $this->_html = preg_replace_callback('/\\s*<pre(\\b[^>]*?>[\\s\\S]*?<\\/pre>)\\s*/i' | ||||||
|  |             ,array($this, '_removePreCB') | ||||||
|  |             ,$this->_html); | ||||||
|  |          | ||||||
|  |         // replace TEXTAREAs with placeholders | ||||||
|  |         $this->_html = preg_replace_callback( | ||||||
|  |             '/\\s*<textarea(\\b[^>]*?>[\\s\\S]*?<\\/textarea>)\\s*/i' | ||||||
|  |             ,array($this, '_removeTextareaCB') | ||||||
|  |             ,$this->_html); | ||||||
|  |          | ||||||
|  |         // trim each line. | ||||||
|  |         // @todo take into account attribute values that span multiple lines. | ||||||
|  |         $this->_html = preg_replace('/^\\s+|\\s+$/m', '', $this->_html); | ||||||
|  |          | ||||||
|  |         // remove ws around block/undisplayed elements | ||||||
|  |         $this->_html = preg_replace('/\\s+(<\\/?(?:area|base(?:font)?|blockquote|body' | ||||||
|  |             .'|caption|center|col(?:group)?|dd|dir|div|dl|dt|fieldset|form' | ||||||
|  |             .'|frame(?:set)?|h[1-6]|head|hr|html|legend|li|link|map|menu|meta' | ||||||
|  |             .'|ol|opt(?:group|ion)|p|param|t(?:able|body|head|d|h||r|foot|itle)' | ||||||
|  |             .'|ul)\\b[^>]*>)/i', '$1', $this->_html); | ||||||
|  |          | ||||||
|  |         // remove ws outside of all elements | ||||||
|  |         $this->_html = preg_replace( | ||||||
|  |             '/>(\\s(?:\\s*))?([^<]+)(\\s(?:\s*))?</' | ||||||
|  |             ,'>$1$2$3<' | ||||||
|  |             ,$this->_html); | ||||||
|  |          | ||||||
|  |         // use newlines before 1st attribute in open tags (to limit line lengths) | ||||||
|  |         $this->_html = preg_replace('/(<[a-z\\-]+)\\s+([^>]+>)/i', "$1\n$2", $this->_html); | ||||||
|  |          | ||||||
|  |         // fill placeholders | ||||||
|  |         $this->_html = str_replace( | ||||||
|  |             array_keys($this->_placeholders) | ||||||
|  |             ,array_values($this->_placeholders) | ||||||
|  |             ,$this->_html | ||||||
|  |         ); | ||||||
|  |         // issue 229: multi-pass to catch scripts that didn't get replaced in textareas | ||||||
|  |         $this->_html = str_replace( | ||||||
|  |             array_keys($this->_placeholders) | ||||||
|  |             ,array_values($this->_placeholders) | ||||||
|  |             ,$this->_html | ||||||
|  |         ); | ||||||
|  |         return $this->_html; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     protected function _commentCB($m) | ||||||
|  |     { | ||||||
|  |         return (0 === strpos($m[1], '[') || false !== strpos($m[1], '<![')) | ||||||
|  |             ? $m[0] | ||||||
|  |             : ''; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     protected function _reservePlace($content) | ||||||
|  |     { | ||||||
|  |         $placeholder = '%' . $this->_replacementHash . count($this->_placeholders) . '%'; | ||||||
|  |         $this->_placeholders[$placeholder] = $content; | ||||||
|  |         return $placeholder; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected $_isXhtml = null; | ||||||
|  |     protected $_replacementHash = null; | ||||||
|  |     protected $_placeholders = array(); | ||||||
|  |     protected $_cssMinifier = null; | ||||||
|  |     protected $_jsMinifier = null; | ||||||
|  |  | ||||||
|  |     protected function _removePreCB($m) | ||||||
|  |     { | ||||||
|  |         return $this->_reservePlace("<pre{$m[1]}"); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     protected function _removeTextareaCB($m) | ||||||
|  |     { | ||||||
|  |         return $this->_reservePlace("<textarea{$m[1]}"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function _removeStyleCB($m) | ||||||
|  |     { | ||||||
|  |         $openStyle = "<style{$m[1]}"; | ||||||
|  |         $css = $m[2]; | ||||||
|  |         // remove HTML comments | ||||||
|  |         $css = preg_replace('/(?:^\\s*<!--|-->\\s*$)/', '', $css); | ||||||
|  |          | ||||||
|  |         // remove CDATA section markers | ||||||
|  |         $css = $this->_removeCdata($css); | ||||||
|  |          | ||||||
|  |         // minify | ||||||
|  |         $minifier = $this->_cssMinifier | ||||||
|  |             ? $this->_cssMinifier | ||||||
|  |             : 'trim'; | ||||||
|  |         $css = call_user_func($minifier, $css); | ||||||
|  |          | ||||||
|  |         return $this->_reservePlace($this->_needsCdata($css) | ||||||
|  |             ? "{$openStyle}/*<![CDATA[*/{$css}/*]]>*/</style>" | ||||||
|  |             : "{$openStyle}{$css}</style>" | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function _removeScriptCB($m) | ||||||
|  |     { | ||||||
|  |         $openScript = "<script{$m[2]}"; | ||||||
|  |         $js = $m[3]; | ||||||
|  |          | ||||||
|  |         // whitespace surrounding? preserve at least one space | ||||||
|  |         $ws1 = ($m[1] === '') ? '' : ' '; | ||||||
|  |         $ws2 = ($m[4] === '') ? '' : ' '; | ||||||
|  |  | ||||||
|  |         // remove HTML comments (and ending "//" if present) | ||||||
|  |         if ($this->_jsCleanComments) { | ||||||
|  |             $js = preg_replace('/(?:^\\s*<!--\\s*|\\s*(?:\\/\\/)?\\s*-->\\s*$)/', '', $js); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // remove CDATA section markers | ||||||
|  |         $js = $this->_removeCdata($js); | ||||||
|  |          | ||||||
|  |         // minify | ||||||
|  |         $minifier = $this->_jsMinifier | ||||||
|  |             ? $this->_jsMinifier | ||||||
|  |             : 'trim'; | ||||||
|  |         $js = call_user_func($minifier, $js); | ||||||
|  |          | ||||||
|  |         return $this->_reservePlace($this->_needsCdata($js) | ||||||
|  |             ? "{$ws1}{$openScript}/*<![CDATA[*/{$js}/*]]>*/</script>{$ws2}" | ||||||
|  |             : "{$ws1}{$openScript}{$js}</script>{$ws2}" | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function _removeCdata($str) | ||||||
|  |     { | ||||||
|  |         return (false !== strpos($str, '<![CDATA[')) | ||||||
|  |             ? str_replace(array('<![CDATA[', ']]>'), '', $str) | ||||||
|  |             : $str; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     protected function _needsCdata($str) | ||||||
|  |     { | ||||||
|  |         return ($this->_isXhtml && preg_match('/(?:[<&]|\\-\\-|\\]\\]>)/', $str)); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										225
									
								
								vendor/mrclay/minify/min/lib/Minify/HTML/Helper.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										225
									
								
								vendor/mrclay/minify/min/lib/Minify/HTML/Helper.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,225 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_HTML_Helper | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Helpers for writing Minfy URIs into HTML | ||||||
|  |  * | ||||||
|  |  * @package Minify | ||||||
|  |  * @author Stephen Clay <steve@mrclay.org> | ||||||
|  |  */ | ||||||
|  | class Minify_HTML_Helper { | ||||||
|  |     public $rewriteWorks = true; | ||||||
|  |     public $minAppUri = '/min'; | ||||||
|  |     public $groupsConfigFile = ''; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get an HTML-escaped Minify URI for a group or set of files | ||||||
|  |      *  | ||||||
|  |      * @param string|array $keyOrFiles a group key or array of filepaths/URIs | ||||||
|  |      * @param array $opts options: | ||||||
|  |      *   'farExpires' : (default true) append a modified timestamp for cache revving | ||||||
|  |      *   'debug' : (default false) append debug flag | ||||||
|  |      *   'charset' : (default 'UTF-8') for htmlspecialchars | ||||||
|  |      *   'minAppUri' : (default '/min') URI of min directory | ||||||
|  |      *   'rewriteWorks' : (default true) does mod_rewrite work in min app? | ||||||
|  |      *   'groupsConfigFile' : specify if different | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public static function getUri($keyOrFiles, $opts = array()) | ||||||
|  |     { | ||||||
|  |         $opts = array_merge(array( // default options | ||||||
|  |             'farExpires' => true | ||||||
|  |             ,'debug' => false | ||||||
|  |             ,'charset' => 'UTF-8' | ||||||
|  |             ,'minAppUri' => '/min' | ||||||
|  |             ,'rewriteWorks' => true | ||||||
|  |             ,'groupsConfigFile' => '' | ||||||
|  |         ), $opts); | ||||||
|  |         $h = new self; | ||||||
|  |         $h->minAppUri = $opts['minAppUri']; | ||||||
|  |         $h->rewriteWorks = $opts['rewriteWorks']; | ||||||
|  |         $h->groupsConfigFile = $opts['groupsConfigFile']; | ||||||
|  |         if (is_array($keyOrFiles)) { | ||||||
|  |             $h->setFiles($keyOrFiles, $opts['farExpires']); | ||||||
|  |         } else { | ||||||
|  |             $h->setGroup($keyOrFiles, $opts['farExpires']); | ||||||
|  |         } | ||||||
|  |         $uri = $h->getRawUri($opts['farExpires'], $opts['debug']); | ||||||
|  |         return htmlspecialchars($uri, ENT_QUOTES, $opts['charset']); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get non-HTML-escaped URI to minify the specified files | ||||||
|  |      * | ||||||
|  |      * @param bool $farExpires | ||||||
|  |      * @param bool $debug | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public function getRawUri($farExpires = true, $debug = false) | ||||||
|  |     { | ||||||
|  |         $path = rtrim($this->minAppUri, '/') . '/'; | ||||||
|  |         if (! $this->rewriteWorks) { | ||||||
|  |             $path .= '?'; | ||||||
|  |         } | ||||||
|  |         if (null === $this->_groupKey) { | ||||||
|  |             // @todo: implement shortest uri | ||||||
|  |             $path = self::_getShortestUri($this->_filePaths, $path); | ||||||
|  |         } else { | ||||||
|  |             $path .= "g=" . $this->_groupKey; | ||||||
|  |         } | ||||||
|  |         if ($debug) { | ||||||
|  |             $path .= "&debug"; | ||||||
|  |         } elseif ($farExpires && $this->_lastModified) { | ||||||
|  |             $path .= "&" . $this->_lastModified; | ||||||
|  |         } | ||||||
|  |         return $path; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set the files that will comprise the URI we're building | ||||||
|  |      * | ||||||
|  |      * @param array $files | ||||||
|  |      * @param bool $checkLastModified | ||||||
|  |      */ | ||||||
|  |     public function setFiles($files, $checkLastModified = true) | ||||||
|  |     { | ||||||
|  |         $this->_groupKey = null; | ||||||
|  |         if ($checkLastModified) { | ||||||
|  |             $this->_lastModified = self::getLastModified($files); | ||||||
|  |         } | ||||||
|  |         // normalize paths like in /min/f=<paths> | ||||||
|  |         foreach ($files as $k => $file) { | ||||||
|  |             if (0 === strpos($file, '//')) { | ||||||
|  |                 $file = substr($file, 2); | ||||||
|  |             } elseif (0 === strpos($file, '/') | ||||||
|  |                       || 1 === strpos($file, ':\\')) { | ||||||
|  |                 $file = substr($file, strlen($_SERVER['DOCUMENT_ROOT']) + 1); | ||||||
|  |             } | ||||||
|  |             $file = strtr($file, '\\', '/'); | ||||||
|  |             $files[$k] = $file; | ||||||
|  |         } | ||||||
|  |         $this->_filePaths = $files; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set the group of files that will comprise the URI we're building | ||||||
|  |      * | ||||||
|  |      * @param string $key | ||||||
|  |      * @param bool $checkLastModified | ||||||
|  |      */ | ||||||
|  |     public function setGroup($key, $checkLastModified = true) | ||||||
|  |     { | ||||||
|  |         $this->_groupKey = $key; | ||||||
|  |         if ($checkLastModified) { | ||||||
|  |             if (! $this->groupsConfigFile) { | ||||||
|  |                 $this->groupsConfigFile = dirname(dirname(dirname(dirname(__FILE__)))) . '/groupsConfig.php'; | ||||||
|  |             } | ||||||
|  |             if (is_file($this->groupsConfigFile)) { | ||||||
|  |                 $gc = (require $this->groupsConfigFile); | ||||||
|  |                 $keys = explode(',', $key); | ||||||
|  |                 foreach ($keys as $key) { | ||||||
|  |                     if (isset($gc[$key])) { | ||||||
|  |                         $this->_lastModified = self::getLastModified($gc[$key], $this->_lastModified); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get the max(lastModified) of all files | ||||||
|  |      * | ||||||
|  |      * @param array|string $sources | ||||||
|  |      * @param int $lastModified | ||||||
|  |      * @return int | ||||||
|  |      */ | ||||||
|  |     public static function getLastModified($sources, $lastModified = 0) | ||||||
|  |     { | ||||||
|  |         $max = $lastModified; | ||||||
|  |         foreach ((array)$sources as $source) { | ||||||
|  |             if (is_object($source) && isset($source->lastModified)) { | ||||||
|  |                 $max = max($max, $source->lastModified); | ||||||
|  |             } elseif (is_string($source)) { | ||||||
|  |                 if (0 === strpos($source, '//')) { | ||||||
|  |                     $source = $_SERVER['DOCUMENT_ROOT'] . substr($source, 1); | ||||||
|  |                 } | ||||||
|  |                 if (is_file($source)) { | ||||||
|  |                     $max = max($max, filemtime($source)); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return $max; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected $_groupKey = null; // if present, URI will be like g=... | ||||||
|  |     protected $_filePaths = array(); | ||||||
|  |     protected $_lastModified = null; | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * In a given array of strings, find the character they all have at | ||||||
|  |      * a particular index | ||||||
|  |      * | ||||||
|  |      * @param array $arr array of strings | ||||||
|  |      * @param int $pos index to check | ||||||
|  |      * @return mixed a common char or '' if any do not match | ||||||
|  |      */ | ||||||
|  |     protected static function _getCommonCharAtPos($arr, $pos) { | ||||||
|  |         if (!isset($arr[0][$pos])) { | ||||||
|  |             return ''; | ||||||
|  |         } | ||||||
|  |         $c = $arr[0][$pos]; | ||||||
|  |         $l = count($arr); | ||||||
|  |         if ($l === 1) { | ||||||
|  |             return $c; | ||||||
|  |         } | ||||||
|  |         for ($i = 1; $i < $l; ++$i) { | ||||||
|  |             if ($arr[$i][$pos] !== $c) { | ||||||
|  |                 return ''; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return $c; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get the shortest URI to minify the set of source files | ||||||
|  |      * | ||||||
|  |      * @param array $paths root-relative URIs of files | ||||||
|  |      * @param string $minRoot root-relative URI of the "min" application | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     protected static function _getShortestUri($paths, $minRoot = '/min/') { | ||||||
|  |         $pos = 0; | ||||||
|  |         $base = ''; | ||||||
|  |         while (true) { | ||||||
|  |             $c = self::_getCommonCharAtPos($paths, $pos); | ||||||
|  |             if ($c === '') { | ||||||
|  |                 break; | ||||||
|  |             } else { | ||||||
|  |                 $base .= $c; | ||||||
|  |             } | ||||||
|  |             ++$pos; | ||||||
|  |         } | ||||||
|  |         $base = preg_replace('@[^/]+$@', '', $base); | ||||||
|  |         $uri = $minRoot . 'f=' . implode(',', $paths); | ||||||
|  |          | ||||||
|  |         if (substr($base, -1) === '/') { | ||||||
|  |             // we have a base dir! | ||||||
|  |             $basedPaths = $paths; | ||||||
|  |             $l = count($paths); | ||||||
|  |             for ($i = 0; $i < $l; ++$i) { | ||||||
|  |                 $basedPaths[$i] = substr($paths[$i], strlen($base)); | ||||||
|  |             } | ||||||
|  |             $base = substr($base, 0, strlen($base) - 1); | ||||||
|  |             $bUri = $minRoot . 'b=' . $base . '&f=' . implode(',', $basedPaths); | ||||||
|  |  | ||||||
|  |             $uri = strlen($uri) < strlen($bUri) | ||||||
|  |                 ? $uri | ||||||
|  |                 : $bUri; | ||||||
|  |         } | ||||||
|  |         return $uri; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										216
									
								
								vendor/mrclay/minify/min/lib/Minify/ImportProcessor.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								vendor/mrclay/minify/min/lib/Minify/ImportProcessor.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,216 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_ImportProcessor | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Linearize a CSS/JS file by including content specified by CSS import | ||||||
|  |  * declarations. In CSS files, relative URIs are fixed. | ||||||
|  |  * | ||||||
|  |  * @imports will be processed regardless of where they appear in the source | ||||||
|  |  * files; i.e. @imports commented out or in string content will still be | ||||||
|  |  * processed! | ||||||
|  |  * | ||||||
|  |  * This has a unit test but should be considered "experimental". | ||||||
|  |  * | ||||||
|  |  * @package Minify | ||||||
|  |  * @author Stephen Clay <steve@mrclay.org> | ||||||
|  |  * @author Simon Schick <simonsimcity@gmail.com> | ||||||
|  |  */ | ||||||
|  | class Minify_ImportProcessor { | ||||||
|  |  | ||||||
|  |     public static $filesIncluded = array(); | ||||||
|  |  | ||||||
|  |     public static function process($file) | ||||||
|  |     { | ||||||
|  |         self::$filesIncluded = array(); | ||||||
|  |         self::$_isCss = (strtolower(substr($file, -4)) === '.css'); | ||||||
|  |         $obj = new Minify_ImportProcessor(dirname($file)); | ||||||
|  |         return $obj->_getContent($file); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // allows callback funcs to know the current directory | ||||||
|  |     private $_currentDir = null; | ||||||
|  |  | ||||||
|  |     // allows callback funcs to know the directory of the file that inherits this one | ||||||
|  |     private $_previewsDir = null; | ||||||
|  |  | ||||||
|  |     // allows _importCB to write the fetched content back to the obj | ||||||
|  |     private $_importedContent = ''; | ||||||
|  |  | ||||||
|  |     private static $_isCss = null; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param String $currentDir | ||||||
|  |      * @param String $previewsDir Is only used internally | ||||||
|  |      */ | ||||||
|  |     private function __construct($currentDir, $previewsDir = "") | ||||||
|  |     { | ||||||
|  |         $this->_currentDir = $currentDir; | ||||||
|  |         $this->_previewsDir = $previewsDir; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function _getContent($file, $is_imported = false) | ||||||
|  |     { | ||||||
|  |         $file = realpath($file); | ||||||
|  |         if (! $file | ||||||
|  |             || in_array($file, self::$filesIncluded) | ||||||
|  |             || false === ($content = @file_get_contents($file)) | ||||||
|  |         ) { | ||||||
|  |             // file missing, already included, or failed read | ||||||
|  |             return ''; | ||||||
|  |         } | ||||||
|  |         self::$filesIncluded[] = realpath($file); | ||||||
|  |         $this->_currentDir = dirname($file); | ||||||
|  |  | ||||||
|  |         // remove UTF-8 BOM if present | ||||||
|  |         if (pack("CCC",0xef,0xbb,0xbf) === substr($content, 0, 3)) { | ||||||
|  |             $content = substr($content, 3); | ||||||
|  |         } | ||||||
|  |         // ensure uniform EOLs | ||||||
|  |         $content = str_replace("\r\n", "\n", $content); | ||||||
|  |  | ||||||
|  |         // process @imports | ||||||
|  |         $content = preg_replace_callback( | ||||||
|  |             '/ | ||||||
|  |                 @import\\s+ | ||||||
|  |                 (?:url\\(\\s*)?      # maybe url( | ||||||
|  |                 [\'"]?               # maybe quote | ||||||
|  |                 (.*?)                # 1 = URI | ||||||
|  |                 [\'"]?               # maybe end quote | ||||||
|  |                 (?:\\s*\\))?         # maybe ) | ||||||
|  |                 ([a-zA-Z,\\s]*)?     # 2 = media list | ||||||
|  |                 ;                    # end token | ||||||
|  |             /x' | ||||||
|  |             ,array($this, '_importCB') | ||||||
|  |             ,$content | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         // You only need to rework the import-path if the script is imported | ||||||
|  |         if (self::$_isCss && $is_imported) { | ||||||
|  |             // rewrite remaining relative URIs | ||||||
|  |             $content = preg_replace_callback( | ||||||
|  |                 '/url\\(\\s*([^\\)\\s]+)\\s*\\)/' | ||||||
|  |                 ,array($this, '_urlCB') | ||||||
|  |                 ,$content | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $this->_importedContent . $content; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function _importCB($m) | ||||||
|  |     { | ||||||
|  |         $url = $m[1]; | ||||||
|  |         $mediaList = preg_replace('/\\s+/', '', $m[2]); | ||||||
|  |  | ||||||
|  |         if (strpos($url, '://') > 0) { | ||||||
|  |             // protocol, leave in place for CSS, comment for JS | ||||||
|  |             return self::$_isCss | ||||||
|  |                 ? $m[0] | ||||||
|  |                 : "/* Minify_ImportProcessor will not include remote content */"; | ||||||
|  |         } | ||||||
|  |         if ('/' === $url[0]) { | ||||||
|  |             // protocol-relative or root path | ||||||
|  |             $url = ltrim($url, '/'); | ||||||
|  |             $file = realpath($_SERVER['DOCUMENT_ROOT']) . DIRECTORY_SEPARATOR | ||||||
|  |                 . strtr($url, '/', DIRECTORY_SEPARATOR); | ||||||
|  |         } else { | ||||||
|  |             // relative to current path | ||||||
|  |             $file = $this->_currentDir . DIRECTORY_SEPARATOR | ||||||
|  |                 . strtr($url, '/', DIRECTORY_SEPARATOR); | ||||||
|  |         } | ||||||
|  |         $obj = new Minify_ImportProcessor(dirname($file), $this->_currentDir); | ||||||
|  |         $content = $obj->_getContent($file, true); | ||||||
|  |         if ('' === $content) { | ||||||
|  |             // failed. leave in place for CSS, comment for JS | ||||||
|  |             return self::$_isCss | ||||||
|  |                 ? $m[0] | ||||||
|  |                 : "/* Minify_ImportProcessor could not fetch '{$file}' */"; | ||||||
|  |         } | ||||||
|  |         return (!self::$_isCss || preg_match('@(?:^$|\\ball\\b)@', $mediaList)) | ||||||
|  |             ? $content | ||||||
|  |             : "@media {$mediaList} {\n{$content}\n}\n"; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function _urlCB($m) | ||||||
|  |     { | ||||||
|  |         // $m[1] is either quoted or not | ||||||
|  |         $quote = ($m[1][0] === "'" || $m[1][0] === '"') | ||||||
|  |             ? $m[1][0] | ||||||
|  |             : ''; | ||||||
|  |         $url = ($quote === '') | ||||||
|  |             ? $m[1] | ||||||
|  |             : substr($m[1], 1, strlen($m[1]) - 2); | ||||||
|  |         if ('/' !== $url[0]) { | ||||||
|  |             if (strpos($url, '//') > 0) { | ||||||
|  |                 // probably starts with protocol, do not alter | ||||||
|  |             } else { | ||||||
|  |                 // prepend path with current dir separator (OS-independent) | ||||||
|  |                 $path = $this->_currentDir | ||||||
|  |                     . DIRECTORY_SEPARATOR . strtr($url, '/', DIRECTORY_SEPARATOR); | ||||||
|  |                 // update the relative path by the directory of the file that imported this one | ||||||
|  |                 $url = self::getPathDiff(realpath($this->_previewsDir), $path); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return "url({$quote}{$url}{$quote})"; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param string $from | ||||||
|  |      * @param string $to | ||||||
|  |      * @param string $ps | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     private function getPathDiff($from, $to, $ps = DIRECTORY_SEPARATOR) | ||||||
|  |     { | ||||||
|  |         $realFrom = $this->truepath($from); | ||||||
|  |         $realTo = $this->truepath($to); | ||||||
|  |  | ||||||
|  |         $arFrom = explode($ps, rtrim($realFrom, $ps)); | ||||||
|  |         $arTo = explode($ps, rtrim($realTo, $ps)); | ||||||
|  |         while (count($arFrom) && count($arTo) && ($arFrom[0] == $arTo[0])) | ||||||
|  |         { | ||||||
|  |             array_shift($arFrom); | ||||||
|  |             array_shift($arTo); | ||||||
|  |         } | ||||||
|  |         return str_pad("", count($arFrom) * 3, '..' . $ps) . implode($ps, $arTo); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * This function is to replace PHP's extremely buggy realpath(). | ||||||
|  |      * @param string $path The original path, can be relative etc. | ||||||
|  |      * @return string The resolved path, it might not exist. | ||||||
|  |      * @see http://stackoverflow.com/questions/4049856/replace-phps-realpath | ||||||
|  |      */ | ||||||
|  |     function truepath($path) | ||||||
|  |     { | ||||||
|  |         // whether $path is unix or not | ||||||
|  |         $unipath = strlen($path) == 0 || $path{0} != '/'; | ||||||
|  |         // attempts to detect if path is relative in which case, add cwd | ||||||
|  |         if (strpos($path, ':') === false && $unipath) | ||||||
|  |             $path = $this->_currentDir . DIRECTORY_SEPARATOR . $path; | ||||||
|  |  | ||||||
|  |         // resolve path parts (single dot, double dot and double delimiters) | ||||||
|  |         $path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path); | ||||||
|  |         $parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen'); | ||||||
|  |         $absolutes = array(); | ||||||
|  |         foreach ($parts as $part) { | ||||||
|  |             if ('.' == $part) | ||||||
|  |                 continue; | ||||||
|  |             if ('..' == $part) { | ||||||
|  |                 array_pop($absolutes); | ||||||
|  |             } else { | ||||||
|  |                 $absolutes[] = $part; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         $path = implode(DIRECTORY_SEPARATOR, $absolutes); | ||||||
|  |         // resolve any symlinks | ||||||
|  |         if (file_exists($path) && linkinfo($path) > 0) | ||||||
|  |             $path = readlink($path); | ||||||
|  |         // put initial separator that could have been lost | ||||||
|  |         $path = !$unipath ? '/' . $path : $path; | ||||||
|  |         return $path; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										230
									
								
								vendor/mrclay/minify/min/lib/Minify/JS/ClosureCompiler.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										230
									
								
								vendor/mrclay/minify/min/lib/Minify/JS/ClosureCompiler.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,230 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_JS_ClosureCompiler | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Minify Javascript using Google's Closure Compiler API | ||||||
|  |  * | ||||||
|  |  * @link http://code.google.com/closure/compiler/ | ||||||
|  |  * @package Minify | ||||||
|  |  * @author Stephen Clay <steve@mrclay.org> | ||||||
|  |  * | ||||||
|  |  * @todo can use a stream wrapper to unit test this? | ||||||
|  |  */ | ||||||
|  | class Minify_JS_ClosureCompiler { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var string The option key for the maximum POST byte size | ||||||
|  |      */ | ||||||
|  |     const OPTION_MAX_BYTES = 'maxBytes'; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var string The option key for additional params. @see __construct | ||||||
|  |      */ | ||||||
|  |     const OPTION_ADDITIONAL_OPTIONS = 'additionalParams'; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var string The option key for the fallback Minifier | ||||||
|  |      */ | ||||||
|  |     const OPTION_FALLBACK_FUNCTION = 'fallbackFunc'; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var string The option key for the service URL | ||||||
|  |      */ | ||||||
|  |     const OPTION_COMPILER_URL = 'compilerUrl'; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var int The default maximum POST byte size according to https://developers.google.com/closure/compiler/docs/api-ref | ||||||
|  |      */ | ||||||
|  |     const DEFAULT_MAX_BYTES = 200000; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var string[] $DEFAULT_OPTIONS The default options to pass to the compiler service | ||||||
|  |      * | ||||||
|  |      * @note This would be a constant if PHP allowed it | ||||||
|  |      */ | ||||||
|  |     private static $DEFAULT_OPTIONS = array( | ||||||
|  |         'output_format' => 'text', | ||||||
|  |         'compilation_level' => 'SIMPLE_OPTIMIZATIONS' | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var string $url URL of compiler server. defaults to Google's | ||||||
|  |      */ | ||||||
|  |     protected $serviceUrl = 'http://closure-compiler.appspot.com/compile'; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var int $maxBytes The maximum JS size that can be sent to the compiler server in bytes | ||||||
|  |      */ | ||||||
|  |     protected $maxBytes = self::DEFAULT_MAX_BYTES; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var string[] $additionalOptions Additional options to pass to the compiler service | ||||||
|  |      */ | ||||||
|  |     protected $additionalOptions = array(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var callable Function to minify JS if service fails. Default is JSMin | ||||||
|  |      */ | ||||||
|  |     protected $fallbackMinifier = array('JSMin', 'minify'); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Minify JavaScript code via HTTP request to a Closure Compiler API | ||||||
|  |      * | ||||||
|  |      * @param string $js input code | ||||||
|  |      * @param array $options Options passed to __construct(). @see __construct | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public static function minify($js, array $options = array()) | ||||||
|  |     { | ||||||
|  |         $obj = new self($options); | ||||||
|  |         return $obj->min($js); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param array $options Options with keys available below: | ||||||
|  |      * | ||||||
|  |      *  fallbackFunc     : (callable) function to minify if service unavailable. Default is JSMin. | ||||||
|  |      * | ||||||
|  |      *  compilerUrl      : (string) URL to closure compiler server | ||||||
|  |      * | ||||||
|  |      *  maxBytes         : (int) The maximum amount of bytes to be sent as js_code in the POST request. | ||||||
|  |      *                     Defaults to 200000. | ||||||
|  |      * | ||||||
|  |      *  additionalParams : (string[]) Additional parameters to pass to the compiler server. Can be anything named | ||||||
|  |      *                     in https://developers.google.com/closure/compiler/docs/api-ref except for js_code and | ||||||
|  |      *                     output_info | ||||||
|  |      */ | ||||||
|  |     public function __construct(array $options = array()) | ||||||
|  |     { | ||||||
|  |         if (isset($options[self::OPTION_FALLBACK_FUNCTION])) { | ||||||
|  |             $this->fallbackMinifier = $options[self::OPTION_FALLBACK_FUNCTION]; | ||||||
|  |         } | ||||||
|  |         if (isset($options[self::OPTION_COMPILER_URL])) { | ||||||
|  |             $this->serviceUrl = $options[self::OPTION_COMPILER_URL]; | ||||||
|  |         } | ||||||
|  |         if (isset($options[self::OPTION_ADDITIONAL_OPTIONS]) && is_array($options[self::OPTION_ADDITIONAL_OPTIONS])) { | ||||||
|  |             $this->additionalOptions = $options[self::OPTION_ADDITIONAL_OPTIONS]; | ||||||
|  |         } | ||||||
|  |         if (isset($options[self::OPTION_MAX_BYTES])) { | ||||||
|  |             $this->maxBytes = (int) $options[self::OPTION_MAX_BYTES]; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Call the service to perform the minification | ||||||
|  |      * | ||||||
|  |      * @param string $js JavaScript code | ||||||
|  |      * @return string | ||||||
|  |      * @throws Minify_JS_ClosureCompiler_Exception | ||||||
|  |      */ | ||||||
|  |     public function min($js) | ||||||
|  |     { | ||||||
|  |         $postBody = $this->buildPostBody($js); | ||||||
|  |  | ||||||
|  |         if ($this->maxBytes > 0) { | ||||||
|  |             $bytes = (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) | ||||||
|  |                 ? mb_strlen($postBody, '8bit') | ||||||
|  |                 : strlen($postBody); | ||||||
|  |             if ($bytes > $this->maxBytes) { | ||||||
|  |                 throw new Minify_JS_ClosureCompiler_Exception( | ||||||
|  |                     'POST content larger than ' . $this->maxBytes . ' bytes' | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $response = $this->getResponse($postBody); | ||||||
|  |  | ||||||
|  |         if (preg_match('/^Error\(\d\d?\):/', $response)) { | ||||||
|  |             if (is_callable($this->fallbackMinifier)) { | ||||||
|  |                 // use fallback | ||||||
|  |                 $response = "/* Received errors from Closure Compiler API:\n$response" | ||||||
|  |                           . "\n(Using fallback minifier)\n*/\n"; | ||||||
|  |                 $response .= call_user_func($this->fallbackMinifier, $js); | ||||||
|  |             } else { | ||||||
|  |                 throw new Minify_JS_ClosureCompiler_Exception($response); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($response === '') { | ||||||
|  |             $errors = $this->getResponse($this->buildPostBody($js, true)); | ||||||
|  |             throw new Minify_JS_ClosureCompiler_Exception($errors); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $response; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get the response for a given POST body | ||||||
|  |      * | ||||||
|  |      * @param string $postBody | ||||||
|  |      * @return string | ||||||
|  |      * @throws Minify_JS_ClosureCompiler_Exception | ||||||
|  |      */ | ||||||
|  |     protected function getResponse($postBody) | ||||||
|  |     { | ||||||
|  |         $allowUrlFopen = preg_match('/1|yes|on|true/i', ini_get('allow_url_fopen')); | ||||||
|  |  | ||||||
|  |         if ($allowUrlFopen) { | ||||||
|  |             $contents = file_get_contents($this->serviceUrl, false, stream_context_create(array( | ||||||
|  |                 'http' => array( | ||||||
|  |                     'method' => 'POST', | ||||||
|  |                     'header' => "Content-type: application/x-www-form-urlencoded\r\nConnection: close\r\n", | ||||||
|  |                     'content' => $postBody, | ||||||
|  |                     'max_redirects' => 0, | ||||||
|  |                     'timeout' => 15, | ||||||
|  |                 ) | ||||||
|  |             ))); | ||||||
|  |         } elseif (defined('CURLOPT_POST')) { | ||||||
|  |             $ch = curl_init($this->serviceUrl); | ||||||
|  |             curl_setopt($ch, CURLOPT_POST, true); | ||||||
|  |             curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | ||||||
|  |             curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/x-www-form-urlencoded')); | ||||||
|  |             curl_setopt($ch, CURLOPT_POSTFIELDS, $postBody); | ||||||
|  |             curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); | ||||||
|  |             curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15); | ||||||
|  |             $contents = curl_exec($ch); | ||||||
|  |             curl_close($ch); | ||||||
|  |         } else { | ||||||
|  |             throw new Minify_JS_ClosureCompiler_Exception( | ||||||
|  |                "Could not make HTTP request: allow_url_open is false and cURL not available" | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (false === $contents) { | ||||||
|  |             throw new Minify_JS_ClosureCompiler_Exception( | ||||||
|  |                "No HTTP response from server" | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return trim($contents); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Build a POST request body | ||||||
|  |      * | ||||||
|  |      * @param string $js JavaScript code | ||||||
|  |      * @param bool $returnErrors | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     protected function buildPostBody($js, $returnErrors = false) | ||||||
|  |     { | ||||||
|  |         return http_build_query( | ||||||
|  |             array_merge( | ||||||
|  |                 self::$DEFAULT_OPTIONS, | ||||||
|  |                 $this->additionalOptions, | ||||||
|  |                 array( | ||||||
|  |                     'js_code' => $js, | ||||||
|  |                     'output_info' => ($returnErrors ? 'errors' : 'compiled_code') | ||||||
|  |                 ) | ||||||
|  |             ), | ||||||
|  |             null, | ||||||
|  |             '&' | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class Minify_JS_ClosureCompiler_Exception extends Exception {} | ||||||
							
								
								
									
										143
									
								
								vendor/mrclay/minify/min/lib/Minify/Lines.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								vendor/mrclay/minify/min/lib/Minify/Lines.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,143 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_Lines   | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Add line numbers in C-style comments for easier debugging of combined content | ||||||
|  |  * | ||||||
|  |  * @package Minify | ||||||
|  |  * @author Stephen Clay <steve@mrclay.org> | ||||||
|  |  * @author Adam Pedersen (Issue 55 fix) | ||||||
|  |  */ | ||||||
|  | class Minify_Lines { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Add line numbers in C-style comments | ||||||
|  |      * | ||||||
|  |      * This uses a very basic parser easily fooled by comment tokens inside | ||||||
|  |      * strings or regexes, but, otherwise, generally clean code will not be  | ||||||
|  |      * mangled. URI rewriting can also be performed. | ||||||
|  |      * | ||||||
|  |      * @param string $content | ||||||
|  |      *  | ||||||
|  |      * @param array $options available options: | ||||||
|  |      *  | ||||||
|  |      * 'id': (optional) string to identify file. E.g. file name/path | ||||||
|  |      * | ||||||
|  |      * 'currentDir': (default null) if given, this is assumed to be the | ||||||
|  |      * directory of the current CSS file. Using this, minify will rewrite | ||||||
|  |      * all relative URIs in import/url declarations to correctly point to | ||||||
|  |      * the desired files, and prepend a comment with debugging information about | ||||||
|  |      * this process. | ||||||
|  |      *  | ||||||
|  |      * @return string  | ||||||
|  |      */ | ||||||
|  |     public static function minify($content, $options = array())  | ||||||
|  |     { | ||||||
|  |         $id = (isset($options['id']) && $options['id']) | ||||||
|  |             ? $options['id'] | ||||||
|  |             : ''; | ||||||
|  |         $content = str_replace("\r\n", "\n", $content); | ||||||
|  |  | ||||||
|  |         // Hackily rewrite strings with XPath expressions that are | ||||||
|  |         // likely to throw off our dumb parser (for Prototype 1.6.1). | ||||||
|  |         $content = str_replace('"/*"', '"/"+"*"', $content); | ||||||
|  |         $content = preg_replace('@([\'"])(\\.?//?)\\*@', '$1$2$1+$1*', $content); | ||||||
|  |  | ||||||
|  |         $lines = explode("\n", $content); | ||||||
|  |         $numLines = count($lines); | ||||||
|  |         // determine left padding | ||||||
|  |         $padTo = strlen((string) $numLines); // e.g. 103 lines = 3 digits | ||||||
|  |         $inComment = false; | ||||||
|  |         $i = 0; | ||||||
|  |         $newLines = array(); | ||||||
|  |         while (null !== ($line = array_shift($lines))) { | ||||||
|  |             if (('' !== $id) && (0 == $i % 50)) { | ||||||
|  |                 if ($inComment) { | ||||||
|  |                     array_push($newLines, '', "/* {$id} *|", ''); | ||||||
|  |                 } else { | ||||||
|  |                     array_push($newLines, '', "/* {$id} */", ''); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             ++$i; | ||||||
|  |             $newLines[] = self::_addNote($line, $i, $inComment, $padTo); | ||||||
|  |             $inComment = self::_eolInComment($line, $inComment); | ||||||
|  |         } | ||||||
|  |         $content = implode("\n", $newLines) . "\n"; | ||||||
|  |          | ||||||
|  |         // check for desired URI rewriting | ||||||
|  |         if (isset($options['currentDir'])) { | ||||||
|  |             Minify_CSS_UriRewriter::$debugText = ''; | ||||||
|  |             $content = Minify_CSS_UriRewriter::rewrite( | ||||||
|  |                  $content | ||||||
|  |                 ,$options['currentDir'] | ||||||
|  |                 ,isset($options['docRoot']) ? $options['docRoot'] : $_SERVER['DOCUMENT_ROOT'] | ||||||
|  |                 ,isset($options['symlinks']) ? $options['symlinks'] : array() | ||||||
|  |             ); | ||||||
|  |             $content = "/* Minify_CSS_UriRewriter::\$debugText\n\n"  | ||||||
|  |                      . Minify_CSS_UriRewriter::$debugText . "*/\n" | ||||||
|  |                      . $content; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         return $content; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Is the parser within a C-style comment at the end of this line? | ||||||
|  |      * | ||||||
|  |      * @param string $line current line of code | ||||||
|  |      *  | ||||||
|  |      * @param bool $inComment was the parser in a comment at the | ||||||
|  |      * beginning of the line? | ||||||
|  |      * | ||||||
|  |      * @return bool | ||||||
|  |      */ | ||||||
|  |     private static function _eolInComment($line, $inComment) | ||||||
|  |     { | ||||||
|  |         // crude way to avoid things like // */ | ||||||
|  |         $line = preg_replace('~//.*?(\\*/|/\\*).*~', '', $line); | ||||||
|  |  | ||||||
|  |         while (strlen($line)) { | ||||||
|  |             $search = $inComment | ||||||
|  |                 ? '*/' | ||||||
|  |                 : '/*'; | ||||||
|  |             $pos = strpos($line, $search); | ||||||
|  |             if (false === $pos) { | ||||||
|  |                 return $inComment; | ||||||
|  |             } else { | ||||||
|  |                 if ($pos == 0 | ||||||
|  |                     || ($inComment | ||||||
|  |                         ? substr($line, $pos, 3) | ||||||
|  |                         : substr($line, $pos-1, 3)) != '*/*') | ||||||
|  |                 { | ||||||
|  |                         $inComment = ! $inComment; | ||||||
|  |                 } | ||||||
|  |                 $line = substr($line, $pos + 2); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return $inComment; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Prepend a comment (or note) to the given line | ||||||
|  |      * | ||||||
|  |      * @param string $line current line of code | ||||||
|  |      * | ||||||
|  |      * @param string $note content of note/comment | ||||||
|  |      *  | ||||||
|  |      * @param bool $inComment was the parser in a comment at the | ||||||
|  |      * beginning of the line? | ||||||
|  |      * | ||||||
|  |      * @param int $padTo minimum width of comment | ||||||
|  |      *  | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     private static function _addNote($line, $note, $inComment, $padTo) | ||||||
|  |     { | ||||||
|  |         return $inComment | ||||||
|  |             ? '/* ' . str_pad($note, $padTo, ' ', STR_PAD_RIGHT) . ' *| ' . $line | ||||||
|  |             : '/* ' . str_pad($note, $padTo, ' ', STR_PAD_RIGHT) . ' */ ' . $line; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										28
									
								
								vendor/mrclay/minify/min/lib/Minify/Loader.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								vendor/mrclay/minify/min/lib/Minify/Loader.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_Loader | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Class autoloader | ||||||
|  |  * | ||||||
|  |  * @package Minify | ||||||
|  |  * @author Stephen Clay <steve@mrclay.org> | ||||||
|  |  */ | ||||||
|  | class Minify_Loader { | ||||||
|  |     public function loadClass($class) | ||||||
|  |     { | ||||||
|  |         $file = dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR; | ||||||
|  |         $file .= strtr($class, "\\_", DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR) . '.php'; | ||||||
|  |         if (is_readable($file)) { | ||||||
|  |             require $file; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static public function register() | ||||||
|  |     { | ||||||
|  |         $inst = new self(); | ||||||
|  |         spl_autoload_register(array($inst, 'loadClass')); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										47
									
								
								vendor/mrclay/minify/min/lib/Minify/Logger.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								vendor/mrclay/minify/min/lib/Minify/Logger.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_Logger   | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /**  | ||||||
|  |  * Message logging class | ||||||
|  |  *  | ||||||
|  |  * @package Minify | ||||||
|  |  * @author Stephen Clay <steve@mrclay.org> | ||||||
|  |  * | ||||||
|  |  * @todo lose this singleton! pass log object in Minify::serve and distribute to others | ||||||
|  |  */ | ||||||
|  | class Minify_Logger { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set logger object.  | ||||||
|  |      * | ||||||
|  |      * The object should have a method "log" that accepts a value as 1st argument and | ||||||
|  |      * an optional string label as the 2nd. | ||||||
|  |      * | ||||||
|  |      * @param mixed $obj or a "falsey" value to disable | ||||||
|  |      * @return null | ||||||
|  |      */ | ||||||
|  |     public static function setLogger($obj = null) { | ||||||
|  |         self::$_logger = $obj | ||||||
|  |             ? $obj | ||||||
|  |             : null; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Pass a message to the logger (if set) | ||||||
|  |      * | ||||||
|  |      * @param string $msg message to log | ||||||
|  |      * @return null | ||||||
|  |      */ | ||||||
|  |     public static function log($msg, $label = 'Minify') { | ||||||
|  |         if (! self::$_logger) return; | ||||||
|  |         self::$_logger->log($msg, $label); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * @var mixed logger object (like FirePHP) or null (i.e. no logger available) | ||||||
|  |      */ | ||||||
|  |     private static $_logger = null; | ||||||
|  | } | ||||||
							
								
								
									
										37
									
								
								vendor/mrclay/minify/min/lib/Minify/Packer.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								vendor/mrclay/minify/min/lib/Minify/Packer.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_Packer | ||||||
|  |  * | ||||||
|  |  * To use this class you must first download the PHP port of Packer | ||||||
|  |  * and place the file "class.JavaScriptPacker.php" in /lib (or your | ||||||
|  |  * include_path).  | ||||||
|  |  * @link http://joliclic.free.fr/php/javascript-packer/en/ | ||||||
|  |  * | ||||||
|  |  * Be aware that, as long as HTTP encoding is used, scripts minified with JSMin | ||||||
|  |  * will provide better client-side performance, as they need not be unpacked in | ||||||
|  |  * client-side code. | ||||||
|  |  *  | ||||||
|  |  * @package Minify   | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | if (false === (@include 'class.JavaScriptPacker.php')) { | ||||||
|  |     trigger_error( | ||||||
|  |         'The script "class.JavaScriptPacker.php" is required. Please see: http:' | ||||||
|  |         .'//code.google.com/p/minify/source/browse/trunk/min/lib/Minify/Packer.php' | ||||||
|  |         ,E_USER_ERROR | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Minify Javascript using Dean Edward's Packer | ||||||
|  |  *  | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  | class Minify_Packer { | ||||||
|  |     public static function minify($code, $options = array()) | ||||||
|  |     { | ||||||
|  |         // @todo: set encoding options based on $options :) | ||||||
|  |         $packer = new JavascriptPacker($code, 'Normal', true, false); | ||||||
|  |         return trim($packer->pack()); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										187
									
								
								vendor/mrclay/minify/min/lib/Minify/Source.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								vendor/mrclay/minify/min/lib/Minify/Source.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,187 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_Source   | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /**  | ||||||
|  |  * A content source to be minified by Minify.  | ||||||
|  |  *  | ||||||
|  |  * This allows per-source minification options and the mixing of files with | ||||||
|  |  * content from other sources. | ||||||
|  |  *  | ||||||
|  |  * @package Minify | ||||||
|  |  * @author Stephen Clay <steve@mrclay.org> | ||||||
|  |  */ | ||||||
|  | class Minify_Source { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var int time of last modification | ||||||
|  |      */ | ||||||
|  |     public $lastModified = null; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * @var callback minifier function specifically for this source. | ||||||
|  |      */ | ||||||
|  |     public $minifier = null; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * @var array minification options specific to this source. | ||||||
|  |      */ | ||||||
|  |     public $minifyOptions = null; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var string full path of file | ||||||
|  |      */ | ||||||
|  |     public $filepath = null; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * @var string HTTP Content Type (Minify requires one of the constants Minify::TYPE_*) | ||||||
|  |      */ | ||||||
|  |     public $contentType = null; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Create a Minify_Source | ||||||
|  |      *  | ||||||
|  |      * In the $spec array(), you can either provide a 'filepath' to an existing | ||||||
|  |      * file (existence will not be checked!) or give 'id' (unique string for  | ||||||
|  |      * the content), 'content' (the string content) and 'lastModified'  | ||||||
|  |      * (unixtime of last update). | ||||||
|  |      *  | ||||||
|  |      * As a shortcut, the controller will replace "//" at the beginning | ||||||
|  |      * of a filepath with $_SERVER['DOCUMENT_ROOT'] . '/'. | ||||||
|  |      * | ||||||
|  |      * @param array $spec options | ||||||
|  |      */ | ||||||
|  |     public function __construct($spec) | ||||||
|  |     { | ||||||
|  |         if (isset($spec['filepath'])) { | ||||||
|  |             if (0 === strpos($spec['filepath'], '//')) { | ||||||
|  |                 $spec['filepath'] = $_SERVER['DOCUMENT_ROOT'] . substr($spec['filepath'], 1); | ||||||
|  |             } | ||||||
|  |             $segments = explode('.', $spec['filepath']); | ||||||
|  |             $ext = strtolower(array_pop($segments)); | ||||||
|  |             switch ($ext) { | ||||||
|  |             case 'js'   : $this->contentType = 'application/x-javascript'; | ||||||
|  |                           break; | ||||||
|  |             case 'css'  : $this->contentType = 'text/css'; | ||||||
|  |                           break; | ||||||
|  |             case 'htm'  : // fallthrough | ||||||
|  |             case 'html' : $this->contentType = 'text/html'; | ||||||
|  |                           break; | ||||||
|  |             } | ||||||
|  |             $this->filepath = $spec['filepath']; | ||||||
|  |             $this->_id = $spec['filepath']; | ||||||
|  |             $this->lastModified = filemtime($spec['filepath']) | ||||||
|  |                 // offset for Windows uploaders with out of sync clocks | ||||||
|  |                 + round(Minify::$uploaderHoursBehind * 3600); | ||||||
|  |         } elseif (isset($spec['id'])) { | ||||||
|  |             $this->_id = 'id::' . $spec['id']; | ||||||
|  |             if (isset($spec['content'])) { | ||||||
|  |                 $this->_content = $spec['content']; | ||||||
|  |             } else { | ||||||
|  |                 $this->_getContentFunc = $spec['getContentFunc']; | ||||||
|  |             } | ||||||
|  |             $this->lastModified = isset($spec['lastModified']) | ||||||
|  |                 ? $spec['lastModified'] | ||||||
|  |                 : time(); | ||||||
|  |         } | ||||||
|  |         if (isset($spec['contentType'])) { | ||||||
|  |             $this->contentType = $spec['contentType']; | ||||||
|  |         } | ||||||
|  |         if (isset($spec['minifier'])) { | ||||||
|  |             $this->minifier = $spec['minifier']; | ||||||
|  |         } | ||||||
|  |         if (isset($spec['minifyOptions'])) { | ||||||
|  |             $this->minifyOptions = $spec['minifyOptions']; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Get content | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public function getContent() | ||||||
|  |     { | ||||||
|  |         $content = (null !== $this->filepath) | ||||||
|  |             ? file_get_contents($this->filepath) | ||||||
|  |             : ((null !== $this->_content) | ||||||
|  |                 ? $this->_content | ||||||
|  |                 : call_user_func($this->_getContentFunc, $this->_id) | ||||||
|  |             ); | ||||||
|  |         // remove UTF-8 BOM if present | ||||||
|  |         return (pack("CCC",0xef,0xbb,0xbf) === substr($content, 0, 3)) | ||||||
|  |             ? substr($content, 3) | ||||||
|  |             : $content; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Get id | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public function getId() | ||||||
|  |     { | ||||||
|  |         return $this->_id; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Verifies a single minification call can handle all sources | ||||||
|  |      * | ||||||
|  |      * @param array $sources Minify_Source instances | ||||||
|  |      *  | ||||||
|  |      * @return bool true iff there no sources with specific minifier preferences. | ||||||
|  |      */ | ||||||
|  |     public static function haveNoMinifyPrefs($sources) | ||||||
|  |     { | ||||||
|  |         foreach ($sources as $source) { | ||||||
|  |             if (null !== $source->minifier | ||||||
|  |                 || null !== $source->minifyOptions) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Get unique string for a set of sources | ||||||
|  |      * | ||||||
|  |      * @param array $sources Minify_Source instances | ||||||
|  |      *  | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public static function getDigest($sources) | ||||||
|  |     { | ||||||
|  |         foreach ($sources as $source) { | ||||||
|  |             $info[] = array( | ||||||
|  |                 $source->_id, $source->minifier, $source->minifyOptions | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |         return md5(serialize($info)); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Get content type from a group of sources | ||||||
|  |      *  | ||||||
|  |      * This is called if the user doesn't pass in a 'contentType' options   | ||||||
|  |      *  | ||||||
|  |      * @param array $sources Minify_Source instances | ||||||
|  |      *  | ||||||
|  |      * @return string content type. e.g. 'text/css' | ||||||
|  |      */ | ||||||
|  |     public static function getContentType($sources) | ||||||
|  |     { | ||||||
|  |         foreach ($sources as $source) { | ||||||
|  |             if ($source->contentType !== null) { | ||||||
|  |                 return $source->contentType; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return 'text/plain'; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     protected $_content = null; | ||||||
|  |     protected $_getContentFunc = null; | ||||||
|  |     protected $_id = null; | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										382
									
								
								vendor/mrclay/minify/min/lib/Minify/YUI/CssCompressor.java
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										382
									
								
								vendor/mrclay/minify/min/lib/Minify/YUI/CssCompressor.java
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,382 @@ | |||||||
|  | /* | ||||||
|  |  * YUI Compressor | ||||||
|  |  * http://developer.yahoo.com/yui/compressor/ | ||||||
|  |  * Author: Julien Lecomte -  http://www.julienlecomte.net/ | ||||||
|  |  * Author: Isaac Schlueter - http://foohack.com/ | ||||||
|  |  * Author: Stoyan Stefanov - http://phpied.com/ | ||||||
|  |  * Copyright (c) 2011 Yahoo! Inc.  All rights reserved. | ||||||
|  |  * The copyrights embodied in the content of this file are licensed | ||||||
|  |  * by Yahoo! Inc. under the BSD (revised) open source license. | ||||||
|  |  */ | ||||||
|  | package com.yahoo.platform.yui.compressor; | ||||||
|  |  | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.io.Reader; | ||||||
|  | import java.io.Writer; | ||||||
|  | import java.util.regex.Pattern; | ||||||
|  | import java.util.regex.Matcher; | ||||||
|  | import java.util.ArrayList; | ||||||
|  |  | ||||||
|  | public class CssCompressor { | ||||||
|  |  | ||||||
|  |     private StringBuffer srcsb = new StringBuffer(); | ||||||
|  |  | ||||||
|  |     public CssCompressor(Reader in) throws IOException { | ||||||
|  |         // Read the stream... | ||||||
|  |         int c; | ||||||
|  |         while ((c = in.read()) != -1) { | ||||||
|  |             srcsb.append((char) c); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Leave data urls alone to increase parse performance. | ||||||
|  |     protected String extractDataUrls(String css, ArrayList preservedTokens) { | ||||||
|  |  | ||||||
|  |     	int maxIndex = css.length() - 1; | ||||||
|  |         int appendIndex = 0; | ||||||
|  |  | ||||||
|  |     	StringBuffer sb = new StringBuffer(); | ||||||
|  |  | ||||||
|  |         Pattern p = Pattern.compile("url\\(\\s*([\"']?)data\\:"); | ||||||
|  |         Matcher m = p.matcher(css); | ||||||
|  |          | ||||||
|  |         /*  | ||||||
|  |          * Since we need to account for non-base64 data urls, we need to handle  | ||||||
|  |          * ' and ) being part of the data string. Hence switching to indexOf, | ||||||
|  |          * to determine whether or not we have matching string terminators and | ||||||
|  |          * handling sb appends directly, instead of using matcher.append* methods. | ||||||
|  |          */ | ||||||
|  |  | ||||||
|  |         while (m.find()) { | ||||||
|  |  | ||||||
|  |         	int startIndex = m.start() + 4;  	// "url(".length() | ||||||
|  |     		String terminator = m.group(1);     // ', " or empty (not quoted) | ||||||
|  |     		 | ||||||
|  |     		if (terminator.length() == 0) { | ||||||
|  |     		 	terminator = ")"; | ||||||
|  |     		} | ||||||
|  |  | ||||||
|  |     		boolean foundTerminator = false; | ||||||
|  |  | ||||||
|  |     		int endIndex = m.end() - 1; | ||||||
|  |     		while(foundTerminator == false && endIndex+1 <= maxIndex) { | ||||||
|  |     			endIndex = css.indexOf(terminator, endIndex+1); | ||||||
|  |  | ||||||
|  |     			if ((endIndex > 0) && (css.charAt(endIndex-1) != '\\')) { | ||||||
|  |     				foundTerminator = true; | ||||||
|  |     				if (!")".equals(terminator)) { | ||||||
|  |     					endIndex = css.indexOf(")", endIndex);  | ||||||
|  |     				} | ||||||
|  |     			} | ||||||
|  |     		} | ||||||
|  |  | ||||||
|  |     		// Enough searching, start moving stuff over to the buffer | ||||||
|  | 			sb.append(css.substring(appendIndex, m.start())); | ||||||
|  |  | ||||||
|  |     		if (foundTerminator) { | ||||||
|  |     			String token = css.substring(startIndex, endIndex); | ||||||
|  |     			token = token.replaceAll("\\s+", ""); | ||||||
|  | 	    		preservedTokens.add(token); | ||||||
|  |  | ||||||
|  | 	    		String preserver = "url(___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___)"; | ||||||
|  | 	    		sb.append(preserver); | ||||||
|  |  | ||||||
|  | 	    		appendIndex = endIndex + 1; | ||||||
|  |     		} else { | ||||||
|  |     			// No end terminator found, re-add the whole match. Should we throw/warn here? | ||||||
|  |     			sb.append(css.substring(m.start(), m.end())); | ||||||
|  |     			appendIndex = m.end(); | ||||||
|  |     		} | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         sb.append(css.substring(appendIndex)); | ||||||
|  |  | ||||||
|  |         return sb.toString(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void compress(Writer out, int linebreakpos) | ||||||
|  |             throws IOException { | ||||||
|  |  | ||||||
|  |         Pattern p; | ||||||
|  |         Matcher m; | ||||||
|  |         String css = srcsb.toString(); | ||||||
|  |  | ||||||
|  |         int startIndex = 0; | ||||||
|  |         int endIndex = 0; | ||||||
|  |         int i = 0; | ||||||
|  |         int max = 0; | ||||||
|  |         ArrayList preservedTokens = new ArrayList(0); | ||||||
|  |         ArrayList comments = new ArrayList(0); | ||||||
|  |         String token; | ||||||
|  |         int totallen = css.length(); | ||||||
|  |         String placeholder; | ||||||
|  |  | ||||||
|  |         css = this.extractDataUrls(css, preservedTokens); | ||||||
|  |  | ||||||
|  |         StringBuffer sb = new StringBuffer(css); | ||||||
|  |  | ||||||
|  |         // collect all comment blocks... | ||||||
|  |         while ((startIndex = sb.indexOf("/*", startIndex)) >= 0) { | ||||||
|  |             endIndex = sb.indexOf("*/", startIndex + 2); | ||||||
|  |             if (endIndex < 0) { | ||||||
|  |                 endIndex = totallen; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             token = sb.substring(startIndex + 2, endIndex); | ||||||
|  |             comments.add(token); | ||||||
|  |             sb.replace(startIndex + 2, endIndex, "___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_" + (comments.size() - 1) + "___"); | ||||||
|  |             startIndex += 2; | ||||||
|  |         } | ||||||
|  |         css = sb.toString(); | ||||||
|  |  | ||||||
|  |         // preserve strings so their content doesn't get accidentally minified | ||||||
|  |         sb = new StringBuffer(); | ||||||
|  |         p = Pattern.compile("(\"([^\\\\\"]|\\\\.|\\\\)*\")|(\'([^\\\\\']|\\\\.|\\\\)*\')"); | ||||||
|  |         m = p.matcher(css); | ||||||
|  |         while (m.find()) { | ||||||
|  |             token = m.group(); | ||||||
|  |             char quote = token.charAt(0); | ||||||
|  |             token = token.substring(1, token.length() - 1); | ||||||
|  |  | ||||||
|  |             // maybe the string contains a comment-like substring? | ||||||
|  |             // one, maybe more? put'em back then | ||||||
|  |             if (token.indexOf("___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_") >= 0) { | ||||||
|  |                 for (i = 0, max = comments.size(); i < max; i += 1) { | ||||||
|  |                     token = token.replace("___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_" + i + "___", comments.get(i).toString()); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // minify alpha opacity in filter strings | ||||||
|  |             token = token.replaceAll("(?i)progid:DXImageTransform.Microsoft.Alpha\\(Opacity=", "alpha(opacity="); | ||||||
|  |  | ||||||
|  |             preservedTokens.add(token); | ||||||
|  |             String preserver = quote + "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___" + quote; | ||||||
|  |             m.appendReplacement(sb, preserver); | ||||||
|  |         } | ||||||
|  |         m.appendTail(sb); | ||||||
|  |         css = sb.toString(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         // strings are safe, now wrestle the comments | ||||||
|  |         for (i = 0, max = comments.size(); i < max; i += 1) { | ||||||
|  |  | ||||||
|  |             token = comments.get(i).toString(); | ||||||
|  |             placeholder = "___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_" + i + "___"; | ||||||
|  |  | ||||||
|  |             // ! in the first position of the comment means preserve | ||||||
|  |             // so push to the preserved tokens while stripping the ! | ||||||
|  |             if (token.startsWith("!")) { | ||||||
|  |                 preservedTokens.add(token); | ||||||
|  |                 css = css.replace(placeholder,  "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___"); | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // \ in the last position looks like hack for Mac/IE5 | ||||||
|  |             // shorten that to /*\*/ and the next one to /**/ | ||||||
|  |             if (token.endsWith("\\")) { | ||||||
|  |                 preservedTokens.add("\\"); | ||||||
|  |                 css = css.replace(placeholder,  "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___"); | ||||||
|  |                 i = i + 1; // attn: advancing the loop | ||||||
|  |                 preservedTokens.add(""); | ||||||
|  |                 css = css.replace("___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_" + i + "___",  "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___"); | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // keep empty comments after child selectors (IE7 hack) | ||||||
|  |             // e.g. html >/**/ body | ||||||
|  |             if (token.length() == 0) { | ||||||
|  |                 startIndex = css.indexOf(placeholder); | ||||||
|  |                 if (startIndex > 2) { | ||||||
|  |                     if (css.charAt(startIndex - 3) == '>') { | ||||||
|  |                         preservedTokens.add(""); | ||||||
|  |                         css = css.replace(placeholder,  "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___"); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // in all other cases kill the comment | ||||||
|  |             css = css.replace("/*" + placeholder + "*/", ""); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         // Normalize all whitespace strings to single spaces. Easier to work with that way. | ||||||
|  |         css = css.replaceAll("\\s+", " "); | ||||||
|  |  | ||||||
|  |         // Remove the spaces before the things that should not have spaces before them. | ||||||
|  |         // But, be careful not to turn "p :link {...}" into "p:link{...}" | ||||||
|  |         // Swap out any pseudo-class colons with the token, and then swap back. | ||||||
|  |         sb = new StringBuffer(); | ||||||
|  |         p = Pattern.compile("(^|\\})(([^\\{:])+:)+([^\\{]*\\{)"); | ||||||
|  |         m = p.matcher(css); | ||||||
|  |         while (m.find()) { | ||||||
|  |             String s = m.group(); | ||||||
|  |             s = s.replaceAll(":", "___YUICSSMIN_PSEUDOCLASSCOLON___"); | ||||||
|  |             s = s.replaceAll( "\\\\", "\\\\\\\\" ).replaceAll( "\\$", "\\\\\\$" ); | ||||||
|  |             m.appendReplacement(sb, s); | ||||||
|  |         } | ||||||
|  |         m.appendTail(sb); | ||||||
|  |         css = sb.toString(); | ||||||
|  |         // Remove spaces before the things that should not have spaces before them. | ||||||
|  |         css = css.replaceAll("\\s+([!{};:>+\\(\\)\\],])", "$1"); | ||||||
|  |         // bring back the colon | ||||||
|  |         css = css.replaceAll("___YUICSSMIN_PSEUDOCLASSCOLON___", ":"); | ||||||
|  |  | ||||||
|  |         // retain space for special IE6 cases | ||||||
|  |         css = css.replaceAll(":first\\-(line|letter)(\\{|,)", ":first-$1 $2"); | ||||||
|  |  | ||||||
|  |         // no space after the end of a preserved comment | ||||||
|  |         css = css.replaceAll("\\*/ ", "*/"); | ||||||
|  |  | ||||||
|  |         // If there is a @charset, then only allow one, and push to the top of the file. | ||||||
|  |         css = css.replaceAll("^(.*)(@charset \"[^\"]*\";)", "$2$1"); | ||||||
|  |         css = css.replaceAll("^(\\s*@charset [^;]+;\\s*)+", "$1"); | ||||||
|  |  | ||||||
|  |         // Put the space back in some cases, to support stuff like | ||||||
|  |         // @media screen and (-webkit-min-device-pixel-ratio:0){ | ||||||
|  |         css = css.replaceAll("\\band\\(", "and ("); | ||||||
|  |  | ||||||
|  |         // Remove the spaces after the things that should not have spaces after them. | ||||||
|  |         css = css.replaceAll("([!{}:;>+\\(\\[,])\\s+", "$1"); | ||||||
|  |  | ||||||
|  |         // remove unnecessary semicolons | ||||||
|  |         css = css.replaceAll(";+}", "}"); | ||||||
|  |  | ||||||
|  |         // Replace 0(px,em,%) with 0. | ||||||
|  |         css = css.replaceAll("([\\s:])(0)(px|em|%|in|cm|mm|pc|pt|ex)", "$1$2"); | ||||||
|  |  | ||||||
|  |         // Replace 0 0 0 0; with 0. | ||||||
|  |         css = css.replaceAll(":0 0 0 0(;|})", ":0$1"); | ||||||
|  |         css = css.replaceAll(":0 0 0(;|})", ":0$1"); | ||||||
|  |         css = css.replaceAll(":0 0(;|})", ":0$1"); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         // Replace background-position:0; with background-position:0 0; | ||||||
|  |         // same for transform-origin | ||||||
|  |         sb = new StringBuffer(); | ||||||
|  |         p = Pattern.compile("(?i)(background-position|transform-origin|webkit-transform-origin|moz-transform-origin|o-transform-origin|ms-transform-origin):0(;|})"); | ||||||
|  |         m = p.matcher(css); | ||||||
|  |         while (m.find()) { | ||||||
|  |             m.appendReplacement(sb, m.group(1).toLowerCase() + ":0 0" + m.group(2)); | ||||||
|  |         } | ||||||
|  |         m.appendTail(sb); | ||||||
|  |         css = sb.toString(); | ||||||
|  |  | ||||||
|  |         // Replace 0.6 to .6, but only when preceded by : or a white-space | ||||||
|  |         css = css.replaceAll("(:|\\s)0+\\.(\\d+)", "$1.$2"); | ||||||
|  |  | ||||||
|  |         // Shorten colors from rgb(51,102,153) to #336699 | ||||||
|  |         // This makes it more likely that it'll get further compressed in the next step. | ||||||
|  |         p = Pattern.compile("rgb\\s*\\(\\s*([0-9,\\s]+)\\s*\\)"); | ||||||
|  |         m = p.matcher(css); | ||||||
|  |         sb = new StringBuffer(); | ||||||
|  |         while (m.find()) { | ||||||
|  |             String[] rgbcolors = m.group(1).split(","); | ||||||
|  |             StringBuffer hexcolor = new StringBuffer("#"); | ||||||
|  |             for (i = 0; i < rgbcolors.length; i++) { | ||||||
|  |                 int val = Integer.parseInt(rgbcolors[i]); | ||||||
|  |                 if (val < 16) { | ||||||
|  |                     hexcolor.append("0"); | ||||||
|  |                 } | ||||||
|  |                 hexcolor.append(Integer.toHexString(val)); | ||||||
|  |             } | ||||||
|  |             m.appendReplacement(sb, hexcolor.toString()); | ||||||
|  |         } | ||||||
|  |         m.appendTail(sb); | ||||||
|  |         css = sb.toString(); | ||||||
|  |  | ||||||
|  |         // Shorten colors from #AABBCC to #ABC. Note that we want to make sure | ||||||
|  |         // the color is not preceded by either ", " or =. Indeed, the property | ||||||
|  |         //     filter: chroma(color="#FFFFFF"); | ||||||
|  |         // would become | ||||||
|  |         //     filter: chroma(color="#FFF"); | ||||||
|  |         // which makes the filter break in IE. | ||||||
|  |         // We also want to make sure we're only compressing #AABBCC patterns inside { }, not id selectors ( #FAABAC {} ) | ||||||
|  |         // We also want to avoid compressing invalid values (e.g. #AABBCCD to #ABCD) | ||||||
|  |         p = Pattern.compile("(\\=\\s*?[\"']?)?" + "#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])" + "(:?\\}|[^0-9a-fA-F{][^{]*?\\})"); | ||||||
|  |  | ||||||
|  |         m = p.matcher(css); | ||||||
|  |         sb = new StringBuffer(); | ||||||
|  |         int index = 0; | ||||||
|  |  | ||||||
|  |         while (m.find(index)) { | ||||||
|  |  | ||||||
|  |         	sb.append(css.substring(index, m.start())); | ||||||
|  |  | ||||||
|  |         	boolean isFilter = (m.group(1) != null && !"".equals(m.group(1)));  | ||||||
|  |  | ||||||
|  |         	if (isFilter) { | ||||||
|  |         		// Restore, as is. Compression will break filters | ||||||
|  |         		sb.append(m.group(1) + "#" + m.group(2) + m.group(3) + m.group(4) + m.group(5) + m.group(6) + m.group(7)); | ||||||
|  |         	} else { | ||||||
|  |         		if( m.group(2).equalsIgnoreCase(m.group(3)) && | ||||||
|  |                     m.group(4).equalsIgnoreCase(m.group(5)) && | ||||||
|  |                     m.group(6).equalsIgnoreCase(m.group(7))) { | ||||||
|  |  | ||||||
|  | 	        		// #AABBCC pattern | ||||||
|  | 	                sb.append("#" + (m.group(3) + m.group(5) + m.group(7)).toLowerCase()); | ||||||
|  |  | ||||||
|  |         		} else { | ||||||
|  |  | ||||||
|  |         			// Non-compressible color, restore, but lower case. | ||||||
|  |         			sb.append("#" + (m.group(2) + m.group(3) + m.group(4) + m.group(5) + m.group(6) + m.group(7)).toLowerCase()); | ||||||
|  |         		} | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |         	index = m.end(7); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         sb.append(css.substring(index)); | ||||||
|  |         css = sb.toString(); | ||||||
|  |  | ||||||
|  |         // border: none -> border:0 | ||||||
|  |         sb = new StringBuffer(); | ||||||
|  |         p = Pattern.compile("(?i)(border|border-top|border-right|border-bottom|border-right|outline|background):none(;|})"); | ||||||
|  |         m = p.matcher(css); | ||||||
|  |         while (m.find()) { | ||||||
|  |             m.appendReplacement(sb, m.group(1).toLowerCase() + ":0" + m.group(2)); | ||||||
|  |         } | ||||||
|  |         m.appendTail(sb); | ||||||
|  |         css = sb.toString(); | ||||||
|  |  | ||||||
|  |         // shorter opacity IE filter | ||||||
|  |         css = css.replaceAll("(?i)progid:DXImageTransform.Microsoft.Alpha\\(Opacity=", "alpha(opacity="); | ||||||
|  |  | ||||||
|  |         // Remove empty rules. | ||||||
|  |         css = css.replaceAll("[^\\}\\{/;]+\\{\\}", ""); | ||||||
|  |  | ||||||
|  |         // TODO: Should this be after we re-insert tokens. These could alter the break points. However then | ||||||
|  |         // we'd need to make sure we don't break in the middle of a string etc. | ||||||
|  |         if (linebreakpos >= 0) { | ||||||
|  |             // Some source control tools don't like it when files containing lines longer | ||||||
|  |             // than, say 8000 characters, are checked in. The linebreak option is used in | ||||||
|  |             // that case to split long lines after a specific column. | ||||||
|  |             i = 0; | ||||||
|  |             int linestartpos = 0; | ||||||
|  |             sb = new StringBuffer(css); | ||||||
|  |             while (i < sb.length()) { | ||||||
|  |                 char c = sb.charAt(i++); | ||||||
|  |                 if (c == '}' && i - linestartpos > linebreakpos) { | ||||||
|  |                     sb.insert(i, '\n'); | ||||||
|  |                     linestartpos = i; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             css = sb.toString(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Replace multiple semi-colons in a row by a single one | ||||||
|  |         // See SF bug #1980989 | ||||||
|  |         css = css.replaceAll(";;+", ";"); | ||||||
|  |  | ||||||
|  |         // restore preserved comments and strings | ||||||
|  |         for(i = 0, max = preservedTokens.size(); i < max; i++) { | ||||||
|  |             css = css.replace("___YUICSSMIN_PRESERVED_TOKEN_" + i + "___", preservedTokens.get(i).toString()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Trim the final string (for any leading or trailing white spaces) | ||||||
|  |         css = css.trim(); | ||||||
|  |  | ||||||
|  |         // Write the output... | ||||||
|  |         out.write(css); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										171
									
								
								vendor/mrclay/minify/min/lib/Minify/YUI/CssCompressor.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								vendor/mrclay/minify/min/lib/Minify/YUI/CssCompressor.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,171 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_YUI_CssCompressor  | ||||||
|  |  * @package Minify | ||||||
|  |  * | ||||||
|  |  * YUI Compressor | ||||||
|  |  * Author: Julien Lecomte -  http://www.julienlecomte.net/ | ||||||
|  |  * Author: Isaac Schlueter - http://foohack.com/ | ||||||
|  |  * Author: Stoyan Stefanov - http://phpied.com/ | ||||||
|  |  * Author: Steve Clay      - http://www.mrclay.org/ (PHP port) | ||||||
|  |  * Copyright (c) 2009 Yahoo! Inc.  All rights reserved. | ||||||
|  |  * The copyrights embodied in the content of this file are licensed | ||||||
|  |  * by Yahoo! Inc. under the BSD (revised) open source license. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Compress CSS (incomplete DO NOT USE) | ||||||
|  |  *  | ||||||
|  |  * @see https://github.com/yui/yuicompressor/blob/master/src/com/yahoo/platform/yui/compressor/CssCompressor.java | ||||||
|  |  * | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  | class Minify_YUI_CssCompressor { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Minify a CSS string | ||||||
|  |      * | ||||||
|  |      * @param string $css | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public function compress($css, $linebreakpos = 0) | ||||||
|  |     { | ||||||
|  |         $css = str_replace("\r\n", "\n", $css); | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * @todo comment removal | ||||||
|  |          * @todo re-port from newer Java version | ||||||
|  |          */ | ||||||
|  |  | ||||||
|  |         // Normalize all whitespace strings to single spaces. Easier to work with that way. | ||||||
|  |         $css = preg_replace('@\s+@', ' ', $css); | ||||||
|  |  | ||||||
|  |         // Make a pseudo class for the Box Model Hack | ||||||
|  |         $css = preg_replace("@\"\\\\\"}\\\\\"\"@", "___PSEUDOCLASSBMH___", $css); | ||||||
|  |  | ||||||
|  |         // Remove the spaces before the things that should not have spaces before them. | ||||||
|  |         // But, be careful not to turn "p :link {...}" into "p:link{...}" | ||||||
|  |         // Swap out any pseudo-class colons with the token, and then swap back. | ||||||
|  |         $css = preg_replace_callback("@(^|\\})(([^\\{:])+:)+([^\\{]*\\{)@", array($this, '_removeSpacesCB'), $css); | ||||||
|  |  | ||||||
|  |         $css = preg_replace("@\\s+([!{};:>+\\(\\)\\],])@", "$1", $css); | ||||||
|  |         $css = str_replace("___PSEUDOCLASSCOLON___", ":", $css); | ||||||
|  |  | ||||||
|  |         // Remove the spaces after the things that should not have spaces after them. | ||||||
|  |         $css = preg_replace("@([!{}:;>+\\(\\[,])\\s+@", "$1", $css); | ||||||
|  |  | ||||||
|  |         // Add the semicolon where it's missing. | ||||||
|  |         $css = preg_replace("@([^;\\}])}@", "$1;}", $css); | ||||||
|  |  | ||||||
|  |         // Replace 0(px,em,%) with 0. | ||||||
|  |         $css = preg_replace("@([\\s:])(0)(px|em|%|in|cm|mm|pc|pt|ex)@", "$1$2", $css); | ||||||
|  |  | ||||||
|  |         // Replace 0 0 0 0; with 0. | ||||||
|  |         $css = str_replace(":0 0 0 0;", ":0;", $css); | ||||||
|  |         $css = str_replace(":0 0 0;", ":0;", $css); | ||||||
|  |         $css = str_replace(":0 0;", ":0;", $css); | ||||||
|  |  | ||||||
|  |         // Replace background-position:0; with background-position:0 0; | ||||||
|  |         $css = str_replace("background-position:0;", "background-position:0 0;", $css); | ||||||
|  |  | ||||||
|  |         // Replace 0.6 to .6, but only when preceded by : or a white-space | ||||||
|  |         $css = preg_replace("@(:|\\s)0+\\.(\\d+)@", "$1.$2", $css); | ||||||
|  |  | ||||||
|  |         // Shorten colors from rgb(51,102,153) to #336699 | ||||||
|  |         // This makes it more likely that it'll get further compressed in the next step. | ||||||
|  |         $css = preg_replace_callback("@rgb\\s*\\(\\s*([0-9,\\s]+)\\s*\\)@", array($this, '_shortenRgbCB'), $css); | ||||||
|  |  | ||||||
|  |         // Shorten colors from #AABBCC to #ABC. Note that we want to make sure | ||||||
|  |         // the color is not preceded by either ", " or =. Indeed, the property | ||||||
|  |         //     filter: chroma(color="#FFFFFF"); | ||||||
|  |         // would become | ||||||
|  |         //     filter: chroma(color="#FFF"); | ||||||
|  |         // which makes the filter break in IE. | ||||||
|  |         $css = preg_replace_callback("@([^\"'=\\s])(\\s*)#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])@", array($this, '_shortenHexCB'), $css); | ||||||
|  |  | ||||||
|  |         // Remove empty rules. | ||||||
|  |         $css = preg_replace("@[^\\}]+\\{;\\}@", "", $css); | ||||||
|  |  | ||||||
|  |         $linebreakpos = isset($this->_options['linebreakpos']) | ||||||
|  |             ? $this->_options['linebreakpos'] | ||||||
|  |             : 0; | ||||||
|  |  | ||||||
|  |         if ($linebreakpos > 0) { | ||||||
|  |             // Some source control tools don't like it when files containing lines longer | ||||||
|  |             // than, say 8000 characters, are checked in. The linebreak option is used in | ||||||
|  |             // that case to split long lines after a specific column. | ||||||
|  |             $i = 0; | ||||||
|  |             $linestartpos = 0; | ||||||
|  |             $sb = $css; | ||||||
|  |  | ||||||
|  |             // make sure strlen returns byte count | ||||||
|  |             $mbIntEnc = null; | ||||||
|  |             if (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) { | ||||||
|  |                 $mbIntEnc = mb_internal_encoding(); | ||||||
|  |                 mb_internal_encoding('8bit'); | ||||||
|  |             } | ||||||
|  |             $sbLength = strlen($css); | ||||||
|  |             while ($i < $sbLength) { | ||||||
|  |                 $c = $sb[$i++]; | ||||||
|  |                 if ($c === '}' && $i - $linestartpos > $linebreakpos) { | ||||||
|  |                     $sb = substr_replace($sb, "\n", $i, 0); | ||||||
|  |                     $sbLength++; | ||||||
|  |                     $linestartpos = $i; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             $css = $sb; | ||||||
|  |  | ||||||
|  |             // undo potential mb_encoding change | ||||||
|  |             if ($mbIntEnc !== null) { | ||||||
|  |                 mb_internal_encoding($mbIntEnc); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Replace the pseudo class for the Box Model Hack | ||||||
|  |         $css = str_replace("___PSEUDOCLASSBMH___", "\"\\\\\"}\\\\\"\"", $css); | ||||||
|  |  | ||||||
|  |         // Replace multiple semi-colons in a row by a single one | ||||||
|  |         // See SF bug #1980989 | ||||||
|  |         $css = preg_replace("@;;+@", ";", $css); | ||||||
|  |  | ||||||
|  |         // prevent triggering IE6 bug: http://www.crankygeek.com/ie6pebug/ | ||||||
|  |         $css = preg_replace('/:first-l(etter|ine)\\{/', ':first-l$1 {', $css); | ||||||
|  |  | ||||||
|  |         // Trim the final string (for any leading or trailing white spaces) | ||||||
|  |         $css = trim($css); | ||||||
|  |  | ||||||
|  |         return $css; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function _removeSpacesCB($m) | ||||||
|  |     { | ||||||
|  |         return str_replace(':', '___PSEUDOCLASSCOLON___', $m[0]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function _shortenRgbCB($m) | ||||||
|  |     { | ||||||
|  |         $rgbcolors = explode(',', $m[1]); | ||||||
|  |         $hexcolor = '#'; | ||||||
|  |         for ($i = 0; $i < count($rgbcolors); $i++) { | ||||||
|  |             $val = round($rgbcolors[$i]); | ||||||
|  |             if ($val < 16) { | ||||||
|  |                 $hexcolor .= '0'; | ||||||
|  |             } | ||||||
|  |             $hexcolor .= dechex($val); | ||||||
|  |         } | ||||||
|  |         return $hexcolor; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function _shortenHexCB($m) | ||||||
|  |     { | ||||||
|  |         // Test for AABBCC pattern | ||||||
|  |         if ((strtolower($m[3])===strtolower($m[4])) && | ||||||
|  |                 (strtolower($m[5])===strtolower($m[6])) && | ||||||
|  |                 (strtolower($m[7])===strtolower($m[8]))) { | ||||||
|  |             return $m[1] . $m[2] . "#" . $m[3] . $m[5] . $m[7]; | ||||||
|  |         } else { | ||||||
|  |             return $m[0]; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										156
									
								
								vendor/mrclay/minify/min/lib/Minify/YUICompressor.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								vendor/mrclay/minify/min/lib/Minify/YUICompressor.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,156 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Class Minify_YUICompressor  | ||||||
|  |  * @package Minify | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Compress Javascript/CSS using the YUI Compressor | ||||||
|  |  *  | ||||||
|  |  * You must set $jarFile and $tempDir before calling the minify functions. | ||||||
|  |  * Also, depending on your shell's environment, you may need to specify | ||||||
|  |  * the full path to java in $javaExecutable or use putenv() to setup the | ||||||
|  |  * Java environment. | ||||||
|  |  *  | ||||||
|  |  * <code> | ||||||
|  |  * Minify_YUICompressor::$jarFile = '/path/to/yuicompressor-2.4.6.jar'; | ||||||
|  |  * Minify_YUICompressor::$tempDir = '/tmp'; | ||||||
|  |  * $code = Minify_YUICompressor::minifyJs( | ||||||
|  |  *   $code | ||||||
|  |  *   ,array('nomunge' => true, 'line-break' => 1000) | ||||||
|  |  * ); | ||||||
|  |  * </code> | ||||||
|  |  * | ||||||
|  |  * Note: In case you run out stack (default is 512k), you may increase stack size in $options: | ||||||
|  |  *   array('stack-size' => '2048k') | ||||||
|  |  * | ||||||
|  |  * @todo unit tests, $options docs | ||||||
|  |  *  | ||||||
|  |  * @package Minify | ||||||
|  |  * @author Stephen Clay <steve@mrclay.org> | ||||||
|  |  */ | ||||||
|  | class Minify_YUICompressor { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Filepath of the YUI Compressor jar file. This must be set before | ||||||
|  |      * calling minifyJs() or minifyCss(). | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public static $jarFile = null; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Writable temp directory. This must be set before calling minifyJs() | ||||||
|  |      * or minifyCss(). | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public static $tempDir = null; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Filepath of "java" executable (may be needed if not in shell's PATH) | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public static $javaExecutable = 'java'; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Minify a Javascript string | ||||||
|  |      *  | ||||||
|  |      * @param string $js | ||||||
|  |      *  | ||||||
|  |      * @param array $options (verbose is ignored) | ||||||
|  |      *  | ||||||
|  |      * @see http://www.julienlecomte.net/yuicompressor/README | ||||||
|  |      *  | ||||||
|  |      * @return string  | ||||||
|  |      */ | ||||||
|  |     public static function minifyJs($js, $options = array()) | ||||||
|  |     { | ||||||
|  |         return self::_minify('js', $js, $options); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Minify a CSS string | ||||||
|  |      *  | ||||||
|  |      * @param string $css | ||||||
|  |      *  | ||||||
|  |      * @param array $options (verbose is ignored) | ||||||
|  |      *  | ||||||
|  |      * @see http://www.julienlecomte.net/yuicompressor/README | ||||||
|  |      *  | ||||||
|  |      * @return string  | ||||||
|  |      */ | ||||||
|  |     public static function minifyCss($css, $options = array()) | ||||||
|  |     { | ||||||
|  |         return self::_minify('css', $css, $options); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     private static function _minify($type, $content, $options) | ||||||
|  |     { | ||||||
|  |         self::_prepare(); | ||||||
|  |         if (! ($tmpFile = tempnam(self::$tempDir, 'yuic_'))) { | ||||||
|  |             throw new Exception('Minify_YUICompressor : could not create temp file in "'.self::$tempDir.'".'); | ||||||
|  |         } | ||||||
|  |         file_put_contents($tmpFile, $content); | ||||||
|  |         exec(self::_getCmd($options, $type, $tmpFile), $output, $result_code); | ||||||
|  |         unlink($tmpFile); | ||||||
|  |         if ($result_code != 0) { | ||||||
|  |             throw new Exception('Minify_YUICompressor : YUI compressor execution failed.'); | ||||||
|  |         } | ||||||
|  |         return implode("\n", $output); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     private static function _getCmd($userOptions, $type, $tmpFile) | ||||||
|  |     { | ||||||
|  |         $o = array_merge( | ||||||
|  |             array( | ||||||
|  |                 'charset' => '' | ||||||
|  |                 ,'line-break' => 5000 | ||||||
|  |                 ,'type' => $type | ||||||
|  |                 ,'nomunge' => false | ||||||
|  |                 ,'preserve-semi' => false | ||||||
|  |                 ,'disable-optimizations' => false | ||||||
|  | 	            ,'stack-size' => '' | ||||||
|  |             ) | ||||||
|  |             ,$userOptions | ||||||
|  |         ); | ||||||
|  |         $cmd = self::$javaExecutable | ||||||
|  | 	         . (!empty($o['stack-size']) | ||||||
|  | 	            ? ' -Xss' . $o['stack-size'] | ||||||
|  | 	            : '') | ||||||
|  | 	         . ' -jar ' . escapeshellarg(self::$jarFile) | ||||||
|  |              . " --type {$type}" | ||||||
|  |              . (preg_match('/^[\\da-zA-Z0-9\\-]+$/', $o['charset']) | ||||||
|  |                 ? " --charset {$o['charset']}"  | ||||||
|  |                 : '') | ||||||
|  |              . (is_numeric($o['line-break']) && $o['line-break'] >= 0 | ||||||
|  |                 ? ' --line-break ' . (int)$o['line-break'] | ||||||
|  |                 : ''); | ||||||
|  |         if ($type === 'js') { | ||||||
|  |             foreach (array('nomunge', 'preserve-semi', 'disable-optimizations') as $opt) { | ||||||
|  |                 $cmd .= $o[$opt]  | ||||||
|  |                     ? " --{$opt}" | ||||||
|  |                     : ''; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return $cmd . ' ' . escapeshellarg($tmpFile); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     private static function _prepare() | ||||||
|  |     { | ||||||
|  |         if (! is_file(self::$jarFile)) { | ||||||
|  |             throw new Exception('Minify_YUICompressor : $jarFile('.self::$jarFile.') is not a valid file.'); | ||||||
|  |         } | ||||||
|  |         if (! is_readable(self::$jarFile)) { | ||||||
|  |             throw new Exception('Minify_YUICompressor : $jarFile('.self::$jarFile.') is not readable.'); | ||||||
|  |         } | ||||||
|  |         if (! is_dir(self::$tempDir)) { | ||||||
|  |             throw new Exception('Minify_YUICompressor : $tempDir('.self::$tempDir.') is not a valid direcotry.'); | ||||||
|  |         } | ||||||
|  |         if (! is_writable(self::$tempDir)) { | ||||||
|  |             throw new Exception('Minify_YUICompressor : $tempDir('.self::$tempDir.') is not writable.'); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										384
									
								
								vendor/mrclay/minify/min/lib/MrClay/Cli.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										384
									
								
								vendor/mrclay/minify/min/lib/MrClay/Cli.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,384 @@ | |||||||
|  | <?php  | ||||||
|  |  | ||||||
|  | namespace MrClay; | ||||||
|  |  | ||||||
|  | use MrClay\Cli\Arg; | ||||||
|  | use InvalidArgumentException; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Forms a front controller for a console app, handling and validating arguments (options) | ||||||
|  |  * | ||||||
|  |  * Instantiate, add arguments, then call validate(). Afterwards, the user's valid arguments | ||||||
|  |  * and their values will be available in $cli->values. | ||||||
|  |  * | ||||||
|  |  * You may also specify that some arguments be used to provide input/output. By communicating | ||||||
|  |  * solely through the file pointers provided by openInput()/openOutput(), you can make your | ||||||
|  |  * app more flexible to end users. | ||||||
|  |  * | ||||||
|  |  * @author Steve Clay <steve@mrclay.org> | ||||||
|  |  * @license http://www.opensource.org/licenses/mit-license.php  MIT License | ||||||
|  |  */ | ||||||
|  | class Cli { | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * @var array validation errors | ||||||
|  |      */ | ||||||
|  |     public $errors = array(); | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * @var array option values available after validation. | ||||||
|  |      *  | ||||||
|  |      * E.g. array( | ||||||
|  |      *      'a' => false              // option was missing | ||||||
|  |      *     ,'b' => true               // option was present | ||||||
|  |      *     ,'c' => "Hello"            // option had value | ||||||
|  |      *     ,'f' => "/home/user/file"  // file path from root | ||||||
|  |      *     ,'f.raw' => "~/file"       // file path as given to option | ||||||
|  |      * ) | ||||||
|  |      */ | ||||||
|  |     public $values = array(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var array | ||||||
|  |      */ | ||||||
|  |     public $moreArgs = array(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var array | ||||||
|  |      */ | ||||||
|  |     public $debug = array(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var bool The user wants help info | ||||||
|  |      */ | ||||||
|  |     public $isHelpRequest = false; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var Arg[] | ||||||
|  |      */ | ||||||
|  |     protected $_args = array(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var resource | ||||||
|  |      */ | ||||||
|  |     protected $_stdin = null; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var resource | ||||||
|  |      */ | ||||||
|  |     protected $_stdout = null; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * @param bool $exitIfNoStdin (default true) Exit() if STDIN is not defined | ||||||
|  |      */ | ||||||
|  |     public function __construct($exitIfNoStdin = true) | ||||||
|  |     { | ||||||
|  |         if ($exitIfNoStdin && ! defined('STDIN')) { | ||||||
|  |             exit('This script is for command-line use only.'); | ||||||
|  |         } | ||||||
|  |         if (isset($GLOBALS['argv'][1]) | ||||||
|  |              && ($GLOBALS['argv'][1] === '-?' || $GLOBALS['argv'][1] === '--help')) { | ||||||
|  |             $this->isHelpRequest = true; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param Arg|string $letter | ||||||
|  |      * @return Arg | ||||||
|  |      */ | ||||||
|  |     public function addOptionalArg($letter) | ||||||
|  |     { | ||||||
|  |         return $this->addArgument($letter, false); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param Arg|string $letter | ||||||
|  |      * @return Arg | ||||||
|  |      */ | ||||||
|  |     public function addRequiredArg($letter) | ||||||
|  |     { | ||||||
|  |         return $this->addArgument($letter, true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param string $letter | ||||||
|  |      * @param bool $required | ||||||
|  |      * @param Arg|null $arg | ||||||
|  |      * @return Arg | ||||||
|  |      * @throws InvalidArgumentException | ||||||
|  |      */ | ||||||
|  |     public function addArgument($letter, $required, Arg $arg = null) | ||||||
|  |     { | ||||||
|  |         if (! preg_match('/^[a-zA-Z]$/', $letter)) { | ||||||
|  |             throw new InvalidArgumentException('$letter must be in [a-zA-Z]'); | ||||||
|  |         } | ||||||
|  |         if (! $arg) { | ||||||
|  |             $arg = new Arg($required); | ||||||
|  |         } | ||||||
|  |         $this->_args[$letter] = $arg; | ||||||
|  |         return $arg; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param string $letter | ||||||
|  |      * @return Arg|null | ||||||
|  |      */ | ||||||
|  |     public function getArgument($letter) | ||||||
|  |     { | ||||||
|  |         return isset($this->_args[$letter]) ? $this->_args[$letter] : null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* | ||||||
|  |      * Read and validate options | ||||||
|  |      *  | ||||||
|  |      * @return bool true if all options are valid | ||||||
|  |      */ | ||||||
|  |     public function validate() | ||||||
|  |     { | ||||||
|  |         $options = ''; | ||||||
|  |         $this->errors = array(); | ||||||
|  |         $this->values = array(); | ||||||
|  |         $this->_stdin = null; | ||||||
|  |          | ||||||
|  |         if ($this->isHelpRequest) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         $lettersUsed = ''; | ||||||
|  |         foreach ($this->_args as $letter => $arg) { | ||||||
|  |             /* @var Arg $arg  */ | ||||||
|  |             $options .= $letter; | ||||||
|  |             $lettersUsed .= $letter; | ||||||
|  |              | ||||||
|  |             if ($arg->mayHaveValue || $arg->mustHaveValue) { | ||||||
|  |                 $options .= ($arg->mustHaveValue ? ':' : '::'); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->debug['argv'] = $GLOBALS['argv']; | ||||||
|  |         $argvCopy = array_slice($GLOBALS['argv'], 1); | ||||||
|  |         $o = getopt($options); | ||||||
|  |         $this->debug['getopt_options'] = $options; | ||||||
|  |         $this->debug['getopt_return'] = $o; | ||||||
|  |  | ||||||
|  |         foreach ($this->_args as $letter => $arg) { | ||||||
|  |             /* @var Arg $arg  */ | ||||||
|  |             $this->values[$letter] = false; | ||||||
|  |             if (isset($o[$letter])) { | ||||||
|  |                 if (is_bool($o[$letter])) { | ||||||
|  |  | ||||||
|  |                     // remove from argv copy | ||||||
|  |                     $k = array_search("-$letter", $argvCopy); | ||||||
|  |                     if ($k !== false) { | ||||||
|  |                         array_splice($argvCopy, $k, 1); | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     if ($arg->mustHaveValue) { | ||||||
|  |                         $this->addError($letter, "Missing value"); | ||||||
|  |                     } else { | ||||||
|  |                         $this->values[$letter] = true; | ||||||
|  |                     } | ||||||
|  |                 } else { | ||||||
|  |                     // string | ||||||
|  |                     $this->values[$letter] = $o[$letter]; | ||||||
|  |                     $v =& $this->values[$letter]; | ||||||
|  |  | ||||||
|  |                     // remove from argv copy | ||||||
|  |                     // first look for -ovalue or -o=value | ||||||
|  |                     $pattern = "/^-{$letter}=?" . preg_quote($v, '/') . "$/"; | ||||||
|  |                     $foundInArgv = false; | ||||||
|  |                     foreach ($argvCopy as $k => $argV) { | ||||||
|  |                         if (preg_match($pattern, $argV)) { | ||||||
|  |                             array_splice($argvCopy, $k, 1); | ||||||
|  |                             $foundInArgv = true; | ||||||
|  |                             break; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                     if (! $foundInArgv) { | ||||||
|  |                         // space separated | ||||||
|  |                         $k = array_search("-$letter", $argvCopy); | ||||||
|  |                         if ($k !== false) { | ||||||
|  |                             array_splice($argvCopy, $k, 2); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                      | ||||||
|  |                     // check that value isn't really another option | ||||||
|  |                     if (strlen($lettersUsed) > 1) { | ||||||
|  |                         $pattern = "/^-[" . str_replace($letter, '', $lettersUsed) . "]/i"; | ||||||
|  |                         if (preg_match($pattern, $v)) { | ||||||
|  |                             $this->addError($letter, "Value was read as another option: %s", $v); | ||||||
|  |                             return false; | ||||||
|  |                         }     | ||||||
|  |                     } | ||||||
|  |                     if ($arg->assertFile || $arg->assertDir) { | ||||||
|  |                         if ($v[0] !== '/' && $v[0] !== '~') { | ||||||
|  |                             $this->values["$letter.raw"] = $v; | ||||||
|  |                             $v = getcwd() . "/$v"; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                     if ($arg->assertFile) { | ||||||
|  |                         if ($arg->useAsInfile) { | ||||||
|  |                             $this->_stdin = $v; | ||||||
|  |                         } elseif ($arg->useAsOutfile) { | ||||||
|  |                             $this->_stdout = $v; | ||||||
|  |                         } | ||||||
|  |                         if ($arg->assertReadable && ! is_readable($v)) { | ||||||
|  |                             $this->addError($letter, "File not readable: %s", $v); | ||||||
|  |                             continue; | ||||||
|  |                         } | ||||||
|  |                         if ($arg->assertWritable) { | ||||||
|  |                             if (is_file($v)) { | ||||||
|  |                                 if (! is_writable($v)) { | ||||||
|  |                                     $this->addError($letter, "File not writable: %s", $v); | ||||||
|  |                                 } | ||||||
|  |                             } else { | ||||||
|  |                                 if (! is_writable(dirname($v))) { | ||||||
|  |                                     $this->addError($letter, "Directory not writable: %s", dirname($v)); | ||||||
|  |                                 } | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                     } elseif ($arg->assertDir && $arg->assertWritable && ! is_writable($v)) { | ||||||
|  |                         $this->addError($letter, "Directory not readable: %s", $v); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 if ($arg->isRequired()) { | ||||||
|  |                     $this->addError($letter, "Missing"); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         $this->moreArgs = $argvCopy; | ||||||
|  |         reset($this->moreArgs); | ||||||
|  |         return empty($this->errors); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get the full paths of file(s) passed in as unspecified arguments | ||||||
|  |      * | ||||||
|  |      * @return array | ||||||
|  |      */ | ||||||
|  |     public function getPathArgs() | ||||||
|  |     { | ||||||
|  |         $r = $this->moreArgs; | ||||||
|  |         foreach ($r as $k => $v) { | ||||||
|  |             if ($v[0] !== '/' && $v[0] !== '~') { | ||||||
|  |                 $v = getcwd() . "/$v"; | ||||||
|  |                 $v = str_replace('/./', '/', $v); | ||||||
|  |                 do { | ||||||
|  |                     $v = preg_replace('@/[^/]+/\\.\\./@', '/', $v, 1, $changed); | ||||||
|  |                 } while ($changed); | ||||||
|  |                 $r[$k] = $v; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return $r; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Get a short list of errors with options | ||||||
|  |      *  | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public function getErrorReport() | ||||||
|  |     { | ||||||
|  |         if (empty($this->errors)) { | ||||||
|  |             return ''; | ||||||
|  |         } | ||||||
|  |         $r = "Some arguments did not pass validation:\n"; | ||||||
|  |         foreach ($this->errors as $letter => $arr) { | ||||||
|  |             $r .= "  $letter : " . implode(', ', $arr) . "\n"; | ||||||
|  |         } | ||||||
|  |         $r .= "\n"; | ||||||
|  |         return $r; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public function getArgumentsListing() | ||||||
|  |     { | ||||||
|  |         $r = "\n"; | ||||||
|  |         foreach ($this->_args as $letter => $arg) { | ||||||
|  |             /* @var Arg $arg  */ | ||||||
|  |             $desc = $arg->getDescription(); | ||||||
|  |             $flag = " -$letter "; | ||||||
|  |             if ($arg->mayHaveValue) { | ||||||
|  |                 $flag .= "[VAL]"; | ||||||
|  |             } elseif ($arg->mustHaveValue) { | ||||||
|  |                 $flag .= "VAL"; | ||||||
|  |             } | ||||||
|  |             if ($arg->assertFile) { | ||||||
|  |                 $flag = str_replace('VAL', 'FILE', $flag); | ||||||
|  |             } elseif ($arg->assertDir) { | ||||||
|  |                 $flag = str_replace('VAL', 'DIR', $flag); | ||||||
|  |             } | ||||||
|  |             if ($arg->isRequired()) { | ||||||
|  |                 $desc = "(required) $desc"; | ||||||
|  |             } | ||||||
|  |             $flag = str_pad($flag, 12, " ", STR_PAD_RIGHT); | ||||||
|  |             $desc = wordwrap($desc, 70); | ||||||
|  |             $r .= $flag . str_replace("\n", "\n            ", $desc) . "\n\n"; | ||||||
|  |         } | ||||||
|  |         return $r; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Get resource of open input stream. May be STDIN or a file pointer | ||||||
|  |      * to the file specified by an option with 'STDIN'. | ||||||
|  |      * | ||||||
|  |      * @return resource | ||||||
|  |      */ | ||||||
|  |     public function openInput() | ||||||
|  |     { | ||||||
|  |         if (null === $this->_stdin) { | ||||||
|  |             return STDIN; | ||||||
|  |         } else { | ||||||
|  |             $this->_stdin = fopen($this->_stdin, 'rb'); | ||||||
|  |             return $this->_stdin; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     public function closeInput() | ||||||
|  |     { | ||||||
|  |         if (null !== $this->_stdin) { | ||||||
|  |             fclose($this->_stdin); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Get resource of open output stream. May be STDOUT or a file pointer | ||||||
|  |      * to the file specified by an option with 'STDOUT'. The file will be | ||||||
|  |      * truncated to 0 bytes on opening. | ||||||
|  |      * | ||||||
|  |      * @return resource | ||||||
|  |      */ | ||||||
|  |     public function openOutput() | ||||||
|  |     { | ||||||
|  |         if (null === $this->_stdout) { | ||||||
|  |             return STDOUT; | ||||||
|  |         } else { | ||||||
|  |             $this->_stdout = fopen($this->_stdout, 'wb'); | ||||||
|  |             return $this->_stdout; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     public function closeOutput() | ||||||
|  |     { | ||||||
|  |         if (null !== $this->_stdout) { | ||||||
|  |             fclose($this->_stdout); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param string $letter | ||||||
|  |      * @param string $msg | ||||||
|  |      * @param string $value | ||||||
|  |      */ | ||||||
|  |     protected function addError($letter, $msg, $value = null) | ||||||
|  |     { | ||||||
|  |         if ($value !== null) { | ||||||
|  |             $value = var_export($value, 1); | ||||||
|  |         } | ||||||
|  |         $this->errors[$letter][] = sprintf($msg, $value); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										183
									
								
								vendor/mrclay/minify/min/lib/MrClay/Cli/Arg.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								vendor/mrclay/minify/min/lib/MrClay/Cli/Arg.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,183 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace MrClay\Cli; | ||||||
|  |  | ||||||
|  | use BadMethodCallException; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * An argument for a CLI app. This specifies the argument, what values it expects and | ||||||
|  |  * how it's treated during validation. | ||||||
|  |  * | ||||||
|  |  * By default, the argument will be assumed to be an optional letter flag with no value following. | ||||||
|  |  * | ||||||
|  |  * If the argument may receive a value, call mayHaveValue(). If there's whitespace after the | ||||||
|  |  * flag, the value will be returned as true instead of the string. | ||||||
|  |  * | ||||||
|  |  * If the argument MUST be accompanied by a value, call mustHaveValue(). In this case, whitespace | ||||||
|  |  * is permitted between the flag and its value. | ||||||
|  |  * | ||||||
|  |  * Use assertFile() or assertDir() to indicate that the argument must return a string value | ||||||
|  |  * specifying a file or directory. During validation, the value will be resolved to a | ||||||
|  |  * full file/dir path (not necessarily existing!) and the original value will be accessible | ||||||
|  |  * via a "*.raw" key. E.g. $cli->values['f.raw'] | ||||||
|  |  * | ||||||
|  |  * Use assertReadable()/assertWritable() to cause the validator to test the file/dir for | ||||||
|  |  * read/write permissions respectively. | ||||||
|  |  * | ||||||
|  |  * @method \MrClay\Cli\Arg mayHaveValue() Assert that the argument, if present, may receive a string value | ||||||
|  |  * @method \MrClay\Cli\Arg mustHaveValue() Assert that the argument, if present, must receive a string value | ||||||
|  |  * @method \MrClay\Cli\Arg assertFile() Assert that the argument's value must specify a file | ||||||
|  |  * @method \MrClay\Cli\Arg assertDir() Assert that the argument's value must specify a directory | ||||||
|  |  * @method \MrClay\Cli\Arg assertReadable() Assert that the specified file/dir must be readable | ||||||
|  |  * @method \MrClay\Cli\Arg assertWritable() Assert that the specified file/dir must be writable | ||||||
|  |  * | ||||||
|  |  * @property-read bool mayHaveValue | ||||||
|  |  * @property-read bool mustHaveValue | ||||||
|  |  * @property-read bool assertFile | ||||||
|  |  * @property-read bool assertDir | ||||||
|  |  * @property-read bool assertReadable | ||||||
|  |  * @property-read bool assertWritable | ||||||
|  |  * @property-read bool useAsInfile | ||||||
|  |  * @property-read bool useAsOutfile | ||||||
|  |  * | ||||||
|  |  * @author Steve Clay <steve@mrclay.org> | ||||||
|  |  * @license http://www.opensource.org/licenses/mit-license.php  MIT License | ||||||
|  |  */ | ||||||
|  | class Arg { | ||||||
|  |     /** | ||||||
|  |      * @return array | ||||||
|  |      */ | ||||||
|  |     public function getDefaultSpec() | ||||||
|  |     { | ||||||
|  |         return array( | ||||||
|  |             'mayHaveValue' => false, | ||||||
|  |             'mustHaveValue' => false, | ||||||
|  |             'assertFile' => false, | ||||||
|  |             'assertDir' => false, | ||||||
|  |             'assertReadable' => false, | ||||||
|  |             'assertWritable' => false, | ||||||
|  |             'useAsInfile' => false, | ||||||
|  |             'useAsOutfile' => false, | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var array | ||||||
|  |      */ | ||||||
|  |     protected $spec = array(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var bool | ||||||
|  |      */ | ||||||
|  |     protected $required = false; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     protected $description = ''; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param bool $isRequired | ||||||
|  |      */ | ||||||
|  |     public function __construct($isRequired = false) | ||||||
|  |     { | ||||||
|  |         $this->spec = $this->getDefaultSpec(); | ||||||
|  |         $this->required = (bool) $isRequired; | ||||||
|  |         if ($isRequired) { | ||||||
|  |             $this->spec['mustHaveValue'] = true; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Assert that the argument's value points to a writable file. When | ||||||
|  |      * Cli::openOutput() is called, a write pointer to this file will | ||||||
|  |      * be provided. | ||||||
|  |      * @return Arg | ||||||
|  |      */ | ||||||
|  |     public function useAsOutfile() | ||||||
|  |     { | ||||||
|  |         $this->spec['useAsOutfile'] = true; | ||||||
|  |         return $this->assertFile()->assertWritable(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Assert that the argument's value points to a readable file. When | ||||||
|  |      * Cli::openInput() is called, a read pointer to this file will | ||||||
|  |      * be provided. | ||||||
|  |      * @return Arg | ||||||
|  |      */ | ||||||
|  |     public function useAsInfile() | ||||||
|  |     { | ||||||
|  |         $this->spec['useAsInfile'] = true; | ||||||
|  |         return $this->assertFile()->assertReadable(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @return array | ||||||
|  |      */ | ||||||
|  |     public function getSpec() | ||||||
|  |     { | ||||||
|  |         return $this->spec; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param string $desc | ||||||
|  |      * @return Arg | ||||||
|  |      */ | ||||||
|  |     public function setDescription($desc) | ||||||
|  |     { | ||||||
|  |         $this->description = $desc; | ||||||
|  |         return $this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public function getDescription() | ||||||
|  |     { | ||||||
|  |         return $this->description; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @return bool | ||||||
|  |      */ | ||||||
|  |     public function isRequired() | ||||||
|  |     { | ||||||
|  |         return $this->required; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Note: magic methods declared in class PHPDOC | ||||||
|  |      * | ||||||
|  |      * @param string $name | ||||||
|  |      * @param array $args | ||||||
|  |      * @return Arg | ||||||
|  |      * @throws BadMethodCallException | ||||||
|  |      */ | ||||||
|  |     public function __call($name, array $args = array()) | ||||||
|  |     { | ||||||
|  |         if (array_key_exists($name, $this->spec)) { | ||||||
|  |             $this->spec[$name] = true; | ||||||
|  |             if ($name === 'assertFile' || $name === 'assertDir') { | ||||||
|  |                 $this->spec['mustHaveValue'] = true; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             throw new BadMethodCallException('Method does not exist'); | ||||||
|  |         } | ||||||
|  |         return $this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Note: magic properties declared in class PHPDOC | ||||||
|  |      * | ||||||
|  |      * @param string $name | ||||||
|  |      * @return bool|null | ||||||
|  |      */ | ||||||
|  |     public function __get($name) | ||||||
|  |     { | ||||||
|  |         if (array_key_exists($name, $this->spec)) { | ||||||
|  |             return $this->spec[$name]; | ||||||
|  |         } | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								vendor/ornicar/php-user-agent/CHANGELOG.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								vendor/ornicar/php-user-agent/CHANGELOG.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | # CHANGELOG | ||||||
|  |  | ||||||
|  | ### 1.0.1 (????-??-??) | ||||||
|  |  | ||||||
|  |  * f1b82e5 - [Composer] Add branch alias support | ||||||
|  |  | ||||||
|  | ### 1.0.0 (2013-08-09) | ||||||
|  |  | ||||||
|  |  * Add a version following semver spec. | ||||||
|  |  | ||||||
|  | ### v1.0 (2010-04-13) | ||||||
|  |  | ||||||
|  |  * Create initial 1.0 version | ||||||
							
								
								
									
										21
									
								
								vendor/ornicar/php-user-agent/LICENSE
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/ornicar/php-user-agent/LICENSE
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | The MIT License | ||||||
|  |  | ||||||
|  | Copyright (c) 2010 Thibault Duplessis | ||||||
|  |  | ||||||
|  | Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  | of this software and associated documentation files (the "Software"), to deal | ||||||
|  | in the Software without restriction, including without limitation the rights | ||||||
|  | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  | copies of the Software, and to permit persons to whom the Software is | ||||||
|  | furnished to do so, subject to the following conditions: | ||||||
|  |  | ||||||
|  | The above copyright notice and this permission notice shall be included in | ||||||
|  | all copies or substantial portions of the Software. | ||||||
|  |  | ||||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  | THE SOFTWARE. | ||||||
							
								
								
									
										92
									
								
								vendor/ornicar/php-user-agent/README.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								vendor/ornicar/php-user-agent/README.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,92 @@ | |||||||
|  | # PHP User Agent | ||||||
|  |  | ||||||
|  | Browser detection in PHP5. | ||||||
|  | Uses a simple and fast algorithm to recognize major browsers. | ||||||
|  |  | ||||||
|  | ## Overview | ||||||
|  |  | ||||||
|  | ``` php | ||||||
|  | $userAgent = new phpUserAgent(); | ||||||
|  |  | ||||||
|  | $userAgent->getBrowserName()      // firefox | ||||||
|  | $userAgent->getBrowserVersion()   // 3.6 | ||||||
|  | $userAgent->getOperatingSystem()  // linux | ||||||
|  | $userAgent->getEngine()           // gecko | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ### Why you should use it | ||||||
|  |  | ||||||
|  | PHP provides a native function to detect user browser: [get_browser()](http://us2.php.net/manual/en/function.get-browser.php). | ||||||
|  | get_browser() requires the "browscap.ini" file which is 300KB+. | ||||||
|  | Loading and processing this file impact script performance. | ||||||
|  | And sometimes, the production server just doesn't provide browscap.ini. | ||||||
|  |  | ||||||
|  | Although get_browser() surely provides excellent detection results, in most | ||||||
|  | cases a much simpler method can be just as effective. | ||||||
|  | php-user-agent has the advantage of being compact and easy to extend. | ||||||
|  | It is performant as well, since it doesn't do any iteration or recursion. | ||||||
|  |  | ||||||
|  | ## Usage | ||||||
|  |  | ||||||
|  | ``` php | ||||||
|  | // include classes or rely on Composer autoloader | ||||||
|  | require_once '/path/to/php-user-agent/phpUserAgent.php'; | ||||||
|  | require_once '/path/to/php-user-agent/phpUserAgentStringParser.php'; | ||||||
|  |  | ||||||
|  | // Create a user agent | ||||||
|  | $userAgent = new phpUserAgent(); | ||||||
|  |  | ||||||
|  | // Interrogate the user agent | ||||||
|  | $userAgent->getBrowserName()      // firefox | ||||||
|  | $userAgent->getBrowserVersion()   // 3.6 | ||||||
|  | $userAgent->getOperatingSystem()  // linux | ||||||
|  | $userAgent->getEngine()           // gecko | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ## Advanced | ||||||
|  |  | ||||||
|  | ### Custom user agent string | ||||||
|  |  | ||||||
|  | When you create a phpUserAgent object, the current user agent string is used. | ||||||
|  | You can specify another user agent string: | ||||||
|  |  | ||||||
|  | ``` php | ||||||
|  | // use another user agent string | ||||||
|  | $userAgent = new phpUserAgent('msnbot/2.0b (+http://search.msn.com/msnbot.htm)'); | ||||||
|  | $userAgent->getBrowserName() // msnbot | ||||||
|  |  | ||||||
|  | // use current user agent string | ||||||
|  | $userAgent = new phpUserAgent($_SERVER['HTTP_USER_AGENT'); | ||||||
|  | // this is equivalent to: | ||||||
|  | $userAgent = new phpUserAgent(); | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ### Custom parser class | ||||||
|  |  | ||||||
|  | By default, phpUserAgentStringParser is used to analyse the user agent string. | ||||||
|  | You can replace the parser instance and customize it to match your needs: | ||||||
|  |  | ||||||
|  | ``` php | ||||||
|  | // create a custom user agent string parser | ||||||
|  | class myUserAgentStringParser extends phpUserAgentStringParser | ||||||
|  | { | ||||||
|  |   // override methods | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // inject the custom parser when creating a user agent: | ||||||
|  | $userAgent = new phpUserAgent(null, new myUserAgentStringParser()); | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ## Run tests | ||||||
|  |  | ||||||
|  | You can run the unit tests on your server: | ||||||
|  |  | ||||||
|  | ``` bash | ||||||
|  | $ php prove.php | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ## Contribute | ||||||
|  |  | ||||||
|  | If you found a browser of operating system this library fails to recognize, | ||||||
|  | feel free to submit an issue. Please provide the user agent string. | ||||||
|  | And well, if you also want to provide the patch, it's even better. | ||||||
							
								
								
									
										194
									
								
								vendor/ornicar/php-user-agent/lib/phpUserAgent.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										194
									
								
								vendor/ornicar/php-user-agent/lib/phpUserAgent.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,194 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Simple PHP User agent | ||||||
|  |  * | ||||||
|  |  * @link      http://github.com/ornicar/php-user-agent | ||||||
|  |  * @version   1.0 | ||||||
|  |  * @author    Thibault Duplessis <thibault.duplessis at gmail dot com> | ||||||
|  |  * @license   MIT License | ||||||
|  |  * | ||||||
|  |  * Documentation: http://github.com/ornicar/php-user-agent/blob/master/README.markdown | ||||||
|  |  * Tickets:       http://github.com/ornicar/php-user-agent/issues | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | class phpUserAgent | ||||||
|  | { | ||||||
|  |   protected $userAgentString; | ||||||
|  |   protected $browserName; | ||||||
|  |   protected $browserVersion; | ||||||
|  |   protected $operatingSystem; | ||||||
|  |   protected $engine; | ||||||
|  |  | ||||||
|  |   public function __construct($userAgentString = null, phpUserAgentStringParser $userAgentStringParser = null) | ||||||
|  |   { | ||||||
|  |     $this->configureFromUserAgentString($userAgentString, $userAgentStringParser); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Get the browser name | ||||||
|  |    * | ||||||
|  |    * @return string the browser name | ||||||
|  |    */ | ||||||
|  |   public function getBrowserName() | ||||||
|  |   { | ||||||
|  |     return $this->browserName; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Set the browser name | ||||||
|  |    * | ||||||
|  |    * @param   string  $name the browser name | ||||||
|  |    */ | ||||||
|  |   public function setBrowserName($name) | ||||||
|  |   { | ||||||
|  |     $this->browserName = $name; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Get the browser version | ||||||
|  |    * | ||||||
|  |    * @return string the browser version | ||||||
|  |    */ | ||||||
|  |   public function getBrowserVersion() | ||||||
|  |   { | ||||||
|  |     return $this->browserVersion; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Set the browser version | ||||||
|  |    * | ||||||
|  |    * @param   string  $version the browser version | ||||||
|  |    */ | ||||||
|  |   public function setBrowserVersion($version) | ||||||
|  |   { | ||||||
|  |     $this->browserVersion = $version; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Get the operating system name | ||||||
|  |    * | ||||||
|  |    * @return  string the operating system name | ||||||
|  |    */ | ||||||
|  |   public function getOperatingSystem() | ||||||
|  |   { | ||||||
|  |     return $this->operatingSystem; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Set the operating system name | ||||||
|  |    * | ||||||
|  |    * @param   string $operatingSystem the operating system name | ||||||
|  |    */ | ||||||
|  |   public function setOperatingSystem($operatingSystem) | ||||||
|  |   { | ||||||
|  |     $this->operatingSystem = $operatingSystem; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Get the engine name | ||||||
|  |    * | ||||||
|  |    * @return  string the engine name | ||||||
|  |    */ | ||||||
|  |   public function getEngine() | ||||||
|  |   { | ||||||
|  |     return $this->engine; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Set the engine name | ||||||
|  |    * | ||||||
|  |    * @param   string $operatingSystem the engine name | ||||||
|  |    */ | ||||||
|  |   public function setEngine($engine) | ||||||
|  |   { | ||||||
|  |     $this->engine = $engine; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Get the user agent string | ||||||
|  |    * | ||||||
|  |    * @return  string the user agent string | ||||||
|  |    */ | ||||||
|  |   public function getUserAgentString() | ||||||
|  |   { | ||||||
|  |     return $this->userAgentString; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Set the user agent string | ||||||
|  |    * | ||||||
|  |    * @param   string $userAgentString the user agent string | ||||||
|  |    */ | ||||||
|  |   public function setUserAgentString($userAgentString) | ||||||
|  |   { | ||||||
|  |     $this->userAgentString = $userAgentString; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Tell whether this user agent is unknown or not | ||||||
|  |    * | ||||||
|  |    * @return boolean  true if this user agent is unknown, false otherwise | ||||||
|  |    */ | ||||||
|  |   public function isUnknown() | ||||||
|  |   { | ||||||
|  |     return empty($this->browserName); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * @return string combined browser name and version | ||||||
|  |    */ | ||||||
|  |   public function getFullName() | ||||||
|  |   { | ||||||
|  |     return $this->getBrowserName().' '.$this->getBrowserVersion(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function __toString() | ||||||
|  |   { | ||||||
|  |     return $this->getFullName(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Configure the user agent from a user agent string | ||||||
|  |    * @param   string                    $userAgentString        the user agent string | ||||||
|  |    * @param   phpUserAgentStringParser  $userAgentStringParser  the parser used to parse the string | ||||||
|  |    */ | ||||||
|  |   public function configureFromUserAgentString($userAgentString, phpUserAgentStringParser $userAgentStringParser = null) | ||||||
|  |   { | ||||||
|  |     if(null === $userAgentStringParser) | ||||||
|  |     { | ||||||
|  |       $userAgentStringParser = new phpUserAgentStringParser(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $this->setUserAgentString($userAgentString); | ||||||
|  |  | ||||||
|  |     $this->fromArray($userAgentStringParser->parse($userAgentString)); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Convert the user agent to a data array | ||||||
|  |    * | ||||||
|  |    * @return  array data | ||||||
|  |    */ | ||||||
|  |   public function toArray() | ||||||
|  |   { | ||||||
|  |     return array( | ||||||
|  |       'browser_name'      => $this->getBrowserName(), | ||||||
|  |       'browser_version'   => $this->getBrowserVersion(), | ||||||
|  |       'operating_system'  => $this->getOperatingSystem() | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Configure the user agent from a data array | ||||||
|  |    * | ||||||
|  |    * @param array $data | ||||||
|  |    */ | ||||||
|  |   public function fromArray(array $data) | ||||||
|  |   { | ||||||
|  |     $this->setBrowserName($data['browser_name']); | ||||||
|  |     $this->setBrowserVersion($data['browser_version']); | ||||||
|  |     $this->setOperatingSystem($data['operating_system']); | ||||||
|  |     $this->setEngine($data['engine']); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										321
									
								
								vendor/ornicar/php-user-agent/lib/phpUserAgentStringParser.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										321
									
								
								vendor/ornicar/php-user-agent/lib/phpUserAgentStringParser.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,321 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Simple PHP User Agent string parser | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | class phpUserAgentStringParser | ||||||
|  | { | ||||||
|  |   /** | ||||||
|  |    * Parse a user agent string. | ||||||
|  |    * | ||||||
|  |    * @param   string  $userAgentString  defaults to $_SERVER['HTTP_USER_AGENT'] if empty | ||||||
|  |    * @return  array   (                 the user agent informations | ||||||
|  |    *            'browser_name'      => 'firefox', | ||||||
|  |    *            'browser_version'   => '3.6', | ||||||
|  |    *            'operating_system'  => 'linux' | ||||||
|  |    *          ) | ||||||
|  |    */ | ||||||
|  |   public function parse($userAgentString = null) | ||||||
|  |   { | ||||||
|  |     // use current user agent string as default | ||||||
|  |     if(!$userAgentString) | ||||||
|  |     { | ||||||
|  |       $userAgentString = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // parse quickly (with medium accuracy) | ||||||
|  |     $informations = $this->doParse($userAgentString); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     // run some filters to increase accuracy | ||||||
|  |     foreach($this->getFilters() as $filter) | ||||||
|  |     { | ||||||
|  |       $this->$filter($informations); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return $informations; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Detect quickly informations from the user agent string | ||||||
|  |    *  | ||||||
|  |    * @param   string $userAgentString   user agent string | ||||||
|  |    * @return  array                     user agent informations array | ||||||
|  |    */ | ||||||
|  |   protected function doParse($userAgentString) | ||||||
|  |   { | ||||||
|  |     $userAgent = array( | ||||||
|  |       'string'            => $this->cleanUserAgentString($userAgentString), | ||||||
|  |       'browser_name'      => null, | ||||||
|  |       'browser_version'   => null, | ||||||
|  |       'operating_system'  => null, | ||||||
|  |       'engine'            => null | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     if(empty($userAgent['string'])) | ||||||
|  |     { | ||||||
|  |       return $userAgent; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // build regex that matches phrases for known browsers | ||||||
|  |     // (e.g. "Firefox/2.0" or "MSIE 6.0" (This only matches the major and minor | ||||||
|  |     // version numbers.  E.g. "2.0.0.6" is parsed as simply "2.0" | ||||||
|  |     $pattern = '#('.join('|', $this->getKnownBrowsers()).')[/ ]+([0-9]+(?:\.[0-9]+)?)#'; | ||||||
|  |  | ||||||
|  |     // Find all phrases (or return empty array if none found) | ||||||
|  |     if (preg_match_all($pattern, $userAgent['string'], $matches)) | ||||||
|  |     { | ||||||
|  |       // Since some UAs have more than one phrase (e.g Firefox has a Gecko phrase, | ||||||
|  |       // Opera 7,8 have a MSIE phrase), use the last one found (the right-most one | ||||||
|  |       // in the UA).  That's usually the most correct. | ||||||
|  |       $i = count($matches[1])-1; | ||||||
|  |  | ||||||
|  |       if (isset($matches[1][$i])) | ||||||
|  |       { | ||||||
|  |         $userAgent['browser_name'] = $matches[1][$i]; | ||||||
|  |       } | ||||||
|  |       if (isset($matches[2][$i])) | ||||||
|  |       { | ||||||
|  |         $userAgent['browser_version'] = $matches[2][$i]; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Find operating system | ||||||
|  |     $pattern = '#'.join('|', $this->getKnownOperatingSystems()).'#'; | ||||||
|  |      | ||||||
|  |     if (preg_match($pattern, $userAgent['string'], $match)) | ||||||
|  |     { | ||||||
|  |       if (isset($match[0])) | ||||||
|  |       { | ||||||
|  |         $userAgent['operating_system'] = $match[0]; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Find engine | ||||||
|  |     $pattern = '#'.join('|', $this->getKnownEngines()).'#'; | ||||||
|  |      | ||||||
|  |     if (preg_match($pattern, $userAgent['string'], $match)) | ||||||
|  |     { | ||||||
|  |       if (isset($match[0])) | ||||||
|  |       { | ||||||
|  |         $userAgent['engine'] = $match[0]; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return $userAgent; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Make user agent string lowercase, and replace browser aliases | ||||||
|  |    * | ||||||
|  |    * @param   string $userAgentString the dirty user agent string | ||||||
|  |    * @return  string                  the clean user agent string | ||||||
|  |    */ | ||||||
|  |   public function cleanUserAgentString($userAgentString) | ||||||
|  |   { | ||||||
|  |     // clean up the string | ||||||
|  |     $userAgentString = trim(strtolower($userAgentString)); | ||||||
|  |  | ||||||
|  |     // replace browser names with their aliases | ||||||
|  |     $userAgentString = strtr($userAgentString, $this->getKnownBrowserAliases()); | ||||||
|  |  | ||||||
|  |     // replace operating system names with their aliases | ||||||
|  |     $userAgentString = strtr($userAgentString, $this->getKnownOperatingSystemAliases()); | ||||||
|  |  | ||||||
|  |     // replace engine names with their aliases | ||||||
|  |     $userAgentString = strtr($userAgentString, $this->getKnownEngineAliases()); | ||||||
|  |  | ||||||
|  |     return $userAgentString; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Get the list of filters that get called when parsing a user agent | ||||||
|  |    * | ||||||
|  |    * @return  array list of valid callables | ||||||
|  |    */ | ||||||
|  |   public function getFilters() | ||||||
|  |   { | ||||||
|  |     return array( | ||||||
|  |       'filterAndroid', | ||||||
|  |       'filterGoogleChrome', | ||||||
|  |       'filterSafariVersion', | ||||||
|  |       'filterOperaVersion', | ||||||
|  |       'filterYahoo', | ||||||
|  |       'filterMsie', | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Add a filter to be called when parsing a user agent | ||||||
|  |    *  | ||||||
|  |    * @param   string $filter name of the filter method | ||||||
|  |    */ | ||||||
|  |   public function addFilter($filter) | ||||||
|  |   { | ||||||
|  |     $this->filters += $filter; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Get known browsers | ||||||
|  |    * | ||||||
|  |    * @return  array the browsers | ||||||
|  |    */ | ||||||
|  |   protected function getKnownBrowsers() | ||||||
|  |   { | ||||||
|  |     return array( | ||||||
|  |       'msie', | ||||||
|  |       'firefox', | ||||||
|  |       'safari', | ||||||
|  |       'webkit', | ||||||
|  |       'opera', | ||||||
|  |       'netscape', | ||||||
|  |       'konqueror', | ||||||
|  |       'gecko', | ||||||
|  |       'chrome', | ||||||
|  |       'googlebot', | ||||||
|  |       'iphone', | ||||||
|  |       'msnbot', | ||||||
|  |       'applewebkit' | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Get known browser aliases | ||||||
|  |    * | ||||||
|  |    * @return  array the browser aliases | ||||||
|  |    */ | ||||||
|  |   protected function getKnownBrowserAliases() | ||||||
|  |   { | ||||||
|  |     return array( | ||||||
|  |       'shiretoko'     => 'firefox', | ||||||
|  |       'namoroka'      => 'firefox', | ||||||
|  |       'shredder'      => 'firefox', | ||||||
|  |       'minefield'     => 'firefox', | ||||||
|  |       'granparadiso'  => 'firefox' | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Get known operating system | ||||||
|  |    * | ||||||
|  |    * @return  array the operating systems | ||||||
|  |    */ | ||||||
|  |   protected function getKnownOperatingSystems() | ||||||
|  |   { | ||||||
|  |     return array( | ||||||
|  |       'windows', | ||||||
|  |       'macintosh', | ||||||
|  |       'linux', | ||||||
|  |       'freebsd', | ||||||
|  |       'unix', | ||||||
|  |       'iphone' | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Get known operating system aliases | ||||||
|  |    * | ||||||
|  |    * @return  array the operating system aliases | ||||||
|  |    */ | ||||||
|  |   protected function getKnownOperatingSystemAliases() | ||||||
|  |   { | ||||||
|  |     return array(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Get known engines | ||||||
|  |    * | ||||||
|  |    * @return  array the engines | ||||||
|  |    */ | ||||||
|  |   protected function getKnownEngines() | ||||||
|  |   { | ||||||
|  |     return array( | ||||||
|  |       'gecko', | ||||||
|  |       'webkit', | ||||||
|  |       'trident', | ||||||
|  |       'presto' | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Get known engines aliases | ||||||
|  |    * | ||||||
|  |    * @return  array the engines aliases | ||||||
|  |    */ | ||||||
|  |   protected function getKnownEngineAliases() | ||||||
|  |   { | ||||||
|  |     return array(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Filters | ||||||
|  |    */ | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Google chrome has a safari like signature | ||||||
|  |    */ | ||||||
|  |   protected function filterGoogleChrome(array &$userAgent) | ||||||
|  |   { | ||||||
|  |     if ('safari' === $userAgent['browser_name'] && strpos($userAgent['string'], 'chrome/')) | ||||||
|  |     { | ||||||
|  |       $userAgent['browser_name'] = 'chrome'; | ||||||
|  |       $userAgent['browser_version'] = preg_replace('|.+chrome/([0-9]+(?:\.[0-9]+)?).+|', '$1', $userAgent['string']); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Safari version is not encoded "normally" | ||||||
|  |    */ | ||||||
|  |   protected function filterSafariVersion(array &$userAgent) | ||||||
|  |   { | ||||||
|  |     if ('safari' === $userAgent['browser_name'] && strpos($userAgent['string'], ' version/')) | ||||||
|  |     { | ||||||
|  |       $userAgent['browser_version'] = preg_replace('|.+\sversion/([0-9]+(?:\.[0-9]+)?).+|', '$1', $userAgent['string']); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Opera 10.00 (and higher) version number is located at the end | ||||||
|  |    */ | ||||||
|  |   protected function filterOperaVersion(array &$userAgent) | ||||||
|  |   { | ||||||
|  |     if('opera' === $userAgent['browser_name'] && strpos($userAgent['string'], ' version/')) | ||||||
|  |     { | ||||||
|  |       $userAgent['browser_version'] = preg_replace('|.+\sversion/([0-9]+\.[0-9]+)\s*.*|', '$1', $userAgent['string']); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Yahoo bot has a special user agent string | ||||||
|  |    */ | ||||||
|  |   protected function filterYahoo(array &$userAgent) | ||||||
|  |   { | ||||||
|  |     if (null === $userAgent['browser_name'] && strpos($userAgent['string'], 'yahoo! slurp')) | ||||||
|  |     { | ||||||
|  |       $userAgent['browser_name'] = 'yahoobot'; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * MSIE does not always declare its engine | ||||||
|  |    */ | ||||||
|  |   protected function filterMsie(array &$userAgent) | ||||||
|  |   { | ||||||
|  |     if ('msie' === $userAgent['browser_name'] && empty($userAgent['engine'])) | ||||||
|  |     { | ||||||
|  |       $userAgent['engine'] = 'trident'; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Android has a safari like signature | ||||||
|  |      */ | ||||||
|  |     protected function filterAndroid(array &$userAgent) { | ||||||
|  |         if ('safari' === $userAgent['browser_name'] && strpos($userAgent['string'], 'android ')) { | ||||||
|  |             $userAgent['browser_name'] = 'android'; | ||||||
|  |             $userAgent['operating_system'] = 'android'; | ||||||
|  |             $userAgent['browser_version'] = preg_replace('|.+android ([0-9]+(?:\.[0-9]+)+).+|', '$1', $userAgent['string']); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -215,7 +215,11 @@ class OutputFormatter implements OutputFormatterInterface | |||||||
|             } elseif ('bg' == $match[0]) { |             } elseif ('bg' == $match[0]) { | ||||||
|                 $style->setBackground($match[1]); |                 $style->setBackground($match[1]); | ||||||
|             } else { |             } else { | ||||||
|                 $style->setOption($match[1]); |                 try { | ||||||
|  |                     $style->setOption($match[1]); | ||||||
|  |                 } catch (\InvalidArgumentException $e) { | ||||||
|  |                     return false; | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										39
									
								
								vendor/tracy/tracy/src/Tracy/Debugger.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										39
									
								
								vendor/tracy/tracy/src/Tracy/Debugger.php
									
									
									
									
										vendored
									
									
								
							| @@ -23,6 +23,8 @@ class Debugger | |||||||
| 		PRODUCTION = TRUE, | 		PRODUCTION = TRUE, | ||||||
| 		DETECT = NULL; | 		DETECT = NULL; | ||||||
|  |  | ||||||
|  | 	const COOKIE_SECRET = 'tracy-debug'; | ||||||
|  |  | ||||||
| 	/** @var string */ | 	/** @var string */ | ||||||
| 	public static $version = '2.3-dev'; | 	public static $version = '2.3-dev'; | ||||||
|  |  | ||||||
| @@ -126,18 +128,7 @@ class Debugger | |||||||
| 		self::$time = isset($_SERVER['REQUEST_TIME_FLOAT']) ? $_SERVER['REQUEST_TIME_FLOAT'] : microtime(TRUE); | 		self::$time = isset($_SERVER['REQUEST_TIME_FLOAT']) ? $_SERVER['REQUEST_TIME_FLOAT'] : microtime(TRUE); | ||||||
| 		error_reporting(E_ALL | E_STRICT); | 		error_reporting(E_ALL | E_STRICT); | ||||||
|  |  | ||||||
| 		// production/development mode detection | 		self::$productionMode = is_bool($mode) ? $mode : !self::detectDebugMode($mode); | ||||||
| 		if (is_bool($mode)) { |  | ||||||
| 			self::$productionMode = $mode; |  | ||||||
|  |  | ||||||
| 		} elseif ($mode !== self::DETECT || self::$productionMode === NULL) { // IP addresses or computer names whitelist detection |  | ||||||
| 			$list = is_string($mode) ? preg_split('#[,\s]+#', $mode) : (array) $mode; |  | ||||||
| 			if (!isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { |  | ||||||
| 				$list[] = '127.0.0.1'; |  | ||||||
| 				$list[] = '::1'; |  | ||||||
| 			} |  | ||||||
| 			self::$productionMode = !in_array(isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : php_uname('n'), $list, TRUE); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// logging configuration | 		// logging configuration | ||||||
| 		if ($email !== NULL) { | 		if ($email !== NULL) { | ||||||
| @@ -518,4 +509,28 @@ class Debugger | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Detects debug mode by IP address. | ||||||
|  | 	 * @param  string|array  IP addresses or computer names whitelist detection | ||||||
|  | 	 * @return bool | ||||||
|  | 	 */ | ||||||
|  | 	public static function detectDebugMode($list = NULL) | ||||||
|  | 	{ | ||||||
|  | 		$addr = isset($_SERVER['REMOTE_ADDR']) | ||||||
|  | 			? $_SERVER['REMOTE_ADDR'] | ||||||
|  | 			: php_uname('n'); | ||||||
|  | 		$secret = isset($_COOKIE[self::COOKIE_SECRET]) && is_string($_COOKIE[self::COOKIE_SECRET]) | ||||||
|  | 			? $_COOKIE[self::COOKIE_SECRET] | ||||||
|  | 			: NULL; | ||||||
|  | 		$list = is_string($list) | ||||||
|  | 			? preg_split('#[,\s]+#', $list) | ||||||
|  | 			: (array) $list; | ||||||
|  | 		if (!isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { | ||||||
|  | 			$list[] = '127.0.0.1'; | ||||||
|  | 			$list[] = '::1'; | ||||||
|  | 		} | ||||||
|  | 		return in_array($addr, $list, TRUE) || in_array("$secret@$addr", $list, TRUE); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user