Autoptimize - Version 0.1

Version Description

  • First released version.
Download this release

Release Info

Developer turl
Plugin Icon 128x128 Autoptimize
Version 0.1
Comparing to
See all releases

Version 0.1

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&eacute;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.