rendered paste body<?php/** * A class to encode & decode bencoded data. * */class bencoder{ /** * Pass mixed PHP data and expect a bencoded string to be returned. * * @param mixed $data * @return string */ public static function encode($data) { if (is_array($data)) { ksort($data); if (is_string(key($data))) { return self::encode_dictionary($data); } else { return self::encode_list($data); } } else if (is_numeric($data)) { return self::encode_int($data); } else if (is_string($data)) { return self::encode_string($data); } else { throw new Exception('invalid data'); } } private static function encode_string($data) { return strlen($data) . ":" . $data; } private static function encode_int($data) { return 'i' . $data . 'e'; } private static function encode_list(array $data) { $return = 'l'; foreach ($data as $datum) { $return .= self::encode($datum); } $return .= 'e'; return $return; } private static function encode_dictionary(array $data) { $return = 'd'; foreach ($data as $key => $value) { $return .= self::encode_string($key); $return .= self::encode($value); } $return .= 'e'; return $return; } /** * Pass in a bencoded string and get back an int, string, or array * depending on the bencoded data. * * @param $data string * @return mixed */ public static function decode($data) { // every time something external calls decode we will reset the pointer // it will be left alone for internal recursive calls return self::_decode($data, TRUE); } /** * Does the actual decoding. This is private so that the caller cannot * request the pointer to be reset. * * @param $data string * @param $reset_pointer boolean * @return mixed */ private static function _decode($data, $reset_pointer = FALSE) { static $pointer = 0; if ($reset_pointer) $pointer = 0; // decoding a string if (is_numeric($data[$pointer])) { $strlength = ''; while (is_numeric($data[$pointer])) { $strlength .= $data[$pointer]; $pointer++; } $pointer++; $strlength = (int)$strlength; $decoded = substr($data, $pointer, $strlength); $pointer += $strlength; } else { switch ($data[$pointer]) { // decoding an integer case 'i': $number = ''; $pointer++; // advance past the 'i' while (is_numeric($data[$pointer])) { $number .= $data[$pointer]; $pointer++; } $pointer++; // advance past the ending 'e' $decoded = (int)$number; break; // decoding a list case 'l': $decoded = array(); $pointer++; // advance past the 'l' while (isset($data[$pointer]) && $data[$pointer] != 'e') { $decoded[] = self::_decode($data); } $pointer++; // advance past the ending 'e' break; // decoding a dictionary case 'd': $decoded = array(); $pointer++; // advance past the 'd' while (isset($data[$pointer]) && $data[$pointer] != 'e') { $decoded[self::_decode($data)] = self::_decode($data); } $pointer++; // advance past ending 'e' break; // encountered invalid bencoding default: throw new Exception('invalid data: [' . $pointer . '] = ' . $data[$pointer]); } } return $decoded; }}//// TESTS://// ENCODING// int$data = 3;var_dump(bencoder::encode($data));// list$data = array(45,754,5434);var_dump(bencoder::encode($data));// dictionary$data = array ( 'cow' => 'moo', 'spam' => 'eggs' ); var_dump(bencoder::encode($data));// list nested in dictionary$data = array ( 'spam' => array ('a','b') );var_dump(bencoder::encode($data));// nested lists$data = array ( array(1,2,3), array(3,2,1) );var_dump(bencoder::encode($data));// DECODING:// string$data = '4:spam';var_dump(bencoder::decode($data));// int$data = 'i5435e';var_dump(bencoder::decode($data));// list$data = 'li45ei754ei5434ee';var_dump(bencoder::decode($data));// nested lists$data = 'lli1ei2ei3eeli3ei2ei1eee';var_dump(bencoder::decode($data));// list nested in dictionary$data = 'd4:spaml1:a1:bee';var_dump(bencoder::decode($data));