Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
99 KB
Referenced Files
None
Subscribers
None
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ecc1ff7..bb98e51 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,741 +1,753 @@
# Changelog
The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).
Exclamation symbols (:exclamation:) note something of importance e.g. breaking changes. Click them to learn more.
## [Unreleased]
### Notes
-- [:ledger: View file changes][Unreleased] ∙ [:page_with_curl: DB migration script][unreleased-sql-migration]
-- [:exclamation:][unreleased-bc-minimum-php-81] PHP 8.1+ required!
+- [:ledger: View file changes][Unreleased]
+### Added
+### Changed
+### Deprecated
+### Removed
+### Fixed
+### Security
+
+## [0.83.0] - 2024-05-25
+### Notes
+- [:ledger: View file changes][0.83.0] ∙ [:page_with_curl: DB migration script][0.83.0-sql-migration]
+- [:exclamation:][0.83.0-bc-minimum-php-81] PHP 8.1+ required!
+- Last version with database support built in to the core.
### Added
- Bot API 7.0 (@noplanman, @TiiFuchs) (#1459)
-- Bot API 7.1 (@noplanman)
+- Bot API 7.1 (@noplanman) (#1465)
### Changed
-- [:exclamation:][unreleased-bc-user-to-users] Various fields have been pluralised from "user" to "users".
+- [:exclamation:][0.83.0-bc-user-to-users] Various fields have been pluralised from "user" to "users".
### Deprecated
### Removed
### Fixed
### Security
## [0.82.0] - 2023-10-26
### Notes
- [:ledger: View file changes][0.82.0] ∙ [:page_with_curl: DB migration script][0.82.0-sql-migration]
- Really the last version that supports PHP 7! Only PHP 8 after this one.
### Added
- Bot API 6.8, 6.9 (@noplanman) (#1418, #1427)
- Test against PHP 8.3 (@sergiy-petrov) (#1421)
### Fixed
- Missing `thumbnail_url` renaming.
- Fix broken exception handling (@mlocati) (#1425)
## [0.81.0] - 2023-05-27
### Notes
- [:ledger: View file changes][0.81.0] ∙ [:page_with_curl: DB migration script][0.81.0-sql-migration]
- Last version that supports PHP 7.
### Added
- Support dynamic Entity properties for newer PHP versions (@alesinicio, @TiiFuchs) (#1390)
- Bot API 6.4, 6.5, 6.6, 6.7 (@noplanman) (#1389)
### Removed
- Keyboard validations (@noplanman) (#1395)
### Fixed
- Fixed a bug where new incoming updates are not correctly passed to the Command object after the first time when getUpdates is used. (@uspilot) (#1384)
## [0.80.0] - 2022-11-09
### Notes
- [:ledger: View file changes][0.80.0] ∙ [:page_with_curl: DB migration script][0.80.0-sql-migration]
### Added
- Bot API 6.3 (@TiiFuchs) (#1371)
### Changed
- [:exclamation:][0.80.0-bc-commands-with-underscores] Commands can now contain underscores (`FooBarCommand` is handled by `/foo_bar`). (@mlocati) (#1365)
## [0.79.0] - 2022-09-04
### Notes
- [:ledger: View file changes][0.79.0]
### Added
- Bot API 6.2 (@OxMohsen) (#1350)
### Removed
- `VoiceChatX` entities, use `VideoChatX` entities instead.
- `all_members_are_administrators` property from `Message` entity. Database column still exists, but may be removed in the future.
- `Request::getChatMembersCount()`, use `Request::getChatMemberCount()` instead.
- `Request::kickChatMember()`, use `Request::banChatMember()` instead.
## [0.78.0] - 2022-07-03
### Notes
- [:ledger: View file changes][0.78.0] ∙ [:page_with_curl: DB migration script][0.78.0-sql-migration]
- 64 bit PHP install required to handle files larger than 2GB!
### Added
- Bot API 6.1 (@jyxjjj, @OxMohsen, @noplanman) (#1333, #1338, #1339)
- New Update field helpers for Command class.
## [0.77.1] - 2022-04-24
### Notes
- [:ledger: View file changes][0.77.1]
### Fixed
- PHP8+ `mixed` type hint removed
## [0.77.0] - 2022-04-24
### Notes
- [:ledger: View file changes][0.77.0] ∙ [:page_with_curl: DB migration script][0.77.0-sql-migration]
### Added
- Bot API 6.0 (@TiiFuchs) (#1318)
### Deprecated
- Telegram changed `voice_chat_X` to `video_chat_X`. `VoiceChatX` event classes are deprecated, use new `VideoChatX` event classes instead.
### Fixed
- Return correct data in `Entity::jsonSerialize` (@TiiFuchs)
## [0.76.1] - 2022-03-30
### Notes
- [:ledger: View file changes][0.76.1]
### Fixed
- Fix Entity serialising for Keyboards (@TiiFuchs) (#1304)
## [0.76.0] - 2022-03-20
### Notes
- [:ledger: View file changes][0.76.0]
### Added
- Bot API 5.6 (@TiiFuchs) (#1275)
- Bot API 5.7 (@TiiFuchs) (#1284)
- PSR3 (psr/log) version 2 and 3 compatible (@noplanman) (#1287)
- Entity implements and uses JsonSerializable now (@TiiFuchs)
- Test with PHP 8.1 on Travis CI (@osavchenko) (#1291)
### Changed
- Bugfix: Fixed condition in \Longman\TelegramBot\Entities\Chat::isGroupChat() that previously also counted super groups and channels. (@TiiFuchs)
## [0.75.0] - 2021-12-29
### Notes
- [:ledger: View file changes][0.75.0] ∙ [:page_with_curl: DB migration script][0.75.0-sql-migration]
### Added
- Ability to directly set commands paths. (@wright-tw, @noplanman) (#1252)
- Bot API 5.4. (@TiiFuchs, @noplanman) (#1266)
- Bot API 5.5. (@TiiFuchs, @noplanman) (#1267)
- The field `message_auto_delete_time` was added to the Chat Entity (@TiiFuchs) (#1265)
### Removed
- [:exclamation:][0.75.0-bc-removed-chatactions] Removed deprecated `ChatAction::` `RECORD_AUDIO` and `UPLOAD_AUDIO`. Use `RECORD_VOICE` and `UPLOAD_VOICE` instead. (@TiiFuchs) (#1267)
### Fixed
- PHP 8.1 deprecations. (@maxgorovenko) (#1260)
## [0.74.0] - 2021-06-26
### Notes
- [:ledger: View file changes][0.74.0]
### Added
- [:exclamation:][0.74.0-bc-chatmember-subentities] Bot API 5.3 (Personalized Commands, Keyboard Placeholders). (@TiiFuchs, @noplanman) (#1229, #1231)
## [0.73.1] - 2021-06-20
### Notes
- [:ledger: View file changes][0.73.1]
### Fixed
- Allow new optional parameters when setting and deleting webhook. (@TiiFuchs) (#1226)
## [0.73.0] - 2021-06-14
### Notes
- [:ledger: View file changes][0.73.0] ∙ [:page_with_curl: DB migration script][0.73.0-sql-migration]
### Added
- Bot API 5.2 (Payments 2.0). (#1216)
- Possibility to connect to MySQL DB with unix socket. (@Tynik) (#1220)
### Changed
- `Telegram::runCommands` returns array of `ServerResponse` objects of executed commands. (#1223)
### Fixed
- Regex for namespace extraction from custom command classes.
- Nested and user-triggered `Telegram::runCommands`. (#1223)
## [0.72.0] - 2021-04-16
### Notes
- [:ledger: View file changes][0.72.0] ∙ [:page_with_curl: DB migration script][0.72.0-sql-migration]
### Added
- Bot API 5.1 (ChatMember Update types, Improved Invite Links, Voice Chat). (@massadm, @noplanman) (#1199)
- Method to allow adding command classes directly. (@alligator77, @noplanman) (#1207, #1209)
### Deprecated
- `Telegram::handleGetUpdates` method should be passed a `$data` array for parameters. (#1202)
### Fixed
- `message.edit_date` is now of type `timestamp`. (#1191)
- Allow all update types by default when using `getUpdates` method. (#1202)
## [0.71.0] - 2021-03-05
### Notes
- [:ledger: View file changes][0.71.0]
### Added
- Define a custom Bot API server and file download URI. (#1168)
### Changed
- Improved error messages for empty input. (#1164)
- Log update when processing it, not when fetching input. (#1164)
### Fixed
- `getUpdates` method wrongly sends only 1 Update when a limit of 0 is passed. (#1169)
- `Telegram::runCommands()` now passes the correct message text to the commands. (#1181)
- Request limiter accepts chat ID as integer and string. (#1182)
- Calling Keyboard constructor without any parameters. (@hutattedonmyarm) (#1184)
## [0.70.1] - 2020-12-25
### Notes
- [:ledger: View file changes][0.70.1]
### Added
- Extra parameter for `Request::sendMessage()` to pass options and return all response objects for split messages. (#1163)
### Fixed
- Ensure download and upload path variables are defined. (#1162)
## [0.70.0] - 2020-12-21
### Notes
- [:ledger: View file changes][0.70.0] ∙ [:page_with_curl: DB migration script][0.70.0-sql-migration]
- [:exclamation:][0.70.0-bc-minimum-php-73] PHP 7.3+ required, so make sure your code is up to date with correct types!
### Added
- Bot API 5.0 (Big update!). (#1147)
### Changed
- Upgrade code to PHP 7.3. (#1136, #1158)
- Speed up `/clean` query. (@dva-re) (#1139)
- Various code prettifications. (@akalongman) (#1140, #1141, #1142, #1143)
### Security
- Minimum PHP 7.3, allow PHP 8.0. (#1136, #1158)
## [0.64.0] - 2020-10-04
### Notes
- [:ledger: View file changes][0.64.0]
### Added
- Support for Guzzle 7. (@KristobalJunta) (#1133)
### Fixed
- Correct SQL migration script for older versions of MySQL. (#1135)
## [0.63.1] - 2020-06-24
### Notes
- [:ledger: View file changes][0.63.1]
- This fixed version is necessary for Windows users.
### Fixed
- Regex in `getFileNamespace()` that introduced a breaking bug in #1114. (@jacklul) (#1115)
- Fixed `runCommands()` not working due to custom namespace feature. (@jacklul) (#1115, #1118)
## [0.63.0] - 2020-06-17
### Notes
- [:ledger: View file changes][0.63.0] ∙ [:page_with_curl: DB migration script][0.63.0-sql-migration]
### Added
- New method `setUpdateFilter($callback)` used to filter `processUpdate(Update $update)` calls. If `$callback` returns `false` the update isn't processed and an empty falsey `ServerResponse` is returned. (@VRciF) (#1045)
- Replaced 'generic' and 'genericmessage' strings with Telegram::GENERIC_COMMAND and Telegram::GENERIC_MESSAGE_COMMAND constants. (@1int) (#1074)
- Bot API 4.8 (Extra Poll and Dice features). (#1082)
- Allow custom MySQL port to be defined for tests. (#1090)
- New static method `Entity::escapeMarkdownV2` for MarkdownV2. (#1094)
- Remove bot token from debug http logs, this can be disabled by setting `TelegramLog::$remove_bot_token` parameter to `false`. (@jacklul) (#1095)
- `TelegramLog::$always_log_request_and_response` parameter to force output of the request and response data to the debug log, also for successful requests. (#1089)
- Bot API 4.9 (New `via_bot` field). (#1112)
### Changed
- [:exclamation:][0.63.0-bc-static-method-entityescapemarkdown] Made `Entity::escapeMarkdown` static, to not require an `Entity` object. (#1094)
- Allow custom namespacing for commands. (@Jonybang) (#689)
### Fixed
- Primary key for `poll_answer` also requires the `user_id`. (#1087)
- Small SQL foreign key fixes. (#1105)
## [0.62.0] - 2020-04-08
### Notes
- [:ledger: View file changes][0.62.0] ∙ [:page_with_curl: DB migration script][0.62.0-sql-migration]
### Added
- Bot API 4.5 (Unique file IDs, MarkdownV2). (#1046)
- Chain the exception thrown when getting commands from path. (#1030)
- Support `language_code` in `DB::selectChats()` for filtering the chats selection. (#1058)
- Bot API 4.6 (Polls 2.0). (#1066)
- Bot API 4.7 (Dice, Sticker Sets, Bot Commands). (#1067)
### Changed
- Save notes an unescaped JSON, to allow easy DB reading and editing of values. (#1005)
- `Request::setClient()` now accepts more flexible `ClientInterface`. (#1068)
### Removed
- Unnecessary `instanceof` checks for entities. (#1068)
- Unused `Request::$input` variable. (#1068)
### Fixed
- Execution of `/start` command without any custom implementation.
- Return `animation` type for GIF Message (which returns both `animation` and `document`). (#1044)
- Change lowercase function to `mb_strtolower` from `strtolower` because of `latin-extented` characters. (#1051)
- Extend `Request::mediaInputHelper()` to include `thumb` parameter. (#1059)
- Various docblock annotations. (#1068)
## [0.61.1] - 2019-11-23
### Notes
- [:ledger: View file changes][0.61.1]
### Added
- Tests for schema update scripts, to ensure that updates work as expected. (#1025)
### Fixed
- Parameter `inline_query_id` in `InlineQuery::answerInlineQuery`. (#1021)
- Corrected DB schema update 0.60.0-0.61.0. (#1025)
## [0.61.0] - 2019-11-02
### Notes
- [:ledger: View file changes][0.61.0] ∙ [:page_with_curl: DB migration script][0.61.0-sql-migration]
- :exclamation: Built-in logging (Monolog) has been removed, a custom PSR-3 logger must be used now! (see #964 for more info)
### Added
- Code snippet in `GenericmessageCommand` to keep obsolete service message system commands working. (#999)
- Static boolean property `SystemCommand::$execute_deprecated` (must be assigned before handling the request) to try and execute any deprecated system command. (#999)
- Improved MySQL DB index for `message` table, making the cleanup much faster on bigger databases. (Thanks to @damianperez) (#1015)
- `/cleanup` command now supports dry run which simply outputs all queries that would be run. (#1015)
### Changed
- Small readme and code fixes / simplifications. (#1001)
- Upgrade PHPUnit to 8.x and PHPCS to 3.5. For tests now minimum PHP version is 7.2. (#1008)
- Updated updates log importer (requires PHP7+). (#1009)
### Removed
- Service message system commands, which are now handled by `GenericmessageCommand`. (#999)
- [:exclamation:][0.61.0-bc-remove-monolog-from-core] Monolog has been removed as built-in logging engine. (#1009)
- Assets have been moved to a dedicated repository. (#1012)
### Fixed
- Boolean value for Polls gets saved correctly in MySQL DB. (#996)
- Correctly use `Request::answerInlineQuery` in `InlineQuery::answer`. (#1001)
- PSR-12 incompatibilities in the codebase. (#1008)
- Improved and corrected `/cleanup` command. (#1015)
## [0.60.0] - 2019-08-16
### Notes
- [:ledger: View file changes][0.60.0]
### Added
- Bot API 4.4 (Animated stickers, `ChatPermissions`). (#990)
### Changed
- Allow passing native entity objects to requests. (#991)
### Fixed
- Non-existing commands now correctly execute `GenericCommand` again. (#993)
## [0.59.1] - 2019-07-18
### Notes
- [:ledger: View file changes][0.59.1]
- :exclamation: Deprecated logging method will be removed in the next version, update to PSR-3 now! (see #964 for more info)
### Added
- Issue labels set automatically via templates.
### Changed
- Logging only updates or only debug/errors is now possible. (#983)
### Fixed
- Don't output deprecation notices if no logging is enabled. (#983)
- Respect custom HTTP Client initialisation, no matter when it is set. (#986)
## [0.59.0] - 2019-07-07
### Notes
- [:ledger: View file changes][0.59.0]
### Changed
- Touched up readme including header and badges. (#981)
- Updated changelog to be more useful for external integrations like [Tidelift] and GitHub releases. (#981)
### Removed
- Abstract methods from `InputMedia` interface, as method annotations didn't work for propagation. (#978)
## [0.58.0] - 2019-06-26
### Notes
- [:ledger: View file changes][0.58.0] ∙ [:page_with_curl: DB migration script][0.58.0-sql-migration]
- Logging now uses [PSR-3] `LoggerInterface`. Learn more about how to use it here: #964
### Added
- New funding and support details. (#971)
- Custom issue templates. (#972)
- Bot API 4.3 (Seamless Telegram Login, `LoginUrl`) (#957)
- `reply_markup` field to `Message` entity. (#957)
### Changed
- Use PSR-12 for code style. (#966)
- Some general housekeeping. (#972)
- [:exclamation:][0.58.0-bc-return-value-of-empty-entity-properties] Return an empty array for Entity properties with no items, instead of `null`. (#969)
- `TelegramLog` now adheres to [PSR-3] `LoggerInterface` and allows custom logger implementations. (#964)
### Deprecated
- Old logging that uses Monolog still works but will be removed in the near future. Use `TelegramLog::initialize($logger, $update_logger);` from now on. (#964)
- [:exclamation:][0.58.0-bc-startcommand-is-now-a-usercommand] `StartCommand` is now a `UserCommand` (not `SystemCommand` any more). (#970)
### Removed
- Botan.io integration completely removed. (#968)
### Fixed
- `forward_date` is now correctly saved to the DB. (#967)
- Broken `StickerSet::getStickers()` method. (#969)
- Smaller code and docblock fixes. (#973)
### Security
- Security disclosure managed by [Tidelift]. (#971)
- Don't allow a user to call system commands directly. (#970)
## [0.57.0] - 2019-06-01
### Notes
- [:ledger: View file changes][0.57.0] ∙ [:page_with_curl: DB migration script][0.57.0-sql-migration]
- :grey_exclamation: This is a big update and involves a bunch of MySQL database updates, so please *review the changelog carefully*.
### Added
- New logo! :tada: (#954)
- Bot API 4.2 (Polls). (#948)
- `getIsMember()` method to `ChatMember` entity. (#948)
- `getForwardSenderName()` method to `Message` entity. (#948)
- `forward_sender_name` (and forgotten `forward_signature`) DB fields. (#948)
- Added missing API fields to Entities and DB. (#885)
- Created database tables for `shipping_query` and `pre_checkout_query`. (#885)
### Fixed
- Missing DB table name specifier in `/cleanup` command. (#947)
## [0.56.0] - 2019-04-15
### Notes
- [:ledger: View file changes][0.56.0] ∙ [:page_with_curl: DB migration script][0.56.0-sql-migration]
- :grey_exclamation: This is a big update, so please *review the changelog carefully*!
### Added
- Helper for sending `InputMedia` objects using `Request::sendMediaGroup()` and `Request::editMediaMessage()` methods.
- Allow passing absolute file path for InputFile fields, instead of `Request::encodeFile($path)`. (#934)
### Changed
- All Message field types dynamically search for an existing Command class that can handle them. (#940)
- Upgrade dependencies. (#945)
### Deprecated
- Botan.io service has been discontinued. (#925)
- Most built-in System Commands will be handled by GenericmessageCommand by default in a future release and will require a custom implementation. (#940)
### Fixed
- Constraint errors in `/cleanup` command. (#930)
- Return correct objects for requests. (#934)
- PHPCS: static before visibility declaration. (#945)
## [0.55.1] - 2019-01-06
### Notes
- [:ledger: View file changes][0.55.1]
### Added
- Add missing `Request::editMessageMedia()` and `CallbackQuery::getChatInstance()` methods. (#916)
### Fixed
- Return correct message type. (#913)
## [0.55.0] - 2018-12-20
### Notes
- [:ledger: View file changes][0.55.0] ∙ [:page_with_curl: DB migration script][0.55.0-sql-migration]
### Added
- Bot API 4.0 and 4.1 (Telegram Passport) (#870, #871)
- Test PHP 7.3 with Travis. (#903)
### Changed
- [:exclamation:][0.55.0-bc-move-animation-out-of-games-namespace] Move Animation entity out of Games namespace.
### Fixed
- Added missing `video_note` to `Message` types.
## [0.54.1] - 2018-10-23
### Notes
- [:ledger: View file changes][0.54.1]
### Fixed
- `sendToActiveChats` now works correctly for any valid Request action. (#898)
## [0.54.0] - 2018-07-21
### Notes
- [:ledger: View file changes][0.54.0] ∙ [:page_with_curl: DB migration script][0.54.0-sql-migration]
### Added
- `ChatAction` class to simplify chat action selection. (#859)
- Telegram Games platform! (#732)
- Ability to set custom MySQL port. (#860)
- New `InvalidBotTokenException` exception. (#855)
### Changed
- [:exclamation:][0.54.0-bc-rename-constants] Rename and ensure no redefinition of constants: `BASE_PATH` -> `TB_BASE_PATH`, `BASE_COMMANDS_PATH` -> `TB_BASE_COMMANDS_PATH`. (#813)
- Improve readability of readme code snippets. (#861)
### Fixed
- Response from `getStickerSet`. (#838)
## [0.53.0] - 2018-04-01
### Notes
- [:ledger: View file changes][0.53.0] ∙ [:page_with_curl: DB migration script][0.53.0-sql-migration]
### Added
- Implemented new changes for Bot API 3.6 (streamable InputMediaVideo, connected website). (#799)
- `Telegram::getLastUpdateId()` method, returns ID of the last update that was processed. (#767)
- `Telegram::useGetUpdatesWithoutDatabase()` method, enables `Telegram::handleGetUpdates()` to run without a database. (#767)
### Changed
- Updated Travis to use Trusty containers (for HHVM) and add PHP 7.2 to the tests. (#739)
- Add debug log entry instead of throwing an exception for duplicate updates. (#765)
- `Telegram::handleGetUpdates()` can now work without a database connection (not enabled by default). (#767)
- Improved `/sendtochannel` and `/sendtoall` commands, using new message helpers. (#810)
### Fixed
- PHPCS fixes for updated CodeSniffer dependency. (#739)
- Send messages correctly via `/sendtochannel`. (#803)
## [0.52.0] - 2018-01-07
### Notes
- [:ledger: View file changes][0.52.0]
### Fixed
- Entity relations and wrong types for payments. (#731)
- Allow empty string for `switch_inline_query` and `switch_inline_query_current_chat` (InlineKeyboardButton). (#736)
- Fix empty date entry for User and Chat entities, using the current timestamp instead. (#738)
## [0.51.0] - 2017-12-05
### Notes
- [:ledger: View file changes][0.51.0] ∙ [:page_with_curl: DB migration script][0.51.0-sql-migration]
### Added
- Implemented new changes for Bot API 3.5 (InputMedia, MediaGroup). (#718)
## [0.50.0] - 2017-10-17
### Notes
- [:ledger: View file changes][0.50.0]
### Added
- Finish implementing payments, adding all missing type checks and docblock methods. (#647)
- Implemented new changes for Bot API 3.4 (Live Locations). (#675)
### Changed
- [:exclamation:][0.50.0-bc-messagegetcommand-return-value] `Message::getCommand()` returns `null` if not a command, instead of `false`. (#654)
### Fixed
- SQL update script for version 0.44.1-0.45.0.
- Issues found by Scrutinizer (Type hints and return values). (#654)
- Check inline keyboard button parameter value correctly. (#672)
## [0.49.0] - 2017-09-17
### Notes
- [:ledger: View file changes][0.49.0]
### Added
- Donation section and links in readme.
- Missing payment methods in `Request` class.
- Some helper methods for replying to commands and answering queries.
### Changed
- Updated and optimised all DB classes, removing a lot of bulky code.
### Fixed
- Ensure named SQL statement parameters are unique.
- Channel selection when using `DB::selectChats()`.
## [0.48.0] - 2017-08-26
### Notes
- [:ledger: View file changes][0.48.0] ∙ [:page_with_curl: DB migration script][0.48.0-sql-migration]
### Added
- New entities, methods, update types and inline keyboard button for Payments (Bot API 3.0).
- Add new methods, fields and objects for working with stickers (Bot API 3.2).
- New fields for Chat, User and Message objects (Bot API 3.3). `is_bot` added to `user` DB table.
### Changed
- [:exclamation:][0.48.0-bc-correct-printerror] Corrected `ServerResponse->printError` method to print by default and return by setting `$return` parameter.
- Ensure command names are handled as lower case.
### Fixed
- Correctly save `reply_to_message` to DB.
## [0.47.1] - 2017-08-06
### Notes
- [:ledger: View file changes][0.47.1]
### Added
- Linked version numbers in changelog for easy verification of code changes.
### Fixed
- Private-only commands work with edited messages now too.
## [0.47.0] - 2017-08-06 [YANKED]
### Notes
- [:ledger: View file changes][0.47.0]
### Changed
- Updated readme to latest state of 0.47.0.
### Fixed
- `Telegram::enableAdmin()` now handles duplicate additions properly.
- `Request::getMe()` failure doesn't break cron execution any more.
### Security
- [:exclamation:][0.47.0-bc-private-only-admin-commands] New command parameter `$private_only` to enforce usage in private chats only (set by default for Admin commands).
## [0.46.0] - 2017-07-15
### Notes
- [:ledger: View file changes][0.46.0]
### Added
- Callbacks can be added to be executed when callback queries are called.
- New Bot API 3.1 changes (#550).
- `/cleanup` command for admins, that cleans out old entries from the DB.
### Changed
- [:exclamation:][0.46.0-bc-request-class-refactor] Big refactor of the `Request` class, removing most custom method implementations.
## [0.45.0] - 2017-06-25
### Notes
- [:ledger: View file changes][0.45.0] ∙ [:page_with_curl: DB migration script][0.45.0-sql-migration]
### Added
- Documents can be sent by providing its contents via Psr7 stream (as opposed to passing a file path).
- Allow setting a custom Guzzle HTTP Client for requests (#511, #536).
- First implementations towards Bots API 3.0.
### Changed
- [:exclamation:][0.45.0-bc-chats-params-array] `Request::sendToActiveChats` and `DB::selectChats` now accept parameters as an options array and allow selecting of channels.
### Deprecated
- Deprecated `Message::getNewChatMember()` (Use `Message::getNewChatMembers()` instead to get an array of all newly added members).
### Removed
- [:exclamation:][0.45.0-bc-up-download-directory] Upload and download directories are not set any more by default and must be set manually.
- [:exclamation:][0.45.0-bc-remove-deprecated-methods] Completely removed `Telegram::getBotName()` and `Entity::getBotName()` (Use `::getBotUsername()` instead).
- [:exclamation:][0.45.0-bc-remove-deprecated-methods] Completely removed deprecated `Telegram::unsetWebhook()` (Use `Telegram::deleteWebhook()` instead).
### Fixed
- ID fields are now typed with `PARAM_STR` PDO data type, to allow huge numbers.
- Message type data type for PDO corrected.
- Indexed table columns now have a fitting length.
- Take `custom_input` into account when using getUpdates method (mainly for testing).
- Request limiter has been fixed to correctly support channels.
## [0.44.1] - 2017-04-25
### Notes
- [:ledger: View file changes][0.44.1]
### Fixed
- Erroneous exception when using webhook without a database connection.
## [0.44.0] - 2017-04-25
### Notes
- [:ledger: View file changes][0.44.0]
### Added
- Proper standalone `scrutinizer.yml` config.
- Human-readable `last_error_date_string` for debug command.
### Changed
- Bot username no longer required for object instantiation.
### Removed
- All examples have been moved to a [dedicated repository][example-bot].
### Fixed
- [:exclamation:][0.44.0-bc-update-content-type] Format of Update content type using `$update->getUpdateContent()`.
## [0.43.0] - 2017-04-17
### Notes
- [:ledger: View file changes][0.43.0]
### Added
- Travis CI webhook for Support Bot.
- Interval for request limiter.
- `isRunCommands()` method to check if called via `runCommands()`.
- Ensure coding standards for `tests` folder with `phpcs`.
### Changed
- Move default commands to `examples` folder.
- All links point to new organisation repo.
- Add PHP 7.1 support and update dependencies.
### Fixed
- Prevent handling the same Telegram updates multiple times, throw exception instead.
## [0.42.0] - 2017-04-09
### Notes
- [:ledger: View file changes][0.42.0]
### Added
- Added `getBotId()` to directly access bot ID.
### Changed
- Rename `bot_name` to `bot_username` everywhere.
### Deprecated
- Deprecated `Telegram::getBotName()` (Use `Telegram::getBotUsername()` instead).
### Fixed
- Tests are more reliable now, using a properly formatted API key.
## [0.41.0] - 2017-03-25
### Notes
- [:ledger: View file changes][0.41.0]
### Added
- `$show_in_help` attribute for commands, to set if it should be displayed in the `/help` command.
- Link to new Telegram group: `https://telegram.me/PHP_Telegram_Bot_Support`
- Introduce change log.
## [0.40.1] - 2017-03-07
### Notes
- [:ledger: View file changes][0.40.1]
### Fixed
- Infinite message loop, caused by incorrect Entity variable.
## [0.40.0] - 2017-02-20
### Notes
- [:ledger: View file changes][0.40.0]
### Added
- Request limiter for incoming requests.
### Fixed
- Faulty formatting in logger.
## [0.39.0] - 2017-01-20
### Notes
- [:ledger: View file changes][0.39.0]
### Added
- Newest bot API changes.
- Allow direct access to PDO object (`DB::getPdo()`).
- Simple `/debug` command that displays various system information to help debugging.
- Crontab-friendly script.
### Changed
- Botan integration improvements.
- Make logger more flexible.
### Fixed
- Various bugs and recommendations by Scrutinizer.
## [0.38.1] - 2016-12-25
### Notes
- [:ledger: View file changes][0.38.1]
### Fixed
- Usage of self-signed certificates in conjunction with the new `allowed_updates` webhook parameter.
## [0.38.0] - 2016-12-25
### Notes
- [:ledger: View file changes][0.38.0]
### Added
- New `switch_inline_query_current_chat` option for inline keyboard.
- Support for `channel_post` and `edited_channel_post`.
- New alias `deleteWebhook` (for `unsetWebhook`).
### Changed
- Update WebhookInfo entity and `setWebhook` to allow passing of new arguments.
## [0.37.1] - 2016-12-24
### Notes
- [:ledger: View file changes][0.37.1]
### Fixed
- Keyboards that are built without using the KeyboardButton objects.
- Commands that are called via `/command@botname` by correctly passing them the bot name.
## [0.37.0] - 2016-12-13
### Notes
- [:ledger: View file changes][0.37.0]
### Changed
- Logging improvements to Botan integration.
### Deprecated
- Move `hideKeyboard` to `removeKeyboard`.
-[unreleased-sql-migration]: https://github.com/php-telegram-bot/core/tree/develop/utils/db-schema-update/0.82.0-unreleased.sql
-[unreleased-bc-unreleased-bc-minimum-php-81]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#minimum-php-81
-[unreleased-bc-unreleased-bc-user-to-users]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#user-to-users
+[0.83.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.82.0-0.83.0.sql
+[0.83.0-bc-minimum-php-81]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#minimum-php-81
+[0.83.0-bc-user-to-users]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#user-to-users
[0.82.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.81.0-0.82.0.sql
[0.81.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.80.0-0.81.0.sql
[0.80.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.79.0-0.80.0.sql
[0.80.0-bc-commands-with-underscores]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#commands-with-underscores
[0.78.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.77.1-0.78.0.sql
[0.77.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.76.1-0.77.0.sql
[0.75.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.74.0-0.75.0.sql
[0.75.0-bc-removed-chatactions]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#removed-deprecated-chatactions
[0.74.0-bc-chatmember-subentities]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#chatmember-subentities
[0.73.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.72.0-0.73.0.sql
[0.72.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.71.0-0.72.0.sql
[0.70.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.64.0-0.70.0.sql
[0.70.0-bc-minimum-php-73]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#minimum-php-73
[0.63.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.62.0-0.63.0.sql
[0.63.0-bc-static-method-entityescapemarkdown]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#static-method-entityescapemarkdown
[0.62.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.61.1-0.62.0.sql
[0.61.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.60.0-0.61.0.sql
[0.61.0-bc-remove-monolog-from-core]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#remove-monolog-from-core
[0.58.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.57.0-0.58.0.sql
[0.58.0-bc-return-value-of-empty-entity-properties]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#return-value-of-empty-entity-properties
[0.58.0-bc-startcommand-is-now-a-usercommand]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#startcommand-is-now-a-usercommand
[0.57.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.56.0-0.57.0.sql
[0.55.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.54.1-0.55.0.sql
[0.55.0-bc-move-animation-out-of-games-namespace]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#move-animation-out-of-games-namespace
[0.54.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.53.0-0.54.0.sql
[0.54.0-bc-rename-constants]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#rename-constants
[0.53.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.52.0-0.53.0.sql
[0.51.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.50.0-0.51.0.sql
[0.50.0-bc-messagegetcommand-return-value]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#messagegetcommand-return-value
[0.48.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.47.1-0.48.0.sql
[0.48.0-bc-correct-printerror]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#correct-printerror
[0.47.0-bc-private-only-admin-commands]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#private-only-admin-commands
[0.46.0-bc-request-class-refactor]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#request-class-refactor
[0.46.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/0.45.0/utils/db-schema-update/0.44.1-0.45.0.sql
[0.45.0-bc-remove-deprecated-methods]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#remove-deprecated-methods
[0.45.0-bc-chats-params-array]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#chats-params-array
[0.45.0-bc-up-download-directory]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#up-download-directory
[0.44.0-bc-update-content-type]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#update-getupdatecontent
[example-bot]: https://github.com/php-telegram-bot/example-bot
[PSR-3]: https://www.php-fig.org/psr/psr-3
[Tidelift]: https://tidelift.com/subscription/pkg/packagist-longman-telegram-bot?utm_source=packagist-longman-telegram-bot&utm_medium=referral&utm_campaign=changelog
[Unreleased]: https://github.com/php-telegram-bot/core/compare/master...develop
+[0.83.0]: https://github.com/php-telegram-bot/core/compare/0.82.0...0.83.0
[0.82.0]: https://github.com/php-telegram-bot/core/compare/0.81.0...0.82.0
[0.81.0]: https://github.com/php-telegram-bot/core/compare/0.80.0...0.81.0
[0.80.0]: https://github.com/php-telegram-bot/core/compare/0.79.0...0.80.0
[0.79.0]: https://github.com/php-telegram-bot/core/compare/0.78.0...0.79.0
[0.78.0]: https://github.com/php-telegram-bot/core/compare/0.77.1...0.78.0
[0.77.1]: https://github.com/php-telegram-bot/core/compare/0.77.0...0.77.1
[0.77.0]: https://github.com/php-telegram-bot/core/compare/0.76.1...0.77.0
[0.76.1]: https://github.com/php-telegram-bot/core/compare/0.76.0...0.76.1
[0.76.0]: https://github.com/php-telegram-bot/core/compare/0.75.0...0.76.0
[0.75.0]: https://github.com/php-telegram-bot/core/compare/0.74.0...0.75.0
[0.74.0]: https://github.com/php-telegram-bot/core/compare/0.73.1...0.74.0
[0.73.1]: https://github.com/php-telegram-bot/core/compare/0.73.0...0.73.1
[0.73.0]: https://github.com/php-telegram-bot/core/compare/0.72.0...0.73.0
[0.72.0]: https://github.com/php-telegram-bot/core/compare/0.71.0...0.72.0
[0.71.0]: https://github.com/php-telegram-bot/core/compare/0.70.1...0.71.0
[0.70.1]: https://github.com/php-telegram-bot/core/compare/0.70.0...0.70.1
[0.70.0]: https://github.com/php-telegram-bot/core/compare/0.64.0...0.70.0
[0.64.0]: https://github.com/php-telegram-bot/core/compare/0.63.1...0.64.0
[0.63.1]: https://github.com/php-telegram-bot/core/compare/0.63.0...0.63.1
[0.63.0]: https://github.com/php-telegram-bot/core/compare/0.62.0...0.63.0
[0.62.0]: https://github.com/php-telegram-bot/core/compare/0.61.1...0.62.0
[0.61.1]: https://github.com/php-telegram-bot/core/compare/0.61.0...0.61.1
[0.61.0]: https://github.com/php-telegram-bot/core/compare/0.60.0...0.61.0
[0.60.0]: https://github.com/php-telegram-bot/core/compare/0.59.1...0.60.0
[0.59.1]: https://github.com/php-telegram-bot/core/compare/0.59.0...0.59.1
[0.59.0]: https://github.com/php-telegram-bot/core/compare/0.58.0...0.59.0
[0.58.0]: https://github.com/php-telegram-bot/core/compare/0.57.0...0.58.0
[0.57.0]: https://github.com/php-telegram-bot/core/compare/0.56.0...0.57.0
[0.56.0]: https://github.com/php-telegram-bot/core/compare/0.55.1...0.56.0
[0.55.1]: https://github.com/php-telegram-bot/core/compare/0.55.0...0.55.1
[0.55.0]: https://github.com/php-telegram-bot/core/compare/0.54.1...0.55.0
[0.54.1]: https://github.com/php-telegram-bot/core/compare/0.54.0...0.54.1
[0.54.0]: https://github.com/php-telegram-bot/core/compare/0.53.0...0.54.0
[0.53.0]: https://github.com/php-telegram-bot/core/compare/0.52.0...0.53.0
[0.52.0]: https://github.com/php-telegram-bot/core/compare/0.51.0...0.52.0
[0.51.0]: https://github.com/php-telegram-bot/core/compare/0.50.0...0.51.0
[0.50.0]: https://github.com/php-telegram-bot/core/compare/0.49.0...0.50.0
[0.49.0]: https://github.com/php-telegram-bot/core/compare/0.48.0...0.49.0
[0.48.0]: https://github.com/php-telegram-bot/core/compare/0.47.1...0.48.0
[0.47.1]: https://github.com/php-telegram-bot/core/compare/0.47.0...0.47.1
[0.47.0]: https://github.com/php-telegram-bot/core/compare/0.46.0...0.47.0
[0.46.0]: https://github.com/php-telegram-bot/core/compare/0.45.0...0.46.0
[0.45.0]: https://github.com/php-telegram-bot/core/compare/0.44.1...0.45.0
[0.44.1]: https://github.com/php-telegram-bot/core/compare/0.44.0...0.44.1
[0.44.0]: https://github.com/php-telegram-bot/core/compare/0.43.0...0.44.0
[0.43.0]: https://github.com/php-telegram-bot/core/compare/0.42.0...0.43.0
[0.42.0]: https://github.com/php-telegram-bot/core/compare/0.41.0...0.42.0
[0.41.0]: https://github.com/php-telegram-bot/core/compare/0.40.1...0.41.0
[0.40.1]: https://github.com/php-telegram-bot/core/compare/0.40.0...0.40.1
[0.40.0]: https://github.com/php-telegram-bot/core/compare/0.39.0...0.40.0
[0.39.0]: https://github.com/php-telegram-bot/core/compare/0.38.1...0.39.0
[0.38.1]: https://github.com/php-telegram-bot/core/compare/0.38.0...0.38.1
[0.38.0]: https://github.com/php-telegram-bot/core/compare/0.37.1...0.38.0
[0.37.1]: https://github.com/php-telegram-bot/core/compare/0.37.0...0.37.1
[0.37.0]: https://github.com/php-telegram-bot/core/compare/0.36...0.37.0
diff --git a/src/Entities/Message.php b/src/Entities/Message.php
index 0523122..f8baa98 100644
--- a/src/Entities/Message.php
+++ b/src/Entities/Message.php
@@ -1,344 +1,343 @@
<?php
/**
* This file is part of the TelegramBot package.
*
* (c) Avtandil Kikabidze aka LONGMAN <akalongman@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Longman\TelegramBot\Entities;
use Longman\TelegramBot\Entities\Games\Game;
use Longman\TelegramBot\Entities\Giveaway\Giveaway;
use Longman\TelegramBot\Entities\Giveaway\GiveawayCompleted;
use Longman\TelegramBot\Entities\Giveaway\GiveawayCreated;
use Longman\TelegramBot\Entities\Giveaway\GiveawayWinners;
use Longman\TelegramBot\Entities\Message\Factory as MaybeInaccessibleMessageFactory;
use Longman\TelegramBot\Entities\Message\MaybeInaccessibleMessage;
use Longman\TelegramBot\Entities\MessageOrigin\Factory as MessageOriginFactory;
use Longman\TelegramBot\Entities\MessageOrigin\MessageOrigin;
use Longman\TelegramBot\Entities\Payments\Invoice;
use Longman\TelegramBot\Entities\Payments\SuccessfulPayment;
use Longman\TelegramBot\Entities\TelegramPassport\PassportData;
use Longman\TelegramBot\Entities\Topics\ForumTopicClosed;
use Longman\TelegramBot\Entities\Topics\ForumTopicCreated;
use Longman\TelegramBot\Entities\Topics\ForumTopicEdited;
use Longman\TelegramBot\Entities\Topics\ForumTopicReopened;
use Longman\TelegramBot\Entities\Topics\GeneralForumTopicHidden;
use Longman\TelegramBot\Entities\Topics\GeneralForumTopicUnhidden;
/**
* Class Message
*
* Represents a message
*
* @link https://core.telegram.org/bots/api#message
*
* @method int getMessageId() Unique message identifier
- * @method int getMessageThreadId() Optional. Unique identifier of a message thread to which the message belongs;
-for supergroups only
+ * @method int getMessageThreadId() Optional. Unique identifier of a message thread to which the message belongs; for supergroups only
* @method User getFrom() Optional. Sender, can be empty for messages sent to channels
* @method Chat getSenderChat() Optional. Sender of the message, sent on behalf of a chat. The channel itself for channel messages. The supergroup itself for messages from anonymous group administrators. The linked channel for messages automatically forwarded to the discussion group
* @method int getSenderBoostCount() Optional. If the sender of the message boosted the chat, the number of boosts added by the user
* @method int getDate() Date the message was sent in Unix time
* @method Chat getChat() Conversation the message belongs to
* @method MessageOrigin getForwardOrigin() Optional. Information about the original message for forwarded messages
* @method bool getIsTopicMessage() Optional. True, if the message is sent to a forum topic
* @method bool getIsAutomaticForward() Optional. True, if the message is a channel post that was automatically forwarded to the connected discussion group
* @method ReplyToMessage getReplyToMessage() Optional. For replies, the original message. Note that the Message object in this field will not contain further reply_to_message fields even if it itself is a reply.
* @method ExternalReplyInfo getExternalReply() Optional. Information about the message that is being replied to, which may come from another chat or forum topic
* @method TextQuote getQuote() Optional. For replies that quote part of the original message, the quoted part of the message
* @method Story getReplyToStory() Optional. For replies to a story, the original story
* @method User getViaBot() Optional. Bot through which the message was sent
* @method int getEditDate() Optional. Date the message was last edited in Unix time
* @method bool getHasProtectedContent() Optional. True, if the message can't be forwarded
* @method string getMediaGroupId() Optional. The unique identifier of a media message group this message belongs to
* @method string getAuthorSignature() Optional. Signature of the post author for messages in channels
* @method LinkPreviewOptions getLinkPreviewOptions() Optional. Options used for link preview generation for the message, if it is a text message and link preview options were changed
* @method MessageEntity[] getEntities() Optional. For text messages, special entities like usernames, URLs, bot commands, etc. that appear in the text
* @method MessageEntity[] getCaptionEntities() Optional. For messages with a caption, special entities like usernames, URLs, bot commands, etc. that appear in the caption
* @method Audio getAudio() Optional. Message is an audio file, information about the file
* @method Document getDocument() Optional. Message is a general file, information about the file
* @method Animation getAnimation() Optional. Message is an animation, information about the animation. For backward compatibility, when this field is set, the document field will also be set
* @method Game getGame() Optional. Message is a game, information about the game.
* @method PhotoSize[] getPhoto() Optional. Message is a photo, available sizes of the photo
* @method Sticker getSticker() Optional. Message is a sticker, information about the sticker
* @method Story getStory() Optional. Message is a forwarded story
* @method Video getVideo() Optional. Message is a video, information about the video
* @method Voice getVoice() Optional. Message is a voice message, information about the file
* @method VideoNote getVideoNote() Optional. Message is a video note message, information about the video
* @method string getCaption() Optional. Caption for the document, photo or video, 0-200 characters
* @method bool getHasMediaSpoiler() Optional. True, if the message media is covered by a spoiler animation
* @method Contact getContact() Optional. Message is a shared contact, information about the contact
* @method Location getLocation() Optional. Message is a shared location, information about the location
* @method Venue getVenue() Optional. Message is a venue, information about the venue
* @method Poll getPoll() Optional. Message is a native poll, information about the poll
* @method Dice getDice() Optional. Message is a dice with random value, 1-6 for “🎲” and “🎯” base emoji, 1-5 for “🏀” and “⚽” base emoji, 1-64 for “🎰” base emoji
* @method User[] getNewChatMembers() Optional. A new member(s) was added to the group, information about them (one of this members may be the bot itself)
* @method User getLeftChatMember() Optional. A member was removed from the group, information about them (this member may be the bot itself)
* @method string getNewChatTitle() Optional. A chat title was changed to this value
* @method PhotoSize[] getNewChatPhoto() Optional. A chat photo was changed to this value
* @method MessageAutoDeleteTimerChanged getMessageAutoDeleteTimerChanged() Optional. Service message: auto-delete timer settings changed in the chat
* @method bool getDeleteChatPhoto() Optional. Service message: the chat photo was deleted
* @method bool getGroupChatCreated() Optional. Service message: the group has been created
* @method bool getSupergroupChatCreated() Optional. Service message: the supergroup has been created. This field can't be received in a message coming through updates, because bot can’t be a member of a supergroup when it is created. It can only be found in reply_to_message if someone replies to a very first message in a directly created supergroup.
* @method bool getChannelChatCreated() Optional. Service message: the channel has been created. This field can't be received in a message coming through updates, because bot can’t be a member of a channel when it is created. It can only be found in reply_to_message if someone replies to a very first message in a channel.
* @method int getMigrateToChatId() Optional. The group has been migrated to a supergroup with the specified identifier. This number may be greater than 32 bits and some programming languages may have difficulty/silent defects in interpreting it. But it smaller than 52 bits, so a signed 64 bit integer or double-precision float type are safe for storing this identifier.
* @method int getMigrateFromChatId() Optional. The supergroup has been migrated from a group with the specified identifier. This number may be greater than 32 bits and some programming languages may have difficulty/silent defects in interpreting it. But it smaller than 52 bits, so a signed 64 bit integer or double-precision float type are safe for storing this identifier.
* @method MaybeInaccessibleMessage getPinnedMessage() Optional. Specified message was pinned. Note that the Message object in this field will not contain further reply_to_message fields even if it is itself a reply.
* @method Invoice getInvoice() Optional. Message is an invoice for a payment, information about the invoice.
* @method SuccessfulPayment getSuccessfulPayment() Optional. Message is a service message about a successful payment, information about the payment.
* @method UsersShared getUsersShared() Optional. Service message: users were shared with the bot
* @method ChatShared getChatShared() Optional. Service message: a chat was shared with the bot
* @method string getConnectedWebsite() Optional. The domain name of the website on which the user has logged in.
* @method WriteAccessAllowed getWriteAccessAllowed() Optional. Service message: the user allowed the bot added to the attachment menu to write messages
* @method PassportData getPassportData() Optional. Telegram Passport data
* @method ProximityAlertTriggered getProximityAlertTriggered() Optional. Service message. A user in the chat triggered another user's proximity alert while sharing Live Location.
* @method ChatBoostAdded getBoostAdded() Optional. Service message: user boosted the chat
* @method ForumTopicCreated getForumTopicCreated() Optional. Service message: forum topic created
* @method ForumTopicEdited getForumTopicEdited() Optional. Service message: forum topic edited
* @method ForumTopicClosed getForumTopicClosed() Optional. Service message: forum topic closed
* @method ForumTopicReopened getForumTopicReopened() Optional. Service message: forum topic reopened
* @method GeneralForumTopicHidden getGeneralForumTopicHidden() Optional. Service message: the 'General' forum topic hidden
* @method GeneralForumTopicUnhidden getGeneralForumTopicUnhidden() Optional. Service message: the 'General' forum topic unhidden
* @method GiveawayCreated getGiveawayCreated() Optional. Service message: a scheduled giveaway was created
* @method Giveaway getGiveaway() Optional. The message is a scheduled giveaway message
* @method GiveawayWinners getGiveawayWinners() Optional. A giveaway with public winners was completed
* @method GiveawayCompleted getGiveawayCompleted() Optional. Service message: a giveaway without public winners was completed
* @method VideoChatScheduled getVideoChatScheduled() Optional. Service message: voice chat scheduled
* @method VideoChatStarted getVideoChatStarted() Optional. Service message: voice chat started
* @method VideoChatEnded getVideoChatEnded() Optional. Service message: voice chat ended
* @method VideoChatParticipantsInvited getVideoChatParticipantsInvited() Optional. Service message: new participants invited to a voice chat
* @method WebAppData getWebAppData() Optional. Service message: data sent by a Web App
* @method InlineKeyboard getReplyMarkup() Optional. Inline keyboard attached to the message. login_url buttons are represented as ordinary url buttons.
*/
class Message extends Entity implements MaybeInaccessibleMessage
{
/**
* {@inheritdoc}
*/
protected function subEntities(): array
{
return [
'from' => User::class,
'sender_chat' => Chat::class,
'chat' => Chat::class,
'forward_origin' => MessageOriginFactory::class,
'reply_to_message' => ReplyToMessage::class,
'external_reply' => ExternalReplyInfo::class,
'quote' => TextQuote::class,
'reply_to_story' => Story::class,
'via_bot' => User::class,
'link_preview_options' => LinkPreviewOptions::class,
'entities' => [MessageEntity::class],
'animation' => Animation::class,
'audio' => Audio::class,
'document' => Document::class,
'photo' => [PhotoSize::class],
'sticker' => Sticker::class,
'story' => Story::class,
'video' => Video::class,
'video_note' => VideoNote::class,
'voice' => Voice::class,
'caption_entities' => [MessageEntity::class],
'contact' => Contact::class,
'dice' => Dice::class,
'game' => Game::class,
'poll' => Poll::class,
'venue' => Venue::class,
'location' => Location::class,
'new_chat_members' => [User::class],
'left_chat_member' => User::class,
'new_chat_photo' => [PhotoSize::class],
'message_auto_delete_timer_changed' => MessageAutoDeleteTimerChanged::class,
'pinned_message' => MaybeInaccessibleMessageFactory::class,
'invoice' => Invoice::class,
'successful_payment' => SuccessfulPayment::class,
'users_shared' => UsersShared::class,
'chat_shared' => ChatShared::class,
'write_access_allowed' => WriteAccessAllowed::class,
'passport_data' => PassportData::class,
'proximity_alert_triggered' => ProximityAlertTriggered::class,
'boost_added' => ChatBoostAdded::class,
'forum_topic_created' => ForumTopicCreated::class,
'forum_topic_edited' => ForumTopicEdited::class,
'forum_topic_closed' => ForumTopicClosed::class,
'forum_topic_reopened' => ForumTopicReopened::class,
'general_forum_topic_hidden' => GeneralForumTopicHidden::class,
'general_forum_topic_unhidden' => GeneralForumTopicUnhidden::class,
'giveaway_created' => GiveawayCreated::class,
'giveaway' => Giveaway::class,
'giveaway_winners' => GiveawayWinners::class,
'giveaway_completed' => GiveawayCompleted::class,
'video_chat_scheduled' => VideoChatScheduled::class,
'video_chat_started' => VideoChatStarted::class,
'video_chat_ended' => VideoChatEnded::class,
'video_chat_participants_invited' => VideoChatParticipantsInvited::class,
'web_app_data' => WebAppData::class,
'reply_markup' => InlineKeyboard::class,
];
}
/**
* return the entire command like /echo or /echo@bot1 if specified
*
* @return string|null
*/
public function getFullCommand(): ?string
{
$text = $this->getProperty('text') ?? '';
if (strpos($text, '/') !== 0) {
return null;
}
$no_EOL = strtok($text, PHP_EOL);
$no_space = strtok($text, ' ');
//try to understand which separator \n or space divide /command from text
return strlen($no_space) < strlen($no_EOL) ? $no_space : $no_EOL;
}
/**
* Get command
*
* @return string|null
*/
public function getCommand(): ?string
{
if ($command = $this->getProperty('command')) {
return $command;
}
$full_command = $this->getFullCommand() ?? '';
if (strpos($full_command, '/') !== 0) {
return null;
}
$full_command = substr($full_command, 1);
//check if command is followed by bot username
$split_cmd = explode('@', $full_command);
if (!isset($split_cmd[1])) {
//command is not followed by name
return $full_command;
}
if (strtolower($split_cmd[1]) === strtolower($this->getBotUsername())) {
//command is addressed to me
return $split_cmd[0];
}
return null;
}
/**
* For text messages, the actual UTF-8 text of the message, 0-4096 characters.
*
* @param bool $without_cmd
*
* @return string|null
*/
public function getText($without_cmd = false): ?string
{
$text = $this->getProperty('text');
if ($without_cmd && $command = $this->getFullCommand()) {
if (strlen($command) + 1 < strlen($text)) {
return substr($text, strlen($command) + 1);
}
return '';
}
return $text;
}
/**
* Bot added in chat
*
* @return bool
*/
public function botAddedInChat(): bool
{
foreach ($this->getNewChatMembers() as $member) {
if ($member instanceof User && $member->getUsername() === $this->getBotUsername()) {
return true;
}
}
return false;
}
/**
* Detect type based on properties.
*
* @return string
*/
public function getType(): string
{
$types = [
'text',
'animation',
'audio',
'document',
'photo',
'sticker',
'video',
'video_note',
'voice',
'contact',
'dice',
'game',
'poll',
'venue',
'location',
'new_chat_members',
'left_chat_member',
'new_chat_title',
'new_chat_photo',
'delete_chat_photo',
'group_chat_created',
'supergroup_chat_created',
'channel_chat_created',
'message_auto_delete_timer_changed',
'migrate_to_chat_id',
'migrate_from_chat_id',
'pinned_message',
'invoice',
'successful_payment',
'users_shared',
'chat_shared',
'write_access_allowed',
'passport_data',
'proximity_alert_triggered',
'boost_added',
'forum_topic_created',
'forum_topic_edited',
'forum_topic_closed',
'forum_topic_reopened',
'general_forum_topic_hidden',
'general_forum_topic_unhidden',
'video_chat_scheduled',
'video_chat_started',
'video_chat_ended',
'video_chat_participants_invited',
'web_app_data',
'reply_markup',
];
$is_command = $this->getCommand() !== null;
foreach ($types as $type) {
if ($this->getProperty($type) !== null) {
if ($is_command && $type === 'text') {
return 'command';
}
return $type;
}
}
return 'message';
}
}
diff --git a/src/Telegram.php b/src/Telegram.php
index bbc9480..506af69 100644
--- a/src/Telegram.php
+++ b/src/Telegram.php
@@ -1,1336 +1,1336 @@
<?php
/**
* This file is part of the TelegramBot package.
*
* (c) Avtandil Kikabidze aka LONGMAN <akalongman@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Longman\TelegramBot;
defined('TB_BASE_PATH') || define('TB_BASE_PATH', __DIR__);
defined('TB_BASE_COMMANDS_PATH') || define('TB_BASE_COMMANDS_PATH', TB_BASE_PATH . '/Commands');
use Exception;
use InvalidArgumentException;
use Longman\TelegramBot\Commands\AdminCommand;
use Longman\TelegramBot\Commands\Command;
use Longman\TelegramBot\Commands\SystemCommand;
use Longman\TelegramBot\Commands\UserCommand;
use Longman\TelegramBot\Entities\Chat;
use Longman\TelegramBot\Entities\ServerResponse;
use Longman\TelegramBot\Entities\Update;
use Longman\TelegramBot\Entities\User;
use Longman\TelegramBot\Exception\TelegramException;
use PDO;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use RegexIterator;
class Telegram
{
/**
* Version
*
* @var string
*/
- protected $version = '0.82.0';
+ protected $version = '0.83.0';
/**
* Telegram API key
*
* @var string
*/
protected $api_key = '';
/**
* Telegram Bot username
*
* @var string
*/
protected $bot_username = '';
/**
* Telegram Bot id
*
* @var int
*/
protected $bot_id = 0;
/**
* Raw request data (json) for webhook methods
*
* @var string
*/
protected $input = '';
/**
* Custom commands paths
*
* @var array
*/
protected $commands_paths = [];
/**
* Custom command class names
* ```
* [
* 'User' => [
* // command_name => command_class
* 'start' => 'name\space\to\StartCommand',
* ],
* 'Admin' => [], //etc
* ]
* ```
*
* @var array
*/
protected $command_classes = [
Command::AUTH_USER => [],
Command::AUTH_ADMIN => [],
Command::AUTH_SYSTEM => [],
];
/**
* Custom commands objects
*
* @var array
*/
protected $commands_objects = [];
/**
* Current Update object
*
* @var Update
*/
protected $update;
/**
* Upload path
*
* @var string
*/
protected $upload_path = '';
/**
* Download path
*
* @var string
*/
protected $download_path = '';
/**
* MySQL integration
*
* @var bool
*/
protected $mysql_enabled = false;
/**
* PDO object
*
* @var PDO
*/
protected $pdo;
/**
* Commands config
*
* @var array
*/
protected $commands_config = [];
/**
* Admins list
*
* @var array
*/
protected $admins_list = [];
/**
* ServerResponse of the last Command execution
*
* @var ServerResponse
*/
protected $last_command_response;
/**
* Check if runCommands() is running in this session
*
* @var bool
*/
protected $run_commands = false;
/**
* Is running getUpdates without DB enabled
*
* @var bool
*/
protected $getupdates_without_database = false;
/**
* Last update ID
* Only used when running getUpdates without a database
*
* @var int
*/
protected $last_update_id;
/**
* The command to be executed when there's a new message update and nothing more suitable is found
*/
public const GENERIC_MESSAGE_COMMAND = 'genericmessage';
/**
* The command to be executed by default (when no other relevant commands are applicable)
*/
public const GENERIC_COMMAND = 'generic';
/**
* Update filter method
*
* @var callable
*/
protected $update_filter;
/**
* Telegram constructor.
*
* @param string $api_key
* @param string $bot_username
*
* @throws TelegramException
*/
public function __construct(string $api_key, string $bot_username = '')
{
if (empty($api_key)) {
throw new TelegramException('API KEY not defined!');
}
preg_match('/(\d+):[\w\-]+/', $api_key, $matches);
if (!isset($matches[1])) {
throw new TelegramException('Invalid API KEY defined!');
}
$this->bot_id = (int) $matches[1];
$this->api_key = $api_key;
$this->bot_username = $bot_username;
//Add default system commands path
$this->addCommandsPath(TB_BASE_COMMANDS_PATH . '/SystemCommands');
Request::initialize($this);
}
/**
* Initialize Database connection
*
* @param array $credentials
* @param string $table_prefix
* @param string $encoding
*
* @return Telegram
* @throws TelegramException
*/
public function enableMySql(array $credentials, string $table_prefix = '', string $encoding = 'utf8mb4'): Telegram
{
$this->pdo = DB::initialize($credentials, $this, $table_prefix, $encoding);
ConversationDB::initializeConversation();
$this->mysql_enabled = true;
return $this;
}
/**
* Initialize Database external connection
*
* @param PDO $external_pdo_connection PDO database object
* @param string $table_prefix
*
* @return Telegram
* @throws TelegramException
*/
public function enableExternalMySql(PDO $external_pdo_connection, string $table_prefix = ''): Telegram
{
$this->pdo = DB::externalInitialize($external_pdo_connection, $this, $table_prefix);
ConversationDB::initializeConversation();
$this->mysql_enabled = true;
return $this;
}
/**
* Get commands list
*
* @return array $commands
* @throws TelegramException
*/
public function getCommandsList(): array
{
$commands = [];
foreach ($this->commands_paths as $path) {
try {
//Get all "*Command.php" files
$files = new RegexIterator(
new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path)
),
'/^.+Command.php$/'
);
foreach ($files as $file) {
// Convert filename to command
$command = $this->classNameToCommandName(substr($file->getFilename(), 0, -4));
// Invalid Classname
if (is_null($command)) {
continue;
}
// Already registered
if (array_key_exists($command, $commands)) {
continue;
}
require_once $file->getPathname();
$command_obj = $this->getCommandObject($command, $file->getPathname());
if ($command_obj instanceof Command) {
$commands[$command] = $command_obj;
}
}
} catch (Exception $e) {
throw new TelegramException('Error getting commands from path: ' . $path, 0, $e);
}
}
return $commands;
}
/**
* Get classname of predefined commands
*
* @see command_classes
*
* @param string $auth Auth of command
* @param string $command Command name
* @param string $filepath Path to the command file
*
* @return string|null
*/
public function getCommandClassName(string $auth, string $command, string $filepath = ''): ?string
{
$command = mb_strtolower($command);
// Invalid command
if (trim($command) === '') {
return null;
}
$auth = $this->ucFirstUnicode($auth);
// First, check for directly assigned command class.
if ($command_class = $this->command_classes[$auth][$command] ?? null) {
return $command_class;
}
// Start with default namespace.
$command_namespace = __NAMESPACE__ . '\\Commands\\' . $auth . 'Commands';
// Check if we can get the namespace from the file (if passed).
if ($filepath && !($command_namespace = $this->getFileNamespace($filepath))) {
return null;
}
$command_class = $command_namespace . '\\' . $this->commandNameToClassName($command);
if (class_exists($command_class)) {
return $command_class;
}
return null;
}
/**
* Get an object instance of the passed command
*
* @param string $command
* @param string $filepath
*
* @return Command|null
*/
public function getCommandObject(string $command, string $filepath = ''): ?Command
{
if (isset($this->commands_objects[$command])) {
return $this->commands_objects[$command];
}
$which = [Command::AUTH_SYSTEM];
$this->isAdmin() && $which[] = Command::AUTH_ADMIN;
$which[] = Command::AUTH_USER;
foreach ($which as $auth) {
$command_class = $this->getCommandClassName($auth, $command, $filepath);
if ($command_class) {
$command_obj = new $command_class($this, $this->update);
if ($auth === Command::AUTH_SYSTEM && $command_obj instanceof SystemCommand) {
return $command_obj;
}
if ($auth === Command::AUTH_ADMIN && $command_obj instanceof AdminCommand) {
return $command_obj;
}
if ($auth === Command::AUTH_USER && $command_obj instanceof UserCommand) {
return $command_obj;
}
}
}
return null;
}
/**
* Get namespace from php file by src path
*
* @param string $src (absolute path to file)
*
* @return string|null ("Longman\TelegramBot\Commands\SystemCommands" for example)
*/
protected function getFileNamespace(string $src): ?string
{
$content = file_get_contents($src);
if (preg_match('#^\s*namespace\s+(.+?);#m', $content, $m)) {
return $m[1];
}
return null;
}
/**
* Set custom input string for debug purposes
*
* @param string $input (json format)
*
* @return Telegram
*/
public function setCustomInput(string $input): Telegram
{
$this->input = $input;
return $this;
}
/**
* Get custom input string for debug purposes
*
* @return string
*/
public function getCustomInput(): string
{
return $this->input;
}
/**
* Get the ServerResponse of the last Command execution
*
* @return ServerResponse
*/
public function getLastCommandResponse(): ServerResponse
{
return $this->last_command_response;
}
/**
* Handle getUpdates method
*
* @todo Remove backwards compatibility for old signature and force $data to be an array.
*
* @param array|int|null $data
* @param int|null $timeout
*
* @return ServerResponse
* @throws TelegramException
*/
public function handleGetUpdates($data = null, ?int $timeout = null): ServerResponse
{
if (empty($this->bot_username)) {
throw new TelegramException('Bot Username is not defined!');
}
if (!DB::isDbConnected() && !$this->getupdates_without_database) {
return new ServerResponse(
[
'ok' => false,
'description' => 'getUpdates needs MySQL connection! (This can be overridden - see documentation)',
],
$this->bot_username
);
}
$offset = 0;
$limit = null;
// By default, get update types sent by Telegram.
$allowed_updates = [];
// @todo Backwards compatibility for old signature, remove in next version.
if (!is_array($data)) {
$limit = $data;
@trigger_error(
sprintf('Use of $limit and $timeout parameters in %s is deprecated. Use $data array instead.', __METHOD__),
E_USER_DEPRECATED
);
} else {
$offset = $data['offset'] ?? $offset;
$limit = $data['limit'] ?? $limit;
$timeout = $data['timeout'] ?? $timeout;
$allowed_updates = $data['allowed_updates'] ?? $allowed_updates;
}
// Take custom input into account.
if ($custom_input = $this->getCustomInput()) {
try {
$input = json_decode($this->input, true, 512, JSON_THROW_ON_ERROR);
if (empty($input)) {
throw new TelegramException('Custom input is empty');
}
$response = new ServerResponse($input, $this->bot_username);
} catch (\Throwable $e) {
throw new TelegramException('Invalid custom input JSON: ' . $e->getMessage());
}
} else {
if (DB::isDbConnected() && $last_update = DB::selectTelegramUpdate(1)) {
// Get last Update id from the database.
$last_update = reset($last_update);
$this->last_update_id = $last_update['id'] ?? null;
}
if ($this->last_update_id !== null) {
$offset = $this->last_update_id + 1; // As explained in the telegram bot API documentation.
}
$response = Request::getUpdates(compact('offset', 'limit', 'timeout', 'allowed_updates'));
}
if ($response->isOk()) {
// Log update.
TelegramLog::update($response->toJson());
// Process all updates
/** @var Update $update */
foreach ($response->getResult() as $update) {
$this->processUpdate($update);
}
if (!DB::isDbConnected() && !$custom_input && $this->last_update_id !== null && $offset === 0) {
// Mark update(s) as read after handling
$offset = $this->last_update_id + 1;
$limit = 1;
Request::getUpdates(compact('offset', 'limit', 'timeout', 'allowed_updates'));
}
}
return $response;
}
/**
* Handle bot request from webhook
*
* @return bool
*
* @throws TelegramException
*/
public function handle(): bool
{
if ($this->bot_username === '') {
throw new TelegramException('Bot Username is not defined!');
}
$input = Request::getInput();
if (empty($input)) {
throw new TelegramException('Input is empty! The webhook must not be called manually, only by Telegram.');
}
// Log update.
TelegramLog::update($input);
$post = json_decode($input, true);
if (empty($post)) {
throw new TelegramException('Invalid input JSON! The webhook must not be called manually, only by Telegram.');
}
if ($response = $this->processUpdate(new Update($post, $this->bot_username))) {
return $response->isOk();
}
return false;
}
/**
* Get the command name from the command type
*
* @param string $type
*
* @return string
*/
protected function getCommandFromType(string $type): string
{
return $this->ucFirstUnicode(str_replace('_', '', $type));
}
/**
* Process bot Update request
*
* @param Update $update
*
* @return ServerResponse
* @throws TelegramException
*/
public function processUpdate(Update $update): ServerResponse
{
$this->update = $update;
$this->last_update_id = $update->getUpdateId();
if (is_callable($this->update_filter)) {
$reason = 'Update denied by update_filter';
try {
$allowed = (bool) call_user_func_array($this->update_filter, [$update, $this, &$reason]);
} catch (Exception $e) {
$allowed = false;
}
if (!$allowed) {
TelegramLog::debug($reason);
return new ServerResponse(['ok' => false, 'description' => 'denied']);
}
}
//Load admin commands
if ($this->isAdmin()) {
$this->addCommandsPath(TB_BASE_COMMANDS_PATH . '/AdminCommands', false);
}
//Make sure we have an up-to-date command list
//This is necessary to "require" all the necessary command files!
$this->commands_objects = $this->getCommandsList();
//If all else fails, it's a generic message.
$command = self::GENERIC_MESSAGE_COMMAND;
$update_type = $this->update->getUpdateType();
if ($update_type === 'message') {
$message = $this->update->getMessage();
$type = $message->getType();
// Let's check if the message object has the type field we're looking for...
$command_tmp = $type === 'command' ? $message->getCommand() : $this->getCommandFromType($type);
// ...and if a fitting command class is available.
$command_obj = $command_tmp ? $this->getCommandObject($command_tmp) : null;
// Empty usage string denotes a non-executable command.
// @see https://github.com/php-telegram-bot/core/issues/772#issuecomment-388616072
if (
($command_obj === null && $type === 'command')
|| ($command_obj !== null && $command_obj->getUsage() !== '')
) {
$command = $command_tmp;
}
} elseif ($update_type !== null) {
$command = $this->getCommandFromType($update_type);
}
//Make sure we don't try to process update that was already processed
$last_id = DB::selectTelegramUpdate(1, $this->update->getUpdateId());
if ($last_id && count($last_id) === 1) {
TelegramLog::debug('Duplicate update received, processing aborted!');
return Request::emptyResponse();
}
DB::insertRequest($this->update);
return $this->executeCommand($command);
}
/**
* Execute /command
*
* @param string $command
*
* @return ServerResponse
* @throws TelegramException
*/
public function executeCommand(string $command): ServerResponse
{
$command = mb_strtolower($command);
$command_obj = $this->commands_objects[$command] ?? $this->getCommandObject($command);
if (!$command_obj || !$command_obj->isEnabled()) {
//Failsafe in case the Generic command can't be found
if ($command === self::GENERIC_COMMAND) {
throw new TelegramException('Generic command missing!');
}
//Handle a generic command or non existing one
$this->last_command_response = $this->executeCommand(self::GENERIC_COMMAND);
} else {
//execute() method is executed after preExecute()
//This is to prevent executing a DB query without a valid connection
if ($this->update) {
$this->last_command_response = $command_obj->setUpdate($this->update)->preExecute();
} else {
$this->last_command_response = $command_obj->preExecute();
}
}
return $this->last_command_response;
}
/**
* @deprecated
*
* @param string $command
*
* @return string
*/
protected function sanitizeCommand(string $command): string
{
return str_replace(' ', '', $this->ucWordsUnicode(str_replace('_', ' ', $command)));
}
/**
* Enable a single Admin account
*
* @param int $admin_id Single admin id
*
* @return Telegram
*/
public function enableAdmin(int $admin_id): Telegram
{
if ($admin_id <= 0) {
TelegramLog::error('Invalid value "' . $admin_id . '" for admin.');
} elseif (!in_array($admin_id, $this->admins_list, true)) {
$this->admins_list[] = $admin_id;
}
return $this;
}
/**
* Enable a list of Admin Accounts
*
* @param array $admin_ids List of admin ids
*
* @return Telegram
*/
public function enableAdmins(array $admin_ids): Telegram
{
foreach ($admin_ids as $admin_id) {
$this->enableAdmin($admin_id);
}
return $this;
}
/**
* Get list of admins
*
* @return array
*/
public function getAdminList(): array
{
return $this->admins_list;
}
/**
* Check if the passed user is an admin
*
* If no user id is passed, the current update is checked for a valid message sender.
*
* @param int|null $user_id
*
* @return bool
*/
public function isAdmin($user_id = null): bool
{
if ($user_id === null && $this->update !== null) {
//Try to figure out if the user is an admin
$update_methods = [
'getMessage',
'getEditedMessage',
'getChannelPost',
'getEditedChannelPost',
'getInlineQuery',
'getChosenInlineResult',
'getCallbackQuery',
];
foreach ($update_methods as $update_method) {
$object = call_user_func([$this->update, $update_method]);
if ($object !== null && $from = $object->getFrom()) {
$user_id = $from->getId();
break;
}
}
}
return ($user_id === null) ? false : in_array($user_id, $this->admins_list, true);
}
/**
* Check if user required the db connection
*
* @return bool
*/
public function isDbEnabled(): bool
{
return $this->mysql_enabled;
}
/**
* Add a single custom command class
*
* @param string $command_class Full command class name
*
* @return Telegram
*/
public function addCommandClass(string $command_class): Telegram
{
if (!$command_class || !class_exists($command_class)) {
$error = sprintf('Command class "%s" does not exist.', $command_class);
TelegramLog::error($error);
throw new InvalidArgumentException($error);
}
if (!is_a($command_class, Command::class, true)) {
$error = sprintf('Command class "%s" does not extend "%s".', $command_class, Command::class);
TelegramLog::error($error);
throw new InvalidArgumentException($error);
}
// Dummy object to get data from.
$command_object = new $command_class($this);
$auth = null;
$command_object->isSystemCommand() && $auth = Command::AUTH_SYSTEM;
$command_object->isAdminCommand() && $auth = Command::AUTH_ADMIN;
$command_object->isUserCommand() && $auth = Command::AUTH_USER;
if ($auth) {
$command = mb_strtolower($command_object->getName());
$this->command_classes[$auth][$command] = $command_class;
}
return $this;
}
/**
* Add multiple custom command classes
*
* @param array $command_classes List of full command class names
*
* @return Telegram
*/
public function addCommandClasses(array $command_classes): Telegram
{
foreach ($command_classes as $command_class) {
$this->addCommandClass($command_class);
}
return $this;
}
/**
* Set a single custom commands path
*
* @param string $path Custom commands path to set
*
* @return Telegram
*/
public function setCommandsPath(string $path): Telegram
{
$this->commands_paths = [];
$this->addCommandsPath($path);
return $this;
}
/**
* Add a single custom commands path
*
* @param string $path Custom commands path to add
* @param bool $before If the path should be prepended or appended to the list
*
* @return Telegram
*/
public function addCommandsPath(string $path, bool $before = true): Telegram
{
if (!is_dir($path)) {
TelegramLog::error('Commands path "' . $path . '" does not exist.');
} elseif (!in_array($path, $this->commands_paths, true)) {
if ($before) {
array_unshift($this->commands_paths, $path);
} else {
$this->commands_paths[] = $path;
}
}
return $this;
}
/**
* Set multiple custom commands paths
*
* @param array $paths Custom commands paths to add
*
* @return Telegram
*/
public function setCommandsPaths(array $paths): Telegram
{
$this->commands_paths = [];
$this->addCommandsPaths($paths);
return $this;
}
/**
* Add multiple custom commands paths
*
* @param array $paths Custom commands paths to add
* @param bool $before If the paths should be prepended or appended to the list
*
* @return Telegram
*/
public function addCommandsPaths(array $paths, bool $before = true): Telegram
{
foreach ($paths as $path) {
$this->addCommandsPath($path, $before);
}
return $this;
}
/**
* Return the list of commands paths
*
* @return array
*/
public function getCommandsPaths(): array
{
return $this->commands_paths;
}
/**
* Return the list of command classes
*
* @return array
*/
public function getCommandClasses(): array
{
return $this->command_classes;
}
/**
* Set custom upload path
*
* @param string $path Custom upload path
*
* @return Telegram
*/
public function setUploadPath(string $path): Telegram
{
$this->upload_path = $path;
return $this;
}
/**
* Get custom upload path
*
* @return string
*/
public function getUploadPath(): string
{
return $this->upload_path;
}
/**
* Set custom download path
*
* @param string $path Custom download path
*
* @return Telegram
*/
public function setDownloadPath(string $path): Telegram
{
$this->download_path = $path;
return $this;
}
/**
* Get custom download path
*
* @return string
*/
public function getDownloadPath(): string
{
return $this->download_path;
}
/**
* Set command config
*
* Provide further variables to a particular commands.
* For example you can add the channel name at the command /sendtochannel
* Or you can add the api key for external service.
*
* @param string $command
* @param array $config
*
* @return Telegram
*/
public function setCommandConfig(string $command, array $config): Telegram
{
$this->commands_config[$command] = $config;
return $this;
}
/**
* Get command config
*
* @param string $command
*
* @return array
*/
public function getCommandConfig(string $command): array
{
return $this->commands_config[$command] ?? [];
}
/**
* Get API key
*
* @return string
*/
public function getApiKey(): string
{
return $this->api_key;
}
/**
* Get Bot name
*
* @return string
*/
public function getBotUsername(): string
{
return $this->bot_username;
}
/**
* Get Bot Id
*
* @return int
*/
public function getBotId(): int
{
return $this->bot_id;
}
/**
* Get Version
*
* @return string
*/
public function getVersion(): string
{
return $this->version;
}
/**
* Set Webhook for bot
*
* @param string $url
* @param array $data Optional parameters.
*
* @return ServerResponse
* @throws TelegramException
*/
public function setWebhook(string $url, array $data = []): ServerResponse
{
if ($url === '') {
throw new TelegramException('Hook url is empty!');
}
$data = array_intersect_key($data, array_flip([
'certificate',
'ip_address',
'max_connections',
'allowed_updates',
'drop_pending_updates',
'secret_token',
]));
$data['url'] = $url;
// If the certificate is passed as a path, encode and add the file to the data array.
if (!empty($data['certificate']) && is_string($data['certificate'])) {
$data['certificate'] = Request::encodeFile($data['certificate']);
}
$result = Request::setWebhook($data);
if (!$result->isOk()) {
throw new TelegramException(
'Webhook was not set! Error: ' . $result->getErrorCode() . ' ' . $result->getDescription()
);
}
return $result;
}
/**
* Delete any assigned webhook
*
* @param array $data
*
* @return ServerResponse
* @throws TelegramException
*/
public function deleteWebhook(array $data = []): ServerResponse
{
$result = Request::deleteWebhook($data);
if (!$result->isOk()) {
throw new TelegramException(
'Webhook was not deleted! Error: ' . $result->getErrorCode() . ' ' . $result->getDescription()
);
}
return $result;
}
/**
* Replace function `ucwords` for UTF-8 characters in the class definition and commands
*
* @param string $str
* @param string $encoding (default = 'UTF-8')
*
* @return string
*/
protected function ucWordsUnicode(string $str, string $encoding = 'UTF-8'): string
{
return mb_convert_case($str, MB_CASE_TITLE, $encoding);
}
/**
* Replace function `ucfirst` for UTF-8 characters in the class definition and commands
*
* @param string $str
* @param string $encoding (default = 'UTF-8')
*
* @return string
*/
protected function ucFirstUnicode(string $str, string $encoding = 'UTF-8'): string
{
return mb_strtoupper(mb_substr($str, 0, 1, $encoding), $encoding)
. mb_strtolower(mb_substr($str, 1, mb_strlen($str), $encoding), $encoding);
}
/**
* Enable requests limiter
*
* @param array $options
*
* @return Telegram
* @throws TelegramException
*/
public function enableLimiter(array $options = []): Telegram
{
Request::setLimiter(true, $options);
return $this;
}
/**
* Run provided commands
*
* @param array $commands
*
* @return ServerResponse[]
*
* @throws TelegramException
*/
public function runCommands(array $commands): array
{
if (empty($commands)) {
throw new TelegramException('No command(s) provided!');
}
$this->run_commands = true;
// Check if this request has a user Update / comes from Telegram.
if ($userUpdate = $this->update) {
$from = $this->update->getMessage()->getFrom();
$chat = $this->update->getMessage()->getChat();
} else {
// Fall back to the Bot user.
$from = new User([
'id' => $this->getBotId(),
'first_name' => $this->getBotUsername(),
'username' => $this->getBotUsername(),
]);
// Try to get "live" Bot info.
$response = Request::getMe();
if ($response->isOk()) {
/** @var User $result */
$result = $response->getResult();
$from = new User([
'id' => $result->getId(),
'first_name' => $result->getFirstName(),
'username' => $result->getUsername(),
]);
}
// Give Bot access to admin commands.
$this->enableAdmin($from->getId());
// Lock the bot to a private chat context.
$chat = new Chat([
'id' => $from->getId(),
'type' => 'private',
]);
}
$newUpdate = static function ($text = '') use ($from, $chat) {
return new Update([
'update_id' => -1,
'message' => [
'message_id' => -1,
'date' => time(),
'from' => json_decode($from->toJson(), true),
'chat' => json_decode($chat->toJson(), true),
'text' => $text,
],
]);
};
$responses = [];
foreach ($commands as $command) {
$this->update = $newUpdate($command);
// Refresh commands list for new Update object.
$this->commands_objects = $this->getCommandsList();
$responses[] = $this->executeCommand($this->update->getMessage()->getCommand());
}
// Reset Update to initial context.
$this->update = $userUpdate;
return $responses;
}
/**
* Is this session initiated by runCommands()
*
* @return bool
*/
public function isRunCommands(): bool
{
return $this->run_commands;
}
/**
* Switch to enable running getUpdates without a database
*
* @param bool $enable
*
* @return Telegram
*/
public function useGetUpdatesWithoutDatabase(bool $enable = true): Telegram
{
$this->getupdates_without_database = $enable;
return $this;
}
/**
* Return last update id
*
* @return int|null
*/
public function getLastUpdateId(): ?int
{
return $this->last_update_id;
}
/**
* Set an update filter callback
*
* @param callable $callback
*
* @return Telegram
*/
public function setUpdateFilter(callable $callback): Telegram
{
$this->update_filter = $callback;
return $this;
}
/**
* Return update filter callback
*
* @return callable|null
*/
public function getUpdateFilter(): ?callable
{
return $this->update_filter;
}
/**
* Converts the name of a class into the name of a command.
*
* @param string $class For example FooBarCommand
*
* @return string|null for example foo_bar. In case of errors, returns null.
*/
protected function classNameToCommandName(string $class): ?string
{
// If $class doesn't end with 'Command'
if (substr($class, -7) !== 'Command') {
return null;
}
return mb_strtolower(preg_replace('/(.)(?=[\p{Lu}])/u', '$1_', substr($class, 0, -7)));
}
/**
* Converts a command name into the name of a class.
*
* @param string $command For example foo_bar
*
* @return string|null for example FooBarCommand. In case of errors, returns null.
*/
protected function commandNameToClassName(string $command): ?string
{
if (trim($command) === '') {
return null;
}
return str_replace(' ', '', $this->ucWordsUnicode(str_replace('_', ' ', $command))) . 'Command';
}
}
diff --git a/utils/db-schema-update/0.82.0-unreleased.sql b/utils/db-schema-update/0.82.0-0.83.0.sql
similarity index 100%
rename from utils/db-schema-update/0.82.0-unreleased.sql
rename to utils/db-schema-update/0.82.0-0.83.0.sql

File Metadata

Mime Type
text/x-diff
Expires
Sun, Nov 15, 4:12 AM (1 d, 22 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
148920
Default Alt Text
(99 KB)

Event Timeline