first commit
This commit is contained in:
		
							
								
								
									
										18
									
								
								vendor/matthiasmullie/minify/LICENSE
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								vendor/matthiasmullie/minify/LICENSE
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| Copyright (c) 2012 Matthias Mullie | ||||
|  | ||||
| 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. | ||||
							
								
								
									
										7
									
								
								vendor/matthiasmullie/minify/data/js/keywords_after.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								vendor/matthiasmullie/minify/data/js/keywords_after.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| in | ||||
| public | ||||
| extends | ||||
| private | ||||
| protected | ||||
| implements | ||||
| instanceof | ||||
							
								
								
									
										26
									
								
								vendor/matthiasmullie/minify/data/js/keywords_before.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								vendor/matthiasmullie/minify/data/js/keywords_before.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| do | ||||
| in | ||||
| let | ||||
| new | ||||
| var | ||||
| case | ||||
| else | ||||
| enum | ||||
| void | ||||
| with | ||||
| class | ||||
| const | ||||
| yield | ||||
| delete | ||||
| export | ||||
| import | ||||
| public | ||||
| static | ||||
| typeof | ||||
| extends | ||||
| package | ||||
| private | ||||
| function | ||||
| protected | ||||
| implements | ||||
| instanceof | ||||
							
								
								
									
										63
									
								
								vendor/matthiasmullie/minify/data/js/keywords_reserved.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								vendor/matthiasmullie/minify/data/js/keywords_reserved.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | ||||
| do | ||||
| if | ||||
| in | ||||
| for | ||||
| let | ||||
| new | ||||
| try | ||||
| var | ||||
| case | ||||
| else | ||||
| enum | ||||
| eval | ||||
| null | ||||
| this | ||||
| true | ||||
| void | ||||
| with | ||||
| break | ||||
| catch | ||||
| class | ||||
| const | ||||
| false | ||||
| super | ||||
| throw | ||||
| while | ||||
| yield | ||||
| delete | ||||
| export | ||||
| import | ||||
| public | ||||
| return | ||||
| static | ||||
| switch | ||||
| typeof | ||||
| default | ||||
| extends | ||||
| finally | ||||
| package | ||||
| private | ||||
| continue | ||||
| debugger | ||||
| function | ||||
| arguments | ||||
| interface | ||||
| protected | ||||
| implements | ||||
| instanceof | ||||
| abstract | ||||
| boolean | ||||
| byte | ||||
| char | ||||
| double | ||||
| final | ||||
| float | ||||
| goto | ||||
| int | ||||
| long | ||||
| native | ||||
| short | ||||
| synchronized | ||||
| throws | ||||
| transient | ||||
| volatile | ||||
							
								
								
									
										46
									
								
								vendor/matthiasmullie/minify/data/js/operators.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								vendor/matthiasmullie/minify/data/js/operators.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| + | ||||
| - | ||||
| * | ||||
| / | ||||
| % | ||||
| = | ||||
| += | ||||
| -= | ||||
| *= | ||||
| /= | ||||
| %= | ||||
| <<= | ||||
| >>= | ||||
| >>>= | ||||
| &= | ||||
| ^= | ||||
| |= | ||||
| & | ||||
| | | ||||
| ^ | ||||
| ~ | ||||
| << | ||||
| >> | ||||
| >>> | ||||
| == | ||||
| === | ||||
| != | ||||
| !== | ||||
| > | ||||
| < | ||||
| >= | ||||
| <= | ||||
| && | ||||
| || | ||||
| ! | ||||
| . | ||||
| [ | ||||
| ] | ||||
| ? | ||||
| : | ||||
| , | ||||
| ; | ||||
| ( | ||||
| ) | ||||
| { | ||||
| } | ||||
							
								
								
									
										43
									
								
								vendor/matthiasmullie/minify/data/js/operators_after.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								vendor/matthiasmullie/minify/data/js/operators_after.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| + | ||||
| - | ||||
| * | ||||
| / | ||||
| % | ||||
| = | ||||
| += | ||||
| -= | ||||
| *= | ||||
| /= | ||||
| %= | ||||
| <<= | ||||
| >>= | ||||
| >>>= | ||||
| &= | ||||
| ^= | ||||
| |= | ||||
| & | ||||
| | | ||||
| ^ | ||||
| << | ||||
| >> | ||||
| >>> | ||||
| == | ||||
| === | ||||
| != | ||||
| !== | ||||
| > | ||||
| < | ||||
| >= | ||||
| <= | ||||
| && | ||||
| || | ||||
| . | ||||
| [ | ||||
| ] | ||||
| ? | ||||
| : | ||||
| , | ||||
| ; | ||||
| ( | ||||
| ) | ||||
| } | ||||
							
								
								
									
										43
									
								
								vendor/matthiasmullie/minify/data/js/operators_before.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								vendor/matthiasmullie/minify/data/js/operators_before.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| + | ||||
