Completed
Push — master ( ac4cc7...3c4d8e )
by Tobias
03:01
created

UploadedFile::__construct()   C

Complexity

Conditions 12
Paths 9

Size

Total Lines 36

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 12.0135

Importance

Changes 0
Metric Value
dl 0
loc 36
ccs 21
cts 22
cp 0.9545
rs 6.9666
c 0
b 0
f 0
cc 12
nc 9
nop 5
crap 12.0135

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Nyholm\Psr7;
6
7
use Psr\Http\Message\{StreamInterface, UploadedFileInterface};
8
9
/**
10
 * @author Michael Dowling and contributors to guzzlehttp/psr7
11
 * @author Tobias Nyholm <[email protected]>
12
 * @author Martijn van der Ven <[email protected]>
13
 */
14
final class UploadedFile implements UploadedFileInterface
15
{
16
    /** @var array */
17
    private const ERRORS = [
18
        \UPLOAD_ERR_OK => 1,
19
        \UPLOAD_ERR_INI_SIZE => 1,
20
        \UPLOAD_ERR_FORM_SIZE => 1,
21
        \UPLOAD_ERR_PARTIAL => 1,
22
        \UPLOAD_ERR_NO_FILE => 1,
23
        \UPLOAD_ERR_NO_TMP_DIR => 1,
24
        \UPLOAD_ERR_CANT_WRITE => 1,
25
        \UPLOAD_ERR_EXTENSION => 1,
26
    ];
27
28
    /** @var string */
29
    private $clientFilename;
30
31
    /** @var string */
32
    private $clientMediaType;
33
34
    /** @var int */
35
    private $error;
36
37
    /** @var string|null */
38
    private $file;
39
40
    /** @var bool */
41
    private $moved = false;
42
43
    /** @var int */
44
    private $size;
45
46
    /** @var StreamInterface|null */
47
    private $stream;
48
49
    /**
50
     * @param StreamInterface|string|resource $streamOrFile
51
     * @param int $size
52
     * @param int $errorStatus
53
     * @param string|null $clientFilename
54
     * @param string|null $clientMediaType
55
     */
56 76
    public function __construct($streamOrFile, $size, $errorStatus, $clientFilename = null, $clientMediaType = null)
57
    {
58 76
        if (false === \is_int($errorStatus) || !isset(self::ERRORS[$errorStatus])) {
59 9
            throw new \InvalidArgumentException('Upload file error status must be an integer value and one of the "UPLOAD_ERR_*" constants.');
60
        }
61
62 67
        if (false === \is_int($size)) {
63
            throw new \InvalidArgumentException('Upload file size must be an integer');
64
        }
65
66 67
        if (null !== $clientFilename && !\is_string($clientFilename)) {
67 6
            throw new \InvalidArgumentException('Upload file client filename must be a string or null');
68
        }
69
70 61
        if (null !== $clientMediaType && !\is_string($clientMediaType)) {
71 6
            throw new \InvalidArgumentException('Upload file client media type must be a string or null');
72
        }
73
74 55
        $this->error = $errorStatus;
75 55
        $this->size = $size;
76 55
        $this->clientFilename = $clientFilename;
77 55
        $this->clientMediaType = $clientMediaType;
78
79 55
        if (\UPLOAD_ERR_OK === $this->error) {
80
            // Depending on the value set file or stream variable.
81 33
            if (\is_string($streamOrFile)) {
82 2
                $this->file = $streamOrFile;
83 31
            } elseif (\is_resource($streamOrFile)) {
84 1
                $this->stream = Stream::create($streamOrFile);
85 30
            } elseif ($streamOrFile instanceof StreamInterface) {
86 23
                $this->stream = $streamOrFile;
87
            } else {
88 7
                throw new \InvalidArgumentException('Invalid stream or file provided for UploadedFile');
89
            }
90
        }
91 48
    }
92
93
    /**
94
     * @throws \RuntimeException if is moved or not ok
95
     */
96 35
    private function validateActive(): void
97
    {
98 35
        if (\UPLOAD_ERR_OK !== $this->error) {
99 14
            throw new \RuntimeException('Cannot retrieve stream due to upload error');
100
        }
101
102 21
        if ($this->moved) {
103 4
            throw new \RuntimeException('Cannot retrieve stream after it has already been moved');
104
        }
105 21
    }
106
107 19
    public function getStream(): StreamInterface
108
    {
109 19
        $this->validateActive();
110
111 12
        if ($this->stream instanceof StreamInterface) {
112 11
            return $this->stream;
113
        }
114
115 1
        $resource = \fopen($this->file, 'r');
116
117 1
        return Stream::create($resource);
118
    }
119
120 23
    public function moveTo($targetPath): void
121
    {
122 23
        $this->validateActive();
123
124 16
        if (!\is_string($targetPath) || '' === $targetPath) {
125 8
            throw new \InvalidArgumentException('Invalid path provided for move operation; must be a non-empty string');
126
        }
127
128 8
        if (null !== $this->file) {
129 1
            $this->moved = 'cli' === \PHP_SAPI ? \rename($this->file, $targetPath) : \move_uploaded_file($this->file, $targetPath);
130
        } else {
131 7
            $stream = $this->getStream();
132 7
            if ($stream->isSeekable()) {
133 7
                $stream->rewind();
134
            }
135
136
            // Copy the contents of a stream into another stream until end-of-file.
137 7
            $dest = Stream::create(\fopen($targetPath, 'w'));
138 7
            while (!$stream->eof()) {
139 7
                if (!$dest->write($stream->read(1048576))) {
140
                    break;
141
                }
142
            }
143
144 7
            $this->moved = true;
145
        }
146
147 8
        if (false === $this->moved) {
148
            throw new \RuntimeException(\sprintf('Uploaded file could not be moved to %s', $targetPath));
149
        }
150 8
    }
151
152 3
    public function getSize(): int
153
    {
154 3
        return $this->size;
155
    }
156
157 10
    public function getError(): int
158
    {
159 10
        return $this->error;
160
    }
161
162 3
    public function getClientFilename(): ?string
163
    {
164 3
        return $this->clientFilename;
165
    }
166
167 3
    public function getClientMediaType(): ?string
168
    {
169 3
        return $this->clientMediaType;
170
    }
171
}
172