2022-12-29 20:40:06 +01:00
< ? php declare ( strict_types = 1 );
2018-02-28 13:43:45 +01:00
2021-12-10 17:50:41 +01:00
namespace danog\MadelineProto ;
2024-01-18 22:19:41 +01:00
if (( PHP_MAJOR_VERSION === 8 && PHP_MINOR_VERSION < 1 ) || PHP_MAJOR_VERSION < 8 ) {
die ( 'MadelineProto requires at least PHP 8.2, PHP 8.3+ is recommended.' . PHP_EOL );
}
if ( PHP_INT_SIZE < 8 ) {
die ( 'A 64-bit build of PHP is required to run MadelineProto, PHP 8.2+ is required, 8.3+ is recommended.' . PHP_EOL );
}
2021-12-03 18:15:56 +01:00
if ( \defined ( 'MADELINE_PHP' )) {
2022-09-21 19:51:34 +02:00
throw new \Exception ( 'Please do not include madeline.php twice, use require_once \'madeline.php\';!' );
2021-12-03 18:15:56 +01:00
}
2023-10-01 20:05:04 +02:00
if ( ! \defined ( 'MADELINE_ALLOW_COMPOSER' ) && class_exists ( \Composer\Autoload\ClassLoader :: class )) {
2023-07-09 18:42:42 +02:00
throw new \Exception ( 'Composer autoloader detected: madeline.php is incompatible with Composer, please install MadelineProto using composer: https://docs.madelineproto.xyz/docs/INSTALLATION.html#composer-from-existing-project' );
2021-12-03 18:15:56 +01:00
}
2020-07-11 20:01:54 +02:00
\define ( 'MADELINE_PHP' , __FILE__ );
2021-12-10 17:50:41 +01:00
class Installer
Merge alpha into master (async, huge bugfixes and more) (#546)
* Implement async and lots of bugfixes
* Implement more async
* Implement async, implement bugfixes for the connection module, for the datacenter module, huge bugfixes, huge perfomance improvements, media DCs for https, advanced selecting, custom var_dump, totally rewritten IOLoop and response mechanism, promises, improvements to the TL parser, custom mb_substr
* Apply fixes from StyleCI
* Bugfixes
* Apply fixes from StyleCI
* Bugfixes, implement combined promises
* Apply fixes from StyleCI
* Support passing method arguments as callable
* Starting to write async upload logic
* Apply fixes from StyleCI
* Start implementing async file upload
* Apply fixes from StyleCI
* bugfix
* Apply fixes from StyleCI
* Start rewriting connection module
* Add PHP file docblocks for all classes
* Start working on new async stream API
* Finish writing stream API
* More stream API fixes
* Apply fixes from StyleCI
* Rewrite DataCenter and Connection modules
* Clean up stream API documentation
* Fixes
* Apply fixes from StyleCI
* Add referenced parameter to get length of buffer to read in getReadBuffer API
* Moved all MessageHandler code in the Connection module, added a PHP version warning in the phar
* Start fixing reads
* Fix all protocol stream wrappers
* Apply fixes from StyleCI
* Implement disconnection, and remove end function
* Working async RPC
* Implement async file upload
* Bugfix
* Method recall bugfixes
* Bugfixes
* Trait bugfixes
* Fix FIFO buffer
* Bugfixes and speedtests
* Async logging
* Implement websocket streams
* Implement loop API, signal API, clean closing and start changing layer
* Small magna, websocket and HTTP fixes
* Clean up loop API
* Improved stack traces, 2FA and async
* Login fixes
* Added instructions for manual verification
* Small fixes
* More app info improvements
* More app info improvements
* TL and 2FA fixes
* Update to layer 89
* More bugfixes
* Implement broken media reporting
* Remove debug comments
* PHP 7.2 backwards compatibility
* Bugfixes
* Async key generation
* Some simplifications
* Transport fixes
* Cleanup
* async API
* Performance fixes
* Fixes to async API
* Bugfixes
* Implement one-time async loop
* Authorization and logging fixes
* Update to layer 91
* 7to5 fix
* Null coalesce conversion
* Implement socks5 proxy
* Implement HTTP proxy
* Fixes to HTTP proxy
* MTProxy and socks5 fixes
* Disable PHP 5 conversion
* Proxies have higher priority
* Avoid error handling in vendor
* Override composer dependencies
* Fix travis build
* Final composer fixes
* Proxy logic fixes
* Fix get_updates update handling
* Do not use parallel file driver if not supported
* Refactor loader and implement HTTP fixes
* Suppress errors in loader
* HTTP and authorization fixes
* HTTP fixes
* Improved peer management
* Use HTTP protocol on altervista
* Small bugfixes
* Minor fixes
* Docufix
* Docufix
* Legacy fixes
* Fix message queue
* Avoid updating if using MTProxy
* Improve logs and examples
* Trim final newlines while converting parse mode
* Reimplement noResponse flag
* Async combined event handler and APIFactory fixes
* Actually return config
* Case-insensitive methods
* Bugfix
* Apply fixes from StyleCI (#545)
* MTProxy fixes
* PHP 5 warning
* Improved PHP 5 warning
* Use <br> along with newlines in web logs
* Update docs
2018-12-26 20:51:14 +01:00
{
2023-11-11 16:55:29 +01:00
public const RELEASE_TEMPLATE = 'https://phar.madelineproto.xyz/release%s?v=new' ;
public const PHAR_TEMPLATE = 'https://github.com/danog/MadelineProto/releases/latest/download/madeline%s.phar?v=%s' ;
2021-12-10 17:50:41 +01:00
/**
* Phar lock instance .
*
* @ var resource | null
*/
private static $lock = null ;
/**
* Installer lock instance .
*
* @ var resource | null
*/
private $lockInstaller = null ;
/**
* PHP version .
*
* @ var string
*/
private $version ;
/**
* Constructor .
*/
public function __construct ()
{
2023-10-01 20:05:04 +02:00
$backtrace = debug_backtrace ( 0 );
2021-12-10 18:41:52 +01:00
if ( \count ( $backtrace ) === 1 ) {
2021-12-10 17:50:41 +01:00
if ( isset ( $GLOBALS [ 'argv' ]) && ! empty ( $GLOBALS [ 'argv' ])) {
$arguments = \array_slice ( $GLOBALS [ 'argv' ], 1 );
} elseif ( isset ( $_GET [ 'argv' ]) && ! empty ( $_GET [ 'argv' ])) {
$arguments = $_GET [ 'argv' ];
} else {
$arguments = [];
}
if ( \count ( $arguments ) >= 2 ) {
2023-10-01 20:05:04 +02:00
\define ( \MADELINE_WORKER_TYPE :: class , array_shift ( $arguments ));
2021-12-10 17:50:41 +01:00
\define ( \MADELINE_WORKER_ARGS :: class , $arguments );
} else {
die ( 'MadelineProto loader: you must include this file in another PHP script, see https://docs.madelineproto.xyz for more info.' . PHP_EOL );
}
2021-12-10 18:41:52 +01:00
\define ( 'MADELINE_REAL_ROOT' , \dirname ( $backtrace [ 0 ][ " file " ]));
2021-12-10 17:50:41 +01:00
}
2023-10-01 20:05:04 +02:00
$this -> version = ( string ) min ( 81 , ( int ) ( PHP_MAJOR_VERSION . PHP_MINOR_VERSION ));
\define ( 'MADELINE_PHAR_GLOB' , getcwd () . DIRECTORY_SEPARATOR . " madeline*- { $this -> version } .phar " );
\define ( 'MADELINE_PHAR_VERSION' , getcwd () . DIRECTORY_SEPARATOR . " madeline.version " );
\define ( 'MADELINE_RELEASE_URL' , sprintf ( self :: RELEASE_TEMPLATE , $this -> version ));
Merge alpha into master (async, huge bugfixes and more) (#546)
* Implement async and lots of bugfixes
* Implement more async
* Implement async, implement bugfixes for the connection module, for the datacenter module, huge bugfixes, huge perfomance improvements, media DCs for https, advanced selecting, custom var_dump, totally rewritten IOLoop and response mechanism, promises, improvements to the TL parser, custom mb_substr
* Apply fixes from StyleCI
* Bugfixes
* Apply fixes from StyleCI
* Bugfixes, implement combined promises
* Apply fixes from StyleCI
* Support passing method arguments as callable
* Starting to write async upload logic
* Apply fixes from StyleCI
* Start implementing async file upload
* Apply fixes from StyleCI
* bugfix
* Apply fixes from StyleCI
* Start rewriting connection module
* Add PHP file docblocks for all classes
* Start working on new async stream API
* Finish writing stream API
* More stream API fixes
* Apply fixes from StyleCI
* Rewrite DataCenter and Connection modules
* Clean up stream API documentation
* Fixes
* Apply fixes from StyleCI
* Add referenced parameter to get length of buffer to read in getReadBuffer API
* Moved all MessageHandler code in the Connection module, added a PHP version warning in the phar
* Start fixing reads
* Fix all protocol stream wrappers
* Apply fixes from StyleCI
* Implement disconnection, and remove end function
* Working async RPC
* Implement async file upload
* Bugfix
* Method recall bugfixes
* Bugfixes
* Trait bugfixes
* Fix FIFO buffer
* Bugfixes and speedtests
* Async logging
* Implement websocket streams
* Implement loop API, signal API, clean closing and start changing layer
* Small magna, websocket and HTTP fixes
* Clean up loop API
* Improved stack traces, 2FA and async
* Login fixes
* Added instructions for manual verification
* Small fixes
* More app info improvements
* More app info improvements
* TL and 2FA fixes
* Update to layer 89
* More bugfixes
* Implement broken media reporting
* Remove debug comments
* PHP 7.2 backwards compatibility
* Bugfixes
* Async key generation
* Some simplifications
* Transport fixes
* Cleanup
* async API
* Performance fixes
* Fixes to async API
* Bugfixes
* Implement one-time async loop
* Authorization and logging fixes
* Update to layer 91
* 7to5 fix
* Null coalesce conversion
* Implement socks5 proxy
* Implement HTTP proxy
* Fixes to HTTP proxy
* MTProxy and socks5 fixes
* Disable PHP 5 conversion
* Proxies have higher priority
* Avoid error handling in vendor
* Override composer dependencies
* Fix travis build
* Final composer fixes
* Proxy logic fixes
* Fix get_updates update handling
* Do not use parallel file driver if not supported
* Refactor loader and implement HTTP fixes
* Suppress errors in loader
* HTTP and authorization fixes
* HTTP fixes
* Improved peer management
* Use HTTP protocol on altervista
* Small bugfixes
* Minor fixes
* Docufix
* Docufix
* Legacy fixes
* Fix message queue
* Avoid updating if using MTProxy
* Improve logs and examples
* Trim final newlines while converting parse mode
* Reimplement noResponse flag
* Async combined event handler and APIFactory fixes
* Actually return config
* Case-insensitive methods
* Bugfix
* Apply fixes from StyleCI (#545)
* MTProxy fixes
* PHP 5 warning
* Improved PHP 5 warning
* Use <br> along with newlines in web logs
* Update docs
2018-12-26 20:51:14 +01:00
}
2021-12-10 17:50:41 +01:00
/**
* Destructor .
*/
public function __destruct ()
{
if ( $this -> lockInstaller ) {
2023-10-01 20:05:04 +02:00
flock ( $this -> lockInstaller , LOCK_UN );
fclose ( $this -> lockInstaller );
2021-12-10 17:50:41 +01:00
$this -> lockInstaller = null ;
}
Merge alpha into master (async, huge bugfixes and more) (#546)
* Implement async and lots of bugfixes
* Implement more async
* Implement async, implement bugfixes for the connection module, for the datacenter module, huge bugfixes, huge perfomance improvements, media DCs for https, advanced selecting, custom var_dump, totally rewritten IOLoop and response mechanism, promises, improvements to the TL parser, custom mb_substr
* Apply fixes from StyleCI
* Bugfixes
* Apply fixes from StyleCI
* Bugfixes, implement combined promises
* Apply fixes from StyleCI
* Support passing method arguments as callable
* Starting to write async upload logic
* Apply fixes from StyleCI
* Start implementing async file upload
* Apply fixes from StyleCI
* bugfix
* Apply fixes from StyleCI
* Start rewriting connection module
* Add PHP file docblocks for all classes
* Start working on new async stream API
* Finish writing stream API
* More stream API fixes
* Apply fixes from StyleCI
* Rewrite DataCenter and Connection modules
* Clean up stream API documentation
* Fixes
* Apply fixes from StyleCI
* Add referenced parameter to get length of buffer to read in getReadBuffer API
* Moved all MessageHandler code in the Connection module, added a PHP version warning in the phar
* Start fixing reads
* Fix all protocol stream wrappers
* Apply fixes from StyleCI
* Implement disconnection, and remove end function
* Working async RPC
* Implement async file upload
* Bugfix
* Method recall bugfixes
* Bugfixes
* Trait bugfixes
* Fix FIFO buffer
* Bugfixes and speedtests
* Async logging
* Implement websocket streams
* Implement loop API, signal API, clean closing and start changing layer
* Small magna, websocket and HTTP fixes
* Clean up loop API
* Improved stack traces, 2FA and async
* Login fixes
* Added instructions for manual verification
* Small fixes
* More app info improvements
* More app info improvements
* TL and 2FA fixes
* Update to layer 89
* More bugfixes
* Implement broken media reporting
* Remove debug comments
* PHP 7.2 backwards compatibility
* Bugfixes
* Async key generation
* Some simplifications
* Transport fixes
* Cleanup
* async API
* Performance fixes
* Fixes to async API
* Bugfixes
* Implement one-time async loop
* Authorization and logging fixes
* Update to layer 91
* 7to5 fix
* Null coalesce conversion
* Implement socks5 proxy
* Implement HTTP proxy
* Fixes to HTTP proxy
* MTProxy and socks5 fixes
* Disable PHP 5 conversion
* Proxies have higher priority
* Avoid error handling in vendor
* Override composer dependencies
* Fix travis build
* Final composer fixes
* Proxy logic fixes
* Fix get_updates update handling
* Do not use parallel file driver if not supported
* Refactor loader and implement HTTP fixes
* Suppress errors in loader
* HTTP and authorization fixes
* HTTP fixes
* Improved peer management
* Use HTTP protocol on altervista
* Small bugfixes
* Minor fixes
* Docufix
* Docufix
* Legacy fixes
* Fix message queue
* Avoid updating if using MTProxy
* Improve logs and examples
* Trim final newlines while converting parse mode
* Reimplement noResponse flag
* Async combined event handler and APIFactory fixes
* Actually return config
* Case-insensitive methods
* Bugfix
* Apply fixes from StyleCI (#545)
* MTProxy fixes
* PHP 5 warning
* Improved PHP 5 warning
* Use <br> along with newlines in web logs
* Update docs
2018-12-26 20:51:14 +01:00
}
2021-12-10 17:50:41 +01:00
/**
* Extract composer package versions from phar .
*
* @ return array < string , string >
*/
2022-12-08 20:16:40 +01:00
private static function extractVersions ( ? string $release ) : array
2021-12-10 17:50:41 +01:00
{
2022-12-08 20:16:40 +01:00
$release ? ? = '' ;
2021-12-10 17:50:41 +01:00
$phar = " madeline- $release .phar " ;
$packages = [ 'danog/madelineproto' => 'old' ];
2023-10-01 20:05:04 +02:00
if ( ! file_exists ( " phar:// $phar /vendor/composer/installed.json " )) {
2021-12-10 17:50:41 +01:00
return $packages ;
}
2023-10-01 20:05:04 +02:00
$composer = json_decode ( file_get_contents ( " phar:// $phar /vendor/composer/installed.json " ), true ) ? : [];
2021-12-10 17:50:41 +01:00
if ( ! isset ( $composer [ 'packages' ])) {
return $packages ;
}
foreach ( $composer [ 'packages' ] as $dep ) {
$name = $dep [ 'name' ];
2023-11-11 16:55:29 +01:00
if ( str_starts_with ( $name , 'phabel/transpiler' )) {
2023-10-01 20:05:04 +02:00
$name = explode ( '/' , $name , 3 )[ 2 ];
2021-12-10 17:50:41 +01:00
}
$version = $dep [ 'version_normalized' ];
2023-10-01 20:05:04 +02:00
if ( $name === 'danog/madelineproto' && substr ( $version , 0 , 2 ) === '90' ) {
$version = substr ( $version , 2 );
2020-02-05 23:11:29 +01:00
}
2021-12-10 17:50:41 +01:00
$packages [ $name ] = $version ;
}
return $packages ;
}
2020-01-18 19:05:43 +01:00
2021-12-10 17:50:41 +01:00
/**
* Report installs to composer .
*/
2022-12-08 20:16:40 +01:00
private static function reportComposer ( ? string $local_release , ? string $remote_release ) : void
2021-12-10 17:50:41 +01:00
{
$previous = self :: extractVersions ( $local_release );
$current = self :: extractVersions ( $remote_release );
$postData = [ 'downloads' => []];
foreach ( $current as $name => $version ) {
if ( isset ( $previous [ $name ]) && $previous [ $name ] === $version ) {
continue ;
2020-01-18 18:37:30 +01:00
}
2021-12-10 17:50:41 +01:00
$postData [ 'downloads' ][] = [
'name' => $name ,
2023-11-11 16:55:29 +01:00
'version' => $version ,
2021-12-10 17:50:41 +01:00
];
}
2020-01-18 19:05:43 +01:00
2022-12-08 20:16:40 +01:00
$phpVersion = 'PHP ' . PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION ;
2021-12-10 17:50:41 +01:00
$opts = [ 'http' =>
[
'method' => 'POST' ,
'header' => [
'Content-Type: application/json' ,
2023-10-01 20:05:04 +02:00
sprintf (
2021-12-10 17:50:41 +01:00
'User-Agent: Composer/%s (%s; %s; %s; %s%s)' ,
'MProto v7' ,
2023-10-01 20:05:04 +02:00
\function_exists ( 'php_uname' ) ? @ php_uname ( 's' ) : 'Unknown' ,
\function_exists ( 'php_uname' ) ? @ php_uname ( 'r' ) : 'Unknown' ,
2021-12-10 17:50:41 +01:00
$phpVersion ,
'streams' ,
2023-10-01 20:05:04 +02:00
getenv ( 'CI' ) ? '; CI' : ''
2023-11-11 16:55:29 +01:00
),
2020-01-18 18:37:30 +01:00
],
2023-10-01 20:05:04 +02:00
'content' => json_encode ( $postData ),
2021-12-10 17:50:41 +01:00
'timeout' => 6 ,
],
];
2023-10-01 20:05:04 +02:00
@ file_get_contents ( " https://packagist.org/downloads/ " , false , stream_context_create ( $opts ));
2021-12-10 17:50:41 +01:00
}
/**
* Load phar file .
*/
2022-12-08 20:16:40 +01:00
private static function load ( ? string $release ) : mixed
2021-12-10 17:50:41 +01:00
{
if ( $release === null ) {
throw new \Exception ( 'Could not download MadelineProto, please check your internet connection and PHP configuration!' );
}
$phar = " madeline- $release .phar " ;
if ( ! self :: $lock ) {
2023-10-01 20:05:04 +02:00
self :: $lock = fopen ( " $phar .lock " , 'c' );
2021-12-10 17:50:41 +01:00
}
2023-10-01 20:05:04 +02:00
flock ( self :: $lock , LOCK_SH );
2023-07-09 18:42:42 +02:00
return require_once $phar ;
2018-07-19 12:04:17 +02:00
}
2021-04-07 16:03:19 +02:00
2021-12-13 18:04:47 +01:00
/**
* Unlock phar .
*
*/
2022-12-08 20:16:40 +01:00
public static function unlock () : void
2021-12-13 18:04:47 +01:00
{
2023-10-01 20:05:04 +02:00
flock ( self :: $lock , LOCK_UN );
2021-12-13 18:04:47 +01:00
}
2021-12-10 17:50:41 +01:00
/**
* Lock installer .
*/
2022-12-08 20:16:40 +01:00
private function lock ( string $version ) : bool
2021-12-10 17:50:41 +01:00
{
if ( $this -> lockInstaller ) {
return true ;
}
2023-10-01 20:05:04 +02:00
$this -> lockInstaller = fopen ( $version , 'w' );
return flock ( $this -> lockInstaller , LOCK_EX | LOCK_NB );
2021-12-10 17:50:41 +01:00
}
/**
* Install MadelineProto .
*/
2022-12-29 20:46:59 +01:00
public function install ()
2021-12-10 17:50:41 +01:00
{
2023-10-01 20:05:04 +02:00
if ( file_exists ( MADELINE_PHAR_VERSION )) {
$local_release = file_get_contents ( MADELINE_PHAR_VERSION ) ? : null ;
2021-12-10 17:50:41 +01:00
} else {
2023-10-01 20:05:04 +02:00
touch ( MADELINE_PHAR_VERSION );
2021-12-10 17:50:41 +01:00
$local_release = null ;
}
\define ( 'HAD_MADELINE_PHAR' , !! $local_release );
2023-10-01 20:05:04 +02:00
if ( $local_release !== null && file_exists ( " madeline- $local_release .phar " )) {
2021-12-10 17:50:41 +01:00
return self :: load ( $local_release );
}
2023-10-01 20:05:04 +02:00
$remote_release = file_get_contents ( MADELINE_RELEASE_URL ) ? : null ;
2023-01-15 19:09:27 +01:00
$madeline_phar = " madeline- $remote_release .phar " ;
if ( ! $this -> lock ( MADELINE_PHAR_VERSION )) {
2023-10-01 20:05:04 +02:00
flock ( $this -> lockInstaller , LOCK_EX );
2021-12-10 17:50:41 +01:00
return $this -> install ();
}
2023-10-01 20:05:04 +02:00
if ( ! file_exists ( $madeline_phar )) {
2021-12-13 14:55:50 +01:00
for ( $x = 0 ; $x < 10 ; $x ++ ) {
2023-10-01 20:05:04 +02:00
$pharTest = file_get_contents ( sprintf ( self :: PHAR_TEMPLATE , $this -> version , $remote_release . $x ));
2023-11-11 16:55:29 +01:00
if ( $pharTest && str_contains ( $pharTest , $remote_release )) {
2021-12-13 14:55:50 +01:00
$phar = $pharTest ;
2021-12-13 15:35:55 +01:00
unset ( $pharTest );
2021-12-13 14:55:50 +01:00
break ;
}
2023-10-01 20:05:04 +02:00
sleep ( 1 );
2021-12-13 14:55:50 +01:00
}
if ( ! isset ( $phar )) {
2021-12-10 17:50:41 +01:00
return self :: load ( $local_release );
}
2023-10-01 20:05:04 +02:00
self :: $lock = fopen ( " $madeline_phar .lock " , 'w' );
flock ( self :: $lock , LOCK_EX );
file_put_contents ( $madeline_phar , $phar );
2021-12-10 17:50:41 +01:00
unset ( $phar );
self :: reportComposer ( $local_release , $remote_release );
}
2023-10-01 20:05:04 +02:00
fwrite ( $this -> lockInstaller , $remote_release );
fflush ( $this -> lockInstaller );
2021-12-10 17:50:41 +01:00
return self :: load ( $remote_release );
2021-09-06 16:22:07 +02:00
}
2018-02-28 13:43:45 +01:00
}
2021-12-10 17:50:41 +01:00
return ( new \danog\MadelineProto\Installer ) -> install ();