Torrent File#
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
(wasMetaVersion::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 filesfalse
: Do not alignint $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'
Magnet Link#
A helper to generate a magnet link for the torrent.
<?php
$magnet = $torrent->getMagnetLink(); // 'magnet:?xt=urn:btih:...'
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 arraysUse
getRawData()->getArray()
to have a real array
Getter methods on
Node
andFileDataEvent
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()
returnsDateTimeImmutable
.Use$torrent->getCreationDate()->getTimestamp()
for int timestamp.$torrent->getAnnounceList()
now returns an instance ofAnnounceList
.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.