Révision 008ae173

b/admin/unzip.lib.php
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
?>
b/admin/zip.lib.php
1
<?php
2
/* $Id: zip.lib.php,v 2.4 2004/11/03 13:56:52 garvinhicking Exp $ */
3
// vim: expandtab sw=4 ts=4 sts=4:
4

  
5

  
6
/**
7
 * Zip file creation class.
8
 * Makes zip files.
9
 *
10
 * Based on :
11
 *
12
 *  http://www.zend.com/codex.php?id=535&single=1
13
 *  By Eric Mueller <eric@themepark.com>
14
 *
15
 *  http://www.zend.com/codex.php?id=470&single=1
16
 *  by Denis125 <webmaster@atlant.ru>
17
 *
18
 *  a patch from Peter Listiak <mlady@users.sourceforge.net> for last modified
19
 *  date and time of the compressed file
20
 *
21
 * Official ZIP file format: http://www.pkware.com/appnote.txt
22
 *
23
 * @access  public
24
 */
25
class zipfile
26
{
27
    /**
28
     * Array to store compressed data
29
     *
30
     * @var  array    $datasec
31
     */
32
    var $datasec      = array();
33

  
34
    /**
35
     * Central directory
36
     *
37
     * @var  array    $ctrl_dir
38
     */
39
    var $ctrl_dir     = array();
40

  
41
    /**
42
     * End of central directory record
43
     *
44
     * @var  string   $eof_ctrl_dir
45
     */
46
    var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00";
47

  
48
    /**
49
     * Last offset position
50
     *
51
     * @var  integer  $old_offset
52
     */
53
    var $old_offset   = 0;
54

  
55

  
56
    /**
57
     * Converts an Unix timestamp to a four byte DOS date and time format (date
58
     * in high two bytes, time in low two bytes allowing magnitude comparison).
59
     *
60
     * @param  integer  the current Unix timestamp
61
     *
62
     * @return integer  the current date in a four byte DOS format
63
     *
64
     * @access private
65
     */
66
    function unix2DosTime($unixtime = 0) {
67
        $timearray = ($unixtime == 0) ? getdate() : getdate($unixtime);
68

  
69
        if ($timearray['year'] < 1980) {
70
            $timearray['year']    = 1980;
71
            $timearray['mon']     = 1;
72
            $timearray['mday']    = 1;
73
            $timearray['hours']   = 0;
74
            $timearray['minutes'] = 0;
75
            $timearray['seconds'] = 0;
76
        } // end if
77

  
78
        return (($timearray['year'] - 1980) << 25) | ($timearray['mon'] << 21) | ($timearray['mday'] << 16) |
79
                ($timearray['hours'] << 11) | ($timearray['minutes'] << 5) | ($timearray['seconds'] >> 1);
80
    } // end of the 'unix2DosTime()' method
81

  
82

  
83
    /**
84
     * Adds "file" to archive
85
     *
86
     * @param  string   file contents
87
     * @param  string   name of the file in the archive (may contains the path)
88
     * @param  integer  the current timestamp
89
     *
90
     * @access public
91
     */
92
    function addFile($data, $name, $time = 0)
93
    {
94
        $name     = str_replace('\\', '/', $name);
95

  
96
        $dtime    = dechex($this->unix2DosTime($time));
97
        $hexdtime = '\x' . $dtime[6] . $dtime[7]
98
                  . '\x' . $dtime[4] . $dtime[5]
99
                  . '\x' . $dtime[2] . $dtime[3]
100
                  . '\x' . $dtime[0] . $dtime[1];
101
        eval('$hexdtime = "' . $hexdtime . '";');
102

  
103
        $fr   = "\x50\x4b\x03\x04";
104
        $fr   .= "\x14\x00";            // ver needed to extract
105
        $fr   .= "\x00\x00";            // gen purpose bit flag
106
        $fr   .= "\x08\x00";            // compression method
107
        $fr   .= $hexdtime;             // last mod time and date
108

  
109
        // "local file header" segment
110
        $unc_len = strlen($data);
111
        $crc     = crc32($data);
112
        $zdata   = gzcompress($data);
113
        $zdata   = substr(substr($zdata, 0, strlen($zdata) - 4), 2); // fix crc bug
114
        $c_len   = strlen($zdata);
115
        $fr      .= pack('V', $crc);             // crc32
116
        $fr      .= pack('V', $c_len);           // compressed filesize
117
        $fr      .= pack('V', $unc_len);         // uncompressed filesize
118
        $fr      .= pack('v', strlen($name));    // length of filename
119
        $fr      .= pack('v', 0);                // extra field length
120
        $fr      .= $name;
121

  
122
        // "file data" segment
123
        $fr .= $zdata;
124

  
125
        // "data descriptor" segment (optional but necessary if archive is not
126
        // served as file)
127
        // nijel(2004-10-19): this seems not to be needed at all and causes
128
        // problems in some cases (bug #1037737)
129
        //$fr .= pack('V', $crc);                 // crc32
130
        //$fr .= pack('V', $c_len);               // compressed filesize
131
        //$fr .= pack('V', $unc_len);             // uncompressed filesize
132

  
133
        // add this entry to array
134
        $this -> datasec[] = $fr;
135

  
136
        // now add to central directory record
137
        $cdrec = "\x50\x4b\x01\x02";
138
        $cdrec .= "\x00\x00";                // version made by
139
        $cdrec .= "\x14\x00";                // version needed to extract
140
        $cdrec .= "\x00\x00";                // gen purpose bit flag
141
        $cdrec .= "\x08\x00";                // compression method
142
        $cdrec .= $hexdtime;                 // last mod time & date
143
        $cdrec .= pack('V', $crc);           // crc32
144
        $cdrec .= pack('V', $c_len);         // compressed filesize
145
        $cdrec .= pack('V', $unc_len);       // uncompressed filesize
146
        $cdrec .= pack('v', strlen($name) ); // length of filename
147
        $cdrec .= pack('v', 0 );             // extra field length
148
        $cdrec .= pack('v', 0 );             // file comment length
149
        $cdrec .= pack('v', 0 );             // disk number start
150
        $cdrec .= pack('v', 0 );             // internal file attributes
151
        $cdrec .= pack('V', 32 );            // external file attributes - 'archive' bit set
152

  
153
        $cdrec .= pack('V', $this -> old_offset ); // relative offset of local header
154
        $this -> old_offset += strlen($fr);
155

  
156
        $cdrec .= $name;
157

  
158
        // optional extra field, file comment goes here
159
        // save to central directory
160
        $this -> ctrl_dir[] = $cdrec;
161
    } // end of the 'addFile()' method
162

  
163

  
164
    /**
165
     * Dumps out file
166
     *
167
     * @return  string  the zipped file
168
     *
169
     * @access public
170
     */
171
    function file()
172
    {
173
        $data    = implode('', $this -> datasec);
174
        $ctrldir = implode('', $this -> ctrl_dir);
175

  
176
        return
177
            $data .
178
            $ctrldir .
179
            $this -> eof_ctrl_dir .
180
            pack('v', sizeof($this -> ctrl_dir)) .  // total # of entries "on this disk"
181
            pack('v', sizeof($this -> ctrl_dir)) .  // total # of entries overall
182
            pack('V', strlen($ctrldir)) .           // size of central dir
183
            pack('V', strlen($data)) .              // offset to start of central dir
184
            "\x00\x00";                             // .zip file comment length
185
    } // end of the 'file()' method
186

  
187
} // end of the 'zipfile' class
188
?>

Formats disponibles : Unified diff