mirror of
https://github.com/danog/tg-file-decoder.git
synced 2024-11-26 12:24:40 +01:00
Refactor API
This commit is contained in:
parent
464800a3c5
commit
9d9c253848
@ -11,7 +11,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.1"
|
||||
"php-64bit": ">=8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9",
|
||||
|
@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<files psalm-version="dev-master@ef3b018e89c4ffc157332c13e2ebf9cf22320d17">
|
||||
<file src="src/functions.php">
|
||||
<UnusedVariable>
|
||||
<code><![CDATA[$BIG_ENDIAN]]></code>
|
||||
</UnusedVariable>
|
||||
</file>
|
||||
</files>
|
@ -1,11 +1,13 @@
|
||||
<?xml version="1.0"?>
|
||||
<psalm
|
||||
errorLevel="5"
|
||||
errorLevel="1"
|
||||
resolveFromConfigFile="true"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="https://getpsalm.org/schema/config"
|
||||
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
|
||||
errorBaseline="psalm-baseline.xml"
|
||||
findUnusedCode="true"
|
||||
findUnusedPsalmSuppress="true"
|
||||
ignoreInternalFunctionFalseReturn="true"
|
||||
>
|
||||
<projectFiles>
|
||||
<directory name="src" />
|
||||
|
699
src/FileId.php
699
src/FileId.php
@ -19,6 +19,8 @@
|
||||
namespace danog\Decoder;
|
||||
|
||||
use danog\Decoder\PhotoSizeSource\PhotoSizeSourceDialogPhoto;
|
||||
use danog\Decoder\PhotoSizeSource\PhotoSizeSourceDialogPhotoBig;
|
||||
use danog\Decoder\PhotoSizeSource\PhotoSizeSourceDialogPhotoSmall;
|
||||
use danog\Decoder\PhotoSizeSource\PhotoSizeSourceLegacy;
|
||||
use danog\Decoder\PhotoSizeSource\PhotoSizeSourceStickersetThumbnail;
|
||||
use danog\Decoder\PhotoSizeSource\PhotoSizeSourceStickersetThumbnailVersion;
|
||||
@ -31,73 +33,73 @@ use danog\Decoder\PhotoSizeSource\PhotoSizeSourceThumbnail;
|
||||
*/
|
||||
final class FileId
|
||||
{
|
||||
/**
|
||||
* Bot API file ID version.
|
||||
*
|
||||
*/
|
||||
private int $version = 4;
|
||||
|
||||
/**
|
||||
* Bot API file ID subversion.
|
||||
*
|
||||
*/
|
||||
private int $subVersion = 47;
|
||||
|
||||
/**
|
||||
* DC ID.
|
||||
*
|
||||
*/
|
||||
private int $dcId = 0;
|
||||
|
||||
/**
|
||||
* File type.
|
||||
*
|
||||
*/
|
||||
private FileIdType $type = FileIdType::NONE;
|
||||
|
||||
/**
|
||||
* File reference.
|
||||
*
|
||||
*/
|
||||
private string $fileReference = '';
|
||||
/**
|
||||
* File URL for weblocation.
|
||||
*
|
||||
*/
|
||||
private string $url = '';
|
||||
|
||||
/**
|
||||
* File id.
|
||||
*
|
||||
*/
|
||||
private int $id;
|
||||
/**
|
||||
* File access hash.
|
||||
*
|
||||
*/
|
||||
private int $accessHash;
|
||||
|
||||
/**
|
||||
* Photo volume ID.
|
||||
*
|
||||
*/
|
||||
private int $volumeId;
|
||||
/**
|
||||
* Photo local ID.
|
||||
*
|
||||
*/
|
||||
private int $localId;
|
||||
|
||||
/**
|
||||
* Photo size source.
|
||||
*
|
||||
*/
|
||||
private PhotoSizeSource $photoSizeSource;
|
||||
/**
|
||||
* Basic constructor function.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
public function __construct(
|
||||
/**
|
||||
* DC ID.
|
||||
*
|
||||
*/
|
||||
public readonly int $dcId,
|
||||
|
||||
/**
|
||||
* File type.
|
||||
*
|
||||
*/
|
||||
public readonly FileIdType $type,
|
||||
|
||||
/**
|
||||
* File id.
|
||||
*
|
||||
*/
|
||||
public readonly ?int $id,
|
||||
/**
|
||||
* File access hash.
|
||||
*
|
||||
*/
|
||||
public readonly int $accessHash,
|
||||
|
||||
/**
|
||||
* Photo size source.
|
||||
*
|
||||
*/
|
||||
public readonly ?PhotoSizeSource $photoSizeSource = null,
|
||||
|
||||
/**
|
||||
* Photo volume ID.
|
||||
*
|
||||
*/
|
||||
public readonly ?int $volumeId = null,
|
||||
/**
|
||||
* Photo local ID.
|
||||
*
|
||||
*/
|
||||
public readonly ?int $localId = null,
|
||||
|
||||
/**
|
||||
* File reference.
|
||||
*
|
||||
*/
|
||||
public readonly ?string $fileReference = null,
|
||||
/**
|
||||
* File URL for weblocation.
|
||||
*
|
||||
*/
|
||||
public readonly ?string $url = null,
|
||||
|
||||
/**
|
||||
* Bot API file ID version.
|
||||
*
|
||||
*/
|
||||
public readonly int $version = 4,
|
||||
|
||||
/**
|
||||
* Bot API file ID subversion.
|
||||
*
|
||||
*/
|
||||
public readonly int $subVersion = 47,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
@ -108,66 +110,139 @@ final class FileId
|
||||
*/
|
||||
public static function fromBotAPI(string $fileId): self
|
||||
{
|
||||
$result = new self;
|
||||
$resultArray = internalDecode($fileId);
|
||||
$result->setVersion($resultArray['version']);
|
||||
$result->setSubVersion($resultArray['subVersion']);
|
||||
$result->setType($resultArray['typeId']);
|
||||
$result->setDcId($resultArray['dc_id']);
|
||||
$result->setAccessHash($resultArray['access_hash']);
|
||||
$orig = $fileId;
|
||||
$fileId = rleDecode(base64urlDecode($fileId));
|
||||
$version = \ord($fileId[\strlen($fileId) - 1]);
|
||||
$subVersion = $version === 4 ? \ord($fileId[\strlen($fileId) - 2]) : 0;
|
||||
|
||||
if ($resultArray['hasReference']) {
|
||||
$result->setFileReference($resultArray['fileReference']);
|
||||
}
|
||||
if ($resultArray['hasWebLocation']) {
|
||||
$result->setUrl($resultArray['url']);
|
||||
return $result;
|
||||
}
|
||||
$result->setId($resultArray['id']);
|
||||
$res = \fopen('php://memory', 'rw+b');
|
||||
\assert($res !== false);
|
||||
\fwrite($res, $fileId);
|
||||
\fseek($res, 0);
|
||||
$fileId = $res;
|
||||
$read = function (int $length) use (&$fileId): string {
|
||||
$res = \stream_get_contents($fileId, $length);
|
||||
\assert($res !== false);
|
||||
return $res;
|
||||
};
|
||||
|
||||
if ($result->getType()->value <= FileIdType::PHOTO->value) {
|
||||
if (isset($resultArray['volume_id'])) {
|
||||
$result->setVolumeId($resultArray['volume_id']);
|
||||
$typeId = unpackInt($read(4));
|
||||
$dc_id = unpackInt($read(4));
|
||||
$fileReference = $typeId & FILE_REFERENCE_FLAG ? readTLString($fileId) : null;
|
||||
$hasWebLocation = (bool) ($typeId & WEB_LOCATION_FLAG);
|
||||
$typeId &= ~FILE_REFERENCE_FLAG;
|
||||
$typeId &= ~WEB_LOCATION_FLAG;
|
||||
|
||||
if ($hasWebLocation) {
|
||||
$url = readTLString($fileId);
|
||||
$access_hash = unpackLong($read(8));
|
||||
return new self(
|
||||
$dc_id,
|
||||
FileIdType::from($typeId),
|
||||
null,
|
||||
$access_hash,
|
||||
fileReference: $fileReference,
|
||||
url: $url,
|
||||
version: $version,
|
||||
subVersion: $subVersion
|
||||
);
|
||||
}
|
||||
$id = unpackLong($read(8));
|
||||
$access_hash = unpackLong($read(8));
|
||||
|
||||
$volume_id = null;
|
||||
$local_id = null;
|
||||
$photoSizeSource = null;
|
||||
if ($typeId <= FileIdType::PHOTO->value) {
|
||||
if ($subVersion < 32) {
|
||||
$volume_id = unpackLong($read(8));
|
||||
$local_id = unpackInt($read(4));
|
||||
}
|
||||
if (isset($resultArray['local_id'])) {
|
||||
$result->setLocalId($resultArray['local_id']);
|
||||
}
|
||||
switch ($resultArray['photosize_source']) {
|
||||
|
||||
/** @psalm-suppress MixedArgument */
|
||||
$photosize_source = PhotoSizeSourceType::from($subVersion >= 4 ? \unpack('V', $read(4))[1] : 0);
|
||||
switch ($photosize_source) {
|
||||
case PhotoSizeSourceType::LEGACY:
|
||||
$photoSizeSource = new PhotoSizeSourceLegacy(unpackLong($read(8)));
|
||||
break;
|
||||
case PhotoSizeSourceType::FULL_LEGACY:
|
||||
$photoSizeSource = new PhotoSizeSourceLegacy($resultArray['photosize_source']);
|
||||
$photoSizeSource->setSecret($resultArray['secret']);
|
||||
$volume_id = unpackLong($read(8));
|
||||
$photoSizeSource = new PhotoSizeSourceLegacy(unpackLong($read(8)));
|
||||
$local_id = unpackInt($read(4));
|
||||
break;
|
||||
case PhotoSizeSourceType::THUMBNAIL:
|
||||
$photoSizeSource = new PhotoSizeSourceThumbnail($resultArray['photosize_source']);
|
||||
$photoSizeSource->setThumbType($resultArray['thumbnail_type']);
|
||||
$photoSizeSource->setThumbFileType($resultArray['file_type']);
|
||||
/** @var array{file_type: int, thumbnail_type: string} */
|
||||
$result = \unpack('Vfile_type/athumbnail_type', $read(8));
|
||||
$photoSizeSource = new PhotoSizeSourceThumbnail(
|
||||
FileIdType::from($result['file_type']),
|
||||
$result['thumbnail_type']
|
||||
);
|
||||
break;
|
||||
case PhotoSizeSourceType::DIALOGPHOTO_BIG:
|
||||
case PhotoSizeSourceType::DIALOGPHOTO_SMALL:
|
||||
$clazz = $photosize_source === PhotoSizeSourceType::DIALOGPHOTO_SMALL
|
||||
? PhotoSizeSourceDialogPhotoSmall::class
|
||||
: PhotoSizeSourceDialogPhotoBig::class;
|
||||
$photoSizeSource = new $clazz(
|
||||
unpackLong($read(8)),
|
||||
unpackLong($read(8)),
|
||||
);
|
||||
break;
|
||||
case PhotoSizeSourceType::STICKERSET_THUMBNAIL:
|
||||
$photoSizeSource = new PhotoSizeSourceStickersetThumbnail(
|
||||
unpackLong($read(8)),
|
||||
unpackLong($read(8))
|
||||
);
|
||||
break;
|
||||
case PhotoSizeSourceType::DIALOGPHOTO_BIG_LEGACY:
|
||||
case PhotoSizeSourceType::DIALOGPHOTO_SMALL_LEGACY:
|
||||
case PhotoSizeSourceType::DIALOGPHOTO_BIG:
|
||||
case PhotoSizeSourceType::DIALOGPHOTO_SMALL:
|
||||
$photoSizeSource = new PhotoSizeSourceDialogPhoto($resultArray['photosize_source']);
|
||||
$photoSizeSource->setDialogId($resultArray['dialog_id']);
|
||||
$photoSizeSource->setDialogAccessHash($resultArray['dialog_access_hash']);
|
||||
$clazz = $photosize_source === PhotoSizeSourceType::DIALOGPHOTO_SMALL_LEGACY
|
||||
? PhotoSizeSourceDialogPhotoSmall::class
|
||||
: PhotoSizeSourceDialogPhotoBig::class;
|
||||
$photoSizeSource = new $clazz(
|
||||
unpackLong($read(8)),
|
||||
unpackLong($read(8))
|
||||
);
|
||||
|
||||
$volume_id = unpackLong($read(8));
|
||||
$local_id = unpackInt($read(4));
|
||||
break;
|
||||
case PhotoSizeSourceType::STICKERSET_THUMBNAIL:
|
||||
case PhotoSizeSourceType::STICKERSET_THUMBNAIL_LEGACY:
|
||||
$photoSizeSource = new PhotoSizeSourceStickersetThumbnail($resultArray['photosize_source']);
|
||||
$photoSizeSource->setStickerSetId($resultArray['sticker_set_id']);
|
||||
$photoSizeSource->setStickerSetAccessHash($resultArray['sticker_set_access_hash']);
|
||||
$photoSizeSource = new PhotoSizeSourceStickersetThumbnail(
|
||||
unpackLong($read(8)),
|
||||
unpackLong($read(8)),
|
||||
);
|
||||
|
||||
$volume_id = unpackLong($read(8));
|
||||
$local_id = unpackInt($read(4));
|
||||
break;
|
||||
case PhotoSizeSourceType::STICKERSET_THUMBNAIL_VERSION:
|
||||
$photoSizeSource = new PhotoSizeSourceStickersetThumbnailVersion($resultArray['photosize_source']);
|
||||
$photoSizeSource->setStickerSetId($resultArray['sticker_set_id']);
|
||||
$photoSizeSource->setStickerSetAccessHash($resultArray['sticker_set_access_hash']);
|
||||
$photoSizeSource->setStickerSetVersion($resultArray['sticker_version']);
|
||||
$photoSizeSource = new PhotoSizeSourceStickersetThumbnailVersion(
|
||||
unpackLong($read(8)),
|
||||
unpackLong($read(8)),
|
||||
unpackInt($read(4))
|
||||
);
|
||||
break;
|
||||
}
|
||||
$result->setPhotoSizeSource($photoSizeSource);
|
||||
}
|
||||
$l = \fstat($fileId)['size'] - \ftell($fileId);
|
||||
$l -= $version >= 4 ? 2 : 1;
|
||||
if ($l > 0) {
|
||||
\trigger_error("File ID $orig has $l bytes of leftover data");
|
||||
}
|
||||
|
||||
return $result;
|
||||
return new self(
|
||||
dcId: $dc_id,
|
||||
type: FileIdType::from($typeId),
|
||||
id: $id,
|
||||
accessHash: $access_hash,
|
||||
volumeId: $volume_id,
|
||||
localId: $local_id,
|
||||
fileReference: $fileReference,
|
||||
version: $version,
|
||||
subVersion: $subVersion,
|
||||
photoSizeSource: $photoSizeSource,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -176,76 +251,86 @@ final class FileId
|
||||
*/
|
||||
public function getBotAPI(): string
|
||||
{
|
||||
$type = $this->getType()->value;
|
||||
if ($this->hasFileReference()) {
|
||||
$type = $this->type->value;
|
||||
if ($this->fileReference !== null) {
|
||||
$type |= FILE_REFERENCE_FLAG;
|
||||
}
|
||||
if ($this->hasUrl()) {
|
||||
if ($this->url !== null) {
|
||||
$type |= WEB_LOCATION_FLAG;
|
||||
}
|
||||
|
||||
$fileId = \pack('VV', $type, $this->getDcId());
|
||||
if ($this->hasFileReference()) {
|
||||
$fileId .= packTLString($this->getFileReference());
|
||||
$fileId = \pack('VV', $type, $this->dcId);
|
||||
if ($this->fileReference !== null) {
|
||||
$fileId .= packTLString($this->fileReference);
|
||||
}
|
||||
if ($this->hasUrl()) {
|
||||
$fileId .= packTLString($this->getUrl());
|
||||
$fileId .= packLong($this->getAccessHash());
|
||||
if ($this->url !== null) {
|
||||
$fileId .= packTLString($this->url);
|
||||
$fileId .= packLong($this->accessHash);
|
||||
return base64urlEncode(rleEncode($fileId));
|
||||
}
|
||||
|
||||
$fileId .= packLong($this->getId());
|
||||
$fileId .= packLong($this->getAccessHash());
|
||||
\assert($this->id !== null);
|
||||
$fileId .= packLong($this->id);
|
||||
$fileId .= packLong($this->accessHash);
|
||||
|
||||
if ($this->getType()->value <= FileIdType::PHOTO->value) {
|
||||
$photoSize = $this->getPhotoSizeSource();
|
||||
$fileId .= \pack('V', $photoSize->getType());
|
||||
switch ($photoSize->getType()) {
|
||||
case PhotoSizeSourceType::LEGACY:
|
||||
assert($photoSize instanceof PhotoSizeSourceLegacy);
|
||||
$fileId .= packLong($photoSize->getSecret());
|
||||
if ($this->photoSizeSource !== null) {
|
||||
$photoSize = $this->photoSizeSource;
|
||||
$writeExtra = false;
|
||||
switch (true) {
|
||||
case $photoSize instanceof PhotoSizeSourceLegacy:
|
||||
if ($this->volumeId === null) {
|
||||
$writeExtra = true;
|
||||
$fileId .= \pack('V', PhotoSizeSourceType::LEGACY->value);
|
||||
$fileId .= packLong($photoSize->secret);
|
||||
} else {
|
||||
$fileId .= \pack('V', PhotoSizeSourceType::FULL_LEGACY->value);
|
||||
$fileId .= packLong($this->volumeId);
|
||||
$fileId .= packLong($photoSize->secret);
|
||||
$fileId .= \pack('l', $this->localId);
|
||||
}
|
||||
break;
|
||||
case PhotoSizeSourceType::FULL_LEGACY:
|
||||
assert($photoSize instanceof PhotoSizeSourceLegacy);
|
||||
$fileId .= packLong($this->getVolumeId());
|
||||
$fileId .= packLong($photoSize->getSecret());
|
||||
$fileId .= \pack('l', $this->getLocalId());
|
||||
case $photoSize instanceof PhotoSizeSourceThumbnail:
|
||||
$fileId .= \pack('V', PhotoSizeSourceType::THUMBNAIL->value);
|
||||
$fileId .= \pack('Va4', $photoSize->thumbFileType->value, $photoSize->thumbType);
|
||||
break;
|
||||
case PhotoSizeSourceType::THUMBNAIL:
|
||||
assert($photoSize instanceof PhotoSizeSourceThumbnail);
|
||||
$fileId .= \pack('Va4', $photoSize->getThumbFileType(), $photoSize->getThumbType());
|
||||
case $photoSize instanceof PhotoSizeSourceDialogPhoto:
|
||||
$fileId .= \pack(
|
||||
'V',
|
||||
($writeExtra = $this->volumeId !== null) ?
|
||||
(
|
||||
$photoSize->isSmallDialogPhoto()
|
||||
? PhotoSizeSourceType::DIALOGPHOTO_SMALL_LEGACY->value
|
||||
: PhotoSizeSourceType::DIALOGPHOTO_BIG_LEGACY->value
|
||||
) : (
|
||||
$photoSize->isSmallDialogPhoto()
|
||||
? PhotoSizeSourceType::DIALOGPHOTO_SMALL->value
|
||||
: PhotoSizeSourceType::DIALOGPHOTO_BIG->value
|
||||
)
|
||||
);
|
||||
$fileId .= packLong($photoSize->dialogId);
|
||||
$fileId .= packLong($photoSize->dialogAccessHash);
|
||||
break;
|
||||
case PhotoSizeSourceType::DIALOGPHOTO_BIG:
|
||||
case PhotoSizeSourceType::DIALOGPHOTO_SMALL:
|
||||
case PhotoSizeSourceType::DIALOGPHOTO_BIG_LEGACY:
|
||||
case PhotoSizeSourceType::DIALOGPHOTO_SMALL_LEGACY:
|
||||
assert($photoSize instanceof PhotoSizeSourceDialogPhoto);
|
||||
$fileId .= packLongBig($photoSize->getDialogId());
|
||||
$fileId .= packLong($photoSize->getDialogAccessHash());
|
||||
case $photoSize instanceof PhotoSizeSourceStickersetThumbnail:
|
||||
$writeExtra = $this->volumeId !== null;
|
||||
$fileId .= packLong($photoSize->stickerSetId);
|
||||
$fileId .= packLong($photoSize->stickerSetAccessHash);
|
||||
break;
|
||||
case PhotoSizeSourceType::STICKERSET_THUMBNAIL:
|
||||
case PhotoSizeSourceType::STICKERSET_THUMBNAIL_LEGACY:
|
||||
assert($photoSize instanceof PhotoSizeSourceStickersetThumbnail);
|
||||
$fileId .= packLong($photoSize->getStickerSetId());
|
||||
$fileId .= packLong($photoSize->getStickerSetAccessHash());
|
||||
break;
|
||||
case PhotoSizeSourceType::STICKERSET_THUMBNAIL_VERSION:
|
||||
assert($photoSize instanceof PhotoSizeSourceStickersetThumbnailVersion);
|
||||
$fileId .= packLong($photoSize->getStickerSetId());
|
||||
$fileId .= packLong($photoSize->getStickerSetAccessHash());
|
||||
$fileId .= \pack('l', $photoSize->getStickerSetVersion());
|
||||
case $photoSize instanceof PhotoSizeSourceStickersetThumbnailVersion:
|
||||
$fileId .= packLong($photoSize->stickerSetId);
|
||||
$fileId .= packLong($photoSize->stickerSetAccessHash);
|
||||
$fileId .= \pack('l', $photoSize->stickerSetVersion);
|
||||
break;
|
||||
}
|
||||
if ($photoSize->getType() >= PhotoSizeSourceType::DIALOGPHOTO_SMALL_LEGACY && $photoSize->getType()->value <= PhotoSizeSourceType::STICKERSET_THUMBNAIL_LEGACY->value) {
|
||||
$fileId .= packLong($this->getVolumeId());
|
||||
$fileId .= \pack('l', $this->getLocalId());
|
||||
if ($writeExtra && $this->volumeId !== null && $this->localId !== null) {
|
||||
$fileId .= packLong($this->volumeId);
|
||||
$fileId .= \pack('l', $this->localId);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->getVersion() >= 4) {
|
||||
$fileId .= \chr($this->getSubVersion());
|
||||
if ($this->version >= 4) {
|
||||
$fileId .= \chr($this->subVersion);
|
||||
}
|
||||
$fileId .= \chr($this->getVersion());
|
||||
$fileId .= \chr($this->version);
|
||||
|
||||
return base64urlEncode(rleEncode($fileId));
|
||||
}
|
||||
@ -274,306 +359,4 @@ final class FileId
|
||||
{
|
||||
return $this->getBotAPI();
|
||||
}
|
||||
/**
|
||||
* Get bot API file ID version.
|
||||
*
|
||||
*/
|
||||
public function getVersion(): int
|
||||
{
|
||||
return $this->version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set bot API file ID version.
|
||||
*
|
||||
* @param int $version Bot API file ID version.
|
||||
*
|
||||
*/
|
||||
public function setVersion(int $version): self
|
||||
{
|
||||
$this->version = $version;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bot API file ID subversion.
|
||||
*
|
||||
*/
|
||||
public function getSubVersion(): int
|
||||
{
|
||||
return $this->subVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set bot API file ID subversion.
|
||||
*
|
||||
* @param int $subVersion Bot API file ID subversion.
|
||||
*
|
||||
*/
|
||||
public function setSubVersion(int $subVersion): self
|
||||
{
|
||||
$this->subVersion = $subVersion;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file type.
|
||||
*
|
||||
*/
|
||||
public function getType(): FileIdType
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set file type.
|
||||
*
|
||||
* @param FileIdType $type File type.
|
||||
*
|
||||
*/
|
||||
public function setType(FileIdType $type): self
|
||||
{
|
||||
$this->type = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file reference.
|
||||
*
|
||||
*/
|
||||
public function getFileReference(): string
|
||||
{
|
||||
return $this->fileReference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set file reference.
|
||||
*
|
||||
* @param string $fileReference File reference.
|
||||
*
|
||||
*/
|
||||
public function setFileReference(string $fileReference): self
|
||||
{
|
||||
$this->fileReference = $fileReference;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if has file reference.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasFileReference(): bool
|
||||
{
|
||||
return !empty($this->fileReference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file URL for weblocation.
|
||||
*
|
||||
*/
|
||||
public function getUrl(): string
|
||||
{
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if has file URL.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasUrl(): bool
|
||||
{
|
||||
return !empty($this->url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set file URL for weblocation.
|
||||
*
|
||||
* @param string $url File URL for weblocation.
|
||||
*
|
||||
*/
|
||||
public function setUrl(string $url): self
|
||||
{
|
||||
$this->url = $url;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file id.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set file id.
|
||||
*
|
||||
* @param int $id File id.
|
||||
*
|
||||
*/
|
||||
public function setId(int $id): self
|
||||
{
|
||||
$this->id = $id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if has file id.
|
||||
*
|
||||
*/
|
||||
public function hasId(): bool
|
||||
{
|
||||
return isset($this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file access hash.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getAccessHash()
|
||||
{
|
||||
return $this->accessHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set file access hash.
|
||||
*
|
||||
* @param int $accessHash File access hash.
|
||||
*
|
||||
*/
|
||||
public function setAccessHash(int $accessHash): self
|
||||
{
|
||||
$this->accessHash = $accessHash;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get photo volume ID.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getVolumeId()
|
||||
{
|
||||
return $this->volumeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set photo volume ID.
|
||||
*
|
||||
* @param int $volumeId Photo volume ID.
|
||||
*
|
||||
*/
|
||||
public function setVolumeId(int $volumeId): self
|
||||
{
|
||||
$this->volumeId = $volumeId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Check if has volume ID.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasVolumeId(): bool
|
||||
{
|
||||
return isset($this->volumeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get photo local ID.
|
||||
*
|
||||
*/
|
||||
public function getLocalId(): int
|
||||
{
|
||||
return $this->localId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set photo local ID.
|
||||
*
|
||||
* @param int $localId Photo local ID.
|
||||
*
|
||||
*/
|
||||
public function setLocalId(int $localId): self
|
||||
{
|
||||
$this->localId = $localId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if has local ID.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasLocalId(): bool
|
||||
{
|
||||
return isset($this->localId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get photo size source.
|
||||
*
|
||||
*/
|
||||
public function getPhotoSizeSource(): PhotoSizeSource
|
||||
{
|
||||
return $this->photoSizeSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set photo size source.
|
||||
*
|
||||
* @param PhotoSizeSource $photoSizeSource Photo size source.
|
||||
*
|
||||
*/
|
||||
public function setPhotoSizeSource(PhotoSizeSource $photoSizeSource): self
|
||||
{
|
||||
$this->photoSizeSource = $photoSizeSource;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if has photo size source.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasPhotoSizeSource(): bool
|
||||
{
|
||||
return isset($this->photoSizeSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get dC ID.
|
||||
*
|
||||
*/
|
||||
public function getDcId(): int
|
||||
{
|
||||
return $this->dcId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set dC ID.
|
||||
*
|
||||
* @param int $dcId DC ID.
|
||||
*
|
||||
*/
|
||||
public function setDcId(int $dcId): self
|
||||
{
|
||||
$this->dcId = $dcId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
@ -18,50 +18,9 @@
|
||||
|
||||
namespace danog\Decoder;
|
||||
|
||||
use danog\Decoder\PhotoSizeSource\PhotoSizeSourceLegacy;
|
||||
|
||||
/**
|
||||
* Represents source of photosize.
|
||||
*
|
||||
* @template T
|
||||
*/
|
||||
abstract class PhotoSizeSource
|
||||
{
|
||||
/**
|
||||
* Source type.
|
||||
*
|
||||
*/
|
||||
private PhotoSizeSourceType $type;
|
||||
|
||||
/**
|
||||
* Set photosize source type.
|
||||
*
|
||||
* @param PhotoSizeSourceType $type Type
|
||||
*/
|
||||
public function __construct(PhotoSizeSourceType $type)
|
||||
{
|
||||
$this->type = $type;
|
||||
}
|
||||
/**
|
||||
* Get photosize source type.
|
||||
*
|
||||
* @return integer
|
||||
*
|
||||
* @psalm-return (
|
||||
* T is PhotoSizeSourceLegacy ?
|
||||
* ? \danog\Decoder\PhotoSizeSourceType::LEGACY
|
||||
* : (T is PhotoSizeSourceDialogPhoto
|
||||
* ? \danog\Decoder\PhotoSizeSourceType::DIALOGPHOTO_*
|
||||
* (T is PhotoSizeSourceStickersetThumbnail
|
||||
* ? \danog\Decoder\PhotoSizeSourceType::STICKERSET_THUMBNAIL
|
||||
* : \danog\Decoder\PhotoSizeSourceType::THUMBNAIL
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @internal Internal use
|
||||
*/
|
||||
public function getType(): PhotoSizeSourceType
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
}
|
||||
|
@ -19,77 +19,22 @@
|
||||
namespace danog\Decoder\PhotoSizeSource;
|
||||
|
||||
use danog\Decoder\PhotoSizeSource;
|
||||
use danog\Decoder\PhotoSizeSourceType;
|
||||
|
||||
/**
|
||||
* Represents source of photosize.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @extends PhotoSizeSource<PhotoSizeSourceDialogPhoto>
|
||||
*/
|
||||
final class PhotoSizeSourceDialogPhoto extends PhotoSizeSource
|
||||
abstract class PhotoSizeSourceDialogPhoto extends PhotoSizeSource
|
||||
{
|
||||
/**
|
||||
* ID of dialog.
|
||||
*
|
||||
*/
|
||||
private int $dialogId;
|
||||
/**
|
||||
* Access hash of dialog.
|
||||
*
|
||||
*/
|
||||
private int $dialogAccessHash;
|
||||
|
||||
/**
|
||||
* Get dialog ID.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getDialogId()
|
||||
{
|
||||
return $this->dialogId;
|
||||
public function __construct(
|
||||
public readonly int $dialogId,
|
||||
public readonly int $dialogAccessHash,
|
||||
) {
|
||||
}
|
||||
/**
|
||||
* Set dialog ID.
|
||||
*
|
||||
* @param int $id Dialog ID
|
||||
*
|
||||
*/
|
||||
public function setDialogId(int $id): self
|
||||
{
|
||||
$this->dialogId = $id;
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Get access hash of dialog.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getDialogAccessHash()
|
||||
{
|
||||
return $this->dialogAccessHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set access hash of dialog.
|
||||
*
|
||||
* @param int $dialogAccessHash Access hash of dialog
|
||||
*
|
||||
*/
|
||||
public function setDialogAccessHash(int $dialogAccessHash): self
|
||||
{
|
||||
$this->dialogAccessHash = $dialogAccessHash;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether the big or small version of the photo is being used.
|
||||
*
|
||||
*/
|
||||
public function isSmallDialogPhoto(): bool
|
||||
{
|
||||
return \in_array($this->getType(), [PhotoSizeSourceType::DIALOGPHOTO_SMALL_LEGACY, PhotoSizeSourceType::DIALOGPHOTO_SMALL], true);
|
||||
}
|
||||
abstract public function isSmallDialogPhoto(): bool;
|
||||
}
|
||||
|
36
src/PhotoSizeSource/PhotoSizeSourceDialogPhotoBig.php
Normal file
36
src/PhotoSizeSource/PhotoSizeSourceDialogPhotoBig.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* Photosize source class.
|
||||
*
|
||||
* This file is part of tg-file-decoder.
|
||||
* tg-file-decoder is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
* tg-file-decoder is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Affero General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License along with tg-file-decoder.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @author Daniil Gentili <daniil@daniil.it>
|
||||
* @copyright 2016-2019 Daniil Gentili <daniil@daniil.it>
|
||||
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
|
||||
*
|
||||
* @link https://github.com/tg-file-decoder Documentation
|
||||
*/
|
||||
|
||||
namespace danog\Decoder\PhotoSizeSource;
|
||||
|
||||
/**
|
||||
* Represents source of photosize.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
final class PhotoSizeSourceDialogPhotoBig extends PhotoSizeSourceDialogPhoto
|
||||
{
|
||||
/**
|
||||
* Get whether the big or small version of the photo is being used.
|
||||
*
|
||||
*/
|
||||
public function isSmallDialogPhoto(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
36
src/PhotoSizeSource/PhotoSizeSourceDialogPhotoSmall.php
Normal file
36
src/PhotoSizeSource/PhotoSizeSourceDialogPhotoSmall.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* Photosize source class.
|
||||
*
|
||||
* This file is part of tg-file-decoder.
|
||||
* tg-file-decoder is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
* tg-file-decoder is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Affero General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License along with tg-file-decoder.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @author Daniil Gentili <daniil@daniil.it>
|
||||
* @copyright 2016-2019 Daniil Gentili <daniil@daniil.it>
|
||||
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
|
||||
*
|
||||
* @link https://github.com/tg-file-decoder Documentation
|
||||
*/
|
||||
|
||||
namespace danog\Decoder\PhotoSizeSource;
|
||||
|
||||
/**
|
||||
* Represents source of photosize.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
final class PhotoSizeSourceDialogPhotoSmall extends PhotoSizeSourceDialogPhoto
|
||||
{
|
||||
/**
|
||||
* Get whether the big or small version of the photo is being used.
|
||||
*
|
||||
*/
|
||||
public function isSmallDialogPhoto(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
@ -24,37 +24,11 @@ use danog\Decoder\PhotoSizeSource;
|
||||
* Represents source of photosize.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @extends PhotoSizeSource<PhotoSizeSourceLegacy>
|
||||
*/
|
||||
final class PhotoSizeSourceLegacy extends PhotoSizeSource
|
||||
{
|
||||
/**
|
||||
* Secret legacy ID.
|
||||
*
|
||||
*/
|
||||
private int $secret;
|
||||
|
||||
/**
|
||||
* Get secret legacy ID.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getSecret()
|
||||
{
|
||||
return $this->secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set secret legacy ID.
|
||||
*
|
||||
* @param int $secret Secret legacy ID
|
||||
*
|
||||
*/
|
||||
public function setSecret(int $secret): self
|
||||
{
|
||||
$this->secret = $secret;
|
||||
|
||||
return $this;
|
||||
public function __construct(
|
||||
public readonly int $secret,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
@ -24,65 +24,21 @@ use danog\Decoder\PhotoSizeSource;
|
||||
* Represents source of photosize.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @extends PhotoSizeSource<PhotoSizeSourceStickersetThumbnail>
|
||||
*/
|
||||
final class PhotoSizeSourceStickersetThumbnail extends PhotoSizeSource
|
||||
{
|
||||
/**
|
||||
* Stickerset ID.
|
||||
*
|
||||
*/
|
||||
private int $stickerSetId;
|
||||
/**
|
||||
* Stickerset access hash.
|
||||
*
|
||||
*/
|
||||
private int $stickerSetAccessHash;
|
||||
public function __construct(
|
||||
/**
|
||||
* Stickerset ID.
|
||||
*
|
||||
*/
|
||||
public readonly int $stickerSetId,
|
||||
/**
|
||||
* Stickerset access hash.
|
||||
*
|
||||
*/
|
||||
public readonly int $stickerSetAccessHash
|
||||
) {
|
||||
|
||||
/**
|
||||
* Get stickerset ID.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getStickerSetId()
|
||||
{
|
||||
return $this->stickerSetId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set stickerset ID.
|
||||
*
|
||||
* @param int $stickerSetId Stickerset ID
|
||||
*
|
||||
*/
|
||||
public function setStickerSetId(int $stickerSetId): self
|
||||
{
|
||||
$this->stickerSetId = $stickerSetId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get stickerset access hash.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getStickerSetAccessHash()
|
||||
{
|
||||
return $this->stickerSetAccessHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set stickerset access hash.
|
||||
*
|
||||
* @param int $stickerSetAccessHash Stickerset access hash
|
||||
*
|
||||
*/
|
||||
public function setStickerSetAccessHash(int $stickerSetAccessHash): self
|
||||
{
|
||||
$this->stickerSetAccessHash = $stickerSetAccessHash;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
@ -24,92 +24,26 @@ use danog\Decoder\PhotoSizeSource;
|
||||
* Represents source of photosize.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @extends PhotoSizeSource<PhotoSizeSourceStickersetThumbnailVersion>
|
||||
*/
|
||||
final class PhotoSizeSourceStickersetThumbnailVersion extends PhotoSizeSource
|
||||
{
|
||||
/**
|
||||
* Stickerset ID.
|
||||
*
|
||||
*/
|
||||
private int $stickerSetId;
|
||||
/**
|
||||
* Stickerset access hash.
|
||||
*
|
||||
*/
|
||||
private int $stickerSetAccessHash;
|
||||
/**
|
||||
* Stickerset version.
|
||||
*
|
||||
*/
|
||||
private int $stickerSetVersion;
|
||||
public function __construct(
|
||||
/**
|
||||
* Stickerset ID.
|
||||
*
|
||||
*/
|
||||
public readonly int $stickerSetId,
|
||||
/**
|
||||
* Stickerset access hash.
|
||||
*
|
||||
*/
|
||||
public readonly int $stickerSetAccessHash,
|
||||
/**
|
||||
* Stickerset version.
|
||||
*
|
||||
*/
|
||||
public readonly int $stickerSetVersion
|
||||
) {
|
||||
|
||||
/**
|
||||
* Get stickerset ID.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getStickerSetId()
|
||||
{
|
||||
return $this->stickerSetId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set stickerset ID.
|
||||
*
|
||||
* @param int $stickerSetId Stickerset ID
|
||||
*
|
||||
*/
|
||||
public function setStickerSetId(int $stickerSetId): self
|
||||
{
|
||||
$this->stickerSetId = $stickerSetId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get stickerset access hash.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getStickerSetAccessHash()
|
||||
{
|
||||
return $this->stickerSetAccessHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set stickerset access hash.
|
||||
*
|
||||
* @param int $stickerSetAccessHash Stickerset access hash
|
||||
*
|
||||
*/
|
||||
public function setStickerSetAccessHash(int $stickerSetAccessHash): self
|
||||
{
|
||||
$this->stickerSetAccessHash = $stickerSetAccessHash;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get stickerset version.
|
||||
*
|
||||
*/
|
||||
public function getStickerSetVersion(): int
|
||||
{
|
||||
return $this->stickerSetVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set stickerset version.
|
||||
*
|
||||
* @param int $stickerSetVersion Stickerset version.
|
||||
*
|
||||
*/
|
||||
public function setStickerSetVersion(int $stickerSetVersion): self
|
||||
{
|
||||
$this->stickerSetVersion = $stickerSetVersion;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
@ -25,62 +25,20 @@ use danog\Decoder\PhotoSizeSource;
|
||||
* Represents source of photosize.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @extends PhotoSizeSource<PhotoSizeSourceThumbnail>
|
||||
*/
|
||||
final class PhotoSizeSourceThumbnail extends PhotoSizeSource
|
||||
{
|
||||
/**
|
||||
* File type of original file.
|
||||
*
|
||||
*/
|
||||
private FileIdType $thumbFileType;
|
||||
/**
|
||||
* Thumbnail size.
|
||||
*
|
||||
*/
|
||||
private string $thumbType;
|
||||
|
||||
/**
|
||||
* Get file type of original file.
|
||||
*
|
||||
*/
|
||||
public function getThumbFileType(): FileIdType
|
||||
{
|
||||
return $this->thumbFileType;
|
||||
}
|
||||
/**
|
||||
* Set file type of original file.
|
||||
*
|
||||
* @param FileIdType $thumbFileType File type of original file
|
||||
*
|
||||
*/
|
||||
public function setThumbFileType(FileIdType $thumbFileType): self
|
||||
{
|
||||
$this->thumbFileType = $thumbFileType;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get thumbnail size.
|
||||
*
|
||||
*/
|
||||
public function getThumbType(): string
|
||||
{
|
||||
return $this->thumbType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set thumbnail size.
|
||||
*
|
||||
* @param string $thumbType Thumbnail size
|
||||
*
|
||||
*/
|
||||
public function setThumbType(string $thumbType): self
|
||||
{
|
||||
$this->thumbType = $thumbType;
|
||||
|
||||
return $this;
|
||||
public function __construct(
|
||||
/**
|
||||
* File type of original file.
|
||||
*
|
||||
*/
|
||||
public readonly FileIdType $thumbFileType,
|
||||
/**
|
||||
* Thumbnail size.
|
||||
*
|
||||
*/
|
||||
public readonly string $thumbType,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,9 @@
|
||||
|
||||
namespace danog\Decoder;
|
||||
|
||||
/**
|
||||
* @internal Not for public use
|
||||
*/
|
||||
enum PhotoSizeSourceType: int
|
||||
{
|
||||
case LEGACY = 0;
|
||||
|
@ -29,51 +29,51 @@ use danog\Decoder\PhotoSizeSource\PhotoSizeSourceThumbnail;
|
||||
*/
|
||||
final class UniqueFileId
|
||||
{
|
||||
/**
|
||||
* File type.
|
||||
*
|
||||
*/
|
||||
private UniqueFileIdType $type;
|
||||
/**
|
||||
* File ID.
|
||||
*
|
||||
*/
|
||||
private int $id;
|
||||
/**
|
||||
* Photo volume ID.
|
||||
*
|
||||
*/
|
||||
private int $volumeId;
|
||||
/**
|
||||
* Photo local ID.
|
||||
*
|
||||
*/
|
||||
private int $localId;
|
||||
/**
|
||||
* Photo subtype.
|
||||
*
|
||||
*/
|
||||
private int $subType;
|
||||
/**
|
||||
* Sticker set ID.
|
||||
*
|
||||
*/
|
||||
private int $stickerSetId;
|
||||
/**
|
||||
* Sticker set version.
|
||||
*
|
||||
*/
|
||||
private int $stickerSetVersion;
|
||||
/**
|
||||
* Weblocation URL.
|
||||
*
|
||||
*/
|
||||
private string $url;
|
||||
/**
|
||||
* Basic constructor function.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
public function __construct(
|
||||
/**
|
||||
* File type.
|
||||
*
|
||||
*/
|
||||
public readonly UniqueFileIdType $type,
|
||||
/**
|
||||
* File ID.
|
||||
*
|
||||
*/
|
||||
public readonly ?int $id = null,
|
||||
/**
|
||||
* Photo subtype.
|
||||
*
|
||||
*/
|
||||
public readonly ?int $subType = null,
|
||||
/**
|
||||
* Photo volume ID.
|
||||
*
|
||||
*/
|
||||
public readonly ?int $volumeId = null,
|
||||
/**
|
||||
* Photo local ID.
|
||||
*
|
||||
*/
|
||||
public readonly ?int $localId = null,
|
||||
/**
|
||||
* Sticker set ID.
|
||||
*
|
||||
*/
|
||||
public readonly ?int $stickerSetId = null,
|
||||
/**
|
||||
* Sticker set version.
|
||||
*
|
||||
*/
|
||||
public readonly ?int $stickerSetVersion = null,
|
||||
/**
|
||||
* Weblocation URL.
|
||||
*
|
||||
*/
|
||||
public readonly ?string $url= null,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
@ -91,23 +91,25 @@ final class UniqueFileId
|
||||
*/
|
||||
public function getUniqueBotAPI(): string
|
||||
{
|
||||
$fileId = \pack('V', $this->getType());
|
||||
if ($this->getType() === UniqueFileIdType::WEB) {
|
||||
$fileId .= packTLString($this->getUrl());
|
||||
} elseif ($this->getType() === UniqueFileIdType::PHOTO) {
|
||||
if ($this->hasVolumeId()) {
|
||||
$fileId .= packLong($this->getVolumeId());
|
||||
$fileId .= \pack('l', $this->getLocalId());
|
||||
} elseif ($this->hasStickerSetId()) {
|
||||
$fileId .= \chr($this->getSubType());
|
||||
$fileId .= packLong($this->getStickerSetId());
|
||||
$fileId .= \pack('l', $this->getStickerSetVersion());
|
||||
$fileId = \pack('V', $this->type->value);
|
||||
if ($this->url !== null) {
|
||||
$fileId .= packTLString($this->url);
|
||||
} elseif ($this->type === UniqueFileIdType::PHOTO) {
|
||||
if ($this->volumeId !== null) {
|
||||
$fileId .= packLong($this->volumeId);
|
||||
$fileId .= \pack('l', $this->localId);
|
||||
} elseif ($this->stickerSetId !== null) {
|
||||
\assert($this->subType !== null);
|
||||
$fileId .= \chr($this->subType);
|
||||
$fileId .= packLong($this->stickerSetId);
|
||||
$fileId .= \pack('l', $this->stickerSetVersion);
|
||||
} else {
|
||||
$fileId .= packLong($this->getId());
|
||||
$fileId .= \chr($this->getSubType());
|
||||
\assert($this->subType !== null && $this->id !== null);
|
||||
$fileId .= packLong($this->id);
|
||||
$fileId .= \chr($this->subType);
|
||||
}
|
||||
} elseif ($this->hasId()) {
|
||||
$fileId .= packLong($this->getId());
|
||||
} elseif ($this->id !== null) {
|
||||
$fileId .= packLong($this->id);
|
||||
}
|
||||
|
||||
return base64urlEncode(rleEncode($fileId));
|
||||
@ -121,28 +123,61 @@ final class UniqueFileId
|
||||
*/
|
||||
public static function fromUniqueBotAPI(string $fileId): self
|
||||
{
|
||||
$result = new self();
|
||||
$resultArray = internalDecodeUnique($fileId);
|
||||
$result->setType($resultArray['typeId']);
|
||||
if ($result->getType() === UniqueFileIdType::WEB) {
|
||||
$result->setUrl($resultArray['url']);
|
||||
} elseif ($result->getType() === UniqueFileIdType::PHOTO) {
|
||||
if (isset($resultArray['volume_id'])) {
|
||||
$result->setVolumeId($resultArray['volume_id']);
|
||||
$result->setLocalId($resultArray['local_id']);
|
||||
} elseif (isset($resultArray['id'])) {
|
||||
$result->setId($resultArray['id']);
|
||||
$result->setSubType($resultArray['subType']);
|
||||
} elseif (isset($resultArray['sticker_set_id'])) {
|
||||
$result->setStickerSetId($resultArray['sticker_set_id']);
|
||||
$result->setStickerSetVersion($resultArray['sticker_set_version']);
|
||||
$result->setSubType($resultArray['subType']);
|
||||
}
|
||||
} elseif (isset($resultArray['id'])) {
|
||||
$result->setId($resultArray['id']);
|
||||
}
|
||||
$orig = $fileId;
|
||||
$fileId = rleDecode(base64urlDecode($fileId));
|
||||
|
||||
return $result;
|
||||
/** @var int */
|
||||
$typeId = \unpack('V', $fileId)[1];
|
||||
$type = UniqueFileIdType::from($typeId);
|
||||
$url = null;
|
||||
|
||||
$subType = null;
|
||||
$id = null;
|
||||
$fileId = \substr($fileId, 4);
|
||||
$volume_id = null;
|
||||
$local_id = null;
|
||||
$sticker_set_id = null;
|
||||
$sticker_set_version = null;
|
||||
if ($type === UniqueFileIdType::WEB) {
|
||||
$res = \fopen('php://memory', 'rw+b');
|
||||
\assert($res !== false);
|
||||
\fwrite($res, $fileId);
|
||||
\fseek($res, 0);
|
||||
$fileId = $res;
|
||||
$url = readTLString($fileId);
|
||||
|
||||
$l = \fstat($fileId)['size'] - \ftell($fileId);
|
||||
\trigger_error("Unique file ID $orig has $l bytes of leftover data");
|
||||
} elseif (\strlen($fileId) === 12) {
|
||||
// Legacy photos
|
||||
$volume_id = unpackLong(\substr($fileId, 0, 8));
|
||||
$local_id = unpackInt(\substr($fileId, 8));
|
||||
} elseif (\strlen($fileId) === 9) {
|
||||
// Dialog photos/thumbnails
|
||||
$id = unpackLong($fileId);
|
||||
$subType = \ord($fileId[8]);
|
||||
} elseif (\strlen($fileId) === 13) {
|
||||
// Stickerset ID/version
|
||||
$subType = \ord($fileId[0]);
|
||||
$sticker_set_id = unpackLong(\substr($fileId, 1, 8));
|
||||
$sticker_set_version = unpackInt(\substr($fileId, 9));
|
||||
} elseif (\strlen($fileId) === 8) {
|
||||
// Any other document
|
||||
$id = unpackLong($fileId);
|
||||
} else {
|
||||
$l = \strlen($fileId);
|
||||
\trigger_error("Unique file ID $orig has $l bytes of leftover data");
|
||||
}
|
||||
return new self(
|
||||
type: $type,
|
||||
id: $id,
|
||||
subType: $subType,
|
||||
volumeId: $volume_id,
|
||||
localId: $local_id,
|
||||
stickerSetId: $sticker_set_id,
|
||||
stickerSetVersion: $sticker_set_version,
|
||||
url: $url
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -164,287 +199,45 @@ final class UniqueFileId
|
||||
*/
|
||||
public static function fromFileId(FileId $fileId): self
|
||||
{
|
||||
$result = new self();
|
||||
$result->setType($fileId->getType()->toUnique());
|
||||
if ($result->hasUrl()) {
|
||||
$result->setType(UniqueFileIdType::WEB);
|
||||
if ($fileId->url !== null) {
|
||||
return new self(
|
||||
UniqueFileIdType::WEB,
|
||||
url: $fileId->url
|
||||
);
|
||||
}
|
||||
if ($result->getType() === UniqueFileIdType::WEB) {
|
||||
$result->setUrl($fileId->getUrl());
|
||||
} elseif ($result->getType() === UniqueFileIdType::PHOTO) {
|
||||
if ($fileId->hasVolumeId()) {
|
||||
$result->setVolumeId($fileId->getVolumeId());
|
||||
$result->setLocalId($fileId->getLocalId());
|
||||
} elseif ($fileId->hasId()) {
|
||||
$result->setId($fileId->getId());
|
||||
$photoSize = $fileId->getPhotoSizeSource();
|
||||
if ($photoSize instanceof PhotoSizeSourceThumbnail) {
|
||||
$type = $photoSize->getThumbType();
|
||||
if ($type === 'a') {
|
||||
$type = \chr(0);
|
||||
} elseif ($type === 'c') {
|
||||
$type = \chr(1);
|
||||
} else {
|
||||
$type = \chr(\ord($type)+5);
|
||||
}
|
||||
$result->setSubType(\ord($type));
|
||||
} elseif ($photoSize instanceof PhotoSizeSourceDialogPhoto) {
|
||||
$result->setSubType($photoSize->isSmallDialogPhoto() ? 0 : 1);
|
||||
} elseif ($photoSize instanceof PhotoSizeSourceStickersetThumbnailVersion) {
|
||||
$result->setSubType(2);
|
||||
$result->setStickerSetId($photoSize->getStickerSetId());
|
||||
$result->setStickerSetVersion($photoSize->getStickerSetVersion());
|
||||
$type = $fileId->type->toUnique();
|
||||
if ($type === UniqueFileIdType::PHOTO) {
|
||||
$photoSize = $fileId->photoSizeSource;
|
||||
$subType = null;
|
||||
if ($photoSize instanceof PhotoSizeSourceThumbnail) {
|
||||
$subType = \ord($photoSize->thumbType);
|
||||
if ($subType === 97) {
|
||||
$subType = 0;
|
||||
} elseif ($subType === 99) {
|
||||
$subType = 1;
|
||||
} else {
|
||||
$subType = $subType+5;
|
||||
}
|
||||
$subType = $subType;
|
||||
} elseif ($photoSize instanceof PhotoSizeSourceDialogPhoto) {
|
||||
$subType = $photoSize->isSmallDialogPhoto() ? 0 : 1;
|
||||
} elseif ($photoSize instanceof PhotoSizeSourceStickersetThumbnailVersion) {
|
||||
return new self(
|
||||
$type,
|
||||
$fileId->id,
|
||||
2,
|
||||
stickerSetId: $photoSize->stickerSetId,
|
||||
stickerSetVersion: $photoSize->stickerSetVersion,
|
||||
);
|
||||
}
|
||||
} elseif ($fileId->hasId()) {
|
||||
$result->setId($fileId->getId());
|
||||
return new self(
|
||||
$type,
|
||||
$fileId->id,
|
||||
$subType,
|
||||
$fileId->volumeId,
|
||||
$fileId->localId,
|
||||
);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get unique file type.
|
||||
*
|
||||
*/
|
||||
public function getType(): UniqueFileIdType
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set file type.
|
||||
*
|
||||
* @param UniqueFileIdType $type File type.
|
||||
*
|
||||
*/
|
||||
public function setType(UniqueFileIdType $type): self
|
||||
{
|
||||
$this->type = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file ID.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set file ID.
|
||||
*
|
||||
* @param int $id File ID.
|
||||
*
|
||||
*/
|
||||
public function setId(int $id): self
|
||||
{
|
||||
$this->id = $id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if has ID.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasId(): bool
|
||||
{
|
||||
return isset($this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get photo volume ID.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getVolumeId()
|
||||
{
|
||||
return $this->volumeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set photo volume ID.
|
||||
*
|
||||
* @param int $volumeId Photo volume ID.
|
||||
*
|
||||
*/
|
||||
public function setVolumeId(int $volumeId): self
|
||||
{
|
||||
$this->volumeId = $volumeId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Check if has volume ID.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasVolumeId(): bool
|
||||
{
|
||||
return isset($this->volumeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get photo local ID.
|
||||
*
|
||||
*/
|
||||
public function getLocalId(): int
|
||||
{
|
||||
return $this->localId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set photo local ID.
|
||||
*
|
||||
* @param int $localId Photo local ID.
|
||||
*
|
||||
*/
|
||||
public function setLocalId(int $localId): self
|
||||
{
|
||||
$this->localId = $localId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if has local ID.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasLocalId(): bool
|
||||
{
|
||||
return isset($this->localId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get weblocation URL.
|
||||
*
|
||||
*/
|
||||
public function getUrl(): string
|
||||
{
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set weblocation URL.
|
||||
*
|
||||
* @param string $url Weblocation URL
|
||||
*
|
||||
*/
|
||||
public function setUrl(string $url): self
|
||||
{
|
||||
$this->url = $url;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if has weblocation URL.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasUrl(): bool
|
||||
{
|
||||
return isset($this->url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get photo subtype.
|
||||
*
|
||||
*/
|
||||
public function getSubType(): int
|
||||
{
|
||||
return $this->subType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Has photo subtype?
|
||||
*
|
||||
*/
|
||||
public function hasSubType(): bool
|
||||
{
|
||||
return isset($this->subType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set photo subtype.
|
||||
*
|
||||
* @param int $subType Photo subtype
|
||||
*
|
||||
*/
|
||||
public function setSubType(int $subType): self
|
||||
{
|
||||
$this->subType = $subType;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get sticker set ID.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getStickerSetId()
|
||||
{
|
||||
return $this->stickerSetId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Has sticker set ID?
|
||||
*
|
||||
*/
|
||||
public function hasStickerSetId(): bool
|
||||
{
|
||||
return isset($this->stickerSetId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set sticker set ID.
|
||||
*
|
||||
* @param int $stickerSetId Sticker set ID
|
||||
*
|
||||
*/
|
||||
public function setStickerSetId(int $stickerSetId): self
|
||||
{
|
||||
$this->stickerSetId = $stickerSetId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get sticker set version.
|
||||
*
|
||||
*/
|
||||
public function getStickerSetVersion(): int
|
||||
{
|
||||
return $this->stickerSetVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Has sticker set version.
|
||||
*
|
||||
*/
|
||||
public function hasStickerSetVersion(): bool
|
||||
{
|
||||
return isset($this->stickerSetVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set sticker set version.
|
||||
*
|
||||
* @param int $stickerSetVersion Sticker set version
|
||||
*
|
||||
*/
|
||||
public function setStickerSetVersion(int $stickerSetVersion): self
|
||||
{
|
||||
$this->stickerSetVersion = $stickerSetVersion;
|
||||
|
||||
return $this;
|
||||
return new self($type, $fileId->id);
|
||||
}
|
||||
}
|
||||
|
@ -4,92 +4,45 @@ namespace danog\Decoder;
|
||||
|
||||
const WEB_LOCATION_FLAG = 1 << 24;
|
||||
const FILE_REFERENCE_FLAG = 1 << 25;
|
||||
const LONG = PHP_INT_SIZE === 8 ? 'Q' : 'l2';
|
||||
|
||||
/** @psalm-suppress UnusedVariable */
|
||||
$BIG_ENDIAN = \pack('L', 1) === \pack('N', 1);
|
||||
|
||||
/**
|
||||
* Unpack long properly, returns an actual number in any case.
|
||||
*
|
||||
* @param string $field Field to unpack
|
||||
* @internal
|
||||
*
|
||||
* @return string|int
|
||||
* @param string $field Field to unpack
|
||||
*/
|
||||
function unpackLong(string $field)
|
||||
function unpackLong(string $field): int
|
||||
{
|
||||
if (PHP_INT_SIZE === 8) {
|
||||
/** @psalm-suppress InvalidGlobal */
|
||||
global $BIG_ENDIAN; // Evil
|
||||
return \unpack('q', $BIG_ENDIAN ? \strrev($field) : $field)[1];
|
||||
}
|
||||
if (\class_exists(\tgseclib\Math\BigInteger::class)) {
|
||||
return (string) new \tgseclib\Math\BigInteger(\strrev($field), -256);
|
||||
}
|
||||
if (\class_exists(\phpseclib\Math\BigInteger::class)) {
|
||||
return (string) new \phpseclib\Math\BigInteger(\strrev($field), -256);
|
||||
}
|
||||
throw new \Error('Please install phpseclib to unpack bot API file IDs');
|
||||
global $BIG_ENDIAN; // Evil
|
||||
/** @psalm-suppress MixedReturnStatement */
|
||||
return \unpack('q', $BIG_ENDIAN ? \strrev($field) : $field)[1];
|
||||
}
|
||||
/**
|
||||
* Unpack integer.
|
||||
* @internal
|
||||
*
|
||||
* @param string $field Field to unpack
|
||||
*/
|
||||
function unpackInt(string $field): int
|
||||
{
|
||||
/** @psalm-suppress MixedReturnStatement */
|
||||
return \unpack('l', $field)[1];
|
||||
}
|
||||
/**
|
||||
* Pack string long.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
*/
|
||||
function packLongBig(string|int $field): string
|
||||
function packLong(int $field): string
|
||||
{
|
||||
if (PHP_INT_SIZE === 8) {
|
||||
/** @psalm-suppress InvalidGlobal */
|
||||
global $BIG_ENDIAN; // Evil
|
||||
$res = \pack('q', $field);
|
||||
return $BIG_ENDIAN ? \strrev($res) : $res;
|
||||
}
|
||||
|
||||
if (\class_exists(\tgseclib\Math\BigInteger::class)) {
|
||||
return (new \tgseclib\Math\BigInteger($field))->toBytes();
|
||||
}
|
||||
if (\class_exists(\phpseclib\Math\BigInteger::class)) {
|
||||
return (new \phpseclib\Math\BigInteger($field))->toBytes();
|
||||
}
|
||||
throw new \Error('Please install phpseclib to unpack bot API file IDs');
|
||||
global $BIG_ENDIAN; // Evil
|
||||
$res = \pack('q', $field);
|
||||
return $BIG_ENDIAN ? \strrev($res) : $res;
|
||||
}
|
||||
/**
|
||||
* Fix long parameters in case of 32 bit systems.
|
||||
*
|
||||
* @param array $params Parameters
|
||||
* @param string $field 64-bit field
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function fixLong(array &$params, string $field)
|
||||
{
|
||||
if (PHP_INT_SIZE === 8) {
|
||||
return;
|
||||
}
|
||||
$params[$field] = [
|
||||
$params[$field.'1'],
|
||||
$params[$field.'2'],
|
||||
];
|
||||
unset($params[$field.'1'], $params[$field.'2']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode long to string.
|
||||
*
|
||||
* @param string|int|int[] $fields Fields to encode
|
||||
*
|
||||
*/
|
||||
function packLong(string|int|array $fields): string
|
||||
{
|
||||
if (\is_string($fields)) { // Already encoded, we hope
|
||||
return $fields;
|
||||
}
|
||||
if (PHP_INT_SIZE === 8) {
|
||||
return \pack(LONG, $fields);
|
||||
}
|
||||
return \pack(LONG, ...$fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Base64URL decode.
|
||||
*
|
||||
@ -195,7 +148,7 @@ function posmod(int $a, int $b): int
|
||||
/**
|
||||
* Read TL string.
|
||||
*
|
||||
* @param mixed $stream Byte stream
|
||||
* @param resource $stream Byte stream
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
@ -207,6 +160,7 @@ function readTLString(mixed $stream): string
|
||||
throw new \InvalidArgumentException("Length too big!");
|
||||
}
|
||||
if ($l === 254) {
|
||||
/** @var int */
|
||||
$long_len = \unpack('V', \stream_get_contents($stream, 3).\chr(0))[1];
|
||||
$x = \stream_get_contents($stream, $long_len);
|
||||
$resto = posmod(-$long_len, 4);
|
||||
@ -229,6 +183,7 @@ function readTLString(mixed $stream): string
|
||||
*
|
||||
* @param string $string String
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
function packTLString(string $string): string
|
||||
{
|
||||
@ -246,186 +201,3 @@ function packTLString(string $string): string
|
||||
}
|
||||
return $concat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal decode function.
|
||||
*
|
||||
* I know that you will use this directly giuseppe
|
||||
*
|
||||
* @param string $fileId Bot API file ID
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
*/
|
||||
function internalDecode(string $fileId): array
|
||||
{
|
||||
$orig = $fileId;
|
||||
$fileId = rleDecode(base64urlDecode($fileId));
|
||||
$result = [];
|
||||
$result['version'] = \ord($fileId[\strlen($fileId) - 1]);
|
||||
$result['subVersion'] = $result['version'] === 4 ? \ord($fileId[\strlen($fileId) - 2]) : 0;
|
||||
|
||||
$result += \unpack('VtypeId/Vdc_id', $fileId);
|
||||
$result['hasReference'] = (bool) ($result['typeId'] & FILE_REFERENCE_FLAG);
|
||||
$result['hasWebLocation'] = (bool) ($result['typeId'] & WEB_LOCATION_FLAG);
|
||||
$result['typeId'] &= ~FILE_REFERENCE_FLAG;
|
||||
$result['typeId'] &= ~WEB_LOCATION_FLAG;
|
||||
$result['type'] = FileIdType::from($result['typeId']);
|
||||
$res = \fopen('php://memory', 'rw+b');
|
||||
\fwrite($res, \substr($fileId, 8));
|
||||
\fseek($res, 0);
|
||||
$fileId = $res;
|
||||
|
||||
if ($result['hasReference']) {
|
||||
$result['fileReference'] = readTLString($fileId);
|
||||
}
|
||||
if ($result['hasWebLocation']) {
|
||||
$result['url'] = readTLString($fileId);
|
||||
$result['access_hash'] = \unpack(LONG.'access_hash', \stream_get_contents($fileId, 8));
|
||||
fixLong($result, 'access_hash');
|
||||
return $result;
|
||||
}
|
||||
|
||||
$result += \unpack(LONG.'id/'.LONG.'access_hash', \stream_get_contents($fileId, 16));
|
||||
fixLong($result, 'id');
|
||||
fixLong($result, 'access_hash');
|
||||
|
||||
if ($result['typeId'] <= FileIdType::PHOTO->value) {
|
||||
$parsePhotoSize = function () use (&$result, &$fileId) {
|
||||
$result['photosize_source'] = $result['subVersion'] >= 4 ? \unpack('V', \stream_get_contents($fileId, 4))[1] : 0;
|
||||
switch ($result['photosize_source']) {
|
||||
case PhotoSizeSourceType::LEGACY:
|
||||
$result += \unpack(LONG.'secret', \stream_get_contents($fileId, 8));
|
||||
fixLong($result, 'secret');
|
||||
break;
|
||||
case PhotoSizeSourceType::THUMBNAIL:
|
||||
$result += \unpack('Vfile_type/athumbnail_type', \stream_get_contents($fileId, 8));
|
||||
break;
|
||||
case PhotoSizeSourceType::DIALOGPHOTO_BIG:
|
||||
case PhotoSizeSourceType::DIALOGPHOTO_SMALL:
|
||||
$result['photo_size'] = $result['photosize_source'] === PhotoSizeSourceType::DIALOGPHOTO_SMALL ? 'photo_small' : 'photo_big';
|
||||
$result['dialog_id'] = unpackLong(\stream_get_contents($fileId, 8));
|
||||
$result['dialog_access_hash'] = \unpack(LONG, \stream_get_contents($fileId, 8))[1];
|
||||
fixLong($result, 'dialog_access_hash');
|
||||
break;
|
||||
case PhotoSizeSourceType::STICKERSET_THUMBNAIL:
|
||||
$result += \unpack(LONG.'sticker_set_id/'.LONG.'sticker_set_access_hash', \stream_get_contents($fileId, 16));
|
||||
fixLong($result, 'sticker_set_id');
|
||||
fixLong($result, 'sticker_set_access_hash');
|
||||
break;
|
||||
|
||||
case PhotoSizeSourceType::FULL_LEGACY:
|
||||
$result += \unpack(LONG.'volume_id/'.LONG.'secret/llocal_id', \stream_get_contents($fileId, 20));
|
||||
fixLong($result, 'volume_id');
|
||||
fixLong($result, 'secret');
|
||||
break;
|
||||
case PhotoSizeSourceType::DIALOGPHOTO_BIG_LEGACY:
|
||||
case PhotoSizeSourceType::DIALOGPHOTO_SMALL_LEGACY:
|
||||
$result['photo_size'] = $result['photosize_source'] === PhotoSizeSourceType::DIALOGPHOTO_SMALL_LEGACY ? 'photo_small' : 'photo_big';
|
||||
$result['dialog_id'] = unpackLong(\stream_get_contents($fileId, 8));
|
||||
$result['dialog_access_hash'] = \unpack(LONG, \stream_get_contents($fileId, 8))[1];
|
||||
fixLong($result, 'dialog_access_hash');
|
||||
|
||||
$result += \unpack(LONG.'volume_id/llocal_id', \stream_get_contents($fileId, 12));
|
||||
fixLong($result, 'volume_id');
|
||||
break;
|
||||
case PhotoSizeSourceType::STICKERSET_THUMBNAIL_LEGACY:
|
||||
$result += \unpack(LONG.'sticker_set_id/'.LONG.'sticker_set_access_hash', \stream_get_contents($fileId, 16));
|
||||
fixLong($result, 'sticker_set_id');
|
||||
fixLong($result, 'sticker_set_access_hash');
|
||||
|
||||
$result += \unpack(LONG.'volume_id/llocal_id', \stream_get_contents($fileId, 12));
|
||||
fixLong($result, 'volume_id');
|
||||
break;
|
||||
|
||||
case PhotoSizeSourceType::STICKERSET_THUMBNAIL_VERSION:
|
||||
$result += \unpack(LONG.'sticker_set_id/'.LONG.'sticker_set_access_hash/lsticker_version', \stream_get_contents($fileId, 20));
|
||||
fixLong($result, 'sticker_set_id');
|
||||
fixLong($result, 'sticker_set_access_hash');
|
||||
break;
|
||||
}
|
||||
};
|
||||
if ($result['subVersion'] >= 32) {
|
||||
$parsePhotoSize();
|
||||
} else {
|
||||
$result += \unpack(LONG.'volume_id', \stream_get_contents($fileId, 8));
|
||||
fixLong($result, 'volume_id');
|
||||
|
||||
if ($result['subVersion'] >= 22) {
|
||||
$parsePhotoSize();
|
||||
$result += \unpack('llocal_id', \stream_get_contents($fileId, 4));
|
||||
} else {
|
||||
$result += \unpack(LONG.'secret/llocal_id', \stream_get_contents($fileId, 12));
|
||||
fixLong($result, 'volume_id');
|
||||
fixLong($result, 'secret');
|
||||
}
|
||||
}
|
||||
}
|
||||
$l = \fstat($fileId)['size'] - \ftell($fileId);
|
||||
$l -= $result['version'] >= 4 ? 2 : 1;
|
||||
if ($l > 0) {
|
||||
\trigger_error("File ID $orig has $l bytes of leftover data");
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
/**
|
||||
* Internal decode function.
|
||||
*
|
||||
* I know that you will use this directly giuseppe
|
||||
*
|
||||
* @param string $fileId Bot API file ID
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
*/
|
||||
function internalDecodeUnique(string $fileId): array
|
||||
{
|
||||
$orig = $fileId;
|
||||
$fileId = rleDecode(base64urlDecode($fileId));
|
||||
|
||||
$result = \unpack('VtypeId', $fileId);
|
||||
$result['type'] = UniqueFileIdType::from($result['typeId']);
|
||||
|
||||
$fileId = \substr($fileId, 4);
|
||||
if ($result['typeId'] === UniqueFileIdType::WEB) {
|
||||
$res = \fopen('php://memory', 'rw+b');
|
||||
\fwrite($res, $fileId);
|
||||
\fseek($res, 0);
|
||||
$fileId = $res;
|
||||
$result['url'] = readTLString($fileId);
|
||||
|
||||
$l = \fstat($fileId)['size'] - \ftell($fileId);
|
||||
} elseif (\strlen($fileId) === 12) {
|
||||
// Legacy photos
|
||||
$result += \unpack(LONG.'volume_id/llocal_id', $fileId);
|
||||
fixLong($result, 'volume_id');
|
||||
|
||||
$l = 0;
|
||||
} elseif (\strlen($fileId) === 9) {
|
||||
// Dialog photos/thumbnails
|
||||
$result += \unpack(LONG.'id/CsubType', $fileId);
|
||||
fixLong($result, 'id');
|
||||
|
||||
$l = 0;
|
||||
} elseif (\strlen($fileId) === 13) {
|
||||
// Stickerset ID/version
|
||||
$result += \unpack('CsubType/'.LONG.'sticker_set_id/lsticker_set_version', $fileId);
|
||||
fixLong($result, 'sticker_set_id');
|
||||
|
||||
$l = 0;
|
||||
} elseif (\strlen($fileId) === 8) {
|
||||
// Any other document
|
||||
$result += \unpack(LONG.'id', $fileId);
|
||||
fixLong($result, 'id');
|
||||
|
||||
$l = 0;
|
||||
} else {
|
||||
$l = \strlen($fileId);
|
||||
}
|
||||
if ($l > 0) {
|
||||
\trigger_error("Unique file ID $orig has $l bytes of leftover data");
|
||||
}
|
||||
|
||||
\assert($result !== false);
|
||||
return $result;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user