• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nette / http / 12735233527

12 Jan 2025 04:27PM UTC coverage: 83.456%. Remained the same
12735233527

push

github

dg
FileUpload::__construct() accepts path

8 of 8 new or added lines in 1 file covered. (100.0%)

20 existing lines in 3 files now uncovered.

908 of 1088 relevant lines covered (83.46%)

0.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.13
/src/Http/FileUpload.php
1
<?php
2

3
/**
4
 * This file is part of the Nette Framework (https://nette.org)
5
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6
 */
7

8
declare(strict_types=1);
9

10
namespace Nette\Http;
11

12
use Nette;
13
use Nette\Utils\Image;
14

15

16
/**
17
 * Provides access to individual files that have been uploaded by a client.
18
 *
19
 * @property-read string $name
20
 * @property-read string $sanitizedName
21
 * @property-read string $untrustedFullPath
22
 * @property-read string|null $contentType
23
 * @property-read int $size
24
 * @property-read string $temporaryFile
25
 * @property-read int $error
26
 * @property-read bool $ok
27
 * @property-read string|null $contents
28
 */
29
final class FileUpload
30
{
31
        use Nette\SmartObject;
32

33
        /** @deprecated */
34
        public const IMAGE_MIME_TYPES = ['image/gif', 'image/png', 'image/jpeg', 'image/webp'];
35

36
        private readonly string $name;
37
        private readonly ?string $fullPath;
38
        private string|false|null $type = null;
39
        private string|false|null $extension = null;
40
        private readonly int $size;
41
        private string $tmpName;
42
        private readonly int $error;
43

44

45
        public function __construct(array|string|null $value)
1✔
46
        {
47
                if (is_string($value)) {
1✔
48
                        $value = [
1✔
49
                                'name' => basename($value),
1✔
50
                                'full_path' => $value,
1✔
51
                                'size' => filesize($value),
1✔
52
                                'tmp_name' => $value,
1✔
53
                                'error' => UPLOAD_ERR_OK,
1✔
54
                        ];
55
                }
56

57
                $this->name = $value['name'] ?? '';
1✔
58
                $this->fullPath = $value['full_path'] ?? null;
1✔
59
                $this->size = $value['size'] ?? 0;
1✔
60
                $this->tmpName = $value['tmp_name'] ?? '';
1✔
61
                $this->error = $value['error'] ?? UPLOAD_ERR_NO_FILE;
1✔
62
        }
1✔
63

64

65
        /**
66
         * @deprecated use getUntrustedName()
67
         */
68
        public function getName(): string
69
        {
70
                return $this->name;
1✔
71
        }
72

73

74
        /**
75
         * Returns the original file name as submitted by the browser. Do not trust the value returned by this method.
76
         * A client could send a malicious filename with the intention to corrupt or hack your application.
77
         */
78
        public function getUntrustedName(): string
79
        {
80
                return $this->name;
1✔
81
        }
82

83

84
        /**
85
         * Returns the sanitized file name. The resulting name contains only ASCII characters [a-zA-Z0-9.-].
86
         * If the name does not contain such characters, it returns 'unknown'. If the file is an image supported by PHP,
87
         * it returns the correct file extension. Do not blindly trust the value returned by this method.
88
         */
89
        public function getSanitizedName(): string
90
        {
91
                $name = Nette\Utils\Strings::webalize($this->name, '.', lower: false);
1✔
92
                $name = str_replace(['-.', '.-'], '.', $name);
1✔
93
                $name = trim($name, '.-');
1✔
94
                $name = $name === '' ? 'unknown' : $name;
1✔
95
                if ($this->isImage()) {
1✔
96
                        $name = preg_replace('#\.[^.]+$#D', '', $name);
1✔
97
                        $name .= '.' . $this->getSuggestedExtension();
1✔
98
                }
99

100
                return $name;
1✔
101
        }
102

103

104
        /**
105
         * Returns the original full path as submitted by the browser during directory upload. Do not trust the value
106
         * returned by this method. A client could send a malicious directory structure with the intention to corrupt
107
         * or hack your application.
108
         *
109
         * The full path is only available in PHP 8.1 and above. In previous versions, this method returns the file name.
110
         */
111
        public function getUntrustedFullPath(): string
112
        {
113
                return $this->fullPath ?? $this->name;
1✔
114
        }
115

116

117
        /**
118
         * Detects the MIME content type of the uploaded file based on its signature. Requires PHP extension fileinfo.
119
         * If the upload was not successful or the detection failed, it returns null.
120
         */
121
        public function getContentType(): ?string
122
        {
123
                if ($this->isOk()) {
1✔
124
                        $this->type ??= finfo_file(finfo_open(FILEINFO_MIME_TYPE), $this->tmpName);
1✔
125
                }
126

127
                return $this->type ?: null;
1✔
128
        }
129

130

131
        /**
132
         * Returns the appropriate file extension (without the period) corresponding to the detected MIME type. Requires the PHP extension fileinfo.
133
         */
134
        public function getSuggestedExtension(): ?string
135
        {
136
                if ($this->isOk() && $this->extension === null) {
1✔
137
                        $exts = finfo_file(finfo_open(FILEINFO_EXTENSION), $this->tmpName);
1✔
138
                        if ($exts && $exts !== '???') {
1✔
139
                                return $this->extension = preg_replace('~[/,].*~', '', $exts);
1✔
140
                        }
141
                        [, , $type] = @getimagesize($this->tmpName); // @ - files smaller than 12 bytes causes read error
1✔
142
                        if ($type) {
1✔
UNCOV
143
                                return $this->extension = image_type_to_extension($type, false);
×
144
                        }
145
                        $this->extension = false;
1✔
146
                }
147

148
                return $this->extension ?: null;
1✔
149
        }
150

151

152
        /**
153
         * Returns the size of the uploaded file in bytes.
154
         */
155
        public function getSize(): int
156
        {
157
                return $this->size;
1✔
158
        }
159

160

161
        /**
162
         * Returns the path of the temporary location of the uploaded file.
163
         */
164
        public function getTemporaryFile(): string
165
        {
166
                return $this->tmpName;
1✔
167
        }
168

169

170
        /**
171
         * Returns the path of the temporary location of the uploaded file.
172
         */
173
        public function __toString(): string
174
        {
175
                return $this->tmpName;
1✔
176
        }
177

178

179
        /**
180
         * Returns the error code. It has to be one of UPLOAD_ERR_XXX constants.
181
         * @see http://php.net/manual/en/features.file-upload.errors.php
182
         */
183
        public function getError(): int
184
        {
185
                return $this->error;
1✔
186
        }
187

188

189
        /**
190
         * Returns true if the file was uploaded successfully.
191
         */
192
        public function isOk(): bool
193
        {
194
                return $this->error === UPLOAD_ERR_OK;
1✔
195
        }
196

197

198
        /**
199
         * Returns true if the user has uploaded a file.
200
         */
201
        public function hasFile(): bool
202
        {
203
                return $this->error !== UPLOAD_ERR_NO_FILE;
1✔
204
        }
205

206

207
        /**
208
         * Moves an uploaded file to a new location. If the destination file already exists, it will be overwritten.
209
         */
210
        public function move(string $dest): static
211
        {
UNCOV
212
                $dir = dirname($dest);
×
UNCOV
213
                Nette\Utils\FileSystem::createDir($dir);
×
UNCOV
214
                @unlink($dest); // @ - file may not exists
×
215
                Nette\Utils\Callback::invokeSafe(
×
216
                        is_uploaded_file($this->tmpName) ? 'move_uploaded_file' : 'rename',
×
217
                        [$this->tmpName, $dest],
×
218
                        function (string $message) use ($dest): void {
×
219
                                throw new Nette\InvalidStateException("Unable to move uploaded file '$this->tmpName' to '$dest'. $message");
220
                        },
×
221
                );
UNCOV
222
                @chmod($dest, 0o666); // @ - possible low permission to chmod
×
223
                $this->tmpName = $dest;
×
UNCOV
224
                return $this;
×
225
        }
226

227

228
        /**
229
         * Returns true if the uploaded file is an image and the format is supported by PHP, so it can be loaded using the toImage() method.
230
         * Detection is based on its signature, the integrity of the file is not checked. Requires PHP extensions fileinfo & gd.
231
         */
232
        public function isImage(): bool
233
        {
234
                $types = array_map(fn($type) => Image::typeToMimeType($type), Image::getSupportedTypes());
1✔
235
                return in_array($this->getContentType(), $types, strict: true);
1✔
236
        }
237

238

239
        /**
240
         * Converts uploaded image to Nette\Utils\Image object.
241
         * @throws Nette\Utils\ImageException  If the upload was not successful or is not a valid image
242
         */
243
        public function toImage(): Image
244
        {
UNCOV
245
                return Image::fromFile($this->tmpName);
×
246
        }
247

248

249
        /**
250
         * Returns a pair of [width, height] with dimensions of the uploaded image.
251
         */
252
        public function getImageSize(): ?array
253
        {
254
                return $this->isImage()
1✔
255
                        ? array_intersect_key(getimagesize($this->tmpName), [0, 1])
1✔
256
                        : null;
1✔
257
        }
258

259

260
        /**
261
         * Returns image file extension based on detected content type (without dot).
262
         * @deprecated use getSuggestedExtension()
263
         */
264
        public function getImageFileExtension(): ?string
265
        {
UNCOV
266
                return $this->getSuggestedExtension();
×
267
        }
268

269

270
        /**
271
         * Returns the contents of the uploaded file. If the upload was not successful, it returns null.
272
         */
273
        public function getContents(): ?string
274
        {
275
                // future implementation can try to work around safe_mode and open_basedir limitations
276
                return $this->isOk()
1✔
277
                        ? file_get_contents($this->tmpName)
1✔
278
                        : null;
1✔
279
        }
280
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc