1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\Application\Responses;
9:
10: use Nette;
11:
12:
13: 14: 15:
16: class FileResponse implements Nette\Application\IResponse
17: {
18: use Nette\SmartObject;
19:
20:
21: public $resuming = true;
22:
23:
24: private $file;
25:
26:
27: private $contentType;
28:
29:
30: private $name;
31:
32:
33: private $forceDownload;
34:
35:
36: 37: 38: 39: 40:
41: public function __construct($file, $name = null, $contentType = null, $forceDownload = true)
42: {
43: if (!is_file($file)) {
44: throw new Nette\Application\BadRequestException("File '$file' doesn't exist.");
45: }
46:
47: $this->file = $file;
48: $this->name = $name ? $name : basename($file);
49: $this->contentType = $contentType ? $contentType : 'application/octet-stream';
50: $this->forceDownload = $forceDownload;
51: }
52:
53:
54: 55: 56: 57:
58: public function getFile()
59: {
60: return $this->file;
61: }
62:
63:
64: 65: 66: 67:
68: public function getName()
69: {
70: return $this->name;
71: }
72:
73:
74: 75: 76: 77:
78: public function getContentType()
79: {
80: return $this->contentType;
81: }
82:
83:
84: 85: 86: 87:
88: public function send(Nette\Http\IRequest $httpRequest, Nette\Http\IResponse $httpResponse)
89: {
90: $httpResponse->setContentType($this->contentType);
91: $httpResponse->setHeader('Content-Disposition',
92: ($this->forceDownload ? 'attachment' : 'inline')
93: . '; filename="' . $this->name . '"'
94: . '; filename*=utf-8\'\'' . rawurlencode($this->name));
95:
96: $filesize = $length = filesize($this->file);
97: $handle = fopen($this->file, 'r');
98:
99: if ($this->resuming) {
100: $httpResponse->setHeader('Accept-Ranges', 'bytes');
101: if (preg_match('#^bytes=(\d*)-(\d*)\z#', $httpRequest->getHeader('Range'), $matches)) {
102: list(, $start, $end) = $matches;
103: if ($start === '') {
104: $start = max(0, $filesize - $end);
105: $end = $filesize - 1;
106:
107: } elseif ($end === '' || $end > $filesize - 1) {
108: $end = $filesize - 1;
109: }
110: if ($end < $start) {
111: $httpResponse->setCode(416);
112: return;
113: }
114:
115: $httpResponse->setCode(206);
116: $httpResponse->setHeader('Content-Range', 'bytes ' . $start . '-' . $end . '/' . $filesize);
117: $length = $end - $start + 1;
118: fseek($handle, $start);
119:
120: } else {
121: $httpResponse->setHeader('Content-Range', 'bytes 0-' . ($filesize - 1) . '/' . $filesize);
122: }
123: }
124:
125: $httpResponse->setHeader('Content-Length', $length);
126: while (!feof($handle) && $length > 0) {
127: echo $s = fread($handle, min(4000000, $length));
128: $length -= strlen($s);
129: }
130: fclose($handle);
131: }
132: }
133: