Version 1
[yaffs-website] / vendor / zendframework / zend-diactoros / src / UploadedFile.php
1 <?php
2 /**
3  * Zend Framework (http://framework.zend.com/)
4  *
5  * @see       http://github.com/zendframework/zend-diactoros for the canonical source repository
6  * @copyright Copyright (c) 2015-2016 Zend Technologies USA Inc. (http://www.zend.com)
7  * @license   https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
8  */
9
10 namespace Zend\Diactoros;
11
12 use InvalidArgumentException;
13 use Psr\Http\Message\StreamInterface;
14 use Psr\Http\Message\UploadedFileInterface;
15 use RuntimeException;
16
17 class UploadedFile implements UploadedFileInterface
18 {
19     /**
20      * @var string
21      */
22     private $clientFilename;
23
24     /**
25      * @var string
26      */
27     private $clientMediaType;
28
29     /**
30      * @var int
31      */
32     private $error;
33
34     /**
35      * @var null|string
36      */
37     private $file;
38
39     /**
40      * @var bool
41      */
42     private $moved = false;
43
44     /**
45      * @var int
46      */
47     private $size;
48
49     /**
50      * @var null|StreamInterface
51      */
52     private $stream;
53
54     /**
55      * @param string|resource $streamOrFile
56      * @param int $size
57      * @param int $errorStatus
58      * @param string|null $clientFilename
59      * @param string|null $clientMediaType
60      * @throws InvalidArgumentException
61      */
62     public function __construct($streamOrFile, $size, $errorStatus, $clientFilename = null, $clientMediaType = null)
63     {
64         if ($errorStatus === UPLOAD_ERR_OK) {
65             if (is_string($streamOrFile)) {
66                 $this->file = $streamOrFile;
67             }
68             if (is_resource($streamOrFile)) {
69                 $this->stream = new Stream($streamOrFile);
70             }
71
72             if (! $this->file && ! $this->stream) {
73                 if (! $streamOrFile instanceof StreamInterface) {
74                     throw new InvalidArgumentException('Invalid stream or file provided for UploadedFile');
75                 }
76                 $this->stream = $streamOrFile;
77             }
78         }
79
80         if (! is_int($size)) {
81             throw new InvalidArgumentException('Invalid size provided for UploadedFile; must be an int');
82         }
83         $this->size = $size;
84
85         if (! is_int($errorStatus)
86             || 0 > $errorStatus
87             || 8 < $errorStatus
88         ) {
89             throw new InvalidArgumentException(
90                 'Invalid error status for UploadedFile; must be an UPLOAD_ERR_* constant'
91             );
92         }
93         $this->error = $errorStatus;
94
95         if (null !== $clientFilename && ! is_string($clientFilename)) {
96             throw new InvalidArgumentException(
97                 'Invalid client filename provided for UploadedFile; must be null or a string'
98             );
99         }
100         $this->clientFilename = $clientFilename;
101
102         if (null !== $clientMediaType && ! is_string($clientMediaType)) {
103             throw new InvalidArgumentException(
104                 'Invalid client media type provided for UploadedFile; must be null or a string'
105             );
106         }
107         $this->clientMediaType = $clientMediaType;
108     }
109
110     /**
111      * {@inheritdoc}
112      * @throws \RuntimeException if the upload was not successful.
113      */
114     public function getStream()
115     {
116         if ($this->error !== UPLOAD_ERR_OK) {
117             throw new RuntimeException('Cannot retrieve stream due to upload error');
118         }
119
120         if ($this->moved) {
121             throw new RuntimeException('Cannot retrieve stream after it has already been moved');
122         }
123
124         if ($this->stream instanceof StreamInterface) {
125             return $this->stream;
126         }
127
128         $this->stream = new Stream($this->file);
129         return $this->stream;
130     }
131
132     /**
133      * {@inheritdoc}
134      *
135      * @see http://php.net/is_uploaded_file
136      * @see http://php.net/move_uploaded_file
137      * @param string $targetPath Path to which to move the uploaded file.
138      * @throws \RuntimeException if the upload was not successful.
139      * @throws \InvalidArgumentException if the $path specified is invalid.
140      * @throws \RuntimeException on any error during the move operation, or on
141      *     the second or subsequent call to the method.
142      */
143     public function moveTo($targetPath)
144     {
145         if ($this->moved) {
146             throw new RuntimeException('Cannot move file; already moved!');
147         }
148
149         if ($this->error !== UPLOAD_ERR_OK) {
150             throw new RuntimeException('Cannot retrieve stream due to upload error');
151         }
152
153         if (! is_string($targetPath) || empty($targetPath)) {
154             throw new InvalidArgumentException(
155                 'Invalid path provided for move operation; must be a non-empty string'
156             );
157         }
158
159         $targetDirectory = dirname($targetPath);
160         if (! is_dir($targetDirectory) || ! is_writable($targetDirectory)) {
161             throw new RuntimeException(sprintf(
162                 'The target directory `%s` does not exists or is not writable',
163                 $targetDirectory
164             ));
165         }
166
167         $sapi = PHP_SAPI;
168         switch (true) {
169             case (empty($sapi) || 0 === strpos($sapi, 'cli') || ! $this->file):
170                 // Non-SAPI environment, or no filename present
171                 $this->writeFile($targetPath);
172                 break;
173             default:
174                 // SAPI environment, with file present
175                 if (false === move_uploaded_file($this->file, $targetPath)) {
176                     throw new RuntimeException('Error occurred while moving uploaded file');
177                 }
178                 break;
179         }
180
181         $this->moved = true;
182     }
183
184     /**
185      * {@inheritdoc}
186      *
187      * @return int|null The file size in bytes or null if unknown.
188      */
189     public function getSize()
190     {
191         return $this->size;
192     }
193
194     /**
195      * {@inheritdoc}
196      *
197      * @see http://php.net/manual/en/features.file-upload.errors.php
198      * @return int One of PHP's UPLOAD_ERR_XXX constants.
199      */
200     public function getError()
201     {
202         return $this->error;
203     }
204
205     /**
206      * {@inheritdoc}
207      *
208      * @return string|null The filename sent by the client or null if none
209      *     was provided.
210      */
211     public function getClientFilename()
212     {
213         return $this->clientFilename;
214     }
215
216     /**
217      * {@inheritdoc}
218      */
219     public function getClientMediaType()
220     {
221         return $this->clientMediaType;
222     }
223
224     /**
225      * Write internal stream to given path
226      *
227      * @param string $path
228      */
229     private function writeFile($path)
230     {
231         $handle = fopen($path, 'wb+');
232         if (false === $handle) {
233             throw new RuntimeException('Unable to write to designated path');
234         }
235
236         $stream = $this->getStream();
237         $stream->rewind();
238         while (! $stream->eof()) {
239             fwrite($handle, $stream->read(4096));
240         }
241
242         fclose($handle);
243     }
244 }