1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @link http://www.yiiframework.com/ |
4
|
|
|
* @copyright Copyright (c) 2008 Yii Software LLC |
5
|
|
|
* @license http://www.yiiframework.com/license/ |
6
|
|
|
*/ |
7
|
|
|
|
8
|
|
|
namespace yii\http; |
9
|
|
|
|
10
|
|
|
use Psr\Http\Message\StreamInterface; |
11
|
|
|
use Psr\Http\Message\UploadedFileInterface; |
12
|
|
|
use yii\base\BaseObject; |
13
|
|
|
use yii\base\InvalidArgumentException; |
14
|
|
|
use yii\di\Instance; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* UploadedFile represents the information for an uploaded file. |
18
|
|
|
* |
19
|
|
|
* You can retrieve the set of an uploaded file from application 'request' component: |
20
|
|
|
* |
21
|
|
|
* ```php |
22
|
|
|
* $uploadedFiles = Yii::$app->request->getUploadedFiles(); |
23
|
|
|
* ``` |
24
|
|
|
* |
25
|
|
|
* You can use [[saveAs()]] to save file on the server. |
26
|
|
|
* You may also query other information about the file, including [[clientFilename]], |
27
|
|
|
* [[tempFilename]], [[clientMediaType]], [[size]] and [[error]]. |
28
|
|
|
* |
29
|
|
|
* For more details and usage information on UploadedFile, see the [guide article on handling uploads](guide:input-file-upload) |
30
|
|
|
* and [PSR-7 Uploaded Files specs](http://www.php-fig.org/psr/psr-7/#16-uploaded-files). |
31
|
|
|
* |
32
|
|
|
* @property string $clientFilename the original name of the file being uploaded. |
33
|
|
|
* @property int $error an error code describing the status of this file uploading. |
34
|
|
|
* @property int $size the actual size of the uploaded file in bytes. |
35
|
|
|
* @property string $clientMediaType the MIME-type of the uploaded file (such as "image/gif"). |
36
|
|
|
* Since this MIME type is not checked on the server-side, do not take this value for granted. |
37
|
|
|
* Instead, use [[\yii\helpers\FileHelper::getMimeType()]] to determine the exact MIME type. |
38
|
|
|
* @property string $baseName Original file base name. This property is read-only. |
39
|
|
|
* @property string $extension File extension. This property is read-only. |
40
|
|
|
* @property bool $hasError Whether there is an error with the uploaded file. Check [[error]] for detailed |
41
|
|
|
* error code information. This property is read-only. |
42
|
|
|
* |
43
|
|
|
* @author Qiang Xue <[email protected]> |
44
|
|
|
* @author Paul Klimov <[email protected]> |
45
|
|
|
* @since 2.0 |
46
|
|
|
*/ |
47
|
|
|
class UploadedFile extends BaseObject implements UploadedFileInterface |
48
|
|
|
{ |
49
|
|
|
/** |
50
|
|
|
* @var string the path of the uploaded file on the server. |
51
|
|
|
* Note, this is a temporary file which will be automatically deleted by PHP |
52
|
|
|
* after the current request is processed. |
53
|
|
|
*/ |
54
|
|
|
public $tempFilename; |
55
|
|
|
|
56
|
|
|
/** |
57
|
|
|
* @var string the original name of the file being uploaded |
58
|
|
|
*/ |
59
|
|
|
private $_clientFilename; |
60
|
|
|
/** |
61
|
|
|
* @var string the MIME-type of the uploaded file (such as "image/gif"). |
62
|
|
|
* Since this MIME type is not checked on the server-side, do not take this value for granted. |
63
|
|
|
* Instead, use [[\yii\helpers\FileHelper::getMimeType()]] to determine the exact MIME type. |
64
|
|
|
*/ |
65
|
|
|
private $_clientMediaType; |
66
|
|
|
/** |
67
|
|
|
* @var int the actual size of the uploaded file in bytes |
68
|
|
|
*/ |
69
|
|
|
private $_size; |
70
|
|
|
/** |
71
|
|
|
* @var int an error code describing the status of this file uploading. |
72
|
|
|
* @see http://www.php.net/manual/en/features.file-upload.errors.php |
73
|
|
|
*/ |
74
|
|
|
private $_error; |
75
|
|
|
/** |
76
|
|
|
* @var StreamInterface stream for this file. |
77
|
|
|
* @since 2.1.0 |
78
|
|
|
*/ |
79
|
|
|
private $_stream; |
80
|
|
|
|
81
|
|
|
|
82
|
|
|
/** |
83
|
|
|
* String output. |
84
|
|
|
* This is PHP magic method that returns string representation of an object. |
85
|
|
|
* The implementation here returns the uploaded file's name. |
86
|
|
|
* @return string the string representation of the object |
87
|
|
|
*/ |
88
|
|
|
public function __toString() |
89
|
|
|
{ |
90
|
|
|
return $this->clientFilename; |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
/** |
94
|
|
|
* Saves the uploaded file. |
95
|
|
|
* Note that this method uses php's move_uploaded_file() method. If the target file `$file` |
96
|
|
|
* already exists, it will be overwritten. |
97
|
|
|
* @param string $file the file path used to save the uploaded file |
98
|
|
|
* @param bool $deleteTempFile whether to delete the temporary file after saving. |
99
|
|
|
* If true, you will not be able to save the uploaded file again in the current request. |
100
|
|
|
* @return bool true whether the file is saved successfully |
101
|
|
|
* @see error |
102
|
|
|
*/ |
103
|
|
|
public function saveAs($file, $deleteTempFile = true) |
104
|
|
|
{ |
105
|
|
|
if ($this->error == UPLOAD_ERR_OK) { |
106
|
|
|
if ($deleteTempFile) { |
107
|
|
|
$this->moveTo($file); |
108
|
|
|
return true; |
109
|
|
|
} elseif (is_uploaded_file($this->tempFilename)) { |
110
|
|
|
return copy($this->tempFilename, $file); |
111
|
|
|
} |
112
|
|
|
} |
113
|
|
|
return false; |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
/** |
117
|
|
|
* @return string original file base name |
118
|
|
|
*/ |
119
|
1 |
|
public function getBaseName() |
120
|
|
|
{ |
121
|
|
|
// https://github.com/yiisoft/yii2/issues/11012 |
122
|
1 |
|
$pathInfo = pathinfo('_' . $this->getClientFilename(), PATHINFO_FILENAME); |
123
|
1 |
|
return mb_substr($pathInfo, 1, mb_strlen($pathInfo, '8bit'), '8bit'); |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
/** |
127
|
|
|
* @return string file extension |
128
|
|
|
*/ |
129
|
2 |
|
public function getExtension() |
130
|
|
|
{ |
131
|
2 |
|
return strtolower(pathinfo($this->getClientFilename(), PATHINFO_EXTENSION)); |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* @return bool whether there is an error with the uploaded file. |
136
|
|
|
* Check [[error]] for detailed error code information. |
137
|
|
|
*/ |
138
|
|
|
public function getHasError() |
139
|
|
|
{ |
140
|
|
|
return $this->error != UPLOAD_ERR_OK; |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
/** |
144
|
|
|
* {@inheritdoc} |
145
|
|
|
* @since 2.1.0 |
146
|
|
|
*/ |
147
|
3 |
|
public function getStream() |
148
|
|
|
{ |
149
|
3 |
|
if (!$this->_stream instanceof StreamInterface) { |
150
|
2 |
|
if ($this->_stream === null) { |
151
|
1 |
|
if ($this->getError() !== UPLOAD_ERR_OK) { |
152
|
|
|
throw new \RuntimeException('Unable to create file stream due to upload error: ' . $this->getError()); |
153
|
|
|
} |
154
|
|
|
$stream = [ |
155
|
1 |
|
'class' => FileStream::class, |
156
|
1 |
|
'filename' => $this->tempFilename, |
157
|
1 |
|
'mode' => 'r', |
158
|
|
|
]; |
159
|
1 |
|
} elseif ($this->_stream instanceof \Closure) { |
160
|
1 |
|
$stream = call_user_func($this->_stream, $this); |
161
|
|
|
} else { |
162
|
1 |
|
$stream = $this->_stream; |
163
|
|
|
} |
164
|
|
|
|
165
|
2 |
|
$this->_stream = Instance::ensure($stream, StreamInterface::class); |
166
|
|
|
} |
167
|
3 |
|
return $this->_stream; |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* @param StreamInterface|\Closure|array $stream stream instance or its DI compatible configuration. |
172
|
|
|
* @since 2.1.0 |
173
|
|
|
*/ |
174
|
5 |
|
public function setStream($stream) |
175
|
|
|
{ |
176
|
5 |
|
$this->_stream = $stream; |
|
|
|
|
177
|
5 |
|
} |
178
|
|
|
|
179
|
|
|
/** |
180
|
|
|
* {@inheritdoc} |
181
|
|
|
* @since 2.1.0 |
182
|
|
|
*/ |
183
|
|
|
public function moveTo($targetPath) |
184
|
|
|
{ |
185
|
|
|
if ($this->error !== UPLOAD_ERR_OK) { |
186
|
|
|
throw new \RuntimeException('Unable to move file due to upload error: ' . $this->error); |
187
|
|
|
} |
188
|
|
|
if (!move_uploaded_file($this->tempFilename, $targetPath)) { |
189
|
|
|
throw new \RuntimeException('Unable to move uploaded file.'); |
190
|
|
|
} |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
/** |
194
|
|
|
* {@inheritdoc} |
195
|
|
|
* @since 2.1.0 |
196
|
|
|
*/ |
197
|
1 |
|
public function getSize() |
198
|
|
|
{ |
199
|
1 |
|
return $this->_size; |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
/** |
203
|
|
|
* @param int $size the actual size of the uploaded file in bytes. |
204
|
|
|
* @throws InvalidArgumentException on invalid size given. |
205
|
|
|
* @since 2.1.0 |
206
|
|
|
*/ |
207
|
28 |
|
public function setSize($size) |
208
|
|
|
{ |
209
|
28 |
|
if (!is_int($size)) { |
210
|
|
|
throw new InvalidArgumentException('"' . get_class($this) . '::$size" must be an integer.'); |
211
|
|
|
} |
212
|
28 |
|
$this->_size = $size; |
213
|
28 |
|
} |
214
|
|
|
|
215
|
|
|
/** |
216
|
|
|
* {@inheritdoc} |
217
|
|
|
* @since 2.1.0 |
218
|
|
|
*/ |
219
|
21 |
|
public function getError() |
220
|
|
|
{ |
221
|
21 |
|
return $this->_error; |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
/** |
225
|
|
|
* @param int $error upload error code. |
226
|
|
|
* @throws InvalidArgumentException on invalid error given. |
227
|
|
|
* @since 2.1.0 |
228
|
|
|
*/ |
229
|
29 |
|
public function setError($error) |
230
|
|
|
{ |
231
|
29 |
|
if (!is_int($error)) { |
232
|
|
|
throw new InvalidArgumentException('"' . get_class($this) . '::$error" must be an integer.'); |
233
|
|
|
} |
234
|
29 |
|
$this->_error = $error; |
235
|
29 |
|
} |
236
|
|
|
|
237
|
|
|
/** |
238
|
|
|
* {@inheritdoc} |
239
|
|
|
* @since 2.1.0 |
240
|
|
|
*/ |
241
|
14 |
|
public function getClientFilename() |
242
|
|
|
{ |
243
|
14 |
|
return $this->_clientFilename; |
244
|
|
|
} |
245
|
|
|
|
246
|
|
|
/** |
247
|
|
|
* @param string $clientFilename the original name of the file being uploaded. |
248
|
|
|
* @since 2.1.0 |
249
|
|
|
*/ |
250
|
28 |
|
public function setClientFilename($clientFilename) |
251
|
|
|
{ |
252
|
28 |
|
$this->_clientFilename = $clientFilename; |
253
|
28 |
|
} |
254
|
|
|
|
255
|
|
|
/** |
256
|
|
|
* {@inheritdoc} |
257
|
|
|
* @since 2.1.0 |
258
|
|
|
*/ |
259
|
1 |
|
public function getClientMediaType() |
260
|
|
|
{ |
261
|
1 |
|
return $this->_clientMediaType; |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
/** |
265
|
|
|
* @param string $clientMediaType the MIME-type of the uploaded file (such as "image/gif"). |
266
|
|
|
* @since 2.1.0 |
267
|
|
|
*/ |
268
|
28 |
|
public function setClientMediaType($clientMediaType) |
269
|
|
|
{ |
270
|
28 |
|
$this->_clientMediaType = $clientMediaType; |
271
|
28 |
|
} |
272
|
|
|
} |
273
|
|
|
|
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.