All pastes #953554 Raw Edit

PHP bencoding parser

public php v1 · immutable
#953554 ·published 2008-03-23 04:39 UTC
rendered paste body
<?php/** * A class to encode & decode bencoded data. * * @author Michael Cooney */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));