xref: /dokuwiki/vendor/splitbrain/php-archive/src/FileInfo.php (revision 4593dbd2856db337dc8104c2a5e0dcbe4e7f84e1)
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 the filesize. always 0 for directories
78     */
79    public function getSize()
80    {
81        if($this->isdir) return 0;
82        return $this->size;
83    }
84
85    /**
86     * @param int $size
87     */
88    public function setSize($size)
89    {
90        $this->size = $size;
91    }
92
93    /**
94     * @return int
95     */
96    public function getCompressedSize()
97    {
98        return $this->csize;
99    }
100
101    /**
102     * @param int $csize
103     */
104    public function setCompressedSize($csize)
105    {
106        $this->csize = $csize;
107    }
108
109    /**
110     * @return int
111     */
112    public function getMtime()
113    {
114        return $this->mtime;
115    }
116
117    /**
118     * @param int $mtime
119     */
120    public function setMtime($mtime)
121    {
122        $this->mtime = $mtime;
123    }
124
125    /**
126     * @return int
127     */
128    public function getGid()
129    {
130        return $this->gid;
131    }
132
133    /**
134     * @param int $gid
135     */
136    public function setGid($gid)
137    {
138        $this->gid = $gid;
139    }
140
141    /**
142     * @return int
143     */
144    public function getUid()
145    {
146        return $this->uid;
147    }
148
149    /**
150     * @param int $uid
151     */
152    public function setUid($uid)
153    {
154        $this->uid = $uid;
155    }
156
157    /**
158     * @return string
159     */
160    public function getComment()
161    {
162        return $this->comment;
163    }
164
165    /**
166     * @param string $comment
167     */
168    public function setComment($comment)
169    {
170        $this->comment = $comment;
171    }
172
173    /**
174     * @return string
175     */
176    public function getGroup()
177    {
178        return $this->group;
179    }
180
181    /**
182     * @param string $group
183     */
184    public function setGroup($group)
185    {
186        $this->group = $group;
187    }
188
189    /**
190     * @return boolean
191     */
192    public function getIsdir()
193    {
194        return $this->isdir;
195    }
196
197    /**
198     * @param boolean $isdir
199     */
200    public function setIsdir($isdir)
201    {
202        // default mode for directories
203        if ($isdir && $this->mode === 0664) {
204            $this->mode = 0775;
205        }
206        $this->isdir = $isdir;
207    }
208
209    /**
210     * @return int
211     */
212    public function getMode()
213    {
214        return $this->mode;
215    }
216
217    /**
218     * @param int $mode
219     */
220    public function setMode($mode)
221    {
222        $this->mode = $mode;
223    }
224
225    /**
226     * @return string
227     */
228    public function getOwner()
229    {
230        return $this->owner;
231    }
232
233    /**
234     * @param string $owner
235     */
236    public function setOwner($owner)
237    {
238        $this->owner = $owner;
239    }
240
241    /**
242     * @return string
243     */
244    public function getPath()
245    {
246        return $this->path;
247    }
248
249    /**
250     * @param string $path
251     */
252    public function setPath($path)
253    {
254        $this->path = $this->cleanPath($path);
255    }
256
257    /**
258     * Cleans up a path and removes relative parts, also strips leading slashes
259     *
260     * @param string $path
261     * @return string
262     */
263    protected function cleanPath($path)
264    {
265        $path    = str_replace('\\', '/', $path);
266        $path    = explode('/', $path);
267        $newpath = array();
268        foreach ($path as $p) {
269            if ($p === '' || $p === '.') {
270                continue;
271            }
272            if ($p === '..') {
273                array_pop($newpath);
274                continue;
275            }
276            array_push($newpath, $p);
277        }
278        return trim(implode('/', $newpath), '/');
279    }
280
281    /**
282     * Strip given prefix or number of path segments from the filename
283     *
284     * The $strip parameter allows you to strip a certain number of path components from the filenames
285     * found in the tar file, similar to the --strip-components feature of GNU tar. This is triggered when
286     * an integer is passed as $strip.
287     * Alternatively a fixed string prefix may be passed in $strip. If the filename matches this prefix,
288     * the prefix will be stripped. It is recommended to give prefixes with a trailing slash.
289     *
290     * @param  int|string $strip
291     * @return FileInfo
292     */
293    public function strip($strip)
294    {
295        $filename = $this->getPath();
296        $striplen = strlen($strip);
297        if (is_int($strip)) {
298            // if $strip is an integer we strip this many path components
299            $parts = explode('/', $filename);
300            if (!$this->getIsdir()) {
301                $base = array_pop($parts); // keep filename itself
302            } else {
303                $base = '';
304            }
305            $filename = join('/', array_slice($parts, $strip));
306            if ($base) {
307                $filename .= "/$base";
308            }
309        } else {
310            // if strip is a string, we strip a prefix here
311            if (substr($filename, 0, $striplen) == $strip) {
312                $filename = substr($filename, $striplen);
313            }
314        }
315
316        $this->setPath($filename);
317    }
318
319    /**
320     * Does the file match the given include and exclude expressions?
321     *
322     * Exclude rules take precedence over include rules
323     *
324     * @param string $include Regular expression of files to include
325     * @param string $exclude Regular expression of files to exclude
326     * @return bool
327     */
328    public function match($include = '', $exclude = '')
329    {
330        $extract = true;
331        if ($include && !preg_match($include, $this->getPath())) {
332            $extract = false;
333        }
334        if ($exclude && preg_match($exclude, $this->getPath())) {
335            $extract = false;
336        }
337
338        return $extract;
339    }
340}
341
342class FileInfoException extends \Exception
343{
344}