Subversion Repositories svnkaklik

Rev

Details | Last modification | View Log

Rev Author Line No. Line
6 kaklik 1
<?php
2
/*************************
3
  Coppermine Photo Gallery
4
  ************************
5
  Copyright (c) 2003-2005 Coppermine Dev Team
6
  v1.1 originaly written by Gregory DEMAR
7
 
8
  This program is free software; you can redistribute it and/or modify
9
  it under the terms of the GNU General Public License as published by
10
  the Free Software Foundation; either version 2 of the License, or
11
  (at your option) any later version.
12
  ********************************************
13
  Coppermine version: 1.3.3
14
  $Source: /cvsroot/coppermine/stable/include/archive.php,v $
15
  $Revision: 1.4 $
16
  $Author: gaugau $
17
  $Date: 2005/04/19 03:17:11 $
18
**********************************************/
19
 
20
/*--------------------------------------------------
21
 | TAR/GZIP/ZIP ARCHIVE CLASSES
22
 | By Devin Doucette
23
 | Copyright (c) 2003 Devin Doucette
24
 | Email: darksnoopy@shaw.ca
25
 +--------------------------------------------------
26
 | Email bugs/suggestions to darksnoopy@shaw.ca
27
 +--------------------------------------------------
28
 | This script has been created and released under
29
 | the GNU GPL and is free to use and redistribute
30
 | only if this copyright statement is not removed
31
 +--------------------------------------------------*/
32
 
33
/*------------------------------------------------------------
34
 | To create tar files:
35
 | $example = new tarfile($cwd,$flags); // args optional
36
 | -current working directory
37
 | -flags (array):
38
 |  -overwrite - whether to overwrite existing files or return
39
 |    an error message
40
 |  -defaultperms - default file permissions (like chmod(),
41
 |    must include 0 in front of value [eg. 0777, 0644])
42
 |  -recursesd[1,0] - whether or not to include subdirs
43
 |  -storepath[1,0] - whether or not to store relative paths
44
 |  -replacestats[array] - values to replace those from files
45
 |   -mode - same as the result of a fileperms() call
46
 |   -uid/gid - user/group id
47
 |   -time - timestamp
48
 |   -type - file type (5=dir,1=link,0=file)
49
 |   -link - the file that is linked to
50
 |   -path - only supported in USTAR, not recommended
51
 +------------------------------------------------------------*/
52
 
53
/*------------------------------------------------------------
54
 | To create gzip files:
55
 | $example = new gzfile($cwd,$flags); // args optional
56
 | -current working directory
57
 | -flags (array):
58
 |  -overwrite - whether to overwrite existing files or return
59
 |    an error message
60
 |  -defaultperms - default file permissions (like chmod(),
61
 |    must include 0 in front of value [eg. 0777, 0644])
62
 +------------------------------------------------------------*/
63
 
64
/*------------------------------------------------------------
65
 | To create zip files:
66
 | $example = new zipfile($cwd,$flags); // args optional
67
 | -current working directory
68
 | -flags (array):
69
 |  -overwrite - whether to overwrite existing files or return
70
 |    an error message
71
 |  -defaultperms - default file permissions (like chmod(),
72
 |    must include 0 in front of value [eg. 0777, 0644])
73
 |  -time - timestamp to use to replace the mtime from files
74
 |  -recursesd[1,0] - whether or not to include subdirs
75
 |  -storepath[1,0] - whether or not to store relative paths
76
 |  -level[0-9] - compression level (0 = none, 9 = max)
77
 |  -comment - comment to add to the archive
78
 +------------------------------------------------------------*/
79
 
80
/*------------------------------------------------------------
81
 | To add files:
82
 | $example->addfile($data,$filename,$flags);
83
 | -data - file contents
84
 | -filename - name of file to be put in archive
85
 | -flags (all flags are optional)
86
 | -flags (tar) [array]: -same flags as tarfile()
87
 | -flags (gzip) [string]: -comment to add to archive
88
 | -flags (zip) [array] -time - last modification time
89
 |
90
 | $example->addfiles($filelist); // tar and zip only
91
 | -filelist - array of file names relative to CWD
92
 |
93
 | $example->adddirectories($dirlist); // tar and zip only
94
 | -dirlist - array of directory names relative to CWD
95
 +------------------------------------------------------------*/
