PluginProbe
Autoptimize / 2.3.3
Autoptimize v2.3.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 / external / php / minify-2.1.7-html.php

minify-2.1.7-html.php in Autoptimize 2.3.3, at classes/external/php/minify-2.1.7-html.php

258 lines 8.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 * @var boolean
22 */
23 protected $_jsCleanComments = true;
24
25 /**
26 * "Minify" an HTML page
27 *
28 * @param string $html
29 *
30 * @param array $options
31 *
32 * 'cssMinifier' : (optional) callback function to process content of STYLE
33 * elements.
34 *
35 * 'jsMinifier' : (optional) callback function to process content of SCRIPT
36 * elements. Note: the type attribute is ignored.
37 *
38 * 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
39 * unset, minify will sniff for an XHTML doctype.
40 *
41 * @return string
42 */
43 public static function minify($html, $options = array()) {
44 $min = new self($html, $options);
45 return $min->process();
46 }
47
48
49 /**
50 * Create a minifier object
51 *
52 * @param string $html
53 *
54 * @param array $options
55 *
56 * 'cssMinifier' : (optional) callback function to process content of STYLE
57 * elements.
58 *
59 * 'jsMinifier' : (optional) callback function to process content of SCRIPT
60 * elements. Note: the type attribute is ignored.
61 *
62 * 'jsCleanComments' : (optional) whether to remove HTML comments beginning and end of script block
63 *
64 * 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
65 * unset, minify will sniff for an XHTML doctype.
66 *
67 * @return null
68 */
69 public function __construct($html, $options = array())
70 {
71 $this->_html = str_replace("\r\n", "\n", trim($html));
72 if (isset($options['xhtml'])) {
73 $this->_isXhtml = (bool)$options['xhtml'];
74 }
75 if (isset($options['cssMinifier'])) {
76 $this->_cssMinifier = $options['cssMinifier'];
77 }
78 if (isset($options['jsMinifier'])) {
79 $this->_jsMinifier = $options['jsMinifier'];
80 }
81 if (isset($options['jsCleanComments'])) {
82 $this->_jsCleanComments = (bool)$options['jsCleanComments'];
83 }
84 }
85
86
87 /**
88 * Minify the markeup given in the constructor
89 *
90 * @return string
91 */
92 public function process()
93 {
94 if ($this->_isXhtml === null) {
95 $this->_isXhtml = (false !== strpos($this->_html, '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML'));
96 }
97
98 $this->_replacementHash = 'MINIFYHTML' . md5($_SERVER['REQUEST_TIME']);
99 $this->_placeholders = array();
100
101 // replace SCRIPTs (and minify) with placeholders
102 $this->_html = preg_replace_callback(
103 '/(\\s*)<script(\\b[^>]*?>)([\\s\\S]*?)<\\/script>(\\s*)/i'
104 ,array($this, '_removeScriptCB')
105 ,$this->_html);
106
107 // replace STYLEs (and minify) with placeholders
108 $this->_html = preg_replace_callback(
109 '/\\s*<style(\\b[^>]*>)([\\s\\S]*?)<\\/style>\\s*/i'
110 ,array($this, '_removeStyleCB')
111 ,$this->_html);
112
113 // remove HTML comments (not containing IE conditional comments).
114 $this->_html = preg_replace_callback(
115 '/<!--([\\s\\S]*?)-->/'
116 ,array($this, '_commentCB')
117 ,$this->_html);
118
119 // replace PREs with placeholders
120 $this->_html = preg_replace_callback('/\\s*<pre(\\b[^>]*?>[\\s\\S]*?<\\/pre>)\\s*/i'
121 ,array($this, '_removePreCB')
122 ,$this->_html);
123
124 // replace TEXTAREAs with placeholders
125 $this->_html = preg_replace_callback(
126 '/\\s*<textarea(\\b[^>]*?>[\\s\\S]*?<\\/textarea>)\\s*/i'
127 ,array($this, '_removeTextareaCB')
128 ,$this->_html);
129
130 // trim each line.
131 // @todo take into account attribute values that span multiple lines.
132 $this->_html = preg_replace('/^\\s+|\\s+$/m', '', $this->_html);
133
134 // remove ws around block/undisplayed elements
135 $this->_html = preg_replace('/\\s+(<\\/?(?:area|base(?:font)?|blockquote|body'
136 .'|caption|center|cite|col(?:group)?|dd|dir|div|dl|dt|fieldset|form'
137 .'|frame(?:set)?|h[1-6]|head|hr|html|legend|li|link|map|menu|meta'
138 .'|ol|opt(?:group|ion)|p|param|t(?:able|body|head|d|h||r|foot|itle)'
139 .'|ul)\\b[^>]*>)/i', '$1', $this->_html);
140
141 // remove ws outside of all elements
142 $this->_html = preg_replace(
143 '/>(\\s(?:\\s*))?([^<]+)(\\s(?:\s*))?</'
144 ,'>$1$2$3<'
145 ,$this->_html);
146
147 // use newlines before 1st attribute in open tags (to limit line lengths)
148 $this->_html = preg_replace('/(<[a-z\\-]+)\\s+([^>]+>)/i', "$1\n$2", $this->_html);
149
150 // fill placeholders
151 $this->_html = str_replace(
152 array_keys($this->_placeholders)
153 ,array_values($this->_placeholders)
154 ,$this->_html
155 );
156 // issue 229: multi-pass to catch scripts that didn't get replaced in textareas
157 $this->_html = str_replace(
158 array_keys($this->_placeholders)
159 ,array_values($this->_placeholders)
160 ,$this->_html
161 );
162 return $this->_html;
163 }
164
165 protected function _commentCB($m)
166 {
167 return (0 === strpos($m[1], '[') || false !== strpos($m[1], '<!['))
168 ? $m[0]
169 : '';
170 }
171
172 protected function _reservePlace($content)
173 {
174 $placeholder = '%' . $this->_replacementHash . count($this->_placeholders) . '%';
175 $this->_placeholders[$placeholder] = $content;
176 return $placeholder;
177 }
178
179 protected $_isXhtml = null;
180 protected $_replacementHash = null;
181 protected $_placeholders = array();
182 protected $_cssMinifier = null;
183 protected $_jsMinifier = null;
184
185 protected function _removePreCB($m)
186 {
187 return $this->_reservePlace("<pre{$m[1]}");
188 }
189
190 protected function _removeTextareaCB($m)
191 {
192 return $this->_reservePlace("<textarea{$m[1]}");
193 }
194
195 protected function _removeStyleCB($m)
196 {
197 $openStyle = "<style{$m[1]}";
198 $css = $m[2];
199 // remove HTML comments
200 $css = preg_replace('/(?:^\\s*<!--|-->\\s*$)/', '', $css);
201
202 // remove CDATA section markers
203 $css = $this->_removeCdata($css);
204
205 // minify
206 $minifier = $this->_cssMinifier
207 ? $this->_cssMinifier
208 : 'trim';
209 $css = call_user_func($minifier, $css);
210
211 return $this->_reservePlace($this->_needsCdata($css)
212 ? "{$openStyle}/*<![CDATA[*/{$css}/*]]>*/</style>"
213 : "{$openStyle}{$css}</style>"
214 );
215 }
216
217 protected function _removeScriptCB($m)
218 {
219 $openScript = "<script{$m[2]}";
220 $js = $m[3];
221
222 // whitespace surrounding? preserve at least one space
223 $ws1 = ($m[1] === '') ? '' : ' ';
224 $ws2 = ($m[4] === '') ? '' : ' ';
225
226 // remove HTML comments (and ending "//" if present)
227 if ($this->_jsCleanComments) {
228 $js = preg_replace('/(?:^\\s*<!--\\s*|\\s*(?:\\/\\/)?\\s*-->\\s*$)/', '', $js);
229 }
230
231 // remove CDATA section markers
232 $js = $this->_removeCdata($js);
233
234 // minify
235 $minifier = $this->_jsMinifier
236 ? $this->_jsMinifier
237 : 'trim';
238 $js = call_user_func($minifier, $js);
239
240 return $this->_reservePlace($this->_needsCdata($js)
241 ? "{$ws1}{$openScript}/*<![CDATA[*/{$js}/*]]>*/</script>{$ws2}"
242 : "{$ws1}{$openScript}{$js}</script>{$ws2}"
243 );
244 }
245
246 protected function _removeCdata($str)
247 {
248 return (false !== strpos($str, '<![CDATA['))
249 ? str_replace(array('<![CDATA[', ']]>'), '', $str)
250 : $str;
251 }
252
253 protected function _needsCdata($str)
254 {
255 return ($this->_isXhtml && preg_match('/(?:[<&]|\\-\\-|\\]\\]>)/', $str));
256 }
257 }
258