BEncoded is a PHP OOP wrapper for two lightenc.php functions from Theory.org for manipulating bencoded data. It lets you transform bencoded files, retrieve data from them, add some, delete, calculate info hashes and do other things using a simple interface.
Can't want to see? Download now or view its source.
First version on 1 July 2011; last update on 23 January 2012.
Bencoding is used in BitTorrent files (.torrent) to serialize arrays, integers and strings into a single string that can be stored and safely unserialized later.
Try uploading a bencoded file (such as any .torrent file) in the box below (drag & drop works in Firefox and Chrome). You will see the contents of this file that was retrieved using the BEncoded class.
The demo form above uses FileDrop JavaScript uploader.
<?php
require 'bencoded.php';
$be = new BEncoded;
$be->NewNode('dict', 'child');
$be->Set('child/key', 'value');
$be->Set('child/_key', '_val');
echo $be->ToString(); // => d5:childd4:_key4:_val3:key5:valueee
echo $be->Get('child/key'); // => value
var_export( $be->Get('child') );
// => array ( 'isDct' => true, 'key' => 'value', '_key' => '_val', )
// isDct is an internal marker used to differentiate between Dictionaries and Lists.
$be->FromFile('1.torrent');
// or this, which is the same:
//$be = new BEncoded(file_get_contents('1.torrent'));
echo $be->InfoHash(); // => DFE39EFFF439B78BB2DD2CAEB69B72ACFE660710
BEncoded class
is released in public domain – feel free to use it as you wish.
BEncoded uses two functions writen by someone else, which, however, are also in public domain judging from the head comment.
Please give feedback in the comments if you are using this class or need some help. As of today, this class is known to be used at i-Tools.org.
Some functions (Get, Delete, etc.) support referencing of nodes using a special path format. Its syntax is the same as for web paths: /root_node/child/sub/... with some additions:
Everything is performed using PHPBEncoded
class; one instance represents one bundle
of bencoded data.
PHPBEncoded
uses exceptions to report errors – currently there's just one exception
class, PHPEBEncode
, which is just like standard PHP Exception class with one added property – PHPEBEncode->$obj
– which contains an instance of PHPBEncoded
that has caused the error or PHPnull
if a static method has caused it.
static function Decode($str);
Decodes PHP$str
into a dictionary, list, integer or string. Throws EBEncode if couldn't.
static function Encode($data, $tempChar = null);
Turns PHP$data
into bencoded string. Throws EBEncode if couldn't.
PHPnull
, all nodes which name start with PHP$tempChar
will be excluded from result; see also bskip().static function TypeOf($value);
PHP$value
is an array and contains isDct keystatic function HashOf($nodes, $raw = false);
Calculates bencoded hash – SHA-1 of the bencoded string. Returns an upper-case string 40 characters long (PHP$raw == false
) or raw binary string 20 characters long (PHP$raw == true
).
Can be used to calculate torrent info-hashes (hash of torrent's info dictionary) as explained here.
See also PHPBEncoded->
InfoHash instance method that can be used to quickly retrieve the hash from currently loaded .torrent file.
$value = array('str1', 'str2');
echo BEncoded::HashOf($value);
920EBA4204B15839A1DD57D359C3609ABF4FEF3A
PHPBEncoded
class has the following public properties (which are not recommended to be changed directly):
PHPBEncoded
instance owns and operates upon.function __construct($str = null);
function TempChar($new = null);
If PHP$new
is given, sets new PHPBEncoded->
$tempChar that is used to omit keys (when exporting using ToString, Encode, bencode and others) from all dictionaries that start with this specific substring. This can be used to create temporary variables or some other internal fields that must not be present in exported (encoded) data.
Returns new temporary character. See also bskip.
Default temp char is PHPnull
meaning no keys are excluded. To set temp char to PHPnull
after it has been set pass empty string (PHP''
), not PHPnull
.
echo 'Current: ', $be->TempChar();
echo 'New: ', $be->TempChar('_');
echo 'It\'s null again: ', $be->TempChar('');
$be = new BEncoded;
$be->NewNode('dict', '/');
$be->Set('key', 'value');
$be->Set('_key', '_val');
$be->Set('other', 1.23);
echo 'Current temp char: ', $be->TempChar(), "\n";
echo $be->Export(), "\n\n";
echo 'New temp char: ', $be->TempChar('_'), "\n";
echo $be->Export(), "\n\n";
echo 'No temp char again: ', $be->TempChar(''), "\n";
echo $be->Export(), "\n\n";
Current temp char: key: 'value' _key: '_val' other: 1.2 New temp char: _ key: 'value' other: 1.2 No temp char again: key: 'value' _key: '_val' other: 1.2
As you can see, when temp char is «_» all keys starting with underscore were ignored. This works on all children as well:
$be = new BEncoded();
$be->NewNode('dict', 'child');
$be->Set('child/key', 'value');
$be->Set('child/_key', '_val');
echo 'Current temp char: ', $be->TempChar(), "\n";
echo $be->Export(), "\n\n";
echo 'New temp char: ', $be->TempChar('_'), "\n";
echo $be->Export(), "\n\n";
Current temp char: child: key: 'value' _key: '_val' New temp char: _ child: key: 'value'
function FromString($str);
Loads unserialized data from bencoded string PHP;str
into the PHPBEncoded
instance. Returns nothing. Throws EBEncode if PHP$str
decodes to a non-array (neither a list nor a dictionary).
function FromFile($file);
Loads unserialized data from bencoded file PHP;file
into the PHPBEncoded
instance. Returns nothing. Throws EBEncode if the file couldn't be read.
See also FromString, Decode.
function ToString();
Serializes data of current PHPBEncoded
instance using bencoding and returns it as a string.
function ToFile($file);
Serializes data of current PHPBEncoded
instance using bencoding and saves it to file PHP$file
. Returns number of bytes written. Throws EBEncode if the file couldn't be written.
function Root();
Returns the root of the current node tree.
Attention: it's only a shallow copy meaning that if you change all but immediate items of the result you'll effectively change the data within the PHPBEncoded
instance.
function ValueOf($name);
Returns value of the node located on given path (PHP$name
).
Attention: it's only a shallow copy meaning that if you change all but immediate items of the result you'll effectively change the data within the PHPBEncoded
instance.
function Get($name);
Alias for ValueOf; returns value of the node located on given path (PHP$name
).
Attention: it's only a shallow copy meaning that if you change all but immediate items of the result you'll effectively change the data within the PHPBEncoded
instance.
function Set($name, $value);
Sets the value of node located on given path (PHP$name
) to PHP$value
. Returns new value.
function Copy($src, $dest);
Copies the value of node PHP$src
to PHP$dest
. Returns the copied value of PHP$src
.
Attention: a regular PHP shallow copy is performed meaning that all objects and references are copied by reference.
function Exchange($node_1, $node_2);
Swaps values of two nodes so that PHP$node_2
acquires the old value of PHP$node_1
and PHP$node_1
acquires the value of PHP$node_2
. Returns nothing.
function Delete($name);
Deletes node located on given path (PHP$name
) by setting it to PHParray()
. Returns an empty array (PHParray()
).
function Export($name = '');
Mostly debug method useful for recursively dumping a particular node value. Unlike Dump Export takes node path instead of value to dump. If PHP$name
is omitted the entire tree is exported.
Returns the dumped string – see Dump for details.
Note: if you see non-numeric list keys prefixed with # it means this list was Cast from a dictionary. As explained there, it's normal and such keys will be treated as numeric when encoding (using ToString, Encode, bencode or others).
function Dump($value, $prefix = '');
Mostly debug method useful for recursively dumping a particular value.
See also Export which is the same but takes a node path to dump instead of some value.
Current TempChar is respected and fitting keys are skipped.
announce: 'http://bt4.rutracker.org/ann announce-list: #0 #0 'http://bt4.rutracker.org/ann' #1 #0 'http://retracker.local/announce' #2 #0 'http://ix4.rutracker.net/ann' comment: 'http://rutracker.org/forum/viewtopic.php' creation date: 1278929913.0
Scalar types (integers and strings) are output using var_export() while array types are output recursively with indentation and their keys in the lead (prefixed with # for lists).
The example above was produced from this tree:
array (
'announce' => 'http://bt4.rutracker.org/ann',
'announce-list' =>
array (
0 =>
array (
0 => 'http://bt4.rutracker.org/ann',
),
1 =>
array (
0 => 'http://retracker.local/announce',
),
2 =>
array (
0 => 'http://ix4.rutracker.net/ann',
),
),
'comment' => 'http://rutracker.org/forum/viewtopic.php',
'creation date' => 1278929913,
)
function NewNode($type, $name);
Creates a new node and returns its value.
PHP0
PHP''
PHParray()
(empty list)PHParray()
(empty dictionary)
Throws EBEncode if PHP$type
is invalid.
function SetEmpty($name);
Sets node located on path %%$name)) to «empty» value and returns it. New value depends on previous node type:
PHP0
.PHP''
.PHParray()
(empty list).PHParray()
(empty dictionary).function Cast($name, $asType, $onlyIfNum = false) {
Typecasts (converts) node located on path PHP$name)) into new type
$asTypePHP. Does nothing if the node is already of type
$asType%%.
Returns new value (or the previous value if no casting was done).
Throws EBEncode when:
PHP$asType
isn't one of: int, str, list or dict;PHParray(0 => $value)
).PHP0
(PHParray(0 => $value)
).PHPBEncoded->
ToString, PHPBEncoded::
Encode, bencode) this value it will gain numeric keys.
Attention: casting dict to list does not mean it loses its named keys – they are retained but ignored. If you cast the same dict into list and then back into dict it will regain its previous key names. If you want to remove the keys you need to do this on your own and then Set the new value to PHP$name
.
function InfoHash($raw = false)%%
Returns an info hash of a BitTorrent .torrent file. Info hash is simply a 40-character SHA-1 hash of bencoded string of the torrent's info dictionary (that holds all file information).
PHPtrue
, returns binary SHA-1 hash that is 20 chars long; if PHPfalse
the hash is converted to a 40-charactered uppercase string.
Calls PHPBEncoded::
HashOf static method on current info node.
$be = new BEncoded;
$be->FromFile('my.torrent');
echo 'Torrent infohash: ', $be->InfoHash(), "\n";
echo 'Direct calculation: ', BEncoded::HashOf($be->Get('info'));
Torrent infohash: DFE39EFFF439B78BB2DD2CAEB69B72ACFE660710 Direct calculation: DFE39EFFF439B78BB2DD2CAEB69B72ACFE660710
These functions represent the encoding/decoding core; bdecode and bencode were taken from Theory.org and fixed by me (see their description for exact changes).
PHPBEncoded
uses these functions in some of its methods so in general you don't need to call them directly but would construct an instance of PHPBEncoded
or use its static methods.
function bdecode($s, &$pos = 0);
Decodes an input string PHP$s
starting at offset PHP$pos
, updating the latter if it was given.
OOP wrappers are PHPBEncoded::
Decode (static) and PHPBEncoded->
FromString and other instance methods;
Changes in comparison to the original function:
function bencode(&$d, $tempChar = null);
Turns PHP$d
into a bencoded string omitting keys starting with PHP$tempChar
– see bskip and PHPBEncoded->
TempChar. PHP$d
is passed by reference only to avoid copying of the input data (that can be large) when PHP passes it to this function.
OOP wrappers are PHPBEncoded::
Encode (static) and PHPBEncoded->
ToString and other instance methods;
Changes in comparison to the original function:
PHPnull
values and dict keys starting with PHP$tempChar
(see PHPBEncoded->
TempChar) are now skippedюPHPEBEncode
exception is now thrown if list contains non-numeric keys.function bskip($key, &$value, $tempChar = null);
A helper function that returns PHPtrue
if PHP$key
of the given PHP$value
array must be omitted from encoded result or PHPfalse
if it should be included. THis is used to:
PHPnull
values;PHPBEncoded->
TempChar) if PHP$tempChar !== null
.This function is used in bencode.
This is the end of PHPBEncoded
API description. Go to the beginning, download the class or drop a comment below.