1<?php 2 3namespace splitbrain\PHPArchive; 4 5/** 6 * Class FileInfo 7 * 8 * stores meta data about a file in an Archive 9 * 10 * @author Andreas Gohr <andi@splitbrain.org> 11 * @package splitbrain\PHPArchive 12 * @license MIT 13 */ 14class FileInfo 15{ 16 17 protected $isdir = false; 18 protected $path = ''; 19 protected $size = 0; 20 protected $csize = 0; 21 protected $mtime = 0; 22 protected $mode = 0664; 23 protected $owner = ''; 24 protected $group = ''; 25 protected $uid = 0; 26 protected $gid = 0; 27 protected $comment = ''; 28 29 /** 30 * initialize dynamic defaults 31 * 32 * @param string $path The path of the file, can also be set later through setPath() 33 */ 34 public function __construct($path = '') 35 { 36 $this->mtime = time(); 37 $this->setPath($path); 38 } 39 40 /** 41 * Factory to build FileInfo from existing file or directory 42 * 43 * @param string $path path to a file on the local file system 44 * @param string $as optional path to use inside the archive 45 * @throws FileInfoException 46 * @return FileInfo 47 */ 48 public static function fromPath($path, $as = '') 49 { 50 clearstatcache(false, $path); 51 52 if (!file_exists($path)) { 53 throw new FileInfoException("$path does not exist"); 54 } 55 56 $stat = stat($path); 57 $file = new FileInfo(); 58 59 $file->setPath($path); 60 $file->setIsdir(is_dir($path)); 61 $file->setMode(fileperms($path)); 62 $file->setOwner(fileowner($path)); 63 $file->setGroup(filegroup($path)); 64 $file->setSize(filesize($path)); 65 $file->setUid($stat['uid']); 66 $file->setGid($stat['gid']); 67 $file->setMtime($stat['mtime']); 68 69 if ($as) { 70 $file->setPath($as); 71 } 72 73 return $file; 74 } 75 76 /** 77 * @return int 78 */ 79 public function getSize() 80 { 81 return $this->size; 82 } 83 84 /** 85 * @param int $size 86 */ 87 public function setSize($size) 88 { 89 $this->size = $size; 90 } 91 92 /** 93 * @return int 94 */ 95 public function getCompressedSize() 96 { 97 return $this->csize; 98 } 99 100 /** 101 * @param int $csize 102 */ 103 public function setCompressedSize($csize) 104 { 105 $this->csize = $csize; 106 } 107 108 /** 109 * @return int 110 */ 111 public function getMtime() 112 { 113 return $this->mtime; 114 } 115 116 /** 117 * @param int $mtime 118 */ 119 public function setMtime($mtime) 120 { 121 $this->mtime = $mtime; 122 } 123 124 /** 125 * @return int 126 */ 127 public function getGid() 128 { 129 return $this->gid; 130 } 131 132 /** 133 * @param int $gid 134 */ 135 public function setGid($gid) 136 { 137 $this->gid = $gid; 138 } 139 140 /** 141 * @return int 142 */ 143 public function getUid() 144 { 145 return $this->uid; 146 } 147 148 /** 149 * @param int $uid 150 */ 151 public function setUid($uid) 152 { 153 $this->uid = $uid; 154 } 155 156 /** 157 * @return string 158 */ 159 public function getComment() 160 { 161 return $this->comment; 162 } 163 164 /** 165 * @param string $comment 166 */ 167 public function setComment($comment) 168 { 169 $this->comment = $comment; 170 } 171 172 /** 173 * @return string 174 */ 175 public function getGroup() 176 { 177 return $this->group; 178 } 179 180 /** 181 * @param string $group 182 */ 183 public function setGroup($group) 184 { 185 $this->group = $group; 186 } 187 188 /** 189 * @return boolean 190 */ 191 public function getIsdir() 192 { 193 return $this->isdir; 194 } 195 196 /** 197 * @param boolean $isdir 198 */ 199 public function setIsdir($isdir) 200 { 201 // default mode for directories 202 if ($isdir && $this->mode === 0664) { 203 $this->mode = 0775; 204 } 205 $this->isdir = $isdir; 206 } 207 208 /** 209 * @return int 210 */ 211 public function getMode() 212 { 213 return $this->mode; 214 } 215 216 /** 217 * @param int $mode 218 */ 219 public function setMode($mode) 220 { 221 $this->mode = $mode; 222 } 223 224 /** 225 * @return string 226 */ 227 public function getOwner() 228 { 229 return $this->owner; 230 } 231 232 /** 233 * @param string $owner 234 */ 235 public function setOwner($owner) 236 { 237 $this->owner = $owner; 238 } 239 240 /** 241 * @return string 242 */ 243 public function getPath() 244 { 245 return $this->path; 246 } 247 248 /** 249 * @param string $path 250 */ 251 public function setPath($path) 252 { 253 $this->path = $this->cleanPath($path); 254 } 255 256 /** 257 * Cleans up a path and removes relative parts, also strips leading slashes 258 * 259 * @param string $path 260 * @return string 261 */ 262 protected function cleanPath($path) 263 { 264 $path = str_replace('\\', '/', $path); 265 $path = explode('/', $path); 266 $newpath = array(); 267 foreach ($path as $p) { 268 if ($p === '' || $p === '.') { 269 continue; 270 } 271 if ($p === '..') { 272 array_pop($newpath); 273 continue; 274 } 275 array_push($newpath, $p); 276 } 277 return trim(implode('/', $newpath), '/'); 278 } 279 280 /** 281 * Strip given prefix or number of path segments from the filename 282 * 283 * The $strip parameter allows you to strip a certain number of path components from the filenames 284 * found in the tar file, similar to the --strip-components feature of GNU tar. This is triggered when 285 * an integer is passed as $strip. 286 * Alternatively a fixed string prefix may be passed in $strip. If the filename matches this prefix, 287 * the prefix will be stripped. It is recommended to give prefixes with a trailing slash. 288 * 289 * @param int|string $strip 290 * @return FileInfo 291 */ 292 public function strip($strip) 293 { 294 $filename = $this->getPath(); 295 $striplen = strlen($strip); 296 if (is_int($strip)) { 297 // if $strip is an integer we strip this many path components 298 $parts = explode('/', $filename); 299 if (!$this->getIsdir()) { 300 $base = array_pop($parts); // keep filename itself 301 } else { 302 $base = ''; 303 } 304 $filename = join('/', array_slice($parts, $strip)); 305 if ($base) { 306 $filename .= "/$base"; 307 } 308 } else { 309 // if strip is a string, we strip a prefix here 310 if (substr($filename, 0, $striplen) == $strip) { 311 $filename = substr($filename, $striplen); 312 } 313 } 314 315 $this->setPath($filename); 316 } 317 318 /** 319 * Does the file match the given include and exclude expressions? 320 * 321 * Exclude rules take precedence over include rules 322 * 323 * @param string $include Regular expression of files to include 324 * @param string $exclude Regular expression of files to exclude 325 * @return bool 326 */ 327 public function match($include = '', $exclude = '') 328 { 329 $extract = true; 330 if ($include && !preg_match($include, $this->getPath())) { 331 $extract = false; 332 } 333 if ($exclude && preg_match($exclude, $this->getPath())) { 334 $extract = false; 335 } 336 337 return $extract; 338 } 339} 340 341class FileInfoException extends \Exception 342{ 343}