From f9470f1ebc9fc6ae27aaaf06dbf5a29f7a3321c8 Mon Sep 17 00:00:00 2001 From: Pavel Djundik Date: Mon, 27 Nov 2023 21:41:58 +0200 Subject: [PATCH] Add types, minor fixes --- phpstan.neon | 1 + src/MinecraftPing.php | 82 +++++++++++++++++++++++++++++++----------- src/MinecraftQuery.php | 68 ++++++++++++++++++++++------------- view.php | 12 +++---- view_serverping.php | 15 ++++---- 5 files changed, 119 insertions(+), 59 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index 25d991c..cf2b02f 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -4,5 +4,6 @@ parameters: level: max paths: - src + - . excludePaths: - vendor diff --git a/src/MinecraftPing.php b/src/MinecraftPing.php index 234d4b7..3c8f073 100644 --- a/src/MinecraftPing.php +++ b/src/MinecraftPing.php @@ -26,16 +26,22 @@ class MinecraftPing * */ + /** @var ?resource $Socket */ private $Socket; - private $ServerAddress; - private $ServerPort; - private $Timeout; + private string $ServerAddress; + private int $ServerPort; + private float $Timeout; - public function __construct( $Address, $Port = 25565, $Timeout = 2, $ResolveSRV = true ) + public function __construct( string $Address, int $Port = 25565, float $Timeout = 2, bool $ResolveSRV = true ) { + if( $Timeout < 0 ) + { + throw new \InvalidArgumentException( 'Timeout must be a positive integer.' ); + } + $this->ServerAddress = $Address; - $this->ServerPort = (int)$Port; - $this->Timeout = (int)$Timeout; + $this->ServerPort = $Port; + $this->Timeout = $Timeout; if( $ResolveSRV ) { @@ -50,7 +56,7 @@ public function __destruct( ) $this->Close( ); } - public function Close( ) + public function Close( ) : void { if( $this->Socket !== null ) { @@ -60,23 +66,29 @@ public function Close( ) } } - public function Connect( ) + public function Connect( ) : void { - $this->Socket = @\fsockopen( $this->ServerAddress, $this->ServerPort, $errno, $errstr, (float)$this->Timeout ); + $Socket = @\fsockopen( $this->ServerAddress, $this->ServerPort, $errno, $errstr, $this->Timeout ); - if( !$this->Socket ) + if( $Socket === false ) { - $this->Socket = null; - throw new MinecraftPingException( "Failed to connect or create a socket: $errno ($errstr)" ); } + $this->Socket = $Socket; + // Set Read/Write timeout - \stream_set_timeout( $this->Socket, $this->Timeout ); + \stream_set_timeout( $this->Socket, (int)$this->Timeout ); } - public function Query( ) + /** @return array|false */ + public function Query( ) : array|bool { + if( $this->Socket === null ) + { + throw new MinecraftPingException( 'Socket is not open.' ); + } + $TimeStart = \microtime( true ); // for read timeout purposes // See http://wiki.vg/Protocol (Status Ping) @@ -95,7 +107,7 @@ public function Query( ) if( $Length < 10 ) { - return FALSE; + return false; } $this->ReadVarInt( ); // packet type, in server ping it's 0 @@ -104,7 +116,7 @@ public function Query( ) if( $Length < 2 ) { - return FALSE; + return false; } $Data = ""; @@ -116,6 +128,12 @@ public function Query( ) } $Remainder = $Length - \strlen( $Data ); + + if( $Remainder <= 0 ) + { + break; + } + $block = \fread( $this->Socket, $Remainder ); // and finally the json string // abort if there is no progress if( !$block ) @@ -133,23 +151,45 @@ public function Query( ) throw new MinecraftPingException( 'JSON parsing failed: ' . \json_last_error_msg( ) ); } + if( !\is_array( $Data ) ) + { + return false; + } + return $Data; } - public function QueryOldPre17( ) + /** @return array|false */ + public function QueryOldPre17( ) : array|bool { + if( $this->Socket === null ) + { + throw new MinecraftPingException( 'Socket is not open.' ); + } + \fwrite( $this->Socket, "\xFE\x01" ); $Data = \fread( $this->Socket, 512 ); + + if( empty( $Data ) ) + { + return false; + } + $Len = \strlen( $Data ); if( $Len < 4 || $Data[ 0 ] !== "\xFF" ) { - return FALSE; + return false; } $Data = \substr( $Data, 3 ); // Strip packet header (kick message packet and short length) $Data = \iconv( 'UTF-16BE', 'UTF-8', $Data ); + if( $Data === false ) + { + return false; + } + // Are we dealing with Minecraft 1.4+ server? if( $Data[ 1 ] === "\xA7" && $Data[ 2 ] === "\x31" ) { @@ -175,7 +215,7 @@ public function QueryOldPre17( ) ); } - private function ReadVarInt( ) + private function ReadVarInt( ) : int { $i = 0; $j = 0; @@ -207,7 +247,7 @@ private function ReadVarInt( ) return $i; } - private function ResolveSRV() + private function ResolveSRV() : void { if( \ip2long( $this->ServerAddress ) !== false ) { @@ -228,7 +268,7 @@ private function ResolveSRV() if( isset( $Record[ 0 ][ 'port' ] ) ) { - $this->ServerPort = $Record[ 0 ][ 'port' ]; + $this->ServerPort = (int)$Record[ 0 ][ 'port' ]; } } } diff --git a/src/MinecraftQuery.php b/src/MinecraftQuery.php index 3dddd6e..fda31b3 100644 --- a/src/MinecraftQuery.php +++ b/src/MinecraftQuery.php @@ -14,15 +14,16 @@ class MinecraftQuery const STATISTIC = 0x00; const HANDSHAKE = 0x09; + /** @var ?resource $Socket */ private $Socket; - private $Players; - private $Info; + private ?array $Players = null; + private ?array $Info = null; - public function Connect( $Ip, $Port = 25565, $Timeout = 3, $ResolveSRV = true ) + public function Connect( string $Ip, int $Port = 25565, float $Timeout = 3, bool $ResolveSRV = true ) : void { - if( !is_int( $Timeout ) || $Timeout < 0 ) + if( $Timeout < 0 ) { - throw new \InvalidArgumentException( 'Timeout must be an integer.' ); + throw new \InvalidArgumentException( 'Timeout must be a positive integer.' ); } if( $ResolveSRV ) @@ -30,14 +31,16 @@ public function Connect( $Ip, $Port = 25565, $Timeout = 3, $ResolveSRV = true ) $this->ResolveSRV( $Ip, $Port ); } - $this->Socket = @\fsockopen( 'udp://' . $Ip, (int)$Port, $ErrNo, $ErrStr, (float)$Timeout ); + $Socket = @\fsockopen( 'udp://' . $Ip, $Port, $ErrNo, $ErrStr, $Timeout ); - if( $ErrNo || $this->Socket === false ) + if( $ErrNo || $Socket === false ) { throw new MinecraftQueryException( 'Could not create socket: ' . $ErrStr ); } - \stream_set_timeout( $this->Socket, $Timeout ); + $this->Socket = $Socket; + + \stream_set_timeout( $this->Socket, (int)$Timeout ); \stream_set_blocking( $this->Socket, true ); try @@ -48,13 +51,13 @@ public function Connect( $Ip, $Port = 25565, $Timeout = 3, $ResolveSRV = true ) } finally { - \fclose( $this->Socket ); + \fclose( $Socket ); } } - public function ConnectBedrock( $Ip, $Port = 19132, $Timeout = 3, $ResolveSRV = true ) + public function ConnectBedrock( string $Ip, int $Port = 19132, float $Timeout = 3, bool $ResolveSRV = true ) : void { - if( !is_int( $Timeout ) || $Timeout < 0 ) + if( $Timeout < 0 ) { throw new \InvalidArgumentException( 'Timeout must be an integer.' ); } @@ -64,14 +67,16 @@ public function ConnectBedrock( $Ip, $Port = 19132, $Timeout = 3, $ResolveSRV = $this->ResolveSRV( $Ip, $Port ); } - $this->Socket = @\fsockopen( 'udp://' . $Ip, (int)$Port, $ErrNo, $ErrStr, (float)$Timeout ); + $Socket = @\fsockopen( 'udp://' . $Ip, $Port, $ErrNo, $ErrStr, $Timeout ); - if( $ErrNo || $this->Socket === false ) + if( $ErrNo || $Socket === false ) { throw new MinecraftQueryException( 'Could not create socket: ' . $ErrStr ); } - \stream_set_timeout( $this->Socket, $Timeout ); + $this->Socket = $Socket; + + \stream_set_timeout( $this->Socket, (int)$Timeout ); \stream_set_blocking( $this->Socket, true ); try @@ -80,23 +85,25 @@ public function ConnectBedrock( $Ip, $Port = 19132, $Timeout = 3, $ResolveSRV = } finally { - \fclose( $this->Socket ); + \fclose( $Socket ); } } - public function GetInfo( ) + /** @return array|false */ + public function GetInfo( ) : array|bool { return isset( $this->Info ) ? $this->Info : false; } - public function GetPlayers( ) + /** @return array|false */ + public function GetPlayers( ) : array|bool { return isset( $this->Players ) ? $this->Players : false; } - private function GetChallenge( ) + private function GetChallenge( ) : string { - $Data = $this->WriteData( self :: HANDSHAKE ); + $Data = $this->WriteData( self::HANDSHAKE ); if( $Data === false ) { @@ -106,9 +113,9 @@ private function GetChallenge( ) return \pack( 'N', $Data ); } - private function GetStatus( $Challenge ) + private function GetStatus( string $Challenge ) : void { - $Data = $this->WriteData( self :: STATISTIC, $Challenge . \pack( 'c*', 0x00, 0x00, 0x00, 0x00 ) ); + $Data = $this->WriteData( self::STATISTIC, $Challenge . \pack( 'c*', 0x00, 0x00, 0x00, 0x00 ) ); if( !$Data ) { @@ -198,8 +205,13 @@ private function GetStatus( $Challenge ) } } - private function GetBedrockStatus( ) + private function GetBedrockStatus( ) : void { + if( $this->Socket === null ) + { + throw new MinecraftQueryException( 'Socket is not open.' ); + } + // hardcoded magic https://github.com/facebookarchive/RakNet/blob/1a169895a900c9fc4841c556e16514182b75faf8/Source/RakPeer.cpp#L135 $OFFLINE_MESSAGE_DATA_ID = \pack( 'c*', 0x00, 0xFF, 0xFF, 0x00, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, 0xFD, 0xFD, 0xFD, 0x12, 0x34, 0x56, 0x78 ); @@ -255,8 +267,14 @@ private function GetBedrockStatus( ) $this->Players = null; } - private function WriteData( $Command, $Append = "" ) + /** @return string|false */ + private function WriteData( int $Command, string $Append = "" ) : string|bool { + if( $this->Socket === null ) + { + throw new MinecraftQueryException( 'Socket is not open.' ); + } + $Command = \pack( 'c*', 0xFE, 0xFD, $Command, 0x01, 0x02, 0x03, 0x04 ) . $Append; $Length = \strlen( $Command ); @@ -280,7 +298,7 @@ private function WriteData( $Command, $Append = "" ) return \substr( $Data, 5 ); } - private function ResolveSRV( &$Address, &$Port ) + private function ResolveSRV( string &$Address, int &$Port ) : void { if( \ip2long( $Address ) !== false ) { @@ -301,7 +319,7 @@ private function ResolveSRV( &$Address, &$Port ) if( isset( $Record[ 0 ][ 'port' ] ) ) { - $Port = $Record[ 0 ][ 'port' ]; + $Port = (int)$Record[ 0 ][ 'port' ]; } } } diff --git a/view.php b/view.php index b1ce8cf..469ace7 100644 --- a/view.php +++ b/view.php @@ -9,13 +9,13 @@ // Edit this <- // Display everything in browser, because some people can't look in logs for errors - Error_Reporting( E_ALL | E_STRICT ); - Ini_Set( 'display_errors', true ); + error_reporting( E_ALL | E_STRICT ); + ini_set( 'display_errors', true ); require __DIR__ . '/src/MinecraftQuery.php'; require __DIR__ . '/src/MinecraftQueryException.php'; - $Timer = MicroTime( true ); + $Timer = microtime( true ); $Query = new MinecraftQuery( ); @@ -28,7 +28,7 @@ $Exception = $e; } - $Timer = Number_Format( MicroTime( true ) - $Timer, 4, '.', '' ); + $Timer = number_format( microtime( true ) - $Timer, 4, '.', '' ); ?> @@ -68,7 +68,7 @@
getMessage( ) ); ?>
-
getTraceAsString(), false ); ?>
+
getTraceAsString(), false ); ?>
@@ -85,7 +85,7 @@ "; print_r( $InfoValue ); diff --git a/view_serverping.php b/view_serverping.php index 8b17fb6..9b2f09d 100644 --- a/view_serverping.php +++ b/view_serverping.php @@ -9,13 +9,13 @@ // Edit this <- // Display everything in browser, because some people can't look in logs for errors - Error_Reporting( E_ALL | E_STRICT ); - Ini_Set( 'display_errors', true ); + error_reporting( E_ALL | E_STRICT ); + ini_set( 'display_errors', true ); require __DIR__ . '/src/MinecraftPing.php'; require __DIR__ . '/src/MinecraftPingException.php'; - $Timer = MicroTime( true ); + $Timer = microtime( true ); $Info = false; $Query = null; @@ -53,7 +53,7 @@ $Query->Close( ); } - $Timer = Number_Format( MicroTime( true ) - $Timer, 4, '.', '' ); + $Timer = number_format( microtime( true ) - $Timer, 4, '.', '' ); ?> @@ -93,7 +93,7 @@
getMessage( ) ); ?>
-
getTraceAsString(), false ); ?>
+
getTraceAsString(), false ); ?>
@@ -111,8 +111,9 @@ '; - }else if( Is_Array( $InfoValue ) ) + echo ''; + } + else if( is_array( $InfoValue ) ) { echo "
";
 		print_r( $InfoValue );