1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* ownCloud - Music app |
5
|
|
|
* |
6
|
|
|
* This file is licensed under the Affero General Public License version 3 or |
7
|
|
|
* later. See the COPYING file. |
8
|
|
|
* |
9
|
|
|
* @author Morris Jobke <[email protected]> |
10
|
|
|
* @copyright Morris Jobke 2013, 2014 |
11
|
|
|
*/ |
12
|
|
|
|
13
|
|
|
namespace OCA\Music\Http; |
14
|
|
|
|
15
|
|
|
use OCP\AppFramework\Http\Response; |
16
|
|
|
use OCP\AppFramework\Http; |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* A renderer for files |
20
|
|
|
*/ |
21
|
|
|
class FileResponse extends Response { |
22
|
|
|
|
23
|
|
|
protected $file; |
24
|
|
|
protected $start; |
25
|
|
|
protected $end; |
26
|
|
|
protected $rangeRequest; |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* @param \OC\Files\Node\File|array $file file |
30
|
|
|
* @param int $statusCode the Http status code, defaults to 200 |
31
|
|
|
*/ |
32
|
|
|
public function __construct($file, $statusCode=Http::STATUS_OK) { |
33
|
|
|
|
34
|
|
|
if (is_array($file)) { |
35
|
|
|
$this->file = $file['content']; |
36
|
|
|
$this->addHeader('Content-type', $file['mimetype'] .'; charset=utf-8'); |
37
|
|
|
} else { |
38
|
|
|
$this->file = $file; |
39
|
|
|
$this->addHeader('Content-type', $file->getMimetype() .'; charset=utf-8'); |
40
|
|
|
} |
41
|
|
|
if (isset($_SERVER['HTTP_RANGE'])) { |
42
|
|
|
$size = $file->getSize(); |
43
|
|
|
// Note that we do not support Range Header of the type |
44
|
|
|
// bytes=x-x,y-y |
45
|
|
|
if (!preg_match('/^bytes=\d*-\d*$/', $_SERVER['HTTP_RANGE'])) { |
46
|
|
|
$this->addHeader('Content-Range: bytes */' . $size); |
47
|
|
|
$this->setStatus(Http::STATUS_REQUEST_RANGE_NOT_SATISFIABLE); |
48
|
|
|
} else { |
49
|
|
|
$parts = explode('-', substr($_SERVER['HTTP_RANGE'], 6)); |
50
|
|
|
$this->start = $parts[0] != '' ? (int)$parts[0] : 0; |
51
|
|
|
$this->end = $parts[1] != '' ? (int)$parts[1] : $size; |
52
|
|
|
$this->end = $size < $this->end ? $size : $this->end; |
53
|
|
|
|
54
|
|
|
if ($this->start > $this->end) { |
55
|
|
|
$this->addHeader('Content-Range: bytes */' . $size); |
56
|
|
|
$this->setStatus(Http::STATUS_REQUEST_RANGE_NOT_SATISFIABLE); |
57
|
|
|
} else { |
58
|
|
|
$this->addHeader('Accept-Ranges', 'bytes'); |
59
|
|
|
$this->setStatus(Http::STATUS_PARTIAL_CONTENT); |
60
|
|
|
$this->rangeRequest = true; |
61
|
|
|
} |
62
|
|
|
} |
63
|
|
|
} else { |
64
|
|
|
$this->setStatus($statusCode); |
65
|
|
|
} |
66
|
|
|
} |
67
|
|
|
|
68
|
|
|
/** |
69
|
|
|
* Returns the rendered json |
70
|
|
|
* @return string the file |
71
|
|
|
*/ |
72
|
|
|
public function render(){ |
73
|
|
|
if (is_string($this->file)) { |
74
|
|
|
if ($this->rangeRequest) { |
75
|
|
|
// Request Range Not Satisfiable |
76
|
|
View Code Duplication |
if (!isset($this->start) && !isset($this->end) || $this->start > $this->end) { |
|
|
|
|
77
|
|
|
return null; |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
return substr($this->file, $this->start, $this->end - $this->start + 1); |
81
|
|
|
} |
82
|
|
|
return $this->file; |
83
|
|
|
} |
84
|
|
|
if ($this->rangeRequest) { |
85
|
|
|
// Request Range Not Satisfiable |
86
|
|
View Code Duplication |
if (!isset($this->start) && !isset($this->end) || $this->start > $this->end) { |
|
|
|
|
87
|
|
|
return null; |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
$handle = fopen('oc://' . $this->file->getPath(), 'r'); |
91
|
|
|
fseek($handle, $this->start); |
92
|
|
|
$content = ''; |
93
|
|
|
$rangeSize = $this->end - $this->start + 1; |
94
|
|
|
while(!feof($handle)) { |
95
|
|
|
$content .= fread($handle, 8192); // 8k chunk |
96
|
|
|
if (strlen($content) > $rangeSize) { |
97
|
|
|
$content = substr($content, $rangeSize); |
98
|
|
|
break; |
99
|
|
|
} |
100
|
|
|
} |
101
|
|
|
fclose($handle); |
102
|
|
|
return $content; |
103
|
|
|
} |
104
|
|
|
return $this->file->getContent(); |
105
|
|
|
} |
106
|
|
|
} |
107
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.