getid3_gzip   A
last analyzed

Complexity

Total Complexity 28

Size/Duplication

Total Lines 256
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 139
c 1
b 0
f 0
dl 0
loc 256
rs 10
wmc 28

3 Methods

Rating   Name   Duplication   Size   Complexity  
A get_xflag_type() 0 8 1
A get_os_type() 0 20 1
F Analyze() 0 215 26
1
<?php
2
// +----------------------------------------------------------------------+
3
// | PHP version 5                                                        |
4
// +----------------------------------------------------------------------+
5
// | Copyright (c) 2002-2006 James Heinrich, Allan Hansen                 |
6
// +----------------------------------------------------------------------+
7
// | This source file is subject to version 2 of the GPL license,         |
8
// | that is bundled with this package in the file license.txt and is     |
9
// | available through the world-wide-web at the following url:           |
10
// | http://www.gnu.org/copyleft/gpl.html                                 |
11
// +----------------------------------------------------------------------+
12
// | getID3() - http://getid3.sourceforge.net or http://www.getid3.org    |
13
// +----------------------------------------------------------------------+
14
// | Authors: James Heinrich <info�getid3*org>                            |
15
// |          Allan Hansen <ah�artemis*dk>                                |
16
// +----------------------------------------------------------------------+
17
// | module.archive.gzip.php                                              |
18
// | module for analyzing GZIP files                                      |
19
// | dependencies: PHP compiled with zlib support (optional)              |
20
// +----------------------------------------------------------------------+
21
// | Module originally written by Mike Mozolin <teddybear�mail*ru>        |
22
// +----------------------------------------------------------------------+
23
//
24
// $Id: module.archive.gzip.php,v 1.4 2006/12/04 16:00:35 ah Exp $
25
26
class getid3_gzip extends getid3_handler
27
{
28
29
    // public: Optional file list - disable for speed.
30
    public $option_gzip_parse_contents = true; // decode gzipped files, if possible, and parse recursively (.tar.gz for example)
31
32
    // Reads the gzip-file
33
    public function Analyze()
34
    {
35
        $info = &$this->getid3->info;
36
37
        $info['fileformat'] = 'gzip';
38
39
        $start_length  = 10;
40
        $unpack_header = 'a1id1/a1id2/a1cmethod/a1flags/a4mtime/a1xflags/a1os';
41
42
        //+---+---+---+---+---+---+---+---+---+---+
43
        //|ID1|ID2|CM |FLG|     MTIME     |XFL|OS |
44
        //+---+---+---+---+---+---+---+---+---+---+
45
46
        @fseek($this->getid3->fp, 0);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for fseek(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

46
        /** @scrutinizer ignore-unhandled */ @fseek($this->getid3->fp, 0);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
47
        $buffer = @fread($this->getid3->fp, $info['filesize']);
48
49
        $arr_members = explode("\x1F\x8B\x08", $buffer);
0 ignored issues
show
Bug introduced by
It seems like $buffer can also be of type false; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

49
        $arr_members = explode("\x1F\x8B\x08", /** @scrutinizer ignore-type */ $buffer);
Loading history...
50
51
        while (true) {
52
            $is_wrong_members = false;
53
            $num_members      = intval(count($arr_members));
54
            for ($i = 0; $i < $num_members; $i++) {
55
                if (0 == strlen($arr_members[$i])) {
56
                    continue;
57
                }
58
                $buf = "\x1F\x8B\x08" . $arr_members[$i];
59
60
                $attr = unpack($unpack_header, substr($buf, 0, $start_length));
61
                if (!$this->get_os_type(ord($attr['os']))) {
62
                    // Merge member with previous if wrong OS type
63
                    $arr_members[$i - 1] .= $buf;
64
                    $arr_members[$i]     = '';
65
                    $is_wrong_members    = true;
66
                    continue;
67
                }
68
            }
69
            if (!$is_wrong_members) {
70
                break;
71
            }
72
        }
73
74
        $fpointer = 0;
0 ignored issues
show
Unused Code introduced by
The assignment to $fpointer is dead and can be removed.
Loading history...
75
        $idx      = 0;
76
        for ($i = 0; $i < $num_members; $i++) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $num_members does not seem to be defined for all execution paths leading up to this point.
Loading history...
77
            if (0 == strlen($arr_members[$i])) {
78
                continue;
79
            }
80
            $info_gzip_member_header_idx = &$info['gzip']['member_header'][++$idx];
81
82
            $buff = "\x1F\x8B\x08" . $arr_members[$i];
83
84
            $attr                                          = unpack($unpack_header, substr($buff, 0, $start_length));
85
            $info_gzip_member_header_idx['filemtime']      = getid3_lib::LittleEndian2Int($attr['mtime']);
86
            $info_gzip_member_header_idx['raw']['id1']     = ord($attr['cmethod']);
87
            $info_gzip_member_header_idx['raw']['id2']     = ord($attr['cmethod']);
88
            $info_gzip_member_header_idx['raw']['cmethod'] = ord($attr['cmethod']);
89
            $info_gzip_member_header_idx['raw']['os']      = ord($attr['os']);
90
            $info_gzip_member_header_idx['raw']['xflags']  = ord($attr['xflags']);
91
            $info_gzip_member_header_idx['raw']['flags']   = ord($attr['flags']);
92
93
            $info_gzip_member_header_idx['flags']['crc16']    = (bool)($info_gzip_member_header_idx['raw']['flags'] & 0x02);
94
            $info_gzip_member_header_idx['flags']['extra']    = (bool)($info_gzip_member_header_idx['raw']['flags'] & 0x04);
95
            $info_gzip_member_header_idx['flags']['filename'] = (bool)($info_gzip_member_header_idx['raw']['flags'] & 0x08);
96
            $info_gzip_member_header_idx['flags']['comment']  = (bool)($info_gzip_member_header_idx['raw']['flags'] & 0x10);
97
98
            $info_gzip_member_header_idx['compression'] = $this->get_xflag_type($info_gzip_member_header_idx['raw']['xflags']);
99
100
            $info_gzip_member_header_idx['os'] = $this->get_os_type($info_gzip_member_header_idx['raw']['os']);
101
            if (!$info_gzip_member_header_idx['os']) {
102
                $info['error'][] = 'Read error on gzip file';
103
                return false;
104
            }
105
106
            $fpointer      = 10;
107
            $arr_xsubfield = [];
108
109
            // bit 2 - FLG.FEXTRA
110
            //+---+---+=================================+
111
            //| XLEN  |...XLEN bytes of "extra field"...|
112
            //+---+---+=================================+
113
114
            if ($info_gzip_member_header_idx['flags']['extra']) {
115
                $w_xlen   = substr($buff, $fpointer, 2);
116
                $xlen     = getid3_lib::LittleEndian2Int($w_xlen);
117
                $fpointer += 2;
118
119
                $info_gzip_member_header_idx['raw']['xfield'] = substr($buff, $fpointer, $xlen);
120
121
                // Extra SubFields
122
                //+---+---+---+---+==================================+
123
                //|SI1|SI2|  LEN  |... LEN bytes of subfield data ...|
124
                //+---+---+---+---+==================================+
125
126
                $idx = 0;
127
                while (true) {
128
                    if ($idx >= $xlen) {
129
                        break;
130
                    }
131
                    $si1 = ord(substr($buff, $fpointer + $idx++, 1));
132
                    $si2 = ord(substr($buff, $fpointer + $idx++, 1));
133
                    if ((0x41 == $si1) && (0x70 == $si2)) {
134
                        $w_xsublen       = substr($buff, $fpointer + $idx, 2);
135
                        $xsublen         = getid3_lib::LittleEndian2Int($w_xsublen);
136
                        $idx             += 2;
137
                        $arr_xsubfield[] = substr($buff, $fpointer + $idx, $xsublen);
138
                        $idx             += $xsublen;
139
                    } else {
140
                        break;
141
                    }
142
                }
143
                $fpointer += $xlen;
144
            }
145
146
            // bit 3 - FLG.FNAME
147
            //+=========================================+
148
            //|...original file name, zero-terminated...|
149
            //+=========================================+
150
            // GZIP files may have only one file, with no filename, so assume original filename is current filename without .gz
151
152
            $info_gzip_member_header_idx['filename'] = eregi_replace('.gz$', '', @$info['filename']);
153
            if ($info_gzip_member_header_idx['flags']['filename']) {
154
                while (true) {
155
                    if (0 == ord($buff[$fpointer])) {
156
                        $fpointer++;
157
                        break;
158
                    }
159
                    $info_gzip_member_header_idx['filename'] .= $buff[$fpointer];
160
                    $fpointer++;
161
                }
162
            }
163
164
            // bit 4 - FLG.FCOMMENT
165
            //+===================================+
166
            //|...file comment, zero-terminated...|
167
            //+===================================+
168
169
            if ($info_gzip_member_header_idx['flags']['comment']) {
170
                while (true) {
171
                    if (0 == ord($buff[$fpointer])) {
172
                        $fpointer++;
173
                        break;
174
                    }
175
                    $info_gzip_member_header_idx['comment'] .= $buff[$fpointer];
176
                    $fpointer++;
177
                }
178
            }
179
180
            // bit 1 - FLG.FHCRC
181
            //+---+---+
182
            //| CRC16 |
183
            //+---+---+
184
185
            if ($info_gzip_member_header_idx['flags']['crc16']) {
186
                $w_crc                                = substr($buff, $fpointer, 2);
187
                $info_gzip_member_header_idx['crc16'] = getid3_lib::LittleEndian2Int($w_crc);
188
                $fpointer                             += 2;
189
            }
190
191
            // bit 0 - FLG.FTEXT
192
            //if ($info_gzip_member_header_idx['raw']['flags'] & 0x01) {
193
            //  Ignored...
194
            //}
195
            // bits 5, 6, 7 - reserved
196
197
            $info_gzip_member_header_idx['crc32']    = getid3_lib::LittleEndian2Int(substr($buff, strlen($buff) - 8, 4));
198
            $info_gzip_member_header_idx['filesize'] = getid3_lib::LittleEndian2Int(substr($buff, strlen($buff) - 4));
199
200
            if ($this->option_gzip_parse_contents) {
201
                // Try to inflate GZip
202
203
                if (!function_exists('gzinflate')) {
204
                    $this->getid3->warning('PHP does not have zlib support - contents not parsed.');
205
                    return true;
206
                }
207
208
                $csize    = 0;
0 ignored issues
show
Unused Code introduced by
The assignment to $csize is dead and can be removed.
Loading history...
209
                $inflated = '';
0 ignored issues
show
Unused Code introduced by
The assignment to $inflated is dead and can be removed.
Loading history...
210
                $chkcrc32 = '';
0 ignored issues
show
Unused Code introduced by
The assignment to $chkcrc32 is dead and can be removed.
Loading history...
211
212
                $cdata    = substr($buff, $fpointer);
213
                $cdata    = substr($cdata, 0, strlen($cdata) - 8);
214
                $csize    = strlen($cdata);
215
                $inflated = gzinflate($cdata);
216
217
                // Calculate CRC32 for inflated content
218
                $info_gzip_member_header_idx['crc32_valid'] = (bool)(sprintf('%u', crc32($inflated)) == $info_gzip_member_header_idx['crc32']);
219
220
                //// Analyse contents
221
222
                // write content to temp file
223
                if (false === ($temp_file_name = tempnam('*', 'getID3'))) {
224
                    throw new getid3_exception('Unable to create temporary file.');
225
                }
226
227
                if ($tmp = fopen($temp_file_name, 'wb')) {
228
                    fwrite($tmp, $inflated);
229
                    fclose($tmp);
230
231
                    // clone getid3 - we want same settings
232
                    $clone = clone $this->getid3;
233
                    unset($clone->info);
234
                    try {
235
                        $clone->Analyze($temp_file_name);
236
                        $info_gzip_member_header_idx['parsed_content'] = $clone->info;
237
                    } catch (getid3_exception $e) {
238
                        // unable to parse contents
239
                    }
240
241
                    unlink($temp_file_name);
242
                } // Unknown/unhandled format
243
                else {
244
                }
245
            }
246
        }
247
        return true;
248
    }
249
250
    // Converts the OS type
251
    public static function get_os_type($key)
252
    {
253
        static $os_type = [
254
            '0'   => 'FAT filesystem (MS-DOS, OS/2, NT/Win32)',
255
            '1'   => 'Amiga',
256
            '2'   => 'VMS (or OpenVMS)',
257
            '3'   => 'Unix',
258
            '4'   => 'VM/CMS',
259
            '5'   => 'Atari TOS',
260
            '6'   => 'HPFS filesystem (OS/2, NT)',
261
            '7'   => 'Macintosh',
262
            '8'   => 'Z-System',
263
            '9'   => 'CP/M',
264
            '10'  => 'TOPS-20',
265
            '11'  => 'NTFS filesystem (NT)',
266
            '12'  => 'QDOS',
267
            '13'  => 'Acorn RISCOS',
268
            '255' => 'unknown'
269
        ];
270
        return @$os_type[$key];
271
    }
272
273
    // Converts the eXtra FLags
274
    public static function get_xflag_type($key)
275
    {
276
        static $xflag_type = [
277
            '0' => 'unknown',
278
            '2' => 'maximum compression',
279
            '4' => 'fastest algorithm'
280
        ];
281
        return @$xflag_type[$key];
282
    }
283
284
}
285
286
287