| 1: | <?php
|
| 2: |
|
| 3: |
|
| 4: | |
| 5: | |
| 6: | |
| 7: | |
| 8: | |
| 9: | |
| 10: |
|
| 11: | |
| 12: | |
| 13: | |
| 14: | |
| 15: | |
| 16: | |
| 17: | |
| 18: | |
| 19: | |
| 20: | |
| 21: | |
| 22: | |
| 23: | |
| 24: | |
| 25: | |
| 26: | |
| 27: | |
| 28: | |
| 29: | |
| 30: | |
| 31: | |
| 32: | |
| 33: | |
| 34: | |
| 35: | |
| 36: | |
| 37: | |
| 38: | |
| 39: | |
| 40: | |
| 41: | |
| 42: | |
| 43: | |
| 44: | |
| 45: | |
| 46: | |
| 47: | |
| 48: | |
| 49: | |
| 50: | |
| 51: | |
| 52: | |
| 53: | |
| 54: | |
| 55: | |
| 56: | |
| 57: | |
| 58: | |
| 59: | |
| 60: | |
| 61: | |
| 62: | |
| 63: | |
| 64: | |
| 65: | |
| 66: | |
| 67: | |
| 68: | |
| 69: | |
| 70: | |
| 71: | |
| 72: | |
| 73: | |
| 74: | |
| 75: | |
| 76: | |
| 77: |
|
| 78: |
|
| 79: | |
| 80: | |
| 81: | |
| 82: | |
| 83: | |
| 84: | |
| 85: | |
| 86: | |
| 87: | |
| 88: | |
| 89: | |
| 90: | |
| 91: |
|
| 92: | class Tar
|
| 93: | {
|
| 94: | |
| 95: | |
| 96: | |
| 97: |
|
| 98: | public $filename;
|
| 99: | public $isGzipped;
|
| 100: | public $tar_file;
|
| 101: | |
| 102: | |
| 103: |
|
| 104: |
|
| 105: | |
| 106: | |
| 107: | |
| 108: |
|
| 109: | public $files;
|
| 110: | public $directories;
|
| 111: | public $numFiles;
|
| 112: | public $numDirectories;
|
| 113: | |
| 114: | |
| 115: |
|
| 116: |
|
| 117: | |
| 118: | |
| 119: |
|
| 120: | public function __construct()
|
| 121: | {
|
| 122: | }
|
| 123: |
|
| 124: | |
| 125: | |
| 126: | |
| 127: | |
| 128: | |
| 129: | |
| 130: | |
| 131: | |
| 132: |
|
| 133: | public function __computeUnsignedChecksum($bytestring)
|
| 134: | {
|
| 135: | $unsigned_chksum = '';
|
| 136: | for ($i = 0; $i < 512; ++$i) {
|
| 137: | $unsigned_chksum += ord($bytestring[$i]);
|
| 138: | }
|
| 139: | for ($i = 0; $i < 8; ++$i) {
|
| 140: | $unsigned_chksum -= ord($bytestring[148 + $i]);
|
| 141: | $unsigned_chksum += ord(' ') * 8;
|
| 142: | }
|
| 143: |
|
| 144: | return $unsigned_chksum;
|
| 145: | }
|
| 146: |
|
| 147: | |
| 148: | |
| 149: | |
| 150: | |
| 151: | |
| 152: | |
| 153: |
|
| 154: | public function __parseNullPaddedString($string)
|
| 155: | {
|
| 156: | $position = strpos($string, chr(0));
|
| 157: |
|
| 158: | return substr($string, 0, $position);
|
| 159: | }
|
| 160: |
|
| 161: | |
| 162: | |
| 163: | |
| 164: | |
| 165: | |
| 166: |
|
| 167: | public function __parseTar()
|
| 168: | {
|
| 169: |
|
| 170: | $tar_length = strlen($this->tar_file);
|
| 171: | $main_offset = 0;
|
| 172: | $this->numFiles = 0;
|
| 173: | while ($main_offset < $tar_length) {
|
| 174: |
|
| 175: | if (substr($this->tar_file, $main_offset, 512) == str_repeat(chr(0), 512)) {
|
| 176: | break;
|
| 177: | }
|
| 178: |
|
| 179: | $file_name = $this->__parseNullPaddedString(substr($this->tar_file, $main_offset, 100));
|
| 180: |
|
| 181: | $file_mode = substr($this->tar_file, $main_offset + 100, 8);
|
| 182: |
|
| 183: | $file_uid = octdec(substr($this->tar_file, $main_offset + 108, 8));
|
| 184: |
|
| 185: | $file_gid = octdec(substr($this->tar_file, $main_offset + 116, 8));
|
| 186: |
|
| 187: | $file_size = octdec(substr($this->tar_file, $main_offset + 124, 12));
|
| 188: |
|
| 189: | $file_time = octdec(substr($this->tar_file, $main_offset + 136, 12));
|
| 190: |
|
| 191: | $file_chksum = octdec(substr($this->tar_file, $main_offset + 148, 6));
|
| 192: |
|
| 193: | $file_uname = $this->__parseNullPaddedString(substr($this->tar_file, $main_offset + 265, 32));
|
| 194: |
|
| 195: | $file_gname = $this->__parseNullPaddedString(substr($this->tar_file, $main_offset + 297, 32));
|
| 196: |
|
| 197: | if ($this->__computeUnsignedChecksum(substr($this->tar_file, $main_offset, 512)) != $file_chksum) {
|
| 198: | return false;
|
| 199: | }
|
| 200: |
|
| 201: | $file_contents = substr($this->tar_file, $main_offset + 512, $file_size);
|
| 202: |
|
| 203: | |
| 204: | |
| 205: | |
| 206: | |
| 207: | |
| 208: | |
| 209: | |
| 210: | |
| 211: | |
| 212: | |
| 213: |
|
| 214: |
|
| 215: | if ($file_size > 0) {
|
| 216: |
|
| 217: | $this->numFiles++;
|
| 218: |
|
| 219: | $activeFile =& $this->files[];
|
| 220: |
|
| 221: | $activeFile['name'] = $file_name;
|
| 222: | $activeFile['mode'] = $file_mode;
|
| 223: | $activeFile['size'] = $file_size;
|
| 224: | $activeFile['time'] = $file_time;
|
| 225: | $activeFile['user_id'] = $file_uid;
|
| 226: | $activeFile['group_id'] = $file_gid;
|
| 227: | $activeFile['user_name'] = $file_uname;
|
| 228: | $activeFile['group_name'] = $file_gname;
|
| 229: | $activeFile['checksum'] = $file_chksum;
|
| 230: | $activeFile['file'] = $file_contents;
|
| 231: | } else {
|
| 232: |
|
| 233: | $this->numDirectories++;
|
| 234: |
|
| 235: | $activeDir =& $this->directories[];
|
| 236: |
|
| 237: | $activeDir['name'] = $file_name;
|
| 238: | $activeDir['mode'] = $file_mode;
|
| 239: | $activeDir['time'] = $file_time;
|
| 240: | $activeDir['user_id'] = $file_uid;
|
| 241: | $activeDir['group_id'] = $file_gid;
|
| 242: | $activeDir['user_name'] = $file_uname;
|
| 243: | $activeDir['group_name'] = $file_gname;
|
| 244: | $activeDir['checksum'] = $file_chksum;
|
| 245: | }
|
| 246: |
|
| 247: | $main_offset += 512 + (ceil($file_size / 512) * 512);
|
| 248: | }
|
| 249: |
|
| 250: | return true;
|
| 251: | }
|
| 252: |
|
| 253: | |
| 254: | |
| 255: | |
| 256: | |
| 257: | |
| 258: | |
| 259: |
|
| 260: | public function __readTar($filename = '')
|
| 261: | {
|
| 262: |
|
| 263: | if (!$filename) {
|
| 264: | $filename = $this->filename;
|
| 265: | }
|
| 266: |
|
| 267: | $fp = fopen($filename, 'rb');
|
| 268: | $this->tar_file = fread($fp, filesize($filename));
|
| 269: | fclose($fp);
|
| 270: |
|
| 271: | if ($this->tar_file[0] == chr(31) && $this->tar_file[1] == chr(139) && $this->tar_file[2] == chr(8)) {
|
| 272: | if (!function_exists('gzinflate')) {
|
| 273: | return false;
|
| 274: | }
|
| 275: | $this->isGzipped = true;
|
| 276: | $this->tar_file = gzinflate(substr($this->tar_file, 10, -4));
|
| 277: | }
|
| 278: |
|
| 279: | $this->__parseTar();
|
| 280: |
|
| 281: | return true;
|
| 282: | }
|
| 283: |
|
| 284: | |
| 285: | |
| 286: | |
| 287: | |
| 288: | |
| 289: |
|
| 290: | public function __generateTar()
|
| 291: | {
|
| 292: |
|
| 293: | unset($this->tar_file);
|
| 294: |
|
| 295: | if ($this->numDirectories > 0) {
|
| 296: | foreach ($this->directories as $key => $information) {
|
| 297: | unset($header);
|
| 298: |
|
| 299: |
|
| 300: | $header .= str_pad($information['name'], 100, chr(0));
|
| 301: | $header .= str_pad(decoct($information['mode']), 7, '0', STR_PAD_LEFT) . chr(0);
|
| 302: | $header .= str_pad(decoct($information['user_id']), 7, '0', STR_PAD_LEFT) . chr(0);
|
| 303: | $header .= str_pad(decoct($information['group_id']), 7, '0', STR_PAD_LEFT) . chr(0);
|
| 304: | $header .= str_pad(decoct(0), 11, '0', STR_PAD_LEFT) . chr(0);
|
| 305: | $header .= str_pad(decoct($information['time']), 11, '0', STR_PAD_LEFT) . chr(0);
|
| 306: | $header .= str_repeat(' ', 8);
|
| 307: | $header .= '5';
|
| 308: | $header .= str_repeat(chr(0), 100);
|
| 309: | $header .= str_pad('ustar', 6, chr(32));
|
| 310: | $header .= chr(32) . chr(0);
|
| 311: | $header .= str_pad('', 32, chr(0));
|
| 312: | $header .= str_pad('', 32, chr(0));
|
| 313: | $header .= str_repeat(chr(0), 8);
|
| 314: | $header .= str_repeat(chr(0), 8);
|
| 315: | $header .= str_repeat(chr(0), 155);
|
| 316: | $header .= str_repeat(chr(0), 12);
|
| 317: |
|
| 318: | $checksum = str_pad(decoct($this->__computeUnsignedChecksum($header)), 6, '0', STR_PAD_LEFT);
|
| 319: | for ($i = 0; $i < 6; ++$i) {
|
| 320: | $header[148 + $i] = substr($checksum, $i, 1);
|
| 321: | }
|
| 322: | $header[154] = chr(0);
|
| 323: | $header[155] = chr(32);
|
| 324: |
|
| 325: | $this->tar_file .= $header;
|
| 326: | }
|
| 327: | }
|
| 328: |
|
| 329: | if ($this->numFiles > 0) {
|
| 330: | $this->tar_file = '';
|
| 331: | foreach ($this->files as $key => $information) {
|
| 332: | unset($header);
|
| 333: |
|
| 334: |
|
| 335: | $header = str_pad($information['name'], 100, chr(0));
|
| 336: | $header .= str_pad(decoct($information['mode']), 7, '0', STR_PAD_LEFT) . chr(0);
|
| 337: | $header .= str_pad(decoct($information['user_id']), 7, '0', STR_PAD_LEFT) . chr(0);
|
| 338: | $header .= str_pad(decoct($information['group_id']), 7, '0', STR_PAD_LEFT) . chr(0);
|
| 339: | $header .= str_pad(decoct($information['size']), 11, '0', STR_PAD_LEFT) . chr(0);
|
| 340: | $header .= str_pad(decoct($information['time']), 11, '0', STR_PAD_LEFT) . chr(0);
|
| 341: | $header .= str_repeat(' ', 8);
|
| 342: | $header .= '0';
|
| 343: | $header .= str_repeat(chr(0), 100);
|
| 344: | $header .= str_pad('ustar', 6, chr(32));
|
| 345: | $header .= chr(32) . chr(0);
|
| 346: | $header .= str_pad($information['user_name'], 32, chr(0));
|
| 347: | $header .= str_pad($information['group_name'], 32, chr(0));
|
| 348: | $header .= str_repeat(chr(0), 8);
|
| 349: | $header .= str_repeat(chr(0), 8);
|
| 350: | $header .= str_repeat(chr(0), 155);
|
| 351: | $header .= str_repeat(chr(0), 12);
|
| 352: |
|
| 353: | $checksum = str_pad(decoct($this->__computeUnsignedChecksum($header)), 6, '0', STR_PAD_LEFT);
|
| 354: | for ($i = 0; $i < 6; ++$i) {
|
| 355: | $header[148 + $i] = substr($checksum, $i, 1);
|
| 356: | }
|
| 357: | $header[154] = chr(0);
|
| 358: | $header[155] = chr(32);
|
| 359: |
|
| 360: | $file_contents = str_pad($information['file'], ceil($information['size'] / 512) * 512, chr(0));
|
| 361: |
|
| 362: | $this->tar_file .= $header . $file_contents;
|
| 363: | }
|
| 364: | }
|
| 365: |
|
| 366: | $this->tar_file .= str_repeat(chr(0), 512);
|
| 367: |
|
| 368: | return true;
|
| 369: | }
|
| 370: |
|
| 371: | |
| 372: | |
| 373: | |
| 374: | |
| 375: | |
| 376: |
|
| 377: | public function openTAR($filename)
|
| 378: | {
|
| 379: |
|
| 380: | unset($this->filename, $this->isGzipped, $this->tar_file, $this->files, $this->directories, $this->numFiles, $this->numDirectories);
|
| 381: |
|
| 382: |
|
| 383: | if (!file_exists($filename)) {
|
| 384: | return false;
|
| 385: | }
|
| 386: |
|
| 387: | $this->filename = $filename;
|
| 388: |
|
| 389: | $this->__readTar();
|
| 390: |
|
| 391: | return true;
|
| 392: | }
|
| 393: |
|
| 394: | |
| 395: | |
| 396: | |
| 397: | |
| 398: | |
| 399: |
|
| 400: | public function appendTar($filename)
|
| 401: | {
|
| 402: |
|
| 403: | if (!file_exists($filename)) {
|
| 404: | return false;
|
| 405: | }
|
| 406: | $this->__readTar($filename);
|
| 407: |
|
| 408: | return true;
|
| 409: | }
|
| 410: |
|
| 411: | |
| 412: | |
| 413: | |
| 414: | |
| 415: | |
| 416: |
|
| 417: | public function getFile($filename)
|
| 418: | {
|
| 419: | if ($this->numFiles > 0) {
|
| 420: | foreach ($this->files as $key => $information) {
|
| 421: | if ($information['name'] == $filename) {
|
| 422: | return $information;
|
| 423: | }
|
| 424: | }
|
| 425: | }
|
| 426: |
|
| 427: | return false;
|
| 428: | }
|
| 429: |
|
| 430: | |
| 431: | |
| 432: | |
| 433: | |
| 434: | |
| 435: |
|
| 436: | public function getDirectory($dirname)
|
| 437: | {
|
| 438: | if ($this->numDirectories > 0) {
|
| 439: | foreach ($this->directories as $key => $information) {
|
| 440: | if ($information['name'] == $dirname) {
|
| 441: | return $information;
|
| 442: | }
|
| 443: | }
|
| 444: | }
|
| 445: |
|
| 446: | return false;
|
| 447: | }
|
| 448: |
|
| 449: | |
| 450: | |
| 451: | |
| 452: | |
| 453: | |
| 454: |
|
| 455: | public function containsFile($filename)
|
| 456: | {
|
| 457: | if ($this->numFiles > 0) {
|
| 458: | foreach ($this->files as $key => $information) {
|
| 459: | if ($information['name'] == $filename) {
|
| 460: | return true;
|
| 461: | }
|
| 462: | }
|
| 463: | }
|
| 464: |
|
| 465: | return false;
|
| 466: | }
|
| 467: |
|
| 468: | |
| 469: | |
| 470: | |
| 471: | |
| 472: | |
| 473: |
|
| 474: | public function containsDirectory($dirname)
|
| 475: | {
|
| 476: | if ($this->numDirectories > 0) {
|
| 477: | foreach ($this->directories as $key => $information) {
|
| 478: | if ($information['name'] == $dirname) {
|
| 479: | return true;
|
| 480: | }
|
| 481: | }
|
| 482: | }
|
| 483: |
|
| 484: | return false;
|
| 485: | }
|
| 486: |
|
| 487: | |
| 488: | |
| 489: | |
| 490: | |
| 491: | |
| 492: |
|
| 493: | public function addDirectory($dirname)
|
| 494: | {
|
| 495: | if (!file_exists($dirname)) {
|
| 496: | return false;
|
| 497: | }
|
| 498: |
|
| 499: | $file_information = stat($dirname);
|
| 500: |
|
| 501: | $this->numDirectories++;
|
| 502: | $activeDir =& $this->directories[];
|
| 503: | $activeDir['name'] = $dirname;
|
| 504: | $activeDir['mode'] = $file_information['mode'];
|
| 505: | $activeDir['time'] = $file_information['time'];
|
| 506: | $activeDir['user_id'] = $file_information['uid'];
|
| 507: | $activeDir['group_id'] = $file_information['gid'];
|
| 508: | $activeDir['checksum'] = $checksum;
|
| 509: |
|
| 510: | return true;
|
| 511: | }
|
| 512: |
|
| 513: | |
| 514: | |
| 515: | |
| 516: | |
| 517: | |
| 518: | |
| 519: |
|
| 520: | public function addFile($filename, $binary = false)
|
| 521: | {
|
| 522: |
|
| 523: | if (!file_exists($filename)) {
|
| 524: | return false;
|
| 525: | }
|
| 526: |
|
| 527: | if ($this->containsFile($filename)) {
|
| 528: | return false;
|
| 529: | }
|
| 530: |
|
| 531: | $file_information = stat($filename);
|
| 532: |
|
| 533: | if (!$binary) {
|
| 534: | $fp = fopen($filename, 'r');
|
| 535: | } else {
|
| 536: | $fp = fopen($filename, 'rb');
|
| 537: | }
|
| 538: | $file_contents = fread($fp, filesize($filename));
|
| 539: | fclose($fp);
|
| 540: |
|
| 541: | $this->numFiles++;
|
| 542: | $activeFile =& $this->files[];
|
| 543: | $activeFile['name'] = $filename;
|
| 544: | $activeFile['mode'] = $file_information['mode'];
|
| 545: | $activeFile['user_id'] = $file_information['uid'];
|
| 546: | $activeFile['group_id'] = $file_information['gid'];
|
| 547: | $activeFile['size'] = $file_information['size'];
|
| 548: | $activeFile['time'] = $file_information['mtime'];
|
| 549: | $activeFile['checksum'] = isset($checksum) ? $checksum : '';
|
| 550: | $activeFile['user_name'] = '';
|
| 551: | $activeFile['group_name'] = '';
|
| 552: | $activeFile['file'] = trim($file_contents);
|
| 553: |
|
| 554: | return true;
|
| 555: | }
|
| 556: |
|
| 557: | |
| 558: | |
| 559: | |
| 560: | |
| 561: | |
| 562: |
|
| 563: | public function removeFile($filename)
|
| 564: | {
|
| 565: | if ($this->numFiles > 0) {
|
| 566: | foreach ($this->files as $key => $information) {
|
| 567: | if ($information['name'] == $filename) {
|
| 568: | $this->numFiles--;
|
| 569: | unset($this->files[$key]);
|
| 570: |
|
| 571: | return true;
|
| 572: | }
|
| 573: | }
|
| 574: | }
|
| 575: |
|
| 576: | return false;
|
| 577: | }
|
| 578: |
|
| 579: | |
| 580: | |
| 581: | |
| 582: | |
| 583: | |
| 584: |
|
| 585: | public function removeDirectory($dirname)
|
| 586: | {
|
| 587: | if ($this->numDirectories > 0) {
|
| 588: | foreach ($this->directories as $key => $information) {
|
| 589: | if ($information['name'] == $dirname) {
|
| 590: | $this->numDirectories--;
|
| 591: | unset($this->directories[$key]);
|
| 592: |
|
| 593: | return true;
|
| 594: | }
|
| 595: | }
|
| 596: | }
|
| 597: |
|
| 598: | return false;
|
| 599: | }
|
| 600: |
|
| 601: | |
| 602: | |
| 603: | |
| 604: | |
| 605: |
|
| 606: | public function saveTar()
|
| 607: | {
|
| 608: | if (!$this->filename) {
|
| 609: | return false;
|
| 610: | }
|
| 611: |
|
| 612: | $this->toTar($this->filename, $this->isGzipped);
|
| 613: |
|
| 614: | return true;
|
| 615: | }
|
| 616: |
|
| 617: | |
| 618: | |
| 619: | |
| 620: | |
| 621: | |
| 622: | |
| 623: |
|
| 624: | public function toTar($filename, $useGzip)
|
| 625: | {
|
| 626: | if (!$filename) {
|
| 627: | return false;
|
| 628: | }
|
| 629: |
|
| 630: | $this->__generateTar();
|
| 631: |
|
| 632: | if ($useGzip) {
|
| 633: |
|
| 634: | if (!function_exists('gzencode')) {
|
| 635: | return false;
|
| 636: | }
|
| 637: | $file = gzencode($this->tar_file);
|
| 638: | } else {
|
| 639: | $file = $this->tar_file;
|
| 640: | }
|
| 641: |
|
| 642: | $fp = fopen($filename, 'wb');
|
| 643: | fwrite($fp, $file);
|
| 644: | fclose($fp);
|
| 645: |
|
| 646: | return true;
|
| 647: | }
|
| 648: |
|
| 649: | |
| 650: | |
| 651: | |
| 652: | |
| 653: | |
| 654: | |
| 655: |
|
| 656: | public function toTarOutput($filename, $useGzip)
|
| 657: | {
|
| 658: | if (!$filename) {
|
| 659: | return false;
|
| 660: | }
|
| 661: |
|
| 662: | $this->__generateTar();
|
| 663: |
|
| 664: | if ($useGzip) {
|
| 665: |
|
| 666: | if (!function_exists('gzencode')) {
|
| 667: | return false;
|
| 668: | }
|
| 669: | $file = gzencode($this->tar_file);
|
| 670: | } else {
|
| 671: | $file = $this->tar_file;
|
| 672: | }
|
| 673: |
|
| 674: | return $file;
|
| 675: | }
|
| 676: | }
|
| 677: | |