Completed
Push — master ( 8137b1...e31cbc )
by Revin
05:54 queued 02:12
created

HtmlCompressor   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 225
Duplicated Lines 9.78 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 20%

Importance

Changes 0
Metric Value
wmc 29
lcom 1
cbo 1
dl 22
loc 225
ccs 9
cts 45
cp 0.2
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A checkInsidePre() 11 11 3
A checkInsideTextarea() 11 11 3
A getLine() 0 20 4
A html_compress() 0 6 1
A get_line() 0 6 1
A compress() 0 5 1
F htmlCompress() 0 77 16

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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
        $inside_textarea = false;
82
        $bytecount = 0;
83
84
        while ($line = $this->getLine($data)) {
85
            $bytecount += strlen($line);
86
87
            if ($inside_pre) {
88
                list($line, $inside_pre) = $this->checkInsidePre($line);
89
            } elseif ($inside_textarea) {
90
                list($line, $inside_textarea) = $this->checkInsideTextarea($line);
91
            } else {
92
                if (strpos($line, '<pre') !== false) {
93
                    // Only trim the beginning since we just entered a <pre> block...
94
                    $line = ltrim($line);
95
96
                    // If the <pre> ends on the same line, don't turn on $inside_pre...
97
                    list($line, $inside_pre) = $this->checkInsidePre($line);
98
                } 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
                    $line = trim($line);
107
108
                    // And condense multiple spaces down to one
109
                    $line = preg_replace('/\s\s+/', ' ', $line);
110
                }
111
            }
112
113
            // Filter out any blank lines that aren't inside a <pre> block...
114
            if ($inside_pre || $inside_textarea) {
115
                $out .= $line;
116
            } elseif ($line != '') {
117
                $out .= $line . "\n";
118
            }
119
        }
120
121
        // Perform any extra (unsafe) compression techniques...
122
        if (array_key_exists('x', $options) || array_key_exists('extra', $options)) {
123
            // Can break layouts that are dependent on whitespace between tags
124
            $out = str_replace(">\n<", '><', $out);
125
        }
126
127
        // Remove HTML comments...
128
        if (array_key_exists('c', $options) || array_key_exists('no-comments', $options)) {
129
            $out = preg_replace('/(<!--.*?-->)/ms', '', $out);
130
            $out = str_replace('<!>', '', $out);
131
        }
132
133
        // Remove the trailing \n
134
        $out = trim($out);
135
136
        // Output either our stats or the compressed data...
137
        if (array_key_exists('s', $options) || array_key_exists('stats', $options)) {
138 1
            $echo = '';
139 1
            $echo .= "Original Size: $bytecount\n";
140
            $echo .= "Compressed Size: " . strlen($out) . "\n";
141
            $echo .= "Savings: " . round((1 - strlen($out) / $bytecount) * 100, 2) . "%\n";
142 1
            echo $echo;
143
        } else {
144
            return $out;
145 1
        }
146
147 1
        return false;
148
    }
149
150
    /**
151
     * @param $line
152
     * @return array
153
     * @codeCoverageIgnore
154
     */
155 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...
156
    {
157
        $inside_pre = true;
158
159
        if ((strpos($line, '</pre') !== false) && (strripos($line, '</pre') >= strripos($line, '<pre'))) {
160
            $line = rtrim($line);
161
            $inside_pre = false;
162
        }
163
164
        return [$line, $inside_pre];
165
    }
166
167
    /**
168
     * @param $line
169
     * @return array
170
     * @codeCoverageIgnore
171
     */
172 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...
173
    {
174
        $inside_textarea = true;
175
176
        if ((strpos($line, '</textarea') !== false) && (strripos($line, '</textarea') >= strripos($line, '<textarea'))) {
177
            $line = rtrim($line);
178
            $inside_textarea = false;
179
        }
180
181
        return [$line, $inside_textarea];
182
    }
183
184
    /**
185
     * Returns the next line from an open file handle or a string
186
     * @param $data
187
     * @return bool|string
188
     * @codeCoverageIgnore
189
     */
190
    private function getLine(&$data)
191
    {
192
        if (is_resource($data)) {
193
            return fgets($data);
194
        }
195
196
        if (is_string($data)) {
197
            if (strlen($data) > 0) {
198
                $pos = strpos($data, "\n");
199
                $return = substr($data, 0, $pos) . "\n";
200
                $data = substr($data, $pos + 1);
201
202
                return $return;
203
            } else {
204
                return false;
205
            }
206
        }
207
208
        return false;
209
    }
210
211
    /**
212
     * @param $data
213
     * @param null|array $options
214
     * @return bool|mixed|string
215
     * @deprecated
216
     * @codeCoverageIgnore
217
     */
218
    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...
219
    {
220
        \Yii::warning(sprintf('You are using an deprecated method `%s`.', 'html_compress'));
221
222
        return $this->htmlCompress($data, $options);
223
    }
224
225
    /**
226
     * Returns the next line from an open file handle or a string
227
     * @param $data
228
     * @return bool|string
229
     * @deprecated
230
     * @codeCoverageIgnore
231
     */
232
    private function get_line(&$data)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
233
    {
234
        \Yii::warning(sprintf('You are using an deprecated method `%s`.', 'get_line'));
235
236
        return $this->getLine($data);
237
    }
238
}