仰望星辰工作室

better-staridc-MNBT

better-staridc-MNBT/ user/amftp/Class/archive.lib.php 14.1 KB · 510 行 原始文件
Z zfhsh first commit 2 天前
1<?php
2/************************************************
3 * Amysql FTP - AMFTP 3.0
4 * amh.sh
5 * Update:2021-01-15
6 *
7 */
8
9/*--------------------------------------------------
10 | TAR/GZIP/BZIP2/ZIP ARCHIVE CLASSES 2.1
11 | By Devin Doucette
12 | Copyright (c) 2005 Devin Doucette
13 | Email: darksnoopy@shaw.ca
14 +--------------------------------------------------
15 | Email bugs/suggestions to darksnoopy@shaw.ca
16 +--------------------------------------------------
17 | This script has been created and released under
18 | the GNU GPL and is free to use and redistribute
19 | only if this copyright statement is not removed
20 +--------------------------------------------------*/
21
22class archive
23{
24 function archive_init($name)
25 {
26 $this->options = array (
27 'basedir' => ".",
28 'name' => $name,
29 'prepend' => "",
30 'inmemory' => 0,
31 'overwrite' => 0,
32 'recurse' => 1,
33 'storepaths' => 1,
34 'followlinks' => 0,
35 'level' => 3,
36 'method' => 1,
37 'sfx' => "",
38 'type' => "",
39 'comment' => ""
40 );
41 $this->files = array ();
42 $this->exclude = array ();
43 $this->storeonly = array ();
44 $this->error = array ();
45 }
46
47 function set_options($options)
48 {
49 foreach ($options as $key => $value)
50 $this->options[$key] = $value;
51 if (!empty ($this->options['basedir']))
52 {
53 $this->options['basedir'] = str_replace("\\", "/", $this->options['basedir']);
54 $this->options['basedir'] = preg_replace("/\/+/", "/", $this->options['basedir']);
55 $this->options['basedir'] = preg_replace("/\/$/", "", $this->options['basedir']);
56 }
57 if (!empty ($this->options['name']))
58 {
59 $this->options['name'] = str_replace("\\", "/", $this->options['name']);
60 $this->options['name'] = preg_replace("/\/+/", "/", $this->options['name']);
61 }
62 if (!empty ($this->options['prepend']))
63 {
64 $this->options['prepend'] = str_replace("\\", "/", $this->options['prepend']);
65 $this->options['prepend'] = preg_replace("/^(\.*\/+)+/", "", $this->options['prepend']);
66 $this->options['prepend'] = preg_replace("/\/+/", "/", $this->options['prepend']);
67 $this->options['prepend'] = preg_replace("/\/$/", "", $this->options['prepend']) . "/";
68 }
69 }
70
71 function create_archive()
72 {
73 $this->make_list();
74
75 if ($this->options['inmemory'] == 0)
76 {
77 $pwd = getcwd();
78 chdir($this->options['basedir']);
79 if ($this->options['overwrite'] == 0 && file_exists($this->options['name'] . ($this->options['type'] == "gzip" || $this->options['type'] == "bzip" ? ".tmp" : "")))
80 {
81 $this->error[] = "File {$this->options['name']} already exists.";
82 chdir($pwd);
83 return 0;
84 }
85 else if ($this->archive = @fopen($this->options['name'] . ($this->options['type'] == "gzip" || $this->options['type'] == "bzip" ? ".tmp" : ""), "wb+"))
86 chdir($pwd);
87 else
88 {
89 $this->error[] = "Could not open {$this->options['name']} for writing.";
90 chdir($pwd);
91 return 0;
92 }
93 }
94 else
95 $this->archive = "";
96
97 switch ($this->options['type'])
98 {
99 case "gzip":
100 if (!$this->create_tar())
101 {
102 $this->error[] = "Could not create tar file.";
103 return 0;
104 }
105 if (!$this->create_gzip())
106 {
107 $this->error[] = "Could not create gzip file.";
108 return 0;
109 }
110 break;
111 case "tar":
112 if (!$this->create_tar())
113 {
114 $this->error[] = "Could not create tar file.";
115 return 0;
116 }
117 }
118
119 if ($this->options['inmemory'] == 0)
120 {
121 fclose($this->archive);
122 if ($this->options['type'] == "gzip" || $this->options['type'] == "bzip")
123 unlink($this->options['name'] . ".tmp");
124 }
125 }
126
127 function add_data($data)
128 {
129 if ($this->options['inmemory'] == 0)
130 fwrite($this->archive, $data);
131 else
132 $this->archive .= $data;
133 }
134
135 function make_list()
136 {
137 if (!empty ($this->exclude))
138 foreach ($this->files as $key => $value)
139 foreach ($this->exclude as $current)
140 if ($value['name'] == $current['name'])
141 unset ($this->files[$key]);
142 if (!empty ($this->storeonly))
143 foreach ($this->files as $key => $value)
144 foreach ($this->storeonly as $current)
145 if ($value['name'] == $current['name'])
146 $this->files[$key]['method'] = 0;
147 unset ($this->exclude, $this->storeonly);
148 }
149
150 function add_files($list)
151 {
152 $temp = $this->list_files($list);
153 foreach ($temp as $current)
154 $this->files[] = $current;
155 }
156
157 function exclude_files($list)
158 {
159 $temp = $this->list_files($list);
160 foreach ($temp as $current)
161 $this->exclude[] = $current;
162 }
163
164 function store_files($list)
165 {
166 $temp = $this->list_files($list);
167 foreach ($temp as $current)
168 $this->storeonly[] = $current;
169 }
170
171 function list_files($list)
172 {
173 if (!is_array ($list))
174 {
175 $temp = $list;
176 $list = array ($temp);
177 unset ($temp);
178 }
179
180 $files = array ();
181
182 $pwd = getcwd();
183 chdir($this->options['basedir']);
184 foreach ($list as $current)
185 {
186 $current = str_replace("\\", "/", $current);
187 $current = preg_replace("/\/+/", "/", $current);
188 $current = preg_replace("/\/$/", "", $current);
189 if (strstr($current, "*"))
190 {
191 $regex = preg_replace("/([\\\^\$\.\[\]\|\(\)\?\+\{\}\/])/", "\\\\\\1", $current);
192 $regex = str_replace("*", ".*", $regex);
193 $dir = strstr($current, "/") ? substr($current, 0, strrpos($current, "/")) : ".";
194 $temp = $this->parse_dir($dir);
195 foreach ($temp as $current2)
196 if (preg_match("/^{$regex}$/i", $current2['name']))
197 $files[] = $current2;
198 unset ($regex, $dir, $temp, $current);
199 }
200 else if (@is_dir($current))
201 {
202 echo "dir";
203 $temp = $this->parse_dir($current);
204 foreach ($temp as $file)
205 $files[] = $file;
206 unset ($temp, $file);
207 }
208 else if (@file_exists($current))
209 $files[] = array ('name' => $current, 'name2' => $this->options['prepend'] .
210 preg_replace("/(\.+\/+)+/", "", ($this->options['storepaths'] == 0 && strstr($current, "/")) ?
211 substr($current, strrpos($current, "/") + 1) : $current),
212 'type' => @is_link($current) && $this->options['followlinks'] == 0 ? 2 : 0,
213 'ext' => substr($current, strrpos($current, ".")), 'stat' => stat($current));
214 else {
215 echo "other error ";
216 }
217 }
218
219 chdir($pwd);
220
221 unset ($current, $pwd);
222
223 usort($files, array ("archive", "sort_files"));
224 //prt($files); //die;
225 return $files;
226
227 }
228
229 function parse_dir($dirname)
230 {
231 if ($this->options['storepaths'] == 1 && !preg_match("/^(\.+\/*)+$/", $dirname))
232 $files = array (array ('name' => $dirname, 'name2' => $this->options['prepend'] .
233 preg_replace("/(\.+\/+)+/", "", ($this->options['storepaths'] == 0 && strstr($dirname, "/")) ?
234 substr($dirname, strrpos($dirname, "/") + 1) : $dirname), 'type' => 5, 'stat' => stat($dirname)));
235 else
236 $files = array ();
237 $dir = @opendir($dirname);
238
239 while ($file = @readdir($dir))
240 {
241 $fullname = $dirname . "/" . $file;
242 if ($file == "." || $file == "..")
243 continue;
244 else if (@is_dir($fullname))
245 {
246 if (empty ($this->options['recurse']))
247 continue;
248 $temp = $this->parse_dir($fullname);
249 foreach ($temp as $file2)
250 $files[] = $file2;
251 }
252 else if (@file_exists($fullname))
253 $files[] = array ('name' => $fullname, 'name2' => $this->options['prepend'] .
254 preg_replace("/(\.+\/+)+/", "", ($this->options['storepaths'] == 0 && strstr($fullname, "/")) ?
255 substr($fullname, strrpos($fullname, "/") + 1) : $fullname),
256 'type' => @is_link($fullname) && $this->options['followlinks'] == 0 ? 2 : 0,
257 'ext' => substr($file, strrpos($file, ".")), 'stat' => stat($fullname));
258 }
259
260 @closedir($dir);
261
262 return $files;
263 }
264
265 function sort_files($a, $b)
266 {
267 if ($a['type'] != $b['type'])
268 if ($a['type'] == 5 || $b['type'] == 2)
269 return -1;
270 else if ($a['type'] == 2 || $b['type'] == 5)
271 return 1;
272 else if ($a['type'] == 5)
273 return strcmp(strtolower($a['name']), strtolower($b['name']));
274 else if ($a['ext'] != $b['ext'])
275 return strcmp($a['ext'], $b['ext']);
276 else if ($a['stat'][7] != $b['stat'][7])
277 return $a['stat'][7] > $b['stat'][7] ? -1 : 1;
278 else
279 return strcmp(strtolower($a['name']), strtolower($b['name']));
280 return 0;
281 }
282
283 function download_file()
284 {
285 if ($this->options['inmemory'] == 0)
286 {
287 $this->error[] = "Can only use download_file() if archive is in memory. Redirect to file otherwise, it is faster.";
288 return;
289 }
290 switch ($this->options['type'])
291 {
292 case "gzip":
293 header("Content-Type: application/x-gzip");
294 break;
295 case "tar":
296 header("Content-Type: application/x-tar");
297 }
298 $header = "Content-Disposition: attachment; filename=\"";
299 $header .= strstr($this->options['name'], "/") ? substr($this->options['name'], strrpos($this->options['name'], "/") + 1) : $this->options['name'];
300 $header .= "\"";
301 header($header);
302 header("Content-Length: " . strlen($this->archive));
303 header("Content-Transfer-Encoding: binary");
304 header("Cache-Control: no-cache, must-revalidate, max-age=60");
305 header("Expires: Sat, 01 Jan 2000 12:00:00 GMT");
306 print($this->archive);
307 }
308}
309
310class tar_file extends archive
311{
312 function tar_file_init($name)
313 {
314 $this->archive_init($name);
315 $this->options['type'] = "tar";
316 }
317
318 function create_tar()
319 {
320 $pwd = getcwd();
321 chdir($this->options['basedir']);
322
323 foreach ($this->files as $current)
324 {
325 if ($current['name'] == $this->options['name'])
326 continue;
327 if (strlen($current['name2']) > 99)
328 {
329 $path = substr($current['name2'], 0, strpos($current['name2'], "/", strlen($current['name2']) - 100) + 1);
330 $current['name2'] = substr($current['name2'], strlen($path));
331 if (strlen($path) > 154 || strlen($current['name2']) > 99)
332 {
333 $this->error[] = "Could not add {$path}{$current['name2']} to archive because the filename is too long.";
334 continue;
335 }
336 }
337 $block = pack("a100a8a8a8a12a12a8a1a100a6a2a32a32a8a8a155a12", $current['name2'], sprintf("%07o",
338 $current['stat'][2]), sprintf("%07o", $current['stat'][4]), sprintf("%07o", $current['stat'][5]),
339 sprintf("%011o", $current['type'] == 2 ? 0 : $current['stat'][7]), sprintf("%011o", $current['stat'][9]),
340 " ", $current['type'], $current['type'] == 2 ? @readlink($current['name']) : "", "ustar ", " ",
341 "Unknown", "Unknown", "", "", !empty ($path) ? $path : "", "");
342
343 $checksum = 0;
344 for ($i = 0; $i < 512; $i++)
345 $checksum += ord(substr($block, $i, 1));
346 $checksum = pack("a8", sprintf("%07o", $checksum));
347 $block = substr_replace($block, $checksum, 148, 8);
348
349 if ($current['type'] == 2 || $current['stat'][7] == 0)
350 $this->add_data($block);
351 else if ($fp = @fopen($current['name'], "rb"))
352 {
353 $this->add_data($block);
354 while ($temp = fread($fp, 1048576))
355 $this->add_data($temp);
356 if ($current['stat'][7] % 512 > 0)
357 {
358 $temp = "";
359 for ($i = 0; $i < 512 - $current['stat'][7] % 512; $i++)
360 $temp .= "\0";
361 $this->add_data($temp);
362 }
363 fclose($fp);
364 }
365 else
366 $this->error[] = "Could not open file {$current['name']} for reading. It was not added.";
367 }
368
369 $this->add_data(pack("a1024", ""));
370
371 chdir($pwd);
372
373 return 1;
374 }
375
376 function extract_files()
377 {
378 $pwd = getcwd();
379 chdir($this->options['basedir']);
380
381 if ($fp = $this->open_archive())
382 {
383 if ($this->options['inmemory'] == 1)
384 $this->files = array ();
385
386 while ($block = fread($fp, 512))
387 {
388 $temp = unpack("a100name/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1type/a100symlink/a6magic/a2temp/a32temp/a32temp/a8temp/a8temp/a155prefix/a12temp", $block);
389 $file = array (
390 'name' => $temp['prefix'] . $temp['name'],
391 'stat' => array (
392 2 => $temp['mode'],
393 4 => octdec($temp['uid']),
394 5 => octdec($temp['gid']),
395 7 => octdec($temp['size']),
396 9 => octdec($temp['mtime']),
397 ),
398 'checksum' => octdec($temp['checksum']),
399 'type' => $temp['type'],
400 'magic' => $temp['magic'],
401 );
402 if ($file['checksum'] == 0x00000000)
403 break;
404 else if (substr($file['magic'], 0, 5) != "ustar")
405 {
406 $this->error[] = "This script does not support extracting this type of tar file.";
407 break;
408 }
409 $block = substr_replace($block, " ", 148, 8);
410 $checksum = 0;
411 for ($i = 0; $i < 512; $i++)
412 $checksum += ord(substr($block, $i, 1));
413 if ($file['checksum'] != $checksum)
414 $this->error[] = "Could not extract from {$this->options['name']}, it is corrupt.";
415
416 if ($this->options['inmemory'] == 1)
417 {
418 $file['data'] = fread($fp, $file['stat'][7]);
419 fread($fp, (512 - $file['stat'][7] % 512) == 512 ? 0 : (512 - $file['stat'][7] % 512));
420 unset ($file['checksum'], $file['magic']);
421 $this->files[] = $file;
422 }
423 else if ($file['type'] == 5)
424 {
425 if (!is_dir($file['name']))
426 mkdir($file['name'], $file['stat'][2]);
427 }
428 else if ($this->options['overwrite'] == 0 && file_exists($file['name']))
429 {
430 $this->error[] = "{$file['name']} already exists.";
431 continue;
432 }
433 else if ($file['type'] == 2)
434 {
435 symlink($temp['symlink'], $file['name']);
436 chmod($file['name'], $file['stat'][2]);
437 }
438 else if ($new = @fopen($file['name'], "wb"))
439 {
440 fwrite($new, fread($fp, $file['stat'][7]));
441 fread($fp, (512 - $file['stat'][7] % 512) == 512 ? 0 : (512 - $file['stat'][7] % 512));
442 fclose($new);
443 chmod($file['name'], $file['stat'][2]);
444 }
445 else
446 {
447 $this->error[] = "Could not open {$file['name']} for writing.";
448 continue;
449 }
450 chown($file['name'], $file['stat'][4]);
451 chgrp($file['name'], $file['stat'][5]);
452 touch($file['name'], $file['stat'][9]);
453 unset ($file);
454 }
455 }
456 else
457 $this->error[] = "Could not open file {$this->options['name']}";
458
459 chdir($pwd);
460 }
461
462 function open_archive()
463 {
464 return @fopen($this->options['name'], "rb");
465 }
466}
467
468class gzip_file extends tar_file
469{
470 function __construct($name)
471 {
472 $this->tar_file_init($name);
473 $this->options['type'] = "gzip";
474 }
475
476 function create_gzip()
477 {
478 if ($this->options['inmemory'] == 0)
479 {
480 $pwd = getcwd();
481 chdir($this->options['basedir']);
482 if ($fp = gzopen($this->options['name'], "wb{$this->options['level']}"))
483 {
484 fseek($this->archive, 0);
485 while ($temp = fread($this->archive, 1048576))
486 gzwrite($fp, $temp);
487 gzclose($fp);
488 chdir($pwd);
489 }
490 else
491 {
492 $this->error[] = "Could not open {$this->options['name']} for writing.";
493 chdir($pwd);
494 return 0;
495 }
496 }
497 else
498 $this->archive = gzencode($this->archive, $this->options['level']);
499
500 return 1;
501 }
502
503 function open_archive()
504 {
505 return @gzopen($this->options['name'], "rb");
506 }
507}
508
509
510?>