diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f7c4739 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +composer.phar +/vendor/ +/.vscode +test.php +# Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control +# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file +# composer.lock diff --git a/README.md b/README.md new file mode 100644 index 0000000..457549a --- /dev/null +++ b/README.md @@ -0,0 +1,101 @@ +# bot_lib + +simple flexiable and async library based on amphp for telegram bot api. + +## installation + +- download and extract bot_lib repo. +- run `composer update` to install amphp. + +## getting started + +the recomended way is to use amphp's server to run all your bots + +#### server.php + +```php +$server = new Server("127.0.0.1:8080"); // create server instance running on port 8080 +$server->load_file("bot.php", "index"); // load the handlers in "bot.php" and store them in "index" path +$server->load_folder("folder", true); // load all files in a folder. the second param is whether to load recursivly or not +$server->run(); +``` +#### bot.php + +```php +$config = new Config; +$config->load("conf.json"); // can store token +$config->server = "http://loadlhost:8081/bot"; // if you using local telegram-bot-api + +$handler = new Handler; +$hanlder->on_message( + fn($u) => $u->reply("hello"); +); +``` +set webhook to 127.0.0.1:8080/you_bot_file_name (or custom name passed in seacond argument to load_file). + +you can add `token` paramter to the webhook url and the server will set it and use this token. + +run `php server.php`. + +a lot more hanlder, config and server options in examples folder. + +--- +# explanation + +there is 4 main objects in the library + +1. Server: extends Loader. load files and runing the http-server and activating handlers. +2. Config: configuration. +3. Update: extends API and HTTP. contains all the method to send request to bot api. +4. Handler: create handlers that will run asyncronicly. + +### Server +the server is loading all of your robots files, take the handlers, and run a server listen to incoming requests. +once there is a request to the server, it activates the handlers set in the request path. you can set any request path to any file. + +### Handler +all handlers run asynchronicly on every request from the bot. +there is a verity of handlers you can set and ways to control how they will activate. + +to create handler, simply call the method on Handler instance as handler name you want `$handler->handler_name()`. + +you can give it any name you want (accept the handler class methods). +the name can control when the handler is activating. + +handler accepts 3 paramter + +- function (named func): the function to run when handler activated. accept Update instance as paramter. +- filter: string, array or function that determine whether the handler should run or not. accept Update instance as paramter. +- last: if true and handler is activated, the handler will be the last handler to run in corrent request. + +you can pass the parametrs by order (function, filter, last) or by name `$handler->on_message(filter: "blabal", func: fn($u) => $u->reply("blablabl"));` + +#### special handlers names +this list of handler can accept also string or array filters. any other handler should filter with function + +- on_upadte: activates on every update. accepts update type/s as filter (message, callback_query, etc). +- on_message: activates on 'message' updates. accept message/s as filter (/start, menu, word, test, etc). +- on_cbq: activates on 'callback_quesy' updates. accept text to match callback_data as filter. +- on_file: activates when there is file in the request (no metter whet update type). accept file type/s as filter (photo, audio, etc). + +### Config +you can config varios things see src/config.php file. can be set in json file and load using `load` method as shown above. + +### Update +all bot api method and some more in this class. instance of this class is passed to the handlers. + +telegram api methods - https://core.telegram.org/bots/api#available-methods + +added methods: + +- reply: reply to the incoming message. +- delete: delete the message. +- ban: [only in groups and channels] ban the user from chat. +- leave: leave group or channel. +- edit: edit the message. +- forward: forward the message to another chat with or as copy. +- alert: reply to callbacl_quesy this alert. +- editKeyboard: edit inline keyboard. +- editButton: edit only one inline button. + +Also there is a lot of preset variables to many update parts. see update.php file. \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..2748a91 --- /dev/null +++ b/composer.json @@ -0,0 +1,11 @@ +{ + "require": { + "amphp/amp": "^2.5", + "amphp/http": "^1.6", + "amphp/http-client": "^4.5", + "amphp/http-server": "^2.1", + "amphp/log": "^1.1", + "amphp/cluster": "^1.0", + "amphp/file": "^1.0" + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..67b8b1e --- /dev/null +++ b/composer.lock @@ -0,0 +1,2018 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "863af2bfa127873d7d910c6ac0a00395", + "packages": [ + { + "name": "amphp/amp", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/amphp/amp.git", + "reference": "efca2b32a7580087adb8aabbff6be1dc1bb924a9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/amp/zipball/efca2b32a7580087adb8aabbff6be1dc1bb924a9", + "reference": "efca2b32a7580087adb8aabbff6be1dc1bb924a9", + "shasum": "" + }, + "require": { + "php": ">=7" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1", + "ext-json": "*", + "jetbrains/phpstorm-stubs": "^2019.3", + "phpunit/phpunit": "^6.0.9 | ^7", + "psalm/phar": "^3.11@dev", + "react/promise": "^2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Amp\\": "lib" + }, + "files": [ + "lib/functions.php", + "lib/Internal/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A non-blocking concurrency framework for PHP applications.", + "homepage": "http://amphp.org/amp", + "keywords": [ + "async", + "asynchronous", + "awaitable", + "concurrency", + "event", + "event-loop", + "future", + "non-blocking", + "promise" + ], + "support": { + "irc": "irc://irc.freenode.org/amphp", + "issues": "https://github.com/amphp/amp/issues", + "source": "https://github.com/amphp/amp/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2021-01-10T17:06:37+00:00" + }, + { + "name": "amphp/byte-stream", + "version": "v1.8.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/byte-stream.git", + "reference": "acbd8002b3536485c997c4e019206b3f10ca15bd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/byte-stream/zipball/acbd8002b3536485c997c4e019206b3f10ca15bd", + "reference": "acbd8002b3536485c997c4e019206b3f10ca15bd", + "shasum": "" + }, + "require": { + "amphp/amp": "^2", + "php": ">=7.1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1.4", + "friendsofphp/php-cs-fixer": "^2.3", + "jetbrains/phpstorm-stubs": "^2019.3", + "phpunit/phpunit": "^6 || ^7 || ^8", + "psalm/phar": "^3.11.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Amp\\ByteStream\\": "lib" + }, + "files": [ + "lib/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A stream abstraction to make working with non-blocking I/O simple.", + "homepage": "http://amphp.org/byte-stream", + "keywords": [ + "amp", + "amphp", + "async", + "io", + "non-blocking", + "stream" + ], + "support": { + "irc": "irc://irc.freenode.org/amphp", + "issues": "https://github.com/amphp/byte-stream/issues", + "source": "https://github.com/amphp/byte-stream/tree/v1.8.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2021-03-30T17:13:30+00:00" + }, + { + "name": "amphp/cache", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/cache.git", + "reference": "e7bccc526fc2a555d59e6ee8380eeb39a95c0835" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/cache/zipball/e7bccc526fc2a555d59e6ee8380eeb39a95c0835", + "reference": "e7bccc526fc2a555d59e6ee8380eeb39a95c0835", + "shasum": "" + }, + "require": { + "amphp/amp": "^2", + "amphp/serialization": "^1", + "amphp/sync": "^1.2", + "php": ">=7.1" + }, + "conflict": { + "amphp/file": "<0.2 || >=2" + }, + "require-dev": { + "amphp/file": "^1", + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1.1", + "phpunit/phpunit": "^6 | ^7 | ^8 | ^9", + "vimeo/psalm": "^3.11@dev" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Cache\\": "lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + } + ], + "description": "A promise-aware caching API for Amp.", + "homepage": "https://github.com/amphp/cache", + "support": { + "irc": "irc://irc.freenode.org/amphp", + "issues": "https://github.com/amphp/cache/issues", + "source": "https://github.com/amphp/cache/tree/v1.4.0" + }, + "time": "2020-04-19T16:10:08+00:00" + }, + { + "name": "amphp/cluster", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/cluster.git", + "reference": "6211d15eacc4d87a3673ee5439942a74d7660af3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/cluster/zipball/6211d15eacc4d87a3673ee5439942a74d7660af3", + "reference": "6211d15eacc4d87a3673ee5439942a74d7660af3", + "shasum": "" + }, + "require": { + "amphp/amp": "^2", + "amphp/byte-stream": "^1.5", + "amphp/log": "^1.1", + "amphp/parallel": "^1.2", + "amphp/socket": "^1", + "league/climate": "^3", + "monolog/monolog": "^2 || ^1.23", + "php": ">=7.1", + "psr/log": "^1" + }, + "conflict": { + "amphp/file": "<0.2 || >=2" + }, + "require-dev": { + "amphp/file": "^1 || ^0.3", + "amphp/http-server": "^2-RC", + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1.1", + "infection/infection": "^0.7.1", + "phpunit/phpunit": "^8 || ^7" + }, + "suggest": { + "amphp/file": "Required for logging to a file", + "ext-sockets": "Required for socket transfer on systems that do not support SO_REUSEPORT" + }, + "bin": [ + "bin/cluster" + ], + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Cluster\\": "src" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Bob Weinand" + } + ], + "description": "Building multi-core network applications with PHP.", + "homepage": "https://github.com/amphp/cluster", + "keywords": [ + "amp", + "amphp", + "async", + "cluster", + "multi-core", + "multi-process", + "non-blocking", + "parallel", + "sockets", + "watcher" + ], + "support": { + "issues": "https://github.com/amphp/cluster/issues", + "source": "https://github.com/amphp/cluster/tree/master" + }, + "time": "2019-09-26T21:08:20+00:00" + }, + { + "name": "amphp/dns", + "version": "v1.2.3", + "source": { + "type": "git", + "url": "https://github.com/amphp/dns.git", + "reference": "852292532294d7972c729a96b49756d781f7c59d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/dns/zipball/852292532294d7972c729a96b49756d781f7c59d", + "reference": "852292532294d7972c729a96b49756d781f7c59d", + "shasum": "" + }, + "require": { + "amphp/amp": "^2", + "amphp/byte-stream": "^1.1", + "amphp/cache": "^1.2", + "amphp/parser": "^1", + "amphp/windows-registry": "^0.3", + "daverandom/libdns": "^2.0.1", + "ext-filter": "*", + "ext-json": "*", + "php": ">=7.0" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1", + "phpunit/phpunit": "^6 || ^7 || ^8 || ^9" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Dns\\": "lib" + }, + "files": [ + "lib/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Wright", + "email": "addr@daverandom.com" + }, + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + }, + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "Async DNS resolution for Amp.", + "homepage": "https://github.com/amphp/dns", + "keywords": [ + "amp", + "amphp", + "async", + "client", + "dns", + "resolve" + ], + "support": { + "issues": "https://github.com/amphp/dns/issues", + "source": "https://github.com/amphp/dns/tree/v1.2.3" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2020-07-21T19:04:57+00:00" + }, + { + "name": "amphp/file", + "version": "v1.0.2", + "source": { + "type": "git", + "url": "https://github.com/amphp/file.git", + "reference": "54dcef2a3e38f445ae78ea44ff12c95738e46420" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/file/zipball/54dcef2a3e38f445ae78ea44ff12c95738e46420", + "reference": "54dcef2a3e38f445ae78ea44ff12c95738e46420", + "shasum": "" + }, + "require": { + "amphp/amp": "^2.2", + "amphp/byte-stream": "^1.6.1", + "amphp/parallel": "^1.2", + "php": ">=7.1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1.1", + "ext-eio": "^2", + "ext-uv": "^0.3 || ^0.2", + "phpunit/phpunit": "^8 || ^7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Amp\\File\\": "src" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Allows non-blocking access to the filesystem for Amp.", + "homepage": "https://github.com/amphp/file", + "keywords": [ + "amp", + "amphp", + "async", + "disk", + "file", + "filesystem", + "io", + "non-blocking", + "static" + ], + "support": { + "issues": "https://github.com/amphp/file/issues", + "source": "https://github.com/amphp/file/tree/v1.0.2" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2020-07-14T15:15:32+00:00" + }, + { + "name": "amphp/hpack", + "version": "v3.1.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/hpack.git", + "reference": "0dcd35f9a8d9fc04d5fb8af0aeb109d4474cfad8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/hpack/zipball/0dcd35f9a8d9fc04d5fb8af0aeb109d4474cfad8", + "reference": "0dcd35f9a8d9fc04d5fb8af0aeb109d4474cfad8", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "http2jp/hpack-test-case": "^1", + "phpunit/phpunit": "^6 | ^7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Http\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + }, + { + "name": "Bob Weinand" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "HTTP/2 HPack implementation.", + "homepage": "https://github.com/amphp/hpack", + "keywords": [ + "headers", + "hpack", + "http-2" + ], + "support": { + "issues": "https://github.com/amphp/hpack/issues", + "source": "https://github.com/amphp/hpack/tree/v3.1.0" + }, + "time": "2020-01-11T19:33:14+00:00" + }, + { + "name": "amphp/http", + "version": "v1.6.3", + "source": { + "type": "git", + "url": "https://github.com/amphp/http.git", + "reference": "e2b75561011a9596e4574cc867e07a706d56394b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/http/zipball/e2b75561011a9596e4574cc867e07a706d56394b", + "reference": "e2b75561011a9596e4574cc867e07a706d56394b", + "shasum": "" + }, + "require": { + "amphp/hpack": "^3", + "php": ">=7.1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "phpunit/phpunit": "^7 || ^6.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Amp\\Http\\": "src" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Basic HTTP primitives which can be shared by servers and clients.", + "support": { + "issues": "https://github.com/amphp/http/issues", + "source": "https://github.com/amphp/http/tree/v1.6.3" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2020-11-28T17:04:34+00:00" + }, + { + "name": "amphp/http-client", + "version": "v4.5.5", + "source": { + "type": "git", + "url": "https://github.com/amphp/http-client.git", + "reference": "ac286c0a2bf1bf175b08aa89d3086d1e9be03985" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/http-client/zipball/ac286c0a2bf1bf175b08aa89d3086d1e9be03985", + "reference": "ac286c0a2bf1bf175b08aa89d3086d1e9be03985", + "shasum": "" + }, + "require": { + "amphp/amp": "^2.4", + "amphp/byte-stream": "^1.6", + "amphp/hpack": "^3", + "amphp/http": "^1.6", + "amphp/socket": "^1", + "amphp/sync": "^1.3", + "league/uri": "^6", + "php": ">=7.2", + "psr/http-message": "^1" + }, + "conflict": { + "amphp/file": "<0.2" + }, + "require-dev": { + "amphp/file": "^1 || ^0.3 || ^0.2", + "amphp/http-server": "^2", + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1.1", + "amphp/react-adapter": "^2.1", + "clue/socks-react": "^1.0", + "ext-json": "*", + "kelunik/link-header-rfc5988": "^1.0", + "laminas/laminas-diactoros": "^2.3", + "phpunit/phpunit": "^7 || ^8 || ^9", + "vimeo/psalm": "^3.9@dev" + }, + "suggest": { + "amphp/file": "Required for file request bodies and HTTP archive logging", + "ext-json": "Required for logging HTTP archives", + "ext-zlib": "Allows using compression for response bodies." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.x-dev" + } + }, + "autoload": { + "psr-4": { + "Amp\\Http\\Client\\": "src" + }, + "files": [ + "src/Internal/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@gmail.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "Asynchronous concurrent HTTP/2 and HTTP/1.1 client built on the Amp concurrency framework", + "homepage": "https://github.com/amphp/http-client", + "keywords": [ + "async", + "client", + "concurrent", + "http", + "non-blocking", + "rest" + ], + "support": { + "issues": "https://github.com/amphp/http-client/issues", + "source": "https://github.com/amphp/http-client/tree/v4.5.5" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2020-12-23T16:54:43+00:00" + }, + { + "name": "amphp/http-server", + "version": "v2.1.2", + "source": { + "type": "git", + "url": "https://github.com/amphp/http-server.git", + "reference": "d1f71b05c5a2f642b54df88b8b328b721eada625" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/http-server/zipball/d1f71b05c5a2f642b54df88b8b328b721eada625", + "reference": "d1f71b05c5a2f642b54df88b8b328b721eada625", + "shasum": "" + }, + "require": { + "amphp/amp": "^2", + "amphp/byte-stream": "^1.3", + "amphp/hpack": "^3", + "amphp/http": "^1.6", + "amphp/socket": "^1", + "cash/lrucache": "^1", + "league/uri": "^6", + "php": ">=7.2", + "psr/http-message": "^1", + "psr/log": "^1" + }, + "require-dev": { + "amphp/http-client": "^4", + "amphp/log": "^1", + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1.1", + "infection/infection": "^0.9.2", + "league/uri-components": "^2", + "monolog/monolog": "^2 || ^1.23", + "phpunit/phpunit": "^8 || ^7" + }, + "suggest": { + "ext-zlib": "Allows GZip compression of response bodies" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Amp\\Http\\Server\\": "src" + }, + "files": [ + "src/Middleware/functions.php", + "src/functions.php", + "src/Server.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + }, + { + "name": "Bob Weinand" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "A non-blocking HTTP application server for PHP based on Amp.", + "homepage": "https://github.com/amphp/http-server", + "keywords": [ + "amp", + "amphp", + "async", + "http", + "non-blocking", + "server" + ], + "support": { + "issues": "https://github.com/amphp/http-server/issues", + "source": "https://github.com/amphp/http-server/tree/v2.1.2" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2021-04-16T08:52:44+00:00" + }, + { + "name": "amphp/log", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/log.git", + "reference": "25dcd3b58622bd22ffa7129288edb85e0c17081a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/log/zipball/25dcd3b58622bd22ffa7129288edb85e0c17081a", + "reference": "25dcd3b58622bd22ffa7129288edb85e0c17081a", + "shasum": "" + }, + "require": { + "amphp/amp": "^2", + "amphp/byte-stream": "^1.3", + "monolog/monolog": "^2 || ^1.23", + "php": ">=7.1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1.1", + "phpunit/phpunit": "^8 || ^7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Log\\": "src" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Non-blocking logging for PHP based on Amp and Monolog.", + "homepage": "https://github.com/amphp/log", + "keywords": [ + "amp", + "amphp", + "async", + "log", + "logger", + "logging", + "non-blocking" + ], + "support": { + "issues": "https://github.com/amphp/log/issues", + "source": "https://github.com/amphp/log/tree/master" + }, + "time": "2019-09-04T15:31:40+00:00" + }, + { + "name": "amphp/parallel", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/parallel.git", + "reference": "2c1039bf7ca137eae4d954b14c09a7535d7d4e1c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/parallel/zipball/2c1039bf7ca137eae4d954b14c09a7535d7d4e1c", + "reference": "2c1039bf7ca137eae4d954b14c09a7535d7d4e1c", + "shasum": "" + }, + "require": { + "amphp/amp": "^2", + "amphp/byte-stream": "^1.6.1", + "amphp/parser": "^1", + "amphp/process": "^1", + "amphp/serialization": "^1", + "amphp/sync": "^1.0.1", + "php": ">=7.1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1.1", + "phpunit/phpunit": "^8 || ^7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Parallel\\": "lib" + }, + "files": [ + "lib/Context/functions.php", + "lib/Sync/functions.php", + "lib/Worker/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Stephen Coakley", + "email": "me@stephencoakley.com" + } + ], + "description": "Parallel processing component for Amp.", + "homepage": "https://github.com/amphp/parallel", + "keywords": [ + "async", + "asynchronous", + "concurrent", + "multi-processing", + "multi-threading" + ], + "support": { + "issues": "https://github.com/amphp/parallel/issues", + "source": "https://github.com/amphp/parallel/tree/master" + }, + "time": "2020-04-27T15:12:37+00:00" + }, + { + "name": "amphp/parser", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/parser.git", + "reference": "f83e68f03d5b8e8e0365b8792985a7f341c57ae1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/parser/zipball/f83e68f03d5b8e8e0365b8792985a7f341c57ae1", + "reference": "f83e68f03d5b8e8e0365b8792985a7f341c57ae1", + "shasum": "" + }, + "require": { + "php": ">=7" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.3", + "phpunit/phpunit": "^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Parser\\": "lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "A generator parser to make streaming parsers simple.", + "homepage": "https://github.com/amphp/parser", + "keywords": [ + "async", + "non-blocking", + "parser", + "stream" + ], + "support": { + "issues": "https://github.com/amphp/parser/issues", + "source": "https://github.com/amphp/parser/tree/is-valid" + }, + "time": "2017-06-06T05:29:10+00:00" + }, + { + "name": "amphp/process", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/process.git", + "reference": "b88c6aef75c0b22f6f021141dd2d5e7c5db4c124" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/process/zipball/b88c6aef75c0b22f6f021141dd2d5e7c5db4c124", + "reference": "b88c6aef75c0b22f6f021141dd2d5e7c5db4c124", + "shasum": "" + }, + "require": { + "amphp/amp": "^2", + "amphp/byte-stream": "^1.4", + "php": ">=7" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1", + "phpunit/phpunit": "^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Process\\": "lib" + }, + "files": [ + "lib/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Asynchronous process manager.", + "homepage": "https://github.com/amphp/process", + "support": { + "issues": "https://github.com/amphp/process/issues", + "source": "https://github.com/amphp/process/tree/v1.1.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2021-03-30T20:04:22+00:00" + }, + { + "name": "amphp/serialization", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/serialization.git", + "reference": "693e77b2fb0b266c3c7d622317f881de44ae94a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/serialization/zipball/693e77b2fb0b266c3c7d622317f881de44ae94a1", + "reference": "693e77b2fb0b266c3c7d622317f881de44ae94a1", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "phpunit/phpunit": "^9 || ^8 || ^7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Serialization\\": "src" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Serialization tools for IPC and data storage in PHP.", + "homepage": "https://github.com/amphp/serialization", + "keywords": [ + "async", + "asynchronous", + "serialization", + "serialize" + ], + "support": { + "issues": "https://github.com/amphp/serialization/issues", + "source": "https://github.com/amphp/serialization/tree/master" + }, + "time": "2020-03-25T21:39:07+00:00" + }, + { + "name": "amphp/socket", + "version": "v1.1.3", + "source": { + "type": "git", + "url": "https://github.com/amphp/socket.git", + "reference": "b9064b98742d12f8f438eaf73369bdd7d8446331" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/socket/zipball/b9064b98742d12f8f438eaf73369bdd7d8446331", + "reference": "b9064b98742d12f8f438eaf73369bdd7d8446331", + "shasum": "" + }, + "require": { + "amphp/amp": "^2", + "amphp/byte-stream": "^1.6", + "amphp/dns": "^1 || ^0.9", + "ext-openssl": "*", + "kelunik/certificate": "^1.1", + "league/uri-parser": "^1.4", + "php": ">=7.1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1", + "phpunit/phpunit": "^6 || ^7 || ^8", + "vimeo/psalm": "^3.9@dev" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Amp\\Socket\\": "src" + }, + "files": [ + "src/functions.php", + "src/Internal/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@gmail.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Async socket connection / server tools for Amp.", + "homepage": "https://github.com/amphp/socket", + "keywords": [ + "amp", + "async", + "encryption", + "non-blocking", + "sockets", + "tcp", + "tls" + ], + "support": { + "issues": "https://github.com/amphp/socket/issues", + "source": "https://github.com/amphp/socket/tree/master" + }, + "time": "2020-06-25T18:55:28+00:00" + }, + { + "name": "amphp/sync", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/sync.git", + "reference": "613047ac54c025aa800a9cde5b05c3add7327ed4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/sync/zipball/613047ac54c025aa800a9cde5b05c3add7327ed4", + "reference": "613047ac54c025aa800a9cde5b05c3add7327ed4", + "shasum": "" + }, + "require": { + "amphp/amp": "^2.2", + "php": ">=7.1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1.1", + "phpunit/phpunit": "^9 || ^8 || ^7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Sync\\": "src" + }, + "files": [ + "src/functions.php", + "src/ConcurrentIterator/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Stephen Coakley", + "email": "me@stephencoakley.com" + } + ], + "description": "Mutex, Semaphore, and other synchronization tools for Amp.", + "homepage": "https://github.com/amphp/sync", + "keywords": [ + "async", + "asynchronous", + "mutex", + "semaphore", + "synchronization" + ], + "support": { + "issues": "https://github.com/amphp/sync/issues", + "source": "https://github.com/amphp/sync/tree/v1.4.0" + }, + "time": "2020-05-07T18:57:50+00:00" + }, + { + "name": "amphp/windows-registry", + "version": "v0.3.3", + "source": { + "type": "git", + "url": "https://github.com/amphp/windows-registry.git", + "reference": "0f56438b9197e224325e88f305346f0221df1f71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/windows-registry/zipball/0f56438b9197e224325e88f305346f0221df1f71", + "reference": "0f56438b9197e224325e88f305346f0221df1f71", + "shasum": "" + }, + "require": { + "amphp/amp": "^2", + "amphp/byte-stream": "^1.4", + "amphp/process": "^1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\WindowsRegistry\\": "lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Windows Registry Reader.", + "support": { + "issues": "https://github.com/amphp/windows-registry/issues", + "source": "https://github.com/amphp/windows-registry/tree/master" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2020-07-10T16:13:29+00:00" + }, + { + "name": "cash/lrucache", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/cash/LRUCache.git", + "reference": "4fa4c6834cec59690b43526c4da41d6153026289" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cash/LRUCache/zipball/4fa4c6834cec59690b43526c4da41d6153026289", + "reference": "4fa4c6834cec59690b43526c4da41d6153026289", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "cash": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Cash Costello", + "email": "cash.costello@gmail.com" + } + ], + "description": "An efficient memory-based Least Recently Used (LRU) cache", + "homepage": "https://github.com/cash/LRUCache", + "keywords": [ + "cache", + "lru" + ], + "support": { + "issues": "https://github.com/cash/LRUCache/issues", + "source": "https://github.com/cash/LRUCache/tree/1.0.0" + }, + "time": "2013-09-20T18:59:12+00:00" + }, + { + "name": "daverandom/libdns", + "version": "v2.0.2", + "source": { + "type": "git", + "url": "https://github.com/DaveRandom/LibDNS.git", + "reference": "e8b6d6593d18ac3a6a14666d8a68a4703b2e05f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/DaveRandom/LibDNS/zipball/e8b6d6593d18ac3a6a14666d8a68a4703b2e05f9", + "reference": "e8b6d6593d18ac3a6a14666d8a68a4703b2e05f9", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "php": ">=7.0" + }, + "suggest": { + "ext-intl": "Required for IDN support" + }, + "type": "library", + "autoload": { + "psr-4": { + "LibDNS\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "DNS protocol implementation written in pure PHP", + "keywords": [ + "dns" + ], + "support": { + "issues": "https://github.com/DaveRandom/LibDNS/issues", + "source": "https://github.com/DaveRandom/LibDNS/tree/v2.0.2" + }, + "time": "2019-12-03T09:12:46+00:00" + }, + { + "name": "kelunik/certificate", + "version": "v1.1.2", + "source": { + "type": "git", + "url": "https://github.com/kelunik/certificate.git", + "reference": "56542e62d51533d04d0a9713261fea546bff80f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kelunik/certificate/zipball/56542e62d51533d04d0a9713261fea546bff80f6", + "reference": "56542e62d51533d04d0a9713261fea546bff80f6", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "php": ">=5.4" + }, + "require-dev": { + "fabpot/php-cs-fixer": "^1.9", + "phpunit/phpunit": "^4.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "Kelunik\\Certificate\\": "lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Access certificate details and transform between different formats.", + "keywords": [ + "DER", + "certificate", + "certificates", + "openssl", + "pem", + "x509" + ], + "support": { + "issues": "https://github.com/kelunik/certificate/issues", + "source": "https://github.com/kelunik/certificate/tree/v1.1.2" + }, + "time": "2019-05-29T19:02:31+00:00" + }, + { + "name": "league/climate", + "version": "3.7.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/climate.git", + "reference": "5c717c3032c5118be7ad2395dbe0813d9894e8c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/climate/zipball/5c717c3032c5118be7ad2395dbe0813d9894e8c7", + "reference": "5c717c3032c5118be7ad2395dbe0813d9894e8c7", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0", + "psr/log": "^1.0", + "seld/cli-prompt": "^1.0" + }, + "require-dev": { + "mikey179/vfsstream": "^1.4", + "mockery/mockery": "^1.4.2", + "phpunit/phpunit": "^9.5.0" + }, + "suggest": { + "ext-mbstring": "If ext-mbstring is not available you MUST install symfony/polyfill-mbstring" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\CLImate\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Joe Tannenbaum", + "email": "hey@joe.codes", + "homepage": "http://joe.codes/", + "role": "Developer" + }, + { + "name": "Craig Duncan", + "email": "git@duncanc.co.uk", + "homepage": "https://github.com/duncan3dc", + "role": "Developer" + } + ], + "description": "PHP's best friend for the terminal. CLImate allows you to easily output colored text, special formats, and more.", + "keywords": [ + "cli", + "colors", + "command", + "php", + "terminal" + ], + "support": { + "issues": "https://github.com/thephpleague/climate/issues", + "source": "https://github.com/thephpleague/climate/tree/3.7.0" + }, + "time": "2021-01-10T20:18:52+00:00" + }, + { + "name": "league/uri", + "version": "6.4.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri.git", + "reference": "09da64118eaf4c5d52f9923a1e6a5be1da52fd9a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/09da64118eaf4c5d52f9923a1e6a5be1da52fd9a", + "reference": "09da64118eaf4c5d52f9923a1e6a5be1da52fd9a", + "shasum": "" + }, + "require": { + "ext-json": "*", + "league/uri-interfaces": "^2.1", + "php": ">=7.2", + "psr/http-message": "^1.0" + }, + "conflict": { + "league/uri-schemes": "^1.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.16", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpstan/phpstan-strict-rules": "^0.12", + "phpunit/phpunit": "^8.0 || ^9.0", + "psr/http-factory": "^1.0" + }, + "suggest": { + "ext-fileinfo": "Needed to create Data URI from a filepath", + "ext-intl": "Needed to improve host validation", + "league/uri-components": "Needed to easily manipulate URI objects", + "psr/http-factory": "Needed to use the URI factory" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "URI manipulation library", + "homepage": "http://uri.thephpleague.com", + "keywords": [ + "data-uri", + "file-uri", + "ftp", + "hostname", + "http", + "https", + "middleware", + "parse_str", + "parse_url", + "psr-7", + "query-string", + "querystring", + "rfc3986", + "rfc3987", + "rfc6570", + "uri", + "uri-template", + "url", + "ws" + ], + "support": { + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri/issues", + "source": "https://github.com/thephpleague/uri/tree/6.4.0" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2020-11-22T14:29:11+00:00" + }, + { + "name": "league/uri-interfaces", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri-interfaces.git", + "reference": "667f150e589d65d79c89ffe662e426704f84224f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/667f150e589d65d79c89ffe662e426704f84224f", + "reference": "667f150e589d65d79c89ffe662e426704f84224f", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.0", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpstan/phpstan-strict-rules": "^0.12" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "Common interface for URI representation", + "homepage": "http://github.com/thephpleague/uri-interfaces", + "keywords": [ + "rfc3986", + "rfc3987", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/thephpleague/uri-interfaces/issues", + "source": "https://github.com/thephpleague/uri-interfaces/tree/2.2.0" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2020-10-31T13:45:51+00:00" + }, + { + "name": "league/uri-parser", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri-parser.git", + "reference": "671548427e4c932352d9b9279fdfa345bf63fa00" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri-parser/zipball/671548427e4c932352d9b9279fdfa345bf63fa00", + "reference": "671548427e4c932352d9b9279fdfa345bf63fa00", + "shasum": "" + }, + "require": { + "php": ">=7.0.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.0", + "phpstan/phpstan": "^0.9.2", + "phpstan/phpstan-phpunit": "^0.9.4", + "phpstan/phpstan-strict-rules": "^0.9.0", + "phpunit/phpunit": "^6.0" + }, + "suggest": { + "ext-intl": "Allow parsing RFC3987 compliant hosts", + "league/uri-schemes": "Allow validating and normalizing URI parsing results" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "src" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "userland URI parser RFC 3986 compliant", + "homepage": "https://github.com/thephpleague/uri-parser", + "keywords": [ + "parse_url", + "parser", + "rfc3986", + "rfc3987", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/thephpleague/uri-parser/issues", + "source": "https://github.com/thephpleague/uri-parser/tree/master" + }, + "time": "2018-11-22T07:55:51+00:00" + }, + { + "name": "monolog/monolog", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "1cb1cde8e8dd0f70cc0fe51354a59acad9302084" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/1cb1cde8e8dd0f70cc0fe51354a59acad9302084", + "reference": "1cb1cde8e8dd0f70cc0fe51354a59acad9302084", + "shasum": "" + }, + "require": { + "php": ">=7.2", + "psr/log": "^1.0.1" + }, + "provide": { + "psr/log-implementation": "1.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "doctrine/couchdb": "~1.0@dev", + "elasticsearch/elasticsearch": "^7", + "graylog2/gelf-php": "^1.4.2", + "mongodb/mongodb": "^1.8", + "php-amqplib/php-amqplib": "~2.4", + "php-console/php-console": "^3.1.3", + "phpspec/prophecy": "^1.6.1", + "phpstan/phpstan": "^0.12.59", + "phpunit/phpunit": "^8.5", + "predis/predis": "^1.1", + "rollbar/rollbar": "^1.3", + "ruflin/elastica": ">=0.90 <7.0.1", + "swiftmailer/swiftmailer": "^5.3|^6.0" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "php-console/php-console": "Allow sending log messages to Google Chrome", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "https://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/2.2.0" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2020-12-14T13:15:25+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/master" + }, + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "psr/log", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "time": "2021-05-03T11:20:27+00:00" + }, + { + "name": "seld/cli-prompt", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/cli-prompt.git", + "reference": "b8dfcf02094b8c03b40322c229493bb2884423c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/cli-prompt/zipball/b8dfcf02094b8c03b40322c229493bb2884423c5", + "reference": "b8dfcf02094b8c03b40322c229493bb2884423c5", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.63" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Seld\\CliPrompt\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be" + } + ], + "description": "Allows you to prompt for user input on the command line, and optionally hide the characters they type", + "keywords": [ + "cli", + "console", + "hidden", + "input", + "prompt" + ], + "support": { + "issues": "https://github.com/Seldaek/cli-prompt/issues", + "source": "https://github.com/Seldaek/cli-prompt/tree/1.0.4" + }, + "time": "2020-12-15T21:32:01+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.0.0" +} diff --git a/examples/bot.php b/examples/bot.php new file mode 100644 index 0000000..325fded --- /dev/null +++ b/examples/bot.php @@ -0,0 +1,103 @@ +load("conf.json"); +$conf->server = "http://localhost:8081/bot"; +$conf->debug = true; +$conf->apiErrorHandler = function($err, $res){ + if($err){ + print "request error" . PHP_EOL; + } +}; + +$handler = new Handler(); + +// this handler run once per request before any other handler +$handler->before(function($u) { + if(user_in_black_list($u->chatId)) + return []; // disable all handlers + + $u->blabla = "some data"; // will be available to all handlers + $u->user = new User($u->chatId); // say you have class that load user from db, and you wand to use it with all handlers +}); + +$handler->middle(function($u, $next){ + // if you have somthing to run before any handler + // unlike before this handler will run once per handler + + // will done before handler + yield $next($u); // wait the handler to finish + // will done after handler +}); + +$handler->after(function($u){ + // run after all handlers finished + store_in_db($u->user); +}); + +// run everytime on avery update type +// you can filter update type you want this handler to hanlde +$handler->on_update(function(Update $u){ + $u->reply($u->message); +}); + +$handler->on_start( + filter: function($u){ + return str_starts_with($u->message, "/start"); + }, + func: function($u){ + $u->reply("you send \"/start\""); + }, + last: true // if this handler is runnin it will be the last. and no other handlers will run +); + +$handler->hey_i_can_call_handlers_whatever_i_want(function($u){ + $u->reply("haha cool handler name"); +}); + +$handler->on_message( // only few handlers can take array or string as filter. + filter: ["***", "xxx" , "f"], + func: fn($u) => $u->reply("hey! you cant sey stuff like this in here") // arrow function +); + +$handler->on_file(function($u){ + $file = yield $u->download(); + $u->reply("your file downloaded to: " . $file->update["result"]["file_path"]); +}, ["audio", "photo"]); +// here we pass args by order. +// if you wand to write the filter first, you need to use named arguments like on_start handler in this example + +$handler->get_keyboard( + filter: fn($u) => $u->message == "keyboard", + func: fn($u) => $u->reply( + "message with keyboard", + Helpers::keyboard([["option one" => "one"], ["row two" => "two"]]) + ) +); + +$handler->on_cbq( // another name that accept string|array filter + filter: "keyboard", + func: function($u){ + $u->alert("you press the button " . $u->data); + } +); + +// handler without filter will run every request +$handler->do_some_request(function($u){ + $decoded_result = yield $u->Request("http://exapmle.com/json")->decode; + $text_result = yield $u->Request("http://exapmle.com/json")->result; + + // if the result is big you can read is asynchronicly + $file = yield Amp\File\open("big_file", "w"); // open file + $response = yield $u->Request("http://exapmle.com/big_file")->request; // with for response + while(null !== $chunk = yield $response->getBody()->read()){ // read response + yield $file->write($chunk); // write it to the file + } +}); \ No newline at end of file diff --git a/examples/conf.json b/examples/conf.json new file mode 100644 index 0000000..9af7080 --- /dev/null +++ b/examples/conf.json @@ -0,0 +1,3 @@ +{ + "token": "YOUR-TOKEN" +} \ No newline at end of file diff --git a/examples/config.json b/examples/config.json new file mode 100644 index 0000000..71184ed --- /dev/null +++ b/examples/config.json @@ -0,0 +1,3 @@ +{ + "token": "1772947495:AAFdIIn0hJljIdCLq5VYCbeGIC7mF4WCfMo" +} \ No newline at end of file diff --git a/examples/echo-bot.php b/examples/echo-bot.php new file mode 100644 index 0000000..6ffd280 --- /dev/null +++ b/examples/echo-bot.php @@ -0,0 +1,12 @@ +on_update(function($u){ + $u->reply($u->text); +}); diff --git a/examples/edit-file-name.php b/examples/edit-file-name.php new file mode 100644 index 0000000..1aa9286 --- /dev/null +++ b/examples/edit-file-name.php @@ -0,0 +1,15 @@ +on_file(function($u){ + $file = yield $u->download()->decode; // get decoded json response + rename($file["result"]["file_path"], "new_name"); + $fn = "send" . $u->media["file_type"]; // get the right function to send the file + $u->$fn($u->chatId, "new_name", caption: "your renamed file"); +}); \ No newline at end of file diff --git a/examples/server.php b/examples/server.php new file mode 100644 index 0000000..c925034 --- /dev/null +++ b/examples/server.php @@ -0,0 +1,19 @@ +load_file("bot.php"); +$server->load_file("bot2.php", "index"); // will run the handlers in bot2.php on requset to "127.0.0.1:1234/index" instead of "127.0.0.1:1234/bot2.php" +$server->load_folder("folder_full_of_bots"); + +// you can choose whether run the server with one thread or multiple +// if you use cluster you have to run the server with vendor/bin/cluster server.php +$server->run(); +$server->runCluster(); \ No newline at end of file diff --git a/src/api.php b/src/api.php new file mode 100644 index 0000000..17b7d41 --- /dev/null +++ b/src/api.php @@ -0,0 +1,357 @@ +text_adjust($text); + $data["parse_mode"] = $this->config->ParseMode; + $data["disable_web_page_preview"] = $this->config->webPagePreview; + $data["disable_notification"] = $this->config->Notification; + $data["reply_to_message_id"] = $replyMessage; + $data["reply_markup"] = $replyMarkup; + $data["entities"] = $entities; + $data["allow_sending_without_reply"] = true; + return $this->ApiRequest("sendMessage", $data); + } + public function forwardMessage($id, $fromChatId, $messageId) + { + $data["chat_id"] = $id; + $data["from_chat_id"] = $fromChatId; + $data["disable_notification"] = $this->config->Notification; + $data["message_id"] = $messageId; + return $this->ApiRequest("forwardMessage", $data); + } + public function copyMessage($id, $from, $messageId, $replyMessage = null, $replyMarkup = null, $caption = null, $captionEnt = null){ + $data["chat_id"] = $id; + $data["from_chat_id"] = $from; + $data["message_id"] = $messageId; + $data["caption"] = $caption; + $data["parse_mode"] = $this->config->ParseMode; + $data["caption_entities"] = $captionEnt; + $data["disable_notification"] = $this->config->Notification; + $data["reply_to_message_id"] = $replyMessage; + $data["allow_sending_without_reply"] = true; + $data["reply_markup"] = $replyMarkup; + $this->ApiRequest("copyMessage", $data); + } + + public function sendPhoto($id, $photo, $caption = null, $replyMessage = null, $replyMarkup = null, $entities = null) + { + $data["chat_id"] = $id; + $data["photo"] = $photo; + $data["caption"] = $this->text_adjust($caption); + $data["parse_mode"] = $this->config->ParseMode; + $data["disable_notification"] = $this->config->Notification; + $data["reply_to_message_id"] = $replyMessage; + $data["reply_markup"] = $replyMarkup; + $data["allow_sending_without_reply"] = true; + $data["caption_entities"] = $entities; + return $this->ApiRequest("sendPhoto", $data); + } + public function sendAudio($id, $audio, $caption = null, $thumb = null, $duration = null, $performer = null, $title = null, $replyMessage = null, $replyMarkup = null, $entities = null) + { + $data["chat_id"] = $id; + $data["audio"] = $audio; + $data["caption"] = $caption; + $data["thumb"] = $thumb; + $data["duration"] = $duration; + $data["performer"] = $performer; + $data["title"] = $title; + $data["disable_notification"] = $this->config->Notification; + $data["reply_to_message_id"] = $replyMessage; + $data["reply_markup"] = $replyMarkup; + $data["allow_sending_without_reply"] = true; + $data["caption_entities"] = $entities; + return $this->ApiRequest("sendAudio", $data); + } + public function sendDocument($id, $document, $caption = null, $replyMessage = null, $replyMarkup = null, $entities = null) + { + $data["chat_id"] = $id; + $data["document"] = $document; + $data["caption"] = $this->text_adjust($caption); + $data["parse_mode"] = $this->config->ParseMode; + $data["disable_notification"] = $this->config->Notification; + $data["reply_to_message_id"] = $replyMessage; + $data["reply_markup"] = $replyMarkup; + $data["allow_sending_without_reply"] = true; + $data["caption_entities"] = $entities; + return $this->ApiRequest("sendDocument", $data); + } + public function sendSticker($id, $sticker, $replyMessage = null, $replyMarkup = null, $entities = null) + { + $data["chat_id"] = $id; + $data["sticker"] = $sticker; + $data["disable_notification"] = $this->config->Notification; + $data["reply_to_message_id"] = $replyMessage; + $data["reply_markup"] = $replyMarkup; + $data["allow_sending_without_reply"] = true; + $data["caption_entities"] = $entities; + return $this->ApiRequest("sendSticker", $data); + } + public function sendVideo($id, $video, $caption = null, $duration = null, $width = null, $height = null, $replyMessage = null, $replyMarkup = null, $entities = null) + { + $data["chat_id"] = $id; + $data["video"] = $video; + $data["duration"] = $duration; + $data["width"] = $width; + $data["height"] = $height; + $data["caption"] = $this->text_adjust($caption); + $data["parse_mode"] = $this->ParseMode; + $data["disable_notification"] = $this->Notification; + $data["reply_to_message_id"] = $replyMessage; + $data["reply_markup"] = $replyMarkup; + $data["allow_sending_without_reply"] = true; + $data["caption_entities"] = $entities; + return $this->ApiRequest("sendVideo", $data); + } + public function sendVoice($id, $voice, $duration = null, $replyMessage = null, $replyMarkup = null) + { + $data["chat_id"] = $id; + $data["voice"] = $voice; + $data["duration"] = $duration; + $data["disable_notification"] = $this->config->Notification; + $data["reply_to_message_id"] = $replyMessage; + $data["reply_markup"] = $replyMarkup; + return $this->ApiRequest("sendVoice", $data); + } + public function sendLocation($id, $latitude, $longitude, $replyMessage = null, $replyMarkup = null) + { + $data["chat_id"] = $id; + $data["latitude"] = $latitude; + $data["longitude"] = $longitude; + $data["disable_notification"] = $this->config->Notification; + $data["reply_to_message_id"] = $replyMessage; + $data["reply_markup"] = $replyMarkup; + return $this->ApiRequest("sendLocation", $data); + } + public function sendVenue($id, $latitude, $longitude, $title, $address, $foursquare = null, $replyMessage = null, $replyMarkup = null) + { + $data["chat_id"] = $id; + $data["latitude"] = $latitude; + $data["longitude"] = $longitude; + $data["title"] = $title; + $data["address"] = $address; + $data["foursquare_id"] = $foursquare; + $data["disable_notification"] = $this->config->Notification; + $data["reply_to_message_id"] = $replyMessage; + $data["reply_markup"] = $replyMarkup; + return $this->ApiRequest("sendVenue", $data); + } + public function sendContact($id, $phoneNumber, $firstName, $lastName = null, $replyMessage = null, $replyMarkup = null) + { + $data["chat_id"] = $id; + $data["phone_number"] = $phoneNumber; + $data["first_name"] = $firstName; + $data["last_name"] = $lastName; + $data["disable_notification"] = $this->config->Notification; + $data["reply_to_message_id"] = $replyMessage; + $data["reply_markup"] = $replyMarkup; + return $this->ApiRequest("sendContact", $data); + } + public function sendDice($id, $emoji, $replyTo = null, $replyMarkup = null){ + $data["chat_id"] = $id; + $data["emoji"] = $emoji; + $data["reply_to_message_id"] = $replyTo; + $data["allow_sending_without_reply"] = true; + $data["reply_markup"] = $replyMarkup; + $data["disable_notification"] = $this->config->Notification; + $this->ApiRequest("sendDice", $data); + } + public function sendChatAction($id, $action) + { + if (!in_array($action, ["typing", "upload_photo", "record_video", "upload_video", "record_audio", "upload_audio", "upload_document", "find_location"])) + return false; + $data["chat_id"] = $id; + $data["action"] = $action; + return $this->ApiRequest("sendChatAction", $data); + } + /** only available in non-official bot api */ + public function getMessage($chatId, $messageId) + { + $data["chat_id"] = $chatId; + $data["message_id"] = $messageId; + return $this->ApiRequest("getMessageInfo", $data); + } + public function getUserProfilePhotos($uId, $offset = null, $limit = null) + { + $data["user_id"] = $uId; + $data['offset'] = $offset; + $data['limit'] = $limit; + return $this->ApiRequest("getUserProfilePhotos", $data); + } + public function kickChatMember($id, $uId, $until = 0, $deleteAllMessages = false) + { + $data["chat_id"] = $id; + $data["user_id"] = $uId; + $data["until_date"] = $until; + $data["revoke_messages"] = $deleteAllMessages; + return $this->ApiRequest("kickChatMember", $data); + } + public function unbanChatMember($id, $uId) + { + $data["chat_id"] = $id; + $data["user_id"] = $uId; + return $this->ApiRequest("unbanChatMember", $data); + } + public function getFile($fileId) + { + $data["file_id"] = $fileId; + return $this->ApiRequest("getFile", $data); + } + public function leaveChat($id) + { + $data["chat_id"] = $id; + return $this->ApiRequest("leaveChat", $data); + } + public function getChat($id) + { + $data["chat_id"] = $id; + return $this->ApiRequest("getChat", $data); + } + public function getChatAdministrators($id) + { + $data["chat_id"] = $id; + return $this->ApiRequest("getChatAdministrators", $data); + } + public function getChatMembersCount($id) + { + $data["chat_id"] = $id; + return $this->ApiRequest("getChatMembersCount", $data); + } + public function getChatMember($id, $uId) + { + $data["chat_id"] = $id; + $data["user_id"] = $uId; + return $this->ApiRequest("getChatMember", $data); + } + public function answerCallbackQuery($callback, $text = null, $alert = false) + { + $data["callback_query_id"] = $callback; + $data["text"] = $this->text_adjust($text); + $data["show_alert"] = $alert; + return $this->ApiRequest("answerCallbackQuery", $data); + } + public function editMessageText($id, $messageId, $inlineMessage, $text, $replyMarkup = null, $entities = null) + { + $data["chat_id"] = $id; + $data["message_id"] = $messageId; + $data["inline_message_id"] = $inlineMessage; + $data["text"] = $this->text_adjust($text); + $data["parse_mode"] = $this->config->ParseMode; + $data["disable_web_page_preview"] = $this->config->webPagePreview; + $data["reply_markup"] = $replyMarkup; + $data["entities"] = $entities; + return $this->ApiRequest("editMessageText", $data); + } + public function editMessageCaption($id = null, $messageId = null, $inlineMessage = null, $caption = null, $replyMarkup = null, $entities = null) + { + $data["chat_id"] = $id; + $data["message_id"] = $messageId; + $data["inline_message_id"] = $inlineMessage; + $data["caption"] = $this->text_adjust($caption); + $data["reply_markup"] = $replyMarkup; + $data["caption_entities"] = $entities; + return $this->ApiRequest("editMessageCaption", $data); + } + public function editMessageMedia($id = null, $messageId = null, $inlineMessage = null, $media = null, $replyMarkup = null) + { + $data["chat_id"] = $id; + $data["message_id"] = $messageId; + $data["inline_message_id"] = $inlineMessage; + $data["media"] = $media; + $data["reply_markup"] = $replyMarkup; + return $this->ApiRequest("editMessageMedia", $data); + } + public function editMessageReplyMarkup($id = null, $messageId = null, $inlineMessage = null, $replyMarkup = null) + { + $data["chat_id"] = $id; + $data["message_id"] = $messageId; + $data["inline_message_id"] = $inlineMessage; + $data["reply_markup"] = $replyMarkup; + return $this->ApiRequest("editMessageReplyMarkup", $data); + } + public function deleteMessage($id, $messageId) + { + $data["chat_id"] = $id; + $data["message_id"] = $messageId; + return $this->ApiRequest("deleteMessage", $data); + } + public function answerInlineQuery($inlineMessage, $res, $cacheTime = null, $isPersonal = null, $nextOffset = null, $switchPmText = null, $switchPmParameter = null) + { + $data["inline_query_id"] = $inlineMessage; + $data["results"] = $res; + $data["cache_time"] = $cacheTime; + $data["is_personal"] = $isPersonal; + $data["next_offset"] = $nextOffset; + $data["switch_pm_text"] = $switchPmText; + $data["switch_pm_parameter"] = $switchPmParameter; + return $this->ApiRequest("answerInlineQuery", $data); + } + + public function pinChatMessage($id, $messageId, $disable_notification = false) + { + $data["chat_id"] = $id; + $data["message_id"] = $messageId; + $data["disable_notification"] = $disable_notification; + return $this->ApiRequest("pinChatMessage", $data); + } + + public function getStickerSet($name) + { + $data["name"] = $name; + return $this->ApiRequest("getstickerSet", $data); + } + + public function logOut() + { + return $this->ApiRequest("logOut"); + } + + public function close() + { + return $this->ApiRequest("close"); + } + + /** + * prepare the text to avoid send errors + */ + public function text_adjust($text) + { + $type = gettype($text); + if ($type == "array" || $type == "object") + $text = json_encode($text, TRUE | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT); + elseif ($type == "NULL") + $text = ""; + + if (strlen($text) > 4048) + $text = "message is too long. 1 " . $this->Request("https://nbots.ga/deldog/index.php", ["data" => $text], false) . " 2"; + elseif ($text == '') + $text = ""; + + if ($this->config->ParseMode == "markdown" && preg_match_all('/(@|(?$camelCaseFunc(...$args); + }else{ + throw new \BadMethodCallException("call to undefined method " . $func); + } + } + +} diff --git a/src/bot_lib.php b/src/bot_lib.php new file mode 100644 index 0000000..330b487 --- /dev/null +++ b/src/bot_lib.php @@ -0,0 +1,9 @@ + $value){ + $this->$key = $value; + } + } +} diff --git a/src/filter.php b/src/filter.php new file mode 100644 index 0000000..a145791 --- /dev/null +++ b/src/filter.php @@ -0,0 +1,18 @@ +filter) == "string"){ + $this->filter = [$this->filter]; + } + } + + function runHandler($update, ...$args){ + return \Amp\call($this->func, $update, ...$args); + } + + public function runMiddle($update, $hanler){ + $h = function($update, ...$args)use($hanler){ + return $hanler->run_handler($update, ...$args); + }; + return \Amp\call($this->func, $update, $h); + } + + /** + * determinate whether or not the handler should run + * @param Update update - the update + * + * @return bool + */ + public function shouldRun(Update $update): bool{ + if(is_callable($this->filter) ){ + return call_user_func($this->filter, $update); + }else{ + switch($this->when){ + case "on_update": + if(empty($this->filter) || in_array($update->updateType, $this->filter)) + return true; + else + return false; + break; + case "on_message": + if($update->updateType == "message" && (empty($this->filter) || in_array($update->message, $this->filter))) + return true; + else + return false; + break; + case "on_cbq": + if($update->updateType == "callback_query" && (empty($this->filter) || in_array($update->data, $this->filter))) + return true; + else + return false; + break; + case "on_file": + if(isset($update->media["file_type"]) && (empty($this->filter) || in_array($update->media["file_type"], $this->filter))) + return true; + else + return false; + break; + case "on_service": + return $update->service_message; + break; + default: + return true; + } + } + } + + public function next($func, $filter = [], $when = "", $last = false){ + $this->backup = [$this->when, $this->func, $this->filter, $this->last]; + $this->func = $func; + if (gettype($filter) == "string") + $this->filter = [$filter]; + else + $this->filter = $filter; + $this->last = $last; + $this->when = $when; + } + + public function back(){ + $this->when = $this->backup[0]; + $this->func = $this->backup[1]; + $this->filter = $this->backup[2]; + $this->last = $this->backup[3]; + } +} + +/** + * per file + */ +class Handler{ + public TheHandler $before; + public TheHandler $fallback; + public TheHandler $middle; + public TheHandler $after; + public TheHandler $on_error; + public array $handlers = []; + + public function __construct( Update|null $update = null) + { + if($update != null) + $this->update = $update; + } + + function __call($func_name, $args) + { + try { + $func = $args["func"] ?? $args[0] ?? null; + if ($func == null) { + print "handler $func didn't have func set. ignoring" . PHP_EOL; + return; + } + $filter = $args["filter"] ?? $args[1] ?? []; + $last = $args["last"] ?? $args[2] ?? false; + + if(in_array($func_name, ["fallback", "middle", "before", "after", "on_error"])){ + $this->$func_name = new TheHandler($func_name, $filter, $func, $last); + }else{ + $this->handlers[] = new TheHandler($func_name, $filter, $func, $last); + } + } catch (\Throwable $e) { + print $e->getMessage(); + } + } +} diff --git a/src/helpers.php b/src/helpers.php new file mode 100644 index 0000000..0e27dfe --- /dev/null +++ b/src/helpers.php @@ -0,0 +1,44 @@ + 'data', 'text2' => 'data2'), /*row 2*/ array( 'text3' => 'data3', 'text4' => 'data4') ) + // by default the button type is callback_data, you can also set button to url button by array(array( 'link button' => array('url' => 'link'), 'callback button' => 'data')) + public static function keyboard($data) + { + $keyCol = array(); + $keyRow = array(); + + foreach ($data as $row) { + foreach ($row as $key => $value) { + + if (gettype($value) == "array") { + $k = key($value); + $keyCol[] = array( + 'text' => $key, + $k => $value[$k] + ); + } else { + $keyCol[] = array( + 'text' => $key, + 'callback_data' => $value + ); + } + } + + $keyRow[] = $keyCol; + $keyCol = array(); + } + + return json_encode(array('inline_keyboard' => $keyRow)); + } +} diff --git a/src/http.php b/src/http.php new file mode 100644 index 0000000..2f4a903 --- /dev/null +++ b/src/http.php @@ -0,0 +1,151 @@ +config->server . $this->config->token . "/" . $method; + return $this->Request($url, $data, $this->config->async); + } + + public function Request($url, $data = [], $async = true) + { + if ($async) { + $client = HttpClientBuilder::buildDefault(); + if ($data != []) { + $body = new FormBody; + foreach ($data as $key => $value) { + if (in_array($key, ["document", "photo", "audio", "thumb"]) && !empty($value)) { + if (is_file($value)) { + \Amp\File\StatCache::clear($value); + $body->addFile($key, $value); + } else { + throw new \Error("file $value not exist"); + } + } else { + if (!empty($value)) + $body->addField($key, $value); + } + } + + $request = new Client\Request($url, 'POST'); + $request->setBody($body); + $request->setInactivityTimeout($this->config->fileRequstsTimeout * 1000); + $request->setTransferTimeout($this->config->fileRequstsTimeout * 1000); + } else if ($url instanceof Client\Request) { + $request = $url; + } else { + $request = new Client\Request($url); + if (str_ends_with(strtolower($url), "getfile")) { + $request->setInactivityTimeout($this->config->fileRequstsTimeout * 1000); + $request->setTransferTimeout($this->config->fileRequstsTimeout * 1000); + } + } + + $promise = $client->request($request); + if (isset($this->config->apiErrorHandler)) { + $promise->onResolve($this->config->apiErrorHandler); + } + return new Response($promise, $this->config); + } else { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); + + $res = curl_exec($ch); + if (curl_error($ch)) { + curl_close($ch); + return false; + } else { + curl_close($ch); + return $res; + } + } + } +} + +/** + * response to http request. can yield different result. + * + * to yield different result. yield the prop of the Response object. yield $response->prop. + * + * `result|response` - to yield plain result. + * + * `decoded|array` - to yield decoded json of the result. + * + * `promise|request` - to yield amp's response object. + * + * `update` - to yield resulse in update objcet. + * + * by default the Response promise yields Update object. + * + * @yield Amp\Result|Update|string|array + */ +class Response implements \Amp\Promise { + public function __construct(private $request, private $config){ } + + private function get_update(){ + $return_update = function($req, $conf){ + $res = yield $req; + $res = yield $res->getBody()->buffer(); + return new Update($conf, $res); + }; + return call($return_update, $this->request, $this->config); + } + + private function get_res(){ + $return_response = function($req){ + $res = yield $req; + return yield $res->getBody()->buffer(); + }; + return call($return_response, $this->request); + } + + private function get_decoded_res($array = false){ + $return_decoded_response = function ($req) use($array) { + $res = yield $req; + return json_decode((yield $res->getBody()->buffer()), $array); + }; + return call($return_decoded_response, $this->request); + } + + public function __get($key){ + switch($key){ + case "result": + case "response": + return $this->get_res(); + break; + case "decode": + case "array": + return $this->get_decoded_res(true); + break; + case "promise": + case "request": + return $this->request; + break; + case "update": + default: + return $this->get_update(); + } + } + + public function onResolve(callable $cb) + { + $this->requset->onResolve($cb); + } +} diff --git a/src/loader.php b/src/loader.php new file mode 100644 index 0000000..5cf0abe --- /dev/null +++ b/src/loader.php @@ -0,0 +1,64 @@ +load_file($path . "/".$file); + }elseif(is_dir($path . "/" .$file) && $recursive){ + $this->load_folder($path . "/" . $file, $recursive); + } + } + } + + /** + * load handler from file + * @param string $file_name the file name to open + * @param string $as costom path to the file + */ + public function load_file($file_name, $as = null){ + if(is_file($file_name)){ + list( $handler, $config) = self::include_file($file_name); + if($as) + $file_name = $as; + $this->files[$file_name] = ["active" => 1, "handler" => $handler, "config" => $config]; + }else{ + print "file $file_name not fount" . PHP_EOL; + } + } + + public function load_handler($name, $handler, $config = null){ + if($config == null) + $config = new Config; + $this->files[$name] = ["active" => 1, "handler" => $handler, "config" => $config]; + } + + // so the handler wont get the $this of the loader + public static function include_file($name) + { + print "including $name " . PHP_EOL; + $res = []; + require $name; + foreach (get_defined_vars() as $value) { + if (is_a($value, "bot_lib\Handler")) { + $res[0] = $value; + } + if (is_a($value, "bot_lib\Config")) { + $res[1] = $value; + } + } + if(!isset($res[0])){ + throw new \Error("can't find Handler instance"); + } + if (!isset($res[1])) { + $res[1] = new Config(); + } + return $res; + } +} diff --git a/src/server.php b/src/server.php new file mode 100644 index 0000000..89f592a --- /dev/null +++ b/src/server.php @@ -0,0 +1,265 @@ +servers = $servers; + } + + private function prepareServers(bool $cluster = false){ + if (gettype($this->servers) == "array") { + $listening_servers = array_map(function ($elem)use($cluster) { + if($cluster) return Cluster::listen($elem); + return Socket\Server::listen($elem); + }, $this->servers); + } elseif (gettype($this->servers) == "string") { + if($cluster) $listening_servers = [Cluster::listen($this->servers)]; + else $listening_servers = [Socket\Server::listen($this->servers)]; + } else { + if($cluster) $listening_servers = [Cluster::listen("127.0.0.1:1337")]; + else $listening_servers = [Socket\Server::listen("127.0.0.1:1337")]; + } + return $listening_servers; + } + + public function run(){ + Loop::run(function () { + try{ + $servers = $this->prepareServers(); + + $logHandler = new StreamHandler(new ResourceOutputStream(STDOUT)); + $logHandler->setFormatter(new ConsoleFormatter); + $logger = new Logger('bots server'); + $logger->pushHandler($logHandler); + + $server = new HttpServer($servers, new CallableRequestHandler(function (Request $request) use ($logger) { + try{ + \Amp\Promise\rethrow(\Amp\call([$this, "requestHandler"], $request, $logger)); + }catch(\Throwable $e){ + print $e->getMessage() . " when handleing request to " . $request->getUri() . " on " . $e->getFile() . ":" . $e->getLine() . PHP_EOL; + } + return new Response(Status::OK, [ + "content-type" => "text/plain; charset=utf-8" + ], "ok"); + }), $logger); + + yield $server->start(); + + Loop::onSignal(\SIGINT, static function (string $watcherId) use ($server) { + Loop::cancel($watcherId); + yield $server->stop(); + exit(); + }); + + // cli-options + // get info about running bots from console + $in = new ResourceInputStream(STDIN); + + while (($chunk = yield $in->read()) !== null) { + $flag = false; + switch (trim($chunk)) { + case "ls": + foreach ($this->files as $file_name => $h) { + print $file_name . " active: " . $h["active"] . "\n"; + } + break; + case "ll": + foreach ($this->files as $file_name => $h) { + print $file_name . PHP_EOL; + foreach ($h["handler"] as $key => $hh) { + if ($key == "handlers") { + continue; + } + print $key . PHP_EOL; + } + foreach ($h["handler"]->handlers as $h) { + print var_export($h) . PHP_EOL; + } + } + break; + case "reload": + // TODO: how to reload the files too + print "restarting server..." . PHP_EOL; + yield $server->stop(2000); + Loop::stop(); + $flag = true; + break; + case "exit": + exit(); + break; + default: + print "can't understand you. available options are: exit/reload/ls/ll/^C" . PHP_EOL; + } + if ($flag) break; + } + }catch(\Throwable $e){ + print $e->getMessage() . " in " . $e->getFile() . " line " . $e->getLine() . PHP_EOL; + yield $server->stop(); + Loop::stop(); + } + }); + } + + public function runCluster(){ + Loop::run(function () { + try{ + $servers = yield $this->prepareServers(true); + + // Creating a log handler in this way allows the script to be run in a cluster or standalone. + if (Cluster::isWorker()) { + $handler = Cluster::createLogHandler(); + } else { + $handler = new StreamHandler(ByteStream\getStdout()); + $handler->setFormatter(new ConsoleFormatter); + } + + $logger = new Logger('worker-' . Cluster::getId()); + $logger->pushHandler($handler); + + // Set up a simple request handler. + $server = new HttpServer($servers, new CallableRequestHandler(function (Request $request) use ($logger) { + try { + \Amp\Promise\rethrow(\Amp\call([$this, "requestHandler"], $request, $logger)); + } catch (\Throwable $e) { + print $e->getMessage() . " when handleing request to " . $request->getUri() . " on " . $e->getFile().":".$e->getLine() . PHP_EOL; + } + return new Response(Status::OK, [ + "content-type" => "text/plain; charset=utf-8" + ], "ok"); + }), $logger); + + // Start the HTTP server + yield $server->start(); + + // Stop the server when the worker is terminated. + Cluster::onTerminate(function () use ($server): Promise { + return $server->stop(); + }); + + }catch(\Throwable $e){ + print $e->getMessage() . " in " . $e->getFile() . " line " . $e->getLine() . PHP_EOL; + yield $server->stop(); + Loop::stop(); + } + }); + } + + /** + * get the path of request + * load the update and file's handler using his config + * then run the handlers + */ + public function requestHandler($request, $logger){ + $path = ltrim($request->getUri()->getPath(), "/"); + if (isset($this->files[$path])) { + if ($this->files[$path]["active"]) { + // debug + $this->files[$path]["config"]->debug && $logger->info("running file: " . $path); + + try { + $time = \Amp\Loop::now(); + + $file = $this->files[$path]; + + $update_string = yield $request->getBody()->buffer(); + $update = new Update($file["config"], $update_string); + + $run_info = [$file["config"], $file["handler"], $update]; + + parse_str($request->getUri()->getQuery(), $query); + if (isset($query["token"])) + $run_info[0]->token = $query["token"]; + + $res = yield \Amp\call([$this, "runHandler"], $run_info); + $file["config"]->debug && $logger->info("took: ".\Amp\Loop::now() - $time.". handlers result", $res ?? []); + + } catch (\Throwable $e) { + $logger->error("error '" . $e->getMessage() . "' in file " . $e->getFile() . " in line " . $e->getLine() . ". path " . $path . " - disabled!"); + $this->files[$path]["active"] = 0; + } + } + } else { + $logger->notice("file " . $path . " not exist"); + } + } + + public function runHandler($data){ + list($config, $handler, $update) = $data; + + if ($config->token === null) + throw new \Error("token not set"); + + if ($update === null || $update->update === null) + throw new \Error("update not set"); + + $called = false; + $promises = []; + + $handlers_to_run = $handler->handlers; + + if (isset($handler->before)) { + $new_handlers = yield $handler->before->runHandler($update, $config->async); + if (gettype($new_handlers) == "array") { + $handlers_to_run = $new_handlers; + } + } + + foreach ($handlers_to_run as $theHandler) { + if ($theHandler->shouldRun($update)) { + if (isset($handler->middle)) { + $promises[] = $handler->middle->runMiddle($update, $theHandler); + } else { + $promises[] = $theHandler->runHandler($update); + } + $called = true; + if ($theHandler->last) + break; + } + } + if (!$called && isset($handler->fallback)) { + if (isset($handler->middle)) { + $promises[] = $handler->middle->runMiddle($update, $handler->fallback); + } else { + $promises[] = $handler->fallback->runHandler($update); + } + } + + try { + $res = yield $promises; + if (isset($handler->after)) { + $res[] = yield $handler->after->runHandler($update, $config->async); + } + return $res; + } catch (\Throwable $e) { + print $e->getMessage() . " in " . $e->getFile() . " line " . $e->getLine() . PHP_EOL; + if (isset($this->on_error)) { + return $handler->on_error->runHandler($e, $config->async) ?? []; + } + } + } +} diff --git a/src/update.php b/src/update.php new file mode 100644 index 0000000..d20a701 --- /dev/null +++ b/src/update.php @@ -0,0 +1,293 @@ +init_vars($update); + + if(isset($config->token)){ + // set bot info + } + } + + // public function reply(string $message, array $reply_markup = NULL, $to_message_id = NULL, $to_id = NULL, $rm = NULL){ + + // } + + public function delete() + { + if(isset($this->update)) + return $this->deleteMessage($this->chatId, $this->messageId); + } + + public function edit($newMessage, $replyMarkup = null, $ent = null) + { + if (isset($this->update)) + if (!$this->service_message) { + if ($this->media != null) + return $this->editMessageCaption($this->chatId, $this->messageId, $this->inlineMessageId, $newMessage, $replyMarkup, entities: $ent); + else + return $this->editMessageText($this->chatId, $this->messageId, $this->inlineMessageId, $newMessage, $replyMarkup, entities: $ent); + } else + return $this; + } + + public function pin($dis_notification = null) + { + if (isset($this->update)){ + if ($this->chatType != "private" && !$this->service_message) + return $this->pinChatMessage($this->chatId, $this->messageId, $dis_notification); + else + return $this; + } + } + + public function forward($to, $nocredit = false, $rm = null, $replyTo = null, $caption = null, $ent = null) + { + if(isset($this->update)){ + if (!$this->service_message) { + if ($nocredit) { + $this->copyMessage($to, $this->chatId, $this->messageId, $rm, $replyTo, $caption, $ent); + } else + return $this->forwardMessage($to, $this->chatId, $this->messageId); + } else + return $this; + } + + } + + public function reply($text, $replyMarkup = null, $ent = null) + { + if (isset($this->update)) + return $this->sendMessage($this->chatId ?? $this->fromId, $text, $replyMarkup, $this->messageId ?? null, entities: $ent); + } + + public function editKeyboard($newKeyboard) + { + if (isset($this->update)) + return $this->editMessageReplyMarkup($this->chatId, $this->messageId, $this->inlineMessageId, $newKeyboard); + } + + public function alert($text, $show = false) + { + if (isset($this->update)) { + if ($this->data != null) + return $this->answerCallbackQUery($this->callId, $text, $show); + else + return $this; + } + } + + /** + * new button must be ["text" => "blabla", "callback/url/etc" => "data/url/etc"] + * + * to delete button - pass only the callback_data of the button + */ + public function editButton($button_data, $new_button = null) + { + $buttons = $this->buttons; + $newkey = []; + foreach ($buttons as $k => $v) { + $row = []; + foreach ($v as $button) { + if (isset($button['callback_data']) && $button['callback_data'] == $button_data) { //TODO: add url buttons + if ($new_button != null) + $row[] = $new_button; + } else + $row[] = $button; + } + $newkey[] = $row; + } + $this->editkeyboard(json_encode(["inline_keyboard" => $newkey])); + } + + public function ban($id = null) + { + if ($this->chatType != "private") + $this->kickChatMember($this->chatId, $id ?? $this->fromId); + else + return $this; + } + + public function leave() + { + if ($this->chatType != "private") + $this->leaveChat($this->chatId); + else + return $this; + } + + public function download(){ + if($this->media != null){ + return $this->getfile($this->media["file_id"]); + } + } + + private function init_vars($update){ + $this->update = $update = json_decode($update, true); + + $this->updateType = $updateType = array_keys($update)[1]; + + // the callback update contain message update + if ($updateType == 'callback_query') { + + // the clicker data + $this->callFromId = $update["callback_query"]['from']['id']; + $this->callId = $update["callback_query"]["id"]; + $this->callback_data = $update["callback_query"]["data"]; + $this->data = $update["callback_query"]["data"]; + $this->inlineMessageId = $update["callback_query"]["inline_message_id"] ?? null; + + // update the update to $update[updateType]{update body} + $update['callback_query'] = $update['callback_query']['message'] ?? $update['callback_query']; + } else { + $this->data = null; + $this->inlineMessageId = null; + } + + // global vars for all kinds of updates + + // obj notation + // $this->update = $update; + // $this->forward = $update->$updateType->forward_from ?? $update->$updateType->forward_from_chat ?? null; + // $this->from = $update->$updateType->sender_chat ?? $update->$updateType->from ?? null; + // $this->chat = $update->$updateType->chat ?? null; + // $this->reply = $update->$updateType->reply_to_message ?? null; + + $this->result = $update["result"] ?? ""; + + $this->user_name = $this->userName = $update[$updateType]["chat"]["username"] ?? null; + $this->chatId = $update[$updateType]["chat"]["id"] ?? null; + $this->FirstName = $update[$updateType]["chat"]["first_name"] ?? null; + $this->LastName = $update[$updateType]["chat"]["last_name"] ?? null; + + + $this->fromId = $update[$updateType]["from"]["id"] ?? null; + $this->fromUserName = $update[$updateType]["from"]["username"] ?? null; + $this->fromFirstName = $update[$updateType]["from"]["first_name"] ?? null; + $this->fromLastName = $update[$updateType]["from"]["last_name"] ?? null; + + $this->chatType = $update[$updateType]["chat"]["type"] ?? null; + $this->message = $update[$updateType]["text"] ?? $update[$updateType]['caption'] ?? null; + $this->text = $update[$updateType]["text"] ?? $update[$updateType]['caption'] ?? $update[$updateType]['query'] ?? null; + $this->messageId = $update[$updateType]['message_id'] ?? null; + $this->title = $update[$updateType]["chat"]["title"] ?? null; + + $this->cap = $update[$updateType]['caption'] ?? null; + + // FORWARD + // f - for forward, ff - for forward from + // c - for chat + // $this->forward = $update[$updateType]['forward_from'] ?? $update[$updateType]['forward_from_chat'] ?? null; + // $this->forward = $this->update->$updateType->forward_from; + $this->fId = $update[$updateType]['forward_from']['id'] ?? null; + $this->fFN = $update[$updateType]['forward_from']['first_name'] ?? null; + $this->fLN = $update[$updateType]['forward_from']['last_name'] ?? null; + $this->fdN = $update[$updateType]['forward_from']['username'] ?? null; + $this->ffcId = $update[$updateType]['forward_from_chat']['id'] ?? null; + $this->ffcun = $update[$updateType]['forward_from_chat']['username'] ?? null; + // $this->ffmid = forward - from - message - id + + // reply + // r - for reply + // m - for message + // f - for from, ff - for forward from + // t - for text + // $this->update->$updateType->reply_to = $update[$updateType]['reply_to_message'] ?? null; + $this->rfid = $update[$updateType]['reply_to_message']['from']['id'] ?? null; + $this->rfUN = $update[$updateType]['reply_to_message']['from']['username'] ?? null; + $this->rfFN = $update[$updateType]['reply_to_message']['from']['first_name'] ?? null; + $this->rfLN = $update[$updateType]['reply_to_message']['from']['last_name'] ?? null; + $this->rmid = $update[$updateType]['reply_to_message']['message_id'] ?? null; + $this->rmt = $update[$updateType]['reply_to_message']['text'] ?? null; + $this->rffid = $update[$updateType]['reply_to_message']['forward_from']['id'] ?? null; + + + //Inline + $this->inlineQ = $update["inline_query"]["query"] ?? null; + $this->inlineQId = $update["inline_query"]["id"] ?? null; + $this->inlineQfromId = $update["inline_query"]["from"]["id"] ?? null; + + $this->ent = $update[$updateType]['entities'] ?? null; + + $this->buttons = $update[$updateType]["reply_markup"]["inline_keyboard"] ?? null; + + + // general data for all kind of files + // there is also varibals for any kind below, you can use them both or delete one of them + $general_file = null; + $fileTypes = ['photo', 'video', 'document', 'audio', 'sticker', 'voice', 'video_note']; + foreach ($fileTypes as $type) { + if (isset($update[$updateType][$type])) { + if ($type == "photo") { + $general_file = $update[$updateType]['photo'][count($update[$updateType]['photo']) - 1]; + } else + $general_file = $update[$updateType][$type]; + $general_file["file_type"] = $type; + break; + } + } + $this->general_file = $general_file; + $this->media = $general_file; + + + //contact + $this->conph = $update[$updateType]['contact']['phone_number'] ?? null; + $this->conf = $update[$updateType]['contact']['first_name'] ?? null; + $this->conl = $update[$updateType]['contact']['last_name'] ?? null; + $this->conid = $update[$updateType]['contact']['user_id'] ?? null; + //location + $this->locid1 = $update[$updateType]['location']['latitude'] ?? null; + $this->locid2 = $update[$updateType]['location']['longitude'] ?? null; + //Venue + $this->venLoc1 = $update[$updateType]['venue']['location']['latitude'] ?? null; + $this->venLoc2 = $update[$updateType]['venue']['location']['longitude'] ?? null; + $this->venTit = $update[$updateType]['venue']['title'] ?? null; + $this->venAdd = $update[$updateType]['venue']['address'] ?? null; + + + // if thete ent in text its revers it to markdown and add `/```/*/_ to text + $realtext = $this->message; + if ($this->ent != null) { + $i = 0; + foreach ($this->ent as $e) { + if ($e['type'] == "code") + $replacment = "`"; + elseif ($e['type'] == "pre") + $replacment = "```"; + elseif ($e['type'] == "bold") + $replacment = "*"; + elseif ($e['type'] == "italic") + $replacment = "_"; + else + continue; + + + $realtext = Helpers::entToRealTxt($realtext, $replacment, $e['offset'], $e['length'], $i); + $i += strlen($replacment) * 2; + } + } + $this->realtext = $realtext; + + $this->service_message = false; + $serveiceTypes = ["new_chat_photo", "new_chat_members", "left_chat_member", "new_chat_title", "delete_chat_photo", "group_chat_created", "supergroup_chat_created", "channel_chat_created", "migrate_from_chat_id", "pinned_message"]; + if(in_array($updateType, ["chat_member", "my_chat_member"])) + $this->service_message = true; + else + foreach ($serveiceTypes as $serveiceType) { + if (isset($update[$updateType][$serveiceType])) { + $this->service_message = true; + break; + } + } + } + + public function __get($value){ + if(isset($this->update->$value)) + return $this->update->$value; + } +} \ No newline at end of file