rhilip / bencode
一个用于编码和解码 Bencode 数据的纯 PHP 库
v2.4.3
2024-05-13 02:19 UTC
Requires
- php: ^7.3|^8.0|^8.1|^8.2|^8.2|^8.3
Requires (Dev)
- ext-json: *
- phpunit/phpunit: ^9.0
Suggests
- php-64bit: Running 64 bit is recommended to prevent integer overflow
README
Bencode 是由点对点文件共享系统 BitTorrent 使用的编码,用于存储和传输松散结构化的数据。
这是一个纯 PHP 库,允许您编码和解码 Bencode 数据,具有解析和验证种子文件的功能。
此库是从 OPSnet/bencode-torrent 分支出来的,与 sandfoxme/bencode、sandfoxme/torrent-file 采用相同的方法。
安装
composer require rhilip/bencode
如果您不使用 Rhilip\Bencode\TorrentFile
类,您可以将版本指定为 1.x.x
。如果您的 PHP 版本是 5.6
或 7.0-7.2
,请停止在版本 1.2.0
和 2.0.0
。
composer require rhilip/bencode:1.2.0
唯一的重大更改是在 1.x.x
中的 ParseErrorException
重命名为 ParseException
在 2.x.x
。
使用方法
类 Rhilip\Bencode\Bencode
一个用于从文件路径和字符串编码和解码 Bencode 数据的纯 PHP 类。
<?php require '/path/to/vendor/autoload.php'; use Rhilip\Bencode\Bencode; use Rhilip\Bencode\ParseException; // Decodes a BEncoded string Bencode::decode($string); // Encodes string/array/int to a BEncoded string Bencode::encode($data); // Decodes a BEncoded file From path Bencode::load($path); // Encodes string/array/int to a BEncoded file Bencode::dump($path, $data); // With Error Catch try { Bencode::decode('wrong_string'); } catch (ParseException $e) { // do something }
类 Rhilip\Bencode\TorrentFile
一个用于处理种子文件的纯 PHP 类
注意:在版本 2 中添加
<?php require '/path/to/vendor/autoload.php'; use Rhilip\Bencode\TorrentFile; use Rhilip\Bencode\ParseException; // 0. Defined Const print(TorrentFile::PROTOCOL_V1); // v1 print(TorrentFile::PROTOCOL_V2); // v2 print(TorrentFile::PROTOCOL_HYBRID); // hybrid print(TorrentFile::FILEMODE_SINGLE); // single print(TorrentFile::FILEMODE_MULTI); // multi // 1. Load Torrent and get instance try { $torrent = TorrentFile::load($path); $torrent = TorrentFile::loadFromString($string); } catch (ParseException $e) { // do something } // 2. Save Torrent to path or string (for echo) $dumpStatus = $torrent->dump($path); print($torrent->dumpToString()); // 3. Work with Root Fields $torrent->getRootData(); // $root; $rootField = $torrent->getRootField($field, ?$default); // $root[$field] ?? $default; $torrent->setRootField($field, $value); // $root[$field] = $value; $torrent->unsetRootField($field); // unset($root[$field]); $torrent->cleanRootFields(?$allowedKeys); // remove fields which is not allowed in root $torrent->setAnnounce('udp://example.com/announce'); $announce = $torrent->getAnnounce(); $torrent->setAnnounceList([['https://example1.com/announce'], ['https://example2.com/announce', 'https://example3.com/announce']]); $announceList = $torrent->getAnnounceList(); $torrent->setComment('Rhilip\'s Torrent'); $comment = $torrent->getComment(); $torrent->setCreatedBy('Rhilip'); $createdBy = $torrent->getCreatedBy(); $torrent->setCreationDate(time()); $creationDate = $torrent->getCreationDate(); $torrent->setHttpSeeds(['udp://example.com/seed']); $httpSeeds = $torrent->getHttpSeeds(); $torrent->setNodes(['udp://example.com/seed']); $nodes = $torrent->getNodes(); $torrent->setUrlList(['udp://example.com/seed']); $urlList = $torrent->getUrlList(); // 4. Work with Info Field $torrent->getInfoData(); // $root['info']; $infoField = $torrent->getInfoField($field, ?$default); // $info[$field] ?? $default; $torrent->setInfoField($field, $value); // $info[$field] = $value; $torrent->unsetInfoField($field); // unset($info[$field]); $torrent->cleanInfoFields(?$allowedKeys); // remove fields which is not allowed in info $protocol = $torrent->getProtocol(); // TorrentFile::PROTOCOL_{V1,V2,HYBRID} $fileMode = $torrent->getFileMode(); // TorrentFile::FILEMODE_{SINGLE,MULTI} /** * @note since we may edit $root['info'], so when call ->getInfoHash* method, * we will calculate it each call without cache return-value. */ $torrent->getInfoHashV1(?$binary); // If $binary is true return 20-bytes string, otherwise 40-character hexadecimal number $torrent->getInfoHashV2(?$binary); // If $binary is true return 32-bytes string, otherwise 64-character hexadecimal number $torrent->getInfoHash(?$binary); // return v2-infohash if there is one, otherwise return v1-infohash $torrent->getInfoHashs(?$binary); // return [TorrentFile::PROTOCOL_V1 => v1-infohash, TorrentFile::PROTOCOL_V2 => v2-infohash] $torrent->getInfoHashV1ForAnnounce(); // return the v1 info-hash in announce ( 20-bytes string ) $torrent->getInfoHashV2ForAnnounce(); // return the v2 (truncated) info-hash in announce $torrent->getInfoHashsForAnnounce(); // same as getInfoHashs() but in announce $torrent->getPieceLength(); // int try { $torrent->setName($name); } catch(\InvalidArgumentException $e) { // Do something } $name = $torrent->getName(); $torrent->setSource('Rhilip\'s blog'); $source = $torrent->getSource(); $private = $torrent->isPrivate(); // true or false $torrent->setPrivate(true); $magnetLink = $torrent->getMagnetLink(); // 5. Work with torrent, it will try to parse torrent ( cost time ) $torrent->setParseValidator(function ($filename, $paths) { /** * Before parse torrent ( call getSize, getFileCount, getFileList, getFileTree method ), * you can set a validator to test if filename or paths is valid, * And break parse process by any throw Exception. */ print_r([$filename, $paths]); if (str_contains($filename, 'F**k')) { throw new ParseException('Not allowed filename in torrent'); } }); /** * parse method will automatically called when use getSize, getFileCount, getFileList, getFileTree method, * However you can also call parse method manually. */ $torrent->parse(); // ['total_size' => $totalSize, 'count' => $count, 'files' => $fileList, 'fileTree' => $fileTree] /** * Note: Since we prefer to parse `file tree` in info dict in v2 or hybrid torrent, * The padding file may not count in size, fileCount, fileList and fileTree. */ $size = $torrent->getSize(); $count = $torrent->getFileCount(); /** * Return a list like: * [ * ["path" => "filename1", "size" => 123], // 123 is file size * ["path" => "directory/filename2", "size" => 2345] * ] * */ $fileList = $torrent->getFileList(); /** * Return a dict like: * [ * "torrentname" => [ * "directory" => [ * "filename2" => 2345 * ], * "filename1" => 123 * ] * ] * * > Add in v2.4.0 * You can now pass argument to control the fileTree sort type. By default, this argument is TorrentFile::FILETREE_SORT_NORMAL. * Control Const (see different in `tests/TorrentFileTreeSortTest.php` file): * - TorrentFile::FILETREE_SORT_NORMAL : not sort, also means sort by torrent file parsed order * - TorrentFile::FILETREE_SORT_STRING : sort by filename ASC ("natural ordering" and "case-insensitively") * - TorrentFile::FILETREE_SORT_FOLDER : sort by filetype (first folder, then file) * - TorrentFile::FILETREE_SORT_NATURAL: sort by both filetype and filename ( same as `TorrentFile::FILETREE_SORT_STRING | TorrentFile::FILETREE_SORT_FOLDER` ) * */ $fileTree = $torrent->getFileTree(?$sortType = TorrentFile::FILETREE_SORT_NORMAL); // 6. Other method $torrent->cleanCache(); // Note 1: clean,set,unset method are chaining $torrent ->clean() ->setAnnounce('https://example.com/announce') ->setAnnounceList([ ['https://example.com/announce'], ['https://example1.com/announce'] ]) ->setSource('example.com') ->setPrivate(true); // Note 2: parse method may fail when get a deep invalid torrent, so it can wrapper like this try { $torrent = TorrentFile::load($_POST['torrent']['tmp_name']); $torrent/** ->setParseValidator(function () {}) */->parse(); } catch (ParseException $e) { // do something to notice user. } print($torrent->getFileCount()); // safe to use other method without any ParseException
许可
此库根据 MIT 许可证 作为开源软件提供。