PluginProbe
WpStream – Live Streaming, Video on Demand, Pay Per View / 4.8.7
WpStream – Live Streaming, Video on Demand, Pay Per View v4.8.7
4.14.1 4.14.0 4.13.2 4.13.1 4.13 4.12.5 4.12.4 4.12.3 4.12.2 4.12.1 4.12 4.4.4 4.4.5 4.4.6 4.4.7 4.4.8 4.4.9 4.5 4.5.1 4.5.11 4.5.11.1 4.5.11.2 4.5.11.4 4.5.11.5 4.5.11.6 All 181 releases
wpstream / streamify / streamify.php

streamify.php in WpStream – Live Streaming, Video on Demand, Pay Per View 4.8.7, at streamify/streamify.php

441 lines 15.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 define('WPSTREAMIFY_CACHE_DIR', WP_CONTENT_DIR . '/uploads/wpstreamify_cache/');
4
5 function wpstreamify_register_query_vars($vars) {
6 $vars[] = 'wpstreamify_path';
7 return $vars;
8 }
9 add_filter('query_vars', 'wpstreamify_register_query_vars');
10
11 function wpstreamify_proxy_handler() {
12 $path = get_query_var('wpstreamify_path');
13 if (!$path) {
14 return;
15 }
16
17 $originHost = 'https://basicstreaming.wpstream.live/';
18 $remoteUrl = $originHost . $path;
19 $cacheFile = WPSTREAMIFY_CACHE_DIR . basename($path);
20 $fileExtension = pathinfo($path, PATHINFO_EXTENSION);
21
22 if ($fileExtension === 'ts' || $fileExtension === 'm3u8') {
23 wpstreamify_process_hls_request($fileExtension, $cacheFile, $remoteUrl);
24 } else {
25 wpstreamify_serve_404();
26 }
27 }
28
29 function wpstreamify_process_hls_request($fileExtension, $cacheFile, $remoteUrl) {
30 if (file_exists($cacheFile)) {
31 if ($fileExtension === 'm3u8' && wpstreamify_file_is_expired($cacheFile, 2)) {
32 if (!@unlink($cacheFile)) {
33 error_log(sprintf(
34 'wpstreamify_process_hls_request: Failed to delete expired cache file: %s',
35 $cacheFile
36 ));
37 }
38 } else {
39 wpstreamify_serve_cached_file($fileExtension, $cacheFile, 'HIT');
40 exit;
41 }
42 }
43
44 $lockFile = $cacheFile . '.lock';
45 if (file_exists($lockFile)){
46 wpstreamify_wait_for_lock($lockFile, $cacheFile, $fileExtension);
47 wpstreamify_serve_cached_file($fileExtension, $cacheFile, 'WAIT');
48 exit;
49 }
50 else if (wpstreamify_fetch_and_cache_file($lockFile, $cacheFile, $remoteUrl)) {
51 wpstreamify_serve_cached_file($fileExtension, $cacheFile, 'MISS');
52 } else {
53 wpstreamify_serve_500();
54 }
55 exit;
56 }
57
58 function wpstreamify_file_is_expired($filePath, $expirySeconds) {
59 $lastModified = filemtime($filePath);
60 if ($lastModified === false) {
61 error_log(sprintf(
62 'wpstreamify_file_is_expired: Failed to retrieve last modified time for file: %s',
63 $filePath
64 ));
65 return true; // Consider files with unknown modification time as expired
66 }
67 $currentTime = time();
68 return ($currentTime - $lastModified) > $expirySeconds;
69 }
70
71 function wpstreamify_wait_for_lock($lockFile, $cacheFile, $fileExtension) {
72 $cycles = 0;
73 while (file_exists($lockFile) && $cycles++ <= 200) {
74 usleep(100 * 1000);
75 }
76 if (file_exists($cacheFile)) {
77 return true;
78 }
79 else {
80 error_log(sprintf(
81 'wpstreamify_wait_for_lock: Cached file not found after waiting for lock: %s, Lock file: %s',
82 $cacheFile,
83 $lockFile
84 ));
85 return false;
86 }
87 }
88
89 function wpstreamify_serve_cached_file($fileExtension, $cacheFile, $cacheStatus) {
90 header("Access-Control-Allow-Origin: *");
91 header("Access-Control-Allow-Methods: GET, OPTIONS");
92 header("Access-Control-Allow-Headers: Content-Type, Authorization");
93
94 if (!file_exists($cacheFile)) {
95 error_log(sprintf(
96 'wpstreamify_serve_cached_file: Cache file does not exist: %s',
97 $cacheFile
98 ));
99 wpstreamify_serve_404();
100 exit;
101 }
102
103 if (!is_readable($cacheFile)) {
104 error_log(sprintf(
105 'wpstreamify_serve_cached_file: Cache file is not readable: %s',
106 $cacheFile
107 ));
108 wpstreamify_serve_500();
109 exit;
110 }
111
112 if ($fileExtension === 'ts') {
113 header('Content-Type: video/mp2t');
114 header('Cache-Control: public, max-age=300');
115 header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 300) . ' GMT');
116 } elseif ($fileExtension === 'm3u8') {
117 header('Content-Type: application/vnd.apple.mpegurl');
118 header('Cache-Control: public, max-age=2, must-revalidate');
119 header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 2) . ' GMT');
120 }
121
122 header("WPS-Cache-Status: $cacheStatus");
123 status_header(200);
124 $lastModified = filemtime($cacheFile);
125 if ($lastModified === false) {
126 error_log(sprintf(
127 'wpstreamify_serve_cached_file: Failed to retrieve last modified time for cache file: %s',
128 $cacheFile
129 ));
130 wpstreamify_serve_500();
131 exit;
132 }
133 header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $lastModified) . ' GMT');
134
135 if (!@readfile($cacheFile)) {
136 error_log(sprintf(
137 'wpstreamify_serve_cached_file: Failed to read and output cache file: %s',
138 $cacheFile
139 ));
140 wpstreamify_serve_500();
141 exit;
142 }
143 }
144
145
146 function wpstreamify_fetch_and_cache_file($lockFile, $cacheFile, $remoteUrl) {
147 ignore_user_abort(true);
148
149 $lockHandle = fopen($lockFile, 'w');
150 if (!$lockHandle) {
151 error_log(sprintf(
152 'wpstreamify_fetch_and_cache_file: Failed to create or open lock file: %s',
153 $lockFile
154 ));
155 return false;
156 }
157
158 if (flock($lockHandle, LOCK_EX)) {
159 try {
160 $response = wpstreamify_fetch_remote_content($remoteUrl);
161
162 if ($response === false) {
163 error_log(sprintf(
164 'wpstreamify_fetch_and_cache_file: Failed to fetch content from remote URL: %s',
165 $remoteUrl
166 ));
167 } else {
168 if (file_put_contents($cacheFile, $response) === false) {
169 error_log(sprintf(
170 'wpstreamify_fetch_and_cache_file: Failed to write content to cache file: %s',
171 $cacheFile
172 ));
173 }
174 }
175 } catch (Exception $e) {
176 error_log(sprintf(
177 'wpstreamify_fetch_and_cache_file: Exception during fetch and cache process. Remote URL: %s, Error: %s',
178 $remoteUrl,
179 $e->getMessage()
180 ));
181 } finally {
182 flock($lockHandle, LOCK_UN);
183 fclose($lockHandle);
184 if (!@unlink($lockFile)) {
185 error_log(sprintf(
186 'wpstreamify_fetch_and_cache_file: Failed to delete lock file: %s',
187 $lockFile
188 ));
189 }
190 }
191 return true;
192 }
193 else {
194 error_log(sprintf(
195 'wpstreamify_fetch_and_cache_file: Failed to acquire lock on file: %s',
196 $lockFile
197 ));
198 if (!@unlink($lockFile)) {
199 error_log(sprintf(
200 'wpstreamify_fetch_and_cache_file: Failed to delete lock file after failing to acquire lock: %s',
201 $lockFile
202 ));
203 }
204 return false;
205 }
206 }
207
208 function wpstreamify_serve_404() {
209 status_header(404);
210 header('HTTP/1.1 404 Not Found');
211 echo 'Resource not found...';
212 exit;
213 }
214
215 function wpstreamify_serve_500() {
216 status_header(500);
217 header('HTTP/1.1 500 Internal Server Error');
218 echo 'An unexpected error occurred.';
219 exit;
220 }
221
222 add_action('template_redirect', 'wpstreamify_proxy_handler');
223
224 function wpstreamify_fetch_remote_content($url) {
225 $ch = curl_init();
226
227 if ($ch === false) {
228 error_log(sprintf(
229 'wpstreamify_fetch_remote_content: Failed to initialize cURL for URL: %s',
230 $url
231 ));
232 return false;
233 }
234
235 curl_setopt($ch, CURLOPT_URL, $url);
236 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
237 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
238 curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
239 curl_setopt($ch, CURLOPT_USERAGENT, "WpStreamIfy/1.0");
240 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
241 curl_setopt($ch, CURLOPT_TIMEOUT, 15);
242
243 $response = curl_exec($ch);
244
245 if ($response === false) {
246 error_log(sprintf(
247 'wpstreamify_fetch_remote_content: cURL error for URL: %s. Error: %s',
248 $url,
249 curl_error($ch)
250 ));
251 } else {
252 $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
253 if ($httpCode >= 400) {
254 error_log(sprintf(
255 'wpstreamify_fetch_remote_content: HTTP error for URL: %s. Status Code: %d',
256 $url,
257 $httpCode
258 ));
259 $response = false;
260 }
261 }
262
263 curl_close($ch);
264 return $response;
265 }
266
267
268 define('WPSTREAMIFY_CACHE_CLEANUP_THRESHOLD', 300);
269
270 function wpstreamify_custom_cron_intervals($schedules) {
271 $schedules['every_ten_minutes'] = array(
272 'interval' => 600,
273 'display' => __('Every 10 Minutes')
274 );
275 return $schedules;
276 }
277 add_filter('cron_schedules', 'wpstreamify_custom_cron_intervals');
278
279 function wpstreamify_delete_old_hls_files() {
280 if (!defined('WPSTREAMIFY_CACHE_DIR') || !is_dir(WPSTREAMIFY_CACHE_DIR)) {
281 error_log('wpstreamify_delete_old_hls_files: Cache directory is not defined or does not exist.');
282 return;
283 }
284
285 $current_time = time();
286 $files = glob(WPSTREAMIFY_CACHE_DIR . '*');
287
288 if ($files === false) {
289 error_log('wpstreamify_delete_old_hls_files: Failed to read cache directory: ' . WPSTREAMIFY_CACHE_DIR);
290 return;
291 }
292
293 foreach ($files as $file) {
294 if (is_file($file)) {
295 $file_modification_time = filemtime($file);
296 if ($file_modification_time === false) {
297 error_log(sprintf(
298 'wpstreamify_delete_old_hls_files: Failed to get modification time for file: %s',
299 $file
300 ));
301 continue;
302 }
303
304 if ($current_time - $file_modification_time > WPSTREAMIFY_CACHE_CLEANUP_THRESHOLD) {
305 if (!unlink($file)) {
306 error_log(sprintf(
307 'wpstreamify_delete_old_hls_files: Failed to delete file: %s',
308 $file
309 ));
310 }
311 }
312 } else {
313 error_log(sprintf(
314 'wpstreamify_delete_old_hls_files: Skipped non-file entry: %s',
315 $file
316 ));
317 }
318 }
319 }
320
321
322 function wpstreamify_schedule_cleanup_event() {
323 if (!wp_next_scheduled('wpstreamify_cleanup_event')) {
324 if (!wp_schedule_event(time(), 'every_ten_minutes', 'wpstreamify_cleanup_event')) {
325 error_log('wpstreamify_schedule_cleanup_event: Failed to schedule cleanup event.');
326 }
327 }
328 }
329 add_action('wp', 'wpstreamify_schedule_cleanup_event');
330
331 add_action('wpstreamify_cleanup_event', 'wpstreamify_delete_old_hls_files');
332
333 function wpstreamify_unschedule_cleanup_event() {
334 $timestamp = wp_next_scheduled('wpstreamify_cleanup_event');
335 if ($timestamp) {
336 if (!wp_unschedule_event($timestamp, 'wpstreamify_cleanup_event')) {
337 error_log('wpstreamify_unschedule_cleanup_event: Failed to unschedule cleanup event.');
338 }
339 }
340 }
341 register_deactivation_hook(WP_PLUGIN_DIR . '/' . WPSTREAM_PLUGIN_BASE, 'wpstreamify_unschedule_cleanup_event');
342
343 function wpstreamify_add_rewrite_rules() {
344 $rewrite_rules = get_option('rewrite_rules');
345 $rule_pattern = '^wpstreamify/(.+)$';
346 $rule_target = 'index.php?wpstreamify_path=$matches[1]';
347
348 // Check if the rewrite rule already exists
349 if (!isset($rewrite_rules[$rule_pattern]) || $rewrite_rules[$rule_pattern] !== $rule_target) {
350 add_rewrite_rule($rule_pattern, $rule_target, 'top');
351 flush_rewrite_rules();
352 }
353 }
354 add_action('init', 'wpstreamify_add_rewrite_rules');
355
356 function wpstreamify_flush_rewrite_rules() {
357 if (!flush_rewrite_rules()) {
358 error_log('wpstreamify_flush_rewrite_rules: Failed to flush rewrite rules.');
359 }
360 }
361 register_activation_hook(WP_PLUGIN_DIR . '/' . WPSTREAM_PLUGIN_BASE, 'wpstreamify_flush_rewrite_rules');
362 register_deactivation_hook(WP_PLUGIN_DIR . '/' . WPSTREAM_PLUGIN_BASE, 'wpstreamify_flush_rewrite_rules');
363
364 function wpstreamify_disable_hls_canonical_redirect($redirect_url, $requested_url) {
365 if (get_query_var('wpstreamify_path')) {
366 $parsed_url = parse_url($requested_url);
367
368 if ($parsed_url === false) {
369 error_log(sprintf(
370 'wpstreamify_disable_hls_canonical_redirect: Failed to parse requested URL: %s',
371 $requested_url
372 ));
373 return $redirect_url;
374 }
375
376 $path = isset($parsed_url['path']) ? $parsed_url['path'] : '';
377 $fileExtension = pathinfo($path, PATHINFO_EXTENSION);
378
379 if (!$fileExtension) {
380 error_log(sprintf(
381 'wpstreamify_disable_hls_canonical_redirect: Unable to determine file extension for path: %s',
382 $path
383 ));
384 return $redirect_url;
385 }
386
387 if (in_array($fileExtension, ['ts', 'm3u8'], true)) {
388 return false;
389 }
390 }
391 return $redirect_url;
392 }
393 add_filter('redirect_canonical', 'wpstreamify_disable_hls_canonical_redirect', 10, 2);
394
395
396 function wpstreamify_create_cache_dir() {
397 if (!file_exists(WPSTREAMIFY_CACHE_DIR)) {
398 if (!mkdir(WPSTREAMIFY_CACHE_DIR, 0755, true)) {
399 error_log('wpstreamify_create_cache_dir: Failed to create HLS cache directory: ' . WPSTREAMIFY_CACHE_DIR);
400 } elseif (!is_dir(WPSTREAMIFY_CACHE_DIR)) {
401 error_log('wpstreamify_create_cache_dir: Path exists but is not a directory: ' . WPSTREAMIFY_CACHE_DIR);
402 }
403 } elseif (!is_writable(WPSTREAMIFY_CACHE_DIR)) {
404 error_log('wpstreamify_create_cache_dir: Cache directory exists but is not writable: ' . WPSTREAMIFY_CACHE_DIR);
405 }
406 }
407 register_activation_hook(WP_PLUGIN_DIR . '/' . WPSTREAM_PLUGIN_BASE, 'wpstreamify_create_cache_dir');
408
409 function wpstreamify_remove_cache_dir() {
410 if (file_exists(WPSTREAMIFY_CACHE_DIR) && is_dir(WPSTREAMIFY_CACHE_DIR)) {
411 $files = array_diff(scandir(WPSTREAMIFY_CACHE_DIR), ['.', '..']);
412
413 if ($files === false) {
414 error_log('wpstreamify_remove_cache_dir: Failed to scan directory: ' . WPSTREAMIFY_CACHE_DIR);
415 return;
416 }
417
418 foreach ($files as $file) {
419 $filePath = WPSTREAMIFY_CACHE_DIR . DIRECTORY_SEPARATOR . $file;
420 if (is_file($filePath)) {
421 if (!unlink($filePath)) {
422 error_log('wpstreamify_remove_cache_dir: Failed to delete file: ' . $filePath);
423 error_log('Error: ' . json_encode(error_get_last()));
424 }
425 } elseif (is_dir($filePath)) {
426 error_log('wpstreamify_remove_cache_dir: Unexpected directory found inside cache directory: ' . $filePath);
427 } else {
428 error_log('wpstreamify_remove_cache_dir: Skipped unknown entry: ' . $filePath);
429 }
430 }
431
432 if (!rmdir(WPSTREAMIFY_CACHE_DIR)) {
433 error_log('wpstreamify_remove_cache_dir: Failed to remove directory: ' . WPSTREAMIFY_CACHE_DIR);
434 error_log('Error: ' . json_encode(error_get_last()));
435 }
436 } else {
437 error_log('wpstreamify_remove_cache_dir: Cache directory does not exist or is not a directory: ' . WPSTREAMIFY_CACHE_DIR);
438 }
439 }
440 register_deactivation_hook(WP_PLUGIN_DIR . '/' . WPSTREAM_PLUGIN_BASE, 'wpstreamify_remove_cache_dir');
441