2 namespace GuzzleHttp\Psr7;
4 use InvalidArgumentException;
5 use Psr\Http\Message\StreamInterface;
6 use Psr\Http\Message\UploadedFileInterface;
9 class UploadedFile implements UploadedFileInterface
14 private static $errors = [
20 UPLOAD_ERR_NO_TMP_DIR,
21 UPLOAD_ERR_CANT_WRITE,
28 private $clientFilename;
33 private $clientMediaType;
48 private $moved = false;
56 * @var StreamInterface|null
61 * @param StreamInterface|string|resource $streamOrFile
63 * @param int $errorStatus
64 * @param string|null $clientFilename
65 * @param string|null $clientMediaType
67 public function __construct(
71 $clientFilename = null,
72 $clientMediaType = null
74 $this->setError($errorStatus);
75 $this->setSize($size);
76 $this->setClientFilename($clientFilename);
77 $this->setClientMediaType($clientMediaType);
80 $this->setStreamOrFile($streamOrFile);
85 * Depending on the value set file or stream variable
87 * @param mixed $streamOrFile
88 * @throws InvalidArgumentException
90 private function setStreamOrFile($streamOrFile)
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;
99 throw new InvalidArgumentException(
100 'Invalid stream or file provided for UploadedFile'
107 * @throws InvalidArgumentException
109 private function setError($error)
111 if (false === is_int($error)) {
112 throw new InvalidArgumentException(
113 'Upload file error status must be an integer'
117 if (false === in_array($error, UploadedFile::$errors)) {
118 throw new InvalidArgumentException(
119 'Invalid error status for UploadedFile'
123 $this->error = $error;
128 * @throws InvalidArgumentException
130 private function setSize($size)
132 if (false === is_int($size)) {
133 throw new InvalidArgumentException(
134 'Upload file size must be an integer'
142 * @param mixed $param
145 private function isStringOrNull($param)
147 return in_array(gettype($param), ['string', 'NULL']);
151 * @param mixed $param
154 private function isStringNotEmpty($param)
156 return is_string($param) && false === empty($param);
160 * @param string|null $clientFilename
161 * @throws InvalidArgumentException
163 private function setClientFilename($clientFilename)
165 if (false === $this->isStringOrNull($clientFilename)) {
166 throw new InvalidArgumentException(
167 'Upload file client filename must be a string or null'
171 $this->clientFilename = $clientFilename;
175 * @param string|null $clientMediaType
176 * @throws InvalidArgumentException
178 private function setClientMediaType($clientMediaType)
180 if (false === $this->isStringOrNull($clientMediaType)) {
181 throw new InvalidArgumentException(
182 'Upload file client media type must be a string or null'
186 $this->clientMediaType = $clientMediaType;
190 * Return true if there is no upload error
194 private function isOk()
196 return $this->error === UPLOAD_ERR_OK;
202 public function isMoved()
208 * @throws RuntimeException if is moved or not ok
210 private function validateActive()
212 if (false === $this->isOk()) {
213 throw new RuntimeException('Cannot retrieve stream due to upload error');
216 if ($this->isMoved()) {
217 throw new RuntimeException('Cannot retrieve stream after it has already been moved');
223 * @throws RuntimeException if the upload was not successful.
225 public function getStream()
227 $this->validateActive();
229 if ($this->stream instanceof StreamInterface) {
230 return $this->stream;
233 return new LazyOpenStream($this->file, 'r+');
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.
247 public function moveTo($targetPath)
249 $this->validateActive();
251 if (false === $this->isStringNotEmpty($targetPath)) {
252 throw new InvalidArgumentException(
253 'Invalid path provided for move operation; must be a non-empty string'
258 $this->moved = php_sapi_name() == 'cli'
259 ? rename($this->file, $targetPath)
260 : move_uploaded_file($this->file, $targetPath);
264 new LazyOpenStream($targetPath, 'w')
270 if (false === $this->moved) {
271 throw new RuntimeException(
272 sprintf('Uploaded file could not be moved to %s', $targetPath)
280 * @return int|null The file size in bytes or null if unknown.
282 public function getSize()
290 * @see http://php.net/manual/en/features.file-upload.errors.php
291 * @return int One of PHP's UPLOAD_ERR_XXX constants.
293 public function getError()
301 * @return string|null The filename sent by the client or null if none
304 public function getClientFilename()
306 return $this->clientFilename;
312 public function getClientMediaType()
314 return $this->clientMediaType;