PluginProbe
WpStream – Live Streaming, Video on Demand, Pay Per View / 4.12
WpStream – Live Streaming, Video on Demand, Pay Per View v4.12
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 4.5.12 All 180 releases
wpstream / streamify / streamify.php

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

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