PluginProbe
Autoptimize / 1.4
Autoptimize v1.4
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 1.4, at classes/autoptimizeStyles.php

350 lines 9.7 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 private $mhtml = '';
9 private $datauris = false;
10 private $yui = false;
11 private $hashmap = array();
12
13 //Reads the page and collects style tags
14 public function read($options)
15 {
16 //Remove everything that's not the header
17 if($options['justhead'] == true)
18 {
19 $content = explode('</head>',$this->content,2);
20 $this->content = $content[0].'</head>';
21 $this->restofcontent = $content[1];
22 }
23
24 //Store data: URIs setting for later use
25 $this->datauris = $options['datauris'];
26
27 //Do we use yui?
28 $this->yui = $options['yui'];
29
30 //Save IE hacks
31 $this->content = preg_replace('#(<\!--\[if.*\]>.*<\!\[endif\]-->)#Usie',
32 '\'%%IEHACK%%\'.base64_encode("$1").\'%%IEHACK%%\'',$this->content);
33
34 //Get <style> and <link>
35 if(preg_match_all('#(<style[^>]*>.*</style>)|(<link[^>]*text/css[^>]*>)#Usmi',$this->content,$matches))
36 {
37 foreach($matches[0] as $tag)
38 {
39 //Get the media
40 if(strpos($tag,'media=')!==false)
41 {
42 preg_match('#media=(?:"|\')([^>]*)(?:"|\')#Ui',$tag,$medias);
43 $medias = explode(',',$medias[1]);
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 if(preg_match('#<link.*href=("|\')(.*)("|\')#Usmi',$tag,$source))
55 {
56 //<link>
57 $url = current(explode('?',$source[2],2));
58 $path = $this->getpath($url);
59
60 if($path !==false && preg_match('#\.css$#',$path))
61 {
62 //Good link
63 $this->css[] = array($media,$path);
64 }else{
65 //Link is dynamic (.php etc)
66 $tag = '';
67 }
68 }else{
69 //<style>
70 preg_match('#<style.*>(.*)</style>#Usmi',$tag,$code);
71 $code = preg_replace('#^.*<!\[CDATA\[(?:\s*\*/)?(.*)(?://|/\*)\s*?\]\]>.*$#sm','$1',$code[1]);
72 $this->css[] = array($media,'INLINE;'.$code);
73 }
74
75 //Remove the original style tag
76 $this->content = str_replace($tag,'',$this->content);
77 }
78
79 return true;
80 }
81
82 //No styles :(
83 return false;
84 }
85
86 //Joins and optimizes CSS
87 public function minify()
88 {
89 foreach($this->css as $group)
90 {
91 list($media,$css) = $group;
92 if(preg_match('#^INLINE;#',$css))
93 {
94 //<style>
95 $css = preg_replace('#^INLINE;#','',$css);
96 $css = $this->fixurls(ABSPATH.'/index.php',$css);
97 }else{
98 //<link>
99 if($css !== false && file_exists($css) && is_readable($css))
100 {
101 $css = $this->fixurls($css,file_get_contents($css));
102 }else{
103 //Couldn't read CSS. Maybe getpath isn't working?
104 $css = '';
105 }
106 }
107
108 foreach($media as $elem)
109 {
110 if(!isset($this->csscode[$elem]))
111 $this->csscode[$elem] = '';
112 $this->csscode[$elem] .= "\n/*FILESTART*/".$css;
113 }
114 }
115
116 //Check for duplicate code
117 $md5list = array();
118 $tmpcss = $this->csscode;
119 foreach($tmpcss as $media => $code)
120 {
121 $md5sum = md5($code);
122 $medianame = $media;
123 foreach($md5list as $med => $sum)
124 {
125 //If same code
126 if($sum === $md5sum)
127 {
128 //Add the merged code
129 $medianame = $med.', '.$media;
130 $this->csscode[$medianame] = $code;
131 $md5list[$medianame] = $md5list[$med];
132 unset($this->csscode[$med], $this->csscode[$media]);
133 unset($md5list[$med]);
134 }
135 }
136 $md5list[$medianame] = $md5sum;
137 }
138 unset($tmpcss);
139
140 //Manage @imports, while is for recursive import management
141 foreach($this->csscode as &$thiscss)
142 {
143 //Flag to trigger import reconstitution
144 $fiximports = false;
145 while(preg_match_all('#@import.*(?:;|$)#Um',$thiscss,$matches))
146 {
147 foreach($matches[0] as $import)
148 {
149 $url = trim(preg_replace('#^.*((?:https?|ftp)://.*\.css).*$#','$1',$import)," \t\n\r\0\x0B\"'");
150 $path = $this->getpath($url);
151 if(file_exists($path) && is_readable($path))
152 {
153 $code = $this->fixurls($path,file_get_contents($path));
154 /*$media = preg_replace('#^.*(?:\)|"|\')(.*)(?:\s|;).*$#','$1',$import);
155 $media = array_map('trim',explode(' ',$media));
156 if(empty($media))
157 {
158 $thiscss = [...] (Line under)
159 }else{
160 //media in @import - how should I handle these?
161 //TODO: Infinite recursion!
162 }*/
163 $thiscss = preg_replace('#(/\*FILESTART\*/.*)'.preg_quote($import,'#').'#Us','/*FILESTART2*/'.$code.'$1',$thiscss);
164 }else{
165 //getpath is not working?
166 //Encode so preg_match doesn't see it
167 $thiscss = str_replace($import,'/*IMPORT*/'.base64_encode($import).'/*IMPORT*/',$thiscss);
168 $fiximports = true;
169 }
170 }
171 $thiscss = preg_replace('#/\*FILESTART\*/#','',$thiscss);
172 $thiscss = preg_replace('#/\*FILESTART2\*/#','/*FILESTART*/',$thiscss);
173 }
174
175 //Recover imports
176 if($fiximports)
177 {
178 $thiscss = preg_replace('#/\*IMPORT\*/(.*)/\*IMPORT\*/#Use','base64_decode("$1")',$thiscss);
179 }
180 }
181 unset($thiscss);
182
183 //$this->csscode has all the uncompressed code now.
184 $mhtmlcount = 0;
185 foreach($this->csscode as &$code)
186 {
187 //Check for already-minified code
188 $hash = md5($code);
189 $ccheck = new autoptimizeCache($hash,'css');
190 if($ccheck->check())
191 {
192 $code = $ccheck->retrieve();
193 $this->hashmap[md5($code)] = $hash;
194 continue;
195 }
196 unset($ccheck);
197
198 $imgreplace = array();
199 //Do the imaging!
200 if($this->datauris == true && function_exists('base64_encode') && preg_match_all('#(background[^;}]*url\((.*)\)[^;}]*)(?:;|$|})#Usm',$code,$matches))
201 {
202 foreach($matches[2] as $count => $quotedurl)
203 {
204 $url = trim($quotedurl," \t\n\r\0\x0B\"'");
205 $path = $this->getpath($url);
206 if($path != false && preg_match('#\.(jpe?j|png|gif|bmp)$#',$path) && file_exists($path) && is_readable($path) && filesize($path) <= 5120)
207 {
208 //It's an image
209 //Get type
210 switch(end(explode('.',$path)))
211 {
212 case 'jpej':
213 case 'jpg':
214 $dataurihead = 'data:image/jpeg;base64,';
215 break;
216 case 'gif':
217 $dataurihead = 'data:image/gif;base64,';
218 break;
219 case 'png':
220 $dataurihead = 'data:image/png;base64,';
221 break;
222 case 'bmp':
223 $dataurihead = 'data:image/bmp;base64,';
224 break;
225 default:
226 $dataurihead = 'data:application/octet-stream;base64,';
227 }
228
229 //Encode the data
230 $base64data = base64_encode(file_get_contents($path));
231
232 //Add it to the list for replacement
233 $imgreplace[$matches[1][$count]] = str_replace($quotedurl,$dataurihead.$base64data,$matches[1][$count]).";\n*".str_replace($quotedurl,'mhtml:%%MHTML%%!'.$mhtmlcount,$matches[1][$count]).";\n_".$matches[1][$count].';';
234
235 //Store image on the mhtml document
236 $this->mhtml .= "--_\r\nContent-Location:{$mhtmlcount}\r\nContent-Transfer-Encoding:base64\r\n\r\n{$base64data}\r\n";
237 $mhtmlcount++;
238 }
239 }
240 //Replace the images
241 $code = str_replace(array_keys($imgreplace),array_values($imgreplace),$code);
242 }
243
244 //Minify
245 if($this->yui == false && class_exists('Minify_CSS_Compressor'))
246 {
247 $code = trim(Minify_CSS_Compressor::process($code));
248 }elseif($this->yui == true && autoptimizeYUI::available()){
249 $code = autoptimizeYUI::compress('css',$code);
250 }
251
252 $this->hashmap[md5($code)] = $hash;
253 }
254 unset($code);
255 return true;
256 }
257
258 //Caches the CSS in uncompressed, deflated and gzipped form.
259 public function cache()
260 {
261 if($this->datauris)
262 {
263 //MHTML Preparation
264 $this->mhtml = "/*\r\nContent-Type: multipart/related; boundary=\"_\"\r\n\r\n".$this->mhtml."*/\r\n";
265 $md5 = md5($this->mhtml);
266 $cache = new autoptimizeCache($md5,'txt');
267 if(!$cache->check())
268 {
269 //Cache our images for IE
270 $cache->cache($this->mhtml,'text/plain');
271 }
272 $mhtml = AUTOPTIMIZE_CACHE_URL.$cache->getname();
273 }
274
275 //CSS cache
276 foreach($this->csscode as $media => $code)
277 {
278 if($this->datauris)
279 {
280 //Images for ie! Get the right url
281 $code = str_replace('%%MHTML%%',$mhtml,$code);
282 }
283
284 $md5 = $this->hashmap[md5($code)];
285 $cache = new autoptimizeCache($md5,'css');
286 if(!$cache->check())
287 {
288 //Cache our code
289 $cache->cache($code,'text/css');
290 }
291 $this->url[$media] = AUTOPTIMIZE_CACHE_URL.$cache->getname();
292 }
293 }
294
295 //Returns the content
296 public function getcontent()
297 {
298 //Restore IE hacks
299 $this->content = preg_replace('#%%IEHACK%%(.*)%%IEHACK%%#Usie','base64_decode("$1")',$this->content);
300
301 //Restore the full content
302 if(!empty($this->restofcontent))
303 {
304 $this->content .= $this->restofcontent;
305 $this->restofcontent = '';
306 }
307
308 //Add the new stylesheets
309 foreach($this->url as $media => $url)
310 {
311 $this->content = str_replace('</head>','<link type="text/css" media="'.$media.'" href="'.$url.'" rel="stylesheet" /></head>',$this->content);
312 }
313
314 //Return the modified stylesheet
315 return $this->content;
316 }
317
318 private function fixurls($file,$code)
319 {
320 $file = str_replace(ABSPATH,'/',$file); //Sth like /wp-content/file.css
321 $dir = dirname($file); //Like /wp-content
322
323 if(preg_match_all('#url\((.*)\)#Usi',$code,$matches))
324 {
325 $replace = array();
326 foreach($matches[1] as $k => $url)
327 {
328 //Remove quotes
329 $url = trim($url," \t\n\r\0\x0B\"'");
330 if(substr($url,0,1)=='/' || preg_match('#^(https?|ftp)://#i',$url))
331 {
332 //URL is absolute
333 continue;
334 }else{
335 //relative URL. Let's fix it!
336 $newurl = get_settings('home').str_replace('//','/',$dir.'/'.$url); //http://yourblog.com/wp-content/../image.png
337 $hash = md5($url);
338 $code = str_replace($matches[0][$k],$hash,$code);
339 $replace[$hash] = 'url('.$newurl.')';
340 }
341 }
342
343 //Do the replacing here to avoid breaking URLs
344 $code = str_replace(array_keys($replace),array_values($replace),$code);
345 }
346
347 return $code;
348 }
349 }
350