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