NexusPHP 建站优化 (1)自动清理(cleanup)

此文主要解决部分基于NPHP的站点在做大之后,因cleanup相关清理程序超时无法正常运行,导致出现用户等级、做种魔力无法正常更新等情况。主要可能的报错和原因为:

  1. 站点使用Cloudflare作为CDN,因为清理程序运行超过100s,被强制522超时停止运行。
  2. 站点Nginx设置后端超时时间过短,导致502报错。

以下讲解和代码patch均基于本人fork的官方源码 Rhilip/NexusPHP(v1.5.beta5.20120707),不提供除本文外的任何形式的说明以及免费讲解。如果你非NPHP架构或者你站点规模还达不到出现cleanup超时,请勿了解!!

具体请见:Rhilip/NexusPHP#2a833ff


cleanup长耗时任务分析

通过对原有include/cleanup.php中的printProgress方法进行修改,我们可以发现以下任务均为长耗时任务

具体耗时视站内做种人数以及种子相关表大小而定,一般来说如果NPHP宿主机性能较差,在peers表突破1w行之后,做种魔力清算就会突破60s限制(Nginx默认超时时间)。而种子表突破5k行之后,种子情况更新也会突破相关限制。(以上行数均为本人瞎写瞎编)

此外,这两个长耗时任务均处在清理程序首部,容易因为超时自动退出,而且NPHP默认是通过register_shutdown_function("autoclean")的形式进行执行,导致后续清理程序无法正常运行。

考虑通过以下方式进行优化:

  1. 去除Nginx服务超时限制,本地使用crontab定时wget请求cron.php页面。具体方法可见NPHP中include/config.php说明。
  2. 使用PHP_CLI运行cron.php文件,绕过Web服务器的相关超时设置。这也是本文的相关说明要点。

如何批量生成OneDrive分享链接

这篇文章其实早就想写了,然而一直放在自己的ToDO list里面,就那么一直放着放着(还有几篇是一样的命运,就开了个头)。然后一看自己快两个月没更新blog了,随便写点上来分享下。

在很早很早之前,我使用过OneIndex以及它的一系列衍生开源项目分享过文件。然而就如同我在 个人仓库 的说明中写的那样,这一系列的开源项目存在一些很麻烦的问题,我之后便开始使用ShareLink的形式创建分享链接的形式来进行分享。

最开始

当然,最早之前,我是用网页端生成共享链接的方式来进行的,然后随便找个短链接生成网站生成个短链接就行。这个方式怎么说那,虽然原始但是可用23333,毕竟文件量少,简单操作下不需要多少时间。

image-20191211212443500.png

使用rclone link

再后来,我在使用rclone的时候意外发现了rclone link的方法,根据他的介绍,会生成约束最少(没有过期时间,没有密码保护,无需账户匿名即可访问)的链接,也刚好是我需要的链接类型。

image-20191211213709829.png

这个很棒,从此可以很方便的调用rclone并通过获得输出的形式来获得分享链接。

简单的脚本实例如下:

1
2
3
4
5
import subprocess

file_path = "OndDrive:archive"
response = subprocess.check_output('rclone link ' + file_path, shell=True)
share_link = response.decode('utf-8')

通过配合rclone lsjson方法,我们可以快速遍历文件夹,甚至为每一个文件或者文件夹创建链接。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import os
import subprocess

def create_share_link(path): str
response = subprocess.check_output('rclone link ' + path, shell=True)
share_link = response.decode('utf-8')
return share_link

def create_short_link(raw): str
pass

def get_folder_items(path):
response = subprocess.check_output('rclone lsjson ' + path, shell=True)
return json.loads(response.decode('utf-8'))

def folder_loop(base):
# 当前目录信息
par_path = os.path.dirname(base)
fpath = os.path.basename(base)
folder_items = get_folder_info(base)

# 先进行子文件夹循环
item_subfolders = list(filter(lambda x: x.get('IsDir') == True, folder_items))
for subfloder in item_subfolders:
subfolder_loop(os.path.join(base, subfloder.get('Path')))

# 其他文件
items = list(filter(lambda x:x not in item_subfolders, folder_items))
for item in items:
full_path = os.path.join(base, item.get('Path'))
share_link = create_share_link(full_path)
short_link = create_short_link(share_link)
print(full_path, share_link, short_link)

base = "OneDrive:archive"
folder_loop(base)

直接使用python创建

