'english'), $scheme, $wwwDomain, $domain, $port, $host, $purl, $httpsOnly = false, $sslLogin = false, $cname = 'xfss', $cookieSave = false, $cJar = array(), $form, $lpass, $fid, $enableDecoders = false, $embedDL = false, $unescaper = false, $customDecoder = false, $reverseForms = true, $cErrsFDL = array(), $DLregexp = '@https?://(?:[\w\-]+\.)+[\w\-]+(?:\:\d+)?/(?:files|dl?|cgi-bin/dl\.cgi|[\da-zA-Z]{30,})/(?:[^\?\'\"\t<>\r\n\\\]{15,}|v(?:id(?:eo)?)?\.(?:flv|mp4))@i'; private $classVer = 24; public $pluginVer, $pA; public function Download($link) { html_error('[GenericXFS_DL] This plugin can\'t be called directly.'); } protected function onLoad() {} // Placeholder protected function onLoad_Post() {} // Placeholder protected function Start($link, $cErrs = array(), $cErrReplace = true) { if ($this->pluginVer > $this->classVer) html_error('GenericXFS_DL class is outdated, please install last version from: https://pastebin.com/e5TZcfQ2 '); $this->cookie = $this->baseCookie = empty($this->cookie) ? $this->baseCookie : array_merge($this->cookie, $this->baseCookie); $link = explode('|', str_ireplace('%7C', '|', $link), 2); if (count($link) > 1) $this->lpass = rawurldecode($link[1]); if (!preg_match('@https?://(?:[\w\-]+\.)+[\w\-]+(?:\:\d+)?/(\w{12})(?=(?:[/\.]|(?:\.html?))?)@i', str_ireplace('/embed-', '/', $link[0]), $url)) html_error('Invalid link?.'); $this->fid = $url[1]; $url = parse_url($url[0]); $url['scheme'] = ($this->httpsOnly ? 'https' : strtolower($url['scheme'])); $url['host'] = strtolower($url['host']); if ($this->wwwDomain && strpos($url['host'], 'www.') !== 0) $url['host'] = 'www.' . $url['host']; elseif (!$this->wwwDomain && strpos($url['host'], 'www.') === 0) $url['host'] = substr($url['host'], 4); $this->scheme = $url['scheme']; $this->domain = $url['host']; $this->port = (!empty($url['port']) && $url['port'] > 0 && $url['port'] < 65536) ? $url['port'] : 0; $this->host = $this->domain . (!empty($this->port) ? ':'.$this->port : ''); $this->purl = $this->scheme.'://'.$this->host.'/'; $this->link = $GLOBALS['Referer'] = rebuild_url($url); unset($url, $link); $this->enableDecoders = $this->embedDL || $this->unescaper || $this->customDecoder; $this->onLoad(); if (empty($_POST['step']) || empty($_POST['captcha_type'])) { $this->page = $this->GetPage($this->link, $this->cookie); if ($this->scheme != 'https') is_present($this->page, "\nLocation: https://", '[GenericXFS_DL] Please Set "$this->httpsOnly" to true or add https:// to your link.'); if (!empty($cErrs) && is_array($cErrs)) { foreach ($cErrs as $cErr) { if (is_array($cErr)) is_present($this->page, $cErr[0], $cErr[1]); else is_present($this->page, $cErr); } if ($cErrReplace) { $this->onLoad_Post(); return $this->Login(); } } is_present($this->page, 'The file you were looking for could not be found'); is_present($this->page, 'The file was removed by administrator'); is_present($this->page, 'The file was deleted by its owner'); is_present($this->page, 'The file was deleted by administration'); is_present($this->page, 'No such file with this filename', 'Error: Invalid filename, check your link and try again.'); // With the regexp i removed the filename part of the link, this error shouldn't be showed } $this->onLoad_Post(); return $this->Login(); } protected function FindPost($formOp = 'download[1-3]') { //if (!preg_match_all('@
)@is', $this->page, $forms)) return false; $forms = ($this->reverseForms ? array_reverse($forms[0]) : $forms[0]); // In some hosts the freedl form is before the "premium" form so $this->reverseForms must be on false on those hosts. $found = false; foreach ($forms as $form) { if (preg_match('@]*\sname="op"[^>]*\svalue="' . $formOp . '"@i', $form)) { $found = true; break; } } if (!$found) return false; // Remove html commented inputs. while ($comment = cut_str($form, '')) $form = str_replace('', '', $form); $this->form = $form; unset($forms, $form, $ret); preg_match_all('@]*\stype="hidden"[^>]*\sname="(\w+)"[^>]*\svalue="([^"]*)"@i', $this->form, $inputs); $data = array_map('html_entity_decode', array_combine($inputs[1], $inputs[2])); if (($pos = stripos($this->form, '@i', substr($this->form, $pos), $inputs)) $data = array_merge($data, array_map('html_entity_decode', array_combine($inputs[1], $inputs[2]))); if ((stripos($this->form, 'type="submit"') !== false || stripos($this->form, 'type="image"') !== false || stripos($this->form, 'type="button"') !== false || stripos($this->form, '') !== false) && preg_match_all('@<(?:input\s*[^>]*\stype="(?:submit|image|button)"|button)[^>]*\sname="(\w+)"[^>]*\svalue="([^"]*)"@i', $this->form, $inputs)) { $data = array_merge($data, array_map('html_entity_decode', array_combine($inputs[1], $inputs[2]))); if (!empty($data['method_free']) && !empty($data['method_premium'])) $data['method_premium'] = ''; } $this->post = $data; return true; } // Custom page decoder placeholder protected function pageDecoder() { html_error('[GenericXFS_DL] $this->customDecoder is enabled but there is no pageDecoder() function.'); } protected function runDecoders() { // Packed embedded video decoder if (!empty($this->embedDL) && preg_match_all('@eval\s*\(\s*function\s*\(p,a,c,k,e,d\)\s*\{.+\}\s*\(\s*\'([^\r|\n]*)\'\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*\'([^\']+)\'\.split\([\'|\"](.)[\'|\"]\)(?:\s*,\s*\d\s*,\s*\{\})?\)\)@', $this->page, $js)) { $cnt = count($js[0]); for ($i = 0; $i < $cnt; $i++) { $this->page = str_replace($js[0][$i], $this->XFSUnpacker($js[1][$i], $js[2][$i], $js[3][$i], $js[4][$i], $js[5][$i]), $this->page); } } // JS unescape decoder if (!empty($this->unescaper) && preg_match_all('@eval\s*\(unescape\s*\(\s*(\"|\')([%\da-fA-F]+)\1\s*\)\s*\)\s*;?@', $this->page, $js)) { $cnt = count($js[0]); for ($i = 0; $i < $cnt; $i++) { $this->page = str_replace($js[0][$i], urldecode($js[2][$i]), $this->page); } } // Custom decoder function if (!empty($this->customDecoder)) $this->pageDecoder(); } // (Placeholder) Returns video title if available to use on stream video downloads. protected function getVideoTitle() { return false; } protected function getFileName($url) { $fname = basename(parse_url($url, PHP_URL_PATH)); if (preg_match("@^(?:v(?:id(?:eo)?)?|{$this->fid})?\.(mp4|flv)$@i", $fname, $vExt)) { // Possible video/stream // Try to get original filename or title for renaming the file. if (!empty($this->post['fname'])) $newname = $this->post['fname']; else if (($title = $this->getVideoTitle())) $newname = $title; else $newname = false; // I always like to add a letter to mark it as a reconverted video stream and remove the original video .ext if (!empty($newname)) $fname = preg_replace('@(?:\.(?:mp4|flv|mkv|webm|wmv|(m2)?ts|rm(vb)?|mpe?g?|vob|avi|[23]gp))+$@i', '', basename($newname)) . '_S.' . strtolower($vExt[1]); } return $fname; } protected function testDL() { if (!empty($this->enableDecoders)) $this->runDecoders(); if (preg_match($this->DLregexp, $this->page, $DL)) { $this->RedirectDownload($DL[0], basename($this->getFileName($DL[0]))); return true; } return false; } protected function XFSUnpacker($p,$a,$c,$k,$ed) { $k = explode($ed, $k); while ($c--) if ($k[$c]) $p = preg_replace('@\b'.base_convert($c, 10, $a).'\b@', $k[$c], $p); return $p; } protected function findCaptcha() { if (!empty($this->captcha)) return false; if (($pos = stripos($this->page, $this->scheme . '://' . $this->host . '/captchas/')) !== false && preg_match('@(https?://(?:[\w\-]+\.)+[\w\-]+(?:\:\d+)?)?/captchas/[\w\-]+\.(?:jpe?g|png|gif)@i', substr($this->page, $pos), $gdCaptcha)) { // gd Captcha if (empty($gdCaptcha[1])) $gdCaptcha[0] = $this->scheme . '://' . $this->host . $gdCaptcha[0]; $this->captcha = array('type' => 1, 'url' => $gdCaptcha[0]); } elseif (substr_count($this->form, "]*padding-left\s*:\s*(\d+)[^\'>]*'[^>]*>((?:\w+;)|(?:\d))@i", $this->form, $txtCaptcha)) { // Text Captcha (decodeable) $txtCaptcha = array_combine($txtCaptcha[1], $txtCaptcha[2]); ksort($txtCaptcha, SORT_NUMERIC); $txtCaptcha = trim(html_entity_decode(implode($txtCaptcha), ENT_QUOTES, 'UTF-8')); $this->captcha = array('type' => 2, 'key' => $txtCaptcha); } elseif ((stripos($this->page, 'google.com/recaptcha/api/') !== false || stripos($this->page, 'recaptcha.net/') !== false) && preg_match('@(?:https?:)?//(?:[\w\-]+\.)?(?:google\.com/recaptcha/api|recaptcha\.net)/(?:challenge|noscript)\?k=([\w\.\-]+)@i', $this->page, $reCaptcha)) { // Old reCAPTCHA $this->captcha = array('type' => 3, 'key' => $reCaptcha[1]); } elseif (preg_match('@(?:https?:)?//api(?:-secure)?\.solvemedia\.com/papi/challenge\.(?:no)?script\?k=([\w\.\-]+)@i', $this->page, $smCaptcha)) { // SolveMedia Captcha $this->captcha = array('type' => 4, 'key' => $smCaptcha[1]); } elseif (preg_match('@(?:class|id)=["\']g-recaptcha["\']\s+data-sitekey=["\']([\w\.\-]+)["\']@i', $this->page, $reCaptcha2)) { // reCAPTCHA2 $this->captcha = array('type' => 5, 'key' => $reCaptcha2[1]); } return (!empty($this->captcha)); } protected function showCaptcha($step) { if (!empty($this->captcha)) { if (!empty($this->cookie[$this->cname])) { $data = $this->DefaultParamArr($this->link, $this->cookie, 1, 1); $data['cookie_encrypted'] = 1; } else { $data = $this->DefaultParamArr($this->link); } if (!empty($this->post)) foreach ($this->post as $k => $v) $data["T8gXFS[$k]"] = $v; $data['step'] = $step; $data['captcha_type'] = $this->captcha['type']; switch ($this->captcha['type']) { default: return html_error('Unknown captcha type.'); case 1: list($headers, $imgBody) = explode("\r\n\r\n", $this->GetPage($this->captcha['url']), 2); if (substr($headers, 9, 3) != '200') html_error('[1] Error downloading CAPTCHA img.'); $mimetype = (preg_match('@image/[\w+]+@', $headers, $mimetype) ? $mimetype[0] : 'image/jpg'); return $this->EnterCaptcha("data:$mimetype;base64,".base64_encode($imgBody), $data); case 2: $this->post['code'] = $this->captcha['key']; // postCaptcha won't be needed on this case. return true; case 3: return $this->reCAPTCHA($this->captcha['key'], $data); case 4: return $this->SolveMedia($this->captcha['key'], $data); case 5: return $this->reCAPTCHAv2($this->captcha['key'], $data); } } return false; } protected function postCaptcha(&$step) { if (empty($_POST['step']) || empty($_POST['captcha_type'])) return false; $post = (!empty($_POST['T8gXFS']) && is_array($_POST['T8gXFS']) ? array_map('urlencode', $_POST['T8gXFS']) : array()); switch ($_POST['captcha_type']) { default: return html_error('Invalid captcha type.'); case '1': // Image (gd) Captcha $this->captcha = array('type' => 1); if (empty($_POST['captcha'])) html_error('[1] You didn\'t enter the image verification code.'); $post['code'] = urlencode($_POST['captcha']); break; case '3': // Old reCAPTCHA $this->captcha = array('type' => 3); if (empty($_POST['recaptcha_response_field'])) html_error('[3] You didn\'t enter the image verification code.'); if (empty($_POST['recaptcha_challenge_field'])) html_error('[3] Empty reCAPTCHA challenge.'); $post['recaptcha_challenge_field'] = urlencode($_POST['recaptcha_challenge_field']); $post['recaptcha_response_field'] = urlencode($_POST['recaptcha_response_field']); break; case '4': // Solvemedia $this->captcha = array('type' => 4); $post = array_merge($post, $this->verifySolveMedia()); break; case '5': // reCAPTCHA2 $this->captcha = array('type' => 5); $post = array_merge($post, $this->verifyReCaptchav2()); break; } $step = intval($_POST['step']); $_POST['step'] = $_POST['captcha_type'] = false; $this->page = $this->GetPage($this->link, $this->cookie, $post); $this->cookie = GetCookiesArr($this->page, $this->cookie); return true; } // Finds FreeDL countdown on $this->page and calls $this->CountDown(X) for it. // return true if there is a countdown, false otherwise. protected function findCountdown() { if (preg_match('@]*>(?>.*?]*>)\s*(\d+)\s*(?>.*?)@sim', $this->page, $count) || preg_match('@]*>(?>[\w\s]*?]*>)\s*(\d+)\s*(?>[\w\s]*?)@sim', $this->form, $count)) { if ($count[1] > 0) $this->CountDown($count[1] + 2); return true; } return false; } protected function checkCaptcha($step) { if (preg_match('@>\s*Wrong captcha\s*<@i', $this->page)) { if (empty($this->captcha)) html_error("Error: Unknown captcha. [$step]"); else if ($this->captcha['type'] == 2) html_error("Error: Error Decoding Captcha. [$step]"); else html_error("Error: Wrong Captcha Entered. [$step]"); } } protected function FreeDL($step = 1) { if (!$this->postCaptcha($step) && $step == 1 && !empty($this->cookie[$this->cname])) { // Member DL: We need to reload the page with the user's cookies. $this->page = $this->GetPage($this->link, $this->cookie); $this->cookie = GetCookiesArr($this->page, $this->cookie); } if ((($pos = stripos($this->page, 'You have to wait')) !== false || ($pos = stripos($this->page, 'Please wait ')) !== false) && preg_match('@(?:You have to|Please) wait[\W\S]?(?:(?:\s*|\s*