File indexing completed on 2024-12-29 05:27:23
0001 <?php 0002 namespace GuzzleHttp\Psr7; 0003 0004 use InvalidArgumentException; 0005 use Psr\Http\Message\StreamInterface; 0006 use Psr\Http\Message\UploadedFileInterface; 0007 use RuntimeException; 0008 0009 class UploadedFile implements UploadedFileInterface 0010 { 0011 /** 0012 * @var int[] 0013 */ 0014 private static $errors = [ 0015 UPLOAD_ERR_OK, 0016 UPLOAD_ERR_INI_SIZE, 0017 UPLOAD_ERR_FORM_SIZE, 0018 UPLOAD_ERR_PARTIAL, 0019 UPLOAD_ERR_NO_FILE, 0020 UPLOAD_ERR_NO_TMP_DIR, 0021 UPLOAD_ERR_CANT_WRITE, 0022 UPLOAD_ERR_EXTENSION, 0023 ]; 0024 0025 /** 0026 * @var string 0027 */ 0028 private $clientFilename; 0029 0030 /** 0031 * @var string 0032 */ 0033 private $clientMediaType; 0034 0035 /** 0036 * @var int 0037 */ 0038 private $error; 0039 0040 /** 0041 * @var null|string 0042 */ 0043 private $file; 0044 0045 /** 0046 * @var bool 0047 */ 0048 private $moved = false; 0049 0050 /** 0051 * @var int 0052 */ 0053 private $size; 0054 0055 /** 0056 * @var StreamInterface|null 0057 */ 0058 private $stream; 0059 0060 /** 0061 * @param StreamInterface|string|resource $streamOrFile 0062 * @param int $size 0063 * @param int $errorStatus 0064 * @param string|null $clientFilename 0065 * @param string|null $clientMediaType 0066 */ 0067 public function __construct( 0068 $streamOrFile, 0069 $size, 0070 $errorStatus, 0071 $clientFilename = null, 0072 $clientMediaType = null 0073 ) { 0074 $this->setError($errorStatus); 0075 $this->setSize($size); 0076 $this->setClientFilename($clientFilename); 0077 $this->setClientMediaType($clientMediaType); 0078 0079 if ($this->isOk()) { 0080 $this->setStreamOrFile($streamOrFile); 0081 } 0082 } 0083 0084 /** 0085 * Depending on the value set file or stream variable 0086 * 0087 * @param mixed $streamOrFile 0088 * @throws InvalidArgumentException 0089 */ 0090 private function setStreamOrFile($streamOrFile) 0091 { 0092 if (is_string($streamOrFile)) { 0093 $this->file = $streamOrFile; 0094 } elseif (is_resource($streamOrFile)) { 0095 $this->stream = new Stream($streamOrFile); 0096 } elseif ($streamOrFile instanceof StreamInterface) { 0097 $this->stream = $streamOrFile; 0098 } else { 0099 throw new InvalidArgumentException( 0100 'Invalid stream or file provided for UploadedFile' 0101 ); 0102 } 0103 } 0104 0105 /** 0106 * @param int $error 0107 * @throws InvalidArgumentException 0108 */ 0109 private function setError($error) 0110 { 0111 if (false === is_int($error)) { 0112 throw new InvalidArgumentException( 0113 'Upload file error status must be an integer' 0114 ); 0115 } 0116 0117 if (false === in_array($error, UploadedFile::$errors)) { 0118 throw new InvalidArgumentException( 0119 'Invalid error status for UploadedFile' 0120 ); 0121 } 0122 0123 $this->error = $error; 0124 } 0125 0126 /** 0127 * @param int $size 0128 * @throws InvalidArgumentException 0129 */ 0130 private function setSize($size) 0131 { 0132 if (false === is_int($size)) { 0133 throw new InvalidArgumentException( 0134 'Upload file size must be an integer' 0135 ); 0136 } 0137 0138 $this->size = $size; 0139 } 0140 0141 /** 0142 * @param mixed $param 0143 * @return boolean 0144 */ 0145 private function isStringOrNull($param) 0146 { 0147 return in_array(gettype($param), ['string', 'NULL']); 0148 } 0149 0150 /** 0151 * @param mixed $param 0152 * @return boolean 0153 */ 0154 private function isStringNotEmpty($param) 0155 { 0156 return is_string($param) && false === empty($param); 0157 } 0158 0159 /** 0160 * @param string|null $clientFilename 0161 * @throws InvalidArgumentException 0162 */ 0163 private function setClientFilename($clientFilename) 0164 { 0165 if (false === $this->isStringOrNull($clientFilename)) { 0166 throw new InvalidArgumentException( 0167 'Upload file client filename must be a string or null' 0168 ); 0169 } 0170 0171 $this->clientFilename = $clientFilename; 0172 } 0173 0174 /** 0175 * @param string|null $clientMediaType 0176 * @throws InvalidArgumentException 0177 */ 0178 private function setClientMediaType($clientMediaType) 0179 { 0180 if (false === $this->isStringOrNull($clientMediaType)) { 0181 throw new InvalidArgumentException( 0182 'Upload file client media type must be a string or null' 0183 ); 0184 } 0185 0186 $this->clientMediaType = $clientMediaType; 0187 } 0188 0189 /** 0190 * Return true if there is no upload error 0191 * 0192 * @return boolean 0193 */ 0194 private function isOk() 0195 { 0196 return $this->error === UPLOAD_ERR_OK; 0197 } 0198 0199 /** 0200 * @return boolean 0201 */ 0202 public function isMoved() 0203 { 0204 return $this->moved; 0205 } 0206 0207 /** 0208 * @throws RuntimeException if is moved or not ok 0209 */ 0210 private function validateActive() 0211 { 0212 if (false === $this->isOk()) { 0213 throw new RuntimeException('Cannot retrieve stream due to upload error'); 0214 } 0215 0216 if ($this->isMoved()) { 0217 throw new RuntimeException('Cannot retrieve stream after it has already been moved'); 0218 } 0219 } 0220 0221 /** 0222 * {@inheritdoc} 0223 * @throws RuntimeException if the upload was not successful. 0224 */ 0225 public function getStream() 0226 { 0227 $this->validateActive(); 0228 0229 if ($this->stream instanceof StreamInterface) { 0230 return $this->stream; 0231 } 0232 0233 return new LazyOpenStream($this->file, 'r+'); 0234 } 0235 0236 /** 0237 * {@inheritdoc} 0238 * 0239 * @see http://php.net/is_uploaded_file 0240 * @see http://php.net/move_uploaded_file 0241 * @param string $targetPath Path to which to move the uploaded file. 0242 * @throws RuntimeException if the upload was not successful. 0243 * @throws InvalidArgumentException if the $path specified is invalid. 0244 * @throws RuntimeException on any error during the move operation, or on 0245 * the second or subsequent call to the method. 0246 */ 0247 public function moveTo($targetPath) 0248 { 0249 $this->validateActive(); 0250 0251 if (false === $this->isStringNotEmpty($targetPath)) { 0252 throw new InvalidArgumentException( 0253 'Invalid path provided for move operation; must be a non-empty string' 0254 ); 0255 } 0256 0257 if ($this->file) { 0258 $this->moved = php_sapi_name() == 'cli' 0259 ? rename($this->file, $targetPath) 0260 : move_uploaded_file($this->file, $targetPath); 0261 } else { 0262 copy_to_stream( 0263 $this->getStream(), 0264 new LazyOpenStream($targetPath, 'w') 0265 ); 0266 0267 $this->moved = true; 0268 } 0269 0270 if (false === $this->moved) { 0271 throw new RuntimeException( 0272 sprintf('Uploaded file could not be moved to %s', $targetPath) 0273 ); 0274 } 0275 } 0276 0277 /** 0278 * {@inheritdoc} 0279 * 0280 * @return int|null The file size in bytes or null if unknown. 0281 */ 0282 public function getSize() 0283 { 0284 return $this->size; 0285 } 0286 0287 /** 0288 * {@inheritdoc} 0289 * 0290 * @see http://php.net/manual/en/features.file-upload.errors.php 0291 * @return int One of PHP's UPLOAD_ERR_XXX constants. 0292 */ 0293 public function getError() 0294 { 0295 return $this->error; 0296 } 0297 0298 /** 0299 * {@inheritdoc} 0300 * 0301 * @return string|null The filename sent by the client or null if none 0302 * was provided. 0303 */ 0304 public function getClientFilename() 0305 { 0306 return $this->clientFilename; 0307 } 0308 0309 /** 0310 * {@inheritdoc} 0311 */ 0312 public function getClientMediaType() 0313 { 0314 return $this->clientMediaType; 0315 } 0316 }