Passed
Push — master ( 998e10...1efe83 )
by Marcel
06:10
created

lib/Http/AudioStream.php (3 issues)

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
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
	private $path = "";
19
	private $stream;
20
	private $iStart = -1;
21
	private $iEnd = -1;
22
	private $iSize = 0;
23
	private $mimeType = 0;
24
	private $buffer = 8192;
25
	private $mTime = 0;
26
    private $userView ;
27
	private $isStream = false;
28
	
29
	public function __construct($filePath,$user=null) {
30
		
31
		if(is_null($user) || $user === ''){
32
			$user = \OC::$server->getUserSession()->getUser()->getUID();
33
		}
34
        $this->userView = new View('/' . $user . '/files/');
35
		
36
		$this -> path = $filePath;
37
		$fileInfo = $this->userView -> getFileInfo($filePath);
38
		$this -> mimeType = $fileInfo['mimetype'];
39
		$this -> mTime = $fileInfo['mtime'];
40
		$this -> iSize = $fileInfo['size'];
41
        //\OCP\Util::writeLog('audioplayer','path:'.$filePath,\OCP\Util::DEBUG);
42
43
	}
44
45
	/**
46
	 * Open stream
47
	 */
48
	private function openStream() {
49
		if (!($this -> stream = $this->userView->fopen($this -> path, 'rb'))) {
50
			die('Could not open stream for reading');
0 ignored issues
show
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...
51
		}
52
	}
53
54
	/**
55
	 * Set proper header to serve the video content
56
	 */
57
	private function setHeader() {
58
        header("Content-Type: " . $this->mimeType . "; charset=utf-8");
59
		header("Cache-Control: max-age=2592000, public");
60
		header("Expires: " . gmdate('D, d M Y H:i:s', time() + 2592000) . ' GMT');
61
		header("Last-Modified: " . gmdate('D, d M Y H:i:s', $this -> mTime) . ' GMT');
62
63
		$this -> iStart = 0;
64
		$this -> iEnd = $this -> iSize - 1;
65
66
		if (isset($_SERVER['HTTP_RANGE'])) {
67
			$c_end = $this -> iEnd;
68
			$this->isStream = true;
69
		
70
			list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
71
			
72
			if (strpos($range, ',') !== false) {
73
				header('HTTP/1.1 416 Requested Range Not Satisfiable');
74
				header("Content-Range: bytes ".$this->iStart."-".$this->iEnd."/".$this->iSize);
75
				exit ;
76
			}
77
			if ($range === '-') {
78
				$c_start = $this -> iSize - substr($range, 1);
79
			} else {
80
				$range = explode('-', $range);
81
				$c_start = $range[0];
82
				$c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $c_end;
83
			}
84
			$c_end = ($c_end > $this -> iEnd) ? $this -> iEnd : $c_end;
85
			if ($c_start > $c_end || $c_start > $this -> iSize - 1 || $c_end >= $this -> iSize) {
86
				header('HTTP/1.1 416 Requested Range Not Satisfiable');
87
				header("Content-Range: bytes ".$this->iStart."-".$this->iEnd."/".$this->iSize);
88
				exit ;
89
			}
90
			$this -> iStart = $c_start;
91
			$this -> iEnd = $c_end;
92
            $length = $c_end - $c_start + 1;
93
			if($this -> iStart > 0){
94
				fseek($this -> stream, $this -> iStart);
95
			}
96
            header("Accept-Ranges: bytes");
97
            header("Content-Length: $length");
98
			header('HTTP/1.1 206 Partial Content');
99
			header("Content-Range: bytes ".$this->iStart."-".$this->iEnd."/".$this->iSize);
100
			//\OCP\Util::writeLog('audioplayer','SEQ:'.$this->iStart."-".$this->iEnd."/".$this->iSize.'length:'.$length,\OCP\Util::DEBUG);
101
		} else {
102
			header("Content-Length: " . $this -> iSize);
103
			$this->isStream = false;
104
			
105
		}
106
	}
107
108
	/**
109
	 * close opened stream
110
	 */
111
	private function closeStream() {
112
		fclose($this -> stream);
113
		exit ;
0 ignored issues
show
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...
114
	}
115
116
	/**
117
	 * perform the streaming
118
	 */
119
	private function stream() {
120
		if($this->isStream){
121
			//$data = stream_get_contents($this -> stream);
122
			//echo $data;
123
			
124
			$curPos = $this->iStart;
125
	        set_time_limit(0);
126
	        while(!feof($this->stream) && $curPos <= $this->iEnd) {
127
	           if( connection_aborted() || connection_status() !== 0 ) {
128
				   $this->closeStream();
129
			  	}
130
			    $bytesToRead = $this->buffer;
131
	            if(($curPos+$bytesToRead) > ($this->iEnd + 1)) {
132
	                $bytesToRead = $this->iEnd - $curPos + 1;
133
	            }
134
	            $data = fread($this->stream, $bytesToRead);
135
	            echo $data;
136
	            flush();
137
	            $curPos += strlen($data);
138
	        }
139
		}else{
140
			 \OC\Files\Filesystem::readfile($this -> path);
141
		}	
142
	}
143
144
	/**
145
	 * Start streaming video 
146
	 */
147
	public function start() {
148
		
149
		$this -> openStream();
150
		$this -> setHeader();
151
		$this -> stream();
152
		$this -> closeStream();		
153
	}
154
}