s9e/bencode

快速高效的bencode解码器/编码器,旨在优雅地处理格式错误和恶意输入。

2.3.2 2024-04-09 19:49 UTC

README

s9e\Bencode是一个简洁高效的Bencode编码器/解码器。它旨在优雅地处理格式错误和恶意输入。

Build Status Code Coverage Scrutinizer Code Quality

安装

composer require s9e/bencode

用法

解码bencoded字符串

use s9e\Bencode\Bencode;
print_r(Bencode::decode('d3:bar4:spam3:fooi42ee'));
ArrayObject Object
(
    [storage:ArrayObject:private] => Array
        (
            [bar] => spam
            [foo] => 42
        )

)

编码PHP值

use s9e\Bencode\Bencode;
print_r(Bencode::encode(['foo' => 42, 'bar' => 'spam']));
d3:bar4:spam3:fooi42ee

支持以下类型

  • arrayintstring值会被原生编码。
  • float值在无损转换到整数时会强制转换为int
  • bool值会强制转换为int
  • 实现了s9e\Bencode\BencodeSerializable的对象会以它的bencodeSerialize()方法返回的值进行编码。
  • stdClass对象的属性以字典形式编码。
  • ArrayObject的实例被视为数组。
use s9e\Bencode\Bencode;
use s9e\Bencode\BencodeSerializable;

$bencodable = new class implements BencodeSerializable
{
	public function bencodeSerialize(): array|int|string
	{
		return 42;
	}
};

print_r(Bencode::encode($bencodable));
i42e

处理异常

try
{
	s9e\Bencode\Bencode::decode('i123x');
}
catch (s9e\Bencode\Exceptions\DecodingException $e)
{
	var_dump($e->getMessage(), $e->getOffset());
}
string(29) "Illegal character at offset 4"
int(4)
try
{
	s9e\Bencode\Bencode::encode(2.5);
}
catch (s9e\Bencode\Exceptions\EncodingException $e)
{
	var_dump($e->getMessage(), $e->getValue());
}
string(17) "Unsupported value"
float(2.5)

恢复不符合规范的数据

默认情况下,解码器会通过抛出ComplianceError异常来拒绝不符合规范的数据,该异常是DecodingException的子类型。如果您必须处理由不符合规范编码器生成的输入,则decodeNonCompliant方法可能能够通过以下方式恢复它

  • 无序字典会自动排序。
  • 字典中的重复条目会覆盖先前的条目。
  • 用作字典键的整数会被转换为字符串。
  • 整数前的0会被移除。
  • 负零会被转换为0
  • 输入末尾的垃圾数据会被忽略。

在以下示例中,我们尝试正常加载一个无效字典,并在失败时,使用非规范解码器重试。

use s9e\Bencode\Bencode;

$input = 'd3:fooi42e3:bar4:spame';
try
{
	$value = Bencode::decode($input);
}
catch (s9e\Bencode\Exceptions\ComplianceError $e)
{
	echo 'Failed: ', $e->getMessage(), "\nRetry with non-compliant decoder:\n";

	$value = Bencode::decodeNonCompliant($input);
	print_r($value);
}
Failed: Out of order dictionary entry 'bar' at offset 10
Retry with non-compliant decoder:
ArrayObject Object
(
    [storage:ArrayObject:private] => Array
        (
            [bar] => spam
            [foo] => 42
        )

)

实现细节

  • 拒绝无效的bencoded数据,并抛出有意义的异常信息。
  • 使用ArrayObject实例来表示字典。可以使用数组表示法或对象表示法创建和读取字典。
  • 整数范围限制在PHP_INT_MINPHP_INT_MAX之间。
  • 编码器接受布尔值,但将它们转换为整数。
  • 编码器接受等于其整数值的浮点数。