Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Telegram Bot API Client for PHP

[![Bot Api 10.1](https://img.shields.io/badge/Bot%20API-10.1-0088cc.svg?style=flat)](https://core.telegram.org/bots/api-changelog#june-11-2026)
[![Bot Api 10.3](https://img.shields.io/badge/Bot%20API-10.3-0088cc.svg?style=flat)](https://core.telegram.org/bots/api-changelog#august-24-2026)
![PHP >=8.2](https://img.shields.io/badge/PHP->=8.2-777bb3.svg?style=flat)
![Tests Status](https://img.shields.io/github/actions/workflow/status/luzrain/telegram-bot-api/tests.yaml?branch=master&label=Tests)
![Downloads](https://img.shields.io/packagist/dt/luzrain/telegram-bot-api?label=Downloads&color=f28d1a)
Expand Down
54 changes: 22 additions & 32 deletions src/BotApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,8 @@
use Luzrain\TelegramBotApi\Exception\TelegramApiServerException;
use Luzrain\TelegramBotApi\Internal\HttpClient\RequestBuilder;
use Luzrain\TelegramBotApi\Method\GetFile;
use Luzrain\TelegramBotApi\Method\SendMediaGroup;
use Luzrain\TelegramBotApi\Method\SendPaidMedia;
use Luzrain\TelegramBotApi\Type\File;
use Luzrain\TelegramBotApi\Type\InputFile;
use Luzrain\TelegramBotApi\Type\InputMedia;
use Luzrain\TelegramBotApi\Type\InputPaidMedia;
use Luzrain\TelegramBotApi\Type\ResponseParameters;
use Psr\Http\Client\ClientExceptionInterface;
use Psr\Http\Client\ClientInterface;
Expand Down Expand Up @@ -58,42 +54,36 @@ public function call(Method $method): mixed
$multiparts = [];
$files = [];

/** @psalm-suppress UndefinedPropertyFetch */
$extractFiles = static function (InputMedia|InputPaidMedia $inputMedia): array {
$files = [];
if (\property_exists($inputMedia, 'media') && $inputMedia->media instanceof InputFile) {
$files[] = $inputMedia->media;
}
if (\property_exists($inputMedia, 'thumbnail') && $inputMedia->thumbnail instanceof InputFile) {
$files[] = $inputMedia->thumbnail;
}
if (\property_exists($inputMedia, 'photo') && $inputMedia->photo instanceof InputFile) {
$files[] = $inputMedia->photo;
}
if (\property_exists($inputMedia, 'cover') && $inputMedia->cover instanceof InputFile) {
$files[] = $inputMedia->cover;
/**
* Collects every InputFile reachable from a method parameter graph.
*
* Keyed by unique name so that one InputFile instance referenced from two places
* is streamed once. Note that get_object_vars() runs in BotApi scope and therefore
* sees public properties only — every Type property is public by convention.
*
* @param array<string, InputFile> $files
*/
$collectFiles = static function (mixed $value, array &$files) use (&$collectFiles): void {
if ($value instanceof InputFile) {
$files[$value->getUniqueName()] = $value;
} elseif (\is_array($value)) {
foreach ($value as $item) {
$collectFiles($item, $files);
}
} elseif ($value instanceof Type) {
foreach (\get_object_vars($value) as $property) {
$collectFiles($property, $files);
}
}
return $files;
};

foreach ($method->getIterator() as $name => $value) {
if ($value instanceof InputFile) {
$multiparts[$name] = $value->getAttachPath();
$files[] = $value;
$files[$value->getUniqueName()] = $value;
} else {
$multiparts[$name] = \is_scalar($value) ? $value : \json_encode($value, JSON_UNESCAPED_UNICODE);
}

if ($value instanceof InputMedia || $value instanceof InputPaidMedia) {
$files = [...$files, ...$extractFiles($value)];
}

/** @psalm-suppress TypeDoesNotContainType */
if ($name === 'media' && \is_array($value) && ($method instanceof SendMediaGroup || $method instanceof SendPaidMedia)) {
/** @var array<InputMedia|InputPaidMedia> $value */
foreach ($value as $media) {
$files = [...$files, ...$extractFiles($media)];
}
$collectFiles($value, $files);
}
}

Expand Down
21 changes: 21 additions & 0 deletions src/Event/BotSubscriptionUpdated.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace Luzrain\TelegramBotApi\Event;

use Luzrain\TelegramBotApi\Event;
use Luzrain\TelegramBotApi\Type;

final class BotSubscriptionUpdated extends Event
{
public function executeChecker(Type\Update $update): bool
{
return $update->subscription !== null;
}

public function executeCallback(Type\Update $update): mixed
{
return $this->callback($update->subscription);
}
}
21 changes: 21 additions & 0 deletions src/Event/MessageGenerationStopped.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace Luzrain\TelegramBotApi\Event;

use Luzrain\TelegramBotApi\Event;
use Luzrain\TelegramBotApi\Type;

final class MessageGenerationStopped extends Event
{
public function executeChecker(Type\Update $update): bool
{
return $update->stoppedMessageGeneration !== null;
}

public function executeCallback(Type\Update $update): mixed
{
return $this->callback($update->stoppedMessageGeneration);
}
}
36 changes: 36 additions & 0 deletions src/Method/DeleteEphemeralMessage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace Luzrain\TelegramBotApi\Method;

use Luzrain\TelegramBotApi\Method;

/**
* Use this method to delete an ephemeral message. Note that it is not guaranteed that the user will receive
* the message deletion event, especially if they are offline. Returns True on success.
*
* @extends Method<true>
*/
final class DeleteEphemeralMessage extends Method
{
protected static string $methodName = 'deleteEphemeralMessage';

public function __construct(
/**
* Unique identifier for the target chat or username of the target supergroup in the format @username
*/
protected int|string $chatId,

/**
* Identifier of the user who received the message
*/
protected int $receiverUserId,

/**
* Identifier of the ephemeral message to delete
*/
protected int $ephemeralMessageId,
) {
}
}
67 changes: 67 additions & 0 deletions src/Method/EditEphemeralMessageCaption.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

declare(strict_types=1);

namespace Luzrain\TelegramBotApi\Method;

use Luzrain\TelegramBotApi\Method;
use Luzrain\TelegramBotApi\Type\InlineKeyboardMarkup;
use Luzrain\TelegramBotApi\Type\MessageEntity;

/**
* Use this method to edit the caption of an ephemeral message. Note that it is not guaranteed that the user will receive
* the message edit event, especially if they are offline. On success, True is returned.
*
* @extends Method<true>
*/
final class EditEphemeralMessageCaption extends Method
{
protected static string $methodName = 'editEphemeralMessageCaption';

public function __construct(
/**
* Unique identifier for the target chat or username of the target supergroup in the format @username
*/
protected int|string $chatId,

/**
* Identifier of the user who received the message
*/
protected int $receiverUserId,

/**
* Identifier of the ephemeral message to edit
*/
protected int $ephemeralMessageId,

/**
* New caption of the message, 0-1024 characters after entities parsing
*/
protected string|null $caption = null,

/**
* Mode for parsing entities in the message caption. See formatting options for more details.
*
* @see https://core.telegram.org/bots/api#formatting-options
*/
protected string|null $parseMode = null,

/**
* A JSON-serialized list of special entities that appear in the caption, which can be specified instead of parse_mode
*
* @var list<MessageEntity>|null
*/
protected array|null $captionEntities = null,

/**
* Pass True if the caption must be shown above the message media. Supported only for animation, photo and video messages.
*/
protected bool|null $showCaptionAboveMedia = null,

/**
* A JSON-serialized object for an inline keyboard
*/
protected InlineKeyboardMarkup|null $replyMarkup = null,
) {
}
}
48 changes: 48 additions & 0 deletions src/Method/EditEphemeralMessageMedia.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

declare(strict_types=1);

namespace Luzrain\TelegramBotApi\Method;

use Luzrain\TelegramBotApi\Method;
use Luzrain\TelegramBotApi\Type\InlineKeyboardMarkup;
use Luzrain\TelegramBotApi\Type\InputMedia;

/**
* Use this method to edit the media of an ephemeral message. Note that it is not guaranteed that the user will receive
* the message edit event, especially if they are offline. On success, True is returned.
*
* @extends Method<true>
*/
final class EditEphemeralMessageMedia extends Method
{
protected static string $methodName = 'editEphemeralMessageMedia';

public function __construct(
/**
* Unique identifier for the target chat or username of the target supergroup in the format @username
*/
protected int|string $chatId,

/**
* Identifier of the user who received the message
*/
protected int $receiverUserId,

/**
* Identifier of the ephemeral message to edit
*/
protected int $ephemeralMessageId,

/**
* A JSON-serialized object for the new media content of the message
*/
protected InputMedia $media,

/**
* A JSON-serialized object for an inline keyboard
*/
protected InlineKeyboardMarkup|null $replyMarkup = null,
) {
}
}
42 changes: 42 additions & 0 deletions src/Method/EditEphemeralMessageReplyMarkup.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

declare(strict_types=1);

namespace Luzrain\TelegramBotApi\Method;

use Luzrain\TelegramBotApi\Method;
use Luzrain\TelegramBotApi\Type\InlineKeyboardMarkup;

/**
* Use this method to edit only the reply markup of an ephemeral message. Note that it is not guaranteed that the user
* will receive the message edit event, especially if they are offline. On success, True is returned.
*
* @extends Method<true>
*/
final class EditEphemeralMessageReplyMarkup extends Method
{
protected static string $methodName = 'editEphemeralMessageReplyMarkup';

public function __construct(
/**
* Unique identifier for the target chat or username of the target supergroup in the format @username
*/
protected int|string $chatId,

/**
* Identifier of the user who received the message
*/
protected int $receiverUserId,

/**
* Identifier of the ephemeral message to edit
*/
protected int $ephemeralMessageId,

/**
* A JSON-serialized object for an inline keyboard
*/
protected InlineKeyboardMarkup|null $replyMarkup = null,
) {
}
}
Loading
Loading