Added all the files, updated the Readme
This commit is contained in:
parent
e93f1aeb95
commit
9069bd4c68
10
README.md
10
README.md
@ -0,0 +1,10 @@
|
|||||||
|
# Easy Min #
|
||||||
|
|
||||||
|
A simple set of minifying scripts for CSS and Javascript
|
||||||
|
|
||||||
|
## Basic Use: ##
|
||||||
|
|
||||||
|
1. Figure out your file paths, and set them in css.php and js.php.
|
||||||
|
2. Add your css and javascript files to groups, in `config/css_groups.php` and `config/js_groups.php` respectively
|
||||||
|
3. Point your CSS links in your HTML to `css.php/g/[group_name]`, and likewise your javascript to `js.php/g/[group_name]`
|
||||||
|
4. Enjoy a faster loading website
|
15
config/css_groups.php
Normal file
15
config/css_groups.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
return array(
|
||||||
|
/*-----
|
||||||
|
Css
|
||||||
|
-----*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
For each group create an array like so
|
||||||
|
|
||||||
|
'my_group' => array(
|
||||||
|
'path/to/css/file1.css',
|
||||||
|
'path/to/css/file2.css'
|
||||||
|
),
|
||||||
|
*/
|
||||||
|
);
|
11
config/js_groups.php
Normal file
11
config/js_groups.php
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
return array(
|
||||||
|
/*
|
||||||
|
For each group create an array like so
|
||||||
|
|
||||||
|
'my_group' => array(
|
||||||
|
'path/to/css/file1.css',
|
||||||
|
'path/to/css/file2.css'
|
||||||
|
),
|
||||||
|
*/
|
||||||
|
);
|
333
config/jshrink.php
Normal file
333
config/jshrink.php
Normal file
@ -0,0 +1,333 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
JShrink
|
||||||
|
|
||||||
|
Copyright (c) 2009, Robert Hafner
|
||||||
|
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 the <ORGANIZATION> 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 HOLDER 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JShrink
|
||||||
|
*
|
||||||
|
* Usage - JShrink::minify($js);
|
||||||
|
* Usage - JShrink::minify($js, $options);
|
||||||
|
* Usage - JShrink::minify($js, array('flaggedComments' => false));
|
||||||
|
*
|
||||||
|
* @version 0.2
|
||||||
|
* @package JShrink
|
||||||
|
* @author Robert Hafner <tedivm@tedivm.com>
|
||||||
|
* @license http://www.opensource.org/licenses/bsd-license.php
|
||||||
|
*/
|
||||||
|
class JShrink
|
||||||
|
{
|
||||||
|
protected $input;
|
||||||
|
protected $index = 0;
|
||||||
|
|
||||||
|
protected $a = '';
|
||||||
|
protected $b = '';
|
||||||
|
protected $c;
|
||||||
|
|
||||||
|
protected $options;
|
||||||
|
|
||||||
|
static protected $defaultOptions = array('flaggedComments' => true);
|
||||||
|
|
||||||
|
static public function minify($js, $options = array())
|
||||||
|
{
|
||||||
|
try{
|
||||||
|
$currentOptions = array_merge(self::$defaultOptions, $options);
|
||||||
|
|
||||||
|
ob_start();
|
||||||
|
$currentOptions = array_merge(self::$defaultOptions, $options);
|
||||||
|
$me = new JShrink();
|
||||||
|
$me->breakdownScript($js, $currentOptions);
|
||||||
|
$output = ob_get_clean();
|
||||||
|
return $output;
|
||||||
|
|
||||||
|
}catch(Exception $e){
|
||||||
|
ob_end_clean();
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function breakdownScript($js, $currentOptions)
|
||||||
|
{
|
||||||
|
$this->options = $currentOptions;
|
||||||
|
|
||||||
|
$js = str_replace("\r\n", "\n", $js);
|
||||||
|
$this->input = str_replace("\r", "\n", $js);
|
||||||
|
|
||||||
|
$this->a = $this->getReal();
|
||||||
|
|
||||||
|
// the only time the length can be higher than 1 is if a conditional comment needs to be displayed
|
||||||
|
// and the only time that can happen for $a is on the very first run
|
||||||
|
while(strlen($this->a) > 1)
|
||||||
|
{
|
||||||
|
echo $this->a;
|
||||||
|
$this->a = $this->getReal();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->b = $this->getReal();
|
||||||
|
|
||||||
|
while($this->a !== false && !is_null($this->a) && $this->a !== '')
|
||||||
|
{
|
||||||
|
|
||||||
|
// now we give $b the same check for conditional comments we gave $a before we began looping
|
||||||
|
if(strlen($this->b) > 1)
|
||||||
|
{
|
||||||
|
echo $this->a . $this->b;
|
||||||
|
$this->a = $this->getReal();
|
||||||
|
$this->b = $this->getReal();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch($this->a)
|
||||||
|
{
|
||||||
|
// new lines
|
||||||
|
case "\n":
|
||||||
|
// if the next line is something that can't stand alone preserver the newline
|
||||||
|
if(strpos('(-+{[@', $this->b) !== false)
|
||||||
|
{
|
||||||
|
echo $this->a;
|
||||||
|
$this->saveString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if its a space we move down to the string test below
|
||||||
|
if($this->b === ' ')
|
||||||
|
break;
|
||||||
|
|
||||||
|
// otherwise we treat the newline like a space
|
||||||
|
|
||||||
|
case ' ':
|
||||||
|
if(self::isAlphaNumeric($this->b))
|
||||||
|
echo $this->a;
|
||||||
|
|
||||||
|
$this->saveString();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
switch($this->b)
|
||||||
|
{
|
||||||
|
case "\n":
|
||||||
|
if(strpos('}])+-"\'', $this->a) !== false)
|
||||||
|
{
|
||||||
|
echo $this->a;
|
||||||
|
$this->saveString();
|
||||||
|
break;
|
||||||
|
}else{
|
||||||
|
if(self::isAlphaNumeric($this->a))
|
||||||
|
{
|
||||||
|
echo $this->a;
|
||||||
|
$this->saveString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ' ':
|
||||||
|
if(!self::isAlphaNumeric($this->a))
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// check for some regex that breaks stuff
|
||||||
|
if($this->a == '/' && ($this->b == '\'' || $this->b == '"'))
|
||||||
|
{
|
||||||
|
$this->saveRegex();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo $this->a;
|
||||||
|
$this->saveString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// do reg check of doom
|
||||||
|
$this->b = $this->getReal();
|
||||||
|
|
||||||
|
if(($this->b == '/' && strpos('(,=:[!&|?', $this->a) !== false))
|
||||||
|
$this->saveRegex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getChar()
|
||||||
|
{
|
||||||
|
if(isset($this->c))
|
||||||
|
{
|
||||||
|
$char = $this->c;
|
||||||
|
unset($this->c);
|
||||||
|
}else{
|
||||||
|
if(isset($this->input[$this->index]))
|
||||||
|
{
|
||||||
|
$char = $this->input[$this->index];
|
||||||
|
$this->index++;
|
||||||
|
}else{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($char === "\n" || ord($char) >= 32)
|
||||||
|
return $char;
|
||||||
|
|
||||||
|
return ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getReal()
|
||||||
|
{
|
||||||
|
$startIndex = $this->index;
|
||||||
|
$char = $this->getChar();
|
||||||
|
|
||||||
|
if($char == '/')
|
||||||
|
{
|
||||||
|
$this->c = $this->getChar();
|
||||||
|
|
||||||
|
if($this->c == '/')
|
||||||
|
{
|
||||||
|
$thirdCommentString = $this->input[$this->index];
|
||||||
|
|
||||||
|
// kill rest of line
|
||||||
|
$char = $this->getNext("\n");
|
||||||
|
|
||||||
|
if($thirdCommentString == '@')
|
||||||
|
{
|
||||||
|
$endPoint = ($this->index) - $startIndex;
|
||||||
|
unset($this->c);
|
||||||
|
$char = "\n" . substr($this->input, $startIndex, $endPoint);// . "\n";
|
||||||
|
}else{
|
||||||
|
$char = $this->getChar();
|
||||||
|
$char = $this->getChar();
|
||||||
|
}
|
||||||
|
|
||||||
|
}elseif($this->c == '*'){
|
||||||
|
|
||||||
|
$this->getChar(); // current C
|
||||||
|
$thirdCommentString = $this->getChar();
|
||||||
|
|
||||||
|
if($thirdCommentString == '@')
|
||||||
|
{
|
||||||
|
// we're gonna back up a bit and and send the comment back, where the first
|
||||||
|
// char will be echoed and the rest will be treated like a string
|
||||||
|
$this->index = $this->index-2;
|
||||||
|
return '/';
|
||||||
|
|
||||||
|
}elseif($this->getNext('*/')){
|
||||||
|
// kill everything up to the next */
|
||||||
|
|
||||||
|
$this->getChar(); // get *
|
||||||
|
$this->getChar(); // get /
|
||||||
|
|
||||||
|
$char = $this->getChar(); // get next real charactor
|
||||||
|
|
||||||
|
// if YUI-style comments are enabled we reinsert it into the stream
|
||||||
|
if($this->options['flaggedComments'] && $thirdCommentString == '!')
|
||||||
|
{
|
||||||
|
$endPoint = ($this->index - 1) - $startIndex;
|
||||||
|
echo "\n" . substr($this->input, $startIndex, $endPoint) . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
}else{
|
||||||
|
$char = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($char === false)
|
||||||
|
throw new JShrinkException('Stray comment. ' . $this->index);
|
||||||
|
|
||||||
|
// if we're here c is part of the comment and therefore tossed
|
||||||
|
if(isset($this->c))
|
||||||
|
unset($this->c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $char;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getNext($string)
|
||||||
|
{
|
||||||
|
$pos = strpos($this->input, $string, $this->index);
|
||||||
|
|
||||||
|
if($pos === false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
$this->index = $pos ;
|
||||||
|
return $this->input[$this->index];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function saveString()
|
||||||
|
{
|
||||||
|
$this->a = $this->b;
|
||||||
|
if($this->a == '\'' || $this->a == '"')
|
||||||
|
{
|
||||||
|
// save literal string
|
||||||
|
$stringType = $this->a;
|
||||||
|
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
echo $this->a;
|
||||||
|
$this->a = $this->getChar();
|
||||||
|
|
||||||
|
switch($this->a)
|
||||||
|
{
|
||||||
|
case $stringType:
|
||||||
|
break 2;
|
||||||
|
|
||||||
|
case "\n":
|
||||||
|
throw new JShrinkException('Unclosed string. ' . $this->index);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\\':
|
||||||
|
echo $this->a;
|
||||||
|
$this->a = $this->getChar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function saveRegex()
|
||||||
|
{
|
||||||
|
echo $this->a . $this->b;
|
||||||
|
|
||||||
|
while(($this->a = $this->getChar()) !== false)
|
||||||
|
{
|
||||||
|
if($this->a == '/')
|
||||||
|
break;
|
||||||
|
|
||||||
|
if($this->a == '\\')
|
||||||
|
{
|
||||||
|
echo $this->a;
|
||||||
|
$this->a = $this->getChar();
|
||||||
|
}
|
||||||
|
|
||||||
|
if($this->a == "\n")
|
||||||
|
throw new JShrinkException('Stray regex pattern. ' . $this->index);
|
||||||
|
|
||||||
|
echo $this->a;
|
||||||
|
}
|
||||||
|
$this->b = $this->getReal();
|
||||||
|
}
|
||||||
|
|
||||||
|
static protected function isAlphaNumeric($char)
|
||||||
|
{
|
||||||
|
return preg_match('/^[\w\$]$/', $char) === 1 || $char == '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adding a custom exception handler for your own projects just means changing this line
|
||||||
|
class JShrinkException extends Exception {}
|
||||||
|
?>
|
82
css.php
Normal file
82
css.php
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
//Change as needed
|
||||||
|
$base_path = $_SERVER['DOCUMENT_ROOT'];
|
||||||
|
//This GZIPs the CSS for transmission to the user
|
||||||
|
//making file size smaller and transfer rate quicker
|
||||||
|
ob_start("ob_gzhandler");
|
||||||
|
|
||||||
|
//Function for compressing the CSS as tightly as possible
|
||||||
|
function compress($buffer) {
|
||||||
|
//Remove CSS comments
|
||||||
|
$buffer = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $buffer);
|
||||||
|
//Remove tabs, spaces, newlines, etc.
|
||||||
|
$buffer = str_replace(array("\r\n", "\r", "\n", "\t", ' ', ' ', ' '), '', $buffer);
|
||||||
|
$buffer = preg_replace('`\s+`', ' ', $buffer);
|
||||||
|
return $buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Creative rewriting
|
||||||
|
$pi = $_SERVER['PATH_INFO'];
|
||||||
|
$pia = explode('/', $pi);
|
||||||
|
|
||||||
|
$pia_len = count($pia);
|
||||||
|
$i = 1;
|
||||||
|
|
||||||
|
while($i < $pia_len)
|
||||||
|
{
|
||||||
|
$j = $i+1;
|
||||||
|
$j = (isset($pia[$j])) ? $j : $i;
|
||||||
|
|
||||||
|
$_GET[$pia[$i]] = $pia[$j];
|
||||||
|
|
||||||
|
$i = $j + 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Include the css groups
|
||||||
|
$groups = require("./config/css_groups.php");
|
||||||
|
|
||||||
|
$css = '';
|
||||||
|
$modified = array();
|
||||||
|
|
||||||
|
if(isset($groups[$_GET['g']]))
|
||||||
|
{
|
||||||
|
foreach($groups[$_GET['g']] as $file)
|
||||||
|
{
|
||||||
|
$new_file = realpath($base_path.$file);
|
||||||
|
$css .= file_get_contents($new_file);
|
||||||
|
$modified[] = filemtime($new_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Add this page too
|
||||||
|
$modified[] = filemtime($base_path."css.tsp");
|
||||||
|
|
||||||
|
//Get the latest modified date
|
||||||
|
rsort($modified);
|
||||||
|
$last_modified = $modified[0];
|
||||||
|
|
||||||
|
if(!isset($_GET['debug']))
|
||||||
|
{
|
||||||
|
$css = compress($css);
|
||||||
|
}
|
||||||
|
|
||||||
|
$requested_time=(isset($_SERVER['HTTP_IF_MODIFIED_SINCE']))
|
||||||
|
? strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])
|
||||||
|
: time();
|
||||||
|
|
||||||
|
if($last_modified === $requested_time)
|
||||||
|
{
|
||||||
|
header("HTTP/1.1 304 Not Modified");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
header("Content-Type: text/css; charset=utf8");
|
||||||
|
header("Cache-control: public, max-age=691200, must-revalidate");
|
||||||
|
header("Last-Modified: ".gmdate('D, d M Y H:i:s', $last_modified)." GMT");
|
||||||
|
header("Expires: ".gmdate('D, d M Y H:i:s', (filemtime($base_path.'css.tsp') + 691200))." GMT");
|
||||||
|
|
||||||
|
echo $css;
|
||||||
|
|
||||||
|
ob_end_flush();
|
||||||
|
?>
|
74
js.php
Normal file
74
js.php
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
//Change as needed
|
||||||
|
$base_path = $_SERVER['DOCUMENT_ROOT'];
|
||||||
|
|
||||||
|
require('./config/jshrink.php');
|
||||||
|
|
||||||
|
//This GZIPs the js for transmission to the user
|
||||||
|
//making file size smaller and transfer rate quicker
|
||||||
|
ob_start("ob_gzhandler");
|
||||||
|
|
||||||
|
//Creative rewriting
|
||||||
|
$pi = $_SERVER['PATH_INFO'];
|
||||||
|
$pia = explode('/', $pi);
|
||||||
|
|
||||||
|
$pia_len = count($pia);
|
||||||
|
$i = 1;
|
||||||
|
|
||||||
|
while($i < $pia_len)
|
||||||
|
{
|
||||||
|
$j = $i+1;
|
||||||
|
$j = (isset($pia[$j])) ? $j : $i;
|
||||||
|
|
||||||
|
$_GET[$pia[$i]] = $pia[$j];
|
||||||
|
|
||||||
|
$i = $j + 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Include the js groups
|
||||||
|
$groups = require("./config/js_groups.php");
|
||||||
|
|
||||||
|
$js = '';
|
||||||
|
$modified = array();
|
||||||
|
|
||||||
|
if(isset($groups[$_GET['g']]))
|
||||||
|
{
|
||||||
|
foreach($groups[$_GET['g']] as $file)
|
||||||
|
{
|
||||||
|
$new_file = realpath($base_path.$file);
|
||||||
|
$js .= file_get_contents($new_file);
|
||||||
|
$modified[] = filemtime($new_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Add this page too
|
||||||
|
$modified[] = filemtime($base_path."js.tsp");
|
||||||
|
|
||||||
|
//Get the latest modified date
|
||||||
|
rsort($modified);
|
||||||
|
$last_modified = $modified[0];
|
||||||
|
|
||||||
|
if(!isset($_GET['debug']))
|
||||||
|
{
|
||||||
|
$js = JShrink::minify($js, array('flaggedComments' => false));
|
||||||
|
}
|
||||||
|
|
||||||
|
$requested_time=(isset($_SERVER['HTTP_IF_MODIFIED_SINCE']))
|
||||||
|
? strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])
|
||||||
|
: time();
|
||||||
|
|
||||||
|
if($last_modified === $requested_time)
|
||||||
|
{
|
||||||
|
header("HTTP/1.1 304 Not Modified");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
header("Content-Type: application/x-javascript; charset=utf8");
|
||||||
|
header("Cache-control: public, max-age=691200, must-revalidate");
|
||||||
|
header("Last-Modified: ".gmdate('D, d M Y H:i:s', $last_modified)." GMT");
|
||||||
|
header("Expires: ".gmdate('D, d M Y H:i:s', (filemtime($base_path.'js.tsp') + 691200))." GMT");
|
||||||
|
|
||||||
|
echo $js;
|
||||||
|
|
||||||
|
ob_end_flush();
|
||||||
|
?>
|
Loading…
Reference in New Issue
Block a user