Skip to content

Commit

Permalink
Merge ea2512a into f55f014
Browse files Browse the repository at this point in the history
  • Loading branch information
GinoPane committed Feb 15, 2016
2 parents f55f014 + ea2512a commit e1f232c
Show file tree
Hide file tree
Showing 16 changed files with 299 additions and 91 deletions.
3 changes: 3 additions & 0 deletions .gitignore
@@ -1,3 +1,6 @@
/build
/docs
/vendor
/tests/js/sample
/tests/css/sample
composer.lock
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -124,6 +124,7 @@ composer require matthiasmullie/minify

Although it's recommended to use Composer, you can actually [include these files](https://github.com/matthiasmullie/minify/issues/83) anyway you want.

If you use Windows and want to run tests, than please run `tests/convert_symlinks_to_windows_style.sh` from command line in order to convert linux-style test symlinks to windows-style.

## Try it

Expand Down
70 changes: 53 additions & 17 deletions src/CSS.php
Expand Up @@ -2,6 +2,7 @@

namespace MatthiasMullie\Minify;

use MatthiasMullie\Minify\Exception\FileImportException;
use MatthiasMullie\PathConverter\Converter;

/**
Expand All @@ -21,6 +22,11 @@ class CSS extends Minify
*/
protected $maxImportSize = 5;

/**
* @var array Chain of files to be imported
*/
protected static $importChain = array();

/**
* @var string[]
*/
Expand Down Expand Up @@ -208,14 +214,14 @@ protected function combineImports($source, $content)

