Statistiques
| Branche: | Révision :

root / admin / unzip.lib.php @ 008ae173e225b207fc385a6d48e5458c78653ef8

Historique | Voir | Annoter | Télécharger (15,68 ko)

1
<?PHP
2
    /* $Id: unzip.lib.php,v 1.2 2006/01/17 17:02:31 cybot_tm Exp $ */
3
4
    /**
5
     *  ZIP file unpack classes. Contributed to the phpMyAdmin project.
6
     *
7
     *  @category   phpPublic
8
     *  @package    File-Formats-ZIP
9
     *  @subpackage Unzip
10
     *  @filesource unzip.lib.php
11
     *  @version    1.0.1
12
     *
13
     *  @author     Holger Boskugel <vbwebprofi@gmx.de>
14
     *  @copyright  Copyright © 2003, Holger Boskugel, Berlin, Germany
15
     *  @license    http://opensource.org/licenses/gpl-license.php GNU Public License
16
     *
17
     *  @history
18
     *  2003-12-02 - HB : Patched : naming bug : Time/Size of file
19
     *                    Added   : ZIP file comment
20
     *                    Added   : Check BZIP2 support of PHP
21
     *  2003-11-29 - HB * Initial version
22
     */
23
24
    /**
25
     *  Unzip class, which retrieves entries from ZIP files.
26
     *
27
     *  Supports only the compression modes
28
     *  -  0 : Stored,
29
     *  -  8 : Deflated and
30
     *  - 12 : BZIP2
31
     *
32
     *  Based on :<BR>
33
     *  <BR>
34
     *  {@link http://www.pkware.com/products/enterprise/white_papers/appnote.html
35
     *  * Official ZIP file format}<BR>
36
     *  {@link http://msdn.microsoft.com/library/en-us/w98ddk/hh/w98ddk/storage_5l4m.asp
37
     *  * Microsoft DOS date/time format}
38
     *
39
     *  @category   phpPublic
40
     *  @package    File-Formats-ZIP
41
     *  @subpackage Unzip
42
     *  @version    1.0.1
43
     *  @author     Holger Boskugel <vbwebprofi@gmx.de>
44
     *  @uses       SimpleUnzipEntry
45
     *  @example    example.unzip.php Two examples
46
     */
