Issues (9)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/ArchiveEntry.php (7 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
 * (c) 2018 Dennis Birkholz <[email protected]>
5
 *
6
 * $Id$
7
 * Author:    $Format:%an <%ae>, %ai$
8
 * Committer: $Format:%cn <%ce>, %cI$
9
 */
10
11
namespace morgue\archive;
12
13
/**
14
 * This class represents a single entry in an archive (file, directory)
15
 *
16
 * @author Dennis Birkholz <[email protected]>
17
 */
18
final class ArchiveEntry
19
{
20
    const UNIX_ATTRIBUTES_DEFAULT           = UNIX_ATTRIBUTE_USER_READ|UNIX_ATTRIBUTE_USER_WRITE|UNIX_ATTRIBUTE_GROUP_READ|UNIX_ATTRIBUTE_OTHER_READ;
21
    const UNIX_ATTRIBUTES_DEFAULT_FILE      = self::UNIX_ATTRIBUTES_DEFAULT|UNIX_ATTRIBUTE_TYPE_FILE;
22
    const UNIX_ATTRIBUTES_DEFAULT_DIRECTORY = self::UNIX_ATTRIBUTES_DEFAULT|UNIX_ATTRIBUTE_TYPE_DIRECTORY|UNIX_ATTRIBUTE_USER_EXECUTE|UNIX_ATTRIBUTE_GROUP_EXECUTE|UNIX_ATTRIBUTE_OTHER_EXECUTE;
23
24
    /**
25
     * The name of this entry, relative to the archive root or absolute/fully qualified
26
     * @var string
27
     */
28
    private $name;
29
30
    /**
31
     * @var int
32
     */
33
    private $uncompressedSize;
34
35
    /**
36
     * @var int
37
     */
38
    private $sourceSize;
39
40
    /**
41
     * @var int
42
     */
43
    private $targetSize;
44
45
    /**
46
     * @var \DateTimeInterface
47
     */
48
    private $creationTime;
49
50
    /**
51
     * @var \DateTimeInterface
52
     */
53
    private $modificationTime;
54
55
    /**
56
     * CRC32 checksum of the uncompressed file
57
     * @var int
58
     */
59
    private $checksumCrc32;
60
61
    /**
62
     * @var string
63
     */
64
    private $comment;
65
66
    /**
67
     * One of the COMPRESSION_METHOD_* constants
68
     * @var string
69
     */
70
    private $sourceCompressionMethod;
71
72
    /**
73
     * One of the COMPRESSION_METHOD_* constants
74
     * @var string
75
     */
76
    private $targetCompressionMethod;
77
78
    /**
79
     * Combination of DOS_ATTRIBUTE_* flags
80
     * May be unsupported by target file format
81
     * @var int
82
     */
83
    private $dosAttributes;
84
85
    /**
86
     * Combination of UNIX_ATTRIBUTE_* flags
87
     * May be unsupported by target file format
88
     * @var int
89
     */
90
    private $unixAttributes;
91
92
    /**
93
     * A PHP stream to the underlying file
94
     * The stream should not perform any translation (like decompression)
95
     *  so reading from this stream should yield data in the format
96
     *  specified by $sourceCompressionMethod
97
     * @var resource
98
     */
99
    private $sourceStream;
100
101
    /**
102
     * Fully qualified path to the underlying uncompressed file
103
     * @var string
104
     */
105
    private $sourcePath;
106
107
    /**
108
     * Binary string containing the content of this entry
109
     * @var string
110
     */
111
    private $sourceString;
112
113 2
    public function __construct(string $name)
114
    {
115 2
        $this->name = $name;
116 2
    }
117
118
    /**
119
     * Import data from the supplied $stat array. Format is the one returned by stat()/fstat()
120
     * @param array $stat
121
     */
122 3
    private function importStat(array $stat)
123
    {
124 3
        if (!empty($stat['mode']) && $this->unixAttributes === null) {
125 3
            $this->unixAttributes = $stat['mode'];
126
        }
127
128 3
        $timezone = new \DateTimeZone(\date_default_timezone_get());
129
130 3 View Code Duplication
        if (!empty($stat['ctime']) && $this->creationTime === null) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
131 3
            $this->creationTime = (new \DateTimeImmutable('@' . $stat['ctime']))->setTimezone($timezone);
0 ignored issues
show
Documentation Bug introduced by
It seems like (new \DateTimeImmutable(...>setTimezone($timezone) can also be of type false. However, the property $creationTime is declared as type object<DateTimeInterface>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
132
        }
133
134 3 View Code Duplication
        if (!empty($stat['mtime']) && $this->modificationTime === null) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
135 3
            $this->modificationTime = (new \DateTimeImmutable('@' . $stat['mtime']))->setTimezone($timezone);
0 ignored issues
show
Documentation Bug introduced by
It seems like (new \DateTimeImmutable(...>setTimezone($timezone) can also be of type false. However, the property $modificationTime is declared as type object<DateTimeInterface>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
136
        }
137
138 3
        if ($this->unixAttributes & UNIX_ATTRIBUTE_TYPE_DIRECTORY) {
139 1
            $this->sourceSize = 0;
140 1
            $this->targetSize = 0;
141 1
            $this->uncompressedSize = 0;
142 1
            $this->sourceCompressionMethod = COMPRESSION_METHOD_STORE;
143 1
            $this->targetCompressionMethod = COMPRESSION_METHOD_STORE;
144
        }
145
146 2
        elseif ($this->unixAttributes & UNIX_ATTRIBUTE_TYPE_FILE) {
147 2
            $this->sourceSize = $stat['size'];
148 2
            if ($this->sourceCompressionMethod === COMPRESSION_METHOD_STORE) {
149 2
                $this->uncompressedSize = $this->sourceSize;
150
            }
151
        }
152 3
    }
153
154
    /**
155
     * @return resource
156
     */
157 3
    public function getSourceAsStream()
158
    {
159 3
        if ($this->sourceStream !== null) {
160 1
            return $this->sourceStream;
161
        }
162
163 2
        elseif ($this->sourcePath !== null) {
164 1
            return \fopen($this->sourcePath, 'r');
165
        }
166
167
        else {
168 1
            $fp = \fopen('php://memory', 'r+');
169 1
            \fwrite($fp, $this->sourceString);
170 1
            \fseek($fp, 0);
171 1
            return $fp;
172
        }
173
    }
174
175
    /**
176
     * @return string|null
177
     */
178 2
    public function getSourcePath()
179
    {
180 2
        return $this->sourcePath;
181
    }
182
183
    /**
184
     * Set the path of the file that will serve as source for this entry.
185
     * The file must exist and be readable.
186
     * You may provide a URL if a matching stream wrapper is registered with stat support.
187
     * Otherwise, use withSourceStream() to add a stream directly.
188
     *
189
     * @param string $path
190
     * @param string|null $compressionMethod
191
     * @return ArchiveEntry
192
     */
193 6
    public function withSourcePath(string $path, string $compressionMethod = null) : self
194
    {
195 6
        if (!\file_exists($path) || !\is_readable($path)) {
196 1
            throw new \InvalidArgumentException('Can not use non-existing or unreadable file as source.');
197
        }
198
199 5 View Code Duplication
        if ($this->sourcePath !== null || $this->sourceStream !== null || $this->sourceString !== null) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
200 3
            throw new \InvalidArgumentException('Can not replace source, create a new entry instead.');
201
        }
202
203 3
        $obj = clone $this;
204 3
        $obj->sourcePath = $path;
205
206 3
        if ($compressionMethod !== null) {
207 1
            $obj->sourceCompressionMethod = $compressionMethod;
208
        }
209
210 3
        if ($compressionMethod === COMPRESSION_METHOD_STORE) {
211 1
            $obj->uncompressedSize = $obj->sourceSize;
212
        }
213
214 3
        if (($stat = @\stat($path)) !== false) {
215 3
            $obj->importStat($stat);
216
        }
217
218 3
        return $obj;
219
    }
220
221
    /**
222
     * @return resource|null
223
     */
224 1
    public function getSourceStream()
225
    {
226 1
        return $this->sourceStream;
227
    }
228
229
    /**
230
     * @param resource $stream
231
     * @param string $compressionMethod
232
     * @return ArchiveEntry
233
     */
234 4
    public function withSourceStream($stream, string $compressionMethod = null) : self
235
    {
236 4 View Code Duplication
        if ($this->sourcePath !== null || $this->sourceStream !== null || $this->sourceString !== null) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
237 3
            throw new \InvalidArgumentException('Can not replace source, create a new entry instead.');
238
        }
239
240 2
        $obj = clone $this;
241 2
        $obj->sourcePath = null;
242 2
        $obj->sourceStream = $stream;
243 2
        $obj->sourceString = null;
244
245 2
        if ($compressionMethod !== null) {
246 1
            $obj->sourceCompressionMethod = $compressionMethod;
247
        }
248
249 2
        if (($stat = @\fstat($stream)) !== false) {
250 2
            $obj->importStat($stat);
251
        }
252
253 2
        return $obj;
254
    }
255
256
    /**
257
     * @return string|null
258
     */
259 1
    public function getSourceString()
260
    {
261 1
        return $this->sourceString;
262
    }
263
264
    /**
265
     * @param string $content
266
     * @param string $compressionMethod
267
     * @return ArchiveEntry
268
     */
269 4
    public function withSourceString(string $content, string $compressionMethod = null) : self
270
    {
271 4 View Code Duplication
        if ($this->sourcePath !== null || $this->sourceStream !== null || $this->sourceString !== null) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
272 3
            throw new \InvalidArgumentException('Can not replace source, create a new entry instead.');
273
        }
274
275 2
        $obj = clone $this;
276 2
        $obj->sourcePath = null;
277 2
        $obj->sourceStream = null;
278 2
        $obj->sourceString = $content;
279 2
        $obj->sourceSize = \strlen($content);
280
281 2
        if ($compressionMethod !== null) {
282 1
            $obj->sourceCompressionMethod = $compressionMethod;
283
        }
284
285 2
        if ($compressionMethod === COMPRESSION_METHOD_STORE) {
286 1
            $obj->uncompressedSize = $obj->sourceSize;
287
        }
288
289 2
        $now = new \DateTimeImmutable('now', new \DateTimeZone(\date_default_timezone_get()));
290 2
        if ($obj->creationTime === null) {
291 2
            $obj->creationTime = $now;
292
        }
293
294 2
        if ($obj->modificationTime === null) {
295 2
            $obj->modificationTime = $now;
296
        }
297
298 2
        return $obj;
299
    }
300
301
    /**
302
     * @return string|null
303
     */
304 2
    public function getName()
305
    {
306 2
        return $this->name;
307
    }
308
309
    /**
310
     * @param string $name
311
     * @return ArchiveEntry
312
     */
313 1
    public function withName(string $name) : self
314
    {
315 1
        $obj = clone $this;
316 1
        $obj->name = $name;
317 1
        return $obj;
318
    }
319
320
    /**
321
     * @return int|null
322
     */
323 1
    public function getUncompressedSize()
324
    {
325 1
        return $this->uncompressedSize;
326
    }
327
328
    /**
329
     * @param int $uncompressedSize
330
     * @return ArchiveEntry
331
     */
332 1
    public function withUncompressedSize(int $uncompressedSize) : self
333
    {
334 1
        $obj = clone $this;
335 1
        $obj->uncompressedSize = $uncompressedSize;
336 1
        return $obj;
337
    }
338
339
    /**
340
     * @return int|null
341
     */
342 1
    public function getSourceSize()
343
    {
344 1
        return $this->sourceSize;
345
    }
346
347
    /**
348
     * @param int $sourceSize
349
     * @return ArchiveEntry
350
     */
351 1
    public function withSourceSize(int $sourceSize) : self
352
    {
353 1
        $obj = clone $this;
354 1
        $obj->sourceSize = $sourceSize;
355 1
        return $obj;
356
    }
357
358
    /**
359
     * @return int|null
360
     */
361 1
    public function getTargetSize()
362
    {
363 1
        return $this->targetSize;
364
    }
365
366
    /**
367
     * @param int $targetSize
368
     * @return ArchiveEntry
369
     */
370 1
    public function withTargetSize(int $targetSize) : self
371
    {
372 1
        $obj = clone $this;
373 1
        $obj->targetSize = $targetSize;
374 1
        return $obj;
375
    }
376
377
    /**
378
     * @return \DateTimeInterface|null
379
     */
380 1
    public function getCreationTime()
381
    {
382 1
        return $this->creationTime;
383
    }
384
385
    /**
386
     * @param \DateTimeInterface $creationTime
387
     * @return ArchiveEntry
388
     */
389 1
    public function withCreationTime(\DateTimeInterface $creationTime) : self
390
    {
391 1
        $obj = clone $this;
392 1
        $obj->creationTime = $creationTime;
393 1
        return $obj;
394
    }
395
396
    /**
397
     * @return \DateTimeInterface|null
398
     */
399 1
    public function getModificationTime()
400
    {
401 1
        return $this->modificationTime;
402
    }
403
404
    /**
405
     * @param \DateTimeInterface $modificationTime
406
     * @return ArchiveEntry
407
     */
408 1
    public function withModificationTime(\DateTimeInterface $modificationTime) : self
409
    {
410 1
        $obj = clone $this;
411 1
        $obj->modificationTime = $modificationTime;
412 1
        return $obj;
413
    }
414
415
    /**
416
     * @return int|null
417
     */
418 1
    public function getChecksumCrc32()
419
    {
420 1
        return $this->checksumCrc32;
421
    }
422
423
    /**
424
     * @param int $checksumCrc32
425
     * @return ArchiveEntry
426
     */
427 1
    public function withChecksumCrc32(int $checksumCrc32) : self
428
    {
429 1
        $obj = clone $this;
430 1
        $obj->checksumCrc32 = $checksumCrc32;
431 1
        return $obj;
432
    }
433
434
    /**
435
     * @return string|null
436
     */
437 1
    public function getComment()
438
    {
439 1
        return $this->comment;
440
    }
441
442
    /**
443
     * @param string|null $comment
444
     * @return ArchiveEntry
445
     */
446 2
    public function withComment(string $comment = null) : self
447
    {
448 2
        $obj = clone $this;
449 2
        $obj->comment = $comment;
450 2
        return $obj;
451
    }
452
453
    /**
454
     * @return string|null
455
     */
456 1
    public function getSourceCompressionMethod()
457
    {
458 1
        return $this->sourceCompressionMethod;
459
    }
460
461
    /**
462
     * Any of the COMPRESSION_METHOD_* constants
463
     *
464
     * @param string $sourceCompressionMethod
465
     * @return ArchiveEntry
466
     */
467 1
    public function withSourceCompressionMethod($sourceCompressionMethod) : self
468
    {
469 1
        $obj = clone $this;
470 1
        $obj->sourceCompressionMethod = $sourceCompressionMethod;
471 1
        return $obj;
472
    }
473
474
    /**
475
     * @return string|null
476
     */
477 1
    public function getTargetCompressionMethod()
478
    {
479 1
        return $this->targetCompressionMethod;
480
    }
481
482
    /**
483
     * @param string $targetCompressionMethod
484
     * @return ArchiveEntry
485
     */
486 1
    public function withTargetCompressionMethod($targetCompressionMethod) : self
487
    {
488 1
        $obj = clone $this;
489 1
        $obj->targetCompressionMethod = $targetCompressionMethod;
490 1
        return $obj;
491
    }
492
493
    /**
494
     * @return int|null
495
     */
496 1
    public function getDosAttributes()
497
    {
498 1
        return $this->dosAttributes;
499
    }
500
501
    /**
502
     * @param int $dosAttributes
503
     * @return ArchiveEntry
504
     */
505 1
    public function withDosAttributes(int $dosAttributes) : self
506
    {
507 1
        $obj = clone $this;
508 1
        $obj->dosAttributes = $dosAttributes;
509 1
        return $obj;
510
    }
511
512
    /**
513
     * @return int|null
514
     */
515 1
    public function getUnixAttributes()
516
    {
517 1
        return $this->unixAttributes;
518
    }
519
520
    /**
521
     * @param int $unixAttributes
522
     * @return ArchiveEntry
523
     */
524 1
    public function withUnixAttributes(int $unixAttributes) : self
525
    {
526 1
        $obj = clone $this;
527 1
        $obj->unixAttributes = $unixAttributes;
528 1
        return $obj;
529
    }
530
}
531