96
 
97
/*------------------------------------------------------------
98
 | To output files:
99
 | $example->getdata();
100
 | -returns file contents
101
 |
102
 | $example->filedownload($filename);
103
 | -filename - the name to give the file that is being sent
104
 |
105
 | $example->filewrite($filename,$perms); // perms optional
106
 | -filename - the name (including path) of the file to write
107
 | -perms - permissions to give the file after it is written
108
 +------------------------------------------------------------*/
109
 
110
/*------------------------------------------------------------
111
 | To extract files (tar and gzip)
112
 | $example->extract($data);
113
 | -data - data to extract files from
114
 | -returns an array containing file attributes and contents
115
 |
116
 | $example->extractfile($filename);
117
 | -filename - the name (including path) of the file to use
118
 | -returns an array containing file attributes and contents
119
 |
120
 | Both functions will return a string containing any errors
121
 +------------------------------------------------------------*/
122
 
123
class tarfile extends archive {
124
        var $cwd                        = "./";
125
        var $tardata                = "";
126
        var $defaultflags        = array(
127
                'mode'        => 0,
128
                'uid'        => 0,
129
                'gid'        => 0,
130
                'time'        => 0,
131
                'type'        => 0,
132
                'link'        => "",
133
                'path'        => "",
134
        );
135
        var $replacestats        = array();
136
        var $recursesd                = 1;
137
        var $storepath                = 1;
138
 
139
        function tarfile($cwd="./",$flags=array()) {
140
                $this->cwd = $cwd;
141
                $this->defaultflags['mode'] = decoct(0x8000 | 0x0100 | 0x0080 | 0x0020 | 0x0004);
142
                $this->defaultflags['time'] = time();
143
                if(isset($flags['recursesd']))
144
                        $this->recursesd = $flags['recursesd'];
145
                if(isset($flags['storepath']))
146
                        $this->storepath = $flags['storepath'];
147
                if(isset($flags['replacestats'])) {
148
                        if(is_array($flags['replacestats'])) {
149
                                if(isset($flags['replacestats']['mode']))
150
                                        $this->replacestats['mode'] = $flags['replacestats']['mode'];
151
                                if(isset($flags['replacestats']['time']))
152
                                        $this->replacestats['time'] = $flags['replacestats']['time'];
153
                        }
154
                        else if($flags['replacestats'] == 1) {
155
                                $this->replacestats['mode'] = $this->defaultflags['mode'];
156
                                $this->replacestats['time'] = $this->defaultflags['time'];
157
                        }
158
                }
159
 
160
                $this->archive($flags);
161
        }
162
 
163
        function addfile($data,$filename,$flags=array()) {
164
                if(strlen($filename) > 99)
165
                        return $this->error("The file name $filename is too long to archive.");
166
 
167
                $flags['mode'] = isset($this->replacestats['mode'])? $this->replacestats['mode'] : (isset($flags['mode'])? $flags['mode'] : $this->defaultflags['mode']);
168
                $flags['uid'] = isset($flags['uid'])? $flags['uid'] : $this->defaultflags['uid'];
169
                $flags['gid'] = isset($flags['gid'])? $flags['gid'] : $this->defaultflags['gid'];
170
                $flags['time'] = isset($this->replacestats['time'])? $this->replacestats['time'] : (isset($flags['time'])? $flags['time'] : $this->defaultflags['time']);
171
                $flags['type'] = isset($flags['type'])? $flags['type'] : $this->defaultflags['type'];
172
                $flags['link'] = isset($flags['link'])? $flags['link'] : $this->defaultflags['link'];
173
                $flags['path'] = isset($flags['path'])? $flags['path'] : $this->defaultflags['path'];
174
                $flags['size'] = isset($flags['size'])? $flags['size'] : strlen($data);
175
 
176
                if($this->storepath != 1) {
177
                        $filename = strstr($filename,"/")? substr($filename,strrpos($filename,"/")+1) : $filename;
178
                        $flags['path'] = "";
179
                }
180
                else
181
                        $filename = preg_replace("/^(\.{1,2}(\/|\\\))+/","",$filename);
182
 
183
                $blockbeg = pack("a100a8a8a8a12a12",$filename,$flags['mode'],sprintf("%6s ",decoct($flags['uid'])),sprintf("%6s ",decoct($flags['gid'])),sprintf("%11s ",decoct($flags['size'])),sprintf("%11s ",decoct($flags['time'])));
184
                $blockend = pack("a1a100a6a2a32a32a8a8a155",$flags['type'],$flags['link'],"ustar","00","Unknown","Unknown","","",$flags['path']);
185
 
186
                $checksum = 0;
187
                for($i = 0; $i < 148; $i++)
188
                        $checksum += ord(substr($blockbeg,$i,1));
189
                for($i = 148; $i < 156; $i++)
190
                        $checksum += ord(" ");
191
                for($i = 156; $i < 512; $i++)
192
                        $checksum += ord(substr($blockend,$i-156,1));
193
                $checksum = pack("a8",sprintf("%6s ",decoct($checksum)));
194
 
195
                if($flags['size'] % 512 > 0)
196
                        $data .= $this->nullpad(512 - $flags['size'] % 512);
197
 
198
                $this->tardata .= $blockbeg . $checksum . $blockend . pack("a12","") . $data;
199
        }
200
 
201
        function addfiles($filelist) {
202
                $pwd = getcwd();
203
                @chdir($this->cwd);
204
 
205
                foreach($filelist as $current) {
206
                        $file = array();
207
 
208
                        if($this->storepath != 1)
209
                                $file['name'] = strstr($current,"/")? substr($current,strrpos($current,"/")+1) : $current;
210
                        else
211
                                $file['name'] = preg_replace("/^(\.{1,2}(\/|\\\))+/","",$current);
212
 
213
                        $file['mode'] = @fileperms($current);
214
                        if($file['mode'] & 0x4000)
215
                                $file['type'] = 5;        // Directory
216
                        else if($file['mode'] & 0x8000)
217
                                $file['type'] = 0;        // Regular
218
                        else if($file['mode'] & 0xA000)
219
                                $file['type'] = 1;        // Link
220
                        else
221
                                $file['type'] = 9;        // Unknown
222
                        $file['mode'] = decoct($file['mode']);
223
 
224
                        if($file['type'] == 0 && !@file_exists($current))
225
                                return $this->error("$current does not exist");
226
                        else if(strlen($file['name']) > 99) {
227
                                $offset = strrpos($file['name'],"/") + 1;
228
                                $file['path'] = substr($file['name'],0,$offset);
229
                                $file['name'] = substr($file['name'],$offset);
230
                                if(strlen($file['name']) > 99 || strlen($file['path']) > 154)
231
                                        return $this->error("The file name {$file['name']} is too long to archive.");
232
                        }
233
                        else
234
                                $file['path'] = "";
235
 
236
                        $stat = stat($current);
237
 
238
                        if(($file['type'] == 0 || $file['type'] == 1) && $fp = @fopen($current,"rb")) {
239
                                $data = fread($fp,$stat[7]);
240
                                fclose($fp);
241
                        }
242
                        else
243
                                $data = "";
244
 
245
                        $flags = array(
246
                                'mode'        => $file['mode'],
247
                                'uid'        => $stat[4],
248
                                'gid'        => $stat[5],
249
                                'size'        => $stat[7],
250
                                'time'        => $stat[9],
251
                                'type'        => $file['type'],
252
                                'link'        => $file['type'] == 1? @readlink($current) : "",
253
                                'path'        => $file['path'],
254
                        );
255
 
256
                        $this->addfile($data,$file['name'],$flags);
257
                }
258
 
259
                @chdir($pwd);
260
        }
261
 
262
        function extract($data) {
263
                $return = array();
264
                $blocks = strlen($data)/512 - 1;
265
                $offset = 0;
266
 
267
                while($offset < $blocks) {
268
                        $header = substr($data,512*$offset,512);
269
                        $current = unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1type/a100linkname/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor/a155path",$header);
270
                        foreach($current as $k => $v)
271
                                $current[$k] = trim($v);
272
                        $current['mode'] = octdec($current['mode']);
273
                        $current['uid'] = octdec($current['uid']);
274
                        $current['gid'] = octdec($current['gid']);
275
                        $current['size'] = octdec($current['size']);
276
                        $current['mtime'] = octdec($current['mtime']);
277
                        $current['checksum'] = octdec($current['checksum']);
278
                        $current['type'] = octdec($current['type']);
279
 
280
                        if($this->storepath != 1)
281
                                $current['filename'] = substr($current['filename'],strrpos($current['filename'],"/")+1);
282
 
283
                        $checksum = 0;
284
                        for($i = 0; $i < 148; $i++)
285
                                $checksum += ord(substr($header,$i,1));
286
                        for($i = 148; $i < 156; $i++)
287
                                $checksum += ord(" ");
288
                        for($i = 156; $i < 512; $i++)
289
                                $checksum += ord(substr($header,$i,1));
290
                        if($current['checksum'] != $checksum)
291
                                return $this->error("Checksum error.");
292
 
293
                        $size = ceil($current['size']/512);
294
                        $current['data'] = substr($data,512*(++$offset),$current['size']);
295
                        $offset += $size;
296
                        $return[] = $current;
297
                }
298
 
299
                return $return;
300
        }
301
 
302
        function getdata() {
303
                return $this->tardata . pack("a512","");
304
        }
305
 
306
        function filedownload($filename) {
307
                @header("Content-type: application/x-tar");
308
                @header("Content-disposition: attachment; filename=$filename");
309
 
310
                print($this->getdata());
311
        }
312
 
313
        function nullpad($bytes) {
314
                $return = "";
315
                for($i = 0; $i < $bytes; ++$i)
316
                        $return .= "\0";
317
                return $return;
318
        }
319
}
320
 
