| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971 |
- <?php
- /* $Id: SimpleHTTP.php 3307 2007-12-16 22:32:03Z warion $ */
- /*******************************************************************************
- LICENSE
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License (GPL)
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- To read the license please visit http://www.gnu.org/copyleft/gpl.html
- *******************************************************************************/
- // states
- define('SIMPLEHTTP_STATE_NULL', 0); // null
- define('SIMPLEHTTP_STATE_OK', 1); // ok
- define('SIMPLEHTTP_STATE_ERROR', -1); // error
- /**
- * SimpleHTTP
- */
- class SimpleHTTP
- {
- // public fields
- // timeout
- var $timeout = 20;
- /**
- * Temporarily use HTTP/1.0 until chunked encoding is sorted out
- * Valid values are '1.0' or '1.1'
- * @param string $httpVersion
- */
- var $httpVersion = "1.0";
- /**
- * Cookie string used in raw HTTP request
- * @param string $cookie
- */
- var $cookie = "";
- /**
- * URI/path used in GET request:
- * @param string $getcmd
- */
- var $getcmd = "";
- /**
- * the raw HTTP request to send to the remote webserver
- * @param string $request
- */
- var $request = "";
- /**
- * the raw HTTP response received from the remote webserver
- * @param string $responseBody
- */
- var $responseBody = "";
- /**
- * Array of HTTP response headers
- * @param array $responseHeaders
- */
- var $responseHeaders = array();
- /**
- * Indicates if we got the response line or not from webserver
- * 'HTTP/1.1 200 OK
- * etc
- * @param bool $gotResponseLine
- */
- var $gotResponseLine = false;
- /**
- * Status code of webserver response
- * @param string $status
- */
- var $status = "";
- /**
- * socket
- */
- var $socket = 0;
- /**
- * Error string
- * @param string $errstr
- */
- var $errstr = "";
- /**
- * Error number
- * @param int $errno
- */
- var $errno = 0;
- // user-agent
- var $userAgent = "";
- // filename
- var $filename = "";
- // url
- var $url = "";
- // referer
- var $referer = "";
- // messages
- var $messages = array();
- // state
- var $state = SIMPLEHTTP_STATE_NULL;
- // Number of redirects we've followed so far:
- var $redirectCount = 0;
- // Maximum number of redirects to follow:
- var $redirectMax = 5;
- // The redirect URL specified in the location header for a 30x status code:
- var $redirectUrl = "";
- // Can PHP do TLS?
- var $canTLS = null;
- // =========================================================================
- // public static methods
- // =========================================================================
- /**
- * accessor for singleton
- *
- * @return SimpleHTTP
- */
- function getInstance() {
- global $instanceSimpleHTTP;
- // initialize if needed
- if (!isset($instanceSimpleHTTP))
- SimpleHTTP::initialize();
- return $instanceSimpleHTTP;
- }
- /**
- * initialize SimpleHTTP.
- */
- function initialize() {
- global $instanceSimpleHTTP;
- // create instance
- if (!isset($instanceSimpleHTTP))
- $instanceSimpleHTTP = new SimpleHTTP();
- }
- /**
- * getState
- *
- * @return state
- */
- function getState() {
- global $instanceSimpleHTTP;
- return (isset($instanceSimpleHTTP))
- ? $instanceSimpleHTTP->state
- : SIMPLEHTTP_STATE_NULL;
- }
- /**
- * getMessages
- *
- * @return array
- */
- function getMessages() {
- global $instanceSimpleHTTP;
- return (isset($instanceSimpleHTTP))
- ? $instanceSimpleHTTP->messages
- : array();
- }
- /**
- * getMessages
- *
- * @return string
- */
- function getFilename() {
- global $instanceSimpleHTTP;
- return (isset($instanceSimpleHTTP))
- ? $instanceSimpleHTTP->filename
- : "";
- }
- /**
- * method to get data from URL -- uses timeout and user agent
- *
- * @param $get_url
- * @param $get_referer
- * @return string
- */
- function getData($get_url, $get_referer = "") {
- global $instanceSimpleHTTP;
- // initialize if needed
- if (!isset($instanceSimpleHTTP))
- SimpleHTTP::initialize();
- // call instance-method
- return $instanceSimpleHTTP->instance_getData($get_url, $get_referer);
- }
- /**
- * get torrent from URL. Has support for specific sites
- *
- * @param $durl
- * @return string
- */
- function getTorrent($durl) {
- global $instanceSimpleHTTP;
- // initialize if needed
- if (!isset($instanceSimpleHTTP))
- SimpleHTTP::initialize();
- // call instance-method
- return $instanceSimpleHTTP->instance_getTorrent($durl);
- }
- /**
- * get nzb from URL.
- *
- * @param $durl
- * @return string
- */
- function getNzb($durl) {
- global $instanceSimpleHTTP;
- // initialize if needed
- if (!isset($instanceSimpleHTTP))
- SimpleHTTP::initialize();
- // call instance-method
- return $instanceSimpleHTTP->instance_getNzb($durl);
- }
- /**
- * get size from URL.
- *
- * @param $durl
- * @return int
- */
- function getRemoteSize($durl) {
- global $instanceSimpleHTTP;
- // initialize if needed
- if (!isset($instanceSimpleHTTP))
- SimpleHTTP::initialize();
- // call instance-method
- return $instanceSimpleHTTP->instance_getRemoteSize($durl);
- }
- // =========================================================================
- // ctor
- // =========================================================================
- /**
- * do not use direct, use the factory-method !
- *
- * @return SimpleHTTP
- */
- function SimpleHTTP() {
- global $cfg;
- // user-agent
- $this->userAgent = $cfg['user_agent'];
- // ini-settings
- @ini_set("allow_url_fopen", "1");
- @ini_set("user_agent", $this->userAgent);
- }
- // =========================================================================
- // public methods
- // =========================================================================
- /**
- * method to get data from URL -- uses timeout and user agent
- *
- * @param $get_url
- * @param $get_referer
- * @return string
- */
- function instance_getData($get_url, $get_referer = "") {
- global $cfg, $db;
- // set fields
- $this->url = $get_url;
- $this->referer = $get_referer;
- // (re)set state
- $this->state = SIMPLEHTTP_STATE_NULL;
- // (re-)set some vars
- $this->cookie = "";
- $this->request = "";
- $this->responseBody = "";
- $this->responseHeaders = array();
- $this->gotResponseLine = false;
- $this->status = "";
- $this->errstr = "";
- $this->errno = 0;
- $this->socket = 0;
- /**
- * array of URL component parts for use in raw HTTP request
- * @param array $domain
- */
- $domain = parse_url($this->url);
- if (
- empty($domain) || // Check URL is a well-formed HTTP/HTTPS URL.
- empty($domain['scheme']) || ($domain['scheme'] != 'http' && $domain['scheme'] != 'https') ||
- empty($domain['host'])
- ) {
- $this->state = SIMPLEHTTP_STATE_ERROR;
- $msg = "Error fetching " . $this->url .". This is not a valid HTTP/HTTPS URL.";
- array_push($this->messages, $msg);
- AuditAction($cfg["constants"]["error"], $msg);
- return($data="");
- }
- $secure = $domain['scheme'] == 'https';
- if ($secure && !$this->_canTLS()) {
- $this->state = SIMPLEHTTP_STATE_ERROR;
- $msg = "Error fetching " . $this->url .". PHP does not have module OpenSSL, which is needed for HTTPS.";
- array_push($this->messages, $msg);
- AuditAction($cfg["constants"]["error"], $msg);
- return($data="");
- }
- // get-command
- if (!array_key_exists("path", $domain))
- $domain["path"] = "/";
- $this->getcmd = $domain["path"];
- if (!array_key_exists("query", $domain))
- $domain["query"] = "";
- // append the query string if included:
- $this->getcmd .= (!empty($domain["query"])) ? "?" . $domain["query"] : "";
- // Check to see if cookie required for this domain:
- $sql = "SELECT c.data AS data FROM tf_cookies AS c LEFT JOIN tf_users AS u ON ( u.uid = c.uid ) WHERE u.user_id = ".$db->qstr($cfg["user"])." AND c.host = ".$db->qstr($domain['host']);
- $this->cookie = $db->GetOne($sql);
- if ($db->ErrorNo() != 0) dbError($sql);
- if (!array_key_exists("port", $domain))
- $domain["port"] = $secure ? 443 : 80;
- // Fetch the data using fsockopen():
- $this->socket = @fsockopen( // connect to server, let PHP handle TLS layer for an HTTPS connection
- ($secure ? 'tls://' : '') . $domain["host"], $domain["port"],
- $this->errno, $this->errstr, $this->timeout
- );
- if (!empty($this->socket)) {
- // Write the outgoing HTTP request using cookie info
- // Standard HTTP/1.1 request looks like:
- //
- // GET /url/path/example.php HTTP/1.1
- // Host: example.com
- // Accept: */*
- // Accept-Language: en-us
- // User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.8.1) Gecko/20061010 Firefox/2.0
- // Connection: Close
- // Cookie: uid=12345;pass=asdfasdf;
- //
- //$this->request = "GET " . ($this->httpVersion=="1.1" ? $this->getcmd : $this->url ). " HTTP/" . $this->httpVersion ."\r\n";
- $this->request = "GET ".$this->_fullURLEncode($this->getcmd)." HTTP/".$this->httpVersion."\r\n";
- $this->request .= (!empty($this->referer)) ? "Referer: " . $this->referer . "\r\n" : "";
- $this->request .= "Accept: */*\r\n";
- $this->request .= "Accept-Language: en-us\r\n";
- $this->request .= "User-Agent: ".$this->userAgent."\r\n";
- $this->request .= "Host: " . $domain["host"] . "\r\n";
- if($this->httpVersion=="1.1"){
- $this->request .= "Connection: Close\r\n";
- }
- if(!empty($this->cookie)){
- $this->request .= "Cookie: " . $this->cookie . "\r\n";
- }
- $this->request .= "\r\n";
- // Send header packet information to server
- fputs($this->socket, $this->request);
- // socket-options
- stream_set_timeout($this->socket, $this->timeout);
- // meta-data
- $info = stream_get_meta_data($this->socket);
- // Get response headers:
- while ((!$info['timed_out']) && ($line = @fgets($this->socket, 500000))) {
- // First empty line/\r\n indicates end of response headers:
- if($line == "\r\n"){
- break;
- }
- if (!$this->gotResponseLine) {
- preg_match("@HTTP/[^ ]+ (\d\d\d)@", $line, $matches);
- // TODO: Use this to see if we redirected (30x) and follow the redirect:
- $this->status = $matches[1];
- $this->gotResponseLine = true;
- continue;
- }
- // Get response headers:
- preg_match("/^([^:]+):\s*(.*)/", trim($line), $matches);
- $this->responseHeaders[strtolower($matches[1])] = $matches[2];
- // meta-data
- $info = stream_get_meta_data($this->socket);
- }
- if(
- $this->httpVersion=="1.1"
- && isset($this->responseHeaders["transfer-encoding"])
- && !empty($this->responseHeaders["transfer-encoding"])
- ) {
- /*
- // NOT CURRENTLY WORKING, USE HTTP/1.0 ONLY UNTIL THIS IS FIXED!
- */
- // Get body of HTTP response:
- // Handle chunked encoding:
- /*
- length := 0
- read chunk-size, chunk-extension (if any) and CRLF
- while (chunk-size > 0) {
- read chunk-data and CRLF
- append chunk-data to entity-body
- length := length + chunk-size
- read chunk-size and CRLF
- }
- */
- // Used to count total of all chunk lengths, the content-length:
- $chunkLength=0;
- // Get first chunk size:
- $chunkSize = hexdec(trim(fgets($this->socket)));
- // 0 size chunk indicates end of content:
- while ((!$info['timed_out']) && ($chunkSize > 0)) {
- // Read in up to $chunkSize chars:
- $line = @fgets($this->socket, $chunkSize);
- // Discard crlf after current chunk:
- fgets($this->socket);
- // Append chunk to response body:
- $this->responseBody .= $line;
- // Keep track of total chunk/content length:
- $chunkLength += $chunkSize;
- // Read next chunk size:
- $chunkSize = hexdec(trim(fgets($this->socket)));
- // meta-data
- $info = stream_get_meta_data($this->socket);
- }
- $this->responseHeaders["content-length"] = $chunkLength;
- } else {
- while ((!$info['timed_out']) && ($line = @fread($this->socket, 500000))) {
- $this->responseBody .= $line;
- // meta-data
- $info = stream_get_meta_data($this->socket);
- }
- }
- @fclose($this->socket); // Close our connection
- } else {
- return "Error fetching ".$this->url.". PHP Error No=".$this->errno." . PHP Error String=".$this->errstr;
- }
- /*
- Check if we need to follow a redirect:
- http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
- Each of these HTTP response status codes indicates a redirect and the
- content should be included in the Location field/header:
- 300 Multiple Locations
- 301 Moved Permanently
- 302 Found (has a temp location somewhere else on server)
- 303 See Other (should be fetched using GET, probably not relevant but won't hurt to include it)
- 307 Temporary Redirect
- */
- if( preg_match("/^30[0-37]$/D", $this->status) > 0 ){
- // Check we're not already over the max redirects limit:
- if ( $this->redirectCount > $this->redirectMax ) {
- $this->state = SIMPLEHTTP_STATE_ERROR;
- $msg = "Error fetching " . $this->url .". The maximum number of allowed redirects ";
- $msg .="(" .$this->redirectMax. ") was exceeded. Last followed URL was: " .$this->redirectUrl;
- array_push($this->messages , $msg);
- AuditAction($cfg["constants"]["error"], $msg);
- return($data="");
- } else {
- $this->redirectCount++;
- // Check we have a location to get redirected content:
- if( isset($this->responseHeaders["location"]) && !empty($this->responseHeaders["location"]) ){
- // 3 different cases for location header:
- // - full URL (scheme://.../foobar) -- just go to that URL,
- // - absolute URL (/foobar) -- keep everything up to host/port,
- // and replace end of request,
- // - relative URL (foobar) -- keep everything up to last component of path,
- // and replace end of request.
- $redirectLocation = $this->responseHeaders["location"];
- if (preg_match('#^(ht|f)tp(s)?://#', $redirectLocation) > 0) {
- // Case 1: full URL. Just use it.
- $this->redirectUrl = $redirectLocation;
- } else {
- // Cases 2 or 3: partial URL.
- // Keep scheme/user/pass/host/port of current request.
- $redirectUrlBase =
- $domain['scheme'].'://'.
- ((isset($domain['user']) || isset($domain['pass'])) ?
- ((isset($domain['user']) ? $domain['user'] : '').
- (isset($domain['pass']) ? ':'.$domain['pass'] : '').'@') : '').
- $domain['host'].
- (isset($domain['port']) ? ':'.$domain['port'] : '');
- if ($redirectLocation[0] == '/') {
- // Case 2: absolute URL.
- // Append it to current request's base.
- $this->redirectUrl = $redirectUrlBase . $redirectLocation;
- } else {
- // Case 3: relative URL.
- // Append it to current request's base + path stripped of its last component.
- $domainPathAry = explode('/', $domain['path']);
- array_splice($domainPathAry, -1, 1, $redirectLocation);
- $domainPathNew = implode('/', $domainPathAry);
- $this->redirectUrl =
- $redirectUrlBase .
- ((isset($domainPathNew) &&
- strlen($domainPathNew) > 0 &&
- $domainPathNew[0] == '/') ? '' : '/') .
- $domainPathNew;
- }
- }
- } else {
- $msg = "Error fetching " . $this->url .". A redirect status code (" . $this->status . ")";
- $msg .= " was sent from the remote webserver, but no location header was set to obtain the redirected content from.";
- AuditAction($cfg["constants"]["error"], $msg);
- array_push($this->messages , $msg);
- return($data="");
- }
- $this->instance_getData($this->redirectUrl);
- }
- }
- // Trim any extraneous linefeed chars:
- $this->responseBody = trim($this->responseBody, "\r\n");
- // If a filename is associated with this content, assign it to $filename
- if (isset($this->responseHeaders["content-disposition"]) && !empty($this->responseHeaders["content-disposition"])) {
- // Content-disposition: attachment; filename="nameoffile":
- // Don't think single quotes can be used to escape filename here, but just in case check for ' and ":
- if (preg_match("/filename=(['\"])([^\\1]+)\\1/", $this->responseHeaders["content-disposition"], $matches)) {
- if(isset($matches[2]) && !empty($matches[2])){
- $file_name = $matches[2];
- // Only accept filenames, not paths:
- if (!preg_match("@/@", $file_name))
- $this->filename = $file_name;
- }
- }
- }
- // state
- $this->state = SIMPLEHTTP_STATE_OK;
- // return content
- return $this->responseBody;
- }
- /**
- * get torrent from URL. Has support for specific sites
- *
- * @param $durl
- * @return string
- */
- function instance_getTorrent($durl) {
- global $cfg;
- // (re)set state
- $this->state = SIMPLEHTTP_STATE_NULL;
- // (re)set redir-count
- $this->redirectCount = 0;
- // Initialize file name:
- $this->filename = "";
- $domain = parse_url($durl);
- // Check we have a remote URL:
- if (!isset($domain["host"])) {
- // Not a remote URL:
- $msg = "The torrent requested for download (".$durl.") is not a remote torrent. Please enter a valid remote torrent URL such as http://example.com/example.torrent\n";
- AuditAction($cfg["constants"]["error"], $msg);
- array_push($this->messages , $msg);
- // state
- $this->state = SIMPLEHTTP_STATE_ERROR;
- // return empty data:
- return ($data="");
- }
- if (strtolower(substr($domain["path"], -8)) != ".torrent") {
- /*
- In these cases below, we check for torrent URLs that have to be manipulated in some
- way to obtain the torrent content. These are sites that perhaps use redirection or
- URL rewriting in some way.
- */
- // Check known domain types
- // mininova
- if (strpos(strtolower($domain["host"]), "mininova") !== false) {
- // Sample (http://www.mininova.org/rss.xml):
- // http://www.mininova.org/tor/2254847
- // <a href="/get/2281554">FreeLinux.ISO.iso.torrent</a>
- // If received a /tor/ get the required information
- if (strpos($durl, "/tor/") !== false) {
- // Get the contents of the /tor/ to find the real torrent name
- $data = $this->instance_getData($durl);
- // Check for the tag used on mininova.org
- if (preg_match("/<a href=\"\/get\/[0-9].[^\"]+\">(.[^<]+)<\/a>/i", $data, $data_preg_match)) {
- // This is the real torrent filename
- $this->filename = $data_preg_match[1];
- }
- // Change to GET torrent url
- $durl = str_replace("/tor/", "/get/", $durl);
- }
- // Now fetch the torrent file
- $data = $this->instance_getData($durl);
- // demonoid
- } elseif (strpos(strtolower($domain["host"]), "demonoid") !== false) {
- // Sample (http://www.demonoid.com/rss/0.xml):
- // http://www.demonoid.com/files/details/241739/6976998/
- // <a href="/files/download/HTTP/241739/6976998">...</a>
- // If received a /details/ page url, change it to the download url
- if (strpos($durl, "/details/") !== false) {
- // Need to make it grab the torrent
- $durl = str_replace("/details/", "/download/HTTP/", $durl);
- }
- // Now fetch the torrent file
- $data = $this->instance_getData($durl);
- // isohunt
- } elseif (strpos(strtolower($domain["host"]), "isohunt") !== false) {
- // Sample (http://isohunt.com/js/rss.php):
- $treferer = "http://" . $domain["host"] . "/btDetails.php?id=";
- // http://isohunt.com/torrent_details/7591035/
- // http://isohunt.com/download/7591035/
- // If the url points to the details page, change it to the download url
- if (strpos($durl, "/torrent_details/") !== false) {
- // Need to make it grab the torrent
- $durl = str_replace("/torrent_details/", "/download/", $durl);
- }
- // old one, but still works:
- // http://isohunt.com/btDetails.php?ihq=&id=8464972
- // http://isohunt.com/download.php?mode=bt&id=8837938
- // If the url points to the details page, change it to the download url
- if (strpos(strtolower($durl), "/btdetails.php?") !== false) {
- // Need to make it grab the torrent
- $durl = str_replace("/btDetails.php?", "/download.php?", $durl) . "&mode=bt";
- }
- // Now fetch the torrent file
- $data = $this->instance_getData($durl, $treferer);
- // details.php
- } elseif (strpos(strtolower($durl), "details.php?") !== false) {
- // Sample (http://www.bitmetv.org/rss.php?passkey=123456):
- // http://www.bitmetv.org/details.php?id=18435&hit=1
- // Strip final &hit=1 if present, since it only ever returns a 302
- // redirect to the same URL without the &hit=1.
- $durl2 = preg_replace('/&hit=1$/', '', $durl);
- $treferer = "http://" . $domain["host"] . "/details.php?id=";
- $data = $this->instance_getData($durl2, $treferer);
- // Sample (http://www.bitmetv.org/details.php?id=18435)
- // download.php/18435/SpiderMan%20Season%204.torrent
- if (preg_match("/(download.php.[^\"]+)/i", $data, $data_preg_match)) {
- $torrent = substr($data_preg_match[0], 0, -1);
- $turl2 = "http://" . $domain["host"] . "/" . $torrent;
- $data = $this->instance_getData($turl2);
- } else {
- $msg = "Error: could not find link to torrent file in $durl";
- AuditAction($cfg["constants"]["error"], $msg);
- array_push($this->messages , $msg);
- // state
- $this->state = SIMPLEHTTP_STATE_ERROR;
- // return empty data:
- return($data="");
- }
- // torrentspy
- } elseif (strpos(strtolower($domain["host"]), "torrentspy") !== false) {
- // Sample (http://torrentspy.com/rss.asp):
- // http://www.torrentspy.com/torrent/1166188/gentoo_livedvd_i686_installer_2007_0
- $treferer = "http://" . $domain["host"] . "/download.asp?id=";
- $data = $this->instance_getData($durl, $treferer);
- // If received a /download.asp?, a /directory.asp?mode=torrentdetails
- // or a /torrent/, extract real torrent link
- if (
- strpos($durl, "/download.asp?") !== false ||
- strpos($durl, "/directory.asp?mode=torrentdetails") !== false ||
- strpos($durl, "/torrent/") !== false
- ) {
- // Check for the tag used in download details page
- if (preg_match("#<a\s+id=\"downloadlink0\"[^>]*?\s+href=\"(http[^\"]+)\"#i", $data, $data_preg_match)) {
- // This is the real torrent download link
- $durl = $data_preg_match[1];
- // Follow it
- $data = $this->instance_getData($durl);
- }
- }
- // download.asp
- } elseif (strpos(strtolower($durl), "download.asp?") !== false) {
- $treferer = "http://" . $domain["host"] . "/download.asp?id=";
- $data = $this->instance_getData($durl, $treferer);
- // default
- } else {
- // Fallback case for any URL not ending in .torrent and not matching the above cases:
- $data = $this->instance_getData($durl);
- }
- } else {
- $data = $this->instance_getData($durl);
- }
- // Make sure we have a torrent file
- if (strpos($data, "d8:") === false) {
- // We don't have a Torrent File... it is something else. Let the user know about it:
- $msg = "Content returned from $durl does not appear to be a valid torrent.";
- AuditAction($cfg["constants"]["error"], $msg);
- array_push($this->messages , $msg);
- // Display the first part of $data if debuglevel higher than 1:
- if ($cfg["debuglevel"] > 1){
- if (strlen($data) > 0){
- array_push($this->messages , "Displaying first 1024 chars of output: ");
- array_push($this->messages , htmlentities(substr($data, 0, 1023)), ENT_QUOTES);
- } else {
- array_push($this->messages , "Output from $durl was empty.");
- }
- } else {
- array_push($this->messages , "Set debuglevel > 2 in 'Admin, Webapps' to see the content returned from $durl.");
- }
- $data = "";
- // state
- $this->state = SIMPLEHTTP_STATE_ERROR;
- } else {
- // If the torrent file name isn't set already, do it now:
- if ((!isset($this->filename)) || (strlen($this->filename) == 0)) {
- // Get the name of the torrent, and make it the filename
- if (preg_match("/name([0-9][^:]):(.[^:]+)/i", $data, $data_preg_match)) {
- $filelength = $data_preg_match[1];
- $file_name = $data_preg_match[2];
- $this->filename = substr($file_name, 0, $filelength).".torrent";
- } else {
- require_once('inc/classes/BDecode.php');
- $btmeta = @BDecode($data);
- $this->filename = ((is_array($btmeta)) && (!empty($btmeta['info'])) && (!empty($btmeta['info']['name'])))
- ? trim($btmeta['info']['name']).".torrent"
- : "";
- }
- }
- // state
- $this->state = SIMPLEHTTP_STATE_OK;
- }
- return $data;
- }
- /**
- * get nzb from URL
- *
- * @param $durl
- * @return string
- */
- function instance_getNzb($durl) {
- global $cfg;
- // (re)set state
- $this->state = SIMPLEHTTP_STATE_NULL;
- // (re)set redir-count
- $this->redirectCount = 0;
- // Initialize file name:
- $this->filename = "";
- $domain = parse_url($durl);
- // Check we have a remote URL:
- if (!isset($domain["host"])) {
- // Not a remote URL:
- $msg = "The nzb requested for download (".$durl.") is not a remote nzb. Please enter a valid remote nzb URL such as http://example.com/example.nzb\n";
- AuditAction($cfg["constants"]["error"], $msg);
- array_push($this->messages , $msg);
- // state
- $this->state = SIMPLEHTTP_STATE_ERROR;
- // return empty data:
- return ($data="");
- }
- if (strtolower(substr($domain["path"], -4)) != ".nzb") {
- /*
- In these cases below, we check for URLs that have to be manipulated in some
- way to obtain the content. These are sites that perhaps use redirection or
- URL rewriting in some way.
- */
- // details.php
- if (strpos(strtolower($durl), "details.php?") !== false) {
- // Sample (http://www.bitmetv.org/rss.php?passkey=123456):
- // http://www.bitmetv.org/details.php?id=18435&hit=1
- // Strip final &hit=1 if present, since it only ever returns a 302
- // redirect to the same URL without the &hit=1.
- $durl2 = preg_replace('/&hit=1$/', '', $durl);
- $treferer = "http://" . $domain["host"] . "/details.php?id=";
- $data = $this->instance_getData($durl, $treferer);
- // Sample (http://www.bitmetv.org/details.php?id=18435)
- // download.php/18435/SpiderMan%20Season%204.torrent
- if (preg_match("/(download.php.[^\"]+)/i", $data, $data_preg_match)) {
- $tr = substr($data_preg_match[0], 0, -1);
- $turl2 = "http://" . $domain["host"] . "/" . $tr;
- $data = $this->instance_getData($turl2);
- } else {
- $msg = "Error: could not find link to nzb file in $durl";
- AuditAction($cfg["constants"]["error"], $msg);
- array_push($this->messages , $msg);
- // state
- $this->state = SIMPLEHTTP_STATE_ERROR;
- // return empty data:
- return($data="");
- }
- // download.asp
- } elseif (strpos(strtolower($durl), "download.asp?") !== false) {
- // Sample (TF's TorrentSpy Search):
- // http://www.torrentspy.com/download.asp?id=519793
- $treferer = "http://" . $domain["host"] . "/download.asp?id=";
- $data = $this->instance_getData($durl, $treferer);
- // default
- } else {
- // Fallback case for any URL not ending in .nzb and not matching the above cases:
- $data = $this->instance_getData($durl);
- }
- } else {
- $data = $this->instance_getData($durl);
- }
- // Make sure we have a nzb file
- if (strpos($data, "nzb") === false) {
- // We don't have a nzb File... it is something else. Let the user know about it:
- $msg = "Content returned from $durl does not appear to be a valid nzb.";
- AuditAction($cfg["constants"]["error"], $msg);
- array_push($this->messages , $msg);
- // Display the first part of $data if debuglevel higher than 1:
- if ($cfg["debuglevel"] > 1){
- if (strlen($data) > 0){
- array_push($this->messages , "Displaying first 1024 chars of output: ");
- array_push($this->messages , htmlentities(substr($data, 0, 1023)), ENT_QUOTES);
- } else {
- array_push($this->messages , "Output from $durl was empty.");
- }
- } else {
- array_push($this->messages , "Set debuglevel > 2 in 'Admin, Webapps' to see the content returned from $durl.");
- }
- $data = "";
- // state
- $this->state = SIMPLEHTTP_STATE_ERROR;
- } else {
- // state
- $this->state = SIMPLEHTTP_STATE_OK;
- }
- return $data;
- }
- /**
- * get size from URL.
- *
- * @param $durl
- * @return string
- */
- function instance_getRemoteSize($durl) {
- // set fields
- $this->url = $durl;
- $this->timeout = 8;
- $this->status = "";
- $this->errstr = "";
- $this->errno = 0;
- // domain
- $domain = parse_url($this->url);
- if (!isset($domain["port"]))
- $domain["port"] = 80;
- // check we have a remote URL:
- if (!isset($domain["host"]))
- return 0;
- // check we have a remote path:
- if (!isset($domain["path"]))
- return 0;
- // open socket
- $this->socket = @fsockopen($domain["host"], $domain["port"], $this->errno, $this->errstr, $this->timeout);
- if (!$this->socket)
- return 0;
- // send HEAD request
- $this->request = "HEAD ".$domain["path"]." HTTP/1.0\r\nConnection: Close\r\n\r\n";
- @fwrite($this->socket, $this->request);
- // socket options
- stream_set_timeout($this->socket, $this->timeout);
- // meta data
- $info = stream_get_meta_data($this->socket);
- // read the response
- $this->responseBody = "";
- $ctr = 0;
- while ((!$info['timed_out']) && ($ctr < 25)) {
- $s = @fgets($this->socket, 4096);
- $this->responseBody .= $s;
- if (strcmp($s, "\r\n") == 0 || strcmp($s, "\n") == 0)
- break;
- // meta data
- $info = stream_get_meta_data($this->socket);
- // increment counter
- $ctr++;
- }
- // close socket
- @fclose($this->socket);
- // try to get Content-Length in response-body
- preg_match('/Content-Length:\s([0-9].+?)\s/', $this->responseBody, $matches);
- return (isset($matches[1]))
- ? $matches[1]
- : 0;
- }
- /**
- * Check whether PHP can do TLS.
- *
- * @return bool
- */
- function _canTLS() {
- // Just check whether openssl extension is available.
- if (!isset($this->canTLS))
- $this->canTLS = extension_loaded('openssl');
- return $this->canTLS;
- }
- /**
- * URL-encode all fragments of an URL, not re-encoding what is already encoded.
- *
- * @param $url
- * @return string
- */
- function _fullURLEncode($url) {
- # Split URL into fragments, delimiters are: '+', ':', '@', '/', '?', '=', '&' and /%[[:xdigit:]]{2}/.
- $fragments = preg_split('#[+:@/?=&]+|%[[:xdigit:]]{2}#', $url, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE);
- for ($i = count($fragments) - 1; $i >= 0; $i--) {
- $fragment = $fragments[$i]; # $fragment[0] is the fragment, $fragment[1] is its starting position.
- $url = substr_replace($url, rawurlencode($fragment[0]), $fragment[1], strlen($fragment[0]));
- }
- return $url;
- }
- }
- ?>
|