cs-fix
This commit is contained in:
parent
72d353fff0
commit
e0b293b9a1
5
.gitignore
vendored
5
.gitignore
vendored
@ -116,3 +116,8 @@ madeline.php
|
|||||||
.vscode/*
|
.vscode/*
|
||||||
.vscode
|
.vscode
|
||||||
custom.md
|
custom.md
|
||||||
|
composer.lock
|
||||||
|
phpunit.xml
|
||||||
|
vendor
|
||||||
|
.php_cs.cache
|
||||||
|
coverage
|
||||||
|
14
.php_cs.dist
Normal file
14
.php_cs.dist
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$config = new Amp\CodeStyle\Config();
|
||||||
|
$config->getFinder()
|
||||||
|
->in(__DIR__ . '/src')
|
||||||
|
->in(__DIR__ . '/tests')
|
||||||
|
->in(__DIR__ . '/userbots')
|
||||||
|
->name(__DIR__ . '/*.php');
|
||||||
|
|
||||||
|
$cacheDir = getenv('TRAVIS') ? getenv('HOME') . '/.php-cs-fixer' : __DIR__;
|
||||||
|
|
||||||
|
$config->setCacheFile($cacheDir . '/.php_cs.cache');
|
||||||
|
|
||||||
|
return $config;
|
@ -33,7 +33,8 @@
|
|||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpdocumentor/reflection-docblock": "^3.1",
|
"phpdocumentor/reflection-docblock": "^3.1",
|
||||||
"ennexa/amp-update-cache": "dev-master",
|
"ennexa/amp-update-cache": "dev-master",
|
||||||
"phpunit/phpunit": "^8"
|
"phpunit/phpunit": "^8",
|
||||||
|
"amphp/php-cs-fixer-config": "dev-master"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"ext-libtgvoip": "Install the php-libtgvoip extension to make phone calls (https://github.com/danog/php-libtgvoip)"
|
"ext-libtgvoip": "Install the php-libtgvoip extension to make phone calls (https://github.com/danog/php-libtgvoip)"
|
||||||
@ -62,5 +63,14 @@
|
|||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/danog/dns"
|
"url": "https://github.com/danog/dns"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"scripts": {
|
||||||
|
"check": [
|
||||||
|
"@cs",
|
||||||
|
"@test"
|
||||||
|
],
|
||||||
|
"cs": "PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix -v --diff --dry-run",
|
||||||
|
"cs-fix": "PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix -v --diff",
|
||||||
|
"test": "@php -dzend.assertions=1 -dassert.exception=1 ./vendor/bin/phpunit --coverage-text"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,10 @@
|
|||||||
|
|
||||||
namespace phpseclib\Math;
|
namespace phpseclib\Math;
|
||||||
|
|
||||||
if (PHP_MAJOR_VERSION < 7 && !(class_exists(\Phar::class) && \Phar::running())) {
|
if (PHP_MAJOR_VERSION < 7 && !(\class_exists(\Phar::class) && \Phar::running())) {
|
||||||
throw new \Exception('MadelineProto requires php 7 to run natively, use phar.madelineproto.xyz to run on PHP 5.6');
|
throw new \Exception('MadelineProto requires php 7 to run natively, use phar.madelineproto.xyz to run on PHP 5.6');
|
||||||
}
|
}
|
||||||
if (defined('HHVM_VERSION')) {
|
if (\defined('HHVM_VERSION')) {
|
||||||
$engines = [['PHP64', ['OpenSSL']], ['BCMath', ['OpenSSL']], ['PHP32', ['OpenSSL']]];
|
$engines = [['PHP64', ['OpenSSL']], ['BCMath', ['OpenSSL']], ['PHP32', ['OpenSSL']]];
|
||||||
foreach ($engines as $engine) {
|
foreach ($engines as $engine) {
|
||||||
try {
|
try {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
if (!class_exists('ReflectionGenerator')) {
|
if (!\class_exists('ReflectionGenerator')) {
|
||||||
class ReflectionGenerator
|
class ReflectionGenerator
|
||||||
{
|
{
|
||||||
private $generator;
|
private $generator;
|
||||||
|
@ -20,10 +20,10 @@
|
|||||||
namespace danog\MadelineProto;
|
namespace danog\MadelineProto;
|
||||||
|
|
||||||
use Amp\Deferred;
|
use Amp\Deferred;
|
||||||
use function Amp\File\put;
|
|
||||||
use function Amp\File\rename;
|
|
||||||
use function Amp\File\get;
|
|
||||||
use function Amp\File\exists;
|
use function Amp\File\exists;
|
||||||
|
use function Amp\File\get;
|
||||||
|
use function Amp\File\put;
|
||||||
|
use function Amp\File\rename as renameAsync;
|
||||||
|
|
||||||
class API extends APIFactory
|
class API extends APIFactory
|
||||||
{
|
{
|
||||||
@ -48,11 +48,11 @@ class API extends APIFactory
|
|||||||
$this->asyncAPIPromise = null;
|
$this->asyncAPIPromise = null;
|
||||||
});
|
});
|
||||||
$this->setInitPromise($this->__construct_async($params, $settings, $deferred));
|
$this->setInitPromise($this->__construct_async($params, $settings, $deferred));
|
||||||
foreach (get_object_vars(new APIFactory('', $this, $this->async)) as $key => $var) {
|
foreach (\get_object_vars(new APIFactory('', $this, $this->async)) as $key => $var) {
|
||||||
if (in_array($key, ['namespace', 'API', 'lua', 'async', 'asyncAPIPromise', 'methods', 'asyncInitPromise'])) {
|
if (\in_array($key, ['namespace', 'API', 'lua', 'async', 'asyncAPIPromise', 'methods', 'asyncInitPromise'])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (is_null($this->{$key})) {
|
if (\is_null($this->{$key})) {
|
||||||
$this->{$key} = new APIFactory($key, $this->API, $this->async);
|
$this->{$key} = new APIFactory($key, $this->API, $this->async);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -60,7 +60,7 @@ class API extends APIFactory
|
|||||||
|
|
||||||
public function __construct_async($params, $settings, $deferred)
|
public function __construct_async($params, $settings, $deferred)
|
||||||
{
|
{
|
||||||
if (is_string($params)) {
|
if (\is_string($params)) {
|
||||||
Logger::constructorFromSettings($settings);
|
Logger::constructorFromSettings($settings);
|
||||||
|
|
||||||
$realpaths = Serialization::realpaths($params);
|
$realpaths = Serialization::realpaths($params);
|
||||||
@ -79,32 +79,32 @@ class API extends APIFactory
|
|||||||
\danog\MadelineProto\Magic::class_exists();
|
\danog\MadelineProto\Magic::class_exists();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$unserialized = unserialize($tounserialize);
|
$unserialized = \unserialize($tounserialize);
|
||||||
} catch (\danog\MadelineProto\Bug74586Exception $e) {
|
} catch (\danog\MadelineProto\Bug74586Exception $e) {
|
||||||
class_exists('\\Volatile');
|
\class_exists('\\Volatile');
|
||||||
$tounserialize = str_replace('O:26:"danog\\MadelineProto\\Button":', 'O:35:"danog\\MadelineProto\\TL\\Types\\Button":', $tounserialize);
|
$tounserialize = \str_replace('O:26:"danog\\MadelineProto\\Button":', 'O:35:"danog\\MadelineProto\\TL\\Types\\Button":', $tounserialize);
|
||||||
foreach (['RSA', 'TL\\TLMethod', 'TL\\TLConstructor', 'MTProto', 'API', 'DataCenter', 'Connection', 'TL\\Types\\Button', 'TL\\Types\\Bytes', 'APIFactory'] as $class) {
|
foreach (['RSA', 'TL\\TLMethod', 'TL\\TLConstructor', 'MTProto', 'API', 'DataCenter', 'Connection', 'TL\\Types\\Button', 'TL\\Types\\Bytes', 'APIFactory'] as $class) {
|
||||||
class_exists('\\danog\\MadelineProto\\'.$class);
|
\class_exists('\\danog\\MadelineProto\\'.$class);
|
||||||
}
|
}
|
||||||
$unserialized = \danog\Serialization::unserialize($tounserialize);
|
$unserialized = \danog\Serialization::unserialize($tounserialize);
|
||||||
} catch (\danog\MadelineProto\Exception $e) {
|
} catch (\danog\MadelineProto\Exception $e) {
|
||||||
if ($e->getFile() === 'MadelineProto' && $e->getLine() === 1) {
|
if ($e->getFile() === 'MadelineProto' && $e->getLine() === 1) {
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
if (defined('MADELINEPROTO_TEST') && MADELINEPROTO_TEST === 'pony') {
|
if (\defined('MADELINEPROTO_TEST') && MADELINEPROTO_TEST === 'pony') {
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
class_exists('\\Volatile');
|
\class_exists('\\Volatile');
|
||||||
foreach (['RSA', 'TL\\TLMethod', 'TL\\TLConstructor', 'MTProto', 'API', 'DataCenter', 'Connection', 'TL\\Types\\Button', 'TL\\Types\\Bytes', 'APIFactory'] as $class) {
|
foreach (['RSA', 'TL\\TLMethod', 'TL\\TLConstructor', 'MTProto', 'API', 'DataCenter', 'Connection', 'TL\\Types\\Button', 'TL\\Types\\Bytes', 'APIFactory'] as $class) {
|
||||||
class_exists('\\danog\\MadelineProto\\'.$class);
|
\class_exists('\\danog\\MadelineProto\\'.$class);
|
||||||
}
|
}
|
||||||
$changed = false;
|
$changed = false;
|
||||||
if (strpos($tounserialize, 'O:26:"danog\\MadelineProto\\Button":') !== false) {
|
if (\strpos($tounserialize, 'O:26:"danog\\MadelineProto\\Button":') !== false) {
|
||||||
$tounserialize = str_replace('O:26:"danog\\MadelineProto\\Button":', 'O:35:"danog\\MadelineProto\\TL\\Types\\Button":', $tounserialize);
|
$tounserialize = \str_replace('O:26:"danog\\MadelineProto\\Button":', 'O:35:"danog\\MadelineProto\\TL\\Types\\Button":', $tounserialize);
|
||||||
$changed = true;
|
$changed = true;
|
||||||
}
|
}
|
||||||
if (strpos($e->getMessage(), "Erroneous data format for unserializing 'phpseclib\\Math\\BigInteger'") === 0) {
|
if (\strpos($e->getMessage(), "Erroneous data format for unserializing 'phpseclib\\Math\\BigInteger'") === 0) {
|
||||||
$tounserialize = str_replace('phpseclib\\Math\\BigInteger', 'phpseclib\\Math\\BigIntegor', $tounserialize);
|
$tounserialize = \str_replace('phpseclib\\Math\\BigInteger', 'phpseclib\\Math\\BigIntegor', $tounserialize);
|
||||||
$changed = true;
|
$changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,7 +170,7 @@ class API extends APIFactory
|
|||||||
$this->async = $async;
|
$this->async = $async;
|
||||||
|
|
||||||
if ($this->API) {
|
if ($this->API) {
|
||||||
if ($this->API->event_handler && class_exists($this->API->event_handler) && is_subclass_of($this->API->event_handler, '\danog\MadelineProto\EventHandler')) {
|
if ($this->API->event_handler && \class_exists($this->API->event_handler) && \is_subclass_of($this->API->event_handler, '\danog\MadelineProto\EventHandler')) {
|
||||||
$this->API->setEventHandler($this->API->event_handler);
|
$this->API->setEventHandler($this->API->event_handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -183,7 +183,7 @@ class API extends APIFactory
|
|||||||
|
|
||||||
public function __destruct()
|
public function __destruct()
|
||||||
{
|
{
|
||||||
if (\danog\MadelineProto\Magic::$has_thread && is_object(\Thread::getCurrentThread()) || Magic::is_fork()) {
|
if (\danog\MadelineProto\Magic::$has_thread && \is_object(\Thread::getCurrentThread()) || Magic::is_fork()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($this->asyncInitPromise) {
|
if ($this->asyncInitPromise) {
|
||||||
@ -209,13 +209,13 @@ class API extends APIFactory
|
|||||||
|
|
||||||
private function from_camel_case($input)
|
private function from_camel_case($input)
|
||||||
{
|
{
|
||||||
preg_match_all('!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!', $input, $matches);
|
\preg_match_all('!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!', $input, $matches);
|
||||||
$ret = $matches[0];
|
$ret = $matches[0];
|
||||||
foreach ($ret as &$match) {
|
foreach ($ret as &$match) {
|
||||||
$match = $match == strtoupper($match) ? strtolower($match) : lcfirst($match);
|
$match = $match == \strtoupper($match) ? \strtolower($match) : \lcfirst($match);
|
||||||
}
|
}
|
||||||
|
|
||||||
return implode('_', $ret);
|
return \implode('_', $ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function my_get_self()
|
public function my_get_self()
|
||||||
@ -229,15 +229,15 @@ class API extends APIFactory
|
|||||||
foreach ($this->API->get_method_namespaces() as $namespace) {
|
foreach ($this->API->get_method_namespaces() as $namespace) {
|
||||||
$this->{$namespace} = new APIFactory($namespace, $this->API, $this->async);
|
$this->{$namespace} = new APIFactory($namespace, $this->API, $this->async);
|
||||||
}
|
}
|
||||||
$methods = get_class_methods($this->API);
|
$methods = \get_class_methods($this->API);
|
||||||
foreach ($methods as $method) {
|
foreach ($methods as $method) {
|
||||||
if ($method == 'method_call_async_read') {
|
if ($method == 'method_call_async_read') {
|
||||||
unset($methods[array_search('method_call', $methods)]);
|
unset($methods[\array_search('method_call', $methods)]);
|
||||||
} elseif (stripos($method, 'async') !== false) {
|
} elseif (\stripos($method, 'async') !== false) {
|
||||||
if (strpos($method, '_async') !== false) {
|
if (\strpos($method, '_async') !== false) {
|
||||||
unset($methods[array_search(str_ireplace('_async', '', $method), $methods)]);
|
unset($methods[\array_search(\str_ireplace('_async', '', $method), $methods)]);
|
||||||
} else {
|
} else {
|
||||||
unset($methods[array_search(str_ireplace('async', '', $method), $methods)]);
|
unset($methods[\array_search(\str_ireplace('async', '', $method), $methods)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -247,24 +247,24 @@ class API extends APIFactory
|
|||||||
|
|
||||||
if ($method == 'method_call_async_read') {
|
if ($method == 'method_call_async_read') {
|
||||||
$method = 'method_call';
|
$method = 'method_call';
|
||||||
} elseif (stripos($method, 'async') !== false) {
|
} elseif (\stripos($method, 'async') !== false) {
|
||||||
if (strpos($method, '_async') !== false) {
|
if (\strpos($method, '_async') !== false) {
|
||||||
$method = str_ireplace('_async', '', $method);
|
$method = \str_ireplace('_async', '', $method);
|
||||||
} else {
|
} else {
|
||||||
$method = str_ireplace('async', '', $method);
|
$method = \str_ireplace('async', '', $method);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$actual_method = $actual_method === 'get_self_async' ? [$this, 'my_get_self'] : [$this->API, $actual_method];
|
$actual_method = $actual_method === 'get_self_async' ? [$this, 'my_get_self'] : [$this->API, $actual_method];
|
||||||
$this->methods[strtolower($method)] = $actual_method;
|
$this->methods[\strtolower($method)] = $actual_method;
|
||||||
if (strpos($method, '_') !== false) {
|
if (\strpos($method, '_') !== false) {
|
||||||
$this->methods[strtolower(str_replace('_', '', $method))] = $actual_method;
|
$this->methods[\strtolower(\str_replace('_', '', $method))] = $actual_method;
|
||||||
} else {
|
} else {
|
||||||
$this->methods[strtolower($this->from_camel_case($method))] = $actual_method;
|
$this->methods[\strtolower($this->from_camel_case($method))] = $actual_method;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->API->wrapper = $this;
|
$this->API->wrapper = $this;
|
||||||
if ($this->API->event_handler && class_exists($this->API->event_handler) && is_subclass_of($this->API->event_handler, '\danog\MadelineProto\EventHandler')) {
|
if ($this->API->event_handler && \class_exists($this->API->event_handler) && \is_subclass_of($this->API->event_handler, '\danog\MadelineProto\EventHandler')) {
|
||||||
$this->API->setEventHandler($this->API->event_handler);
|
$this->API->setEventHandler($this->API->event_handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -280,7 +280,7 @@ class API extends APIFactory
|
|||||||
$methods[] = $method['method'];
|
$methods[] = $method['method'];
|
||||||
}
|
}
|
||||||
|
|
||||||
return array_merge($methods, get_class_methods($this->API));
|
return \array_merge($methods, \get_class_methods($this->API));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function serialize($filename = null)
|
public function serialize($filename = null)
|
||||||
@ -307,12 +307,12 @@ class API extends APIFactory
|
|||||||
if ($this->API && $this->API->asyncInitPromise) {
|
if ($this->API && $this->API->asyncInitPromise) {
|
||||||
yield $this->API->initAsync();
|
yield $this->API->initAsync();
|
||||||
}
|
}
|
||||||
$this->serialized = time();
|
$this->serialized = \time();
|
||||||
$realpaths = Serialization::realpaths($filename);
|
$realpaths = Serialization::realpaths($filename);
|
||||||
Logger::log('Waiting for exclusive lock of serialization lockfile...');
|
Logger::log('Waiting for exclusive lock of serialization lockfile...');
|
||||||
|
|
||||||
$unlock = yield Tools::flock($realpaths['lockfile'], LOCK_EX);
|
$unlock = yield Tools::flock($realpaths['lockfile'], LOCK_EX);
|
||||||
|
|
||||||
Logger::log('Lock acquired, serializing');
|
Logger::log('Lock acquired, serializing');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -326,8 +326,8 @@ class API extends APIFactory
|
|||||||
$this->API->settings['logger']['logger_param'] = [$this->API, 'noop'];
|
$this->API->settings['logger']['logger_param'] = [$this->API, 'noop'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$wrote = yield put($realpaths['tempfile'], serialize($this));
|
$wrote = yield put($realpaths['tempfile'], \serialize($this));
|
||||||
yield rename($realpaths['tempfile'], $realpaths['file']);
|
yield renameAsync($realpaths['tempfile'], $realpaths['file']);
|
||||||
} finally {
|
} finally {
|
||||||
if (!$this->getting_api_id) {
|
if (!$this->getting_api_id) {
|
||||||
$this->API->settings['updates']['callback'] = $update_closure;
|
$this->API->settings['updates']['callback'] = $update_closure;
|
||||||
|
@ -139,7 +139,7 @@ class APIFactory extends AsyncConstruct
|
|||||||
public function __call($name, $arguments)
|
public function __call($name, $arguments)
|
||||||
{
|
{
|
||||||
$yielded = $this->call($this->__call_async($name, $arguments));
|
$yielded = $this->call($this->__call_async($name, $arguments));
|
||||||
$async = $this->lua === false && (is_array(end($arguments)) && isset(end($arguments)['async']) ? end($arguments)['async'] : ($this->async && $name !== 'loop'));
|
$async = $this->lua === false && (\is_array(\end($arguments)) && isset(\end($arguments)['async']) ? \end($arguments)['async'] : ($this->async && $name !== 'loop'));
|
||||||
if ($async) {
|
if ($async) {
|
||||||
return $yielded;
|
return $yielded;
|
||||||
}
|
}
|
||||||
@ -173,7 +173,7 @@ class APIFactory extends AsyncConstruct
|
|||||||
yield $this->API->initAsync();
|
yield $this->API->initAsync();
|
||||||
$this->API->logger->logger('Finished init asynchronously');
|
$this->API->logger->logger('Finished init asynchronously');
|
||||||
}
|
}
|
||||||
if (isset($this->session) && !is_null($this->session) && time() - $this->serialized > $this->API->settings['serialization']['serialization_interval']) {
|
if (isset($this->session) && !\is_null($this->session) && \time() - $this->serialized > $this->API->settings['serialization']['serialization_interval']) {
|
||||||
Logger::log("Didn't serialize in a while, doing that now...");
|
Logger::log("Didn't serialize in a while, doing that now...");
|
||||||
$this->serialize($this->session);
|
$this->serialize($this->session);
|
||||||
}
|
}
|
||||||
@ -187,18 +187,17 @@ class APIFactory extends AsyncConstruct
|
|||||||
$this->API->logger->logger('Finished init asynchronously');
|
$this->API->logger->logger('Finished init asynchronously');
|
||||||
}
|
}
|
||||||
|
|
||||||
$lower_name = strtolower($name);
|
$lower_name = \strtolower($name);
|
||||||
if ($this->namespace !== '' || !isset($this->methods[$lower_name])) {
|
if ($this->namespace !== '' || !isset($this->methods[$lower_name])) {
|
||||||
$name = $this->namespace.$name;
|
$name = $this->namespace.$name;
|
||||||
$aargs = isset($arguments[1]) && is_array($arguments[1]) ? $arguments[1] : [];
|
$aargs = isset($arguments[1]) && \is_array($arguments[1]) ? $arguments[1] : [];
|
||||||
$aargs['apifactory'] = true;
|
$aargs['apifactory'] = true;
|
||||||
$aargs['datacenter'] = $this->API->datacenter->curdc;
|
$aargs['datacenter'] = $this->API->datacenter->curdc;
|
||||||
$args = isset($arguments[0]) && is_array($arguments[0]) ? $arguments[0] : [];
|
$args = isset($arguments[0]) && \is_array($arguments[0]) ? $arguments[0] : [];
|
||||||
|
|
||||||
return yield $this->API->method_call_async_read($name, $args, $aargs);
|
return yield $this->API->method_call_async_read($name, $args, $aargs);
|
||||||
} else {
|
|
||||||
return yield $this->methods[$lower_name](...$arguments);
|
|
||||||
}
|
}
|
||||||
|
return yield $this->methods[$lower_name](...$arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function &__get($name)
|
public function &__get($name)
|
||||||
@ -228,7 +227,7 @@ class APIFactory extends AsyncConstruct
|
|||||||
$this->API->init();
|
$this->API->init();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->API->__construct(array_replace_recursive($this->API->settings, $value));
|
return $this->API->__construct(\array_replace_recursive($this->API->settings, $value));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->API->storage[$name] = $value;
|
return $this->API->storage[$name] = $value;
|
||||||
|
@ -26,7 +26,7 @@ class Absolute
|
|||||||
{
|
{
|
||||||
public static function absolute($file)
|
public static function absolute($file)
|
||||||
{
|
{
|
||||||
if (($file[0] !== '/') && ($file[1] !== ':') && !in_array(substr($file, 0, 4), ['phar', 'http'])) {
|
if (($file[0] !== '/') && ($file[1] !== ':') && !\in_array(\substr($file, 0, 4), ['phar', 'http'])) {
|
||||||
$file = Magic::getcwd().'/'.$file;
|
$file = Magic::getcwd().'/'.$file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,19 +50,19 @@ class AnnotationsBuilder
|
|||||||
\danog\MadelineProto\Logger::log('Generating properties...', \danog\MadelineProto\Logger::NOTICE);
|
\danog\MadelineProto\Logger::log('Generating properties...', \danog\MadelineProto\Logger::NOTICE);
|
||||||
$fixture = DocBlockFactory::createInstance();
|
$fixture = DocBlockFactory::createInstance();
|
||||||
$class = new \ReflectionClass(APIFactory::class);
|
$class = new \ReflectionClass(APIFactory::class);
|
||||||
$content = file_get_contents($filename = $class->getFileName());
|
$content = \file_get_contents($filename = $class->getFileName());
|
||||||
foreach ($class->getProperties() as $property) {
|
foreach ($class->getProperties() as $property) {
|
||||||
if ($raw_docblock = $property->getDocComment()) {
|
if ($raw_docblock = $property->getDocComment()) {
|
||||||
$docblock = $fixture->create($raw_docblock);
|
$docblock = $fixture->create($raw_docblock);
|
||||||
if ($docblock->hasTag('internal')) {
|
if ($docblock->hasTag('internal')) {
|
||||||
$content = str_replace("\n ".$raw_docblock."\n public \$".$property->getName().';', '', $content);
|
$content = \str_replace("\n ".$raw_docblock."\n public \$".$property->getName().';', '', $content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach ($this->get_method_namespaces() as $namespace) {
|
foreach ($this->get_method_namespaces() as $namespace) {
|
||||||
$content = preg_replace('/(class( \\w+[,]?){0,}\\n{\\n)/', '${1}'." /**\n"." * @internal this is a internal property generated by build_docs.php, don't change manually\n"." *\n"." * @var {$namespace}\n"." */\n"." public \${$namespace};\n", $content);
|
$content = \preg_replace('/(class( \\w+[,]?){0,}\\n{\\n)/', '${1}'." /**\n"." * @internal this is a internal property generated by build_docs.php, don't change manually\n"." *\n"." * @var {$namespace}\n"." */\n"." public \${$namespace};\n", $content);
|
||||||
}
|
}
|
||||||
file_put_contents($filename, $content);
|
\file_put_contents($filename, $content);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -71,25 +71,25 @@ class AnnotationsBuilder
|
|||||||
private function createInternalClasses()
|
private function createInternalClasses()
|
||||||
{
|
{
|
||||||
\danog\MadelineProto\Logger::log('Creating internal classes...', \danog\MadelineProto\Logger::NOTICE);
|
\danog\MadelineProto\Logger::log('Creating internal classes...', \danog\MadelineProto\Logger::NOTICE);
|
||||||
$handle = fopen(dirname(__FILE__).'/InternalDoc.php', 'w');
|
$handle = \fopen(\dirname(__FILE__).'/InternalDoc.php', 'w');
|
||||||
foreach ($this->methods->by_id as $id => $data) {
|
foreach ($this->methods->by_id as $id => $data) {
|
||||||
if (!strpos($data['method'], '.')) {
|
if (!\strpos($data['method'], '.')) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
list($namespace, $method) = explode('.', $data['method']);
|
list($namespace, $method) = \explode('.', $data['method']);
|
||||||
if (!in_array($namespace, $this->get_method_namespaces())) {
|
if (!\in_array($namespace, $this->get_method_namespaces())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$type = str_replace(['.', '<', '>'], ['_', '_of_', ''], $data['type']);
|
$type = \str_replace(['.', '<', '>'], ['_', '_of_', ''], $data['type']);
|
||||||
foreach ($data['params'] as $param) {
|
foreach ($data['params'] as $param) {
|
||||||
if (in_array($param['name'], ['flags', 'random_id'])) {
|
if (\in_array($param['name'], ['flags', 'random_id'])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$stype = 'type';
|
$stype = 'type';
|
||||||
if (isset($param['subtype'])) {
|
if (isset($param['subtype'])) {
|
||||||
$stype = 'subtype';
|
$stype = 'subtype';
|
||||||
}
|
}
|
||||||
$ptype = str_replace('.', '_', $param[$stype]);
|
$ptype = \str_replace('.', '_', $param[$stype]);
|
||||||
switch ($ptype) {
|
switch ($ptype) {
|
||||||
case 'true':
|
case 'true':
|
||||||
case 'false':
|
case 'false':
|
||||||
@ -98,39 +98,39 @@ class AnnotationsBuilder
|
|||||||
$internalDoc[$namespace][$method]['attr'][$param['name']] = $ptype;
|
$internalDoc[$namespace][$method]['attr'][$param['name']] = $ptype;
|
||||||
}
|
}
|
||||||
if ($type === 'Bool') {
|
if ($type === 'Bool') {
|
||||||
$type = strtolower($type);
|
$type = \strtolower($type);
|
||||||
}
|
}
|
||||||
$internalDoc[$namespace][$method]['return'] = $type;
|
$internalDoc[$namespace][$method]['return'] = $type;
|
||||||
}
|
}
|
||||||
fwrite($handle, "<?php\n");
|
\fwrite($handle, "<?php\n");
|
||||||
fwrite($handle, "/**\n");
|
\fwrite($handle, "/**\n");
|
||||||
fwrite($handle, " * This file is automatic generated by build_docs.php file\n");
|
\fwrite($handle, " * This file is automatic generated by build_docs.php file\n");
|
||||||
fwrite($handle, " * and is used only for autocomplete in multiple IDE\n");
|
\fwrite($handle, " * and is used only for autocomplete in multiple IDE\n");
|
||||||
fwrite($handle, " * don't modify manually.\n");
|
\fwrite($handle, " * don't modify manually.\n");
|
||||||
fwrite($handle, " */\n\n");
|
\fwrite($handle, " */\n\n");
|
||||||
fwrite($handle, "namespace danog\\MadelineProto;\n");
|
\fwrite($handle, "namespace danog\\MadelineProto;\n");
|
||||||
foreach ($internalDoc as $namespace => $methods) {
|
foreach ($internalDoc as $namespace => $methods) {
|
||||||
fwrite($handle, "\ninterface {$namespace}\n{");
|
\fwrite($handle, "\ninterface {$namespace}\n{");
|
||||||
foreach ($methods as $method => $properties) {
|
foreach ($methods as $method => $properties) {
|
||||||
fwrite($handle, "\n /**\n");
|
\fwrite($handle, "\n /**\n");
|
||||||
if (isset($properties['attr'])) {
|
if (isset($properties['attr'])) {
|
||||||
fwrite($handle, " * @param array params [\n");
|
\fwrite($handle, " * @param array params [\n");
|
||||||
foreach ($properties['attr'] as $name => $type) {
|
foreach ($properties['attr'] as $name => $type) {
|
||||||
fwrite($handle, " * {$type} {$name},\n");
|
\fwrite($handle, " * {$type} {$name},\n");
|
||||||
}
|
}
|
||||||
fwrite($handle, " * ]\n");
|
\fwrite($handle, " * ]\n");
|
||||||
fwrite($handle, " *\n");
|
\fwrite($handle, " *\n");
|
||||||
}
|
}
|
||||||
fwrite($handle, " * @return {$properties['return']}\n");
|
\fwrite($handle, " * @return {$properties['return']}\n");
|
||||||
fwrite($handle, " */\n");
|
\fwrite($handle, " */\n");
|
||||||
fwrite($handle, " public function {$method}(");
|
\fwrite($handle, " public function {$method}(");
|
||||||
if (isset($properties['attr'])) {
|
if (isset($properties['attr'])) {
|
||||||
fwrite($handle, 'array $params');
|
\fwrite($handle, 'array $params');
|
||||||
}
|
}
|
||||||
fwrite($handle, ");\n");
|
\fwrite($handle, ");\n");
|
||||||
}
|
}
|
||||||
fwrite($handle, "}\n");
|
\fwrite($handle, "}\n");
|
||||||
}
|
}
|
||||||
fclose($handle);
|
\fclose($handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ class CombinedAPI
|
|||||||
|
|
||||||
public function __magic_construct($session, $paths = [])
|
public function __magic_construct($session, $paths = [])
|
||||||
{
|
{
|
||||||
set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
|
\set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
|
||||||
\danog\MadelineProto\Magic::class_exists();
|
\danog\MadelineProto\Magic::class_exists();
|
||||||
|
|
||||||
$realpaths = Serialization::realpaths($session);
|
$realpaths = Serialization::realpaths($session);
|
||||||
@ -46,23 +46,23 @@ class CombinedAPI
|
|||||||
$this->addInstance($path, $settings);
|
$this->addInstance($path, $settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file_exists($realpaths['file'])) {
|
if (\file_exists($realpaths['file'])) {
|
||||||
if (!file_exists($realpaths['lockfile'])) {
|
if (!\file_exists($realpaths['lockfile'])) {
|
||||||
touch($realpaths['lockfile']);
|
\touch($realpaths['lockfile']);
|
||||||
clearstatcache();
|
\clearstatcache();
|
||||||
}
|
}
|
||||||
$realpaths['lockfile'] = fopen($realpaths['lockfile'], 'r');
|
$realpaths['lockfile'] = \fopen($realpaths['lockfile'], 'r');
|
||||||
\danog\MadelineProto\Logger::log('Waiting for shared lock of serialization lockfile...');
|
\danog\MadelineProto\Logger::log('Waiting for shared lock of serialization lockfile...');
|
||||||
flock($realpaths['lockfile'], LOCK_SH);
|
\flock($realpaths['lockfile'], LOCK_SH);
|
||||||
\danog\MadelineProto\Logger::log('Shared lock acquired, deserializing...');
|
\danog\MadelineProto\Logger::log('Shared lock acquired, deserializing...');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$tounserialize = file_get_contents($realpaths['file']);
|
$tounserialize = \file_get_contents($realpaths['file']);
|
||||||
} finally {
|
} finally {
|
||||||
flock($realpaths['lockfile'], LOCK_UN);
|
\flock($realpaths['lockfile'], LOCK_UN);
|
||||||
fclose($realpaths['lockfile']);
|
\fclose($realpaths['lockfile']);
|
||||||
}
|
}
|
||||||
$deserialized = unserialize($tounserialize);
|
$deserialized = \unserialize($tounserialize);
|
||||||
|
|
||||||
/*foreach ($deserialized['instance_paths'] as $path) {
|
/*foreach ($deserialized['instance_paths'] as $path) {
|
||||||
$this->addInstance($path, isset($paths[$path]) ? $paths[$path] : []);
|
$this->addInstance($path, isset($paths[$path]) ? $paths[$path] : []);
|
||||||
@ -118,7 +118,7 @@ class CombinedAPI
|
|||||||
|
|
||||||
public function __destruct()
|
public function __destruct()
|
||||||
{
|
{
|
||||||
if (\danog\MadelineProto\Magic::$has_thread && is_object(\Thread::getCurrentThread()) || Magic::is_fork()) {
|
if (\danog\MadelineProto\Magic::$has_thread && \is_object(\Thread::getCurrentThread()) || Magic::is_fork()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,7 +131,7 @@ class CombinedAPI
|
|||||||
$instance->serialize();
|
$instance->serialize();
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
if (is_null($this->session)) {
|
if (\is_null($this->session)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($filename === '') {
|
if ($filename === '') {
|
||||||
@ -139,24 +139,24 @@ class CombinedAPI
|
|||||||
}
|
}
|
||||||
Logger::log(\danog\MadelineProto\Lang::$current_lang['serializing_madelineproto']);
|
Logger::log(\danog\MadelineProto\Lang::$current_lang['serializing_madelineproto']);
|
||||||
$realpaths = Serialization::realpaths($filename);
|
$realpaths = Serialization::realpaths($filename);
|
||||||
if (!file_exists($realpaths['lockfile'])) {
|
if (!\file_exists($realpaths['lockfile'])) {
|
||||||
touch($realpaths['lockfile']);
|
\touch($realpaths['lockfile']);
|
||||||
clearstatcache();
|
\clearstatcache();
|
||||||
}
|
}
|
||||||
$realpaths['lockfile'] = fopen($realpaths['lockfile'], 'w');
|
$realpaths['lockfile'] = \fopen($realpaths['lockfile'], 'w');
|
||||||
\danog\MadelineProto\Logger::log('Waiting for exclusive lock of serialization lockfile...');
|
\danog\MadelineProto\Logger::log('Waiting for exclusive lock of serialization lockfile...');
|
||||||
flock($realpaths['lockfile'], LOCK_EX);
|
\flock($realpaths['lockfile'], LOCK_EX);
|
||||||
\danog\MadelineProto\Logger::log('Lock acquired, serializing');
|
\danog\MadelineProto\Logger::log('Lock acquired, serializing');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$wrote = file_put_contents($realpaths['tempfile'], serialize(['event_handler' => $this->event_handler, 'event_handler_instance' => $this->event_handler_instance, 'instance_paths' => $this->instance_paths]));
|
$wrote = \file_put_contents($realpaths['tempfile'], \serialize(['event_handler' => $this->event_handler, 'event_handler_instance' => $this->event_handler_instance, 'instance_paths' => $this->instance_paths]));
|
||||||
rename($realpaths['tempfile'], $realpaths['file']);
|
\rename($realpaths['tempfile'], $realpaths['file']);
|
||||||
} finally {
|
} finally {
|
||||||
flock($realpaths['lockfile'], LOCK_UN);
|
\flock($realpaths['lockfile'], LOCK_UN);
|
||||||
fclose($realpaths['lockfile']);
|
\fclose($realpaths['lockfile']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->serialized = time();
|
$this->serialized = \time();
|
||||||
|
|
||||||
return $wrote;
|
return $wrote;
|
||||||
}
|
}
|
||||||
@ -170,7 +170,7 @@ class CombinedAPI
|
|||||||
}
|
}
|
||||||
public function setEventHandler($event_handler)
|
public function setEventHandler($event_handler)
|
||||||
{
|
{
|
||||||
if (!class_exists($event_handler) || !is_subclass_of($event_handler, '\danog\MadelineProto\CombinedEventHandler')) {
|
if (!\class_exists($event_handler) || !\is_subclass_of($event_handler, '\danog\MadelineProto\CombinedEventHandler')) {
|
||||||
throw new \danog\MadelineProto\Exception('Wrong event handler was defined');
|
throw new \danog\MadelineProto\Exception('Wrong event handler was defined');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,13 +188,13 @@ class CombinedAPI
|
|||||||
if ($method === 'onLoop') {
|
if ($method === 'onLoop') {
|
||||||
$this->loop_callback = [$this->event_handler_instance, 'onLoop'];
|
$this->loop_callback = [$this->event_handler_instance, 'onLoop'];
|
||||||
} elseif ($method === 'onAny') {
|
} elseif ($method === 'onAny') {
|
||||||
foreach (end($this->instances)->API->constructors->by_id as $constructor) {
|
foreach (\end($this->instances)->API->constructors->by_id as $constructor) {
|
||||||
if ($constructor['type'] === 'Update' && !isset($this->event_handler_methods[$constructor['predicate']])) {
|
if ($constructor['type'] === 'Update' && !isset($this->event_handler_methods[$constructor['predicate']])) {
|
||||||
$this->event_handler_methods[$constructor['predicate']] = [$this->event_handler_instance, 'onAny'];
|
$this->event_handler_methods[$constructor['predicate']] = [$this->event_handler_instance, 'onAny'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$method_name = lcfirst(substr($method, 2));
|
$method_name = \lcfirst(\substr($method, 2));
|
||||||
$this->event_handler_methods[$method_name] = [$this->event_handler_instance, $method];
|
$this->event_handler_methods[$method_name] = [$this->event_handler_instance, $method];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -228,7 +228,7 @@ class CombinedAPI
|
|||||||
|
|
||||||
public function loop($max_forks = 0)
|
public function loop($max_forks = 0)
|
||||||
{
|
{
|
||||||
if (is_callable($max_forks)) {
|
if (\is_callable($max_forks)) {
|
||||||
return $this->wait($max_forks());
|
return $this->wait($max_forks());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ abstract class CombinedEventHandler
|
|||||||
|
|
||||||
final public function __sleep()
|
final public function __sleep()
|
||||||
{
|
{
|
||||||
$keys = method_exists($this, '__magic_sleep') ? $this->__magic_sleep() : get_object_vars($this);
|
$keys = \method_exists($this, '__magic_sleep') ? $this->__magic_sleep() : \get_object_vars($this);
|
||||||
unset($keys['CombinedAPI']);
|
unset($keys['CombinedAPI']);
|
||||||
if (isset($this->CombinedAPI) && $this->CombinedAPI instanceof CombinedAPI) {
|
if (isset($this->CombinedAPI) && $this->CombinedAPI instanceof CombinedAPI) {
|
||||||
foreach ($this->CombinedAPI->instance_paths as $path) {
|
foreach ($this->CombinedAPI->instance_paths as $path) {
|
||||||
@ -47,7 +47,7 @@ abstract class CombinedEventHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return array_keys($keys);
|
return \array_keys($keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
final public function referenceInstance($path)
|
final public function referenceInstance($path)
|
||||||
|
@ -126,16 +126,16 @@ class Connection extends Session
|
|||||||
protected $datacenter;
|
protected $datacenter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connection ID
|
* Connection ID.
|
||||||
*
|
*
|
||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
private $id = 0;
|
private $id = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DC ID and connection ID concatenated
|
* DC ID and connection ID concatenated.
|
||||||
*
|
*
|
||||||
* @var
|
* @var
|
||||||
*/
|
*/
|
||||||
private $datacenterId = '';
|
private $datacenterId = '';
|
||||||
|
|
||||||
@ -237,7 +237,7 @@ class Connection extends Session
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get connection ID
|
* Get connection ID.
|
||||||
*
|
*
|
||||||
* @return integer
|
* @return integer
|
||||||
*/
|
*/
|
||||||
@ -247,7 +247,7 @@ class Connection extends Session
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get datacenter concatenated with connection ID
|
* Get datacenter concatenated with connection ID.
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
@ -277,7 +277,7 @@ class Connection extends Session
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if is a media connection
|
* Check if is a media connection.
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
@ -287,7 +287,7 @@ class Connection extends Session
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if is a CDN connection
|
* Check if is a CDN connection.
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
|
@ -41,7 +41,6 @@ use Amp\Socket\ClientTlsContext;
|
|||||||
use Amp\Socket\ConnectException;
|
use Amp\Socket\ConnectException;
|
||||||
use Amp\Socket\Socket;
|
use Amp\Socket\Socket;
|
||||||
use Amp\TimeoutException;
|
use Amp\TimeoutException;
|
||||||
use danog\MadelineProto\MTProto\AuthKey;
|
|
||||||
use danog\MadelineProto\MTProto\PermAuthKey;
|
use danog\MadelineProto\MTProto\PermAuthKey;
|
||||||
use danog\MadelineProto\MTProto\TempAuthKey;
|
use danog\MadelineProto\MTProto\TempAuthKey;
|
||||||
use danog\MadelineProto\Stream\Common\BufferedRawStream;
|
use danog\MadelineProto\Stream\Common\BufferedRawStream;
|
||||||
@ -146,10 +145,10 @@ class DataCenter
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set auth key information from saved auth array
|
* Set auth key information from saved auth array.
|
||||||
*
|
*
|
||||||
* @param array $saved Saved auth array
|
* @param array $saved Saved auth array
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function setDataCenterConnections(array $saved)
|
public function setDataCenterConnections(array $saved)
|
||||||
@ -827,7 +826,7 @@ class DataCenter
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Connection instance for authorization
|
* Get Connection instance for authorization.
|
||||||
*
|
*
|
||||||
* @param string $dc DC ID
|
* @param string $dc DC ID
|
||||||
*
|
*
|
||||||
@ -882,10 +881,10 @@ class DataCenter
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if connected to datacenter using HTTP
|
* Check if connected to datacenter using HTTP.
|
||||||
*
|
*
|
||||||
* @param string $datacenter DC ID
|
* @param string $datacenter DC ID
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function isHttp(string $datacenter)
|
public function isHttp(string $datacenter)
|
||||||
@ -894,7 +893,7 @@ class DataCenter
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all DCs
|
* Get all DCs.
|
||||||
*
|
*
|
||||||
* @param boolean $all
|
* @param boolean $all
|
||||||
* @return void
|
* @return void
|
||||||
|
@ -32,7 +32,7 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
const READ_WEIGHT = 1;
|
const READ_WEIGHT = 1;
|
||||||
const READ_WEIGHT_MEDIA = 5;
|
const READ_WEIGHT_MEDIA = 5;
|
||||||
const WRITE_WEIGHT = 10;
|
const WRITE_WEIGHT = 10;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Temporary auth key.
|
* Temporary auth key.
|
||||||
*
|
*
|
||||||
@ -266,7 +266,7 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Create MTProto sessions if needed
|
* Create MTProto sessions if needed.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
@ -329,7 +329,7 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
if ($id === -1 || !isset($this->connections[$id])) {
|
if ($id === -1 || !isset($this->connections[$id])) {
|
||||||
$this->connections = [];
|
$this->connections = [];
|
||||||
$this->availableConnections = [];
|
$this->availableConnections = [];
|
||||||
|
|
||||||
yield $this->connectMore($count);
|
yield $this->connectMore($count);
|
||||||
} else {
|
} else {
|
||||||
yield $this->connections[$id]->connect($ctx);
|
yield $this->connections[$id]->connect($ctx);
|
||||||
@ -337,16 +337,16 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect to the DC using count more sockets
|
* Connect to the DC using count more sockets.
|
||||||
*
|
*
|
||||||
* @param integer $count Number of sockets to open
|
* @param integer $count Number of sockets to open
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
private function connectMore(int $count)
|
private function connectMore(int $count)
|
||||||
{
|
{
|
||||||
$ctx = $this->ctx->getCtx();
|
$ctx = $this->ctx->getCtx();
|
||||||
$count += $previousCount = count($this->connections);
|
$count += $previousCount = \count($this->connections);
|
||||||
for ($x = $previousCount; $x < $count; $x++) {
|
for ($x = $previousCount; $x < $count; $x++) {
|
||||||
$this->availableConnections[$x] = 0;
|
$this->availableConnections[$x] = 0;
|
||||||
$this->connections[$x] = new Connection();
|
$this->connections[$x] = new Connection();
|
||||||
@ -408,7 +408,7 @@ class DataCenterConnection implements JsonSerializable
|
|||||||
return $this->connections[0];
|
return $this->connections[0];
|
||||||
}
|
}
|
||||||
$max = \max($this->availableConnections);
|
$max = \max($this->availableConnections);
|
||||||
$key = array_search($max, $this->availableConnections);
|
$key = \array_search($max, $this->availableConnections);
|
||||||
|
|
||||||
// Decrease to implement round robin
|
// Decrease to implement round robin
|
||||||
$this->availableConnections[$key]--;
|
$this->availableConnections[$key]--;
|
||||||
|
@ -31,7 +31,7 @@ class DocsBuilder
|
|||||||
public function __construct($logger, $settings)
|
public function __construct($logger, $settings)
|
||||||
{
|
{
|
||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
|
\set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
|
||||||
$this->construct_TL($settings['tl_schema']);
|
$this->construct_TL($settings['tl_schema']);
|
||||||
if (isset($settings['tl_schema']['td']) && !isset($settings['tl_schema']['telegram'])) {
|
if (isset($settings['tl_schema']['td']) && !isset($settings['tl_schema']['telegram'])) {
|
||||||
$this->constructors = $this->td_constructors;
|
$this->constructors = $this->td_constructors;
|
||||||
@ -39,10 +39,10 @@ class DocsBuilder
|
|||||||
$this->td = true;
|
$this->td = true;
|
||||||
}
|
}
|
||||||
$this->settings = $settings;
|
$this->settings = $settings;
|
||||||
if (!file_exists($this->settings['output_dir'])) {
|
if (!\file_exists($this->settings['output_dir'])) {
|
||||||
mkdir($this->settings['output_dir']);
|
\mkdir($this->settings['output_dir']);
|
||||||
}
|
}
|
||||||
chdir($this->settings['output_dir']);
|
\chdir($this->settings['output_dir']);
|
||||||
$this->index = $settings['readme'] ? 'README.md' : 'index.md';
|
$this->index = $settings['readme'] ? 'README.md' : 'index.md';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,18 +51,18 @@ class DocsBuilder
|
|||||||
|
|
||||||
public function end($what)
|
public function end($what)
|
||||||
{
|
{
|
||||||
return end($what);
|
return \end($what);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function escape($hwat)
|
public function escape($hwat)
|
||||||
{
|
{
|
||||||
return str_replace('_', '\\_', $hwat);
|
return \str_replace('_', '\\_', $hwat);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function mk_docs()
|
public function mk_docs()
|
||||||
{
|
{
|
||||||
\danog\MadelineProto\Logger::log('Generating documentation index...', \danog\MadelineProto\Logger::NOTICE);
|
\danog\MadelineProto\Logger::log('Generating documentation index...', \danog\MadelineProto\Logger::NOTICE);
|
||||||
file_put_contents($this->index, '---
|
\file_put_contents($this->index, '---
|
||||||
title: '.$this->settings['title'].'
|
title: '.$this->settings['title'].'
|
||||||
description: '.$this->settings['description'].'
|
description: '.$this->settings['description'].'
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
@ -79,37 +79,37 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
[Types](types/)');
|
[Types](types/)');
|
||||||
$this->mk_methodS();
|
$this->mk_methodS();
|
||||||
$this->mk_constructors();
|
$this->mk_constructors();
|
||||||
foreach (glob('types/*') as $unlink) {
|
foreach (\glob('types/*') as $unlink) {
|
||||||
unlink($unlink);
|
\unlink($unlink);
|
||||||
}
|
}
|
||||||
if (file_exists('types')) {
|
if (\file_exists('types')) {
|
||||||
rmdir('types');
|
\rmdir('types');
|
||||||
}
|
}
|
||||||
mkdir('types');
|
\mkdir('types');
|
||||||
ksort($this->types);
|
\ksort($this->types);
|
||||||
$index = '';
|
$index = '';
|
||||||
\danog\MadelineProto\Logger::log('Generating types documentation...', \danog\MadelineProto\Logger::NOTICE);
|
\danog\MadelineProto\Logger::log('Generating types documentation...', \danog\MadelineProto\Logger::NOTICE);
|
||||||
$last_namespace = '';
|
$last_namespace = '';
|
||||||
foreach ($this->types as $otype => $keys) {
|
foreach ($this->types as $otype => $keys) {
|
||||||
$new_namespace = preg_replace('/_.*/', '', $otype);
|
$new_namespace = \preg_replace('/_.*/', '', $otype);
|
||||||
//$br = $new_namespace != $last_namespace ? '***<br><br>' : '';
|
//$br = $new_namespace != $last_namespace ? '***<br><br>' : '';
|
||||||
$type = str_replace(['.', '<', '>'], ['_', '_of_', ''], $otype);
|
$type = \str_replace(['.', '<', '>'], ['_', '_of_', ''], $otype);
|
||||||
$type = preg_replace('/.*_of_/', '', $type);
|
$type = \preg_replace('/.*_of_/', '', $type);
|
||||||
$index .= '['.str_replace('_', '\\_', $type).']('.$type.'.md)<a name="'.$type.'"></a>
|
$index .= '['.\str_replace('_', '\\_', $type).']('.$type.'.md)<a name="'.$type.'"></a>
|
||||||
|
|
||||||
';
|
';
|
||||||
$constructors = '';
|
$constructors = '';
|
||||||
foreach ($keys['constructors'] as $data) {
|
foreach ($keys['constructors'] as $data) {
|
||||||
$predicate = str_replace('.', '_', $data['predicate']).(isset($data['layer']) && $data['layer'] !== '' ? '_'.$data['layer'] : '');
|
$predicate = \str_replace('.', '_', $data['predicate']).(isset($data['layer']) && $data['layer'] !== '' ? '_'.$data['layer'] : '');
|
||||||
$md_predicate = str_replace('_', '\\_', $predicate);
|
$md_predicate = \str_replace('_', '\\_', $predicate);
|
||||||
$constructors .= '['.$md_predicate.'](../constructors/'.$predicate.'.md)
|
$constructors .= '['.$md_predicate.'](../constructors/'.$predicate.'.md)
|
||||||
|
|
||||||
';
|
';
|
||||||
}
|
}
|
||||||
$methods = '';
|
$methods = '';
|
||||||
foreach ($keys['methods'] as $data) {
|
foreach ($keys['methods'] as $data) {
|
||||||
$name = str_replace('.', '_', $data['method']);
|
$name = \str_replace('.', '_', $data['method']);
|
||||||
$md_name = str_replace('_', '->', $name);
|
$md_name = \str_replace('_', '->', $name);
|
||||||
$methods .= '[$MadelineProto->'.$md_name.'](../methods/'.$name.'.md)
|
$methods .= '[$MadelineProto->'.$md_name.'](../methods/'.$name.'.md)
|
||||||
|
|
||||||
';
|
';
|
||||||
@ -120,7 +120,7 @@ title: '.$type.'
|
|||||||
description: constructors and methods of type '.$type.'
|
description: constructors and methods of type '.$type.'
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
---
|
---
|
||||||
# Type: '.str_replace('_', '\\_', $type).'
|
# Type: '.\str_replace('_', '\\_', $type).'
|
||||||
[Back to types index](index.md)
|
[Back to types index](index.md)
|
||||||
|
|
||||||
|
|
||||||
@ -128,7 +128,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
';
|
';
|
||||||
$header .= isset($this->td_descriptions['types'][$otype]) ? $this->td_descriptions['types'][$otype].PHP_EOL.PHP_EOL : '';
|
$header .= isset($this->td_descriptions['types'][$otype]) ? $this->td_descriptions['types'][$otype].PHP_EOL.PHP_EOL : '';
|
||||||
if (!isset($this->settings['td'])) {
|
if (!isset($this->settings['td'])) {
|
||||||
if (in_array($type, ['User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputDialogPeer', 'DialogPeer', 'InputPeer', 'NotifyPeer', 'InputNotifyPeer'])) {
|
if (\in_array($type, ['User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputDialogPeer', 'DialogPeer', 'InputPeer', 'NotifyPeer', 'InputNotifyPeer'])) {
|
||||||
$header .= 'You can directly provide the [Update](Update.md) or [Message](Message.md) object here, MadelineProto will automatically extract the destination chat id.
|
$header .= 'You can directly provide the [Update](Update.md) or [Message](Message.md) object here, MadelineProto will automatically extract the destination chat id.
|
||||||
|
|
||||||
The following syntaxes can also be used:
|
The following syntaxes can also be used:
|
||||||
@ -152,7 +152,7 @@ $'.$type." = 'https://t.me/danogentili'; // t.me URLs
|
|||||||
|
|
||||||
A [Chat](Chat.md), a [User](User.md), an [InputPeer](InputPeer.md), an [InputDialogPeer](InputDialogPeer.md), an [InputNotifyPeer](InputNotifyPeer.md), an [InputUser](InputUser.md), an [InputChannel](InputChannel.md), a [Peer](Peer.md), an [DialogPeer](DialogPeer.md), [NotifyPeer](NotifyPeer.md), or a [Chat](Chat.md) object can also be used.\n\n\n";
|
A [Chat](Chat.md), a [User](User.md), an [InputPeer](InputPeer.md), an [InputDialogPeer](InputDialogPeer.md), an [InputNotifyPeer](InputNotifyPeer.md), an [InputUser](InputUser.md), an [InputChannel](InputChannel.md), a [Peer](Peer.md), an [DialogPeer](DialogPeer.md), [NotifyPeer](NotifyPeer.md), or a [Chat](Chat.md) object can also be used.\n\n\n";
|
||||||
}
|
}
|
||||||
if (in_array($type, ['InputEncryptedChat'])) {
|
if (\in_array($type, ['InputEncryptedChat'])) {
|
||||||
$header .= 'You can directly provide the [Update](Update.md) or [EncryptedMessage](EncryptedMessage.md) object here, MadelineProto will automatically extract the destination chat id.
|
$header .= 'You can directly provide the [Update](Update.md) or [EncryptedMessage](EncryptedMessage.md) object here, MadelineProto will automatically extract the destination chat id.
|
||||||
|
|
||||||
The following syntax can also be used:
|
The following syntax can also be used:
|
||||||
@ -164,7 +164,7 @@ $'.$type.' = -147286699; // Numeric chat id returned by request_secret_chat, can
|
|||||||
|
|
||||||
';
|
';
|
||||||
}
|
}
|
||||||
if (in_array($type, ['InputFile', 'InputEncryptedFile'])) {
|
if (\in_array($type, ['InputFile', 'InputEncryptedFile'])) {
|
||||||
$header .= 'The following syntax can also be used:
|
$header .= 'The following syntax can also be used:
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -174,22 +174,22 @@ $'.$type.' = \'filename.mp4\'; // The file path can also be used
|
|||||||
|
|
||||||
';
|
';
|
||||||
}
|
}
|
||||||
if (in_array($type, ['InputPhoto'])) {
|
if (\in_array($type, ['InputPhoto'])) {
|
||||||
$header .= 'You can also provide a [MessageMedia](MessageMedia.md), [Message](Message.md), [Update](Update.md), [Photo](Photo.md) here, MadelineProto will automatically convert it to the right type.
|
$header .= 'You can also provide a [MessageMedia](MessageMedia.md), [Message](Message.md), [Update](Update.md), [Photo](Photo.md) here, MadelineProto will automatically convert it to the right type.
|
||||||
|
|
||||||
';
|
';
|
||||||
}
|
}
|
||||||
if (in_array($type, ['InputDocument'])) {
|
if (\in_array($type, ['InputDocument'])) {
|
||||||
$header .= 'You can also provide a [MessageMedia](MessageMedia.md), [Message](Message.md), [Update](Update.md), [Document](Document.md) here, MadelineProto will automatically convert it to the right type.
|
$header .= 'You can also provide a [MessageMedia](MessageMedia.md), [Message](Message.md), [Update](Update.md), [Document](Document.md) here, MadelineProto will automatically convert it to the right type.
|
||||||
|
|
||||||
';
|
';
|
||||||
}
|
}
|
||||||
if (in_array($type, ['InputMedia'])) {
|
if (\in_array($type, ['InputMedia'])) {
|
||||||
$header .= 'You can also provide a [MessageMedia](MessageMedia.md), [Message](Message.md), [Update](Update.md), [Document](Document.md), [Photo](Photo.md), [InputDocument](InputDocument.md), [InputPhoto](InputPhoto.md) here, MadelineProto will automatically convert it to the right type.
|
$header .= 'You can also provide a [MessageMedia](MessageMedia.md), [Message](Message.md), [Update](Update.md), [Document](Document.md), [Photo](Photo.md), [InputDocument](InputDocument.md), [InputPhoto](InputPhoto.md) here, MadelineProto will automatically convert it to the right type.
|
||||||
|
|
||||||
';
|
';
|
||||||
}
|
}
|
||||||
if (in_array($type, ['InputMessage'])) {
|
if (\in_array($type, ['InputMessage'])) {
|
||||||
$header .= 'The following syntax can also be used:
|
$header .= 'The following syntax can also be used:
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -199,7 +199,7 @@ $'.$type.' = 142; // Numeric message ID
|
|||||||
|
|
||||||
';
|
';
|
||||||
}
|
}
|
||||||
if (in_array($type, ['KeyboardButton'])) {
|
if (\in_array($type, ['KeyboardButton'])) {
|
||||||
$header .= 'Clicking these buttons:
|
$header .= 'Clicking these buttons:
|
||||||
|
|
||||||
To click these buttons simply run the `click` method:
|
To click these buttons simply run the `click` method:
|
||||||
@ -235,7 +235,7 @@ You can also access the properties of the constructor as a normal array, for exa
|
|||||||
|
|
||||||
';
|
';
|
||||||
if (!isset($this->settings['td'])) {
|
if (!isset($this->settings['td'])) {
|
||||||
if (in_array($type, ['PhoneCall'])) {
|
if (\in_array($type, ['PhoneCall'])) {
|
||||||
$methods = '';
|
$methods = '';
|
||||||
$constructors = '';
|
$constructors = '';
|
||||||
$header .= 'This is an object of type `\\danog\\MadelineProto\\VoIP`.
|
$header .= 'This is an object of type `\\danog\\MadelineProto\\VoIP`.
|
||||||
@ -418,14 +418,14 @@ After modifying it, you must always parse the new configuration with a call to `
|
|||||||
';
|
';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (file_exists('types/'.$type.'.md')) {
|
if (\file_exists('types/'.$type.'.md')) {
|
||||||
\danog\MadelineProto\Logger::log($type);
|
\danog\MadelineProto\Logger::log($type);
|
||||||
}
|
}
|
||||||
file_put_contents('types/'.$type.'.md', $header.$constructors.$methods);
|
\file_put_contents('types/'.$type.'.md', $header.$constructors.$methods);
|
||||||
$last_namespace = $new_namespace;
|
$last_namespace = $new_namespace;
|
||||||
}
|
}
|
||||||
\danog\MadelineProto\Logger::log('Generating types index...', \danog\MadelineProto\Logger::NOTICE);
|
\danog\MadelineProto\Logger::log('Generating types index...', \danog\MadelineProto\Logger::NOTICE);
|
||||||
file_put_contents('types/'.$this->index, '---
|
\file_put_contents('types/'.$this->index, '---
|
||||||
title: Types
|
title: Types
|
||||||
description: List of types
|
description: List of types
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
@ -436,7 +436,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
|
|
||||||
'.$index);
|
'.$index);
|
||||||
\danog\MadelineProto\Logger::log('Generating additional types...', \danog\MadelineProto\Logger::NOTICE);
|
\danog\MadelineProto\Logger::log('Generating additional types...', \danog\MadelineProto\Logger::NOTICE);
|
||||||
file_put_contents('types/string.md', '---
|
\file_put_contents('types/string.md', '---
|
||||||
title: string
|
title: string
|
||||||
description: A UTF8 string of variable length
|
description: A UTF8 string of variable length
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
@ -446,7 +446,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
|
|
||||||
A UTF8 string of variable length. The total length in bytes of the string must not be bigger than 16777215.
|
A UTF8 string of variable length. The total length in bytes of the string must not be bigger than 16777215.
|
||||||
');
|
');
|
||||||
file_put_contents('types/bytes.md', '---
|
\file_put_contents('types/bytes.md', '---
|
||||||
title: bytes
|
title: bytes
|
||||||
description: A string of variable length
|
description: A string of variable length
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
@ -464,7 +464,7 @@ When JSON-serialized, turns into an array of the following format:
|
|||||||
];
|
];
|
||||||
```
|
```
|
||||||
');
|
');
|
||||||
file_put_contents('types/int.md', '---
|
\file_put_contents('types/int.md', '---
|
||||||
title: integer
|
title: integer
|
||||||
description: A 32 bit signed integer ranging from -2147483648 to 2147483647
|
description: A 32 bit signed integer ranging from -2147483648 to 2147483647
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
@ -474,7 +474,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
|
|
||||||
A 32 bit signed integer ranging from `-2147483648` to `2147483647`.
|
A 32 bit signed integer ranging from `-2147483648` to `2147483647`.
|
||||||
');
|
');
|
||||||
file_put_contents('types/int53.md', '---
|
\file_put_contents('types/int53.md', '---
|
||||||
title: integer
|
title: integer
|
||||||
description: A 53 bit signed integer
|
description: A 53 bit signed integer
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
@ -484,7 +484,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
|
|
||||||
A 53 bit signed integer.
|
A 53 bit signed integer.
|
||||||
');
|
');
|
||||||
file_put_contents('types/long.md', '---
|
\file_put_contents('types/long.md', '---
|
||||||
title: long
|
title: long
|
||||||
description: A 32 bit signed integer ranging from -9223372036854775808 to 9223372036854775807
|
description: A 32 bit signed integer ranging from -9223372036854775808 to 9223372036854775807
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
@ -494,7 +494,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
|
|
||||||
A 64 bit signed integer ranging from `-9223372036854775808` to `9223372036854775807`.
|
A 64 bit signed integer ranging from `-9223372036854775808` to `9223372036854775807`.
|
||||||
');
|
');
|
||||||
file_put_contents('types/int128.md', '---
|
\file_put_contents('types/int128.md', '---
|
||||||
title: int128
|
title: int128
|
||||||
description: A 128 bit signed integer
|
description: A 128 bit signed integer
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
@ -504,7 +504,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
|
|
||||||
A 128 bit signed integer represented in little-endian base256 (`string`) format.
|
A 128 bit signed integer represented in little-endian base256 (`string`) format.
|
||||||
');
|
');
|
||||||
file_put_contents('types/int256.md', '---
|
\file_put_contents('types/int256.md', '---
|
||||||
title: int256
|
title: int256
|
||||||
description: A 256 bit signed integer
|
description: A 256 bit signed integer
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
@ -514,7 +514,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
|
|
||||||
A 256 bit signed integer represented in little-endian base256 (`string`) format.
|
A 256 bit signed integer represented in little-endian base256 (`string`) format.
|
||||||
');
|
');
|
||||||
file_put_contents('types/int512.md', '---
|
\file_put_contents('types/int512.md', '---
|
||||||
title: int512
|
title: int512
|
||||||
description: A 512 bit signed integer
|
description: A 512 bit signed integer
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
@ -524,7 +524,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
|
|
||||||
A 512 bit signed integer represented in little-endian base256 (`string`) format.
|
A 512 bit signed integer represented in little-endian base256 (`string`) format.
|
||||||
');
|
');
|
||||||
file_put_contents('types/double.md', '---
|
\file_put_contents('types/double.md', '---
|
||||||
title: double
|
title: double
|
||||||
description: A double precision floating point number
|
description: A double precision floating point number
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
@ -534,7 +534,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
|
|
||||||
A double precision floating point number, single precision can also be used (float).
|
A double precision floating point number, single precision can also be used (float).
|
||||||
');
|
');
|
||||||
file_put_contents('types/!X.md', '---
|
\file_put_contents('types/!X.md', '---
|
||||||
title: !X
|
title: !X
|
||||||
description: Represents a TL serialized payload
|
description: Represents a TL serialized payload
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
@ -544,7 +544,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
|
|
||||||
Represents a TL serialized payload.
|
Represents a TL serialized payload.
|
||||||
');
|
');
|
||||||
file_put_contents('types/X.md', '---
|
\file_put_contents('types/X.md', '---
|
||||||
title: X
|
title: X
|
||||||
description: Represents a TL serialized payload
|
description: Represents a TL serialized payload
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
@ -554,7 +554,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
|
|
||||||
Represents a TL serialized payload.
|
Represents a TL serialized payload.
|
||||||
');
|
');
|
||||||
file_put_contents('constructors/boolFalse.md', '---
|
\file_put_contents('constructors/boolFalse.md', '---
|
||||||
title: boolFalse
|
title: boolFalse
|
||||||
description: Represents a boolean with value equal to false
|
description: Represents a boolean with value equal to false
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
@ -564,7 +564,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
|
|
||||||
Represents a boolean with value equal to `false`.
|
Represents a boolean with value equal to `false`.
|
||||||
');
|
');
|
||||||
file_put_contents('constructors/boolTrue.md', '---
|
\file_put_contents('constructors/boolTrue.md', '---
|
||||||
title: boolTrue
|
title: boolTrue
|
||||||
description: Represents a boolean with value equal to true
|
description: Represents a boolean with value equal to true
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
@ -574,7 +574,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
|
|
||||||
Represents a boolean with value equal to `true`.
|
Represents a boolean with value equal to `true`.
|
||||||
');
|
');
|
||||||
file_put_contents('constructors/null.md', '---
|
\file_put_contents('constructors/null.md', '---
|
||||||
title: null
|
title: null
|
||||||
description: Represents a null value
|
description: Represents a null value
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
@ -584,7 +584,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
|
|
||||||
Represents a `null` value.
|
Represents a `null` value.
|
||||||
');
|
');
|
||||||
file_put_contents('types/Bool.md', '---
|
\file_put_contents('types/Bool.md', '---
|
||||||
title: Bool
|
title: Bool
|
||||||
description: Represents a boolean.
|
description: Represents a boolean.
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
@ -594,7 +594,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
|
|
||||||
Represents a boolean.
|
Represents a boolean.
|
||||||
');
|
');
|
||||||
file_put_contents('types/DataJSON.md', '---
|
\file_put_contents('types/DataJSON.md', '---
|
||||||
title: DataJSON
|
title: DataJSON
|
||||||
description: Any json-encodable data
|
description: Any json-encodable data
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
@ -638,7 +638,7 @@ class Lang
|
|||||||
{
|
{
|
||||||
if (!isset(\danog\MadelineProto\Lang::$lang['en'][$key])) {
|
if (!isset(\danog\MadelineProto\Lang::$lang['en'][$key])) {
|
||||||
\danog\MadelineProto\Lang::$lang['en'][$key] = '';
|
\danog\MadelineProto\Lang::$lang['en'][$key] = '';
|
||||||
file_put_contents(__DIR__.'/Lang.php', sprintf($this->template, var_export(\danog\MadelineProto\Lang::$lang, true), var_export(\danog\MadelineProto\Lang::$lang['en'], true)));
|
\file_put_contents(__DIR__.'/Lang.php', \sprintf($this->template, \var_export(\danog\MadelineProto\Lang::$lang, true), \var_export(\danog\MadelineProto\Lang::$lang['en'], true)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,13 +23,13 @@ trait Constructors
|
|||||||
{
|
{
|
||||||
public function mk_constructors()
|
public function mk_constructors()
|
||||||
{
|
{
|
||||||
foreach (glob('constructors/'.$this->any) as $unlink) {
|
foreach (\glob('constructors/'.$this->any) as $unlink) {
|
||||||
unlink($unlink);
|
\unlink($unlink);
|
||||||
}
|
}
|
||||||
if (file_exists('constructors')) {
|
if (\file_exists('constructors')) {
|
||||||
rmdir('constructors');
|
\rmdir('constructors');
|
||||||
}
|
}
|
||||||
mkdir('constructors');
|
\mkdir('constructors');
|
||||||
$this->docs_constructors = [];
|
$this->docs_constructors = [];
|
||||||
$this->logger->logger('Generating constructors documentation...', \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger('Generating constructors documentation...', \danog\MadelineProto\Logger::NOTICE);
|
||||||
$got = [];
|
$got = [];
|
||||||
@ -44,19 +44,19 @@ trait Constructors
|
|||||||
$type = $this->constructors->find_by_type(str_replace('%', '', $type))['predicate'];
|
$type = $this->constructors->find_by_type(str_replace('%', '', $type))['predicate'];
|
||||||
}*/
|
}*/
|
||||||
$layer = isset($data['layer']) && $data['layer'] !== '' ? '_'.$data['layer'] : '';
|
$layer = isset($data['layer']) && $data['layer'] !== '' ? '_'.$data['layer'] : '';
|
||||||
$type = str_replace(['.', '<', '>'], ['_', '_of_', ''], $data['type']);
|
$type = \str_replace(['.', '<', '>'], ['_', '_of_', ''], $data['type']);
|
||||||
$php_type = preg_replace('/.*_of_/', '', $type);
|
$php_type = \preg_replace('/.*_of_/', '', $type);
|
||||||
$constructor = str_replace(['.', '<', '>'], ['_', '_of_', ''], $data['predicate']);
|
$constructor = \str_replace(['.', '<', '>'], ['_', '_of_', ''], $data['predicate']);
|
||||||
$php_constructor = preg_replace('/.*_of_/', '', $constructor);
|
$php_constructor = \preg_replace('/.*_of_/', '', $constructor);
|
||||||
if (!isset($this->types[$php_type])) {
|
if (!isset($this->types[$php_type])) {
|
||||||
$this->types[$php_type] = ['constructors' => [], 'methods' => []];
|
$this->types[$php_type] = ['constructors' => [], 'methods' => []];
|
||||||
}
|
}
|
||||||
if (!in_array($data, $this->types[$php_type]['constructors'])) {
|
if (!\in_array($data, $this->types[$php_type]['constructors'])) {
|
||||||
$this->types[$php_type]['constructors'][] = $data;
|
$this->types[$php_type]['constructors'][] = $data;
|
||||||
}
|
}
|
||||||
$params = '';
|
$params = '';
|
||||||
foreach ($data['params'] as $param) {
|
foreach ($data['params'] as $param) {
|
||||||
if (in_array($param['name'], ['flags', 'random_id', 'random_bytes'])) {
|
if (\in_array($param['name'], ['flags', 'random_id', 'random_bytes'])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($type === 'EncryptedMessage' && $param['name'] === 'bytes' && !isset($this->settings['td'])) {
|
if ($type === 'EncryptedMessage' && $param['name'] === 'bytes' && !isset($this->settings['td'])) {
|
||||||
@ -64,19 +64,19 @@ trait Constructors
|
|||||||
$param['type'] = 'DecryptedMessage';
|
$param['type'] = 'DecryptedMessage';
|
||||||
}
|
}
|
||||||
$type_or_subtype = isset($param['subtype']) ? 'subtype' : 'type';
|
$type_or_subtype = isset($param['subtype']) ? 'subtype' : 'type';
|
||||||
$type_or_bare_type = ctype_upper($this->end(explode('.', $param[$type_or_subtype]))[0]) || in_array($param[$type_or_subtype], ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int53', 'int', 'long', 'int128', 'int256', 'int512']) ? 'types' : 'constructors';
|
$type_or_bare_type = \ctype_upper($this->end(\explode('.', $param[$type_or_subtype]))[0]) || \in_array($param[$type_or_subtype], ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int53', 'int', 'long', 'int128', 'int256', 'int512']) ? 'types' : 'constructors';
|
||||||
$param[$type_or_subtype] = str_replace(['.', 'true', 'false'], ['_', 'Bool', 'Bool'], $param[$type_or_subtype]);
|
$param[$type_or_subtype] = \str_replace(['.', 'true', 'false'], ['_', 'Bool', 'Bool'], $param[$type_or_subtype]);
|
||||||
if (preg_match('/%/', $param[$type_or_subtype])) {
|
if (\preg_match('/%/', $param[$type_or_subtype])) {
|
||||||
$param[$type_or_subtype] = $this->constructors->find_by_type(str_replace('%', '', $param[$type_or_subtype]))['predicate'];
|
$param[$type_or_subtype] = $this->constructors->find_by_type(\str_replace('%', '', $param[$type_or_subtype]))['predicate'];
|
||||||
}
|
}
|
||||||
if (substr($param[$type_or_subtype], -1) === '>') {
|
if (\substr($param[$type_or_subtype], -1) === '>') {
|
||||||
$param[$type_or_subtype] = substr($param[$type_or_subtype], 0, -1);
|
$param[$type_or_subtype] = \substr($param[$type_or_subtype], 0, -1);
|
||||||
}
|
}
|
||||||
$params .= "'".$param['name']."' => ";
|
$params .= "'".$param['name']."' => ";
|
||||||
$param[$type_or_subtype] = '['.$this->escape($param[$type_or_subtype]).'](../'.$type_or_bare_type.'/'.$param[$type_or_subtype].'.md)';
|
$param[$type_or_subtype] = '['.$this->escape($param[$type_or_subtype]).'](../'.$type_or_bare_type.'/'.$param[$type_or_subtype].'.md)';
|
||||||
$params .= (isset($param['subtype']) ? '\\['.$param[$type_or_subtype].'\\]' : $param[$type_or_subtype]).', ';
|
$params .= (isset($param['subtype']) ? '\\['.$param[$type_or_subtype].'\\]' : $param[$type_or_subtype]).', ';
|
||||||
}
|
}
|
||||||
$md_constructor = str_replace('_', '\\_', $constructor.$layer);
|
$md_constructor = \str_replace('_', '\\_', $constructor.$layer);
|
||||||
$this->docs_constructors[$constructor] = '[$'.$md_constructor.'](../constructors/'.$php_constructor.$layer.'.md) = \\['.$params.'\\];<a name="'.$constructor.$layer.'"></a>
|
$this->docs_constructors[$constructor] = '[$'.$md_constructor.'](../constructors/'.$php_constructor.$layer.'.md) = \\['.$params.'\\];<a name="'.$constructor.$layer.'"></a>
|
||||||
|
|
||||||
';
|
';
|
||||||
@ -105,30 +105,30 @@ trait Constructors
|
|||||||
$hasreplymarkup = false;
|
$hasreplymarkup = false;
|
||||||
$hasentities = false;
|
$hasentities = false;
|
||||||
foreach ($data['params'] as $param) {
|
foreach ($data['params'] as $param) {
|
||||||
if (in_array($param['name'], ['flags', 'random_id', 'random_bytes'])) {
|
if (\in_array($param['name'], ['flags', 'random_id', 'random_bytes'])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($type === 'EncryptedMessage' && $param['name'] === 'bytes' && !isset($this->settings['td'])) {
|
if ($type === 'EncryptedMessage' && $param['name'] === 'bytes' && !isset($this->settings['td'])) {
|
||||||
$param['name'] = 'decrypted_message';
|
$param['name'] = 'decrypted_message';
|
||||||
$param['type'] = 'DecryptedMessage';
|
$param['type'] = 'DecryptedMessage';
|
||||||
}
|
}
|
||||||
if ($type === 'DecryptedMessageMedia' && in_array($param['name'], ['key', 'iv'])) {
|
if ($type === 'DecryptedMessageMedia' && \in_array($param['name'], ['key', 'iv'])) {
|
||||||
unset(\danog\MadelineProto\Lang::$lang['en']['object_'.$data['predicate'].'_param_'.$param['name'].'_type_'.$param['type']]);
|
unset(\danog\MadelineProto\Lang::$lang['en']['object_'.$data['predicate'].'_param_'.$param['name'].'_type_'.$param['type']]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$ptype = str_replace('.', '_', $param[isset($param['subtype']) ? 'subtype' : 'type']);
|
$ptype = \str_replace('.', '_', $param[isset($param['subtype']) ? 'subtype' : 'type']);
|
||||||
//$type_or_bare_type = 'types';
|
//$type_or_bare_type = 'types';
|
||||||
/*if (isset($param['subtype'])) {
|
/*if (isset($param['subtype'])) {
|
||||||
if ($param['type'] === 'vector') {
|
if ($param['type'] === 'vector') {
|
||||||
$type_or_bare_type = 'constructors';
|
$type_or_bare_type = 'constructors';
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
if (preg_match('/%/', $ptype)) {
|
if (\preg_match('/%/', $ptype)) {
|
||||||
$ptype = $this->constructors->find_by_type(str_replace('%', '', $ptype))['predicate'];
|
$ptype = $this->constructors->find_by_type(\str_replace('%', '', $ptype))['predicate'];
|
||||||
}
|
}
|
||||||
$type_or_bare_type = (ctype_upper($this->end(explode('_', $ptype))[0]) || in_array($ptype, ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int53', 'int', 'long', 'int128', 'int256', 'int512'])) && $ptype !== 'MTmessage' ? 'types' : 'constructors';
|
$type_or_bare_type = (\ctype_upper($this->end(\explode('_', $ptype))[0]) || \in_array($ptype, ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int53', 'int', 'long', 'int128', 'int256', 'int512'])) && $ptype !== 'MTmessage' ? 'types' : 'constructors';
|
||||||
if (substr($ptype, -1) === '>') {
|
if (\substr($ptype, -1) === '>') {
|
||||||
$ptype = substr($ptype, 0, -1);
|
$ptype = \substr($ptype, 0, -1);
|
||||||
}
|
}
|
||||||
switch ($ptype) {
|
switch ($ptype) {
|
||||||
case 'true':
|
case 'true':
|
||||||
@ -136,25 +136,25 @@ trait Constructors
|
|||||||
$ptype = 'Bool';
|
$ptype = 'Bool';
|
||||||
}
|
}
|
||||||
$human_ptype = $ptype;
|
$human_ptype = $ptype;
|
||||||
if (strpos($type, 'Input') === 0 && in_array($ptype, ['User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputDialogPeer', 'DialogPeer', 'NotifyPeer', 'InputNotifyPeer', 'InputPeer']) && !isset($this->settings['td'])) {
|
if (\strpos($type, 'Input') === 0 && \in_array($ptype, ['User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputDialogPeer', 'DialogPeer', 'NotifyPeer', 'InputNotifyPeer', 'InputPeer']) && !isset($this->settings['td'])) {
|
||||||
$human_ptype = 'Username, chat ID, Update, Message or '.$ptype;
|
$human_ptype = 'Username, chat ID, Update, Message or '.$ptype;
|
||||||
}
|
}
|
||||||
if (strpos($type, 'Input') === 0 && in_array($ptype, ['InputMedia', 'InputDocument', 'InputPhoto']) && !isset($this->settings['td'])) {
|
if (\strpos($type, 'Input') === 0 && \in_array($ptype, ['InputMedia', 'InputDocument', 'InputPhoto']) && !isset($this->settings['td'])) {
|
||||||
$human_ptype = 'MessageMedia, Message, Update or '.$ptype;
|
$human_ptype = 'MessageMedia, Message, Update or '.$ptype;
|
||||||
}
|
}
|
||||||
if (in_array($ptype, ['InputMessage']) && !isset($this->settings['td'])) {
|
if (\in_array($ptype, ['InputMessage']) && !isset($this->settings['td'])) {
|
||||||
$human_ptype = 'Message ID or '.$ptype;
|
$human_ptype = 'Message ID or '.$ptype;
|
||||||
}
|
}
|
||||||
if (in_array($ptype, ['InputEncryptedChat']) && !isset($this->settings['td'])) {
|
if (\in_array($ptype, ['InputEncryptedChat']) && !isset($this->settings['td'])) {
|
||||||
$human_ptype = 'Secret chat ID, Update, EncryptedMessage or '.$ptype;
|
$human_ptype = 'Secret chat ID, Update, EncryptedMessage or '.$ptype;
|
||||||
}
|
}
|
||||||
if (in_array($ptype, ['InputFile']) && !isset($this->settings['td'])) {
|
if (\in_array($ptype, ['InputFile']) && !isset($this->settings['td'])) {
|
||||||
$human_ptype = 'File path or '.$ptype;
|
$human_ptype = 'File path or '.$ptype;
|
||||||
}
|
}
|
||||||
if (in_array($ptype, ['InputEncryptedFile']) && !isset($this->settings['td'])) {
|
if (\in_array($ptype, ['InputEncryptedFile']) && !isset($this->settings['td'])) {
|
||||||
$human_ptype = 'File path or '.$ptype;
|
$human_ptype = 'File path or '.$ptype;
|
||||||
}
|
}
|
||||||
$table .= '|'.str_replace('_', '\\_', $param['name']).'|'.(isset($param['subtype']) ? 'Array of ' : '').'['.str_replace('_', '\\_', $human_ptype).'](../'.$type_or_bare_type.'/'.$ptype.'.md) | '.(isset($param['pow']) || $this->constructors->find_by_predicate(lcfirst($param['type']).'Empty') || ($data['type'] === 'InputMedia' && $param['name'] === 'mime_type') || ($data['type'] === 'DocumentAttribute' && in_array($param['name'], ['w', 'h', 'duration'])) ? 'Optional' : 'Yes').'|';
|
$table .= '|'.\str_replace('_', '\\_', $param['name']).'|'.(isset($param['subtype']) ? 'Array of ' : '').'['.\str_replace('_', '\\_', $human_ptype).'](../'.$type_or_bare_type.'/'.$ptype.'.md) | '.(isset($param['pow']) || $this->constructors->find_by_predicate(\lcfirst($param['type']).'Empty') || ($data['type'] === 'InputMedia' && $param['name'] === 'mime_type') || ($data['type'] === 'DocumentAttribute' && \in_array($param['name'], ['w', 'h', 'duration'])) ? 'Optional' : 'Yes').'|';
|
||||||
|
|
||||||
if (!isset($this->td_descriptions['constructors'][$data['predicate']]['params'][$param['name']])) {
|
if (!isset($this->td_descriptions['constructors'][$data['predicate']]['params'][$param['name']])) {
|
||||||
$this->add_to_lang('object_'.$data['predicate'].'_param_'.$param['name'].'_type_'.$param['type']);
|
$this->add_to_lang('object_'.$data['predicate'].'_param_'.$param['name'].'_type_'.$param['type']);
|
||||||
@ -166,9 +166,9 @@ trait Constructors
|
|||||||
$table .= $this->td_descriptions['constructors'][$data['predicate']]['params'][$param['name']].'|';
|
$table .= $this->td_descriptions['constructors'][$data['predicate']]['params'][$param['name']].'|';
|
||||||
}
|
}
|
||||||
$table .= PHP_EOL;
|
$table .= PHP_EOL;
|
||||||
$pptype = in_array($ptype, ['string', 'bytes']) ? "'".$ptype."'" : $ptype;
|
$pptype = \in_array($ptype, ['string', 'bytes']) ? "'".$ptype."'" : $ptype;
|
||||||
$ppptype = in_array($ptype, ['string']) ? '"'.$ptype.'"' : $ptype;
|
$ppptype = \in_array($ptype, ['string']) ? '"'.$ptype.'"' : $ptype;
|
||||||
$ppptype = in_array($ptype, ['bytes']) ? '{"_": "bytes", "bytes":"base64 encoded '.$ptype.'"}' : $ppptype;
|
$ppptype = \in_array($ptype, ['bytes']) ? '{"_": "bytes", "bytes":"base64 encoded '.$ptype.'"}' : $ppptype;
|
||||||
$params .= ", '".$param['name']."' => ";
|
$params .= ", '".$param['name']."' => ";
|
||||||
$params .= isset($param['subtype']) ? '['.$pptype.', '.$pptype.']' : $pptype;
|
$params .= isset($param['subtype']) ? '['.$pptype.', '.$pptype.']' : $pptype;
|
||||||
$lua_params .= ', '.$param['name'].'=';
|
$lua_params .= ', '.$param['name'].'=';
|
||||||
@ -187,7 +187,7 @@ title: '.$data['predicate'].'
|
|||||||
description: '.$description.'
|
description: '.$description.'
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
---
|
---
|
||||||
# Constructor: '.str_replace('_', '\\_', $data['predicate'].$layer).'
|
# Constructor: '.\str_replace('_', '\\_', $data['predicate'].$layer).'
|
||||||
[Back to constructors index](index.md)
|
[Back to constructors index](index.md)
|
||||||
|
|
||||||
|
|
||||||
@ -200,7 +200,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
if (isset($this->td_descriptions['constructors'][$data['predicate']])) {
|
if (isset($this->td_descriptions['constructors'][$data['predicate']])) {
|
||||||
$header .= $this->td_descriptions['constructors'][$data['predicate']]['description'].PHP_EOL.PHP_EOL;
|
$header .= $this->td_descriptions['constructors'][$data['predicate']]['description'].PHP_EOL.PHP_EOL;
|
||||||
}
|
}
|
||||||
$type = '### Type: ['.str_replace('_', '\\_', $php_type).'](../types/'.$php_type.'.md)
|
$type = '### Type: ['.\str_replace('_', '\\_', $php_type).'](../types/'.$php_type.'.md)
|
||||||
|
|
||||||
|
|
||||||
';
|
';
|
||||||
@ -266,19 +266,19 @@ MadelineProto supports all html entities supported by [html_entity_decode](http:
|
|||||||
';
|
';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_put_contents('constructors/'.$constructor.$layer.'.md', $header.$table.$type.$example);
|
\file_put_contents('constructors/'.$constructor.$layer.'.md', $header.$table.$type.$example);
|
||||||
}
|
}
|
||||||
$this->logger->logger('Generating constructors index...', \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger('Generating constructors index...', \danog\MadelineProto\Logger::NOTICE);
|
||||||
ksort($this->docs_constructors);
|
\ksort($this->docs_constructors);
|
||||||
$last_namespace = '';
|
$last_namespace = '';
|
||||||
foreach ($this->docs_constructors as $constructor => &$value) {
|
foreach ($this->docs_constructors as $constructor => &$value) {
|
||||||
$new_namespace = preg_replace('/_.*/', '', $constructor);
|
$new_namespace = \preg_replace('/_.*/', '', $constructor);
|
||||||
$br = $new_namespace != $last_namespace ? '***
|
$br = $new_namespace != $last_namespace ? '***
|
||||||
<br><br>' : '';
|
<br><br>' : '';
|
||||||
$value = $br.$value;
|
$value = $br.$value;
|
||||||
$last_namespace = $new_namespace;
|
$last_namespace = $new_namespace;
|
||||||
}
|
}
|
||||||
file_put_contents('constructors/'.$this->index, '---
|
\file_put_contents('constructors/'.$this->index, '---
|
||||||
title: Constructors
|
title: Constructors
|
||||||
description: List of constructors
|
description: List of constructors
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
@ -286,6 +286,6 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
# Constructors
|
# Constructors
|
||||||
[Back to API documentation index](..)
|
[Back to API documentation index](..)
|
||||||
|
|
||||||
'.implode('', $this->docs_constructors));
|
'.\implode('', $this->docs_constructors));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,9 +24,13 @@ trait Methods
|
|||||||
public function mk_methods()
|
public function mk_methods()
|
||||||
{
|
{
|
||||||
static $bots;
|
static $bots;
|
||||||
if (!$bots) $bots = json_decode(file_get_contents('https://rpc.madelineproto.xyz/bot.json'), true)['result'];
|
if (!$bots) {
|
||||||
|
$bots = \json_decode(\file_get_contents('https://rpc.madelineproto.xyz/bot.json'), true)['result'];
|
||||||
|
}
|
||||||
static $errors;
|
static $errors;
|
||||||
if (!$errors) $errors = json_decode(file_get_contents('https://rpc.madelineproto.xyz/v1.json'), true);
|
if (!$errors) {
|
||||||
|
$errors = \json_decode(\file_get_contents('https://rpc.madelineproto.xyz/v1.json'), true);
|
||||||
|
}
|
||||||
$new = ['result' => []];
|
$new = ['result' => []];
|
||||||
foreach ($errors['result'] as $code => $suberrors) {
|
foreach ($errors['result'] as $code => $suberrors) {
|
||||||
foreach ($suberrors as $method => $suberrors) {
|
foreach ($suberrors as $method => $suberrors) {
|
||||||
@ -38,30 +42,30 @@ trait Methods
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (glob('methods/'.$this->any) as $unlink) {
|
foreach (\glob('methods/'.$this->any) as $unlink) {
|
||||||
unlink($unlink);
|
\unlink($unlink);
|
||||||
}
|
}
|
||||||
if (file_exists('methods')) {
|
if (\file_exists('methods')) {
|
||||||
rmdir('methods');
|
\rmdir('methods');
|
||||||
}
|
}
|
||||||
mkdir('methods');
|
\mkdir('methods');
|
||||||
$this->docs_methods = [];
|
$this->docs_methods = [];
|
||||||
$this->human_docs_methods = [];
|
$this->human_docs_methods = [];
|
||||||
$this->logger->logger('Generating methods documentation...', \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger('Generating methods documentation...', \danog\MadelineProto\Logger::NOTICE);
|
||||||
foreach ($this->methods->by_id as $id => $data) {
|
foreach ($this->methods->by_id as $id => $data) {
|
||||||
$method = str_replace('.', '_', $data['method']);
|
$method = \str_replace('.', '_', $data['method']);
|
||||||
$php_method = str_replace('.', '->', $data['method']);
|
$php_method = \str_replace('.', '->', $data['method']);
|
||||||
$type = str_replace(['.', '<', '>'], ['_', '_of_', ''], $data['type']);
|
$type = \str_replace(['.', '<', '>'], ['_', '_of_', ''], $data['type']);
|
||||||
$php_type = preg_replace('/.*_of_/', '', $type);
|
$php_type = \preg_replace('/.*_of_/', '', $type);
|
||||||
if (!isset($this->types[$php_type])) {
|
if (!isset($this->types[$php_type])) {
|
||||||
$this->types[$php_type] = ['methods' => [], 'constructors' => []];
|
$this->types[$php_type] = ['methods' => [], 'constructors' => []];
|
||||||
}
|
}
|
||||||
if (!in_array($data, $this->types[$php_type]['methods'])) {
|
if (!\in_array($data, $this->types[$php_type]['methods'])) {
|
||||||
$this->types[$php_type]['methods'][] = $data;
|
$this->types[$php_type]['methods'][] = $data;
|
||||||
}
|
}
|
||||||
$params = '';
|
$params = '';
|
||||||
foreach ($data['params'] as $param) {
|
foreach ($data['params'] as $param) {
|
||||||
if (in_array($param['name'], ['flags', 'random_id', 'random_bytes'])) {
|
if (\in_array($param['name'], ['flags', 'random_id', 'random_bytes'])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($param['name'] === 'data' && $type === 'messages_SentEncryptedMessage' && !isset($this->settings['td'])) {
|
if ($param['name'] === 'data' && $type === 'messages_SentEncryptedMessage' && !isset($this->settings['td'])) {
|
||||||
@ -72,8 +76,8 @@ trait Methods
|
|||||||
$param['type'] = 'InputPeer';
|
$param['type'] = 'InputPeer';
|
||||||
}
|
}
|
||||||
$type_or_subtype = isset($param['subtype']) ? 'subtype' : 'type';
|
$type_or_subtype = isset($param['subtype']) ? 'subtype' : 'type';
|
||||||
$type_or_bare_type = ctype_upper($this->end(explode('.', $param[$type_or_subtype]))[0]) || in_array($param[$type_or_subtype], ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int', 'long', 'int128', 'int256', 'int512', 'int53']) ? 'types' : 'constructors';
|
$type_or_bare_type = \ctype_upper($this->end(\explode('.', $param[$type_or_subtype]))[0]) || \in_array($param[$type_or_subtype], ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int', 'long', 'int128', 'int256', 'int512', 'int53']) ? 'types' : 'constructors';
|
||||||
$param[$type_or_subtype] = str_replace(['.', 'true', 'false'], ['_', 'Bool', 'Bool'], $param[$type_or_subtype]);
|
$param[$type_or_subtype] = \str_replace(['.', 'true', 'false'], ['_', 'Bool', 'Bool'], $param[$type_or_subtype]);
|
||||||
$param[$type_or_subtype] = '['.$this->escape($param[$type_or_subtype]).'](../'.$type_or_bare_type.'/'.$param[$type_or_subtype].'.md)';
|
$param[$type_or_subtype] = '['.$this->escape($param[$type_or_subtype]).'](../'.$type_or_bare_type.'/'.$param[$type_or_subtype].'.md)';
|
||||||
$params .= "'".$param['name']."' => ".(isset($param['subtype']) ? '\\['.$param[$type_or_subtype].'\\]' : $param[$type_or_subtype]).', ';
|
$params .= "'".$param['name']."' => ".(isset($param['subtype']) ? '\\['.$param[$type_or_subtype].'\\]' : $param[$type_or_subtype]).', ';
|
||||||
}
|
}
|
||||||
@ -85,15 +89,15 @@ trait Methods
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$md_method = '['.$php_method.']('.$method.'.md)';
|
$md_method = '['.$php_method.']('.$method.'.md)';
|
||||||
$this->docs_methods[$method] = '$MadelineProto->'.$md_method.'(\\['.$params.'\\]) === [$'.str_replace('_', '\\_', $type).'](../types/'.$php_type.'.md)<a name="'.$method.'"></a>
|
$this->docs_methods[$method] = '$MadelineProto->'.$md_method.'(\\['.$params.'\\]) === [$'.\str_replace('_', '\\_', $type).'](../types/'.$php_type.'.md)<a name="'.$method.'"></a>
|
||||||
|
|
||||||
';
|
';
|
||||||
/*
|
/*
|
||||||
if (!isset(\danog\MadelineProto\MTProto::DISALLOWED_METHODS[$data['method']]) && isset($this->td_descriptions['methods'][$data['method']])) {
|
if (!isset(\danog\MadelineProto\MTProto::DISALLOWED_METHODS[$data['method']]) && isset($this->td_descriptions['methods'][$data['method']])) {
|
||||||
$this->human_docs_methods[$this->td_descriptions['methods'][$data['method']]['description'].': '.$data['method']] = '* <a href="'.$method.'.html" name="'.$method.'">'.$this->td_descriptions['methods'][$data['method']]['description'].': '.$data['method'].'</a>
|
$this->human_docs_methods[$this->td_descriptions['methods'][$data['method']]['description'].': '.$data['method']] = '* <a href="'.$method.'.html" name="'.$method.'">'.$this->td_descriptions['methods'][$data['method']]['description'].': '.$data['method'].'</a>
|
||||||
|
|
||||||
';
|
';
|
||||||
}*/
|
}*/
|
||||||
$params = '';
|
$params = '';
|
||||||
$lua_params = '';
|
$lua_params = '';
|
||||||
$pwr_params = '';
|
$pwr_params = '';
|
||||||
@ -114,7 +118,7 @@ trait Methods
|
|||||||
$hasreplymarkup = false;
|
$hasreplymarkup = false;
|
||||||
$hasmessage = false;
|
$hasmessage = false;
|
||||||
foreach ($data['params'] as $param) {
|
foreach ($data['params'] as $param) {
|
||||||
if (in_array($param['name'], ['flags', 'random_id', 'random_bytes'])) {
|
if (\in_array($param['name'], ['flags', 'random_id', 'random_bytes'])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($param['name'] === 'data' && $type === 'messages_SentEncryptedMessage' && !isset($this->settings['td'])) {
|
if ($param['name'] === 'data' && $type === 'messages_SentEncryptedMessage' && !isset($this->settings['td'])) {
|
||||||
@ -129,32 +133,32 @@ trait Methods
|
|||||||
$param['type'] = 'Vector t';
|
$param['type'] = 'Vector t';
|
||||||
$param['subtype'] = 'int';
|
$param['subtype'] = 'int';
|
||||||
}
|
}
|
||||||
$ptype = str_replace('.', '_', $param[$type_or_subtype = isset($param['subtype']) ? 'subtype' : 'type']);
|
$ptype = \str_replace('.', '_', $param[$type_or_subtype = isset($param['subtype']) ? 'subtype' : 'type']);
|
||||||
switch ($ptype) {
|
switch ($ptype) {
|
||||||
case 'true':
|
case 'true':
|
||||||
case 'false':
|
case 'false':
|
||||||
$ptype = 'Bool';
|
$ptype = 'Bool';
|
||||||
}
|
}
|
||||||
$human_ptype = $ptype;
|
$human_ptype = $ptype;
|
||||||
if (in_array($ptype, ['InputDialogPeer', 'DialogPeer', 'NotifyPeer', 'InputNotifyPeer', 'User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputPeer']) && !isset($this->settings['td'])) {
|
if (\in_array($ptype, ['InputDialogPeer', 'DialogPeer', 'NotifyPeer', 'InputNotifyPeer', 'User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputPeer']) && !isset($this->settings['td'])) {
|
||||||
$human_ptype = 'Username, chat ID, Update, Message or '.$ptype;
|
$human_ptype = 'Username, chat ID, Update, Message or '.$ptype;
|
||||||
}
|
}
|
||||||
if (in_array($ptype, ['InputMedia', 'InputPhoto', 'InputDocument']) && !isset($this->settings['td'])) {
|
if (\in_array($ptype, ['InputMedia', 'InputPhoto', 'InputDocument']) && !isset($this->settings['td'])) {
|
||||||
$human_ptype = 'MessageMedia, Update, Message or '.$ptype;
|
$human_ptype = 'MessageMedia, Update, Message or '.$ptype;
|
||||||
}
|
}
|
||||||
if (in_array($ptype, ['InputMessage']) && !isset($this->settings['td'])) {
|
if (\in_array($ptype, ['InputMessage']) && !isset($this->settings['td'])) {
|
||||||
$human_ptype = 'Message ID or '.$ptype;
|
$human_ptype = 'Message ID or '.$ptype;
|
||||||
}
|
}
|
||||||
if (in_array($ptype, ['InputEncryptedChat']) && !isset($this->settings['td'])) {
|
if (\in_array($ptype, ['InputEncryptedChat']) && !isset($this->settings['td'])) {
|
||||||
$human_ptype = 'Secret chat ID, Update, EncryptedMessage or '.$ptype;
|
$human_ptype = 'Secret chat ID, Update, EncryptedMessage or '.$ptype;
|
||||||
}
|
}
|
||||||
if (in_array($ptype, ['InputFile']) && !isset($this->settings['td'])) {
|
if (\in_array($ptype, ['InputFile']) && !isset($this->settings['td'])) {
|
||||||
$human_ptype = 'File path or '.$ptype;
|
$human_ptype = 'File path or '.$ptype;
|
||||||
}
|
}
|
||||||
if (in_array($ptype, ['InputEncryptedFile']) && !isset($this->settings['td'])) {
|
if (\in_array($ptype, ['InputEncryptedFile']) && !isset($this->settings['td'])) {
|
||||||
$human_ptype = 'File path or '.$ptype;
|
$human_ptype = 'File path or '.$ptype;
|
||||||
}
|
}
|
||||||
$type_or_bare_type = ctype_upper($this->end(explode('.', $param[$type_or_subtype]))[0]) || in_array($param[$type_or_subtype], ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int', 'long', 'int128', 'int256', 'int512', 'int53']) ? 'types' : 'constructors';
|
$type_or_bare_type = \ctype_upper($this->end(\explode('.', $param[$type_or_subtype]))[0]) || \in_array($param[$type_or_subtype], ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int', 'long', 'int128', 'int256', 'int512', 'int53']) ? 'types' : 'constructors';
|
||||||
if (!isset($this->td_descriptions['methods'][$data['method']]['params'][$param['name']])) {
|
if (!isset($this->td_descriptions['methods'][$data['method']]['params'][$param['name']])) {
|
||||||
$this->add_to_lang('method_'.$data['method'].'_param_'.$param['name'].'_type_'.$param['type']);
|
$this->add_to_lang('method_'.$data['method'].'_param_'.$param['name'].'_type_'.$param['type']);
|
||||||
if (isset($this->td_descriptions['methods'][$data['method']]['description'])) {
|
if (isset($this->td_descriptions['methods'][$data['method']]['description'])) {
|
||||||
@ -163,14 +167,14 @@ trait Methods
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isset($this->td_descriptions['methods'][$data['method']])) {
|
if (isset($this->td_descriptions['methods'][$data['method']])) {
|
||||||
$table .= '|'.str_replace('_', '\\_', $param['name']).'|'.(isset($param['subtype']) ? 'Array of ' : '').'['.str_replace('_', '\\_', $human_ptype).'](../'.$type_or_bare_type.'/'.$ptype.'.md) | '.$this->td_descriptions['methods'][$data['method']]['params'][$param['name']].' | '.(isset($param['pow']) || (($id = $this->constructors->find_by_predicate(lcfirst($param['type']).'Empty')) && $id['type'] === $param['type']) || (($id = $this->constructors->find_by_predicate('input'.$param['type'].'Empty')) && $id['type'] === $param['type']) ? 'Optional' : 'Yes').'|';
|
$table .= '|'.\str_replace('_', '\\_', $param['name']).'|'.(isset($param['subtype']) ? 'Array of ' : '').'['.\str_replace('_', '\\_', $human_ptype).'](../'.$type_or_bare_type.'/'.$ptype.'.md) | '.$this->td_descriptions['methods'][$data['method']]['params'][$param['name']].' | '.(isset($param['pow']) || (($id = $this->constructors->find_by_predicate(\lcfirst($param['type']).'Empty')) && $id['type'] === $param['type']) || (($id = $this->constructors->find_by_predicate('input'.$param['type'].'Empty')) && $id['type'] === $param['type']) ? 'Optional' : 'Yes').'|';
|
||||||
} else {
|
} else {
|
||||||
$table .= '|'.str_replace('_', '\\_', $param['name']).'|'.(isset($param['subtype']) ? 'Array of ' : '').'['.str_replace('_', '\\_', $human_ptype).'](../'.$type_or_bare_type.'/'.$ptype.'.md) | '.(isset($param['pow']) || (($id = $this->constructors->find_by_predicate(lcfirst($param['type']).'Empty')) && $id['type'] === $param['type']) || (($id = $this->constructors->find_by_predicate('input'.$param['type'].'Empty')) && $id['type'] === $param['type']) ? 'Optional' : 'Yes').'|';
|
$table .= '|'.\str_replace('_', '\\_', $param['name']).'|'.(isset($param['subtype']) ? 'Array of ' : '').'['.\str_replace('_', '\\_', $human_ptype).'](../'.$type_or_bare_type.'/'.$ptype.'.md) | '.(isset($param['pow']) || (($id = $this->constructors->find_by_predicate(\lcfirst($param['type']).'Empty')) && $id['type'] === $param['type']) || (($id = $this->constructors->find_by_predicate('input'.$param['type'].'Empty')) && $id['type'] === $param['type']) ? 'Optional' : 'Yes').'|';
|
||||||
}
|
}
|
||||||
$table .= PHP_EOL;
|
$table .= PHP_EOL;
|
||||||
$pptype = in_array($ptype, ['string', 'bytes']) ? "'".$ptype."'" : $ptype;
|
$pptype = \in_array($ptype, ['string', 'bytes']) ? "'".$ptype."'" : $ptype;
|
||||||
$ppptype = in_array($ptype, ['string']) ? '"'.$ptype.'"' : $ptype;
|
$ppptype = \in_array($ptype, ['string']) ? '"'.$ptype.'"' : $ptype;
|
||||||
$ppptype = in_array($ptype, ['bytes']) ? '{"_": "bytes", "bytes":"base64 encoded '.$ptype.'"}' : $ppptype;
|
$ppptype = \in_array($ptype, ['bytes']) ? '{"_": "bytes", "bytes":"base64 encoded '.$ptype.'"}' : $ppptype;
|
||||||
|
|
||||||
$params .= "'".$param['name']."' => ";
|
$params .= "'".$param['name']."' => ";
|
||||||
$params .= (isset($param['subtype']) ? '['.$pptype.', '.$pptype.']' : $pptype).', ';
|
$params .= (isset($param['subtype']) ? '['.$pptype.', '.$pptype.']' : $pptype).', ';
|
||||||
@ -200,17 +204,17 @@ title: '.$data['method'].'
|
|||||||
description: '.$description.'
|
description: '.$description.'
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
---
|
---
|
||||||
# Method: '.str_replace('_', '\\_', $data['method']).'
|
# Method: '.\str_replace('_', '\\_', $data['method']).'
|
||||||
[Back to methods index](index.md)
|
[Back to methods index](index.md)
|
||||||
|
|
||||||
|
|
||||||
';
|
';
|
||||||
/*
|
/*
|
||||||
if (isset(\danog\MadelineProto\MTProto::DISALLOWED_METHODS[$data['method']])) {
|
if (isset(\danog\MadelineProto\MTProto::DISALLOWED_METHODS[$data['method']])) {
|
||||||
$header .= '**'.\danog\MadelineProto\MTProto::DISALLOWED_METHODS[$data['method']]."**\n\n\n\n\n";
|
$header .= '**'.\danog\MadelineProto\MTProto::DISALLOWED_METHODS[$data['method']]."**\n\n\n\n\n";
|
||||||
file_put_contents('methods/'.$method.'.md', $header);
|
file_put_contents('methods/'.$method.'.md', $header);
|
||||||
continue;
|
continue;
|
||||||
}*/
|
}*/
|
||||||
if ($this->td) {
|
if ($this->td) {
|
||||||
$header .= 'YOU CANNOT USE THIS METHOD IN MADELINEPROTO
|
$header .= 'YOU CANNOT USE THIS METHOD IN MADELINEPROTO
|
||||||
|
|
||||||
@ -221,14 +225,14 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
$table .= '
|
$table .= '
|
||||||
|
|
||||||
';
|
';
|
||||||
$return = '### Return type: ['.str_replace('_', '\\_', $type).'](../types/'.$php_type.'.md)
|
$return = '### Return type: ['.\str_replace('_', '\\_', $type).'](../types/'.$php_type.'.md)
|
||||||
|
|
||||||
';
|
';
|
||||||
$bot = !in_array($data['method'], $bots);
|
$bot = !\in_array($data['method'], $bots);
|
||||||
$example = '';
|
$example = '';
|
||||||
if (!isset($this->settings['td'])) {
|
if (!isset($this->settings['td'])) {
|
||||||
$example .= '### Can bots use this method: **'.($bot ? 'YES' : 'NO')."**\n\n\n";
|
$example .= '### Can bots use this method: **'.($bot ? 'YES' : 'NO')."**\n\n\n";
|
||||||
$example .= str_replace('[]', '', '### MadelineProto Example ([now async for huge speed and parallelism!](https://docs.madelineproto.xyz/docs/ASYNC.html)):
|
$example .= \str_replace('[]', '', '### MadelineProto Example ([now async for huge speed and parallelism!](https://docs.madelineproto.xyz/docs/ASYNC.html)):
|
||||||
|
|
||||||
|
|
||||||
```php
|
```php
|
||||||
@ -263,7 +267,7 @@ You can provide bot API reply_markup objects here.
|
|||||||
$example .= '
|
$example .= '
|
||||||
## Return value
|
## Return value
|
||||||
|
|
||||||
If the length of the provided message is bigger than 4096, the message will be split in chunks and the method will be called multiple times, with the same parameters (except for the message), and an array of ['.str_replace('_', '\\_', $type).'](../types/'.$php_type.'.md) will be returned instead.
|
If the length of the provided message is bigger than 4096, the message will be split in chunks and the method will be called multiple times, with the same parameters (except for the message), and an array of ['.\str_replace('_', '\\_', $type).'](../types/'.$php_type.'.md) will be returned instead.
|
||||||
|
|
||||||
|
|
||||||
';
|
';
|
||||||
@ -320,21 +324,21 @@ MadelineProto supports all html entities supported by [html_entity_decode](http:
|
|||||||
$example .= "\n\n";
|
$example .= "\n\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_put_contents('methods/'.$method.'.md', $header.$table.$return.$example);
|
\file_put_contents('methods/'.$method.'.md', $header.$table.$return.$example);
|
||||||
}
|
}
|
||||||
$this->logger->logger('Generating methods index...', \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger('Generating methods index...', \danog\MadelineProto\Logger::NOTICE);
|
||||||
ksort($this->docs_methods);
|
\ksort($this->docs_methods);
|
||||||
ksort($this->human_docs_methods);
|
\ksort($this->human_docs_methods);
|
||||||
$last_namespace = '';
|
$last_namespace = '';
|
||||||
foreach ($this->docs_methods as $method => &$value) {
|
foreach ($this->docs_methods as $method => &$value) {
|
||||||
$new_namespace = preg_replace('/_.*/', '', $method);
|
$new_namespace = \preg_replace('/_.*/', '', $method);
|
||||||
$br = $new_namespace != $last_namespace ? '***
|
$br = $new_namespace != $last_namespace ? '***
|
||||||
<br><br>
|
<br><br>
|
||||||
' : '';
|
' : '';
|
||||||
$value = $br.$value;
|
$value = $br.$value;
|
||||||
$last_namespace = $new_namespace;
|
$last_namespace = $new_namespace;
|
||||||
}
|
}
|
||||||
file_put_contents('methods/api_'.$this->index, '---
|
\file_put_contents('methods/api_'.$this->index, '---
|
||||||
title: Methods
|
title: Methods
|
||||||
description: List of methods
|
description: List of methods
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
@ -370,9 +374,9 @@ $MadelineProto->[request_call](https://docs.madelineproto.xyz/request_call.html)
|
|||||||
|
|
||||||
$MadelineProto->[request_secret_chat](https://docs.madelineproto.xyz/request_secret_chat.html)($id);
|
$MadelineProto->[request_secret_chat](https://docs.madelineproto.xyz/request_secret_chat.html)($id);
|
||||||
|
|
||||||
'.implode('', $this->docs_methods));
|
'.\implode('', $this->docs_methods));
|
||||||
|
|
||||||
file_put_contents('methods/'.$this->index, '---
|
\file_put_contents('methods/'.$this->index, '---
|
||||||
title: Methods
|
title: Methods
|
||||||
description: What do you want to do?
|
description: What do you want to do?
|
||||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||||
@ -404,6 +408,6 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
|||||||
|
|
||||||
* [Create a secret chat bot](https://docs.madelineproto.xyz/docs/SECRET_CHATS.html)
|
* [Create a secret chat bot](https://docs.madelineproto.xyz/docs/SECRET_CHATS.html)
|
||||||
|
|
||||||
'.implode('', $this->human_docs_methods));
|
'.\implode('', $this->human_docs_methods));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,9 @@ class EventHandler extends APIFactory
|
|||||||
{
|
{
|
||||||
public function __construct($MadelineProto)
|
public function __construct($MadelineProto)
|
||||||
{
|
{
|
||||||
if (!$MadelineProto) return;
|
if (!$MadelineProto) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
$this->API = $MadelineProto->API;
|
$this->API = $MadelineProto->API;
|
||||||
$this->async = &$MadelineProto->async;
|
$this->async = &$MadelineProto->async;
|
||||||
$this->methods = &$MadelineProto->methods;
|
$this->methods = &$MadelineProto->methods;
|
||||||
|
@ -39,18 +39,18 @@ class Exception extends \Exception
|
|||||||
$this->line = $line;
|
$this->line = $line;
|
||||||
}
|
}
|
||||||
parent::__construct($message, $code, $previous);
|
parent::__construct($message, $code, $previous);
|
||||||
if (strpos($message, 'socket_accept') === false) {
|
if (\strpos($message, 'socket_accept') === false) {
|
||||||
\danog\MadelineProto\Logger::log($message.' in '.basename($this->file).':'.$this->line, \danog\MadelineProto\Logger::FATAL_ERROR);
|
\danog\MadelineProto\Logger::log($message.' in '.\basename($this->file).':'.$this->line, \danog\MadelineProto\Logger::FATAL_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_array($message, ['The session is corrupted!', 'Re-executing query...', 'I had to recreate the temporary authorization key', 'This peer is not present in the internal peer database', "Couldn't get response", 'Chat forbidden', 'The php-libtgvoip extension is required to accept and manage calls. See daniil.it/MadelineProto for more info.', 'File does not exist', 'Please install this fork of phpseclib: https://github.com/danog/phpseclib'])) {
|
if (\in_array($message, ['The session is corrupted!', 'Re-executing query...', 'I had to recreate the temporary authorization key', 'This peer is not present in the internal peer database', "Couldn't get response", 'Chat forbidden', 'The php-libtgvoip extension is required to accept and manage calls. See daniil.it/MadelineProto for more info.', 'File does not exist', 'Please install this fork of phpseclib: https://github.com/danog/phpseclib'])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (strpos($message, 'pg_query') !== false || strpos($message, 'Undefined variable: ') !== false || strpos($message, 'socket_write') !== false || strpos($message, 'socket_read') !== false || strpos($message, 'Received request to switch to DC ') !== false || strpos($message, "Couldn't get response") !== false || strpos($message, 'Re-executing query...') !== false || strpos($message, "Couldn't find peer by provided") !== false || strpos($message, 'id.pwrtelegram.xyz') !== false || strpos($message, 'Please update ') !== false || strpos($message, 'posix_isatty') !== false) {
|
if (\strpos($message, 'pg_query') !== false || \strpos($message, 'Undefined variable: ') !== false || \strpos($message, 'socket_write') !== false || \strpos($message, 'socket_read') !== false || \strpos($message, 'Received request to switch to DC ') !== false || \strpos($message, "Couldn't get response") !== false || \strpos($message, 'Re-executing query...') !== false || \strpos($message, "Couldn't find peer by provided") !== false || \strpos($message, 'id.pwrtelegram.xyz') !== false || \strpos($message, 'Please update ') !== false || \strpos($message, 'posix_isatty') !== false) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (self::$rollbar && class_exists('\\Rollbar\\Rollbar')) {
|
if (self::$rollbar && \class_exists('\\Rollbar\\Rollbar')) {
|
||||||
\Rollbar\Rollbar::log(\Rollbar\Payload\Level::error(), $this, debug_backtrace(0));
|
\Rollbar\Rollbar::log(\Rollbar\Payload\Level::error(), $this, \debug_backtrace(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ class Exception extends \Exception
|
|||||||
$additional = 'Follow the instructions @ https://prime.madelineproto.xyz to install it.';
|
$additional = 'Follow the instructions @ https://prime.madelineproto.xyz to install it.';
|
||||||
}
|
}
|
||||||
$message = 'MadelineProto requires the '.$extensionName.' extension to run. '.$additional;
|
$message = 'MadelineProto requires the '.$extensionName.' extension to run. '.$additional;
|
||||||
if (php_sapi_name() !== 'cli') {
|
if (PHP_SAPI !== 'cli') {
|
||||||
echo $message.'<br>';
|
echo $message.'<br>';
|
||||||
}
|
}
|
||||||
$file = 'MadelineProto';
|
$file = 'MadelineProto';
|
||||||
@ -78,7 +78,7 @@ class Exception extends \Exception
|
|||||||
public static function ExceptionErrorHandler($errno = 0, $errstr = null, $errfile = null, $errline = null)
|
public static function ExceptionErrorHandler($errno = 0, $errstr = null, $errfile = null, $errline = null)
|
||||||
{
|
{
|
||||||
// If error is suppressed with @, don't throw an exception
|
// If error is suppressed with @, don't throw an exception
|
||||||
if (error_reporting() === 0 || strpos($errstr, 'headers already sent') || ($errfile && strpos($errfile, 'vendor/amphp') !== false)) {
|
if (\error_reporting() === 0 || \strpos($errstr, 'headers already sent') || ($errfile && \strpos($errfile, 'vendor/amphp') !== false)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Lang module
|
* Lang module.
|
||||||
*
|
*
|
||||||
* This file is part of MadelineProto.
|
* This file is part of MadelineProto.
|
||||||
* MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
* MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
@ -19,9 +19,9 @@ namespace danog\MadelineProto;
|
|||||||
|
|
||||||
class Lang
|
class Lang
|
||||||
{
|
{
|
||||||
public static $lang = array (
|
public static $lang = [
|
||||||
'it' =>
|
'it' =>
|
||||||
array (
|
[
|
||||||
'phpseclib_fork' => 'Per favore installa questo fork di phpseclib: https://github.com/danog/phpseclib',
|
'phpseclib_fork' => 'Per favore installa questo fork di phpseclib: https://github.com/danog/phpseclib',
|
||||||
'inst_dc' => 'Istanziamento dei DataCenter...',
|
'inst_dc' => 'Istanziamento dei DataCenter...',
|
||||||
'load_rsa' => 'Caricamento delle chiavi RSA...',
|
'load_rsa' => 'Caricamento delle chiavi RSA...',
|
||||||
@ -161,9 +161,9 @@ class Lang
|
|||||||
'done' => 'Fatto!',
|
'done' => 'Fatto!',
|
||||||
'cdn_reupload' => 'Il file non è disponibile sul nostro CDN, richiedo la copia!',
|
'cdn_reupload' => 'Il file non è disponibile sul nostro CDN, richiedo la copia!',
|
||||||
'stored_on_cdn' => 'Il file è scaricabile tramite CDN!',
|
'stored_on_cdn' => 'Il file è scaricabile tramite CDN!',
|
||||||
),
|
],
|
||||||
'en' =>
|
'en' =>
|
||||||
array (
|
[
|
||||||
'req_pq' => 'Requesting pq...',
|
'req_pq' => 'Requesting pq...',
|
||||||
'done' => 'Done!',
|
'done' => 'Done!',
|
||||||
'cdn_reupload' => 'File is not stored on CDN, requesting reupload!',
|
'cdn_reupload' => 'File is not stored on CDN, requesting reupload!',
|
||||||
@ -5157,11 +5157,11 @@ class Lang
|
|||||||
'object_channelAdminLogEventActionToggleSlowMode_param_new_value_type_int' => 'New value',
|
'object_channelAdminLogEventActionToggleSlowMode_param_new_value_type_int' => 'New value',
|
||||||
'object_codeSettings_param_allow_app_hash_type_true' => 'Whether to allow a persistent app hash',
|
'object_codeSettings_param_allow_app_hash_type_true' => 'Whether to allow a persistent app hash',
|
||||||
'object_channelFull_param_slowmode_next_send_date_type_int' => ' Indicates when the user will be allowed to send another message in the supergroup (unixdate)',
|
'object_channelFull_param_slowmode_next_send_date_type_int' => ' Indicates when the user will be allowed to send another message in the supergroup (unixdate)',
|
||||||
),
|
],
|
||||||
);
|
];
|
||||||
|
|
||||||
// THIS WILL BE OVERWRITTEN BY $lang["en"]
|
// THIS WILL BE OVERWRITTEN BY $lang["en"]
|
||||||
public static $current_lang = array (
|
public static $current_lang = [
|
||||||
'req_pq' => 'Requesting pq...',
|
'req_pq' => 'Requesting pq...',
|
||||||
'done' => 'Done!',
|
'done' => 'Done!',
|
||||||
'cdn_reupload' => 'File is not stored on CDN, requesting reupload!',
|
'cdn_reupload' => 'File is not stored on CDN, requesting reupload!',
|
||||||
@ -10155,5 +10155,5 @@ class Lang
|
|||||||
'object_channelAdminLogEventActionToggleSlowMode_param_new_value_type_int' => 'New value',
|
'object_channelAdminLogEventActionToggleSlowMode_param_new_value_type_int' => 'New value',
|
||||||
'object_codeSettings_param_allow_app_hash_type_true' => 'Whether to allow a persistent app hash',
|
'object_codeSettings_param_allow_app_hash_type_true' => 'Whether to allow a persistent app hash',
|
||||||
'object_channelFull_param_slowmode_next_send_date_type_int' => ' Indicates when the user will be allowed to send another message in the supergroup (unixdate)',
|
'object_channelFull_param_slowmode_next_send_date_type_int' => ' Indicates when the user will be allowed to send another message in the supergroup (unixdate)',
|
||||||
);
|
];
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ class Logger
|
|||||||
const CALLABLE_LOGGER = 4;
|
const CALLABLE_LOGGER = 4;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct global logger
|
* Construct global logger.
|
||||||
*
|
*
|
||||||
* @param [type] $mode
|
* @param [type] $mode
|
||||||
* @param [type] $optional
|
* @param [type] $optional
|
||||||
@ -75,19 +75,20 @@ class Logger
|
|||||||
self::$default = new self($mode, $optional, $prefix, $level, $max_size);
|
self::$default = new self($mode, $optional, $prefix, $level, $max_size);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Construct global static logger from MadelineProto settings
|
* Construct global static logger from MadelineProto settings.
|
||||||
*
|
*
|
||||||
* @param array $settings
|
* @param array $settings
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public static function constructorFromSettings(array $settings) {
|
public static function constructorFromSettings(array $settings)
|
||||||
|
{
|
||||||
if (!self::$default) {
|
if (!self::$default) {
|
||||||
// The getLogger function will automatically init the static logger, but we'll do it again anyway
|
// The getLogger function will automatically init the static logger, but we'll do it again anyway
|
||||||
self::$default = self::getLoggerFromSettings(MTProto::getSettings($settings));
|
self::$default = self::getLoggerFromSettings(MTProto::getSettings($settings));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Get logger from MadelineProto settings
|
* Get logger from MadelineProto settings.
|
||||||
*
|
*
|
||||||
* @param array $settings
|
* @param array $settings
|
||||||
* @param string $prefix Optional prefix
|
* @param string $prefix Optional prefix
|
||||||
@ -95,8 +96,8 @@ class Logger
|
|||||||
*/
|
*/
|
||||||
public static function getLoggerFromSettings(array $settings, string $prefix = ''): self
|
public static function getLoggerFromSettings(array $settings, string $prefix = ''): self
|
||||||
{
|
{
|
||||||
if (isset($settings['logger']['rollbar_token']) && $settings['logger']['rollbar_token'] !== '' && class_exists('\\Rollbar\\Rollbar')) {
|
if (isset($settings['logger']['rollbar_token']) && $settings['logger']['rollbar_token'] !== '' && \class_exists('\\Rollbar\\Rollbar')) {
|
||||||
@\Rollbar\Rollbar::init(['environment' => 'production', 'root' => __DIR__, 'access_token' => isset($settings['logger']['rollbar_token']) && !in_array($settings['logger']['rollbar_token'], ['f9fff6689aea4905b58eec73f66c791d', '300afd7ccef346ea84d0c185ae831718', '11a8c2fe4c474328b40a28193f8d63f5', 'beef2d426496462ba34dcaad33d44a14']) || $settings['pwr']['pwr'] ? $settings['logger']['rollbar_token'] : 'c07d9b2f73c2461297b0beaef6c1662f'], false, false);
|
@\Rollbar\Rollbar::init(['environment' => 'production', 'root' => __DIR__, 'access_token' => isset($settings['logger']['rollbar_token']) && !\in_array($settings['logger']['rollbar_token'], ['f9fff6689aea4905b58eec73f66c791d', '300afd7ccef346ea84d0c185ae831718', '11a8c2fe4c474328b40a28193f8d63f5', 'beef2d426496462ba34dcaad33d44a14']) || $settings['pwr']['pwr'] ? $settings['logger']['rollbar_token'] : 'c07d9b2f73c2461297b0beaef6c1662f'], false, false);
|
||||||
} else {
|
} else {
|
||||||
Exception::$rollbar = false;
|
Exception::$rollbar = false;
|
||||||
RPCErrorException::$rollbar = false;
|
RPCErrorException::$rollbar = false;
|
||||||
@ -104,8 +105,8 @@ class Logger
|
|||||||
if (!isset($settings['logger']['logger_param']) && isset($settings['logger']['param'])) {
|
if (!isset($settings['logger']['logger_param']) && isset($settings['logger']['param'])) {
|
||||||
$settings['logger']['logger_param'] = $settings['logger']['param'];
|
$settings['logger']['logger_param'] = $settings['logger']['param'];
|
||||||
}
|
}
|
||||||
if (php_sapi_name() !== 'cli') {
|
if (PHP_SAPI !== 'cli') {
|
||||||
if (isset($settings['logger']['logger_param']) && basename($settings['logger']['logger_param']) === 'MadelineProto.log') {
|
if (isset($settings['logger']['logger_param']) && \basename($settings['logger']['logger_param']) === 'MadelineProto.log') {
|
||||||
$settings['logger']['logger_param'] = Magic::$script_cwd.'/MadelineProto.log';
|
$settings['logger']['logger_param'] = Magic::$script_cwd.'/MadelineProto.log';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -115,12 +116,12 @@ class Logger
|
|||||||
self::$default = $logger;
|
self::$default = $logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (php_sapi_name() !== 'cli') {
|
if (PHP_SAPI !== 'cli') {
|
||||||
try {
|
try {
|
||||||
error_reporting(E_ALL);
|
\error_reporting(E_ALL);
|
||||||
ini_set('log_errors', 1);
|
\ini_set('log_errors', 1);
|
||||||
ini_set('error_log', Magic::$script_cwd.'/MadelineProto.log');
|
\ini_set('error_log', Magic::$script_cwd.'/MadelineProto.log');
|
||||||
error_log('Enabled PHP logging');
|
\error_log('Enabled PHP logging');
|
||||||
} catch (\danog\MadelineProto\Exception $e) {
|
} catch (\danog\MadelineProto\Exception $e) {
|
||||||
$logger->logger('Could not enable PHP logging');
|
$logger->logger('Could not enable PHP logging');
|
||||||
}
|
}
|
||||||
@ -138,39 +139,39 @@ class Logger
|
|||||||
$this->prefix = $prefix === '' ? '' : ', '.$prefix;
|
$this->prefix = $prefix === '' ? '' : ', '.$prefix;
|
||||||
$this->level = $level;
|
$this->level = $level;
|
||||||
|
|
||||||
if ($this->mode === 2 && !file_exists(pathinfo($this->optional, PATHINFO_DIRNAME))) {
|
if ($this->mode === 2 && !\file_exists(\pathinfo($this->optional, PATHINFO_DIRNAME))) {
|
||||||
$this->optional = Magic::$script_cwd.'/MadelineProto.log';
|
$this->optional = Magic::$script_cwd.'/MadelineProto.log';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->mode === 2 && !preg_match('/\.log$/', $this->optional)) {
|
if ($this->mode === 2 && !\preg_match('/\.log$/', $this->optional)) {
|
||||||
$this->optional .= '.log';
|
$this->optional .= '.log';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($mode === 2 && $max_size !== -1 && file_exists($this->optional) && filesize($this->optional) > $max_size) {
|
if ($mode === 2 && $max_size !== -1 && \file_exists($this->optional) && \filesize($this->optional) > $max_size) {
|
||||||
unlink($this->optional);
|
\unlink($this->optional);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->colors[self::ULTRA_VERBOSE] = implode(';', [self::FOREGROUND['light_gray'], self::SET['dim']]);
|
$this->colors[self::ULTRA_VERBOSE] = \implode(';', [self::FOREGROUND['light_gray'], self::SET['dim']]);
|
||||||
$this->colors[self::VERBOSE] = implode(';', [self::FOREGROUND['green'], self::SET['bold']]);
|
$this->colors[self::VERBOSE] = \implode(';', [self::FOREGROUND['green'], self::SET['bold']]);
|
||||||
$this->colors[self::NOTICE] = implode(';', [self::FOREGROUND['yellow'], self::SET['bold']]);
|
$this->colors[self::NOTICE] = \implode(';', [self::FOREGROUND['yellow'], self::SET['bold']]);
|
||||||
$this->colors[self::WARNING] = implode(';', [self::FOREGROUND['white'], self::SET['dim'], self::BACKGROUND['red']]);
|
$this->colors[self::WARNING] = \implode(';', [self::FOREGROUND['white'], self::SET['dim'], self::BACKGROUND['red']]);
|
||||||
$this->colors[self::ERROR] = implode(';', [self::FOREGROUND['white'], self::SET['bold'], self::BACKGROUND['red']]);
|
$this->colors[self::ERROR] = \implode(';', [self::FOREGROUND['white'], self::SET['bold'], self::BACKGROUND['red']]);
|
||||||
$this->colors[self::FATAL_ERROR] = implode(';', [self::FOREGROUND['red'], self::SET['bold'], self::BACKGROUND['light_gray']]);
|
$this->colors[self::FATAL_ERROR] = \implode(';', [self::FOREGROUND['red'], self::SET['bold'], self::BACKGROUND['light_gray']]);
|
||||||
$this->newline = PHP_EOL;
|
$this->newline = PHP_EOL;
|
||||||
|
|
||||||
if ($this->mode === 3) {
|
if ($this->mode === 3) {
|
||||||
$this->stdout = getStdout();
|
$this->stdout = getStdout();
|
||||||
if (php_sapi_name() !== 'cli') {
|
if (PHP_SAPI !== 'cli') {
|
||||||
$this->newline = '<br>'.$this->newline;
|
$this->newline = '<br>'.$this->newline;
|
||||||
}
|
}
|
||||||
} elseif ($this->mode === 2) {
|
} elseif ($this->mode === 2) {
|
||||||
$this->stdout = new ResourceOutputStream(fopen($this->optional, 'a+'));
|
$this->stdout = new ResourceOutputStream(\fopen($this->optional, 'a+'));
|
||||||
} elseif ($this->mode === 1) {
|
} elseif ($this->mode === 1) {
|
||||||
$result = @ini_get('error_log');
|
$result = @\ini_get('error_log');
|
||||||
if ($result === 'syslog') {
|
if ($result === 'syslog') {
|
||||||
$this->stdout = getStderr();
|
$this->stdout = getStderr();
|
||||||
} elseif ($result) {
|
} elseif ($result) {
|
||||||
$this->stdout = new ResourceOutputStream(fopen($result, 'a+'));
|
$this->stdout = new ResourceOutputStream(\fopen($result, 'a+'));
|
||||||
} else {
|
} else {
|
||||||
$this->stdout = getStderr();
|
$this->stdout = getStderr();
|
||||||
}
|
}
|
||||||
@ -179,8 +180,8 @@ class Logger
|
|||||||
|
|
||||||
public static function log($param, $level = self::NOTICE)
|
public static function log($param, $level = self::NOTICE)
|
||||||
{
|
{
|
||||||
if (!is_null(self::$default)) {
|
if (!\is_null(self::$default)) {
|
||||||
self::$default->logger($param, $level, basename(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['file'], '.php'));
|
self::$default->logger($param, $level, \basename(\debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['file'], '.php'));
|
||||||
} else {
|
} else {
|
||||||
echo $param.PHP_EOL;
|
echo $param.PHP_EOL;
|
||||||
}
|
}
|
||||||
@ -193,35 +194,35 @@ class Logger
|
|||||||
}
|
}
|
||||||
if (!self::$printed) {
|
if (!self::$printed) {
|
||||||
self::$printed = true;
|
self::$printed = true;
|
||||||
$this->colors[self::NOTICE] = implode(';', [self::FOREGROUND['light_gray'], self::SET['bold'], self::BACKGROUND['blue']]);
|
$this->colors[self::NOTICE] = \implode(';', [self::FOREGROUND['light_gray'], self::SET['bold'], self::BACKGROUND['blue']]);
|
||||||
|
|
||||||
$this->logger('MadelineProto');
|
$this->logger('MadelineProto');
|
||||||
$this->logger('Copyright (C) 2016-2019 Daniil Gentili');
|
$this->logger('Copyright (C) 2016-2019 Daniil Gentili');
|
||||||
$this->logger('Licensed under AGPLv3');
|
$this->logger('Licensed under AGPLv3');
|
||||||
$this->logger('https://github.com/danog/MadelineProto');
|
$this->logger('https://github.com/danog/MadelineProto');
|
||||||
|
|
||||||
$this->colors[self::NOTICE] = implode(';', [self::FOREGROUND['yellow'], self::SET['bold']]);
|
$this->colors[self::NOTICE] = \implode(';', [self::FOREGROUND['yellow'], self::SET['bold']]);
|
||||||
}
|
}
|
||||||
if ($this->mode === 4) {
|
if ($this->mode === 4) {
|
||||||
return call_user_func_array($this->optional, [$param, $level]);
|
return \call_user_func_array($this->optional, [$param, $level]);
|
||||||
}
|
}
|
||||||
$prefix = $this->prefix;
|
$prefix = $this->prefix;
|
||||||
if (\danog\MadelineProto\Magic::$has_thread && is_object(\Thread::getCurrentThread())) {
|
if (\danog\MadelineProto\Magic::$has_thread && \is_object(\Thread::getCurrentThread())) {
|
||||||
$prefix .= ' (t)';
|
$prefix .= ' (t)';
|
||||||
}
|
}
|
||||||
if ($param instanceof \Throwable) {
|
if ($param instanceof \Throwable) {
|
||||||
$param = (string) $param;
|
$param = (string) $param;
|
||||||
} elseif (!is_string($param)) {
|
} elseif (!\is_string($param)) {
|
||||||
$param = json_encode($param, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|
$param = \json_encode($param, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|
||||||
}
|
}
|
||||||
if ($file === null) {
|
if ($file === null) {
|
||||||
$file = basename(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['file'], '.php');
|
$file = \basename(\debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['file'], '.php');
|
||||||
}
|
}
|
||||||
$param = str_pad($file.$prefix.': ', 16 + strlen($prefix))."\t".$param;
|
$param = \str_pad($file.$prefix.': ', 16 + \strlen($prefix))."\t".$param;
|
||||||
switch ($this->mode) {
|
switch ($this->mode) {
|
||||||
case 1:
|
case 1:
|
||||||
if ($this->stdout->write($param.$this->newline) instanceof Failure) {
|
if ($this->stdout->write($param.$this->newline) instanceof Failure) {
|
||||||
error_log($param);
|
\error_log($param);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -229,7 +230,7 @@ class Logger
|
|||||||
if ($this->stdout->write($param) instanceof Failure) {
|
if ($this->stdout->write($param) instanceof Failure) {
|
||||||
switch ($this->mode) {
|
switch ($this->mode) {
|
||||||
case 3: echo $param; break;
|
case 3: echo $param; break;
|
||||||
case 2: file_put_contents($this->optional, $param, FILE_APPEND); break;
|
case 2: \file_put_contents($this->optional, $param, FILE_APPEND); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -109,7 +109,7 @@ class ReadLoop extends SignalLoop
|
|||||||
} elseif ($error === 0) {
|
} elseif ($error === 0) {
|
||||||
$API->logger->logger("Got NOOP from DC {$datacenter}", \danog\MadelineProto\Logger::WARNING);
|
$API->logger->logger("Got NOOP from DC {$datacenter}", \danog\MadelineProto\Logger::WARNING);
|
||||||
yield $connection->reconnect();
|
yield $connection->reconnect();
|
||||||
} else if ($error === -429) {
|
} elseif ($error === -429) {
|
||||||
$API->logger->logger("Got -429 from DC {$datacenter}", \danog\MadelineProto\Logger::WARNING);
|
$API->logger->logger("Got -429 from DC {$datacenter}", \danog\MadelineProto\Logger::WARNING);
|
||||||
Loop::delay(1*1000, [$connection, 'reconnect']);
|
Loop::delay(1*1000, [$connection, 'reconnect']);
|
||||||
} else {
|
} else {
|
||||||
|
@ -36,7 +36,7 @@ abstract class Loop implements LoopInterface
|
|||||||
private $count = 0;
|
private $count = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MTProto instance
|
* MTProto instance.
|
||||||
*
|
*
|
||||||
* @var \danog\MadelineProto\MTProto
|
* @var \danog\MadelineProto\MTProto
|
||||||
*/
|
*/
|
||||||
|
@ -39,17 +39,16 @@ abstract class ResumableSignalLoop extends SignalLoop implements ResumableLoopIn
|
|||||||
|
|
||||||
public function pause($time = null): Promise
|
public function pause($time = null): Promise
|
||||||
{
|
{
|
||||||
if (!is_null($time)) {
|
if (!\is_null($time)) {
|
||||||
if ($time <= 0) {
|
if ($time <= 0) {
|
||||||
return new Success(0);
|
return new Success(0);
|
||||||
} else {
|
|
||||||
$resume = microtime(true) + $time;
|
|
||||||
if ($this->resumeWatcher) {
|
|
||||||
Loop::cancel($this->resumeWatcher);
|
|
||||||
$this->resumeWatcher = null;
|
|
||||||
}
|
|
||||||
$this->resumeWatcher = Loop::delay($time * 1000, [$this, 'resume'], $resume);
|
|
||||||
}
|
}
|
||||||
|
$resume = \microtime(true) + $time;
|
||||||
|
if ($this->resumeWatcher) {
|
||||||
|
Loop::cancel($this->resumeWatcher);
|
||||||
|
$this->resumeWatcher = null;
|
||||||
|
}
|
||||||
|
$this->resumeWatcher = Loop::delay($time * 1000, [$this, 'resume'], $resume);
|
||||||
}
|
}
|
||||||
$this->resume = new Deferred();
|
$this->resume = new Deferred();
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ class FeedLoop extends ResumableSignalLoop
|
|||||||
private $parsedUpdates = [];
|
private $parsedUpdates = [];
|
||||||
private $channelId;
|
private $channelId;
|
||||||
/**
|
/**
|
||||||
* Update loop
|
* Update loop.
|
||||||
*
|
*
|
||||||
* @var UpdateLoop
|
* @var UpdateLoop
|
||||||
*/
|
*/
|
||||||
@ -94,9 +94,9 @@ class FeedLoop extends ResumableSignalLoop
|
|||||||
|
|
||||||
public function parse($updates)
|
public function parse($updates)
|
||||||
{
|
{
|
||||||
reset($updates);
|
\reset($updates);
|
||||||
while ($updates) {
|
while ($updates) {
|
||||||
$key = key($updates);
|
$key = \key($updates);
|
||||||
$update = $updates[$key];
|
$update = $updates[$key];
|
||||||
unset($updates[$key]);
|
unset($updates[$key]);
|
||||||
if ($update['_'] === 'updateChannelTooLong') {
|
if ($update['_'] === 'updateChannelTooLong') {
|
||||||
@ -124,11 +124,11 @@ class FeedLoop extends ResumableSignalLoop
|
|||||||
$logger('PTS hole');
|
$logger('PTS hole');
|
||||||
$this->updater->setLimit($this->state->pts() + $result);
|
$this->updater->setLimit($this->state->pts() + $result);
|
||||||
yield $this->updater->resume();
|
yield $this->updater->resume();
|
||||||
$updates = array_merge($this->incomingUpdates, $updates);
|
$updates = \array_merge($this->incomingUpdates, $updates);
|
||||||
$this->incomingUpdates = [];
|
$this->incomingUpdates = [];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (isset($update['message']['id'], $update['message']['to_id']) && !in_array($update['_'], ['updateEditMessage', 'updateEditChannelMessage', 'updateMessageID'])) {
|
if (isset($update['message']['id'], $update['message']['to_id']) && !\in_array($update['_'], ['updateEditMessage', 'updateEditChannelMessage', 'updateMessageID'])) {
|
||||||
if (!$this->API->check_msg_id($update['message'])) {
|
if (!$this->API->check_msg_id($update['message'])) {
|
||||||
$logger('MSGID duplicate');
|
$logger('MSGID duplicate');
|
||||||
|
|
||||||
@ -214,7 +214,7 @@ class FeedLoop extends ResumableSignalLoop
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($to) {
|
if ($to) {
|
||||||
$log .= 'to_id '.json_encode($update['message']['to_id']).', ';
|
$log .= 'to_id '.\json_encode($update['message']['to_id']).', ';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($via_bot) {
|
if ($via_bot) {
|
||||||
@ -222,7 +222,7 @@ class FeedLoop extends ResumableSignalLoop
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($entities) {
|
if ($entities) {
|
||||||
$log .= 'entities '.json_encode($update['message']['entities']).', ';
|
$log .= 'entities '.\json_encode($update['message']['entities']).', ';
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->API->logger->logger("Not enough data: for message update $log, getting difference...", \danog\MadelineProto\Logger::VERBOSE);
|
$this->API->logger->logger("Not enough data: for message update $log, getting difference...", \danog\MadelineProto\Logger::VERBOSE);
|
||||||
@ -230,7 +230,6 @@ class FeedLoop extends ResumableSignalLoop
|
|||||||
if ($channelId && $to) {
|
if ($channelId && $to) {
|
||||||
$channelId = false;
|
$channelId = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -244,7 +243,7 @@ class FeedLoop extends ResumableSignalLoop
|
|||||||
if ($channelId !== $this->channelId) {
|
if ($channelId !== $this->channelId) {
|
||||||
if (isset($this->API->feeders[$channelId])) {
|
if (isset($this->API->feeders[$channelId])) {
|
||||||
return yield $this->API->feeders[$channelId]->feedSingle($update);
|
return yield $this->API->feeders[$channelId]->feedSingle($update);
|
||||||
} else if ($this->channelId) {
|
} elseif ($this->channelId) {
|
||||||
return yield $this->API->feeders[false]->feedSingle($update);
|
return yield $this->API->feeders[false]->feedSingle($update);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,8 +72,8 @@ class SeqLoop extends ResumableSignalLoop
|
|||||||
$updates = null;
|
$updates = null;
|
||||||
}
|
}
|
||||||
while ($this->pendingWakeups) {
|
while ($this->pendingWakeups) {
|
||||||
reset($this->pendingWakeups);
|
\reset($this->pendingWakeups);
|
||||||
$channelId = key($this->pendingWakeups);
|
$channelId = \key($this->pendingWakeups);
|
||||||
unset($this->pendingWakeups[$channelId]);
|
unset($this->pendingWakeups[$channelId]);
|
||||||
$this->API->feeders[$channelId]->resume();
|
$this->API->feeders[$channelId]->resume();
|
||||||
}
|
}
|
||||||
@ -82,10 +82,10 @@ class SeqLoop extends ResumableSignalLoop
|
|||||||
|
|
||||||
public function parse($updates)
|
public function parse($updates)
|
||||||
{
|
{
|
||||||
reset($updates);
|
\reset($updates);
|
||||||
while ($updates) {
|
while ($updates) {
|
||||||
$options = [];
|
$options = [];
|
||||||
$key = key($updates);
|
$key = \key($updates);
|
||||||
$update = $updates[$key];
|
$update = $updates[$key];
|
||||||
unset($updates[$key]);
|
unset($updates[$key]);
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ class SeqLoop extends ResumableSignalLoop
|
|||||||
if (!$this->incomingUpdates) {
|
if (!$this->incomingUpdates) {
|
||||||
yield $this->API->updaters[false]->resume();
|
yield $this->API->updaters[false]->resume();
|
||||||
}
|
}
|
||||||
$this->incomingUpdates = array_merge($this->incomingUpdates, [$update], $updates);
|
$this->incomingUpdates = \array_merge($this->incomingUpdates, [$update], $updates);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -84,10 +84,10 @@ class UpdateLoop extends ResumableSignalLoop
|
|||||||
try {
|
try {
|
||||||
$difference = yield $API->method_call_async_read('updates.getChannelDifference', ['channel' => 'channel#'.$this->channelId, 'filter' => ['_' => 'channelMessagesFilterEmpty'], 'pts' => $request_pts, 'limit' => $limit, 'force' => true], ['datacenter' => $API->datacenter->curdc, 'postpone' => $first]);
|
$difference = yield $API->method_call_async_read('updates.getChannelDifference', ['channel' => 'channel#'.$this->channelId, 'filter' => ['_' => 'channelMessagesFilterEmpty'], 'pts' => $request_pts, 'limit' => $limit, 'force' => true], ['datacenter' => $API->datacenter->curdc, 'postpone' => $first]);
|
||||||
} catch (RPCErrorException $e) {
|
} catch (RPCErrorException $e) {
|
||||||
if (in_array($e->rpc, ['CHANNEL_PRIVATE', 'CHAT_FORBIDDEN'])) {
|
if (\in_array($e->rpc, ['CHANNEL_PRIVATE', 'CHAT_FORBIDDEN'])) {
|
||||||
$feeder->signal(true);
|
$feeder->signal(true);
|
||||||
unset($API->updaters[$this->channelId]);
|
unset($API->updaters[$this->channelId], $API->feeders[$this->channelId]);
|
||||||
unset($API->feeders[$this->channelId]);
|
|
||||||
$API->getChannelStates()->remove($this->channelId);
|
$API->getChannelStates()->remove($this->channelId);
|
||||||
$API->logger->logger("Channel private, exiting $this");
|
$API->logger->logger("Channel private, exiting $this");
|
||||||
|
|
||||||
@ -95,11 +95,11 @@ class UpdateLoop extends ResumableSignalLoop
|
|||||||
}
|
}
|
||||||
throw $e;
|
throw $e;
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
if (in_array($e->getMessage(), ['This peer is not present in the internal peer database'])) {
|
if (\in_array($e->getMessage(), ['This peer is not present in the internal peer database'])) {
|
||||||
$feeder->signal(true);
|
$feeder->signal(true);
|
||||||
$API->getChannelStates()->remove($this->channelId);
|
$API->getChannelStates()->remove($this->channelId);
|
||||||
unset($API->updaters[$this->channelId]);
|
unset($API->updaters[$this->channelId], $API->feeders[$this->channelId]);
|
||||||
unset($API->feeders[$this->channelId]);
|
|
||||||
$API->logger->logger("Channel private, exiting $this");
|
$API->logger->logger("Channel private, exiting $this");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -144,7 +144,7 @@ class UpdateLoop extends ResumableSignalLoop
|
|||||||
unset($difference);
|
unset($difference);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new \danog\MadelineProto\Exception('Unrecognized update difference received: '.var_export($difference, true));
|
throw new \danog\MadelineProto\Exception('Unrecognized update difference received: '.\var_export($difference, true));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$API->logger->logger('Resumed and fetching normal difference...', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$API->logger->logger('Resumed and fetching normal difference...', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
@ -187,7 +187,7 @@ class UpdateLoop extends ResumableSignalLoop
|
|||||||
unset($difference);
|
unset($difference);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new \danog\MadelineProto\Exception('Unrecognized update difference received: '.var_export($difference, true));
|
throw new \danog\MadelineProto\Exception('Unrecognized update difference received: '.\var_export($difference, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ class Lua
|
|||||||
|
|
||||||
public function __magic_construct($script, $MadelineProto)
|
public function __magic_construct($script, $MadelineProto)
|
||||||
{
|
{
|
||||||
if (!file_exists($script)) {
|
if (!\file_exists($script)) {
|
||||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['script_not_exist']);
|
throw new Exception(\danog\MadelineProto\Lang::$current_lang['script_not_exist']);
|
||||||
}
|
}
|
||||||
$this->MadelineProto = $MadelineProto;
|
$this->MadelineProto = $MadelineProto;
|
||||||
@ -51,12 +51,12 @@ class Lua
|
|||||||
$this->Lua->registerCallback('tdcli_function', [$this, 'tdcli_function']);
|
$this->Lua->registerCallback('tdcli_function', [$this, 'tdcli_function']);
|
||||||
$this->Lua->registerCallback('madeline_function', [$this, 'madeline_function']);
|
$this->Lua->registerCallback('madeline_function', [$this, 'madeline_function']);
|
||||||
$this->Lua->registerCallback('var_dump', 'var_dump');
|
$this->Lua->registerCallback('var_dump', 'var_dump');
|
||||||
foreach (get_class_methods($this->MadelineProto->API) as $method) {
|
foreach (\get_class_methods($this->MadelineProto->API) as $method) {
|
||||||
$this->Lua->registerCallback($method, [$this->MadelineProto, $method]);
|
$this->Lua->registerCallback($method, [$this->MadelineProto, $method]);
|
||||||
}
|
}
|
||||||
$methods = [];
|
$methods = [];
|
||||||
foreach ($this->MadelineProto->get_methods_namespaced() as $pair) {
|
foreach ($this->MadelineProto->get_methods_namespaced() as $pair) {
|
||||||
$namespace = key($pair);
|
$namespace = \key($pair);
|
||||||
$method = $pair[$namespace];
|
$method = $pair[$namespace];
|
||||||
if ($namespace === 'upload') {
|
if ($namespace === 'upload') {
|
||||||
continue;
|
continue;
|
||||||
@ -64,7 +64,7 @@ class Lua
|
|||||||
$methods[$namespace][$method] = [$this->MadelineProto->{$namespace}, $method];
|
$methods[$namespace][$method] = [$this->MadelineProto->{$namespace}, $method];
|
||||||
}
|
}
|
||||||
foreach ($this->MadelineProto->get_methods_namespaced() as $pair) {
|
foreach ($this->MadelineProto->get_methods_namespaced() as $pair) {
|
||||||
$namespace = key($pair);
|
$namespace = \key($pair);
|
||||||
$method = $pair[$namespace];
|
$method = $pair[$namespace];
|
||||||
if ($namespace === 'upload') {
|
if ($namespace === 'upload') {
|
||||||
continue;
|
continue;
|
||||||
@ -73,7 +73,7 @@ class Lua
|
|||||||
}
|
}
|
||||||
$this->MadelineProto->lua = true;
|
$this->MadelineProto->lua = true;
|
||||||
foreach ($this->MadelineProto->get_methods_namespaced() as $pair) {
|
foreach ($this->MadelineProto->get_methods_namespaced() as $pair) {
|
||||||
$namespace = key($pair);
|
$namespace = \key($pair);
|
||||||
$this->MadelineProto->{$namespace}->lua = true;
|
$this->MadelineProto->{$namespace}->lua = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,7 +85,7 @@ class Lua
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
$result = $this->MadelineProto->API->method_call($params['_'], $params, ['datacenter' => $this->MadelineProto->API->datacenter->curdc]);
|
$result = $this->MadelineProto->API->method_call($params['_'], $params, ['datacenter' => $this->MadelineProto->API->datacenter->curdc]);
|
||||||
if (is_callable($cb)) {
|
if (\is_callable($cb)) {
|
||||||
$cb($this->MadelineProto->mtproto_to_td($result), $cb_extra);
|
$cb($this->MadelineProto->mtproto_to_td($result), $cb_extra);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ class Lua
|
|||||||
public function madeline_function($params, $cb = null, $cb_extra = null)
|
public function madeline_function($params, $cb = null, $cb_extra = null)
|
||||||
{
|
{
|
||||||
$result = $this->MadelineProto->API->method_call($params['_'], $params, ['datacenter' => $this->MadelineProto->API->datacenter->curdc]);
|
$result = $this->MadelineProto->API->method_call($params['_'], $params, ['datacenter' => $this->MadelineProto->API->datacenter->curdc]);
|
||||||
if (is_callable($cb)) {
|
if (\is_callable($cb)) {
|
||||||
$cb($result, $cb_extra);
|
$cb($result, $cb_extra);
|
||||||
}
|
}
|
||||||
self::convert_objects($result);
|
self::convert_objects($result);
|
||||||
@ -110,13 +110,13 @@ class Lua
|
|||||||
|
|
||||||
private function convert_array($array)
|
private function convert_array($array)
|
||||||
{
|
{
|
||||||
if (!is_array($array)) {
|
if (!\is_array($array)) {
|
||||||
return $array;
|
return $array;
|
||||||
}
|
}
|
||||||
if ($this->is_seqential($array)) {
|
if ($this->is_seqential($array)) {
|
||||||
return array_flip(array_map(function ($el) {
|
return \array_flip(\array_map(function ($el) {
|
||||||
return $el + 1;
|
return $el + 1;
|
||||||
}, array_flip($array)));
|
}, \array_flip($array)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,7 +126,7 @@ class Lua
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return isset($arr[0]) && array_keys($arr) === range(0, count($arr) - 1);
|
return isset($arr[0]) && \array_keys($arr) === \range(0, \count($arr) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __get($name)
|
public function __get($name)
|
||||||
@ -168,10 +168,10 @@ class Lua
|
|||||||
|
|
||||||
public static function convert_objects(&$data)
|
public static function convert_objects(&$data)
|
||||||
{
|
{
|
||||||
array_walk_recursive($data, function (&$value, $key) {
|
\array_walk_recursive($data, function (&$value, $key) {
|
||||||
if (is_object($value) && !$value instanceof \phpseclib\Math\BigInteger) {
|
if (\is_object($value) && !$value instanceof \phpseclib\Math\BigInteger) {
|
||||||
$newval = [];
|
$newval = [];
|
||||||
foreach (get_class_methods($value) as $name) {
|
foreach (\get_class_methods($value) as $name) {
|
||||||
$newval[$name] = [$value, $name];
|
$newval[$name] = [$value, $name];
|
||||||
}
|
}
|
||||||
foreach ($value as $key => $name) {
|
foreach ($value as $key => $name) {
|
||||||
|
@ -28,8 +28,6 @@ use danog\MadelineProto\Loop\Update\UpdateLoop;
|
|||||||
use danog\MadelineProto\MTProtoTools\CombinedUpdatesState;
|
use danog\MadelineProto\MTProtoTools\CombinedUpdatesState;
|
||||||
use danog\MadelineProto\MTProtoTools\ReferenceDatabase;
|
use danog\MadelineProto\MTProtoTools\ReferenceDatabase;
|
||||||
use danog\MadelineProto\MTProtoTools\UpdatesState;
|
use danog\MadelineProto\MTProtoTools\UpdatesState;
|
||||||
use danog\MadelineProto\Stream\MTProtoTransport\HttpsStream;
|
|
||||||
use danog\MadelineProto\Stream\MTProtoTransport\HttpStream;
|
|
||||||
use danog\MadelineProto\TL\TLCallback;
|
use danog\MadelineProto\TL\TLCallback;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1160,10 +1158,10 @@ class MTProto extends AsyncConstruct implements TLCallback
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if connected to datacenter using HTTP
|
* Check if connected to datacenter using HTTP.
|
||||||
*
|
*
|
||||||
* @param string $datacenter DC ID
|
* @param string $datacenter DC ID
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function isHttp(string $datacenter)
|
public function isHttp(string $datacenter)
|
||||||
|
@ -29,14 +29,14 @@ trait MsgIdHandler
|
|||||||
|
|
||||||
public function check_message_id($new_message_id, $aargs)
|
public function check_message_id($new_message_id, $aargs)
|
||||||
{
|
{
|
||||||
if (!is_object($new_message_id)) {
|
if (!\is_object($new_message_id)) {
|
||||||
$new_message_id = new \phpseclib\Math\BigInteger(strrev($new_message_id), 256);
|
$new_message_id = new \phpseclib\Math\BigInteger(\strrev($new_message_id), 256);
|
||||||
}
|
}
|
||||||
$min_message_id = (new \phpseclib\Math\BigInteger(time() + $this->time_delta - 300))->bitwise_leftShift(32);
|
$min_message_id = (new \phpseclib\Math\BigInteger(\time() + $this->time_delta - 300))->bitwise_leftShift(32);
|
||||||
if ($min_message_id->compare($new_message_id) > 0) {
|
if ($min_message_id->compare($new_message_id) > 0) {
|
||||||
$this->API->logger->logger('Given message id ('.$new_message_id.') is too old compared to the min value ('.$min_message_id.').', \danog\MadelineProto\Logger::WARNING);
|
$this->API->logger->logger('Given message id ('.$new_message_id.') is too old compared to the min value ('.$min_message_id.').', \danog\MadelineProto\Logger::WARNING);
|
||||||
}
|
}
|
||||||
$max_message_id = (new \phpseclib\Math\BigInteger(time() + $this->time_delta + 30))->bitwise_leftShift(32);
|
$max_message_id = (new \phpseclib\Math\BigInteger(\time() + $this->time_delta + 30))->bitwise_leftShift(32);
|
||||||
if ($max_message_id->compare($new_message_id) < 0) {
|
if ($max_message_id->compare($new_message_id) < 0) {
|
||||||
throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is too new compared to the max value ('.$max_message_id.'). Consider syncing your date.');
|
throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is too new compared to the max value ('.$max_message_id.'). Consider syncing your date.');
|
||||||
}
|
}
|
||||||
@ -47,15 +47,15 @@ trait MsgIdHandler
|
|||||||
if (!\danog\MadelineProto\Magic::$has_thread && $new_message_id->compare($key = $this->get_max_id($incoming = false)) <= 0) {
|
if (!\danog\MadelineProto\Magic::$has_thread && $new_message_id->compare($key = $this->get_max_id($incoming = false)) <= 0) {
|
||||||
throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is lower than or equal to the current limit ('.$key.'). Consider syncing your date.', 1);
|
throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is lower than or equal to the current limit ('.$key.'). Consider syncing your date.', 1);
|
||||||
}
|
}
|
||||||
if (count($this->outgoing_messages) > $this->API->settings['msg_array_limit']['outgoing']) {
|
if (\count($this->outgoing_messages) > $this->API->settings['msg_array_limit']['outgoing']) {
|
||||||
reset($this->outgoing_messages);
|
\reset($this->outgoing_messages);
|
||||||
$key = key($this->outgoing_messages);
|
$key = \key($this->outgoing_messages);
|
||||||
if (!isset($this->outgoing_messages[$key]['promise'])) {
|
if (!isset($this->outgoing_messages[$key]['promise'])) {
|
||||||
unset($this->outgoing_messages[$key]);
|
unset($this->outgoing_messages[$key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->max_outgoing_id = $new_message_id;
|
$this->max_outgoing_id = $new_message_id;
|
||||||
$this->outgoing_messages[strrev($new_message_id->toBytes())] = [];
|
$this->outgoing_messages[\strrev($new_message_id->toBytes())] = [];
|
||||||
} else {
|
} else {
|
||||||
if (!$new_message_id->divide(\danog\MadelineProto\Magic::$four)[1]->equals(\danog\MadelineProto\Magic::$one) && !$new_message_id->divide(\danog\MadelineProto\Magic::$four)[1]->equals(\danog\MadelineProto\Magic::$three)) {
|
if (!$new_message_id->divide(\danog\MadelineProto\Magic::$four)[1]->equals(\danog\MadelineProto\Magic::$one) && !$new_message_id->divide(\danog\MadelineProto\Magic::$four)[1]->equals(\danog\MadelineProto\Magic::$three)) {
|
||||||
throw new \danog\MadelineProto\Exception('message id mod 4 != 1 or 3');
|
throw new \danog\MadelineProto\Exception('message id mod 4 != 1 or 3');
|
||||||
@ -70,33 +70,33 @@ trait MsgIdHandler
|
|||||||
$this->API->logger->logger('WARNING: Given message id ('.$new_message_id.') is lower than or equal to the current limit ('.$key.'). Consider syncing your date.', \danog\MadelineProto\Logger::WARNING);
|
$this->API->logger->logger('WARNING: Given message id ('.$new_message_id.') is lower than or equal to the current limit ('.$key.'). Consider syncing your date.', \danog\MadelineProto\Logger::WARNING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (count($this->incoming_messages) > $this->API->settings['msg_array_limit']['incoming']) {
|
if (\count($this->incoming_messages) > $this->API->settings['msg_array_limit']['incoming']) {
|
||||||
reset($this->incoming_messages);
|
\reset($this->incoming_messages);
|
||||||
$key = key($this->incoming_messages);
|
$key = \key($this->incoming_messages);
|
||||||
if (!isset($this->incoming_messages[$key]['promise'])) {
|
if (!isset($this->incoming_messages[$key]['promise'])) {
|
||||||
unset($this->incoming_messages[$key]);
|
unset($this->incoming_messages[$key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->max_incoming_id = $new_message_id;
|
$this->max_incoming_id = $new_message_id;
|
||||||
$this->incoming_messages[strrev($new_message_id->toBytes())] = [];
|
$this->incoming_messages[\strrev($new_message_id->toBytes())] = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generate_message_id()
|
public function generate_message_id()
|
||||||
{
|
{
|
||||||
$message_id = (new \phpseclib\Math\BigInteger(time() + $this->time_delta))->bitwise_leftShift(32);
|
$message_id = (new \phpseclib\Math\BigInteger(\time() + $this->time_delta))->bitwise_leftShift(32);
|
||||||
if ($message_id->compare($key = $this->get_max_id($incoming = false)) <= 0) {
|
if ($message_id->compare($key = $this->get_max_id($incoming = false)) <= 0) {
|
||||||
$message_id = $key->add(\danog\MadelineProto\Magic::$four);
|
$message_id = $key->add(\danog\MadelineProto\Magic::$four);
|
||||||
}
|
}
|
||||||
$this->check_message_id($message_id, ['outgoing' => true, 'container' => false]);
|
$this->check_message_id($message_id, ['outgoing' => true, 'container' => false]);
|
||||||
|
|
||||||
return strrev($message_id->toBytes());
|
return \strrev($message_id->toBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get_max_id($incoming)
|
public function get_max_id($incoming)
|
||||||
{
|
{
|
||||||
$incoming = $incoming ? 'incoming' : 'outgoing';
|
$incoming = $incoming ? 'incoming' : 'outgoing';
|
||||||
if (isset($this->{'max_'.$incoming.'_id'}) && is_object($this->{'max_'.$incoming.'_id'})) {
|
if (isset($this->{'max_'.$incoming.'_id'}) && \is_object($this->{'max_'.$incoming.'_id'})) {
|
||||||
return $this->{'max_'.$incoming.'_id'};
|
return $this->{'max_'.$incoming.'_id'};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,5 +65,4 @@ trait SeqNoHandler
|
|||||||
|
|
||||||
return \is_string($method) ? !\in_array($method, MTProto::NOT_CONTENT_RELATED) : true;
|
return \is_string($method) ? !\in_array($method, MTProto::NOT_CONTENT_RELATED) : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ abstract class Session
|
|||||||
$this->max_outgoing_id = null;
|
$this->max_outgoing_id = null;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Create MTProto session if needed
|
* Create MTProto session if needed.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
|
@ -68,4 +68,4 @@ trait CallHandler
|
|||||||
{
|
{
|
||||||
return $this->datacenter->getConnection($aargs['datacenter'] ?? $this->datacenter->curdc)->method_call_async_write($method, $args, $aargs);
|
return $this->datacenter->getConnection($aargs['datacenter'] ?? $this->datacenter->curdc)->method_call_async_write($method, $args, $aargs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,11 +29,11 @@ class CombinedUpdatesState
|
|||||||
public function __construct($init = [])
|
public function __construct($init = [])
|
||||||
{
|
{
|
||||||
$this->states[false] = new UpdatesState();
|
$this->states[false] = new UpdatesState();
|
||||||
if (!is_array($init)) {
|
if (!\is_array($init)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
foreach ($init as $channel => $state) {
|
foreach ($init as $channel => $state) {
|
||||||
if (is_array($state)) {
|
if (\is_array($state)) {
|
||||||
$state = new UpdatesState($state, $channel);
|
$state = new UpdatesState($state, $channel);
|
||||||
}
|
}
|
||||||
$this->states[$channel] = $state;
|
$this->states[$channel] = $state;
|
||||||
|
@ -24,10 +24,10 @@ trait Crypt
|
|||||||
public function aes_calculate($msg_key, $auth_key, $to_server = true)
|
public function aes_calculate($msg_key, $auth_key, $to_server = true)
|
||||||
{
|
{
|
||||||
$x = $to_server ? 0 : 8;
|
$x = $to_server ? 0 : 8;
|
||||||
$sha256_a = hash('sha256', $msg_key.substr($auth_key, $x, 36), true);
|
$sha256_a = \hash('sha256', $msg_key.\substr($auth_key, $x, 36), true);
|
||||||
$sha256_b = hash('sha256', substr($auth_key, 40 + $x, 36).$msg_key, true);
|
$sha256_b = \hash('sha256', \substr($auth_key, 40 + $x, 36).$msg_key, true);
|
||||||
$aes_key = substr($sha256_a, 0, 8).substr($sha256_b, 8, 16).substr($sha256_a, 24, 8);
|
$aes_key = \substr($sha256_a, 0, 8).\substr($sha256_b, 8, 16).\substr($sha256_a, 24, 8);
|
||||||
$aes_iv = substr($sha256_b, 0, 8).substr($sha256_a, 8, 16).substr($sha256_b, 24, 8);
|
$aes_iv = \substr($sha256_b, 0, 8).\substr($sha256_a, 8, 16).\substr($sha256_b, 24, 8);
|
||||||
|
|
||||||
return [$aes_key, $aes_iv];
|
return [$aes_key, $aes_iv];
|
||||||
}
|
}
|
||||||
@ -35,12 +35,12 @@ trait Crypt
|
|||||||
public function old_aes_calculate($msg_key, $auth_key, $to_server = true)
|
public function old_aes_calculate($msg_key, $auth_key, $to_server = true)
|
||||||
{
|
{
|
||||||
$x = $to_server ? 0 : 8;
|
$x = $to_server ? 0 : 8;
|
||||||
$sha1_a = sha1($msg_key.substr($auth_key, $x, 32), true);
|
$sha1_a = \sha1($msg_key.\substr($auth_key, $x, 32), true);
|
||||||
$sha1_b = sha1(substr($auth_key, 32 + $x, 16).$msg_key.substr($auth_key, 48 + $x, 16), true);
|
$sha1_b = \sha1(\substr($auth_key, 32 + $x, 16).$msg_key.\substr($auth_key, 48 + $x, 16), true);
|
||||||
$sha1_c = sha1(substr($auth_key, 64 + $x, 32).$msg_key, true);
|
$sha1_c = \sha1(\substr($auth_key, 64 + $x, 32).$msg_key, true);
|
||||||
$sha1_d = sha1($msg_key.substr($auth_key, 96 + $x, 32), true);
|
$sha1_d = \sha1($msg_key.\substr($auth_key, 96 + $x, 32), true);
|
||||||
$aes_key = substr($sha1_a, 0, 8).substr($sha1_b, 8, 12).substr($sha1_c, 4, 12);
|
$aes_key = \substr($sha1_a, 0, 8).\substr($sha1_b, 8, 12).\substr($sha1_c, 4, 12);
|
||||||
$aes_iv = substr($sha1_a, 8, 12).substr($sha1_b, 0, 8).substr($sha1_c, 16, 4).substr($sha1_d, 0, 8);
|
$aes_iv = \substr($sha1_a, 8, 12).\substr($sha1_b, 0, 8).\substr($sha1_c, 16, 4).\substr($sha1_d, 0, 8);
|
||||||
|
|
||||||
return [$aes_key, $aes_iv];
|
return [$aes_key, $aes_iv];
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ use danog\MadelineProto\Tools;
|
|||||||
use phpseclib\Math\BigInteger;
|
use phpseclib\Math\BigInteger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages SRP password calculation
|
* Manages SRP password calculation.
|
||||||
*
|
*
|
||||||
* @author Daniil Gentili <daniil@daniil.it>
|
* @author Daniil Gentili <daniil@daniil.it>
|
||||||
* @link https://docs.madelineproto.xyz MadelineProto documentation
|
* @link https://docs.madelineproto.xyz MadelineProto documentation
|
||||||
@ -34,54 +34,54 @@ class PasswordCalculator
|
|||||||
{
|
{
|
||||||
use AuthKeyHandler;
|
use AuthKeyHandler;
|
||||||
use Tools;
|
use Tools;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The algorithm to use for calculating the hash of new passwords (a PasswordKdfAlgo object)
|
* The algorithm to use for calculating the hash of new passwords (a PasswordKdfAlgo object).
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private $new_algo;
|
private $new_algo;
|
||||||
/**
|
/**
|
||||||
* A secure random string that can be used to compute the password
|
* A secure random string that can be used to compute the password.
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $secure_random = '';
|
private $secure_random = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The algorithm to use for calculatuing the hash of the current password (a PasswordKdfAlgo object)
|
* The algorithm to use for calculatuing the hash of the current password (a PasswordKdfAlgo object).
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private $current_algo;
|
private $current_algo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SRP b parameter
|
* SRP b parameter.
|
||||||
*
|
*
|
||||||
* @var BigInteger
|
* @var BigInteger
|
||||||
*/
|
*/
|
||||||
private $srp_B;
|
private $srp_B;
|
||||||
/**
|
/**
|
||||||
* SRP b parameter for hashing
|
* SRP b parameter for hashing.
|
||||||
*
|
*
|
||||||
* @var BigInteger
|
* @var BigInteger
|
||||||
*/
|
*/
|
||||||
private $srp_BForHash;
|
private $srp_BForHash;
|
||||||
/**
|
/**
|
||||||
* SRP ID
|
* SRP ID.
|
||||||
*
|
*
|
||||||
* @var [type]
|
* @var [type]
|
||||||
*/
|
*/
|
||||||
private $srp_id;
|
private $srp_id;
|
||||||
/**
|
/**
|
||||||
* Logger
|
* Logger.
|
||||||
*
|
*
|
||||||
* @var \danog\MadelineProto\Logger
|
* @var \danog\MadelineProto\Logger
|
||||||
*/
|
*/
|
||||||
public $logger;
|
public $logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize logger
|
* Initialize logger.
|
||||||
*
|
*
|
||||||
* @param \danog\MadelineProto\Logger $logger
|
* @param \danog\MadelineProto\Logger $logger
|
||||||
*/
|
*/
|
||||||
@ -91,7 +91,7 @@ class PasswordCalculator
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Popupate 2FA configuration
|
* Popupate 2FA configuration.
|
||||||
*
|
*
|
||||||
* @param array $object 2FA configuration object obtained using account.getPassword
|
* @param array $object 2FA configuration object obtained using account.getPassword
|
||||||
* @return void
|
* @return void
|
||||||
@ -112,8 +112,8 @@ class PasswordCalculator
|
|||||||
$object['current_algo']['g'] = new BigInteger($object['current_algo']['g']);
|
$object['current_algo']['g'] = new BigInteger($object['current_algo']['g']);
|
||||||
$object['current_algo']['p'] = new BigInteger((string) $object['current_algo']['p'], 256);
|
$object['current_algo']['p'] = new BigInteger((string) $object['current_algo']['p'], 256);
|
||||||
$this->check_p_g($object['current_algo']['p'], $object['current_algo']['g']);
|
$this->check_p_g($object['current_algo']['p'], $object['current_algo']['g']);
|
||||||
$object['current_algo']['gForHash'] = str_pad($object['current_algo']['g']->toBytes(), 256, chr(0), \STR_PAD_LEFT);
|
$object['current_algo']['gForHash'] = \str_pad($object['current_algo']['g']->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
|
||||||
$object['current_algo']['pForHash'] = str_pad($object['current_algo']['p']->toBytes(), 256, chr(0), \STR_PAD_LEFT);
|
$object['current_algo']['pForHash'] = \str_pad($object['current_algo']['p']->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -128,7 +128,7 @@ class PasswordCalculator
|
|||||||
throw new SecurityException('srp_B > p');
|
throw new SecurityException('srp_B > p');
|
||||||
}
|
}
|
||||||
$this->srp_B = $object['srp_B'];
|
$this->srp_B = $object['srp_B'];
|
||||||
$this->srp_BForHash = str_pad($object['srp_B']->toBytes(), 256, chr(0), \STR_PAD_LEFT);
|
$this->srp_BForHash = \str_pad($object['srp_B']->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
|
||||||
$this->srp_id = $object['srp_id'];
|
$this->srp_id = $object['srp_id'];
|
||||||
} else {
|
} else {
|
||||||
$this->current_algo = null;
|
$this->current_algo = null;
|
||||||
@ -143,8 +143,8 @@ class PasswordCalculator
|
|||||||
$object['new_algo']['g'] = new BigInteger($object['new_algo']['g']);
|
$object['new_algo']['g'] = new BigInteger($object['new_algo']['g']);
|
||||||
$object['new_algo']['p'] = new BigInteger((string) $object['new_algo']['p'], 256);
|
$object['new_algo']['p'] = new BigInteger((string) $object['new_algo']['p'], 256);
|
||||||
$this->check_p_g($object['new_algo']['p'], $object['new_algo']['g']);
|
$this->check_p_g($object['new_algo']['p'], $object['new_algo']['g']);
|
||||||
$object['new_algo']['gForHash'] = str_pad($object['new_algo']['g']->toBytes(), 256, chr(0), \STR_PAD_LEFT);
|
$object['new_algo']['gForHash'] = \str_pad($object['new_algo']['g']->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
|
||||||
$object['new_algo']['pForHash'] = str_pad($object['new_algo']['p']->toBytes(), 256, chr(0), \STR_PAD_LEFT);
|
$object['new_algo']['pForHash'] = \str_pad($object['new_algo']['p']->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -155,7 +155,7 @@ class PasswordCalculator
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a random string (eventually prefixed by the specified string)
|
* Create a random string (eventually prefixed by the specified string).
|
||||||
*
|
*
|
||||||
* @param string $prefix Prefix
|
* @param string $prefix Prefix
|
||||||
* @return string Salt
|
* @return string Salt
|
||||||
@ -166,8 +166,8 @@ class PasswordCalculator
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hash specified data using the salt with SHA256
|
* Hash specified data using the salt with SHA256.
|
||||||
*
|
*
|
||||||
* The result will be the SHA256 hash of the salt concatenated with the data concatenated with the salt
|
* The result will be the SHA256 hash of the salt concatenated with the data concatenated with the salt
|
||||||
*
|
*
|
||||||
* @param string $data Data to hash
|
* @param string $data Data to hash
|
||||||
@ -176,11 +176,11 @@ class PasswordCalculator
|
|||||||
*/
|
*/
|
||||||
public function hashSha256(string $data, string $salt): string
|
public function hashSha256(string $data, string $salt): string
|
||||||
{
|
{
|
||||||
return hash('sha256', $salt.$data.$salt, true);
|
return \hash('sha256', $salt.$data.$salt, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hashes the specified password
|
* Hashes the specified password.
|
||||||
*
|
*
|
||||||
* @param string $password Password
|
* @param string $password Password
|
||||||
* @param string $client_salt Client salt
|
* @param string $client_salt Client salt
|
||||||
@ -191,13 +191,13 @@ class PasswordCalculator
|
|||||||
{
|
{
|
||||||
$buf = $this->hashSha256($password, $client_salt);
|
$buf = $this->hashSha256($password, $client_salt);
|
||||||
$buf = $this->hashSha256($buf, $server_salt);
|
$buf = $this->hashSha256($buf, $server_salt);
|
||||||
$hash = hash_pbkdf2('sha512', $buf, $client_salt, 100000, 0, true);
|
$hash = \hash_pbkdf2('sha512', $buf, $client_salt, 100000, 0, true);
|
||||||
|
|
||||||
return $this->hashSha256($hash, $server_salt);
|
return $this->hashSha256($hash, $server_salt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the InputCheckPassword object for checking the validity of a password using account.checkPassword
|
* Get the InputCheckPassword object for checking the validity of a password using account.checkPassword.
|
||||||
*
|
*
|
||||||
* @param string $password The password
|
* @param string $password The password
|
||||||
* @return array InputCheckPassword object
|
* @return array InputCheckPassword object
|
||||||
@ -213,7 +213,7 @@ class PasswordCalculator
|
|||||||
$gForHash = $this->current_algo['gForHash'];
|
$gForHash = $this->current_algo['gForHash'];
|
||||||
$p = $this->current_algo['p'];
|
$p = $this->current_algo['p'];
|
||||||
$pForHash = $this->current_algo['pForHash'];
|
$pForHash = $this->current_algo['pForHash'];
|
||||||
|
|
||||||
$B = $this->srp_B;
|
$B = $this->srp_B;
|
||||||
$BForHash = $this->srp_BForHash;
|
$BForHash = $this->srp_BForHash;
|
||||||
$id = $this->srp_id;
|
$id = $this->srp_id;
|
||||||
@ -221,39 +221,39 @@ class PasswordCalculator
|
|||||||
$x = new BigInteger($this->hashPassword($password, $client_salt, $server_salt), 256);
|
$x = new BigInteger($this->hashPassword($password, $client_salt, $server_salt), 256);
|
||||||
$g_x = $g->powMod($x, $p);
|
$g_x = $g->powMod($x, $p);
|
||||||
|
|
||||||
$k = new BigInteger(hash('sha256', $pForHash.$gForHash, true), 256);
|
$k = new BigInteger(\hash('sha256', $pForHash.$gForHash, true), 256);
|
||||||
$kg_x = $k->multiply($g_x)->powMod(Magic::$one, $p);
|
$kg_x = $k->multiply($g_x)->powMod(Magic::$one, $p);
|
||||||
|
|
||||||
$a = new BigInteger($this->random(2048 / 8), 256);
|
$a = new BigInteger($this->random(2048 / 8), 256);
|
||||||
$A = $g->powMod($a, $p);
|
$A = $g->powMod($a, $p);
|
||||||
$this->check_G($A, $p);
|
$this->check_G($A, $p);
|
||||||
$AForHash = str_pad($A->toBytes(), 256, chr(0), \STR_PAD_LEFT);
|
$AForHash = \str_pad($A->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
|
||||||
|
|
||||||
$b_kg_x = $B->powMod(Magic::$one, $p)->subtract($kg_x);
|
$b_kg_x = $B->powMod(Magic::$one, $p)->subtract($kg_x);
|
||||||
|
|
||||||
$u = new BigInteger(hash('sha256', $AForHash.$BForHash, true), 256);
|
$u = new BigInteger(\hash('sha256', $AForHash.$BForHash, true), 256);
|
||||||
$ux = $u->multiply($x);
|
$ux = $u->multiply($x);
|
||||||
$a_ux = $a->add($ux);
|
$a_ux = $a->add($ux);
|
||||||
|
|
||||||
$S = $b_kg_x->powMod($a_ux, $p);
|
$S = $b_kg_x->powMod($a_ux, $p);
|
||||||
|
|
||||||
$SForHash = str_pad($S->toBytes(), 256, chr(0), \STR_PAD_LEFT);
|
$SForHash = \str_pad($S->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
|
||||||
$K = hash('sha256', $SForHash, true);
|
$K = \hash('sha256', $SForHash, true);
|
||||||
|
|
||||||
$h1 = hash('sha256', $pForHash, true);
|
$h1 = \hash('sha256', $pForHash, true);
|
||||||
$h2 = hash('sha256', $gForHash, true);
|
$h2 = \hash('sha256', $gForHash, true);
|
||||||
$h1 ^= $h2;
|
$h1 ^= $h2;
|
||||||
|
|
||||||
$M1 = hash('sha256', $h1.hash('sha256', $client_salt, true).hash('sha256', $server_salt, true).$AForHash.$BForHash.$K, true);
|
$M1 = \hash('sha256', $h1.\hash('sha256', $client_salt, true).\hash('sha256', $server_salt, true).$AForHash.$BForHash.$K, true);
|
||||||
|
|
||||||
return ['_' => 'inputCheckPasswordSRP', 'srp_id' => $id, 'A' => $AForHash, 'M1' => $M1];
|
return ['_' => 'inputCheckPasswordSRP', 'srp_id' => $id, 'A' => $AForHash, 'M1' => $M1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get parameters to be passed to the account.updatePasswordSettings to update/set a 2FA password
|
* Get parameters to be passed to the account.updatePasswordSettings to update/set a 2FA password.
|
||||||
*
|
*
|
||||||
* The input params array can contain password, new_password, email and hint params.
|
* The input params array can contain password, new_password, email and hint params.
|
||||||
*
|
*
|
||||||
* @param array $params Input params
|
* @param array $params Input params
|
||||||
* @return array account.updatePasswordSettings parameters
|
* @return array account.updatePasswordSettings parameters
|
||||||
*/
|
*/
|
||||||
@ -262,7 +262,7 @@ class PasswordCalculator
|
|||||||
$oldPassword = $this->getCheckPassword($params['password'] ?? '');
|
$oldPassword = $this->getCheckPassword($params['password'] ?? '');
|
||||||
|
|
||||||
$return = ['password' => $oldPassword, 'new_settings' => ['_' => 'account.passwordInputSettings', 'new_algo' => ['_' => 'passwordKdfAlgoUnknown'], 'new_password_hash' => '', 'hint' => '']];
|
$return = ['password' => $oldPassword, 'new_settings' => ['_' => 'account.passwordInputSettings', 'new_algo' => ['_' => 'passwordKdfAlgoUnknown'], 'new_password_hash' => '', 'hint' => '']];
|
||||||
|
|
||||||
$new_settings = &$return['new_settings'];
|
$new_settings = &$return['new_settings'];
|
||||||
|
|
||||||
if (isset($params['new_password']) && $params['new_password'] !== '') {
|
if (isset($params['new_password']) && $params['new_password'] !== '') {
|
||||||
@ -274,7 +274,7 @@ class PasswordCalculator
|
|||||||
|
|
||||||
$x = new BigInteger($this->hashPassword($params['new_password'], $client_salt, $server_salt), 256);
|
$x = new BigInteger($this->hashPassword($params['new_password'], $client_salt, $server_salt), 256);
|
||||||
$v = $g->powMod($x, $p);
|
$v = $g->powMod($x, $p);
|
||||||
$vForHash = str_pad($v->toBytes(), 256, chr(0), \STR_PAD_LEFT);
|
$vForHash = \str_pad($v->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
|
||||||
|
|
||||||
$new_settings['new_algo'] = [
|
$new_settings['new_algo'] = [
|
||||||
'_' => 'passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow',
|
'_' => 'passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow',
|
||||||
|
@ -32,19 +32,19 @@ trait PeerHandler
|
|||||||
|
|
||||||
public function to_supergroup($id)
|
public function to_supergroup($id)
|
||||||
{
|
{
|
||||||
return -($id + pow(10, (int) floor(log($id, 10) + 3)));
|
return -($id + \pow(10, (int) \floor(\log($id, 10) + 3)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function from_supergroup($id)
|
public function from_supergroup($id)
|
||||||
{
|
{
|
||||||
return -$id - pow(10, (int) floor(log(-$id, 10)));
|
return -$id - \pow(10, (int) \floor(\log(-$id, 10)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function is_supergroup($id)
|
public function is_supergroup($id)
|
||||||
{
|
{
|
||||||
$log = log(-$id, 10);
|
$log = \log(-$id, 10);
|
||||||
|
|
||||||
return ($log - intval($log)) * 1000 < 10;
|
return ($log - \intval($log)) * 1000 < 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function add_support($support)
|
public function add_support($support)
|
||||||
@ -84,6 +84,7 @@ trait PeerHandler
|
|||||||
$this->chats[$user['id']] = $user;
|
$this->chats[$user['id']] = $user;
|
||||||
$this->cache_pwr_chat($user['id'], false, true);
|
$this->cache_pwr_chat($user['id'], false, true);
|
||||||
}
|
}
|
||||||
|
// no break
|
||||||
case 'userEmpty':
|
case 'userEmpty':
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -137,7 +138,7 @@ trait PeerHandler
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new \danog\MadelineProto\Exception('Invalid chat provided at key '.$key.': '.var_export($chat, true));
|
throw new \danog\MadelineProto\Exception('Invalid chat provided at key '.$key.': '.\var_export($chat, true));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -208,7 +209,7 @@ trait PeerHandler
|
|||||||
|
|
||||||
public function get_folder_id($id)
|
public function get_folder_id($id)
|
||||||
{
|
{
|
||||||
if (!is_array($id)) {
|
if (!\is_array($id)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (!isset($id['folder_id'])) {
|
if (!isset($id['folder_id'])) {
|
||||||
@ -218,12 +219,13 @@ trait PeerHandler
|
|||||||
}
|
}
|
||||||
public function get_id($id)
|
public function get_id($id)
|
||||||
{
|
{
|
||||||
if (is_array($id)) {
|
if (\is_array($id)) {
|
||||||
switch ($id['_']) {
|
switch ($id['_']) {
|
||||||
case 'updateDialogPinned':
|
case 'updateDialogPinned':
|
||||||
case 'updateDialogUnreadMark':
|
case 'updateDialogUnreadMark':
|
||||||
case 'updateNotifySettings':
|
case 'updateNotifySettings':
|
||||||
$id = $id['peer'];
|
$id = $id['peer'];
|
||||||
|
// no break
|
||||||
case 'updateDraftMessage':
|
case 'updateDraftMessage':
|
||||||
case 'inputDialogPeer':
|
case 'inputDialogPeer':
|
||||||
case 'dialogPeer':
|
case 'dialogPeer':
|
||||||
@ -291,6 +293,7 @@ trait PeerHandler
|
|||||||
return $this->to_supergroup($id['channel_id']);
|
return $this->to_supergroup($id['channel_id']);
|
||||||
case 'updateChatParticipants':
|
case 'updateChatParticipants':
|
||||||
$id = $id['participants'];
|
$id = $id['participants'];
|
||||||
|
// no break
|
||||||
case 'updateChatUserTyping':
|
case 'updateChatUserTyping':
|
||||||
case 'updateChatParticipantAdd':
|
case 'updateChatParticipantAdd':
|
||||||
case 'updateChatParticipantDelete':
|
case 'updateChatParticipantDelete':
|
||||||
@ -325,24 +328,24 @@ trait PeerHandler
|
|||||||
case 'updateEditChannelMessage':
|
case 'updateEditChannelMessage':
|
||||||
return $this->get_id($id['message']);
|
return $this->get_id($id['message']);
|
||||||
default:
|
default:
|
||||||
throw new \danog\MadelineProto\Exception('Invalid constructor given '.var_export($id, true));
|
throw new \danog\MadelineProto\Exception('Invalid constructor given '.\var_export($id, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_string($id)) {
|
if (\is_string($id)) {
|
||||||
if (strpos($id, '#') !== false) {
|
if (\strpos($id, '#') !== false) {
|
||||||
if (preg_match('/^channel#(\d*)/', $id, $matches)) {
|
if (\preg_match('/^channel#(\d*)/', $id, $matches)) {
|
||||||
return $this->to_supergroup($matches[1]);
|
return $this->to_supergroup($matches[1]);
|
||||||
}
|
}
|
||||||
if (preg_match('/^chat#(\d*)/', $id, $matches)) {
|
if (\preg_match('/^chat#(\d*)/', $id, $matches)) {
|
||||||
$id = '-'.$matches[1];
|
$id = '-'.$matches[1];
|
||||||
}
|
}
|
||||||
if (preg_match('/^user#(\d*)/', $id, $matches)) {
|
if (\preg_match('/^user#(\d*)/', $id, $matches)) {
|
||||||
return $matches[1];
|
return $matches[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_numeric($id)) {
|
if (\is_numeric($id)) {
|
||||||
if (is_string($id)) {
|
if (\is_string($id)) {
|
||||||
$id = \danog\MadelineProto\Magic::$bigint ? (float) $id : (int) $id;
|
$id = \danog\MadelineProto\Magic::$bigint ? (float) $id : (int) $id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,7 +357,7 @@ trait PeerHandler
|
|||||||
|
|
||||||
public function get_info_async($id, $recursive = true)
|
public function get_info_async($id, $recursive = true)
|
||||||
{
|
{
|
||||||
if (is_array($id)) {
|
if (\is_array($id)) {
|
||||||
switch ($id['_']) {
|
switch ($id['_']) {
|
||||||
case 'updateEncryption':
|
case 'updateEncryption':
|
||||||
return $this->get_secret_chat($id['chat']['id']);
|
return $this->get_secret_chat($id['chat']['id']);
|
||||||
@ -364,6 +367,7 @@ trait PeerHandler
|
|||||||
return $this->get_secret_chat($id['chat_id']);
|
return $this->get_secret_chat($id['chat_id']);
|
||||||
case 'updateNewEncryptedMessage':
|
case 'updateNewEncryptedMessage':
|
||||||
$id = $id['message'];
|
$id = $id['message'];
|
||||||
|
// no break
|
||||||
case 'encryptedMessage':
|
case 'encryptedMessage':
|
||||||
case 'encryptedMessageService':
|
case 'encryptedMessageService':
|
||||||
$id = $id['chat_id'];
|
$id = $id['chat_id'];
|
||||||
@ -382,7 +386,7 @@ trait PeerHandler
|
|||||||
|
|
||||||
$tried_simple = false;
|
$tried_simple = false;
|
||||||
|
|
||||||
if (is_numeric($id)) {
|
if (\is_numeric($id)) {
|
||||||
if (!isset($this->chats[$id])) {
|
if (!isset($this->chats[$id])) {
|
||||||
try {
|
try {
|
||||||
$this->caching_simple[$id] = true;
|
$this->caching_simple[$id] = true;
|
||||||
@ -421,7 +425,7 @@ trait PeerHandler
|
|||||||
$dbres = [];
|
$dbres = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$dbres = json_decode(yield $this->datacenter->fileGetContents('https://id.pwrtelegram.xyz/db/getusername?id='.$id), true);
|
$dbres = \json_decode(yield $this->datacenter->fileGetContents('https://id.pwrtelegram.xyz/db/getusername?id='.$id), true);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->logger->logger($e);
|
$this->logger->logger($e);
|
||||||
}
|
}
|
||||||
@ -442,19 +446,18 @@ trait PeerHandler
|
|||||||
|
|
||||||
throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database');
|
throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database');
|
||||||
}
|
}
|
||||||
if (preg_match('@(?:t|telegram)\.(?:me|dog)/(joinchat/)?([a-z0-9_-]*)@i', $id, $matches)) {
|
if (\preg_match('@(?:t|telegram)\.(?:me|dog)/(joinchat/)?([a-z0-9_-]*)@i', $id, $matches)) {
|
||||||
if ($matches[1] === '') {
|
if ($matches[1] === '') {
|
||||||
$id = $matches[2];
|
$id = $matches[2];
|
||||||
} else {
|
} else {
|
||||||
$invite = yield $this->method_call_async_read('messages.checkChatInvite', ['hash' => $matches[2]], ['datacenter' => $this->datacenter->curdc]);
|
$invite = yield $this->method_call_async_read('messages.checkChatInvite', ['hash' => $matches[2]], ['datacenter' => $this->datacenter->curdc]);
|
||||||
if (isset($invite['chat'])) {
|
if (isset($invite['chat'])) {
|
||||||
return yield $this->get_info_async($invite['chat']);
|
return yield $this->get_info_async($invite['chat']);
|
||||||
} else {
|
|
||||||
throw new \danog\MadelineProto\Exception('You have not joined this chat');
|
|
||||||
}
|
}
|
||||||
|
throw new \danog\MadelineProto\Exception('You have not joined this chat');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$id = strtolower(str_replace('@', '', $id));
|
$id = \strtolower(\str_replace('@', '', $id));
|
||||||
if ($id === 'me') {
|
if ($id === 'me') {
|
||||||
return yield $this->get_info_async($this->authorization['user']['id']);
|
return yield $this->get_info_async($this->authorization['user']['id']);
|
||||||
}
|
}
|
||||||
@ -466,7 +469,7 @@ trait PeerHandler
|
|||||||
return yield $this->get_info_async($this->supportUser);
|
return yield $this->get_info_async($this->supportUser);
|
||||||
}
|
}
|
||||||
foreach ($this->chats as $chat) {
|
foreach ($this->chats as $chat) {
|
||||||
if (isset($chat['username']) && strtolower($chat['username']) === $id) {
|
if (isset($chat['username']) && \strtolower($chat['username']) === $id) {
|
||||||
return $this->gen_all($chat, $folder_id);
|
return $this->gen_all($chat, $folder_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -532,7 +535,7 @@ trait PeerHandler
|
|||||||
case 'channelForbidden':
|
case 'channelForbidden':
|
||||||
throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database');
|
throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database');
|
||||||
default:
|
default:
|
||||||
throw new \danog\MadelineProto\Exception('Invalid constructor given '.var_export($constructor, true));
|
throw new \danog\MadelineProto\Exception('Invalid constructor given '.\var_export($constructor, true));
|
||||||
}
|
}
|
||||||
if ($folder_id) {
|
if ($folder_id) {
|
||||||
$res['FolderPeer'] = ['_' => 'folderPeer', 'peer' => $res['Peer'], 'folder_id' => $folder_id];
|
$res['FolderPeer'] = ['_' => 'folderPeer', 'peer' => $res['Peer'], 'folder_id' => $folder_id];
|
||||||
@ -549,8 +552,8 @@ trait PeerHandler
|
|||||||
public function get_full_info_async($id)
|
public function get_full_info_async($id)
|
||||||
{
|
{
|
||||||
$partial = yield $this->get_info_async($id);
|
$partial = yield $this->get_info_async($id);
|
||||||
if (time() - $this->full_chat_last_updated($partial['bot_api_id']) < (isset($this->settings['peer']['full_info_cache_time']) ? $this->settings['peer']['full_info_cache_time'] : 0)) {
|
if (\time() - $this->full_chat_last_updated($partial['bot_api_id']) < (isset($this->settings['peer']['full_info_cache_time']) ? $this->settings['peer']['full_info_cache_time'] : 0)) {
|
||||||
return array_merge($partial, $this->full_chats[$partial['bot_api_id']]);
|
return \array_merge($partial, $this->full_chats[$partial['bot_api_id']]);
|
||||||
}
|
}
|
||||||
switch ($partial['type']) {
|
switch ($partial['type']) {
|
||||||
case 'user':
|
case 'user':
|
||||||
@ -568,12 +571,12 @@ trait PeerHandler
|
|||||||
|
|
||||||
$res = [];
|
$res = [];
|
||||||
$res['full'] = $full;
|
$res['full'] = $full;
|
||||||
$res['last_update'] = time();
|
$res['last_update'] = \time();
|
||||||
$this->full_chats[$partial['bot_api_id']] = $res;
|
$this->full_chats[$partial['bot_api_id']] = $res;
|
||||||
|
|
||||||
$partial = yield $this->get_info_async($id);
|
$partial = yield $this->get_info_async($id);
|
||||||
|
|
||||||
return array_merge($partial, $res);
|
return \array_merge($partial, $res);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get_pwr_chat_async($id, $fullfetch = true, $send = true)
|
public function get_pwr_chat_async($id, $fullfetch = true, $send = true)
|
||||||
@ -594,7 +597,7 @@ trait PeerHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isset($full['full']['profile_photo']['sizes'])) {
|
if (isset($full['full']['profile_photo']['sizes'])) {
|
||||||
$res['photo'] = yield $this->photosize_to_botapi_async(end($full['full']['profile_photo']['sizes']), $full['full']['profile_photo']);
|
$res['photo'] = yield $this->photosize_to_botapi_async(\end($full['full']['profile_photo']['sizes']), $full['full']['profile_photo']);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'chat':
|
case 'chat':
|
||||||
@ -612,7 +615,7 @@ trait PeerHandler
|
|||||||
$res['all_members_are_administrators'] = !$res['admins_enabled'];
|
$res['all_members_are_administrators'] = !$res['admins_enabled'];
|
||||||
}
|
}
|
||||||
if (isset($full['full']['chat_photo']['sizes'])) {
|
if (isset($full['full']['chat_photo']['sizes'])) {
|
||||||
$res['photo'] = yield $this->photosize_to_botapi_async(end($full['full']['chat_photo']['sizes']), $full['full']['chat_photo']);
|
$res['photo'] = yield $this->photosize_to_botapi_async(\end($full['full']['chat_photo']['sizes']), $full['full']['chat_photo']);
|
||||||
}
|
}
|
||||||
if (isset($full['full']['exported_invite']['link'])) {
|
if (isset($full['full']['exported_invite']['link'])) {
|
||||||
$res['invite'] = $full['full']['exported_invite']['link'];
|
$res['invite'] = $full['full']['exported_invite']['link'];
|
||||||
@ -634,7 +637,7 @@ trait PeerHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isset($full['full']['chat_photo']['sizes'])) {
|
if (isset($full['full']['chat_photo']['sizes'])) {
|
||||||
$res['photo'] = yield $this->photosize_to_botapi_async(end($full['full']['chat_photo']['sizes']), $full['full']['chat_photo']);
|
$res['photo'] = yield $this->photosize_to_botapi_async(\end($full['full']['chat_photo']['sizes']), $full['full']['chat_photo']);
|
||||||
}
|
}
|
||||||
if (isset($full['full']['exported_invite']['link'])) {
|
if (isset($full['full']['exported_invite']['link'])) {
|
||||||
$res['invite'] = $full['full']['exported_invite']['link'];
|
$res['invite'] = $full['full']['exported_invite']['link'];
|
||||||
@ -686,7 +689,7 @@ trait PeerHandler
|
|||||||
$res['participants'][$key] = $newres;
|
$res['participants'][$key] = $newres;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!isset($res['participants']) && $fullfetch && in_array($res['type'], ['supergroup', 'channel'])) {
|
if (!isset($res['participants']) && $fullfetch && \in_array($res['type'], ['supergroup', 'channel'])) {
|
||||||
$total_count = (isset($res['participants_count']) ? $res['participants_count'] : 0) + (isset($res['admins_count']) ? $res['admins_count'] : 0) + (isset($res['kicked_count']) ? $res['kicked_count'] : 0) + (isset($res['banned_count']) ? $res['banned_count'] : 0);
|
$total_count = (isset($res['participants_count']) ? $res['participants_count'] : 0) + (isset($res['admins_count']) ? $res['admins_count'] : 0) + (isset($res['kicked_count']) ? $res['kicked_count'] : 0) + (isset($res['banned_count']) ? $res['banned_count'] : 0);
|
||||||
$res['participants'] = [];
|
$res['participants'] = [];
|
||||||
$limit = 200;
|
$limit = 200;
|
||||||
@ -700,8 +703,8 @@ trait PeerHandler
|
|||||||
foreach ($filters as $filter) {
|
foreach ($filters as $filter) {
|
||||||
yield $this->recurse_alphabet_search_participants_async($full['InputChannel'], $filter, $q, $total_count, $res);
|
yield $this->recurse_alphabet_search_participants_async($full['InputChannel'], $filter, $q, $total_count, $res);
|
||||||
}
|
}
|
||||||
$this->logger->logger('Fetched '.count($res['participants'])." out of $total_count");
|
$this->logger->logger('Fetched '.\count($res['participants'])." out of $total_count");
|
||||||
$res['participants'] = array_values($res['participants']);
|
$res['participants'] = \array_values($res['participants']);
|
||||||
}
|
}
|
||||||
if (!$fullfetch) {
|
if (!$fullfetch) {
|
||||||
unset($res['participants']);
|
unset($res['participants']);
|
||||||
@ -719,7 +722,7 @@ trait PeerHandler
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ($x = 'a'; $x !== 'aa' && $total_count > count($res['participants']); $x++) {
|
for ($x = 'a'; $x !== 'aa' && $total_count > \count($res['participants']); $x++) {
|
||||||
yield $this->recurse_alphabet_search_participants_async($channel, $filter, $q.$x, $total_count, $res);
|
yield $this->recurse_alphabet_search_participants_async($channel, $filter, $q.$x, $total_count, $res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -740,9 +743,8 @@ trait PeerHandler
|
|||||||
$this->logger->logger($e->rpc);
|
$this->logger->logger($e->rpc);
|
||||||
|
|
||||||
return $has_more;
|
return $has_more;
|
||||||
} else {
|
|
||||||
throw $e;
|
|
||||||
}
|
}
|
||||||
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($cached = $gres['_'] === 'channels.channelParticipantsNotModified') {
|
if ($cached = $gres['_'] === 'channels.channelParticipantsNotModified') {
|
||||||
@ -797,9 +799,9 @@ trait PeerHandler
|
|||||||
}
|
}
|
||||||
$res['participants'][$participant['user_id']] = $newres;
|
$res['participants'][$participant['user_id']] = $newres;
|
||||||
}
|
}
|
||||||
$this->logger->logger('Fetched '.count($gres['participants'])." channel participants with filter $filter, query $q, offset $offset, limit $limit, hash $hash: ".($cached ? 'cached' : 'not cached').', '.($offset + count($gres['participants'])).' participants out of '.$gres['count'].', in total fetched '.count($res['participants']).' out of '.$total_count);
|
$this->logger->logger('Fetched '.\count($gres['participants'])." channel participants with filter $filter, query $q, offset $offset, limit $limit, hash $hash: ".($cached ? 'cached' : 'not cached').', '.($offset + \count($gres['participants'])).' participants out of '.$gres['count'].', in total fetched '.\count($res['participants']).' out of '.$total_count);
|
||||||
$offset += count($gres['participants']);
|
$offset += \count($gres['participants']);
|
||||||
} while (count($gres['participants']));
|
} while (\count($gres['participants']));
|
||||||
|
|
||||||
if ($offset === $limit) {
|
if ($offset === $limit) {
|
||||||
return true;
|
return true;
|
||||||
@ -821,7 +823,7 @@ trait PeerHandler
|
|||||||
foreach ($gres['participants'] as $participant) {
|
foreach ($gres['participants'] as $participant) {
|
||||||
$ids[] = $participant['user_id'];
|
$ids[] = $participant['user_id'];
|
||||||
}
|
}
|
||||||
sort($ids, SORT_NUMERIC);
|
\sort($ids, SORT_NUMERIC);
|
||||||
$gres['hash'] = $this->gen_vector_hash($ids);
|
$gres['hash'] = $this->gen_vector_hash($ids);
|
||||||
$this->channel_participants[$channel['channel_id']][$filter][$q][$offset][$limit] = $gres;
|
$this->channel_participants[$channel['channel_id']][$filter][$q][$offset][$limit] = $gres;
|
||||||
}
|
}
|
||||||
@ -843,7 +845,7 @@ trait PeerHandler
|
|||||||
}
|
}
|
||||||
$this->qres[] = $res;
|
$this->qres[] = $res;
|
||||||
}
|
}
|
||||||
if ($this->last_stored > time() && !$force) {
|
if ($this->last_stored > \time() && !$force) {
|
||||||
//$this->logger->logger("========== WILL SERIALIZE IN ".($this->last_stored - time())." =============");
|
//$this->logger->logger("========== WILL SERIALIZE IN ".($this->last_stored - time())." =============");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -852,7 +854,7 @@ trait PeerHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$payload = json_encode($this->qres);
|
$payload = \json_encode($this->qres);
|
||||||
//$path = '/tmp/ids'.hash('sha256', $payload);
|
//$path = '/tmp/ids'.hash('sha256', $payload);
|
||||||
//file_put_contents($path, $payload);
|
//file_put_contents($path, $payload);
|
||||||
$id = isset($this->authorization['user']['username']) ? $this->authorization['user']['username'] : $this->authorization['user']['id'];
|
$id = isset($this->authorization['user']['username']) ? $this->authorization['user']['username'] : $this->authorization['user']['id'];
|
||||||
@ -863,7 +865,7 @@ trait PeerHandler
|
|||||||
|
|
||||||
$this->logger->logger("============ $result =============", \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger("============ $result =============", \danog\MadelineProto\Logger::VERBOSE);
|
||||||
$this->qres = [];
|
$this->qres = [];
|
||||||
$this->last_stored = time() + 10;
|
$this->last_stored = \time() + 10;
|
||||||
} catch (\danog\MadelineProto\Exception $e) {
|
} catch (\danog\MadelineProto\Exception $e) {
|
||||||
$this->logger->logger('======= COULD NOT STORE IN DB DUE TO '.$e->getMessage().' =============', \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger('======= COULD NOT STORE IN DB DUE TO '.$e->getMessage().' =============', \danog\MadelineProto\Logger::VERBOSE);
|
||||||
}
|
}
|
||||||
@ -873,10 +875,10 @@ trait PeerHandler
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->caching_simple_username[$username] = true;
|
$this->caching_simple_username[$username] = true;
|
||||||
$res = yield $this->method_call_async_read('contacts.resolveUsername', ['username' => str_replace('@', '', $username)], ['datacenter' => $this->datacenter->curdc]);
|
$res = yield $this->method_call_async_read('contacts.resolveUsername', ['username' => \str_replace('@', '', $username)], ['datacenter' => $this->datacenter->curdc]);
|
||||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||||
$this->logger->logger('Username resolution failed with error '.$e->getMessage(), \danog\MadelineProto\Logger::ERROR);
|
$this->logger->logger('Username resolution failed with error '.$e->getMessage(), \danog\MadelineProto\Logger::ERROR);
|
||||||
if (strpos($e->rpc, 'FLOOD_WAIT_') === 0 || $e->rpc === 'AUTH_KEY_UNREGISTERED' || $e->rpc === 'USERNAME_INVALID') {
|
if (\strpos($e->rpc, 'FLOOD_WAIT_') === 0 || $e->rpc === 'AUTH_KEY_UNREGISTERED' || $e->rpc === 'USERNAME_INVALID') {
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,31 +132,31 @@ class ReferenceDatabase implements TLCallback
|
|||||||
|
|
||||||
public function getMethodCallbacks(): array
|
public function getMethodCallbacks(): array
|
||||||
{
|
{
|
||||||
return array_fill_keys(array_keys(self::METHOD_CONTEXT), [[$this, 'addOriginMethod']]);
|
return \array_fill_keys(\array_keys(self::METHOD_CONTEXT), [[$this, 'addOriginMethod']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMethodBeforeCallbacks(): array
|
public function getMethodBeforeCallbacks(): array
|
||||||
{
|
{
|
||||||
return array_fill_keys(array_keys(self::METHOD_CONTEXT), [[$this, 'addOriginMethodContext']]);
|
return \array_fill_keys(\array_keys(self::METHOD_CONTEXT), [[$this, 'addOriginMethodContext']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getConstructorCallbacks(): array
|
public function getConstructorCallbacks(): array
|
||||||
{
|
{
|
||||||
return array_merge(
|
return \array_merge(
|
||||||
array_fill_keys(['document', 'photo', 'fileLocation'], [[$this, 'addReference']]),
|
\array_fill_keys(['document', 'photo', 'fileLocation'], [[$this, 'addReference']]),
|
||||||
array_fill_keys(array_keys(self::CONSTRUCTOR_CONTEXT), [[$this, 'addOrigin']]),
|
\array_fill_keys(\array_keys(self::CONSTRUCTOR_CONTEXT), [[$this, 'addOrigin']]),
|
||||||
['document' => [[$this, 'addReference'], [$this, 'addOrigin']]]
|
['document' => [[$this, 'addReference'], [$this, 'addOrigin']]]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getConstructorBeforeCallbacks(): array
|
public function getConstructorBeforeCallbacks(): array
|
||||||
{
|
{
|
||||||
return array_fill_keys(array_keys(self::CONSTRUCTOR_CONTEXT), [[$this, 'addOriginContext']]);
|
return \array_fill_keys(\array_keys(self::CONSTRUCTOR_CONTEXT), [[$this, 'addOriginContext']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getConstructorSerializeCallbacks(): array
|
public function getConstructorSerializeCallbacks(): array
|
||||||
{
|
{
|
||||||
return array_fill_keys(array_keys(self::LOCATION_CONTEXT), [$this, 'populateReference']);
|
return \array_fill_keys(\array_keys(self::LOCATION_CONTEXT), [$this, 'populateReference']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTypeMismatchCallbacks(): array
|
public function getTypeMismatchCallbacks(): array
|
||||||
@ -167,7 +167,7 @@ class ReferenceDatabase implements TLCallback
|
|||||||
public function reset()
|
public function reset()
|
||||||
{
|
{
|
||||||
if ($this->cacheContexts) {
|
if ($this->cacheContexts) {
|
||||||
$this->API->logger->logger('Found '.count($this->cacheContexts).' pending contexts', \danog\MadelineProto\Logger::ERROR);
|
$this->API->logger->logger('Found '.\count($this->cacheContexts).' pending contexts', \danog\MadelineProto\Logger::ERROR);
|
||||||
$this->cacheContexts = [];
|
$this->cacheContexts = [];
|
||||||
}
|
}
|
||||||
if ($this->cache) {
|
if ($this->cache) {
|
||||||
@ -182,7 +182,7 @@ class ReferenceDatabase implements TLCallback
|
|||||||
$this->API->logger->logger('Trying to add reference out of context, report the following message to @danogentili!', \danog\MadelineProto\Logger::ERROR);
|
$this->API->logger->logger('Trying to add reference out of context, report the following message to @danogentili!', \danog\MadelineProto\Logger::ERROR);
|
||||||
$frames = [];
|
$frames = [];
|
||||||
$previous = '';
|
$previous = '';
|
||||||
foreach (debug_backtrace(0) as $k => $frame) {
|
foreach (\debug_backtrace(0) as $k => $frame) {
|
||||||
if (isset($frame['function']) && $frame['function'] === 'deserialize') {
|
if (isset($frame['function']) && $frame['function'] === 'deserialize') {
|
||||||
if (isset($frame['args'][1]['subtype'])) {
|
if (isset($frame['args'][1]['subtype'])) {
|
||||||
if ($frame['args'][1]['subtype'] === $previous) {
|
if ($frame['args'][1]['subtype'] === $previous) {
|
||||||
@ -205,8 +205,8 @@ class ReferenceDatabase implements TLCallback
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$frames = array_reverse($frames);
|
$frames = \array_reverse($frames);
|
||||||
$tl_trace = array_shift($frames);
|
$tl_trace = \array_shift($frames);
|
||||||
foreach ($frames as $frame) {
|
foreach ($frames as $frame) {
|
||||||
$tl_trace .= "['".$frame."']";
|
$tl_trace .= "['".$frame."']";
|
||||||
}
|
}
|
||||||
@ -219,7 +219,7 @@ class ReferenceDatabase implements TLCallback
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$key = count($this->cacheContexts) - 1;
|
$key = \count($this->cacheContexts) - 1;
|
||||||
switch ($location['_']) {
|
switch ($location['_']) {
|
||||||
case 'document':
|
case 'document':
|
||||||
$locationType = self::DOCUMENT_LOCATION;
|
$locationType = self::DOCUMENT_LOCATION;
|
||||||
@ -254,11 +254,11 @@ class ReferenceDatabase implements TLCallback
|
|||||||
|
|
||||||
public function addOrigin(array $data = [])
|
public function addOrigin(array $data = [])
|
||||||
{
|
{
|
||||||
$key = count($this->cacheContexts) - 1;
|
$key = \count($this->cacheContexts) - 1;
|
||||||
if ($key === -1) {
|
if ($key === -1) {
|
||||||
throw new \danog\MadelineProto\Exception('Trying to add origin with no origin context set');
|
throw new \danog\MadelineProto\Exception('Trying to add origin with no origin context set');
|
||||||
}
|
}
|
||||||
$originType = array_pop($this->cacheContexts);
|
$originType = \array_pop($this->cacheContexts);
|
||||||
if (!isset($this->cache[$key])) {
|
if (!isset($this->cache[$key])) {
|
||||||
$this->API->logger->logger("Removing origin context $originType for {$data['_']}, nothing in the reference cache!", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$this->API->logger->logger("Removing origin context $originType for {$data['_']}, nothing in the reference cache!", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
|
|
||||||
@ -311,7 +311,7 @@ class ReferenceDatabase implements TLCallback
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!isset($origin['stickerset'])) {
|
if (!isset($origin['stickerset'])) {
|
||||||
$key = count($this->cacheContexts) - 1;
|
$key = \count($this->cacheContexts) - 1;
|
||||||
if (!isset($this->cache[$key])) {
|
if (!isset($this->cache[$key])) {
|
||||||
$this->cache[$key] = [];
|
$this->cache[$key] = [];
|
||||||
}
|
}
|
||||||
@ -319,7 +319,7 @@ class ReferenceDatabase implements TLCallback
|
|||||||
foreach ($cache as $location => $reference) {
|
foreach ($cache as $location => $reference) {
|
||||||
$this->cache[$key][$location] = $reference;
|
$this->cache[$key][$location] = $reference;
|
||||||
}
|
}
|
||||||
$this->API->logger->logger("Skipped origin $originType ({$data['_']}) for ".count($cache).' references', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$this->API->logger->logger("Skipped origin $originType ({$data['_']}) for ".\count($cache).' references', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -333,7 +333,7 @@ class ReferenceDatabase implements TLCallback
|
|||||||
foreach ($cache as $location => $reference) {
|
foreach ($cache as $location => $reference) {
|
||||||
$this->storeReference($location, $reference, $originType, $origin);
|
$this->storeReference($location, $reference, $originType, $origin);
|
||||||
}
|
}
|
||||||
$this->API->logger->logger("Added origin $originType ({$data['_']}) to ".count($cache).' references', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$this->API->logger->logger("Added origin $originType ({$data['_']}) to ".\count($cache).' references', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addOriginMethodContext(string $type)
|
public function addOriginMethodContext(string $type)
|
||||||
@ -348,11 +348,11 @@ class ReferenceDatabase implements TLCallback
|
|||||||
|
|
||||||
public function addOriginMethod(array $data, array $res)
|
public function addOriginMethod(array $data, array $res)
|
||||||
{
|
{
|
||||||
$key = count($this->cacheContexts) - 1;
|
$key = \count($this->cacheContexts) - 1;
|
||||||
if ($key === -1) {
|
if ($key === -1) {
|
||||||
throw new \danog\MadelineProto\Exception('Trying to add origin with no origin context set');
|
throw new \danog\MadelineProto\Exception('Trying to add origin with no origin context set');
|
||||||
}
|
}
|
||||||
$originType = array_pop($this->cacheContexts);
|
$originType = \array_pop($this->cacheContexts);
|
||||||
if (!isset($this->cache[$key])) {
|
if (!isset($this->cache[$key])) {
|
||||||
$this->API->logger->logger("Removing origin context $originType for {$data['_']}, nothing in the reference cache!", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$this->API->logger->logger("Removing origin context $originType for {$data['_']}, nothing in the reference cache!", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
|
|
||||||
@ -420,7 +420,7 @@ class ReferenceDatabase implements TLCallback
|
|||||||
foreach ($cache as $location => $reference) {
|
foreach ($cache as $location => $reference) {
|
||||||
$this->storeReference($location, $reference, $originType, $origin);
|
$this->storeReference($location, $reference, $originType, $origin);
|
||||||
}
|
}
|
||||||
$this->API->logger->logger("Added origin $originType ({$data['_']}) to ".count($cache).' references', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$this->API->logger->logger("Added origin $originType ({$data['_']}) to ".\count($cache).' references', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function storeReference(string $location, string $reference, int $originType, array $origin)
|
public function storeReference(string $location, string $reference, int $originType, array $origin)
|
||||||
@ -435,7 +435,7 @@ class ReferenceDatabase implements TLCallback
|
|||||||
$this->refreshed[$location] = true;
|
$this->refreshed[$location] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$key = count($this->cacheContexts) - 1;
|
$key = \count($this->cacheContexts) - 1;
|
||||||
if ($key >= 0) {
|
if ($key >= 0) {
|
||||||
$this->cache[$key][$location] = $reference;
|
$this->cache[$key][$location] = $reference;
|
||||||
}
|
}
|
||||||
@ -472,7 +472,7 @@ class ReferenceDatabase implements TLCallback
|
|||||||
return $this->db[$location]['reference'];
|
return $this->db[$location]['reference'];
|
||||||
}
|
}
|
||||||
|
|
||||||
ksort($this->db[$location]['origins']);
|
\ksort($this->db[$location]['origins']);
|
||||||
$count = 0;
|
$count = 0;
|
||||||
|
|
||||||
foreach ($this->db[$location]['origins'] as $originType => &$origin) {
|
foreach ($this->db[$location]['origins'] as $originType => &$origin) {
|
||||||
@ -481,7 +481,7 @@ class ReferenceDatabase implements TLCallback
|
|||||||
switch ($originType) {
|
switch ($originType) {
|
||||||
// Peer + msg ID
|
// Peer + msg ID
|
||||||
case self::MESSAGE_ORIGIN:
|
case self::MESSAGE_ORIGIN:
|
||||||
if (is_array($origin['peer'])) {
|
if (\is_array($origin['peer'])) {
|
||||||
$origin['peer'] = $this->API->get_id($origin['peer']);
|
$origin['peer'] = $this->API->get_id($origin['peer']);
|
||||||
}
|
}
|
||||||
if ($origin['peer'] < 0) {
|
if ($origin['peer'] < 0) {
|
||||||
@ -569,10 +569,10 @@ class ReferenceDatabase implements TLCallback
|
|||||||
switch ($locationType) {
|
switch ($locationType) {
|
||||||
case self::DOCUMENT_LOCATION:
|
case self::DOCUMENT_LOCATION:
|
||||||
case self::PHOTO_LOCATION:
|
case self::PHOTO_LOCATION:
|
||||||
return $locationType.(is_int($location['id']) ? $this->pack_signed_long($location['id']) : $location['id']);
|
return $locationType.(\is_int($location['id']) ? $this->pack_signed_long($location['id']) : $location['id']);
|
||||||
case self::PHOTO_LOCATION_LOCATION:
|
case self::PHOTO_LOCATION_LOCATION:
|
||||||
$dc_id = $this->pack_signed_int($location['dc_id']);
|
$dc_id = $this->pack_signed_int($location['dc_id']);
|
||||||
$volume_id = is_int($location['volume_id']) ? $this->pack_signed_long($location['volume_id']) : $location['volume_id'];
|
$volume_id = \is_int($location['volume_id']) ? $this->pack_signed_long($location['volume_id']) : $location['volume_id'];
|
||||||
$local_id = $this->pack_signed_int($location['local_id']);
|
$local_id = $this->pack_signed_int($location['local_id']);
|
||||||
|
|
||||||
return $locationType.$dc_id.$volume_id.$local_id;
|
return $locationType.$dc_id.$volume_id.$local_id;
|
||||||
@ -581,6 +581,6 @@ class ReferenceDatabase implements TLCallback
|
|||||||
|
|
||||||
public function __debugInfo()
|
public function __debugInfo()
|
||||||
{
|
{
|
||||||
return ['ReferenceDatabase instance '.spl_object_hash($this)];
|
return ['ReferenceDatabase instance '.\spl_object_hash($this)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,13 +36,13 @@ trait UpdateHandler
|
|||||||
public function pwr_update_handler($update)
|
public function pwr_update_handler($update)
|
||||||
{
|
{
|
||||||
if (isset($this->settings['pwr']['update_handler'])) {
|
if (isset($this->settings['pwr']['update_handler'])) {
|
||||||
if (is_array($this->settings['pwr']['update_handler']) && $this->settings['pwr']['update_handler'][0] === false) {
|
if (\is_array($this->settings['pwr']['update_handler']) && $this->settings['pwr']['update_handler'][0] === false) {
|
||||||
$this->settings['pwr']['update_handler'] = $this->settings['pwr']['update_handler'][1];
|
$this->settings['pwr']['update_handler'] = $this->settings['pwr']['update_handler'][1];
|
||||||
}
|
}
|
||||||
if (is_string($this->settings['pwr']['update_handler'])) {
|
if (\is_string($this->settings['pwr']['update_handler'])) {
|
||||||
return $this->{$this->settings['pwr']['update_handler']}($update);
|
return $this->{$this->settings['pwr']['update_handler']}($update);
|
||||||
}
|
}
|
||||||
in_array($this->settings['pwr']['update_handler'], [['danog\\MadelineProto\\API', 'get_updates_update_handler'], 'get_updates_update_handler']) ? $this->get_updates_update_handler($update) : $this->settings['pwr']['update_handler']($update);
|
\in_array($this->settings['pwr']['update_handler'], [['danog\\MadelineProto\\API', 'get_updates_update_handler'], 'get_updates_update_handler']) ? $this->get_updates_update_handler($update) : $this->settings['pwr']['update_handler']($update);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ trait UpdateHandler
|
|||||||
$this->settings['updates']['run_callback'] = true;
|
$this->settings['updates']['run_callback'] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$params = array_merge(self::DEFAULT_GETUPDATES_PARAMS, $params);
|
$params = \array_merge(self::DEFAULT_GETUPDATES_PARAMS, $params);
|
||||||
|
|
||||||
if (empty($this->updates)) {
|
if (empty($this->updates)) {
|
||||||
$this->update_deferred = new Deferred();
|
$this->update_deferred = new Deferred();
|
||||||
@ -79,13 +79,13 @@ trait UpdateHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($params['offset'] < 0) {
|
if ($params['offset'] < 0) {
|
||||||
$params['offset'] = array_reverse(array_keys((array) $this->updates))[abs($params['offset']) - 1];
|
$params['offset'] = \array_reverse(\array_keys((array) $this->updates))[\abs($params['offset']) - 1];
|
||||||
}
|
}
|
||||||
$updates = [];
|
$updates = [];
|
||||||
foreach ($this->updates as $key => $value) {
|
foreach ($this->updates as $key => $value) {
|
||||||
if ($params['offset'] > $key) {
|
if ($params['offset'] > $key) {
|
||||||
unset($this->updates[$key]);
|
unset($this->updates[$key]);
|
||||||
} elseif ($params['limit'] === null || count($updates) < $params['limit']) {
|
} elseif ($params['limit'] === null || \count($updates) < $params['limit']) {
|
||||||
$updates[] = ['update_id' => $key, 'update' => $value];
|
$updates[] = ['update_id' => $key, 'update' => $value];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -256,7 +256,7 @@ trait UpdateHandler
|
|||||||
$this->config['expires'] = 0;
|
$this->config['expires'] = 0;
|
||||||
yield $this->get_config_async();
|
yield $this->get_config_async();
|
||||||
}
|
}
|
||||||
if (in_array($update['_'], ['updateUserName', 'updateUserPhone', 'updateUserBlocked', 'updateUserPhoto', 'updateContactRegistered', 'updateContactLink'])) {
|
if (\in_array($update['_'], ['updateUserName', 'updateUserPhone', 'updateUserBlocked', 'updateUserPhoto', 'updateContactRegistered', 'updateContactLink'])) {
|
||||||
$id = $this->get_id($update);
|
$id = $this->get_id($update);
|
||||||
$this->full_chats[$id]['last_update'] = 0;
|
$this->full_chats[$id]['last_update'] = 0;
|
||||||
yield $this->get_full_info_async($id);
|
yield $this->get_full_info_async($id);
|
||||||
@ -268,7 +268,7 @@ trait UpdateHandler
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($update['_'] === 'updatePhoneCall') {
|
if ($update['_'] === 'updatePhoneCall') {
|
||||||
if (!class_exists('\\danog\\MadelineProto\\VoIP')) {
|
if (!\class_exists('\\danog\\MadelineProto\\VoIP')) {
|
||||||
$this->logger->logger('The php-libtgvoip extension is required to accept and manage calls. See daniil.it/MadelineProto for more info.', \danog\MadelineProto\Logger::WARNING);
|
$this->logger->logger('The php-libtgvoip extension is required to accept and manage calls. See daniil.it/MadelineProto for more info.', \danog\MadelineProto\Logger::WARNING);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -335,7 +335,7 @@ trait UpdateHandler
|
|||||||
if ($update['_'] === 'updateEncryption') {
|
if ($update['_'] === 'updateEncryption') {
|
||||||
switch ($update['chat']['_']) {
|
switch ($update['chat']['_']) {
|
||||||
case 'encryptedChatRequested':
|
case 'encryptedChatRequested':
|
||||||
if ($this->settings['secret_chats']['accept_chats'] === false || is_array($this->settings['secret_chats']['accept_chats']) && !in_array($update['chat']['admin_id'], $this->settings['secret_chats']['accept_chats'])) {
|
if ($this->settings['secret_chats']['accept_chats'] === false || \is_array($this->settings['secret_chats']['accept_chats']) && !\in_array($update['chat']['admin_id'], $this->settings['secret_chats']['accept_chats'])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$this->logger->logger('Accepting secret chat '.$update['chat']['id'], \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger('Accepting secret chat '.$update['chat']['id'], \danog\MadelineProto\Logger::NOTICE);
|
||||||
@ -383,7 +383,7 @@ trait UpdateHandler
|
|||||||
|
|
||||||
public function pwr_webhook($update)
|
public function pwr_webhook($update)
|
||||||
{
|
{
|
||||||
$payload = json_encode($update);
|
$payload = \json_encode($update);
|
||||||
//$this->logger->logger($update, $payload, json_last_error());
|
//$this->logger->logger($update, $payload, json_last_error());
|
||||||
if ($payload === '') {
|
if ($payload === '') {
|
||||||
$this->logger->logger('EMPTY UPDATE');
|
$this->logger->logger('EMPTY UPDATE');
|
||||||
@ -396,8 +396,8 @@ trait UpdateHandler
|
|||||||
$result = yield (yield $this->datacenter->getHTTPClient()->request($request))->getBody();
|
$result = yield (yield $this->datacenter->getHTTPClient()->request($request))->getBody();
|
||||||
|
|
||||||
$this->logger->logger('Result of webhook query is '.$result, \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger('Result of webhook query is '.$result, \danog\MadelineProto\Logger::NOTICE);
|
||||||
$result = json_decode($result, true);
|
$result = \json_decode($result, true);
|
||||||
if (is_array($result) && isset($result['method']) && $result['method'] != '' && is_string($result['method'])) {
|
if (\is_array($result) && isset($result['method']) && $result['method'] != '' && \is_string($result['method'])) {
|
||||||
try {
|
try {
|
||||||
$this->logger->logger('Reverse webhook command returned', yield $this->method_call_async_read($result['method'], $result, ['datacenter' => $this->datacenter->curdc]));
|
$this->logger->logger('Reverse webhook command returned', yield $this->method_call_async_read($result['method'], $result, ['datacenter' => $this->datacenter->curdc]));
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
|
@ -65,31 +65,31 @@ class Magic
|
|||||||
|
|
||||||
public static function class_exists()
|
public static function class_exists()
|
||||||
{
|
{
|
||||||
set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
|
\set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
|
||||||
set_exception_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionHandler']);
|
\set_exception_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionHandler']);
|
||||||
if (!self::$inited) {
|
if (!self::$inited) {
|
||||||
if (!defined('\\phpseclib\\Crypt\\Common\\SymmetricKey::MODE_IGE') || \phpseclib\Crypt\Common\SymmetricKey::MODE_IGE !== 7) {
|
if (!\defined('\\phpseclib\\Crypt\\Common\\SymmetricKey::MODE_IGE') || \phpseclib\Crypt\Common\SymmetricKey::MODE_IGE !== 7) {
|
||||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['phpseclib_fork']);
|
throw new Exception(\danog\MadelineProto\Lang::$current_lang['phpseclib_fork']);
|
||||||
}
|
}
|
||||||
foreach (['intl', 'xml', 'fileinfo', 'json', 'mbstring'] as $extension) {
|
foreach (['intl', 'xml', 'fileinfo', 'json', 'mbstring'] as $extension) {
|
||||||
if (!extension_loaded($extension)) {
|
if (!\extension_loaded($extension)) {
|
||||||
throw Exception::extension($extension);
|
throw Exception::extension($extension);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self::$has_thread = class_exists('\\Thread') && method_exists('\\Thread', 'getCurrentThread');
|
self::$has_thread = \class_exists('\\Thread') && \method_exists('\\Thread', 'getCurrentThread');
|
||||||
self::$BIG_ENDIAN = pack('L', 1) === pack('N', 1);
|
self::$BIG_ENDIAN = \pack('L', 1) === \pack('N', 1);
|
||||||
self::$bigint = PHP_INT_SIZE < 8;
|
self::$bigint = PHP_INT_SIZE < 8;
|
||||||
self::$ipv6 = (bool) strlen(@file_get_contents('http://v6.ipv6-test.com/api/myip.php', false, stream_context_create(['http' => ['timeout' => 1]]))) > 0;
|
self::$ipv6 = (bool) \strlen(@\file_get_contents('http://v6.ipv6-test.com/api/myip.php', false, \stream_context_create(['http' => ['timeout' => 1]]))) > 0;
|
||||||
preg_match('/const V = (\\d+);/', @file_get_contents('https://raw.githubusercontent.com/danog/MadelineProto/master/src/danog/MadelineProto/MTProto.php'), $matches);
|
\preg_match('/const V = (\\d+);/', @\file_get_contents('https://raw.githubusercontent.com/danog/MadelineProto/master/src/danog/MadelineProto/MTProto.php'), $matches);
|
||||||
if (isset($matches[1]) && \danog\MadelineProto\MTProto::V < (int) $matches[1]) {
|
if (isset($matches[1]) && \danog\MadelineProto\MTProto::V < (int) $matches[1]) {
|
||||||
throw new \danog\MadelineProto\Exception(hex2bin(\danog\MadelineProto\Lang::$current_lang['v_error']), 0, null, 'MadelineProto', 1);
|
throw new \danog\MadelineProto\Exception(\hex2bin(\danog\MadelineProto\Lang::$current_lang['v_error']), 0, null, 'MadelineProto', 1);
|
||||||
}
|
}
|
||||||
if (class_exists('\\danog\\MadelineProto\\VoIP')) {
|
if (\class_exists('\\danog\\MadelineProto\\VoIP')) {
|
||||||
if (!defined('\\danog\\MadelineProto\\VoIP::PHP_LIBTGVOIP_VERSION') || !in_array(\danog\MadelineProto\VoIP::PHP_LIBTGVOIP_VERSION, ['1.3.0'])) {
|
if (!\defined('\\danog\\MadelineProto\\VoIP::PHP_LIBTGVOIP_VERSION') || !\in_array(\danog\MadelineProto\VoIP::PHP_LIBTGVOIP_VERSION, ['1.3.0'])) {
|
||||||
throw new \danog\MadelineProto\Exception(hex2bin(\danog\MadelineProto\Lang::$current_lang['v_tgerror']), 0, null, 'MadelineProto', 1);
|
throw new \danog\MadelineProto\Exception(\hex2bin(\danog\MadelineProto\Lang::$current_lang['v_tgerror']), 0, null, 'MadelineProto', 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self::$emojis = json_decode(self::JSON_EMOJIS);
|
self::$emojis = \json_decode(self::JSON_EMOJIS);
|
||||||
self::$zero = new \phpseclib\Math\BigInteger(0);
|
self::$zero = new \phpseclib\Math\BigInteger(0);
|
||||||
self::$one = new \phpseclib\Math\BigInteger(1);
|
self::$one = new \phpseclib\Math\BigInteger(1);
|
||||||
self::$two = new \phpseclib\Math\BigInteger(2);
|
self::$two = new \phpseclib\Math\BigInteger(2);
|
||||||
@ -102,27 +102,27 @@ class Magic
|
|||||||
self::$zeroeight = new \phpseclib\Math\BigInteger('2147483648');
|
self::$zeroeight = new \phpseclib\Math\BigInteger('2147483648');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
self::$isatty = defined('STDOUT') && function_exists('posix_isatty') && posix_isatty(STDOUT);
|
self::$isatty = \defined('STDOUT') && \function_exists('posix_isatty') && \posix_isatty(STDOUT);
|
||||||
} catch (\danog\MadelineProto\Exception $e) {
|
} catch (\danog\MadelineProto\Exception $e) {
|
||||||
}
|
}
|
||||||
self::$altervista = isset($_SERVER['SERVER_ADMIN']) && strpos($_SERVER['SERVER_ADMIN'], 'altervista.org');
|
self::$altervista = isset($_SERVER['SERVER_ADMIN']) && \strpos($_SERVER['SERVER_ADMIN'], 'altervista.org');
|
||||||
self::$zerowebhost = isset($_SERVER['SERVER_ADMIN']) && strpos($_SERVER['SERVER_ADMIN'], '000webhost.io');
|
self::$zerowebhost = isset($_SERVER['SERVER_ADMIN']) && \strpos($_SERVER['SERVER_ADMIN'], '000webhost.io');
|
||||||
self::$can_getmypid = !self::$altervista && !self::$zerowebhost;
|
self::$can_getmypid = !self::$altervista && !self::$zerowebhost;
|
||||||
self::$revision = @file_get_contents(__DIR__.'/../../../.git/refs/heads/master');
|
self::$revision = @\file_get_contents(__DIR__.'/../../../.git/refs/heads/master');
|
||||||
if (self::$revision) {
|
if (self::$revision) {
|
||||||
self::$revision = trim(self::$revision);
|
self::$revision = \trim(self::$revision);
|
||||||
$latest = @file_get_contents('https://phar.madelineproto.xyz/release');
|
$latest = @\file_get_contents('https://phar.madelineproto.xyz/release');
|
||||||
if ($latest) {
|
if ($latest) {
|
||||||
$latest = self::$revision === trim($latest) ? '' : ' (AN UPDATE IS REQUIRED)';
|
$latest = self::$revision === \trim($latest) ? '' : ' (AN UPDATE IS REQUIRED)';
|
||||||
}
|
}
|
||||||
self::$revision = 'Revision: '.self::$revision.$latest;
|
self::$revision = 'Revision: '.self::$revision.$latest;
|
||||||
}
|
}
|
||||||
self::$can_parallel = false;
|
self::$can_parallel = false;
|
||||||
if (php_sapi_name() === 'cli' && !(class_exists('\\Phar') && \Phar::running())) {
|
if (PHP_SAPI === 'cli' && !(\class_exists('\\Phar') && \Phar::running())) {
|
||||||
try {
|
try {
|
||||||
$back = debug_backtrace(0);
|
$back = \debug_backtrace(0);
|
||||||
define('AMP_WORKER', 1);
|
\define('AMP_WORKER', 1);
|
||||||
$promise = \Amp\File\get(end($back)['file']);
|
$promise = \Amp\File\get(\end($back)['file']);
|
||||||
do {
|
do {
|
||||||
try {
|
try {
|
||||||
if (wait($promise)) {
|
if (wait($promise)) {
|
||||||
@ -138,19 +138,19 @@ class Magic
|
|||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!self::$can_parallel && !defined('AMP_WORKER') || true) {
|
if (!self::$can_parallel && !\defined('AMP_WORKER') || true) {
|
||||||
//define('AMP_WORKER', 1);
|
//define('AMP_WORKER', 1);
|
||||||
}
|
}
|
||||||
$backtrace = debug_backtrace(0);
|
$backtrace = \debug_backtrace(0);
|
||||||
self::$script_cwd = self::$cwd = dirname(end($backtrace)['file']);
|
self::$script_cwd = self::$cwd = \dirname(\end($backtrace)['file']);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
self::$cwd = getcwd();
|
self::$cwd = \getcwd();
|
||||||
self::$can_getcwd = true;
|
self::$can_getcwd = true;
|
||||||
} catch (\danog\MadelineProto\Exception $e) {
|
} catch (\danog\MadelineProto\Exception $e) {
|
||||||
}
|
}
|
||||||
// Even an empty handler is enough to catch ctrl+c
|
// Even an empty handler is enough to catch ctrl+c
|
||||||
if (defined('SIGINT')) {
|
if (\defined('SIGINT')) {
|
||||||
//if (function_exists('pcntl_async_signals')) pcntl_async_signals(true);
|
//if (function_exists('pcntl_async_signals')) pcntl_async_signals(true);
|
||||||
Loop::onSignal(SIGINT, static function () {
|
Loop::onSignal(SIGINT, static function () {
|
||||||
getStdin()->unreference();
|
getStdin()->unreference();
|
||||||
@ -173,18 +173,18 @@ class Magic
|
|||||||
);
|
);
|
||||||
resolver(new Rfc8484StubResolver($DohConfig));
|
resolver(new Rfc8484StubResolver($DohConfig));
|
||||||
}
|
}
|
||||||
if (php_sapi_name() !== 'cli') {
|
if (PHP_SAPI !== 'cli') {
|
||||||
try {
|
try {
|
||||||
error_reporting(E_ALL);
|
\error_reporting(E_ALL);
|
||||||
ini_set('log_errors', 1);
|
\ini_set('log_errors', 1);
|
||||||
ini_set('error_log', Magic::$script_cwd.'/MadelineProto.log');
|
\ini_set('error_log', Magic::$script_cwd.'/MadelineProto.log');
|
||||||
error_log('Enabled PHP logging');
|
\error_log('Enabled PHP logging');
|
||||||
} catch (\danog\MadelineProto\Exception $e) {
|
} catch (\danog\MadelineProto\Exception $e) {
|
||||||
//$this->logger->logger('Could not enable PHP logging');
|
//$this->logger->logger('Could not enable PHP logging');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$res = json_decode(@file_get_contents('https://rpc.madelineproto.xyz/v3.json'), true);
|
$res = \json_decode(@\file_get_contents('https://rpc.madelineproto.xyz/v3.json'), true);
|
||||||
if (isset($res['ok']) && $res['ok']) {
|
if (isset($res['ok']) && $res['ok']) {
|
||||||
RPCErrorException::$errorMethodMap = $res['result'];
|
RPCErrorException::$errorMethodMap = $res['result'];
|
||||||
RPCErrorException::$descriptions += $res['human_result'];
|
RPCErrorException::$descriptions += $res['human_result'];
|
||||||
@ -204,10 +204,10 @@ class Magic
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (self::$pid === null) {
|
if (self::$pid === null) {
|
||||||
self::$pid = getmypid();
|
self::$pid = \getmypid();
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::$is_fork = self::$pid !== getmypid();
|
return self::$is_fork = self::$pid !== \getmypid();
|
||||||
} catch (\danog\MadelineProto\Exception $e) {
|
} catch (\danog\MadelineProto\Exception $e) {
|
||||||
return self::$can_getmypid = false;
|
return self::$can_getmypid = false;
|
||||||
}
|
}
|
||||||
@ -215,6 +215,6 @@ class Magic
|
|||||||
|
|
||||||
public static function getcwd()
|
public static function getcwd()
|
||||||
{
|
{
|
||||||
return self::$can_getcwd ? getcwd() : self::$cwd;
|
return self::$can_getcwd ? \getcwd() : self::$cwd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,8 @@
|
|||||||
|
|
||||||
namespace danog\MadelineProto;
|
namespace danog\MadelineProto;
|
||||||
|
|
||||||
use Amp\Artax\Request;
|
|
||||||
use Amp\Artax\Cookie\ArrayCookieJar;
|
use Amp\Artax\Cookie\ArrayCookieJar;
|
||||||
|
use Amp\Artax\Request;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper for my.telegram.org.
|
* Wrapper for my.telegram.org.
|
||||||
@ -58,8 +58,7 @@ class MyTelegramOrgWrapper
|
|||||||
}
|
}
|
||||||
$this->settings = MTProto::getSettings($this->settings);
|
$this->settings = MTProto::getSettings($this->settings);
|
||||||
$this->datacenter = new DataCenter(
|
$this->datacenter = new DataCenter(
|
||||||
new class($this->settings)
|
new class($this->settings) {
|
||||||
{
|
|
||||||
public function __construct($settings)
|
public function __construct($settings)
|
||||||
{
|
{
|
||||||
$this->logger = Logger::getLoggerFromSettings($settings);
|
$this->logger = Logger::getLoggerFromSettings($settings);
|
||||||
@ -75,11 +74,11 @@ class MyTelegramOrgWrapper
|
|||||||
{
|
{
|
||||||
$this->number = $number;
|
$this->number = $number;
|
||||||
$request = new Request(self::MY_TELEGRAM_URL.'/auth/send_password', 'POST');
|
$request = new Request(self::MY_TELEGRAM_URL.'/auth/send_password', 'POST');
|
||||||
$request = $request->withBody(http_build_query(['phone' => $number]));
|
$request = $request->withBody(\http_build_query(['phone' => $number]));
|
||||||
$request = $request->withHeaders($this->getHeaders('origin'));
|
$request = $request->withHeaders($this->getHeaders('origin'));
|
||||||
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
||||||
$result = yield $response->getBody();
|
$result = yield $response->getBody();
|
||||||
$resulta = json_decode($result, true);
|
$resulta = \json_decode($result, true);
|
||||||
|
|
||||||
if (!isset($resulta['random_hash'])) {
|
if (!isset($resulta['random_hash'])) {
|
||||||
throw new Exception($result);
|
throw new Exception($result);
|
||||||
@ -94,13 +93,13 @@ class MyTelegramOrgWrapper
|
|||||||
}
|
}
|
||||||
|
|
||||||
$request = new Request(self::MY_TELEGRAM_URL.'/auth/login', 'POST');
|
$request = new Request(self::MY_TELEGRAM_URL.'/auth/login', 'POST');
|
||||||
$request = $request->withBody(http_build_query(['phone' => $this->number, 'random_hash' => $this->hash, 'password' => $password]));
|
$request = $request->withBody(\http_build_query(['phone' => $this->number, 'random_hash' => $this->hash, 'password' => $password]));
|
||||||
$request = $request->withHeaders($this->getHeaders('origin'));
|
$request = $request->withHeaders($this->getHeaders('origin'));
|
||||||
$request = $request->withHeader('user-agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13');
|
$request = $request->withHeader('user-agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13');
|
||||||
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
||||||
$result = yield $response->getBody();
|
$result = yield $response->getBody();
|
||||||
|
|
||||||
|
|
||||||
switch ($result) {
|
switch ($result) {
|
||||||
case 'true':
|
case 'true':
|
||||||
//Logger::log(['Login OK'], Logger::VERBOSE);
|
//Logger::log(['Login OK'], Logger::VERBOSE);
|
||||||
@ -128,18 +127,18 @@ class MyTelegramOrgWrapper
|
|||||||
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
||||||
$result = yield $response->getBody();
|
$result = yield $response->getBody();
|
||||||
|
|
||||||
$title = explode('</title>', explode('<title>', $result)[1])[0];
|
$title = \explode('</title>', \explode('<title>', $result)[1])[0];
|
||||||
switch ($title) {
|
switch ($title) {
|
||||||
case 'App configuration':
|
case 'App configuration':
|
||||||
return true;
|
return true;
|
||||||
case 'Create new application':
|
case 'Create new application':
|
||||||
$this->creation_hash = explode('"/>', explode('<input type="hidden" name="hash" value="', $result)[1])[0];
|
$this->creation_hash = \explode('"/>', \explode('<input type="hidden" name="hash" value="', $result)[1])[0];
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logged = false;
|
$this->logged = false;
|
||||||
|
|
||||||
throw new Exception($title);
|
throw new Exception($title);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,15 +153,15 @@ class MyTelegramOrgWrapper
|
|||||||
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
||||||
$result = yield $response->getBody();
|
$result = yield $response->getBody();
|
||||||
|
|
||||||
$cose = explode('<label for="app_id" class="col-md-4 text-right control-label">App api_id:</label>
|
$cose = \explode('<label for="app_id" class="col-md-4 text-right control-label">App api_id:</label>
|
||||||
<div class="col-md-7">
|
<div class="col-md-7">
|
||||||
<span class="form-control input-xlarge uneditable-input" onclick="this.select();"><strong>', $result);
|
<span class="form-control input-xlarge uneditable-input" onclick="this.select();"><strong>', $result);
|
||||||
$asd = explode('</strong></span>', $cose[1]);
|
$asd = \explode('</strong></span>', $cose[1]);
|
||||||
$api_id = $asd[0];
|
$api_id = $asd[0];
|
||||||
$cose = explode('<label for="app_hash" class="col-md-4 text-right control-label">App api_hash:</label>
|
$cose = \explode('<label for="app_hash" class="col-md-4 text-right control-label">App api_hash:</label>
|
||||||
<div class="col-md-7">
|
<div class="col-md-7">
|
||||||
<span class="form-control input-xlarge uneditable-input" onclick="this.select();">', $result);
|
<span class="form-control input-xlarge uneditable-input" onclick="this.select();">', $result);
|
||||||
$asd = explode('</span>', $cose[1]);
|
$asd = \explode('</span>', $cose[1]);
|
||||||
$api_hash = $asd[0];
|
$api_hash = $asd[0];
|
||||||
|
|
||||||
return ['api_id' => (int) $api_id, 'api_hash' => $api_hash];
|
return ['api_id' => (int) $api_id, 'api_hash' => $api_hash];
|
||||||
@ -176,15 +175,15 @@ class MyTelegramOrgWrapper
|
|||||||
if (yield $this->has_app_async()) {
|
if (yield $this->has_app_async()) {
|
||||||
throw new Exception('The app was already created!');
|
throw new Exception('The app was already created!');
|
||||||
}
|
}
|
||||||
|
|
||||||
$request = new Request(self::MY_TELEGRAM_URL.'/apps/create', 'POST');
|
$request = new Request(self::MY_TELEGRAM_URL.'/apps/create', 'POST');
|
||||||
$request = $request->withHeaders($this->getHeaders('app'));
|
$request = $request->withHeaders($this->getHeaders('app'));
|
||||||
$request = $request->withBody(http_build_query(['hash' => $this->creation_hash, 'app_title' => $settings['app_title'], 'app_shortname' => $settings['app_shortname'], 'app_url' => $settings['app_url'], 'app_platform' => $settings['app_platform'], 'app_desc' => $settings['app_desc']]));
|
$request = $request->withBody(\http_build_query(['hash' => $this->creation_hash, 'app_title' => $settings['app_title'], 'app_shortname' => $settings['app_shortname'], 'app_url' => $settings['app_url'], 'app_platform' => $settings['app_platform'], 'app_desc' => $settings['app_desc']]));
|
||||||
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
||||||
$result = yield $response->getBody();
|
$result = yield $response->getBody();
|
||||||
|
|
||||||
if ($result) {
|
if ($result) {
|
||||||
throw new Exception(html_entity_decode($result));
|
throw new Exception(\html_entity_decode($result));
|
||||||
}
|
}
|
||||||
|
|
||||||
$request = new Request(self::MY_TELEGRAM_URL.'/apps');
|
$request = new Request(self::MY_TELEGRAM_URL.'/apps');
|
||||||
@ -192,22 +191,22 @@ class MyTelegramOrgWrapper
|
|||||||
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
||||||
$result = yield $response->getBody();
|
$result = yield $response->getBody();
|
||||||
|
|
||||||
$title = explode('</title>', explode('<title>', $result)[1])[0];
|
$title = \explode('</title>', \explode('<title>', $result)[1])[0];
|
||||||
if ($title === 'Create new application') {
|
if ($title === 'Create new application') {
|
||||||
$this->creation_hash = explode('"/>', explode('<input type="hidden" name="hash" value="', $result)[1])[0];
|
$this->creation_hash = \explode('"/>', \explode('<input type="hidden" name="hash" value="', $result)[1])[0];
|
||||||
|
|
||||||
throw new \danog\MadelineProto\Exception('App creation failed');
|
throw new \danog\MadelineProto\Exception('App creation failed');
|
||||||
}
|
}
|
||||||
|
|
||||||
$cose = explode('<label for="app_id" class="col-md-4 text-right control-label">App api_id:</label>
|
$cose = \explode('<label for="app_id" class="col-md-4 text-right control-label">App api_id:</label>
|
||||||
<div class="col-md-7">
|
<div class="col-md-7">
|
||||||
<span class="form-control input-xlarge uneditable-input" onclick="this.select();"><strong>', $result);
|
<span class="form-control input-xlarge uneditable-input" onclick="this.select();"><strong>', $result);
|
||||||
$asd = explode('</strong></span>', $cose['1']);
|
$asd = \explode('</strong></span>', $cose['1']);
|
||||||
$api_id = $asd['0'];
|
$api_id = $asd['0'];
|
||||||
$cose = explode('<label for="app_hash" class="col-md-4 text-right control-label">App api_hash:</label>
|
$cose = \explode('<label for="app_hash" class="col-md-4 text-right control-label">App api_hash:</label>
|
||||||
<div class="col-md-7">
|
<div class="col-md-7">
|
||||||
<span class="form-control input-xlarge uneditable-input" onclick="this.select();">', $result);
|
<span class="form-control input-xlarge uneditable-input" onclick="this.select();">', $result);
|
||||||
$asd = explode('</span>', $cose['1']);
|
$asd = \explode('</span>', $cose['1']);
|
||||||
$api_hash = $asd['0'];
|
$api_hash = $asd['0'];
|
||||||
|
|
||||||
return ['api_id' => (int) $api_id, 'api_hash' => $api_hash];
|
return ['api_id' => (int) $api_id, 'api_hash' => $api_hash];
|
||||||
@ -254,8 +253,8 @@ class MyTelegramOrgWrapper
|
|||||||
|
|
||||||
$final_headers = [];
|
$final_headers = [];
|
||||||
foreach ($headers as $header) {
|
foreach ($headers as $header) {
|
||||||
list($key, $value) = explode(':', $header, 2);
|
list($key, $value) = \explode(':', $header, 2);
|
||||||
$final_headers[trim($key)] = trim($value);
|
$final_headers[\trim($key)] = \trim($value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $final_headers;
|
return $final_headers;
|
||||||
@ -272,9 +271,9 @@ class MyTelegramOrgWrapper
|
|||||||
public function __call($name, $arguments)
|
public function __call($name, $arguments)
|
||||||
{
|
{
|
||||||
$name .= '_async';
|
$name .= '_async';
|
||||||
$async = is_array(end($arguments)) && isset(end($arguments)['async']) ? end($arguments)['async'] : $this->async;
|
$async = \is_array(\end($arguments)) && isset(\end($arguments)['async']) ? \end($arguments)['async'] : $this->async;
|
||||||
|
|
||||||
if (!method_exists($this, $name)) {
|
if (!\method_exists($this, $name)) {
|
||||||
throw new Exception("$name does not exist!");
|
throw new Exception("$name does not exist!");
|
||||||
}
|
}
|
||||||
return $async ? $this->{$name}(...$arguments) : $this->wait($this->{$name}(...$arguments));
|
return $async ? $this->{$name}(...$arguments) : $this->wait($this->{$name}(...$arguments));
|
||||||
|
@ -25,7 +25,7 @@ class PTSException extends \Exception
|
|||||||
|
|
||||||
public function __toString()
|
public function __toString()
|
||||||
{
|
{
|
||||||
return get_class($this).($this->message !== '' ? ': ' : '').$this->message.PHP_EOL.'TL Trace:'.PHP_EOL.PHP_EOL.$this->getTLTrace().PHP_EOL;
|
return \get_class($this).($this->message !== '' ? ': ' : '').$this->message.PHP_EOL.'TL Trace:'.PHP_EOL.PHP_EOL.$this->getTLTrace().PHP_EOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __construct($message, $file = '')
|
public function __construct($message, $file = '')
|
||||||
|
@ -78,16 +78,16 @@ class RPCErrorException extends \Exception
|
|||||||
return $error;
|
return $error;
|
||||||
}
|
}
|
||||||
|
|
||||||
$error = preg_replace('/\d+$/', "X", $error);
|
$error = \preg_replace('/\d+$/', "X", $error);
|
||||||
|
|
||||||
$description = self::$descriptions[$error] ?? '';
|
$description = self::$descriptions[$error] ?? '';
|
||||||
|
|
||||||
|
|
||||||
if (!isset(self::$errorMethodMap[$code][$method][$error])
|
if (!isset(self::$errorMethodMap[$code][$method][$error])
|
||||||
|| !isset(self::$descriptions[$error])
|
|| !isset(self::$descriptions[$error])
|
||||||
|| $code === 500
|
|| $code === 500
|
||||||
) {
|
) {
|
||||||
$res = json_decode(@file_get_contents('https://rpc.pwrtelegram.xyz/?method='.$method.'&code='.$code.'&error='.$error, false, stream_context_create(['http'=>['timeout' => 3]])), true);
|
$res = \json_decode(@\file_get_contents('https://rpc.pwrtelegram.xyz/?method='.$method.'&code='.$code.'&error='.$error, false, \stream_context_create(['http'=>['timeout' => 3]])), true);
|
||||||
if (isset($res['ok']) && $res['ok'] && isset($res['result'])) {
|
if (isset($res['ok']) && $res['ok'] && isset($res['result'])) {
|
||||||
$description = $res['result'];
|
$description = $res['result'];
|
||||||
|
|
||||||
@ -104,9 +104,9 @@ class RPCErrorException extends \Exception
|
|||||||
|
|
||||||
public function __toString()
|
public function __toString()
|
||||||
{
|
{
|
||||||
$result = sprintf(\danog\MadelineProto\Lang::$current_lang['rpc_tg_error'], self::localizeMessage($this->caller, $this->code, $this->message)." ({$this->code})", $this->rpc, $this->file, $this->line.PHP_EOL, \danog\MadelineProto\Magic::$revision.PHP_EOL.PHP_EOL).PHP_EOL.$this->getTLTrace().PHP_EOL;
|
$result = \sprintf(\danog\MadelineProto\Lang::$current_lang['rpc_tg_error'], self::localizeMessage($this->caller, $this->code, $this->message)." ({$this->code})", $this->rpc, $this->file, $this->line.PHP_EOL, \danog\MadelineProto\Magic::$revision.PHP_EOL.PHP_EOL).PHP_EOL.$this->getTLTrace().PHP_EOL;
|
||||||
if (php_sapi_name() !== 'cli') {
|
if (PHP_SAPI !== 'cli') {
|
||||||
$result = str_replace(PHP_EOL, '<br>'.PHP_EOL, $result);
|
$result = \str_replace(PHP_EOL, '<br>'.PHP_EOL, $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
@ -125,16 +125,15 @@ class RPCErrorException extends \Exception
|
|||||||
$this->line = $level['line'];
|
$this->line = $level['line'];
|
||||||
$this->file = $level['file'];
|
$this->file = $level['file'];
|
||||||
$additional = $level['args'];
|
$additional = $level['args'];
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!self::$rollbar || !class_exists(\Rollbar\Rollbar::class)) {
|
if (!self::$rollbar || !\class_exists(\Rollbar\Rollbar::class)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (in_array($this->rpc, ['CHANNEL_PRIVATE', -404, -429, 'USERNAME_NOT_OCCUPIED', 'ACCESS_TOKEN_INVALID', 'AUTH_KEY_UNREGISTERED', 'SESSION_PASSWORD_NEEDED', 'PHONE_NUMBER_UNOCCUPIED', 'PEER_ID_INVALID', 'CHAT_ID_INVALID', 'USERNAME_INVALID', 'CHAT_WRITE_FORBIDDEN', 'CHAT_ADMIN_REQUIRED', 'PEER_FLOOD'])) {
|
if (\in_array($this->rpc, ['CHANNEL_PRIVATE', -404, -429, 'USERNAME_NOT_OCCUPIED', 'ACCESS_TOKEN_INVALID', 'AUTH_KEY_UNREGISTERED', 'SESSION_PASSWORD_NEEDED', 'PHONE_NUMBER_UNOCCUPIED', 'PEER_ID_INVALID', 'CHAT_ID_INVALID', 'USERNAME_INVALID', 'CHAT_WRITE_FORBIDDEN', 'CHAT_ADMIN_REQUIRED', 'PEER_FLOOD'])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (strpos($this->rpc, 'FLOOD_WAIT_') !== false) {
|
if (\strpos($this->rpc, 'FLOOD_WAIT_') !== false) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$message === 'Telegram is having internal issues, please try again later.' ? \Rollbar\Rollbar::log(\Rollbar\Payload\Level::critical(), $message) : \Rollbar\Rollbar::log(\Rollbar\Payload\Level::error(), $this, $additional);
|
$message === 'Telegram is having internal issues, please try again later.' ? \Rollbar\Rollbar::log(\Rollbar\Payload\Level::critical(), $message) : \Rollbar\Rollbar::log(\Rollbar\Payload\Level::error(), $this, $additional);
|
||||||
|
@ -35,7 +35,7 @@ class RSA
|
|||||||
$this->n = self::getVar($key, 'modulus');
|
$this->n = self::getVar($key, 'modulus');
|
||||||
$this->e = self::getVar($key, 'exponent');
|
$this->e = self::getVar($key, 'exponent');
|
||||||
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['computing_fingerprint'], Logger::ULTRA_VERBOSE);
|
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['computing_fingerprint'], Logger::ULTRA_VERBOSE);
|
||||||
$this->fp = substr(sha1((yield $this->serialize_object_async(['type' => 'bytes'], $this->n->toBytes(), 'key')).(yield $this->serialize_object_async(['type' => 'bytes'], $this->e->toBytes(), 'key')), true), -8);
|
$this->fp = \substr(\sha1((yield $this->serialize_object_async(['type' => 'bytes'], $this->n->toBytes(), 'key')).(yield $this->serialize_object_async(['type' => 'bytes'], $this->e->toBytes(), 'key')), true), -8);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@ -52,7 +52,7 @@ class RSA
|
|||||||
return (new \phpseclib\Math\BigInteger((string) $data, 256))->powMod($this->e, $this->n)->toBytes();
|
return (new \phpseclib\Math\BigInteger((string) $data, 256))->powMod($this->e, $this->n)->toBytes();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Accesses a private variable from an object
|
* Accesses a private variable from an object.
|
||||||
*
|
*
|
||||||
* @param object $obj
|
* @param object $obj
|
||||||
* @param string $var
|
* @param string $var
|
||||||
@ -61,7 +61,7 @@ class RSA
|
|||||||
*/
|
*/
|
||||||
public static function getVar($obj, $var)
|
public static function getVar($obj, $var)
|
||||||
{
|
{
|
||||||
$reflection = new \ReflectionClass(get_class($obj));
|
$reflection = new \ReflectionClass(\get_class($obj));
|
||||||
$prop = $reflection->getProperty($var);
|
$prop = $reflection->getProperty($var);
|
||||||
$prop->setAccessible(true);
|
$prop->setAccessible(true);
|
||||||
return $prop->getValue($obj);
|
return $prop->getValue($obj);
|
||||||
|
@ -43,12 +43,12 @@ trait AuthKeyHandler
|
|||||||
$b = new \phpseclib\Math\BigInteger($this->random(256), 256);
|
$b = new \phpseclib\Math\BigInteger($this->random(256), 256);
|
||||||
$params['g_a'] = new \phpseclib\Math\BigInteger((string) $params['g_a'], 256);
|
$params['g_a'] = new \phpseclib\Math\BigInteger((string) $params['g_a'], 256);
|
||||||
$this->check_G($params['g_a'], $dh_config['p']);
|
$this->check_G($params['g_a'], $dh_config['p']);
|
||||||
$key = ['auth_key' => str_pad($params['g_a']->powMod($b, $dh_config['p'])->toBytes(), 256, chr(0), \STR_PAD_LEFT)];
|
$key = ['auth_key' => \str_pad($params['g_a']->powMod($b, $dh_config['p'])->toBytes(), 256, \chr(0), \STR_PAD_LEFT)];
|
||||||
//$this->logger->logger($key);
|
//$this->logger->logger($key);
|
||||||
$key['fingerprint'] = substr(sha1($key['auth_key'], true), -8);
|
$key['fingerprint'] = \substr(\sha1($key['auth_key'], true), -8);
|
||||||
$key['visualization_orig'] = substr(sha1($key['auth_key'], true), 16);
|
$key['visualization_orig'] = \substr(\sha1($key['auth_key'], true), 16);
|
||||||
$key['visualization_46'] = substr(hash('sha256', $key['auth_key'], true), 20);
|
$key['visualization_46'] = \substr(\hash('sha256', $key['auth_key'], true), 20);
|
||||||
$this->secret_chats[$params['id']] = ['key' => $key, 'admin' => false, 'user_id' => $params['admin_id'], 'InputEncryptedChat' => ['_' => 'inputEncryptedChat', 'chat_id' => $params['id'], 'access_hash' => $params['access_hash']], 'in_seq_no_x' => 1, 'out_seq_no_x' => 0, 'in_seq_no' => 0, 'out_seq_no' => 0, 'layer' => 8, 'ttl' => 0, 'ttr' => 100, 'updated' => time(), 'incoming' => [], 'outgoing' => [], 'created' => time(), 'rekeying' => [0], 'key_x' => 'from server', 'mtproto' => 1];
|
$this->secret_chats[$params['id']] = ['key' => $key, 'admin' => false, 'user_id' => $params['admin_id'], 'InputEncryptedChat' => ['_' => 'inputEncryptedChat', 'chat_id' => $params['id'], 'access_hash' => $params['access_hash']], 'in_seq_no_x' => 1, 'out_seq_no_x' => 0, 'in_seq_no' => 0, 'out_seq_no' => 0, 'layer' => 8, 'ttl' => 0, 'ttr' => 100, 'updated' => \time(), 'incoming' => [], 'outgoing' => [], 'created' => \time(), 'rekeying' => [0], 'key_x' => 'from server', 'mtproto' => 1];
|
||||||
$g_b = $dh_config['g']->powMod($b, $dh_config['p']);
|
$g_b = $dh_config['g']->powMod($b, $dh_config['p']);
|
||||||
$this->check_G($g_b, $dh_config['p']);
|
$this->check_G($g_b, $dh_config['p']);
|
||||||
yield $this->method_call_async_read('messages.acceptEncryption', ['peer' => $params['id'], 'g_b' => $g_b->toBytes(), 'key_fingerprint' => $key['fingerprint']], ['datacenter' => $this->datacenter->curdc]);
|
yield $this->method_call_async_read('messages.acceptEncryption', ['peer' => $params['id'], 'g_b' => $g_b->toBytes(), 'key_fingerprint' => $key['fingerprint']], ['datacenter' => $this->datacenter->curdc]);
|
||||||
@ -89,18 +89,18 @@ trait AuthKeyHandler
|
|||||||
$dh_config = yield $this->get_dh_config_async();
|
$dh_config = yield $this->get_dh_config_async();
|
||||||
$params['g_a_or_b'] = new \phpseclib\Math\BigInteger((string) $params['g_a_or_b'], 256);
|
$params['g_a_or_b'] = new \phpseclib\Math\BigInteger((string) $params['g_a_or_b'], 256);
|
||||||
$this->check_G($params['g_a_or_b'], $dh_config['p']);
|
$this->check_G($params['g_a_or_b'], $dh_config['p']);
|
||||||
$key = ['auth_key' => str_pad($params['g_a_or_b']->powMod($this->temp_requested_secret_chats[$params['id']], $dh_config['p'])->toBytes(), 256, chr(0), \STR_PAD_LEFT)];
|
$key = ['auth_key' => \str_pad($params['g_a_or_b']->powMod($this->temp_requested_secret_chats[$params['id']], $dh_config['p'])->toBytes(), 256, \chr(0), \STR_PAD_LEFT)];
|
||||||
unset($this->temp_requested_secret_chats[$params['id']]);
|
unset($this->temp_requested_secret_chats[$params['id']]);
|
||||||
$key['fingerprint'] = substr(sha1($key['auth_key'], true), -8);
|
$key['fingerprint'] = \substr(\sha1($key['auth_key'], true), -8);
|
||||||
//$this->logger->logger($key);
|
//$this->logger->logger($key);
|
||||||
if ($key['fingerprint'] !== $params['key_fingerprint']) {
|
if ($key['fingerprint'] !== $params['key_fingerprint']) {
|
||||||
yield $this->discard_secret_chat_async($params['id']);
|
yield $this->discard_secret_chat_async($params['id']);
|
||||||
|
|
||||||
throw new \danog\MadelineProto\SecurityException('Invalid key fingerprint!');
|
throw new \danog\MadelineProto\SecurityException('Invalid key fingerprint!');
|
||||||
}
|
}
|
||||||
$key['visualization_orig'] = substr(sha1($key['auth_key'], true), 16);
|
$key['visualization_orig'] = \substr(\sha1($key['auth_key'], true), 16);
|
||||||
$key['visualization_46'] = substr(hash('sha256', $key['auth_key'], true), 20);
|
$key['visualization_46'] = \substr(\hash('sha256', $key['auth_key'], true), 20);
|
||||||
$this->secret_chats[$params['id']] = ['key' => $key, 'admin' => true, 'user_id' => $params['participant_id'], 'InputEncryptedChat' => ['chat_id' => $params['id'], 'access_hash' => $params['access_hash'], '_' => 'inputEncryptedChat'], 'in_seq_no_x' => 0, 'out_seq_no_x' => 1, 'in_seq_no' => 0, 'out_seq_no' => 0, 'layer' => 8, 'ttl' => 0, 'ttr' => 100, 'updated' => time(), 'incoming' => [], 'outgoing' => [], 'created' => time(), 'rekeying' => [0], 'key_x' => 'to server', 'mtproto' => 1];
|
$this->secret_chats[$params['id']] = ['key' => $key, 'admin' => true, 'user_id' => $params['participant_id'], 'InputEncryptedChat' => ['chat_id' => $params['id'], 'access_hash' => $params['access_hash'], '_' => 'inputEncryptedChat'], 'in_seq_no_x' => 0, 'out_seq_no_x' => 1, 'in_seq_no' => 0, 'out_seq_no' => 0, 'layer' => 8, 'ttl' => 0, 'ttr' => 100, 'updated' => \time(), 'incoming' => [], 'outgoing' => [], 'created' => \time(), 'rekeying' => [0], 'key_x' => 'to server', 'mtproto' => 1];
|
||||||
yield $this->notify_layer_async($params['id']);
|
yield $this->notify_layer_async($params['id']);
|
||||||
$this->logger->logger('Secret chat '.$params['id'].' completed successfully!', \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger('Secret chat '.$params['id'].' completed successfully!', \danog\MadelineProto\Logger::NOTICE);
|
||||||
}
|
}
|
||||||
@ -154,10 +154,10 @@ trait AuthKeyHandler
|
|||||||
$b = new \phpseclib\Math\BigInteger($this->random(256), 256);
|
$b = new \phpseclib\Math\BigInteger($this->random(256), 256);
|
||||||
$params['g_a'] = new \phpseclib\Math\BigInteger((string) $params['g_a'], 256);
|
$params['g_a'] = new \phpseclib\Math\BigInteger((string) $params['g_a'], 256);
|
||||||
$this->check_G($params['g_a'], $dh_config['p']);
|
$this->check_G($params['g_a'], $dh_config['p']);
|
||||||
$key = ['auth_key' => str_pad($params['g_a']->powMod($b, $dh_config['p'])->toBytes(), 256, chr(0), \STR_PAD_LEFT)];
|
$key = ['auth_key' => \str_pad($params['g_a']->powMod($b, $dh_config['p'])->toBytes(), 256, \chr(0), \STR_PAD_LEFT)];
|
||||||
$key['fingerprint'] = substr(sha1($key['auth_key'], true), -8);
|
$key['fingerprint'] = \substr(\sha1($key['auth_key'], true), -8);
|
||||||
$key['visualization_orig'] = $this->secret_chats[$chat]['key']['visualization_orig'];
|
$key['visualization_orig'] = $this->secret_chats[$chat]['key']['visualization_orig'];
|
||||||
$key['visualization_46'] = substr(hash('sha256', $key['auth_key'], true), 20);
|
$key['visualization_46'] = \substr(\hash('sha256', $key['auth_key'], true), 20);
|
||||||
$this->temp_rekeyed_secret_chats[$params['exchange_id']] = $key;
|
$this->temp_rekeyed_secret_chats[$params['exchange_id']] = $key;
|
||||||
$this->secret_chats[$chat]['rekeying'] = [2, $params['exchange_id']];
|
$this->secret_chats[$chat]['rekeying'] = [2, $params['exchange_id']];
|
||||||
$g_b = $dh_config['g']->powMod($b, $dh_config['p']);
|
$g_b = $dh_config['g']->powMod($b, $dh_config['p']);
|
||||||
@ -177,10 +177,10 @@ trait AuthKeyHandler
|
|||||||
$dh_config = yield $this->get_dh_config_async();
|
$dh_config = yield $this->get_dh_config_async();
|
||||||
$params['g_b'] = new \phpseclib\Math\BigInteger((string) $params['g_b'], 256);
|
$params['g_b'] = new \phpseclib\Math\BigInteger((string) $params['g_b'], 256);
|
||||||
$this->check_G($params['g_b'], $dh_config['p']);
|
$this->check_G($params['g_b'], $dh_config['p']);
|
||||||
$key = ['auth_key' => str_pad($params['g_b']->powMod($this->temp_rekeyed_secret_chats[$params['exchange_id']], $dh_config['p'])->toBytes(), 256, chr(0), \STR_PAD_LEFT)];
|
$key = ['auth_key' => \str_pad($params['g_b']->powMod($this->temp_rekeyed_secret_chats[$params['exchange_id']], $dh_config['p'])->toBytes(), 256, \chr(0), \STR_PAD_LEFT)];
|
||||||
$key['fingerprint'] = substr(sha1($key['auth_key'], true), -8);
|
$key['fingerprint'] = \substr(\sha1($key['auth_key'], true), -8);
|
||||||
$key['visualization_orig'] = $this->secret_chats[$chat]['key']['visualization_orig'];
|
$key['visualization_orig'] = $this->secret_chats[$chat]['key']['visualization_orig'];
|
||||||
$key['visualization_46'] = substr(hash('sha256', $key['auth_key'], true), 20);
|
$key['visualization_46'] = \substr(\hash('sha256', $key['auth_key'], true), 20);
|
||||||
if ($key['fingerprint'] !== $params['key_fingerprint']) {
|
if ($key['fingerprint'] !== $params['key_fingerprint']) {
|
||||||
yield $this->method_call_async_read('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionAbortKey', 'exchange_id' => $params['exchange_id']]]], ['datacenter' => $this->datacenter->curdc]);
|
yield $this->method_call_async_read('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionAbortKey', 'exchange_id' => $params['exchange_id']]]], ['datacenter' => $this->datacenter->curdc]);
|
||||||
|
|
||||||
@ -192,7 +192,7 @@ trait AuthKeyHandler
|
|||||||
$this->secret_chats[$chat]['old_key'] = $this->secret_chats[$chat]['key'];
|
$this->secret_chats[$chat]['old_key'] = $this->secret_chats[$chat]['key'];
|
||||||
$this->secret_chats[$chat]['key'] = $key;
|
$this->secret_chats[$chat]['key'] = $key;
|
||||||
$this->secret_chats[$chat]['ttr'] = 100;
|
$this->secret_chats[$chat]['ttr'] = 100;
|
||||||
$this->secret_chats[$chat]['updated'] = time();
|
$this->secret_chats[$chat]['updated'] = \time();
|
||||||
$this->updaters[false]->resume();
|
$this->updaters[false]->resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,7 +211,7 @@ trait AuthKeyHandler
|
|||||||
$this->secret_chats[$chat]['old_key'] = $this->secret_chats[$chat]['key'];
|
$this->secret_chats[$chat]['old_key'] = $this->secret_chats[$chat]['key'];
|
||||||
$this->secret_chats[$chat]['key'] = $this->temp_rekeyed_secret_chats[$chat];
|
$this->secret_chats[$chat]['key'] = $this->temp_rekeyed_secret_chats[$chat];
|
||||||
$this->secret_chats[$chat]['ttr'] = 100;
|
$this->secret_chats[$chat]['ttr'] = 100;
|
||||||
$this->secret_chats[$chat]['updated'] = time();
|
$this->secret_chats[$chat]['updated'] = \time();
|
||||||
unset($this->temp_rekeyed_secret_chats[$params['exchange_id']]);
|
unset($this->temp_rekeyed_secret_chats[$params['exchange_id']]);
|
||||||
yield $this->method_call_async_read('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionNoop']]], ['datacenter' => $this->datacenter->curdc]);
|
yield $this->method_call_async_read('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionNoop']]], ['datacenter' => $this->datacenter->curdc]);
|
||||||
$this->logger->logger('Secret chat '.$chat.' rekeyed successfully!', \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger('Secret chat '.$chat.' rekeyed successfully!', \danog\MadelineProto\Logger::VERBOSE);
|
||||||
@ -233,7 +233,7 @@ trait AuthKeyHandler
|
|||||||
|
|
||||||
public function get_secret_chat($chat)
|
public function get_secret_chat($chat)
|
||||||
{
|
{
|
||||||
return $this->secret_chats[is_array($chat) ? $chat['chat_id'] : $chat];
|
return $this->secret_chats[\is_array($chat) ? $chat['chat_id'] : $chat];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function discard_secret_chat_async($chat)
|
public function discard_secret_chat_async($chat)
|
||||||
|
@ -27,14 +27,14 @@ trait MessageHandler
|
|||||||
public function encrypt_secret_message_async($chat_id, $message)
|
public function encrypt_secret_message_async($chat_id, $message)
|
||||||
{
|
{
|
||||||
if (!isset($this->secret_chats[$chat_id])) {
|
if (!isset($this->secret_chats[$chat_id])) {
|
||||||
$this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['secret_chat_skipping'], $chat_id));
|
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['secret_chat_skipping'], $chat_id));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$message['random_id'] = $this->random(8);
|
$message['random_id'] = $this->random(8);
|
||||||
$this->secret_chats[$chat_id]['ttr']--;
|
$this->secret_chats[$chat_id]['ttr']--;
|
||||||
if ($this->secret_chats[$chat_id]['layer'] > 8) {
|
if ($this->secret_chats[$chat_id]['layer'] > 8) {
|
||||||
if (($this->secret_chats[$chat_id]['ttr'] <= 0 || time() - $this->secret_chats[$chat_id]['updated'] > 7 * 24 * 60 * 60) && $this->secret_chats[$chat_id]['rekeying'][0] === 0) {
|
if (($this->secret_chats[$chat_id]['ttr'] <= 0 || \time() - $this->secret_chats[$chat_id]['updated'] > 7 * 24 * 60 * 60) && $this->secret_chats[$chat_id]['rekeying'][0] === 0) {
|
||||||
yield $this->rekey_async($chat_id);
|
yield $this->rekey_async($chat_id);
|
||||||
}
|
}
|
||||||
$message = ['_' => 'decryptedMessageLayer', 'layer' => $this->secret_chats[$chat_id]['layer'], 'in_seq_no' => $this->generate_secret_in_seq_no($chat_id), 'out_seq_no' => $this->generate_secret_out_seq_no($chat_id), 'message' => $message];
|
$message = ['_' => 'decryptedMessageLayer', 'layer' => $this->secret_chats[$chat_id]['layer'], 'in_seq_no' => $this->generate_secret_in_seq_no($chat_id), 'out_seq_no' => $this->generate_secret_out_seq_no($chat_id), 'message' => $message];
|
||||||
@ -42,19 +42,19 @@ trait MessageHandler
|
|||||||
}
|
}
|
||||||
$this->secret_chats[$chat_id]['outgoing'][$this->secret_chats[$chat_id]['out_seq_no']] = $message;
|
$this->secret_chats[$chat_id]['outgoing'][$this->secret_chats[$chat_id]['out_seq_no']] = $message;
|
||||||
$message = yield $this->serialize_object_async(['type' => $constructor = $this->secret_chats[$chat_id]['layer'] === 8 ? 'DecryptedMessage' : 'DecryptedMessageLayer'], $message, $constructor, $this->secret_chats[$chat_id]['layer']);
|
$message = yield $this->serialize_object_async(['type' => $constructor = $this->secret_chats[$chat_id]['layer'] === 8 ? 'DecryptedMessage' : 'DecryptedMessageLayer'], $message, $constructor, $this->secret_chats[$chat_id]['layer']);
|
||||||
$message = $this->pack_unsigned_int(strlen($message)).$message;
|
$message = $this->pack_unsigned_int(\strlen($message)).$message;
|
||||||
if ($this->secret_chats[$chat_id]['mtproto'] === 2) {
|
if ($this->secret_chats[$chat_id]['mtproto'] === 2) {
|
||||||
$padding = $this->posmod(-strlen($message), 16);
|
$padding = $this->posmod(-\strlen($message), 16);
|
||||||
if ($padding < 12) {
|
if ($padding < 12) {
|
||||||
$padding += 16;
|
$padding += 16;
|
||||||
}
|
}
|
||||||
$message .= $this->random($padding);
|
$message .= $this->random($padding);
|
||||||
$message_key = substr(hash('sha256', substr($this->secret_chats[$chat_id]['key']['auth_key'], 88 + ($this->secret_chats[$chat_id]['admin'] ? 0 : 8), 32).$message, true), 8, 16);
|
$message_key = \substr(\hash('sha256', \substr($this->secret_chats[$chat_id]['key']['auth_key'], 88 + ($this->secret_chats[$chat_id]['admin'] ? 0 : 8), 32).$message, true), 8, 16);
|
||||||
list($aes_key, $aes_iv) = $this->aes_calculate($message_key, $this->secret_chats[$chat_id]['key']['auth_key'], $this->secret_chats[$chat_id]['admin']);
|
list($aes_key, $aes_iv) = $this->aes_calculate($message_key, $this->secret_chats[$chat_id]['key']['auth_key'], $this->secret_chats[$chat_id]['admin']);
|
||||||
} else {
|
} else {
|
||||||
$message_key = substr(sha1($message, true), -16);
|
$message_key = \substr(\sha1($message, true), -16);
|
||||||
list($aes_key, $aes_iv) = $this->old_aes_calculate($message_key, $this->secret_chats[$chat_id]['key']['auth_key'], true);
|
list($aes_key, $aes_iv) = $this->old_aes_calculate($message_key, $this->secret_chats[$chat_id]['key']['auth_key'], true);
|
||||||
$message .= $this->random($this->posmod(-strlen($message), 16));
|
$message .= $this->random($this->posmod(-\strlen($message), 16));
|
||||||
}
|
}
|
||||||
$message = $this->secret_chats[$chat_id]['key']['fingerprint'].$message_key.$this->ige_encrypt($message, $aes_key, $aes_iv);
|
$message = $this->secret_chats[$chat_id]['key']['fingerprint'].$message_key.$this->ige_encrypt($message, $aes_key, $aes_iv);
|
||||||
|
|
||||||
@ -64,11 +64,11 @@ trait MessageHandler
|
|||||||
public function handle_encrypted_update_async($message, $test = false)
|
public function handle_encrypted_update_async($message, $test = false)
|
||||||
{
|
{
|
||||||
if (!isset($this->secret_chats[$message['message']['chat_id']])) {
|
if (!isset($this->secret_chats[$message['message']['chat_id']])) {
|
||||||
$this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['secret_chat_skipping'], $message['message']['chat_id']));
|
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['secret_chat_skipping'], $message['message']['chat_id']));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$auth_key_id = substr($message['message']['bytes'], 0, 8);
|
$auth_key_id = \substr($message['message']['bytes'], 0, 8);
|
||||||
$old = false;
|
$old = false;
|
||||||
if ($auth_key_id !== $this->secret_chats[$message['message']['chat_id']]['key']['fingerprint']) {
|
if ($auth_key_id !== $this->secret_chats[$message['message']['chat_id']]['key']['fingerprint']) {
|
||||||
if (isset($this->secret_chats[$message['message']['chat_id']]['old_key']['fingerprint'])) {
|
if (isset($this->secret_chats[$message['message']['chat_id']]['old_key']['fingerprint'])) {
|
||||||
@ -84,8 +84,8 @@ trait MessageHandler
|
|||||||
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['fingerprint_mismatch']);
|
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['fingerprint_mismatch']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$message_key = substr($message['message']['bytes'], 8, 16);
|
$message_key = \substr($message['message']['bytes'], 8, 16);
|
||||||
$encrypted_data = substr($message['message']['bytes'], 24);
|
$encrypted_data = \substr($message['message']['bytes'], 24);
|
||||||
if ($this->secret_chats[$message['message']['chat_id']]['mtproto'] === 2) {
|
if ($this->secret_chats[$message['message']['chat_id']]['mtproto'] === 2) {
|
||||||
$this->logger->logger('Trying MTProto v2 decryption for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger('Trying MTProto v2 decryption for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE);
|
||||||
|
|
||||||
@ -113,7 +113,7 @@ trait MessageHandler
|
|||||||
}
|
}
|
||||||
$deserialized = $this->deserialize($message_data, ['type' => '']);
|
$deserialized = $this->deserialize($message_data, ['type' => '']);
|
||||||
$this->secret_chats[$message['message']['chat_id']]['ttr']--;
|
$this->secret_chats[$message['message']['chat_id']]['ttr']--;
|
||||||
if (($this->secret_chats[$message['message']['chat_id']]['ttr'] <= 0 || time() - $this->secret_chats[$message['message']['chat_id']]['updated'] > 7 * 24 * 60 * 60) && $this->secret_chats[$message['message']['chat_id']]['rekeying'][0] === 0) {
|
if (($this->secret_chats[$message['message']['chat_id']]['ttr'] <= 0 || \time() - $this->secret_chats[$message['message']['chat_id']]['updated'] > 7 * 24 * 60 * 60) && $this->secret_chats[$message['message']['chat_id']]['rekeying'][0] === 0) {
|
||||||
yield $this->rekey_async($message['message']['chat_id']);
|
yield $this->rekey_async($message['message']['chat_id']);
|
||||||
}
|
}
|
||||||
unset($message['message']['bytes']);
|
unset($message['message']['bytes']);
|
||||||
@ -126,18 +126,18 @@ trait MessageHandler
|
|||||||
{
|
{
|
||||||
list($aes_key, $aes_iv) = $this->old_aes_calculate($message_key, $this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], true);
|
list($aes_key, $aes_iv) = $this->old_aes_calculate($message_key, $this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], true);
|
||||||
$decrypted_data = $this->ige_decrypt($encrypted_data, $aes_key, $aes_iv);
|
$decrypted_data = $this->ige_decrypt($encrypted_data, $aes_key, $aes_iv);
|
||||||
$message_data_length = unpack('V', substr($decrypted_data, 0, 4))[1];
|
$message_data_length = \unpack('V', \substr($decrypted_data, 0, 4))[1];
|
||||||
$message_data = substr($decrypted_data, 4, $message_data_length);
|
$message_data = \substr($decrypted_data, 4, $message_data_length);
|
||||||
if ($message_data_length > strlen($decrypted_data)) {
|
if ($message_data_length > \strlen($decrypted_data)) {
|
||||||
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_data_length_too_big']);
|
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_data_length_too_big']);
|
||||||
}
|
}
|
||||||
if ($message_key != substr(sha1(substr($decrypted_data, 0, 4 + $message_data_length), true), -16)) {
|
if ($message_key != \substr(\sha1(\substr($decrypted_data, 0, 4 + $message_data_length), true), -16)) {
|
||||||
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_key_mismatch']);
|
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_key_mismatch']);
|
||||||
}
|
}
|
||||||
if (strlen($decrypted_data) - 4 - $message_data_length > 15) {
|
if (\strlen($decrypted_data) - 4 - $message_data_length > 15) {
|
||||||
throw new \danog\MadelineProto\SecurityException('difference between message_data_length and the length of the remaining decrypted buffer is too big');
|
throw new \danog\MadelineProto\SecurityException('difference between message_data_length and the length of the remaining decrypted buffer is too big');
|
||||||
}
|
}
|
||||||
if (strlen($decrypted_data) % 16 != 0) {
|
if (\strlen($decrypted_data) % 16 != 0) {
|
||||||
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['length_not_divisible_16']);
|
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['length_not_divisible_16']);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,21 +148,21 @@ trait MessageHandler
|
|||||||
{
|
{
|
||||||
list($aes_key, $aes_iv) = $this->aes_calculate($message_key, $this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], !$this->secret_chats[$chat_id]['admin']);
|
list($aes_key, $aes_iv) = $this->aes_calculate($message_key, $this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], !$this->secret_chats[$chat_id]['admin']);
|
||||||
$decrypted_data = $this->ige_decrypt($encrypted_data, $aes_key, $aes_iv);
|
$decrypted_data = $this->ige_decrypt($encrypted_data, $aes_key, $aes_iv);
|
||||||
$message_data_length = unpack('V', substr($decrypted_data, 0, 4))[1];
|
$message_data_length = \unpack('V', \substr($decrypted_data, 0, 4))[1];
|
||||||
$message_data = substr($decrypted_data, 4, $message_data_length);
|
$message_data = \substr($decrypted_data, 4, $message_data_length);
|
||||||
if ($message_data_length > strlen($decrypted_data)) {
|
if ($message_data_length > \strlen($decrypted_data)) {
|
||||||
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_data_length_too_big']);
|
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_data_length_too_big']);
|
||||||
}
|
}
|
||||||
if ($message_key != substr(hash('sha256', substr($this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], 88 + ($this->secret_chats[$chat_id]['admin'] ? 8 : 0), 32).$decrypted_data, true), 8, 16)) {
|
if ($message_key != \substr(\hash('sha256', \substr($this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], 88 + ($this->secret_chats[$chat_id]['admin'] ? 8 : 0), 32).$decrypted_data, true), 8, 16)) {
|
||||||
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_key_mismatch']);
|
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_key_mismatch']);
|
||||||
}
|
}
|
||||||
if (strlen($decrypted_data) - 4 - $message_data_length < 12) {
|
if (\strlen($decrypted_data) - 4 - $message_data_length < 12) {
|
||||||
throw new \danog\MadelineProto\SecurityException('padding is too small');
|
throw new \danog\MadelineProto\SecurityException('padding is too small');
|
||||||
}
|
}
|
||||||
if (strlen($decrypted_data) - 4 - $message_data_length > 1024) {
|
if (\strlen($decrypted_data) - 4 - $message_data_length > 1024) {
|
||||||
throw new \danog\MadelineProto\SecurityException('padding is too big');
|
throw new \danog\MadelineProto\SecurityException('padding is too big');
|
||||||
}
|
}
|
||||||
if (strlen($decrypted_data) % 16 != 0) {
|
if (\strlen($decrypted_data) % 16 != 0) {
|
||||||
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['length_not_divisible_16']);
|
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['length_not_divisible_16']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ trait ResponseHandler
|
|||||||
return;
|
return;
|
||||||
case 'decryptedMessageActionNotifyLayer':
|
case 'decryptedMessageActionNotifyLayer':
|
||||||
$this->secret_chats[$update['message']['chat_id']]['layer'] = $update['message']['decrypted_message']['action']['layer'];
|
$this->secret_chats[$update['message']['chat_id']]['layer'] = $update['message']['decrypted_message']['action']['layer'];
|
||||||
if ($update['message']['decrypted_message']['action']['layer'] >= 17 && time() - $this->secret_chats[$update['message']['chat_id']]['created'] > 15) {
|
if ($update['message']['decrypted_message']['action']['layer'] >= 17 && \time() - $this->secret_chats[$update['message']['chat_id']]['created'] > 15) {
|
||||||
yield $this->notify_layer_async($update['message']['chat_id']);
|
yield $this->notify_layer_async($update['message']['chat_id']);
|
||||||
}
|
}
|
||||||
if ($update['message']['decrypted_message']['action']['layer'] >= 73) {
|
if ($update['message']['decrypted_message']['action']['layer'] >= 73) {
|
||||||
@ -90,7 +90,7 @@ trait ResponseHandler
|
|||||||
$this->secret_chats[$update['message']['chat_id']]['in_seq_no']++;
|
$this->secret_chats[$update['message']['chat_id']]['in_seq_no']++;
|
||||||
if ($update['message']['decrypted_message']['layer'] >= 17) {
|
if ($update['message']['decrypted_message']['layer'] >= 17) {
|
||||||
$this->secret_chats[$update['message']['chat_id']]['layer'] = $update['message']['decrypted_message']['layer'];
|
$this->secret_chats[$update['message']['chat_id']]['layer'] = $update['message']['decrypted_message']['layer'];
|
||||||
if ($update['message']['decrypted_message']['layer'] >= 17 && time() - $this->secret_chats[$update['message']['chat_id']]['created'] > 15) {
|
if ($update['message']['decrypted_message']['layer'] >= 17 && \time() - $this->secret_chats[$update['message']['chat_id']]['created'] > 15) {
|
||||||
yield $this->notify_layer_async($update['message']['chat_id']);
|
yield $this->notify_layer_async($update['message']['chat_id']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -99,7 +99,7 @@ trait ResponseHandler
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new \danog\MadelineProto\ResponseException(\danog\MadelineProto\Lang::$current_lang['unrecognized_dec_msg'].var_export($update, true));
|
throw new \danog\MadelineProto\ResponseException(\danog\MadelineProto\Lang::$current_lang['unrecognized_dec_msg'].\var_export($update, true));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,9 +57,8 @@ trait SeqNoHandler
|
|||||||
yield $this->discard_secret_chat_async($chat_id);
|
yield $this->discard_secret_chat_async($chat_id);
|
||||||
|
|
||||||
throw new \danog\MadelineProto\SecurityException('out_seq_no hole: should be '.$C.', is '.($message['decrypted_message']['out_seq_no'] - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2);
|
throw new \danog\MadelineProto\SecurityException('out_seq_no hole: should be '.$C.', is '.($message['decrypted_message']['out_seq_no'] - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2);
|
||||||
} else {
|
|
||||||
$C++;
|
|
||||||
}
|
}
|
||||||
|
$C++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//$this->logger->logger($C, $seqno);
|
//$this->logger->logger($C, $seqno);
|
||||||
|
@ -30,25 +30,25 @@ class Server
|
|||||||
|
|
||||||
public function __construct($settings)
|
public function __construct($settings)
|
||||||
{
|
{
|
||||||
set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
|
\set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
|
||||||
\danog\MadelineProto\Logger::constructor(3);
|
\danog\MadelineProto\Logger::constructor(3);
|
||||||
|
|
||||||
if (!extension_loaded('sockets')) {
|
if (!\extension_loaded('sockets')) {
|
||||||
throw new Exception(['extension', 'sockets']);
|
throw new Exception(['extension', 'sockets']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!extension_loaded('pcntl')) {
|
if (!\extension_loaded('pcntl')) {
|
||||||
throw new Exception(['extension', 'pcntl']);
|
throw new Exception(['extension', 'pcntl']);
|
||||||
}
|
}
|
||||||
$this->settings = $settings;
|
$this->settings = $settings;
|
||||||
$this->mypid = getmypid();
|
$this->mypid = \getmypid();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function start()
|
public function start()
|
||||||
{
|
{
|
||||||
pcntl_signal(SIGTERM, [$this, 'sig_handler']);
|
\pcntl_signal(SIGTERM, [$this, 'sig_handler']);
|
||||||
pcntl_signal(SIGINT, [$this, 'sig_handler']);
|
\pcntl_signal(SIGINT, [$this, 'sig_handler']);
|
||||||
pcntl_signal(SIGCHLD, [$this, 'sig_handler']);
|
\pcntl_signal(SIGCHLD, [$this, 'sig_handler']);
|
||||||
|
|
||||||
$this->sock = new \Socket($this->settings['type'], SOCK_STREAM, $this->settings['protocol']);
|
$this->sock = new \Socket($this->settings['type'], SOCK_STREAM, $this->settings['protocol']);
|
||||||
$this->sock->bind($this->settings['address'], $this->settings['port']);
|
$this->sock->bind($this->settings['address'], $this->settings['port']);
|
||||||
@ -60,7 +60,7 @@ class Server
|
|||||||
$this->sock->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout);
|
$this->sock->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout);
|
||||||
\danog\MadelineProto\Logger::log('Server started! Listening on '.$this->settings['address'].':'.$this->settings['port']);
|
\danog\MadelineProto\Logger::log('Server started! Listening on '.$this->settings['address'].':'.$this->settings['port']);
|
||||||
while (true) {
|
while (true) {
|
||||||
pcntl_signal_dispatch();
|
\pcntl_signal_dispatch();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ($sock = $this->sock->accept()) {
|
if ($sock = $this->sock->accept()) {
|
||||||
@ -73,7 +73,7 @@ class Server
|
|||||||
|
|
||||||
private function handle($socket)
|
private function handle($socket)
|
||||||
{
|
{
|
||||||
$pid = pcntl_fork();
|
$pid = \pcntl_fork();
|
||||||
if ($pid == -1) {
|
if ($pid == -1) {
|
||||||
die('could not fork');
|
die('could not fork');
|
||||||
} elseif ($pid) {
|
} elseif ($pid) {
|
||||||
@ -86,12 +86,12 @@ class Server
|
|||||||
|
|
||||||
public function __destruct()
|
public function __destruct()
|
||||||
{
|
{
|
||||||
if ($this->mypid === getmypid()) {
|
if ($this->mypid === \getmypid()) {
|
||||||
\danog\MadelineProto\Logger::log('Shutting main process '.$this->mypid.' down');
|
\danog\MadelineProto\Logger::log('Shutting main process '.$this->mypid.' down');
|
||||||
unset($this->sock);
|
unset($this->sock);
|
||||||
foreach ($this->pids as $pid) {
|
foreach ($this->pids as $pid) {
|
||||||
\danog\MadelineProto\Logger::log("Waiting for $pid");
|
\danog\MadelineProto\Logger::log("Waiting for $pid");
|
||||||
pcntl_wait($pid);
|
\pcntl_wait($pid);
|
||||||
}
|
}
|
||||||
\danog\MadelineProto\Logger::log('Done, closing main process');
|
\danog\MadelineProto\Logger::log('Done, closing main process');
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ class Server
|
|||||||
exit();
|
exit();
|
||||||
|
|
||||||
case SIGCHLD:
|
case SIGCHLD:
|
||||||
pcntl_waitpid(-1, $status);
|
\pcntl_waitpid(-1, $status);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ class Handler extends \danog\MadelineProto\Connection
|
|||||||
|
|
||||||
public function __magic_construct($socket, $extra, $ip, $port, $protocol, $timeout, $ipv6)
|
public function __magic_construct($socket, $extra, $ip, $port, $protocol, $timeout, $ipv6)
|
||||||
{
|
{
|
||||||
\danog\MadelineProto\Magic::$pid = getmypid();
|
\danog\MadelineProto\Magic::$pid = \getmypid();
|
||||||
$this->sock = $socket;
|
$this->sock = $socket;
|
||||||
$this->sock->setBlocking(true);
|
$this->sock->setBlocking(true);
|
||||||
$this->must_open = false;
|
$this->must_open = false;
|
||||||
@ -47,7 +47,7 @@ class Handler extends \danog\MadelineProto\Connection
|
|||||||
|
|
||||||
public function __destruct()
|
public function __destruct()
|
||||||
{
|
{
|
||||||
echo 'Closing socket in fork '.getmypid().PHP_EOL;
|
echo 'Closing socket in fork '.\getmypid().PHP_EOL;
|
||||||
unset($this->sock);
|
unset($this->sock);
|
||||||
$this->destruct_madeline();
|
$this->destruct_madeline();
|
||||||
}
|
}
|
||||||
@ -71,31 +71,31 @@ class Handler extends \danog\MadelineProto\Connection
|
|||||||
|
|
||||||
$first_byte = $this->sock->read(1);
|
$first_byte = $this->sock->read(1);
|
||||||
|
|
||||||
if ($first_byte === chr(239)) {
|
if ($first_byte === \chr(239)) {
|
||||||
$this->protocol = 'tcp_abridged';
|
$this->protocol = 'tcp_abridged';
|
||||||
} else {
|
} else {
|
||||||
$first_byte .= $this->sock->read(3);
|
$first_byte .= $this->sock->read(3);
|
||||||
if ($first_byte === str_repeat(chr(238), 4)) {
|
if ($first_byte === \str_repeat(\chr(238), 4)) {
|
||||||
$this->protocol = 'tcp_intermediate';
|
$this->protocol = 'tcp_intermediate';
|
||||||
} else {
|
} else {
|
||||||
$this->protocol = 'tcp_full';
|
$this->protocol = 'tcp_full';
|
||||||
|
|
||||||
$packet_length = unpack('V', $first_byte)[1];
|
$packet_length = \unpack('V', $first_byte)[1];
|
||||||
$packet = $this->read($packet_length - 4);
|
$packet = $this->read($packet_length - 4);
|
||||||
if (strrev(hash('crc32b', $first_byte.substr($packet, 0, -4), true)) !== substr($packet, -4)) {
|
if (\strrev(\hash('crc32b', $first_byte.\substr($packet, 0, -4), true)) !== \substr($packet, -4)) {
|
||||||
throw new Exception('CRC32 was not correct!');
|
throw new Exception('CRC32 was not correct!');
|
||||||
}
|
}
|
||||||
$this->in_seq_no++;
|
$this->in_seq_no++;
|
||||||
$in_seq_no = unpack('V', substr($packet, 0, 4))[1];
|
$in_seq_no = \unpack('V', \substr($packet, 0, 4))[1];
|
||||||
if ($in_seq_no != $this->in_seq_no) {
|
if ($in_seq_no != $this->in_seq_no) {
|
||||||
throw new Exception('Incoming seq_no mismatch');
|
throw new Exception('Incoming seq_no mismatch');
|
||||||
}
|
}
|
||||||
|
|
||||||
$buffer = substr($packet, 4, $packet_length - 12);
|
$buffer = \substr($packet, 4, $packet_length - 12);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (true) {
|
while (true) {
|
||||||
pcntl_signal_dispatch();
|
\pcntl_signal_dispatch();
|
||||||
$request_id = 0;
|
$request_id = 0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -103,12 +103,12 @@ class Handler extends \danog\MadelineProto\Connection
|
|||||||
$message = $buffer;
|
$message = $buffer;
|
||||||
$buffer = '';
|
$buffer = '';
|
||||||
} else {
|
} else {
|
||||||
$time = time();
|
$time = \time();
|
||||||
$message = $this->read_message();
|
$message = $this->read_message();
|
||||||
}
|
}
|
||||||
} catch (\danog\MadelineProto\NothingInTheSocketException $e) {
|
} catch (\danog\MadelineProto\NothingInTheSocketException $e) {
|
||||||
echo $e;
|
echo $e;
|
||||||
if (time() - $time < 2) {
|
if (\time() - $time < 2) {
|
||||||
$this->sock = null;
|
$this->sock = null;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@ -139,17 +139,17 @@ class Handler extends \danog\MadelineProto\Connection
|
|||||||
|
|
||||||
public function on_request($request_id, $method, $args)
|
public function on_request($request_id, $method, $args)
|
||||||
{
|
{
|
||||||
if (count($method) === 0 || count($method) > 2) {
|
if (\count($method) === 0 || \count($method) > 2) {
|
||||||
throw new \danog\MadelineProto\Exception('Invalid method called');
|
throw new \danog\MadelineProto\Exception('Invalid method called');
|
||||||
}
|
}
|
||||||
|
|
||||||
array_walk($args, [$this, 'walker']);
|
\array_walk($args, [$this, 'walker']);
|
||||||
|
|
||||||
if ($method[0] === '__construct') {
|
if ($method[0] === '__construct') {
|
||||||
if (count($args) === 1 && is_array($args[0])) {
|
if (\count($args) === 1 && \is_array($args[0])) {
|
||||||
$args[0]['logger'] = ['logger' => 4, 'logger_param' => [$this, 'logger']];
|
$args[0]['logger'] = ['logger' => 4, 'logger_param' => [$this, 'logger']];
|
||||||
$args[0]['updates']['callback'] = [$this, 'update_handler'];
|
$args[0]['updates']['callback'] = [$this, 'update_handler'];
|
||||||
} elseif (count($args) === 2 && is_array($args[1])) {
|
} elseif (\count($args) === 2 && \is_array($args[1])) {
|
||||||
$args[1]['logger'] = ['logger' => 4, 'logger_param' => [$this, 'logger']];
|
$args[1]['logger'] = ['logger' => 4, 'logger_param' => [$this, 'logger']];
|
||||||
$args[1]['updates']['callback'] = [$this, 'update_handler'];
|
$args[1]['updates']['callback'] = [$this, 'update_handler'];
|
||||||
}
|
}
|
||||||
@ -165,42 +165,41 @@ class Handler extends \danog\MadelineProto\Connection
|
|||||||
throw new \danog\MadelineProto\Exception('__construct was not called');
|
throw new \danog\MadelineProto\Exception('__construct was not called');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($method) === 1) {
|
if (\count($method) === 1) {
|
||||||
return $this->madeline->{$method[0]}(...$args);
|
return $this->madeline->{$method[0]}(...$args);
|
||||||
}
|
}
|
||||||
if (count($method) === 2) {
|
if (\count($method) === 2) {
|
||||||
return $this->madeline->{$method[0]}->{$method[1]}(...$args);
|
return $this->madeline->{$method[0]}->{$method[1]}(...$args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function walker(&$arg)
|
private function walker(&$arg)
|
||||||
{
|
{
|
||||||
if (is_array($arg)) {
|
if (\is_array($arg)) {
|
||||||
if (isset($arg['_'])) {
|
if (isset($arg['_'])) {
|
||||||
if ($arg['_'] === 'fileCallback' && isset($arg['callback']) && isset($arg['file']) && !method_exists($this, $arg['callback']['callback'])) {
|
if ($arg['_'] === 'fileCallback' && isset($arg['callback']) && isset($arg['file']) && !\method_exists($this, $arg['callback']['callback'])) {
|
||||||
if (isset($arg['file']['_']) && $arg['file']['_'] === 'stream') {
|
if (isset($arg['file']['_']) && $arg['file']['_'] === 'stream') {
|
||||||
$arg['file'] = fopen('madelineSocket://', 'r+b', false, Stream::getContext($this, $arg['file']['stream_id']));
|
$arg['file'] = \fopen('madelineSocket://', 'r+b', false, Stream::getContext($this, $arg['file']['stream_id']));
|
||||||
}
|
}
|
||||||
$arg = new \danog\MadelineProto\FileCallback($arg['file'], [$this, $arg['callback']['callback']]);
|
$arg = new \danog\MadelineProto\FileCallback($arg['file'], [$this, $arg['callback']['callback']]);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} elseif ($arg['_'] === 'callback' && isset($arg['callback']) && !method_exists($this, $arg['callback'])) {
|
} elseif ($arg['_'] === 'callback' && isset($arg['callback']) && !\method_exists($this, $arg['callback'])) {
|
||||||
$arg = [$this, $arg['callback']];
|
$arg = [$this, $arg['callback']];
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} elseif ($arg['_'] === 'stream' && isset($arg['stream_id'])) {
|
} elseif ($arg['_'] === 'stream' && isset($arg['stream_id'])) {
|
||||||
$arg = fopen('madelineSocket://', 'r+b', false, Stream::getContext($this, $arg['stream_id']));
|
$arg = \fopen('madelineSocket://', 'r+b', false, Stream::getContext($this, $arg['stream_id']));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} elseif ($arg['_'] === 'bytes' && isset($arg['bytes'])) {
|
} elseif ($arg['_'] === 'bytes' && isset($arg['bytes'])) {
|
||||||
$arg = base64_decode($args['bytes']);
|
$arg = \base64_decode($args['bytes']);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} else {
|
|
||||||
array_walk($arg, [$this, 'walker']);
|
|
||||||
}
|
}
|
||||||
|
\array_walk($arg, [$this, 'walker']);
|
||||||
} else {
|
} else {
|
||||||
array_walk($arg, [$this, 'walker']);
|
\array_walk($arg, [$this, 'walker']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -226,15 +225,15 @@ class Handler extends \danog\MadelineProto\Connection
|
|||||||
$exception['code'] = $e->getCode();
|
$exception['code'] = $e->getCode();
|
||||||
$exception['trace'] = ['_' => 'socketTLTrace', 'frames' => []];
|
$exception['trace'] = ['_' => 'socketTLTrace', 'frames' => []];
|
||||||
$tl = false;
|
$tl = false;
|
||||||
foreach (array_reverse($e->getTrace()) as $k => $frame) {
|
foreach (\array_reverse($e->getTrace()) as $k => $frame) {
|
||||||
$tl_frame = ['_' => 'socketTLFrame'];
|
$tl_frame = ['_' => 'socketTLFrame'];
|
||||||
if (isset($frame['function']) && in_array($frame['function'], ['serialize_params', 'serialize_object'])) {
|
if (isset($frame['function']) && \in_array($frame['function'], ['serialize_params', 'serialize_object'])) {
|
||||||
if ($frame['args'][2] !== '') {
|
if ($frame['args'][2] !== '') {
|
||||||
$tl_frame['tl_param'] = (string) $frame['args'][2];
|
$tl_frame['tl_param'] = (string) $frame['args'][2];
|
||||||
$tl = true;
|
$tl = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isset($frame['function']) && ($frame['function'] === 'handle_rpc_error' && $k === count($this->getTrace()) - 1) || $frame['function'] === 'unserialize') {
|
if (isset($frame['function']) && ($frame['function'] === 'handle_rpc_error' && $k === \count($this->getTrace()) - 1) || $frame['function'] === 'unserialize') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (isset($frame['file'])) {
|
if (isset($frame['file'])) {
|
||||||
@ -245,7 +244,7 @@ class Handler extends \danog\MadelineProto\Connection
|
|||||||
$tl_frame['function'] = $frame['function'];
|
$tl_frame['function'] = $frame['function'];
|
||||||
}
|
}
|
||||||
if (isset($frame['args'])) {
|
if (isset($frame['args'])) {
|
||||||
$args = json_encode($frame['args']);
|
$args = \json_encode($frame['args']);
|
||||||
if ($args !== false) {
|
if ($args !== false) {
|
||||||
$tl_frame['args'] = $args;
|
$tl_frame['args'] = $args;
|
||||||
}
|
}
|
||||||
@ -275,7 +274,7 @@ class Handler extends \danog\MadelineProto\Connection
|
|||||||
try {
|
try {
|
||||||
$this->logging = true;
|
$this->logging = true;
|
||||||
|
|
||||||
$message = ['_' => 'socketMessageLog', 'data' => $message, 'level' => $level, 'thread' => \danog\MadelineProto\Magic::$has_thread && is_object(\Thread::getCurrentThread()), 'process' => \danog\MadelineProto\Magic::is_fork(), 'file' => basename(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]['file'], '.php')];
|
$message = ['_' => 'socketMessageLog', 'data' => $message, 'level' => $level, 'thread' => \danog\MadelineProto\Magic::$has_thread && \is_object(\Thread::getCurrentThread()), 'process' => \danog\MadelineProto\Magic::is_fork(), 'file' => \basename(\debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]['file'], '.php')];
|
||||||
|
|
||||||
$this->send_message_safe(yield $this->serialize_object_async(['type' => ''], $message, 'log'));
|
$this->send_message_safe(yield $this->serialize_object_async(['type' => ''], $message, 'log'));
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -26,8 +26,8 @@ class Proxy extends \danog\MadelineProto\Connection
|
|||||||
{
|
{
|
||||||
public function __magic_construct($socket, $extra, $ip, $port, $protocol, $timeout, $ipv6)
|
public function __magic_construct($socket, $extra, $ip, $port, $protocol, $timeout, $ipv6)
|
||||||
{
|
{
|
||||||
\danog\MadelineProto\Logger::log('Got connection '.getmypid().'!');
|
\danog\MadelineProto\Logger::log('Got connection '.\getmypid().'!');
|
||||||
\danog\MadelineProto\Magic::$pid = getmypid();
|
\danog\MadelineProto\Magic::$pid = \getmypid();
|
||||||
\danog\MadelineProto\Lang::$current_lang = [];
|
\danog\MadelineProto\Lang::$current_lang = [];
|
||||||
$this->sock = $socket;
|
$this->sock = $socket;
|
||||||
$this->sock->setBlocking(true);
|
$this->sock->setBlocking(true);
|
||||||
@ -43,7 +43,7 @@ class Proxy extends \danog\MadelineProto\Connection
|
|||||||
|
|
||||||
public function __destruct()
|
public function __destruct()
|
||||||
{
|
{
|
||||||
\danog\MadelineProto\Logger::log('Closing fork '.getmypid().'!');
|
\danog\MadelineProto\Logger::log('Closing fork '.\getmypid().'!');
|
||||||
unset($this->sock);
|
unset($this->sock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,27 +52,27 @@ class Proxy extends \danog\MadelineProto\Connection
|
|||||||
$this->protocol = 'obfuscated2';
|
$this->protocol = 'obfuscated2';
|
||||||
$random = $this->sock->read(64);
|
$random = $this->sock->read(64);
|
||||||
|
|
||||||
$reversed = strrev(substr($random, 8, 48));
|
$reversed = \strrev(\substr($random, 8, 48));
|
||||||
$key = substr($random, 8, 32);
|
$key = \substr($random, 8, 32);
|
||||||
$keyRev = substr($reversed, 0, 32);
|
$keyRev = \substr($reversed, 0, 32);
|
||||||
if (isset($this->extra['secret'])) {
|
if (isset($this->extra['secret'])) {
|
||||||
$key = hash('sha256', $key.$this->extra['secret'], true);
|
$key = \hash('sha256', $key.$this->extra['secret'], true);
|
||||||
$keyRev = hash('sha256', $keyRev.$this->extra['secret'], true);
|
$keyRev = \hash('sha256', $keyRev.$this->extra['secret'], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->obfuscated = ['encryption' => new \phpseclib\Crypt\AES('ctr'), 'decryption' => new \phpseclib\Crypt\AES('ctr')];
|
$this->obfuscated = ['encryption' => new \phpseclib\Crypt\AES('ctr'), 'decryption' => new \phpseclib\Crypt\AES('ctr')];
|
||||||
$this->obfuscated['encryption']->enableContinuousBuffer();
|
$this->obfuscated['encryption']->enableContinuousBuffer();
|
||||||
$this->obfuscated['decryption']->enableContinuousBuffer();
|
$this->obfuscated['decryption']->enableContinuousBuffer();
|
||||||
$this->obfuscated['decryption']->setKey($key);
|
$this->obfuscated['decryption']->setKey($key);
|
||||||
$this->obfuscated['decryption']->setIV(substr($random, 40, 16));
|
$this->obfuscated['decryption']->setIV(\substr($random, 40, 16));
|
||||||
$this->obfuscated['encryption']->setKey($keyRev);
|
$this->obfuscated['encryption']->setKey($keyRev);
|
||||||
$this->obfuscated['encryption']->setIV(substr($reversed, 32, 16));
|
$this->obfuscated['encryption']->setIV(\substr($reversed, 32, 16));
|
||||||
$random = substr_replace($random, substr(@$this->obfuscated['decryption']->encrypt($random), 56, 8), 56, 8);
|
$random = \substr_replace($random, \substr(@$this->obfuscated['decryption']->encrypt($random), 56, 8), 56, 8);
|
||||||
|
|
||||||
if (substr($random, 56, 4) !== str_repeat(chr(0xef), 4)) {
|
if (\substr($random, 56, 4) !== \str_repeat(\chr(0xef), 4)) {
|
||||||
throw new \danog\MadelineProto\Exception('Wrong protocol version');
|
throw new \danog\MadelineProto\Exception('Wrong protocol version');
|
||||||
}
|
}
|
||||||
$dc = abs(unpack('s', substr($random, 60, 2))[1]);
|
$dc = \abs(\unpack('s', \substr($random, 60, 2))[1]);
|
||||||
|
|
||||||
$socket = $this->extra['madeline'][$dc];
|
$socket = $this->extra['madeline'][$dc];
|
||||||
$socket->__construct($socket->proxy, $socket->extra, $socket->ip, $socket->port, $socket->protocol, $timeout = $this->extra['timeout'], $socket->ipv6);
|
$socket->__construct($socket->proxy, $socket->extra, $socket->ip, $socket->port, $socket->protocol, $timeout = $this->extra['timeout'], $socket->ipv6);
|
||||||
@ -82,7 +82,7 @@ class Proxy extends \danog\MadelineProto\Connection
|
|||||||
$write = [];
|
$write = [];
|
||||||
$except = [];
|
$except = [];
|
||||||
while (true) {
|
while (true) {
|
||||||
pcntl_signal_dispatch();
|
\pcntl_signal_dispatch();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$read = [$this->getSocket(), $socket->getSocket()];
|
$read = [$this->getSocket(), $socket->getSocket()];
|
||||||
|
@ -32,18 +32,18 @@ class Stream
|
|||||||
public static function getContext($handler, $stream_id)
|
public static function getContext($handler, $stream_id)
|
||||||
{
|
{
|
||||||
if (!self::$_isRegistered) {
|
if (!self::$_isRegistered) {
|
||||||
stream_wrapper_register(self::WRAPPER_NAME, get_class());
|
\stream_wrapper_register(self::WRAPPER_NAME, __CLASS__);
|
||||||
self::$_isRegistered = true;
|
self::$_isRegistered = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return stream_context_create([self::WRAPPER_NAME => ['handler' => $handler, 'stream_id' => $stream_id]]);
|
return \stream_context_create([self::WRAPPER_NAME => ['handler' => $handler, 'stream_id' => $stream_id]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function stream_open($path, $mode, $options, &$opened_path)
|
public function stream_open($path, $mode, $options, &$opened_path)
|
||||||
{
|
{
|
||||||
$opt = stream_context_get_options($this->context);
|
$opt = \stream_context_get_options($this->context);
|
||||||
|
|
||||||
if (!is_array($opt[self::WRAPPER_NAME]) ||
|
if (!\is_array($opt[self::WRAPPER_NAME]) ||
|
||||||
!isset($opt[self::WRAPPER_NAME]['handler']) ||
|
!isset($opt[self::WRAPPER_NAME]['handler']) ||
|
||||||
!($opt[self::WRAPPER_NAME]['handler'] instanceof Handler) ||
|
!($opt[self::WRAPPER_NAME]['handler'] instanceof Handler) ||
|
||||||
!isset($opt[self::WRAPPER_NAME]['stream_id'])) {
|
!isset($opt[self::WRAPPER_NAME]['stream_id'])) {
|
||||||
|
@ -24,26 +24,26 @@ namespace danog\MadelineProto;
|
|||||||
class Shutdown
|
class Shutdown
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Callbacks to call on shutdown
|
* Callbacks to call on shutdown.
|
||||||
*
|
*
|
||||||
* @var array<callable>
|
* @var array<callable>
|
||||||
*/
|
*/
|
||||||
private static $callbacks = [];
|
private static $callbacks = [];
|
||||||
/**
|
/**
|
||||||
* Whether the main shutdown was registered
|
* Whether the main shutdown was registered.
|
||||||
*
|
*
|
||||||
* @var boolean
|
* @var boolean
|
||||||
*/
|
*/
|
||||||
private static $registered = false;
|
private static $registered = false;
|
||||||
/**
|
/**
|
||||||
* Incremental ID for new callback
|
* Incremental ID for new callback.
|
||||||
*
|
*
|
||||||
* @var integer
|
* @var integer
|
||||||
*/
|
*/
|
||||||
private static $id = 0;
|
private static $id = 0;
|
||||||
/**
|
/**
|
||||||
* Function to be called on shutdown
|
* Function to be called on shutdown.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public static function shutdown()
|
public static function shutdown()
|
||||||
@ -53,11 +53,11 @@ class Shutdown
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Add a callback for script shutdown
|
* Add a callback for script shutdown.
|
||||||
*
|
*
|
||||||
* @param callable $callback The callback to set
|
* @param callable $callback The callback to set
|
||||||
* @param null|string $id The optional callback ID
|
* @param null|string $id The optional callback ID
|
||||||
*
|
*
|
||||||
* @return The callback ID
|
* @return The callback ID
|
||||||
*/
|
*/
|
||||||
public static function addCallback($callback, $id = null)
|
public static function addCallback($callback, $id = null)
|
||||||
@ -67,16 +67,16 @@ class Shutdown
|
|||||||
}
|
}
|
||||||
self::$callbacks[$id] = $callback;
|
self::$callbacks[$id] = $callback;
|
||||||
if (!self::$registered) {
|
if (!self::$registered) {
|
||||||
register_shutdown_function([__CLASS__, 'shutdown']);
|
\register_shutdown_function([__CLASS__, 'shutdown']);
|
||||||
self::$registered = true;
|
self::$registered = true;
|
||||||
}
|
}
|
||||||
return $id;
|
return $id;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Remove a callback from the script shutdown callable list
|
* Remove a callback from the script shutdown callable list.
|
||||||
*
|
*
|
||||||
* @param null|string $id The optional callback ID
|
* @param null|string $id The optional callback ID
|
||||||
*
|
*
|
||||||
* @return bool true if the callback was removed correctly, false otherwise
|
* @return bool true if the callback was removed correctly, false otherwise
|
||||||
*/
|
*/
|
||||||
public static function removeCallback($id)
|
public static function removeCallback($id)
|
||||||
@ -87,4 +87,4 @@ class Shutdown
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,16 +18,16 @@
|
|||||||
|
|
||||||
namespace danog\MadelineProto\Stream\Common;
|
namespace danog\MadelineProto\Stream\Common;
|
||||||
|
|
||||||
|
use Amp\ByteStream\ClosedException;
|
||||||
use Amp\Promise;
|
use Amp\Promise;
|
||||||
use Amp\Success;
|
use Amp\Success;
|
||||||
use danog\MadelineProto\Exception;
|
use danog\MadelineProto\Exception;
|
||||||
use danog\MadelineProto\Stream\Async\RawStream;
|
use danog\MadelineProto\Stream\Async\RawStream;
|
||||||
use danog\MadelineProto\Stream\ConnectionContext;
|
|
||||||
use function Amp\Socket\connect;
|
|
||||||
use danog\MadelineProto\Stream\BufferedStreamInterface;
|
use danog\MadelineProto\Stream\BufferedStreamInterface;
|
||||||
use danog\MadelineProto\Stream\BufferInterface;
|
use danog\MadelineProto\Stream\BufferInterface;
|
||||||
|
use danog\MadelineProto\Stream\ConnectionContext;
|
||||||
use danog\MadelineProto\Stream\RawStreamInterface;
|
use danog\MadelineProto\Stream\RawStreamInterface;
|
||||||
use Amp\ByteStream\ClosedException;
|
use function Amp\Socket\connect;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Buffered raw stream.
|
* Buffered raw stream.
|
||||||
@ -55,7 +55,7 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw
|
|||||||
public function connectAsync(ConnectionContext $ctx, string $header = ''): \Generator
|
public function connectAsync(ConnectionContext $ctx, string $header = ''): \Generator
|
||||||
{
|
{
|
||||||
$this->stream = yield $ctx->getStream($header);
|
$this->stream = yield $ctx->getStream($header);
|
||||||
$this->memory_stream = fopen('php://memory', 'r+');
|
$this->memory_stream = \fopen('php://memory', 'r+');
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -96,7 +96,7 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw
|
|||||||
public function disconnect()
|
public function disconnect()
|
||||||
{
|
{
|
||||||
if ($this->memory_stream) {
|
if ($this->memory_stream) {
|
||||||
fclose($this->memory_stream);
|
\fclose($this->memory_stream);
|
||||||
$this->memory_stream = null;
|
$this->memory_stream = null;
|
||||||
}
|
}
|
||||||
if ($this->stream) {
|
if ($this->stream) {
|
||||||
@ -117,16 +117,16 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw
|
|||||||
if (!$this->stream) {
|
if (!$this->stream) {
|
||||||
throw new ClosedException("MadelineProto stream was disconnected");
|
throw new ClosedException("MadelineProto stream was disconnected");
|
||||||
}
|
}
|
||||||
$size = fstat($this->memory_stream)['size'];
|
$size = \fstat($this->memory_stream)['size'];
|
||||||
$offset = ftell($this->memory_stream);
|
$offset = \ftell($this->memory_stream);
|
||||||
$length = $size - $offset;
|
$length = $size - $offset;
|
||||||
if ($length === 0 || $size > self::MAX_SIZE) {
|
if ($length === 0 || $size > self::MAX_SIZE) {
|
||||||
$new_memory_stream = fopen('php://memory', 'r+');
|
$new_memory_stream = \fopen('php://memory', 'r+');
|
||||||
if ($length) {
|
if ($length) {
|
||||||
fwrite($new_memory_stream, fread($this->memory_stream, $length));
|
\fwrite($new_memory_stream, \fread($this->memory_stream, $length));
|
||||||
fseek($new_memory_stream, 0);
|
\fseek($new_memory_stream, 0);
|
||||||
}
|
}
|
||||||
fclose($this->memory_stream);
|
\fclose($this->memory_stream);
|
||||||
$this->memory_stream = $new_memory_stream;
|
$this->memory_stream = $new_memory_stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,9 +142,9 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw
|
|||||||
*/
|
*/
|
||||||
public function getWriteBuffer(int $length, string $append = ''): Promise
|
public function getWriteBuffer(int $length, string $append = ''): Promise
|
||||||
{
|
{
|
||||||
if (strlen($append)) {
|
if (\strlen($append)) {
|
||||||
$this->append = $append;
|
$this->append = $append;
|
||||||
$this->append_after = $length - strlen($append);
|
$this->append_after = $length - \strlen($append);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new \Amp\Success($this);
|
return new \Amp\Success($this);
|
||||||
@ -162,11 +162,11 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw
|
|||||||
if (!$this->stream) {
|
if (!$this->stream) {
|
||||||
throw new ClosedException("MadelineProto stream was disconnected");
|
throw new ClosedException("MadelineProto stream was disconnected");
|
||||||
}
|
}
|
||||||
$size = fstat($this->memory_stream)['size'];
|
$size = \fstat($this->memory_stream)['size'];
|
||||||
$offset = ftell($this->memory_stream);
|
$offset = \ftell($this->memory_stream);
|
||||||
$buffer_length = $size - $offset;
|
$buffer_length = $size - $offset;
|
||||||
if ($buffer_length >= $length) {
|
if ($buffer_length >= $length) {
|
||||||
return new Success(fread($this->memory_stream, $length));
|
return new Success(\fread($this->memory_stream, $length));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->call($this->bufferReadAsync($length));
|
return $this->call($this->bufferReadAsync($length));
|
||||||
@ -181,11 +181,11 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw
|
|||||||
*/
|
*/
|
||||||
public function bufferReadAsync(int $length): \Generator
|
public function bufferReadAsync(int $length): \Generator
|
||||||
{
|
{
|
||||||
$size = fstat($this->memory_stream)['size'];
|
$size = \fstat($this->memory_stream)['size'];
|
||||||
$offset = ftell($this->memory_stream);
|
$offset = \ftell($this->memory_stream);
|
||||||
$buffer_length = $size - $offset;
|
$buffer_length = $size - $offset;
|
||||||
if ($buffer_length < $length && $buffer_length) {
|
if ($buffer_length < $length && $buffer_length) {
|
||||||
fseek($this->memory_stream, $offset + $buffer_length);
|
\fseek($this->memory_stream, $offset + $buffer_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
while ($buffer_length < $length) {
|
while ($buffer_length < $length) {
|
||||||
@ -195,12 +195,12 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw
|
|||||||
|
|
||||||
throw new \danog\MadelineProto\NothingInTheSocketException();
|
throw new \danog\MadelineProto\NothingInTheSocketException();
|
||||||
}
|
}
|
||||||
fwrite($this->memory_stream, $chunk);
|
\fwrite($this->memory_stream, $chunk);
|
||||||
$buffer_length += strlen($chunk);
|
$buffer_length += \strlen($chunk);
|
||||||
}
|
}
|
||||||
fseek($this->memory_stream, $offset);
|
\fseek($this->memory_stream, $offset);
|
||||||
|
|
||||||
return fread($this->memory_stream, $length);
|
return \fread($this->memory_stream, $length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -213,7 +213,7 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw
|
|||||||
public function bufferWrite(string $data): Promise
|
public function bufferWrite(string $data): Promise
|
||||||
{
|
{
|
||||||
if ($this->append_after) {
|
if ($this->append_after) {
|
||||||
$this->append_after -= strlen($data);
|
$this->append_after -= \strlen($data);
|
||||||
if ($this->append_after === 0) {
|
if ($this->append_after === 0) {
|
||||||
$data .= $this->append;
|
$data .= $this->append;
|
||||||
$this->append = '';
|
$this->append = '';
|
||||||
|
@ -52,7 +52,7 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
*/
|
*/
|
||||||
public function startReadHash()
|
public function startReadHash()
|
||||||
{
|
{
|
||||||
$this->read_hash = hash_init($this->hash_name);
|
$this->read_hash = \hash_init($this->hash_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -74,9 +74,9 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
*/
|
*/
|
||||||
public function getReadHash(): string
|
public function getReadHash(): string
|
||||||
{
|
{
|
||||||
$hash = hash_final($this->read_hash, true);
|
$hash = \hash_final($this->read_hash, true);
|
||||||
if ($this->rev) {
|
if ($this->rev) {
|
||||||
$hash = strrev($hash);
|
$hash = \strrev($hash);
|
||||||
}
|
}
|
||||||
$this->read_hash = null;
|
$this->read_hash = null;
|
||||||
$this->read_check_after = 0;
|
$this->read_check_after = 0;
|
||||||
@ -102,7 +102,7 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
*/
|
*/
|
||||||
public function startWriteHash()
|
public function startWriteHash()
|
||||||
{
|
{
|
||||||
$this->write_hash = hash_init($this->hash_name);
|
$this->write_hash = \hash_init($this->hash_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -124,9 +124,9 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
*/
|
*/
|
||||||
public function getWriteHash(): string
|
public function getWriteHash(): string
|
||||||
{
|
{
|
||||||
$hash = hash_final($this->write_hash, true);
|
$hash = \hash_final($this->write_hash, true);
|
||||||
if ($this->rev) {
|
if ($this->rev) {
|
||||||
$hash = strrev($hash);
|
$hash = \strrev($hash);
|
||||||
}
|
}
|
||||||
$this->write_hash = null;
|
$this->write_hash = null;
|
||||||
$this->write_check_after = 0;
|
$this->write_check_after = 0;
|
||||||
@ -161,16 +161,16 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
throw new \danog\MadelineProto\Exception('Tried to read too much out of frame data');
|
throw new \danog\MadelineProto\Exception('Tried to read too much out of frame data');
|
||||||
}
|
}
|
||||||
$data = yield $this->read_buffer->bufferRead($length);
|
$data = yield $this->read_buffer->bufferRead($length);
|
||||||
hash_update($this->read_hash, $data);
|
\hash_update($this->read_hash, $data);
|
||||||
$hash = $this->getReadHash();
|
$hash = $this->getReadHash();
|
||||||
if ($hash !== yield $this->read_buffer->bufferRead(strlen($hash))) {
|
if ($hash !== yield $this->read_buffer->bufferRead(\strlen($hash))) {
|
||||||
throw new \danog\MadelineProto\Exception('Hash mismatch');
|
throw new \danog\MadelineProto\Exception('Hash mismatch');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
$data = yield $this->read_buffer->bufferRead($length);
|
$data = yield $this->read_buffer->bufferRead($length);
|
||||||
hash_update($this->read_hash, $data);
|
\hash_update($this->read_hash, $data);
|
||||||
if ($this->read_check_after) {
|
if ($this->read_check_after) {
|
||||||
$this->read_check_pos += $length;
|
$this->read_check_pos += $length;
|
||||||
}
|
}
|
||||||
@ -187,10 +187,10 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
*/
|
*/
|
||||||
public function setExtra($hash)
|
public function setExtra($hash)
|
||||||
{
|
{
|
||||||
$rev = strpos($hash, '_rev');
|
$rev = \strpos($hash, '_rev');
|
||||||
$this->rev = false;
|
$this->rev = false;
|
||||||
if ($rev !== false) {
|
if ($rev !== false) {
|
||||||
$hash = substr($hash, 0, $rev);
|
$hash = \substr($hash, 0, $rev);
|
||||||
$this->rev = true;
|
$this->rev = true;
|
||||||
}
|
}
|
||||||
$this->hash_name = $hash;
|
$this->hash_name = $hash;
|
||||||
@ -292,12 +292,12 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
return $this->write_buffer->bufferWrite($length);
|
return $this->write_buffer->bufferWrite($length);
|
||||||
}
|
}
|
||||||
|
|
||||||
$length = strlen($data);
|
$length = \strlen($data);
|
||||||
if ($this->write_check_after && $length + $this->write_check_pos >= $this->write_check_after) {
|
if ($this->write_check_after && $length + $this->write_check_pos >= $this->write_check_after) {
|
||||||
if ($length + $this->write_check_pos > $this->write_check_after) {
|
if ($length + $this->write_check_pos > $this->write_check_after) {
|
||||||
throw new \danog\MadelineProto\Exception('Too much out of frame data was sent, cannot check hash');
|
throw new \danog\MadelineProto\Exception('Too much out of frame data was sent, cannot check hash');
|
||||||
}
|
}
|
||||||
hash_update($this->write_hash, $data);
|
\hash_update($this->write_hash, $data);
|
||||||
|
|
||||||
return $this->write_buffer->bufferWrite($data.$this->getWriteHash());
|
return $this->write_buffer->bufferWrite($data.$this->getWriteHash());
|
||||||
}
|
}
|
||||||
@ -305,7 +305,7 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
|
|||||||
$this->write_check_pos += $length;
|
$this->write_check_pos += $length;
|
||||||
}
|
}
|
||||||
if ($this->write_hash) {
|
if ($this->write_hash) {
|
||||||
hash_update($this->write_hash, $data);
|
\hash_update($this->write_hash, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->write_buffer->bufferWrite($data);
|
return $this->write_buffer->bufferWrite($data);
|
||||||
|
@ -18,12 +18,6 @@
|
|||||||
|
|
||||||
namespace danog\MadelineProto\Stream\Common;
|
namespace danog\MadelineProto\Stream\Common;
|
||||||
|
|
||||||
use Amp\Promise;
|
|
||||||
use Amp\Success;
|
|
||||||
use danog\MadelineProto\Exception;
|
|
||||||
use danog\MadelineProto\Stream\Async\RawStream;
|
|
||||||
use danog\MadelineProto\Stream\ConnectionContext;
|
|
||||||
use function Amp\Socket\connect;
|
|
||||||
use danog\MadelineProto\Stream\BufferedStreamInterface;
|
use danog\MadelineProto\Stream\BufferedStreamInterface;
|
||||||
use danog\MadelineProto\Stream\BufferInterface;
|
use danog\MadelineProto\Stream\BufferInterface;
|
||||||
use danog\MadelineProto\Stream\RawStreamInterface;
|
use danog\MadelineProto\Stream\RawStreamInterface;
|
||||||
@ -44,25 +38,25 @@ class SimpleBufferedRawStream extends BufferedRawStream implements BufferedStrea
|
|||||||
*/
|
*/
|
||||||
public function bufferReadAsync(int $length): \Generator
|
public function bufferReadAsync(int $length): \Generator
|
||||||
{
|
{
|
||||||
$size = fstat($this->memory_stream)['size'];
|
$size = \fstat($this->memory_stream)['size'];
|
||||||
$offset = ftell($this->memory_stream);
|
$offset = \ftell($this->memory_stream);
|
||||||
$buffer_length = $size - $offset;
|
$buffer_length = $size - $offset;
|
||||||
if ($buffer_length < $length && $buffer_length) {
|
if ($buffer_length < $length && $buffer_length) {
|
||||||
fseek($this->memory_stream, $offset + $buffer_length);
|
\fseek($this->memory_stream, $offset + $buffer_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
while ($buffer_length < $length) {
|
while ($buffer_length < $length) {
|
||||||
$chunk = yield $this->read();
|
$chunk = yield $this->read();
|
||||||
if ($chunk === null) {
|
if ($chunk === null) {
|
||||||
fseek($this->memory_stream, $offset);
|
\fseek($this->memory_stream, $offset);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
fwrite($this->memory_stream, $chunk);
|
\fwrite($this->memory_stream, $chunk);
|
||||||
$buffer_length += strlen($chunk);
|
$buffer_length += \strlen($chunk);
|
||||||
}
|
}
|
||||||
fseek($this->memory_stream, $offset);
|
\fseek($this->memory_stream, $offset);
|
||||||
|
|
||||||
return fread($this->memory_stream, $length);
|
return \fread($this->memory_stream, $length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,9 +21,9 @@ namespace danog\MadelineProto\Stream;
|
|||||||
use Amp\CancellationToken;
|
use Amp\CancellationToken;
|
||||||
use Amp\Socket\ClientConnectContext;
|
use Amp\Socket\ClientConnectContext;
|
||||||
use Amp\Uri\Uri;
|
use Amp\Uri\Uri;
|
||||||
use danog\MadelineProto\Stream\Transport\DefaultStream;
|
|
||||||
use danog\MadelineProto\Stream\MTProtoTransport\ObfuscatedStream;
|
|
||||||
use danog\MadelineProto\Exception;
|
use danog\MadelineProto\Exception;
|
||||||
|
use danog\MadelineProto\Stream\MTProtoTransport\ObfuscatedStream;
|
||||||
|
use danog\MadelineProto\Stream\Transport\DefaultStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connection context class.
|
* Connection context class.
|
||||||
@ -66,7 +66,7 @@ class ConnectionContext
|
|||||||
*/
|
*/
|
||||||
private $uri;
|
private $uri;
|
||||||
/**
|
/**
|
||||||
* Whether this connection context will be used by the DNS client
|
* Whether this connection context will be used by the DNS client.
|
||||||
*
|
*
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
@ -109,7 +109,7 @@ class ConnectionContext
|
|||||||
private $key = 0;
|
private $key = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read callback
|
* Read callback.
|
||||||
*
|
*
|
||||||
* @var callable
|
* @var callable
|
||||||
*/
|
*/
|
||||||
@ -149,7 +149,7 @@ class ConnectionContext
|
|||||||
public function setUri($uri): self
|
public function setUri($uri): self
|
||||||
{
|
{
|
||||||
$this->uri = $uri instanceof Uri ? $uri : new Uri($uri);
|
$this->uri = $uri instanceof Uri ? $uri : new Uri($uri);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,7 +197,7 @@ class ConnectionContext
|
|||||||
return $this->cancellationToken;
|
return $this->cancellationToken;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Return a clone of the current connection context
|
* Return a clone of the current connection context.
|
||||||
*
|
*
|
||||||
* @return self
|
* @return self
|
||||||
*/
|
*/
|
||||||
@ -220,7 +220,7 @@ class ConnectionContext
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this is a test connection
|
* Whether this is a test connection.
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
@ -229,7 +229,7 @@ class ConnectionContext
|
|||||||
return $this->test;
|
return $this->test;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Whether this is a media connection
|
* Whether this is a media connection.
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
@ -239,7 +239,7 @@ class ConnectionContext
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this is a CDN connection
|
* Whether this is a CDN connection.
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
@ -249,7 +249,7 @@ class ConnectionContext
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this connection context will only be used by the DNS client
|
* Whether this connection context will only be used by the DNS client.
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
@ -257,9 +257,9 @@ class ConnectionContext
|
|||||||
{
|
{
|
||||||
return $this->isDns;
|
return $this->isDns;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this connection context will only be used by the DNS client
|
* Whether this connection context will only be used by the DNS client.
|
||||||
*
|
*
|
||||||
* @param boolean $isDns
|
* @param boolean $isDns
|
||||||
* @return self
|
* @return self
|
||||||
@ -302,13 +302,13 @@ class ConnectionContext
|
|||||||
*/
|
*/
|
||||||
public function setDc($dc): self
|
public function setDc($dc): self
|
||||||
{
|
{
|
||||||
$int = intval($dc);
|
$int = \intval($dc);
|
||||||
if (!(1 <= $int && $int <= 1000)) {
|
if (!(1 <= $int && $int <= 1000)) {
|
||||||
throw new Exception("Invalid DC id provided: $dc");
|
throw new Exception("Invalid DC id provided: $dc");
|
||||||
}
|
}
|
||||||
$this->dc = $dc;
|
$this->dc = $dc;
|
||||||
$this->media = strpos($dc, '_media') !== false;
|
$this->media = \strpos($dc, '_media') !== false;
|
||||||
$this->cdn = strpos($dc, '_cdn') !== false;
|
$this->cdn = \strpos($dc, '_cdn') !== false;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@ -330,7 +330,7 @@ class ConnectionContext
|
|||||||
*/
|
*/
|
||||||
public function getIntDc()
|
public function getIntDc()
|
||||||
{
|
{
|
||||||
$dc = intval($this->dc);
|
$dc = \intval($this->dc);
|
||||||
if ($this->test) {
|
if ($this->test) {
|
||||||
$dc += 10000;
|
$dc += 10000;
|
||||||
}
|
}
|
||||||
@ -376,16 +376,16 @@ class ConnectionContext
|
|||||||
public function addStream(string $streamName, $extra = null): self
|
public function addStream(string $streamName, $extra = null): self
|
||||||
{
|
{
|
||||||
$this->nextStreams[] = [$streamName, $extra];
|
$this->nextStreams[] = [$streamName, $extra];
|
||||||
$this->key = count($this->nextStreams) - 1;
|
$this->key = \count($this->nextStreams) - 1;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set read callback, called every time the socket reads at least a byte
|
* Set read callback, called every time the socket reads at least a byte.
|
||||||
*
|
*
|
||||||
* @param callback $callable Read callback
|
* @param callback $callable Read callback
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function setReadCallback($callable)
|
public function setReadCallback($callable)
|
||||||
@ -394,7 +394,7 @@ class ConnectionContext
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a read callback is present
|
* Check if a read callback is present.
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
@ -404,7 +404,7 @@ class ConnectionContext
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get read callback
|
* Get read callback.
|
||||||
*
|
*
|
||||||
* @return callable
|
* @return callable
|
||||||
*/
|
*/
|
||||||
@ -444,7 +444,7 @@ class ConnectionContext
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the inputClientProxy proxy MTProto object
|
* Get the inputClientProxy proxy MTProto object.
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
@ -476,13 +476,13 @@ class ConnectionContext
|
|||||||
$string .= ', via ';
|
$string .= ', via ';
|
||||||
$string .= $this->getIpv6() ? 'ipv6' : 'ipv4';
|
$string .= $this->getIpv6() ? 'ipv6' : 'ipv4';
|
||||||
$string .= ' using ';
|
$string .= ' using ';
|
||||||
foreach (array_reverse($this->nextStreams) as $k => $stream) {
|
foreach (\array_reverse($this->nextStreams) as $k => $stream) {
|
||||||
if ($k) {
|
if ($k) {
|
||||||
$string .= ' => ';
|
$string .= ' => ';
|
||||||
}
|
}
|
||||||
$string .= preg_replace('/.*\\\\/', '', $stream[0]);
|
$string .= \preg_replace('/.*\\\\/', '', $stream[0]);
|
||||||
if ($stream[1] && $stream[0] !== DefaultStream::getName()) {
|
if ($stream[1] && $stream[0] !== DefaultStream::getName()) {
|
||||||
$string .= ' ('.json_encode($stream[1]).')';
|
$string .= ' ('.\json_encode($stream[1]).')';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ class AbridgedStream implements BufferedStreamInterface, MTProtoBufferInterface
|
|||||||
*/
|
*/
|
||||||
public function connectAsync(ConnectionContext $ctx, string $header = ''): \Generator
|
public function connectAsync(ConnectionContext $ctx, string $header = ''): \Generator
|
||||||
{
|
{
|
||||||
$this->stream = yield $ctx->getStream(chr(239).$header);
|
$this->stream = yield $ctx->getStream(\chr(239).$header);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,11 +68,11 @@ class AbridgedStream implements BufferedStreamInterface, MTProtoBufferInterface
|
|||||||
{
|
{
|
||||||
$length >>= 2;
|
$length >>= 2;
|
||||||
if ($length < 127) {
|
if ($length < 127) {
|
||||||
$message = chr($length);
|
$message = \chr($length);
|
||||||
} else {
|
} else {
|
||||||
$message = chr(127).substr(pack('V', $length), 0, 3);
|
$message = \chr(127).\substr(\pack('V', $length), 0, 3);
|
||||||
}
|
}
|
||||||
$buffer = yield $this->stream->getWriteBuffer(strlen($message) + $length, $append);
|
$buffer = yield $this->stream->getWriteBuffer(\strlen($message) + $length, $append);
|
||||||
yield $buffer->bufferWrite($message);
|
yield $buffer->bufferWrite($message);
|
||||||
|
|
||||||
return $buffer;
|
return $buffer;
|
||||||
@ -88,9 +88,9 @@ class AbridgedStream implements BufferedStreamInterface, MTProtoBufferInterface
|
|||||||
public function getReadBufferAsync(&$length): \Generator
|
public function getReadBufferAsync(&$length): \Generator
|
||||||
{
|
{
|
||||||
$buffer = yield $this->stream->getReadBuffer($l);
|
$buffer = yield $this->stream->getReadBuffer($l);
|
||||||
$length = ord(yield $buffer->bufferRead(1));
|
$length = \ord(yield $buffer->bufferRead(1));
|
||||||
if ($length >= 127) {
|
if ($length >= 127) {
|
||||||
$length = unpack('V', (yield $buffer->bufferRead(3))."\0")[1];
|
$length = \unpack('V', (yield $buffer->bufferRead(3))."\0")[1];
|
||||||
}
|
}
|
||||||
$length <<= 2;
|
$length <<= 2;
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ class FullStream implements BufferedStreamInterface, MTProtoBufferInterface
|
|||||||
$this->stream->checkWriteHash($length + 8);
|
$this->stream->checkWriteHash($length + 8);
|
||||||
$buffer = yield $this->stream->getWriteBuffer($length + 12, $append);
|
$buffer = yield $this->stream->getWriteBuffer($length + 12, $append);
|
||||||
$this->out_seq_no++;
|
$this->out_seq_no++;
|
||||||
$buffer->bufferWrite(pack('VV', $length + 12, $this->out_seq_no));
|
$buffer->bufferWrite(\pack('VV', $length + 12, $this->out_seq_no));
|
||||||
|
|
||||||
return $buffer;
|
return $buffer;
|
||||||
}
|
}
|
||||||
@ -95,11 +95,11 @@ class FullStream implements BufferedStreamInterface, MTProtoBufferInterface
|
|||||||
{
|
{
|
||||||
$this->stream->startReadHash();
|
$this->stream->startReadHash();
|
||||||
$buffer = yield $this->stream->getReadBuffer($l);
|
$buffer = yield $this->stream->getReadBuffer($l);
|
||||||
$read_length = unpack('V', yield $buffer->bufferRead(4))[1];
|
$read_length = \unpack('V', yield $buffer->bufferRead(4))[1];
|
||||||
$length = $read_length - 12;
|
$length = $read_length - 12;
|
||||||
$this->stream->checkReadHash($read_length - 8);
|
$this->stream->checkReadHash($read_length - 8);
|
||||||
$this->in_seq_no++;
|
$this->in_seq_no++;
|
||||||
$in_seq_no = unpack('V', yield $buffer->bufferRead(4))[1];
|
$in_seq_no = \unpack('V', yield $buffer->bufferRead(4))[1];
|
||||||
if ($in_seq_no != $this->in_seq_no) {
|
if ($in_seq_no != $this->in_seq_no) {
|
||||||
throw new Exception('Incoming seq_no mismatch');
|
throw new Exception('Incoming seq_no mismatch');
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface
|
|||||||
public function getWriteBufferAsync(int $length, string $append = ''): \Generator
|
public function getWriteBufferAsync(int $length, string $append = ''): \Generator
|
||||||
{
|
{
|
||||||
$headers = 'POST '.$this->uri->getPath()." HTTP/1.1\r\nHost: ".$this->uri->getHost().':'.$this->uri->getPort()."\r\n"."Content-Type: application/x-www-form-urlencoded\r\nConnection: keep-alive\r\nKeep-Alive: timeout=100000, max=10000000\r\nContent-Length: ".$length.$this->header."\r\n\r\n";
|
$headers = 'POST '.$this->uri->getPath()." HTTP/1.1\r\nHost: ".$this->uri->getHost().':'.$this->uri->getPort()."\r\n"."Content-Type: application/x-www-form-urlencoded\r\nConnection: keep-alive\r\nKeep-Alive: timeout=100000, max=10000000\r\nContent-Length: ".$length.$this->header."\r\n\r\n";
|
||||||
$buffer = yield $this->stream->getWriteBuffer(strlen($headers) + $length, $append);
|
$buffer = yield $this->stream->getWriteBuffer(\strlen($headers) + $length, $append);
|
||||||
yield $buffer->bufferWrite($headers);
|
yield $buffer->bufferWrite($headers);
|
||||||
|
|
||||||
return $buffer;
|
return $buffer;
|
||||||
@ -122,27 +122,27 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface
|
|||||||
}
|
}
|
||||||
$was_crlf = $piece === "\r\n";
|
$was_crlf = $piece === "\r\n";
|
||||||
}
|
}
|
||||||
$headers = explode("\r\n", $headers);
|
$headers = \explode("\r\n", $headers);
|
||||||
|
|
||||||
list($protocol, $code, $description) = explode(' ', $headers[0], 3);
|
list($protocol, $code, $description) = \explode(' ', $headers[0], 3);
|
||||||
list($protocol, $protocol_version) = explode('/', $protocol);
|
list($protocol, $protocol_version) = \explode('/', $protocol);
|
||||||
if ($protocol !== 'HTTP') {
|
if ($protocol !== 'HTTP') {
|
||||||
throw new \danog\MadelineProto\Exception('Wrong protocol');
|
throw new \danog\MadelineProto\Exception('Wrong protocol');
|
||||||
}
|
}
|
||||||
$code = (int) $code;
|
$code = (int) $code;
|
||||||
unset($headers[0]);
|
unset($headers[0]);
|
||||||
if (array_pop($headers).array_pop($headers) !== '') {
|
if (\array_pop($headers).\array_pop($headers) !== '') {
|
||||||
throw new \danog\MadelineProto\Exception('Wrong last header');
|
throw new \danog\MadelineProto\Exception('Wrong last header');
|
||||||
}
|
}
|
||||||
foreach ($headers as $key => $current_header) {
|
foreach ($headers as $key => $current_header) {
|
||||||
unset($headers[$key]);
|
unset($headers[$key]);
|
||||||
$current_header = explode(':', $current_header, 2);
|
$current_header = \explode(':', $current_header, 2);
|
||||||
$headers[strtolower($current_header[0])] = trim($current_header[1]);
|
$headers[\strtolower($current_header[0])] = \trim($current_header[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$close = $protocol === 'HTTP/1.0';
|
$close = $protocol === 'HTTP/1.0';
|
||||||
if (isset($headers['connection'])) {
|
if (isset($headers['connection'])) {
|
||||||
$close = strtolower($headers['connection']) === 'close';
|
$close = \strtolower($headers['connection']) === 'close';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($code !== 200) {
|
if ($code !== 200) {
|
||||||
|
@ -45,7 +45,7 @@ class IntermediatePaddedStream implements BufferedStreamInterface, MTProtoBuffer
|
|||||||
*/
|
*/
|
||||||
public function connectAsync(ConnectionContext $ctx, string $header = ''): \Generator
|
public function connectAsync(ConnectionContext $ctx, string $header = ''): \Generator
|
||||||
{
|
{
|
||||||
$this->stream = yield $ctx->getStream(str_repeat(chr(221), 4).$header);
|
$this->stream = yield $ctx->getStream(\str_repeat(\chr(221), 4).$header);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -69,7 +69,7 @@ class IntermediatePaddedStream implements BufferedStreamInterface, MTProtoBuffer
|
|||||||
{
|
{
|
||||||
$padding_length = $this->random_int($modulus = 16);
|
$padding_length = $this->random_int($modulus = 16);
|
||||||
$buffer = yield $this->stream->getWriteBuffer(4 + $length + $padding_length, $append.$this->random($padding_length));
|
$buffer = yield $this->stream->getWriteBuffer(4 + $length + $padding_length, $append.$this->random($padding_length));
|
||||||
yield $buffer->bufferWrite(pack('V', $padding_length + $length));
|
yield $buffer->bufferWrite(\pack('V', $padding_length + $length));
|
||||||
|
|
||||||
return $buffer;
|
return $buffer;
|
||||||
}
|
}
|
||||||
@ -84,7 +84,7 @@ class IntermediatePaddedStream implements BufferedStreamInterface, MTProtoBuffer
|
|||||||
public function getReadBufferAsync(&$length): \Generator
|
public function getReadBufferAsync(&$length): \Generator
|
||||||
{
|
{
|
||||||
$buffer = yield $this->stream->getReadBuffer($l);
|
$buffer = yield $this->stream->getReadBuffer($l);
|
||||||
$length = unpack('V', yield $buffer->bufferRead(4))[1];
|
$length = \unpack('V', yield $buffer->bufferRead(4))[1];
|
||||||
|
|
||||||
return $buffer;
|
return $buffer;
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ class IntermediateStream implements BufferedStreamInterface, MTProtoBufferInterf
|
|||||||
*/
|
*/
|
||||||
public function connectAsync(ConnectionContext $ctx, string $header = ''): \Generator
|
public function connectAsync(ConnectionContext $ctx, string $header = ''): \Generator
|
||||||
{
|
{
|
||||||
$this->stream = yield $ctx->getStream(str_repeat(chr(238), 4).$header);
|
$this->stream = yield $ctx->getStream(\str_repeat(\chr(238), 4).$header);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,7 +68,7 @@ class IntermediateStream implements BufferedStreamInterface, MTProtoBufferInterf
|
|||||||
public function getWriteBufferAsync(int $length, string $append = ''): \Generator
|
public function getWriteBufferAsync(int $length, string $append = ''): \Generator
|
||||||
{
|
{
|
||||||
$buffer = yield $this->stream->getWriteBuffer($length + 4, $append);
|
$buffer = yield $this->stream->getWriteBuffer($length + 4, $append);
|
||||||
yield $buffer->bufferWrite(pack('V', $length));
|
yield $buffer->bufferWrite(\pack('V', $length));
|
||||||
|
|
||||||
return $buffer;
|
return $buffer;
|
||||||
}
|
}
|
||||||
@ -83,7 +83,7 @@ class IntermediateStream implements BufferedStreamInterface, MTProtoBufferInterf
|
|||||||
public function getReadBufferAsync(&$length): \Generator
|
public function getReadBufferAsync(&$length): \Generator
|
||||||
{
|
{
|
||||||
$buffer = yield $this->stream->getReadBuffer($l);
|
$buffer = yield $this->stream->getReadBuffer($l);
|
||||||
$length = unpack('V', yield $buffer->bufferRead(4))[1];
|
$length = \unpack('V', yield $buffer->bufferRead(4))[1];
|
||||||
|
|
||||||
return $buffer;
|
return $buffer;
|
||||||
}
|
}
|
||||||
|
@ -61,35 +61,35 @@ class ObfuscatedStream implements BufferedProxyStreamInterface
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
$random = $this->random(64);
|
$random = $this->random(64);
|
||||||
} while (in_array(substr($random, 0, 4), ['PVrG', 'GET ', 'POST', 'HEAD', str_repeat(chr(238), 4), str_repeat(chr(221), 4)]) || $random[0] === chr(0xef) || substr($random, 4, 4) === "\0\0\0\0");
|
} while (\in_array(\substr($random, 0, 4), ['PVrG', 'GET ', 'POST', 'HEAD', \str_repeat(\chr(238), 4), \str_repeat(\chr(221), 4)]) || $random[0] === \chr(0xef) || \substr($random, 4, 4) === "\0\0\0\0");
|
||||||
|
|
||||||
if (strlen($header) === 1) {
|
if (\strlen($header) === 1) {
|
||||||
$header = str_repeat($header, 4);
|
$header = \str_repeat($header, 4);
|
||||||
}
|
}
|
||||||
$random = substr_replace($random, $header.substr($random, 56 + strlen($header)), 56);
|
$random = \substr_replace($random, $header.\substr($random, 56 + \strlen($header)), 56);
|
||||||
$random = substr_replace($random, pack('s', $ctx->getIntDc()).substr($random, 60 + 2), 60);
|
$random = \substr_replace($random, \pack('s', $ctx->getIntDc()).\substr($random, 60 + 2), 60);
|
||||||
|
|
||||||
$reversed = strrev($random);
|
$reversed = \strrev($random);
|
||||||
|
|
||||||
$key = substr($random, 8, 32);
|
$key = \substr($random, 8, 32);
|
||||||
$keyRev = substr($reversed, 8, 32);
|
$keyRev = \substr($reversed, 8, 32);
|
||||||
|
|
||||||
if (isset($this->extra['secret'])) {
|
if (isset($this->extra['secret'])) {
|
||||||
$key = hash('sha256', $key.$this->extra['secret'], true);
|
$key = \hash('sha256', $key.$this->extra['secret'], true);
|
||||||
$keyRev = hash('sha256', $keyRev.$this->extra['secret'], true);
|
$keyRev = \hash('sha256', $keyRev.$this->extra['secret'], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->encrypt = new \phpseclib\Crypt\AES('ctr');
|
$this->encrypt = new \phpseclib\Crypt\AES('ctr');
|
||||||
$this->encrypt->enableContinuousBuffer();
|
$this->encrypt->enableContinuousBuffer();
|
||||||
$this->encrypt->setKey($key);
|
$this->encrypt->setKey($key);
|
||||||
$this->encrypt->setIV(substr($random, 40, 16));
|
$this->encrypt->setIV(\substr($random, 40, 16));
|
||||||
|
|
||||||
$this->decrypt = new \phpseclib\Crypt\AES('ctr');
|
$this->decrypt = new \phpseclib\Crypt\AES('ctr');
|
||||||
$this->decrypt->enableContinuousBuffer();
|
$this->decrypt->enableContinuousBuffer();
|
||||||
$this->decrypt->setKey($keyRev);
|
$this->decrypt->setKey($keyRev);
|
||||||
$this->decrypt->setIV(substr($reversed, 40, 16));
|
$this->decrypt->setIV(\substr($reversed, 40, 16));
|
||||||
|
|
||||||
$random = substr_replace($random, substr(@$this->encrypt->encrypt($random), 56, 8), 56, 8);
|
$random = \substr_replace($random, \substr(@$this->encrypt->encrypt($random), 56, 8), 56, 8);
|
||||||
|
|
||||||
$this->stream = yield $ctx->getStream($random);
|
$this->stream = yield $ctx->getStream($random);
|
||||||
}
|
}
|
||||||
@ -114,9 +114,9 @@ class ObfuscatedStream implements BufferedProxyStreamInterface
|
|||||||
public function getWriteBufferAsync(int $length, string $append = ''): \Generator
|
public function getWriteBufferAsync(int $length, string $append = ''): \Generator
|
||||||
{
|
{
|
||||||
$this->write_buffer = yield $this->stream->getWriteBuffer($length);
|
$this->write_buffer = yield $this->stream->getWriteBuffer($length);
|
||||||
if (strlen($append)) {
|
if (\strlen($append)) {
|
||||||
$this->append = $append;
|
$this->append = $append;
|
||||||
$this->append_after = $length - strlen($append);
|
$this->append_after = $length - \strlen($append);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
@ -162,7 +162,7 @@ class ObfuscatedStream implements BufferedProxyStreamInterface
|
|||||||
public function bufferWrite(string $data): Promise
|
public function bufferWrite(string $data): Promise
|
||||||
{
|
{
|
||||||
if ($this->append_after) {
|
if ($this->append_after) {
|
||||||
$this->append_after -= strlen($data);
|
$this->append_after -= \strlen($data);
|
||||||
if ($this->append_after === 0) {
|
if ($this->append_after === 0) {
|
||||||
$data .= $this->append;
|
$data .= $this->append;
|
||||||
$this->append = '';
|
$this->append = '';
|
||||||
@ -187,11 +187,11 @@ class ObfuscatedStream implements BufferedProxyStreamInterface
|
|||||||
public function setExtra($extra)
|
public function setExtra($extra)
|
||||||
{
|
{
|
||||||
if (isset($extra['secret'])) {
|
if (isset($extra['secret'])) {
|
||||||
if (strlen($extra['secret']) > 17) {
|
if (\strlen($extra['secret']) > 17) {
|
||||||
$extra['secret'] = hex2bin($extra['secret']);
|
$extra['secret'] = \hex2bin($extra['secret']);
|
||||||
}
|
}
|
||||||
if (strlen($extra['secret']) == 17) {
|
if (\strlen($extra['secret']) == 17) {
|
||||||
$extra['secret'] = substr($extra['secret'], 1, 16);
|
$extra['secret'] = \substr($extra['secret'], 1, 16);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface
|
|||||||
$port = $uri->getPort();
|
$port = $uri->getPort();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (strlen(inet_pton($address) === 16)) {
|
if (\strlen(\inet_pton($address) === 16)) {
|
||||||
$address = '['.$address.']';
|
$address = '['.$address.']';
|
||||||
}
|
}
|
||||||
} catch (\danog\MadelineProto\Exception $e) {
|
} catch (\danog\MadelineProto\Exception $e) {
|
||||||
@ -77,27 +77,27 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface
|
|||||||
}
|
}
|
||||||
$was_crlf = $piece === "\r\n";
|
$was_crlf = $piece === "\r\n";
|
||||||
}
|
}
|
||||||
$headers = explode("\r\n", $headers);
|
$headers = \explode("\r\n", $headers);
|
||||||
|
|
||||||
list($protocol, $code, $description) = explode(' ', $headers[0], 3);
|
list($protocol, $code, $description) = \explode(' ', $headers[0], 3);
|
||||||
list($protocol, $protocol_version) = explode('/', $protocol);
|
list($protocol, $protocol_version) = \explode('/', $protocol);
|
||||||
if ($protocol !== 'HTTP') {
|
if ($protocol !== 'HTTP') {
|
||||||
throw new \danog\MadelineProto\Exception('Wrong protocol');
|
throw new \danog\MadelineProto\Exception('Wrong protocol');
|
||||||
}
|
}
|
||||||
$code = (int) $code;
|
$code = (int) $code;
|
||||||
unset($headers[0]);
|
unset($headers[0]);
|
||||||
if (array_pop($headers).array_pop($headers) !== '') {
|
if (\array_pop($headers).\array_pop($headers) !== '') {
|
||||||
throw new \danog\MadelineProto\Exception('Wrong last header');
|
throw new \danog\MadelineProto\Exception('Wrong last header');
|
||||||
}
|
}
|
||||||
foreach ($headers as $key => $current_header) {
|
foreach ($headers as $key => $current_header) {
|
||||||
unset($headers[$key]);
|
unset($headers[$key]);
|
||||||
$current_header = explode(':', $current_header, 2);
|
$current_header = \explode(':', $current_header, 2);
|
||||||
$headers[strtolower($current_header[0])] = trim($current_header[1]);
|
$headers[\strtolower($current_header[0])] = \trim($current_header[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$close = $protocol === 'HTTP/1.0';
|
$close = $protocol === 'HTTP/1.0';
|
||||||
if (isset($headers['connection'])) {
|
if (isset($headers['connection'])) {
|
||||||
$close = strtolower($headers['connection']) === 'close';
|
$close = \strtolower($headers['connection']) === 'close';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($code !== 200) {
|
if ($code !== 200) {
|
||||||
@ -111,7 +111,7 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface
|
|||||||
yield $this->connect($ctx);
|
yield $this->connect($ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
\danog\MadelineProto\Logger::log(trim($read));
|
\danog\MadelineProto\Logger::log(\trim($read));
|
||||||
|
|
||||||
throw new \danog\MadelineProto\Exception($description, $code);
|
throw new \danog\MadelineProto\Exception($description, $code);
|
||||||
}
|
}
|
||||||
@ -125,13 +125,13 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface
|
|||||||
$read = yield $buffer->bufferRead($length);
|
$read = yield $buffer->bufferRead($length);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($secure && method_exists($this->getSocket(), 'enableCrypto')) {
|
if ($secure && \method_exists($this->getSocket(), 'enableCrypto')) {
|
||||||
yield $this->getSocket()->enableCrypto((new ClientTlsContext())->withPeerName($uri->getHost()));
|
yield $this->getSocket()->enableCrypto((new ClientTlsContext())->withPeerName($uri->getHost()));
|
||||||
}
|
}
|
||||||
\danog\MadelineProto\Logger::log('Connected to '.$address.':'.$port.' via http');
|
\danog\MadelineProto\Logger::log('Connected to '.$address.':'.$port.' via http');
|
||||||
|
|
||||||
if (strlen($header)) {
|
if (\strlen($header)) {
|
||||||
yield (yield $this->stream->getWriteBuffer(strlen($header)))->bufferWrite($header);
|
yield (yield $this->stream->getWriteBuffer(\strlen($header)))->bufferWrite($header);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,7 +185,7 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'Proxy-Authorization: Basic '.base64_encode($this->extra['username'].':'.$this->extra['password'])."\r\n";
|
return 'Proxy-Authorization: Basic '.\base64_encode($this->extra['username'].':'.$this->extra['password'])."\r\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,30 +49,30 @@ class SocksProxy implements RawProxyStreamInterface, BufferedProxyStreamInterfac
|
|||||||
$secure = $ctx->isSecure();
|
$secure = $ctx->isSecure();
|
||||||
$ctx->setUri('tcp://'.$this->extra['address'].':'.$this->extra['port'])->secure(false);
|
$ctx->setUri('tcp://'.$this->extra['address'].':'.$this->extra['port'])->secure(false);
|
||||||
|
|
||||||
$methods = chr(0);
|
$methods = \chr(0);
|
||||||
if (isset($this->extra['username']) && isset($this->extra['password'])) {
|
if (isset($this->extra['username']) && isset($this->extra['password'])) {
|
||||||
$methods .= chr(2);
|
$methods .= \chr(2);
|
||||||
}
|
}
|
||||||
$this->stream = yield $ctx->getStream(chr(5).chr(strlen($methods)).$methods);
|
$this->stream = yield $ctx->getStream(\chr(5).\chr(\strlen($methods)).$methods);
|
||||||
|
|
||||||
$l = 2;
|
$l = 2;
|
||||||
|
|
||||||
$buffer = yield $this->stream->getReadBuffer($l);
|
$buffer = yield $this->stream->getReadBuffer($l);
|
||||||
|
|
||||||
$version = ord(yield $buffer->bufferRead(1));
|
$version = \ord(yield $buffer->bufferRead(1));
|
||||||
$method = ord(yield $buffer->bufferRead(1));
|
$method = \ord(yield $buffer->bufferRead(1));
|
||||||
|
|
||||||
if ($version !== 5) {
|
if ($version !== 5) {
|
||||||
throw new \danog\MadelineProto\Exception("Wrong SOCKS5 version: $version");
|
throw new \danog\MadelineProto\Exception("Wrong SOCKS5 version: $version");
|
||||||
}
|
}
|
||||||
if ($method === 2) {
|
if ($method === 2) {
|
||||||
$auth = chr(1).chr(strlen($this->extra['username'])).$this->extra['username'].chr(strlen($this->extra['password'])).$this->extra['password'];
|
$auth = \chr(1).\chr(\strlen($this->extra['username'])).$this->extra['username'].\chr(\strlen($this->extra['password'])).$this->extra['password'];
|
||||||
yield $this->stream->write($auth);
|
yield $this->stream->write($auth);
|
||||||
|
|
||||||
$buffer = yield $this->stream->getReadBuffer($l);
|
$buffer = yield $this->stream->getReadBuffer($l);
|
||||||
|
|
||||||
$version = ord(yield $buffer->bufferRead(1));
|
$version = \ord(yield $buffer->bufferRead(1));
|
||||||
$result = ord(yield $buffer->bufferRead(1));
|
$result = \ord(yield $buffer->bufferRead(1));
|
||||||
|
|
||||||
if ($version !== 1) {
|
if ($version !== 1) {
|
||||||
throw new \danog\MadelineProto\Exception("Wrong authorized SOCKS version: $version");
|
throw new \danog\MadelineProto\Exception("Wrong authorized SOCKS version: $version");
|
||||||
@ -83,50 +83,50 @@ class SocksProxy implements RawProxyStreamInterface, BufferedProxyStreamInterfac
|
|||||||
} elseif ($method !== 0) {
|
} elseif ($method !== 0) {
|
||||||
throw new \danog\MadelineProto\Exception("Wrong method: $method");
|
throw new \danog\MadelineProto\Exception("Wrong method: $method");
|
||||||
}
|
}
|
||||||
$payload = pack('C3', 0x05, 0x01, 0x00);
|
$payload = \pack('C3', 0x05, 0x01, 0x00);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$ip = inet_pton($uri->getHost());
|
$ip = \inet_pton($uri->getHost());
|
||||||
$payload .= $ip ? pack('C1', strlen($ip) === 4 ? 0x01 : 0x04).$ip : pack('C2', 0x03, strlen($uri->getHost())).$uri->getHost();
|
$payload .= $ip ? \pack('C1', \strlen($ip) === 4 ? 0x01 : 0x04).$ip : \pack('C2', 0x03, \strlen($uri->getHost())).$uri->getHost();
|
||||||
} catch (\danog\MadelineProto\Exception $e) {
|
} catch (\danog\MadelineProto\Exception $e) {
|
||||||
$payload .= pack('C2', 0x03, strlen($uri->getHost())).$uri->getHost();
|
$payload .= \pack('C2', 0x03, \strlen($uri->getHost())).$uri->getHost();
|
||||||
}
|
}
|
||||||
|
|
||||||
$payload .= pack('n', $uri->getPort());
|
$payload .= \pack('n', $uri->getPort());
|
||||||
yield $this->stream->write($payload);
|
yield $this->stream->write($payload);
|
||||||
|
|
||||||
$l = 4;
|
$l = 4;
|
||||||
$buffer = yield $this->stream->getReadBuffer($l);
|
$buffer = yield $this->stream->getReadBuffer($l);
|
||||||
|
|
||||||
$version = ord(yield $buffer->bufferRead(1));
|
$version = \ord(yield $buffer->bufferRead(1));
|
||||||
if ($version !== 5) {
|
if ($version !== 5) {
|
||||||
throw new \danog\MadelineProto\Exception("Wrong SOCKS5 version: $version");
|
throw new \danog\MadelineProto\Exception("Wrong SOCKS5 version: $version");
|
||||||
}
|
}
|
||||||
|
|
||||||
$rep = ord(yield $buffer->bufferRead(1));
|
$rep = \ord(yield $buffer->bufferRead(1));
|
||||||
if ($rep !== 0) {
|
if ($rep !== 0) {
|
||||||
throw new \danog\MadelineProto\Exception("Wrong SOCKS5 rep: $rep");
|
throw new \danog\MadelineProto\Exception("Wrong SOCKS5 rep: $rep");
|
||||||
}
|
}
|
||||||
|
|
||||||
$rsv = ord(yield $buffer->bufferRead(1));
|
$rsv = \ord(yield $buffer->bufferRead(1));
|
||||||
if ($rsv !== 0) {
|
if ($rsv !== 0) {
|
||||||
throw new \danog\MadelineProto\Exception("Wrong socks5 final RSV: $rsv");
|
throw new \danog\MadelineProto\Exception("Wrong socks5 final RSV: $rsv");
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (ord(yield $buffer->bufferRead(1))) {
|
switch (\ord(yield $buffer->bufferRead(1))) {
|
||||||
case 1:
|
case 1:
|
||||||
$buffer = yield $this->stream->getReadBuffer($l);
|
$buffer = yield $this->stream->getReadBuffer($l);
|
||||||
$ip = inet_ntop(yield $buffer->bufferRead(4));
|
$ip = \inet_ntop(yield $buffer->bufferRead(4));
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
$l = 16;
|
$l = 16;
|
||||||
$buffer = yield $this->stream->getReadBuffer($l);
|
$buffer = yield $this->stream->getReadBuffer($l);
|
||||||
$ip = inet_ntop(yield $buffer->bufferRead(16));
|
$ip = \inet_ntop(yield $buffer->bufferRead(16));
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
$l = 1;
|
$l = 1;
|
||||||
$buffer = yield $this->stream->getReadBuffer($l);
|
$buffer = yield $this->stream->getReadBuffer($l);
|
||||||
$length = ord(yield $buffer->bufferRead(1));
|
$length = \ord(yield $buffer->bufferRead(1));
|
||||||
|
|
||||||
$buffer = yield $this->stream->getReadBuffer($length);
|
$buffer = yield $this->stream->getReadBuffer($length);
|
||||||
$ip = yield $buffer->bufferRead($length);
|
$ip = yield $buffer->bufferRead($length);
|
||||||
@ -134,15 +134,15 @@ class SocksProxy implements RawProxyStreamInterface, BufferedProxyStreamInterfac
|
|||||||
}
|
}
|
||||||
$l = 2;
|
$l = 2;
|
||||||
$buffer = yield $this->stream->getReadBuffer($l);
|
$buffer = yield $this->stream->getReadBuffer($l);
|
||||||
$port = unpack('n', yield $buffer->bufferRead(2))[1];
|
$port = \unpack('n', yield $buffer->bufferRead(2))[1];
|
||||||
|
|
||||||
\danog\MadelineProto\Logger::log(['Connected to '.$ip.':'.$port.' via socks5']);
|
\danog\MadelineProto\Logger::log(['Connected to '.$ip.':'.$port.' via socks5']);
|
||||||
|
|
||||||
if ($secure && method_exists($this->getSocket(), 'enableCrypto')) {
|
if ($secure && \method_exists($this->getSocket(), 'enableCrypto')) {
|
||||||
yield $this->getSocket()->enableCrypto((new ClientTlsContext())->withPeerName($uri->getHost()));
|
yield $this->getSocket()->enableCrypto((new ClientTlsContext())->withPeerName($uri->getHost()));
|
||||||
}
|
}
|
||||||
if (strlen($header)) {
|
if (\strlen($header)) {
|
||||||
yield (yield $this->stream->getWriteBuffer(strlen($header)))->bufferWrite($header);
|
yield (yield $this->stream->getWriteBuffer(\strlen($header)))->bufferWrite($header);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,14 +18,12 @@
|
|||||||
|
|
||||||
namespace danog\MadelineProto\Stream\Transport;
|
namespace danog\MadelineProto\Stream\Transport;
|
||||||
|
|
||||||
|
use Amp\ByteStream\ClosedException;
|
||||||
use Amp\Promise;
|
use Amp\Promise;
|
||||||
use Amp\Socket\Socket;
|
use Amp\Socket\Socket;
|
||||||
use danog\MadelineProto\Stream\Async\RawStream;
|
use danog\MadelineProto\Stream\Async\RawStream;
|
||||||
use danog\MadelineProto\Stream\RawStreamInterface;
|
|
||||||
use function Amp\Socket\connect;
|
|
||||||
use function Amp\Socket\cryptoConnect;
|
|
||||||
use danog\MadelineProto\Stream\ProxyStreamInterface;
|
use danog\MadelineProto\Stream\ProxyStreamInterface;
|
||||||
use Amp\ByteStream\ClosedException;
|
use danog\MadelineProto\Stream\RawStreamInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default stream wrapper.
|
* Default stream wrapper.
|
||||||
@ -40,7 +38,7 @@ class DefaultStream extends Socket implements RawStreamInterface, ProxyStreamInt
|
|||||||
private $stream;
|
private $stream;
|
||||||
private $connector = 'Amp\\Socket\\connect';
|
private $connector = 'Amp\\Socket\\connect';
|
||||||
private $cryptoConnector = 'Amp\\Socket\\cryptoConnect';
|
private $cryptoConnector = 'Amp\\Socket\\cryptoConnect';
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -18,15 +18,13 @@
|
|||||||
|
|
||||||
namespace danog\MadelineProto\Stream\Transport;
|
namespace danog\MadelineProto\Stream\Transport;
|
||||||
|
|
||||||
|
use Amp\ByteStream\ClosedException;
|
||||||
use Amp\Promise;
|
use Amp\Promise;
|
||||||
use Amp\Socket\Socket;
|
use Amp\Socket\Socket;
|
||||||
use danog\MadelineProto\Stream\Async\RawStream;
|
use danog\MadelineProto\Stream\Async\RawStream;
|
||||||
use danog\MadelineProto\Stream\RawStreamInterface;
|
|
||||||
use function Amp\Socket\connect;
|
|
||||||
use function Amp\Socket\cryptoConnect;
|
|
||||||
use danog\MadelineProto\Stream\ProxyStreamInterface;
|
|
||||||
use Amp\ByteStream\ClosedException;
|
|
||||||
use danog\MadelineProto\Stream\ConnectionContext;
|
use danog\MadelineProto\Stream\ConnectionContext;
|
||||||
|
use danog\MadelineProto\Stream\ProxyStreamInterface;
|
||||||
|
use danog\MadelineProto\Stream\RawStreamInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Premade stream wrapper.
|
* Premade stream wrapper.
|
||||||
@ -39,7 +37,7 @@ class PremadeStream extends Socket implements RawStreamInterface, ProxyStreamInt
|
|||||||
{
|
{
|
||||||
use RawStream;
|
use RawStream;
|
||||||
private $stream;
|
private $stream;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -95,7 +93,7 @@ class PremadeStream extends Socket implements RawStreamInterface, ProxyStreamInt
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if ($this->stream) {
|
if ($this->stream) {
|
||||||
if (method_exists($this->stream, 'close')) {
|
if (\method_exists($this->stream, 'close')) {
|
||||||
$this->stream->close();
|
$this->stream->close();
|
||||||
}
|
}
|
||||||
$this->stream = null;
|
$this->stream = null;
|
||||||
|
@ -61,7 +61,7 @@ class WsStream implements RawStreamInterface
|
|||||||
|
|
||||||
$this->compressionFactory = new Rfc7692CompressionFactory();
|
$this->compressionFactory = new Rfc7692CompressionFactory();
|
||||||
|
|
||||||
$handshake = new Handshake(str_replace('tcp://', $ctx->isSecure() ? 'ws://' : 'wss://', $ctx->getStringUri()));
|
$handshake = new Handshake(\str_replace('tcp://', $ctx->isSecure() ? 'ws://' : 'wss://', $ctx->getStringUri()));
|
||||||
|
|
||||||
$key = generateKey();
|
$key = generateKey();
|
||||||
yield $stream->write($this->generateRequest($handshake, $key));
|
yield $stream->write($this->generateRequest($handshake, $key));
|
||||||
|
@ -25,15 +25,15 @@ trait BotAPI
|
|||||||
{
|
{
|
||||||
public function html_entity_decode($stuff)
|
public function html_entity_decode($stuff)
|
||||||
{
|
{
|
||||||
return html_entity_decode(preg_replace('#< *br */? *>#', "\n", $stuff));
|
return \html_entity_decode(\preg_replace('#< *br */? *>#', "\n", $stuff));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function mb_strlen($text)
|
public function mb_strlen($text)
|
||||||
{
|
{
|
||||||
$length = 0;
|
$length = 0;
|
||||||
$textlength = strlen($text);
|
$textlength = \strlen($text);
|
||||||
for ($x = 0; $x < $textlength; $x++) {
|
for ($x = 0; $x < $textlength; $x++) {
|
||||||
$char = ord($text[$x]);
|
$char = \ord($text[$x]);
|
||||||
if (($char & 0xC0) != 0x80) {
|
if (($char & 0xC0) != 0x80) {
|
||||||
$length += 1 + ($char >= 0xf0);
|
$length += 1 + ($char >= 0xf0);
|
||||||
}
|
}
|
||||||
@ -56,9 +56,9 @@ trait BotAPI
|
|||||||
$new_text = '';
|
$new_text = '';
|
||||||
$current_offset = 0;
|
$current_offset = 0;
|
||||||
$current_length = 0;
|
$current_length = 0;
|
||||||
$text_length = strlen($text);
|
$text_length = \strlen($text);
|
||||||
for ($x = 0; $x < $text_length; $x++) {
|
for ($x = 0; $x < $text_length; $x++) {
|
||||||
$char = ord($text[$x]);
|
$char = \ord($text[$x]);
|
||||||
if (($char & 0xC0) != 0x80) {
|
if (($char & 0xC0) != 0x80) {
|
||||||
$current_offset += 1 + ($char >= 0xf0);
|
$current_offset += 1 + ($char >= 0xf0);
|
||||||
if ($current_offset > $offset) {
|
if ($current_offset > $offset) {
|
||||||
@ -77,10 +77,10 @@ trait BotAPI
|
|||||||
|
|
||||||
public function mb_str_split($text, $length)
|
public function mb_str_split($text, $length)
|
||||||
{
|
{
|
||||||
$tlength = mb_strlen($text, 'UTF-8');
|
$tlength = \mb_strlen($text, 'UTF-8');
|
||||||
$result = [];
|
$result = [];
|
||||||
for ($x = 0; $x < $tlength; $x += $length) {
|
for ($x = 0; $x < $tlength; $x += $length) {
|
||||||
$result[] = mb_substr($text, $x, $length, 'UTF-8');
|
$result[] = \mb_substr($text, $x, $length, 'UTF-8');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
@ -180,7 +180,7 @@ trait BotAPI
|
|||||||
$newd['entities'] = yield $this->MTProto_to_botAPI_async($data['entities'], $sent_arguments);
|
$newd['entities'] = yield $this->MTProto_to_botAPI_async($data['entities'], $sent_arguments);
|
||||||
}
|
}
|
||||||
if (isset($data['media'])) {
|
if (isset($data['media'])) {
|
||||||
$newd = array_merge($newd, yield $this->MTProto_to_botAPI_async($data['media'], $sent_arguments));
|
$newd = \array_merge($newd, yield $this->MTProto_to_botAPI_async($data['media'], $sent_arguments));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $newd;
|
return $newd;
|
||||||
@ -222,7 +222,7 @@ trait BotAPI
|
|||||||
$newd['forward_from_message_id'] = $data['fwd_from']['channel_post'];
|
$newd['forward_from_message_id'] = $data['fwd_from']['channel_post'];
|
||||||
}
|
}
|
||||||
if (isset($data['media'])) {
|
if (isset($data['media'])) {
|
||||||
$newd = array_merge($newd, yield $this->MTProto_to_botAPI_async($data['media'], $sent_arguments));
|
$newd = \array_merge($newd, yield $this->MTProto_to_botAPI_async($data['media'], $sent_arguments));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $newd;
|
return $newd;
|
||||||
@ -289,7 +289,7 @@ trait BotAPI
|
|||||||
}
|
}
|
||||||
$res['photo'] = [];
|
$res['photo'] = [];
|
||||||
foreach ($data['photo']['sizes'] as $key => $photo) {
|
foreach ($data['photo']['sizes'] as $key => $photo) {
|
||||||
if (in_array($photo['_'], ['photoCachedSize', 'photoSize'])) {
|
if (\in_array($photo['_'], ['photoCachedSize', 'photoSize'])) {
|
||||||
$res['photo'][$key] = yield $this->photosize_to_botapi_async($photo, $data['photo']);
|
$res['photo'][$key] = yield $this->photosize_to_botapi_async($photo, $data['photo']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -300,13 +300,13 @@ trait BotAPI
|
|||||||
case 'messageMediaDocument':
|
case 'messageMediaDocument':
|
||||||
$type_name = 'document';
|
$type_name = 'document';
|
||||||
$res = [];
|
$res = [];
|
||||||
if (isset($data['document']['thumbs']) && $data['document']['thumbs'] && in_array(end($data['document']['thumbs'])['_'], ['photoCachedSize', 'photoSize'])) {
|
if (isset($data['document']['thumbs']) && $data['document']['thumbs'] && \in_array(\end($data['document']['thumbs'])['_'], ['photoCachedSize', 'photoSize'])) {
|
||||||
$res['thumb'] = yield $this->photosize_to_botapi_async(end($data['document']['thumbs']), [], true);
|
$res['thumb'] = yield $this->photosize_to_botapi_async(\end($data['document']['thumbs']), [], true);
|
||||||
}
|
}
|
||||||
foreach ($data['document']['attributes'] as $attribute) {
|
foreach ($data['document']['attributes'] as $attribute) {
|
||||||
switch ($attribute['_']) {
|
switch ($attribute['_']) {
|
||||||
case 'documentAttributeFilename':
|
case 'documentAttributeFilename':
|
||||||
$pathinfo = pathinfo($attribute['file_name']);
|
$pathinfo = \pathinfo($attribute['file_name']);
|
||||||
$res['ext'] = isset($pathinfo['extension']) ? '.'.$pathinfo['extension'] : '';
|
$res['ext'] = isset($pathinfo['extension']) ? '.'.$pathinfo['extension'] : '';
|
||||||
$res['file_name'] = $pathinfo['filename'];
|
$res['file_name'] = $pathinfo['filename'];
|
||||||
break;
|
break;
|
||||||
@ -374,11 +374,11 @@ trait BotAPI
|
|||||||
$data['document']['_'] = 'bot_'.$type_name;
|
$data['document']['_'] = 'bot_'.$type_name;
|
||||||
$res['file_size'] = $data['document']['size'];
|
$res['file_size'] = $data['document']['size'];
|
||||||
$res['mime_type'] = $data['document']['mime_type'];
|
$res['mime_type'] = $data['document']['mime_type'];
|
||||||
$res['file_id'] = $this->base64url_encode($this->rle_encode((yield $this->serialize_object_async(['type' => 'File'], $data['document'], 'File')).chr(2)));
|
$res['file_id'] = $this->base64url_encode($this->rle_encode((yield $this->serialize_object_async(['type' => 'File'], $data['document'], 'File')).\chr(2)));
|
||||||
|
|
||||||
return [$type_name => $res, 'caption' => isset($data['caption']) ? $data['caption'] : ''];
|
return [$type_name => $res, 'caption' => isset($data['caption']) ? $data['caption'] : ''];
|
||||||
default:
|
default:
|
||||||
throw new Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['botapi_conversion_error'], $data['_']));
|
throw new Exception(\sprintf(\danog\MadelineProto\Lang::$current_lang['botapi_conversion_error'], $data['_']));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,20 +487,20 @@ trait BotAPI
|
|||||||
$text = $this->html_entity_decode($node->textContent);
|
$text = $this->html_entity_decode($node->textContent);
|
||||||
$length = $this->mb_strlen($text);
|
$length = $this->mb_strlen($text);
|
||||||
$href = $node->getAttribute('href');
|
$href = $node->getAttribute('href');
|
||||||
if (preg_match('|mention:(.*)|', $href, $matches) || preg_match('|tg://user\?id=(.*)|', $href, $matches)) {
|
if (\preg_match('|mention:(.*)|', $href, $matches) || \preg_match('|tg://user\?id=(.*)|', $href, $matches)) {
|
||||||
$mention = yield $this->get_info_async($matches[1]);
|
$mention = yield $this->get_info_async($matches[1]);
|
||||||
if (!isset($mention['InputUser'])) {
|
if (!isset($mention['InputUser'])) {
|
||||||
throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['peer_not_in_db']);
|
throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['peer_not_in_db']);
|
||||||
}
|
}
|
||||||
$entities[] = ['_' => 'inputMessageEntityMentionName', 'offset' => $offset, 'length' => $length, 'user_id' => $mention['InputUser']];
|
$entities[] = ['_' => 'inputMessageEntityMentionName', 'offset' => $offset, 'length' => $length, 'user_id' => $mention['InputUser']];
|
||||||
} elseif (preg_match('|buttonurl:(.*)|', $href)) {
|
} elseif (\preg_match('|buttonurl:(.*)|', $href)) {
|
||||||
if (!isset($entities['buttons'])) {
|
if (!isset($entities['buttons'])) {
|
||||||
$entities['buttons'] = [];
|
$entities['buttons'] = [];
|
||||||
}
|
}
|
||||||
if (strpos(substr($href, -4), '|:new|') !== false) {
|
if (\strpos(\substr($href, -4), '|:new|') !== false) {
|
||||||
$entities['buttons'][] = ['_' => 'keyboardButtonUrl', 'text' => $text, 'url' => str_replace(['buttonurl:', ':new'], '', $href), 'new' => true];
|
$entities['buttons'][] = ['_' => 'keyboardButtonUrl', 'text' => $text, 'url' => \str_replace(['buttonurl:', ':new'], '', $href), 'new' => true];
|
||||||
} else {
|
} else {
|
||||||
$entities['buttons'][] = ['_' => 'keyboardButtonUrl', 'text' => $text, 'url' => str_replace('buttonurl:', '', $href)];
|
$entities['buttons'][] = ['_' => 'keyboardButtonUrl', 'text' => $text, 'url' => \str_replace('buttonurl:', '', $href)];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
@ -524,19 +524,19 @@ trait BotAPI
|
|||||||
return $arguments;
|
return $arguments;
|
||||||
}
|
}
|
||||||
if (isset($arguments['parse_mode']['_'])) {
|
if (isset($arguments['parse_mode']['_'])) {
|
||||||
$arguments['parse_mode'] = str_replace('textParseMode', '', $arguments['parse_mode']['_']);
|
$arguments['parse_mode'] = \str_replace('textParseMode', '', $arguments['parse_mode']['_']);
|
||||||
}
|
}
|
||||||
if (stripos($arguments['parse_mode'], 'markdown') !== false) {
|
if (\stripos($arguments['parse_mode'], 'markdown') !== false) {
|
||||||
$arguments['message'] = \Parsedown::instance()->line($arguments['message']);
|
$arguments['message'] = \Parsedown::instance()->line($arguments['message']);
|
||||||
$arguments['parse_mode'] = 'HTML';
|
$arguments['parse_mode'] = 'HTML';
|
||||||
}
|
}
|
||||||
if (stripos($arguments['parse_mode'], 'html') !== false) {
|
if (\stripos($arguments['parse_mode'], 'html') !== false) {
|
||||||
$new_message = '';
|
$new_message = '';
|
||||||
|
|
||||||
$arguments['message'] = trim($this->html_fixtags($arguments['message']));
|
$arguments['message'] = \trim($this->html_fixtags($arguments['message']));
|
||||||
|
|
||||||
$dom = new \DOMDocument();
|
$dom = new \DOMDocument();
|
||||||
$dom->loadHTML(mb_convert_encoding($arguments['message'], 'HTML-ENTITIES', 'UTF-8'));
|
$dom->loadHTML(\mb_convert_encoding($arguments['message'], 'HTML-ENTITIES', 'UTF-8'));
|
||||||
if (!isset($arguments['entities'])) {
|
if (!isset($arguments['entities'])) {
|
||||||
$arguments['entities'] = [];
|
$arguments['entities'] = [];
|
||||||
}
|
}
|
||||||
@ -568,7 +568,7 @@ trait BotAPI
|
|||||||
|
|
||||||
$text_arr = [];
|
$text_arr = [];
|
||||||
foreach ($this->multipleExplodeKeepDelimiters(["\n"], $args['message']) as $word) {
|
foreach ($this->multipleExplodeKeepDelimiters(["\n"], $args['message']) as $word) {
|
||||||
if (mb_strlen($word, 'UTF-8') > $max_length) {
|
if (\mb_strlen($word, 'UTF-8') > $max_length) {
|
||||||
foreach ($this->mb_str_split($word, $max_length) as $vv) {
|
foreach ($this->mb_str_split($word, $max_length) as $vv) {
|
||||||
$text_arr[] = $vv;
|
$text_arr[] = $vv;
|
||||||
}
|
}
|
||||||
@ -577,7 +577,7 @@ trait BotAPI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$multiple_args_base = array_merge($args, ['entities' => [], 'parse_mode' => 'text', 'message' => '']);
|
$multiple_args_base = \array_merge($args, ['entities' => [], 'parse_mode' => 'text', 'message' => '']);
|
||||||
$multiple_args = [$multiple_args_base];
|
$multiple_args = [$multiple_args_base];
|
||||||
$i = 0;
|
$i = 0;
|
||||||
foreach ($text_arr as $word) {
|
foreach ($text_arr as $word) {
|
||||||
@ -592,7 +592,7 @@ trait BotAPI
|
|||||||
|
|
||||||
$i = 0;
|
$i = 0;
|
||||||
$offset = 0;
|
$offset = 0;
|
||||||
for ($k = 0; $k < count($args['entities']); $k++) {
|
for ($k = 0; $k < \count($args['entities']); $k++) {
|
||||||
$entity = $args['entities'][$k];
|
$entity = $args['entities'][$k];
|
||||||
do {
|
do {
|
||||||
while ($entity['offset'] > $offset + $this->mb_strlen($multiple_args[$i]['message'])) {
|
while ($entity['offset'] > $offset + $this->mb_strlen($multiple_args[$i]['message'])) {
|
||||||
@ -610,7 +610,7 @@ trait BotAPI
|
|||||||
$newentity['offset'] = $offset;
|
$newentity['offset'] = $offset;
|
||||||
|
|
||||||
$prev_length = $this->mb_strlen($multiple_args[$i]['message']);
|
$prev_length = $this->mb_strlen($multiple_args[$i]['message']);
|
||||||
$multiple_args[$i]['message'] = rtrim($multiple_args[$i]['message']);
|
$multiple_args[$i]['message'] = \rtrim($multiple_args[$i]['message']);
|
||||||
$diff = $prev_length - $this->mb_strlen($multiple_args[$i]['message']);
|
$diff = $prev_length - $this->mb_strlen($multiple_args[$i]['message']);
|
||||||
|
|
||||||
if ($diff) {
|
if ($diff) {
|
||||||
@ -627,32 +627,31 @@ trait BotAPI
|
|||||||
$entity = $newentity;
|
$entity = $newentity;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
} else {
|
}
|
||||||
$prev_length = $this->mb_strlen($multiple_args[$i]['message']);
|
$prev_length = $this->mb_strlen($multiple_args[$i]['message']);
|
||||||
$multiple_args[$i]['message'] = rtrim($multiple_args[$i]['message']);
|
$multiple_args[$i]['message'] = \rtrim($multiple_args[$i]['message']);
|
||||||
$diff = $prev_length - $this->mb_strlen($multiple_args[$i]['message']);
|
$diff = $prev_length - $this->mb_strlen($multiple_args[$i]['message']);
|
||||||
if ($diff) {
|
if ($diff) {
|
||||||
$entity['length'] -= $diff;
|
$entity['length'] -= $diff;
|
||||||
foreach ($args['entities'] as $key => &$eentity) {
|
foreach ($args['entities'] as $key => &$eentity) {
|
||||||
if ($key > $k) {
|
if ($key > $k) {
|
||||||
$eentity['offset'] -= $diff;
|
$eentity['offset'] -= $diff;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$multiple_args[$i]['entities'][] = $entity;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
$multiple_args[$i]['entities'][] = $entity;
|
||||||
|
break;
|
||||||
} while (true);
|
} while (true);
|
||||||
}
|
}
|
||||||
$total = 0;
|
$total = 0;
|
||||||
foreach ($multiple_args as $args) {
|
foreach ($multiple_args as $args) {
|
||||||
if (count($args['entities']) > $max_entity_length) {
|
if (\count($args['entities']) > $max_entity_length) {
|
||||||
$total += count($args['entities']) - $max_entity_length;
|
$total += \count($args['entities']) - $max_entity_length;
|
||||||
}
|
}
|
||||||
$c = 0;
|
$c = 0;
|
||||||
foreach ($args['entities'] as $entity) {
|
foreach ($args['entities'] as $entity) {
|
||||||
if (isset($entity['url'])) {
|
if (isset($entity['url'])) {
|
||||||
$c += strlen($entity['url']);
|
$c += \strlen($entity['url']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($c >= $max_entity_size) {
|
if ($c >= $max_entity_size) {
|
||||||
@ -668,7 +667,7 @@ trait BotAPI
|
|||||||
|
|
||||||
public function multipleExplodeKeepDelimiters($delimiters, $string)
|
public function multipleExplodeKeepDelimiters($delimiters, $string)
|
||||||
{
|
{
|
||||||
$initialArray = explode(chr(1), str_replace($delimiters, chr(1), $string));
|
$initialArray = \explode(\chr(1), \str_replace($delimiters, \chr(1), $string));
|
||||||
$finalArray = [];
|
$finalArray = [];
|
||||||
$delimOffset = 0;
|
$delimOffset = 0;
|
||||||
foreach ($initialArray as $item) {
|
foreach ($initialArray as $item) {
|
||||||
@ -685,45 +684,44 @@ trait BotAPI
|
|||||||
public function html_fixtags($text)
|
public function html_fixtags($text)
|
||||||
{
|
{
|
||||||
$diff = 0;
|
$diff = 0;
|
||||||
preg_match_all('#(.*?)(<(\bu\b|\bs\b|\ba\b|\bb\b|\bstrong\b|\bblockquote\b|\bstrike\b|\bdel\b|\bem\b|i|\bcode\b|\bpre\b)[^>]*>)(.*?)([<]\s*/\s*\3[>])#is', $text, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
|
\preg_match_all('#(.*?)(<(\bu\b|\bs\b|\ba\b|\bb\b|\bstrong\b|\bblockquote\b|\bstrike\b|\bdel\b|\bem\b|i|\bcode\b|\bpre\b)[^>]*>)(.*?)([<]\s*/\s*\3[>])#is', $text, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
|
||||||
if ($matches) {
|
if ($matches) {
|
||||||
foreach ($matches as $match) {
|
foreach ($matches as $match) {
|
||||||
if (trim($match[1][0]) != '') {
|
if (\trim($match[1][0]) != '') {
|
||||||
$mod = htmlentities($match[1][0]);
|
$mod = \htmlentities($match[1][0]);
|
||||||
|
|
||||||
$temp = substr($text, 0, $match[1][1] + $diff);
|
$temp = \substr($text, 0, $match[1][1] + $diff);
|
||||||
$temp .= $mod;
|
$temp .= $mod;
|
||||||
$temp .= substr($text, $match[1][1] + $diff + strlen($match[1][0]));
|
$temp .= \substr($text, $match[1][1] + $diff + \strlen($match[1][0]));
|
||||||
|
|
||||||
$diff += strlen($mod) - strlen($match[1][0]);
|
$diff += \strlen($mod) - \strlen($match[1][0]);
|
||||||
|
|
||||||
$text = $temp;
|
$text = $temp;
|
||||||
}
|
}
|
||||||
$mod = htmlentities($match[4][0]);
|
$mod = \htmlentities($match[4][0]);
|
||||||
|
|
||||||
$temp = substr($text, 0, $match[4][1] + $diff);
|
$temp = \substr($text, 0, $match[4][1] + $diff);
|
||||||
$temp .= $mod;
|
$temp .= $mod;
|
||||||
$temp .= substr($text, $match[4][1] + $diff + strlen($match[4][0]));
|
$temp .= \substr($text, $match[4][1] + $diff + \strlen($match[4][0]));
|
||||||
|
|
||||||
$diff += strlen($mod) - strlen($match[4][0]);
|
$diff += \strlen($mod) - \strlen($match[4][0]);
|
||||||
$text = $temp;
|
$text = $temp;
|
||||||
}
|
}
|
||||||
$diff = 0;
|
$diff = 0;
|
||||||
preg_match_all('#<a\s*href=("|\')(.+?)("|\')\s*>#is', $text, $matches, PREG_OFFSET_CAPTURE);
|
\preg_match_all('#<a\s*href=("|\')(.+?)("|\')\s*>#is', $text, $matches, PREG_OFFSET_CAPTURE);
|
||||||
foreach ($matches[2] as $match) {
|
foreach ($matches[2] as $match) {
|
||||||
$mod = htmlentities($match[0]);
|
$mod = \htmlentities($match[0]);
|
||||||
$temp = substr($text, 0, $match[1] + $diff);
|
$temp = \substr($text, 0, $match[1] + $diff);
|
||||||
$temp .= $mod;
|
$temp .= $mod;
|
||||||
$temp .= substr($text, $match[1] + $diff + strlen($match[0]));
|
$temp .= \substr($text, $match[1] + $diff + \strlen($match[0]));
|
||||||
|
|
||||||
$diff += strlen($mod) - strlen($match[0]);
|
$diff += \strlen($mod) - \strlen($match[0]);
|
||||||
$text = $temp;
|
$text = $temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $text;
|
return $text;
|
||||||
} else {
|
|
||||||
return htmlentities($text);
|
|
||||||
}
|
}
|
||||||
|
return \htmlentities($text);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function build_rows($button_list)
|
public function build_rows($button_list)
|
||||||
@ -734,7 +732,7 @@ trait BotAPI
|
|||||||
$cols = 0;
|
$cols = 0;
|
||||||
foreach ($button_list as $button) {
|
foreach ($button_list as $button) {
|
||||||
if (isset($button['new'])) {
|
if (isset($button['new'])) {
|
||||||
if (count($buttons) == 0) {
|
if (\count($buttons) == 0) {
|
||||||
$buttons[] = $button;
|
$buttons[] = $button;
|
||||||
} else {
|
} else {
|
||||||
$row = ['_' => 'keyboardButtonRow', 'buttons' => $buttons];
|
$row = ['_' => 'keyboardButtonRow', 'buttons' => $buttons];
|
||||||
|
@ -23,22 +23,22 @@ trait BotAPIFiles
|
|||||||
{
|
{
|
||||||
public function base64url_decode($data)
|
public function base64url_decode($data)
|
||||||
{
|
{
|
||||||
return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT));
|
return \base64_decode(\str_pad(\strtr($data, '-_', '+/'), \strlen($data) % 4, '=', STR_PAD_RIGHT));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function base64url_encode($data)
|
public function base64url_encode($data)
|
||||||
{
|
{
|
||||||
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
|
return \rtrim(\strtr(\base64_encode($data), '+/', '-_'), '=');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rle_decode($string)
|
public function rle_decode($string)
|
||||||
{
|
{
|
||||||
$new = '';
|
$new = '';
|
||||||
$last = '';
|
$last = '';
|
||||||
$null = chr(0);
|
$null = \chr(0);
|
||||||
foreach (str_split($string) as $cur) {
|
foreach (\str_split($string) as $cur) {
|
||||||
if ($last === $null) {
|
if ($last === $null) {
|
||||||
$new .= str_repeat($last, ord($cur));
|
$new .= \str_repeat($last, \ord($cur));
|
||||||
$last = '';
|
$last = '';
|
||||||
} else {
|
} else {
|
||||||
$new .= $last;
|
$new .= $last;
|
||||||
@ -54,13 +54,13 @@ trait BotAPIFiles
|
|||||||
{
|
{
|
||||||
$new = '';
|
$new = '';
|
||||||
$count = 0;
|
$count = 0;
|
||||||
$null = chr(0);
|
$null = \chr(0);
|
||||||
foreach (str_split($string) as $cur) {
|
foreach (\str_split($string) as $cur) {
|
||||||
if ($cur === $null) {
|
if ($cur === $null) {
|
||||||
$count++;
|
$count++;
|
||||||
} else {
|
} else {
|
||||||
if ($count > 0) {
|
if ($count > 0) {
|
||||||
$new .= $null.chr($count);
|
$new .= $null.\chr($count);
|
||||||
$count = 0;
|
$count = 0;
|
||||||
}
|
}
|
||||||
$new .= $cur;
|
$new .= $cur;
|
||||||
@ -78,14 +78,14 @@ trait BotAPIFiles
|
|||||||
$photoSize['location']['secret'] = $photo['location']['secret'] ?? 0;
|
$photoSize['location']['secret'] = $photo['location']['secret'] ?? 0;
|
||||||
$photoSize['location']['dc_id'] = $photo['dc_id'] ?? 0;
|
$photoSize['location']['dc_id'] = $photo['dc_id'] ?? 0;
|
||||||
$photoSize['location']['_'] = $thumbnail ? 'bot_thumbnail' : 'bot_photo';
|
$photoSize['location']['_'] = $thumbnail ? 'bot_thumbnail' : 'bot_photo';
|
||||||
$data = (yield $this->serialize_object_async(['type' => 'File'], $photoSize['location'], 'File')).chr(2);
|
$data = (yield $this->serialize_object_async(['type' => 'File'], $photoSize['location'], 'File')).\chr(2);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'file_id' => $this->base64url_encode($this->rle_encode($data)),
|
'file_id' => $this->base64url_encode($this->rle_encode($data)),
|
||||||
'width' => $photoSize['w'],
|
'width' => $photoSize['w'],
|
||||||
'height' => $photoSize['h'],
|
'height' => $photoSize['h'],
|
||||||
'file_size' => isset($photoSize['size']) ? $photoSize['size'] : strlen($photoSize['bytes']),
|
'file_size' => isset($photoSize['size']) ? $photoSize['size'] : \strlen($photoSize['bytes']),
|
||||||
'mime_type' => 'image/jpeg',
|
'mime_type' => 'image/jpeg',
|
||||||
'file_name' => $photoSize['location']['volume_id'].'_'.$photoSize['location']['local_id'].$ext
|
'file_name' => $photoSize['location']['volume_id'].'_'.$photoSize['location']['local_id'].$ext
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -93,20 +93,20 @@ trait BotAPIFiles
|
|||||||
public function unpack_file_id($file_id)
|
public function unpack_file_id($file_id)
|
||||||
{
|
{
|
||||||
$file_id = $this->rle_decode($this->base64url_decode($file_id));
|
$file_id = $this->rle_decode($this->base64url_decode($file_id));
|
||||||
if ($file_id[strlen($file_id) - 1] !== chr(2)) {
|
if ($file_id[\strlen($file_id) - 1] !== \chr(2)) {
|
||||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['last_byte_invalid']);
|
throw new Exception(\danog\MadelineProto\Lang::$current_lang['last_byte_invalid']);
|
||||||
}
|
}
|
||||||
$deserialized = $this->deserialize($file_id);
|
$deserialized = $this->deserialize($file_id);
|
||||||
$res = ['type' => str_replace('bot_', '', $deserialized['_'])];
|
$res = ['type' => \str_replace('bot_', '', $deserialized['_'])];
|
||||||
switch ($deserialized['_']) {
|
switch ($deserialized['_']) {
|
||||||
case 'bot_thumbnail':
|
case 'bot_thumbnail':
|
||||||
case 'bot_photo':
|
case 'bot_photo':
|
||||||
$constructor = ['_' => 'photo', 'sizes' => [], 'dc_id' => $deserialized['dc_id']];
|
$constructor = ['_' => 'photo', 'sizes' => [], 'dc_id' => $deserialized['dc_id']];
|
||||||
$constructor['id'] = $deserialized['id'];
|
$constructor['id'] = $deserialized['id'];
|
||||||
$constructor['access_hash'] = $deserialized['access_hash'];
|
$constructor['access_hash'] = $deserialized['access_hash'];
|
||||||
unset($deserialized['id']);
|
unset($deserialized['id'], $deserialized['access_hash'], $deserialized['_']);
|
||||||
unset($deserialized['access_hash']);
|
|
||||||
unset($deserialized['_']);
|
|
||||||
$deserialized['_'] = 'fileLocation';
|
$deserialized['_'] = 'fileLocation';
|
||||||
$constructor['sizes'][0] = ['_' => 'photoSize', 'location' => $deserialized];
|
$constructor['sizes'][0] = ['_' => 'photoSize', 'location' => $deserialized];
|
||||||
$res['MessageMedia'] = ['_' => 'messageMediaPhoto', 'photo' => $constructor, 'caption' => ''];
|
$res['MessageMedia'] = ['_' => 'messageMediaPhoto', 'photo' => $constructor, 'caption' => ''];
|
||||||
@ -114,48 +114,48 @@ trait BotAPIFiles
|
|||||||
return $res;
|
return $res;
|
||||||
case 'bot_voice':
|
case 'bot_voice':
|
||||||
unset($deserialized['_']);
|
unset($deserialized['_']);
|
||||||
$constructor = array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => true]]]);
|
$constructor = \array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => true]]]);
|
||||||
$res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => ''];
|
$res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => ''];
|
||||||
|
|
||||||
return $res;
|
return $res;
|
||||||
case 'bot_video':
|
case 'bot_video':
|
||||||
unset($deserialized['_']);
|
unset($deserialized['_']);
|
||||||
$constructor = array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeVideo', 'round_message' => false]]]);
|
$constructor = \array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeVideo', 'round_message' => false]]]);
|
||||||
$res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => ''];
|
$res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => ''];
|
||||||
|
|
||||||
return $res;
|
return $res;
|
||||||
case 'bot_video_note':
|
case 'bot_video_note':
|
||||||
unset($deserialized['_']);
|
unset($deserialized['_']);
|
||||||
$constructor = array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeVideo', 'round_message' => true]]]);
|
$constructor = \array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeVideo', 'round_message' => true]]]);
|
||||||
$res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => ''];
|
$res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => ''];
|
||||||
|
|
||||||
return $res;
|
return $res;
|
||||||
case 'bot_document':
|
case 'bot_document':
|
||||||
unset($deserialized['_']);
|
unset($deserialized['_']);
|
||||||
$constructor = array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => []]);
|
$constructor = \array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => []]);
|
||||||
$res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => ''];
|
$res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => ''];
|
||||||
|
|
||||||
return $res;
|
return $res;
|
||||||
case 'bot_sticker':
|
case 'bot_sticker':
|
||||||
unset($deserialized['_']);
|
unset($deserialized['_']);
|
||||||
$constructor = array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeSticker']]]);
|
$constructor = \array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeSticker']]]);
|
||||||
$res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => ''];
|
$res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => ''];
|
||||||
|
|
||||||
return $res;
|
return $res;
|
||||||
case 'bot_gif':
|
case 'bot_gif':
|
||||||
unset($deserialized['_']);
|
unset($deserialized['_']);
|
||||||
$constructor = array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeAnimated']]]);
|
$constructor = \array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeAnimated']]]);
|
||||||
$res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => ''];
|
$res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => ''];
|
||||||
|
|
||||||
return $res;
|
return $res;
|
||||||
case 'bot_audio':
|
case 'bot_audio':
|
||||||
unset($deserialized['_']);
|
unset($deserialized['_']);
|
||||||
$constructor = array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => false]]]);
|
$constructor = \array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => false]]]);
|
||||||
$res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => ''];
|
$res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => ''];
|
||||||
|
|
||||||
return $res;
|
return $res;
|
||||||
default:
|
default:
|
||||||
throw new Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['file_type_invalid'], $type));
|
throw new Exception(\sprintf(\danog\MadelineProto\Lang::$current_lang['file_type_invalid'], $type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,9 +25,9 @@ class Exception extends \Exception
|
|||||||
|
|
||||||
public function __toString()
|
public function __toString()
|
||||||
{
|
{
|
||||||
$result = get_class($this).($this->message !== '' ? ': ' : '').$this->message.PHP_EOL.\danog\MadelineProto\Magic::$revision.PHP_EOL.'TL Trace (YOU ABSOLUTELY MUST READ THE TEXT BELOW):'.PHP_EOL.PHP_EOL.$this->getTLTrace().PHP_EOL;
|
$result = \get_class($this).($this->message !== '' ? ': ' : '').$this->message.PHP_EOL.\danog\MadelineProto\Magic::$revision.PHP_EOL.'TL Trace (YOU ABSOLUTELY MUST READ THE TEXT BELOW):'.PHP_EOL.PHP_EOL.$this->getTLTrace().PHP_EOL;
|
||||||
if (php_sapi_name() !== 'cli') {
|
if (PHP_SAPI !== 'cli') {
|
||||||
$result = str_replace(PHP_EOL, '<br>'.PHP_EOL, $result);
|
$result = \str_replace(PHP_EOL, '<br>'.PHP_EOL, $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
|
@ -21,7 +21,7 @@ trait Extension
|
|||||||
{
|
{
|
||||||
public function get_mime_from_extension($extension, $default)
|
public function get_mime_from_extension($extension, $default)
|
||||||
{
|
{
|
||||||
$ext = ltrim($extension, '.');
|
$ext = \ltrim($extension, '.');
|
||||||
if (isset(self::ALL_MIMES[$ext])) {
|
if (isset(self::ALL_MIMES[$ext])) {
|
||||||
return self::ALL_MIMES[$ext][0];
|
return self::ALL_MIMES[$ext][0];
|
||||||
}
|
}
|
||||||
@ -32,7 +32,7 @@ trait Extension
|
|||||||
public function get_extension_from_mime($mime)
|
public function get_extension_from_mime($mime)
|
||||||
{
|
{
|
||||||
foreach (self::ALL_MIMES as $key => $value) {
|
foreach (self::ALL_MIMES as $key => $value) {
|
||||||
if (array_search($mime, $value) !== false) {
|
if (\array_search($mime, $value) !== false) {
|
||||||
return '.'.$key;
|
return '.'.$key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,22 +23,22 @@ trait TD
|
|||||||
{
|
{
|
||||||
public function tdcli_to_td(&$params, $key = null)
|
public function tdcli_to_td(&$params, $key = null)
|
||||||
{
|
{
|
||||||
if (!is_array($params)) {
|
if (!\is_array($params)) {
|
||||||
return $params;
|
return $params;
|
||||||
}
|
}
|
||||||
if (!isset($params['ID'])) {
|
if (!isset($params['ID'])) {
|
||||||
array_walk($params, [$this, 'tdcli_to_td']);
|
\array_walk($params, [$this, 'tdcli_to_td']);
|
||||||
|
|
||||||
return $params;
|
return $params;
|
||||||
}
|
}
|
||||||
foreach ($params as $key => $value) {
|
foreach ($params as $key => $value) {
|
||||||
$value = $this->tdcli_to_td($value);
|
$value = $this->tdcli_to_td($value);
|
||||||
if (preg_match('/_$/', $key)) {
|
if (\preg_match('/_$/', $key)) {
|
||||||
$params[preg_replace('/_$/', '', $key)] = $value;
|
$params[\preg_replace('/_$/', '', $key)] = $value;
|
||||||
unset($params[$key]);
|
unset($params[$key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$params['_'] = lcfirst($params['ID']);
|
$params['_'] = \lcfirst($params['ID']);
|
||||||
unset($params['ID']);
|
unset($params['ID']);
|
||||||
|
|
||||||
return $params;
|
return $params;
|
||||||
@ -48,8 +48,8 @@ trait TD
|
|||||||
{
|
{
|
||||||
$newparams = ['_' => self::REVERSE[$params['_']]];
|
$newparams = ['_' => self::REVERSE[$params['_']]];
|
||||||
foreach (self::TD_PARAMS_CONVERSION[$newparams['_']] as $td => $mtproto) {
|
foreach (self::TD_PARAMS_CONVERSION[$newparams['_']] as $td => $mtproto) {
|
||||||
if (is_array($mtproto)) {
|
if (\is_array($mtproto)) {
|
||||||
switch (end($mtproto)) {
|
switch (\end($mtproto)) {
|
||||||
case 'choose_message_content':
|
case 'choose_message_content':
|
||||||
switch ($params[$td]['_']) {
|
switch ($params[$td]['_']) {
|
||||||
case 'inputMessageText':
|
case 'inputMessageText':
|
||||||
@ -57,7 +57,7 @@ trait TD
|
|||||||
if (isset($params['disable_web_page_preview'])) {
|
if (isset($params['disable_web_page_preview'])) {
|
||||||
$newparams['no_webpage'] = $params[$td]['disable_web_page_preview'];
|
$newparams['no_webpage'] = $params[$td]['disable_web_page_preview'];
|
||||||
}
|
}
|
||||||
$newparams = array_merge($params[$td], $newparams);
|
$newparams = \array_merge($params[$td], $newparams);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['non_text_conversion']);
|
throw new Exception(\danog\MadelineProto\Lang::$current_lang['non_text_conversion']);
|
||||||
@ -65,7 +65,7 @@ trait TD
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$newparams[$mtproto[0]] = isset($params[$td]) ? $params[$td] : null;
|
$newparams[$mtproto[0]] = isset($params[$td]) ? $params[$td] : null;
|
||||||
if (is_array($newparams[$mtproto[0]])) {
|
if (\is_array($newparams[$mtproto[0]])) {
|
||||||
$newparams[$mtproto[0]] = yield $this->mtproto_to_td_async($newparams[$mtproto[0]]);
|
$newparams[$mtproto[0]] = yield $this->mtproto_to_td_async($newparams[$mtproto[0]]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,23 +82,23 @@ trait TD
|
|||||||
|
|
||||||
public function mtproto_to_td_async(&$params)
|
public function mtproto_to_td_async(&$params)
|
||||||
{
|
{
|
||||||
if (!is_array($params)) {
|
if (!\is_array($params)) {
|
||||||
return $params;
|
return $params;
|
||||||
}
|
}
|
||||||
if (!isset($params['_'])) {
|
if (!isset($params['_'])) {
|
||||||
array_walk($params, [$this, 'mtproto_to_td']);
|
\array_walk($params, [$this, 'mtproto_to_td']);
|
||||||
|
|
||||||
return $params;
|
return $params;
|
||||||
}
|
}
|
||||||
$newparams = ['_' => $params['_']];
|
$newparams = ['_' => $params['_']];
|
||||||
if (in_array($params['_'], self::TD_IGNORE)) {
|
if (\in_array($params['_'], self::TD_IGNORE)) {
|
||||||
return $params;
|
return $params;
|
||||||
}
|
}
|
||||||
foreach (self::TD_PARAMS_CONVERSION[$params['_']] as $td => $mtproto) {
|
foreach (self::TD_PARAMS_CONVERSION[$params['_']] as $td => $mtproto) {
|
||||||
if (is_string($mtproto)) {
|
if (\is_string($mtproto)) {
|
||||||
$newparams[$td] = $mtproto;
|
$newparams[$td] = $mtproto;
|
||||||
} else {
|
} else {
|
||||||
switch (end($mtproto)) {
|
switch (\end($mtproto)) {
|
||||||
case 'choose_chat_id_from_botapi':
|
case 'choose_chat_id_from_botapi':
|
||||||
$newparams[$td] = (yield $this->get_info_async($params[$mtproto[0]]))['bot_api_id'] == $this->authorization['user']['id'] ? $params['from_id'] : yield $this->get_info_async($params[$mtproto[0]])['bot_api_id'];
|
$newparams[$td] = (yield $this->get_info_async($params[$mtproto[0]]))['bot_api_id'] == $this->authorization['user']['id'] ? $params['from_id'] : yield $this->get_info_async($params[$mtproto[0]])['bot_api_id'];
|
||||||
break;
|
break;
|
||||||
@ -132,7 +132,7 @@ trait TD
|
|||||||
$newparams[$td] = isset($params['ttl']) ? $params['ttl'] : 0;
|
$newparams[$td] = isset($params['ttl']) ? $params['ttl'] : 0;
|
||||||
break;
|
break;
|
||||||
case 'choose_ttl_expires_in':
|
case 'choose_ttl_expires_in':
|
||||||
$newparams[$td] = $newparams['ttl'] - microtime(true);
|
$newparams[$td] = $newparams['ttl'] - \microtime(true);
|
||||||
break;
|
break;
|
||||||
case 'choose_message_content':
|
case 'choose_message_content':
|
||||||
if ($params['message'] !== '') {
|
if ($params['message'] !== '') {
|
||||||
@ -153,7 +153,7 @@ trait TD
|
|||||||
} else {
|
} else {
|
||||||
$newparams[$td] = isset($params[$mtproto[0]]) ? $params[$mtproto[0]] : null;
|
$newparams[$td] = isset($params[$mtproto[0]]) ? $params[$mtproto[0]] : null;
|
||||||
}
|
}
|
||||||
if (is_array($newparams[$td])) {
|
if (\is_array($newparams[$td])) {
|
||||||
$newparams[$td] = yield $this->mtproto_to_td_async($newparams[$td]);
|
$newparams[$td] = yield $this->mtproto_to_td_async($newparams[$td]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -165,15 +165,15 @@ trait TD
|
|||||||
|
|
||||||
public function td_to_tdcli($params)
|
public function td_to_tdcli($params)
|
||||||
{
|
{
|
||||||
if (!is_array($params)) {
|
if (!\is_array($params)) {
|
||||||
return $params;
|
return $params;
|
||||||
}
|
}
|
||||||
$newparams = [];
|
$newparams = [];
|
||||||
foreach ($params as $key => $value) {
|
foreach ($params as $key => $value) {
|
||||||
if ($key === '_') {
|
if ($key === '_') {
|
||||||
$newparams['ID'] = ucfirst($value);
|
$newparams['ID'] = \ucfirst($value);
|
||||||
} else {
|
} else {
|
||||||
if (!is_numeric($key) && !preg_match('/_^/', $key)) {
|
if (!\is_numeric($key) && !\preg_match('/_^/', $key)) {
|
||||||
$key = $key.'_';
|
$key = $key.'_';
|
||||||
}
|
}
|
||||||
$newparams[$key] = $this->td_to_tdcli($value);
|
$newparams[$key] = $this->td_to_tdcli($value);
|
||||||
|
@ -25,9 +25,9 @@ class Exception extends \Exception
|
|||||||
|
|
||||||
public function __toString()
|
public function __toString()
|
||||||
{
|
{
|
||||||
$result = get_class($this).($this->message !== '' ? ': ' : '').$this->message.PHP_EOL.\danog\MadelineProto\Magic::$revision.PHP_EOL.'TL Trace (YOU ABSOLUTELY MUST READ THE TEXT BELOW):'.PHP_EOL.PHP_EOL.$this->getTLTrace().PHP_EOL;
|
$result = \get_class($this).($this->message !== '' ? ': ' : '').$this->message.PHP_EOL.\danog\MadelineProto\Magic::$revision.PHP_EOL.'TL Trace (YOU ABSOLUTELY MUST READ THE TEXT BELOW):'.PHP_EOL.PHP_EOL.$this->getTLTrace().PHP_EOL;
|
||||||
if (php_sapi_name() !== 'cli') {
|
if (PHP_SAPI !== 'cli') {
|
||||||
$result = str_replace(PHP_EOL, '<br>'.PHP_EOL, $result);
|
$result = \str_replace(PHP_EOL, '<br>'.PHP_EOL, $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
|
@ -31,12 +31,12 @@ trait PrettyException
|
|||||||
public function prettify_tl($init = '')
|
public function prettify_tl($init = '')
|
||||||
{
|
{
|
||||||
$eol = PHP_EOL;
|
$eol = PHP_EOL;
|
||||||
if (php_sapi_name() !== 'cli') {
|
if (PHP_SAPI !== 'cli') {
|
||||||
$eol = '<br>'.PHP_EOL;
|
$eol = '<br>'.PHP_EOL;
|
||||||
}
|
}
|
||||||
$tl = false;
|
$tl = false;
|
||||||
foreach (array_reverse($this->getTrace()) as $k => $frame) {
|
foreach (\array_reverse($this->getTrace()) as $k => $frame) {
|
||||||
if (isset($frame['function']) && in_array($frame['function'], ['serialize_params', 'serialize_object'])) {
|
if (isset($frame['function']) && \in_array($frame['function'], ['serialize_params', 'serialize_object'])) {
|
||||||
if ($frame['args'][2] !== '') {
|
if ($frame['args'][2] !== '') {
|
||||||
$this->tl_trace .= $tl ? "['".$frame['args'][2]."']" : "While serializing: \t".$frame['args'][2];
|
$this->tl_trace .= $tl ? "['".$frame['args'][2]."']" : "While serializing: \t".$frame['args'][2];
|
||||||
$tl = true;
|
$tl = true;
|
||||||
@ -45,18 +45,18 @@ trait PrettyException
|
|||||||
if ($tl) {
|
if ($tl) {
|
||||||
$this->tl_trace .= $eol;
|
$this->tl_trace .= $eol;
|
||||||
}
|
}
|
||||||
if (isset($frame['function']) && ($frame['function'] === 'handle_rpc_error' && $k === count($this->getTrace()) - 1) || $frame['function'] === 'unserialize') {
|
if (isset($frame['function']) && ($frame['function'] === 'handle_rpc_error' && $k === \count($this->getTrace()) - 1) || $frame['function'] === 'unserialize') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$this->tl_trace .= isset($frame['file']) ? str_pad(basename($frame['file']).'('.$frame['line'].'):', 20)."\t" : '';
|
$this->tl_trace .= isset($frame['file']) ? \str_pad(\basename($frame['file']).'('.$frame['line'].'):', 20)."\t" : '';
|
||||||
$this->tl_trace .= isset($frame['function']) ? $frame['function'].'(' : '';
|
$this->tl_trace .= isset($frame['function']) ? $frame['function'].'(' : '';
|
||||||
$this->tl_trace .= isset($frame['args']) ? substr(json_encode($frame['args']), 1, -1) : '';
|
$this->tl_trace .= isset($frame['args']) ? \substr(\json_encode($frame['args']), 1, -1) : '';
|
||||||
$this->tl_trace .= ')';
|
$this->tl_trace .= ')';
|
||||||
$this->tl_trace .= $eol;
|
$this->tl_trace .= $eol;
|
||||||
$tl = false;
|
$tl = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->tl_trace .= $init !== '' ? "['".$init."']" : '';
|
$this->tl_trace .= $init !== '' ? "['".$init."']" : '';
|
||||||
$this->tl_trace = implode($eol, array_reverse(explode($eol, $this->tl_trace)));
|
$this->tl_trace = \implode($eol, \array_reverse(\explode($eol, $this->tl_trace)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,34 +39,34 @@ trait TL
|
|||||||
$this->td_methods = new TLMethod();
|
$this->td_methods = new TLMethod();
|
||||||
$this->td_descriptions = ['types' => [], 'constructors' => [], 'methods' => []];
|
$this->td_descriptions = ['types' => [], 'constructors' => [], 'methods' => []];
|
||||||
foreach ($files as $scheme_type => $file) {
|
foreach ($files as $scheme_type => $file) {
|
||||||
$this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['file_parsing'], basename($file)), \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['file_parsing'], \basename($file)), \danog\MadelineProto\Logger::VERBOSE);
|
||||||
$filec = file_get_contents(\danog\MadelineProto\Absolute::absolute($file));
|
$filec = \file_get_contents(\danog\MadelineProto\Absolute::absolute($file));
|
||||||
$TL_dict = json_decode($filec, true);
|
$TL_dict = \json_decode($filec, true);
|
||||||
if ($TL_dict === null) {
|
if ($TL_dict === null) {
|
||||||
$TL_dict = ['methods' => [], 'constructors' => []];
|
$TL_dict = ['methods' => [], 'constructors' => []];
|
||||||
$type = 'constructors';
|
$type = 'constructors';
|
||||||
$layer = null;
|
$layer = null;
|
||||||
$tl_file = explode("\n", $filec);
|
$tl_file = \explode("\n", $filec);
|
||||||
$key = 0;
|
$key = 0;
|
||||||
$e = null;
|
$e = null;
|
||||||
$class = null;
|
$class = null;
|
||||||
$dparams = [];
|
$dparams = [];
|
||||||
foreach ($tl_file as $line_number => $line) {
|
foreach ($tl_file as $line_number => $line) {
|
||||||
$line = rtrim($line);
|
$line = \rtrim($line);
|
||||||
if (preg_match('|^//@|', $line)) {
|
if (\preg_match('|^//@|', $line)) {
|
||||||
$list = explode(' @', str_replace('//', ' ', $line));
|
$list = \explode(' @', \str_replace('//', ' ', $line));
|
||||||
foreach ($list as $elem) {
|
foreach ($list as $elem) {
|
||||||
if ($elem === '') {
|
if ($elem === '') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$elem = explode(' ', $elem, 2);
|
$elem = \explode(' ', $elem, 2);
|
||||||
if ($elem[0] === 'class') {
|
if ($elem[0] === 'class') {
|
||||||
$elem = explode(' ', $elem[1], 2);
|
$elem = \explode(' ', $elem[1], 2);
|
||||||
$class = $elem[0];
|
$class = $elem[0];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($elem[0] === 'description') {
|
if ($elem[0] === 'description') {
|
||||||
if (!is_null($class)) {
|
if (!\is_null($class)) {
|
||||||
$this->td_descriptions['types'][$class] = $elem[1];
|
$this->td_descriptions['types'][$class] = $elem[1];
|
||||||
$class = null;
|
$class = null;
|
||||||
} else {
|
} else {
|
||||||
@ -81,7 +81,7 @@ trait TL
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$line = preg_replace(['|//.*|', '|^\\s+$|'], '', $line);
|
$line = \preg_replace(['|//.*|', '|^\\s+$|'], '', $line);
|
||||||
if ($line === '') {
|
if ($line === '') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -93,43 +93,43 @@ trait TL
|
|||||||
$type = 'constructors';
|
$type = 'constructors';
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (preg_match('|^===(\d*)===|', $line, $matches)) {
|
if (\preg_match('|^===(\d*)===|', $line, $matches)) {
|
||||||
$layer = (int) $matches[1];
|
$layer = (int) $matches[1];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (strpos($line, 'vector#') === 0) {
|
if (\strpos($line, 'vector#') === 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (strpos($line, ' ?= ') !== false) {
|
if (\strpos($line, ' ?= ') !== false) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$name = preg_replace(['/#.*/', '/\\s.*/'], '', $line);
|
$name = \preg_replace(['/#.*/', '/\\s.*/'], '', $line);
|
||||||
if (in_array($name, ['bytes', 'int128', 'int256', 'int512'])) {
|
if (\in_array($name, ['bytes', 'int128', 'int256', 'int512'])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$clean = preg_replace(['/:bytes /', '/;/', '/#[a-f0-9]+ /', '/ [a-zA-Z0-9_]+\\:flags\\.[0-9]+\\?true/', '/[<]/', '/[>]/', '/ /', '/^ /', '/ $/', '/\\?bytes /', '/{/', '/}/'], [':string ', '', ' ', '', ' ', ' ', ' ', '', '', '?string ', '', ''], $line);
|
$clean = \preg_replace(['/:bytes /', '/;/', '/#[a-f0-9]+ /', '/ [a-zA-Z0-9_]+\\:flags\\.[0-9]+\\?true/', '/[<]/', '/[>]/', '/ /', '/^ /', '/ $/', '/\\?bytes /', '/{/', '/}/'], [':string ', '', ' ', '', ' ', ' ', ' ', '', '', '?string ', '', ''], $line);
|
||||||
$id = hash('crc32b', $clean);
|
$id = \hash('crc32b', $clean);
|
||||||
if (preg_match('/^[^\s]+#([a-f0-9]*)/i', $line, $matches)) {
|
if (\preg_match('/^[^\s]+#([a-f0-9]*)/i', $line, $matches)) {
|
||||||
$nid = str_pad($matches[1], 8, '0', \STR_PAD_LEFT);
|
$nid = \str_pad($matches[1], 8, '0', \STR_PAD_LEFT);
|
||||||
if ($id !== $nid && $scheme_type !== 'botAPI') {
|
if ($id !== $nid && $scheme_type !== 'botAPI') {
|
||||||
$this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['crc32_mismatch'], $id, $nid, $line), \danog\MadelineProto\Logger::ERROR);
|
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['crc32_mismatch'], $id, $nid, $line), \danog\MadelineProto\Logger::ERROR);
|
||||||
}
|
}
|
||||||
$id = $nid;
|
$id = $nid;
|
||||||
}
|
}
|
||||||
if (!is_null($e)) {
|
if (!\is_null($e)) {
|
||||||
$this->td_descriptions[$type][$name] = ['description' => $e, 'params' => $dparams];
|
$this->td_descriptions[$type][$name] = ['description' => $e, 'params' => $dparams];
|
||||||
$e = null;
|
$e = null;
|
||||||
$dparams = [];
|
$dparams = [];
|
||||||
}
|
}
|
||||||
$TL_dict[$type][$key][$type === 'constructors' ? 'predicate' : 'method'] = $name;
|
$TL_dict[$type][$key][$type === 'constructors' ? 'predicate' : 'method'] = $name;
|
||||||
$TL_dict[$type][$key]['id'] = strrev(hex2bin($id));
|
$TL_dict[$type][$key]['id'] = \strrev(\hex2bin($id));
|
||||||
$TL_dict[$type][$key]['params'] = [];
|
$TL_dict[$type][$key]['params'] = [];
|
||||||
$TL_dict[$type][$key]['type'] = preg_replace(['/.+\\s+=\\s+/', '/;/'], '', $line);
|
$TL_dict[$type][$key]['type'] = \preg_replace(['/.+\\s+=\\s+/', '/;/'], '', $line);
|
||||||
if ($layer !== null) {
|
if ($layer !== null) {
|
||||||
$TL_dict[$type][$key]['layer'] = $layer;
|
$TL_dict[$type][$key]['layer'] = $layer;
|
||||||
}
|
}
|
||||||
if ($name !== 'vector' && $TL_dict[$type][$key]['type'] !== 'Vector t') {
|
if ($name !== 'vector' && $TL_dict[$type][$key]['type'] !== 'Vector t') {
|
||||||
foreach (explode(' ', preg_replace(['/^[^\\s]+\\s/', '/=\\s[^\\s]+/', '/\\s$/'], '', $line)) as $param) {
|
foreach (\explode(' ', \preg_replace(['/^[^\\s]+\\s/', '/=\\s[^\\s]+/', '/\\s$/'], '', $line)) as $param) {
|
||||||
if ($param === '') {
|
if ($param === '') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -139,7 +139,7 @@ trait TL
|
|||||||
if ($param === '#') {
|
if ($param === '#') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$explode = explode(':', $param);
|
$explode = \explode(':', $param);
|
||||||
$TL_dict[$type][$key]['params'][] = ['name' => $explode[0], 'type' => $explode[1]];
|
$TL_dict[$type][$key]['params'][] = ['name' => $explode[0], 'type' => $explode[1]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -161,7 +161,7 @@ trait TL
|
|||||||
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['translating_obj'], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['translating_obj'], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||||
foreach ($TL_dict['constructors'] as $elem) {
|
foreach ($TL_dict['constructors'] as $elem) {
|
||||||
if ($scheme_type === 'secret') {
|
if ($scheme_type === 'secret') {
|
||||||
$this->encrypted_layer = max($this->encrypted_layer, $elem['layer']);
|
$this->encrypted_layer = \max($this->encrypted_layer, $elem['layer']);
|
||||||
}
|
}
|
||||||
$this->{($scheme_type === 'td' ? 'td_' : '').'constructors'}->add($elem, $scheme_type);
|
$this->{($scheme_type === 'td' ? 'td_' : '').'constructors'}->add($elem, $scheme_type);
|
||||||
}
|
}
|
||||||
@ -169,7 +169,7 @@ trait TL
|
|||||||
foreach ($TL_dict['methods'] as $elem) {
|
foreach ($TL_dict['methods'] as $elem) {
|
||||||
$this->{($scheme_type === 'td' ? 'td_' : '').'methods'}->add($elem);
|
$this->{($scheme_type === 'td' ? 'td_' : '').'methods'}->add($elem);
|
||||||
if ($scheme_type === 'secret') {
|
if ($scheme_type === 'secret') {
|
||||||
$this->encrypted_layer = max($this->encrypted_layer, $elem['layer']);
|
$this->encrypted_layer = \max($this->encrypted_layer, $elem['layer']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -179,11 +179,11 @@ trait TL
|
|||||||
if ($this->constructors->find_by_id($id) === false) {
|
if ($this->constructors->find_by_id($id) === false) {
|
||||||
unset($this->td_descriptions['constructors'][$name]);
|
unset($this->td_descriptions['constructors'][$name]);
|
||||||
} else {
|
} else {
|
||||||
if (!count($this->td_descriptions['constructors'][$name]['params'])) {
|
if (!\count($this->td_descriptions['constructors'][$name]['params'])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
foreach ($this->td_descriptions['constructors'][$name]['params'] as $k => $param) {
|
foreach ($this->td_descriptions['constructors'][$name]['params'] as $k => $param) {
|
||||||
$this->td_descriptions['constructors'][$name]['params'][$k] = str_replace('nullable', 'optional', $param);
|
$this->td_descriptions['constructors'][$name]['params'][$k] = \str_replace('nullable', 'optional', $param);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -193,7 +193,7 @@ trait TL
|
|||||||
unset($this->td_descriptions['methods'][$name]);
|
unset($this->td_descriptions['methods'][$name]);
|
||||||
} else {
|
} else {
|
||||||
foreach ($this->td_descriptions['methods'][$name]['params'] as $k => $param) {
|
foreach ($this->td_descriptions['methods'][$name]['params'] as $k => $param) {
|
||||||
$this->td_descriptions['constructors'][$name]['params'][$k] = str_replace('nullable', 'optional', $param);
|
$this->td_descriptions['constructors'][$name]['params'][$k] = \str_replace('nullable', 'optional', $param);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -204,7 +204,7 @@ trait TL
|
|||||||
{
|
{
|
||||||
$res = [];
|
$res = [];
|
||||||
foreach ($this->methods->method_namespace as $pair) {
|
foreach ($this->methods->method_namespace as $pair) {
|
||||||
$a = key($pair);
|
$a = \key($pair);
|
||||||
$res[$a] = $a;
|
$res[$a] = $a;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,7 +220,7 @@ trait TL
|
|||||||
{
|
{
|
||||||
$this->tl_callbacks = [];
|
$this->tl_callbacks = [];
|
||||||
foreach ($objects as $object) {
|
foreach ($objects as $object) {
|
||||||
if (!isset(class_implements(get_class($object))['danog\\MadelineProto\\TL\\TLCallback'])) {
|
if (!isset(\class_implements(\get_class($object))['danog\\MadelineProto\\TL\\TLCallback'])) {
|
||||||
throw new Exception('Invalid callback object provided!');
|
throw new Exception('Invalid callback object provided!');
|
||||||
}
|
}
|
||||||
$new = [
|
$new = [
|
||||||
@ -236,10 +236,10 @@ trait TL
|
|||||||
if (!isset($this->tl_callbacks[$type][$match])) {
|
if (!isset($this->tl_callbacks[$type][$match])) {
|
||||||
$this->tl_callbacks[$type][$match] = [];
|
$this->tl_callbacks[$type][$match] = [];
|
||||||
}
|
}
|
||||||
if (in_array($type, [TLCallback::TYPE_MISMATCH_CALLBACK, TLCallback::CONSTRUCTOR_SERIALIZE_CALLBACK])) {
|
if (\in_array($type, [TLCallback::TYPE_MISMATCH_CALLBACK, TLCallback::CONSTRUCTOR_SERIALIZE_CALLBACK])) {
|
||||||
$this->tl_callbacks[$type][$match] = $callback;
|
$this->tl_callbacks[$type][$match] = $callback;
|
||||||
} else {
|
} else {
|
||||||
$this->tl_callbacks[$type][$match] = array_merge($callback, $this->tl_callbacks[$type][$match]);
|
$this->tl_callbacks[$type][$match] = \array_merge($callback, $this->tl_callbacks[$type][$match]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -260,8 +260,8 @@ trait TL
|
|||||||
{
|
{
|
||||||
switch ($type['type']) {
|
switch ($type['type']) {
|
||||||
case 'int':
|
case 'int':
|
||||||
if (!is_numeric($object)) {
|
if (!\is_numeric($object)) {
|
||||||
if (is_array($object) && $type['name'] === 'hash') {
|
if (\is_array($object) && $type['name'] === 'hash') {
|
||||||
$object = $this->gen_vector_hash($object);
|
$object = $this->gen_vector_hash($object);
|
||||||
} else {
|
} else {
|
||||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['not_numeric']);
|
throw new Exception(\danog\MadelineProto\Lang::$current_lang['not_numeric']);
|
||||||
@ -270,40 +270,40 @@ trait TL
|
|||||||
|
|
||||||
return $this->pack_signed_int($object);
|
return $this->pack_signed_int($object);
|
||||||
case '#':
|
case '#':
|
||||||
if (!is_numeric($object)) {
|
if (!\is_numeric($object)) {
|
||||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['not_numeric']);
|
throw new Exception(\danog\MadelineProto\Lang::$current_lang['not_numeric']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->pack_unsigned_int($object);
|
return $this->pack_unsigned_int($object);
|
||||||
case 'long':
|
case 'long':
|
||||||
if (is_object($object)) {
|
if (\is_object($object)) {
|
||||||
return str_pad(strrev($object->toBytes()), 8, chr(0));
|
return \str_pad(\strrev($object->toBytes()), 8, \chr(0));
|
||||||
}
|
}
|
||||||
if (is_string($object) && strlen($object) === 8) {
|
if (\is_string($object) && \strlen($object) === 8) {
|
||||||
return $object;
|
return $object;
|
||||||
}
|
}
|
||||||
if (is_string($object) && strlen($object) === 9 && $object[0] === 'a') {
|
if (\is_string($object) && \strlen($object) === 9 && $object[0] === 'a') {
|
||||||
return substr($object, 1);
|
return \substr($object, 1);
|
||||||
}
|
}
|
||||||
if (!is_numeric($object)) {
|
if (!\is_numeric($object)) {
|
||||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['not_numeric']);
|
throw new Exception(\danog\MadelineProto\Lang::$current_lang['not_numeric']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->pack_signed_long($object);
|
return $this->pack_signed_long($object);
|
||||||
case 'int128':
|
case 'int128':
|
||||||
if (strlen($object) !== 16) {
|
if (\strlen($object) !== 16) {
|
||||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['long_not_16']);
|
throw new Exception(\danog\MadelineProto\Lang::$current_lang['long_not_16']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (string) $object;
|
return (string) $object;
|
||||||
case 'int256':
|
case 'int256':
|
||||||
if (strlen($object) !== 32) {
|
if (\strlen($object) !== 32) {
|
||||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['long_not_32']);
|
throw new Exception(\danog\MadelineProto\Lang::$current_lang['long_not_32']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (string) $object;
|
return (string) $object;
|
||||||
case 'int512':
|
case 'int512':
|
||||||
if (strlen($object) !== 64) {
|
if (\strlen($object) !== 64) {
|
||||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['long_not_64']);
|
throw new Exception(\danog\MadelineProto\Lang::$current_lang['long_not_64']);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,42 +311,42 @@ trait TL
|
|||||||
case 'double':
|
case 'double':
|
||||||
return $this->pack_double($object);
|
return $this->pack_double($object);
|
||||||
case 'string':
|
case 'string':
|
||||||
if (!is_string($object)) {
|
if (!\is_string($object)) {
|
||||||
throw new Exception("You didn't provide a valid string");
|
throw new Exception("You didn't provide a valid string");
|
||||||
}
|
}
|
||||||
$object = pack('C*', ...unpack('C*', $object));
|
$object = \pack('C*', ...\unpack('C*', $object));
|
||||||
$l = strlen($object);
|
$l = \strlen($object);
|
||||||
$concat = '';
|
$concat = '';
|
||||||
if ($l <= 253) {
|
if ($l <= 253) {
|
||||||
$concat .= chr($l);
|
$concat .= \chr($l);
|
||||||
$concat .= $object;
|
$concat .= $object;
|
||||||
$concat .= pack('@'.$this->posmod(-$l - 1, 4));
|
$concat .= \pack('@'.$this->posmod(-$l - 1, 4));
|
||||||
} else {
|
} else {
|
||||||
$concat .= chr(254);
|
$concat .= \chr(254);
|
||||||
$concat .= substr($this->pack_signed_int($l), 0, 3);
|
$concat .= \substr($this->pack_signed_int($l), 0, 3);
|
||||||
$concat .= $object;
|
$concat .= $object;
|
||||||
$concat .= pack('@'.$this->posmod(-$l, 4));
|
$concat .= \pack('@'.$this->posmod(-$l, 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $concat;
|
return $concat;
|
||||||
case 'bytes':
|
case 'bytes':
|
||||||
if (is_array($object) && isset($object['_']) && $object['_'] === 'bytes') {
|
if (\is_array($object) && isset($object['_']) && $object['_'] === 'bytes') {
|
||||||
$object = base64_decode($object['bytes']);
|
$object = \base64_decode($object['bytes']);
|
||||||
}
|
}
|
||||||
if (!is_string($object) && !$object instanceof \danog\MadelineProto\TL\Types\Bytes) {
|
if (!\is_string($object) && !$object instanceof \danog\MadelineProto\TL\Types\Bytes) {
|
||||||
throw new Exception("You didn't provide a valid string");
|
throw new Exception("You didn't provide a valid string");
|
||||||
}
|
}
|
||||||
$l = strlen($object);
|
$l = \strlen($object);
|
||||||
$concat = '';
|
$concat = '';
|
||||||
if ($l <= 253) {
|
if ($l <= 253) {
|
||||||
$concat .= chr($l);
|
$concat .= \chr($l);
|
||||||
$concat .= $object;
|
$concat .= $object;
|
||||||
$concat .= pack('@'.$this->posmod(-$l - 1, 4));
|
$concat .= \pack('@'.$this->posmod(-$l - 1, 4));
|
||||||
} else {
|
} else {
|
||||||
$concat .= chr(254);
|
$concat .= \chr(254);
|
||||||
$concat .= substr($this->pack_signed_int($l), 0, 3);
|
$concat .= \substr($this->pack_signed_int($l), 0, 3);
|
||||||
$concat .= $object;
|
$concat .= $object;
|
||||||
$concat .= pack('@'.$this->posmod(-$l, 4));
|
$concat .= \pack('@'.$this->posmod(-$l, 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $concat;
|
return $concat;
|
||||||
@ -357,39 +357,39 @@ trait TL
|
|||||||
case '!X':
|
case '!X':
|
||||||
return $object;
|
return $object;
|
||||||
case 'Vector t':
|
case 'Vector t':
|
||||||
if (!is_array($object)) {
|
if (!\is_array($object)) {
|
||||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['array_invalid']);
|
throw new Exception(\danog\MadelineProto\Lang::$current_lang['array_invalid']);
|
||||||
}
|
}
|
||||||
if (isset($object['_'])) {
|
if (isset($object['_'])) {
|
||||||
throw new Exception('You must provide an array of '.$type['subtype'].' objects, not a '.$type['subtype']." object. Example: [['_' => ".$type['subtype'].', ... ]]');
|
throw new Exception('You must provide an array of '.$type['subtype'].' objects, not a '.$type['subtype']." object. Example: [['_' => ".$type['subtype'].', ... ]]');
|
||||||
}
|
}
|
||||||
$concat = $this->constructors->find_by_predicate('vector')['id'];
|
$concat = $this->constructors->find_by_predicate('vector')['id'];
|
||||||
$concat .= $this->pack_unsigned_int(count($object));
|
$concat .= $this->pack_unsigned_int(\count($object));
|
||||||
foreach ($object as $k => $current_object) {
|
foreach ($object as $k => $current_object) {
|
||||||
$concat .= yield $this->serialize_object_async(['type' => $type['subtype']], $current_object, $k);
|
$concat .= yield $this->serialize_object_async(['type' => $type['subtype']], $current_object, $k);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $concat;
|
return $concat;
|
||||||
case 'vector':
|
case 'vector':
|
||||||
if (!is_array($object)) {
|
if (!\is_array($object)) {
|
||||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['array_invalid']);
|
throw new Exception(\danog\MadelineProto\Lang::$current_lang['array_invalid']);
|
||||||
}
|
}
|
||||||
$concat = $this->pack_unsigned_int(count($object));
|
$concat = $this->pack_unsigned_int(\count($object));
|
||||||
foreach ($object as $k => $current_object) {
|
foreach ($object as $k => $current_object) {
|
||||||
$concat .= yield $this->serialize_object_async(['type' => $type['subtype']], $current_object, $k);
|
$concat .= yield $this->serialize_object_async(['type' => $type['subtype']], $current_object, $k);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $concat;
|
return $concat;
|
||||||
case 'Object':
|
case 'Object':
|
||||||
if (is_string($object)) {
|
if (\is_string($object)) {
|
||||||
return $object;
|
return $object;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$auto = false;
|
$auto = false;
|
||||||
|
|
||||||
if ($type['type'] === 'InputMessage' && !is_array($object)) {
|
if ($type['type'] === 'InputMessage' && !\is_array($object)) {
|
||||||
$object = ['_' => 'inputMessageID', 'id' => $object];
|
$object = ['_' => 'inputMessageID', 'id' => $object];
|
||||||
} elseif (isset($this->tl_callbacks[TLCallback::TYPE_MISMATCH_CALLBACK][$type['type']]) && (!is_array($object) || isset($object['_']) && $this->constructors->find_by_predicate($object['_'])['type'] !== $type['type'])) {
|
} elseif (isset($this->tl_callbacks[TLCallback::TYPE_MISMATCH_CALLBACK][$type['type']]) && (!\is_array($object) || isset($object['_']) && $this->constructors->find_by_predicate($object['_'])['type'] !== $type['type'])) {
|
||||||
$object = yield $this->tl_callbacks[TLCallback::TYPE_MISMATCH_CALLBACK][$type['type']]($object);
|
$object = yield $this->tl_callbacks[TLCallback::TYPE_MISMATCH_CALLBACK][$type['type']]($object);
|
||||||
if (!isset($object[$type['type']])) {
|
if (!isset($object[$type['type']])) {
|
||||||
throw new \danog\MadelineProto\Exception("Could not convert {$type['type']} object");
|
throw new \danog\MadelineProto\Exception("Could not convert {$type['type']} object");
|
||||||
@ -413,10 +413,10 @@ trait TL
|
|||||||
if ($constructorData === false) {
|
if ($constructorData === false) {
|
||||||
$this->logger->logger($object, \danog\MadelineProto\Logger::FATAL_ERROR);
|
$this->logger->logger($object, \danog\MadelineProto\Logger::FATAL_ERROR);
|
||||||
|
|
||||||
throw new Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['type_extract_error'], $predicate));
|
throw new Exception(\sprintf(\danog\MadelineProto\Lang::$current_lang['type_extract_error'], $predicate));
|
||||||
}
|
}
|
||||||
if ($bare = $type['type'] != '' && $type['type'][0] === '%') {
|
if ($bare = $type['type'] != '' && $type['type'][0] === '%') {
|
||||||
$type['type'] = substr($type['type'], 1);
|
$type['type'] = \substr($type['type'], 1);
|
||||||
}
|
}
|
||||||
if ($predicate === $type['type'] && !$auto) {
|
if ($predicate === $type['type'] && !$auto) {
|
||||||
$bare = true;
|
$bare = true;
|
||||||
@ -435,21 +435,21 @@ trait TL
|
|||||||
|
|
||||||
public function serialize_method_async($method, $arguments)
|
public function serialize_method_async($method, $arguments)
|
||||||
{
|
{
|
||||||
if ($method === 'messages.importChatInvite' && isset($arguments['hash']) && is_string($arguments['hash']) && preg_match('@(?:t|telegram)\.(?:me|dog)/(joinchat/)?([a-z0-9_-]*)@i', $arguments['hash'], $matches)) {
|
if ($method === 'messages.importChatInvite' && isset($arguments['hash']) && \is_string($arguments['hash']) && \preg_match('@(?:t|telegram)\.(?:me|dog)/(joinchat/)?([a-z0-9_-]*)@i', $arguments['hash'], $matches)) {
|
||||||
if ($matches[1] === '') {
|
if ($matches[1] === '') {
|
||||||
$method = 'channels.joinChannel';
|
$method = 'channels.joinChannel';
|
||||||
$arguments['channel'] = $matches[2];
|
$arguments['channel'] = $matches[2];
|
||||||
} else {
|
} else {
|
||||||
$arguments['hash'] = $matches[2];
|
$arguments['hash'] = $matches[2];
|
||||||
}
|
}
|
||||||
} elseif ($method === 'messages.checkChatInvite' && isset($arguments['hash']) && is_string($arguments['hash']) && preg_match('@(?:t|telegram)\.(?:me|dog)/joinchat/([a-z0-9_-]*)@i', $arguments['hash'], $matches)) {
|
} elseif ($method === 'messages.checkChatInvite' && isset($arguments['hash']) && \is_string($arguments['hash']) && \preg_match('@(?:t|telegram)\.(?:me|dog)/joinchat/([a-z0-9_-]*)@i', $arguments['hash'], $matches)) {
|
||||||
$arguments['hash'] = $matches[1];
|
$arguments['hash'] = $matches[1];
|
||||||
} elseif ($method === 'channels.joinChannel' && isset($arguments['channel']) && is_string($arguments['channel']) && preg_match('@(?:t|telegram)\.(?:me|dog)/(joinchat/)?([a-z0-9_-]*)@i', $arguments['channel'], $matches)) {
|
} elseif ($method === 'channels.joinChannel' && isset($arguments['channel']) && \is_string($arguments['channel']) && \preg_match('@(?:t|telegram)\.(?:me|dog)/(joinchat/)?([a-z0-9_-]*)@i', $arguments['channel'], $matches)) {
|
||||||
if ($matches[1] !== '') {
|
if ($matches[1] !== '') {
|
||||||
$method = 'messages.importChatInvite';
|
$method = 'messages.importChatInvite';
|
||||||
$arguments['hash'] = $matches[2];
|
$arguments['hash'] = $matches[2];
|
||||||
}
|
}
|
||||||
} elseif ($method === 'messages.sendMessage' && isset($arguments['peer']['_']) && in_array($arguments['peer']['_'], ['inputEncryptedChat', 'updateEncryption', 'updateEncryptedChatTyping', 'updateEncryptedMessagesRead', 'updateNewEncryptedMessage', 'encryptedMessage', 'encryptedMessageService'])) {
|
} elseif ($method === 'messages.sendMessage' && isset($arguments['peer']['_']) && \in_array($arguments['peer']['_'], ['inputEncryptedChat', 'updateEncryption', 'updateEncryptedChatTyping', 'updateEncryptedMessagesRead', 'updateNewEncryptedMessage', 'encryptedMessage', 'encryptedMessageService'])) {
|
||||||
$method = 'messages.sendEncrypted';
|
$method = 'messages.sendEncrypted';
|
||||||
$arguments = ['peer' => $arguments['peer'], 'message' => $arguments];
|
$arguments = ['peer' => $arguments['peer'], 'message' => $arguments];
|
||||||
if (!isset($arguments['message']['_'])) {
|
if (!isset($arguments['message']['_'])) {
|
||||||
@ -465,9 +465,9 @@ trait TL
|
|||||||
if (isset($arguments['file'])) {
|
if (isset($arguments['file'])) {
|
||||||
if (
|
if (
|
||||||
(
|
(
|
||||||
!is_array($arguments['file']) ||
|
!\is_array($arguments['file']) ||
|
||||||
!(isset($arguments['file']['_']) && $this->constructors->find_by_predicate($arguments['file']['_']) === 'InputEncryptedFile')
|
!(isset($arguments['file']['_']) && $this->constructors->find_by_predicate($arguments['file']['_']) === 'InputEncryptedFile')
|
||||||
) &&
|
) &&
|
||||||
$this->settings['upload']['allow_automatic_upload']
|
$this->settings['upload']['allow_automatic_upload']
|
||||||
) {
|
) {
|
||||||
$arguments['file'] = yield $this->upload_encrypted_async($arguments['file']);
|
$arguments['file'] = yield $this->upload_encrypted_async($arguments['file']);
|
||||||
@ -479,7 +479,7 @@ trait TL
|
|||||||
$arguments['message']['media']['iv'] = $arguments['file']['iv'];
|
$arguments['message']['media']['iv'] = $arguments['file']['iv'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} elseif (in_array($method, ['messages.addChatUser', 'messages.deleteChatUser', 'messages.editChatAdmin', 'messages.editChatPhoto', 'messages.editChatTitle', 'messages.getFullChat', 'messages.exportChatInvite', 'messages.editChatAdmin', 'messages.migrateChat']) && isset($arguments['chat_id']) && (!is_numeric($arguments['chat_id']) || $arguments['chat_id'] < 0)) {
|
} elseif (\in_array($method, ['messages.addChatUser', 'messages.deleteChatUser', 'messages.editChatAdmin', 'messages.editChatPhoto', 'messages.editChatTitle', 'messages.getFullChat', 'messages.exportChatInvite', 'messages.editChatAdmin', 'messages.migrateChat']) && isset($arguments['chat_id']) && (!\is_numeric($arguments['chat_id']) || $arguments['chat_id'] < 0)) {
|
||||||
$res = yield $this->get_info_async($arguments['chat_id']);
|
$res = yield $this->get_info_async($arguments['chat_id']);
|
||||||
if ($res['type'] !== 'chat') {
|
if ($res['type'] !== 'chat') {
|
||||||
throw new \danog\MadelineProto\Exception('chat_id is not a chat id (only normal groups allowed, not supergroups)!');
|
throw new \danog\MadelineProto\Exception('chat_id is not a chat id (only normal groups allowed, not supergroups)!');
|
||||||
@ -487,7 +487,7 @@ trait TL
|
|||||||
$arguments['chat_id'] = $res['chat_id'];
|
$arguments['chat_id'] = $res['chat_id'];
|
||||||
} elseif ($method === 'photos.updateProfilePhoto') {
|
} elseif ($method === 'photos.updateProfilePhoto') {
|
||||||
if (isset($arguments['id'])) {
|
if (isset($arguments['id'])) {
|
||||||
if (!is_array($arguments['id'])) {
|
if (!\is_array($arguments['id'])) {
|
||||||
$method = 'photos.uploadProfilePhoto';
|
$method = 'photos.uploadProfilePhoto';
|
||||||
$arguments['file'] = $arguments['id'];
|
$arguments['file'] = $arguments['id'];
|
||||||
}
|
}
|
||||||
@ -496,7 +496,7 @@ trait TL
|
|||||||
}
|
}
|
||||||
} elseif ($method === 'photos.uploadProfilePhoto') {
|
} elseif ($method === 'photos.uploadProfilePhoto') {
|
||||||
if (isset($arguments['file'])) {
|
if (isset($arguments['file'])) {
|
||||||
if (is_array($arguments['file']) && !in_array($arguments['file']['_'], ['inputFile', 'inputFileBig'])) {
|
if (\is_array($arguments['file']) && !\in_array($arguments['file']['_'], ['inputFile', 'inputFileBig'])) {
|
||||||
$method = 'photos.uploadProfilePhoto';
|
$method = 'photos.uploadProfilePhoto';
|
||||||
$arguments['id'] = $arguments['file'];
|
$arguments['id'] = $arguments['file'];
|
||||||
}
|
}
|
||||||
@ -541,7 +541,7 @@ trait TL
|
|||||||
$arguments['flags'] = $flags;
|
$arguments['flags'] = $flags;
|
||||||
foreach ($tl['params'] as $current_argument) {
|
foreach ($tl['params'] as $current_argument) {
|
||||||
if (!isset($arguments[$current_argument['name']])) {
|
if (!isset($arguments[$current_argument['name']])) {
|
||||||
if (isset($current_argument['pow']) && (in_array($current_argument['type'], ['true', 'false']) || ($flags & $current_argument['pow']) === 0)) {
|
if (isset($current_argument['pow']) && (\in_array($current_argument['type'], ['true', 'false']) || ($flags & $current_argument['pow']) === 0)) {
|
||||||
//$this->logger->logger('Skipping '.$current_argument['name'].' of type '.$current_argument['type');
|
//$this->logger->logger('Skipping '.$current_argument['name'].' of type '.$current_argument['type');
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -549,7 +549,7 @@ trait TL
|
|||||||
$serialized .= yield $this->serialize_object_async(['type' => 'bytes'], $this->random(15 + 4 * $this->random_int($modulus = 3)), 'random_bytes');
|
$serialized .= yield $this->serialize_object_async(['type' => 'bytes'], $this->random(15 + 4 * $this->random_int($modulus = 3)), 'random_bytes');
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($current_argument['name'] === 'data' && isset($tl['method']) && in_array($tl['method'], ['messages.sendEncrypted', 'messages.sendEncryptedFile', 'messages.sendEncryptedService']) && isset($arguments['message'])) {
|
if ($current_argument['name'] === 'data' && isset($tl['method']) && \in_array($tl['method'], ['messages.sendEncrypted', 'messages.sendEncryptedFile', 'messages.sendEncryptedService']) && isset($arguments['message'])) {
|
||||||
$serialized .= yield $this->serialize_object_async($current_argument, yield $this->encrypt_secret_message_async($arguments['peer']['chat_id'], $arguments['message']), 'data');
|
$serialized .= yield $this->serialize_object_async($current_argument, yield $this->encrypt_secret_message_async($arguments['peer']['chat_id'], $arguments['message']), 'data');
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -564,29 +564,29 @@ trait TL
|
|||||||
case 'Vector t':
|
case 'Vector t':
|
||||||
if (isset($arguments['id'])) {
|
if (isset($arguments['id'])) {
|
||||||
$serialized .= $this->constructors->find_by_predicate('vector')['id'];
|
$serialized .= $this->constructors->find_by_predicate('vector')['id'];
|
||||||
$serialized .= $this->pack_unsigned_int(count($arguments['id']));
|
$serialized .= $this->pack_unsigned_int(\count($arguments['id']));
|
||||||
$serialized .= $this->random(8 * count($arguments['id']));
|
$serialized .= $this->random(8 * \count($arguments['id']));
|
||||||
continue 2;
|
continue 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($current_argument['name'] === 'hash' && $current_argument['type'] === 'int') {
|
if ($current_argument['name'] === 'hash' && $current_argument['type'] === 'int') {
|
||||||
$serialized .= pack('@4');
|
$serialized .= \pack('@4');
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($tl['type'] === 'InputMedia' && $current_argument['name'] === 'mime_type') {
|
if ($tl['type'] === 'InputMedia' && $current_argument['name'] === 'mime_type') {
|
||||||
$serialized .= yield $this->serialize_object_async($current_argument, $arguments['file']['mime_type'], $current_argument['name'], $layer);
|
$serialized .= yield $this->serialize_object_async($current_argument, $arguments['file']['mime_type'], $current_argument['name'], $layer);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($tl['type'] === 'DocumentAttribute' && in_array($current_argument['name'], ['w', 'h', 'duration'])) {
|
if ($tl['type'] === 'DocumentAttribute' && \in_array($current_argument['name'], ['w', 'h', 'duration'])) {
|
||||||
$serialized .= pack('@4');
|
$serialized .= \pack('@4');
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (in_array($current_argument['type'], ['bytes', 'string'])) {
|
if (\in_array($current_argument['type'], ['bytes', 'string'])) {
|
||||||
$serialized .= pack('@4');
|
$serialized .= \pack('@4');
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (($id = $this->constructors->find_by_predicate(lcfirst($current_argument['type']).'Empty', isset($tl['layer']) ? $tl['layer'] : -1)) && $id['type'] === $current_argument['type']) {
|
if (($id = $this->constructors->find_by_predicate(\lcfirst($current_argument['type']).'Empty', isset($tl['layer']) ? $tl['layer'] : -1)) && $id['type'] === $current_argument['type']) {
|
||||||
$serialized .= $id['id'];
|
$serialized .= $id['id'];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -618,19 +618,19 @@ trait TL
|
|||||||
break;*/
|
break;*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (in_array($current_argument['type'], ['DataJSON', '%DataJSON'])) {
|
if (\in_array($current_argument['type'], ['DataJSON', '%DataJSON'])) {
|
||||||
$arguments[$current_argument['name']] = ['_' => 'dataJSON', 'data' => json_encode($arguments[$current_argument['name']])];
|
$arguments[$current_argument['name']] = ['_' => 'dataJSON', 'data' => \json_encode($arguments[$current_argument['name']])];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($current_argument['subtype']) && in_array($current_argument['subtype'], ['DataJSON', '%DataJSON'])) {
|
if (isset($current_argument['subtype']) && \in_array($current_argument['subtype'], ['DataJSON', '%DataJSON'])) {
|
||||||
array_walk($arguments[$current_argument['name']], function (&$arg) {
|
\array_walk($arguments[$current_argument['name']], function (&$arg) {
|
||||||
$arg = ['_' => 'dataJSON', 'data' => json_encode($arg)];
|
$arg = ['_' => 'dataJSON', 'data' => \json_encode($arg)];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($current_argument['type'] === 'InputFile'
|
if ($current_argument['type'] === 'InputFile'
|
||||||
&& (
|
&& (
|
||||||
!is_array($arguments[$current_argument['name']])
|
!\is_array($arguments[$current_argument['name']])
|
||||||
|| !(
|
|| !(
|
||||||
isset($arguments[$current_argument['name']]['_'])
|
isset($arguments[$current_argument['name']]['_'])
|
||||||
&& $this->constructors->find_by_predicate($arguments[$current_argument['name']]['_']) === 'InputFile'
|
&& $this->constructors->find_by_predicate($arguments[$current_argument['name']]['_']) === 'InputFile'
|
||||||
@ -641,8 +641,8 @@ trait TL
|
|||||||
$arguments[$current_argument['name']] = yield $this->upload_async($arguments[$current_argument['name']]);
|
$arguments[$current_argument['name']] = yield $this->upload_async($arguments[$current_argument['name']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($current_argument['type'] === 'InputEncryptedChat' && (!is_array($arguments[$current_argument['name']]) || isset($arguments[$current_argument['name']]['_']) && $this->constructors->find_by_predicate($arguments[$current_argument['name']]['_'])['type'] !== $current_argument['type'])) {
|
if ($current_argument['type'] === 'InputEncryptedChat' && (!\is_array($arguments[$current_argument['name']]) || isset($arguments[$current_argument['name']]['_']) && $this->constructors->find_by_predicate($arguments[$current_argument['name']]['_'])['type'] !== $current_argument['type'])) {
|
||||||
if (is_array($arguments[$current_argument['name']])) {
|
if (\is_array($arguments[$current_argument['name']])) {
|
||||||
$arguments[$current_argument['name']] = (yield $this->get_info_async($arguments[$current_argument['name']]))['InputEncryptedChat'];
|
$arguments[$current_argument['name']] = (yield $this->get_info_async($arguments[$current_argument['name']]))['InputEncryptedChat'];
|
||||||
} else {
|
} else {
|
||||||
if (!isset($this->secret_chats[$arguments[$current_argument['name']]])) {
|
if (!isset($this->secret_chats[$arguments[$current_argument['name']]])) {
|
||||||
@ -660,17 +660,17 @@ trait TL
|
|||||||
|
|
||||||
public function get_length($stream, $type = ['type' => ''])
|
public function get_length($stream, $type = ['type' => ''])
|
||||||
{
|
{
|
||||||
if (is_string($stream)) {
|
if (\is_string($stream)) {
|
||||||
$res = fopen('php://memory', 'rw+b');
|
$res = \fopen('php://memory', 'rw+b');
|
||||||
fwrite($res, $stream);
|
\fwrite($res, $stream);
|
||||||
fseek($res, 0);
|
\fseek($res, 0);
|
||||||
$stream = $res;
|
$stream = $res;
|
||||||
} elseif (!is_resource($stream)) {
|
} elseif (!\is_resource($stream)) {
|
||||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['stream_handle_invalid']);
|
throw new Exception(\danog\MadelineProto\Lang::$current_lang['stream_handle_invalid']);
|
||||||
}
|
}
|
||||||
$this->deserialize($stream, $type);
|
$this->deserialize($stream, $type);
|
||||||
|
|
||||||
return ftell($stream);
|
return \ftell($stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -678,81 +678,82 @@ trait TL
|
|||||||
*/
|
*/
|
||||||
public function deserialize($stream, $type = ['type' => ''])
|
public function deserialize($stream, $type = ['type' => ''])
|
||||||
{
|
{
|
||||||
if (is_string($stream)) {
|
if (\is_string($stream)) {
|
||||||
$res = fopen('php://memory', 'rw+b');
|
$res = \fopen('php://memory', 'rw+b');
|
||||||
fwrite($res, $stream);
|
\fwrite($res, $stream);
|
||||||
fseek($res, 0);
|
\fseek($res, 0);
|
||||||
$stream = $res;
|
$stream = $res;
|
||||||
} elseif (!is_resource($stream)) {
|
} elseif (!\is_resource($stream)) {
|
||||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['stream_handle_invalid']);
|
throw new Exception(\danog\MadelineProto\Lang::$current_lang['stream_handle_invalid']);
|
||||||
}
|
}
|
||||||
switch ($type['type']) {
|
switch ($type['type']) {
|
||||||
case 'Bool':
|
case 'Bool':
|
||||||
return $this->deserialize_bool(stream_get_contents($stream, 4));
|
return $this->deserialize_bool(\stream_get_contents($stream, 4));
|
||||||
case 'int':
|
case 'int':
|
||||||
return $this->unpack_signed_int(stream_get_contents($stream, 4));
|
return $this->unpack_signed_int(\stream_get_contents($stream, 4));
|
||||||
case '#':
|
case '#':
|
||||||
return unpack('V', stream_get_contents($stream, 4))[1];
|
return \unpack('V', \stream_get_contents($stream, 4))[1];
|
||||||
case 'long':
|
case 'long':
|
||||||
if (isset($type['idstrlong'])) {
|
if (isset($type['idstrlong'])) {
|
||||||
return stream_get_contents($stream, 8);
|
return \stream_get_contents($stream, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
return \danog\MadelineProto\Magic::$bigint || isset($type['strlong']) ? stream_get_contents($stream, 8) : $this->unpack_signed_long(stream_get_contents($stream, 8));
|
return \danog\MadelineProto\Magic::$bigint || isset($type['strlong']) ? \stream_get_contents($stream, 8) : $this->unpack_signed_long(\stream_get_contents($stream, 8));
|
||||||
case 'double':
|
case 'double':
|
||||||
return $this->unpack_double(stream_get_contents($stream, 8));
|
return $this->unpack_double(\stream_get_contents($stream, 8));
|
||||||
case 'int128':
|
case 'int128':
|
||||||
return stream_get_contents($stream, 16);
|
return \stream_get_contents($stream, 16);
|
||||||
case 'int256':
|
case 'int256':
|
||||||
return stream_get_contents($stream, 32);
|
return \stream_get_contents($stream, 32);
|
||||||
case 'int512':
|
case 'int512':
|
||||||
return stream_get_contents($stream, 64);
|
return \stream_get_contents($stream, 64);
|
||||||
case 'string':
|
case 'string':
|
||||||
case 'bytes':
|
case 'bytes':
|
||||||
$l = ord(stream_get_contents($stream, 1));
|
$l = \ord(\stream_get_contents($stream, 1));
|
||||||
if ($l > 254) {
|
if ($l > 254) {
|
||||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['length_too_big']);
|
throw new Exception(\danog\MadelineProto\Lang::$current_lang['length_too_big']);
|
||||||
}
|
}
|
||||||
if ($l === 254) {
|
if ($l === 254) {
|
||||||
$long_len = unpack('V', stream_get_contents($stream, 3).chr(0))[1];
|
$long_len = \unpack('V', \stream_get_contents($stream, 3).\chr(0))[1];
|
||||||
$x = stream_get_contents($stream, $long_len);
|
$x = \stream_get_contents($stream, $long_len);
|
||||||
$resto = $this->posmod(-$long_len, 4);
|
$resto = $this->posmod(-$long_len, 4);
|
||||||
if ($resto > 0) {
|
if ($resto > 0) {
|
||||||
stream_get_contents($stream, $resto);
|
\stream_get_contents($stream, $resto);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$x = $l ? stream_get_contents($stream, $l) : '';
|
$x = $l ? \stream_get_contents($stream, $l) : '';
|
||||||
$resto = $this->posmod(-($l + 1), 4);
|
$resto = $this->posmod(-($l + 1), 4);
|
||||||
if ($resto > 0) {
|
if ($resto > 0) {
|
||||||
stream_get_contents($stream, $resto);
|
\stream_get_contents($stream, $resto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!is_string($x)) {
|
if (!\is_string($x)) {
|
||||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['deserialize_not_str']);
|
throw new Exception(\danog\MadelineProto\Lang::$current_lang['deserialize_not_str']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $type['type'] === 'bytes' ? new Types\Bytes($x) : $x;
|
return $type['type'] === 'bytes' ? new Types\Bytes($x) : $x;
|
||||||
case 'Vector t':
|
case 'Vector t':
|
||||||
$id = stream_get_contents($stream, 4);
|
$id = \stream_get_contents($stream, 4);
|
||||||
$constructorData = $this->constructors->find_by_id($id);
|
$constructorData = $this->constructors->find_by_id($id);
|
||||||
if ($constructorData === false) {
|
if ($constructorData === false) {
|
||||||
$constructorData = $this->methods->find_by_id($id);
|
$constructorData = $this->methods->find_by_id($id);
|
||||||
$constructorData['predicate'] = 'method_'.$constructorData['method'];
|
$constructorData['predicate'] = 'method_'.$constructorData['method'];
|
||||||
}
|
}
|
||||||
if ($constructorData === false) {
|
if ($constructorData === false) {
|
||||||
throw new Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['type_extract_error_id'], $type['type'], bin2hex(strrev($id))));
|
throw new Exception(\sprintf(\danog\MadelineProto\Lang::$current_lang['type_extract_error_id'], $type['type'], \bin2hex(\strrev($id))));
|
||||||
}
|
}
|
||||||
switch ($constructorData['predicate']) {
|
switch ($constructorData['predicate']) {
|
||||||
case 'gzip_packed':
|
case 'gzip_packed':
|
||||||
return $this->deserialize(gzdecode($this->deserialize($stream, ['type' => 'bytes', 'connection' => $type['connection']])), ['type' => '', 'connection' => $type['connection']]);
|
return $this->deserialize(\gzdecode($this->deserialize($stream, ['type' => 'bytes', 'connection' => $type['connection']])), ['type' => '', 'connection' => $type['connection']]);
|
||||||
case 'Vector t':
|
case 'Vector t':
|
||||||
case 'vector':
|
case 'vector':
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['vector_invalid'].$constructorData['predicate']);
|
throw new Exception(\danog\MadelineProto\Lang::$current_lang['vector_invalid'].$constructorData['predicate']);
|
||||||
}
|
}
|
||||||
|
// no break
|
||||||
case 'vector':
|
case 'vector':
|
||||||
$count = unpack('V', stream_get_contents($stream, 4))[1];
|
$count = \unpack('V', \stream_get_contents($stream, 4))[1];
|
||||||
$result = [];
|
$result = [];
|
||||||
$type['type'] = $type['subtype'];
|
$type['type'] = $type['subtype'];
|
||||||
for ($i = 0; $i < $count; $i++) {
|
for ($i = 0; $i < $count; $i++) {
|
||||||
@ -762,7 +763,7 @@ trait TL
|
|||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
if ($type['type'] != '' && $type['type'][0] === '%') {
|
if ($type['type'] != '' && $type['type'][0] === '%') {
|
||||||
$checkType = substr($type['type'], 1);
|
$checkType = \substr($type['type'], 1);
|
||||||
$constructorData = $this->constructors->find_by_type($checkType);
|
$constructorData = $this->constructors->find_by_type($checkType);
|
||||||
if ($constructorData === false) {
|
if ($constructorData === false) {
|
||||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['constructor_not_found'].$checkType);
|
throw new Exception(\danog\MadelineProto\Lang::$current_lang['constructor_not_found'].$checkType);
|
||||||
@ -770,12 +771,12 @@ trait TL
|
|||||||
} else {
|
} else {
|
||||||
$constructorData = $this->constructors->find_by_predicate($type['type']);
|
$constructorData = $this->constructors->find_by_predicate($type['type']);
|
||||||
if ($constructorData === false) {
|
if ($constructorData === false) {
|
||||||
$id = stream_get_contents($stream, 4);
|
$id = \stream_get_contents($stream, 4);
|
||||||
$constructorData = $this->constructors->find_by_id($id);
|
$constructorData = $this->constructors->find_by_id($id);
|
||||||
if ($constructorData === false) {
|
if ($constructorData === false) {
|
||||||
$constructorData = $this->methods->find_by_id($id);
|
$constructorData = $this->methods->find_by_id($id);
|
||||||
if ($constructorData === false) {
|
if ($constructorData === false) {
|
||||||
throw new Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['type_extract_error_id'], $type['type'], bin2hex(strrev($id))));
|
throw new Exception(\sprintf(\danog\MadelineProto\Lang::$current_lang['type_extract_error_id'], $type['type'], \bin2hex(\strrev($id))));
|
||||||
}
|
}
|
||||||
$constructorData['predicate'] = 'method_'.$constructorData['method'];
|
$constructorData['predicate'] = 'method_'.$constructorData['method'];
|
||||||
}
|
}
|
||||||
@ -785,7 +786,7 @@ trait TL
|
|||||||
if (!isset($type['subtype'])) {
|
if (!isset($type['subtype'])) {
|
||||||
$type['subtype'] = '';
|
$type['subtype'] = '';
|
||||||
}
|
}
|
||||||
return $this->deserialize(gzdecode($this->deserialize($stream, ['type' => 'bytes'])), ['type' => '', 'connection' => $type['connection'], 'subtype' => $type['subtype']]);
|
return $this->deserialize(\gzdecode($this->deserialize($stream, ['type' => 'bytes'])), ['type' => '', 'connection' => $type['connection'], 'subtype' => $type['subtype']]);
|
||||||
}
|
}
|
||||||
if ($constructorData['type'] === 'Vector t') {
|
if ($constructorData['type'] === 'Vector t') {
|
||||||
$constructorData['connection'] = $type['connection'];
|
$constructorData['connection'] = $type['connection'];
|
||||||
@ -818,19 +819,20 @@ trait TL
|
|||||||
$x[$arg['name']] = false;
|
$x[$arg['name']] = false;
|
||||||
continue 2;
|
continue 2;
|
||||||
}
|
}
|
||||||
|
// no break
|
||||||
default:
|
default:
|
||||||
if (($x['flags'] & $arg['pow']) === 0) {
|
if (($x['flags'] & $arg['pow']) === 0) {
|
||||||
continue 2;
|
continue 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (in_array($arg['name'], ['msg_ids', 'msg_id', 'bad_msg_id', 'req_msg_id', 'answer_msg_id', 'first_msg_id'])) {
|
if (\in_array($arg['name'], ['msg_ids', 'msg_id', 'bad_msg_id', 'req_msg_id', 'answer_msg_id', 'first_msg_id'])) {
|
||||||
$arg['idstrlong'] = true;
|
$arg['idstrlong'] = true;
|
||||||
}
|
}
|
||||||
if (in_array($arg['name'], ['key_fingerprint', 'server_salt', 'new_server_salt', 'server_public_key_fingerprints', 'ping_id', 'exchange_id'])) {
|
if (\in_array($arg['name'], ['key_fingerprint', 'server_salt', 'new_server_salt', 'server_public_key_fingerprints', 'ping_id', 'exchange_id'])) {
|
||||||
$arg['strlong'] = true;
|
$arg['strlong'] = true;
|
||||||
}
|
}
|
||||||
if (in_array($arg['name'], ['peer_tag', 'file_token', 'cdn_key', 'cdn_iv'])) {
|
if (\in_array($arg['name'], ['peer_tag', 'file_token', 'cdn_key', 'cdn_iv'])) {
|
||||||
$arg['type'] = 'string';
|
$arg['type'] = 'string';
|
||||||
}
|
}
|
||||||
if ($x['_'] === 'rpc_result' && $arg['name'] === 'result') {
|
if ($x['_'] === 'rpc_result' && $arg['name'] === 'result') {
|
||||||
@ -843,9 +845,9 @@ trait TL
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isset($type['connection']->outgoing_messages[$x['req_msg_id']]['type'])
|
if (isset($type['connection']->outgoing_messages[$x['req_msg_id']]['type'])
|
||||||
&& stripos($type['connection']->outgoing_messages[$x['req_msg_id']]['type'], '<') !== false
|
&& \stripos($type['connection']->outgoing_messages[$x['req_msg_id']]['type'], '<') !== false
|
||||||
) {
|
) {
|
||||||
$arg['subtype'] = str_replace(['Vector<', '>'], '', $type['connection']->outgoing_messages[$x['req_msg_id']]['type']);
|
$arg['subtype'] = \str_replace(['Vector<', '>'], '', $type['connection']->outgoing_messages[$x['req_msg_id']]['type']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isset($type['connection'])) {
|
if (isset($type['connection'])) {
|
||||||
@ -853,11 +855,10 @@ trait TL
|
|||||||
}
|
}
|
||||||
$x[$arg['name']] = $this->deserialize($stream, $arg);
|
$x[$arg['name']] = $this->deserialize($stream, $arg);
|
||||||
if ($arg['name'] === 'random_bytes') {
|
if ($arg['name'] === 'random_bytes') {
|
||||||
if (strlen($x[$arg['name']]) < 15) {
|
if (\strlen($x[$arg['name']]) < 15) {
|
||||||
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['rand_bytes_too_small']);
|
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['rand_bytes_too_small']);
|
||||||
} else {
|
|
||||||
unset($x[$arg['name']]);
|
|
||||||
}
|
}
|
||||||
|
unset($x[$arg['name']]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isset($x['flags'])) {
|
if (isset($x['flags'])) {
|
||||||
@ -865,7 +866,7 @@ trait TL
|
|||||||
unset($x['flags']);
|
unset($x['flags']);
|
||||||
}
|
}
|
||||||
if ($x['_'] === 'dataJSON') {
|
if ($x['_'] === 'dataJSON') {
|
||||||
return json_decode($x['data'], true);
|
return \json_decode($x['data'], true);
|
||||||
} elseif ($constructorData['type'] === 'JSONValue') {
|
} elseif ($constructorData['type'] === 'JSONValue') {
|
||||||
switch ($x['_']) {
|
switch ($x['_']) {
|
||||||
case 'jsonNull':
|
case 'jsonNull':
|
||||||
|
@ -45,7 +45,7 @@ class TLConstructor
|
|||||||
if ($scheme_type === 'secret') {
|
if ($scheme_type === 'secret') {
|
||||||
$this->by_id[$json_dict['id']]['layer'] = $json_dict['layer'];
|
$this->by_id[$json_dict['id']]['layer'] = $json_dict['layer'];
|
||||||
$this->layers[$json_dict['layer']] = $json_dict['layer'];
|
$this->layers[$json_dict['layer']] = $json_dict['layer'];
|
||||||
ksort($this->layers);
|
\ksort($this->layers);
|
||||||
} else {
|
} else {
|
||||||
$json_dict['layer'] = '';
|
$json_dict['layer'] = '';
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ class TLMethod
|
|||||||
{
|
{
|
||||||
$this->by_id[$json_dict['id']] = ['method' => $json_dict['method'], 'type' => $json_dict['type'], 'params' => $json_dict['params']];
|
$this->by_id[$json_dict['id']] = ['method' => $json_dict['method'], 'type' => $json_dict['type'], 'params' => $json_dict['params']];
|
||||||
$this->by_method[$json_dict['method']] = $json_dict['id'];
|
$this->by_method[$json_dict['method']] = $json_dict['id'];
|
||||||
$namespace = explode('.', $json_dict['method']);
|
$namespace = \explode('.', $json_dict['method']);
|
||||||
if (isset($namespace[1])) {
|
if (isset($namespace[1])) {
|
||||||
$this->method_namespace[] = [$namespace[0] => $namespace[1]];
|
$this->method_namespace[] = [$namespace[0] => $namespace[1]];
|
||||||
}
|
}
|
||||||
|
@ -24,11 +24,11 @@ trait TLParams
|
|||||||
public function parse_params($key, $mtproto = false)
|
public function parse_params($key, $mtproto = false)
|
||||||
{
|
{
|
||||||
foreach ($this->by_id[$key]['params'] as $kkey => $param) {
|
foreach ($this->by_id[$key]['params'] as $kkey => $param) {
|
||||||
if (preg_match('/(\w*)\.(\d*)\?(.*)/', $param['type'], $matches)) {
|
if (\preg_match('/(\w*)\.(\d*)\?(.*)/', $param['type'], $matches)) {
|
||||||
$param['pow'] = pow(2, $matches[2]);
|
$param['pow'] = \pow(2, $matches[2]);
|
||||||
$param['type'] = $matches[3];
|
$param['type'] = $matches[3];
|
||||||
}
|
}
|
||||||
if (preg_match('/^(v|V)ector\<(.*)\>$/', $param['type'], $matches)) {
|
if (\preg_match('/^(v|V)ector\<(.*)\>$/', $param['type'], $matches)) {
|
||||||
$param['type'] = $matches[1] === 'v' ? 'vector' : 'Vector t';
|
$param['type'] = $matches[1] === 'v' ? 'vector' : 'Vector t';
|
||||||
$param['subtype'] = $matches[2];
|
$param['subtype'] = $matches[2];
|
||||||
$param['subtype'] = ($mtproto && $param['subtype'] === 'Message' ? 'MT' : '').$param['subtype'];
|
$param['subtype'] = ($mtproto && $param['subtype'] === 'Message' ? 'MT' : '').$param['subtype'];
|
||||||
|
@ -41,7 +41,7 @@ class Button implements \JsonSerializable, \ArrayAccess
|
|||||||
|
|
||||||
public function click($donotwait = false, $params = [])
|
public function click($donotwait = false, $params = [])
|
||||||
{
|
{
|
||||||
if (is_array($donotwait)) {
|
if (\is_array($donotwait)) {
|
||||||
$async = $donotwait;
|
$async = $donotwait;
|
||||||
} else {
|
} else {
|
||||||
$async = $params;
|
$async = $params;
|
||||||
|
@ -41,6 +41,6 @@ class Bytes implements \JsonSerializable
|
|||||||
|
|
||||||
public function jsonSerialize()
|
public function jsonSerialize()
|
||||||
{
|
{
|
||||||
return ['_' => 'bytes', 'bytes' => base64_encode($this->bytes)];
|
return ['_' => 'bytes', 'bytes' => \base64_encode($this->bytes)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,22 +20,21 @@ namespace danog\MadelineProto;
|
|||||||
|
|
||||||
use Amp\Deferred;
|
use Amp\Deferred;
|
||||||
use Amp\Failure;
|
use Amp\Failure;
|
||||||
|
use Amp\File\StatCache;
|
||||||
use Amp\Loop;
|
use Amp\Loop;
|
||||||
use Amp\Promise;
|
use Amp\Promise;
|
||||||
use Amp\Success;
|
use Amp\Success;
|
||||||
|
use phpseclib\Math\BigInteger;
|
||||||
|
use function Amp\ByteStream\getOutputBufferStream;
|
||||||
use function Amp\ByteStream\getStdin;
|
use function Amp\ByteStream\getStdin;
|
||||||
use function Amp\ByteStream\getStdout;
|
use function Amp\ByteStream\getStdout;
|
||||||
|
use function Amp\File\exists;
|
||||||
use function Amp\Promise\all;
|
use function Amp\Promise\all;
|
||||||
use function Amp\Promise\any;
|
use function Amp\Promise\any;
|
||||||
use function Amp\Promise\first;
|
use function Amp\Promise\first;
|
||||||
use function Amp\Promise\some;
|
use function Amp\Promise\some;
|
||||||
use function Amp\Promise\timeout;
|
use function Amp\Promise\timeout;
|
||||||
use function Amp\Promise\wait;
|
use function Amp\Promise\wait;
|
||||||
use function Amp\ByteStream\getOutputBufferStream;
|
|
||||||
use function Amp\File\exists;
|
|
||||||
use function Amp\File\touch;
|
|
||||||
use Amp\File\StatCache;
|
|
||||||
use phpseclib\Math\BigInteger;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Some tools.
|
* Some tools.
|
||||||
@ -50,7 +49,7 @@ trait Tools
|
|||||||
foreach ($ints as $int) {
|
foreach ($ints as $int) {
|
||||||
$hash = $hash->multiply(\danog\MadelineProto\Magic::$twozerotwosixone)->add(\danog\MadelineProto\Magic::$zeroeight)->add(new \phpseclib\Math\BigInteger($int))->divide(\danog\MadelineProto\Magic::$zeroeight)[1];
|
$hash = $hash->multiply(\danog\MadelineProto\Magic::$twozerotwosixone)->add(\danog\MadelineProto\Magic::$zeroeight)->add(new \phpseclib\Math\BigInteger($int))->divide(\danog\MadelineProto\Magic::$zeroeight)[1];
|
||||||
}
|
}
|
||||||
$hash = self::unpack_signed_int(strrev(str_pad($hash->toBytes(), 4, "\0", STR_PAD_LEFT)));
|
$hash = self::unpack_signed_int(\strrev(\str_pad($hash->toBytes(), 4, "\0", STR_PAD_LEFT)));
|
||||||
} else {
|
} else {
|
||||||
$hash = 0;
|
$hash = 0;
|
||||||
foreach ($ints as $int) {
|
foreach ($ints as $int) {
|
||||||
@ -102,33 +101,33 @@ trait Tools
|
|||||||
{
|
{
|
||||||
$resto = $a % $b;
|
$resto = $a % $b;
|
||||||
|
|
||||||
return $resto < 0 ? $resto + abs($b) : $resto;
|
return $resto < 0 ? $resto + \abs($b) : $resto;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function unpack_signed_int($value)
|
public static function unpack_signed_int($value)
|
||||||
{
|
{
|
||||||
if (strlen($value) !== 4) {
|
if (\strlen($value) !== 4) {
|
||||||
throw new TL\Exception(\danog\MadelineProto\Lang::$current_lang['length_not_4']);
|
throw new TL\Exception(\danog\MadelineProto\Lang::$current_lang['length_not_4']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return unpack('l', \danog\MadelineProto\Magic::$BIG_ENDIAN ? strrev($value) : $value)[1];
|
return \unpack('l', \danog\MadelineProto\Magic::$BIG_ENDIAN ? \strrev($value) : $value)[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function unpack_signed_long($value)
|
public static function unpack_signed_long($value)
|
||||||
{
|
{
|
||||||
if (strlen($value) !== 8) {
|
if (\strlen($value) !== 8) {
|
||||||
throw new TL\Exception(\danog\MadelineProto\Lang::$current_lang['length_not_8']);
|
throw new TL\Exception(\danog\MadelineProto\Lang::$current_lang['length_not_8']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return unpack('q', \danog\MadelineProto\Magic::$BIG_ENDIAN ? strrev($value) : $value)[1];
|
return \unpack('q', \danog\MadelineProto\Magic::$BIG_ENDIAN ? \strrev($value) : $value)[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function unpack_signed_long_string($value)
|
public static function unpack_signed_long_string($value)
|
||||||
{
|
{
|
||||||
if (is_int($value)) {
|
if (\is_int($value)) {
|
||||||
return (string) $value;
|
return (string) $value;
|
||||||
}
|
}
|
||||||
if (strlen($value) !== 8) {
|
if (\strlen($value) !== 8) {
|
||||||
throw new TL\Exception(\danog\MadelineProto\Lang::$current_lang['length_not_8']);
|
throw new TL\Exception(\danog\MadelineProto\Lang::$current_lang['length_not_8']);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,25 +138,25 @@ trait Tools
|
|||||||
public static function pack_signed_int($value)
|
public static function pack_signed_int($value)
|
||||||
{
|
{
|
||||||
if ($value > 2147483647) {
|
if ($value > 2147483647) {
|
||||||
throw new TL\Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['value_bigger_than_2147483647'], $value));
|
throw new TL\Exception(\sprintf(\danog\MadelineProto\Lang::$current_lang['value_bigger_than_2147483647'], $value));
|
||||||
}
|
}
|
||||||
if ($value < -2147483648) {
|
if ($value < -2147483648) {
|
||||||
throw new TL\Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['value_smaller_than_2147483648'], $value));
|
throw new TL\Exception(\sprintf(\danog\MadelineProto\Lang::$current_lang['value_smaller_than_2147483648'], $value));
|
||||||
}
|
}
|
||||||
$res = pack('l', $value);
|
$res = \pack('l', $value);
|
||||||
|
|
||||||
return \danog\MadelineProto\Magic::$BIG_ENDIAN ? strrev($res) : $res;
|
return \danog\MadelineProto\Magic::$BIG_ENDIAN ? \strrev($res) : $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function pack_signed_long($value)
|
public static function pack_signed_long($value)
|
||||||
{
|
{
|
||||||
if ($value > 9223372036854775807) {
|
if ($value > 9223372036854775807) {
|
||||||
throw new TL\Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['value_bigger_than_9223372036854775807'], $value));
|
throw new TL\Exception(\sprintf(\danog\MadelineProto\Lang::$current_lang['value_bigger_than_9223372036854775807'], $value));
|
||||||
}
|
}
|
||||||
if ($value < -9.223372036854776E+18) {
|
if ($value < -9.223372036854776E+18) {
|
||||||
throw new TL\Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['value_smaller_than_9223372036854775808'], $value));
|
throw new TL\Exception(\sprintf(\danog\MadelineProto\Lang::$current_lang['value_smaller_than_9223372036854775808'], $value));
|
||||||
}
|
}
|
||||||
$res = \danog\MadelineProto\Magic::$bigint ? self::pack_signed_int($value)."\0\0\0\0" : (\danog\MadelineProto\Magic::$BIG_ENDIAN ? strrev(pack('q', $value)) : pack('q', $value));
|
$res = \danog\MadelineProto\Magic::$bigint ? self::pack_signed_int($value)."\0\0\0\0" : (\danog\MadelineProto\Magic::$BIG_ENDIAN ? \strrev(\pack('q', $value)) : \pack('q', $value));
|
||||||
|
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
@ -165,32 +164,32 @@ trait Tools
|
|||||||
public static function pack_unsigned_int($value)
|
public static function pack_unsigned_int($value)
|
||||||
{
|
{
|
||||||
if ($value > 4294967295) {
|
if ($value > 4294967295) {
|
||||||
throw new TL\Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['value_bigger_than_4294967296'], $value));
|
throw new TL\Exception(\sprintf(\danog\MadelineProto\Lang::$current_lang['value_bigger_than_4294967296'], $value));
|
||||||
}
|
}
|
||||||
if ($value < 0) {
|
if ($value < 0) {
|
||||||
throw new TL\Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['value_smaller_than_0'], $value));
|
throw new TL\Exception(\sprintf(\danog\MadelineProto\Lang::$current_lang['value_smaller_than_0'], $value));
|
||||||
}
|
}
|
||||||
|
|
||||||
return pack('V', $value);
|
return \pack('V', $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function pack_double($value)
|
public static function pack_double($value)
|
||||||
{
|
{
|
||||||
$res = pack('d', $value);
|
$res = \pack('d', $value);
|
||||||
if (strlen($res) !== 8) {
|
if (\strlen($res) !== 8) {
|
||||||
throw new TL\Exception(\danog\MadelineProto\Lang::$current_lang['encode_double_error']);
|
throw new TL\Exception(\danog\MadelineProto\Lang::$current_lang['encode_double_error']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return \danog\MadelineProto\Magic::$BIG_ENDIAN ? strrev($res) : $res;
|
return \danog\MadelineProto\Magic::$BIG_ENDIAN ? \strrev($res) : $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function unpack_double($value)
|
public static function unpack_double($value)
|
||||||
{
|
{
|
||||||
if (strlen($value) !== 8) {
|
if (\strlen($value) !== 8) {
|
||||||
throw new TL\Exception(\danog\MadelineProto\Lang::$current_lang['length_not_8']);
|
throw new TL\Exception(\danog\MadelineProto\Lang::$current_lang['length_not_8']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return unpack('d', \danog\MadelineProto\Magic::$BIG_ENDIAN ? strrev($value) : $value)[1];
|
return \unpack('d', \danog\MadelineProto\Magic::$BIG_ENDIAN ? \strrev($value) : $value)[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function wait($promise)
|
public static function wait($promise)
|
||||||
@ -208,7 +207,6 @@ trait Tools
|
|||||||
try {
|
try {
|
||||||
Loop::run(function () use (&$resolved, &$value, &$exception, $promise) {
|
Loop::run(function () use (&$resolved, &$value, &$exception, $promise) {
|
||||||
$promise->onResolve(function ($e, $v) use (&$resolved, &$value, &$exception) {
|
$promise->onResolve(function ($e, $v) use (&$resolved, &$value, &$exception) {
|
||||||
|
|
||||||
Loop::stop();
|
Loop::stop();
|
||||||
$resolved = true;
|
$resolved = true;
|
||||||
$exception = $e;
|
$exception = $e;
|
||||||
@ -284,10 +282,10 @@ trait Tools
|
|||||||
if ($actual) {
|
if ($actual) {
|
||||||
$promise = $actual;
|
$promise = $actual;
|
||||||
} else {
|
} else {
|
||||||
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0];
|
$trace = \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0];
|
||||||
$file = '';
|
$file = '';
|
||||||
if (isset($trace['file'])) {
|
if (isset($trace['file'])) {
|
||||||
$file .= basename($trace['file'], '.php');
|
$file .= \basename($trace['file'], '.php');
|
||||||
}
|
}
|
||||||
if (isset($trace['line'])) {
|
if (isset($trace['line'])) {
|
||||||
$file .= ":{$trace['line']}";
|
$file .= ":{$trace['line']}";
|
||||||
@ -332,7 +330,6 @@ trait Tools
|
|||||||
if (!$zis || !$zis->destructing) {
|
if (!$zis || !$zis->destructing) {
|
||||||
Promise\rethrow(new Failure($e));
|
Promise\rethrow(new Failure($e));
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if ($logger) {
|
if ($logger) {
|
||||||
$logger->logger($e);
|
$logger->logger($e);
|
||||||
@ -373,7 +370,7 @@ trait Tools
|
|||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Asynchronously lock a file
|
* Asynchronously lock a file
|
||||||
* Resolves with a callbable that MUST eventually be called in order to release the lock
|
* Resolves with a callbable that MUST eventually be called in order to release the lock.
|
||||||
*
|
*
|
||||||
* @param string $file File to lock
|
* @param string $file File to lock
|
||||||
* @param integer $operation Locking mode (see flock)
|
* @param integer $operation Locking mode (see flock)
|
||||||
@ -386,22 +383,22 @@ trait Tools
|
|||||||
}
|
}
|
||||||
public static function noCache(int $status, string $message)
|
public static function noCache(int $status, string $message)
|
||||||
{
|
{
|
||||||
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
|
\header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
|
||||||
header('Cache-Control: post-check=0, pre-check=0', false);
|
\header('Cache-Control: post-check=0, pre-check=0', false);
|
||||||
header('Pragma: no-cache');
|
\header('Pragma: no-cache');
|
||||||
http_response_code($status);
|
\http_response_code($status);
|
||||||
return self::echo($message);
|
return self::echo($message);
|
||||||
}
|
}
|
||||||
public static function flockAsync(string $file, int $operation, $polling)
|
public static function flockAsync(string $file, int $operation, $polling)
|
||||||
{
|
{
|
||||||
if (!yield exists($file)) {
|
if (!yield exists($file)) {
|
||||||
yield touch($file);
|
yield \touch($file);
|
||||||
StatCache::clear($file);
|
StatCache::clear($file);
|
||||||
}
|
}
|
||||||
$operation |= LOCK_NB;
|
$operation |= LOCK_NB;
|
||||||
$res = fopen($file, 'c');
|
$res = \fopen($file, 'c');
|
||||||
do {
|
do {
|
||||||
$result = flock($res, $operation);
|
$result = \flock($res, $operation);
|
||||||
if (!$result) {
|
if (!$result) {
|
||||||
yield self::sleep($polling);
|
yield self::sleep($polling);
|
||||||
}
|
}
|
||||||
@ -409,8 +406,8 @@ trait Tools
|
|||||||
|
|
||||||
return static function () use (&$res) {
|
return static function () use (&$res) {
|
||||||
if ($res) {
|
if ($res) {
|
||||||
flock($res, LOCK_UN);
|
\flock($res, LOCK_UN);
|
||||||
fclose($res);
|
\fclose($res);
|
||||||
$res = null;
|
$res = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -431,20 +428,21 @@ trait Tools
|
|||||||
yield $stdout->write($prompt);
|
yield $stdout->write($prompt);
|
||||||
}
|
}
|
||||||
static $lines = [''];
|
static $lines = [''];
|
||||||
while (count($lines) < 2 && ($chunk = yield $stdin->read()) !== null) {
|
while (\count($lines) < 2 && ($chunk = yield $stdin->read()) !== null) {
|
||||||
$chunk = explode("\n", str_replace(["\r", "\n\n"], "\n", $chunk));
|
$chunk = \explode("\n", \str_replace(["\r", "\n\n"], "\n", $chunk));
|
||||||
$lines[count($lines) - 1] .= array_shift($chunk);
|
$lines[\count($lines) - 1] .= \array_shift($chunk);
|
||||||
$lines = array_merge($lines, $chunk);
|
$lines = \array_merge($lines, $chunk);
|
||||||
}
|
}
|
||||||
return array_shift($lines);
|
return \array_shift($lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function echo ($string) {
|
public static function echo($string)
|
||||||
|
{
|
||||||
return getOutputBufferStream()->write($string);
|
return getOutputBufferStream()->write($string);
|
||||||
}
|
}
|
||||||
public static function is_array_or_alike($var)
|
public static function is_array_or_alike($var)
|
||||||
{
|
{
|
||||||
return is_array($var) ||
|
return \is_array($var) ||
|
||||||
($var instanceof ArrayAccess &&
|
($var instanceof ArrayAccess &&
|
||||||
$var instanceof Traversable &&
|
$var instanceof Traversable &&
|
||||||
$var instanceof Countable);
|
$var instanceof Countable);
|
||||||
|
@ -46,7 +46,7 @@ trait AuthKeyHandler
|
|||||||
|
|
||||||
public function request_call_async($user)
|
public function request_call_async($user)
|
||||||
{
|
{
|
||||||
if (!class_exists('\\danog\\MadelineProto\\VoIP')) {
|
if (!\class_exists('\\danog\\MadelineProto\\VoIP')) {
|
||||||
throw \danog\MadelineProto\Exception::extension('libtgvoip');
|
throw \danog\MadelineProto\Exception::extension('libtgvoip');
|
||||||
}
|
}
|
||||||
$user = yield $this->get_info_async($user);
|
$user = yield $this->get_info_async($user);
|
||||||
@ -54,7 +54,7 @@ trait AuthKeyHandler
|
|||||||
throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['peer_not_in_db']);
|
throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['peer_not_in_db']);
|
||||||
}
|
}
|
||||||
$user = $user['InputUser'];
|
$user = $user['InputUser'];
|
||||||
$this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['calling_user'], $user['user_id']), \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['calling_user'], $user['user_id']), \danog\MadelineProto\Logger::VERBOSE);
|
||||||
$dh_config = yield $this->get_dh_config_async();
|
$dh_config = yield $this->get_dh_config_async();
|
||||||
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['generating_a'], \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['generating_a'], \danog\MadelineProto\Logger::VERBOSE);
|
||||||
$a = \phpseclib\Math\BigInteger::randomRange(\danog\MadelineProto\Magic::$two, $dh_config['p']->subtract(\danog\MadelineProto\Magic::$two));
|
$a = \phpseclib\Math\BigInteger::randomRange(\danog\MadelineProto\Magic::$two, $dh_config['p']->subtract(\danog\MadelineProto\Magic::$two));
|
||||||
@ -62,8 +62,8 @@ trait AuthKeyHandler
|
|||||||
$g_a = $dh_config['g']->powMod($a, $dh_config['p']);
|
$g_a = $dh_config['g']->powMod($a, $dh_config['p']);
|
||||||
$this->check_G($g_a, $dh_config['p']);
|
$this->check_G($g_a, $dh_config['p']);
|
||||||
$controller = new \danog\MadelineProto\VoIP(true, $user['user_id'], $this, \danog\MadelineProto\VoIP::CALL_STATE_REQUESTED);
|
$controller = new \danog\MadelineProto\VoIP(true, $user['user_id'], $this, \danog\MadelineProto\VoIP::CALL_STATE_REQUESTED);
|
||||||
$controller->storage = ['a' => $a, 'g_a' => str_pad($g_a->toBytes(), 256, chr(0), \STR_PAD_LEFT)];
|
$controller->storage = ['a' => $a, 'g_a' => \str_pad($g_a->toBytes(), 256, \chr(0), \STR_PAD_LEFT)];
|
||||||
$res = yield $this->method_call_async_read('phone.requestCall', ['user_id' => $user, 'g_a_hash' => hash('sha256', $g_a->toBytes(), true), 'protocol' => ['_' => 'phoneCallProtocol', 'udp_p2p' => true, 'udp_reflector' => true, 'min_layer' => 65, 'max_layer' => \danog\MadelineProto\VoIP::getConnectionMaxLayer()]], ['datacenter' => $this->datacenter->curdc]);
|
$res = yield $this->method_call_async_read('phone.requestCall', ['user_id' => $user, 'g_a_hash' => \hash('sha256', $g_a->toBytes(), true), 'protocol' => ['_' => 'phoneCallProtocol', 'udp_p2p' => true, 'udp_reflector' => true, 'min_layer' => 65, 'max_layer' => \danog\MadelineProto\VoIP::getConnectionMaxLayer()]], ['datacenter' => $this->datacenter->curdc]);
|
||||||
$controller->setCall($res['phone_call']);
|
$controller->setCall($res['phone_call']);
|
||||||
$this->calls[$res['phone_call']['id']] = $controller;
|
$this->calls[$res['phone_call']['id']] = $controller;
|
||||||
yield $this->updaters[false]->resume();
|
yield $this->updaters[false]->resume();
|
||||||
@ -73,15 +73,15 @@ trait AuthKeyHandler
|
|||||||
|
|
||||||
public function accept_call_async($call)
|
public function accept_call_async($call)
|
||||||
{
|
{
|
||||||
if (!class_exists('\\danog\\MadelineProto\\VoIP')) {
|
if (!\class_exists('\\danog\\MadelineProto\\VoIP')) {
|
||||||
throw new \danog\MadelineProto\Exception();
|
throw new \danog\MadelineProto\Exception();
|
||||||
}
|
}
|
||||||
if ($this->call_status($call['id']) !== \danog\MadelineProto\VoIP::CALL_STATE_ACCEPTED) {
|
if ($this->call_status($call['id']) !== \danog\MadelineProto\VoIP::CALL_STATE_ACCEPTED) {
|
||||||
$this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['call_error_1'], $call['id']));
|
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['call_error_1'], $call['id']));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['accepting_call'], $this->calls[$call['id']]->getOtherID()), \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['accepting_call'], $this->calls[$call['id']]->getOtherID()), \danog\MadelineProto\Logger::VERBOSE);
|
||||||
$dh_config = yield $this->get_dh_config_async();
|
$dh_config = yield $this->get_dh_config_async();
|
||||||
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['generating_b'], \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['generating_b'], \danog\MadelineProto\Logger::VERBOSE);
|
||||||
$b = \phpseclib\Math\BigInteger::randomRange(\danog\MadelineProto\Magic::$two, $dh_config['p']->subtract(\danog\MadelineProto\Magic::$two));
|
$b = \phpseclib\Math\BigInteger::randomRange(\danog\MadelineProto\Magic::$two, $dh_config['p']->subtract(\danog\MadelineProto\Magic::$two));
|
||||||
@ -92,7 +92,7 @@ trait AuthKeyHandler
|
|||||||
$res = yield $this->method_call_async_read('phone.acceptCall', ['peer' => $call, 'g_b' => $g_b->toBytes(), 'protocol' => ['_' => 'phoneCallProtocol', 'udp_reflector' => true, 'udp_p2p' => true, 'min_layer' => 65, 'max_layer' => \danog\MadelineProto\VoIP::getConnectionMaxLayer()]], ['datacenter' => $this->datacenter->curdc]);
|
$res = yield $this->method_call_async_read('phone.acceptCall', ['peer' => $call, 'g_b' => $g_b->toBytes(), 'protocol' => ['_' => 'phoneCallProtocol', 'udp_reflector' => true, 'udp_p2p' => true, 'min_layer' => 65, 'max_layer' => \danog\MadelineProto\VoIP::getConnectionMaxLayer()]], ['datacenter' => $this->datacenter->curdc]);
|
||||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||||
if ($e->rpc === 'CALL_ALREADY_ACCEPTED') {
|
if ($e->rpc === 'CALL_ALREADY_ACCEPTED') {
|
||||||
$this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['call_already_accepted'], $call['id']));
|
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['call_already_accepted'], $call['id']));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -113,24 +113,24 @@ trait AuthKeyHandler
|
|||||||
|
|
||||||
public function confirm_call_async($params)
|
public function confirm_call_async($params)
|
||||||
{
|
{
|
||||||
if (!class_exists('\\danog\\MadelineProto\\VoIP')) {
|
if (!\class_exists('\\danog\\MadelineProto\\VoIP')) {
|
||||||
throw \danog\MadelineProto\Exception::extension('libtgvoip');
|
throw \danog\MadelineProto\Exception::extension('libtgvoip');
|
||||||
}
|
}
|
||||||
if ($this->call_status($params['id']) !== \danog\MadelineProto\VoIP::CALL_STATE_REQUESTED) {
|
if ($this->call_status($params['id']) !== \danog\MadelineProto\VoIP::CALL_STATE_REQUESTED) {
|
||||||
$this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['call_error_2'], $params['id']));
|
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['call_error_2'], $params['id']));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['call_confirming'], $this->calls[$params['id']]->getOtherID()), \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['call_confirming'], $this->calls[$params['id']]->getOtherID()), \danog\MadelineProto\Logger::VERBOSE);
|
||||||
$dh_config = yield $this->get_dh_config_async();
|
$dh_config = yield $this->get_dh_config_async();
|
||||||
$params['g_b'] = new \phpseclib\Math\BigInteger((string) $params['g_b'], 256);
|
$params['g_b'] = new \phpseclib\Math\BigInteger((string) $params['g_b'], 256);
|
||||||
$this->check_G($params['g_b'], $dh_config['p']);
|
$this->check_G($params['g_b'], $dh_config['p']);
|
||||||
$key = str_pad($params['g_b']->powMod($this->calls[$params['id']]->storage['a'], $dh_config['p'])->toBytes(), 256, chr(0), \STR_PAD_LEFT);
|
$key = \str_pad($params['g_b']->powMod($this->calls[$params['id']]->storage['a'], $dh_config['p'])->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
|
||||||
try {
|
try {
|
||||||
$res = yield $this->method_call_async_read('phone.confirmCall', ['key_fingerprint' => substr(sha1($key, true), -8), 'peer' => ['id' => $params['id'], 'access_hash' => $params['access_hash'], '_' => 'inputPhoneCall'], 'g_a' => $this->calls[$params['id']]->storage['g_a'], 'protocol' => ['_' => 'phoneCallProtocol', 'udp_reflector' => true, 'min_layer' => 65, 'max_layer' => \danog\MadelineProto\VoIP::getConnectionMaxLayer()]], ['datacenter' => $this->datacenter->curdc])['phone_call'];
|
$res = yield $this->method_call_async_read('phone.confirmCall', ['key_fingerprint' => \substr(\sha1($key, true), -8), 'peer' => ['id' => $params['id'], 'access_hash' => $params['access_hash'], '_' => 'inputPhoneCall'], 'g_a' => $this->calls[$params['id']]->storage['g_a'], 'protocol' => ['_' => 'phoneCallProtocol', 'udp_reflector' => true, 'min_layer' => 65, 'max_layer' => \danog\MadelineProto\VoIP::getConnectionMaxLayer()]], ['datacenter' => $this->datacenter->curdc])['phone_call'];
|
||||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||||
if ($e->rpc === 'CALL_ALREADY_ACCEPTED') {
|
if ($e->rpc === 'CALL_ALREADY_ACCEPTED') {
|
||||||
$this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['call_already_accepted'], $call['id']));
|
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['call_already_accepted'], $call['id']));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -145,15 +145,15 @@ trait AuthKeyHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
$visualization = [];
|
$visualization = [];
|
||||||
$length = new \phpseclib\Math\BigInteger(count(\danog\MadelineProto\Magic::$emojis));
|
$length = new \phpseclib\Math\BigInteger(\count(\danog\MadelineProto\Magic::$emojis));
|
||||||
foreach (str_split(hash('sha256', $key.str_pad($this->calls[$params['id']]->storage['g_a'], 256, chr(0), \STR_PAD_LEFT), true), 8) as $number) {
|
foreach (\str_split(\hash('sha256', $key.\str_pad($this->calls[$params['id']]->storage['g_a'], 256, \chr(0), \STR_PAD_LEFT), true), 8) as $number) {
|
||||||
$number[0] = chr(ord($number[0]) & 0x7f);
|
$number[0] = \chr(\ord($number[0]) & 0x7f);
|
||||||
$visualization[] = \danog\MadelineProto\Magic::$emojis[(int) (new \phpseclib\Math\BigInteger($number, 256))->divide($length)[1]->toString()];
|
$visualization[] = \danog\MadelineProto\Magic::$emojis[(int) (new \phpseclib\Math\BigInteger($number, 256))->divide($length)[1]->toString()];
|
||||||
}
|
}
|
||||||
$this->calls[$params['id']]->setVisualization($visualization);
|
$this->calls[$params['id']]->setVisualization($visualization);
|
||||||
|
|
||||||
$this->calls[$params['id']]->configuration['endpoints'] = array_merge($res['connections'], $this->calls[$params['id']]->configuration['endpoints']);
|
$this->calls[$params['id']]->configuration['endpoints'] = \array_merge($res['connections'], $this->calls[$params['id']]->configuration['endpoints']);
|
||||||
$this->calls[$params['id']]->configuration = array_merge(['recv_timeout' => $this->config['call_receive_timeout_ms'] / 1000, 'init_timeout' => $this->config['call_connect_timeout_ms'] / 1000, 'data_saving' => \danog\MadelineProto\VoIP::DATA_SAVING_NEVER, 'enable_NS' => true, 'enable_AEC' => true, 'enable_AGC' => true, 'auth_key' => $key, 'auth_key_id' => substr(sha1($key, true), -8), 'call_id' => substr(hash('sha256', $key, true), -16), 'network_type' => \danog\MadelineProto\VoIP::NET_TYPE_ETHERNET], $this->calls[$params['id']]->configuration);
|
$this->calls[$params['id']]->configuration = \array_merge(['recv_timeout' => $this->config['call_receive_timeout_ms'] / 1000, 'init_timeout' => $this->config['call_connect_timeout_ms'] / 1000, 'data_saving' => \danog\MadelineProto\VoIP::DATA_SAVING_NEVER, 'enable_NS' => true, 'enable_AEC' => true, 'enable_AGC' => true, 'auth_key' => $key, 'auth_key_id' => \substr(\sha1($key, true), -8), 'call_id' => \substr(\hash('sha256', $key, true), -16), 'network_type' => \danog\MadelineProto\VoIP::NET_TYPE_ETHERNET], $this->calls[$params['id']]->configuration);
|
||||||
$this->calls[$params['id']]->parseConfig();
|
$this->calls[$params['id']]->parseConfig();
|
||||||
$res = $this->calls[$params['id']]->startTheMagic();
|
$res = $this->calls[$params['id']]->startTheMagic();
|
||||||
|
|
||||||
@ -162,34 +162,34 @@ trait AuthKeyHandler
|
|||||||
|
|
||||||
public function complete_call_async($params)
|
public function complete_call_async($params)
|
||||||
{
|
{
|
||||||
if (!class_exists('\\danog\\MadelineProto\\VoIP')) {
|
if (!\class_exists('\\danog\\MadelineProto\\VoIP')) {
|
||||||
throw \danog\MadelineProto\Exception::extension('libtgvoip');
|
throw \danog\MadelineProto\Exception::extension('libtgvoip');
|
||||||
}
|
}
|
||||||
if ($this->call_status($params['id']) !== \danog\MadelineProto\VoIP::CALL_STATE_ACCEPTED || !isset($this->calls[$params['id']]->storage['b'])) {
|
if ($this->call_status($params['id']) !== \danog\MadelineProto\VoIP::CALL_STATE_ACCEPTED || !isset($this->calls[$params['id']]->storage['b'])) {
|
||||||
$this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['call_error_3'], $params['id']));
|
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['call_error_3'], $params['id']));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['call_completing'], $this->calls[$params['id']]->getOtherID()), \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['call_completing'], $this->calls[$params['id']]->getOtherID()), \danog\MadelineProto\Logger::VERBOSE);
|
||||||
$dh_config = yield $this->get_dh_config_async();
|
$dh_config = yield $this->get_dh_config_async();
|
||||||
if (hash('sha256', $params['g_a_or_b'], true) != $this->calls[$params['id']]->storage['g_a_hash']) {
|
if (\hash('sha256', $params['g_a_or_b'], true) != $this->calls[$params['id']]->storage['g_a_hash']) {
|
||||||
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['invalid_g_a']);
|
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['invalid_g_a']);
|
||||||
}
|
}
|
||||||
$params['g_a_or_b'] = new \phpseclib\Math\BigInteger((string) $params['g_a_or_b'], 256);
|
$params['g_a_or_b'] = new \phpseclib\Math\BigInteger((string) $params['g_a_or_b'], 256);
|
||||||
$this->check_G($params['g_a_or_b'], $dh_config['p']);
|
$this->check_G($params['g_a_or_b'], $dh_config['p']);
|
||||||
$key = str_pad($params['g_a_or_b']->powMod($this->calls[$params['id']]->storage['b'], $dh_config['p'])->toBytes(), 256, chr(0), \STR_PAD_LEFT);
|
$key = \str_pad($params['g_a_or_b']->powMod($this->calls[$params['id']]->storage['b'], $dh_config['p'])->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
|
||||||
if (substr(sha1($key, true), -8) != $params['key_fingerprint']) {
|
if (\substr(\sha1($key, true), -8) != $params['key_fingerprint']) {
|
||||||
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['fingerprint_invalid']);
|
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['fingerprint_invalid']);
|
||||||
}
|
}
|
||||||
$visualization = [];
|
$visualization = [];
|
||||||
$length = new \phpseclib\Math\BigInteger(count(\danog\MadelineProto\Magic::$emojis));
|
$length = new \phpseclib\Math\BigInteger(\count(\danog\MadelineProto\Magic::$emojis));
|
||||||
foreach (str_split(hash('sha256', $key.str_pad($params['g_a_or_b']->toBytes(), 256, chr(0), \STR_PAD_LEFT), true), 8) as $number) {
|
foreach (\str_split(\hash('sha256', $key.\str_pad($params['g_a_or_b']->toBytes(), 256, \chr(0), \STR_PAD_LEFT), true), 8) as $number) {
|
||||||
$number[0] = chr(ord($number[0]) & 0x7f);
|
$number[0] = \chr(\ord($number[0]) & 0x7f);
|
||||||
$visualization[] = \danog\MadelineProto\Magic::$emojis[(int) (new \phpseclib\Math\BigInteger($number, 256))->divide($length)[1]->toString()];
|
$visualization[] = \danog\MadelineProto\Magic::$emojis[(int) (new \phpseclib\Math\BigInteger($number, 256))->divide($length)[1]->toString()];
|
||||||
}
|
}
|
||||||
$this->calls[$params['id']]->setVisualization($visualization);
|
$this->calls[$params['id']]->setVisualization($visualization);
|
||||||
$this->calls[$params['id']]->configuration['endpoints'] = array_merge($params['connections'], $this->calls[$params['id']]->configuration['endpoints']);
|
$this->calls[$params['id']]->configuration['endpoints'] = \array_merge($params['connections'], $this->calls[$params['id']]->configuration['endpoints']);
|
||||||
$this->calls[$params['id']]->configuration = array_merge(['recv_timeout' => $this->config['call_receive_timeout_ms'] / 1000, 'init_timeout' => $this->config['call_connect_timeout_ms'] / 1000, 'data_saving' => \danog\MadelineProto\VoIP::DATA_SAVING_NEVER, 'enable_NS' => true, 'enable_AEC' => true, 'enable_AGC' => true, 'auth_key' => $key, 'auth_key_id' => substr(sha1($key, true), -8), 'call_id' => substr(hash('sha256', $key, true), -16), 'network_type' => \danog\MadelineProto\VoIP::NET_TYPE_ETHERNET], $this->calls[$params['id']]->configuration);
|
$this->calls[$params['id']]->configuration = \array_merge(['recv_timeout' => $this->config['call_receive_timeout_ms'] / 1000, 'init_timeout' => $this->config['call_connect_timeout_ms'] / 1000, 'data_saving' => \danog\MadelineProto\VoIP::DATA_SAVING_NEVER, 'enable_NS' => true, 'enable_AEC' => true, 'enable_AGC' => true, 'auth_key' => $key, 'auth_key_id' => \substr(\sha1($key, true), -8), 'call_id' => \substr(\hash('sha256', $key, true), -16), 'network_type' => \danog\MadelineProto\VoIP::NET_TYPE_ETHERNET], $this->calls[$params['id']]->configuration);
|
||||||
$this->calls[$params['id']]->parseConfig();
|
$this->calls[$params['id']]->parseConfig();
|
||||||
|
|
||||||
return $this->calls[$params['id']]->startTheMagic();
|
return $this->calls[$params['id']]->startTheMagic();
|
||||||
@ -197,7 +197,7 @@ trait AuthKeyHandler
|
|||||||
|
|
||||||
public function call_status($id)
|
public function call_status($id)
|
||||||
{
|
{
|
||||||
if (!class_exists('\\danog\\MadelineProto\\VoIP')) {
|
if (!\class_exists('\\danog\\MadelineProto\\VoIP')) {
|
||||||
throw \danog\MadelineProto\Exception::extension('libtgvoip');
|
throw \danog\MadelineProto\Exception::extension('libtgvoip');
|
||||||
}
|
}
|
||||||
if (isset($this->calls[$id])) {
|
if (isset($this->calls[$id])) {
|
||||||
@ -209,7 +209,7 @@ trait AuthKeyHandler
|
|||||||
|
|
||||||
public function get_call($call)
|
public function get_call($call)
|
||||||
{
|
{
|
||||||
if (!class_exists('\\danog\\MadelineProto\\VoIP')) {
|
if (!\class_exists('\\danog\\MadelineProto\\VoIP')) {
|
||||||
throw \danog\MadelineProto\Exception::extension('libtgvoip');
|
throw \danog\MadelineProto\Exception::extension('libtgvoip');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,40 +218,40 @@ trait AuthKeyHandler
|
|||||||
|
|
||||||
public function discard_call_async($call, $reason, $rating = [], $need_debug = true)
|
public function discard_call_async($call, $reason, $rating = [], $need_debug = true)
|
||||||
{
|
{
|
||||||
if (!class_exists('\\danog\\MadelineProto\\VoIP')) {
|
if (!\class_exists('\\danog\\MadelineProto\\VoIP')) {
|
||||||
throw \danog\MadelineProto\Exception::extension('libtgvoip');
|
throw \danog\MadelineProto\Exception::extension('libtgvoip');
|
||||||
}
|
}
|
||||||
if (!isset($this->calls[$call['id']])) {
|
if (!isset($this->calls[$call['id']])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['call_discarding'], $call['id']), \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['call_discarding'], $call['id']), \danog\MadelineProto\Logger::VERBOSE);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$res = yield $this->method_call_async_read('phone.discardCall', ['peer' => $call, 'duration' => time() - $this->calls[$call['id']]->whenCreated(), 'connection_id' => $this->calls[$call['id']]->getPreferredRelayID(), 'reason' => $reason], ['datacenter' => $this->datacenter->curdc]);
|
$res = yield $this->method_call_async_read('phone.discardCall', ['peer' => $call, 'duration' => \time() - $this->calls[$call['id']]->whenCreated(), 'connection_id' => $this->calls[$call['id']]->getPreferredRelayID(), 'reason' => $reason], ['datacenter' => $this->datacenter->curdc]);
|
||||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||||
if (!in_array($e->rpc, ['CALL_ALREADY_DECLINED', 'CALL_ALREADY_ACCEPTED'])) {
|
if (!\in_array($e->rpc, ['CALL_ALREADY_DECLINED', 'CALL_ALREADY_ACCEPTED'])) {
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!empty($rating)) {
|
if (!empty($rating)) {
|
||||||
$this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['call_set_rating'], $call['id']), \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['call_set_rating'], $call['id']), \danog\MadelineProto\Logger::VERBOSE);
|
||||||
yield $this->method_call_async_read('phone.setCallRating', ['peer' => $call, 'rating' => $rating['rating'], 'comment' => $rating['comment']], ['datacenter' => $this->datacenter->curdc]);
|
yield $this->method_call_async_read('phone.setCallRating', ['peer' => $call, 'rating' => $rating['rating'], 'comment' => $rating['comment']], ['datacenter' => $this->datacenter->curdc]);
|
||||||
}
|
}
|
||||||
if ($need_debug && isset($this->calls[$call['id']])) {
|
if ($need_debug && isset($this->calls[$call['id']])) {
|
||||||
$this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['call_debug_saving'], $call['id']), \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['call_debug_saving'], $call['id']), \danog\MadelineProto\Logger::VERBOSE);
|
||||||
yield $this->method_call_async_read('phone.saveCallDebug', ['peer' => $call, 'debug' => $this->calls[$call['id']]->getDebugLog()], ['datacenter' => $this->datacenter->curdc]);
|
yield $this->method_call_async_read('phone.saveCallDebug', ['peer' => $call, 'debug' => $this->calls[$call['id']]->getDebugLog()], ['datacenter' => $this->datacenter->curdc]);
|
||||||
}
|
}
|
||||||
$update = ['_' => 'updatePhoneCall', 'phone_call' => $this->calls[$call['id']]];
|
$update = ['_' => 'updatePhoneCall', 'phone_call' => $this->calls[$call['id']]];
|
||||||
if (isset($this->settings['pwr']['strict']) && $this->settings['pwr']['strict']) {
|
if (isset($this->settings['pwr']['strict']) && $this->settings['pwr']['strict']) {
|
||||||
$this->pwr_update_handler($update);
|
$this->pwr_update_handler($update);
|
||||||
} else {
|
} else {
|
||||||
in_array($this->settings['updates']['callback'], [['danog\\MadelineProto\\API', 'get_updates_update_handler'], 'get_updates_update_handler']) ? $this->get_updates_update_handler($update) : $this->settings['updates']['callback']($update);
|
\in_array($this->settings['updates']['callback'], [['danog\\MadelineProto\\API', 'get_updates_update_handler'], 'get_updates_update_handler']) ? $this->get_updates_update_handler($update) : $this->settings['updates']['callback']($update);
|
||||||
}
|
}
|
||||||
unset($this->calls[$call['id']]);
|
unset($this->calls[$call['id']]);
|
||||||
}
|
}
|
||||||
public function checkCalls()
|
public function checkCalls()
|
||||||
{
|
{
|
||||||
array_walk($this->calls, function ($controller, $id) {
|
\array_walk($this->calls, function ($controller, $id) {
|
||||||
if ($controller->getCallState() === \danog\MadelineProto\VoIP::CALL_STATE_ENDED) {
|
if ($controller->getCallState() === \danog\MadelineProto\VoIP::CALL_STATE_ENDED) {
|
||||||
$controller->discard();
|
$controller->discard();
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
namespace danog\MadelineProto;
|
namespace danog\MadelineProto;
|
||||||
|
|
||||||
if (class_exists('\\danog\\MadelineProto\\VoIPServerConfigInternal')) {
|
if (\class_exists('\\danog\\MadelineProto\\VoIPServerConfigInternal')) {
|
||||||
/**
|
/**
|
||||||
* Manages storage of VoIP server config.
|
* Manages storage of VoIP server config.
|
||||||
*/
|
*/
|
||||||
@ -90,7 +90,7 @@ if (class_exists('\\danog\\MadelineProto\\VoIPServerConfigInternal')) {
|
|||||||
*/
|
*/
|
||||||
public static function getFinal(): array
|
public static function getFinal(): array
|
||||||
{
|
{
|
||||||
return array_merge(self::$_configDefault, self::$_config);
|
return \array_merge(self::$_configDefault, self::$_config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,11 +28,11 @@ trait ApiStart
|
|||||||
{
|
{
|
||||||
public function api_start_async($settings)
|
public function api_start_async($settings)
|
||||||
{
|
{
|
||||||
if (php_sapi_name() === 'cli') {
|
if (PHP_SAPI === 'cli') {
|
||||||
$stdout = getStdout();
|
$stdout = getStdout();
|
||||||
yield $stdout->write('You did not define a valid API ID/API hash. Do you want to define it now manually, or automatically? (m/a)
|
yield $stdout->write('You did not define a valid API ID/API hash. Do you want to define it now manually, or automatically? (m/a)
|
||||||
Note that you can also provide the API parameters directly in the code using the settings: https://docs.madelineproto.xyz/docs/SETTINGS.html#settingsapp_infoapi_id'.PHP_EOL);
|
Note that you can also provide the API parameters directly in the code using the settings: https://docs.madelineproto.xyz/docs/SETTINGS.html#settingsapp_infoapi_id'.PHP_EOL);
|
||||||
if (strpos(yield $this->readLine('Your choice (m/a): '), 'm') !== false) {
|
if (\strpos(yield $this->readLine('Your choice (m/a): '), 'm') !== false) {
|
||||||
yield $stdout->write('1) Login to my.telegram.org
|
yield $stdout->write('1) Login to my.telegram.org
|
||||||
2) Go to API development tools
|
2) Go to API development tools
|
||||||
3) App title: your app\'s name, can be anything
|
3) App title: your app\'s name, can be anything
|
||||||
@ -45,68 +45,65 @@ Note that you can also provide the API parameters directly in the code using the
|
|||||||
$app['api_hash'] = yield $this->readLine('6) Enter your API hash: ');
|
$app['api_hash'] = yield $this->readLine('6) Enter your API hash: ');
|
||||||
|
|
||||||
return $app;
|
return $app;
|
||||||
|
}
|
||||||
|
$this->my_telegram_org_wrapper = new \danog\MadelineProto\MyTelegramOrgWrapper($settings);
|
||||||
|
yield $this->my_telegram_org_wrapper->login_async(yield $this->readLine('Enter a phone number that is already registered on Telegram: '));
|
||||||
|
yield $this->my_telegram_org_wrapper->complete_login_async(yield $this->readLine('Enter the verification code you received in telegram: '));
|
||||||
|
if (!yield $this->my_telegram_org_wrapper->has_app_async()) {
|
||||||
|
$app_title = yield $this->readLine('Enter the app\'s name, can be anything: ');
|
||||||
|
$short_name = yield $this->readLine('Enter the app\'s short name, can be anything: ');
|
||||||
|
$url = yield $this->readLine('Enter the app/website\'s URL, or t.me/yourusername: ');
|
||||||
|
$description = yield $this->readLine('Describe your app: ');
|
||||||
|
$app = yield $this->my_telegram_org_wrapper->create_app_async(['app_title' => $app_title, 'app_shortname' => $short_name, 'app_url' => $url, 'app_platform' => 'web', 'app_desc' => $description]);
|
||||||
} else {
|
} else {
|
||||||
$this->my_telegram_org_wrapper = new \danog\MadelineProto\MyTelegramOrgWrapper($settings);
|
$app = yield $this->my_telegram_org_wrapper->get_app_async();
|
||||||
yield $this->my_telegram_org_wrapper->login_async(yield $this->readLine('Enter a phone number that is already registered on Telegram: '));
|
}
|
||||||
yield $this->my_telegram_org_wrapper->complete_login_async(yield $this->readLine('Enter the verification code you received in telegram: '));
|
|
||||||
if (!yield $this->my_telegram_org_wrapper->has_app_async()) {
|
return $app;
|
||||||
$app_title = yield $this->readLine('Enter the app\'s name, can be anything: ');
|
}
|
||||||
$short_name = yield $this->readLine('Enter the app\'s short name, can be anything: ');
|
$this->getting_api_id = true;
|
||||||
$url = yield $this->readLine('Enter the app/website\'s URL, or t.me/yourusername: ');
|
if (!isset($this->my_telegram_org_wrapper)) {
|
||||||
$description = yield $this->readLine('Describe your app: ');
|
if (isset($_POST['api_id']) && isset($_POST['api_hash'])) {
|
||||||
$app = yield $this->my_telegram_org_wrapper->create_app_async(['app_title' => $app_title, 'app_shortname' => $short_name, 'app_url' => $url, 'app_platform' => 'web', 'app_desc' => $description]);
|
$app['api_id'] = (int) $_POST['api_id'];
|
||||||
} else {
|
$app['api_hash'] = $_POST['api_hash'];
|
||||||
$app = yield $this->my_telegram_org_wrapper->get_app_async();
|
$this->getting_api_id = false;
|
||||||
|
|
||||||
|
return $app;
|
||||||
|
} elseif (isset($_POST['phone_number'])) {
|
||||||
|
yield $this->web_api_phone_login_async($settings);
|
||||||
|
} else {
|
||||||
|
yield $this->web_api_echo_async();
|
||||||
|
}
|
||||||
|
} elseif (!$this->my_telegram_org_wrapper->logged_in()) {
|
||||||
|
if (isset($_POST['code'])) {
|
||||||
|
yield $this->web_api_complete_login_async();
|
||||||
|
if (yield $this->my_telegram_org_wrapper->has_app_async()) {
|
||||||
|
return yield $this->my_telegram_org_wrapper->get_app_async();
|
||||||
}
|
}
|
||||||
|
yield $this->web_api_echo_async();
|
||||||
|
} elseif (isset($_POST['api_id']) && isset($_POST['api_hash'])) {
|
||||||
|
$app['api_id'] = (int) $_POST['api_id'];
|
||||||
|
$app['api_hash'] = $_POST['api_hash'];
|
||||||
|
$this->getting_api_id = false;
|
||||||
|
|
||||||
|
return $app;
|
||||||
|
} elseif (isset($_POST['phone_number'])) {
|
||||||
|
yield $this->web_api_phone_login_async($settings);
|
||||||
|
} else {
|
||||||
|
$this->my_telegram_org_wrapper = null;
|
||||||
|
yield $this->web_api_echo_async();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isset($_POST['app_title'], $_POST['app_shortname'], $_POST['app_url'], $_POST['app_platform'], $_POST['app_desc'])) {
|
||||||
|
$app = yield $this->web_api_create_app_async();
|
||||||
|
$this->getting_api_id = false;
|
||||||
|
|
||||||
return $app;
|
return $app;
|
||||||
}
|
}
|
||||||
} else {
|
yield $this->web_api_echo_async("You didn't provide all of the required parameters!");
|
||||||
$this->getting_api_id = true;
|
|
||||||
if (!isset($this->my_telegram_org_wrapper)) {
|
|
||||||
if (isset($_POST['api_id']) && isset($_POST['api_hash'])) {
|
|
||||||
$app['api_id'] = (int) $_POST['api_id'];
|
|
||||||
$app['api_hash'] = $_POST['api_hash'];
|
|
||||||
$this->getting_api_id = false;
|
|
||||||
|
|
||||||
return $app;
|
|
||||||
} elseif (isset($_POST['phone_number'])) {
|
|
||||||
yield $this->web_api_phone_login_async($settings);
|
|
||||||
} else {
|
|
||||||
yield $this->web_api_echo_async();
|
|
||||||
}
|
|
||||||
} elseif (!$this->my_telegram_org_wrapper->logged_in()) {
|
|
||||||
if (isset($_POST['code'])) {
|
|
||||||
yield $this->web_api_complete_login_async();
|
|
||||||
if (yield $this->my_telegram_org_wrapper->has_app_async()) {
|
|
||||||
return yield $this->my_telegram_org_wrapper->get_app_async();
|
|
||||||
}
|
|
||||||
yield $this->web_api_echo_async();
|
|
||||||
} elseif (isset($_POST['api_id']) && isset($_POST['api_hash'])) {
|
|
||||||
$app['api_id'] = (int) $_POST['api_id'];
|
|
||||||
$app['api_hash'] = $_POST['api_hash'];
|
|
||||||
$this->getting_api_id = false;
|
|
||||||
|
|
||||||
return $app;
|
|
||||||
} elseif (isset($_POST['phone_number'])) {
|
|
||||||
yield $this->web_api_phone_login_async($settings);
|
|
||||||
} else {
|
|
||||||
$this->my_telegram_org_wrapper = null;
|
|
||||||
yield $this->web_api_echo_async();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (isset($_POST['app_title'], $_POST['app_shortname'], $_POST['app_url'], $_POST['app_platform'], $_POST['app_desc'])) {
|
|
||||||
$app = yield $this->web_api_create_app_async();
|
|
||||||
$this->getting_api_id = false;
|
|
||||||
|
|
||||||
return $app;
|
|
||||||
} else {
|
|
||||||
yield $this->web_api_echo_async("You didn't provide all of the required parameters!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->asyncInitPromise = null;
|
|
||||||
exit;
|
|
||||||
}
|
}
|
||||||
|
$this->asyncInitPromise = null;
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function web_api_phone_login_async($settings)
|
public function web_api_phone_login_async($settings)
|
||||||
|
@ -40,7 +40,7 @@ trait ApiTemplates
|
|||||||
|
|
||||||
public function web_api_echo_template($message, $form)
|
public function web_api_echo_template($message, $form)
|
||||||
{
|
{
|
||||||
return sprintf($this->web_api_template, $message, $form);
|
return \sprintf($this->web_api_template, $message, $form);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get_web_api_template()
|
public function get_web_api_template()
|
||||||
@ -117,7 +117,8 @@ trait ApiTemplates
|
|||||||
<input type="radio" name="app_platform" value="other"> Other (specify in description)
|
<input type="radio" name="app_platform" value="other"> Other (specify in description)
|
||||||
</label>
|
</label>
|
||||||
<br><br>Enter the app description, can be anything: <br><textarea name="app_desc" required></textarea><br><br>
|
<br><br>Enter the app description, can be anything: <br><textarea name="app_desc" required></textarea><br><br>
|
||||||
'));
|
'
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ trait DialogHandler
|
|||||||
|
|
||||||
public function get_full_dialogs_async($force = true)
|
public function get_full_dialogs_async($force = true)
|
||||||
{
|
{
|
||||||
if ($force || !isset($this->dialog_params['offset_date']) || is_null($this->dialog_params['offset_date']) || !isset($this->dialog_params['offset_id']) || is_null($this->dialog_params['offset_id']) || !isset($this->dialog_params['offset_peer']) || is_null($this->dialog_params['offset_peer']) || !isset($this->dialog_params['count']) || is_null($this->dialog_params['count'])) {
|
if ($force || !isset($this->dialog_params['offset_date']) || \is_null($this->dialog_params['offset_date']) || !isset($this->dialog_params['offset_id']) || \is_null($this->dialog_params['offset_id']) || !isset($this->dialog_params['offset_peer']) || \is_null($this->dialog_params['offset_peer']) || !isset($this->dialog_params['count']) || \is_null($this->dialog_params['count'])) {
|
||||||
$this->dialog_params = ['limit' => 100, 'offset_date' => 0, 'offset_id' => 0, 'offset_peer' => ['_' => 'inputPeerEmpty'], 'count' => 0, 'hash' => 0];
|
$this->dialog_params = ['limit' => 100, 'offset_date' => 0, 'offset_id' => 0, 'offset_peer' => ['_' => 'inputPeerEmpty'], 'count' => 0, 'hash' => 0];
|
||||||
}
|
}
|
||||||
if (!isset($this->dialog_params['hash'])) {
|
if (!isset($this->dialog_params['hash'])) {
|
||||||
@ -57,8 +57,8 @@ trait DialogHandler
|
|||||||
$last_peer = 0;
|
$last_peer = 0;
|
||||||
$last_date = 0;
|
$last_date = 0;
|
||||||
$last_id = 0;
|
$last_id = 0;
|
||||||
$res['messages'] = array_reverse($res['messages']);
|
$res['messages'] = \array_reverse($res['messages']);
|
||||||
foreach (array_reverse($res['dialogs']) as $dialog) {
|
foreach (\array_reverse($res['dialogs']) as $dialog) {
|
||||||
$id = $this->get_id($dialog['peer']);
|
$id = $this->get_id($dialog['peer']);
|
||||||
if (!isset($dialogs[$id])) {
|
if (!isset($dialogs[$id])) {
|
||||||
$dialogs[$id] = $dialog;
|
$dialogs[$id] = $dialog;
|
||||||
@ -82,7 +82,7 @@ trait DialogHandler
|
|||||||
$this->dialog_params['offset_date'] = $last_date;
|
$this->dialog_params['offset_date'] = $last_date;
|
||||||
$this->dialog_params['offset_peer'] = $last_peer;
|
$this->dialog_params['offset_peer'] = $last_peer;
|
||||||
$this->dialog_params['offset_id'] = $last_id;
|
$this->dialog_params['offset_id'] = $last_id;
|
||||||
$this->dialog_params['count'] = count($dialogs);
|
$this->dialog_params['count'] = \count($dialogs);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ trait Events
|
|||||||
|
|
||||||
public function setEventHandler($event_handler)
|
public function setEventHandler($event_handler)
|
||||||
{
|
{
|
||||||
if (!class_exists($event_handler) || !is_subclass_of($event_handler, '\danog\MadelineProto\EventHandler')) {
|
if (!\class_exists($event_handler) || !\is_subclass_of($event_handler, '\danog\MadelineProto\EventHandler')) {
|
||||||
throw new \danog\MadelineProto\Exception('Wrong event handler was defined');
|
throw new \danog\MadelineProto\Exception('Wrong event handler was defined');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ trait Events
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$method_name = lcfirst(substr($method, 2));
|
$method_name = \lcfirst(\substr($method, 2));
|
||||||
$this->event_handler_methods[$method_name] = [$this->event_handler_instance, $method];
|
$this->event_handler_methods[$method_name] = [$this->event_handler_instance, $method];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ trait Loop
|
|||||||
|
|
||||||
public function loop_async($max_forks = 0)
|
public function loop_async($max_forks = 0)
|
||||||
{
|
{
|
||||||
if (is_callable($max_forks)) {
|
if (\is_callable($max_forks)) {
|
||||||
$this->logger->logger('Running async callable');
|
$this->logger->logger('Running async callable');
|
||||||
|
|
||||||
return yield $max_forks();
|
return yield $max_forks();
|
||||||
@ -52,20 +52,20 @@ trait Loop
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (in_array($this->settings['updates']['callback'], [['danog\\MadelineProto\\API', 'get_updates_update_handler'], 'get_updates_update_handler'])) {
|
if (\in_array($this->settings['updates']['callback'], [['danog\\MadelineProto\\API', 'get_updates_update_handler'], 'get_updates_update_handler'])) {
|
||||||
$this->logger->logger('Getupdates event handler is enabled, exiting from loop', \danog\MadelineProto\Logger::FATAL_ERROR);
|
$this->logger->logger('Getupdates event handler is enabled, exiting from loop', \danog\MadelineProto\Logger::FATAL_ERROR);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$this->logger->logger('Starting event loop');
|
$this->logger->logger('Starting event loop');
|
||||||
if (!is_callable($this->loop_callback) || (is_array($this->loop_callback) && $this->loop_callback[1] === 'onLoop' && !method_exists(...$this->loop_callback))) {
|
if (!\is_callable($this->loop_callback) || (\is_array($this->loop_callback) && $this->loop_callback[1] === 'onLoop' && !\method_exists(...$this->loop_callback))) {
|
||||||
$this->loop_callback = null;
|
$this->loop_callback = null;
|
||||||
}
|
}
|
||||||
if (php_sapi_name() !== 'cli') {
|
if (PHP_SAPI !== 'cli') {
|
||||||
$needs_restart = true;
|
$needs_restart = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
set_time_limit(-1);
|
\set_time_limit(-1);
|
||||||
} catch (\danog\MadelineProto\Exception $e) {
|
} catch (\danog\MadelineProto\Exception $e) {
|
||||||
$needs_restart = true;
|
$needs_restart = true;
|
||||||
}
|
}
|
||||||
@ -74,37 +74,37 @@ trait Loop
|
|||||||
}
|
}
|
||||||
$this->logger->logger($needs_restart ? 'Will self-restart' : 'Will not self-restart');
|
$this->logger->logger($needs_restart ? 'Will self-restart' : 'Will not self-restart');
|
||||||
|
|
||||||
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
$backtrace = \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||||
$lockfile = dirname(end($backtrace)['file']).'/bot'.$this->authorization['user']['id'].'.lock';
|
$lockfile = \dirname(\end($backtrace)['file']).'/bot'.$this->authorization['user']['id'].'.lock';
|
||||||
unset($backtrace);
|
unset($backtrace);
|
||||||
$try_locking = true;
|
$try_locking = true;
|
||||||
if (!file_exists($lockfile)) {
|
if (!\file_exists($lockfile)) {
|
||||||
touch($lockfile);
|
\touch($lockfile);
|
||||||
$lock = fopen($lockfile, 'r+');
|
$lock = \fopen($lockfile, 'r+');
|
||||||
} elseif (isset($GLOBALS['lock'])) {
|
} elseif (isset($GLOBALS['lock'])) {
|
||||||
$try_locking = false;
|
$try_locking = false;
|
||||||
$lock = $GLOBALS['lock'];
|
$lock = $GLOBALS['lock'];
|
||||||
} else {
|
} else {
|
||||||
$lock = fopen($lockfile, 'r+');
|
$lock = \fopen($lockfile, 'r+');
|
||||||
}
|
}
|
||||||
if ($try_locking) {
|
if ($try_locking) {
|
||||||
$try = 1;
|
$try = 1;
|
||||||
$locked = false;
|
$locked = false;
|
||||||
while (!$locked) {
|
while (!$locked) {
|
||||||
$locked = flock($lock, LOCK_EX | LOCK_NB);
|
$locked = \flock($lock, LOCK_EX | LOCK_NB);
|
||||||
if (!$locked) {
|
if (!$locked) {
|
||||||
$this->closeConnection('Bot is already running');
|
$this->closeConnection('Bot is already running');
|
||||||
if ($try++ >= 30) {
|
if ($try++ >= 30) {
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
sleep(1);
|
\sleep(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Shutdown::addCallback(static function () use ($lock) {
|
Shutdown::addCallback(static function () use ($lock) {
|
||||||
flock($lock, LOCK_UN);
|
\flock($lock, LOCK_UN);
|
||||||
fclose($lock);
|
\fclose($lock);
|
||||||
});
|
});
|
||||||
if ($needs_restart) {
|
if ($needs_restart) {
|
||||||
$logger = &$this->logger;
|
$logger = &$this->logger;
|
||||||
@ -117,24 +117,24 @@ trait Loop
|
|||||||
$params = $_GET;
|
$params = $_GET;
|
||||||
$params['MadelineSelfRestart'] = Tools::random_int();
|
$params['MadelineSelfRestart'] = Tools::random_int();
|
||||||
|
|
||||||
$url = explode($uri, '?', 2)[0] ?? '';
|
$url = \explode($uri, '?', 2)[0] ?? '';
|
||||||
|
|
||||||
$query = http_build_query($params);
|
$query = \http_build_query($params);
|
||||||
$uri = implode('?', [$url, $query]);
|
$uri = \implode('?', [$url, $query]);
|
||||||
|
|
||||||
$payload = $_SERVER['REQUEST_METHOD'].' '.$uri.' '.$_SERVER['SERVER_PROTOCOL']."\r\n".'Host: '.$_SERVER['SERVER_NAME']."\r\n\r\n";
|
$payload = $_SERVER['REQUEST_METHOD'].' '.$uri.' '.$_SERVER['SERVER_PROTOCOL']."\r\n".'Host: '.$_SERVER['SERVER_NAME']."\r\n\r\n";
|
||||||
|
|
||||||
$logger->logger("Connecting to $address:$port");
|
$logger->logger("Connecting to $address:$port");
|
||||||
$a = fsockopen($address, $port);
|
$a = \fsockopen($address, $port);
|
||||||
|
|
||||||
$logger->logger("Sending self-restart payload");
|
$logger->logger("Sending self-restart payload");
|
||||||
$logger->logger($payload);
|
$logger->logger($payload);
|
||||||
fwrite($a, $payload);
|
\fwrite($a, $payload);
|
||||||
|
|
||||||
$logger->logger("Payload sent with token {$params['MadelineSelfRestart']}, waiting for self-restart");
|
$logger->logger("Payload sent with token {$params['MadelineSelfRestart']}, waiting for self-restart");
|
||||||
|
|
||||||
sleep(10);
|
\sleep(10);
|
||||||
fclose($a);
|
\fclose($a);
|
||||||
}, 'restarter');
|
}, 'restarter');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +155,7 @@ trait Loop
|
|||||||
$this->updates = [];
|
$this->updates = [];
|
||||||
foreach ($updates as $update) {
|
foreach ($updates as $update) {
|
||||||
$r = $this->settings['updates']['callback']($update);
|
$r = $this->settings['updates']['callback']($update);
|
||||||
if (is_object($r)) {
|
if (\is_object($r)) {
|
||||||
$this->callFork($r);
|
$this->callFork($r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -171,23 +171,23 @@ trait Loop
|
|||||||
|
|
||||||
public function closeConnection($message = 'OK!')
|
public function closeConnection($message = 'OK!')
|
||||||
{
|
{
|
||||||
if (php_sapi_name() === 'cli' || isset($GLOBALS['exited']) || headers_sent()) {
|
if (PHP_SAPI === 'cli' || isset($GLOBALS['exited']) || \headers_sent()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$this->logger->logger($message);
|
$this->logger->logger($message);
|
||||||
$buffer = @ob_get_contents();
|
$buffer = @\ob_get_contents();
|
||||||
@ob_end_clean();
|
@\ob_end_clean();
|
||||||
header('Connection: close');
|
\header('Connection: close');
|
||||||
ignore_user_abort(true);
|
\ignore_user_abort(true);
|
||||||
$buffer .= '<html><body><h1>'.htmlentities($message).'</h1></body></html>';
|
$buffer .= '<html><body><h1>'.\htmlentities($message).'</h1></body></html>';
|
||||||
echo $buffer;
|
echo $buffer;
|
||||||
$size = max(ob_get_length(), strlen($buffer));
|
$size = \max(\ob_get_length(), \strlen($buffer));
|
||||||
header("Content-Length: $size");
|
\header("Content-Length: $size");
|
||||||
header('Content-Type: text/html');
|
\header('Content-Type: text/html');
|
||||||
ob_end_flush();
|
\ob_end_flush();
|
||||||
flush();
|
\flush();
|
||||||
$GLOBALS['exited'] = true;
|
$GLOBALS['exited'] = true;
|
||||||
if (function_exists('fastcgi_finish_request')) {
|
if (\function_exists('fastcgi_finish_request')) {
|
||||||
\fastcgi_finish_request();
|
\fastcgi_finish_request();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,6 @@
|
|||||||
|
|
||||||
namespace danog\MadelineProto\Wrappers;
|
namespace danog\MadelineProto\Wrappers;
|
||||||
|
|
||||||
use function Amp\ByteStream\getStdin;
|
|
||||||
use function Amp\ByteStream\getStdout;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages simple logging in and out.
|
* Manages simple logging in and out.
|
||||||
*/
|
*/
|
||||||
@ -32,8 +29,8 @@ trait Start
|
|||||||
if ($this->authorized === self::LOGGED_IN) {
|
if ($this->authorized === self::LOGGED_IN) {
|
||||||
return yield $this->get_self_async();
|
return yield $this->get_self_async();
|
||||||
}
|
}
|
||||||
if (php_sapi_name() === 'cli') {
|
if (PHP_SAPI === 'cli') {
|
||||||
if (strpos(yield $this->readLine('Do you want to login as user or bot (u/b)? '), 'b') !== false) {
|
if (\strpos(yield $this->readLine('Do you want to login as user or bot (u/b)? '), 'b') !== false) {
|
||||||
yield $this->bot_login_async(yield $this->readLine('Enter your bot token: '));
|
yield $this->bot_login_async(yield $this->readLine('Enter your bot token: '));
|
||||||
} else {
|
} else {
|
||||||
yield $this->phone_login_async(yield $this->readLine('Enter your phone number: '));
|
yield $this->phone_login_async(yield $this->readLine('Enter your phone number: '));
|
||||||
@ -48,41 +45,40 @@ trait Start
|
|||||||
$this->serialize();
|
$this->serialize();
|
||||||
|
|
||||||
return yield $this->get_self_async();
|
return yield $this->get_self_async();
|
||||||
} else {
|
|
||||||
if ($this->authorized === self::NOT_LOGGED_IN) {
|
|
||||||
if (isset($_POST['phone_number'])) {
|
|
||||||
yield $this->web_phone_login_async();
|
|
||||||
} elseif (isset($_POST['token'])) {
|
|
||||||
yield $this->web_bot_login_async();
|
|
||||||
} else {
|
|
||||||
yield $this->web_echo_async();
|
|
||||||
}
|
|
||||||
} elseif ($this->authorized === self::WAITING_CODE) {
|
|
||||||
if (isset($_POST['phone_code'])) {
|
|
||||||
yield $this->web_complete_phone_login_async();
|
|
||||||
} else {
|
|
||||||
yield $this->web_echo_async("You didn't provide a phone code!");
|
|
||||||
}
|
|
||||||
} elseif ($this->authorized === self::WAITING_PASSWORD) {
|
|
||||||
if (isset($_POST['password'])) {
|
|
||||||
yield $this->web_complete_2fa_login_async();
|
|
||||||
} else {
|
|
||||||
yield $this->web_echo_async("You didn't provide the password!");
|
|
||||||
}
|
|
||||||
} elseif ($this->authorized === self::WAITING_SIGNUP) {
|
|
||||||
if (isset($_POST['first_name'])) {
|
|
||||||
yield $this->web_complete_signup_async();
|
|
||||||
} else {
|
|
||||||
yield $this->web_echo_async("You didn't provide the first name!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($this->authorized === self::LOGGED_IN) {
|
|
||||||
$this->serialize();
|
|
||||||
|
|
||||||
return yield $this->get_self_async();
|
|
||||||
}
|
|
||||||
exit;
|
|
||||||
}
|
}
|
||||||
|
if ($this->authorized === self::NOT_LOGGED_IN) {
|
||||||
|
if (isset($_POST['phone_number'])) {
|
||||||
|
yield $this->web_phone_login_async();
|
||||||
|
} elseif (isset($_POST['token'])) {
|
||||||
|
yield $this->web_bot_login_async();
|
||||||
|
} else {
|
||||||
|
yield $this->web_echo_async();
|
||||||
|
}
|
||||||
|
} elseif ($this->authorized === self::WAITING_CODE) {
|
||||||
|
if (isset($_POST['phone_code'])) {
|
||||||
|
yield $this->web_complete_phone_login_async();
|
||||||
|
} else {
|
||||||
|
yield $this->web_echo_async("You didn't provide a phone code!");
|
||||||
|
}
|
||||||
|
} elseif ($this->authorized === self::WAITING_PASSWORD) {
|
||||||
|
if (isset($_POST['password'])) {
|
||||||
|
yield $this->web_complete_2fa_login_async();
|
||||||
|
} else {
|
||||||
|
yield $this->web_echo_async("You didn't provide the password!");
|
||||||
|
}
|
||||||
|
} elseif ($this->authorized === self::WAITING_SIGNUP) {
|
||||||
|
if (isset($_POST['first_name'])) {
|
||||||
|
yield $this->web_complete_signup_async();
|
||||||
|
} else {
|
||||||
|
yield $this->web_echo_async("You didn't provide the first name!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($this->authorized === self::LOGGED_IN) {
|
||||||
|
$this->serialize();
|
||||||
|
|
||||||
|
return yield $this->get_self_async();
|
||||||
|
}
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function web_phone_login_async()
|
public function web_phone_login_async()
|
||||||
|
@ -27,7 +27,7 @@ trait TOS
|
|||||||
public function check_tos_async()
|
public function check_tos_async()
|
||||||
{
|
{
|
||||||
if ($this->authorized === self::LOGGED_IN && !$this->authorization['user']['bot']) {
|
if ($this->authorized === self::LOGGED_IN && !$this->authorization['user']['bot']) {
|
||||||
if ($this->tos['expires'] < time()) {
|
if ($this->tos['expires'] < \time()) {
|
||||||
$this->logger->logger('Fetching TOS...');
|
$this->logger->logger('Fetching TOS...');
|
||||||
$this->tos = yield $this->method_call_async_read('help.getTermsOfServiceUpdate', [], ['datacenter' => $this->datacenter->curdc]);
|
$this->tos = yield $this->method_call_async_read('help.getTermsOfServiceUpdate', [], ['datacenter' => $this->datacenter->curdc]);
|
||||||
$this->tos['accepted'] = $this->tos['_'] === 'help.termsOfServiceUpdateEmpty';
|
$this->tos['accepted'] = $this->tos['_'] === 'help.termsOfServiceUpdateEmpty';
|
||||||
|
@ -70,7 +70,7 @@ trait Templates
|
|||||||
|
|
||||||
public function web_echo_template($message, $form)
|
public function web_echo_template($message, $form)
|
||||||
{
|
{
|
||||||
return sprintf($this->web_template, $form, $message);
|
return \sprintf($this->web_template, $form, $message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get_web_template()
|
public function get_web_template()
|
||||||
|
@ -4,16 +4,19 @@ function callMe($allable, ...$args)
|
|||||||
{
|
{
|
||||||
return $allable(...$args);
|
return $allable(...$args);
|
||||||
}
|
}
|
||||||
function returnMe($res) {
|
function returnMe($res)
|
||||||
|
{
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
if (!function_exists('is_iterable')) {
|
if (!\function_exists('is_iterable')) {
|
||||||
function is_iterable($var) {
|
function is_iterable($var)
|
||||||
return is_array($var) || $var instanceof Traversable;
|
{
|
||||||
|
return \is_array($var) || $var instanceof Traversable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!function_exists('error_clear_last')) {
|
if (!\function_exists('error_clear_last')) {
|
||||||
function error_clear_last() {
|
function error_clear_last()
|
||||||
@trigger_error("");
|
{
|
||||||
|
@\trigger_error("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ final class APITest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public function testCanUseProtocol($transport, $obfuscated, $protocol, $test_mode, $ipv6): void
|
public function testCanUseProtocol($transport, $obfuscated, $protocol, $test_mode, $ipv6): void
|
||||||
{
|
{
|
||||||
$ping = ['ping_id' => random_int(PHP_INT_MIN, PHP_INT_MAX)];
|
$ping = ['ping_id' => \random_int(PHP_INT_MIN, PHP_INT_MAX)];
|
||||||
$MadelineProto = new \danog\MadelineProto\API(
|
$MadelineProto = new \danog\MadelineProto\API(
|
||||||
[
|
[
|
||||||
'app_info' => [
|
'app_info' => [
|
||||||
|
265
tests/random.php
265
tests/random.php
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Random_* Compatibility Library
|
* Random_* Compatibility Library
|
||||||
* for using the new PHP 7 random_* API in PHP 5 projects
|
* for using the new PHP 7 random_* API in PHP 5 projects.
|
||||||
*
|
*
|
||||||
* @version 2.0.17
|
* @version 2.0.17
|
||||||
* @released 2018-07-04
|
* @released 2018-07-04
|
||||||
@ -29,12 +29,11 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
use phpseclib\Crypt;
|
|
||||||
|
|
||||||
if (!defined('PHP_VERSION_ID')) {
|
if (!\defined('PHP_VERSION_ID')) {
|
||||||
// This constant was introduced in PHP 5.2.7
|
// This constant was introduced in PHP 5.2.7
|
||||||
$RandomCompatversion = array_map('intval', explode('.', PHP_VERSION));
|
$RandomCompatversion = \array_map('intval', \explode('.', PHP_VERSION));
|
||||||
define('PHP_VERSION_ID', $RandomCompatversion[0] * 10000 + $RandomCompatversion[1] * 100 + $RandomCompatversion[2]);
|
\define('PHP_VERSION_ID', $RandomCompatversion[0] * 10000 + $RandomCompatversion[1] * 100 + $RandomCompatversion[2]);
|
||||||
$RandomCompatversion = null;
|
$RandomCompatversion = null;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -43,16 +42,16 @@ if (!defined('PHP_VERSION_ID')) {
|
|||||||
if (PHP_VERSION_ID >= 70000) {
|
if (PHP_VERSION_ID >= 70000) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!defined('RANDOM_COMPAT_READ_BUFFER')) {
|
if (!\defined('RANDOM_COMPAT_READ_BUFFER')) {
|
||||||
define('RANDOM_COMPAT_READ_BUFFER', 8);
|
\define('RANDOM_COMPAT_READ_BUFFER', 8);
|
||||||
}
|
}
|
||||||
$RandomCompatDIR = dirname(__FILE__);
|
$RandomCompatDIR = \dirname(__FILE__);
|
||||||
require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'byte_safe_strings.php';
|
require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'byte_safe_strings.php';
|
||||||
require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'cast_to_int.php';
|
require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'cast_to_int.php';
|
||||||
require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'error_polyfill.php';
|
require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'error_polyfill.php';
|
||||||
if (!is_callable('random_bytes')) {
|
if (!\is_callable('random_bytes')) {
|
||||||
/**
|
/**
|
||||||
* PHP 5.2.0 - 5.6.x way to implement random_bytes()
|
* PHP 5.2.0 - 5.6.x way to implement random_bytes().
|
||||||
*
|
*
|
||||||
* We use conditional statements here to define the function in accordance
|
* We use conditional statements here to define the function in accordance
|
||||||
* to the operating environment. It's a micro-optimization.
|
* to the operating environment. It's a micro-optimization.
|
||||||
@ -65,28 +64,28 @@ if (!is_callable('random_bytes')) {
|
|||||||
*
|
*
|
||||||
* See RATIONALE.md for our reasoning behind this particular order
|
* See RATIONALE.md for our reasoning behind this particular order
|
||||||
*/
|
*/
|
||||||
if (extension_loaded('libsodium')) {
|
if (\extension_loaded('libsodium')) {
|
||||||
// See random_bytes_libsodium.php
|
// See random_bytes_libsodium.php
|
||||||
if (PHP_VERSION_ID >= 50300 && is_callable('\\Sodium\\randombytes_buf')) {
|
if (PHP_VERSION_ID >= 50300 && \is_callable('\\Sodium\\randombytes_buf')) {
|
||||||
require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_libsodium.php';
|
require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_libsodium.php';
|
||||||
} elseif (method_exists('Sodium', 'randombytes_buf')) {
|
} elseif (\method_exists('Sodium', 'randombytes_buf')) {
|
||||||
require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_libsodium_legacy.php';
|
require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_libsodium_legacy.php';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Reading directly from /dev/urandom:
|
* Reading directly from /dev/urandom:.
|
||||||
*/
|
*/
|
||||||
if (DIRECTORY_SEPARATOR === '/') {
|
if (DIRECTORY_SEPARATOR === '/') {
|
||||||
// DIRECTORY_SEPARATOR === '/' on Unix-like OSes -- this is a fast
|
// DIRECTORY_SEPARATOR === '/' on Unix-like OSes -- this is a fast
|
||||||
// way to exclude Windows.
|
// way to exclude Windows.
|
||||||
$RandomCompatUrandom = true;
|
$RandomCompatUrandom = true;
|
||||||
$RandomCompat_basedir = ini_get('open_basedir');
|
$RandomCompat_basedir = \ini_get('open_basedir');
|
||||||
if (!empty($RandomCompat_basedir)) {
|
if (!empty($RandomCompat_basedir)) {
|
||||||
$RandomCompat_open_basedir = explode(PATH_SEPARATOR, strtolower($RandomCompat_basedir));
|
$RandomCompat_open_basedir = \explode(PATH_SEPARATOR, \strtolower($RandomCompat_basedir));
|
||||||
$RandomCompatUrandom = array() !== array_intersect(array('/dev', '/dev/', '/dev/urandom'), $RandomCompat_open_basedir);
|
$RandomCompatUrandom = [] !== \array_intersect(['/dev', '/dev/', '/dev/urandom'], $RandomCompat_open_basedir);
|
||||||
$RandomCompat_open_basedir = null;
|
$RandomCompat_open_basedir = null;
|
||||||
}
|
}
|
||||||
if (!is_callable('random_bytes') && $RandomCompatUrandom && @is_readable('/dev/urandom')) {
|
if (!\is_callable('random_bytes') && $RandomCompatUrandom && @\is_readable('/dev/urandom')) {
|
||||||
// Error suppression on is_readable() in case of an open_basedir
|
// Error suppression on is_readable() in case of an open_basedir
|
||||||
// or safe_mode failure. All we care about is whether or not we
|
// or safe_mode failure. All we care about is whether or not we
|
||||||
// can read it at this point. If the PHP environment is going to
|
// can read it at this point. If the PHP environment is going to
|
||||||
@ -101,7 +100,7 @@ if (!is_callable('random_bytes')) {
|
|||||||
$RandomCompatUrandom = false;
|
$RandomCompatUrandom = false;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* mcrypt_create_iv()
|
* mcrypt_create_iv().
|
||||||
*
|
*
|
||||||
* We only want to use mcypt_create_iv() if:
|
* We only want to use mcypt_create_iv() if:
|
||||||
*
|
*
|
||||||
@ -118,7 +117,7 @@ if (!is_callable('random_bytes')) {
|
|||||||
* - If we're on Windows, we want to use PHP >= 5.3.7 or else
|
* - If we're on Windows, we want to use PHP >= 5.3.7 or else
|
||||||
* we get insufficient entropy errors.
|
* we get insufficient entropy errors.
|
||||||
*/
|
*/
|
||||||
if (!is_callable('random_bytes') && (DIRECTORY_SEPARATOR === '/' || PHP_VERSION_ID >= 50307) && (DIRECTORY_SEPARATOR !== '/' || (PHP_VERSION_ID <= 50609 || PHP_VERSION_ID >= 50613)) && extension_loaded('mcrypt')) {
|
if (!\is_callable('random_bytes') && (DIRECTORY_SEPARATOR === '/' || PHP_VERSION_ID >= 50307) && (DIRECTORY_SEPARATOR !== '/' || (PHP_VERSION_ID <= 50609 || PHP_VERSION_ID >= 50613)) && \extension_loaded('mcrypt')) {
|
||||||
// See random_bytes_mcrypt.php
|
// See random_bytes_mcrypt.php
|
||||||
require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_mcrypt.php';
|
require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_mcrypt.php';
|
||||||
}
|
}
|
||||||
@ -127,12 +126,12 @@ if (!is_callable('random_bytes')) {
|
|||||||
* This is a Windows-specific fallback, for when the mcrypt extension
|
* This is a Windows-specific fallback, for when the mcrypt extension
|
||||||
* isn't loaded.
|
* isn't loaded.
|
||||||
*/
|
*/
|
||||||
if (!is_callable('random_bytes') && extension_loaded('com_dotnet') && class_exists('COM')) {
|
if (!\is_callable('random_bytes') && \extension_loaded('com_dotnet') && \class_exists('COM')) {
|
||||||
$RandomCompat_disabled_classes = preg_split('#\\s*,\\s*#', strtolower(ini_get('disable_classes')));
|
$RandomCompat_disabled_classes = \preg_split('#\\s*,\\s*#', \strtolower(\ini_get('disable_classes')));
|
||||||
if (!in_array('com', $RandomCompat_disabled_classes)) {
|
if (!\in_array('com', $RandomCompat_disabled_classes)) {
|
||||||
try {
|
try {
|
||||||
$RandomCompatCOMtest = new COM('CAPICOM.Utilities.1');
|
$RandomCompatCOMtest = new COM('CAPICOM.Utilities.1');
|
||||||
if (method_exists($RandomCompatCOMtest, 'GetRandom')) {
|
if (\method_exists($RandomCompatCOMtest, 'GetRandom')) {
|
||||||
// See random_bytes_com_dotnet.php
|
// See random_bytes_com_dotnet.php
|
||||||
require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_com_dotnet.php';
|
require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_com_dotnet.php';
|
||||||
}
|
}
|
||||||
@ -144,39 +143,39 @@ if (!is_callable('random_bytes')) {
|
|||||||
$RandomCompatCOMtest = null;
|
$RandomCompatCOMtest = null;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* throw new Exception
|
* throw new Exception.
|
||||||
*/
|
*/
|
||||||
if (!is_callable('random_bytes')) {
|
if (!\is_callable('random_bytes')) {
|
||||||
/**
|
/**
|
||||||
* Safely serialize variables
|
* Safely serialize variables.
|
||||||
*
|
*
|
||||||
* If a class has a private __sleep() it'll emit a warning
|
* If a class has a private __sleep() it'll emit a warning
|
||||||
* @return mixed
|
* @return mixed
|
||||||
* @param mixed $arr
|
* @param mixed $arr
|
||||||
*/
|
*/
|
||||||
function safe_serialize(&$arr)
|
function safe_serialize(&$arr)
|
||||||
{
|
{
|
||||||
if (is_object($arr)) {
|
if (\is_object($arr)) {
|
||||||
return '';
|
return '';
|
||||||
}
|
|
||||||
if (!is_array($arr)) {
|
|
||||||
return serialize($arr);
|
|
||||||
}
|
|
||||||
// prevent circular array recursion
|
|
||||||
if (isset($arr['__phpseclib_marker'])) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
$safearr = [];
|
|
||||||
$arr['__phpseclib_marker'] = true;
|
|
||||||
foreach (array_keys($arr) as $key) {
|
|
||||||
// do not recurse on the '__phpseclib_marker' key itself, for smaller memory usage
|
|
||||||
if ($key !== '__phpseclib_marker') {
|
|
||||||
$safearr[$key] = safe_serialize($arr[$key]);
|
|
||||||
}
|
}
|
||||||
|
if (!\is_array($arr)) {
|
||||||
|
return \serialize($arr);
|
||||||
|
}
|
||||||
|
// prevent circular array recursion
|
||||||
|
if (isset($arr['__phpseclib_marker'])) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
$safearr = [];
|
||||||
|
$arr['__phpseclib_marker'] = true;
|
||||||
|
foreach (\array_keys($arr) as $key) {
|
||||||
|
// do not recurse on the '__phpseclib_marker' key itself, for smaller memory usage
|
||||||
|
if ($key !== '__phpseclib_marker') {
|
||||||
|
$safearr[$key] = safe_serialize($arr[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unset($arr['__phpseclib_marker']);
|
||||||
|
return \serialize($safearr);
|
||||||
}
|
}
|
||||||
unset($arr['__phpseclib_marker']);
|
|
||||||
return serialize($safearr);
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* We don't have any more options, so let's throw an exception right now
|
* We don't have any more options, so let's throw an exception right now
|
||||||
* and hope the developer won't let it fail silently.
|
* and hope the developer won't let it fail silently.
|
||||||
@ -188,104 +187,104 @@ if (!is_callable('random_bytes')) {
|
|||||||
*/
|
*/
|
||||||
function random_bytes($length)
|
function random_bytes($length)
|
||||||
{
|
{
|
||||||
static $crypto = false, $v;
|
static $crypto = false, $v;
|
||||||
if ($crypto === false) {
|
if ($crypto === false) {
|
||||||
// save old session data
|
// save old session data
|
||||||
$old_session_id = session_id();
|
$old_session_id = \session_id();
|
||||||
$old_use_cookies = ini_get('session.use_cookies');
|
$old_use_cookies = \ini_get('session.use_cookies');
|
||||||
$old_session_cache_limiter = session_cache_limiter();
|
$old_session_cache_limiter = \session_cache_limiter();
|
||||||
$_OLD_SESSION = isset($_SESSION) ? $_SESSION : false;
|
$_OLD_SESSION = isset($_SESSION) ? $_SESSION : false;
|
||||||
if ($old_session_id != '') {
|
if ($old_session_id != '') {
|
||||||
session_write_close();
|
\session_write_close();
|
||||||
}
|
|
||||||
session_id(1);
|
|
||||||
ini_set('session.use_cookies', 0);
|
|
||||||
session_cache_limiter('');
|
|
||||||
session_start();
|
|
||||||
$v = (isset($_SERVER) ? safe_serialize($_SERVER) : '') . (isset($_POST) ? safe_serialize($_POST) : '') . (isset($_GET) ? safe_serialize($_GET) : '') . (isset($_COOKIE) ? safe_serialize($_COOKIE) : '') . safe_serialize($GLOBALS) . safe_serialize($_SESSION) . safe_serialize($_OLD_SESSION);
|
|
||||||
$v = $seed = $_SESSION['seed'] = sha1($v, true);
|
|
||||||
if (!isset($_SESSION['count'])) {
|
|
||||||
$_SESSION['count'] = 0;
|
|
||||||
}
|
|
||||||
$_SESSION['count']++;
|
|
||||||
session_write_close();
|
|
||||||
// restore old session data
|
|
||||||
if ($old_session_id != '') {
|
|
||||||
session_id($old_session_id);
|
|
||||||
session_start();
|
|
||||||
ini_set('session.use_cookies', $old_use_cookies);
|
|
||||||
session_cache_limiter($old_session_cache_limiter);
|
|
||||||
} else {
|
|
||||||
if ($_OLD_SESSION !== false) {
|
|
||||||
$_SESSION = $_OLD_SESSION;
|
|
||||||
unset($_OLD_SESSION);
|
|
||||||
} else {
|
|
||||||
unset($_SESSION);
|
|
||||||
}
|
}
|
||||||
}
|
\session_id(1);
|
||||||
// in SSH2 a shared secret and an exchange hash are generated through the key exchange process.
|
\ini_set('session.use_cookies', 0);
|
||||||
// the IV client to server is the hash of that "nonce" with the letter A and for the encryption key it's the letter C.
|
\session_cache_limiter('');
|
||||||
// if the hash doesn't produce enough a key or an IV that's long enough concat successive hashes of the
|
\session_start();
|
||||||
// original hash and the current hash. we'll be emulating that. for more info see the following URL:
|
$v = (isset($_SERVER) ? safe_serialize($_SERVER) : '') . (isset($_POST) ? safe_serialize($_POST) : '') . (isset($_GET) ? safe_serialize($_GET) : '') . (isset($_COOKIE) ? safe_serialize($_COOKIE) : '') . safe_serialize($GLOBALS) . safe_serialize($_SESSION) . safe_serialize($_OLD_SESSION);
|
||||||
//
|
$v = $seed = $_SESSION['seed'] = \sha1($v, true);
|
||||||
// http://tools.ietf.org/html/rfc4253#section-7.2
|
if (!isset($_SESSION['count'])) {
|
||||||
//
|
$_SESSION['count'] = 0;
|
||||||
// see the is_string($crypto) part for an example of how to expand the keys
|
}
|
||||||
$key = sha1($seed . 'A', true);
|
$_SESSION['count']++;
|
||||||
$iv = sha1($seed . 'C', true);
|
\session_write_close();
|
||||||
// ciphers are used as per the nist.gov link below. also, see this link:
|
// restore old session data
|
||||||
//
|
if ($old_session_id != '') {
|
||||||
// http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator#Designs_based_on_cryptographic_primitives
|
\session_id($old_session_id);
|
||||||
switch (true) {
|
\session_start();
|
||||||
case class_exists('\\phpseclib\\Crypt\\AES'):
|
\ini_set('session.use_cookies', $old_use_cookies);
|
||||||
|
\session_cache_limiter($old_session_cache_limiter);
|
||||||
|
} else {
|
||||||
|
if ($_OLD_SESSION !== false) {
|
||||||
|
$_SESSION = $_OLD_SESSION;
|
||||||
|
unset($_OLD_SESSION);
|
||||||
|
} else {
|
||||||
|
unset($_SESSION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// in SSH2 a shared secret and an exchange hash are generated through the key exchange process.
|
||||||
|
// the IV client to server is the hash of that "nonce" with the letter A and for the encryption key it's the letter C.
|
||||||
|
// if the hash doesn't produce enough a key or an IV that's long enough concat successive hashes of the
|
||||||
|
// original hash and the current hash. we'll be emulating that. for more info see the following URL:
|
||||||
|
//
|
||||||
|
// http://tools.ietf.org/html/rfc4253#section-7.2
|
||||||
|
//
|
||||||
|
// see the is_string($crypto) part for an example of how to expand the keys
|
||||||
|
$key = \sha1($seed . 'A', true);
|
||||||
|
$iv = \sha1($seed . 'C', true);
|
||||||
|
// ciphers are used as per the nist.gov link below. also, see this link:
|
||||||
|
//
|
||||||
|
// http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator#Designs_based_on_cryptographic_primitives
|
||||||
|
switch (true) {
|
||||||
|
case \class_exists('\\phpseclib\\Crypt\\AES'):
|
||||||
$crypto = new \phpseclib\Crypt\AES('ctr');
|
$crypto = new \phpseclib\Crypt\AES('ctr');
|
||||||
break;
|
break;
|
||||||
case class_exists('\\phpseclib\\Crypt\\Twofish'):
|
case \class_exists('\\phpseclib\\Crypt\\Twofish'):
|
||||||
$crypto = new \phpseclib\Crypt\Twofish('ctr');
|
$crypto = new \phpseclib\Crypt\Twofish('ctr');
|
||||||
break;
|
break;
|
||||||
case class_exists('\\phpseclib\\Crypt\\Blowfish'):
|
case \class_exists('\\phpseclib\\Crypt\\Blowfish'):
|
||||||
$crypto = new \phpseclib\Crypt\Blowfish('ctr');
|
$crypto = new \phpseclib\Crypt\Blowfish('ctr');
|
||||||
break;
|
break;
|
||||||
case class_exists('\\phpseclib\\Crypt\\TripleDES'):
|
case \class_exists('\\phpseclib\\Crypt\\TripleDES'):
|
||||||
$crypto = new \phpseclib\Crypt\TripleDES('ctr');
|
$crypto = new \phpseclib\Crypt\TripleDES('ctr');
|
||||||
break;
|
break;
|
||||||
case class_exists('\\phpseclib\\Crypt\\DES'):
|
case \class_exists('\\phpseclib\\Crypt\\DES'):
|
||||||
$crypto = new \phpseclib\Crypt\DES('ctr');
|
$crypto = new \phpseclib\Crypt\DES('ctr');
|
||||||
break;
|
break;
|
||||||
case class_exists('\\phpseclib\\Crypt\\RC4'):
|
case \class_exists('\\phpseclib\\Crypt\\RC4'):
|
||||||
$crypto = new \phpseclib\Crypt\RC4();
|
$crypto = new \phpseclib\Crypt\RC4();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new \RuntimeException(__CLASS__ . ' requires at least one symmetric cipher be loaded');
|
throw new \RuntimeException(__CLASS__ . ' requires at least one symmetric cipher be loaded');
|
||||||
}
|
}
|
||||||
$crypto->setKey(substr($key, 0, $crypto->getKeyLength() >> 3));
|
$crypto->setKey(\substr($key, 0, $crypto->getKeyLength() >> 3));
|
||||||
$crypto->setIV(substr($iv, 0, $crypto->getBlockLength() >> 3));
|
$crypto->setIV(\substr($iv, 0, $crypto->getBlockLength() >> 3));
|
||||||
$crypto->enableContinuousBuffer();
|
$crypto->enableContinuousBuffer();
|
||||||
}
|
}
|
||||||
//return $crypto->encrypt(str_repeat("\0", $length));
|
//return $crypto->encrypt(str_repeat("\0", $length));
|
||||||
// the following is based off of ANSI X9.31:
|
// the following is based off of ANSI X9.31:
|
||||||
//
|
//
|
||||||
// http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf
|
// http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf
|
||||||
//
|
//
|
||||||
// OpenSSL uses that same standard for it's random numbers:
|
// OpenSSL uses that same standard for it's random numbers:
|
||||||
//
|
//
|
||||||
// http://www.opensource.apple.com/source/OpenSSL/OpenSSL-38/openssl/fips-1.0/rand/fips_rand.c
|
// http://www.opensource.apple.com/source/OpenSSL/OpenSSL-38/openssl/fips-1.0/rand/fips_rand.c
|
||||||
// (do a search for "ANS X9.31 A.2.4")
|
// (do a search for "ANS X9.31 A.2.4")
|
||||||
$result = '';
|
$result = '';
|
||||||
while (strlen($result) < $length) {
|
while (\strlen($result) < $length) {
|
||||||
$i = $crypto->encrypt(microtime());
|
$i = $crypto->encrypt(\microtime());
|
||||||
// strlen(microtime()) == 21
|
// strlen(microtime()) == 21
|
||||||
$r = $crypto->encrypt($i ^ $v);
|
$r = $crypto->encrypt($i ^ $v);
|
||||||
// strlen($v) == 20
|
// strlen($v) == 20
|
||||||
$v = $crypto->encrypt($r ^ $i);
|
$v = $crypto->encrypt($r ^ $i);
|
||||||
// strlen($r) == 20
|
// strlen($r) == 20
|
||||||
$result .= $r;
|
$result .= $r;
|
||||||
}
|
}
|
||||||
return substr($result, 0, $length);
|
return \substr($result, 0, $length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!is_callable('random_int')) {
|
if (!\is_callable('random_int')) {
|
||||||
require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_int.php';
|
require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_int.php';
|
||||||
}
|
}
|
||||||
$RandomCompatDIR = null;
|
$RandomCompatDIR = null;
|
||||||
|
@ -14,13 +14,13 @@ If not, see <http://www.gnu.org/licenses/>.
|
|||||||
/**
|
/**
|
||||||
* Various ways to load MadelineProto.
|
* Various ways to load MadelineProto.
|
||||||
*/
|
*/
|
||||||
if (!file_exists(__DIR__.'/../vendor/autoload.php')) {
|
if (!\file_exists(__DIR__.'/../vendor/autoload.php')) {
|
||||||
echo 'You did not run composer update, using madeline.php'.PHP_EOL;
|
echo 'You did not run composer update, using madeline.php'.PHP_EOL;
|
||||||
if ($phar = getenv('TRAVIS_PHAR')) {
|
if ($phar = \getenv('TRAVIS_PHAR')) {
|
||||||
include $phar;
|
include $phar;
|
||||||
} else {
|
} else {
|
||||||
if (!file_exists('madeline.php')) {
|
if (!\file_exists('madeline.php')) {
|
||||||
copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');
|
\copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');
|
||||||
}
|
}
|
||||||
include 'madeline.php';
|
include 'madeline.php';
|
||||||
}
|
}
|
||||||
@ -31,23 +31,23 @@ if (!file_exists(__DIR__.'/../vendor/autoload.php')) {
|
|||||||
/*
|
/*
|
||||||
* Load .env for settings
|
* Load .env for settings
|
||||||
*/
|
*/
|
||||||
if (file_exists('.env')) {
|
if (\file_exists('.env')) {
|
||||||
echo 'Loading .env...'.PHP_EOL;
|
echo 'Loading .env...'.PHP_EOL;
|
||||||
$dotenv = Dotenv\Dotenv::create(getcwd());
|
$dotenv = Dotenv\Dotenv::create(\getcwd());
|
||||||
$dotenv->load();
|
$dotenv->load();
|
||||||
}
|
}
|
||||||
if (getenv('TEST_SECRET_CHAT') == '') {
|
if (\getenv('TEST_SECRET_CHAT') == '') {
|
||||||
echo ('TEST_SECRET_CHAT is not defined in .env, please define it (copy .env.example).'.PHP_EOL);
|
echo('TEST_SECRET_CHAT is not defined in .env, please define it (copy .env.example).'.PHP_EOL);
|
||||||
die(1);
|
die(1);
|
||||||
}
|
}
|
||||||
echo 'Loading settings...'.PHP_EOL;
|
echo 'Loading settings...'.PHP_EOL;
|
||||||
$settings = json_decode(getenv('MTPROTO_SETTINGS'), true) ?: [];
|
$settings = \json_decode(\getenv('MTPROTO_SETTINGS'), true) ?: [];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Load MadelineProto
|
* Load MadelineProto
|
||||||
*/
|
*/
|
||||||
echo 'Loading MadelineProto...'.PHP_EOL;
|
echo 'Loading MadelineProto...'.PHP_EOL;
|
||||||
$MadelineProto = new \danog\MadelineProto\API(getcwd().'/testing.madeline', $settings);
|
$MadelineProto = new \danog\MadelineProto\API(\getcwd().'/testing.madeline', $settings);
|
||||||
$MadelineProto->fileGetContents('https://google.com');
|
$MadelineProto->fileGetContents('https://google.com');
|
||||||
$MadelineProto->start();
|
$MadelineProto->start();
|
||||||
|
|
||||||
@ -82,13 +82,13 @@ try {
|
|||||||
/**
|
/**
|
||||||
* A small example message to use for tests.
|
* A small example message to use for tests.
|
||||||
*/
|
*/
|
||||||
$message = (getenv('TRAVIS_COMMIT') == '') ? 'I iz works always (io laborare sembre) (yo lavorar siempre) (mi labori ĉiam) (я всегда работать) (Ik werkuh altijd) (Ngimbonga ngaso sonke isikhathi ukusebenza)' : ('Travis ci tests in progress: commit '.getenv('TRAVIS_COMMIT').', job '.getenv('TRAVIS_JOB_NUMBER').', PHP version: '.getenv('TRAVIS_PHP_VERSION'));
|
$message = (\getenv('TRAVIS_COMMIT') == '') ? 'I iz works always (io laborare sembre) (yo lavorar siempre) (mi labori ĉiam) (я всегда работать) (Ik werkuh altijd) (Ngimbonga ngaso sonke isikhathi ukusebenza)' : ('Travis ci tests in progress: commit '.\getenv('TRAVIS_COMMIT').', job '.\getenv('TRAVIS_JOB_NUMBER').', PHP version: '.\getenv('TRAVIS_PHP_VERSION'));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try making a phone call
|
* Try making a phone call
|
||||||
*/
|
*/
|
||||||
if (!getenv('TRAVIS_COMMIT') && stripos($MadelineProto->readline('Do you want to make a call? (y/n): '), 'y') !== false) {
|
if (!\getenv('TRAVIS_COMMIT') && \stripos($MadelineProto->readline('Do you want to make a call? (y/n): '), 'y') !== false) {
|
||||||
$controller = $MadelineProto->request_call(getenv('TEST_SECRET_CHAT'))->play('input.raw')->then('input.raw')->playOnHold(['input.raw'])->setOutputFile('output.raw');
|
$controller = $MadelineProto->request_call(\getenv('TEST_SECRET_CHAT'))->play('input.raw')->then('input.raw')->playOnHold(['input.raw'])->setOutputFile('output.raw');
|
||||||
while ($controller->getCallState() < \danog\MadelineProto\VoIP::CALL_STATE_READY) {
|
while ($controller->getCallState() < \danog\MadelineProto\VoIP::CALL_STATE_READY) {
|
||||||
$MadelineProto->get_updates();
|
$MadelineProto->get_updates();
|
||||||
}
|
}
|
||||||
@ -101,7 +101,7 @@ if (!getenv('TRAVIS_COMMIT') && stripos($MadelineProto->readline('Do you want to
|
|||||||
/*
|
/*
|
||||||
* Try receiving a phone call
|
* Try receiving a phone call
|
||||||
*/
|
*/
|
||||||
if (!getenv('TRAVIS_COMMIT') && stripos($MadelineProto->readline('Do you want to handle incoming calls? (y/n): '), 'y') !== false) {
|
if (!\getenv('TRAVIS_COMMIT') && \stripos($MadelineProto->readline('Do you want to handle incoming calls? (y/n): '), 'y') !== false) {
|
||||||
$howmany = $MadelineProto->readline('How many calls would you like me to handle? ');
|
$howmany = $MadelineProto->readline('How many calls would you like me to handle? ');
|
||||||
$offset = 0;
|
$offset = 0;
|
||||||
while ($howmany > 0) {
|
while ($howmany > 0) {
|
||||||
@ -111,7 +111,7 @@ if (!getenv('TRAVIS_COMMIT') && stripos($MadelineProto->readline('Do you want to
|
|||||||
$offset = $update['update_id'] + 1; // Just like in the bot API, the offset must be set to the last update_id
|
$offset = $update['update_id'] + 1; // Just like in the bot API, the offset must be set to the last update_id
|
||||||
switch ($update['update']['_']) {
|
switch ($update['update']['_']) {
|
||||||
case 'updatePhoneCall':
|
case 'updatePhoneCall':
|
||||||
if (is_object($update['update']['phone_call']) && $update['update']['phone_call']->getCallState() === \danog\MadelineProto\VoIP::CALL_STATE_INCOMING) {
|
if (\is_object($update['update']['phone_call']) && $update['update']['phone_call']->getCallState() === \danog\MadelineProto\VoIP::CALL_STATE_INCOMING) {
|
||||||
$update['update']['phone_call']->accept()->play('input.raw')->then('input.raw')->playOnHold(['input.raw'])->setOutputFile('output.raw');
|
$update['update']['phone_call']->accept()->play('input.raw')->then('input.raw')->playOnHold(['input.raw'])->setOutputFile('output.raw');
|
||||||
$howmany--;
|
$howmany--;
|
||||||
}
|
}
|
||||||
@ -123,12 +123,12 @@ if (!getenv('TRAVIS_COMMIT') && stripos($MadelineProto->readline('Do you want to
|
|||||||
/*
|
/*
|
||||||
* Secret chat usage
|
* Secret chat usage
|
||||||
*/
|
*/
|
||||||
if (!getenv('TRAVIS_COMMIT') && stripos($MadelineProto->readline('Do you want to make the secret chat tests? (y/n): '), 'y') !== false) {
|
if (!\getenv('TRAVIS_COMMIT') && \stripos($MadelineProto->readline('Do you want to make the secret chat tests? (y/n): '), 'y') !== false) {
|
||||||
/**
|
/**
|
||||||
* Request a secret chat.
|
* Request a secret chat.
|
||||||
*/
|
*/
|
||||||
$secret_chat_id = $MadelineProto->request_secret_chat(getenv('TEST_SECRET_CHAT'));
|
$secret_chat_id = $MadelineProto->request_secret_chat(\getenv('TEST_SECRET_CHAT'));
|
||||||
echo 'Waiting for '.getenv('TEST_SECRET_CHAT').' (secret chat id '.$secret_chat_id.') to accept the secret chat...'.PHP_EOL;
|
echo 'Waiting for '.\getenv('TEST_SECRET_CHAT').' (secret chat id '.$secret_chat_id.') to accept the secret chat...'.PHP_EOL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wait until the other party accepts it
|
* Wait until the other party accepts it
|
||||||
@ -167,13 +167,13 @@ if (!getenv('TRAVIS_COMMIT') && stripos($MadelineProto->readline('Do you want to
|
|||||||
'message' => '', // No text message, only media
|
'message' => '', // No text message, only media
|
||||||
'media' => [
|
'media' => [
|
||||||
'_' => 'decryptedMessageMediaDocument',
|
'_' => 'decryptedMessageMediaDocument',
|
||||||
'thumb' => file_get_contents('tests/faust.preview.jpg'), // The thumbnail must be generated manually, it must be in jpg format, 90x90
|
'thumb' => \file_get_contents('tests/faust.preview.jpg'), // The thumbnail must be generated manually, it must be in jpg format, 90x90
|
||||||
'thumb_w' => 90,
|
'thumb_w' => 90,
|
||||||
'thumb_h' => 90,
|
'thumb_h' => 90,
|
||||||
'mime_type' => mime_content_type('tests/faust.jpg'), // The file's mime type
|
'mime_type' => \mime_content_type('tests/faust.jpg'), // The file's mime type
|
||||||
'caption' => 'This file was uploaded using @MadelineProto', // The caption
|
'caption' => 'This file was uploaded using @MadelineProto', // The caption
|
||||||
'file_name' => 'faust.jpg', // The file's name
|
'file_name' => 'faust.jpg', // The file's name
|
||||||
'size' => filesize('tests/faust.jpg'), // The file's size
|
'size' => \filesize('tests/faust.jpg'), // The file's size
|
||||||
'attributes' => [
|
'attributes' => [
|
||||||
['_' => 'documentAttributeImageSize', 'w' => 1280, 'h' => 914], // Image's resolution
|
['_' => 'documentAttributeImageSize', 'w' => 1280, 'h' => 914], // Image's resolution
|
||||||
],
|
],
|
||||||
@ -191,11 +191,11 @@ if (!getenv('TRAVIS_COMMIT') && stripos($MadelineProto->readline('Do you want to
|
|||||||
'message' => '',
|
'message' => '',
|
||||||
'media' => [
|
'media' => [
|
||||||
'_' => 'decryptedMessageMediaPhoto',
|
'_' => 'decryptedMessageMediaPhoto',
|
||||||
'thumb' => file_get_contents('tests/faust.preview.jpg'),
|
'thumb' => \file_get_contents('tests/faust.preview.jpg'),
|
||||||
'thumb_w' => 90,
|
'thumb_w' => 90,
|
||||||
'thumb_h' => 90,
|
'thumb_h' => 90,
|
||||||
'caption' => 'This file was uploaded using @MadelineProto',
|
'caption' => 'This file was uploaded using @MadelineProto',
|
||||||
'size' => filesize('tests/faust.jpg'),
|
'size' => \filesize('tests/faust.jpg'),
|
||||||
'w' => 1280,
|
'w' => 1280,
|
||||||
'h' => 914,
|
'h' => 914,
|
||||||
],
|
],
|
||||||
@ -203,20 +203,20 @@ if (!getenv('TRAVIS_COMMIT') && stripos($MadelineProto->readline('Do you want to
|
|||||||
];
|
];
|
||||||
|
|
||||||
// GIF, secret chat
|
// GIF, secret chat
|
||||||
$secret_media['gif'] = ['peer' => $secret_chat_id, 'file' => 'tests/pony.mp4', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => file_get_contents('tests/pony.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => mime_content_type('tests/pony.mp4'), 'caption' => 'test', 'file_name' => 'pony.mp4', 'size' => filesize('tests/faust.jpg'), 'attributes' => [['_' => 'documentAttributeAnimated']]]]];
|
$secret_media['gif'] = ['peer' => $secret_chat_id, 'file' => 'tests/pony.mp4', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => \file_get_contents('tests/pony.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => \mime_content_type('tests/pony.mp4'), 'caption' => 'test', 'file_name' => 'pony.mp4', 'size' => \filesize('tests/faust.jpg'), 'attributes' => [['_' => 'documentAttributeAnimated']]]]];
|
||||||
|
|
||||||
// Sticker, secret chat
|
// Sticker, secret chat
|
||||||
$secret_media['sticker'] = ['peer' => $secret_chat_id, 'file' => 'tests/lel.webp', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => file_get_contents('tests/lel.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => mime_content_type('tests/lel.webp'), 'caption' => 'test', 'file_name' => 'lel.webp', 'size' => filesize('tests/lel.webp'), 'attributes' => [['_' => 'documentAttributeSticker', 'alt' => 'LEL', 'stickerset' => ['_' => 'inputStickerSetEmpty']]]]]];
|
$secret_media['sticker'] = ['peer' => $secret_chat_id, 'file' => 'tests/lel.webp', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => \file_get_contents('tests/lel.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => \mime_content_type('tests/lel.webp'), 'caption' => 'test', 'file_name' => 'lel.webp', 'size' => \filesize('tests/lel.webp'), 'attributes' => [['_' => 'documentAttributeSticker', 'alt' => 'LEL', 'stickerset' => ['_' => 'inputStickerSetEmpty']]]]]];
|
||||||
|
|
||||||
// Document, secret chat
|
// Document, secret chat
|
||||||
$secret_media['document'] = ['peer' => $secret_chat_id, 'file' => 'tests/60', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => file_get_contents('tests/faust.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => 'magic/magic', 'caption' => 'test', 'file_name' => 'magic.magic', 'size' => filesize('tests/60'), 'attributes' => [['_' => 'documentAttributeFilename', 'file_name' => 'fairy']]]]];
|
$secret_media['document'] = ['peer' => $secret_chat_id, 'file' => 'tests/60', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => \file_get_contents('tests/faust.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => 'magic/magic', 'caption' => 'test', 'file_name' => 'magic.magic', 'size' => \filesize('tests/60'), 'attributes' => [['_' => 'documentAttributeFilename', 'file_name' => 'fairy']]]]];
|
||||||
|
|
||||||
// Video, secret chat
|
// Video, secret chat
|
||||||
$secret_media['video'] = ['peer' => $secret_chat_id, 'file' => 'tests/swing.mp4', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => file_get_contents('tests/swing.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => mime_content_type('tests/swing.mp4'), 'caption' => 'test', 'file_name' => 'swing.mp4', 'size' => filesize('tests/swing.mp4'), 'attributes' => [['_' => 'documentAttributeVideo']]]]];
|
$secret_media['video'] = ['peer' => $secret_chat_id, 'file' => 'tests/swing.mp4', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => \file_get_contents('tests/swing.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => \mime_content_type('tests/swing.mp4'), 'caption' => 'test', 'file_name' => 'swing.mp4', 'size' => \filesize('tests/swing.mp4'), 'attributes' => [['_' => 'documentAttributeVideo']]]]];
|
||||||
|
|
||||||
// audio, secret chat
|
// audio, secret chat
|
||||||
$secret_media['audio'] = ['peer' => $secret_chat_id, 'file' => 'tests/mosconi.mp3', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => file_get_contents('tests/faust.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => mime_content_type('tests/mosconi.mp3'), 'caption' => 'test', 'file_name' => 'mosconi.mp3', 'size' => filesize('tests/mosconi.mp3'), 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => false, 'title' => 'AH NON LO SO IO', 'performer' => 'IL DIO GERMANO MOSCONI']]]]];
|
$secret_media['audio'] = ['peer' => $secret_chat_id, 'file' => 'tests/mosconi.mp3', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => \file_get_contents('tests/faust.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => \mime_content_type('tests/mosconi.mp3'), 'caption' => 'test', 'file_name' => 'mosconi.mp3', 'size' => \filesize('tests/mosconi.mp3'), 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => false, 'title' => 'AH NON LO SO IO', 'performer' => 'IL DIO GERMANO MOSCONI']]]]];
|
||||||
$secret_media['voice'] = ['peer' => $secret_chat_id, 'file' => 'tests/mosconi.mp3', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => file_get_contents('tests/faust.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => mime_content_type('tests/mosconi.mp3'), 'caption' => 'test', 'file_name' => 'mosconi.mp3', 'size' => filesize('tests/mosconi.mp3'), 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => true, 'title' => 'AH NON LO SO IO', 'performer' => 'IL DIO GERMANO MOSCONI']]]]];
|
$secret_media['voice'] = ['peer' => $secret_chat_id, 'file' => 'tests/mosconi.mp3', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => \file_get_contents('tests/faust.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => \mime_content_type('tests/mosconi.mp3'), 'caption' => 'test', 'file_name' => 'mosconi.mp3', 'size' => \filesize('tests/mosconi.mp3'), 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => true, 'title' => 'AH NON LO SO IO', 'performer' => 'IL DIO GERMANO MOSCONI']]]]];
|
||||||
|
|
||||||
foreach ($secret_media as $type => $smessage) {
|
foreach ($secret_media as $type => $smessage) {
|
||||||
\danog\MadelineProto\Logger::log("Encrypting and uploading $type...");
|
\danog\MadelineProto\Logger::log("Encrypting and uploading $type...");
|
||||||
@ -224,7 +224,7 @@ if (!getenv('TRAVIS_COMMIT') && stripos($MadelineProto->readline('Do you want to
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$mention = $MadelineProto->get_info(getenv('TEST_USERNAME')); // Returns an array with all of the constructors that can be extracted from a username or an id
|
$mention = $MadelineProto->get_info(\getenv('TEST_USERNAME')); // Returns an array with all of the constructors that can be extracted from a username or an id
|
||||||
$mention = $mention['user_id']; // Selects only the numeric user id
|
$mention = $mention['user_id']; // Selects only the numeric user id
|
||||||
$media = [];
|
$media = [];
|
||||||
|
|
||||||
@ -247,7 +247,7 @@ $media['voice'] = ['_' => 'inputMediaUploadedDocument', 'file' => 'tests/mosconi
|
|||||||
$media['document'] = ['_' => 'inputMediaUploadedDocument', 'file' => 'tests/60', 'mime_type' => 'magic/magic', 'attributes' => [['_' => 'documentAttributeFilename', 'file_name' => 'magic.magic']]];
|
$media['document'] = ['_' => 'inputMediaUploadedDocument', 'file' => 'tests/60', 'mime_type' => 'magic/magic', 'attributes' => [['_' => 'documentAttributeFilename', 'file_name' => 'magic.magic']]];
|
||||||
|
|
||||||
$message = 'yay';
|
$message = 'yay';
|
||||||
$mention = $MadelineProto->get_info(getenv('TEST_USERNAME')); // Returns an array with all of the constructors that can be extracted from a username or an id
|
$mention = $MadelineProto->get_info(\getenv('TEST_USERNAME')); // Returns an array with all of the constructors that can be extracted from a username or an id
|
||||||
$mention = $mention['user_id']; // Selects only the numeric user id
|
$mention = $mention['user_id']; // Selects only the numeric user id
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -256,8 +256,8 @@ $MadelineProto->upload('big');
|
|||||||
var_dump(time()-$t);
|
var_dump(time()-$t);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
foreach (json_decode(getenv('TEST_DESTINATION_GROUPS'), true) as $peer) {
|
foreach (\json_decode(\getenv('TEST_DESTINATION_GROUPS'), true) as $peer) {
|
||||||
$sentMessage = $MadelineProto->messages->sendMessage(['peer' => $peer, 'message' => $message, 'entities' => [['_' => 'inputMessageEntityMentionName', 'offset' => 0, 'length' => mb_strlen($message), 'user_id' => $mention]]]);
|
$sentMessage = $MadelineProto->messages->sendMessage(['peer' => $peer, 'message' => $message, 'entities' => [['_' => 'inputMessageEntityMentionName', 'offset' => 0, 'length' => \mb_strlen($message), 'user_id' => $mention]]]);
|
||||||
\danog\MadelineProto\Logger::log($sentMessage, \danog\MadelineProto\Logger::NOTICE);
|
\danog\MadelineProto\Logger::log($sentMessage, \danog\MadelineProto\Logger::NOTICE);
|
||||||
|
|
||||||
foreach ($media as $type => $inputMedia) {
|
foreach ($media as $type => $inputMedia) {
|
||||||
@ -266,7 +266,7 @@ foreach (json_decode(getenv('TEST_DESTINATION_GROUPS'), true) as $peer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (json_decode(getenv('TEST_DESTINATION_GROUPS'), true) as $peer) {
|
foreach (\json_decode(\getenv('TEST_DESTINATION_GROUPS'), true) as $peer) {
|
||||||
$sentMessage = $MadelineProto->messages->sendMessage(['peer' => $peer, 'message' => $message, 'entities' => [['_' => 'inputMessageEntityMentionName', 'offset' => 0, 'length' => mb_strlen($message), 'user_id' => $mention]]]);
|
$sentMessage = $MadelineProto->messages->sendMessage(['peer' => $peer, 'message' => $message, 'entities' => [['_' => 'inputMessageEntityMentionName', 'offset' => 0, 'length' => \mb_strlen($message), 'user_id' => $mention]]]);
|
||||||
\danog\MadelineProto\Logger::log($sentMessage, \danog\MadelineProto\Logger::NOTICE);
|
\danog\MadelineProto\Logger::log($sentMessage, \danog\MadelineProto\Logger::NOTICE);
|
||||||
}
|
}
|
||||||
|
@ -11,10 +11,10 @@ You should have received a copy of the GNU General Public License along with Mad
|
|||||||
If not, see <http://www.gnu.org/licenses/>.
|
If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!file_exists(__DIR__.'/../vendor/autoload.php')) {
|
if (!\file_exists(__DIR__.'/../vendor/autoload.php')) {
|
||||||
echo 'You did not run composer update, using madeline.php'.PHP_EOL;
|
echo 'You did not run composer update, using madeline.php'.PHP_EOL;
|
||||||
if (!file_exists('madeline.php')) {
|
if (!\file_exists('madeline.php')) {
|
||||||
copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');
|
\copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');
|
||||||
}
|
}
|
||||||
include 'madeline.php';
|
include 'madeline.php';
|
||||||
} else {
|
} else {
|
||||||
@ -28,11 +28,11 @@ try {
|
|||||||
$MadelineProto = new \danog\MadelineProto\API('MadelineProto_bot.madeline');
|
$MadelineProto = new \danog\MadelineProto\API('MadelineProto_bot.madeline');
|
||||||
} catch (\danog\MadelineProto\Exception $e) {
|
} catch (\danog\MadelineProto\Exception $e) {
|
||||||
$MadelineProto = new \danog\MadelineProto\API($settings);
|
$MadelineProto = new \danog\MadelineProto\API($settings);
|
||||||
$authorization = $MadelineProto->bot_login(readline('Enter a bot token: '));
|
$authorization = $MadelineProto->bot_login(\readline('Enter a bot token: '));
|
||||||
\danog\MadelineProto\Logger::log($authorization, \danog\MadelineProto\Logger::NOTICE);
|
\danog\MadelineProto\Logger::log($authorization, \danog\MadelineProto\Logger::NOTICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file_exists('token.php') && $MadelineProto === false) {
|
if (\file_exists('token.php') && $MadelineProto === false) {
|
||||||
include_once 'token.php';
|
include_once 'token.php';
|
||||||
$MadelineProto = new \danog\MadelineProto\API($settings);
|
$MadelineProto = new \danog\MadelineProto\API($settings);
|
||||||
$authorization = $MadelineProto->bot_login($MadelineProto_token);
|
$authorization = $MadelineProto->bot_login($MadelineProto_token);
|
||||||
@ -82,7 +82,7 @@ while (true) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (isset($update['update']['message']['message']) && preg_match('|/start|', $update['update']['message']['message'])) {
|
if (isset($update['update']['message']['message']) && \preg_match('|/start|', $update['update']['message']['message'])) {
|
||||||
$MadelineProto->messages->sendMessage(['peer' => $update['update']['message']['from_id'], 'message' => $start, 'reply_to_msg_id' => $update['update']['message']['id'], 'parse_mode' => 'markdown', 'reply_markup' => $reply_markup]);
|
$MadelineProto->messages->sendMessage(['peer' => $update['update']['message']['from_id'], 'message' => $start, 'reply_to_msg_id' => $update['update']['message']['id'], 'parse_mode' => 'markdown', 'reply_markup' => $reply_markup]);
|
||||||
}
|
}
|
||||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||||
@ -95,7 +95,7 @@ while (true) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (preg_match('|/start|', $update['update']['message']['message'])) {
|
if (\preg_match('|/start|', $update['update']['message']['message'])) {
|
||||||
$MadelineProto->messages->sendMessage(['peer' => $update['update']['message']['to_id'], 'message' => $start, 'reply_to_msg_id' => $update['update']['message']['id'], 'parse_mode' => 'markdown', 'reply_markup' => $reply_markup]);
|
$MadelineProto->messages->sendMessage(['peer' => $update['update']['message']['to_id'], 'message' => $start, 'reply_to_msg_id' => $update['update']['message']['id'], 'parse_mode' => 'markdown', 'reply_markup' => $reply_markup]);
|
||||||
}
|
}
|
||||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||||
@ -111,18 +111,18 @@ while (true) {
|
|||||||
$MadelineProto->messages->setInlineBotResults(['query_id' => $update['update']['query_id'], 'results' => [], 'cache_time' => 0, 'switch_pm' => $sswitch]);
|
$MadelineProto->messages->setInlineBotResults(['query_id' => $update['update']['query_id'], 'results' => [], 'cache_time' => 0, 'switch_pm' => $sswitch]);
|
||||||
} else {
|
} else {
|
||||||
$toset = ['query_id' => $update['update']['query_id'], 'results' => [], 'cache_time' => 0, 'private' => true];
|
$toset = ['query_id' => $update['update']['query_id'], 'results' => [], 'cache_time' => 0, 'private' => true];
|
||||||
$rows = explode("\n", $update['update']['query']);
|
$rows = \explode("\n", $update['update']['query']);
|
||||||
$text = array_shift($rows);
|
$text = \array_shift($rows);
|
||||||
if (empty($rows)) {
|
if (empty($rows)) {
|
||||||
$MadelineProto->messages->setInlineBotResults(['query_id' => $update['update']['query_id'], 'results' => [], 'cache_time' => 0, 'switch_pm' => $sswitch]);
|
$MadelineProto->messages->setInlineBotResults(['query_id' => $update['update']['query_id'], 'results' => [], 'cache_time' => 0, 'switch_pm' => $sswitch]);
|
||||||
} else {
|
} else {
|
||||||
array_walk($rows, function (&$value, $key) {
|
\array_walk($rows, function (&$value, $key) {
|
||||||
$value = explode('|', $value);
|
$value = \explode('|', $value);
|
||||||
array_walk($value, function (&$value, $key) {
|
\array_walk($value, function (&$value, $key) {
|
||||||
$value = ['text' => trim($value), 'url' => 'https://yayponies.eu'];
|
$value = ['text' => \trim($value), 'url' => 'https://yayponies.eu'];
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
$toset['results'] = [['_' => 'inputBotInlineResult', 'id' => (string) random_int(0, pow(2, 31) - 1), 'type' => 'article', 'title' => $text, 'description' => 'Your keyboard', 'send_message' => ['_' => 'inputBotInlineMessageText', 'message' => $text, 'reply_markup' => ['inline_keyboard' => $rows]]]];
|
$toset['results'] = [['_' => 'inputBotInlineResult', 'id' => (string) \random_int(0, \pow(2, 31) - 1), 'type' => 'article', 'title' => $text, 'description' => 'Your keyboard', 'send_message' => ['_' => 'inputBotInlineMessageText', 'message' => $text, 'reply_markup' => ['inline_keyboard' => $rows]]]];
|
||||||
$MadelineProto->messages->setInlineBotResults($toset);
|
$MadelineProto->messages->setInlineBotResults($toset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,10 +11,10 @@ You should have received a copy of the GNU General Public License along with Mad
|
|||||||
If not, see <http://www.gnu.org/licenses/>.
|
If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!file_exists(__DIR__.'/../vendor/autoload.php')) {
|
if (!\file_exists(__DIR__.'/../vendor/autoload.php')) {
|
||||||
echo 'You did not run composer update, using madeline.php'.PHP_EOL;
|
echo 'You did not run composer update, using madeline.php'.PHP_EOL;
|
||||||
if (!file_exists('madeline.php')) {
|
if (!\file_exists('madeline.php')) {
|
||||||
copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');
|
\copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');
|
||||||
}
|
}
|
||||||
include 'madeline.php';
|
include 'madeline.php';
|
||||||
} else {
|
} else {
|
||||||
@ -36,7 +36,7 @@ try {
|
|||||||
} catch (\danog\MadelineProto\Exception $e) {
|
} catch (\danog\MadelineProto\Exception $e) {
|
||||||
\danog\MadelineProto\Logger::log($e->getMessage());
|
\danog\MadelineProto\Logger::log($e->getMessage());
|
||||||
}
|
}
|
||||||
if (file_exists('token.php') && $MadelineProto === false) {
|
if (\file_exists('token.php') && $MadelineProto === false) {
|
||||||
include_once 'token.php';
|
include_once 'token.php';
|
||||||
$MadelineProto = new \danog\MadelineProto\API($settings);
|
$MadelineProto = new \danog\MadelineProto\API($settings);
|
||||||
$authorization = $MadelineProto->bot_login($pipes_token);
|
$authorization = $MadelineProto->bot_login($pipes_token);
|
||||||
@ -44,11 +44,11 @@ if (file_exists('token.php') && $MadelineProto === false) {
|
|||||||
}
|
}
|
||||||
if ($uMadelineProto === false) {
|
if ($uMadelineProto === false) {
|
||||||
echo 'Loading MadelineProto...'.PHP_EOL;
|
echo 'Loading MadelineProto...'.PHP_EOL;
|
||||||
$uMadelineProto = new \danog\MadelineProto\API(array_merge($settings, ['updates' => ['handle_updates' => false]]));
|
$uMadelineProto = new \danog\MadelineProto\API(\array_merge($settings, ['updates' => ['handle_updates' => false]]));
|
||||||
$sentCode = $uMadelineProto->phone_login(readline());
|
$sentCode = $uMadelineProto->phone_login(\readline());
|
||||||
\danog\MadelineProto\Logger::log($sentCode, \danog\MadelineProto\Logger::NOTICE);
|
\danog\MadelineProto\Logger::log($sentCode, \danog\MadelineProto\Logger::NOTICE);
|
||||||
echo 'Enter the code you received: ';
|
echo 'Enter the code you received: ';
|
||||||
$code = fgets(STDIN, (isset($sentCode['type']['length']) ? $sentCode['type']['length'] : 5) + 1);
|
$code = \fgets(STDIN, (isset($sentCode['type']['length']) ? $sentCode['type']['length'] : 5) + 1);
|
||||||
$authorization = $uMadelineProto->complete_phone_login($code);
|
$authorization = $uMadelineProto->complete_phone_login($code);
|
||||||
\danog\MadelineProto\Logger::log($authorization, \danog\MadelineProto\Logger::NOTICE);
|
\danog\MadelineProto\Logger::log($authorization, \danog\MadelineProto\Logger::NOTICE);
|
||||||
if ($authorization['_'] === 'account.noPassword') {
|
if ($authorization['_'] === 'account.noPassword') {
|
||||||
@ -56,14 +56,14 @@ if ($uMadelineProto === false) {
|
|||||||
}
|
}
|
||||||
if ($authorization['_'] === 'account.password') {
|
if ($authorization['_'] === 'account.password') {
|
||||||
\danog\MadelineProto\Logger::log('2FA is enabled', \danog\MadelineProto\Logger::NOTICE);
|
\danog\MadelineProto\Logger::log('2FA is enabled', \danog\MadelineProto\Logger::NOTICE);
|
||||||
$authorization = $uMadelineProto->complete_2fa_login(readline('Please enter your password (hint '.$authorization['hint'].'): '));
|
$authorization = $uMadelineProto->complete_2fa_login(\readline('Please enter your password (hint '.$authorization['hint'].'): '));
|
||||||
}
|
}
|
||||||
echo 'Serializing MadelineProto to session.madeline...'.PHP_EOL;
|
echo 'Serializing MadelineProto to session.madeline...'.PHP_EOL;
|
||||||
echo 'Wrote '.\danog\MadelineProto\Serialization::serialize('session.madeline', $uMadelineProto).' bytes'.PHP_EOL;
|
echo 'Wrote '.\danog\MadelineProto\Serialization::serialize('session.madeline', $uMadelineProto).' bytes'.PHP_EOL;
|
||||||
}
|
}
|
||||||
function inputify(&$stuff)
|
function inputify(&$stuff)
|
||||||
{
|
{
|
||||||
$stuff['_'] = 'input'.ucfirst($stuff['_']);
|
$stuff['_'] = 'input'.\ucfirst($stuff['_']);
|
||||||
|
|
||||||
return $stuff;
|
return $stuff;
|
||||||
}
|
}
|
||||||
@ -127,7 +127,7 @@ while (true) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (preg_match('|/start|', $update['update']['message']['message'])) {
|
if (\preg_match('|/start|', $update['update']['message']['message'])) {
|
||||||
$MadelineProto->messages->sendMessage(['peer' => $update['update']['message']['from_id'], 'message' => $start, 'reply_to_msg_id' => $update['update']['message']['id']]);
|
$MadelineProto->messages->sendMessage(['peer' => $update['update']['message']['from_id'], 'message' => $start, 'reply_to_msg_id' => $update['update']['message']['id']]);
|
||||||
}
|
}
|
||||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||||
@ -140,7 +140,7 @@ while (true) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (preg_match('|/start|', $update['update']['message']['message'])) {
|
if (\preg_match('|/start|', $update['update']['message']['message'])) {
|
||||||
$MadelineProto->messages->sendMessage(['peer' => $update['update']['message']['to_id'], 'message' => $start, 'reply_to_msg_id' => $update['update']['message']['id']]);
|
$MadelineProto->messages->sendMessage(['peer' => $update['update']['message']['to_id'], 'message' => $start, 'reply_to_msg_id' => $update['update']['message']['id']]);
|
||||||
}
|
}
|
||||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||||
@ -156,19 +156,19 @@ while (true) {
|
|||||||
$MadelineProto->messages->setInlineBotResults(['query_id' => $update['update']['query_id'], 'results' => [], 'cache_time' => 0, 'switch_pm' => $sswitch]);
|
$MadelineProto->messages->setInlineBotResults(['query_id' => $update['update']['query_id'], 'results' => [], 'cache_time' => 0, 'switch_pm' => $sswitch]);
|
||||||
} else {
|
} else {
|
||||||
$toset = ['query_id' => $update['update']['query_id'], 'results' => [], 'cache_time' => 0, 'private' => true];
|
$toset = ['query_id' => $update['update']['query_id'], 'results' => [], 'cache_time' => 0, 'private' => true];
|
||||||
if (preg_match('|\$\s*$|', $update['update']['query'])) {
|
if (\preg_match('|\$\s*$|', $update['update']['query'])) {
|
||||||
$exploded = explode('|', preg_replace('/\$\s*$/', '', $update['update']['query']));
|
$exploded = \explode('|', \preg_replace('/\$\s*$/', '', $update['update']['query']));
|
||||||
array_walk($exploded, function (&$value, $key) {
|
\array_walk($exploded, function (&$value, $key) {
|
||||||
$value = preg_replace(['/^\s+/', '/\s+$/'], '', $value);
|
$value = \preg_replace(['/^\s+/', '/\s+$/'], '', $value);
|
||||||
});
|
});
|
||||||
$query = array_shift($exploded);
|
$query = \array_shift($exploded);
|
||||||
foreach ($exploded as $current => $botq) {
|
foreach ($exploded as $current => $botq) {
|
||||||
$bot = preg_replace('|:.*|', '', $botq);
|
$bot = \preg_replace('|:.*|', '', $botq);
|
||||||
if ($bot === '' || $uMadelineProto->get_info($bot)['bot_api_id'] === $MadelineProto->API->authorization['user']['id']) {
|
if ($bot === '' || $uMadelineProto->get_info($bot)['bot_api_id'] === $MadelineProto->API->authorization['user']['id']) {
|
||||||
$toset['switch_pm'] = $sswitch;
|
$toset['switch_pm'] = $sswitch;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$select = preg_replace('|'.$bot.':|', '', $botq);
|
$select = \preg_replace('|'.$bot.':|', '', $botq);
|
||||||
$results = $uMadelineProto->messages->getInlineBotResults(['bot' => $bot, 'peer' => $update['update']['user_id'], 'query' => $query, 'offset' => $offset]);
|
$results = $uMadelineProto->messages->getInlineBotResults(['bot' => $bot, 'peer' => $update['update']['user_id'], 'query' => $query, 'offset' => $offset]);
|
||||||
if (isset($results['switch_pm'])) {
|
if (isset($results['switch_pm'])) {
|
||||||
$toset['switch_pm'] = $results['switch_pm'];
|
$toset['switch_pm'] = $results['switch_pm'];
|
||||||
@ -176,13 +176,13 @@ while (true) {
|
|||||||
}
|
}
|
||||||
$toset['gallery'] = $results['gallery'];
|
$toset['gallery'] = $results['gallery'];
|
||||||
$toset['results'] = [];
|
$toset['results'] = [];
|
||||||
if (is_numeric($select)) {
|
if (\is_numeric($select)) {
|
||||||
$toset['results'][0] = $results['results'][$select - 1];
|
$toset['results'][0] = $results['results'][$select - 1];
|
||||||
} elseif ($select === '') {
|
} elseif ($select === '') {
|
||||||
$toset['results'] = $results['results'];
|
$toset['results'] = $results['results'];
|
||||||
} else {
|
} else {
|
||||||
foreach ($results['results'] as $result) {
|
foreach ($results['results'] as $result) {
|
||||||
if (isset($result['send_message']['message']) && preg_match('|'.$select.'|', $result['send_message']['message'])) {
|
if (isset($result['send_message']['message']) && \preg_match('|'.$select.'|', $result['send_message']['message'])) {
|
||||||
$toset['results'][0] = $result;
|
$toset['results'][0] = $result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -190,7 +190,7 @@ while (true) {
|
|||||||
if (!isset($toset['results'][0])) {
|
if (!isset($toset['results'][0])) {
|
||||||
$toset['results'] = $results['results'];
|
$toset['results'] = $results['results'];
|
||||||
}
|
}
|
||||||
if (count($exploded) - 1 === $current || !isset($toset['results'][0]['send_message']['message'])) {
|
if (\count($exploded) - 1 === $current || !isset($toset['results'][0]['send_message']['message'])) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$query = $toset['results'][0]['send_message']['message'];
|
$query = $toset['results'][0]['send_message']['message'];
|
||||||
@ -199,7 +199,7 @@ while (true) {
|
|||||||
if (empty($toset['results'])) {
|
if (empty($toset['results'])) {
|
||||||
$toset['switch_pm'] = $sswitch;
|
$toset['switch_pm'] = $sswitch;
|
||||||
} else {
|
} else {
|
||||||
array_walk($toset['results'], 'translate');
|
\array_walk($toset['results'], 'translate');
|
||||||
}
|
}
|
||||||
$MadelineProto->messages->setInlineBotResults($toset);
|
$MadelineProto->messages->setInlineBotResults($toset);
|
||||||
}
|
}
|
||||||
|
@ -11,10 +11,10 @@ You should have received a copy of the GNU General Public License along with Mad
|
|||||||
If not, see <http://www.gnu.org/licenses/>.
|
If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!file_exists(__DIR__.'/../vendor/autoload.php')) {
|
if (!\file_exists(__DIR__.'/../vendor/autoload.php')) {
|
||||||
echo 'You did not run composer update, using madeline.php'.PHP_EOL;
|
echo 'You did not run composer update, using madeline.php'.PHP_EOL;
|
||||||
if (!file_exists('madeline.php')) {
|
if (!\file_exists('madeline.php')) {
|
||||||
copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');
|
\copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');
|
||||||
}
|
}
|
||||||
include 'madeline.php';
|
include 'madeline.php';
|
||||||
} else {
|
} else {
|
||||||
@ -33,15 +33,15 @@ try {
|
|||||||
}
|
}
|
||||||
function base64url_decode($data)
|
function base64url_decode($data)
|
||||||
{
|
{
|
||||||
return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT));
|
return \base64_decode(\str_pad(\strtr($data, '-_', '+/'), \strlen($data) % 4, '=', STR_PAD_RIGHT));
|
||||||
}
|
}
|
||||||
function rle_decode($string)
|
function rle_decode($string)
|
||||||
{
|
{
|
||||||
$base256 = '';
|
$base256 = '';
|
||||||
$last = '';
|
$last = '';
|
||||||
foreach (str_split($string) as $cur) {
|
foreach (\str_split($string) as $cur) {
|
||||||
if ($last === chr(0)) {
|
if ($last === \chr(0)) {
|
||||||
$base256 .= str_repeat($last, ord($cur));
|
$base256 .= \str_repeat($last, \ord($cur));
|
||||||
$last = '';
|
$last = '';
|
||||||
} else {
|
} else {
|
||||||
$base256 .= $last;
|
$base256 .= $last;
|
||||||
@ -63,12 +63,12 @@ function foreach_offset_length($string)
|
|||||||
}
|
}
|
||||||
$string = str_replace($a, $b, $string);*/
|
$string = str_replace($a, $b, $string);*/
|
||||||
$res = [];
|
$res = [];
|
||||||
$strlen = strlen($string);
|
$strlen = \strlen($string);
|
||||||
for ($offset = 0; $offset < strlen($string); $offset++) {
|
for ($offset = 0; $offset < \strlen($string); $offset++) {
|
||||||
// for ($length = $strlen - $offset; $length > 0; $length--) {
|
// for ($length = $strlen - $offset; $length > 0; $length--) {
|
||||||
foreach (['i' => 4, 'q' => 8] as $c => $length) {
|
foreach (['i' => 4, 'q' => 8] as $c => $length) {
|
||||||
$s = substr($string, $offset, $length);
|
$s = \substr($string, $offset, $length);
|
||||||
if (strlen($s) === $length) {
|
if (\strlen($s) === $length) {
|
||||||
$number = \danog\PHP\Struct::unpack('<'.$c, $s)[0];
|
$number = \danog\PHP\Struct::unpack('<'.$c, $s)[0];
|
||||||
//$number = ord($s);
|
//$number = ord($s);
|
||||||
$res[] = ['number' => $number, 'offset' => $offset, 'length' => $length];
|
$res[] = ['number' => $number, 'offset' => $offset, 'length' => $length];
|
||||||
@ -82,7 +82,7 @@ function foreach_offset_length($string)
|
|||||||
$res = ['offset' => 0, 'files' => []];
|
$res = ['offset' => 0, 'files' => []];
|
||||||
function getfiles($token, &$params)
|
function getfiles($token, &$params)
|
||||||
{
|
{
|
||||||
foreach (json_decode(file_get_contents('https://api.telegram.org/bot'.$token.'/getupdates?offset='.$params['offset']), true)['result'] as $update) {
|
foreach (\json_decode(\file_get_contents('https://api.telegram.org/bot'.$token.'/getupdates?offset='.$params['offset']), true)['result'] as $update) {
|
||||||
$params['offset'] = $update['update_id'] + 1;
|
$params['offset'] = $update['update_id'] + 1;
|
||||||
if (isset($update['message']['audio'])) {
|
if (isset($update['message']['audio'])) {
|
||||||
$params['files'][$update['message']['message_id']] = $update['message']['audio']['file_id'];
|
$params['files'][$update['message']['message_id']] = $update['message']['audio']['file_id'];
|
||||||
@ -100,7 +100,7 @@ function getfiles($token, &$params)
|
|||||||
$params['files'][$update['message']['message_id']] = $update['message']['voice']['file_id'];
|
$params['files'][$update['message']['message_id']] = $update['message']['voice']['file_id'];
|
||||||
}
|
}
|
||||||
if (isset($update['message']['photo'])) {
|
if (isset($update['message']['photo'])) {
|
||||||
$params['files'][$update['message']['message_id']] = end($update['message']['photo'])['file_id'];
|
$params['files'][$update['message']['message_id']] = \end($update['message']['photo'])['file_id'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -108,9 +108,9 @@ function recurse($array, $prefix = '')
|
|||||||
{
|
{
|
||||||
$res = [];
|
$res = [];
|
||||||
foreach ($array as $k => $v) {
|
foreach ($array as $k => $v) {
|
||||||
if (is_array($v)) {
|
if (\is_array($v)) {
|
||||||
$res = array_merge(recurse($v, $prefix.$k.'->'), $res);
|
$res = \array_merge(recurse($v, $prefix.$k.'->'), $res);
|
||||||
} elseif (is_int($v)) {
|
} elseif (\is_int($v)) {
|
||||||
$res[$prefix.$k] = $v;
|
$res[$prefix.$k] = $v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,17 +135,17 @@ while (true) {
|
|||||||
$bot_api_id_b256 = base64url_decode($bot_api_id);
|
$bot_api_id_b256 = base64url_decode($bot_api_id);
|
||||||
$bot_api_id_rledecoded = rle_decode($bot_api_id_b256);
|
$bot_api_id_rledecoded = rle_decode($bot_api_id_b256);
|
||||||
$message .= PHP_EOL.PHP_EOL;
|
$message .= PHP_EOL.PHP_EOL;
|
||||||
for ($x = 0; $x < strlen($bot_api_id_rledecoded) - 3; $x++) {
|
for ($x = 0; $x < \strlen($bot_api_id_rledecoded) - 3; $x++) {
|
||||||
$message .= 'Bytes '.$x.'-'.($x + 4).': '.\danog\PHP\Struct::unpack('<i', substr($bot_api_id_rledecoded, $x, 4))[0].PHP_EOL;
|
$message .= 'Bytes '.$x.'-'.($x + 4).': '.\danog\PHP\Struct::unpack('<i', \substr($bot_api_id_rledecoded, $x, 4))[0].PHP_EOL;
|
||||||
}
|
}
|
||||||
$message .= PHP_EOL.PHP_EOL.
|
$message .= PHP_EOL.PHP_EOL.
|
||||||
'First 4 bytes: '.ord($bot_api_id_rledecoded[0]).' '.ord($bot_api_id_rledecoded[1]).' '.ord($bot_api_id_rledecoded[2]).' '.ord($bot_api_id_rledecoded[3]).PHP_EOL.
|
'First 4 bytes: '.\ord($bot_api_id_rledecoded[0]).' '.\ord($bot_api_id_rledecoded[1]).' '.\ord($bot_api_id_rledecoded[2]).' '.\ord($bot_api_id_rledecoded[3]).PHP_EOL.
|
||||||
'First 4 bytes (single integer): '.(\danog\PHP\Struct::unpack('<i', substr($bot_api_id_rledecoded, 0, 4))[0]).PHP_EOL.
|
'First 4 bytes (single integer): '.(\danog\PHP\Struct::unpack('<i', \substr($bot_api_id_rledecoded, 0, 4))[0]).PHP_EOL.
|
||||||
'bytes 8-16: '.(\danog\PHP\Struct::unpack('<q', substr($bot_api_id_rledecoded, 8, 8))[0]).PHP_EOL.
|
'bytes 8-16: '.(\danog\PHP\Struct::unpack('<q', \substr($bot_api_id_rledecoded, 8, 8))[0]).PHP_EOL.
|
||||||
'bytes 16-24: '.(\danog\PHP\Struct::unpack('<q', substr($bot_api_id_rledecoded, 16, 8))[0]).PHP_EOL.
|
'bytes 16-24: '.(\danog\PHP\Struct::unpack('<q', \substr($bot_api_id_rledecoded, 16, 8))[0]).PHP_EOL.
|
||||||
'Last byte: '.ord(substr($bot_api_id_rledecoded, -1)).PHP_EOL.
|
'Last byte: '.\ord(\substr($bot_api_id_rledecoded, -1)).PHP_EOL.
|
||||||
'Total length: '.strlen($bot_api_id_b256).PHP_EOL.
|
'Total length: '.\strlen($bot_api_id_b256).PHP_EOL.
|
||||||
'Total length (rledecoded): '.strlen($bot_api_id_rledecoded).PHP_EOL.
|
'Total length (rledecoded): '.\strlen($bot_api_id_rledecoded).PHP_EOL.
|
||||||
PHP_EOL.'<b>param (value): start-end (length)</b>'.PHP_EOL.PHP_EOL;
|
PHP_EOL.'<b>param (value): start-end (length)</b>'.PHP_EOL.PHP_EOL;
|
||||||
$bot_api = foreach_offset_length($bot_api_id_rledecoded);
|
$bot_api = foreach_offset_length($bot_api_id_rledecoded);
|
||||||
//$mtproto = $MadelineProto->get_download_info($update['update']['message']['media'])['InputFileLocation'];
|
//$mtproto = $MadelineProto->get_download_info($update['update']['message']['media'])['InputFileLocation'];
|
||||||
@ -177,16 +177,16 @@ while (true) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ksort($m);
|
\ksort($m);
|
||||||
foreach ($m as $key => $bn) {
|
foreach ($m as $key => $bn) {
|
||||||
$message .= $bn;
|
$message .= $bn;
|
||||||
}
|
}
|
||||||
foreach ($mtproto as $key => $n) {
|
foreach ($mtproto as $key => $n) {
|
||||||
$message .= $key.' ('.$n.'): not found'.PHP_EOL;
|
$message .= $key.' ('.$n.'): not found'.PHP_EOL;
|
||||||
}
|
}
|
||||||
$message .= PHP_EOL.PHP_EOL.'File number: '.\danog\PHP\Struct::unpack('<i', substr($bot_api_id_rledecoded, 8, 4))[0];
|
$message .= PHP_EOL.PHP_EOL.'File number: '.\danog\PHP\Struct::unpack('<i', \substr($bot_api_id_rledecoded, 8, 4))[0];
|
||||||
if ($update['update']['message']['from_id'] === 101374607) {
|
if ($update['update']['message']['from_id'] === 101374607) {
|
||||||
$message = \danog\PHP\Struct::unpack('<i', substr($bot_api_id_rledecoded, 8, 4))[0];
|
$message = \danog\PHP\Struct::unpack('<i', \substr($bot_api_id_rledecoded, 8, 4))[0];
|
||||||
}
|
}
|
||||||
$MadelineProto->messages->sendMessage(['peer' => $update['update']['message']['from_id'], 'message' => $message, 'reply_to_msg_id' => $update['update']['message']['id'], 'parse_mode' => 'markdown']);
|
$MadelineProto->messages->sendMessage(['peer' => $update['update']['message']['from_id'], 'message' => $message, 'reply_to_msg_id' => $update['update']['message']['id'], 'parse_mode' => 'markdown']);
|
||||||
}
|
}
|
||||||
@ -198,7 +198,7 @@ while (true) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (isset($update['update']['message']['media']) && $update['update']['message']['media'] == 'messageMediaPhoto' && $update['update']['message']['media'] == 'messageMediaDocument') {
|
if (isset($update['update']['message']['media']) && $update['update']['message']['media'] == 'messageMediaPhoto' && $update['update']['message']['media'] == 'messageMediaDocument') {
|
||||||
$time = time();
|
$time = \time();
|
||||||
// $file = $MadelineProto->download_to_dir($update['update']['message']['media'], '/tmp');
|
// $file = $MadelineProto->download_to_dir($update['update']['message']['media'], '/tmp');
|
||||||
// $MadelineProto->messages->sendMessage(['peer' => $update['update']['message']['from_id'], 'message' => 'Downloaded to '.$file.' in '.(time() - $time).' seconds', 'reply_to_msg_id' => $update['update']['message']['id'], 'entities' => [['_' => 'messageEntityPre', 'offset' => 0, 'length' => strlen($res), 'language' => 'json']]]);
|
// $MadelineProto->messages->sendMessage(['peer' => $update['update']['message']['from_id'], 'message' => 'Downloaded to '.$file.' in '.(time() - $time).' seconds', 'reply_to_msg_id' => $update['update']['message']['id'], 'entities' => [['_' => 'messageEntityPre', 'offset' => 0, 'length' => strlen($res), 'language' => 'json']]]);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user