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

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