Created
December 24, 2021 11:48
-
-
Save ALiwoto/88a7f9f251cc899a33be8b5f13f227ef to your computer and use it in GitHub Desktop.
Some Hash Utils for telegram (NOT by me)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** @noinspection SpellCheckingInspection */ | |
/** @noinspection PhpMissingBreakStatementInspection */ | |
namespace TelegramBot\Util; | |
use TelegramBot\Exception\UtilException; | |
/** | |
* Trait HashUtil | |
* @package TelegramBot\Util | |
*/ | |
class HashUtil | |
{ | |
public const WEB_LOCATION_FLAG = 1 << 24; | |
public const FILE_REFERENCE_FLAG = 1 << 25; | |
public const THUMBNAIL = 0x00; | |
public const PROFILE_PHOTO = 0x01; | |
public const PHOTO = 0x02; | |
public const VOICE = 0x03; | |
public const VIDEO = 0x04; | |
public const DOCUMENT = 0x05; | |
public const ENCRYPTED = 0x06; | |
public const TEMP = 0x07; | |
public const STICKER = 0x08; | |
public const AUDIO = 0x09; | |
public const GIF = 0x0A; | |
public const ENCRYPTED_THUMBNAIL = 0x0B; | |
public const WALLPAPER = 0x0C; | |
public const VIDEO_NOTE = 0x0D; | |
public const SECURE_RAW = 0x0F; | |
public const SECURE = 0x10; | |
public const BACKGROUND = 0x11; | |
public const SIZE = 0x12; | |
/** | |
* @param string $type | |
* @param int $dc_id | |
* @param int $id | |
* @param int $access_hash | |
* @param int|null $volume_id | |
* @param int|null $secret | |
* @param int|null $local_id | |
* @return string | |
* @throws UtilException | |
*/ | |
public static function encodeFileIdInfo( | |
string $type, | |
int $dc_id, | |
int $id, | |
int $access_hash, | |
int $volume_id = null, | |
int $secret = null, | |
int $local_id = null | |
) { | |
switch ($type) { | |
case 'Thumb': | |
$file_type = self::THUMBNAIL; | |
case 'Photo': | |
if (empty($file_type)) { | |
$file_type = self::PHOTO; | |
} | |
if (empty($volume_id) or empty($secret) or empty($local_id)) { | |
throw new UtilException("Missing required parameters for file type"); | |
} | |
$file_id = pack('VVqqqqV', $file_type, $dc_id, $id, $access_hash, $volume_id, $secret, $local_id); | |
break; | |
case 'Voice': | |
$file_type = self::VOICE; | |
case 'Video': | |
if (empty($file_type)) { | |
$file_type = self::VIDEO; | |
} | |
case 'Document': | |
if (empty($file_type)) { | |
$file_type = self::DOCUMENT; | |
} | |
case 'Sticker': | |
if (empty($file_type)) { | |
$file_type = self::STICKER; | |
} | |
case 'Audio': | |
if (empty($file_type)) { | |
$file_type = self::AUDIO; | |
} | |
case 'Animation': | |
if (empty($file_type)) { | |
$file_type = self::GIF; | |
} | |
case 'VideoNote': | |
if (empty($file_type)) { | |
$file_type = self::VIDEO_NOTE; | |
} | |
$file_id = pack('VVqq', $file_type, $dc_id, $id, $access_hash); | |
break; | |
default: | |
$file_id = null; | |
break; | |
} | |
return self::base64UrlEncode(self::rleEncode($file_id . chr(2))); | |
} | |
/** | |
* @param string $string | |
* @return string | |
*/ | |
protected static function base64UrlEncode(string $string): string | |
{ | |
return str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($string)); | |
} | |
/** | |
* @param string $string | |
* @return string | |
*/ | |
protected static function rleEncode(string $string): string | |
{ | |
$new = ''; | |
$count = 0; | |
$null = chr(0); | |
foreach (str_split($string) as $cur) { | |
if ($cur === $null) { | |
$count++; | |
} else { | |
if ($count > 0) { | |
$new .= $null . chr($count); | |
$count = 0; | |
} | |
$new .= $cur; | |
} | |
} | |
return $new; | |
} | |
/** | |
* @param string $file_id | |
* @return array | |
*/ | |
public static function decodeFileIdInfo(string $file_id) | |
{ | |
$file_info = self::rleDecode(self::base64UrlDecode($file_id)); | |
$file_type = unpack('C', substr($file_info, 0, 1))[1]; | |
$file_flags = unpack('V', chr(0) . substr($file_info, 1, 3))[1]; | |
$version = \ord($file_info[\strlen($file_info) - 1]); | |
$subVersion = $version === 4 ? \ord($file_info[\strlen($file_info) - 2]) : 0; | |
$file_info = substr($file_info, 4); | |
$dc_id = unpack('V', $file_info)[1]; | |
$file_info = substr($file_info, 4); | |
switch ($file_type) { | |
case self::THUMBNAIL: | |
if (empty($type)) { | |
$type = 'Thumb'; | |
} | |
case self::PROFILE_PHOTO: | |
if (empty($type)) { | |
$type = 'profile_photo'; | |
} | |
case self::PHOTO: | |
if (empty($type)) { | |
$type = 'Photo'; | |
} | |
$infostring = 'qid/qaccess_hash/qvolume_id/qsecret/Vrobastrana/Vlocal_id'; | |
//$local_id = unpack('V', substr($file_info, -6))[1]; | |
break; | |
case self::VOICE: | |
$type = 'Voice'; | |
case self::VIDEO: | |
if (empty($type)) { | |
$type = 'Video'; | |
} | |
case self::DOCUMENT: | |
if (empty($type)) { | |
$type = 'Document'; | |
} | |
case self::ENCRYPTED: | |
if (empty($type)) { | |
$type = 'Encrypted'; | |
} | |
case self::TEMP: | |
if (empty($type)) { | |
$type = 'Temp'; | |
} | |
case self::STICKER: | |
if (empty($type)) { | |
$type = 'Sticker'; | |
} | |
case self::AUDIO: | |
if (empty($type)) { | |
$type = 'Audio'; | |
} | |
case self::GIF: | |
if (empty($type)) { | |
$type = 'Animation'; | |
} | |
case self::ENCRYPTED_THUMBNAIL: | |
if (empty($type)) { | |
$type = 'EncryptedThumbnail'; | |
} | |
case self::WALLPAPER: | |
if (empty($type)) { | |
$type = 'Wallpaper'; | |
} | |
case self::VIDEO_NOTE: | |
if (empty($type)) { | |
$type = 'VideoNote'; | |
} | |
//case 0x0E: | |
// :shrug: | |
case self::SECURE_RAW: | |
if (empty($type)) { | |
$type = 'SecureRaw'; | |
} | |
case self::SECURE: | |
if (empty($type)) { | |
$type = 'Secure'; | |
} | |
case self::BACKGROUND: | |
if (empty($type)) { | |
$type = 'Background'; | |
} | |
case self::SIZE: | |
if (empty($type)) { | |
$type = 'Size'; | |
} | |
$infostring = 'qid/qaccess_hash'; | |
break; | |
default: | |
$infostring = ''; | |
$type = $file_type; | |
break; | |
} | |
if ($file_flags & self::FILE_REFERENCE_FLAG) { | |
$frlen = ord($file_info[0]); | |
$file_info[0] = chr(0); | |
if ($frlen == 254) { | |
$frlen = unpack('V', $file_info)[1]; | |
$pad = self::posmod(-$frlen, 4); | |
} else { | |
$pad = self::posmod(-$frlen, -4); | |
} | |
$file_reference = substr($file_info, 0, $frlen); | |
$file_info = substr($file_info, $frlen+$pad); | |
} | |
$decrypted_info = unpack($infostring, $file_info); | |
$decrypted_info['type'] = $type; | |
$decrypted_info['dc_id'] = $dc_id; | |
$decrypted_info['version'] = "$version.$subVersion"; | |
$decrypted_info['flags'] = $file_flags; | |
if (isset($file_reference)) { | |
$decrypted_info['file_reference'] = self::base64UrlEncode($file_reference); | |
} | |
if (isset($local_id)) { | |
$decrypted_info['local_id'] = $local_id; | |
} | |
return $decrypted_info; | |
} | |
/** | |
* @param string $string | |
* @return string | |
*/ | |
protected static function rleDecode(string $string): string | |
{ | |
$new = ''; | |
$last = ''; | |
$null = chr(0); | |
foreach (str_split($string) as $cur) { | |
if ($last === $null) { | |
$new .= str_repeat($last, ord($cur)); | |
$last = ''; | |
} else { | |
$new .= $last; | |
$last = $cur; | |
} | |
} | |
return $new . $last; | |
} | |
/** | |
* @param string $string | |
* @return string | |
*/ | |
protected static function base64UrlDecode(string $string): string | |
{ | |
return base64_decode(str_pad(strtr($string, '-_', '+/'), strlen($string) % 4, '=', STR_PAD_RIGHT)); | |
} | |
/** | |
* @param int $chat_creator | |
* @param int $chat_id | |
* @param int $access_hash | |
* @return string | |
*/ | |
public static function encodeChatInviteHashInfo(int $chat_creator, int $chat_id, int $access_hash): string | |
{ | |
$inverted_hash = pack('q', $access_hash); | |
$inverted_hash = unpack('q', strrev($inverted_hash))[1]; | |
if (strpos((string)$chat_id, '-100') === 0) { | |
$chat_id = substr($chat_id, 4); | |
$chat_id = (int)$chat_id; | |
} else { | |
$chat_id = substr($chat_id, 1); | |
} | |
$chat_id = (int)$chat_id; | |
$chat_invite_hash = pack('NNq', $chat_creator, $chat_id, $inverted_hash); | |
return self::base64UrlEncode($chat_invite_hash); | |
} | |
/** | |
* @param string $chat_invite_hash | |
* @return array | |
*/ | |
public static function decodeChatInviteHashInfo(string $chat_invite_hash): array | |
{ | |
$chat_invite_info = self::base64UrlDecode($chat_invite_hash); | |
$decrypted_info = unpack('Nchat_creator/Nchat_id/qaccess_hash', $chat_invite_info); | |
if (strlen($decrypted_info['chat_id']) < 10) { | |
$chat_id = '-' . $decrypted_info['chat_id']; | |
$decrypted_info['chat_id'] = (int)$chat_id; | |
return $decrypted_info; | |
} | |
$chat_id = '-100' . $decrypted_info['chat_id']; | |
$decrypted_info['chat_id'] = (int)$chat_id; | |
$real_hash = pack('q', $decrypted_info['access_hash']); | |
$decrypted_info['access_hash'] = unpack('q', strrev($real_hash))[1]; | |
return $decrypted_info; | |
} | |
/** | |
* @param int $dc_id | |
* @param int $message_id | |
* @param int $chat_id | |
* @param int $access_hash | |
* @return string | |
*/ | |
public static function encodeInlineMessageIdInfo( | |
int $dc_id, | |
int $message_id, | |
int $chat_id, | |
int $access_hash | |
): string { | |
if ($chat_id < 0) { | |
$chat_id = substr($chat_id, 4); | |
$chat_id = (int)$chat_id * -1; | |
} | |
$inline_message_id = pack('VVlq', $dc_id, $message_id, $chat_id, $access_hash); | |
return self::base64UrlEncode($inline_message_id); | |
} | |
/** | |
* @param string $inline_message_id | |
* @return array | |
*/ | |
public static function decodeInlineMessageIdInfo(string $inline_message_id): array | |
{ | |
$inline_message_info = self::base64UrlDecode($inline_message_id); | |
$decrypted_info = unpack('Vdc_id/Vmessage_id/lchat_id/qaccess_hash', $inline_message_info); | |
if ($decrypted_info['chat_id'] < 0) { | |
$chat_id = '-100' . ($decrypted_info['chat_id'] * -1); | |
$decrypted_info['chat_id'] = (int)$chat_id; | |
return $decrypted_info; | |
} | |
$decrypted_info['user_id'] = $decrypted_info['chat_id']; | |
unset($decrypted_info['chat_id']); | |
return $decrypted_info; | |
} | |
/** | |
* @param int $a | |
* @param int $b | |
* @return int | |
*/ | |
public static function posmod(int $a, int $b): int | |
{ | |
$resto = $a % $b; | |
return $resto < 0 ? $resto + \abs($b) : $resto; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment