pingpong24 Posted December 27, 2005 Posted December 27, 2005 (edited) expandcollapse popup<?php // +----------------------------------------------------------------------+ // | Decode and Encode data in Bittorrent format | // +----------------------------------------------------------------------+ // | Copyright (C) 2004-2005 Markus Tacker <m@tacker.org> | // +----------------------------------------------------------------------+ // | This library is free software; you can redistribute it and/or | // | modify it under the terms of the GNU Lesser General Public | // | License as published by the Free Software Foundation; either | // | version 2.1 of the License, or (at your option) any later version. | // | | // | This library 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 | // | Lesser General Public License for more details. | // | | // | You should have received a copy of the GNU Lesser General Public | // | License along with this library; if not, write to the | // | Free Software Foundation, Inc. | // | 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | // +----------------------------------------------------------------------+ /** * Encode data in Bittorrent format * * Based on * Original Python implementation by Petru Paler <petru@paler.net> * PHP translation by Gerard Krijgsman <webmaster@animesuki.com> * Gerard's regular exp[b][/b]ressions removed by Carl Ritson <critson@perlfu.co.uk> * Info on the .torrent file format * BEncoding is a simple, easy to implement method of associating * data types with information in a file. The values in a torrent * file are bEncoded. * There are 4 different data types that can be bEncoded: * Integers, Strings, Lists and Dictionaries. * [http://www.monduna.com/bt/faq.html] * * @package File_Bittorrent * @category File * @author Markus Tacker <m@tacker.org> * @version $Id: Decode.php 49 2005-10-19 17:06:23Z m $ */ /** * Include required classes */ require_once 'PEAR.php'; require_once 'PHP/Compat.php'; require_once 'File/Bittorrent/Encode.php'; /** * Load replacement functions */ PHP_Compat::loadFunction('file_get_contents'); /** * Encode data in Bittorrent format * * Based on * Original Python implementation by Petru Paler <petru@paler.net> * PHP translation by Gerard Krijgsman <webmaster@animesuki.com> * Gerard's regular exp[b][/b]ressions removed by Carl Ritson <critson@perlfu.co.uk> * Info on the .torrent file format * BEncoding is a simple, easy to implement method of associating * data types with information in a file. The values in a torrent * file are bEncoded. * There are 4 different data types that can be bEncoded: * Integers, Strings, Lists and Dictionaries. * [http://www.monduna.com/bt/faq.html] * * @package File_Bittorrent * @category File * @author Markus Tacker <m@tacker.org> */ class File_Bittorrent_Decode { /** * @var string Name of the torrent */ var $name = ''; /** * @var string Filename of the torrent */ var $filename = ''; /** * @var string Comment */ var $comment = ''; /** * @var int Creation date as unix timestamp */ var $date = 0; /** * @var array Files in the torrent */ var $files = array(); /** * @var int Size of of the full torrent (after download) */ var $size = 0; /** * @var string Signature of the software which created the torrent */ var $created_by = ''; /** * @var string tracker (the tracker the torrent has been received from) */ var $announce = ''; /** * @var array List of known trackers for the torrent */ var $announce_list = array(); /** * @var string Source string * @access private */ var $_source = ''; /** * @var int Source length * @access private */ var $_source_length = 0; /** * @var int Current position of the string * @access private */ var $_position = 0; /** * @var string Info hash */ var $info_hash; /** * @var mixed The last error object or null if no error has occurred. */ var $last_error; /** * Decode a Bencoded string * * @param string * @return mixed */ function decode($str) { $this->_source = $str; $this->_position = 0; $this->_source_length = strlen($this->_source); return $this->_bdecode(); } /** * Decode .torrent file and accumulate information * * @param string Filename * @return mixed Returns an arrayon success or false on error */ function decodeFile($file) { // Check file if (!is_file($file)) { $this->last_error = PEAR::raiseError('File_Bittorrent_Decode::decode() - Not a file.', null, null, "Given filename '$file' is not a valid file."); return false; } // Reset public attributes $this->name = ''; $this->filename = ''; $this->comment = ''; $this->date = 0; $this->files = array(); $this->size = 0; $this->created_by = ''; $this->announce = ''; $this->announce_list = array(); $this->_position = 0; $this->info_hash = ''; // Decode .torrent $this->_source = file_get_contents($file); $this->_source_length = strlen($this->_source); $decoded = $this->_bdecode(); if (!is_array($decoded)) { $this->last_error = PEAR::raiseError('File_Bittorrent_Decode::decode() - Corrupted bencoded data.', null, null, "Failed to decode data from file '$file'."); return false; } // Compute info_hash $Encoder = new File_Bittorrent_Encode; $this->info_hash = sha1($Encoder->encode($decoded['info'])); // Pull information form decoded data $this->filename = basename($file); // Name of the torrent - statet by the torrent's author $this->name = $decoded['info']['name']; // Authors may add comments to a torrent if (isset($decoded['comment'])) { $this->comment = $decoded['comment']; } // Creation date of the torrent as unix timestamp if (isset($decoded['creation date'])) { $this->date = $decoded['creation date']; } // This contains the signature of the application used to create the torrent if (isset($decoded['created by'])) { $this->created_by = $decoded['created by']; } // Get the directory separator $sep = (PHP_OS == 'Linux') ? '/' : '\\'; // There is sometimes an array listing all files // in the torrent with their individual filesize if (isset($decoded['info']['files']) and is_array($decoded['info']['files'])) { foreach ($decoded['info']['files'] as $file) { $path = join($sep, $file['path']); // We are computing the total size of the download heres $this->size += $file['length']; $this->files[] = array( 'filename' => $path, 'size' => $file['length'], ); } // In case the torrent contains only on file } elseif(isset($decoded['info']['name'])) { $this->files[] = array( 'filename' => $decoded['info']['name'], 'size' => $decoded['info']['length'], ); } // If the the info->length field is present we are dealing with // a single file torrent. if (isset($decoded['info']['length']) and $this->size == 0) { $this->size = $decoded['info']['length']; } // This contains the tracker the torrent has been received from if (isset($decoded['announce'])) { $this->announce = $decoded['announce']; } // This contains a list of all known trackers for this torrent if (isset($decoded['announce-list']) and is_array($decoded['announce-list'])) { foreach($decoded['announce-list'] as $item) { if (!isset($item[0])) continue; $this->announce_list[] = $item[0]; } } // Currently, I'm not sure how to determine an error // Just try to fetch the info from the decoded data // and return it return array( 'name' => $this->name, 'filename' => $this->filename, 'comment' => $this->comment, 'date' => $this->date, 'created_by' => $this->created_by, 'files' => $this->files, 'size' => $this->size, 'announce' => $this->announce, 'announce_list' => $this->announce_list, ); } /** * Decode a BEncoded String * * @access private * @return mixed Returns the representation of the data in the BEncoded string or false on error */ function _bdecode() { switch ($this->_getChar()) { case 'i': $this->_position++; return $this->_decode_int(); break; case 'l': $this->_position++; return $this->_decode_list(); break; case 'd': $this->_position++; return $this->_decode_dict(); break; default: return $this->_decode_string(); } } /** * Decode a BEncoded dictionary * * Dictionaries are prefixed with a d and terminated by an e. They * are similar to list, except that items are in key value pairs. The * dictionary {"key":"value", "Monduna":"com", "bit":"Torrents", "number":7} * would bEncode to d3:key5:value7:Monduna3:com3:bit:8:Torrents6:numberi7ee * * @access private * @return array */ function _decode_dict() { while ($char = $this->_getChar()) { if ($char == 'e') break; $key = $this->_decode_string(); $val = $this->_bdecode(); $return[$key] = $val; } $this->_position++; return $return; } /** * Decode a BEncoded string * * Strings are prefixed with their length followed by a colon. * For example, "Monduna" would bEncode to 7:Monduna and "BitTorrents" * would bEncode to 11:BitTorrents. * * @access private * @return string|false */ function _decode_string() { // Find position of colon // Supress error message if colon is not found which may be caused by a corrupted or wrong encoded string if(!$pos_colon = @strpos($this->_source, ':', $this->_position)) { return false; } // Get length of string $str_length = intval(substr($this->_source, $this->_position, $pos_colon)); // Get string $return = substr($this->_source, $pos_colon + 1, $str_length); // Move Pointer after string $this->_position = $pos_colon + $str_length + 1; return $return; } /** * Decode a BEncoded integer * * Integers are prefixed with an i and terminated by an e. For * example, 123 would bEcode to i123e, -3272002 would bEncode to * i-3272002e. * * @access private * @return int */ function _decode_int() { $pos_e = strpos($this->_source, 'e', $this->_position); $return = intval(substr($this->_source, $this->_position, $pos_e - $this->_position)); $this->_position = $pos_e + 1; return $return; } /** * Decode a BEncoded list * * Lists are prefixed with a l and terminated by an e. The list * should contain a series of bEncoded elements. For example, the * list of strings ["Monduna", "Bit", "Torrents"] would bEncode to * l7:Monduna3:Bit8:Torrentse. The list [1, "Monduna", 3, ["Sub", "List"]] * would bEncode to li1e7:Mondunai3el3:Sub4:Listee * * @access private * @return array */ function _decode_list() { $return = array(); $char = $this->_getChar(); while ($this->_source{$this->_position} != 'e') { $val = $this->_bdecode(); $return[] = $val; } $this->_position++; return $return; } /** * Get the char at the current position * * @access private * @return string|false */ function _getChar() { if (empty($this->_source)) return false; if ($this->_position >= $this->_source_length) return false; return $this->_source{$this->_position}; } /** * Returns the online stats for the torrent * * @return array|false */ function getStats() { // Check if we can access remote data if (!ini_get('allow_url_fopen')) { $this->last_error = PEAR::raiseError('File_Bittorrent_Decode::getStats() - "allow_url_fopen" must be enabled.'); return false; } // Query the scrape page $packed_hash = pack('H*', $this->info_hash); $scrape_url = preg_replace('/\/announce$/', '/scrape', $this->announce) . '?info_hash=' . urlencode($packed_hash); $scrape_data = file_get_contents($scrape_url); $stats = $this->decode($scrape_data); if (!isset($stats['files'][$packed_hash])) { $this->last_error = PEAR::raiseError('File_Bittorrent_Decode::getStats() - Invalid scrape data: "' . $scrape_data . '"'); return false; } return $stats['files'][$packed_hash]; } } ?>That is the PHP version of decoding a torrent, however i dont understand what $this-> does... therefore have no clue how to code it using autoit, i am using an external SHA1 program to hash using solid snakes HASHING UDF.All i want to do is get all the verables into Strings, so put info_hash data into $INFO_hash then RUN SHA1 on $INFO_hash and thats it.. all done.how to decode the torrent file: http://www.monduna.com/bt/faq.html#TERM_12However i cant code it Below is what is found inside an average torrent file. however many things are missing as its binary i couldnt copy and paste everything.d8:announce44:http://zerowing.idsoftware.com:6969/announce13:creation datei1135684016e4:infod6:lengthi11001339e4:name32:doom3-linux-1.3.1302-sdk.x86.run12:piece lengthi65536e6:pieces3360:¯Âµ¦.¨z z«hY.<^3_8Ê)|%Ï=ß]=ë¬-Ы¤Úåñ'Ã¥´^8kb{3Sؤè);¿]ötË7R^ýüöõ#¬â]Fé`yt©ÊüÐv>Ü¡z9)\ ª}amF&í £òW¹ç® bJÊ7«×¨§E ¹ÐÖÝ&z"Ì3w G® fnÇ<¢¤Ð@Dim $name = ""Dim $filename = ""Dim $comment = ""Dim $date = 0Dim $files ; arrayDim $size = 0Dim $created_by = ""dim $announce = ""dim $announce_list ;arraydim $_source = "" Dim $_source_length = 0Dim $_position = 0Dim $info_hash Dim $last_error Above is all the verables i need to extract from the Bencode torrent file.I have attached an example torrent, i named it demo.txt because demo.torrent is blocked from geting uploaded.#Include <FileHashSHA1.au3> $file = FileOpen("demo.torrent", 0) dim $counter = 1 while 1 $test = FileRead($file, 1) if @error = -1 exitloop $counter = $counter + 1 wend $torrentdata = FileRead($file, $test) ; due to verable torrent file size.. this way i get the entire torrent data FileClose($file) ; NOW once you have $torrentdata, i want to sperate out all the stuff into string ; such as "info" to $info_hash then SHA1 hashing it. $decoded_info_hash =_FileHashSHA1($info_hash) ;now i have info hash, decodedAs you can see i can do rest of the code, only part i am stuck on is extracting all the required data.demo.txt Edited December 27, 2005 by pingpong24 NumCR Super Fast EASY NUMBER OCR, easiest and the fastest AUTOIT OCR released on this forum
Ndru Posted December 27, 2005 Posted December 27, 2005 The pseudo-variable $this is a reference to the calling object in PHP
netmaniack Posted June 28, 2006 Posted June 28, 2006 i think this is a bit better code expandcollapse popup<? /* Basic knowledge of how bencoding works is assumed. Details can be found at <http://bitconjurer.org/BitTorrent/protocol.html>. How to use these functions: An "object" is defined to be an associative array with at least the keys "type" and "value" present. The "type" key contains a string which is one of "string", "integer", "list" or "dictionary". The "value" key contains the appropriate thing, either a string, an integer, a list which is just a flat array, or a dictionary, which is an associative array. In the case of "list" and "dictionary", the values of the contained array are agaib "objects". Description of the functions: string benc($obj); Takes an object as argument and returns the bencoded form of it as string. Returns the undefined/unset value on failure. Examples: benc(array(type => "string", value => "spam")) returns "4:spam". benc(array(type => "integer", value => 3)) returns "i3e". benc(array(type => "list", value => array( array(type => "string", value => "spam"), array(type => "string", value => "eggs") ))) returns "l4:spam4:eggse" benc(array(type => "dictionary", value => array( cow => array(type => "string", value => "moo"), spam => array(type => "string", value => "eggs"), ))) returns "d3:cow3:moo4:spam4:eggse" object bdec($str); Returns the object that results from bdecoding the given string. Note that those aren't real php objects, but merely "objects" as described above. The returned objects have two additional keys: "string" and "strlen". They represent the bencoded form of the returned objects, as it was given in the original bencoded string. Use this to extract certain portions of a bencoded string without having to re-encode it (and avoiding possible re-ordering of dictionary keys). $x["strlen"] is always equivalent to strlen($x["string"]). The "string" attribute of the top-level returned object will be the same as the original bencoded string, unless there's trailing garbage at the end of the string. This function returns the undefined/unset value on failure. Example: bdec("d4:spaml11:spiced pork3:hamee") returns this monster: Array ( [type] => dictionary [value] => Array ( [spam] => Array ( [type] => list [value] => Array ( [0] => Array ( [type] => string [value] => spiced pork [strlen] => 14 [string] => 11:spiced pork ) [1] => Array ( [type] => string [value] => ham [strlen] => 5 [string] => 3:ham ) ) [strlen] => 21 [string] => l11:spiced pork3:hame ) ) [strlen] => 29 [string] => d4:spaml11:spiced pork3:hamee ) object bdec_file($filename, $maxsize); Opens the specified file, reads its contents (up to the specified length), and returns whatever bdec() returns for those contents. This is a simple convenience function. */ function benc($obj) { if (!is_array($obj) || !isset($obj["type"]) || !isset($obj["value"])) return; $c = $obj["value"]; switch ($obj["type"]) { case "string": return benc_str($c); case "integer": return benc_int($c); case "list": return benc_list($c); case "dictionary": return benc_dict($c); default: return; } } function benc_str($s) { return strlen($s) . ":$s"; } function benc_int($i) { return "i" . $i . "e"; } function benc_list($a) { $s = "l"; foreach ($a as $e) { $s .= benc($e); } $s .= "e"; return $s; } function benc_dict($d) { $s = "d"; $keys = array_keys($d); sort($keys); foreach ($keys as $k) { $v = $d[$k]; $s .= benc_str($k); $s .= benc($v); } $s .= "e"; return $s; } function bdec_file($f, $ms) { $fp = fopen($f, "rb"); if (!$fp) return; $e = fread($fp, $ms); fclose($fp); return bdec($e); } function bdec($s) { if (preg_match('/^(\d+):/', $s, $m)) { $l = $m[1]; $pl = strlen($l) + 1; $v = substr($s, $pl, $l); $ss = substr($s, 0, $pl + $l); if (strlen($v) != $l) return; return array(type => "string", value => $v, strlen => strlen($ss), string => $ss); } if (preg_match('/^i(\d+)e/', $s, $m)) { $v = $m[1]; $ss = "i" . $v . "e"; if ($v === "-0") return; if ($v[0] == "0" && strlen($v) != 1) return; return array(type => "integer", value => $v, strlen => strlen($ss), string => $ss); } switch ($s[0]) { case "l": return bdec_list($s); case "d": return bdec_dict($s); default: return; } } function bdec_list($s) { if ($s[0] != "l") return; $sl = strlen($s); $i = 1; $v = array(); $ss = "l"; for (;;) { if ($i >= $sl) return; if ($s[$i] == "e") break; $ret = bdec(substr($s, $i)); if (!isset($ret) || !is_array($ret)) return; $v[] = $ret; $i += $ret["strlen"]; $ss .= $ret["string"]; } $ss .= "e"; return array(type => "list", value => $v, strlen => strlen($ss), string => $ss); } function bdec_dict($s) { if ($s[0] != "d") return; $sl = strlen($s); $i = 1; $v = array(); $ss = "d"; for (;;) { if ($i >= $sl) return; if ($s[$i] == "e") break; $ret = bdec(substr($s, $i)); if (!isset($ret) || !is_array($ret) || $ret["type"] != "string") return; $k = $ret["value"]; $i += $ret["strlen"]; $ss .= $ret["string"]; if ($i >= $sl) return; $ret = bdec(substr($s, $i)); if (!isset($ret) || !is_array($ret)) return; $v[$k] = $ret; $i += $ret["strlen"]; $ss .= $ret["string"]; } $ss .= "e"; return array(type => "dictionary", value => $v, strlen => strlen($ss), string => $ss); } ?>
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now