Issues (41)

src/Message/UploadedFile.php (5 issues)

1
<?php
2
3
namespace DMT\Aura\Psr\Message;
4
5
use Aura\Web\Request\Values;
6
use InvalidArgumentException;
7
use Psr\Http\Message\StreamInterface;
8
use Psr\Http\Message\UploadedFileInterface;
9
use RuntimeException;
10
use const UPLOAD_ERR_OK;
11
12
/**
13
 * Class UploadedFile
14
 *
15
 * @package DMT\Aura\Psr\Message
16
 */
17
class UploadedFile implements UploadedFileInterface
18
{
19
    /** @var StreamInterface $stream */
20
    private $stream;
21
    /** @var Values $file */
22
    private $file;
23
24
    /**
25
     * UploadedFile constructor.
26
     *
27
     * @param StreamInterface $stream
28
     * @param int|null $size
29
     * @param int $error
30
     * @param string|null $clientFilename
31
     * @param string|null $clientMediaType
32
     */
33 15
    public function __construct(
34
        StreamInterface $stream,
35
        int $size = null,
36
        int $error = UPLOAD_ERR_OK,
37
        string $clientFilename = null,
38
        string $clientMediaType = null
39
    ) {
40 15
        $this->stream = $stream;
41 15
        $this->file = new Values([
42 15
            'error' => $error,
43 15
            'name' => $clientFilename,
44 15
            'size' => $size,
45 15
            'tmp_name' => $stream->getMetadata('uri'),
46 15
            'type' => $clientMediaType,
47
        ]);
48 15
    }
49
50
    /**
51
     * Get the inner object.
52
     *
53
     * @return Values
54
     */
55 1
    public function getInnerObject(): Values
56
    {
57 1
        return $this->file;
58
    }
59
60
    /**
61
     * Retrieve a stream representing the uploaded file.
62
     *
63
     * @return StreamInterface
64
     * @throws RuntimeException
65
     */
66 10
    public function getStream(): StreamInterface
67
    {
68 10
        $this->validateStream();
69
70 9
        return $this->stream;
71
    }
72
73
    /**
74
     * Move the uploaded file to a new location.
75
     *
76
     * @param string $targetPath
77
     * @throws InvalidArgumentException
78
     * @throws RuntimeException
79
     */
80 4
    public function moveTo($targetPath)
81
    {
82 4
        if (!is_string($targetPath) || $targetPath === '') {
0 ignored issues
show
The condition is_string($targetPath) is always true.
Loading history...
83
            throw new InvalidArgumentException('invalid target path');
84
        }
85
86 4
        $target = fopen($targetPath, 'w');
87 4
        if ($target === false) {
88
            throw new RuntimeException('target is not writeable');
89
        }
90
91 4
        $stream = $this->getStream();
92 4
        $stream->rewind();
93
94 4
        while (!$stream->eof()) {
95 4
            if (fwrite($target, $stream->read(8196)) === false) {
96
                throw new RuntimeException('error whilst writing to target');
97
            }
98
        }
99
100 4
        $stream->close();
101 4
    }
102
103
    /**
104
     * Retrieve the file size.
105
     *
106
     * @return int|null
107
     */
108 5
    public function getSize()
109
    {
110 5
        return $this->file->get('size');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->file->get('size') also could return the type array which is incompatible with the documented return type integer|null.
Loading history...
111
    }
112
113
    /**
114
     * Retrieve the error associated with the uploaded file.
115
     *
116
     * @return int
117
     */
118 11
    public function getError(): int
119
    {
120 11
        return $this->file->get('error', UPLOAD_ERR_OK);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->file->get('error', UPLOAD_ERR_OK) could return the type array which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
121
    }
122
123
    /**
124
     * Retrieve the filename sent by the client.
125
     *
126
     * @return string|null
127
     */
128 5
    public function getClientFilename()
129
    {
130 5
        return $this->file->get('name');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->file->get('name') also could return the type array which is incompatible with the documented return type null|string.
Loading history...
131
    }
132
133
    /**
134
     * Retrieve the media type sent by the client.
135
     *
136
     * @return string|null
137
     */
138 5
    public function getClientMediaType()
139
    {
140 5
        return $this->file->get('type');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->file->get('type') also could return the type array which is incompatible with the documented return type null|string.
Loading history...
141
    }
142
143
    /**
144
     * Validate the stream.
145
     *
146
     * @throws RuntimeException
147
     */
148 10
    private function validateStream()
149
    {
150 10
        if ($this->getError() !== UPLOAD_ERR_OK) {
151 1
            throw new RuntimeException('file contains errors');
152
        }
153
154 9
        if (!$this->stream->isReadable()) {
155 2
            throw new RuntimeException('file cannot be read');
156
        }
157 9
    }
158
}
159