321
class gzfile extends archive {
322
        var $gzdata = "";
323
 
324
        function addfile($data,$filename=null,$comment=null) {
325
                $flags = bindec("000".(!empty($comment)? "1" : "0").(!empty($filename)? "1" : "0")."000");
326
                $this->gzdata .= pack("C1C1C1C1VC1C1",0x1f,0x8b,8,$flags,time(),2,0xFF);
327
 
328
                if(!empty($filename))
329
                        $this->gzdata .= "$filename\0";
330
 
331
                if(!empty($comment))
332
                        $this->gzdata .= "$comment\0";
333
 
334
                $this->gzdata .= gzdeflate($data);
335
 
336
                $this->gzdata .= pack("VV",crc32($data),strlen($data));
337
        }
338
 
339
        function extract($data) {
340
                $id = unpack("H2id1/H2id2",substr($data,0,2));
341
                if($id['id1'] != "1f" || $id['id2'] != "8b")
342
                        return $this->error("Not valid gzip data.");
343
 
344
                $temp = unpack("Cflags",substr($data,2,1));
345
                $temp = decbin($temp['flags']);
346
                if($temp & 0x8)
347
                        $flags['name'] = 1;
348
                if($temp & 0x4)
349
                        $flags['comment'] = 1;
350
 
351
                $offset = 10;
352
 
353
                $filename = "";
354
                while(!empty($flags['name'])) {
355
                        $char = substr($data,$offset,1);
356
                        $offset++;
357
                        if($char == "\0")
358
                                break;
359
                        $filename .= $char;
360
                }
361
                if($filename == "")
362
                        $filename = "file";
363
 
364
                $comment = "";
365
                while(!empty($flags['comment'])) {
366
                        $char = substr($data,$offset,1);
367
                        $offset++;
368
                        if($char == "\0")
369
                                break;
370
                        $comment .= $char;
371
                }
372
 
373
                $temp = unpack("Vcrc32/Visize",substr($data,strlen($data)-8,8));
374
                $crc32 = $temp['crc32'];
375
                $isize = $temp['isize'];
376
 
377
                $data = gzinflate(substr($data,$offset,strlen($data)-8-$offset));
378
 
379
                if($crc32 != crc32($data))
380
                        return $this->error("Checksum error");
381
 
382
                return array('filename'=>$filename,'comment'=>$comment,'size'=>$isize,'data'=>$data);
383
        }
384
 
385
        function getdata() {
386
                return $this->gzdata;
387
        }
388
 
389
        function filedownload($filename) {
390
                @header("Content-type: application/x-gzip");
391
                @header("Content-disposition: attachment; filename=$filename");
392
 
393
                print($this->getdata());
394
        }
395
}
396
 