// only replace the import with the content if we can grab the
// content of the file
if (strlen($importPath) < PHP_MAXPATHLEN && file_exists($importPath) && is_file($importPath)) {
if ($this->canImportFile($importPath) && $this->isNotInImportChain($importPath)) {
// grab referenced file & minify it (which may include importing
// yet other @import statements recursively)
$minifier = new static($importPath);
$importContent = $minifier->execute($source);

// check if this is only valid for certain media
if ($match['media']) {
if (!empty($match['media'])) {
$importContent = '@media '.$match['media'].'{'.$importContent.'}';
}

Expand Down Expand Up @@ -259,21 +265,15 @@ protected function importFiles($source, $content)

// only replace the import with the content if we're able to get
// the content of the file, and it's relatively small
$import = strlen($path) < PHP_MAXPATHLEN;
$import = $import && file_exists($path);
$import = $import && is_file($path);
$import = $import && filesize($path) <= $this->maxImportSize * 1024;
if (!$import) {
continue;
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.')';
}

// 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
Expand All @@ -295,8 +295,14 @@ public function execute($path = null)
{
$content = '';

// loop files
// loop css data (raw data and files)
foreach ($this->data as $source => $css) {

//put current source into import chain if it is a valid file
if ($this->canImportFile($source)) {
array_push(self::$importChain, $source);
}

/*
* Let's first take out strings & comments, since we can't just remove
* whitespace anywhere. If whitespace occurs inside a string, we should
Expand Down Expand Up @@ -331,6 +337,9 @@ public function execute($path = null)

// combine css
$content .= $css;

//remove current file from chain
array_pop(self::$importChain);
}

$content = $this->moveImportsToTop($content);
Expand Down Expand Up @@ -577,4 +586,31 @@ protected function stripWhitespace($content)

return trim($content);
}

/**
* Check if file is small enough to be imported.
*
* @param $path The path to the file.
* @return bool
*/
protected function canImportBySize($path)
{
return (($size = @filesize($path)) && ($size <= $this->maxImportSize * 1024));
}

/**
* Check if current file was not imported previously in the same import chain.
*
* @param $path The path to the file.
* @return bool
* @throws FileImportException
*/
protected function isNotInImportChain($path)
{
if (in_array($path, self::$importChain)) {
throw new FileImportException("Failed to import file \"{$path}\" : import loop detected");
}

return true;
}
}
10 changes: 0 additions & 10 deletions src/Exception.php

This file was deleted.

10 changes: 10 additions & 0 deletions src/Exception/BasicException.php
@@ -0,0 +1,10 @@
<?php

namespace MatthiasMullie\Minify\Exception;

/**
* @author Matthias Mullie <minify@mullie.eu>
*/
class BasicException extends \Exception
{
}
10 changes: 10 additions & 0 deletions src/Exception/FileImportException.php
@@ -0,0 +1,10 @@
<?php

namespace MatthiasMullie\Minify\Exception;

/**
* @author Matthias Mullie <minify@mullie.eu>
*/
class FileImportException extends BasicException
{
}
10 changes: 10 additions & 0 deletions src/Exception/IOException.php
@@ -0,0 +1,10 @@
<?php

namespace MatthiasMullie\Minify\Exception;

/**
* @author Matthias Mullie <minify@mullie.eu>
*/
class IOException extends BasicException
{
}
31 changes: 21 additions & 10 deletions src/JS.php
Expand Up @@ -211,9 +211,7 @@ protected function extractRegex()
};

// it's a regex if we can find an opening and (not escaped) closing /,
// include \n because it may be there for a reason
// (https://github.com/matthiasmullie/minify/issues/56)
$pattern = '(\/.*?(?<!\\\\)(\\\\\\\\)*+\/\n?)';
$pattern = '(\/.*?(?<!\\\\)(\\\\\\\\)*+\/)';

// / can't be preceded by variable, value, or similar because then
// it's going to be division
Expand Down Expand Up @@ -256,19 +254,32 @@ protected function stripWhitespace($content)
// collapse consecutive line feeds into just 1
$content = preg_replace('/\n+/', "\n", $content);

// replace newlines after a closing slash of a replaced regex
// (https://github.com/matthiasmullie/minify/issues/56)
// using positive look-behind here
$content = preg_replace('/(?<=\/)\n/', ';', $content);

$before = $this->getOperatorsForRegex($this->operatorsBefore, '/');
$after = $this->getOperatorsForRegex($this->operatorsAfter, '/');
$operators = $before + $after;

// strip whitespace that ends in (or next line begin with) an operator
// that allows statements to be broken up over multiple lines
unset($before['+'], $before['-'], $after['+'], $after['-']);
$content = preg_replace('/('.implode('|', $before).')\s+/', '\\1', $content);
$content = preg_replace('/\s+('.implode('|', $after).')/', '\\1', $content);
$content = preg_replace(
array(
'/('.implode('|', $before).')\s+/',
'/\s+('.implode('|', $after).')/'
), '\\1', $content
);

// make sure + and - can't be mistaken for, or joined into ++ and --
$content = preg_replace('/(?<![\+\-])\s*([\+\-])(?![\+\-])/', '\\1', $content);
$content = preg_replace('/(?<![\+\-])([\+\-])\s*(?![\+\-])/', '\\1', $content);
$content = preg_replace(
array(
'/(?<![\+\-])\s*([\+\-])(?![\+\-])/',
'/(?<![\+\-])([\+\-])\s*(?![\+\-])/'
), '\\1', $content
);

/*
* We didn't strip whitespace after a couple of operators because they
Expand Down Expand Up @@ -427,7 +438,7 @@ protected function propertyNotation($content)
* we want to use property notation on) - this is to make sure
* standalone ['value'] arrays aren't confused for keys-of-an-array.
* We can (and only have to) check the last character, because PHP's
* regex implementation doesn't allow un-fixed-length lookbehind
* regex implementation doesn't allow unfixed-length look-behind
* assertions.
*/
preg_match('/(\[[^\]]+\])[^\]]*$/', static::REGEX_VARIABLE, $previousChar);
Expand All @@ -436,8 +447,8 @@ protected function propertyNotation($content)
/*
* Make sure word preceding the ['value'] is not a keyword, e.g.
* return['x']. Because -again- PHP's regex implementation doesn't allow
* un-fixed-length lookbehind assertions, I'm just going to do a lot of
* separate lookbehind assertions, one for each keyword.
* unfixed-length look-behind assertions, I'm just going to do a lot of
* separate look-behind assertions, one for each keyword.
*/
$keywords = $this->getKeywordsForRegex($keywords);
$keywords = '(?<!'.implode(')(?<!', $keywords).')';
Expand Down

0 comments on commit e1f232c

Please sign in to comment.