那么如果抛开,或者半抛开rclone(仅refresh仍使用rclone)是否可行?毕竟我们有时候还需要构建其他类型的分享链接。

结论当然是可行的!(不然就没这篇文章了)

官方文档 : Access OneDrive and SharePoint via Microsoft Graph API - OneDrive dev center | Microsoft Docs

根据 文档 说明,创建链接只需要一个简单的POST请求即可,请求地址如下

1
2
3
4
5
POST /drives/{driveId}/items/{itemId}/createLink
POST /groups/{groupId}/drive/items/{itemId}/createLink
POST /me/drive/items/{itemId}/createLink
POST /sites/{siteId}/drive/items/{itemId}/createLink
POST /users/{userId}/drive/items/{itemId}/createLink

而请求的主体部分是一个json字典,通过更改type和scope,我们就可以设定分享链接的类型(注意你所在域的设置),如下

1
2
3
4
{
"type": "view",
"scope": "anonymous"
}

而请求的返回则同样是一个json字典,我们最需要的生成分享链接在 ["link"]["webUrl"]

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"id": "123ABC",
"roles": ["write"],
"link": {
"type": "view",
"scope": "anonymous",
"webUrl": "https://1drv.ms/A6913278E564460AA616C71B28AD6EB6",
"application": {
"id": "1234",
"displayName": "Sample Application"
},
}
}

这样我们就只需要知道itemId,就可以通过构造http请求来获得分享链接了,构造的代码段如下

请注意,此处及之后的示例代码均没有考虑token过期,返回错误导致所需字段不存在的异常情况,实际上token有效期只有1小时,如果文件数过多容易过期失效,而且MS的服务器也很容易返回非token过期的其他异常情况

1
2
3
4
def share_by_id(id_):
share_req = requests.post('https://graph.microsoft.com/v1.0/me/drive/items/{}/createLink'.format(
id_), headers={'Authorization': 'bearer ' + token}, json={'type': 'view', 'scope': 'anonymous'})
return share_req.json()['link']['webUrl']

最关键的解决了,我们需要开始知道itemId如何获取,方法也十分简单,通过请求对应文件上层目录就可以获得其children信息,其中就有包括itemId的数据。同样根目录也有对应的请求方法。

简单构造分享两级目录的代码段如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 获得driveid
did = requests.get('https://graph.microsoft.com/v1.0/me/drives', headers={'Authorization': 'bearer ' + token}).json()['value'][0]['id']

# 列出根目录
root = requests.get('https://graph.microsoft.com/v1.0/me/drive/root/children', headers={'Authorization': 'bearer ' + token}).json()

for folder in root['value']:
folder_id = folder['id']
# 列某id下的目录信息
folder_req = requests.get('https://graph.microsoft.com/v1.0/drives/{}/items/{}/children'.format(did, folder_id), headers={'Authorization': 'bearer ' + token})
folder_ = folder_req.json()
for item in folder_['value']:
id_ = item_['id']
name_ = item_['name']

# 创建分享链接
share_link = share_by_id(id_)
print('获得 {} 的分享链接 {}' .format(name_, share_link))

driveid通过解析rclone的rclone.conf文件进行获取。此外,如果你自己重申请(refresh) token存在困难(就比如我),refresh token也可以交给rclone来进行。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import json
import subprocess
import configparser

did = 'adfasdfas'
token = 'adfasdfasdf'

rclone_config_path = '~/.config/rclone/rclone.conf'

subprocess.run('rclone about OneDirve:', shell=True)

config = configparser.ConfigParser()
config.read(rclone_config_path)

did = config['OneDrive']['drive_id']
raw_token = json.loads(config['OneDrive']['token'])

token = raw_token['access_token']

2019.12.19更新:

因为OneDrive一次只返回200个子目录结果,所以我们需要对进入创建sharelink之前,通过递归的方式获得所有items,基本代码段如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

def get_items(link):
f = requests.get(link, headers={'Authorization': 'bearer ' + token})
fj = f.json()
v = fj['value']

if fj.get('@odata.nextLink'):
v.extend(get_items(fj['@odata.nextLink']))

return v

all_items = get_items('https://graph.microsoft.com/v1.0/drives/{}/items/{}/children'.format(did, folder_id))
for item in all_itmes:
id_ = item_['id']
share_link = share_by_id(id_)

没有了,基本代码就这些,基于这些代码,我是怎么玩的,以及怎么处理异常的就不具体贴出来了~