397
class zipfile extends archive {
398
        var $cwd                = "./";
399
        var $comment        = "";
400
        var $level                = 9;
401
        var $offset                = 0;
402
        var $recursesd        = 1;
403
        var $storepath        = 1;
404
        var $replacetime        = 0;
405
        var $central        = array();
406
        var $zipdata        = array();
407
 
408
        function zipfile($cwd="./",$flags=array()) {
409
                $this->cwd = $cwd;
410
                if(isset($flags['time']))
411
                        $this->replacetime = $flags['time'];
412
                if(isset($flags['recursesd']))
413
                        $this->recursesd = $flags['recursesd'];
414
                if(isset($flags['storepath']))
415
                        $this->storepath = $flags['storepath'];
416
                if(isset($flags['level']))
417
                        $this->level = $flags['level'];
418
                if(isset($flags['comment']))
419
                        $this->comment = $flags['comment'];
420
 
421
                $this->archive($flags);
422
        }
423
 
424
        function addfile($data,$filename,$flags=array()) {
425
                if($this->storepath != 1)
426
                        $filename = strstr($filename,"/")? substr($filename,strrpos($filename,"/")+1) : $filename;
427
                else
428
                        $filename = preg_replace("/^(\.{1,2}(\/|\\\))+/","",$filename);
429
 
430
                $mtime = !empty($this->replacetime)? getdate($this->replacetime) : (isset($flags['time'])? getdate($flags['time']) : getdate());
431
                $mtime = preg_replace("/(..){1}(..){1}(..){1}(..){1}/","\\x\\4\\x\\3\\x\\2\\x\\1",dechex(($mtime['year']-1980<<25)|($mtime['mon']<<21)|($mtime['mday']<<16)|($mtime['hours']<<11)|($mtime['minutes']<<5)|($mtime['seconds']>>1)));
432
                eval('$mtime = "'.$mtime.'";');
433
 
434
                $crc32 = crc32($data);
435
                $normlength = strlen($data);
436
                if(function_exists('gzcompress') ){
437
                        $data = gzcompress($data,$this->level);
438
                }
439
                $data = substr($data,2,strlen($data)-6);
440
                $complength = strlen($data);
441
 
442
                $this->zipdata[] = "\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00".$mtime.pack("VVVvv",$crc32,$complength,$normlength,strlen($filename),0x00).$filename.$data.pack("VVV",$crc32,$complength,$normlength);
443
                $this->central[] = "\x50\x4b\x01\x02\x00\x00\x14\x00\x00\x00\x08\x00".$mtime.pack("VVVvvvvvVV",$crc32,$complength,$normlength,strlen($filename),0x00,0x00,0x00,0x00,0x0000,$this->offset).$filename;
444
 
445
                $this->offset = strlen(implode("",$this->zipdata));
446
        }
447
 
448
        function addfiles($filelist) {
449
                $pwd = getcwd();
450
                @chdir($this->cwd);
451
 
452
                foreach($filelist as $current) {
453
                        if(!@file_exists($current))
454
                                continue;
455
 
456
                        $stat = stat($current);
457
 
458
                        if($fp = @fopen($current,"rb")) {
459
                                $data = fread($fp,$stat[7]);
460
                                fclose($fp);
461
                        }
462
                        else
463
                                $data = "";
464
 
465
                        $flags = array('time'=>$stat[9]);
466
 
467
                        $this->addfile($data,$current,$flags);
468
                }
469
 
470
                @chdir($pwd);
471
        }
472
 
473
        function getdata() {
474
                $central = implode("",$this->central);
475
                $zipdata = implode("",$this->zipdata);
476
                return $zipdata.$central."\x50\x4b\x05\x06\x00\x00\x00\x00".pack("vvVVv",sizeof($this->central),sizeof($this->central),strlen($central),strlen($zipdata),strlen($this->comment)).$this->comment;
477
        }
478
 
479
        function filedownload($filename) {
480
                @header("Content-type: application/zip");
481
                @header("Content-disposition: attachment; filename=$filename");
482
 
483
                print($this->getdata());
484
        }
485
}
486
 
