Completed
Push — master ( bdcaed...b839dd )
by Revin
12:51
created

HtmlCompressor   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 197
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 15.79%

Importance

Changes 8
Bugs 0 Features 0
Metric Value
wmc 23
c 8
b 0
f 0
lcom 1
cbo 1
dl 0
loc 197
ccs 9
cts 57
cp 0.1579
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A html_compress() 0 6 1
A get_line() 0 6 1
A compress() 0 5 1
C htmlCompress() 0 68 13
A checkInsidePre() 0 11 3
A getLine() 0 20 4
1
<?php
2
/**
3
 * HtmlCompressor.php
4
 * @author Revin Roman
5
 * @link https://rmrevin.ru
6
 */
7
8
namespace rmrevin\yii\minify;
9
10
/**
11
 * Class HtmlCompressor
12
 * @package rmrevin\yii\minify
13
 */
14
class HtmlCompressor
15
{
16
17
    /**
18
     * @param string $data is either a handle to an open file, or an HTML string
19
     * @param null|array $options key => value array of execute options
20
     * The possible keys are:
21
     *
22
     *  - `c` or `no-comments` - removes HTML comments
23
     *  - `s` or `stats` - output filesize savings calculation
24
     *  - `x` or `extra` - perform extra (possibly unsafe) compression operations
25
     *
26
     * Example: HtmlCompressor::compress($HtmlCode, $options = ['no-comments' => true])
27
     *
28
     * @return string
29
     */
30 1
    public static function compress($data, $options = null)
31
    {
32
        return (new static)
33
            ->htmlCompress($data, $options);
34 1
    }
35
36
37
    /**
38
     * HTML Compressor 1.0.1
39
     * Original Author: Tyler Hall <[email protected]>
40
     * Edited by: Revin Roman <[email protected]>
41
     * Latest Source and Bug Tracker: http://github.com/tylerhall/html-compressor
42
     *
43
     * Attemps to reduce the filesize of an HTML document by removing unnecessary
44
     * whitespace at the beginning and end of lines, inside closing tags, and
45
     * stripping blank lines completely. <pre> tags are respected and their contents
46
     * are left alone. Warning, nested <pre> tags may exhibit unexpected behaviour.
47
     *
48
     * This code is licensed under the MIT Open Source License.
49
     * Copyright (c) 2010 [email protected]
50
     * Permission is hereby granted, free of charge, to any person obtaining a copy
51
     * of this software and associated documentation files (the "Software"), to deal
52
     * in the Software without restriction, including without limitation the rights
53
     * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
54
     * copies of the Software, and to permit persons to whom the Software is
55
     * furnished to do so, subject to the following conditions:
56
     *
57
     * The above copyright notice and this permission notice shall be included in
58
     * all copies or substantial portions of the Software.
59
     *
60
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
61
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
62
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
63
     * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
64
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
65
     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
66
     * THE SOFTWARE.
67
     *
68
     * @param $data
69
     * @param null|array $options
70
     * @return bool|mixed|string
71
     */
72 1
    private function htmlCompress($data, $options = null)
73
    {
74
        if (!isset($options)) {
75 1
            $options = [];
76
        }
77
78
        $data .= "\n";
79
        $out = '';
80
        $inside_pre = false;
81
        $bytecount = 0;
82
83
        while ($line = $this->getLine($data)) {
84
            $bytecount += strlen($line);
85
86
            if (!$inside_pre) {
87
                if (strpos($line, '<pre') === false) {
88
                    // Since we're not inside a <pre> block, we can trim both ends of the line
89
                    $line = trim($line);
90
91
                    // And condense multiple spaces down to one
92
                    $line = preg_replace('/\s\s+/', ' ', $line);
93
                } else {
94
                    // Only trim the beginning since we just entered a <pre> block...
95
                    $line = ltrim($line);
96
97
                    // If the <pre> ends on the same line, don't turn on $inside_pre...
98
                    list($line, $inside_pre) = $this->checkInsidePre($line);
99
                }
100
            } else {
101
                list($line, $inside_pre) = $this->checkInsidePre($line);
102
            }
103
104
            // Filter out any blank lines that aren't inside a <pre> block...
105
            if ($inside_pre) {
106
                $out .= $line;
107
            } elseif ($line != '') {
108
                $out .= $line . "\n";
109
            }
110
        }
111
112
        // Perform any extra (unsafe) compression techniques...
113
        if (array_key_exists('x', $options) || array_key_exists('extra', $options)) {
114
            // Can break layouts that are dependent on whitespace between tags
115
            $out = str_replace(">\n<", '><', $out);
116
        }
117
118
        // Remove HTML comments...
119
        if (array_key_exists('c', $options) || array_key_exists('no-comments', $options)) {
120
            $out = preg_replace('/(<!--.*?-->)/ms', '', $out);
121
            $out = str_replace('<!>', '', $out);
122
        }
123
124
        // Remove the trailing \n
125
        $out = trim($out);
126
127
        // Output either our stats or the compressed data...
128
        if (array_key_exists('s', $options) || array_key_exists('stats', $options)) {
129 1
            $echo = '';
130 1
            $echo .= "Original Size: $bytecount\n";
131
            $echo .= "Compressed Size: " . strlen($out) . "\n";
132
            $echo .= "Savings: " . round((1 - strlen($out) / $bytecount) * 100, 2) . "%\n";
133 1
            echo $echo;
134
        } else {
135
            return $out;
136 1
        }
137
138 1
        return false;
139
    }
140
141
    /**
142
     * @param $line
143
     * @return array
144
     */
145
    private function checkInsidePre($line)
146
    {
147
        $inside_pre = true;
148
149
        if ((strpos($line, '</pre') !== false) && (strripos($line, '</pre') >= strripos($line, '<pre'))) {
150
            $line = rtrim($line);
151
            $inside_pre = false;
152
        }
153
154
        return [$line, $inside_pre];
155
    }
156
157
    /**
158
     * Returns the next line from an open file handle or a string
159
     * @param $data
160
     * @return bool|string
161
     */
162
    private function getLine(&$data)
163
    {
164
        if (is_resource($data)) {
165
            return fgets($data);
166
        }
167
168
        if (is_string($data)) {
169
            if (strlen($data) > 0) {
170
                $pos = strpos($data, "\n");
171
                $return = substr($data, 0, $pos) . "\n";
172
                $data = substr($data, $pos + 1);
173
174
                return $return;
175
            } else {
176
                return false;
177
            }
178
        }
179
180
        return false;
181
    }
182
183
    /**
184
     * @param $data
185
     * @param null|array $options
186
     * @return bool|mixed|string
187
     * @deprecated
188
     * @codeCoverageIgnore
189
     */
190
    private function html_compress($data, $options = null)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
191
    {
192
        \Yii::warning(sprintf('You are using an deprecated method `%s`.', 'html_compress'));
193
194
        return $this->htmlCompress($data, $options);
195
    }
196
197
    /**
198
     * Returns the next line from an open file handle or a string
199
     * @param $data
200
     * @return bool|string
201
     * @deprecated
202
     * @codeCoverageIgnore
203
     */
204
    private function get_line(&$data)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
205
    {
206
        \Yii::warning(sprintf('You are using an deprecated method `%s`.', 'get_line'));
207
208
        return $this->getLine($data);
209
    }
210
}