Torrent File#

Packagist GitLab GitHub Bitbucket Gitea

A PHP Class to work with torrent files

Installation#

composer require arokettu/torrent-file

Documentation#

Loading, Saving and Creating#

Load an existing torrent#

New in version 1.2: loadFromString()

New in version 2.1: loadFromStream()

You can load a torrent from file, from string, or from stream.

<?php

use Arokettu\Torrent\TorrentFile;

// from file
$torrent = TorrentFile::load('debian.torrent');
// from string
$torrent = TorrentFile::loadFromString(file_get_contents('debian.torrent'));
// from stream
$torrent = TorrentFile::loadFromStream(fopen('debian.torrent', 'r'));

Save torrent#

New in version 1.2: storeToString()

New in version 2.1: storeToStream()

You can save your torrent to file, to string, or to stream.

<?php

// to file
$torrent->store('debian.torrent');
// to string
$torrentString = $torrent->storeToString();
// to stream
$torrent->storeToStream($stream);
// to new php://temp stream
$phpTemp = $torrent->storeToStream();

Create a torrent for existing directory or file#

New in version 1.1: $options

New in version 2.0: $eventDispatcher

New in version 2.2: pieceAlign, detectExec, detectSymlinks

Changed in version 2.2: sortFiles, md5sum became noop

New in version 2.3/3.1: version

New in version 2.5/3.3/4.1: forceMultifile

The library can create a torrent file from scratch for a file or a directory.

<?php

use Arokettu\Torrent\TorrentFile;

$torrent = TorrentFile::fromPath(
    '/home/user/ISO/Debian',
    pieceLength: 512 * 1024,
);

// pass an instance of PSR-14 event dispatcher to receive progress events:
$torrent = TorrentFile::fromPath('/home/user/ISO/Debian', $eventDispatcher);
// dispatcher will receive instances of \Arokettu\Torrent\FileSystem\FileDataProgressEvent
//    only in 2.0 and later

Available options:

version

BitTorrent metadata file version.

  • MetaVersion::V1 as described in BEP-3 spec.

  • MetaVersion::V2 as described in BEP-52 spec.

  • MetaVersion::HybridV1V2 with both V1 and V2 metadata.

Default: MetaVersion::HybridV1V2 (was MetaVersion::V1 in 2.x)

pieceLength

The number of bytes that each logical piece in the peer protocol refers to. Must be a power of 2 and at least 16 KiB. Default: 524_288 (512 KiB)

pieceAlign

Align files to piece boundaries by inserting pad files. The option is ignored for V2 and V1+V2 torrent files because files in V2 are always aligned.

  • true: Align all files

  • false: Do not align

  • int $bytes: Align files larger than $bytes in length

Default: false

detectExec

The library detects executable attribute and sets it on files. Default: true

detectSymlinks

The library detects symlinks and creates symlink torrent objects. Only symlinks leading to files in the torrent data directory are detected. Default: false

forceMultifile

V1 torrents are created in ‘directory’ mode even when created for a single file. This mode fixes some possible incompatibilities between V1 and V2 data in hybrid torrents. Always enabled in hybrid torrents, meaningless for pure V2. Default: false

Note

Defaults may change in minor versions. If you care about their specific values, set them explicitly.

Warning

Parameter order is not guaranteed for options. Please use named parameters.

Root Fields#

Fields of the torrent file that are not parts of the info dictionary. By changing these fields you’re not creating a separate torrent file (not changing infohash). All fields can be unset by passing null.

Announce#

The URL of the tracker. string.

<?php
$torrent->setAnnounce('udp://example.com/announce');
$announce = $torrent->getAnnounce();

Announce List#

Note

BEP-12 Multitracker Metadata Extension

Changed in version 3.0: AnnounceList object is returned instead of array of arrays

A list of lists of tracker URLs. See the type section for acceptable formats.

<?php
// accepts AnnounceList objects or iterables of valid structure
//      (same as AnnounceList::fromIterable())
$torrent->setAnnounceList([['udp://example.com/announce']]);
// get Announce List as AnnounceList object
$torrent->getAnnounceList();
// get Announce List as array
$torrent->getAnnounceList()->toArray();

Comment#

Optional description. string.

<?php
$torrent->setComment('My Torrent');
$comment = $torrent->getComment();

Created By#

Optional info about the creator. string.

<?php
$torrent->setCreatedBy('Me');
$createdBy = $torrent->getCreatedBy();

Creation Date#

Changed in version 3.0: DateTimeImmutable is returned instead of int

Optional info about the creator. DateTimeImmutable.

<?php
// set by DateTime or DateTimeImmutable
$torrent->setCreationDate(new DateTime('now'));
// set by int timestamp
$torrent->setCreationDate(time());
// get DateTimeImmutable object
$creationDate = $torrent->getCreationDate();
// get int timestamp
$creationDate = $torrent->getCreationDate()->getTimestamp();

Http Seeds#

Note

BEP-17 HTTP Seeding

