Test Failed
Pull Request — master (#1)
by
unknown
38:28
created

HtmlCompressor.php (5 issues)

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
 * HtmlCompressor.php
4
 * @author Revin Roman
5
 * @link https://processfast.ru
6
 */
7
8
namespace processfast\yii\minify;
9
10
/**
11
 * Class HtmlCompressor
12
 * @package processfast\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
    public static function compress($data, $options = null)
31
    {
32
        return (new static)
33
            ->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
    private function htmlCompress($data, $options = null)
73
    {
74
        if (!isset($options)) {
75
            $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);
0 ignored issues
show
Unused Code Comprehensibility introduced by
40% 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...
130
// adding browser's condition's exceptions
131
	    $out = preg_replace('#\\s*<!--[^\\[].*?(?<!!)-->\\s*#s', '', $out);
132
            $out = str_replace('<!>', '', $out);
133
        }
134
135
        // Remove the trailing \n
136
        $out = trim($out);
137
138
        // Output either our stats or the compressed data...
139
        if (array_key_exists('s', $options) || array_key_exists('stats', $options)) {
140
            $echo = '';
141
            $echo .= "Original Size: $bytecount\n";
142
            $echo .= "Compressed Size: " . strlen($out) . "\n";
143
            $echo .= "Savings: " . round((1 - strlen($out) / $bytecount) * 100, 2) . "%\n";
144
            echo $echo;
145
        } else {
146
            return $out;
147
        }
148
149
        return false;
150
    }
151
152
    /**
153
     * @param $line
154
     * @return array
155
     * @codeCoverageIgnore
156
     */
157 View Code Duplication
    private function checkInsidePre($line)
0 ignored issues
show
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...
158
    {
159
        $inside_pre = true;
160
161
        if ((strpos($line, '</pre') !== false) && (strripos($line, '</pre') >= strripos($line, '<pre'))) {
162
            $line = rtrim($line);
163
            $inside_pre = false;
164
        }
165
166
        return [$line, $inside_pre];
167
    }
168
169
    /**
170
     * @param $line
171
     * @return array
172
     * @codeCoverageIgnore
173
     */
174 View Code Duplication
    private function checkInsideTextarea($line)
0 ignored issues
show
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...
175
    {
176
        $inside_textarea = true;
177
178
        if ((strpos($line, '</textarea') !== false) && (strripos($line, '</textarea') >= strripos($line, '<textarea'))) {
179
            $line = rtrim($line);
180
            $inside_textarea = false;
181
        }
182
183
        return [$line, $inside_textarea];
184
    }
185
186
    /**
187
     * Returns the next line from an open file handle or a string
188
     * @param $data
189
     * @return bool|string
190
     * @codeCoverageIgnore
191
     */
192
    private function getLine(&$data)
193
    {
194
        if (is_resource($data)) {
195
            return fgets($data);
196
        }
197
198
        if (is_string($data)) {
199
            if (strlen($data) > 0) {
200
                $pos = strpos($data, "\n");
201
                $return = substr($data, 0, $pos) . "\n";
202
                $data = substr($data, $pos + 1);
203
204
                return $return;
205
            } else {
206
                return false;
207
            }
208
        }
209
210
        return false;
211
    }
212
213
    /**
214
     * @param $data
215
     * @param null|array $options
216
     * @return bool|mixed|string
217
     * @deprecated
218
     * @codeCoverageIgnore
219
     */
220
    private function html_compress($data, $options = null)
0 ignored issues
show
This method is not used, and could be removed.
Loading history...
221
    {
222
        \Yii::warning(sprintf('You are using an deprecated method `%s`.', 'html_compress'));
223
224
        return $this->htmlCompress($data, $options);
225
    }
226
227
    /**
228
     * Returns the next line from an open file handle or a string
229
     * @param $data
230
     * @return bool|string
231
     * @deprecated
232
     * @codeCoverageIgnore
233
     */
234
    private function get_line(&$data)
0 ignored issues
show
This method is not used, and could be removed.
Loading history...
235
    {
236
        \Yii::warning(sprintf('You are using an deprecated method `%s`.', 'get_line'));
237
238
        return $this->getLine($data);
239
    }
240
}