Completed
Push — master ( 2fd39c...5d8d2a )
by Revin
02:32
created

HtmlCompressor::checkInsidePre()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 11
Ratio 100 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 11
loc 11
ccs 7
cts 7
cp 1
rs 9.4285
cc 3
eloc 6
nc 2
nop 1
crap 3
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
        $inside_textarea = false;
82 1
        $bytecount = 0;
83
84 1
        while ($line = $this->getLine($data)) {
85 1
            $bytecount += strlen($line);
86
87 1
            if ($inside_pre) {
88 1
                list($line, $inside_pre) = $this->checkInsidePre($line);
89 1
            } elseif ($inside_textarea) {
90
                list($line, $inside_textarea) = $this->checkInsideTextarea($line);
91
            } else {
92 1
                if (strpos($line, '<pre') !== false) {
93
                    // Only trim the beginning since we just entered a <pre> block...
94 1
                    $line = ltrim($line);
95
96
                    // If the <pre> ends on the same line, don't turn on $inside_pre...
97 1
                    list($line, $inside_pre) = $this->checkInsidePre($line);
98 1
                } elseif (strpos($line, '<textarea') !== false) {
99
                    // Only trim the beginning since we just entered a <textarea> block...
100
                    $line = ltrim($line);
101
102
                    // If the <textarea> ends on the same line, don't turn on $inside_textarea...
103
                    list($line, $inside_textarea) = $this->checkInsideTextarea($line);
104
                } else {
105
                    // Since we're not inside a <pre> block, we can trim both ends of the line
106 1
                    $line = trim($line);
107
108
                    // And condense multiple spaces down to one
109 1
                    $line = preg_replace('/\s\s+/', ' ', $line);
110
                }
111
            }
112
113
            // Filter out any blank lines that aren't inside a <pre> block...
114 1
            if ($inside_pre || $inside_textarea) {
115 1
                $out .= $line;
116 1
            } elseif ($line != '') {
117 1
                $out .= $line . "\n";
118 1
            }
119 1
        }
120
121
        // Perform any extra (unsafe) compression techniques...
122 1
        if (array_key_exists('x', $options) || array_key_exists('extra', $options)) {
123
            // Can break layouts that are dependent on whitespace between tags
124 1
            $out = str_replace(">\n<", '><', $out);
125 1
        }
126
127
        // Remove HTML comments...
128 1
        if (array_key_exists('c', $options) || array_key_exists('no-comments', $options)) {
129 1
            $out = preg_replace('/(<!--.*?-->)/ms', '', $out);
130 1
            $out = str_replace('<!>', '', $out);
131 1
        }
132
133
        // Remove the trailing \n
134 1
        $out = trim($out);
135
136
        // Output either our stats or the compressed data...
137 1
        if (array_key_exists('s', $options) || array_key_exists('stats', $options)) {
138 1
            $echo = '';
139 1
            $echo .= "Original Size: $bytecount\n";
140 1
            $echo .= "Compressed Size: " . strlen($out) . "\n";
141 1
            $echo .= "Savings: " . round((1 - strlen($out) / $bytecount) * 100, 2) . "%\n";
142 1
            echo $echo;
143 1
        } else {
144 1
            return $out;
145
        }
146
147 1
        return false;
148
    }
149
150
    /**
151
     * @param $line
152
     * @return array
153
     */
154 1 View Code Duplication
    private function checkInsidePre($line)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
155
    {
156 1
        $inside_pre = true;
157
158 1
        if ((strpos($line, '</pre') !== false) && (strripos($line, '</pre') >= strripos($line, '<pre'))) {
159 1
            $line = rtrim($line);
160 1
            $inside_pre = false;
161 1
        }
162
163 1
        return [$line, $inside_pre];
164
    }
165
166
    /**
167
     * @param $line
168
     * @return array
169
     */
170 View Code Duplication
    private function checkInsideTextarea($line)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
171
    {
172
        $inside_textarea = true;
173
174
        if ((strpos($line, '</textarea') !== false) && (strripos($line, '</textarea') >= strripos($line, '<textarea'))) {
175
            $line = rtrim($line);
176
            $inside_textarea = false;
177
        }
178
179
        return [$line, $inside_textarea];
180
    }
181
182
    /**
183
     * Returns the next line from an open file handle or a string
184
     * @param $data
185
     * @return bool|string
186
     */
187 1
    private function getLine(&$data)
188
    {
189 1
        if (is_resource($data)) {
190
            return fgets($data);
191
        }
192
193 1
        if (is_string($data)) {
194 1
            if (strlen($data) > 0) {
195 1
                $pos = strpos($data, "\n");
196 1
                $return = substr($data, 0, $pos) . "\n";
197 1
                $data = substr($data, $pos + 1);
198
199 1
                return $return;
200
            } else {
201
                return false;
202
            }
203
        }
204
205 1
        return false;
206
    }
207
208
    /**
209
     * @param $data
210
     * @param null|array $options
211
     * @return bool|mixed|string
212
     * @deprecated
213
     * @codeCoverageIgnore
214
     */
215
    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...
216
    {
217
        \Yii::warning(sprintf('You are using an deprecated method `%s`.', 'html_compress'));
218
219
        return $this->htmlCompress($data, $options);
220
    }
221
222
    /**
223
     * Returns the next line from an open file handle or a string
224
     * @param $data
225
     * @return bool|string
226
     * @deprecated
227
     * @codeCoverageIgnore
228
     */
229
    private function get_line(&$data)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
230
    {
231
        \Yii::warning(sprintf('You are using an deprecated method `%s`.', 'get_line'));
232
233
        return $this->getLine($data);
234
    }
235
}