| - | ||||
| * | ||||
| / | ||||
| % | ||||
| = | ||||
| += | ||||
| -= | ||||
| *= | ||||
| /= | ||||
| %= | ||||
| <<= | ||||
| >>= | ||||
| >>>= | ||||
| &= | ||||
| ^= | ||||
| |= | ||||
| & | ||||
| | | ||||
| ^ | ||||
| ~ | ||||
| << | ||||
| >> | ||||
| >>> | ||||
| == | ||||
| === | ||||
| != | ||||
| !== | ||||
| > | ||||
| < | ||||
| >= | ||||
| <= | ||||
| && | ||||
| || | ||||
| ! | ||||
| . | ||||
| [ | ||||
| ? | ||||
| : | ||||
| , | ||||
| ; | ||||
| ( | ||||
| { | ||||
							
								
								
									
										752
									
								
								vendor/matthiasmullie/minify/src/CSS.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										752
									
								
								vendor/matthiasmullie/minify/src/CSS.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,752 @@ | ||||
| <?php | ||||
| /** | ||||
|  * CSS Minifier | ||||
|  * | ||||
|  * Please report bugs on https://github.com/matthiasmullie/minify/issues | ||||
|  * | ||||
|  * @author Matthias Mullie <minify@mullie.eu> | ||||
|  * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved | ||||
|  * @license MIT License | ||||
|  */ | ||||
|  | ||||
| namespace MatthiasMullie\Minify; | ||||
|  | ||||
| use MatthiasMullie\Minify\Exceptions\FileImportException; | ||||
| use MatthiasMullie\PathConverter\ConverterInterface; | ||||
| use MatthiasMullie\PathConverter\Converter; | ||||
|  | ||||
| /** | ||||
|  * CSS minifier | ||||
|  * | ||||
|  * Please report bugs on https://github.com/matthiasmullie/minify/issues | ||||
|  * | ||||
|  * @package Minify | ||||
|  * @author Matthias Mullie <minify@mullie.eu> | ||||
|  * @author Tijs Verkoyen <minify@verkoyen.eu> | ||||
|  * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved | ||||
|  * @license MIT License | ||||
|  */ | ||||
| class CSS extends Minify | ||||
| { | ||||
|     /** | ||||
|      * @var int maximum inport size in kB | ||||
|      */ | ||||
|     protected $maxImportSize = 5; | ||||
|  | ||||
|     /** | ||||
|      * @var string[] valid import extensions | ||||
|      */ | ||||
|     protected $importExtensions = array( | ||||
|         'gif' => 'data:image/gif', | ||||
|         'png' => 'data:image/png', | ||||
|         'jpe' => 'data:image/jpeg', | ||||
|         'jpg' => 'data:image/jpeg', | ||||
|         'jpeg' => 'data:image/jpeg', | ||||
|         'svg' => 'data:image/svg+xml', | ||||
|         'woff' => 'data:application/x-font-woff', | ||||
|         'tif' => 'image/tiff', | ||||
|         'tiff' => 'image/tiff', | ||||
|         'xbm' => 'image/x-xbitmap', | ||||
|     ); | ||||
|  | ||||
|     /** | ||||
|      * Set the maximum size if files to be imported. | ||||
|      * | ||||
|      * Files larger than this size (in kB) will not be imported into the CSS. | ||||
|      * Importing files into the CSS as data-uri will save you some connections, | ||||
|      * but we should only import relatively small decorative images so that our | ||||
|      * CSS file doesn't get too bulky. | ||||
|      * | ||||
|      * @param int $size Size in kB | ||||
|      */ | ||||
|     public function setMaxImportSize($size) | ||||
|     { | ||||
|         $this->maxImportSize = $size; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Set the type of extensions to be imported into the CSS (to save network | ||||
|      * connections). | ||||
|      * Keys of the array should be the file extensions & respective values | ||||
|      * should be the data type. | ||||
|      * | ||||
|      * @param string[] $extensions Array of file extensions | ||||
|      */ | ||||
|     public function setImportExtensions(array $extensions) | ||||
|     { | ||||
|         $this->importExtensions = $extensions; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Move any import statements to the top. | ||||
|      * | ||||
|      * @param string $content Nearly finished CSS content | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     protected function moveImportsToTop($content) | ||||
|     { | ||||
|         if (preg_match_all('/(;?)(@import (?<url>url\()?(?P<quotes>["\']?).+?(?P=quotes)(?(url)\)));?/', $content, $matches)) { | ||||
|             // remove from content | ||||
|             foreach ($matches[0] as $import) { | ||||
|                 $content = str_replace($import, '', $content); | ||||
|             } | ||||
|  | ||||
|             // add to top | ||||
|             $content = implode(';', $matches[2]).';'.trim($content, ';'); | ||||
|         } | ||||
|  | ||||
|         return $content; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Combine CSS from import statements. | ||||
|      * | ||||
|      * @import's will be loaded and their content merged into the original file, | ||||
|      * to save HTTP requests. | ||||
|      * | ||||
|      * @param string   $source  The file to combine imports for | ||||
|      * @param string   $content The CSS content to combine imports for | ||||
|      * @param string[] $parents Parent paths, for circular reference checks | ||||
|      * | ||||
|      * @return string | ||||
|      * | ||||
|      * @throws FileImportException | ||||
|      */ | ||||
|     protected function combineImports($source, $content, $parents) | ||||
|     { | ||||
|         $importRegexes = array( | ||||
|             // @import url(xxx) | ||||
|             '/ | ||||
|             # import statement | ||||
|             @import | ||||
|  | ||||
|             # whitespace | ||||
|             \s+ | ||||
|  | ||||
|                 # open url() | ||||
|                 url\( | ||||
|  | ||||
|                     # (optional) open path enclosure | ||||
|                     (?P<quotes>["\']?) | ||||
|  | ||||
|                         # fetch path | ||||
|                         (?P<path>.+?) | ||||
|  | ||||
|                     # (optional) close path enclosure | ||||
|                     (?P=quotes) | ||||
|  | ||||
|                 # close url() | ||||
|                 \) | ||||
|  | ||||
|                 # (optional) trailing whitespace | ||||
|                 \s* | ||||
|  | ||||
|                 # (optional) media statement(s) | ||||
|                 (?P<media>[^;]*) | ||||
|  | ||||
|                 # (optional) trailing whitespace | ||||
|                 \s* | ||||
|  | ||||
|             # (optional) closing semi-colon | ||||
|             ;? | ||||
|  | ||||
|             /ix', | ||||
|  | ||||
|             // @import 'xxx' | ||||
|             '/ | ||||
|  | ||||
|             # import statement | ||||
|             @import | ||||
|  | ||||
|             # whitespace | ||||
|             \s+ | ||||
|  | ||||
|                 # open path enclosure | ||||
|                 (?P<quotes>["\']) | ||||
|  | ||||
|                     # fetch path | ||||
|                     (?P<path>.+?) | ||||
|  | ||||
|                 # close path enclosure | ||||
|                 (?P=quotes) | ||||
|  | ||||
|                 # (optional) trailing whitespace | ||||
|                 \s* | ||||
|  | ||||
|                 # (optional) media statement(s) | ||||
|                 (?P<media>[^;]*) | ||||
|  | ||||
|                 # (optional) trailing whitespace | ||||
|                 \s* | ||||
|  | ||||
|             # (optional) closing semi-colon | ||||
|             ;? | ||||
|  | ||||
|             /ix', | ||||
|         ); | ||||
|  | ||||
|         // find all relative imports in css | ||||
|         $matches = array(); | ||||
|         foreach ($importRegexes as $importRegex) { | ||||
|             if (preg_match_all($importRegex, $content, $regexMatches, PREG_SET_ORDER)) { | ||||
|                 $matches = array_merge($matches, $regexMatches); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         $search = array(); | ||||
|         $replace = array(); | ||||
|  | ||||
|         // loop the matches | ||||
|         foreach ($matches as $match) { | ||||
|             // get the path for the file that will be imported | ||||
|             $importPath = dirname($source).'/'.$match['path']; | ||||
|  | ||||
|             // only replace the import with the content if we can grab the | ||||
|             // content of the file | ||||
|             if (!$this->canImportByPath($match['path']) || !$this->canImportFile($importPath)) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             // check if current file was not imported previously in the same | ||||
|             // import chain. | ||||
|             if (in_array($importPath, $parents)) { | ||||
|                 throw new FileImportException('Failed to import file "'.$importPath.'": circular reference detected.'); | ||||
|             } | ||||
|  | ||||
|             // grab referenced file & minify it (which may include importing | ||||
|             // yet other @import statements recursively) | ||||
|             $minifier = new static($importPath); | ||||
|             $minifier->setMaxImportSize($this->maxImportSize); | ||||
|             $minifier->setImportExtensions($this->importExtensions); | ||||
|             $importContent = $minifier->execute($source, $parents); | ||||
|  | ||||
|             // check if this is only valid for certain media | ||||
|             if (!empty($match['media'])) { | ||||
|                 $importContent = '@media '.$match['media'].'{'.$importContent.'}'; | ||||
|             } | ||||
|  | ||||
|             // add to replacement array | ||||
|             $search[] = $match[0]; | ||||
|             $replace[] = $importContent; | ||||
|         } | ||||
|  | ||||
|         // replace the import statements | ||||
|         return str_replace($search, $replace, $content); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Import files into the CSS, base64-ized. | ||||
|      * | ||||
|      * @url(image.jpg) images will be loaded and their content merged into the | ||||
|      * original file, to save HTTP requests. | ||||
|      * | ||||
|      * @param string $source  The file to import files for | ||||
|      * @param string $content The CSS content to import files for | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     protected function importFiles($source, $content) | ||||
|     { | ||||
|         $regex = '/url\((["\']?)(.+?)\\1\)/i'; | ||||
|         if ($this->importExtensions && preg_match_all($regex, $content, $matches, PREG_SET_ORDER)) { | ||||
|             $search = array(); | ||||
|             $replace = array(); | ||||
|  | ||||
|             // loop the matches | ||||
|             foreach ($matches as $match) { | ||||
|                 $extension = substr(strrchr($match[2], '.'), 1); | ||||
|                 if ($extension && !array_key_exists($extension, $this->importExtensions)) { | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|                 // get the path for the file that will be imported | ||||
|                 $path = $match[2]; | ||||
|                 $path = dirname($source).'/'.$path; | ||||
|  | ||||
|                 // only replace the import with the content if we're able to get | ||||
|                 // the content of the file, and it's relatively small | ||||
|                 if ($this->canImportFile($path) && $this->canImportBySize($path)) { | ||||
|                     // grab content && base64-ize | ||||
|                     $importContent = $this->load($path); | ||||
|                     $importContent = base64_encode($importContent); | ||||
|  | ||||
|                     // build replacement | ||||
|                     $search[] = $match[0]; | ||||
|                     $replace[] = 'url('.$this->importExtensions[$extension].';base64,'.$importContent.')'; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             // replace the import statements | ||||
|             $content = str_replace($search, $replace, $content); | ||||
|         } | ||||
|  | ||||
|         return $content; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Minify the data. | ||||
|      * Perform CSS optimizations. | ||||
|      * | ||||
|      * @param string[optional] $path    Path to write the data to | ||||
|      * @param string[]         $parents Parent paths, for circular reference checks | ||||
|      * | ||||
|      * @return string The minified data | ||||
|      */ | ||||
|     public function execute($path = null, $parents = array()) | ||||
|     { | ||||
|         $content = ''; | ||||
|  | ||||
|         // loop CSS data (raw data and files) | ||||
|         foreach ($this->data as $source => $css) { | ||||
|             /* | ||||
|              * Let's first take out strings & comments, since we can't just | ||||
|              * remove whitespace anywhere. If whitespace occurs inside a string, | ||||
|              * we should leave it alone. E.g.: | ||||
|              * p { content: "a   test" } | ||||
|              */ | ||||
|             $this->extractStrings(); | ||||
|             $this->stripComments(); | ||||
|             $this->extractCalcs(); | ||||
|             $css = $this->replace($css); | ||||
|  | ||||
|             $css = $this->stripWhitespace($css); | ||||
|             $css = $this->shortenColors($css); | ||||
|             $css = $this->shortenZeroes($css); | ||||
|             $css = $this->shortenFontWeights($css); | ||||
|             $css = $this->stripEmptyTags($css); | ||||
|  | ||||
|             // restore the string we've extracted earlier | ||||
|             $css = $this->restoreExtractedData($css); | ||||
|  | ||||
|             $source = is_int($source) ? '' : $source; | ||||
|             $parents = $source ? array_merge($parents, array($source)) : $parents; | ||||
|             $css = $this->combineImports($source, $css, $parents); | ||||
|             $css = $this->importFiles($source, $css); | ||||
|  | ||||
|             /* | ||||
|              * If we'll save to a new path, we'll have to fix the relative paths | ||||
|              * to be relative no longer to the source file, but to the new path. | ||||
|              * If we don't write to a file, fall back to same path so no | ||||
|              * conversion happens (because we still want it to go through most | ||||
|              * of the move code, which also addresses url() & @import syntax...) | ||||
|              */ | ||||
|             $converter = $this->getPathConverter($source, $path ?: $source); | ||||
|             $css = $this->move($converter, $css); | ||||
|  | ||||
|             // combine css | ||||
|             $content .= $css; | ||||
|         } | ||||
|  | ||||
|         $content = $this->moveImportsToTop($content); | ||||
|  | ||||
|         return $content; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Moving a css file should update all relative urls. | ||||
|      * Relative references (e.g. ../images/image.gif) in a certain css file, | ||||
|      * will have to be updated when a file is being saved at another location | ||||
|      * (e.g. ../../images/image.gif, if the new CSS file is 1 folder deeper). | ||||
|      * | ||||
|      * @param ConverterInterface $converter Relative path converter | ||||
|      * @param string             $content   The CSS content to update relative urls for | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     protected function move(ConverterInterface $converter, $content) | ||||
|     { | ||||
|         /* | ||||
|          * Relative path references will usually be enclosed by url(). @import | ||||
|          * is an exception, where url() is not necessary around the path (but is | ||||
|          * allowed). | ||||
|          * This *could* be 1 regular expression, where both regular expressions | ||||
|          * in this array are on different sides of a |. But we're using named | ||||
|          * patterns in both regexes, the same name on both regexes. This is only | ||||
|          * possible with a (?J) modifier, but that only works after a fairly | ||||
|          * recent PCRE version. That's why I'm doing 2 separate regular | ||||
|          * expressions & combining the matches after executing of both. | ||||
|          */ | ||||
|         $relativeRegexes = array( | ||||
|             // url(xxx) | ||||
|             '/ | ||||
|             # open url() | ||||
|             url\( | ||||
|  | ||||
|                 \s* | ||||
|  | ||||
|                 # open path enclosure | ||||
|                 (?P<quotes>["\'])? | ||||
|  | ||||
|                     # fetch path | ||||
|                     (?P<path>.+?) | ||||
|  | ||||
|                 # close path enclosure | ||||
|                 (?(quotes)(?P=quotes)) | ||||
|  | ||||
|                 \s* | ||||
|  | ||||
|             # close url() | ||||
|             \) | ||||
|  | ||||
|             /ix', | ||||
|  | ||||
|             // @import "xxx" | ||||
|             '/ | ||||
|             # import statement | ||||
|             @import | ||||
|  | ||||
|             # whitespace | ||||
|             \s+ | ||||
|  | ||||
|                 # we don\'t have to check for @import url(), because the | ||||
|                 # condition above will already catch these | ||||
|  | ||||
|                 # open path enclosure | ||||
|                 (?P<quotes>["\']) | ||||
|  | ||||
|                     # fetch path | ||||
|                     (?P<path>.+?) | ||||
|  | ||||
|                 # close path enclosure | ||||
|                 (?P=quotes) | ||||
|  | ||||
|             /ix', | ||||
|         ); | ||||
|  | ||||
|         // find all relative urls in css | ||||
|         $matches = array(); | ||||
|         foreach ($relativeRegexes as $relativeRegex) { | ||||
|             if (preg_match_all($relativeRegex, $content, $regexMatches, PREG_SET_ORDER)) { | ||||
|                 $matches = array_merge($matches, $regexMatches); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         $search = array(); | ||||
|         $replace = array(); | ||||
|  | ||||
|         // loop all urls | ||||
|         foreach ($matches as $match) { | ||||
|             // determine if it's a url() or an @import match | ||||
|             $type = (strpos($match[0], '@import') === 0 ? 'import' : 'url'); | ||||
|  | ||||
|             $url = $match['path']; | ||||
|             if ($this->canImportByPath($url)) { | ||||
|                 // attempting to interpret GET-params makes no sense, so let's discard them for awhile | ||||
|                 $params = strrchr($url, '?'); | ||||
|                 $url = $params ? substr($url, 0, -strlen($params)) : $url; | ||||
|  | ||||
|                 // fix relative url | ||||
|                 $url = $converter->convert($url); | ||||
|  | ||||
|                 // now that the path has been converted, re-apply GET-params | ||||
|                 $url .= $params; | ||||
|             } | ||||
|  | ||||
|             /* | ||||
|              * Urls with control characters above 0x7e should be quoted. | ||||
|              * According to Mozilla's parser, whitespace is only allowed at the | ||||
|              * end of unquoted urls. | ||||
|              * Urls with `)` (as could happen with data: uris) should also be | ||||
|              * quoted to avoid being confused for the url() closing parentheses. | ||||
|              * And urls with a # have also been reported to cause issues. | ||||
|              * Urls with quotes inside should also remain escaped. | ||||
|              * | ||||
|              * @see https://developer.mozilla.org/nl/docs/Web/CSS/url#The_url()_functional_notation | ||||
|              * @see https://hg.mozilla.org/mozilla-central/rev/14abca4e7378 | ||||
|              * @see https://github.com/matthiasmullie/minify/issues/193 | ||||
|              */ | ||||
|             $url = trim($url); | ||||
|             if (preg_match('/[\s\)\'"#\x{7f}-\x{9f}]/u', $url)) { | ||||
|                 $url = $match['quotes'] . $url . $match['quotes']; | ||||
|             } | ||||
|  | ||||
|             // build replacement | ||||
|             $search[] = $match[0]; | ||||
|             if ($type === 'url') { | ||||
|                 $replace[] = 'url('.$url.')'; | ||||
|             } elseif ($type === 'import') { | ||||
|                 $replace[] = '@import "'.$url.'"'; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // replace urls | ||||
|         return str_replace($search, $replace, $content); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Shorthand hex color codes. | ||||
|      * #FF0000 -> #F00. | ||||
|      * | ||||
|      * @param string $content The CSS content to shorten the hex color codes for | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     protected function shortenColors($content) | ||||
|     { | ||||
|         $content = preg_replace('/(?<=[: ])#([0-9a-z])\\1([0-9a-z])\\2([0-9a-z])\\3(?:([0-9a-z])\\4)?(?=[; }])/i', '#$1$2$3$4', $content); | ||||
|  | ||||
|         // remove alpha channel if it's pointless... | ||||
|         $content = preg_replace('/(?<=[: ])#([0-9a-z]{6})ff?(?=[; }])/i', '#$1', $content); | ||||
|         $content = preg_replace('/(?<=[: ])#([0-9a-z]{3})f?(?=[; }])/i', '#$1', $content); | ||||
|  | ||||
|         $colors = array( | ||||
|             // we can shorten some even more by replacing them with their color name | ||||
|             '#F0FFFF' => 'azure', | ||||
|             '#F5F5DC' => 'beige', | ||||
|             '#A52A2A' => 'brown', | ||||
|             '#FF7F50' => 'coral', | ||||
|             '#FFD700' => 'gold', | ||||
|             '#808080' => 'gray', | ||||
|             '#008000' => 'green', | ||||
|             '#4B0082' => 'indigo', | ||||
|             '#FFFFF0' => 'ivory', | ||||
|             '#F0E68C' => 'khaki', | ||||
|             '#FAF0E6' => 'linen', | ||||
|             '#800000' => 'maroon', | ||||
|             '#000080' => 'navy', | ||||
|             '#808000' => 'olive', | ||||
|             '#CD853F' => 'peru', | ||||
|             '#FFC0CB' => 'pink', | ||||
|             '#DDA0DD' => 'plum', | ||||
|             '#800080' => 'purple', | ||||
|             '#F00' => 'red', | ||||
|             '#FA8072' => 'salmon', | ||||
|             '#A0522D' => 'sienna', | ||||
|             '#C0C0C0' => 'silver', | ||||
|             '#FFFAFA' => 'snow', | ||||
|             '#D2B48C' => 'tan', | ||||
|             '#FF6347' => 'tomato', | ||||
|             '#EE82EE' => 'violet', | ||||
|             '#F5DEB3' => 'wheat', | ||||
|             // or the other way around | ||||
|             'WHITE' => '#fff', | ||||
|             'BLACK' => '#000', | ||||
|         ); | ||||
|  | ||||
|         return preg_replace_callback( | ||||
|             '/(?<=[: ])('.implode('|', array_keys($colors)).')(?=[; }])/i', | ||||
|             function ($match) use ($colors) { | ||||
|                 return $colors[strtoupper($match[0])]; | ||||
|             }, | ||||
|             $content | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Shorten CSS font weights. | ||||
|      * | ||||
|      * @param string $content The CSS content to shorten the font weights for | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     protected function shortenFontWeights($content) | ||||
|     { | ||||
|         $weights = array( | ||||
|             'normal' => 400, | ||||
|             'bold' => 700, | ||||
|         ); | ||||
|  | ||||
|         $callback = function ($match) use ($weights) { | ||||
|             return $match[1].$weights[$match[2]]; | ||||
|         }; | ||||
|  | ||||
|         return preg_replace_callback('/(font-weight\s*:\s*)('.implode('|', array_keys($weights)).')(?=[;}])/', $callback, $content); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Shorthand 0 values to plain 0, instead of e.g. -0em. | ||||
|      * | ||||
|      * @param string $content The CSS content to shorten the zero values for | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     protected function shortenZeroes($content) | ||||
|     { | ||||
|         // we don't want to strip units in `calc()` expressions: | ||||
|         // `5px - 0px` is valid, but `5px - 0` is not | ||||
|         // `10px * 0` is valid (equates to 0), and so is `10 * 0px`, but | ||||
|         // `10 * 0` is invalid | ||||
|         // we've extracted calcs earlier, so we don't need to worry about this | ||||
|  | ||||
|         // reusable bits of code throughout these regexes: | ||||
|         // before & after are used to make sure we don't match lose unintended | ||||
|         // 0-like values (e.g. in #000, or in http://url/1.0) | ||||
|         // units can be stripped from 0 values, or used to recognize non 0 | ||||
|         // values (where wa may be able to strip a .0 suffix) | ||||
|         $before = '(?<=[:(, ])'; | ||||
|         $after = '(?=[ ,);}])'; | ||||
|         $units = '(em|ex|%|px|cm|mm|in|pt|pc|ch|rem|vh|vw|vmin|vmax|vm)'; | ||||
|  | ||||
|         // strip units after zeroes (0px -> 0) | ||||
|         // NOTE: it should be safe to remove all units for a 0 value, but in | ||||
|         // practice, Webkit (especially Safari) seems to stumble over at least | ||||
|         // 0%, potentially other units as well. Only stripping 'px' for now. | ||||
|         // @see https://github.com/matthiasmullie/minify/issues/60 | ||||
|         $content = preg_replace('/'.$before.'(-?0*(\.0+)?)(?<=0)px'.$after.'/', '\\1', $content); | ||||
|  | ||||
|         // strip 0-digits (.0 -> 0) | ||||
|         $content = preg_replace('/'.$before.'\.0+'.$units.'?'.$after.'/', '0\\1', $content); | ||||
|         // strip trailing 0: 50.10 -> 50.1, 50.10px -> 50.1px | ||||
|         $content = preg_replace('/'.$before.'(-?[0-9]+\.[0-9]+)0+'.$units.'?'.$after.'/', '\\1\\2', $content); | ||||
|         // strip trailing 0: 50.00 -> 50, 50.00px -> 50px | ||||
|         $content = preg_replace('/'.$before.'(-?[0-9]+)\.0+'.$units.'?'.$after.'/', '\\1\\2', $content); | ||||
|         // strip leading 0: 0.1 -> .1, 01.1 -> 1.1 | ||||
|         $content = preg_replace('/'.$before.'(-?)0+([0-9]*\.[0-9]+)'.$units.'?'.$after.'/', '\\1\\2\\3', $content); | ||||
|  | ||||
|         // strip negative zeroes (-0 -> 0) & truncate zeroes (00 -> 0) | ||||
|         $content = preg_replace('/'.$before.'-?0+'.$units.'?'.$after.'/', '0\\1', $content); | ||||
|  | ||||
|         // IE doesn't seem to understand a unitless flex-basis value (correct - | ||||
|         // it goes against the spec), so let's add it in again (make it `%`, | ||||
|         // which is only 1 char: 0%, 0px, 0 anything, it's all just the same) | ||||
|         // @see https://developer.mozilla.org/nl/docs/Web/CSS/flex | ||||
|         $content = preg_replace('/flex:([0-9]+\s[0-9]+\s)0([;\}])/', 'flex:${1}0%${2}', $content); | ||||
|         $content = preg_replace('/flex-basis:0([;\}])/', 'flex-basis:0%${1}', $content); | ||||
|  | ||||
|         return $content; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Strip empty tags from source code. | ||||
|      * | ||||
|      * @param string $content | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     protected function stripEmptyTags($content) | ||||
|     { | ||||
|         $content = preg_replace('/(?<=^)[^\{\};]+\{\s*\}/', '', $content); | ||||
|         $content = preg_replace('/(?<=(\}|;))[^\{\};]+\{\s*\}/', '', $content); | ||||
|  | ||||
|         return $content; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Strip comments from source code. | ||||
|      */ | ||||
|     protected function stripComments() | ||||
|     { | ||||
|         // PHP only supports $this inside anonymous functions since 5.4 | ||||
|         $minifier = $this; | ||||
|         $callback = function ($match) use ($minifier) { | ||||
|             $count = count($minifier->extracted); | ||||
|             $placeholder = '/*'.$count.'*/'; | ||||
|             $minifier->extracted[$placeholder] = $match[0]; | ||||
|  | ||||
|             return $placeholder; | ||||
|         }; | ||||
|         $this->registerPattern('/\n?\/\*(!|.*?@license|.*?@preserve).*?\*\/\n?/s', $callback); | ||||
|  | ||||
|         $this->registerPattern('/\/\*.*?\*\//s', ''); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Strip whitespace. | ||||
|      * | ||||
|      * @param string $content The CSS content to strip the whitespace for | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     protected function stripWhitespace($content) | ||||
|     { | ||||
|         // remove leading & trailing whitespace | ||||
|         $content = preg_replace('/^\s*/m', '', $content); | ||||
|         $content = preg_replace('/\s*$/m', '', $content); | ||||
|  | ||||
|         // replace newlines with a single space | ||||
|         $content = preg_replace('/\s+/', ' ', $content); | ||||
|  | ||||
|         // remove whitespace around meta characters | ||||
|         // inspired by stackoverflow.com/questions/15195750/minify-compress-css-with-regex | ||||
|         $content = preg_replace('/\s*([\*$~^|]?+=|[{};,>~]|!important\b)\s*/', '$1', $content); | ||||
|         $content = preg_replace('/([\[(:>\+])\s+/', '$1', $content); | ||||
|         $content = preg_replace('/\s+([\]\)>\+])/', '$1', $content); | ||||
|         $content = preg_replace('/\s+(:)(?![^\}]*\{)/', '$1', $content); | ||||
|  | ||||
|         // whitespace around + and - can only be stripped inside some pseudo- | ||||
|         // classes, like `:nth-child(3+2n)` | ||||
|         // not in things like `calc(3px + 2px)`, shorthands like `3px -2px`, or | ||||
|         // selectors like `div.weird- p` | ||||
|         $pseudos = array('nth-child', 'nth-last-child', 'nth-last-of-type', 'nth-of-type'); | ||||
|         $content = preg_replace('/:('.implode('|', $pseudos).')\(\s*([+-]?)\s*(.+?)\s*([+-]?)\s*(.*?)\s*\)/', ':$1($2$3$4$5)', $content); | ||||
|  | ||||
|         // remove semicolon/whitespace followed by closing bracket | ||||
|         $content = str_replace(';}', '}', $content); | ||||
|  | ||||
|         return trim($content); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Replace all `calc()` occurrences. | ||||
|      */ | ||||
|     protected function extractCalcs() | ||||
|     { | ||||
|         // PHP only supports $this inside anonymous functions since 5.4 | ||||
|         $minifier = $this; | ||||
|         $callback = function ($match) use ($minifier) { | ||||
|             $length = strlen($match[1]); | ||||
|             $expr = ''; | ||||
|             $opened = 0; | ||||
|  | ||||
|             for ($i = 0; $i < $length; $i++) { | ||||
|                 $char = $match[1][$i]; | ||||
|                 $expr .= $char; | ||||
|                 if ($char === '(') { | ||||
|                     $opened++; | ||||
|                 } elseif ($char === ')' && --$opened === 0) { | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|             $rest = str_replace($expr, '', $match[1]); | ||||
|             $expr = trim(substr($expr, 1, -1)); | ||||
|  | ||||
|             $count = count($minifier->extracted); | ||||
|             $placeholder = 'calc('.$count.')'; | ||||
|             $minifier->extracted[$placeholder] = 'calc('.$expr.')'; | ||||
|  | ||||
|             return $placeholder.$rest; | ||||
|         }; | ||||
|  | ||||
|         $this->registerPattern('/calc(\(.+?)(?=$|;|}|calc\()/', $callback); | ||||
|         $this->registerPattern('/calc(\(.+?)(?=$|;|}|calc\()/m', $callback); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Check if file is small enough to be imported. | ||||
|      * | ||||
|      * @param string $path The path to the file | ||||
|      * | ||||
|      * @return bool | ||||
|      */ | ||||
|     protected function canImportBySize($path) | ||||
|     { | ||||
|         return ($size = @filesize($path)) && $size <= $this->maxImportSize * 1024; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Check if file a file can be imported, going by the path. | ||||
|      * | ||||
|      * @param string $path | ||||
|      * | ||||
|      * @return bool | ||||
|      */ | ||||
|     protected function canImportByPath($path) | ||||
|     { | ||||
|         return preg_match('/^(data:|https?:|\\/)/', $path) === 0; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Return a converter to update relative paths to be relative to the new | ||||
|      * destination. | ||||
|      * | ||||
|      * @param string $source | ||||
|      * @param string $target | ||||
|      * | ||||
|      * @return ConverterInterface | ||||
|      */ | ||||
|     protected function getPathConverter($source, $target) | ||||
|     { | ||||
|         return new Converter($source, $target); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										20
									
								
								vendor/matthiasmullie/minify/src/Exception.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								vendor/matthiasmullie/minify/src/Exception.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| <?php | ||||
| /** | ||||
|  * Base Exception | ||||
|  * | ||||
|  * @deprecated Use Exceptions\BasicException instead | ||||
|  * | ||||
|  * @author Matthias Mullie <minify@mullie.eu> | ||||
|  */ | ||||
| namespace MatthiasMullie\Minify; | ||||
|  | ||||
| /** | ||||
|  * Base Exception Class | ||||
|  * @deprecated Use Exceptions\BasicException instead | ||||
|  * | ||||
|  * @package Minify | ||||
|  * @author Matthias Mullie <minify@mullie.eu> | ||||
|  */ | ||||
| abstract class Exception extends \Exception | ||||
| { | ||||
| } | ||||
							
								
								
									
										23
									
								
								vendor/matthiasmullie/minify/src/Exceptions/BasicException.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								vendor/matthiasmullie/minify/src/Exceptions/BasicException.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| <?php | ||||
| /** | ||||
|  * Basic exception | ||||
|  * | ||||
|  * Please report bugs on https://github.com/matthiasmullie/minify/issues | ||||
|  * | ||||
|  * @author Matthias Mullie <minify@mullie.eu> | ||||
|  * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved | ||||
|  * @license MIT License | ||||
|  */ | ||||
| namespace MatthiasMullie\Minify\Exceptions; | ||||
|  | ||||
| use MatthiasMullie\Minify\Exception; | ||||
|  | ||||
| /** | ||||
|  * Basic Exception Class | ||||
|  * | ||||
|  * @package Minify\Exception | ||||
|  * @author Matthias Mullie <minify@mullie.eu> | ||||
|  */ | ||||
| abstract class BasicException extends Exception | ||||
| { | ||||
| } | ||||
							
								
								
									
										21
									
								
								vendor/matthiasmullie/minify/src/Exceptions/FileImportException.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/matthiasmullie/minify/src/Exceptions/FileImportException.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| <?php | ||||
| /** | ||||
|  * File Import Exception | ||||
|  * | ||||
|  * Please report bugs on https://github.com/matthiasmullie/minify/issues | ||||
|  * | ||||
|  * @author Matthias Mullie <minify@mullie.eu> | ||||
|  * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved | ||||
|  * @license MIT License | ||||
|  */ | ||||
| namespace MatthiasMullie\Minify\Exceptions; | ||||
|  | ||||
| /** | ||||
|  * File Import Exception Class | ||||
|  * | ||||
|  * @package Minify\Exception | ||||
|  * @author Matthias Mullie <minify@mullie.eu> | ||||
|  */ | ||||
| class FileImportException extends BasicException | ||||
| { | ||||
| } | ||||
							
								
								
									
										21
									
								
								vendor/matthiasmullie/minify/src/Exceptions/IOException.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/matthiasmullie/minify/src/Exceptions/IOException.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| <?php | ||||
| /** | ||||
|  * IO Exception | ||||
|  * | ||||
|  * Please report bugs on https://github.com/matthiasmullie/minify/issues | ||||
|  * | ||||
|  * @author Matthias Mullie <minify@mullie.eu> | ||||
|  * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved | ||||
|  * @license MIT License | ||||
|  */ | ||||
| namespace MatthiasMullie\Minify\Exceptions; | ||||
|  | ||||
| /** | ||||
|  * IO Exception Class | ||||
|  * | ||||
|  * @package Minify\Exception | ||||
|  * @author Matthias Mullie <minify@mullie.eu> | ||||
|  */ | ||||
| class IOException extends BasicException | ||||
| { | ||||
| } | ||||
							
								
								
									
										612
									
								
								vendor/matthiasmullie/minify/src/JS.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										612
									
								
								vendor/matthiasmullie/minify/src/JS.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										497
									
								
								vendor/matthiasmullie/minify/src/Minify.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										497
									
								
								vendor/matthiasmullie/minify/src/Minify.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,497 @@ | ||||
| <?php | ||||
| /** | ||||
|  * Abstract minifier class | ||||
|  * | ||||
|  * Please report bugs on https://github.com/matthiasmullie/minify/issues | ||||
|  * | ||||
|  * @author Matthias Mullie <minify@mullie.eu> | ||||
|  * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved | ||||
|  * @license MIT License | ||||
|  */ | ||||
| namespace MatthiasMullie\Minify; | ||||
|  | ||||
| use MatthiasMullie\Minify\Exceptions\IOException; | ||||
| use Psr\Cache\CacheItemInterface; | ||||
|  | ||||
| /** | ||||
|  * Abstract minifier class. | ||||
|  * | ||||
|  * Please report bugs on https://github.com/matthiasmullie/minify/issues | ||||
|  * | ||||
|  * @package Minify | ||||
|  * @author Matthias Mullie <minify@mullie.eu> | ||||
|  * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved | ||||
|  * @license MIT License | ||||
|  */ | ||||
| abstract class Minify | ||||
| { | ||||
|     /** | ||||
|      * The data to be minified. | ||||
|      * | ||||
|      * @var string[] | ||||
|      */ | ||||
|     protected $data = array(); | ||||
|  | ||||
|     /** | ||||
|      * Array of patterns to match. | ||||
|      * | ||||
|      * @var string[] | ||||
|      */ | ||||
|     protected $patterns = array(); | ||||
|  | ||||
|     /** | ||||
|      * This array will hold content of strings and regular expressions that have | ||||
|      * been extracted from the JS source code, so we can reliably match "code", | ||||
|      * without having to worry about potential "code-like" characters inside. | ||||
|      * | ||||
|      * @var string[] | ||||
|      */ | ||||
|     public $extracted = array(); | ||||
|  | ||||
|     /** | ||||
|      * Init the minify class - optionally, code may be passed along already. | ||||
|      */ | ||||
|     public function __construct(/* $data = null, ... */) | ||||
|     { | ||||
|         // it's possible to add the source through the constructor as well ;) | ||||
|         if (func_num_args()) { | ||||
|             call_user_func_array(array($this, 'add'), func_get_args()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Add a file or straight-up code to be minified. | ||||
|      * | ||||
|      * @param string|string[] $data | ||||
|      * | ||||
|      * @return static | ||||
|      */ | ||||
|     public function add($data /* $data = null, ... */) | ||||
|     { | ||||
|         // bogus "usage" of parameter $data: scrutinizer warns this variable is | ||||
|         // not used (we're using func_get_args instead to support overloading), | ||||
|         // but it still needs to be defined because it makes no sense to have | ||||
|         // this function without argument :) | ||||
|         $args = array($data) + func_get_args(); | ||||
|  | ||||
|         // this method can be overloaded | ||||
|         foreach ($args as $data) { | ||||
|             if (is_array($data)) { | ||||
|                 call_user_func_array(array($this, 'add'), $data); | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             // redefine var | ||||
|             $data = (string) $data; | ||||
|  | ||||
|             // load data | ||||
|             $value = $this->load($data); | ||||
|             $key = ($data != $value) ? $data : count($this->data); | ||||
|  | ||||
|             // replace CR linefeeds etc. | ||||
|             // @see https://github.com/matthiasmullie/minify/pull/139 | ||||
|             $value = str_replace(array("\r\n", "\r"), "\n", $value); | ||||
|  | ||||
|             // store data | ||||
|             $this->data[$key] = $value; | ||||
|         } | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Add a file to be minified. | ||||
|      * | ||||
|      * @param string|string[] $data | ||||
|      * | ||||
|      * @return static | ||||
|      *  | ||||
|      * @throws IOException | ||||
|      */ | ||||
|     public function addFile($data /* $data = null, ... */) | ||||
|     { | ||||
|         // bogus "usage" of parameter $data: scrutinizer warns this variable is | ||||
|         // not used (we're using func_get_args instead to support overloading), | ||||
|         // but it still needs to be defined because it makes no sense to have | ||||
|         // this function without argument :) | ||||
|         $args = array($data) + func_get_args(); | ||||
|  | ||||
|         // this method can be overloaded | ||||
|         foreach ($args as $path) { | ||||
|             if (is_array($path)) { | ||||
|                 call_user_func_array(array($this, 'addFile'), $path); | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             // redefine var | ||||
|             $path = (string) $path; | ||||
|  | ||||
|             // check if we can read the file | ||||
|             if (!$this->canImportFile($path)) { | ||||
|                 throw new IOException('The file "'.$path.'" could not be opened for reading. Check if PHP has enough permissions.'); | ||||
|             } | ||||
|  | ||||
|             $this->add($path); | ||||
|         } | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Minify the data & (optionally) saves it to a file. | ||||
|      * | ||||
|      * @param string[optional] $path Path to write the data to | ||||
|      * | ||||
|      * @return string The minified data | ||||
|      */ | ||||
|     public function minify($path = null) | ||||
|     { | ||||
|         $content = $this->execute($path); | ||||
|  | ||||
|         // save to path | ||||
|         if ($path !== null) { | ||||
|             $this->save($content, $path); | ||||
|         } | ||||
|  | ||||
|         return $content; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Minify & gzip the data & (optionally) saves it to a file. | ||||
|      * | ||||
|      * @param string[optional] $path  Path to write the data to | ||||
|      * @param int[optional]    $level Compression level, from 0 to 9 | ||||
|      * | ||||
|      * @return string The minified & gzipped data | ||||
|      */ | ||||
|     public function gzip($path = null, $level = 9) | ||||
|     { | ||||
|         $content = $this->execute($path); | ||||
|         $content = gzencode($content, $level, FORCE_GZIP); | ||||
|  | ||||
|         // save to path | ||||
|         if ($path !== null) { | ||||
|             $this->save($content, $path); | ||||
|         } | ||||
|  | ||||
|         return $content; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Minify the data & write it to a CacheItemInterface object. | ||||
|      * | ||||
|      * @param CacheItemInterface $item Cache item to write the data to | ||||
|      * | ||||
|      * @return CacheItemInterface Cache item with the minifier data | ||||
|      */ | ||||
|     public function cache(CacheItemInterface $item) | ||||
|     { | ||||
|         $content = $this->execute(); | ||||
|         $item->set($content); | ||||
|  | ||||
|         return $item; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Minify the data. | ||||
|      * | ||||
|      * @param string[optional] $path Path to write the data to | ||||
|      * | ||||
|      * @return string The minified data | ||||
|      */ | ||||
|     abstract public function execute($path = null); | ||||
|  | ||||
|     /** | ||||
|      * Load data. | ||||
|      * | ||||
|      * @param string $data Either a path to a file or the content itself | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     protected function load($data) | ||||
|     { | ||||
|         // check if the data is a file | ||||
|         if ($this->canImportFile($data)) { | ||||
|             $data = file_get_contents($data); | ||||
|  | ||||
|             // strip BOM, if any | ||||
|             if (substr($data, 0, 3) == "\xef\xbb\xbf") { | ||||
|                 $data = substr($data, 3); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $data; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Save to file. | ||||
|      * | ||||
|      * @param string $content The minified data | ||||
|      * @param string $path    The path to save the minified data to | ||||
|      * | ||||
|      * @throws IOException | ||||
|      */ | ||||
|     protected function save($content, $path) | ||||
|     { | ||||
|         $handler = $this->openFileForWriting($path); | ||||
|  | ||||
|         $this->writeToFile($handler, $content); | ||||
|  | ||||
|         @fclose($handler); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Register a pattern to execute against the source content. | ||||
|      * | ||||
|      * @param string          $pattern     PCRE pattern | ||||
|      * @param string|callable $replacement Replacement value for matched pattern | ||||
|      */ | ||||
|     protected function registerPattern($pattern, $replacement = '') | ||||
|     { | ||||
|         // study the pattern, we'll execute it more than once | ||||
|         $pattern .= 'S'; | ||||
|  | ||||
|         $this->patterns[] = array($pattern, $replacement); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * We can't "just" run some regular expressions against JavaScript: it's a | ||||
|      * complex language. E.g. having an occurrence of // xyz would be a comment, | ||||
|      * unless it's used within a string. Of you could have something that looks | ||||
|      * like a 'string', but inside a comment. | ||||
|      * The only way to accurately replace these pieces is to traverse the JS one | ||||
|      * character at a time and try to find whatever starts first. | ||||
|      * | ||||
|      * @param string $content The content to replace patterns in | ||||
|      * | ||||
|      * @return string The (manipulated) content | ||||
|      */ | ||||
|     protected function replace($content) | ||||
|     { | ||||
|         $processed = ''; | ||||
|         $positions = array_fill(0, count($this->patterns), -1); | ||||
|         $matches = array(); | ||||
|  | ||||
|         while ($content) { | ||||
|             // find first match for all patterns | ||||
|             foreach ($this->patterns as $i => $pattern) { | ||||
|                 list($pattern, $replacement) = $pattern; | ||||
|  | ||||
|                 // we can safely ignore patterns for positions we've unset earlier, | ||||
|                 // because we know these won't show up anymore | ||||
|                 if (array_key_exists($i, $positions) == false) { | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|                 // no need to re-run matches that are still in the part of the | ||||
|                 // content that hasn't been processed | ||||
|                 if ($positions[$i] >= 0) { | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|                 $match = null; | ||||
|                 if (preg_match($pattern, $content, $match, PREG_OFFSET_CAPTURE)) { | ||||
|                     $matches[$i] = $match; | ||||
|  | ||||
|                     // we'll store the match position as well; that way, we | ||||
|                     // don't have to redo all preg_matches after changing only | ||||
|                     // the first (we'll still know where those others are) | ||||
|                     $positions[$i] = $match[0][1]; | ||||
|                 } else { | ||||
|                     // if the pattern couldn't be matched, there's no point in | ||||
|                     // executing it again in later runs on this same content; | ||||
|                     // ignore this one until we reach end of content | ||||
|                     unset($matches[$i], $positions[$i]); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             // no more matches to find: everything's been processed, break out | ||||
|             if (!$matches) { | ||||
|                 $processed .= $content; | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|             // see which of the patterns actually found the first thing (we'll | ||||
|             // only want to execute that one, since we're unsure if what the | ||||
|             // other found was not inside what the first found) | ||||
|             $discardLength = min($positions); | ||||
|             $firstPattern = array_search($discardLength, $positions); | ||||
|             $match = $matches[$firstPattern][0][0]; | ||||
|  | ||||
|             // execute the pattern that matches earliest in the content string | ||||
|             list($pattern, $replacement) = $this->patterns[$firstPattern]; | ||||
|             $replacement = $this->replacePattern($pattern, $replacement, $content); | ||||
|  | ||||
|             // figure out which part of the string was unmatched; that's the | ||||
|             // part we'll execute the patterns on again next | ||||
|             $content = (string) substr($content, $discardLength); | ||||
|             $unmatched = (string) substr($content, strpos($content, $match) + strlen($match)); | ||||
|  | ||||
|             // move the replaced part to $processed and prepare $content to | ||||
|             // again match batch of patterns against | ||||
|             $processed .= substr($replacement, 0, strlen($replacement) - strlen($unmatched)); | ||||
|             $content = $unmatched; | ||||
|  | ||||
|             // first match has been replaced & that content is to be left alone, | ||||
|             // the next matches will start after this replacement, so we should | ||||
|             // fix their offsets | ||||
|             foreach ($positions as $i => $position) { | ||||
|                 $positions[$i] -= $discardLength + strlen($match); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $processed; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * This is where a pattern is matched against $content and the matches | ||||
|      * are replaced by their respective value. | ||||
|      * This function will be called plenty of times, where $content will always | ||||
|      * move up 1 character. | ||||
|      * | ||||
|      * @param string          $pattern     Pattern to match | ||||
|      * @param string|callable $replacement Replacement value | ||||
|      * @param string          $content     Content to match pattern against | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     protected function replacePattern($pattern, $replacement, $content) | ||||
|     { | ||||
|         if (is_callable($replacement)) { | ||||
|             return preg_replace_callback($pattern, $replacement, $content, 1, $count); | ||||
|         } else { | ||||
|             return preg_replace($pattern, $replacement, $content, 1, $count); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Strings are a pattern we need to match, in order to ignore potential | ||||
|      * code-like content inside them, but we just want all of the string | ||||
|      * content to remain untouched. | ||||
|      * | ||||
|      * This method will replace all string content with simple STRING# | ||||
|      * placeholder text, so we've rid all strings from characters that may be | ||||
|      * misinterpreted. Original string content will be saved in $this->extracted | ||||
|      * and after doing all other minifying, we can restore the original content | ||||
|      * via restoreStrings(). | ||||
|      * | ||||
|      * @param string[optional] $chars | ||||
|      * @param string[optional] $placeholderPrefix | ||||
|      */ | ||||
|     protected function extractStrings($chars = '\'"', $placeholderPrefix = '') | ||||
|     { | ||||
|         // PHP only supports $this inside anonymous functions since 5.4 | ||||
|         $minifier = $this; | ||||
|         $callback = function ($match) use ($minifier, $placeholderPrefix) { | ||||
|             // check the second index here, because the first always contains a quote | ||||
|             if ($match[2] === '') { | ||||
|                 /* | ||||
|                  * Empty strings need no placeholder; they can't be confused for | ||||
|                  * anything else anyway. | ||||
|                  * But we still needed to match them, for the extraction routine | ||||
|                  * to skip over this particular string. | ||||
|                  */ | ||||
|                 return $match[0]; | ||||
|             } | ||||
|  | ||||
|             $count = count($minifier->extracted); | ||||
|             $placeholder = $match[1].$placeholderPrefix.$count.$match[1]; | ||||
|             $minifier->extracted[$placeholder] = $match[1].$match[2].$match[1]; | ||||
|  | ||||
|             return $placeholder; | ||||
|         }; | ||||
|  | ||||
|         /* | ||||
|          * The \\ messiness explained: | ||||
|          * * Don't count ' or " as end-of-string if it's escaped (has backslash | ||||
|          * in front of it) | ||||
|          * * Unless... that backslash itself is escaped (another leading slash), | ||||
|          * in which case it's no longer escaping the ' or " | ||||
|          * * So there can be either no backslash, or an even number | ||||
|          * * multiply all of that times 4, to account for the escaping that has | ||||
|          * to be done to pass the backslash into the PHP string without it being | ||||
|          * considered as escape-char (times 2) and to get it in the regex, | ||||
|          * escaped (times 2) | ||||
|          */ | ||||
|         $this->registerPattern('/(['.$chars.'])(.*?(?<!\\\\)(\\\\\\\\)*+)\\1/s', $callback); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * This method will restore all extracted data (strings, regexes) that were | ||||
|      * replaced with placeholder text in extract*(). The original content was | ||||
|      * saved in $this->extracted. | ||||
|      * | ||||
|      * @param string $content | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     protected function restoreExtractedData($content) | ||||
|     { | ||||
|         if (!$this->extracted) { | ||||
|             // nothing was extracted, nothing to restore | ||||
|             return $content; | ||||
|         } | ||||
|  | ||||
|         $content = strtr($content, $this->extracted); | ||||
|  | ||||
|         $this->extracted = array(); | ||||
|  | ||||
|         return $content; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Check if the path is a regular file and can be read. | ||||
|      * | ||||
|      * @param string $path | ||||
|      * | ||||
|      * @return bool | ||||
|      */ | ||||
|     protected function canImportFile($path) | ||||
|     { | ||||
|         $parsed = parse_url($path); | ||||
|         if ( | ||||
|             // file is elsewhere | ||||
|             isset($parsed['host']) || | ||||
|             // file responds to queries (may change, or need to bypass cache) | ||||
|             isset($parsed['query']) | ||||
|         ) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         return strlen($path) < PHP_MAXPATHLEN && @is_file($path) && is_readable($path); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Attempts to open file specified by $path for writing. | ||||
|      * | ||||
|      * @param string $path The path to the file | ||||
|      * | ||||
|      * @return resource Specifier for the target file | ||||
|      * | ||||
|      * @throws IOException | ||||
|      */ | ||||
|     protected function openFileForWriting($path) | ||||
|     { | ||||
|         if (($handler = @fopen($path, 'w')) === false) { | ||||
|             throw new IOException('The file "'.$path.'" could not be opened for writing. Check if PHP has enough permissions.'); | ||||
|         } | ||||
|  | ||||
|         return $handler; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Attempts to write $content to the file specified by $handler. $path is used for printing exceptions. | ||||
|      * | ||||
|      * @param resource $handler The resource to write to | ||||
|      * @param string   $content The content to write | ||||
|      * @param string   $path    The path to the file (for exception printing only) | ||||
|      * | ||||
|      * @throws IOException | ||||
|      */ | ||||
|     protected function writeToFile($handler, $content, $path = '') | ||||
|     { | ||||
|         if (($result = @fwrite($handler, $content)) === false || ($result < strlen($content))) { | ||||
|             throw new IOException('The file "'.$path.'" could not be written to. Check your disk space and file permissions.'); | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user