使用Service Account接力rclone,突破GD单账号每日上传750G限制

嗯,标题比较绕口,改了好几遍都觉得不好。
不过本文的目的在于:

暂时只针对本地文件上传GD/TD,GD/TD内互传可能不适用

  1. 创建Service Account并添加到teamdrive(现在也叫共享云端硬盘)中。(至于为什么要用SA,当然是因为创建真实用户账户成本过高,而且不能批量添加呀。)
  2. 使用python脚本运行rclone,以多账户协力的形式突破单账号750G上传限制,并在对应账户上传超限(750G/帐号)时进行切换。

其中第一步的主要思想来自folderclone,第二步相关实践来自 @superstaraug 等人,对此分别表示感谢。

成品项目见:https://github.com/Rhilip/AutoRclone

此文的目的在于上传文件到共享云端硬盘,仅在部分步骤中利用了folderclone相关脚本(所以偷懒直接fork修改了)来批量创建Service Account并添加到teamdrive中。
如果你对foldercloneTD to GDshared to GD(即“他人分享转成自己可管理文件”),TD to TD等Google Drive内部文件捣腾玩法感兴趣,你可以参考本文的参考链接第一条。

参考链接:

补充方案: rclone 750G 自动换号 – AutoRclone – Google 迷

本文非 https://github.com/xyou365/AutoRclone 项目相关介绍及教程,请勿在本人Blog中询问。

============================

请注意:本教程第一、二部分教程使用OAuth2客户端形式完成,与 567899.xyz 等人手动创建辅助账户不同,请视你需要,选择本教程或参考该他人教程,完成Service Account的创建以及Shared Drive用户添加,并得到SA的JSON文件。如果你已经完成了上述步骤,请直接跳转本教程第三部分Rclone设置。

请根据你个人需求创建项目数量,已知限制如下

  1. 一个真实帐号最多能创建12(或25)个项目,每个项目最多100个SA账户,每个账户(无论是真实还是SA)每日最多上传750G
  2. 一个共享云端硬盘最多添加600个账户

获取并设置GoodReads的APIKEY

GoodReads 自2020年12月8日起不再提供公开API申请,故本文作废。
原文见 https://help.goodreads.com/s/article/Does-Goodreads-support-the-use-of-APIs

我们在 豆瓣资源下载大师 的 7.5.9 及之后版本中添加了对GoodReads评分获取的支持。
基于一些考虑,我们并没有内置APIKEY,如果你希望开启豆瓣图书页面的GoodReads链接以及评分信息的展示,请考虑自己申请APIKEY并填入,或使用文后提供的一些来自网络收集的apikey。
或如果你想分享你申请或者收集到的apikey,也可在评论区留言。

PHP解析 ipv6wry.db 数据库

我可能算是比较关注 ipv6wry.db 这个IPv6数据库的人之一了吧,之前就有写了自动更新脚本 Rhilip/ipv6wry.db ,再早之前在PT-help中也使用了该库。

昨天晚上不知道在想些什么,搜索了一圈没见到 PHP 版本解析库,突然就有写一个的想法。

Github Source: https://github.com/Rhilip/ipv6wry-php
Packgist: https://packagist.org/packages/rhilip/ipv6wry

前人们的工作

  • 官方给出的解析工具中只有 C、Python 版本的实现

  • 真红酱在他的CSDN中使用的方法是使用Python导出CSV文件,然后入库,然后直接根据IPv6前四个字段的值检索数据库。这样的问题是数据库里面需要存储近11w条数据,且不好得到更新(或者说更新过于麻烦)。

    1568881326812.png

  • JohnWong/python-tool 公开了另外一种Python的实现,只不过其实现基于Python2。不过好在2017年,本人就在工具 PT-help 中将其实现改成了Python3。

IPDB格式说明

以下说明来自官方文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
文件头
0~3 字符串 "IPDB"
4~5 short 版本号,现在是2
6 byte 偏移地址长度(2~8)
7 byte IP地址长度(4或8或12或16, 现在只支持4(ipv4)和8(ipv6))
8~15 int64 记录数
16~23 int64 索引区第一条记录的偏移
24 byte 地址字段数(1~255)[版本2新增,版本1是2]
25~31 reserve 保留,用00填充

