Encoding#

Scalars and arrays#

Warning

Possibly breaking change in 1.4 and 2.4:

Before 1.4 and 2.4 null was encoded as empty string and false was encoded as 0. Since bencode spec doesn’t have bool and null values, it is not considered a bc break. Judging by info[private] behavior in BitTorrent spec, the old behavior could be considered as a bug.

<?php

use SandFox\Bencode\Bencode;

// non sequential array will become a dictionary
$encoded = Bencode::encode([
    // sequential array will become a list
    'arr' => [1,2,3,4],
    // integer is stored as is
    'int' => 123,
    // float will become a string
    'float' => 3.1415,
    // true will be an integer 1
    'true' => true,
    // false and null values will be skipped
    'false' => false,
    // string can contain any binary data
    'string' => "test\0test",
]);
// "d" .
// "3:arr" . "l" . "i1e" . "i2e" . "i3e" . "i4e" . "e" .
// "5:float" . "6:3.1415" .
// "3:int" . "i123e" .
// "6:string" . "9:test\0test" .
// "4:true" . "i1e" .
// "e"

Objects#

Traversable and stdClass#

Traversable and stdClass become dictionaries:

<?php

use SandFox\Bencode\Bencode;

$encoded = Bencode::encode(
    new ArrayObject([1,2,3])
); // "d1:0i1e1:1i2e1:2i3ee"

$std = new stdClass();
$std->a = '123';
$std->b = 456;
$encoded = Bencode::encode($std);
// "d1:a3:1231:bi456ee"

Big integer support#

New in version 1.5/2.5: GMP support

New in version 1.6/2.6: Pear’s Math_BigInteger, brick/math, BigIntType support

Note

More in the decoding section

GMP object, Pear’s Math_BigInteger, brick/math BigInteger, and internal type BigIntType (simple numeric string wrapper) will become integers:

<?php

use Brick\Math\BigInteger;
use SandFox\Bencode\Bencode;
use SandFox\Bencode\Types\BigIntType;

$encoded = Bencode::encode([
    'gmp' => gmp_pow(2, 96),
    'brick' => BigInteger::of(2)->power(96),
    'pear' => (new Math_BigInteger(1))->bitwise_leftShift(96),
    'internal' => new BigIntType('7922816251426433759354395033'),
]); // "d5:bricki79228162514264337593543950336e3:gmpi792..."

__toString()#

Objects implementing __toString() are cast to strings:

<?php

use SandFox\Bencode\Bencode;

class ToString
{
    public function __toString()
    {
        return 'I am string';
    }
}

$encoded = Bencode::encode(
    new ToString(),
); // "11:I am string"

Object Wrappers#

New in version 1.7/2.7/3.0: DictType

You can use any traversable as a list by wrapping it with ListType. Keys will be discarded in that case.

<?php

use SandFox\Bencode\Bencode;
use SandFox\Bencode\Types\ListType;

$encoded = Bencode::encode(
    new ListType(new ArrayObject([1,2,3]))
); // "li1ei2ei3ee"

You can use any traversable as a dictionary by wrapping it with DictType. Keys will be cast to string and must be unique.

Note

DictType is added for future compatibility with 3.x and is a noop in 1.x/2.x.

<?php

use SandFox\Bencode\Bencode;
use SandFox\Bencode\Types\DictType;

$encoded = Bencode::encode(new DictType(
    (function () {
        yield 'key1' => 'value1';
        yield 'key2' => 'value2';
    })()
)); // "d4:key16:value14:key26:value2e"

BencodeSerializable#

New in version 1.2.

New in version 1.7/2.7/3.0: JsonSerializable handling

You can also force object representation by implementing BencodeSerializable interface. This will work exactly like JsonSerializable interface.

<?php

use SandFox\Bencode\Bencode;
use SandFox\Bencode\Types\BencodeSerializable;

class MyFile implements BencodeSerializable
{
    public function bencodeSerialize()
    {
        return [
            'class' => static::class,
            'name'  => 'myfile.torrent',
            'size'  => 5 * 1024 * 1024,
        ];
    }
}

$file = new MyFile;

$encoded = Bencode::encode($file);
// "d5:class6:MyFile4:name14:myfile.torrent4:sizei5242880ee"

Optionally you can use JsonSerializable itself too:

<?php

use SandFox\Bencode\Bencode;

class MyFile implements JsonSerializable
{
    public function jsonSerialize()
    {
        return [
            'class' => static::class,
            'name'  => 'myfile.torrent',
            'size'  => 5 * 1024 * 1024,
        ];
    }
}

$file = new MyFile;

$encoded = Bencode::encode($file, [
    'useJsonSerializable' => true,
]); // "d5:class6:MyFile4:name14:myfile.torrent4:sizei5242880ee"

Working with files#

Save data to file:

<?php

use SandFox\Bencode\Bencode;

Bencode::dump('testfile.torrent', $data);

Working with streams#

New in version 1.5/2.5.

Save data to a writable stream or to a new php://temp if no stream is specified

<?php

use SandFox\Bencode\Bencode;

Bencode::encodeToStream($data, fopen('...', 'w'));

Encoder object#

New in version 1.7/2.7/3.0.

Encoder object can be configured on creation and used multiple times.

<?php

use SandFox\Bencode\Bencode;
use SandFox\Bencode\Encoder;

$encoder = new Encoder(['useJsonSerializable' => true]);
// all calls available:
$encoder->encode($data);
$encoder->encodeToStream($data, $stream);
$encoder->dump($data, $filename);