parent
32c04f1621
commit
a49c63af09
@ -1,141 +0,0 @@ |
||||
<?php |
||||
/** |
||||
* Created by PhpStorm. |
||||
* User: Rhilip |
||||
* Date: 2019/4/21 |
||||
* Time: 21:12 |
||||
*/ |
||||
class Bencode |
||||
{ |
||||
/** |
||||
* Decodes a BEncoded string to the following values: |
||||
* - Dictionary (starts with d, ends with e) |
||||
* - List (starts with l, ends with e |
||||
* - Integer (starts with i, ends with e |
||||
* - String (starts with number denoting number of characters followed by : and then the string) |
||||
* |
||||
* @see https://wiki.theory.org/index.php/BitTorrentSpecification |
||||
* |
||||
* @param string $data |
||||
* @param int $pos |
||||
* @return mixed |
||||
*/ |
||||
public static function decode($data, &$pos = 0) |
||||
{ |
||||
$start_decode = ($pos === 0); |
||||
if ($data[$pos] === 'd') { |
||||
$pos++; |
||||
$return = []; |
||||
while ($data[$pos] !== 'e') { |
||||
$key = self::decode($data, $pos); |
||||
$value = self::decode($data, $pos); |
||||
if ($key === null || $value === null) { |
||||
break; |
||||
} |
||||
if (!is_string($key)) { |
||||
throw new RuntimeException('Invalid key type, must be string: ' . gettype($key)); |
||||
} |
||||
$return[$key] = $value; |
||||
} |
||||
ksort($return); |
||||
$pos++; |
||||
} elseif ($data[$pos] === 'l') { |
||||
$pos++; |
||||
$return = []; |
||||
while ($data[$pos] !== 'e') { |
||||
$value = self::decode($data, $pos); |
||||
$return[] = $value; |
||||
} |
||||
$pos++; |
||||
} elseif ($data[$pos] === 'i') { |
||||
$pos++; |
||||
$digits = strpos($data, 'e', $pos) - $pos; |
||||
$return = substr($data, $pos, $digits); |
||||
if ($return === '-0') { |
||||
throw new RuntimeException('Cannot have integer value -0'); |
||||
} |
||||
$multiplier = 1; |
||||
if ($return[0] === '-') { |
||||
$multiplier = -1; |
||||
$return = substr($return, 1); |
||||
} |
||||
if (!ctype_digit($return)) { |
||||
throw new RuntimeException('Cannot have non-digit values in integer number: ' . $return); |
||||
} |
||||
$return = $multiplier * ((int)$return); |
||||
$pos += $digits + 1; |
||||
} else { |
||||
$digits = strpos($data, ':', $pos) - $pos; |
||||
$len = (int)substr($data, $pos, $digits); |
||||
$pos += ($digits + 1); |
||||
$return = substr($data, $pos, $len); |
||||
$pos += $len; |
||||
} |
||||
if ($start_decode) { |
||||
if ($pos !== strlen($data)) { |
||||
throw new RuntimeException('Could not fully decode bencode string'); |
||||
} |
||||
} |
||||
return $return; |
||||
} |
||||
/** |
||||
* @param mixed $data |
||||
* @return string |
||||
*/ |
||||
public static function encode($data) |
||||
{ |
||||
if (is_array($data)) { |
||||
$return = ''; |
||||
$check = -1; |
||||
$list = true; |
||||
foreach ($data as $key => $value) { |
||||
if ($key !== ++$check) { |
||||
$list = false; |
||||
break; |
||||
} |
||||
} |
||||
if ($list) { |
||||
$return .= 'l'; |
||||
foreach ($data as $value) { |
||||
$return .= self::encode($value); |
||||
} |
||||
} else { |
||||
$return .= 'd'; |
||||
foreach ($data as $key => $value) { |
||||
$return .= self::encode(strval($key)); |
||||
$return .= self::encode($value); |
||||
} |
||||
} |
||||
$return .= 'e'; |
||||
} elseif (is_integer($data)) { |
||||
$return = 'i' . $data . 'e'; |
||||
} else { |
||||
$return = strlen($data) . ':' . $data; |
||||
} |
||||
return $return; |
||||
} |
||||
/** |
||||
* Given a path to a file, decode the contents of it |
||||
* |
||||
* @param string $path |
||||
* @return mixed |
||||
*/ |
||||
public static function load($path) |
||||
{ |
||||
if (is_file($path)) { |
||||
return self::decode(file_get_contents($path)); |
||||
} |
||||
return null; |
||||
} |
||||
/** |
||||
* Given a path for a file, encode the contents of it |
||||
* |
||||
* @param string $path |
||||
* @param $data |
||||
* @return mixed |
||||
*/ |
||||
public static function dump($path, $data) |
||||
{ |
||||
return file_put_contents($path, self::encode($data)); |
||||
} |
||||
} |
Loading…
Reference in new issue