记录区
array 字符串[地址字段数]
与qqwry.dat大致相同,但是没有结束IP地址
01开头的废弃不用
02+偏移地址[偏移长度]表示重定向
20~FF开头的为正常的字符串,采用UTF-8编码,00结尾

索引区
struct{
IP[IP地址长度] little endian, 开始IP地址
偏移[偏移长度] little endian, 记录偏移地址
}索引[记录数];

所以直接使用该 ipv6wry.db 的核心思想在于从索引区找到记录区的偏移地址,然后根据读取字符串(UTF-8编码)以及是否有重定向偏移继续读取。

版本实现

Rhilip/ipv6wry-php 使用单例模式,当前(v0.1.0)向外开放两个静态方法

1
2
3
4
5
6
7
8
9
10
11
/**
* 设定 ipv6wry.db 数据库位置(使之能使用外部的ipv6wry.db库进行解析)
*/
\Rhilip\Ipv6Wry\IpLocation::setDbPath(string $db_path = null): void;

/**
* 解析IPv6地址,
* 如果解析成功返回 ['ip' => $ip, 'area' => $area]
* 如果解析失败返回 ['error' => $error]
*/
\Rhilip\Ipv6Wry\IpLocation::searchIp(string $ipv6): array;

编写过程主要参照的是之前在PT-help中的实现(不过没有实现其IPv4查询的部分),并参照其他PHP的GeoIP库的实现。下面就随便讲一下中间遇到的主要问题以及解决方法。

漫谈PT(6):Multitracker and client behaviour

昨晚在群里和tjupt的 @zcqian 等人讨论关于Multitracker 以及BEP相关规定,也让我学习到很多,正好整理整理。作为这个鸽了好久的系列文章第6节发布。

顺带这篇文章讨论的东西有些脱离了PT架构了,不如系列名改成 “漫谈PT” 吧。

此文行文过程中尽可能从Bittorrent client开源源码中找到对应支持点,但因为本人没有学过C++的相应知识,对libtorrent以及libtransmission的理解可能仅在于表面的调用关系上,如果有纰漏还请指出,感谢。

1563937196964.png

Multitracker 在torrent种子中的实现 (BEP0012)

对于单tracker(一般pt站点)的种子,对其种子文件进行解码(以下解码均指Bencode2Json)可以看到如下结构。

1
2
3
4
{
"announce": "http://tracker1.example.com/announce",
"info": {...}
}

而我们知道Bittorrent是P2P的形式,所以tracker数越多,可能获得的peers就越多。故 BEP0012 规定了 Multitracker Metadata Extension ,为torrent种子引入announce-list键值。一个多tracker的种子解码结构一般如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"announce": "http://tracker1.example.com/announce",
"announce-list": [
[
"http://tracker1.example.com/announce"
],
[
"http://tracker2.example.com/announce"
],
[
"udp://tracker3.example.com:6969/announce"
],
...
],
"info": {...}
}

在 BEP0012 中,对bittorrent client(以下简记client)如何处理进行了规定,即在顶层字典中出现 announce-list 字段时,该种子为Multitracker。announce-list 字段为一个list,包含若干个tier,每个tier里面可能有一个或若干个tracker,即结构为 announce-list: List[List[Tracker]]

在此时,client会忽略顶层字典中的 announce 字段,所以在实践中我们一般会把原announce字段的值作为 announce-list的第一个tier中第一个tracker,并把其他tracker另起tier放入。

uTorrent打开某Multitracker 时Tracker列表展示。每一行为一个tracker,并用空行作为Tracker的分割标识**(实际是tier的分割标识)**。对每一个tier,ut每次只使用其中一个tracker。

Snipaste_2019-07-24_08-24-08.png

使用Cloudflare Worker构建Pt-Gen

FotoJet.png

最早的时候,Pt-Gen是作为Pt-help的一个子项,使用flask内置的web server提供服务,后来BFDZ将其单独提取出来(BFDZ/PT-Gen),但是仍然存在部署较为困难的问题。

过去近1年的Pt-Gen的运行中,我曾经迁移过多次宿主机。目前托给ourhelp组的Pt-Gen服务器更是远在欧洲大陆。此外因为网络的问题,也导致部分时间段与豆瓣服务器无法连接,导致Pt-Gen服务的SLA特别差。

近期,我得知八蠢想要构建基于AWS lambda的Pt-Gen,也正好最近看到了有关Cloudflare Worker的一些介绍。正好这也是Cf-worker的用途之一——“构建完全依赖于 Web API 的“无服务器”应用程序”。

