[ Index ]
|
|
Code source de PHP PEAR 1.4.5
|
[Sommaire]
[Imprimer]
1 <?php #PHP_ARCHIVE_HEADER-0.8.0
2 error_reporting(E_ALL);
3 if (function_exists('mb_internal_encoding')) {
4 mb_internal_encoding('ASCII');
5 }
6 if (!class_exists('PHP_Archive')) {
7
8
9
10
11
12
13
14
15 define('PHP_ARCHIVE_COMPRESSED', 1);
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 class PHP_Archive
36 {
37
38
39
40
41
42 private $_compressed;
43
44
45
46 private $_archiveName = null;
47
48
49
50
51 protected $currentFilename = null;
52
53
54
55
56 protected $internalFileLength = null;
57
58
59
60
61 protected $currentStat = null;
62
63
64
65 protected $fp = null;
66
67
68
69 protected $position = 0;
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86 private static $_pharMapping = array();
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101 private static $_manifest = array();
102
103
104
105
106
107
108 private static $_fileStart = array();
109
110
111
112
113
114 private $_basename;
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129 public static final function mapPhar($file, $dataoffset)
130 {
131 $file = realpath($file);
132
133 if (!in_array($file, get_included_files())) {
134 die('SECURITY ERROR: PHP_Archive::mapPhar can only be called from within ' .
135 'the phar that initiates it');
136 }
137 if (!is_array(self::$_pharMapping)) {
138 self::$_pharMapping = array();
139 }
140 if (!isset(self::$_manifest[$file])) {
141 $fp = fopen($file, 'rb');
142
143 fseek($fp, $dataoffset);
144 $manifest_length = unpack('Vlen', fread($fp, 4));
145 $manifest = '';
146 $last = '1';
147 while (strlen($last) && strlen($manifest) < $manifest_length['len']) {
148 $read = 8192;
149 if ($manifest_length['len'] - strlen($manifest) < 8192) {
150 $read = $manifest_length['len'] - strlen($manifest);
151 }
152 $last = fread($fp, $read);
153 $manifest .= $last;
154 }
155 if (strlen($manifest) < $manifest_length['len']) {
156 die('ERROR: manifest length read was "' . strlen($manifest) .'" should be "' .
157 $manifest_length['len'] . '"');
158 }
159 $info = self::_unserializeManifest($manifest);
160 if (!$info) {
161 die;
162 }
163 $alias = $info['alias'];
164 self::$_manifest[$file] = $info['manifest'];
165 $compressed = $info['compressed'];
166 self::$_fileStart[$file] = ftell($fp);
167 fclose($fp);
168 }
169 if ($compressed) {
170 if (!function_exists('gzinflate')) {
171 die('Error: zlib extension is not enabled - gzinflate() function needed' .
172 ' for compressed .phars');
173 }
174 }
175 if (isset(self::$_pharMapping[$alias])) {
176 die('ERROR: PHP_Archive::mapPhar has already been called for alias "' .
177 $alias . '" cannot re-alias to "' . $file . '"');
178 }
179 self::$_pharMapping[$alias] = array($file, $compressed, $dataoffset);
180 }
181
182
183
184
185 private static function processFile($path)
186 {
187 if ($path == '.') {
188 return '';
189 }
190 $std = str_replace("\\", "/", $path);
191 while ($std != ($std = ereg_replace("[^\/:?]+/\.\./", "", $std))) ;
192 $std = str_replace("/./", "", $std);
193 if (strlen($std) > 1 && $std[0] == '/') {
194 $std = substr($std, 1);
195 }
196 if (strncmp($std, "./", 2) == 0) {
197 return substr($std, 2);
198 } else {
199 return $std;
200 }
201 }
202
203
204
205
206
207 protected function selectFile($path, $allowdirs = true)
208 {
209 $std = self::processFile($path);
210 if (isset(self::$_manifest[$this->_archiveName][$path])) {
211 $this->_setCurrentFile($path);
212 return true;
213 }
214 if (!$allowdirs) {
215 return 'Error: "' . $path . '" is not a file in phar "' . $this->_basename . '"';
216 }
217 foreach (self::$_manifest[$this->_archiveName] as $file => $info) {
218 if (empty($std) ||
219
220 strncmp($std.'/', $path, strlen($std)+1) == 0) {
221 $this->currentFilename = $this->internalFileLength = $this->currentStat = null;
222 return true;
223 }
224 }
225 return 'Error: "' . $path . '" not found in phar "' . $this->_basename . '"';
226 }
227
228 private function _setCurrentFile($path)
229 {
230 $this->currentStat = array(
231 2 => 0100444, // file mode, readable by all, writeable by none
232 4 => 0, // uid
233 5 => 0, // gid
234 7 => self::$_manifest[$this->_archiveName][$path][0], // size
235 9 => self::$_manifest[$this->_archiveName][$path][1], // creation time
236 );
237 $this->currentFilename = $path;
238 $this->internalFileLength = self::$_manifest[$this->_archiveName][$path][2];
239
240 if (is_resource(@$this->fp)) {
241 fseek($this->fp, self::$_fileStart[$this->_archiveName] + self::$_manifest[$this->_archiveName][$path][5]);
242 }
243 }
244
245
246
247
248
249
250
251 public function extractFile($path)
252 {
253 $this->fp = @fopen($this->_archiveName, "rb");
254 if (!$this->fp) {
255 return array('Error: cannot open phar "' . $this->_archiveName . '"');
256 }
257 if (($e = $this->selectFile($path, false)) === true) {
258 $data = '';
259 $count = $this->internalFileLength;
260 while ($count) {
261 if ($count < 8192) {
262 $data .= @fread($this->fp, $count);
263 $count = 0;
264 } else {
265 $count -= 8192;
266 $data .= @fread($this->fp, 8192);
267 }
268 }
269 @fclose($this->fp);
270 if (self::$_manifest[$this->_archiveName][$path][4] & PHP_ARCHIVE_COMPRESSED) {
271 $data = gzinflate($data);
272 }
273 if (!isset(self::$_manifest[$this->_archiveName][$path]['ok'])) {
274 if (strlen($data) != $this->currentStat[7]) {
275 return array("Not valid internal .phar file (size error {$size} != " .
276 $this->currentStat[7] . ")");
277 }
278 if (self::$_manifest[$this->_archiveName][$path][3] != crc32($data)) {
279 return array("Not valid internal .phar file (checksum error)");
280 }
281 self::$_manifest[$this->_archiveName][$path]['ok'] = true;
282 }
283 return $data;
284 } else {
285 @fclose($this->fp);
286 return array($e);
287 }
288 }
289
290
291
292
293
294
295
296
297
298
299
300
301 public function initializeStream($file)
302 {
303 $info = parse_url($file);
304 if (!isset($info['host']) || !count(self::$_pharMapping)) {
305
306 return false;
307 }
308 if (!isset($info['path'])) {
309
310 $info['path'] = $info['host'];
311 $info['host'] = '';
312 } elseif (strlen($info['path']) > 1) {
313 $info['path'] = substr($info['path'], 1);
314 }
315 if (isset(self::$_pharMapping[$info['host']])) {
316 $this->_basename = $info['host'];
317 $this->_archiveName = self::$_pharMapping[$info['host']][0];
318 $this->_compressed = self::$_pharMapping[$info['host']][1];
319 } else {
320
321 $pharinfo = end(self::$_pharMapping);
322 $this->_basename = key(self::$_pharMapping);
323 $this->_archiveName = $pharinfo[0];
324 $this->_compressed = $pharinfo[1];
325 }
326 $file = $info['path'];
327 return $file;
328 }
329
330
331
332
333
334
335
336 private static function _unserializeManifest($manifest)
337 {
338
339 $info = unpack('V', substr($manifest, 0, 4));
340 $apiver = substr($manifest, 4, 2);
341 $apiver = bin2hex($apiver);
342 $apiver_dots = hexdec($apiver[0]) . '.' . hexdec($apiver[1]) . '.' . hexdec($apiver[2]);
343 $majorcompat = hexdec($apiver[0]);
344 $calcapi = explode('.', '0.8.0');
345 if ($calcapi[0] != $majorcompat) {
346 trigger_error('Phar is incompatible API version ' . $apiver_dots . ', but ' .
347 'PHP_Archive is API version 0.8.0');
348 return false;
349 }
350 if ($calcapi[0] === '0') {
351 if ('0.8.0' != $apiver_dots) {
352 trigger_error('Phar is API version ' . $apiver_dots .
353 ', but PHP_Archive is API version 0.8.0', E_USER_ERROR);
354 return false;
355 }
356 }
357 $ret = array('compressed' => $apiver[3]);
358 $aliaslen = unpack('V', substr($manifest, 6, 4));
359 $ret['alias'] = substr($manifest, 10, $aliaslen[1]);
360 $manifest = substr($manifest, 10 + $aliaslen[1]);
361 $offset = 0;
362 $start = 0;
363 for ($i = 0; $i < $info[1]; $i++) {
364
365 $len = unpack('V', substr($manifest, $start, 4));
366 $start += 4;
367
368 $savepath = substr($manifest, $start, $len[1]);
369 $start += $len[1];
370
371
372
373
374
375
376 $ret['manifest'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ce', substr($manifest, $start, 17)));
377 $ret['manifest'][$savepath][5] = $offset;
378 $offset += $ret['manifest'][$savepath][2];
379 $start += 17;
380 }
381 return $ret;
382 }
383
384
385
386
387
388
389
390 public function stream_open($file)
391 {
392 return $this->_streamOpen($file);
393 }
394
395
396
397
398
399
400
401
402
403 private function _streamOpen($file, $searchForDir = false)
404 {
405 $path = $this->initializeStream($file);
406 if (!$path) {
407 trigger_error('Error: Unknown phar in "' . $file . '"', E_USER_ERROR);
408 }
409 if (is_array($this->file = $this->extractFile($path))) {
410 trigger_error($this->file[0], E_USER_ERROR);
411 return false;
412 }
413 if ($path != $this->currentFilename) {
414 if (!$searchForDir) {
415 trigger_error("Cannot open '$file', is a directory", E_USER_ERROR);
416 return false;
417 } else {
418 $this->file = '';
419 return true;
420 }
421 }
422
423 if (!is_null($this->file) && $this->file !== false) {
424 return true;
425 } else {
426 return false;
427 }
428 }
429
430
431
432
433
434
435
436 public function stream_read($count)
437 {
438 $ret = substr($this->file, $this->position, $count);
439 $this->position += strlen($ret);
440 return $ret;
441 }
442
443
444
445
446
447 function stream_eof()
448 {
449 return $this->position >= $this->currentStat[7];
450 }
451
452
453
454
455
456
457
458 public function stream_seek($pos, $whence)
459 {
460 switch ($whence) {
461 case SEEK_SET:
462 if ($pos < 0) {
463 return false;
464 }
465 $this->position = $pos;
466 break;
467 case SEEK_CUR:
468 if ($pos + $this->currentStat[7] < 0) {
469 return false;
470 }
471 $this->position += $pos;
472 break;
473 case SEEK_END:
474 if ($pos + $this->currentStat[7] < 0) {
475 return false;
476 }
477 $this->position = $pos + $this->currentStat[7];
478 default:
479 return false;
480 }
481 return true;
482 }
483
484
485
486
487
488 public function stream_tell()
489 {
490 return $this->position;
491 }
492
493
494
495
496
497
498
499 public function stream_stat()
500 {
501 return $this->_stream_stat();
502 }
503
504
505
506
507
508
509 public function _stream_stat($file = null)
510 {
511 $std = $file ? self::processFile($file) : $this->currentFilename;
512 if ($file) {
513 if (isset(self::$_manifest[$this->_archiveName][$file])) {
514 $this->_setCurrentFile($file);
515 $isdir = false;
516 } else {
517 $isdir = true;
518 }
519 } else {
520 $isdir = false;
521 }
522 $mode = $isdir ? 0040444 : 0100444;
523
524
525 return array(
526 0, 0, $mode, 0, 0, 0, 0, 0, 0, 0, 0, 0, // non-associative indices
527 'dev' => 0, 'ino' => 0,
528 'mode' => $mode,
529 'nlink' => 0, 'uid' => 0, 'gid' => 0, 'rdev' => 0, 'blksize' => 0, 'blocks' => 0,
530 'size' => $this->currentStat[7],
531 'atime' => $this->currentStat[9],
532 'mtime' => $this->currentStat[9],
533 'ctime' => $this->currentStat[9],
534 );
535 }
536
537
538
539
540
541
542
543 public function url_stat($url, $flags)
544 {
545 $path = $this->initializeStream($url);
546 return $this->_stream_stat($path);
547 }
548
549
550
551
552
553
554 public function dir_opendir($path)
555 {
556 $info = parse_url($path);
557 $path = !empty($info['path']) ?
558 $info['host'] . $info['path'] : $info['host'] . '/';
559 $path = $this->initializeStream('phar://' . $path);
560 if (isset(self::$_manifest[$this->_archiveName][$path])) {
561 trigger_error('Error: "' . $path . '" is a file, and cannot be opened with opendir',
562 E_USER_ERROR);
563 return false;
564 }
565 if ($path == false) {
566 trigger_error('Error: Unknown phar in "' . $file . '"', E_USER_ERROR);
567 return false;
568 }
569 $this->fp = @fopen($this->_archiveName, "rb");
570 if (!$this->fp) {
571 trigger_error('Error: cannot open phar "' . $this->_archiveName . '"');
572 return false;
573 }
574 $this->_dirFiles = array();
575 foreach (self::$_manifest[$this->_archiveName] as $file => $info) {
576 if ($path == '/') {
577 if (strpos($file, '/')) {
578 $a = explode('/', $file);
579 $this->_dirFiles[array_shift($a)] = true;
580 } else {
581 $this->_dirFiles[$file] = true;
582 }
583 } elseif (strpos($file, $path) === 0) {
584 $fname = substr($file, strlen($path) + 1);
585 if (strpos($fname, '/')) {
586 $a = explode('/', $fname);
587 $this->_dirFiles[array_shift($a)] = true;
588 } elseif (strlen($file) != strlen($path)) {
589
590 $this->_dirFiles[$fname] = true;
591 }
592 }
593 }
594 @fclose($this->fp);
595 @uksort($this->_dirFiles, 'strnatcmp');
596 return true;
597 }
598
599
600
601
602
603 public function dir_readdir()
604 {
605 $ret = key($this->_dirFiles);
606 @next($this->_dirFiles);
607 if (!$ret) {
608 return false;
609 }
610 return $ret;
611 }
612
613
614
615
616
617 public function dir_closedir()
618 {
619 $this->_dirFiles = array();
620 reset($this->_dirFiles);
621 return true;
622 }
623
624
625
626
627
628 public function dir_rewinddir()
629 {
630 reset($this->_dirFiles);
631 return true;
632 }
633
634
635
636
637
638 public final function APIVersion()
639 {
640 return '0.8.0';
641 }
642 }}
643 if (!class_exists('Phar')) {
644 if (!in_array('phar', stream_get_wrappers())) {
645 stream_wrapper_register('phar', 'PHP_Archive');
646 }
647 PHP_Archive::mapPhar(__FILE__, __COMPILER_HALT_OFFSET__);
648 } else {
649 Phar::mapPhar();
650 }
651 if (class_exists('PHP_Archive') && !in_array('phar', stream_get_wrappers())) {
652 stream_wrapper_register('phar', 'PHP_Archive');
653 }
654 @ini_set('memory_limit', -1);
655
656 require_once 'phar://go-pear.phar/index.php';
657 __HALT_COMPILER();! @ go-pear.phar Archive/Tar.php 4D') ο Console/Getopt.phpK&