AudioStream   A
last analyzed

Complexity

Total Complexity 25

Size/Duplication

Total Lines 138
Duplicated Lines 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
eloc 79
c 4
b 0
f 0
dl 0
loc 138
rs 10
wmc 25

6 Methods

Rating   Name   Duplication   Size   Complexity  
A start() 0 6 1
B stream() 0 22 7
A closeStream() 0 3 1
B setHeader() 0 47 11
A openStream() 0 3 2
A __construct() 0 13 3
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-2019 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 libasys
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 string $path = "";
20
    private $stream;
21
    private int $iStart = -1;
22
    private int $iEnd = -1;
23
    private $iSize = 0;
24
    private $mimeType = 0;
25
    private int $buffer = 8192;
26
    private $mTime = 0;
27
    private $userView;
28
    private bool $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 libasys
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 libasys
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 libasys
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
}