PluginProbe
Autoptimize / 0.9
Autoptimize v0.9
2.2.2 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.5.0 2.5.1 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 All 107 releases
autoptimize / classes / autoptimizeStyles.php

autoptimizeStyles.php in Autoptimize 0.9, at classes/autoptimizeStyles.php

258 lines 6.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 class autoptimizeStyles extends autoptimizeBase
3 {
4 private $css = array();
5 private $csscode = array();
6 private $url = array();
7 private $restofcontent = '';
8
9 //Reads the page and collects style tags
10 public function read($options)
11 {
12 //Remove everything that's not the header
13 if($options['justhead'] == true)
14 {
15 $content = explode('</head>',$this->content,2);
16 $this->content = $content[0].'</head>';
17 $this->restofcontent = $content[1];
18 }
19
20 //Save IE hacks
21 $this->content = preg_replace('#(<\!--\[if.*\]>.*<\!\[endif\]-->)#Usie',
22 '\'%%IEHACK%%\'.base64_encode("$1").\'%%IEHACK%%\'',$this->content);
23
24 //Get <style> and <link>
25 if(preg_match_all('#(<style[^>]*>.*</style>)|(<link[^>]*text/css[^>]*>)#Usmi',$this->content,$matches))
26 {
27 foreach($matches[0] as $tag)
28 {
29 if(preg_match('#<link.*href=("|\')(.*)("|\')#Usmi',$tag,$source))
30 {
31 //<link>
32 $url = current(explode('?',$source[2],2));
33 $path = $this->getpath($url);
34 $media = array('all');
35
36 if($path !==false && preg_match('#\.css$#',$path))
37 {
38 //Good link
39 //Get the media
40 if(strpos($tag,'media=')!==false)
41 {
42 $medias = preg_replace('#^.*media=(?:"|\')(.*)(?:"|\').*$#U','$1',$tag);
43 $medias = explode(',',$medias);
44 $media = array();
45 foreach($medias as $elem)
46 {
47 $media[] = current(explode(' ',trim($elem),2));
48 }
49 }else{
50 //No media specified - applies to all
51 $media = array('all');
52 }
53
54 $this->css[] = array($media,$path);
55 }else{
56 //Link is dynamic (.php etc)
57 $tag = '';
58 }
59 }else{
60 //<style>
61 preg_match('#<style.*>(.*)</style>#Usmi',$tag,$code);
62 $code = preg_replace('#^.*<!\[CDATA\[(?:\s*\*/)?(.*)(?://|/\*)\s*?\]\]>.*$#sm','$1',$code[1]);
63 $this->css[] = array('all','INLINE;'.$code);
64 }
65
66 //Remove the original style tag
67 $this->content = str_replace($tag,'',$this->content);
68 }
69
70 return true;
71 }
72
73 //No styles :(
74 return false;
75 }
76
77 //Joins and optimizes CSS
78 public function minify()
79 {
80 foreach($this->css as $group)
81 {
82 list($media,$css) = $group;
83 if(preg_match('#^INLINE;#',$css))
84 {
85 //<style>
86 $css = preg_replace('#^INLINE;#','',$css);
87 $css = $this->fixurls(ABSPATH.'/index.php',$css);
88 if(!isset($this->csscode['all']))
89 $this->csscode['all'] = '';
90 $this->csscode['all'] .= "\n/*FILESTART*/".$css;
91 }else{
92 //<link>
93 if($css !== false && file_exists($css) && is_readable($css))
94 {
95 $css = $this->fixurls($css,file_get_contents($css));
96 foreach($media as $elem)
97 {
98 if(!isset($this->csscode[$elem]))
99 $this->csscode[$elem] = '';
100 $this->csscode[$elem] .= "\n/*FILESTART*/".$css;
101 }
102 }/*else{
103 //Couldn't read CSS. Maybe getpath isn't working?
104 }*/
105 }
106 }
107
108 //Check for duplicate code
109 $md5list = array();
110 $tmpcss = $this->csscode;
111 foreach($tmpcss as $media => $code)
112 {
113 $md5sum = md5($code);
114 $medianame = $media;
115 foreach($md5list as $med => $sum)
116 {
117 //If same code
118 if($sum === $md5sum)
119 {
120 //Add the merged code
121 $medianame = $med.', '.$media;
122 $this->csscode[$medianame] = $code;
123 $md5list[$medianame] = $md5list[$med];
124 unset($this->csscode[$med], $this->csscode[$media]);
125 unset($md5list[$med]);
126 }
127 }
128 $md5list[$medianame] = $md5sum;
129 }
130 unset($tmpcss);
131
132 //Manage @imports, while is for recursive import management
133 foreach($this->csscode as &$thiscss)
134 {
135 //Flag to trigger import reconstitution
136 $fiximports = false;
137 while(preg_match_all('#@import.*(?:;|$)#Um',$thiscss,$matches))
138 {
139 foreach($matches[0] as $import)
140 {
141 $url = trim(preg_replace('#.+((?:https?|ftp)://.*\.css)(?:\s|"|\').+#','$1',$import)," \t\n\r\0\x0B\"'");
142 $path = $this->getpath($url);
143 if(file_exists($path) && is_readable($path))
144 {
145 $code = $this->fixurls($path,file_get_contents($path));
146 /*$media = preg_replace('#^.*(?:\)|"|\')(.*)(?:\s|;).*$#','$1',$import);
147 $media = array_map('trim',explode(' ',$media));
148 if(empty($media))
149 {
150 $thiscss = [...] (Line under)
151 }else{
152 //media in @import - how should I handle these?
153 //TODO: Infinite recursion!
154 }*/
155 $thiscss = preg_replace('#(/\*FILESTART\*/.*)'.preg_quote($import,'#').'#Us',$code.'$1',$thiscss);
156 }else{
157 //getpath is not working?
158 //Encode so preg_match doesn't see it
159 $thiscss = str_replace($import,'/*IMPORT*/'.base64_encode($import).'/*IMPORT*/',$thiscss);
160 $fiximports = true;
161 }
162 }
163 }
164
165 //Recover imports
166 if($fiximports)
167 {
168 $thiscss = preg_replace('#/\*IMPORT\*/(.*)/\*IMPORT\*/#Use','base64_decode("$1")',$thiscss);
169 }
170 }
171 unset($thiscss);
172
173 //$this->csscode has all the uncompressed code now.
174 if(class_exists('Minify_CSS_Compressor'))
175 {
176 foreach($this->csscode as &$code)
177 {
178 $code = trim(Minify_CSS_Compressor::process($code));
179 }
180 unset($code);
181 return true;
182 }
183
184 return false;
185 }
186
187 //Caches the CSS in uncompressed, deflated and gzipped form.
188 public function cache()
189 {
190 foreach($this->csscode as $media => $code)
191 {
192 $md5 = md5($code);
193 $cache = new autoptimizeCache($md5);
194 if(!$cache->check())
195 {
196 //Cache our code
197 $cache->cache($code,'text/css');
198 }
199 $this->url[$media] = AUTOPTIMIZE_CACHE_URL.$cache->getname();
200 }
201 }
202
203 //Returns the content
204 public function getcontent()
205 {
206 //Restore IE hacks
207 $this->content = preg_replace('#%%IEHACK%%(.*)%%IEHACK%%#Usie','base64_decode("$1")',$this->content);
208
209 //Restore the full content
210 if(!empty($this->restofcontent))
211 {
212 $this->content .= $this->restofcontent;
213 $this->restofcontent = '';
214 }
215
216 //Add the new stylesheets
217 foreach($this->url as $media => $url)
218 {
219 $this->content = str_replace('</head>','<link type="text/css" media="'.$media.'" href="'.$url.'" rel="stylesheet" /></head>',$this->content);
220 }
221
222 //Return the modified stylesheet
223 return $this->content;
224 }
225
226 private function fixurls($file,$code)
227 {
228 $file = str_replace(ABSPATH,'/',$file); //Sth like /wp-content/file.css
229 $dir = dirname($file); //Like /wp-content
230
231 if(preg_match_all('#url\((.*)\)#Usi',$code,$matches))
232 {
233 $replace = array();
234 foreach($matches[1] as $k => $url)
235 {
236 //Remove quotes
237 $url = trim($url," \t\n\r\0\x0B\"'");
238 if(substr($url,0,1)=='/' || preg_match('#^(https?|ftp)://#i',$url))
239 {
240 //URL is absolute
241 continue;
242 }else{
243 //relative URL. Let's fix it!
244 $newurl = get_settings('home').str_replace('//','/',$dir.'/'.$url); //http://yourblog.com/wp-content/../image.png
245 $hash = md5($url);
246 $code = str_replace($matches[0][$k],$hash,$code);
247 $replace[$hash] = 'url('.$newurl.')';
248 }
249 }
250
251 //Do the replacing here to avoid breaking URLs
252 $code = str_replace(array_keys($replace),array_values($replace),$code);
253 }
254
255 return $code;
256 }
257 }
258