47
    class SimpleUnzip {
48
// 2003-12-02 - HB >
49
        /**
50
         *  Array to store file entries
51
         *
52
         *  @var    string
53
         *  @access public
54
         *  @see    ReadFile()
55
         *  @since  1.0.1
56
         */
57
        var $Comment = '';
58
// 2003-12-02 - HB <
59
60
        /**
61
         *  Array to store file entries
62
         *
63
         *  @var    array
64
         *  @access public
65
         *  @see    ReadFile()
66
         *  @since  1.0
67
         */
68
        var $Entries = array();
69
70
        /**
71
         *  Name of the ZIP file
72
         *
73
         *  @var    string
74
         *  @access public
75
         *  @see    ReadFile()
76
         *  @since  1.0
77
         */
78
        var $Name = '';
79
80
        /**
81
         *  Size of the ZIP file
82
         *
83
         *  @var    integer
84
         *  @access public
85
         *  @see    ReadFile()
86
         *  @since  1.0
87
         */
88
        var $Size = 0;
89
90
        /**
91
         *  Time of the ZIP file (unix timestamp)
92
         *
93
         *  @var    integer
94
         *  @access public
95
         *  @see    ReadFile()
96
         *  @since  1.0
97
         */
98
        var $Time = 0;
99
100
        /**
101
         *  Contructor of the class
102
         *
103
         *  @param  string      File name
104
         *  @return SimpleUnzip Instanced class
105
         *  @access public
106
         *  @uses   SimpleUnzip::ReadFile() Opens file on new if specified
107
         *  @since  1.0
108
         */
109
        function SimpleUnzip($in_FileName = '')
110
        {
111
            if ($in_FileName !== '') {
112
                SimpleUnzip::ReadFile($in_FileName);
113
            }
114
        } // end of the 'SimpleUnzip' constructor
115
116
        /**
117
         *  Counts the entries
118
         *
119
         *  @return integer Count of ZIP entries
120
         *  @access public
121
         *  @uses   $Entries
122
         *  @since  1.0
123
         */
124
        function Count()
125
        {
126
            return count($this->Entries);
127
        } // end of the 'Count()' method
128
129
        /**
130
         *  Gets data of the specified ZIP entry
131
         *
132
         *  @param  integer Index of the ZIP entry
133
         *  @return mixed   Data for the ZIP entry
134
         *  @uses   SimpleUnzipEntry::$Data
135
         *  @access public
136
         *  @since  1.0
137
         */
138
        function GetData($in_Index)
139
        {
140
            return $this->Entries[$in_Index]->Data;
141
        } // end of the 'GetData()' method
142
143
        /**
144
         *  Gets an entry of the ZIP file
145
         *
146
         *  @param  integer             Index of the ZIP entry
147
         *  @return SimpleUnzipEntry    Entry of the ZIP file
148
         *  @uses   $Entries
149
         *  @access public
150
         *  @since  1.0
151
         */
152
        function GetEntry($in_Index)
153
        {
154
            return $this->Entries[$in_Index];
155
        } // end of the 'GetEntry()' method
156
157
        /**
158
         *  Gets error code for the specified ZIP entry
159
         *
160
         *  @param  integer     Index of the ZIP entry
161
         *  @return integer     Error code for the ZIP entry
162
         *  @uses   SimpleUnzipEntry::$Error
163
         *  @access public
164
         *  @since   1.0
165
         */
166
        function GetError($in_Index)
167
        {
168
            return $this->Entries[$in_Index]->Error;
169
        } // end of the 'GetError()' method
170
171
        /**
172
         *  Gets error message for the specified ZIP entry
173
         *
174
         *  @param  integer     Index of the ZIP entry
175
         *  @return string      Error message for the ZIP entry
176
         *  @uses   SimpleUnzipEntry::$ErrorMsg
177
         *  @access public
178
         *  @since  1.0
179
         */
180
        function GetErrorMsg($in_Index)
181
        {
182
            return $this->Entries[$in_Index]->ErrorMsg;
183
        } // end of the 'GetErrorMsg()' method
184
185
        /**
186
         *  Gets file name for the specified ZIP entry
187
         *
188
         *  @param  integer     Index of the ZIP entry
189
         *  @return string      File name for the ZIP entry
190
         *  @uses   SimpleUnzipEntry::$Name
191
         *  @access public
192
         *  @since  1.0
193
         */
194
        function GetName($in_Index)
195
        {
196
            return $this->Entries[$in_Index]->Name;
197
        } // end of the 'GetName()' method
198
199
        /**
200
         *  Gets path of the file for the specified ZIP entry
201
         *
202
         *  @param  integer     Index of the ZIP entry
203
         *  @return string      Path of the file for the ZIP entry
204
         *  @uses   SimpleUnzipEntry::$Path
205
         *  @access public
206
         *  @since  1.0
207
         */
208
        function GetPath($in_Index)
209
        {
210
            return $this->Entries[$in_Index]->Path;
211
        } // end of the 'GetPath()' method
212
213
        /**
214
         *  Gets file time for the specified ZIP entry
215
         *
216
         *  @param  integer     Index of the ZIP entry
217
         *  @return integer     File time for the ZIP entry (unix timestamp)
218
         *  @uses   SimpleUnzipEntry::$Time
219
         *  @access public
220
         *  @since  1.0
221
         */
222
        function GetTime($in_Index)
223
        {
224
            return $this->Entries[$in_Index]->Time;
225
        } // end of the 'GetTime()' method
226
227
        /**
228
         *  Reads ZIP file and extracts the entries
229
         *
230
         *  @param  string              File name of the ZIP archive
231
         *  @return array               ZIP entry list (see also class variable {@link $Entries $Entries})
232
         *  @uses   SimpleUnzipEntry    For the entries
233
         *  @access public
234
         *  @since  1.0
235
         */
236
        function ReadFile($in_FileName)
237
        {
238
            $this->Entries = array();
239
240
            // Get file parameters
241
            $this->Name = $in_FileName;
242
            $this->Time = filemtime($in_FileName);
243
            $this->Size = filesize($in_FileName);
244
245
            // Read file
246
            $oF = fopen($in_FileName, 'rb');
247
            $vZ = fread($oF, $this->Size);
248
            fclose($oF);
249
250
// 2003-12-02 - HB >
251
            // Cut end of central directory
252
            $aE = explode("\x50\x4b\x05\x06", $vZ);
253
254
            // Easiest way, but not sure if format changes
255
            //$this->Comment = substr($aE[1], 18);
256
257
            // Normal way
258
            $aP = unpack('x16/v1CL', $aE[1]);
259
            $this->Comment = substr($aE[1], 18, $aP['CL']);
260
261
            // Translates end of line from other operating systems
262
            $this->Comment = strtr($this->Comment, array("\r\n" => "\n",
263
                                                         "\r"   => "\n"));
264
// 2003-12-02 - HB <
265
266
            // Cut the entries from the central directory
267
            $aE = explode("\x50\x4b\x01\x02", $vZ);
268
            // Explode to each part
269
            $aE = explode("\x50\x4b\x03\x04", $aE[0]);
270
            // Shift out spanning signature or empty entry
271
            array_shift($aE);
272
273
            // Loop through the entries
274
            foreach ($aE as $vZ) {
275
                $aI = array();
276
                $aI['E']  = 0;
277
                $aI['EM'] = '';
278
                // Retrieving local file header information
279
                $aP = unpack('v1VN/v1GPF/v1CM/v1FT/v1FD/V1CRC/V1CS/V1UCS/v1FNL', $vZ);
280
                // Check if data is encrypted
281
                $bE = ($aP['GPF'] && 0x0001) ? TRUE : FALSE;
282
                $nF = $aP['FNL'];
283
284
                // Special case : value block after the compressed data
285
                if ($aP['GPF'] & 0x0008) {
286
                    $aP1 = unpack('V1CRC/V1CS/V1UCS', substr($vZ, -12));
287
288
                    $aP['CRC'] = $aP1['CRC'];
289
                    $aP['CS']  = $aP1['CS'];
290
                    $aP['UCS'] = $aP1['UCS'];
291
292
                    $vZ = substr($vZ, 0, -12);
293
                }
294
295
                // Getting stored filename
296
                $aI['N'] = substr($vZ, 26, $nF);
297
298
                if (substr($aI['N'], -1) == '/') {
299
                    // is a directory entry - will be skipped
300
                    continue;
301
                }
302
303
                // Truncate full filename in path and filename
304
                $aI['P'] = dirname($aI['N']);
305
                $aI['P'] = $aI['P'] == '.' ? '' : $aI['P'];
306
                $aI['N'] = basename($aI['N']);
307
308
                $vZ = substr($vZ, 26 + $nF);
309
310
                if (strlen($vZ) != $aP['CS']) {
311
                  $aI['E']  = 1;
312
                  $aI['EM'] = 'Compressed size is not equal with the value in header information.';
313
                } else {
314
                    if ($bE) {
315
                        $aI['E']  = 5;
316
                        $aI['EM'] = 'File is encrypted, which is not supported from this class.';
317
                    } else {
318
                        switch($aP['CM']) {
319
                            case 0: // Stored
320
                                // Here is nothing to do, the file ist flat.
321
                                break;
322
323
                            case 8: // Deflated
324
                                $vZ = gzinflate($vZ);
325
                                break;
326
327
                            case 12: // BZIP2
328
// 2003-12-02 - HB >
329
                                if (! extension_loaded('bz2')) {
330
                                    if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
331
                                      @dl('php_bz2.dll');
332
                                    } else {
333
                                      @dl('bz2.so');
334
                                    }
335
                                }
336
337
                                if (extension_loaded('bz2')) {
338
// 2003-12-02 - HB <
339
                                    $vZ = bzdecompress($vZ);
340
// 2003-12-02 - HB >
341
                                } else {
342
                                    $aI['E']  = 7;
343
                                    $aI['EM'] = "PHP BZIP2 extension not available.";
344
                                }
345
// 2003-12-02 - HB <
346
347
                                break;
348
349
                            default:
350
                              $aI['E']  = 6;
351
                              $aI['EM'] = "De-/Compression method {$aP['CM']} is not supported.";
352
                        }
353
354
// 2003-12-02 - HB >
355
                        if (! $aI['E']) {
356
// 2003-12-02 - HB <
357
                            if ($vZ === FALSE) {
358
                                $aI['E']  = 2;
359
                                $aI['EM'] = 'Decompression of data failed.';
360
                            } else {
361
                                if (strlen($vZ) != $aP['UCS']) {
362
                                    $aI['E']  = 3;
363
                                    $aI['EM'] = 'Uncompressed size is not equal with the value in header information.';
364
                                } else {
365
                                    if (crc32($vZ) != $aP['CRC']) {
366
                                        $aI['E']  = 4;
367
                                        $aI['EM'] = 'CRC32 checksum is not equal with the value in header information.';
368
                                    }
369
                                }
370
                            }
371
// 2003-12-02 - HB >
372
                        }
373
// 2003-12-02 - HB <
374
                    }
375
                }
376
377
                $aI['D'] = $vZ;
378
379
                // DOS to UNIX timestamp
380
                $aI['T'] = mktime(($aP['FT']  & 0xf800) >> 11,
381
                                  ($aP['FT']  & 0x07e0) >>  5,
382
                                  ($aP['FT']  & 0x001f) <<  1,
383
                                  ($aP['FD']  & 0x01e0) >>  5,
384
                                  ($aP['FD']  & 0x001f),
385
                                  (($aP['FD'] & 0xfe00) >>  9) + 1980);
386
387
                $this->Entries[] = &new SimpleUnzipEntry($aI);
388
            } // end for each entries
389
390
            return $this->Entries;
391
        } // end of the 'ReadFile()' method
