PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / trunk
Tutor LMS – eLearning and online course solution vtrunk
4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 4.0.2 4.0.1 4.0.0 3.9.15 3.9.14 3.9.13 3.9.12 3.9.11 trunk 1.0.0 1.0.0-alpha 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.2.0 1.2.1 1.2.11 1.2.12 1.2.13 1.2.20 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 1.8.10 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.14 1.9.15 1.9.16 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.10 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.1.1 2.1.10 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.3.0 2.4.0 2.5.0 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.1.0 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.7.0 3.7.1 3.7.2 3.7.3 3.7.4 3.8.0 3.8.1 3.8.2 3.8.3 3.9.0 3.9.1 3.9.10 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9
tutor / classes / Video_Stream.php
tutor / classes Last commit date
Addons.php 1 month ago Admin.php 1 month ago Ajax.php 5 days ago Announcements.php 1 month ago Assets.php 3 weeks ago Backend_Page_Trait.php 1 year ago BaseController.php 1 year ago Config.php 1 month ago Container.php 1 year ago Course.php 3 days ago Course_Embed.php 3 years ago Course_Filter.php 5 days ago Course_List.php 1 month ago Course_Settings_Tabs.php 1 month ago Course_Widget.php 1 year ago Custom_Validation.php 1 month ago Dashboard.php 1 month ago Earnings.php 10 months ago FormHandler.php 1 month ago Frontend.php 1 month ago Gutenberg.php 1 year ago Icon.php 1 week ago Input.php 1 month ago Instructor.php 1 month ago Instructors_List.php 1 month ago Lesson.php 5 days ago Options_V2.php 1 month ago Permalink.php 1 month ago Post_types.php 1 month ago Private_Course_Access.php 1 month ago Q_And_A.php 1 month ago Question_Answers_List.php 1 year ago Quiz.php 1 week ago QuizBuilder.php 1 week ago Quiz_Attempts_List.php 1 month ago RestAPI.php 1 month ago Reviews.php 1 month ago Rewrite_Rules.php 2 years ago SampleCourse.php 1 month ago Shortcode.php 1 month ago Singleton.php 1 year ago Student.php 1 month ago Students_List.php 1 year ago Taxonomies.php 1 year ago Template.php 1 month ago Theme_Compatibility.php 3 years ago Tools.php 1 year ago Tools_V2.php 2 months ago Tutor.php 5 days ago TutorEDD.php 1 month ago Tutor_Base.php 2 years ago Tutor_Setup.php 1 month ago Upgrader.php 1 month ago User.php 3 weeks ago UserPreference.php 1 month ago Utils.php 5 days ago Video_Stream.php 5 days ago WhatsNew.php 1 month ago Withdraw.php 1 month ago Withdraw_Requests_List.php 1 year ago WooCommerce.php 1 week ago
Video_Stream.php
252 lines
1 <?php
2 /**
3 * Video Stream
4 *
5 * @package Tutor\VideoStream
6 * @author Themeum <support@themeum.com>
7 * @link https://themeum.com
8 * @since 1.0.0
9 */
10
11 namespace TUTOR;
12
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit;
15 }
16
17
18 /**
19 * Class Video_Stream
20 *
21 * @since 1.0.0
22 */
23 class Video_Stream {
24
25 /**
26 * Path
27 *
28 * @since 1.0.0
29 *
30 * @var string
31 */
32 private $path = '';
33
34 /**
35 * Stream
36 *
37 * @since 1.0.0
38 *
39 * @var string
40 */
41 private $stream = '';
42
43 /**
44 * Buffer time
45 *
46 * @since 1.0.0
47 *
48 * @var string
49 */
50 private $buffer = 102400;
51
52 /**
53 * Start
54 *
55 * @since 1.0.0
56 *
57 * @var int
58 */
59 private $start = -1;
60
61 /**
62 * End
63 *
64 * @since 1.0.0
65 *
66 * @var int
67 */
68 private $end = -1;
69
70 /**
71 * Size
72 *
73 * @since 1.0.0
74 *
75 * @var int
76 */
77 private $size = 0;
78
79 /**
80 * Video format
81 *
82 * @since 1.0.0
83 *
84 * @var string
85 */
86 private $video_format;
87
88 /**
89 * Resolve dependencies
90 *
91 * @since 1.0.0
92 *
93 * @param string $file_path file path.
94 */
95 public function __construct( $file_path ) {
96 $this->video_format = apply_filters(
97 'tutor_video_types',
98 array(
99 'mp4' => 'video/mp4',
100 'webm' => 'video/webm',
101 'ogg' => 'video/ogg',
102 )
103 );
104 $this->path = $file_path;
105 }
106
107 /**
108 * Whether the file is a real video inside the uploads directory.
109 *
110 * @since 4.0.2
111 *
112 * @param string $file_path file path.
113 *
114 * @return bool
115 */
116 private function is_allowed_path( $file_path ) {
117 $real_file = $file_path ? realpath( $file_path ) : false;
118 if ( ! $real_file || ! is_file( $real_file ) ) {
119 return false;
120 }
121
122 $uploads = wp_get_upload_dir();
123 $real_uploads = ! empty( $uploads['basedir'] ) ? realpath( $uploads['basedir'] ) : false;
124 if ( ! $real_uploads ) {
125 return false;
126 }
127
128 $real_file = wp_normalize_path( $real_file );
129 $real_uploads = trailingslashit( wp_normalize_path( $real_uploads ) );
130 $is_allowed = 0 === strpos( $real_file, $real_uploads );
131
132 return (bool) apply_filters( 'tutor_video_stream_is_allowed_path', $is_allowed, $real_file );
133 }
134
135 /**
136 * Open stream
137 *
138 * @since 1.0.0
139 *
140 * @return void
141 */
142 private function open() {
143 $this->stream = fopen( $this->path, 'rb' );
144 if ( ! ( $this->stream ) ) {
145 die( 'Could not open stream for reading' );
146 }
147 }
148
149 /**
150 * Set proper header to serve the video content
151 *
152 * @since 1.0.0
153 *
154 * @return void
155 */
156 private function set_header() {
157 ob_get_clean();
158
159 header( 'Content-Type: ' . $this->video_format[ strtolower( pathinfo( $this->path, PATHINFO_EXTENSION ) ) ] );
160 header( 'Cache-Control: max-age=2592000, public' );
161 header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', tutor_time() + 2592000 ) . ' GMT' );
162 header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s', @filemtime( $this->path ) ) . ' GMT' );
163 $this->start = 0;
164 $this->size = filesize( $this->path );
165 $this->end = $this->size - 1;
166 header( 'Accept-Ranges: 0-' . $this->end );
167
168 if ( isset( $_SERVER['HTTP_RANGE'] ) ) {
169 $c_end = $this->end;
170 list(, $range) = explode( '=', sanitize_text_field( wp_unslash( $_SERVER['HTTP_RANGE'] ) ), 2 );
171
172 if ( '-' == $range ) {
173 $c_start = $this->size - substr( $range, 1 );
174 } else {
175 $range = explode( '-', $range );
176 $c_start = $range[0];
177
178 $c_end = ( isset( $range[1] ) && is_numeric( $range[1] ) ) ? $range[1] : $c_end;
179 }
180 $c_end = ( $c_end > $this->end ) ? $this->end : $c_end;
181 if ( $c_start > $c_end || $c_start > $this->size - 1 || $c_end >= $this->size ) {
182 header( 'HTTP/1.1 416 Requested Range Not Satisfiable' );
183 header( "Content-Range: bytes $this->start-$this->end/$this->size" );
184 exit;
185 }
186 $this->start = $c_start;
187 $this->end = $c_end;
188 $length = $this->end - $this->start + 1;
189 header( 'HTTP/1.1 206 Partial Content' );
190 header( 'Content-Length: ' . $length );
191 header( "Content-Range: bytes $this->start-$this->end/" . $this->size );
192 header( 'Accept-Ranges: bytes' );
193 } else {
194 header( 'Content-Length: ' . $this->size );
195 }
196
197 }
198
199 /**
200 * Close currently opened stream
201 *
202 * @since 1.0.0
203 *
204 * @return void
205 */
206 private function end() {
207 fclose( $this->stream );
208 exit;
209 }
210
211 /**
212 * Perform the streaming of calculated range
213 *
214 * @since 1.0.0
215 *
216 * @return void
217 */
218 private function stream() {
219 $i = $this->start;
220 set_time_limit( 0 );
221 while ( ! feof( $this->stream ) && $i <= $this->end ) {
222 $bytes_to_read = $this->buffer;
223 if ( ( $i + $bytes_to_read ) > $this->end ) {
224 $bytes_to_read = $this->end - $i + 1;
225 }
226 $data = @stream_get_contents( $this->stream, $bytes_to_read, $i );
227 echo wp_kses_post( $data );
228 flush();
229 $i += $bytes_to_read;
230 }
231 }
232
233 /**
234 * Start streaming tutor video content
235 *
236 * @since 1.0.0
237 *
238 * @return void
239 */
240 public function start() {
241 if ( ! $this->is_allowed_path( $this->path ) ) {
242 status_header( 403 );
243 exit;
244 }
245
246 $this->open();
247 $this->set_header();
248 $this->stream();
249 $this->end();
250 }
251 }
252