Completed
Push — master ( 9a01d9...c990d6 )
by frank
08:32
created

classes/external/php/minify-html.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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 <[email protected]>
18
 */
19
class Minify_HTML {
20
21
    /**
22
     * "Minify" an HTML page
23
     *
24
     * @param string $html
25
     *
26
     * @param array $options
27
     *
28
     * 'cssMinifier' : (optional) callback function to process content of STYLE
29
     * elements.
30
     * 
31
     * 'jsMinifier' : (optional) callback function to process content of SCRIPT
32
     * elements. Note: the type attribute is ignored.
33
     * 
34
     * 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
35
     * unset, minify will sniff for an XHTML doctype.
36
	 * 
37
     * 'keepComments' : (optional boolean) should the HTML comments be kept
38
     * in the HTML Code?
39
     * 
40
     * @return string
41
     */
42
    public static function minify($html, $options = array()) {
43
        $min = new Minify_HTML($html, $options);
44
        return $min->process();
45
    }
46
    
47
    
48
    /**
49
     * Create a minifier object
50
     *
51
     * @param string $html
52
     *
53
     * @param array $options
54
     *
55
     * 'cssMinifier' : (optional) callback function to process content of STYLE
56
     * elements.
57
     * 
58
     * 'jsMinifier' : (optional) callback function to process content of SCRIPT
59
     * elements. Note: the type attribute is ignored.
60
     * 
61
     * 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
62
     * unset, minify will sniff for an XHTML doctype.
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['keepComments'])) {
82
            $this->_keepComments = $options['keepComments'];
83
        }
84
    }
85
    
86
    
87
    /**
88
     * Minify the markeup given in the constructor
89
     * 
90
     * @return string
91
     */
92
    public function process()
93
    {
94 View Code Duplication
        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
		if  ($this->_keepComments == false) {
115
			$this->_html = preg_replace_callback(
116
				'/<!--([\\s\\S]*?)-->/'
117
				,array($this, '_commentCB')
118
				,$this->_html);
119
        }
120
		
121
        // replace PREs with placeholders
122
        $this->_html = preg_replace_callback('/\\s*(<pre\\b[^>]*?>[\\s\\S]*?<\\/pre>)\\s*/i'
123
            ,array($this, '_removePreCB')
124
            ,$this->_html);
125
        
126
        // replace TEXTAREAs with placeholders
127
        $this->_html = preg_replace_callback(
128
            '/\\s*(<textarea\\b[^>]*?>[\\s\\S]*?<\\/textarea>)\\s*/i'
129
            ,array($this, '_removeTextareaCB')
130
            ,$this->_html);
131
			
132
		// replace data: URIs with placeholders
133
        $this->_html = preg_replace_callback(
134
            '/(=("|\')data:.*\\2)/Ui'
135
            ,array($this, '_removeDataURICB')
136
            ,$this->_html);
137
        
138
        // trim each line.
139
        // replace by space instead of '' to avoid newline after opening tag getting zapped
140
        $this->_html = preg_replace('/^\s+|\s+$/m', ' ', $this->_html);
141
        
142
        // remove ws around block/undisplayed elements
143
        $this->_html = preg_replace('/\\s+(<\\/?(?:area|article|aside|base(?:font)?|blockquote|body'
144
            .'|canvas|caption|center|col(?:group)?|dd|dir|div|dl|dt|fieldset|figcaption|figure|footer|form'
145
            .'|frame(?:set)?|h[1-6]|head|header|hgroup|hr|html|legend|li|link|main|map|menu|meta|nav'
146
            .'|ol|opt(?:group|ion)|output|p|param|section|t(?:able|body|head|d|h||r|foot|itle)'
147
            .'|ul|video)\\b[^>]*>)/i', '$1', $this->_html);
148
            
149
        // remove ws outside of all elements
150
        $this->_html = preg_replace_callback(
151
            '/>([^<]+)</'
152
            ,array($this, '_outsideTagCB')
153
            ,$this->_html);
154
        
155
        // use newlines before 1st attribute in open tags (to limit line lengths)
156
        //$this->_html = preg_replace('/(<[a-z\\-]+)\\s+([^>]+>)/i', "$1\n$2", $this->_html);
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
157
        
158
        // fill placeholders
159
        $this->_html = str_replace(
160
            array_keys($this->_placeholders)
161
            ,array_values($this->_placeholders)
162
            ,$this->_html
163
        );
164
        return $this->_html;
165
    }
166
    
167
    protected function _commentCB($m)
168
    {
169
        return (0 === strpos($m[1], '[') || false !== strpos($m[1], '<!['))
170
            ? $m[0]
171
            : '';
172
    }
173
    
174
    protected function _reservePlace($content)
175
    {
176
        $placeholder = '%' . $this->_replacementHash . count($this->_placeholders) . '%';
177
        $this->_placeholders[$placeholder] = $content;
178
        return $placeholder;
179
    }
180
181
    protected $_isXhtml = null;
182
    protected $_replacementHash = null;
183
    protected $_placeholders = array();
184
    protected $_cssMinifier = null;
185
    protected $_jsMinifier = null;
186
	protected $_keepComments = false;
187
188
    protected function _outsideTagCB($m)
189
    {
190
        return '>' . preg_replace('/^\\s+|\\s+$/', ' ', $m[1]) . '<';
191
    }
192
    
193
    protected function _removePreCB($m)
194
    {
195
        return $this->_reservePlace($m[1]);
196
    }
197
    
198
    protected function _removeTextareaCB($m)
199
    {
200
        return $this->_reservePlace($m[1]);
201
    }
202
	
203
	protected function _removeDataURICB($m)
204
    {
205
        return $this->_reservePlace($m[1]);
206
    }
207
208 View Code Duplication
    protected function _removeStyleCB($m)
209
    {
210
        $openStyle = $m[1];
211
        $css = $m[2];
212
        // remove HTML comments
213
        $css = preg_replace('/(?:^\\s*<!--|-->\\s*$)/', '', $css);
214
        
215
        // remove CDATA section markers
216
        $css = $this->_removeCdata($css);
217
        
218
        // minify
219
        $minifier = $this->_cssMinifier
220
            ? $this->_cssMinifier
221
            : 'trim';
222
        $css = call_user_func($minifier, $css);
223
        
224
        return $this->_reservePlace($this->_needsCdata($css)
225
            ? "{$openStyle}/*<![CDATA[*/{$css}/*]]>*/</style>"
226
            : "{$openStyle}{$css}</style>"
227
        );
228
    }
229
230 View Code Duplication
    protected function _removeScriptCB($m)
231
    {
232
        $openScript = $m[2];
233
        $js = $m[3];
234
        
235
        // whitespace surrounding? preserve at least one space
236
        $ws1 = ($m[1] === '') ? '' : ' ';
237
        $ws2 = ($m[4] === '') ? '' : ' ';
238
 
239
        // remove HTML comments (and ending "//" if present)
240
        $js = preg_replace('/(?:^\\s*<!--\\s*|\\s*(?:\\/\\/)?\\s*-->\\s*$)/', '', $js);
241
            
242
        // remove CDATA section markers
243
        $js = $this->_removeCdata($js);
244
        
245
        // minify
246
        $minifier = $this->_jsMinifier
247
            ? $this->_jsMinifier
248
            : 'trim'; 
249
        $js = call_user_func($minifier, $js);
250
        
251
        return $this->_reservePlace($this->_needsCdata($js)
252
            ? "{$ws1}{$openScript}/*<![CDATA[*/{$js}/*]]>*/</script>{$ws2}"
253
            : "{$ws1}{$openScript}{$js}</script>{$ws2}"
254
        );
255
    }
256
257
    protected function _removeCdata($str)
258
    {
259
        return (false !== strpos($str, '<![CDATA['))
260
            ? str_replace(array('/* <![CDATA[ */','/* ]]> */','/*<![CDATA[*/','/*]]>*/','<![CDATA[', ']]>'), '', $str)
261
            : $str;
262
    }
263
    
264
    protected function _needsCdata($str)
265
    {
266
        return ($this->_isXhtml && preg_match('/(?:[<&]|\\-\\-|\\]\\]>)/', $str));
267
    }
268
}
269