A list of HTTP seeding URLs. See the type section for acceptable formats.

<?php
// accepts UriList objects or iterables of valid structure
//      (same as UriList::fromIterable())
$torrent->setHttpSeeds(['udp://example.com/seed']);
// get Http Seeds as UriList object
$torrent->getHttpSeeds();
// get Http Seeds as array
$torrent->getHttpSeeds()->toArray();

Nodes#

Note

BEP-5 DHT Protocol

A list of DHT nodes. See the type section for acceptable formats.

<?php
// accepts NodeList objects or iterables of valid structure
//      (same as NodeList::fromIterable())
$torrent->setNodes(['udp://example.com/seed']);
// get Url List as UriList object
$torrent->getNodes();
// get Url List as array
$torrent->getNodes()->toArray();

Url List#

Note

BEP-19 WebSeed - HTTP/FTP Seeding

A list of webseed URLs. See the type section for acceptable formats.

<?php
// accepts UriList objects or iterables of valid structure
//      (same as UriList::fromIterable())
$torrent->setUrlList(['udp://example.com/seed']);
// get Url List as UriList object
$torrent->setUrlList();
// get Url List as array
$torrent->setUrlList()->toArray();

Info Fields#

Fields of the info dictionary of the torrent file. The info dictionary is the primary data of the torrent file. Using any setters here will change infoHash and the result will be considered a separate torrent file by the trackers.

Directory or File#

New in version 2.2.

A method to check if a directory or a file is encoded.

<?php
$isDirectory = $torrent->isDirectory();

Info Hash#

Methods to get info hash of the torrent file.

V1#

New in version 2.3/3.1.

Get V1 info hash if V1 metadata is present or null if not.

<?php
$infoHash = $torrent->getInfoHashV1();
V2#

New in version 2.3/3.1.

Get V2 info hash if V2 metadata is present or null if not.

<?php
$infoHash = $torrent->getInfoHashV2();
General method#

Changed in version 2.3/3.1: The method returns V2 info hash if the metadata is present

Get V2 info hash if V2 metadata is present, fall back to V1 info hash.

<?php
$infoHash = $torrent->getInfoHash();
All hashes#

New in version 2.3/3.1.

Get all available hashes as array.

<?php
$infoHashes = $torrent->getInfoHashes();
$infoHashes[1]; // V1 info hash if V1 metadata is present
$infoHashes[2]; // V2 info hash if V2 metadata is present

Name#

A base name of the encoded file or directory.

Warning

Setter will do a minimal check that the name can be a valid file name: it should not be empty and should not contain slashes and zero bytes. It also won’t allow you to unset the name.

However the content of the name field in the parsed file is not guaranteed to exist or be valid.

<?php
// should be a valid file/dir name
$torrent->setName('file.iso');
// stored name may be null or invalid :(
$name = $torrent->getName();

Private#

Note

BEP-27 Private Torrents

Get / set / unset the private flag.

<?php
$isPrivate = $torrent->isPrivate();
$torrent->setPrivate(true);

Helper Methods#

Display Name#

A helper to suggest a display name:

  • name if name is set and is not empty

  • infohash as a fallback

<?php
$displayName = TorrentFile::fromPath('~/isos/debian.iso')
    ->getDisplayName(); // 'debian.iso'

File Name#

A helper to suggest a file name: getDisplayName() + '.torrent'

<?php
$filename = TorrentFile::fromPath('~/isos/debian.iso')
    ->getFileName(); // 'debian.iso.torrent'

Raw Data#

Warning

Since 2.2 getRawData() is guaranteed to return the structure as it is encoded in the bencoded torrent file. In earlier versions it returned whatever junk TorrentFile stored internally.

Changed in version 2.2: Consistent return format

Changed in version 4.0: Uses ListObject and DictObject instances instead of array

A helper method that dumps raw torrent data as an array-like structure.

<?php
// get raw data (in readonly array-like structures)
$data = $torrent->getRawData();
// info dictionary
var_dump($data['info']);
// fields
var_dump($data['creation date']);
// etc...

// get a real array
$array = $data->getArray();

Data Types#

All data types are immutable. All lists implement Traversable, Countable and a read only ArrayAccess with numeric keys. All lists wipe duplicates.

AnnounceList#

AnnounceList is a list of UriList’s. It represents the outer list in the announce-list field in the torrent file.

Creation#

Announce list can be created from the following structures:

<?php

use Arokettu\Torrent\DataTypes\AnnounceList;
use Arokettu\Torrent\DataTypes\UriList;

// Build from iterable
$announceList = AnnounceList::fromIterable([
    ['url1', 'url2'],   // a list of urls with the same priority
    'url3',             // a single url will be a list of a single item
]);
// OOP way
$announceList = AnnounceList::create(
    UriList::create('url1', 'url2'),
    UriList::create('url3'),
);
Modification#
<?php

use Arokettu\Torrent\DataTypes\AnnounceList;
use Arokettu\Torrent\DataTypes\UriList;

