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

nette / application / 20834855301

08 Jan 2026 10:54PM UTC coverage: 84.605% (+1.7%) from 82.856%
20834855301

push

github

dg
added CLAUDE.md

1940 of 2293 relevant lines covered (84.61%)

0.85 hits per line

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

88.1
/src/Application/Responses/FileResponse.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\Application\Responses;
11

12
use Nette;
13
use function strlen;
14

15

16
/**
17
 * File download response.
18
 */
19
final class FileResponse implements Nette\Application\Response
20
{
21
        public bool $resuming = true;
22
        private readonly string $name;
23

24

25
        public function __construct(
1✔
26
                private readonly string $file,
27
                ?string $name = null,
28
                private readonly string $contentType = 'application/octet-stream',
29
                private readonly bool $forceDownload = true,
30
        ) {
31
                if (!is_file($file) || !is_readable($file)) {
1✔
32
                        throw new Nette\Application\BadRequestException("File '$file' doesn't exist or is not readable.");
×
33
                }
34

35
                $this->name = $name ?? basename($file);
1✔
36
        }
1✔
37

38

39
        /**
40
         * Returns the path to a downloaded file.
41
         */
42
        public function getFile(): string
43
        {
44
                return $this->file;
×
45
        }
46

47

48
        /**
49
         * Returns the file name.
50
         */
51
        public function getName(): string
52
        {
53
                return $this->name;
×
54
        }
55

56

57
        /**
58
         * Returns the MIME content type of a downloaded file.
59
         */
60
        public function getContentType(): string
61
        {
62
                return $this->contentType;
×
63
        }
64

65

66
        /**
67
         * Sends response to output.
68
         */
69
        public function send(Nette\Http\IRequest $httpRequest, Nette\Http\IResponse $httpResponse): void
1✔
70
        {
71
                $httpResponse->setContentType($this->contentType);
1✔
72
                $httpResponse->setHeader(
1✔
73
                        'Content-Disposition',
1✔
74
                        ($this->forceDownload ? 'attachment' : 'inline')
1✔
75
                                . '; filename="' . $this->name . '"'
1✔
76
                                . '; filename*=utf-8\'\'' . rawurlencode($this->name),
1✔
77
                );
78

79
                $filesize = $length = filesize($this->file);
1✔
80
                $handle = fopen($this->file, 'r');
1✔
81
                if (!$handle) {
1✔
82
                        throw new Nette\Application\BadRequestException("Cannot open file: '{$this->file}'.");
×
83
                }
84

85
                if ($this->resuming) {
1✔
86
                        $httpResponse->setHeader('Accept-Ranges', 'bytes');
1✔
87
                        if (preg_match('#^bytes=(\d*)-(\d*)$#D', (string) $httpRequest->getHeader('Range'), $matches)) {
1✔
88
                                [, $start, $end] = $matches;
1✔
89
                                if ($start === '') {
1✔
90
                                        $start = max(0, $filesize - $end);
1✔
91
                                        $end = $filesize - 1;
1✔
92

93
                                } elseif ($end === '' || $end > $filesize - 1) {
1✔
94
                                        $end = $filesize - 1;
1✔
95
                                }
96

97
                                if ($end < $start) {
1✔
98
                                        $httpResponse->setCode(416); // requested range not satisfiable
1✔
99
                                        return;
1✔
100
                                }
101

102
                                $httpResponse->setCode(206);
1✔
103
                                $httpResponse->setHeader('Content-Range', 'bytes ' . $start . '-' . $end . '/' . $filesize);
1✔
104
                                $length = $end - $start + 1;
1✔
105
                                fseek($handle, (int) $start);
1✔
106

107
                        } else {
108
                                $httpResponse->setHeader('Content-Range', 'bytes 0-' . ($filesize - 1) . '/' . $filesize);
1✔
109
                        }
110
                }
111

112
                $httpResponse->setHeader('Content-Length', (string) $length);
1✔
113
                while (!feof($handle) && $length > 0) {
1✔
114
                        echo $s = fread($handle, min(4_000_000, $length));
1✔
115
                        $length -= strlen($s);
1✔
116
                }
117

118
                fclose($handle);
1✔
119
        }
1✔
120
}
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