487
class archive {
488
        var $overwrite                = 0;
489
        var $defaultperms        = 0644;
490
 
491
        function archive($flags=array()) {
492
                if(isset($flags['overwrite']))
493
                        $this->overwrite = $flags['overwrite'];
494
                if(isset($flags['defaultperms']))
495
                        $this->defaultperms = $flags['defaultperms'];
496
        }
497
 
498
        function adddirectories($dirlist) {
499
                $pwd = getcwd();
500
                @chdir($this->cwd);
501
 
502
                $filelist = array();
503
 
504
                foreach($dirlist as $current) {
505
                        if(@is_dir($current)) {
506
                                $temp = $this->parsedirectories($current);
507
                                foreach($temp as $filename)
508
                                        $filelist[] = $filename;
509
                        }
510
                        else if(@file_exists($current))
511
                                $filelist[] = $current;
512
                }
513
 
514
                @chdir($pwd);
515
                $this->addfiles($filelist);
516
        }
517
 
518
        function parsedirectories($dirname) {
519
                $filelist = array();
520
                $dir = @opendir($dirname);
521
 
522
                while($file = @readdir($dir)) {
523
                        if($file == "." || $file == "..")
524
                                continue;
525
                        else if(@is_dir($dirname."/".$file)) {
526
                                if($this->recursesd != 1)
527
                                        continue;
528
                                $temp = $this->parsedirectories($dirname."/".$file);
529
                                foreach($temp as $file2)
530
                                        $filelist[] = $file2;
531
                        }
532
                        else if(@file_exists($dirname."/".$file))
533
                                $filelist[] = $dirname."/".$file;
534
                }
535
 
536
                @closedir($dir);
537
 
538
                return $filelist;
539
        }
540
 
541
        function filewrite($filename,$perms=null) {
542
                if($this->overwrite != 1 && @file_exists($filename))
543
                        return $this->error("File $filename already exists.");
544
 
545
                if(@file_exists($filename))
546
                        @unlink($filename);
547
 
548
                $fp = @fopen($filename,"wb");
549
 
550
                if(!fwrite($fp,$this->getdata()))
551
                        return $this->error("Could not write data to $filename.");
552
 
553
                @fclose($fp);
554
 
555
                if(!isset($perms))
556
                        $perms = $this->defaultperms;
557
 
558
                @chmod($filename,$perms);
559
        }
560
 
561
        function extractfile($filename) {
562
                if($fp = @fopen($filename,"rb")) {
563
                        return $this->extract(fread($fp,filesize($filename)));
564
                        @fclose($fp);
565
                }
566
                else
567
                        return $this->error("Could not open $filename.");
568
        }
569
 
570
        function error($error) {
571
                $this->errors[] = $error;
572
                return 0;
573
        }
574
} ?>