1
|
|
|
<?php |
2
|
|
|
namespace Fyuze\Http\Message; |
3
|
|
|
|
4
|
|
|
use InvalidArgumentException; |
5
|
|
|
use Psr\Http\Message\StreamInterface; |
6
|
|
|
use Psr\Http\Message\UploadedFileInterface; |
7
|
|
|
use RuntimeException; |
8
|
|
|
|
9
|
|
|
class Upload implements UploadedFileInterface |
10
|
|
|
{ |
11
|
|
|
/** |
12
|
|
|
* @var StreamInterface |
13
|
|
|
*/ |
14
|
|
|
protected $stream; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* @var int |
18
|
|
|
*/ |
19
|
|
|
protected $size; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* @var int |
23
|
|
|
*/ |
24
|
|
|
protected $error; |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* @var string |
28
|
|
|
*/ |
29
|
|
|
protected $clientFilename; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* @var string |
33
|
|
|
*/ |
34
|
|
|
protected $clientMediaType; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* @var bool |
38
|
|
|
*/ |
39
|
|
|
protected $moved = false; |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* @param $resource |
43
|
|
|
* @param int $size |
44
|
|
|
* @param int $error |
45
|
|
|
* @param null $clientFilename |
46
|
|
|
* @param null $clientMediaType |
47
|
|
|
*/ |
48
|
6 |
|
public function __construct( |
49
|
|
|
$resource, |
50
|
|
|
$size = 0, |
51
|
|
|
$error = UPLOAD_ERR_OK, |
52
|
|
|
$clientFilename = null, |
53
|
|
|
$clientMediaType = null |
54
|
|
|
) |
55
|
|
|
{ |
56
|
6 |
|
if (is_resource($resource) === false |
57
|
6 |
|
&& is_string($resource) === false |
58
|
6 |
|
&& is_object($resource) === false |
59
|
6 |
|
) { |
60
|
1 |
|
throw new InvalidArgumentException( |
61
|
1 |
|
sprintf('Aruement 1 must be resource or string. %s provided', gettype($resource)) |
62
|
1 |
|
); |
63
|
|
|
} |
64
|
|
|
|
65
|
5 |
|
$this->stream = is_resource($resource) ? new Stream($resource) : $resource; |
|
|
|
|
66
|
5 |
|
$this->size = $size; |
67
|
5 |
|
$this->error = $error; |
68
|
5 |
|
$this->clientFilename = $clientFilename; |
69
|
5 |
|
$this->clientMediaType = $clientMediaType; |
70
|
5 |
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* {@inheritdoc} |
74
|
|
|
* |
75
|
|
|
* @return StreamInterface Stream representation of the uploaded file. |
76
|
|
|
* @throws \RuntimeException in cases when no stream is available or can be |
77
|
|
|
* created. |
78
|
|
|
*/ |
79
|
6 |
|
public function getStream() |
80
|
|
|
{ |
81
|
6 |
|
if ($this->moved === true) { |
82
|
1 |
|
throw new \RuntimeException('File has already been moved to disk.'); |
83
|
|
|
} |
84
|
|
|
|
85
|
6 |
|
if ($this->stream instanceof StreamInterface) { |
86
|
2 |
|
return $this->stream; |
87
|
|
|
} |
88
|
|
|
|
89
|
4 |
|
return $this->stream = new Stream($this->stream); |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
/** |
93
|
|
|
* {@inheritdoc} |
94
|
|
|
* |
95
|
|
|
* @see http://php.net/is_uploaded_file |
96
|
|
|
* @see http://php.net/move_uploaded_file |
97
|
|
|
* @param string $targetPath Path to which to move the uploaded file. |
98
|
|
|
* @throws \InvalidArgumentException if the $path specified is invalid. |
99
|
|
|
* @throws \RuntimeException on any error during the move operation, or on |
100
|
|
|
* the second or subsequent call to the method. |
101
|
|
|
*/ |
102
|
4 |
|
public function moveTo($targetPath) |
103
|
|
|
{ |
104
|
4 |
|
if ($this->moved === true) { |
105
|
1 |
|
throw new RuntimeException('This file has already been moved.'); |
106
|
|
|
} |
107
|
|
|
|
108
|
4 |
|
if (is_writable($targetPath) === false) { |
109
|
1 |
|
throw new InvalidArgumentException( |
110
|
|
|
'Unable to write to target path' |
111
|
1 |
|
); |
112
|
|
|
} |
113
|
|
|
|
114
|
3 |
|
if (strpos(PHP_SAPI, 'cli') === 0) { |
115
|
|
|
|
116
|
3 |
|
$stream = new Stream($targetPath, 'wb+'); |
117
|
3 |
|
$this->getStream()->rewind(); |
118
|
3 |
|
$stream->write($this->stream->getContents()); |
119
|
|
|
|
120
|
3 |
|
} else { |
121
|
|
|
// @codeCoverageIgnoreStart |
122
|
|
|
if (move_uploaded_file($this->stream, $targetPath) === false) { |
123
|
|
|
throw new RuntimeException('There was a problem moving your uploaded file.'); |
124
|
|
|
} |
125
|
|
|
// @codeCoverageIgnoreEnd |
126
|
|
|
} |
127
|
|
|
|
128
|
3 |
|
$this->moved = true; |
129
|
3 |
|
} |
130
|
|
|
|
131
|
|
|
/** |
132
|
|
|
* {@inheritdoc} |
133
|
|
|
* |
134
|
|
|
* @return int|null The file size in bytes or null if unknown. |
135
|
|
|
*/ |
136
|
3 |
|
public function getSize() |
137
|
|
|
{ |
138
|
3 |
|
return $this->size; |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
/** |
142
|
|
|
* {@inheritdoc} |
143
|
|
|
* |
144
|
|
|
* @see http://php.net/manual/en/features.file-upload.errors.php |
145
|
|
|
* @return int One of PHP's UPLOAD_ERR_XXX constants. |
146
|
|
|
*/ |
147
|
3 |
|
public function getError() |
148
|
|
|
{ |
149
|
3 |
|
return $this->error; |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
/** |
153
|
|
|
* {@inheritdoc} |
154
|
|
|
* |
155
|
|
|
* @return string|null The filename sent by the client or null if none |
156
|
|
|
* was provided. |
157
|
|
|
*/ |
158
|
3 |
|
public function getClientFilename() |
159
|
|
|
{ |
160
|
3 |
|
return $this->clientFilename; |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* {@inheritdoc} |
165
|
|
|
* |
166
|
|
|
* @return string|null The media type sent by the client or null if none |
167
|
|
|
* was provided. |
168
|
|
|
*/ |
169
|
3 |
|
public function getClientMediaType() |
170
|
|
|
{ |
171
|
3 |
|
return $this->clientMediaType; |
172
|
|
|
} |
173
|
|
|
} |
174
|
|
|
|
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 theid
property of an instance of theAccount
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.