在这节及之后的PT架构书写过程中,我将使用ThinkPHP 5作为MVC框架,rchouinard/bencode 作为Bencode编码库,实现一个演示性质的Private Tracker。在此,我将默认你已经对前面的内容有所理解,并对PHP以及composer有了解运用。
该项目代码见: https://github.com/Rhilip/Simple-Private-Tracker ,仅供学习无法运行~
请注意,本文所列方法,仅表示本人的一种实现。实际只要符合BEP 0003以及BEP 0027的都是可行的实现~
请注意,本处所列代码并不一定是最新的,仅代表思考逻辑过程,具体代码请看repo
相关commit:c2c37e668a3f63722b6d4d736e957c8cda76b2a8
基础准备
首先,我们需要准备好PHP环境(建议为7.x)以及数据库,因为学习,所以缓存暂时使用文件缓存。并使用composer安装 ThinkPHP5以及bencode ,其命令分别如下:
1 | composer create-project topthink/think=5.0.* tp5 --prefer-dist |
准备相关数据表,分别用来存储 Torrent(种子信息)、User(用户信息)、Peer(做种人信息)、Snatch(做种完成情况),此处为了方便(偷懒)直接使用NP的建表语句(-> 见 NexusPHP/_db/dbstructure.sql 相关)就行(实际很多字段不需要)。顺带也方面后续兼容~
而文件夹方面,依次添加以下文件:
1 | ├─application |
并在路由(route\route.php)中注册两个控制器
1 | Route::get('tracker/scrape','tracker/Index/scrape'); |
并在设置中开启你的debug模式以及应用trace,准备postman或其他作为调试工具。
方法准备
我们先要为TrackerController 准备一些公用方法,分别用于构造响应信息(包括正常的以及错误)、禁用浏览器访问。修改app\Http\Controllers\TrackerController.php为以下信息:
1 |
|
我们将在$errormsg中定义错误信息,并在announce以及scrape这两个公开方法中定义具体逻辑。而所有的响应应该使用bencResp构造。
构建Scrape
相比较为复杂的Announce逻辑,我们先来处理较为简单的Scrape逻辑:
- 从请求头中获取所有
info_hash信息, - 从数据库中匹配出来对应的做种内容,
- 构造返回或错误信息。
下面我们开始写Scrape的具体逻辑。首先我们先禁用掉 非GET请求 以及 浏览器及非BT客户端请求。代码如下,但实际上,因为已经设置的路由关系,我们其实已经禁止了非GET请求,这里需要不需要都无所谓了
1 | // 1. Block NON-GET requests, (though it should be block in Router) |
然后我们从请求头中获取info_hash信息,并检查其是否存在(这里附加对各个info_hash的字节数进行检查也行)。当其不存在时,返回错误信息。
注意,根据BEP0048规定 ,info_hash在url中是以info_hash=xxxxx&info_hash=yyyyy的形式存在的,故本人之前的写法是错误的(之前写法见Archive.org的备份,只能匹配info_hash[]=xxxx的情况)
应为:
1 | preg_match_all('/info_hash=([^&]*)/i', urldecode(Request::server('query_string')), $info_hash_match); |
针对info_hash未找到的情况进行处理。
1 | if (count($info_hash) < 1) { |
使用查询构造器生成SQL语句并查询,并对查询结果进行检查;当数据库中未检查到该种子时,返回错误信息。
1 | $res = Db::table("torrents") |
如果没有任何问题,我们需要把原来数据库中查询的结果(如下)进行转换
1 | array(1) { |
方法如下,并最后使用bencResp($obj)的方式进行编码并发送
1 | $rep = [ |