// append a list
$announceList = AnnounceList::append(
    $announceList,
    UriList::create('url4'),
);
// prepend a list
$announceList = AnnounceList::prepend(
    $announceList,
    UriList::create('url4'),
);
// remove a list
$announceList = AnnounceList::remove(
    $announceList,
    UriList::create('url4'),
);
Array representation#
<?php

// toArray() return an array of arrays of strings,
// the same structure as it is represented in the torrent file
$data = $announceList->toArray();
// toArrayOfUriLists() return array of UriList objects
$lists = $announceList->toArrayOfUriLists();

Node#

Node represents an item in the DHT nodes list.

Creation#
<?php

use Arokettu\Torrent\DataTypes\Node;

// Build from array
$node = Node::fromArray(['localhost', 11111]);
// OOP way
$node = new Node('127.0.0.1', 12345);
Fields#

Changed in version 3.0.1: getters were replaced with readonly properties

<?php

$host = $node->host; // node host or ip
$port = $node->port; // node port

// also with array access that mimics the representation in the torrent file
$host = $node[0];
$port = $node[1];
Array representation#
<?php

// toArray() return a node-array [$host, $port],
// the same structure as it is represented in the torrent file
$data = $node->toArray();

NodeList#

NodeList is a list of Node’s. It represents the nodes field in the torrent file.

Creation#

Node list can be created from the following structures:

<?php

use Arokettu\Torrent\DataTypes\Node;
use Arokettu\Torrent\DataTypes\NodeList;

// Build from iterable
$nodeList = NodeList::fromIterable([
    ['localhost', 11111],   // [host|ip : string, port : int]
    ['127.0.0.1', 12345],   // [host|ip : string, port : int]
]);
// OOP way
$nodeList = NodeList::create(
    new Node('localhost', 11111),
    new Node('127.0.0.1', 12345),
);
Modification#
<?php

use Arokettu\Torrent\DataTypes\Node;
use Arokettu\Torrent\DataTypes\NodeList;

// append a node
$nodeList = NodeList::append(
    $nodeList,
    new Node('fe00::1234', 12321),
);
// prepend a node
$nodeList = NodeList::prepend(
    $nodeList,
    new Node('fe00::1234', 12321),
);
// remove a node
$nodeList = NodeList::remove(
    $nodeList,
    new Node('fe00::1234', 12321),
);
Array representation#
<?php

// toArray() return an array of node-arrays [$host, $port],
// the same structure as it is represented in the torrent file
$data = $nodeList->toArray();
// toArrayOfNodes() return array of Node objects
$nodes = $nodeList->toArrayOfNodes();

UriList#

UriList is a list of strings. It represents the url-list and httpseeds fields and the inner lists in the announce-list field in the torrent file.

Creation#

Uri list can be created from the following structures:

<?php

use Arokettu\Torrent\DataTypes\UriList;

// Build from iterable
$uriList = UriList::fromIterable([
    'https://example.com/announce',
    'udp://example.com/announce',
]);
// OOP way
$uriList = UriList::create(
    'https://example.com/announce',
    'udp://example.com/announce',
);
Modification#
<?php

use Arokettu\Torrent\DataTypes\UriList;

// append a list
$uriList = UriList::append(
    $uriList,
    'udp://example.net/announce',
);
// prepend a list
$uriList = UriList::prepend(
    $uriList,
    'udp://example.net/announce',
);
// remove a list
$uriList = UriList::remove(
    $uriList,
    'udp://example.net/announce',
);
Array representation#
<?php

// toArray() return an array of strings,
// the same structure as it is represented in the torrent file
$data = $uriList->toArray();

Upgrade Notes#

Upgrade from 3.x to 4.0#

  • Namespace was changed to Arokettu\\Torrent\\

    • Alases for the new namespace were added to 1.4.0, 2.4.0, 3.2.0 for future compatibility

  • getRawData() returns immutable objects with ArrayAccess&Countable&Iterable capabilities instead of arrays

    • Use getRawData()->getArray() to have a real array

  • Getter methods on Node and FileDataEvent were removed, use exposed public readonly properties

Upgrade from 2.x to 3.0#

  • PHP 8.1 is now required.

  • TorrentFile::forPath() uses named parameters instead of options array.

  • $torrent->getCreationDate() returns DateTimeImmutable.
    Use $torrent->getCreationDate()->getTimestamp() for int timestamp.
  • $torrent->getAnnounceList() now returns an instance of AnnounceList.
    Use $torrent->getAnnounceList()->toArray() for array.

Upgrade from 1.x to 2.0#

Breaking changes:

  • PHP 7.4 is now required.

  • Custom event system based on FileDataProgress is removed. It was never documented anyway.

Future Plans#

  • Files model (chunks and offsets for files)

  • Chunks model (files and their offsets, chunk data validation)

  • Info verification for existing files on disk

License#

The library is available as open source under the terms of the MIT License.