然而,与AWS lambda不同的是,cf-worker只支持Javscript。于是将原来Pt-Gen改成javascript的格式并使用Travis CI进行自动构建。

项目地址: https://github.com/Rhilip/pt-gen-cfworker
项目Demo地址: https://ptgen.rhilip.workers.dev/

Cloudflare Worker介绍

文档: https://workers.cloudflare.com/docs

Cloudflare Worker是Cloudflare推出的serverless服务,可以使用Javascript以及WebAssembly语言进行编程,其最简单的代码示例如下:

1
2
3
4
5
6
7
8
9
10
// 1. Register a FetchEvent listener that sends a custom
// response for the given request.
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})

// 2. Return a custom request object
async function handleRequest(request) {
return new Response("hello world")
}

并提供了相应的CLI工具 Wrangler 进行APP构建。此外,还提供了很简洁的调试界面。

最为良心的Cloudflare Worker是可以免费使用的(免费计划一天最多100,000次请求)

通知:Pt-help和ourhelp合并

因为功能相似,本人于之前建立的Pt-help(域名 api.rhilip.info/tool)已与ourhelp组 (域名 api.ourhelp.club)相关功能进行合并。

  1. 目前ourhelp域名是仅供ourbits.club网站使用的。本人原域名将继续提供无CORS限制的接口。但两者共享同一资源池,共享同一个资源请求限制。

  2. 原本人使用的 有/tool前缀的API point,由后端Nginx的rewrite方法提供,相关规则如下。原API使用者无需更换请求地址。但仍建议参照ourhelp域名下相关暴露方法修改请求地址。

    1
    2
    3
    4
    5
    6
    7
    location ~* ^/tool(/.*)?$ {        
    if ($host = 'api.rhilip.info') {
    rewrite ^(.*)/tool/movieinfo/gen(.*)$ $1/infogen$2 last;
    rewrite ^(.*)/tool/ptboard(.*)$ $1/ptboard$2 last;
    rewrite ^(.*)/tool/geo(.*)$ $1/geo$2 last;
    }
    }
  3. ourhelp使用后端基于 Rhilip/PT-help 修改,并闭源更新,符合原repo的开源协议MIT。

  4. 注意:https://api.rhilip.info 仅允许使用https访问,而 api.ourhelp.club 同时支持http以及https协议访问。

Rhilip@ourhelp

2019.06.30


更新:

  1. (2019.06.30) 因为无法解决的CORS问题,不再提供git-pages下的ptboard,ptanalytics,ptgen组件。使用gitpages会被meta自动跳转到api.rhilip.info下,建议更换收藏地址。

使用git-chglog规范commit信息

一个很好的git commit历史很容易帮助自己在code review的时候知道自己做了什么修改。在一段时间之前,我很喜欢使用以下格式,即一个emoji表情加一段文字说明。

1
:bug: Fix torrent link return miss....

摘自: https://github.com/Rhilip/Pt-Autoseed/commit/e776a9c19788d022e2d095fbebafe7705d154ca4

通过emoji表情,可以快速的定位到主要修改的作用,而文字也起到补充作用说明了。例如上面的例子就是一个bug fix,修复了链接丢失的情况。

详细的emoji表情列表可以参考以下两个网站:

而随着我开始写RidPT这个系统性的大工程时,以及当我需要自动化的生成CHANGELOG.md的时候,纯粹的emoji表情+文字说明变得不够方便。于是,我将目标瞄向了根据git commit log自动生成CHANGELOG的工具上,于是发现了这个 git-chglog

安装 git-chglog

git-chglog: https://github.com/git-chglog/git-chglog

作为使用go编写的跨平台工具,git-chglog的安装十分方便,只需要下载编译好的二进制文件,并将其放到$PATH中即可。

本人最近使用scoop作为Windows平台下软件包的管理工具。在本处介绍下scoop的安装方法。也十分简单。。。。装完scoop之后直接使用scoop install git-chglog即可,且会自动将其放入$PATH而不需要手动添加,过程如下:

TIM截图20190605193757.png

git-chglog使用

在食用前请看下大神写的 commit message介绍: https://github.com/pvdlg/conventional-commit-types
,以对于commit格式有所了解。
在git仓库中使用git-chglog --init即可进入该软件的交互创建过程。这里我以ronggang/PT-Plugin-Plus为示例:

TIM截图20190605194828.png

