Completed
Push — master ( b839dd...8b4745 )
by Revin
13:10 queued 06:30
created

HtmlCompressor::compress()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 5
ccs 3
cts 3
cp 1
rs 9.4285
cc 1
eloc 3
nc 1
nop 2
crap 1
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 1
        return (new static)
33 1
            ->htmlCompress($data, $options);
34
    }
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 1
        if (!isset($options)) {
75 1
            $options = [];
76 1
        }
77
78 1
        $data .= "\n";
79 1
        $out = '';
80 1
        $inside_pre = false;
81 1
        $bytecount = 0;
82
83 1
        while ($line = $this->getLine($data)) {
84 1
            $bytecount += strlen($line);
85
86 1
            if (!$inside_pre) {
87 1
                if (strpos($line, '<pre') === false) {
88
                    // Since we're not inside a <pre> block, we can trim both ends of the line
89 1
                    $line = trim($line);
90
91
                    // And condense multiple spaces down to one
92 1
                    $line = preg_replace('/\s\s+/', ' ', $line);
93 1
                } else {
94
                    // Only trim the beginning since we just entered a <pre> block...
95 1
                    $line = ltrim($line);
96
97
                    // If the <pre> ends on the same line, don't turn on $inside_pre...
98 1
                    list($line, $inside_pre) = $this->checkInsidePre($line);
99
                }
100 1
            } else {
101 1
                list($line, $inside_pre) = $this->checkInsidePre($line);
102
            }
103
104
            // Filter out any blank lines that aren't inside a <pre> block...
105 1
            if ($inside_pre) {
106 1
                $out .= $line;
107 1
            } elseif ($line != '') {
108 1
                $out .= $line . "\n";
109 1
            }
110 1
        }
111
112
        // Perform any extra (unsafe) compression techniques...
113 1
        if (array_key_exists('x', $options) || array_key_exists('extra', $options)) {
114
            // Can break layouts that are dependent on whitespace between tags
115 1
            $out = str_replace(">\n<", '><', $out);
116 1
        }
117
118
        // Remove HTML comments...
119 1
        if (array_key_exists('c', $options) || array_key_exists('no-comments', $options)) {
120 1
            $out = preg_replace('/(<!--.*?-->)/ms', '', $out);
121 1
            $out = str_replace('<!>', '', $out);
122 1
        }
123
124
        // Remove the trailing \n
125 1
        $out = trim($out);
126
127
        // Output either our stats or the compressed data...
128 1
        if (array_key_exists('s', $options) || array_key_exists('stats', $options)) {
129 1
            $echo = '';
130 1
            $echo .= "Original Size: $bytecount\n";
131 1
            $echo .= "Compressed Size: " . strlen($out) . "\n";
132 1
            $echo .= "Savings: " . round((1 - strlen($out) / $bytecount) * 100, 2) . "%\n";
133 1
            echo $echo;
134 1
        } else {
135 1
            return $out;
136
        }
137
138 1
        return false;
139
    }
140
141
    /**
142
     * @param $line
143
     * @return array
144
     */
145 1
    private function checkInsidePre($line)
146
    {
147 1
        $inside_pre = true;
148
149 1
        if ((strpos($line, '</pre') !== false) && (strripos($line, '</pre') >= strripos($line, '<pre'))) {
150 1
            $line = rtrim($line);
151 1
            $inside_pre = false;
152 1
        }
153
154 1
        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 1
    private function getLine(&$data)
163
    {
164 1
        if (is_resource($data)) {
165
            return fgets($data);
166
        }
167
168 1
        if (is_string($data)) {
169 1
            if (strlen($data) > 0) {
170 1
                $pos = strpos($data, "\n");
171 1
                $return = substr($data, 0, $pos) . "\n";
172 1
                $data = substr($data, $pos + 1);
173
174 1
                return $return;
175
            } else {
176
                return false;
177
            }
178
        }
179
180 1
        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
}