├── README.md
├── includes
└── extend.php
├── panel_api.php
└── player_api.php
/README.md:
--------------------------------------------------------------------------------
1 | # XtreamCodesExtendAPI
2 | Xtream Codes 1.6 - Extend API Functionality
3 |
4 | Poorly written extension to Xtream Codes 1.60 to allow player_api.php to be implemented. This will allow the WHMCS Web TV Player and Xtream Codes API based Android / iOS players to have limited functionality with the older Xtream Codes panel.
5 |
6 |
7 | !BETA - INCOMPLETE!
8 |
9 |
10 | FEATURES
11 | --------
12 | - Decoded Xtream Codes 2x API backported to 1.6
13 | - Live TV, EPG and VOD functionality reimplemented
14 | - CORS implementation in NGINX
15 |
16 | LIMITATIONS
17 | -----------
18 | - No TV Series support in 1.6x
19 | - No Catchup support in 1.6x
20 |
21 | FUTURE PLANS
22 | ------------
23 | - Implement TV Series support manually
24 |
25 | INSTALLATION
26 | ------------
27 | - Just extract the files to /home/xtreamcodes/iptv_xtream_codes and overwrite. Backup your old files!
28 |
--------------------------------------------------------------------------------
/includes/extend.php:
--------------------------------------------------------------------------------
1 | "iPhone", "/ipod/i" => "iPod", "/ipad/i" => "iPad", "/android/i" => "Android", "/blackberry/i" => "BlackBerry", "/webos/i" => "Mobile");
31 |
32 | foreach ($aMobileUA as $sMobileKey => $sMobileOS ) {
33 | if (preg_match($sMobileKey, $_SERVER["HTTP_USER_AGENT"])) {
34 | return true;
35 | }
36 | }
37 |
38 | return false;
39 | }
40 |
41 | function CronChecking($file_name, $time = 600)
42 | {
43 | if (file_exists($file_name)) {
44 | $pid = trim(file_get_contents($file_name));
45 |
46 | if (file_exists("/proc/" . $pid)) {
47 | if ((time() - filemtime($file_name)) < $time) {
48 | exit("Running...");
49 | }
50 |
51 | posix_kill($pid, 9);
52 | }
53 | }
54 |
55 | file_put_contents($file_name, getmypid());
56 | return false;
57 | }
58 |
59 | function BlockIP($ip, $reason)
60 | {
61 | global $ipTV_db;
62 |
63 | if (in_array($ip, ipTV_Stream::getAllowedIPsAdmin(true))) {
64 | return NULL;
65 | }
66 |
67 | $ipTV_db->query("INSERT INTO `blocked_ips` (`ip`,`notes`,`date`) VALUES('%s','%s','%d')", $ip, $reason, time());
68 |
69 | if (0 < $ipTV_db->affected_rows()) {
70 | Servers::RunCommandServer(array_keys(ipTV_lib::$StreamingServers), "sudo /sbin/iptables -A INPUT -s $ip -j DROP");
71 | }
72 | }
73 |
74 | function CheckFlood()
75 | {
76 | global $ipTV_db;
77 | $user_ip = ipTV_Stream::getUserIP();
78 |
79 | if (empty($user_ip)) {
80 | return NULL;
81 | }
82 |
83 | if ((ipTV_lib::$settings["flood_limit"] == 0) || in_array($user_ip, ipTV_Stream::getAllowedIPsAdmin(true))) {
84 | return NULL;
85 | }
86 |
87 | $restreamers = array_filter(array_unique(explode(",", ipTV_lib::$settings["flood_ips_exclude"])));
88 |
89 | if (in_array($user_ip, $restreamers)) {
90 | return NULL;
91 | }
92 |
93 | $user_activity_now = TMP_DIR . "user_activity_now.ips";
94 | $user_ip_file = TMP_DIR . $user_ip . ".flood";
95 | if (!file_exists($user_activity_now) || (20 <= time() - filemtime($user_activity_now))) {
96 | $ipTV_db->query("SELECT DISTINCT `user_ip`,t2.is_restreamer FROM `user_activity_now` t1 INNER JOIN `users` t2 ON t2.id = t1.user_id");
97 | $connected_ips = $ipTV_db->get_rows(true, "user_ip");
98 | file_put_contents($user_activity_now, json_encode($connected_ips));
99 | }
100 | else {
101 | $connected_ips = json_decode(file_get_contents($user_activity_now), true);
102 | }
103 |
104 | if (array_key_exists($user_ip, $connected_ips)) {
105 | if ($connected_ips[$user_ip]["is_restreamer"] == 0) {
106 | if (ipTV_lib::$settings["flood_apply_clients"] != 1) {
107 | return NULL;
108 | }
109 | }
110 |
111 | if ($connected_ips[$user_ip]["is_restreamer"] == 1) {
112 | if (ipTV_lib::$settings["flood_apply_restreamers"] != 1) {
113 | return NULL;
114 | }
115 | }
116 | }
117 |
118 | if (file_exists($user_ip_file)) {
119 | $flood_row = json_decode(file_get_contents($user_ip_file), true);
120 | $frequency_settings = ipTV_lib::$settings["flood_seconds"];
121 | $limit_attempts = ipTV_lib::$settings["flood_max_attempts"];
122 | $flood_limit = ipTV_lib::$settings["flood_limit"];
123 |
124 | if ($limit_attempts <= $flood_row["attempts"]) {
125 | $ipTV_db->query("INSERT INTO `blocked_ips` (`ip`,`notes`,`date`) VALUES('%s','%s','%d')", $user_ip, "FLOOD ATTACK", time());
126 | Servers::RunCommandServer(array_keys(ipTV_lib::$StreamingServers), "sudo /sbin/iptables -A INPUT -s $user_ip -j DROP");
127 | unlink($user_ip_file);
128 | return NULL;
129 | }
130 |
131 | if ((time() - $flood_row["last_request"]) <= $frequency_settings) {
132 | ++$flood_row["requests"];
133 |
134 | if ($flood_limit <= $flood_row["requests"]) {
135 | ++$flood_row["attempts"];
136 | $flood_row["requests"] = 0;
137 | }
138 |
139 | $flood_row["last_request"] = time();
140 | file_put_contents($user_ip_file, json_encode($flood_row), LOCK_EX);
141 | }
142 | else {
143 | $flood_row["attempts"] = $flood_row["requests"] = 0;
144 | $flood_row["last_request"] = time();
145 | file_put_contents($user_ip_file, json_encode($flood_row), LOCK_EX);
146 | }
147 | }
148 | else {
149 | file_put_contents($user_ip_file, json_encode(array("requests" => 0, "attempts" => 0, "last_request" => time())), LOCK_EX);
150 | }
151 | }
152 |
153 | function GetEPGs()
154 | {
155 | global $ipTV_db;
156 | $ipTV_db->query("\n SELECT t1.*,COUNT(DISTINCT t2.`id`) as total_rows\n FROM `epg` t1\n LEFT JOIN `epg_data` t2 ON t1.id = t2.epg_id\n GROUP BY t1.id\n ORDER BY t1.id DESC\n ");
157 | return 0 < $ipTV_db->num_rows() ? $ipTV_db->get_rows() : array();
158 | }
159 |
160 | function GetEPGStream($stream_id, $from_now = false)
161 | {
162 | global $ipTV_db;
163 | $ipTV_db->query("SELECT `type`,`movie_propeties`,`epg_id`,`channel_id`FROM `streams` WHERE `id` = '%d'", $stream_id);
164 |
165 | if (0 < $ipTV_db->num_rows()) {
166 | $data = $ipTV_db->get_row();
167 |
168 | if ($data["type"] != 2) {
169 | if ($from_now) {
170 | $ipTV_db->query("SELECT * FROM `epg_data` WHERE `epg_id` = '%d' AND `channel_id` = '%s' AND `end` >= '%d'", $data["epg_id"], $data["channel_id"], time());
171 | }
172 | else {
173 | $ipTV_db->query("SELECT * FROM `epg_data` WHERE `epg_id` = '%d' AND `channel_id` = '%s'", $data["epg_id"], $data["channel_id"]);
174 | }
175 |
176 | return $ipTV_db->get_rows();
177 | }
178 | else {
179 | return $data["movie_propeties"];
180 | }
181 | }
182 |
183 | return array();
184 | }
185 |
186 | function GetEPGStreamPlayer($stream_id, $limit = 4)
187 | {
188 | global $ipTV_db;
189 | $ipTV_db->query("SELECT `type`,`movie_propeties`,`epg_id`,`channel_id`FROM `streams` WHERE `id` = '%d'", $stream_id);
190 |
191 | if (0 < $ipTV_db->num_rows()) {
192 | $data = $ipTV_db->get_row();
193 |
194 | if ($data["type"] != 2) {
195 | $ipTV_db->query("SELECT * FROM `epg_data` WHERE `epg_id` = '%d' AND `channel_id` = '%s' AND `end` >= '%d' ORDER BY `start` ASC LIMIT %d", $data["epg_id"], $data["channel_id"], time(), $limit);
196 | return $ipTV_db->get_rows();
197 | }
198 | else {
199 | return $data["movie_propeties"];
200 | }
201 | }
202 |
203 | return array();
204 | }
205 |
206 | function GetTotalCPUsage()
207 | {
208 | $total_cpu = intval(shell_exec("ps aux|awk 'NR > 0 { s +=\$3 }; END {print s}'"));
209 | $cores = intval(shell_exec("grep --count processor /proc/cpuinfo"));
210 | return intval($total_cpu / $cores);
211 | }
212 |
213 | function portal_auth($sn, $mac, $ver, $stb_type, $image_version, $device_id, $device_id2, $hw_version, $req_ip)
214 | {
215 | global $ipTV_db;
216 | $ipTV_db->query("SELECT * FROM `mag_devices` WHERE `mac` = '%s'", $mac);
217 |
218 | if (0 < $ipTV_db->num_rows()) {
219 | $mag_info_db = $ipTV_db->get_row();
220 | $ipTV_db->query("SELECT * FROM `users` WHERE `id` = '%d' AND `is_mag` = 1", $mag_info_db["user_id"]);
221 |
222 | if (0 < $ipTV_db->num_rows()) {
223 | $user_info_db = $ipTV_db->get_row();
224 | $user_info_db["allowed_ips"] = json_decode($user_info_db["allowed_ips"], true);
225 | }
226 |
227 | $total_info = array_merge($mag_info_db, $user_info_db);
228 | $ipTV_db->query("UPDATE `mag_devices` SET `ip` = '%s' WHERE `mag_id` = '%d'", $req_ip, $total_info["mag_id"]);
229 | if ((empty($total_info["stb_type"]) && !empty($stb_type)) || (empty($total_info["sn"]) && !empty($sn)) || (empty($total_info["ver"]) && !empty($ver)) || (empty($total_info["image_version"]) && !empty($image_version)) || (empty($total_info["device_id"]) && !empty($device_id)) || (empty($total_info["device_id2"]) && !empty($device_id2)) || (empty($total_info["hw_version"]) && !empty($hw_version))) {
230 | if (empty($total_info["stb_type"]) && !empty($stb_type)) {
231 | $ipTV_db->query("UPDATE `mag_devices` SET `stb_type` = '%s' WHERE `mag_id` = '%d'", $stb_type, $total_info["mag_id"]);
232 | $total_info["stb_type"] = $stb_type;
233 | }
234 |
235 | if (empty($total_info["sn"]) && !empty($sn)) {
236 | $ipTV_db->query("UPDATE `mag_devices` SET `sn` = '%s' WHERE `mag_id` = '%d'", $sn, $total_info["mag_id"]);
237 | $total_info["sn"] = $sn;
238 | }
239 |
240 | if (empty($total_info["ver"]) && !empty($ver)) {
241 | $ipTV_db->query("UPDATE `mag_devices` SET `ver` = '%s' WHERE `mag_id` = '%d'", $ver, $total_info["mag_id"]);
242 | $total_info["ver"] = $ver;
243 | }
244 |
245 | if (empty($total_info["image_version"]) && !empty($image_version)) {
246 | $ipTV_db->query("UPDATE `mag_devices` SET `image_version` = '%s' WHERE `mag_id` = '%d'", $image_version, $total_info["mag_id"]);
247 | $total_info["image_version"] = $image_version;
248 | }
249 |
250 | if (empty($total_info["device_id"]) && !empty($device_id)) {
251 | $ipTV_db->query("UPDATE `mag_devices` SET `device_id` = '%s' WHERE `mag_id` = '%d'", $device_id, $total_info["mag_id"]);
252 | $total_info["device_id"] = $device_id;
253 | }
254 |
255 | if (empty($total_info["device_id2"]) && !empty($device_id2)) {
256 | $ipTV_db->query("UPDATE `mag_devices` SET `device_id2` = '%s' WHERE `mag_id` = '%d'", $device_id2, $total_info["mag_id"]);
257 | $total_info["device_id"] = $device_id2;
258 | }
259 |
260 | if (empty($total_info["hw_version"]) && !empty($hw_version)) {
261 | $ipTV_db->query("UPDATE `mag_devices` SET `hw_version` = '%s' WHERE `mag_id` = '%d'", $hw_version, $total_info["mag_id"]);
262 | $total_info["hw_version"] = $hw_version;
263 | }
264 |
265 | return array("total_info" => prepair_mag_cols($total_info), "mag_info_db" => prepair_mag_cols($mag_info_db), "fav_channels" => empty($mag_info_db["fav_channels"]) ? array() : json_decode($mag_info_db["fav_channels"], true));
266 | }
267 | else {
268 | if (($total_info["sn"] == $sn) && ($total_info["hw_version"] == $hw_version) && ($total_info["device_id2"] == $device_id2) && ($total_info["device_id"] == $device_id) && ($total_info["image_version"] == $image_version) && ($total_info["ver"] == $ver)) {
269 | return array("total_info" => prepair_mag_cols($total_info), "mag_info_db" => prepair_mag_cols($mag_info_db), "fav_channels" => empty($mag_info_db["fav_channels"]) ? array() : json_decode($mag_info_db["fav_channels"], true));
270 | }
271 | }
272 | }
273 |
274 | return false;
275 | }
276 |
277 | function get_from_cookie($cookie, $type)
278 | {
279 | if (!empty($cookie)) {
280 | $explode = explode(";", $cookie);
281 |
282 | foreach ($explode as $data ) {
283 | $data = explode("=", $data);
284 | $output[trim($data[0])] = trim($data[1]);
285 | }
286 |
287 | switch ($type) {
288 | case "mac":
289 | if (array_key_exists("mac", $output)) {
290 | return base64_encode(strtoupper(urldecode($output["mac"])));
291 | }
292 | }
293 | }
294 |
295 | return false;
296 | }
297 |
298 | function prepair_mag_cols($array)
299 | {
300 | $output = array();
301 |
302 | foreach ($array as $key => $value ) {
303 | if (($key == "mac") || ($key == "ver") || ($key == "hw_version")) {
304 | $output[$key] = base64_decode($value);
305 | }
306 |
307 | $output[$key] = $value;
308 | }
309 |
310 | unset($output["fav_channels"]);
311 | return $output;
312 | }
313 |
314 | function GetCategories($type = NULL, $remove_empty = false)
315 | {
316 | global $ipTV_db;
317 |
318 | $query = "SELECT id, category_name, category_type FROM `stream_categories`";
319 |
320 | switch ($type) {
321 | case NULL:
322 | break;
323 |
324 | case "live":
325 | $query .= " WHERE category_type = 'live'";
326 | break;
327 |
328 | case "movie":
329 | $query .= " WHERE category_type = 'movie'";
330 | break;
331 | }
332 |
333 | $query .= " GROUP BY category_name, category_type ORDER BY id ASC;";
334 | $ipTV_db->query($query);
335 | return 0 < $ipTV_db->num_rows() ? $ipTV_db->get_rows(true, "id") : array();
336 | }
337 |
338 | function GenerateUniqueCode()
339 | {
340 | return substr(md5(ipTV_lib::$settings["unique_id"]), 0, 15);
341 | }
342 |
343 | function encodeToUtf8($string)
344 | {
345 | return mb_convert_encoding($string, "UTF-8", mb_detect_encoding($string, "UTF-8, ISO-8859-1, ISO-8859-15", true));
346 | }
347 |
348 | function GenerateList($user_id, $device_key, $output_key = "", $force_download = false)
349 | {
350 | global $ipTV_db;
351 |
352 | if (!RowExists("users", "id", $user_id)) {
353 | return false;
354 | }
355 |
356 | if (empty($device_key)) {
357 | return false;
358 | }
359 |
360 | if (empty($output_key)) {
361 | $ipTV_db->query("SELECT t1.output_ext FROM `access_output` t1 INNER JOIN `devices` t2 ON t2.default_output = t1.access_output_id AND `device_key` = '%s'", $device_key);
362 | $output_ext = $ipTV_db->get_col();
363 | }
364 | else {
365 | $ipTV_db->query("SELECT t1.output_ext FROM `access_output` t1 WHERE `output_key` = '%s'", $output_key);
366 | $output_ext = $ipTV_db->get_col();
367 | }
368 |
369 | if (empty($output_ext)) {
370 | return false;
371 | }
372 |
373 | $user_info = ipTV_Stream::GetUserInfo($user_id, NULL, NULL, true, true, false);
374 |
375 | if (empty($user_info)) {
376 | return false;
377 | }
378 |
379 | if (!empty($user_info["exp_date"]) && ($user_info["exp_date"] <= time())) {
380 | return false;
381 | }
382 |
383 | $ipTV_db->query("SELECT t1.*,t2.*\n FROM `devices` t1\n LEFT JOIN `access_output` t2 ON t2.access_output_id = t1.default_output\n WHERE t1.device_key = '%s' LIMIT 1", $device_key);
384 | $domain_name = ipTV_lib::$StreamingServers[SERVER_ID]["site_url"];
385 |
386 | if (0 < $ipTV_db->num_rows()) {
387 | $device_info = $ipTV_db->get_row();
388 | $data = "";
389 |
390 | if ($device_key == "starlivev5") {
391 | $output_array = array();
392 | $output_array["iptvstreams_list"] = array();
393 | $output_array["iptvstreams_list"]["@version"] = 1;
394 | $output_array["iptvstreams_list"]["group"] = array();
395 | $output_array["iptvstreams_list"]["group"]["name"] = "IPTV";
396 | $output_array["iptvstreams_list"]["group"]["channel"] = array();
397 |
398 | foreach ($user_info["channels"] as $channel_info ) {
399 | if ($channel_info["direct_source"] == 0) {
400 | $url = $domain_name . "{$channel_info["type_output"]}/{$user_info["username"]}/{$user_info["password"]}/";
401 |
402 | if ($channel_info["live"] == 0) {
403 | $url .= $channel_info["id"] . "." . $channel_info["container_extension"];
404 | $movie_propeties = json_decode($channel_info["movie_propeties"], true);
405 |
406 | if (!empty($movie_propeties["movie_image"])) {
407 | $icon = $movie_propeties["movie_image"];
408 | }
409 | }
410 | else {
411 | $url .= $channel_info["id"] . "." . $output_ext;
412 | $icon = $channel_info["stream_icon"];
413 | }
414 | }
415 | else {
416 | list($url) = json_decode($channel_info["stream_source"], true);
417 | }
418 |
419 | $channel = array();
420 | $channel["name"] = $channel_info["stream_display_name"];
421 | $icon = "";
422 | $channel["icon"] = $icon;
423 | $channel["stream_url"] = $url;
424 | $channel["stream_type"] = 0;
425 | $output_array["iptvstreams_list"]["group"]["channel"][] = $channel;
426 | }
427 |
428 | $data = json_encode((object) $output_array);
429 | }
430 | else {
431 | if (!empty($device_info["device_header"])) {
432 | $data = str_replace(array("{BOUQUET_NAME}", "{USERNAME}", "{PASSWORD}", "{SERVER_URL}", "{OUTPUT_KEY}"), array(ipTV_lib::$settings["bouquet_name"], $user_info["username"], $user_info["password"], $domain_name, $output_key), $device_info["device_header"]) . "\n";
433 | }
434 |
435 | if (!empty($device_info["device_conf"])) {
436 | if (preg_match("/\{URL\#(.*?)\}/", $device_info["device_conf"], $matches)) {
437 | $url_encoded_charts = str_split($matches[1]);
438 | $url_pattern = $matches[0];
439 | }
440 | else {
441 | $url_encoded_charts = array();
442 | $url_pattern = "{URL}";
443 | }
444 |
445 | foreach ($user_info["channels"] as $channel ) {
446 | if ($channel["direct_source"] == 0) {
447 | $url = $domain_name . "{$channel["type_output"]}/{$user_info["username"]}/{$user_info["password"]}/";
448 | $icon = "";
449 |
450 | if ($channel["live"] == 0) {
451 | $url .= $channel["id"] . "." . $channel["container_extension"];
452 | $movie_propeties = json_decode($channel["movie_propeties"], true);
453 |
454 | if (!empty($movie_propeties["movie_image"])) {
455 | $icon = $movie_propeties["movie_image"];
456 | }
457 | }
458 | else {
459 | $url .= $channel["id"] . "." . $output_ext;
460 | $icon = $channel["stream_icon"];
461 | }
462 | }
463 | else {
464 | list($url) = json_decode($channel["stream_source"], true);
465 | }
466 |
467 | $esr_id = ($channel["live"] == 1 ? 1 : 4097);
468 | $sid = (!empty($channel["custom_sid"]) ? $channel["custom_sid"] : ":0:1:0:0:0:0:0:0:0:");
469 | $data .= str_replace(array($url_pattern, "{ESR_ID}", "{SID}", "{CHANNEL_NAME}", "{CHANNEL_ID}", "{CATEGORY}", "{CHANNEL_ICON}"), array(str_replace($url_encoded_charts, array_map("urlencode", $url_encoded_charts), $url), $esr_id, $sid, $channel["stream_display_name"], $channel["channel_id"], $channel["category_name"], $icon), $device_info["device_conf"]) . "\r\n";
470 | }
471 |
472 | $data .= $device_info["device_footer"];
473 | $data = trim($data);
474 | }
475 | }
476 |
477 | if ($force_download === true) {
478 | header("Content-Description: File Transfer");
479 | header("Content-Type: application/octet-stream");
480 | header("Expires: 0");
481 | header("Cache-Control: must-revalidate");
482 | header("Pragma: public");
483 | header("Content-Disposition: attachment; filename=\"" . str_replace("{USERNAME}", $user_info["username"], $device_info["device_filename"]) . "\"");
484 | header("Content-Length: " . strlen($data));
485 | echo $data;
486 | exit();
487 | }
488 |
489 | return $data;
490 | }
491 |
492 | return false;
493 | }
494 |
495 | function GetServerConnections($end = NULL, $limit = false, $from = 0, $to = 0)
496 | {
497 | global $ipTV_db;
498 |
499 | switch ($end) {
500 | case "open":
501 | $query = "\n SELECT t1.*,t3.stream_display_name,t4.server_name as source_name,t5.server_name as dest_name\n FROM `server_activity` t1\n LEFT JOIN `streams` t3 ON t3.id = t1.stream_id\n LEFT JOIN `streaming_servers` t4 ON t4.id = t1.source_server_id\n LEFT JOIN `streaming_servers` t5 ON t5.id = t1.dest_server_id\n WHERE ISNULL(t1.`date_end`)\n ORDER BY t1.id DESC ";
502 | break;
503 |
504 | case "closed":
505 | $query = "\n SELECT t1.*,t3.stream_display_name,t4.server_name as source_name,t5.server_name as dest_name\n FROM `server_activity` t1\n LEFT JOIN `streams` t3 ON t3.id = t1.stream_id\n LEFT JOIN `streaming_servers` t4 ON t4.id = t1.source_server_id\n LEFT JOIN `streaming_servers` t5 ON t5.id = t1.dest_server_id\n WHERE t1.`date_end` IS NOT NULL\n ORDER BY t1.id DESC ";
506 | break;
507 |
508 | default:
509 | $query = "\n SELECT t1.*,t3.stream_display_name,t4.server_name as source_name,t5.server_name as dest_name\n FROM `server_activity` t1\n LEFT JOIN `streams` t3 ON t3.id = t1.stream_id\n LEFT JOIN `streaming_servers` t4 ON t4.id = t1.source_server_id\n LEFT JOIN `streaming_servers` t5 ON t5.id = t1.dest_server_id\n ORDER BY (t1.`date_end` IS NOT NULL),t1.id DESC ";
510 | }
511 |
512 | if ($limit === true) {
513 | $query .= "LIMIT $from,$to";
514 | }
515 |
516 | $ipTV_db->query($query);
517 | $activities = array();
518 |
519 | if (0 < $ipTV_db->num_rows()) {
520 | $activities = $ipTV_db->get_rows();
521 | }
522 |
523 | return $activities;
524 | }
525 |
526 | function GetConnections($end, $server_id = NULL)
527 | {
528 | global $ipTV_db;
529 | $extra = "";
530 |
531 | if (!is_null($server_id)) {
532 | $extra = "WHERE t1.server_id = '" . intval($server_id) . "'";
533 | }
534 |
535 | switch ($end) {
536 | case "open":
537 | $query = "\n SELECT t1.*,t2.*,t3.*,t4.*,t5.mac,t6.bitrate\n FROM `user_activity_now` t1\n LEFT JOIN `users` t2 ON t2.id = t1.user_id\n LEFT JOIN `streams` t3 ON t3.id = t1.stream_id\n LEFT JOIN `streaming_servers` t4 ON t4.id = t1.server_id\n LEFT JOIN `mag_devices` t5 on t5.user_id = t2.id\n LEFT JOIN `streams_sys` t6 ON t6.stream_id = t1.stream_id AND t6.server_id = t1.server_id\n $extra\n ORDER BY t1.activity_id DESC";
538 | break;
539 |
540 | case "closed":
541 | $query = "\n SELECT t1.*,t2.*,t3.*,t4.*,t5.mac,t6.bitrate\n FROM `user_activity` t1\n LEFT JOIN `users` t2 ON t2.id = t1.user_id\n LEFT JOIN `streams` t3 ON t3.id = t1.stream_id\n LEFT JOIN `streaming_servers` t4 ON t4.id = t1.server_id\n LEFT JOIN `mag_devices` t5 on t5.user_id = t2.id\n LEFT JOIN `streams_sys` t6 ON t6.stream_id = t1.stream_id AND t6.server_id = t1.server_id\n $extra\n ORDER BY t1.activity_id DESC";
542 | break;
543 | }
544 |
545 | $ipTV_db->query($query);
546 | return $ipTV_db->get_rows();
547 | }
548 |
549 | function Is_Running($file_name)
550 | {
551 | $pid_running = false;
552 |
553 | if (file_exists($file_name)) {
554 | $data = file($file_name);
555 |
556 | foreach ($data as $pid ) {
557 | $pid = (int) $pid;
558 | if ((0 < $pid) && file_exists("/proc/" . $pid)) {
559 | $pid_running = $pid;
560 | break;
561 | }
562 | }
563 | }
564 |
565 | if ($pid_running && ($pid_running != getmypid())) {
566 | if (file_exists($file_name)) {
567 | file_put_contents($file_name, $pid);
568 | }
569 |
570 | return true;
571 | }
572 | else {
573 | file_put_contents($file_name, getmypid());
574 | return false;
575 | }
576 | }
577 |
578 | function crontab_refresh()
579 | {
580 | if (file_exists(TMP_DIR . "crontab_refresh")) {
581 | return false;
582 | }
583 |
584 | $crons = scandir(CRON_PATH);
585 | $jobs = array();
586 |
587 | foreach ($crons as $cron ) {
588 | $full_path = CRON_PATH . $cron;
589 |
590 | if (!is_file($full_path)) {
591 | continue;
592 | }
593 |
594 | if (pathinfo($full_path, PATHINFO_EXTENSION) != "php") {
595 | continue;
596 | }
597 |
598 | $jobs[] = "*/1 * * * * " . PHP_BIN . " " . $full_path . " # Xtream-Codes IPTV Panel";
599 | }
600 |
601 | $crontab = trim(shell_exec("crontab -l"));
602 |
603 | if (!empty($crontab)) {
604 | $lines = explode("\n", $crontab);
605 | $lines = array_map("trim", $lines);
606 |
607 | if ($lines == $jobs) {
608 | file_put_contents(TMP_DIR . "crontab_refresh", 1);
609 | return true;
610 | }
611 |
612 | $counter = count($lines);
613 |
614 | for ($i = 0; $i < $counter; $i++) {
615 | if (stripos($lines[$i], CRON_PATH)) {
616 | unset($lines[$i]);
617 | }
618 | }
619 |
620 | foreach ($jobs as $job ) {
621 | array_push($lines, $job);
622 | }
623 | }
624 | else {
625 | $lines = $jobs;
626 | }
627 |
628 | shell_exec("crontab -r");
629 | $tmpfname = tempnam("/tmp", "crontab");
630 | $handle = fopen($tmpfname, "w");
631 | fwrite($handle, implode("\r\n", $lines) . "\r\n");
632 | fclose($handle);
633 | shell_exec("crontab $tmpfname");
634 | @unlink($tmpfname);
635 | file_put_contents(TMP_DIR . "crontab_refresh", 1);
636 | }
637 |
638 | function RowExists($table, $search_by, $needle)
639 | {
640 | global $ipTV_db;
641 | $ipTV_db->query("SELECT * FROM `$table` WHERE `$search_by` = '%s'", $needle);
642 |
643 | if (0 < $ipTV_db->num_rows()) {
644 | return true;
645 | }
646 |
647 | return false;
648 | }
649 |
650 | function memory_usage()
651 | {
652 | $memory_usage = trim(shell_exec("free -m"));
653 |
654 | if (empty($memory_usage)) {
655 | return false;
656 | }
657 |
658 | $data = explode("\n", $memory_usage);
659 | $memory_usage = array();
660 | $swap_usage = array();
661 |
662 | foreach ($data as $line ) {
663 | $output = preg_replace("!\s+!", " ", str_replace(":", "", $line));
664 | if (!strstr($output, "Mem") && !strstr($output, "Swap")) {
665 | continue;
666 | }
667 |
668 | $info = explode(" ", $output);
669 |
670 | if ($info[0] == "Mem") {
671 | $memory_usage["total"] = $info[1];
672 | $memory_usage["used"] = $info[2] - $info[6];
673 |
674 | if ($memory_usage["used"] < 0) {
675 | $memory_usage["used"] = $info[2];
676 | }
677 |
678 | $memory_usage["free"] = $info[3];
679 | $memory_usage["percent"] = sprintf("%0.2f", ($memory_usage["used"] / $memory_usage["total"]) * 100);
680 | }
681 | else {
682 | $swap_usage["total"] = $info[1];
683 | $swap_usage["used"] = $info[2];
684 | $swap_usage["free"] = $info[3];
685 |
686 | if ($swap_usage["total"] != 0) {
687 | $swap_usage["percent"] = sprintf("%0.2f", ($info[2] / $info[1]) * 100);
688 | }
689 | else {
690 | $swap_usage["percent"] = 0;
691 | }
692 | }
693 | }
694 |
695 | return array($memory_usage, $swap_usage);
696 | }
697 |
698 | function get_boottime()
699 | {
700 | if (file_exists("/proc/uptime") && is_readable("/proc/uptime")) {
701 | $tmp = explode(" ", file_get_contents("/proc/uptime"));
702 | return secondsToTime(intval($tmp[0]));
703 | }
704 |
705 | return "";
706 | }
707 |
708 | function secondsToTime($inputSeconds)
709 | {
710 | $secondsInAMinute = 60;
711 | $secondsInAnHour = 60 * $secondsInAMinute;
712 | $secondsInADay = 24 * $secondsInAnHour;
713 | $days = (int) floor($inputSeconds / $secondsInADay);
714 | $hourSeconds = $inputSeconds % $secondsInADay;
715 | $hours = (int) floor($hourSeconds / $secondsInAnHour);
716 | $minuteSeconds = $hourSeconds % $secondsInAnHour;
717 | $minutes = (int) floor($minuteSeconds / $secondsInAMinute);
718 | $remainingSeconds = $minuteSeconds % $secondsInAMinute;
719 | $seconds = (int) ceil($remainingSeconds);
720 | $final = "";
721 |
722 | if ($days != 0) {
723 | $final .= "{$days}d ";
724 | }
725 |
726 | if ($hours != 0) {
727 | $final .= "{$hours}h ";
728 | }
729 |
730 | if ($minutes != 0) {
731 | $final .= "{$minutes}m ";
732 | }
733 |
734 | $final .= "{$seconds}s";
735 | return $final;
736 | }
737 |
738 | class ipTV_lib
739 | {
740 | /**
741 | * Input parameters
742 | *
743 | * @var array
744 | */
745 | static public $request = array();
746 | /**
747 | * Database Instance
748 | *
749 | * @var instance
750 | */
751 | static public $ipTV_db;
752 | /**
753 | * Settings
754 | *
755 | * @var array
756 | */
757 | static public $settings = array();
758 | /**
759 | * Settings for Licence
760 | *
761 | * @var array
762 | */
763 | static public $GetXtreamInfo = array();
764 | /**
765 | * Servers
766 | *
767 | * @var array
768 | */
769 | static public $StreamingServers = array();
770 | static public $SegmentsSettings = array();
771 | static public $countries = array();
772 |
773 | static public function init()
774 | {
775 | if (!empty($_GET)) {
776 | self::cleanGlobals($_GET);
777 | }
778 |
779 | if (!empty($_POST)) {
780 | self::cleanGlobals($_POST);
781 | }
782 |
783 | if (!empty($_SESSION)) {
784 | self::cleanGlobals($_SESSION);
785 | }
786 |
787 | if (!empty($_COOKIE)) {
788 | self::cleanGlobals($_COOKIE);
789 | }
790 |
791 | $input = @self::parseIncomingRecursively($_GET, array());
792 | self::$request = @self::parseIncomingRecursively($_POST, $input);
793 | self::GetSettings();
794 | ini_set("date.timezone", self::$settings["default_timezone"]);
795 | self::GetXtreamInfo();
796 | self::$StreamingServers = self::GetServers();
797 | self::$SegmentsSettings = self::calculateSegNumbers();
798 | crontab_refresh();
799 | }
800 |
801 | static public function calculateSegNumbers()
802 | {
803 | $segments_settings = array();
804 | $segments_settings["seg_time"] = 10;
805 | $segments_settings["seg_list_size"] = 6;
806 | return $segments_settings;
807 | }
808 |
809 | static public function isValidMAC($mac)
810 | {
811 | return preg_match("/^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$/", $mac) == 1;
812 | }
813 |
814 | static public function GetSettings()
815 | {
816 | self::$ipTV_db->query("SELECT * FROM `settings`");
817 | $rows = self::$ipTV_db->get_row();
818 |
819 | foreach ($rows as $key => $val ) {
820 | self::$settings[$key] = $val;
821 | }
822 |
823 | self::$settings["allow_countries"] = json_decode(self::$settings["allow_countries"], true);
824 |
825 | if (array_key_exists("bouquet_name", self::$settings)) {
826 | self::$settings["bouquet_name"] = str_replace(" ", "_", self::$settings["bouquet_name"]);
827 | }
828 | }
829 |
830 | static public function GetServers()
831 | {
832 | self::$ipTV_db->query("SELECT * FROM `streaming_servers`");
833 | $servers = array();
834 |
835 | foreach (self::$ipTV_db->get_rows() as $row ) {
836 | if (!empty($row["vpn_ip"]) && (inet_pton($row["vpn_ip"]) !== false)) {
837 | $url = $row["vpn_ip"];
838 | }
839 | else if (empty($row["domain_name"])) {
840 | $url = $row["server_ip"];
841 | }
842 | else {
843 | $url = str_replace(array("http://", "/"), "", $row["domain_name"]);
844 | }
845 |
846 | $row["api_url"] = "http://" . $url . ":" . $row["http_broadcast_port"] . "/api.php?password=" . ipTV_lib::$settings["live_streaming_pass"];
847 | $row["site_url"] = "http://" . $url . ":" . $row["http_broadcast_port"] . "/";
848 | $row["api_url_ip"] = "http://" . $row["server_ip"] . ":" . $row["http_broadcast_port"] . "/api.php?password=" . ipTV_lib::$settings["live_streaming_pass"];
849 | $row["site_url_ip"] = "http://" . $row["server_ip"] . ":" . $row["http_broadcast_port"] . "/";
850 | $row["ssh_password"] = self::mc_decrypt($row["ssh_password"], md5(self::$settings["unique_id"]));
851 | $servers[$row["id"]] = $row;
852 | }
853 |
854 | return $servers;
855 | }
856 |
857 | static public function GetFFmpegArguments($parse_StreamArguments = array(), $add_default = true)
858 | {
859 | global $_LANG;
860 | self::$ipTV_db->query("SELECT * FROM `streams_arguments`");
861 | $rows = array();
862 |
863 | if (0 < self::$ipTV_db->num_rows()) {
864 | foreach (self::$ipTV_db->get_rows() as $row ) {
865 | if (array_key_exists($row["id"], $parse_StreamArguments)) {
866 | if (count($parse_StreamArguments[$row["id"]]) == 2) {
867 | $value = $parse_StreamArguments[$row["id"]]["val"];
868 | }
869 | else {
870 | $value = $parse_StreamArguments[$row["id"]]["value"];
871 | }
872 | }
873 | else {
874 | $value = ($add_default ? $row["argument_default_value"] : "");
875 | }
876 |
877 | if ($row["argument_type"] == "radio") {
878 | if (is_null($value) || (0 < $value)) {
879 | $no = false;
880 | $yes = true;
881 | }
882 | else {
883 | $no = true;
884 | $yes = false;
885 | }
886 |
887 | if ($yes) {
888 | $mode = " " . $_LANG["yes"] . " . " . $_LANG["no"];
889 | }
890 | else {
891 | $mode = " " . $_LANG["yes"] . " . " . $_LANG["no"];
892 | }
893 | }
894 | else if ($row["argument_type"] == "text") {
895 | $mode = "";
896 | }
897 |
898 | $row["mode"] = $mode;
899 | $rows[$row["id"]] = $row;
900 | }
901 | }
902 |
903 | return $rows;
904 | }
905 |
906 | static public function mc_encrypt($encrypt, $key)
907 | {
908 | $encrypt = serialize($encrypt);
909 | $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_DEV_URANDOM);
910 | $key = pack("H*", $key);
911 | $mac = hash_hmac("sha256", $encrypt, substr(bin2hex($key), -32));
912 | $passcrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $encrypt . $mac, MCRYPT_MODE_CBC, $iv);
913 | $encoded = base64_encode($passcrypt) . "|" . base64_encode($iv);
914 | return $encoded;
915 | }
916 |
917 | static public function mc_decrypt($decrypt, $key)
918 | {
919 | $decrypt = explode("|", $decrypt . "|");
920 | $decoded = base64_decode($decrypt[0]);
921 | $iv = base64_decode($decrypt[1]);
922 |
923 | if (strlen($iv) !== mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC)) {
924 | return false;
925 | }
926 |
927 | $key = pack("H*", $key);
928 | $decrypted = trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $decoded, MCRYPT_MODE_CBC, $iv));
929 | $mac = substr($decrypted, -64);
930 | $decrypted = substr($decrypted, 0, -64);
931 | $calcmac = hash_hmac("sha256", $decrypted, substr(bin2hex($key), -32));
932 |
933 | if ($calcmac !== $mac) {
934 | return false;
935 | }
936 |
937 | $decrypted = unserialize($decrypted);
938 | return $decrypted;
939 | }
940 |
941 | static public function formatOffset($offset)
942 | {
943 | $hours = $offset / 3600;
944 | $remainder = $offset % 3600;
945 | $sign = (0 < $hours ? "+" : "-");
946 | $hour = (int) abs($hours);
947 | $minutes = (int) abs($remainder / 60);
948 | if (($hour == 0) && ($minutes == 0)) {
949 | $sign = " ";
950 | }
951 |
952 | return $sign . str_pad($hour, 2, "0", STR_PAD_LEFT) . ":" . str_pad($minutes, 2, "0");
953 | }
954 |
955 | static public function GetTimeZones($current = NULL)
956 | {
957 | $utc = new DateTimeZone("UTC");
958 | $dt = new DateTime("now", $utc);
959 | $timezones = array();
960 |
961 | foreach (DateTimeZone::listIdentifiers() as $tz ) {
962 | $current_tz = new DateTimeZone($tz);
963 | $offset = $current_tz->getOffset($dt);
964 | $transition = $current_tz->getTransitions($dt->getTimestamp(), $dt->getTimestamp());
965 | $abbr = $transition[0]["abbr"];
966 | if (!is_null($current) && ($current == $tz)) {
967 | $timezones[] = "";
968 | }
969 | else {
970 | $timezones[] = "";
971 | }
972 | }
973 |
974 | return $timezones;
975 | }
976 |
977 | static public function GetCurrentTimeOffset()
978 | {
979 | $utc = new DateTimeZone("UTC");
980 | $dt = new DateTime("now", $utc);
981 | $current_timezone = ipTV_lib::$settings["default_timezone"];
982 | $current_tz = new DateTimeZone($current_timezone);
983 | $offset = $current_tz->getOffset($dt);
984 | return self::formatOffset($offset);
985 | }
986 |
987 | static public function SimpleWebGet($url, $save_cache = false)
988 | {
989 | $ch = curl_init();
990 | curl_setopt($ch, CURLOPT_URL, $url);
991 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
992 | curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
993 | curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
994 | curl_setopt($ch, CURLOPT_TIMEOUT, 30);
995 | curl_setopt($ch, CURLOPT_MAXREDIRS, 10);
996 | $res = curl_exec($ch);
997 | curl_close($ch);
998 |
999 | if ($res !== false) {
1000 | if ($save_cache) {
1001 | $unique_id = uniqid();
1002 | file_put_contents(TMP_DIR . $unique_id, $res);
1003 | return TMP_DIR . $unique_id;
1004 | }
1005 | }
1006 |
1007 | return trim($res);
1008 | }
1009 |
1010 | static public function curlMultiRequest($urls, $callback = NULL, $array_key = "raw")
1011 | {
1012 | if (empty($urls)) {
1013 | return array();
1014 | }
1015 |
1016 | $ch = array();
1017 | $results = array();
1018 | $mh = curl_multi_init();
1019 |
1020 | foreach ($urls as $key => $val ) {
1021 | $ch[$key] = curl_init();
1022 | curl_setopt($ch[$key], CURLOPT_URL, $val["url"]);
1023 | curl_setopt($ch[$key], CURLOPT_RETURNTRANSFER, true);
1024 | curl_setopt($ch[$key], CURLOPT_FOLLOWLOCATION, true);
1025 | curl_setopt($ch[$key], CURLOPT_CONNECTTIMEOUT, 120);
1026 | curl_setopt($ch[$key], CURLOPT_TIMEOUT, 120);
1027 | curl_setopt($ch[$key], CURLOPT_MAXREDIRS, 10);
1028 |
1029 | if ($val["postdata"] != NULL) {
1030 | curl_setopt($ch[$key], CURLOPT_POST, true);
1031 | curl_setopt($ch[$key], CURLOPT_POSTFIELDS, http_build_query($val["postdata"]));
1032 | }
1033 |
1034 | curl_multi_add_handle($mh, $ch[$key]);
1035 | }
1036 |
1037 | $running = NULL;
1038 |
1039 | do {
1040 | curl_multi_exec($mh, $running);
1041 | } while (0 < $running);
1042 |
1043 | foreach ($ch as $key => $val ) {
1044 | $results[$key] = curl_multi_getcontent($val);
1045 |
1046 | if ($callback != NULL) {
1047 | $results[$key] = call_user_func($callback, $results[$key], true);
1048 |
1049 | if (isset($results[$key][$array_key])) {
1050 | $results[$key] = $results[$key][$array_key];
1051 | }
1052 | }
1053 |
1054 | if (!$results[$key]) {
1055 | $results[$key] = array();
1056 | ipTV_lib::SaveLog("Server [$key] is DOWN!");
1057 | }
1058 |
1059 | curl_multi_remove_handle($mh, $val);
1060 | }
1061 |
1062 | curl_multi_close($mh);
1063 | return $results;
1064 | }
1065 |
1066 | static public function cleanGlobals(&$data, $iteration = 0)
1067 | {
1068 | if (10 <= $iteration) {
1069 | return NULL;
1070 | }
1071 |
1072 | foreach ($data as $k => $v ) {
1073 | if (is_array($v)) {
1074 | self::cleanGlobals($data[$k], ++$iteration);
1075 | }
1076 | else {
1077 | $v = str_replace(chr("0"), "", $v);
1078 | $v = str_replace("\000", "", $v);
1079 | $v = str_replace("\000", "", $v);
1080 | $v = str_replace("../", "../", $v);
1081 | $v = str_replace("", "", $v);
1082 | $data[$k] = $v;
1083 | }
1084 | }
1085 | }
1086 |
1087 | static public function parseIncomingRecursively(&$data, $input = array(), $iteration = 0)
1088 | {
1089 | if (20 <= $iteration) {
1090 | return $input;
1091 | }
1092 |
1093 | if (!is_array($data)) {
1094 | return $input;
1095 | }
1096 |
1097 | foreach ($data as $k => $v ) {
1098 | if (is_array($v)) {
1099 | $input[$k] = self::parseIncomingRecursively($data[$k], array(), $iteration + 1);
1100 | }
1101 | else {
1102 | $k = self::parseCleanKey($k);
1103 | $v = self::parseCleanValue($v);
1104 | $input[$k] = $v;
1105 | }
1106 | }
1107 |
1108 | return $input;
1109 | }
1110 |
1111 | static public function parseCleanKey($key)
1112 | {
1113 | if ($key === "") {
1114 | return "";
1115 | }
1116 |
1117 | $key = htmlspecialchars(urldecode($key));
1118 | $key = str_replace("..", "", $key);
1119 | $key = preg_replace("/\_\_(.+?)\_\_/", "", $key);
1120 | $key = preg_replace("/^([\w\.\-\_]+)$/", "\$1", $key);
1121 | return $key;
1122 | }
1123 |
1124 | static public function parseCleanValue($val)
1125 | {
1126 | if ($val == "") {
1127 | return "";
1128 | }
1129 |
1130 | $val = str_replace(" ", " ", stripslashes($val));
1131 | $val = str_replace(array("\r\n", "\n\r", "\r"), "\n", $val);
1132 | $val = str_replace("", "-->", $val);
1134 | $val = str_ireplace("