krz/vox-populi

A Tumblr web client.

clone: git clone https://gitbay.org/krz/vox-populi.git

main: vendor/guzzlehttp/psr7/src/UploadedFile.php · raw

  1<?php
  2namespace GuzzleHttp\Psr7;
  3
  4use InvalidArgumentException;
  5use Psr\Http\Message\StreamInterface;
  6use Psr\Http\Message\UploadedFileInterface;
  7use RuntimeException;
  8
  9class 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}