Interim commit.
[yaffs-website] / vendor / guzzlehttp / psr7 / src / UploadedFile.php
1 <?php
2 namespace GuzzleHttp\Psr7;
3
4 use InvalidArgumentException;
5 use Psr\Http\Message\StreamInterface;
6 use Psr\Http\Message\UploadedFileInterface;
7 use RuntimeException;
8
9 class UploadedFile implements UploadedFileInterface
10 {
11     /**
12      * @var int[]
13      */
14     private static $errors = [
15         UPLOAD_ERR_OK,
16         UPLOAD_ERR_INI_SIZE,
17         UPLOAD_ERR_FORM_SIZE,
18         UPLOAD_ERR_PARTIAL,
19         UPLOAD_ERR_NO_FILE,
20         UPLOAD_ERR_NO_TMP_DIR,
21         UPLOAD_ERR_CANT_WRITE,
22         UPLOAD_ERR_EXTENSION,
23     ];
24
25     /**
26      * @var string
27      */
28     private $clientFilename;
29
30     /**
31      * @var string
32      */
33     private $clientMediaType;
34
35     /**
36      * @var int
37      */
38     private $error;
39
40     /**
41      * @var null|string
42      */
43     private $file;
44
45     /**
46      * @var bool
47      */
48     private $moved = false;
49
50     /**
51      * @var int
52      */
53     private $size;
54
55     /**
56      * @var StreamInterface|null
57      */
58     private $stream;
59
60     /**
61      * @param StreamInterface|string|resource $streamOrFile
62      * @param int $size
63      * @param int $errorStatus
64      * @param string|null $clientFilename
65      * @param string|null $clientMediaType
66      */
67     public function __construct(
68         $streamOrFile,
69         $size,
70         $errorStatus,
71         $clientFilename = null,
72         $clientMediaType = null
73     ) {
74         $this->setError($errorStatus);
75         $this->setSize($size);
76         $this->setClientFilename($clientFilename);
77         $this->setClientMediaType($clientMediaType);
78
79         if ($this->isOk()) {
80             $this->setStreamOrFile($streamOrFile);
81         }
82     }
83
84     /**
85      * Depending on the value set file or stream variable
86      *
87      * @param mixed $streamOrFile
88      * @throws InvalidArgumentException
89      */
90     private function setStreamOrFile($streamOrFile)
91     {
92         if (is_string($streamOrFile)) {
93             $this->file = $streamOrFile;
94         } elseif (is_resource($streamOrFile)) {
95             $this->stream = new Stream($streamOrFile);
96         } elseif ($streamOrFile instanceof StreamInterface) {
97             $this->stream = $streamOrFile;
98         } else {
99             throw new InvalidArgumentException(
100                 'Invalid stream or file provided for UploadedFile'
101             );
102         }
103     }
104
105     /**
106      * @param int $error
107      * @throws InvalidArgumentException
108      */
109     private function setError($error)
110     {
111         if (false === is_int($error)) {
112             throw new InvalidArgumentException(
113                 'Upload file error status must be an integer'
114             );
115         }
116
117         if (false === in_array($error, UploadedFile::$errors)) {
118             throw new InvalidArgumentException(
119                 'Invalid error status for UploadedFile'
120             );
121         }
122
123         $this->error = $error;
124     }
125
126     /**
127      * @param int $size
128      * @throws InvalidArgumentException
129      */
130     private function setSize($size)
131     {
132         if (false === is_int($size)) {
133             throw new InvalidArgumentException(
134                 'Upload file size must be an integer'
135             );
136         }
137
138         $this->size = $size;
139     }
140
141     /**
142      * @param mixed $param
143      * @return boolean
144      */
145     private function isStringOrNull($param)
146     {
147         return in_array(gettype($param), ['string', 'NULL']);
148     }
149
150     /**
151      * @param mixed $param
152      * @return boolean
153      */
154     private function isStringNotEmpty($param)
155     {
156         return is_string($param) && false === empty($param);
157     }
158
159     /**
160      * @param string|null $clientFilename
161      * @throws InvalidArgumentException
162      */
163     private function setClientFilename($clientFilename)
164     {
165         if (false === $this->isStringOrNull($clientFilename)) {
166             throw new InvalidArgumentException(
167                 'Upload file client filename must be a string or null'
168             );
169         }
170
171         $this->clientFilename = $clientFilename;
172     }
173
174     /**
175      * @param string|null $clientMediaType
176      * @throws InvalidArgumentException
177      */
178     private function setClientMediaType($clientMediaType)
179     {
180         if (false === $this->isStringOrNull($clientMediaType)) {
181             throw new InvalidArgumentException(
182                 'Upload file client media type must be a string or null'
183             );
184         }
185
186         $this->clientMediaType = $clientMediaType;
187     }
188
189     /**
190      * Return true if there is no upload error
191      *
192      * @return boolean
193      */
194     private function isOk()
195     {
196         return $this->error === UPLOAD_ERR_OK;
197     }
198
199     /**
200      * @return boolean
201      */
202     public function isMoved()
203     {
204         return $this->moved;
205     }
206
207     /**
208      * @throws RuntimeException if is moved or not ok
209      */
210     private function validateActive()
211     {
212         if (false === $this->isOk()) {
213             throw new RuntimeException('Cannot retrieve stream due to upload error');
214         }
215
216         if ($this->isMoved()) {
217             throw new RuntimeException('Cannot retrieve stream after it has already been moved');
218         }
219     }
220
221     /**
222      * {@inheritdoc}
223      * @throws RuntimeException if the upload was not successful.
224      */
225     public function getStream()
226     {
227         $this->validateActive();
228
229         if ($this->stream instanceof StreamInterface) {
230             return $this->stream;
231         }
232
233         return new LazyOpenStream($this->file, 'r+');
234     }
235
236     /**
237      * {@inheritdoc}
238      *
239      * @see http://php.net/is_uploaded_file
240      * @see http://php.net/move_uploaded_file
241      * @param string $targetPath Path to which to move the uploaded file.
242      * @throws RuntimeException if the upload was not successful.
243      * @throws InvalidArgumentException if the $path specified is invalid.
244      * @throws RuntimeException on any error during the move operation, or on
245      *     the second or subsequent call to the method.
246      */
247     public function moveTo($targetPath)
248     {
249         $this->validateActive();
250
251         if (false === $this->isStringNotEmpty($targetPath)) {
252             throw new InvalidArgumentException(
253                 'Invalid path provided for move operation; must be a non-empty string'
254             );
255         }
256
257         if ($this->file) {
258             $this->moved = php_sapi_name() == 'cli'
259                 ? rename($this->file, $targetPath)
260                 : move_uploaded_file($this->file, $targetPath);
261         } else {
262             copy_to_stream(
263                 $this->getStream(),
264                 new LazyOpenStream($targetPath, 'w')
265             );
266
267             $this->moved = true;
268         }
269
270         if (false === $this->moved) {
271             throw new RuntimeException(
272                 sprintf('Uploaded file could not be moved to %s', $targetPath)
273             );
274         }
275     }
276
277     /**
278      * {@inheritdoc}
279      *
280      * @return int|null The file size in bytes or null if unknown.
281      */
282     public function getSize()
283     {
284         return $this->size;
285     }
286
287     /**
288      * {@inheritdoc}
289      *
290      * @see http://php.net/manual/en/features.file-upload.errors.php
291      * @return int One of PHP's UPLOAD_ERR_XXX constants.
292      */
293     public function getError()
294     {
295         return $this->error;
296     }
297
298     /**
299      * {@inheritdoc}
300      *
301      * @return string|null The filename sent by the client or null if none
302      *     was provided.
303      */
304     public function getClientFilename()
305     {
306         return $this->clientFilename;
307     }
308
309     /**
310      * {@inheritdoc}
311      */
312     public function getClientMediaType()
313     {
314         return $this->clientMediaType;
315     }
316 }