分别问了以下几个问题:

  • 仓库地址 (What is the URL of your repository?): 直接回车就行,软件会读.git目录下配置信息

  • 喜欢的样式(What is your favorite style?): 有github, gitlab, bitbucket, none 四种类型,一般根据你仓库托管的选就行。

  • Commit样式(Choose the format of your favorite commit message):同样有多个选项,对信息提取的完备性依次下降。

1
2
3
4
<type>(<scope>): <subject> -- feat(core): Add new feature
<type>: <subject> -- feat: Add new feature
<<type> subject> -- Add new feature
<subject> -- Add new feature (Not detect `type` field)
  • 生成CHANGLOG.md的样式(What is your favorite template style?): 提供三个选项 keep-a-changelog, standard, cool,以及参考示例。我观察了很久没发现大的区别,主要是commit的时间的位置以及样式不同。
  • Merge是否显示(Do you include Merge Commit in CHANGELOG?): 根据需求选择y/n
  • Revert是否显示(Do you include Revert Commit in CHANGELOG?): 根据需求选择y/n
  • 配置.chglog目录(In which directory do you output configuration files and templates?):默认即可,如果已经有重复文件存在会提示是否需要覆盖。

完成问题的回答之后,就可以使用git-chglog自动生成了。

如果并不带任何附加的话,默认是输出到stdout的,需要使用 git-chglog --output CHANGELOG.md 才能生成文件形式放在仓库根目录下。

PhpStorm中使用插件生成格式化commit信息

我们可以很简便的使用IDE的插件来生成格式化的commit信息,如我在PhpStorm中就使用Git Commit Template这款插件进行commit信息生成

TIM截图20190605205014.png

在每个对话框中输入信息后就可以点击OK键,格式化的commit信息就自动的放入了Commit Message中。其生成的格式如下:

1
2
3
4
5
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>

使用git hook在提交commit的时候更新CHANGELOG.md

但是每次都需要键入git-chglog的形式生成CHANGELOG.md过于麻烦,我们可以使用git hook的形式,用钩子在我们commit之前进行CHANGELOG.md的更新。

创建 /.git/hooks/pre-commit文件,内容如下

1
2
3
#!/bin/sh
git-chglog -output CHANGELOG.md
exit 0;

这样,CHANGELOG.md的自动更新就不用我们去手动管理了。

PHP下Bencode库差异及性能对比

如果你有过注意,我曾在最近为国内某一PT站点更换了其Bencode库。究其原因在于,NexusPHP自带的Bencode库解析出来的Array中含有较多的无用元素,且性能较低,在一定程度上拖慢了种子上传过程中的解析速度,此外还占用过多内存。

概览

本次对比的对象有NexusPHP自带的、本人新写RidPT(但是还没有写完的)所用的Bencode库,以及其他在 https://packagist.org/ 中注册有Bencode库标识(tag)的相关库,列表如下:

PHP
Bencode Library
Ver. Size Encode From
Array/Object
Decode From
String/File Loc
NexusPHP(benc.php) - 2.56 KB √/× √/√
RidPT(Bencode.php) - 4.32 KB √/× √/√
————— —- —— ——
sandfoxme/bencode 1.3.0 62 KB √/√ √/√
rych/bencode 1.0.0 35 KB √/× √/×
dsmithhayes/bencode 0.1.3 529 KB √/× √/×
s9e/Bencode 1.1.1 14 KB √/× √/×
nrk/bencoder 1.0.0 132 KB √/× √/√
pure-bencode/pure-bencode 1.1 178 KB √/× √/×
ppokatilo/bencode 1.0.0 4 KB √/√ √/×
nirosa/bencode dev 13 KB √/× √/×
OPSnet/bencode-torrent v0.11.0 41 KB ×/× √/√
akatsuki/bencode 1.0.0 10 KB √/√ √/×

注1. RidPT使用的Bencode库基于 OPSnet/bencode-torrent 改写,并学习了 sandfoxme/bencode 的一些暴露方法。

注2. 从Decode From File Loc的意思是库内置有相关方法,可以直接给文件地址就可以生成对应的Array,而不用外置使用file_get_content()或者fread()方法(其库内有内置该方法,如以下伪代码 Bencode::load($file_loc [, $max_torrent_size] );

太长不看

推荐使用以下库: RidPT(Bencode.php) 替代原NexusPHP中benc!!!!

替换方法: