Version Description
- First released version.
Download this release
Release Info
Developer | turl |
Plugin | Autoptimize |
Version | 0.1 |
Comparing to | |
See all releases |
Version 0.1
- autoptimize.php +94 -0
- classes/autoptimizeBase.php +37 -0
- classes/autoptimizeCache.php +40 -0
- classes/autoptimizeConfig.php +104 -0
- classes/autoptimizeHTML.php +40 -0
- classes/autoptimizeScripts.php +158 -0
- classes/autoptimizeStyles.php +149 -0
- classes/jsmin-1.1.1.php +291 -0
- classes/minify-css-compressor.php +250 -0
- classes/minify-html.php +245 -0
- config/default.php +37 -0
- readme.txt +32 -0
autoptimize.php
ADDED
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
Plugin Name: Autoptimize
|
4 |
+
Plugin URI: http://www.turleando.com.ar/
|
5 |
+
Description: Optimiza tu sitio web, uniendo el CSS y JavaScript, y comprimiéndolo.
|
6 |
+
Version: 0.1
|
7 |
+
Author: Emilio López
|
8 |
+
Author URI: http://www.turleando.com.ar/
|
9 |
+
Released under the GNU General Public License (GPL)
|
10 |
+
http://www.gnu.org/licenses/gpl.txt
|
11 |
+
*/
|
12 |
+
|
13 |
+
//Load config class
|
14 |
+
@include(WP_PLUGIN_DIR.'/autoptimize/classes/autoptimizeConfig.php');
|
15 |
+
|
16 |
+
//Set up the buffering
|
17 |
+
function autoptimize_start_buffering()
|
18 |
+
{
|
19 |
+
//Pre-2.6 compatibility
|
20 |
+
if(!defined('WP_PLUGIN_URL'))
|
21 |
+
define('WP_PLUGIN_URL',WP_CONTENT_URL.'/plugins');
|
22 |
+
if(!defined('WP_PLUGIN_DIR'))
|
23 |
+
define('WP_PLUGIN_DIR',WP_CONTENT_DIR.'/plugins');
|
24 |
+
|
25 |
+
//Config element
|
26 |
+
$conf = autoptimizeConfig::instance();
|
27 |
+
|
28 |
+
//Load our always-on classes
|
29 |
+
@include(WP_PLUGIN_DIR.'/autoptimize/classes/autoptimizeBase.php');
|
30 |
+
@include(WP_PLUGIN_DIR.'/autoptimize/classes/autoptimizeCache.php');
|
31 |
+
|
32 |
+
//Load extra classes and set some vars
|
33 |
+
if($conf->get('autoptimize_html'))
|
34 |
+
{
|
35 |
+
@include(WP_PLUGIN_DIR.'/autoptimize/classes/autoptimizeHTML.php');
|
36 |
+
@include(WP_PLUGIN_DIR.'/autoptimize/classes/minify-html.php');
|
37 |
+
}
|
38 |
+
|
39 |
+
if($conf->get('autoptimize_js'))
|
40 |
+
{
|
41 |
+
@include(WP_PLUGIN_DIR.'/autoptimize/classes/autoptimizeScripts.php');
|
42 |
+
@include(WP_PLUGIN_DIR.'/autoptimize/classes/jsmin-1.1.1.php');
|
43 |
+
define('CONCATENATE_SCRIPTS',false);
|
44 |
+
define('COMPRESS_SCRIPTS',false);
|
45 |
+
}
|
46 |
+
|
47 |
+
if($conf->get('autoptimize_css'))
|
48 |
+
{
|
49 |
+
@include(WP_PLUGIN_DIR.'/autoptimize/classes/autoptimizeStyles.php');
|
50 |
+
@include(WP_PLUGIN_DIR.'/autoptimize/classes/minify-css-compressor.php');
|
51 |
+
define('COMPRESS_CSS',false);
|
52 |
+
}
|
53 |
+
|
54 |
+
//Now, start the real thing!
|
55 |
+
ob_start('autoptimize_end_buffering');
|
56 |
+
}
|
57 |
+
|
58 |
+
//Action on end -
|
59 |
+
function autoptimize_end_buffering($content)
|
60 |
+
{
|
61 |
+
//Config element
|
62 |
+
$conf = autoptimizeConfig::instance();
|
63 |
+
|
64 |
+
//Choose the classes
|
65 |
+
$classes = array();
|
66 |
+
if($conf->get('autoptimize_js'))
|
67 |
+
$classes[] = 'autoptimizeScripts';
|
68 |
+
if($conf->get('autoptimize_css'))
|
69 |
+
$classes[] = 'autoptimizeStyles';
|
70 |
+
if($conf->get('autoptimize_html'))
|
71 |
+
$classes[] = 'autoptimizeHTML';
|
72 |
+
|
73 |
+
//Run the classes
|
74 |
+
foreach($classes as $name)
|
75 |
+
{
|
76 |
+
$instance = new $name($content);
|
77 |
+
if($instance->read())
|
78 |
+
{
|
79 |
+
$instance->minify();
|
80 |
+
$instance->cache();
|
81 |
+
$content = $instance->getcontent();
|
82 |
+
}
|
83 |
+
unset($instance);
|
84 |
+
}
|
85 |
+
return $content;
|
86 |
+
}
|
87 |
+
|
88 |
+
|
89 |
+
$conf = autoptimizeConfig::instance();
|
90 |
+
if($conf->get('autoptimize_html') || $conf->get('autoptimize_js') || $conf->get('autoptimize_css'))
|
91 |
+
{
|
92 |
+
//Hook to wordpress
|
93 |
+
add_action('template_redirect','autoptimize_start_buffering',2);
|
94 |
+
}
|
classes/autoptimizeBase.php
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
abstract class autoptimizeBase
|
4 |
+
{
|
5 |
+
protected $content = '';
|
6 |
+
|
7 |
+
public function __construct($content)
|
8 |
+
{
|
9 |
+
$this->content = $content;
|
10 |
+
//Best place to catch errors
|
11 |
+
}
|
12 |
+
|
13 |
+
//Reads the page and collects tags
|
14 |
+
abstract public function read();
|
15 |
+
|
16 |
+
//Joins and optimizes collected things
|
17 |
+
abstract public function minify();
|
18 |
+
|
19 |
+
//Caches the things
|
20 |
+
abstract public function cache();
|
21 |
+
|
22 |
+
//Returns the content
|
23 |
+
abstract public function getcontent();
|
24 |
+
|
25 |
+
//Converts an URL to a full path
|
26 |
+
protected function getpath($url)
|
27 |
+
{
|
28 |
+
$path = str_replace(get_settings('home'),'',$url);
|
29 |
+
if(preg_match('#^(https?|ftp)://#i',$path))
|
30 |
+
{
|
31 |
+
//External script (adsense, etc)
|
32 |
+
return false;
|
33 |
+
}
|
34 |
+
$path = str_replace('//','/',ABSPATH.$path);
|
35 |
+
return $path;
|
36 |
+
}
|
37 |
+
}
|
classes/autoptimizeCache.php
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class autopimizeCache
|
4 |
+
{
|
5 |
+
private $filename;
|
6 |
+
private $mime;
|
7 |
+
private $cachedir;
|
8 |
+
|
9 |
+
public function __construct($cachedir,$md5)
|
10 |
+
{
|
11 |
+
$this->cachedir = $cachedir;
|
12 |
+
$this->filename = 'autoptimize_'.$md5.'.php';
|
13 |
+
}
|
14 |
+
|
15 |
+
public function check()
|
16 |
+
{
|
17 |
+
if(!file_exists($this->cachedir.$this->filename))
|
18 |
+
{
|
19 |
+
//No cached file, sorry
|
20 |
+
return false;
|
21 |
+
}
|
22 |
+
//Cache exists!
|
23 |
+
return true;
|
24 |
+
}
|
25 |
+
|
26 |
+
public function cache($code,$mime)
|
27 |
+
{
|
28 |
+
$phpcode = file_get_contents(WP_PLUGIN_DIR.'/autoptimize/config/default.php');
|
29 |
+
$phpcode = str_replace(array('%%CONTENT%%','exit;'),array($mime,''),$phpcode);
|
30 |
+
file_put_contents($this->cachedir.$this->filename,$phpcode);
|
31 |
+
file_put_contents($this->cachedir.$this->filename.'.deflate',gzencode($code,9,FORCE_DEFLATE));
|
32 |
+
file_put_contents($this->cachedir.$this->filename.'.gzip',gzencode($code,9,FORCE_GZIP));
|
33 |
+
file_put_contents($this->cachedir.$this->filename.'.none',$code);
|
34 |
+
}
|
35 |
+
|
36 |
+
public function getname()
|
37 |
+
{
|
38 |
+
return $this->filename;
|
39 |
+
}
|
40 |
+
}
|
classes/autoptimizeConfig.php
ADDED
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class autoptimizeConfig
|
4 |
+
{
|
5 |
+
private $config = null;
|
6 |
+
static private $instance = null;
|
7 |
+
|
8 |
+
private function __construct()
|
9 |
+
{
|
10 |
+
//Singleton
|
11 |
+
if(is_admin())
|
12 |
+
{
|
13 |
+
//Add the admin page and settings
|
14 |
+
add_action('admin_menu',array($this,'addmenu'));
|
15 |
+
add_action('admin_init',array($this,'registersettings'));
|
16 |
+
}
|
17 |
+
}
|
18 |
+
|
19 |
+
static public function instance()
|
20 |
+
{
|
21 |
+
//Only one instance
|
22 |
+
if (self::$instance == null)
|
23 |
+
{
|
24 |
+
self::$instance = new autoptimizeConfig();
|
25 |
+
}
|
26 |
+
|
27 |
+
return self::$instance;
|
28 |
+
}
|
29 |
+
|
30 |
+
public function show()
|
31 |
+
{
|
32 |
+
?>
|
33 |
+
<div class="wrap">
|
34 |
+
<h2>Autoptimize Settings</h2>
|
35 |
+
|
36 |
+
<form method="post" action="options.php">
|
37 |
+
<?php settings_fields('autoptimize'); ?>
|
38 |
+
<table class="form-table">
|
39 |
+
|
40 |
+
<tr valign="top">
|
41 |
+
<th scope="row">Optimize HTML Code?</th>
|
42 |
+
<td><input type="checkbox" name="autoptimize_html" <?php echo get_option('autoptimize_html')?'checked="checked" ':''; ?>/></td>
|
43 |
+
</tr>
|
44 |
+
|
45 |
+
<tr valign="top">
|
46 |
+
<th scope="row">Optimize JavaScript Code?</th>
|
47 |
+
<td><input type="checkbox" name="autoptimize_js" <?php echo get_option('autoptimize_js')?'checked="checked" ':''; ?>/></td>
|
48 |
+
</tr>
|
49 |
+
|
50 |
+
<tr valign="top">
|
51 |
+
<th scope="row">Optimize CSS Code? </th>
|
52 |
+
<td><input type="checkbox" name="autoptimize_css" <?php echo get_option('autoptimize_css')?'checked="checked" ':''; ?>/></td>
|
53 |
+
</tr>
|
54 |
+
|
55 |
+
</table>
|
56 |
+
|
57 |
+
<p class="submit">
|
58 |
+
<input type="submit" class="button-primary" value="<?php _e('Save Changes') ?>" />
|
59 |
+
</p>
|
60 |
+
|
61 |
+
</form>
|
62 |
+
</div>
|
63 |
+
<?php
|
64 |
+
}
|
65 |
+
|
66 |
+
public function addmenu()
|
67 |
+
{
|
68 |
+
add_options_page('Autoptimize Options','Autoptimize',8,'autoptimize',array($this,'show'));
|
69 |
+
}
|
70 |
+
|
71 |
+
public function registersettings()
|
72 |
+
{
|
73 |
+
register_setting('autoptimize','autoptimize_html');
|
74 |
+
register_setting('autoptimize','autoptimize_js');
|
75 |
+
register_setting('autoptimize','autoptimize_css');
|
76 |
+
}
|
77 |
+
|
78 |
+
public function get($key)
|
79 |
+
{
|
80 |
+
if(!is_array($this->config))
|
81 |
+
{
|
82 |
+
//Default config
|
83 |
+
$config = array('autoptimize_html' => 1,
|
84 |
+
'autoptimize_js' => 1,
|
85 |
+
'autoptimize_css' => 1);
|
86 |
+
|
87 |
+
//Override with user settings
|
88 |
+
if(get_option('autoptimize_html')!==false)
|
89 |
+
$config['autoptimize_html'] = get_option('autoptimize_html');
|
90 |
+
if(get_option('autoptimize_js')!==false)
|
91 |
+
$config['autoptimize_js'] = get_option('autoptimize_js');
|
92 |
+
if(get_option('autoptimize_css')!==false)
|
93 |
+
$config['autoptimize_css'] = get_option('autoptimize_css');
|
94 |
+
|
95 |
+
//Save for next question
|
96 |
+
$this->config = $config;
|
97 |
+
}
|
98 |
+
|
99 |
+
if(isset($this->config[$key]))
|
100 |
+
return $this->config[$key];
|
101 |
+
|
102 |
+
return false;
|
103 |
+
}
|
104 |
+
}
|
classes/autoptimizeHTML.php
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class autoptimizeHTML extends autoptimizeBase
|
4 |
+
{
|
5 |
+
private $url = '';
|
6 |
+
|
7 |
+
//Does nothing
|
8 |
+
public function read()
|
9 |
+
{
|
10 |
+
//Nothing to read for HTML
|
11 |
+
return true;
|
12 |
+
}
|
13 |
+
|
14 |
+
//Joins and optimizes CSS
|
15 |
+
public function minify()
|
16 |
+
{
|
17 |
+
if(class_exists('Minify_HTML'))
|
18 |
+
{
|
19 |
+
//Remove whitespace
|
20 |
+
$this->content = Minify_HTML::minify($this->content);
|
21 |
+
return true;
|
22 |
+
}
|
23 |
+
|
24 |
+
//Didn't minify :(
|
25 |
+
return false;
|
26 |
+
}
|
27 |
+
|
28 |
+
//Does nothing
|
29 |
+
public function cache()
|
30 |
+
{
|
31 |
+
//No cache for HTML
|
32 |
+
return true;
|
33 |
+
}
|
34 |
+
|
35 |
+
//Returns the content
|
36 |
+
public function getcontent()
|
37 |
+
{
|
38 |
+
return $this->content;
|
39 |
+
}
|
40 |
+
}
|
classes/autoptimizeScripts.php
ADDED
@@ -0,0 +1,158 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class autoptimizeScripts extends autoptimizeBase
|
4 |
+
{
|
5 |
+
private $scripts = array();
|
6 |
+
private $dontmove = array('document.write','google_ad_client','show_ads.js');
|
7 |
+
private $domove = array('gaJsHost');
|
8 |
+
private $jscode = '';
|
9 |
+
private $url = '';
|
10 |
+
private $move = array();
|
11 |
+
|
12 |
+
//Reads the page and collects script tags
|
13 |
+
public function read()
|
14 |
+
{
|
15 |
+
//Get script files
|
16 |
+
if(preg_match_all('#<script.*</script>#Usmi',$this->content,$matches))
|
17 |
+
{
|
18 |
+
foreach($matches[0] as $tag)
|
19 |
+
{
|
20 |
+
if(preg_match('#src=("|\')(.*)("|\')#Usmi',$tag,$source))
|
21 |
+
{
|
22 |
+
//External script
|
23 |
+
$url = current(explode('?',$source[2],2));
|
24 |
+
$path = $this->getpath($url);
|
25 |
+
if($path !==false && preg_match('#\.js$#',$path))
|
26 |
+
{
|
27 |
+
//Good script
|
28 |
+
$this->scripts[] = $path;
|
29 |
+
}else{
|
30 |
+
//External script (example: google analytics)
|
31 |
+
//OR Script is dynamic (.php etc)
|
32 |
+
if($this->ismovable($tag))
|
33 |
+
{
|
34 |
+
$this->move[] = $tag;
|
35 |
+
}
|
36 |
+
}
|
37 |
+
}else{
|
38 |
+
//Inline script
|
39 |
+
if($this->ismergeable($tag))
|
40 |
+
{
|
41 |
+
preg_match('#<script.*>(.*)</script>#Usmi',$tag,$code);
|
42 |
+
$code = preg_replace('#.*<!\[CDATA\[(?:\s*\*/)?(.*)(?://|/\*)\s*?\]\]>.*#sm','$1',$code[1]);
|
43 |
+
$code = preg_replace('/(?:^\\s*<!--\\s*|\\s*(?:\\/\\/)?\\s*-->\\s*$)/','',$code);
|
44 |
+
$this->scripts[] = 'INLINE;'.$code;
|
45 |
+
}else{
|
46 |
+
//Can we move this?
|
47 |
+
if($this->ismovable($tag))
|
48 |
+
{
|
49 |
+
$this->move[] = $tag;
|
50 |
+
}/*else{
|
51 |
+
//We shouldn't touch this
|
52 |
+
}*/
|
53 |
+
}
|
54 |
+
}
|
55 |
+
|
56 |
+
//Remove the original script tag
|
57 |
+
$this->content = str_replace($tag,'',$this->content);
|
58 |
+
}
|
59 |
+
|
60 |
+
return true;
|
61 |
+
}
|
62 |
+
|
63 |
+
//No script files :(
|
64 |
+
return false;
|
65 |
+
}
|
66 |
+
|
67 |
+
//Joins and optimizes JS
|
68 |
+
public function minify()
|
69 |
+
{
|
70 |
+
foreach($this->scripts as $script)
|
71 |
+
{
|
72 |
+
if(preg_match('#^INLINE;#',$script))
|
73 |
+
{
|
74 |
+
//Inline script
|
75 |
+
$script = preg_replace('#^INLINE;#','',$script);
|
76 |
+
$this->jscode .= "\n".$script;
|
77 |
+
}else{
|
78 |
+
//External script
|
79 |
+
if($script !== false && file_exists($script) && is_readable($script))
|
80 |
+
{
|
81 |
+
$script = file_get_contents($script);
|
82 |
+
$this->jscode .= "\n".$script;
|
83 |
+
}/*else{
|
84 |
+
//Couldn't read JS. Maybe getpath isn't working?
|
85 |
+
}*/
|
86 |
+
}
|
87 |
+
}
|
88 |
+
|
89 |
+
//$this->jscode has all the uncompressed code now.
|
90 |
+
if(class_exists('JSMin'))
|
91 |
+
{
|
92 |
+
$this->jscode = trim(JSMin::minify($this->jscode));
|
93 |
+
return true;
|
94 |
+
}
|
95 |
+
|
96 |
+
return false;
|
97 |
+
}
|
98 |
+
|
99 |
+
//Caches the JS in uncompressed, deflated and gzipped form.
|
100 |
+
public function cache()
|
101 |
+
{
|
102 |
+
$md5 = md5($this->jscode);
|
103 |
+
$cache = new autopimizeCache(WP_PLUGIN_DIR.'/autoptimize/cache/',$md5);
|
104 |
+
if(!$cache->check())
|
105 |
+
{
|
106 |
+
//Cache our code
|
107 |
+
$cache->cache($this->jscode,'text/javascript');
|
108 |
+
}
|
109 |
+
$this->url = WP_PLUGIN_URL.'/autoptimize/cache/'.$cache->getname();
|
110 |
+
}
|
111 |
+
|
112 |
+
//Returns the content
|
113 |
+
public function getcontent()
|
114 |
+
{
|
115 |
+
$bodyreplacement = implode('',$this->move).'<script type="text/javascript" src="'.$this->url.'"></script></body>';
|
116 |
+
$this->content = str_replace('</body>',$bodyreplacement,$this->content);
|
117 |
+
return $this->content;
|
118 |
+
}
|
119 |
+
|
120 |
+
//Checks agains the whitelist
|
121 |
+
private function ismergeable($tag)
|
122 |
+
{
|
123 |
+
foreach($this->domove as $match)
|
124 |
+
{
|
125 |
+
if(strpos($tag,$match)!==false)
|
126 |
+
{
|
127 |
+
//Matched something
|
128 |
+
return false;
|
129 |
+
}
|
130 |
+
}
|
131 |
+
|
132 |
+
//If we're here it's safe to merge
|
133 |
+
return true;
|
134 |
+
}
|
135 |
+
|
136 |
+
//Checks agains the blacklist
|
137 |
+
private function ismovable($tag)
|
138 |
+
{
|
139 |
+
$allowed = !$this->ismergeable($tag);
|
140 |
+
|
141 |
+
if($allowed == true)
|
142 |
+
{
|
143 |
+
return true;
|
144 |
+
}
|
145 |
+
|
146 |
+
foreach($this->dontmove as $match)
|
147 |
+
{
|
148 |
+
if(strpos($tag,$match)!==false)
|
149 |
+
{
|
150 |
+
//Matched something
|
151 |
+
return false;
|
152 |
+
}
|
153 |
+
}
|
154 |
+
|
155 |
+
//If we're here it's safe to move
|
156 |
+
return true;
|
157 |
+
}
|
158 |
+
}
|
classes/autoptimizeStyles.php
ADDED
@@ -0,0 +1,149 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class autoptimizeStyles extends autoptimizeBase
|
4 |
+
{
|
5 |
+
private $css = array();
|
6 |
+
private $csscode = '';
|
7 |
+
private $url = '';
|
8 |
+
|
9 |
+
//Reads the page and collects style tags
|
10 |
+
public function read()
|
11 |
+
{
|
12 |
+
//Save IE hacks
|
13 |
+
$this->content = preg_replace('#(<\!--\[if IE.*\]>.*<\!\[endif\]-->)#Usie',
|
14 |
+
'\'%%IEHACK%%\'.base64_encode("$1").\'%%IEHACK%%\'',$this->content);
|
15 |
+
|
16 |
+
//Get <style> and <link>
|
17 |
+
if(preg_match_all('#(<style[^>]*>.*</style>)|(<link[^>]*text/css[^>]*>)#Usmi',$this->content,$matches))
|
18 |
+
{
|
19 |
+
foreach($matches[0] as $tag)
|
20 |
+
{
|
21 |
+
if(preg_match('#<link.*href=("|\')(.*)("|\')#Usmi',$tag,$source))
|
22 |
+
{
|
23 |
+
//<link>
|
24 |
+
$url = current(explode('?',$source[2],2));
|
25 |
+
$path = $this->getpath($url);
|
26 |
+
if($path !==false && preg_match('#\.css$#',$path))
|
27 |
+
{
|
28 |
+
//Good link
|
29 |
+
$this->css[] = $path;
|
30 |
+
}else{
|
31 |
+
//Link is dynamic (.php etc)
|
32 |
+
$tag = '';
|
33 |
+
}
|
34 |
+
}else{
|
35 |
+
//<style>
|
36 |
+
preg_match('#<style.*>(.*)</style>#Usmi',$tag,$code);
|
37 |
+
$code = preg_replace('#.*<!\[CDATA\[(?:\s*\*/)?(.*)(?://|/\*)\s*?\]\]>.*#sm','$1',$code[1]);
|
38 |
+
$this->css[] = 'INLINE;'.$code;
|
39 |
+
}
|
40 |
+
|
41 |
+
//Remove the original style tag
|
42 |
+
$this->content = str_replace($tag,'',$this->content);
|
43 |
+
}
|
44 |
+
|
45 |
+
return true;
|
46 |
+
}
|
47 |
+
|
48 |
+
//No styles :(
|
49 |
+
return false;
|
50 |
+
}
|
51 |
+
|
52 |
+
//Joins and optimizes CSS
|
53 |
+
public function minify()
|
54 |
+
{
|
55 |
+
foreach($this->css as $css)
|
56 |
+
{
|
57 |
+
if(preg_match('#^INLINE;#',$css))
|
58 |
+
{
|
59 |
+
//<style>
|
60 |
+
$css = preg_replace('#^INLINE;#','',$css);
|
61 |
+
$css = $this->fixurls(ABSPATH.'/index.php',$css);
|
62 |
+
$this->csscode .= "\n/*FILESTART*/".$css;
|
63 |
+
}else{
|
64 |
+
//<link>
|
65 |
+
if($css !== false && file_exists($css) && is_readable($css))
|
66 |
+
{
|
67 |
+
$css = $this->fixurls($css,file_get_contents($css));
|
68 |
+
$this->csscode .= "\n/*FILESTART*/".$css;
|
69 |
+
}/*else{
|
70 |
+
//Couldn't read CSS. Maybe getpath isn't working?
|
71 |
+
}*/
|
72 |
+
}
|
73 |
+
}
|
74 |
+
|
75 |
+
//Manage @imports, while is for recursive import management
|
76 |
+
while(preg_match_all('#@import (?:url\()?.*(?:\)?)\s*;#',$this->csscode,$matches))
|
77 |
+
{
|
78 |
+
foreach($matches[0] as $import)
|
79 |
+
{
|
80 |
+
$url = preg_replace('#.*(?:url\()?(?:"|\')(.*)(?:"|\')(?:\))?.*$#','$1',$import);
|
81 |
+
$path = $this->getpath($url);
|
82 |
+
if(file_exists($path) && is_readable($path))
|
83 |
+
{
|
84 |
+
$code = $this->fixurls($path,file_get_contents($path));
|
85 |
+
$this->csscode = preg_replace('#(/\*FILESTART\*/.*)'.preg_quote($import,'#').'#Us',$code.'$1',$this->csscode);
|
86 |
+
}/*else{
|
87 |
+
//getpath is not working?
|
88 |
+
}*/
|
89 |
+
}
|
90 |
+
}
|
91 |
+
|
92 |
+
//$this->csscode has all the uncompressed code now.
|
93 |
+
if(class_exists('Minify_CSS_Compressor'))
|
94 |
+
{
|
95 |
+
$this->csscode = trim(Minify_CSS_Compressor::process($this->csscode));
|
96 |
+
return true;
|
97 |
+
}
|
98 |
+
|
99 |
+
return false;
|
100 |
+
}
|
101 |
+
|
102 |
+
//Caches the CSS in uncompressed, deflated and gzipped form.
|
103 |
+
public function cache()
|
104 |
+
{
|
105 |
+
$md5 = md5($this->csscode);
|
106 |
+
$cache = new autopimizeCache(WP_PLUGIN_DIR.'/autoptimize/cache/',$md5);
|
107 |
+
if(!$cache->check())
|
108 |
+
{
|
109 |
+
//Cache our code
|
110 |
+
$cache->cache($this->csscode,'text/css');
|
111 |
+
}
|
112 |
+
$this->url = WP_PLUGIN_URL.'/autoptimize/cache/'.$cache->getname();
|
113 |
+
}
|
114 |
+
|
115 |
+
//Returns the content
|
116 |
+
public function getcontent()
|
117 |
+
{
|
118 |
+
//Restore IE hacks
|
119 |
+
$this->content = preg_replace('#%%IEHACK%%(.*)%%IEHACK%%#Usie','base64_decode("$1")',$this->content);
|
120 |
+
$this->content = str_replace('</head>','<link type="text/css" href="'.$this->url.'" rel="stylesheet" /></head>',$this->content);
|
121 |
+
return $this->content;
|
122 |
+
}
|
123 |
+
|
124 |
+
private function fixurls($file,$code)
|
125 |
+
{
|
126 |
+
$file = str_replace(ABSPATH,'/',$file); //Sth like /wp-content/file.css
|
127 |
+
$dir = dirname($file); //Like /wp-content
|
128 |
+
|
129 |
+
if(preg_match_all('#url\((.*)\)#Usi',$code,$matches))
|
130 |
+
{
|
131 |
+
foreach($matches[1] as $url)
|
132 |
+
{
|
133 |
+
//Remove quotes
|
134 |
+
$url = preg_replace('#^(?:"|\')(.*)(?:"|\')$#','$1',$url);
|
135 |
+
if(substr($url,0,1)=='/' || preg_match('#^(https?|ftp)://#i',$url))
|
136 |
+
{
|
137 |
+
//URL is absolute
|
138 |
+
continue;
|
139 |
+
}else{
|
140 |
+
//relative URL. Let's fix it!
|
141 |
+
$newurl = get_settings('home').str_replace('//','/',$dir.'/'.$url); //http://yourblog.com/wp-content/../image.png
|
142 |
+
$code = str_replace($url,$newurl,$code);
|
143 |
+
}
|
144 |
+
}
|
145 |
+
}
|
146 |
+
|
147 |
+
return $code;
|
148 |
+
}
|
149 |
+
}
|
classes/jsmin-1.1.1.php
ADDED
@@ -0,0 +1,291 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* jsmin.php - PHP implementation of Douglas Crockford's JSMin.
|
4 |
+
*
|
5 |
+
* This is pretty much a direct port of jsmin.c to PHP with just a few
|
6 |
+
* PHP-specific performance tweaks. Also, whereas jsmin.c reads from stdin and
|
7 |
+
* outputs to stdout, this library accepts a string as input and returns another
|
8 |
+
* string as output.
|
9 |
+
*
|
10 |
+
* PHP 5 or higher is required.
|
11 |
+
*
|
12 |
+
* Permission is hereby granted to use this version of the library under the
|
13 |
+
* same terms as jsmin.c, which has the following license:
|
14 |
+
*
|
15 |
+
* --
|
16 |
+
* Copyright (c) 2002 Douglas Crockford (www.crockford.com)
|
17 |
+
*
|
18 |
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
19 |
+
* this software and associated documentation files (the "Software"), to deal in
|
20 |
+
* the Software without restriction, including without limitation the rights to
|
21 |
+
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
22 |
+
* of the Software, and to permit persons to whom the Software is furnished to do
|
23 |
+
* so, subject to the following conditions:
|
24 |
+
*
|
25 |
+
* The above copyright notice and this permission notice shall be included in all
|
26 |
+
* copies or substantial portions of the Software.
|
27 |
+
*
|
28 |
+
* The Software shall be used for Good, not Evil.
|
29 |
+
*
|
30 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
31 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
32 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
33 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
34 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
35 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
36 |
+
* SOFTWARE.
|
37 |
+
* --
|
38 |
+
*
|
39 |
+
* @package JSMin
|
40 |
+
* @author Ryan Grove <ryan@wonko.com>
|
41 |
+
* @copyright 2002 Douglas Crockford <douglas@crockford.com> (jsmin.c)
|
42 |
+
* @copyright 2008 Ryan Grove <ryan@wonko.com> (PHP port)
|
43 |
+
* @license http://opensource.org/licenses/mit-license.php MIT License
|
44 |
+
* @version 1.1.1 (2008-03-02)
|
45 |
+
* @link http://code.google.com/p/jsmin-php/
|
46 |
+
*/
|
47 |
+
|
48 |
+
class JSMin {
|
49 |
+
const ORD_LF = 10;
|
50 |
+
const ORD_SPACE = 32;
|
51 |
+
|
52 |
+
protected $a = '';
|
53 |
+
protected $b = '';
|
54 |
+
protected $input = '';
|
55 |
+
protected $inputIndex = 0;
|
56 |
+
protected $inputLength = 0;
|
57 |
+
protected $lookAhead = null;
|
58 |
+
protected $output = '';
|
59 |
+
|
60 |
+
// -- Public Static Methods --------------------------------------------------
|
61 |
+
|
62 |
+
public static function minify($js) {
|
63 |
+
$jsmin = new JSMin($js);
|
64 |
+
return $jsmin->min();
|
65 |
+
}
|
66 |
+
|
67 |
+
// -- Public Instance Methods ------------------------------------------------
|
68 |
+
|
69 |
+
public function __construct($input) {
|
70 |
+
$this->input = str_replace("\r\n", "\n", $input);
|
71 |
+
$this->inputLength = strlen($this->input);
|
72 |
+
}
|
73 |
+
|
74 |
+
// -- Protected Instance Methods ---------------------------------------------
|
75 |
+
|
76 |
+
protected function action($d) {
|
77 |
+
switch($d) {
|
78 |
+
case 1:
|
79 |
+
$this->output .= $this->a;
|
80 |
+
|
81 |
+
case 2:
|
82 |
+
$this->a = $this->b;
|
83 |
+
|
84 |
+
if ($this->a === "'" || $this->a === '"') {
|
85 |
+
for (;;) {
|
86 |
+
$this->output .= $this->a;
|
87 |
+
$this->a = $this->get();
|
88 |
+
|
89 |
+
if ($this->a === $this->b) {
|
90 |
+
break;
|
91 |
+
}
|
92 |
+
|
93 |
+
if (ord($this->a) <= self::ORD_LF) {
|
94 |
+
throw new JSMinException('Unterminated string literal.');
|
95 |
+
}
|
96 |
+
|
97 |
+
if ($this->a === '\\') {
|
98 |
+
$this->output .= $this->a;
|
99 |
+
$this->a = $this->get();
|
100 |
+
}
|
101 |
+
}
|
102 |
+
}
|
103 |
+
|
104 |
+
case 3:
|
105 |
+
$this->b = $this->next();
|
106 |
+
|
107 |
+
if ($this->b === '/' && (
|
108 |
+
$this->a === '(' || $this->a === ',' || $this->a === '=' ||
|
109 |
+
$this->a === ':' || $this->a === '[' || $this->a === '!' ||
|
110 |
+
$this->a === '&' || $this->a === '|' || $this->a === '?')) {
|
111 |
+
|
112 |
+
$this->output .= $this->a . $this->b;
|
113 |
+
|
114 |
+
for (;;) {
|
115 |
+
$this->a = $this->get();
|
116 |
+
|
117 |
+
if ($this->a === '/') {
|
118 |
+
break;
|
119 |
+
} elseif ($this->a === '\\') {
|
120 |
+
$this->output .= $this->a;
|
121 |
+
$this->a = $this->get();
|
122 |
+
} elseif (ord($this->a) <= self::ORD_LF) {
|
123 |
+
throw new JSMinException('Unterminated regular expression '.
|
124 |
+
'literal.');
|
125 |
+
}
|
126 |
+
|
127 |
+
$this->output .= $this->a;
|
128 |
+
}
|
129 |
+
|
130 |
+
$this->b = $this->next();
|
131 |
+
}
|
132 |
+
}
|
133 |
+
}
|
134 |
+
|
135 |
+
protected function get() {
|
136 |
+
$c = $this->lookAhead;
|
137 |
+
$this->lookAhead = null;
|
138 |
+
|
139 |
+
if ($c === null) {
|
140 |
+
if ($this->inputIndex < $this->inputLength) {
|
141 |
+
$c = $this->input[$this->inputIndex];
|
142 |
+
$this->inputIndex += 1;
|
143 |
+
} else {
|
144 |
+
$c = null;
|
145 |
+
}
|
146 |
+
}
|
147 |
+
|
148 |
+
if ($c === "\r") {
|
149 |
+
return "\n";
|
150 |
+
}
|
151 |
+
|
152 |
+
if ($c === null || $c === "\n" || ord($c) >= self::ORD_SPACE) {
|
153 |
+
return $c;
|
154 |
+
}
|
155 |
+
|
156 |
+
return ' ';
|
157 |
+
}
|
158 |
+
|
159 |
+
protected function isAlphaNum($c) {
|
160 |
+
return ord($c) > 126 || $c === '\\' || preg_match('/^[\w\$]$/', $c) === 1;
|
161 |
+
}
|
162 |
+
|
163 |
+
protected function min() {
|
164 |
+
$this->a = "\n";
|
165 |
+
$this->action(3);
|
166 |
+
|
167 |
+
while ($this->a !== null) {
|
168 |
+
switch ($this->a) {
|
169 |
+
case ' ':
|
170 |
+
if ($this->isAlphaNum($this->b)) {
|
171 |
+
$this->action(1);
|
172 |
+
} else {
|
173 |
+
$this->action(2);
|
174 |
+
}
|
175 |
+
break;
|
176 |
+
|
177 |
+
case "\n":
|
178 |
+
switch ($this->b) {
|
179 |
+
case '{':
|
180 |
+
case '[':
|
181 |
+
case '(':
|
182 |
+
case '+':
|
183 |
+
case '-':
|
184 |
+
$this->action(1);
|
185 |
+
break;
|
186 |
+
|
187 |
+
case ' ':
|
188 |
+
$this->action(3);
|
189 |
+
break;
|
190 |
+
|
191 |
+
default:
|
192 |
+
if ($this->isAlphaNum($this->b)) {
|
193 |
+
$this->action(1);
|
194 |
+
}
|
195 |
+
else {
|
196 |
+
$this->action(2);
|
197 |
+
}
|
198 |
+
}
|
199 |
+
break;
|
200 |
+
|
201 |
+
default:
|
202 |
+
switch ($this->b) {
|
203 |
+
case ' ':
|
204 |
+
if ($this->isAlphaNum($this->a)) {
|
205 |
+
$this->action(1);
|
206 |
+
break;
|
207 |
+
}
|
208 |
+
|
209 |
+
$this->action(3);
|
210 |
+
break;
|
211 |
+
|
212 |
+
case "\n":
|
213 |
+
switch ($this->a) {
|
214 |
+
case '}':
|
215 |
+
case ']':
|
216 |
+
case ')':
|
217 |
+
case '+':
|
218 |
+
case '-':
|
219 |
+
case '"':
|
220 |
+
case "'":
|
221 |
+
$this->action(1);
|
222 |
+
break;
|
223 |
+
|
224 |
+
default:
|
225 |
+
if ($this->isAlphaNum($this->a)) {
|
226 |
+
$this->action(1);
|
227 |
+
}
|
228 |
+
else {
|
229 |
+
$this->action(3);
|
230 |
+
}
|
231 |
+
}
|
232 |
+
break;
|
233 |
+
|
234 |
+
default:
|
235 |
+
$this->action(1);
|
236 |
+
break;
|
237 |
+
}
|
238 |
+
}
|
239 |
+
}
|
240 |
+
|
241 |
+
return $this->output;
|
242 |
+
}
|
243 |
+
|
244 |
+
protected function next() {
|
245 |
+
$c = $this->get();
|
246 |
+
|
247 |
+
if ($c === '/') {
|
248 |
+
switch($this->peek()) {
|
249 |
+
case '/':
|
250 |
+
for (;;) {
|
251 |
+
$c = $this->get();
|
252 |
+
|
253 |
+
if (ord($c) <= self::ORD_LF) {
|
254 |
+
return $c;
|
255 |
+
}
|
256 |
+
}
|
257 |
+
|
258 |
+
case '*':
|
259 |
+
$this->get();
|
260 |
+
|
261 |
+
for (;;) {
|
262 |
+
switch($this->get()) {
|
263 |
+
case '*':
|
264 |
+
if ($this->peek() === '/') {
|
265 |
+
$this->get();
|
266 |
+
return ' ';
|
267 |
+
}
|
268 |
+
break;
|
269 |
+
|
270 |
+
case null:
|
271 |
+
throw new JSMinException('Unterminated comment.');
|
272 |
+
}
|
273 |
+
}
|
274 |
+
|
275 |
+
default:
|
276 |
+
return $c;
|
277 |
+
}
|
278 |
+
}
|
279 |
+
|
280 |
+
return $c;
|
281 |
+
}
|
282 |
+
|
283 |
+
protected function peek() {
|
284 |
+
$this->lookAhead = $this->get();
|
285 |
+
return $this->lookAhead;
|
286 |
+
}
|
287 |
+
}
|
288 |
+
|
289 |
+
// -- Exceptions ---------------------------------------------------------------
|
290 |
+
class JSMinException extends Exception {}
|
291 |
+
?>
|
classes/minify-css-compressor.php
ADDED
@@ -0,0 +1,250 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Class Minify_CSS_Compressor
|
4 |
+
* @package Minify
|
5 |
+
*/
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Compress CSS
|
9 |
+
*
|
10 |
+
* This is a heavy regex-based removal of whitespace, unnecessary
|
11 |
+
* comments and tokens, and some CSS value minimization, where practical.
|
12 |
+
* Many steps have been taken to avoid breaking comment-based hacks,
|
13 |
+
* including the ie5/mac filter (and its inversion), but expect tricky
|
14 |
+
* hacks involving comment tokens in 'content' value strings to break
|
15 |
+
* minimization badly. A test suite is available.
|
16 |
+
*
|
17 |
+
* @package Minify
|
18 |
+
* @author Stephen Clay <steve@mrclay.org>
|
19 |
+
* @author http://code.google.com/u/1stvamp/ (Issue 64 patch)
|
20 |
+
*/
|
21 |
+
class Minify_CSS_Compressor {
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Minify a CSS string
|
25 |
+
*
|
26 |
+
* @param string $css
|
27 |
+
*
|
28 |
+
* @param array $options (currently ignored)
|
29 |
+
*
|
30 |
+
* @return string
|
31 |
+
*/
|
32 |
+
public static function process($css, $options = array())
|
33 |
+
{
|
34 |
+
$obj = new Minify_CSS_Compressor($options);
|
35 |
+
return $obj->_process($css);
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
* @var array options
|
40 |
+
*/
|
41 |
+
protected $_options = null;
|
42 |
+
|
43 |
+
/**
|
44 |
+
* @var bool Are we "in" a hack?
|
45 |
+
*
|
46 |
+
* I.e. are some browsers targetted until the next comment?
|
47 |
+
*/
|
48 |
+
protected $_inHack = false;
|
49 |
+
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Constructor
|
53 |
+
*
|
54 |
+
* @param array $options (currently ignored)
|
55 |
+
*
|
56 |
+
* @return null
|
57 |
+
*/
|
58 |
+
private function __construct($options) {
|
59 |
+
$this->_options = $options;
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Minify a CSS string
|
64 |
+
*
|
65 |
+
* @param string $css
|
66 |
+
*
|
67 |
+
* @return string
|
68 |
+
*/
|
69 |
+
protected function _process($css)
|
70 |
+
{
|
71 |
+
$css = str_replace("\r\n", "\n", $css);
|
72 |
+
|
73 |
+
// preserve empty comment after '>'
|
74 |
+
// http://www.webdevout.net/css-hacks#in_css-selectors
|
75 |
+
$css = preg_replace('@>/\\*\\s*\\*/@', '>/*keep*/', $css);
|
76 |
+
|
77 |
+
// preserve empty comment between property and value
|
78 |
+
// http://css-discuss.incutio.com/?page=BoxModelHack
|
79 |
+
$css = preg_replace('@/\\*\\s*\\*/\\s*:@', '/*keep*/:', $css);
|
80 |
+
$css = preg_replace('@:\\s*/\\*\\s*\\*/@', ':/*keep*/', $css);
|
81 |
+
|
82 |
+
// apply callback to all valid comments (and strip out surrounding ws
|
83 |
+
$css = preg_replace_callback('@\\s*/\\*([\\s\\S]*?)\\*/\\s*@'
|
84 |
+
,array($this, '_commentCB'), $css);
|
85 |
+
|
86 |
+
// remove ws around { } and last semicolon in declaration block
|
87 |
+
$css = preg_replace('/\\s*{\\s*/', '{', $css);
|
88 |
+
$css = preg_replace('/;?\\s*}\\s*/', '}', $css);
|
89 |
+
|
90 |
+
// remove ws surrounding semicolons
|
91 |
+
$css = preg_replace('/\\s*;\\s*/', ';', $css);
|
92 |
+
|
93 |
+
// remove ws around urls
|
94 |
+
$css = preg_replace('/
|
95 |
+
url\\( # url(
|
96 |
+
\\s*
|
97 |
+
([^\\)]+?) # 1 = the URL (really just a bunch of non right parenthesis)
|
98 |
+
\\s*
|
99 |
+
\\) # )
|
100 |
+
/x', 'url($1)', $css);
|
101 |
+
|
102 |
+
// remove ws between rules and colons
|
103 |
+
$css = preg_replace('/
|
104 |
+
\\s*
|
105 |
+
([{;]) # 1 = beginning of block or rule separator
|
106 |
+
\\s*
|
107 |
+
([\\*_]?[\\w\\-]+) # 2 = property (and maybe IE filter)
|
108 |
+
\\s*
|
109 |
+
:
|
110 |
+
\\s*
|
111 |
+
(\\b|[#\'"]) # 3 = first character of a value
|
112 |
+
/x', '$1$2:$3', $css);
|
113 |
+
|
114 |
+
// remove ws in selectors
|
115 |
+
$css = preg_replace_callback('/
|
116 |
+
(?: # non-capture
|
117 |
+
\\s*
|
118 |
+
[^~>+,\\s]+ # selector part
|
119 |
+
\\s*
|
120 |
+
[,>+~] # combinators
|
121 |
+
)+
|
122 |
+
\\s*
|
123 |
+
[^~>+,\\s]+ # selector part
|
124 |
+
{ # open declaration block
|
125 |
+
/x'
|
126 |
+
,array($this, '_selectorsCB'), $css);
|
127 |
+
|
128 |
+
// minimize hex colors
|
129 |
+
$css = preg_replace('/([^=])#([a-f\\d])\\2([a-f\\d])\\3([a-f\\d])\\4([\\s;\\}])/i'
|
130 |
+
, '$1#$2$3$4$5', $css);
|
131 |
+
|
132 |
+
// remove spaces between font families
|
133 |
+
$css = preg_replace_callback('/font-family:([^;}]+)([;}])/'
|
134 |
+
,array($this, '_fontFamilyCB'), $css);
|
135 |
+
|
136 |
+
$css = preg_replace('/@import\\s+url/', '@import url', $css);
|
137 |
+
|
138 |
+
// replace any ws involving newlines with a single newline
|
139 |
+
$css = preg_replace('/[ \\t]*\\n+\\s*/', "\n", $css);
|
140 |
+
|
141 |
+
// separate common descendent selectors w/ newlines (to limit line lengths)
|
142 |
+
$css = preg_replace('/([\\w#\\.\\*]+)\\s+([\\w#\\.\\*]+){/', "$1\n$2{", $css);
|
143 |
+
|
144 |
+
// Use newline after 1st numeric value (to limit line lengths).
|
145 |
+
$css = preg_replace('/
|
146 |
+
((?:padding|margin|border|outline):\\d+(?:px|em)?) # 1 = prop : 1st numeric value
|
147 |
+
\\s+
|
148 |
+
/x'
|
149 |
+
,"$1\n", $css);
|
150 |
+
|
151 |
+
// prevent triggering IE6 bug: http://www.crankygeek.com/ie6pebug/
|
152 |
+
$css = preg_replace('/:first-l(etter|ine)\\{/', ':first-l$1 {', $css);
|
153 |
+
|
154 |
+
return trim($css);
|
155 |
+
}
|
156 |
+
|
157 |
+
/**
|
158 |
+
* Replace what looks like a set of selectors
|
159 |
+
*
|
160 |
+
* @param array $m regex matches
|
161 |
+
*
|
162 |
+
* @return string
|
163 |
+
*/
|
164 |
+
protected function _selectorsCB($m)
|
165 |
+
{
|
166 |
+
// remove ws around the combinators
|
167 |
+
return preg_replace('/\\s*([,>+~])\\s*/', '$1', $m[0]);
|
168 |
+
}
|
169 |
+
|
170 |
+
/**
|
171 |
+
* Process a comment and return a replacement
|
172 |
+
*
|
173 |
+
* @param array $m regex matches
|
174 |
+
*
|
175 |
+
* @return string
|
176 |
+
*/
|
177 |
+
protected function _commentCB($m)
|
178 |
+
{
|
179 |
+
$hasSurroundingWs = (trim($m[0]) !== $m[1]);
|
180 |
+
$m = $m[1];
|
181 |
+
// $m is the comment content w/o the surrounding tokens,
|
182 |
+
// but the return value will replace the entire comment.
|
183 |
+
if ($m === 'keep') {
|
184 |
+
return '/**/';
|
185 |
+
}
|
186 |
+
if ($m === '" "') {
|
187 |
+
// component of http://tantek.com/CSS/Examples/midpass.html
|
188 |
+
return '/*" "*/';
|
189 |
+
}
|
190 |
+
if (preg_match('@";\\}\\s*\\}/\\*\\s+@', $m)) {
|
191 |
+
// component of http://tantek.com/CSS/Examples/midpass.html
|
192 |
+
return '/*";}}/* */';
|
193 |
+
}
|
194 |
+
if ($this->_inHack) {
|
195 |
+
// inversion: feeding only to one browser
|
196 |
+
if (preg_match('@
|
197 |
+
^/ # comment started like /*/
|
198 |
+
\\s*
|
199 |
+
(\\S[\\s\\S]+?) # has at least some non-ws content
|
200 |
+
\\s*
|
201 |
+
/\\* # ends like /*/ or /**/
|
202 |
+
@x', $m, $n)) {
|
203 |
+
// end hack mode after this comment, but preserve the hack and comment content
|
204 |
+
$this->_inHack = false;
|
205 |
+
return "/*/{$n[1]}/**/";
|
206 |
+
}
|
207 |
+
}
|
208 |
+
if (substr($m, -1) === '\\') { // comment ends like \*/
|
209 |
+
// begin hack mode and preserve hack
|
210 |
+
$this->_inHack = true;
|
211 |
+
return '/*\\*/';
|
212 |
+
}
|
213 |
+
if ($m !== '' && $m[0] === '/') { // comment looks like /*/ foo */
|
214 |
+
// begin hack mode and preserve hack
|
215 |
+
$this->_inHack = true;
|
216 |
+
return '/*/*/';
|
217 |
+
}
|
218 |
+
if ($this->_inHack) {
|
219 |
+
// a regular comment ends hack mode but should be preserved
|
220 |
+
$this->_inHack = false;
|
221 |
+
return '/**/';
|
222 |
+
}
|
223 |
+
// Issue 107: if there's any surrounding whitespace, it may be important, so
|
224 |
+
// replace the comment with a single space
|
225 |
+
return $hasSurroundingWs // remove all other comments
|
226 |
+
? ' '
|
227 |
+
: '';
|
228 |
+
}
|
229 |
+
|
230 |
+
/**
|
231 |
+
* Process a font-family listing and return a replacement
|
232 |
+
*
|
233 |
+
* @param array $m regex matches
|
234 |
+
*
|
235 |
+
* @return string
|
236 |
+
*/
|
237 |
+
protected function _fontFamilyCB($m)
|
238 |
+
{
|
239 |
+
$m[1] = preg_replace('/
|
240 |
+
\\s*
|
241 |
+
(
|
242 |
+
"[^"]+" # 1 = family in double qutoes
|
243 |
+
|\'[^\']+\' # or 1 = family in single quotes
|
244 |
+
|[\\w\\-]+ # or 1 = unquoted family
|
245 |
+
)
|
246 |
+
\\s*
|
247 |
+
/x', '$1', $m[1]);
|
248 |
+
return 'font-family:' . $m[1] . $m[2];
|
249 |
+
}
|
250 |
+
}
|
classes/minify-html.php
ADDED
@@ -0,0 +1,245 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Class Minify_HTML
|
4 |
+
* @package Minify
|
5 |
+
*/
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Compress HTML
|
9 |
+
*
|
10 |
+
* This is a heavy regex-based removal of whitespace, unnecessary comments and
|
11 |
+
* tokens. IE conditional comments are preserved. There are also options to have
|
12 |
+
* STYLE and SCRIPT blocks compressed by callback functions.
|
13 |
+
*
|
14 |
+
* A test suite is available.
|
15 |
+
*
|
16 |
+
* @package Minify
|
17 |
+
* @author Stephen Clay <steve@mrclay.org>
|
18 |
+
*/
|
19 |
+
class Minify_HTML {
|
20 |
+
|
21 |
+
/**
|
22 |
+
* "Minify" an HTML page
|
23 |
+
*
|
24 |
+
* @param string $html
|
25 |
+
*
|
26 |
+
* @param array $options
|
27 |
+
*
|
28 |
+
* 'cssMinifier' : (optional) callback function to process content of STYLE
|
29 |
+
* elements.
|
30 |
+
*
|
31 |
+
* 'jsMinifier' : (optional) callback function to process content of SCRIPT
|
32 |
+
* elements. Note: the type attribute is ignored.
|
33 |
+
*
|
34 |
+
* 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
|
35 |
+
* unset, minify will sniff for an XHTML doctype.
|
36 |
+
*
|
37 |
+
* @return string
|
38 |
+
*/
|
39 |
+
public static function minify($html, $options = array()) {
|
40 |
+
$min = new Minify_HTML($html, $options);
|
41 |
+
return $min->process();
|
42 |
+
}
|
43 |
+
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Create a minifier object
|
47 |
+
*
|
48 |
+
* @param string $html
|
49 |
+
*
|
50 |
+
* @param array $options
|
51 |
+
*
|
52 |
+
* 'cssMinifier' : (optional) callback function to process content of STYLE
|
53 |
+
* elements.
|
54 |
+
*
|
55 |
+
* 'jsMinifier' : (optional) callback function to process content of SCRIPT
|
56 |
+
* elements. Note: the type attribute is ignored.
|
57 |
+
*
|
58 |
+
* 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
|
59 |
+
* unset, minify will sniff for an XHTML doctype.
|
60 |
+
*
|
61 |
+
* @return null
|
62 |
+
*/
|
63 |
+
public function __construct($html, $options = array())
|
64 |
+
{
|
65 |
+
$this->_html = str_replace("\r\n", "\n", trim($html));
|
66 |
+
if (isset($options['xhtml'])) {
|
67 |
+
$this->_isXhtml = (bool)$options['xhtml'];
|
68 |
+
}
|
69 |
+
if (isset($options['cssMinifier'])) {
|
70 |
+
$this->_cssMinifier = $options['cssMinifier'];
|
71 |
+
}
|
72 |
+
if (isset($options['jsMinifier'])) {
|
73 |
+
$this->_jsMinifier = $options['jsMinifier'];
|
74 |
+
}
|
75 |
+
}
|
76 |
+
|
77 |
+
|
78 |
+
/**
|
79 |
+
* Minify the markeup given in the constructor
|
80 |
+
*
|
81 |
+
* @return string
|
82 |
+
*/
|
83 |
+
public function process()
|
84 |
+
{
|
85 |
+
if ($this->_isXhtml === null) {
|
86 |
+
$this->_isXhtml = (false !== strpos($this->_html, '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML'));
|
87 |
+
}
|
88 |
+
|
89 |
+
$this->_replacementHash = 'MINIFYHTML' . md5($_SERVER['REQUEST_TIME']);
|
90 |
+
$this->_placeholders = array();
|
91 |
+
|
92 |
+
// replace SCRIPTs (and minify) with placeholders
|
93 |
+
$this->_html = preg_replace_callback(
|
94 |
+
'/(\\s*)(<script\\b[^>]*?>)([\\s\\S]*?)<\\/script>(\\s*)/i'
|
95 |
+
,array($this, '_removeScriptCB')
|
96 |
+
,$this->_html);
|
97 |
+
|
98 |
+
// replace STYLEs (and minify) with placeholders
|
99 |
+
$this->_html = preg_replace_callback(
|
100 |
+
'/\\s*(<style\\b[^>]*?>)([\\s\\S]*?)<\\/style>\\s*/i'
|
101 |
+
,array($this, '_removeStyleCB')
|
102 |
+
,$this->_html);
|
103 |
+
|
104 |
+
// remove HTML comments (not containing IE conditional comments).
|
105 |
+
$this->_html = preg_replace_callback(
|
106 |
+
'/<!--([\\s\\S]*?)-->/'
|
107 |
+
,array($this, '_commentCB')
|
108 |
+
,$this->_html);
|
109 |
+
|
110 |
+
// replace PREs with placeholders
|
111 |
+
$this->_html = preg_replace_callback('/\\s*(<pre\\b[^>]*?>[\\s\\S]*?<\\/pre>)\\s*/i'
|
112 |
+
,array($this, '_removePreCB')
|
113 |
+
,$this->_html);
|
114 |
+
|
115 |
+
// replace TEXTAREAs with placeholders
|
116 |
+
$this->_html = preg_replace_callback(
|
117 |
+
'/\\s*(<textarea\\b[^>]*?>[\\s\\S]*?<\\/textarea>)\\s*/i'
|
118 |
+
,array($this, '_removeTextareaCB')
|
119 |
+
,$this->_html);
|
120 |
+
|
121 |
+
// trim each line.
|
122 |
+
// @todo take into account attribute values that span multiple lines.
|
123 |
+
$this->_html = preg_replace('/^\\s+|\\s+$/m', '', $this->_html);
|
124 |
+
|
125 |
+
// remove ws around block/undisplayed elements
|
126 |
+
$this->_html = preg_replace('/\\s+(<\\/?(?:area|base(?:font)?|blockquote|body'
|
127 |
+
.'|caption|center|cite|col(?:group)?|dd|dir|div|dl|dt|fieldset|form'
|
128 |
+
.'|frame(?:set)?|h[1-6]|head|hr|html|legend|li|link|map|menu|meta'
|
129 |
+
.'|ol|opt(?:group|ion)|p|param|t(?:able|body|head|d|h||r|foot|itle)'
|
130 |
+
.'|ul)\\b[^>]*>)/i', '$1', $this->_html);
|
131 |
+
|
132 |
+
// remove ws outside of all elements
|
133 |
+
$this->_html = preg_replace_callback(
|
134 |
+
'/>([^<]+)</'
|
135 |
+
,array($this, '_outsideTagCB')
|
136 |
+
,$this->_html);
|
137 |
+
|
138 |
+
// use newlines before 1st attribute in open tags (to limit line lengths)
|
139 |
+
$this->_html = preg_replace('/(<[a-z\\-]+)\\s+([^>]+>)/i', "$1\n$2", $this->_html);
|
140 |
+
|
141 |
+
// fill placeholders
|
142 |
+
$this->_html = str_replace(
|
143 |
+
array_keys($this->_placeholders)
|
144 |
+
,array_values($this->_placeholders)
|
145 |
+
,$this->_html
|
146 |
+
);
|
147 |
+
return $this->_html;
|
148 |
+
}
|
149 |
+
|
150 |
+
protected function _commentCB($m)
|
151 |
+
{
|
152 |
+
return (0 === strpos($m[1], '[') || false !== strpos($m[1], '<!['))
|
153 |
+
? $m[0]
|
154 |
+
: '';
|
155 |
+
}
|
156 |
+
|
157 |
+
protected function _reservePlace($content)
|
158 |
+
{
|
159 |
+
$placeholder = '%' . $this->_replacementHash . count($this->_placeholders) . '%';
|
160 |
+
$this->_placeholders[$placeholder] = $content;
|
161 |
+
return $placeholder;
|
162 |
+
}
|
163 |
+
|
164 |
+
protected $_isXhtml = null;
|
165 |
+
protected $_replacementHash = null;
|
166 |
+
protected $_placeholders = array();
|
167 |
+
protected $_cssMinifier = null;
|
168 |
+
protected $_jsMinifier = null;
|
169 |
+
|
170 |
+
protected function _outsideTagCB($m)
|
171 |
+
{
|
172 |
+
return '>' . preg_replace('/^\\s+|\\s+$/', ' ', $m[1]) . '<';
|
173 |
+
}
|
174 |
+
|
175 |
+
protected function _removePreCB($m)
|
176 |
+
{
|
177 |
+
return $this->_reservePlace($m[1]);
|
178 |
+
}
|
179 |
+
|
180 |
+
protected function _removeTextareaCB($m)
|
181 |
+
{
|
182 |
+
return $this->_reservePlace($m[1]);
|
183 |
+
}
|
184 |
+
|
185 |
+
protected function _removeStyleCB($m)
|
186 |
+
{
|
187 |
+
$openStyle = $m[1];
|
188 |
+
$css = $m[2];
|
189 |
+
// remove HTML comments
|
190 |
+
$css = preg_replace('/(?:^\\s*<!--|-->\\s*$)/', '', $css);
|
191 |
+
|
192 |
+
// remove CDATA section markers
|
193 |
+
$css = $this->_removeCdata($css);
|
194 |
+
|
195 |
+
// minify
|
196 |
+
$minifier = $this->_cssMinifier
|
197 |
+
? $this->_cssMinifier
|
198 |
+
: 'trim';
|
199 |
+
$css = call_user_func($minifier, $css);
|
200 |
+
|
201 |
+
return $this->_reservePlace($this->_needsCdata($css)
|
202 |
+
? "{$openStyle}/*<![CDATA[*/{$css}/*]]>*/</style>"
|
203 |
+
: "{$openStyle}{$css}</style>"
|
204 |
+
);
|
205 |
+
}
|
206 |
+
|
207 |
+
protected function _removeScriptCB($m)
|
208 |
+
{
|
209 |
+
$openScript = $m[2];
|
210 |
+
$js = $m[3];
|
211 |
+
|
212 |
+
// whitespace surrounding? preserve at least one space
|
213 |
+
$ws1 = ($m[1] === '') ? '' : ' ';
|
214 |
+
$ws2 = ($m[4] === '') ? '' : ' ';
|
215 |
+
|
216 |
+
// remove HTML comments (and ending "//" if present)
|
217 |
+
$js = preg_replace('/(?:^\\s*<!--\\s*|\\s*(?:\\/\\/)?\\s*-->\\s*$)/', '', $js);
|
218 |
+
|
219 |
+
// remove CDATA section markers
|
220 |
+
$js = $this->_removeCdata($js);
|
221 |
+
|
222 |
+
// minify
|
223 |
+
$minifier = $this->_jsMinifier
|
224 |
+
? $this->_jsMinifier
|
225 |
+
: 'trim';
|
226 |
+
$js = call_user_func($minifier, $js);
|
227 |
+
|
228 |
+
return $this->_reservePlace($this->_needsCdata($js)
|
229 |
+
? "{$ws1}{$openScript}/*<![CDATA[*/{$js}/*]]>*/</script>{$ws2}"
|
230 |
+
: "{$ws1}{$openScript}{$js}</script>{$ws2}"
|
231 |
+
);
|
232 |
+
}
|
233 |
+
|
234 |
+
protected function _removeCdata($str)
|
235 |
+
{
|
236 |
+
return (false !== strpos($str, '<![CDATA['))
|
237 |
+
? str_replace(array('<![CDATA[', ']]>'), '', $str)
|
238 |
+
: $str;
|
239 |
+
}
|
240 |
+
|
241 |
+
protected function _needsCdata($str)
|
242 |
+
{
|
243 |
+
return ($this->_isXhtml && preg_match('/(?:[<&]|\\-\\-|\\]\\]>)/', $str));
|
244 |
+
}
|
245 |
+
}
|
config/default.php
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php exit;
|
2 |
+
// Determine supported compression method
|
3 |
+
$gzip = strstr($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip');
|
4 |
+
$deflate = strstr($_SERVER['HTTP_ACCEPT_ENCODING'], 'deflate');
|
5 |
+
|
6 |
+
// Determine used compression method
|
7 |
+
$encoding = $gzip ? 'gzip' : ($deflate ? 'deflate' : 'none');
|
8 |
+
|
9 |
+
// Check for buggy versions of Internet Explorer
|
10 |
+
if (!strstr($_SERVER['HTTP_USER_AGENT'], 'Opera') &&
|
11 |
+
preg_match('/^Mozilla\/4\.0 \(compatible; MSIE ([0-9]\.[0-9])/i', $_SERVER['HTTP_USER_AGENT'], $matches))
|
12 |
+
{
|
13 |
+
$version = floatval($matches[1]);
|
14 |
+
|
15 |
+
if ($version < 6)
|
16 |
+
$encoding = 'none';
|
17 |
+
|
18 |
+
if ($version == 6 && !strstr($_SERVER['HTTP_USER_AGENT'], 'EV1'))
|
19 |
+
$encoding = 'none';
|
20 |
+
}
|
21 |
+
|
22 |
+
//Get data
|
23 |
+
$contents = file_get_contents(__FILE__.'.'.$encoding);
|
24 |
+
|
25 |
+
if (isset($encoding) && $encoding != 'none')
|
26 |
+
{
|
27 |
+
// Send compressed contents
|
28 |
+
header('Content-Encoding: '.$encoding);
|
29 |
+
header('Content-Length: '.strlen($contents));
|
30 |
+
}
|
31 |
+
header('Vary: Accept-Encoding');
|
32 |
+
|
33 |
+
header('Content-type: %%CONTENT%%; charset=utf-8');
|
34 |
+
header('Cache-Control: max-age=315360000, public, must-revalidate');
|
35 |
+
header('Expires: '.gmdate('D, d M Y H:i:s', time() + 315360000).' GMT'); //10 years
|
36 |
+
|
37 |
+
echo $contents;
|
readme.txt
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
=== Autoptimize ===
|
2 |
+
Contributors: turl
|
3 |
+
Donate link: http://www.turleando.com.ar/autoptimize/
|
4 |
+
Tags: css, html, javascript, js, optimize, speed, cache
|
5 |
+
Requires at least: 2.6
|
6 |
+
Tested up to: 2.8
|
7 |
+
Stable tag: 0.1
|
8 |
+
|
9 |
+
Autoptimize is a Wordpress plugin that automatically merges, minifies and compresses CSS, Javascript and HTML code. It speeds up your visitor's browsing, and helps you save bandwidth.
|
10 |
+
|
11 |
+
== Description ==
|
12 |
+
|
13 |
+
Autoptimize makes optimizing your site really easy. It concatenates all scripts and styles, minifies and compresses them, adds expires headers, caches them, and moves styles to the page head, and scripts to the footer. It also minifies the HTML code itself, making your page really lightweight.
|
14 |
+
|
15 |
+
I also recommend using WP Super Cache in conjuction with Autoptimize to speed up your blog.
|
16 |
+
|
17 |
+
== Installation ==
|
18 |
+
|
19 |
+
1. Upload the `autoptimize` folder to to the `/wp-content/plugins/` directory
|
20 |
+
1. Activate the plugin through the 'Plugins' menu in WordPress
|
21 |
+
1. Go to `Settings -> Autoptimize` and enable the options you want. Generally this means all the options, but if you experience problems you might want to disable some.
|
22 |
+
|
23 |
+
== Frequently Asked Questions ==
|
24 |
+
|
25 |
+
= What does the plugin do to help speed up my site? =
|
26 |
+
|
27 |
+
It concatenates all scripts and styles, minifies and compresses them, adds expires headers, caches them, and moves styles to the page head, and scripts to the footer. It also minifies the HTML code itself, making your page really lightweight.
|
28 |
+
|
29 |
+
== Changelog ==
|
30 |
+
|
31 |
+
= 0.1 =
|
32 |
+
* First released version.
|