AudioStream::__construct()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 2
nop 2
dl 0
loc 13
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Audio Player
4
 *
5
 * This file is licensed under the Affero General Public License version 3 or
6
 * later. See the LICENSE.md file.
7
 *
8
 * @author Marcel Scherello <[email protected]>
9
 * @author Sebastian Doell <[email protected]>
10
 * @copyright 2016-2021 Marcel Scherello
11
 * @copyright 2015 Sebastian Doell
12
 */
13
 
14
namespace OCA\audioplayer\Http;
15
use \OC\Files\View;
0 ignored issues
show
Bug introduced by
The type \OC\Files\View was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
 
17
class AudioStream
18
{
19
    private $path = "";
20
    private $stream;
21
    private $iStart = -1;
22
    private $iEnd = -1;
23
    private $iSize = 0;
24
    private $mimeType = 0;
25
    private $buffer = 8192;
26
    private $mTime = 0;
27
    private $userView;
28
    private $isStream = false;
29
30
    public function __construct($filePath, $user = null)
31
    {
32
33
        if (is_null($user) || $user === '') {
34
            $user = \OC::$server->getUserSession()->getUser()->getUID();
35
        }
36
        $this->userView = new View('/' . $user . '/files/');
37
38
        $this->path = $filePath;
39
        $fileInfo = $this->userView->getFileInfo($filePath);
40
		$this -> mimeType = $fileInfo['mimetype'];
41
		$this -> mTime = $fileInfo['mtime'];
42
		$this -> iSize = $fileInfo['size'];
43
        //\OCP\Util::writeLog('audioplayer','path:'.$filePath,\OCP\Util::DEBUG);
44
45
	}
46
47
	/**
48
	 * Open stream
49
	 */
50
	private function openStream() {
51
		if (!($this -> stream = $this->userView->fopen($this -> path, 'rb'))) {
52
			die('Could not open stream for reading');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
53
		}
54
	}
55
56
	/**
57
	 * Set proper header to serve the video content
58
	 */
59
	private function setHeader() {
60
        header("Content-Type: " . $this->mimeType . "; charset=utf-8");
61
		header("Cache-Control: max-age=2592000, public");
62
		header("Expires: " . gmdate('D, d M Y H:i:s', time() + 2592000) . ' GMT');
63
		header("Last-Modified: " . gmdate('D, d M Y H:i:s', $this -> mTime) . ' GMT');
64
65
		$this -> iStart = 0;
66
		$this -> iEnd = $this -> iSize - 1;
67
68
		if (isset($_SERVER['HTTP_RANGE'])) {
69
			$c_end = $this -> iEnd;
70
			$this->isStream = true;
71
		
72
			list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
73
			
74
			if (strpos($range, ',') !== false) {
75
				http_response_code(416);
76
				header("Content-Range: bytes ".$this->iStart."-".$this->iEnd."/".$this->iSize);
77
				exit ;
78
			}
79
			if ($range === '-') {
80
				$c_start = $this -> iSize - substr($range, 1);
81
			} else {
82
				$range = explode('-', $range);
83
				$c_start = $range[0];
84
				$c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $c_end;
85
			}
86
			$c_end = ($c_end > $this -> iEnd) ? $this -> iEnd : $c_end;
87
			if ($c_start > $c_end || $c_start > $this -> iSize - 1 || $c_end >= $this -> iSize) {
88
				http_response_code(416);
89
				header("Content-Range: bytes ".$this->iStart."-".$this->iEnd."/".$this->iSize);
90
				exit ;
91
			}
92
			$this -> iStart = $c_start;
93
			$this -> iEnd = $c_end;
94
            $length = $c_end - $c_start + 1;
95
			if($this -> iStart > 0){
96
				fseek($this -> stream, $this -> iStart);
0 ignored issues
show
Bug introduced by
It seems like $this->iStart can also be of type string; however, parameter $offset of fseek() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

96
				fseek($this -> stream, /** @scrutinizer ignore-type */ $this -> iStart);
Loading history...
97
			}
98
            header("Accept-Ranges: bytes");
99
            header("Content-Length: $length");
100
			http_response_code(206);
101
			header("Content-Range: bytes ".$this->iStart."-".$this->iEnd."/".$this->iSize);
102
			//\OCP\Util::writeLog('audioplayer','SEQ:'.$this->iStart."-".$this->iEnd."/".$this->iSize.'length:'.$length,\OCP\Util::DEBUG);
103
		} else {
104
			header("Content-Length: " . $this -> iSize);
105
			$this->isStream = false;
106
			
107
		}
108
	}
109
110
	/**
111
	 * close opened stream
112
	 */
113
	private function closeStream() {
114
		fclose($this -> stream);
115
		exit ;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
116
	}
117
118
	/**
119
	 * perform the streaming
120
	 */
121
	private function stream() {
122
		if($this->isStream){
123
			//$data = stream_get_contents($this -> stream);
124
			//echo $data;
125
			
126
			$curPos = $this->iStart;
127
	        set_time_limit(0);
128
	        while(!feof($this->stream) && $curPos <= $this->iEnd) {
129
	           if( connection_aborted() || connection_status() !== 0 ) {
130
				   $this->closeStream();
131
			  	}
132
			    $bytesToRead = $this->buffer;
133
	            if(($curPos+$bytesToRead) > ($this->iEnd + 1)) {
134
	                $bytesToRead = $this->iEnd - $curPos + 1;
135
	            }
136
	            $data = fread($this->stream, $bytesToRead);
137
	            echo $data;
138
	            flush();
139
	            $curPos += strlen($data);
140
	        }
141
		}else{
142
			 \OC\Files\Filesystem::readfile($this -> path);
143
		}	
144
	}
145
146
	/**
147
	 * Start streaming video 
148
	 */
149
	public function start() {
150
		
151
		$this -> openStream();
152
		$this -> setHeader();
153
		$this -> stream();
154
		$this -> closeStream();		
155
	}
156
}