1<?php 2// stolen from PEAR2_Pyrus_Developer_Creator_Tar by Greg Beaver, the original author, for use in unit tests 3class tarmaker 4{ 5 /** 6 * Path to archive file 7 * 8 * @var string 9 */ 10 protected $archive; 11 /** 12 * Temporary stream used for creating the archive 13 * 14 * @var stream 15 */ 16 protected $tmp; 17 protected $path; 18 protected $compress; 19 function __construct($path, $compress = 'zlib') 20 { 21 $this->compress = $compress; 22 if ($compress === 'bz2' && !function_exists('bzopen')) { 23 throw new PEAR2_Pyrus_Developer_Creator_Exception( 24 'bzip2 extension not available'); 25 } 26 if ($compress === 'zlib' && !function_exists('gzopen')) { 27 throw new PEAR2_Pyrus_Developer_Creator_Exception( 28 'zlib extension not available'); 29 } 30 $this->path = $path; 31 } 32 33 /** 34 * save a file inside this package 35 * 36 * This code is modified from Vincent Lascaux's File_Archive 37 * package, which is licensed under the LGPL license. 38 * @param string relative path within the package 39 * @param string|resource file contents or open file handle 40 */ 41 function addFile($path, $fileOrStream, $stat = null) 42 { 43 clearstatcache(); 44 if ($stat === null) { 45 if (is_resource($fileOrStream)) { 46 $stat = fstat($fileOrStream); 47 } else { 48 $stat = array( 49 'mode' => 0x8000 + 0644, 50 'uid' => 0, 51 'gid' => 0, 52 'size' => strlen($fileOrStream), 53 'mtime' => time(), 54 ); 55 } 56 } 57 58 $link = null; 59 if ($stat['mode'] & 0x4000) { 60 $type = 5; // Directory 61 } else if ($stat['mode'] & 0x8000) { 62 $type = 0; // Regular 63 } else if ($stat['mode'] & 0xA000) { 64 $type = 1; // Link 65 $link = @readlink($current); 66 } else { 67 $type = 9; // Unknown 68 } 69 70 $filePrefix = ''; 71 if (strlen($path) > 255) { 72 throw new Exception( 73 "$path is too long, must be 255 characters or less" 74 ); 75 } else if (strlen($path) > 100) { 76 $filePrefix = substr($path, 0, strlen($path)-100); 77 $path = substr($path, -100); 78 } 79 80 $block = pack('a100a8a8a8a12A12', 81 $path, 82 decoct($stat['mode']), 83 sprintf('%6s ',decoct($stat['uid'])), 84 sprintf('%6s ',decoct($stat['gid'])), 85 sprintf('%11s ',decoct($stat['size'])), 86 sprintf('%11s ',decoct($stat['mtime'])) 87 ); 88 89 $blockend = pack('a1a100a6a2a32a32a8a8a155a12', 90 $type, 91 $link, 92 'ustar', 93 '00', 94 'Pyrus', 95 'Pyrus', 96 '', 97 '', 98 $filePrefix, 99 ''); 100 101 $checkheader = array_merge(str_split($block), str_split($blockend)); 102 if (!function_exists('_pear2tarchecksum')) { 103 function _pear2tarchecksum($a, $b) {return $a + ord($b);} 104 } 105 $checksum = 256; // 8 * ord(' '); 106 $checksum += array_reduce($checkheader, '_pear2tarchecksum'); 107 108 $checksum = pack('a8', sprintf('%6s ', decoct($checksum))); 109 110 fwrite($this->tmp, (binary)$block . $checksum . $blockend, 512); 111 if (is_resource($fileOrStream)) { 112 stream_copy_to_stream($fileOrStream, $this->tmp); 113 if ($stat['size'] % 512) { 114 fwrite($this->tmp, (binary)str_repeat("\0", 512 - $stat['size'] % 512)); 115 } 116 } else { 117 fwrite($this->tmp, (binary)$fileOrStream); 118 if (strlen($fileOrStream) % 512) { 119 fwrite($this->tmp, (binary)str_repeat("\0", 512 - strlen($fileOrStream) % 512)); 120 } 121 } 122 } 123 124 /** 125 * Initialize the package creator 126 */ 127 function init() 128 { 129 switch ($this->compress) { 130 case 'zlib' : 131 $this->tmp = gzopen($this->path, 'wb'); 132 break; 133 case 'bz2' : 134 $this->tmp = bzopen($this->path, 'w'); 135 break; 136 case 'none' : 137 $this->tmp = fopen($this->path, 'wb'); 138 break; 139 default : 140 throw new Exception( 141 'unknown compression type ' . $this->compress); 142 } 143 } 144 145 /** 146 * Create an internal directory, creating parent directories as needed 147 * 148 * @param string $dir 149 */ 150 function mkdir($dir) 151 { 152 $this->addFile($dir, "", array( 153 'mode' => 0x4000 + 0644, 154 'uid' => 0, 155 'gid' => 0, 156 'size' => 0, 157 'mtime' => time(), 158 )); 159 } 160 161 /** 162 * Finish saving the package 163 */ 164 function close() 165 { 166 fwrite($this->tmp, pack('a1024', '')); 167 fclose($this->tmp); 168 } 169}