392
    } // end of the 'SimpleUnzip' class
393
394
    /**
395
     *  Entry of the ZIP file.
396
     *
397
     *  @category   phpPublic
398
     *  @package    File-Formats-ZIP
399
     *  @subpackage Unzip
400
     *  @version    1.0
401
     *  @author     Holger Boskugel <vbwebprofi@gmx.de>
402
     *  @example    example.unzip.php Two examples
403
     */
404
    class SimpleUnzipEntry {
405
        /**
406
         *  Data of the file entry
407
         *
408
         *  @var    mixed
409
         *  @access public
410
         *  @see    SimpleUnzipEntry()
411
         *  @since  1.0
412
         */
413
        var $Data = '';
414
415
        /**
416
         *  Error of the file entry
417
         *
418
         *  - 0 : No error raised.<BR>
419
         *  - 1 : Compressed size is not equal with the value in header information.<BR>
420
         *  - 2 : Decompression of data failed.<BR>
421
         *  - 3 : Uncompressed size is not equal with the value in header information.<BR>
422
         *  - 4 : CRC32 checksum is not equal with the value in header information.<BR>
423
         *  - 5 : File is encrypted, which is not supported from this class.<BR>
424
         *  - 6 : De-/Compression method ... is not supported.<BR>
425
         *  - 7 : PHP BZIP2 extension not available.
426
         *
427
         *  @var    integer
428
         *  @access public
429
         *  @see    SimpleUnzipEntry()
430
         *  @since  1.0
431
         */
432
        var $Error = 0;
433
434
        /**
435
         *  Error message of the file entry
436
         *
437
         *  @var    string
438
         *  @access public
439
         *  @see    SimpleUnzipEntry()
440
         *  @since  1.0
441
         */
442
        var $ErrorMsg = '';
443
444
        /**
445
         *  File name of the file entry
446
         *
447
         *  @var    string
448
         *  @access public
449
         *  @see    SimpleUnzipEntry()
450
         *  @since  1.0
451
         */
452
        var $Name = '';
453
454
        /**
455
         *  File path of the file entry
456
         *
457
         *  @var    string
458
         *  @access public
459
         *  @see    SimpleUnzipEntry()
460
         *  @since  1.0
461
         */
462
        var $Path = '';
463
464
        /**
465
         *  File time of the file entry (unix timestamp)
466
         *
467
         *  @var    integer
468
         *  @access public
469
         *  @see    SimpleUnzipEntry()
470
         *  @since  1.0
471
         */
472
        var $Time = 0;
473
474
        /**
475
         *  Contructor of the class
476
         *
477
         *  @param  array               Entry datas
478
         *  @return SimpleUnzipEntry    Instanced class
479
         *  @access public
480
         *  @since  1.0
481
         */
482
        function SimpleUnzipEntry($in_Entry)
483
        {
484
            $this->Data     = $in_Entry['D'];
485
            $this->Error    = $in_Entry['E'];
486
            $this->ErrorMsg = $in_Entry['EM'];
487
            $this->Name     = $in_Entry['N'];
488
            $this->Path     = $in_Entry['P'];
489
            $this->Time     = $in_Entry['T'];
490
        } // end of the 'SimpleUnzipEntry' constructor
491
    } // end of the 'SimpleUnzipEntry' class
492
?>