Subversion Repositories cheapmusic

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
103 - 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
}