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

nette / http / 21830508055

09 Feb 2026 03:10PM UTC coverage: 83.772% (+0.03%) from 83.744%
21830508055

push

github

dg
added RequestFactory::setForceHttps()

8 of 9 new or added lines in 2 files covered. (88.89%)

75 existing lines in 9 files now uncovered.

924 of 1103 relevant lines covered (83.77%)

0.84 hits per line

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

77.78
/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
use function array_intersect_key, array_map, basename, chmod, dirname, file_get_contents, filesize, finfo_file, finfo_open, getimagesize, image_type_to_extension, in_array, is_string, is_uploaded_file, preg_replace, str_replace, trim, unlink;
15
use const FILEINFO_EXTENSION, FILEINFO_MIME_TYPE, UPLOAD_ERR_NO_FILE, UPLOAD_ERR_OK;
16

17

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

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

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

46

47
        /** @param array{name?: string, full_path?: string, size?: int, tmp_name?: string, error?: int, type?: string}|string|null  $value */
48
        public function __construct(array|string|null $value)
1✔
49
        {
50
                if (is_string($value)) {
1✔
51
                        $value = [
1✔
52
                                'name' => basename($value),
1✔
53
                                'full_path' => $value,
1✔
54
                                'size' => filesize($value),
1✔
55
                                'tmp_name' => $value,
1✔
56
                                'error' => UPLOAD_ERR_OK,
57
                        ];
58
                }
59

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

67

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

76

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

86

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

103
                return $name;
1✔
104
        }
105

106

107
        /**
108
         * Returns the original full path as submitted by the browser during directory upload. Do not trust the value
109
         * returned by this method. A client could send a malicious directory structure with the intention to corrupt
110
         * or hack your application.
111
         */
112
        public function getUntrustedFullPath(): string
113
        {
114
                return $this->fullPath ?? $this->name;
1✔
115
        }
116

117

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

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

131

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

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

152

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

161

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

170

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

179

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

189

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

198

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

207

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

228

229
        /**
230
         * 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.
231
         * Detection is based on its signature, the integrity of the file is not checked. Requires PHP extensions fileinfo & gd.
232
         */
233
        public function isImage(): bool
234
        {
235
                $types = array_map(Image::typeToMimeType(...), Image::getSupportedTypes());
1✔
236
                return in_array($this->getContentType(), $types, strict: true);
1✔
237
        }
238

239

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

249

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

261

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

271

272
        /**
273
         * Returns the contents of the uploaded file. If the upload was not successful, it returns null.
274
         */
275
        public function getContents(): ?string
276
        {
277
                // future implementation can try to work around safe_mode and open_basedir limitations
278
                return $this->isOk()
1✔
279
                        ? file_get_contents($this->tmpName)
1✔
280
                        : null;
1✔
281
        }
282
}
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