BioTorrents.de’s version of Gazelle
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

bencode.class.php 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. <?php
  2. #declare(strict_types=1);
  3. /**
  4. * If we're running a 32bit PHP version, we use small objects to store ints.
  5. * Overhead from the function calls is small enough to not worry about
  6. */
  7. class Int64
  8. {
  9. private $Num;
  10. public function __construct($Val)
  11. {
  12. $this->Num = $Val;
  13. }
  14. public static function make($Val)
  15. {
  16. return PHP_INT_SIZE === 4 ? new Int64($Val) : (int)$Val;
  17. }
  18. public static function get($Val)
  19. {
  20. return PHP_INT_SIZE === 4 ? $Val->Num : $Val;
  21. }
  22. public static function is_int($Val)
  23. {
  24. return is_int($Val) || (is_object($Val) && get_class($Val) === 'Int64');
  25. }
  26. }
  27. /**
  28. * The encode class is simple and straightforward. The only thing to
  29. * note is that empty dictionaries are represented by boolean trues
  30. */
  31. class Bencode
  32. {
  33. private $DefaultKeys = array( // Get rid of everything except these keys to save some space
  34. 'created by', 'creation date', 'encoding', 'info', 'comment');
  35. private $Data;
  36. public $Enc;
  37. /**
  38. * Encode an arbitrary array (usually one that's just been decoded)
  39. *
  40. * @param array $Arg the thing to encode
  41. * @param mixed $Keys string or array with keys in the input array to encode or true to encode everything
  42. * @return bencoded string representing the content of the input array
  43. */
  44. public function encode($Arg = false, $Keys = false)
  45. {
  46. if ($Arg === false) {
  47. $Data =& $this->Dec;
  48. } else {
  49. $Data =& $Arg;
  50. }
  51. if ($Keys === true) {
  52. $this->Data = $Data;
  53. } elseif ($Keys === false) {
  54. $this->Data = array_intersect_key($Data, array_flip($this->DefaultKeys));
  55. } elseif (is_array($Keys)) {
  56. $this->Data = array_intersect_key($Data, array_flip($Keys));
  57. } else {
  58. $this->Data = isset($Data[$Keys]) ? $Data[$Keys] : false;
  59. }
  60. if (!$this->Data) {
  61. return false;
  62. }
  63. $this->Enc = $this->_benc();
  64. return $this->Enc;
  65. }
  66. /**
  67. * Internal encoding function that does the actual job
  68. *
  69. * @return bencoded string
  70. */
  71. private function _benc()
  72. {
  73. if (!is_array($this->Data)) {
  74. if (Int64::is_int($this->Data)) { // Integer
  75. return 'i'.Int64::get($this->Data).'e';
  76. }
  77. if ($this->Data === true) { // Empty dictionary
  78. return 'de';
  79. }
  80. return strlen($this->Data).':'.$this->Data; // String
  81. }
  82. if (empty($this->Data) || Int64::is_int(key($this->Data))) {
  83. $IsDict = false;
  84. } else {
  85. $IsDict = true;
  86. ksort($this->Data); // Dictionaries must be sorted
  87. }
  88. $Ret = $IsDict ? 'd' : 'l';
  89. foreach ($this->Data as $Key => $Value) {
  90. if ($IsDict) {
  91. $Ret .= strlen($Key).':'.$Key;
  92. }
  93. $this->Data = $Value;
  94. $Ret .= $this->_benc();
  95. }
  96. return $Ret.'e';
  97. }
  98. }