Issues (57)

Security Analysis    not enabled

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/UploadedFile.php (1 issue)

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
namespace Thruster\Component\HttpMessage;
4
5
use RuntimeException;
6
use InvalidArgumentException;
7
use Psr\Http\Message\StreamInterface;
8
use Psr\Http\Message\UploadedFileInterface;
9
10
/**
11
 * Class UploadedFile
12
 *
13
 * @package Thruster\Component\HttpMessage
14
 * @author  Aurimas Niekis <[email protected]>
15
 */
16
class UploadedFile implements UploadedFileInterface
17
{
18
    const ERRORS = [
19
        UPLOAD_ERR_OK,
20
        UPLOAD_ERR_INI_SIZE,
21
        UPLOAD_ERR_FORM_SIZE,
22
        UPLOAD_ERR_PARTIAL,
23
        UPLOAD_ERR_NO_FILE,
24
        UPLOAD_ERR_NO_TMP_DIR,
25
        UPLOAD_ERR_CANT_WRITE,
26
        UPLOAD_ERR_EXTENSION,
27
    ];
28
29
    /**
30
     * @var string
31
     */
32
    private $clientFilename;
33
34
    /**
35
     * @var string
36
     */
37
    private $clientMediaType;
38
39
    /**
40
     * @var int
41
     */
42
    private $error;
43
44
    /**
45
     * @var null|string
46
     */
47
    private $file;
48
49
    /**
50
     * @var bool
51
     */
52
    private $moved = false;
53
54
    /**
55
     * @var int
56
     */
57
    private $size;
58
59
    /**
60
     * @var StreamInterface|null
61
     */
62
    private $stream;
63
64
    /**
65
     * @param StreamInterface|string|resource $streamOrFile
66
     * @param int $size
67
     * @param int $errorStatus
68
     * @param string|null $clientFilename
69
     * @param string|null $clientMediaType
70
     */
71 74
    public function __construct(
72
        $streamOrFile,
73
        $size,
74
        $errorStatus,
75
        $clientFilename = null,
76
        $clientMediaType = null
77
    ) {
78 74
        $this->setError($errorStatus);
79 65
        $this->setSize($size);
80 61
        $this->setClientFilename($clientFilename);
81 55
        $this->setClientMediaType($clientMediaType);
82
83 49
        if ($this->isOk()) {
84 27
            $this->setStreamOrFile($streamOrFile);
85
        }
86 42
    }
87
88
    /**
89
     * Depending on the value set file or stream variable
90
     *
91
     * @param mixed $streamOrFile
92
     * @throws InvalidArgumentException
93
     */
94 27
    private function setStreamOrFile($streamOrFile)
95
    {
96 27
        if (is_string($streamOrFile)) {
97 7
            $this->file = $streamOrFile;
98 20
        } elseif (is_resource($streamOrFile)) {
99 1
            $this->stream = new Stream($streamOrFile);
100
        } elseif ($streamOrFile instanceof StreamInterface) {
101 12
            $this->stream = $streamOrFile;
102
        } else {
103 7
            throw new InvalidArgumentException(
104 7
                'Invalid stream or file provided for UploadedFile'
105
            );
106
        }
107 20
    }
108
109
    /**
110
     * @param int $error
111
     * @throws InvalidArgumentException
112
     */
113 74
    private function setError($error)
114
    {
115 74
        if (false === is_int($error)) {
116 7
            throw new InvalidArgumentException(
117 7
                'Upload file error status must be an integer'
118
            );
119
        }
120
121 67
        if (false === in_array($error, static::ERRORS)) {
122 2
            throw new InvalidArgumentException(
123 2
                'Invalid error status for UploadedFile'
124
            );
125
        }
126
127 65
        $this->error = $error;
128 65
    }
129
130
    /**
131
     * @param int $size
132
     * @throws InvalidArgumentException
133
     */
134 65
    private function setSize($size)
135
    {
136 65
        if (false === is_int($size)) {
137 4
            throw new InvalidArgumentException(
138 4
                'Upload file size must be an integer'
139
            );
140
        }
141
142 61
        $this->size = $size;
143 61
    }
144
145
    /**
146
     * @param mixed $param
147
     * @return boolean
148
     */
149 61
    private function isStringOrNull($param)
150
    {
151 61
        return in_array(gettype($param), ['string', 'NULL']);
152
    }
153
154
    /**
155
     * @param mixed $param
156
     * @return boolean
157
     */
158 12
    private function isStringNotEmpty($param)
159
    {
160 12
        return is_string($param) && false === empty($param);
161
    }
162
163
    /**
164
     * @param string|null $clientFilename
165
     * @throws InvalidArgumentException
166
     */
167 61
    private function setClientFilename($clientFilename)
168
    {
169 61
        if (false === $this->isStringOrNull($clientFilename)) {
170 6
            throw new InvalidArgumentException(
171 6
                'Upload file client filename must be a string or null'
172
            );
173
        }
174
175 55
        $this->clientFilename = $clientFilename;
176 55
    }
177
178
    /**
179
     * @param string|null $clientMediaType
180
     * @throws InvalidArgumentException
181
     */
182 55
    private function setClientMediaType($clientMediaType)
183
    {
184 55
        if (false === $this->isStringOrNull($clientMediaType)) {
185 6
            throw new InvalidArgumentException(
186 6
                'Upload file client media type must be a string or null'
187
            );
188
        }
189
190 49
        $this->clientMediaType = $clientMediaType;
191 49
    }
192
193
    /**
194
     * Return true if there is no upload error
195
     *
196
     * @return boolean
197
     */
198 49
    private function isOk()
199
    {
200 49
        return $this->error === UPLOAD_ERR_OK;
201
    }
202
203
    /**
204
     * @return boolean
205
     */
206 15
    public function isMoved()
207
    {
208 15
        return $this->moved;
209
    }
210
211
    /**
212
     * @throws RuntimeException if is moved or not ok
213
     */
214 29
    private function validateActive()
215
    {
216 29
        if (false === $this->isOk()) {
217 14
            throw new RuntimeException('Cannot retrieve stream due to upload error');
218
        }
219
220 15
        if ($this->isMoved()) {
221 2
            throw new RuntimeException('Cannot retrieve stream after it has already been moved');
222
        }
223 15
    }
224
225
    /**
226
     * {@inheritdoc}
227
     * @throws RuntimeException if the upload was not successful.
228
     */
229 13
    public function getStream()
230
    {
231 13
        $this->validateActive();
232
233 6
        if ($this->stream instanceof StreamInterface) {
234 5
            return $this->stream;
235
        }
236
237 1
        return new LazyOpenStream($this->file, 'r+');
238
    }
239
240
    /**
241
     * {@inheritdoc}
242
     *
243
     * @see http://php.net/is_uploaded_file
244
     * @see http://php.net/move_uploaded_file
245
     * @param string $targetPath Path to which to move the uploaded file.
246
     * @throws RuntimeException if the upload was not successful.
247
     * @throws InvalidArgumentException if the $path specified is invalid.
248
     * @throws RuntimeException on any error during the move operation, or on
249
     *     the second or subsequent call to the method.
250
     */
251 19
    public function moveTo($targetPath)
252
    {
253 19
        $this->validateActive();
254
255 12
        if (false === $this->isStringNotEmpty($targetPath)) {
256 8
            throw new InvalidArgumentException(
257 8
                'Invalid path provided for move operation; must be a non-empty string'
258
            );
259
        }
260
261 4
        if ($this->file) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->file of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
262 1
            $this->moved = php_sapi_name() == 'cli'
263 1
                ? rename($this->file, $targetPath)
264 1
                : move_uploaded_file($this->file, $targetPath);
265
        } else {
266 3
            copy_to_stream(
267 3
                $this->getStream(),
268 3
                new LazyOpenStream($targetPath, 'w')
269
            );
270
271 3
            $this->moved = true;
272
        }
273
274 4
        if (false === $this->moved) {
275
            throw new RuntimeException(
276
                sprintf('Uploaded file could not be moved to %s', $targetPath)
277
            );
278
        }
279 4
    }
280
281
    /**
282
     * {@inheritdoc}
283
     *
284
     * @return int|null The file size in bytes or null if unknown.
285
     */
286 1
    public function getSize()
287
    {
288 1
        return $this->size;
289
    }
290
291
    /**
292
     * {@inheritdoc}
293
     *
294
     * @see http://php.net/manual/en/features.file-upload.errors.php
295
     * @return int One of PHP's UPLOAD_ERR_XXX constants.
296
     */
297 7
    public function getError()
298
    {
299 7
        return $this->error;
300
    }
301
302
    /**
303
     * {@inheritdoc}
304
     *
305
     * @return string|null The filename sent by the client or null if none
306
     *     was provided.
307
     */
308 1
    public function getClientFilename()
309
    {
310 1
        return $this->clientFilename;
311
    }
312
313
    /**
314
     * {@inheritdoc}
315
     */
316 1
    public function getClientMediaType()
317
    {
318 1
        return $this->clientMediaType;
319
    }
320
}
321