Source for file Decode.php
Documentation is available at Decode.php
// +----------------------------------------------------------------------+
// | Decode and Encode data in Bittorrent format |
// +----------------------------------------------------------------------+
// | Copyright (C) 2004-2006 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
* Original Python implementation by Petru Paler <petru@paler.net>
* PHP translation by Gerard Krijgsman <webmaster@animesuki.com>
* Gerard's regular expressions 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
* 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
* @author Markus Tacker <m@tacker.org>
* @author Robin H. Johnson <robbat2@gentoo.org>
* @version $Id: Decode.php 65 2006-10-23 10:46:20Z m $
* Include required classes
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
* Original Python implementation by Petru Paler <petru@paler.net>
* PHP translation by Gerard Krijgsman <webmaster@animesuki.com>
* Gerard's regular expressions 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
* 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
* @author Markus Tacker <m@tacker.org>
* @author Robin H. Johnson <robbat2@gentoo.org>
* @var string Name of the torrent
* @var string Filename of the torrent
* @var int Creation date as unix timestamp
* @var array Files in the torrent
* @var int Size of of the full torrent (after download)
* @var string Signature of the software which created the torrent
* @var string tracker (the tracker the torrent has been received from)
* @var array List of known trackers for the torrent
* @var string Source string
* @var int Current position of the string
* @var mixed The last error object or null if no error has occurred.
* @var array Decoded data from File_Bittorrent_Decode::decodeFile()
* Decode a Bencoded string
$this->_source_length = strlen($this->_source);
$result = $this->_bdecode ();
if ($this->_position < $this->_source_length) {
$this->last_error = PEAR ::raiseError ('File_Bittorrent_Decode::decode() - Trailing garbage in file.');
* Decode .torrent file and accumulate information
* @return mixed Returns an arrayon success or false on error
$this->last_error = PEAR ::raiseError ('File_Bittorrent_Decode::decode() - Not a file.', null , null , " Given filename '$file' is not a valid file." );
// Reset public attributes
$this->_source_length = strlen($this->_source);
$this->decoded = $this->_bdecode ();
$this->last_error = PEAR ::raiseError ('File_Bittorrent_Decode::decode() - Corrupted bencoded data.', null , null , " Failed to decode data from file '$file'." );
// Pull information form decoded data
// Name of the torrent - statet by the torrent's author
// Authors may add comments to a torrent
if (isset ($this->decoded['comment'])) {
// Creation date of the torrent as unix timestamp
if (isset ($this->decoded['creation date'])) {
// This contains the signature of the application used to create the torrent
if (isset ($this->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
foreach ($this->decoded['info']['files'] as $file) {
$path = join($sep, $file['path']);
// We are computing the total size of the download heres
$this->size += $file['length'];
'size' => $file['length'],
// In case the torrent contains only on file
} elseif (isset ($this->decoded['info']['name'])) {
'filename' => $this->decoded['info']['name'],
'size' => $this->decoded['info']['length'],
// If the the info->length field is present we are dealing with
// a single file torrent.
if (isset ($this->decoded['info']['length']) and $this->size == 0 ) {
// This contains the tracker the torrent has been received from
if (isset ($this->decoded['announce'])) {
// This contains a list of all known trackers for this torrent
// Currently, I'm not sure how to determine an error
// Just try to fetch the info from the decoded data
* Decode a BEncoded String
* @return mixed Returns the representation of the data in the BEncoded string or false on error
switch ($this->_getChar ()) {
return $this->_decode_int ();
return $this->_decode_list ();
return $this->_decode_dict ();
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
while ($char = $this->_getChar ()) {
$this->last_error = PEAR ::raiseError ('File_Bittorrent_Decode::_decode_dict() - Invalid dictionary key.');
$key = $this->_decode_string ();
if (isset ($return[$key])) {
$this->last_error = PEAR ::raiseError ('File_Bittorrent_Decode::_decode_dict() - Duplicate dictionary key.');
$this->last_error = PEAR ::raiseError ('File_Bittorrent_Decode::_decode_dict() - Missorted dictionary key.');
$val = $this->_bdecode ();
$this->last_error = PEAR ::raiseError ('File_Bittorrent_Decode::_decode_dict() - Invalid value.');
$this->last_error = PEAR ::raiseError ('File_Bittorrent_Decode::_decode_dict() - Unterminated dictionary.');
* 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.
function _decode_string ()
// Check for bad leading zero
if (substr($this->_source, $this->_position, 1 ) == '0' and
substr($this->_source, $this->_position + 1 , 1 ) != ':') {
$this->last_error = PEAR ::raiseError ('File_Bittorrent_Decode::_decode_string() - Leading zero in string length.');
// 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)) {
$this->last_error = PEAR ::raiseError ('File_Bittorrent_Decode::_decode_string() - Colon not found.');
$str_length = intval(substr($this->_source, $this->_position, $pos_colon));
if ($str_length + $pos_colon + 1 > $this->_source_length) {
$this->last_error = PEAR ::raiseError ('File_Bittorrent_Decode::_decode_string() - Input too short for string length.');
$return = substr($this->_source, $pos_colon + 1 , $str_length);
// Move Pointer after string
$this->_position = $pos_colon + $str_length + 1;
* 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
$pos_e = strpos($this->_source, 'e', $this->_position);
$this->last_error = PEAR ::raiseError ('File_Bittorrent_Decode::_decode_int() - Empty integer.');
if (substr($this->_source, $this->_position, 1 ) == '-') $p++;
if (substr($this->_source, $p, 1 ) == '0' and
($p != $this->_position or $pos_e > $p+1 )) {
$this->last_error = PEAR ::raiseError ('File_Bittorrent_Decode::_decode_int() - Leading zero in integer.');
for ($i = $p; $i < $pos_e-1; $i++ ) {
$this->last_error = PEAR ::raiseError ('File_Bittorrent_Decode::_decode_int() - Non-digit characters in integer.');
// The return value showld be automatically casted to float if the intval would
// overflow. The "+ 0" accomplishes exactly that, using the internal casting
$return = substr($this->_source, $this->_position, $pos_e - $this->_position) + 0;
$this->_position = $pos_e + 1;
* 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
$char = $this->_getChar ();
$this->last_error = PEAR ::raiseError ('File_Bittorrent_Decode::_decode_list() - Unterminated list.');
while ($char !== false && substr($this->_source, $this->_position, 1 ) != 'e') {
$val = $this->_bdecode ();
// Empty does not work here
$this->last_error = PEAR ::raiseError ('File_Bittorrent_Decode::_decode_list() - Unterminated list.');
* Get the char at the current position
if (empty ($this->_source)) return false;
if ($this->_position >= $this->_source_length) return false;
return substr($this->_source, $this->_position, 1 );
* Returns the online stats for the torrent
// Check if we can access remote data
$this->last_error = PEAR ::raiseError ('File_Bittorrent_Decode::getStats() - "allow_url_fopen" must be enabled.');
$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 $stats['files'][$packed_hash];
Documentation generated on Tue, 13 Mar 2007 10:00:11 -0500 by phpDocumentor 1.3.0. PEAR Logo Copyright © PHP Group 2004.
|