PluginProbe ʕ •ᴥ•ʔ
LiteSpeed Cache / 7.0.0.1
LiteSpeed Cache v7.0.0.1
trunk 1.0.15 1.9.1.1 2.9.9.2 3.6.4 4.6 5.7.0.1 6.5.4 7.0.0.1 7.0.1 7.1 7.2 7.3 7.3.0.1 7.4 7.5 7.5.0.1 7.6 7.6.1 7.6.2 7.7 7.8 7.8.0.1 7.8.1
litespeed-cache / lib / html-min.cls.php
litespeed-cache / lib Last commit date
css_js_min 1 year ago guest.cls.php 1 year ago html-min.cls.php 1 year ago object-cache.php 1 year ago php-compatibility.func.php 1 year ago urirewriter.cls.php 1 year ago
html-min.cls.php
288 lines
1 <?php
2 /**
3 * Compress HTML
4 *
5 * This is a heavy regex-based removal of whitespace, unnecessary comments and
6 * tokens. IE conditional comments are preserved. There are also options to have
7 * STYLE and SCRIPT blocks compressed by callback functions.
8 *
9 * A test suite is available.
10 *
11 * @package Minify
12 * @author Stephen Clay <steve@mrclay.org>
13 */
14 namespace LiteSpeed\Lib ;
15
16 defined( 'WPINC' ) || exit ;
17
18 class HTML_MIN
19 {
20 /**
21 * @var string
22 */
23 protected $_html = '';
24
25 /**
26 * @var boolean
27 */
28 protected $_jsCleanComments = true;
29 protected $_skipComments = array();
30
31 /**
32 * "Minify" an HTML page
33 *
34 * @param string $html
35 *
36 * @param array $options
37 *
38 * 'cssMinifier' : (optional) callback function to process content of STYLE
39 * elements.
40 *
41 * 'jsMinifier' : (optional) callback function to process content of SCRIPT
42 * elements. Note: the type attribute is ignored.
43 *
44 * 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
45 * unset, minify will sniff for an XHTML doctype.
46 *
47 * @return string
48 */
49 public static function minify($html, $options = array())
50 {
51 $min = new self($html, $options);
52
53 return $min->process();
54 }
55
56 /**
57 * Create a minifier object
58 *
59 * @param string $html
60 *
61 * @param array $options
62 *
63 * 'cssMinifier' : (optional) callback function to process content of STYLE
64 * elements.
65 *
66 * 'jsMinifier' : (optional) callback function to process content of SCRIPT
67 * elements. Note: the type attribute is ignored.
68 *
69 * 'jsCleanComments' : (optional) whether to remove HTML comments beginning and end of script block
70 *
71 * 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
72 * unset, minify will sniff for an XHTML doctype.
73 */
74 public function __construct($html, $options = array())
75 {
76 $this->_html = str_replace("\r\n", "\n", trim($html));
77 if (isset($options['xhtml'])) {
78 $this->_isXhtml = (bool)$options['xhtml'];
79 }
80 if (isset($options['cssMinifier'])) {
81 $this->_cssMinifier = $options['cssMinifier'];
82 }
83 if (isset($options['jsMinifier'])) {
84 $this->_jsMinifier = $options['jsMinifier'];
85 }
86 if (isset($options['jsCleanComments'])) {
87 $this->_jsCleanComments = (bool)$options['jsCleanComments'];
88 }
89 if (isset($options['skipComments'])) {
90 $this->_skipComments = $options['skipComments'];
91 }
92 }
93
94 /**
95 * Minify the markeup given in the constructor
96 *
97 * @return string
98 */
99 public function process()
100 {
101 if ($this->_isXhtml === null) {
102 $this->_isXhtml = (false !== strpos($this->_html, '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML'));
103 }
104
105 $this->_replacementHash = 'MINIFYHTML' . md5($_SERVER['REQUEST_TIME']);
106 $this->_placeholders = array();
107
108 // replace SCRIPTs (and minify) with placeholders
109 $this->_html = preg_replace_callback(
110 '/(\\s*)<script(\\b[^>]*?>)([\\s\\S]*?)<\\/script>(\\s*)/i'
111 ,array($this, '_removeScriptCB')
112 ,$this->_html);
113
114 // replace STYLEs (and minify) with placeholders
115 $this->_html = preg_replace_callback(
116 '/\\s*<style(\\b[^>]*>)([\\s\\S]*?)<\\/style>\\s*/i'
117 ,array($this, '_removeStyleCB')
118 ,$this->_html);
119
120 // remove HTML comments (not containing IE conditional comments).
121 $this->_html = preg_replace_callback(
122 '/<!--([\\s\\S]*?)-->/'
123 ,array($this, '_commentCB')
124 ,$this->_html);
125
126 // replace PREs with placeholders
127 $this->_html = preg_replace_callback('/\\s*<pre(\\b[^>]*?>[\\s\\S]*?<\\/pre>)\\s*/i'
128 ,array($this, '_removePreCB')
129 ,$this->_html);
130
131 // replace TEXTAREAs with placeholders
132 $this->_html = preg_replace_callback(
133 '/\\s*<textarea(\\b[^>]*?>[\\s\\S]*?<\\/textarea>)\\s*/i'
134 ,array($this, '_removeTextareaCB')
135 ,$this->_html);
136
137 // trim each line.
138 // @todo take into account attribute values that span multiple lines.
139 $this->_html = preg_replace('/^\\s+|\\s+$/m', '', $this->_html);
140
141 // remove ws around block/undisplayed elements
142 $this->_html = preg_replace('/\\s+(<\\/?(?:area|article|aside|base(?:font)?|blockquote|body'
143 .'|canvas|caption|center|col(?:group)?|dd|dir|div|dl|dt|fieldset|figcaption|figure|footer|form'
144 .'|frame(?:set)?|h[1-6]|head|header|hgroup|hr|html|legend|li|link|main|map|menu|meta|nav'
145 .'|ol|opt(?:group|ion)|output|p|param|section|t(?:able|body|head|d|h||r|foot|itle)'
146 .'|ul|video)\\b[^>]*>)/i', '$1', $this->_html);
147
148 // remove ws outside of all elements
149 $this->_html = preg_replace(
150 '/>(\\s(?:\\s*))?([^<]+)(\\s(?:\s*))?</'
151 ,'>$1$2$3<'
152 ,$this->_html);
153
154 // use newlines before 1st attribute in open tags (to limit line lengths)
155 // $this->_html = preg_replace('/(<[a-z\\-]+)\\s+([^>]+>)/i', "$1\n$2", $this->_html);
156
157 // fill placeholders
158 $this->_html = str_replace(
159 array_keys($this->_placeholders)
160 ,array_values($this->_placeholders)
161 ,$this->_html
162 );
163 // issue 229: multi-pass to catch scripts that didn't get replaced in textareas
164 $this->_html = str_replace(
165 array_keys($this->_placeholders)
166 ,array_values($this->_placeholders)
167 ,$this->_html
168 );
169
170 return $this->_html;
171 }
172
173 /**
174 * From LSCWP 6.2: Changed the function to test for special comments that will be skipped. See: https://github.com/litespeedtech/lscache_wp/pull/622
175 */
176 protected function _commentCB($m)
177 {
178 // If is IE conditional comment return it.
179 if(0 === strpos($m[1], '[') || false !== strpos($m[1], '<![')) return $m[0];
180
181 // Check if comment text is present in Page Optimization -> HTML Settings -> HTML Keep comments
182 if(count($this->_skipComments) > 0){
183 foreach ($this->_skipComments as $comment) {
184 if ($comment && strpos($m[1], $comment) !== false) {
185 return $m[0];
186 }
187 }
188 }
189
190 // Comment can be removed.
191 return '';
192 }
193
194 protected function _reservePlace($content)
195 {
196 $placeholder = '%' . $this->_replacementHash . count($this->_placeholders) . '%';
197 $this->_placeholders[$placeholder] = $content;
198
199 return $placeholder;
200 }
201
202 protected $_isXhtml = null;
203 protected $_replacementHash = null;
204 protected $_placeholders = array();
205 protected $_cssMinifier = null;
206 protected $_jsMinifier = null;
207
208 protected function _removePreCB($m)
209 {
210 return $this->_reservePlace("<pre{$m[1]}");
211 }
212
213 protected function _removeTextareaCB($m)
214 {
215 return $this->_reservePlace("<textarea{$m[1]}");
216 }
217
218 protected function _removeStyleCB($m)
219 {
220 $openStyle = "<style{$m[1]}";
221 $css = $m[2];
222 // remove HTML comments
223 $css = preg_replace('/(?:^\\s*<!--|-->\\s*$)/', '', $css);
224
225 // remove CDATA section markers
226 $css = $this->_removeCdata($css);
227
228 // minify
229 $minifier = $this->_cssMinifier
230 ? $this->_cssMinifier
231 : 'trim';
232 $css = call_user_func($minifier, $css);
233
234 return $this->_reservePlace($this->_needsCdata($css)
235 ? "{$openStyle}/*<![CDATA[*/{$css}/*]]>*/</style>"
236 : "{$openStyle}{$css}</style>"
237 );
238 }
239
240 protected function _removeScriptCB($m)
241 {
242 $openScript = "<script{$m[2]}";
243 $js = $m[3];
244
245 // whitespace surrounding? preserve at least one space
246 $ws1 = ($m[1] === '') ? '' : ' ';
247 $ws2 = ($m[4] === '') ? '' : ' ';
248
249 // remove HTML comments (and ending "//" if present)
250 if ($this->_jsCleanComments) {
251 $js = preg_replace('/(?:^\\s*<!--\\s*|\\s*(?:\\/\\/)?\\s*-->\\s*$)/', '', $js);
252 }
253
254 // remove CDATA section markers
255 $js = $this->_removeCdata($js);
256
257 // minify
258 /**
259 * Added 2nd param by LiteSpeed
260 *
261 * @since 2.2.3
262 */
263 if ( $this->_jsMinifier ) {
264 $js = call_user_func( $this->_jsMinifier, $js, trim( $m[ 2 ] ) ) ;
265 }
266 else {
267 $js = trim( $js ) ;
268 }
269
270 return $this->_reservePlace($this->_needsCdata($js)
271 ? "{$ws1}{$openScript}/*<![CDATA[*/{$js}/*]]>*/</script>{$ws2}"
272 : "{$ws1}{$openScript}{$js}</script>{$ws2}"
273 );
274 }
275
276 protected function _removeCdata($str)
277 {
278 return (false !== strpos($str, '<![CDATA['))
279 ? str_replace(array('<![CDATA[', ']]>'), '', $str)
280 : $str;
281 }
282
283 protected function _needsCdata($str)
284 {
285 return ($this->_isXhtml && preg_match('/(?:[<&]|\\-\\-|\\]\\]>)/', $str));
286 }
287 }
288