Skip to content

Commit f9470f1

Browse files
committed
Add types, minor fixes
1 parent 68c9938 commit f9470f1

File tree

5 files changed

+119
-59
lines changed

5 files changed

+119
-59
lines changed

phpstan.neon

+1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ parameters:
44
level: max
55
paths:
66
- src
7+
- .
78
excludePaths:
89
- vendor

src/MinecraftPing.php

+61-21
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,22 @@ class MinecraftPing
2626
*
2727
*/
2828

29+
/** @var ?resource $Socket */
2930
private $Socket;
30-
private $ServerAddress;
31-
private $ServerPort;
32-
private $Timeout;
31+
private string $ServerAddress;
32+
private int $ServerPort;
33+
private float $Timeout;
3334

34-
public function __construct( $Address, $Port = 25565, $Timeout = 2, $ResolveSRV = true )
35+
public function __construct( string $Address, int $Port = 25565, float $Timeout = 2, bool $ResolveSRV = true )
3536
{
37+
if( $Timeout < 0 )
38+
{
39+
throw new \InvalidArgumentException( 'Timeout must be a positive integer.' );
40+
}
41+
3642
$this->ServerAddress = $Address;
37-
$this->ServerPort = (int)$Port;
38-
$this->Timeout = (int)$Timeout;
43+
$this->ServerPort = $Port;
44+
$this->Timeout = $Timeout;
3945

4046
if( $ResolveSRV )
4147
{
@@ -50,7 +56,7 @@ public function __destruct( )
5056
$this->Close( );
5157
}
5258

53-
public function Close( )
59+
public function Close( ) : void
5460
{
5561
if( $this->Socket !== null )
5662
{
@@ -60,23 +66,29 @@ public function Close( )
6066
}
6167
}
6268

63-
public function Connect( )
69+
public function Connect( ) : void
6470
{
65-
$this->Socket = @\fsockopen( $this->ServerAddress, $this->ServerPort, $errno, $errstr, (float)$this->Timeout );
71+
$Socket = @\fsockopen( $this->ServerAddress, $this->ServerPort, $errno, $errstr, $this->Timeout );
6672

67-
if( !$this->Socket )
73+
if( $Socket === false )
6874
{
69-
$this->Socket = null;
70-
7175
throw new MinecraftPingException( "Failed to connect or create a socket: $errno ($errstr)" );
7276
}
7377

78+
$this->Socket = $Socket;
79+
7480
// Set Read/Write timeout
75-
\stream_set_timeout( $this->Socket, $this->Timeout );
81+
\stream_set_timeout( $this->Socket, (int)$this->Timeout );
7682
}
7783

78-
public function Query( )
84+
/** @return array|false */
85+
public function Query( ) : array|bool
7986
{
87+
if( $this->Socket === null )
88+
{
89+
throw new MinecraftPingException( 'Socket is not open.' );
90+
}
91+
8092
$TimeStart = \microtime( true ); // for read timeout purposes
8193

8294
// See http://wiki.vg/Protocol (Status Ping)
@@ -95,7 +107,7 @@ public function Query( )
95107

96108
if( $Length < 10 )
97109
{
98-
return FALSE;
110+
return false;
99111
}
100112

101113
$this->ReadVarInt( ); // packet type, in server ping it's 0
@@ -104,7 +116,7 @@ public function Query( )
104116

105117
if( $Length < 2 )
106118
{
107-
return FALSE;
119+
return false;
108120
}
109121

110122
$Data = "";
@@ -116,6 +128,12 @@ public function Query( )
116128
}
117129

118130
$Remainder = $Length - \strlen( $Data );
131+
132+
if( $Remainder <= 0 )
133+
{
134+
break;
135+
}
136+
119137
$block = \fread( $this->Socket, $Remainder ); // and finally the json string
120138
// abort if there is no progress
121139
if( !$block )
@@ -133,23 +151,45 @@ public function Query( )
133151
throw new MinecraftPingException( 'JSON parsing failed: ' . \json_last_error_msg( ) );
134152
}
135153

154+
if( !\is_array( $Data ) )
155+
{
156+
return false;
157+
}
158+
136159
return $Data;
137160
}
138161

139-
public function QueryOldPre17( )
162+
/** @return array|false */
163+
public function QueryOldPre17( ) : array|bool
140164
{
165+
if( $this->Socket === null )
166+
{
167+
throw new MinecraftPingException( 'Socket is not open.' );
168+
}
169+
141170
\fwrite( $this->Socket, "\xFE\x01" );
142171
$Data = \fread( $this->Socket, 512 );
172+
173+
if( empty( $Data ) )
174+
{
175+
return false;
176+
}
177+
143178
$Len = \strlen( $Data );
144179

145180
if( $Len < 4 || $Data[ 0 ] !== "\xFF" )
146181
{
147-
return FALSE;
182+
return false;
148183
}
149184

150185
$Data = \substr( $Data, 3 ); // Strip packet header (kick message packet and short length)
151186
$Data = \iconv( 'UTF-16BE', 'UTF-8', $Data );
152187

188+
if( $Data === false )
189+
{
190+
return false;
191+
}
192+
153193
// Are we dealing with Minecraft 1.4+ server?
154194
if( $Data[ 1 ] === "\xA7" && $Data[ 2 ] === "\x31" )
155195
{
@@ -175,7 +215,7 @@ public function QueryOldPre17( )
175215
);
176216
}
177217

178-
private function ReadVarInt( )
218+
private function ReadVarInt( ) : int
179219
{
180220
$i = 0;
181221
$j = 0;
@@ -207,7 +247,7 @@ private function ReadVarInt( )
207247
return $i;
208248
}
209249

210-
private function ResolveSRV()
250+
private function ResolveSRV() : void
211251
{
212252
if( \ip2long( $this->ServerAddress ) !== false )
213253
{
@@ -228,7 +268,7 @@ private function ResolveSRV()
228268

229269
if( isset( $Record[ 0 ][ 'port' ] ) )
230270
{
231-
$this->ServerPort = $Record[ 0 ][ 'port' ];
271+
$this->ServerPort = (int)$Record[ 0 ][ 'port' ];
232272
}
233273
}
234274
}

src/MinecraftQuery.php

+43-25
Original file line numberDiff line numberDiff line change
@@ -14,30 +14,33 @@ class MinecraftQuery
1414
const STATISTIC = 0x00;
1515
const HANDSHAKE = 0x09;
1616

17+
/** @var ?resource $Socket */
1718
private $Socket;
18-
private $Players;
19-
private $Info;
19+
private ?array $Players = null;
20+
private ?array $Info = null;
2021

21-
public function Connect( $Ip, $Port = 25565, $Timeout = 3, $ResolveSRV = true )
22+
public function Connect( string $Ip, int $Port = 25565, float $Timeout = 3, bool $ResolveSRV = true ) : void
2223
{
23-
if( !is_int( $Timeout ) || $Timeout < 0 )
24+
if( $Timeout < 0 )
2425
{
25-
throw new \InvalidArgumentException( 'Timeout must be an integer.' );
26+
throw new \InvalidArgumentException( 'Timeout must be a positive integer.' );
2627
}
2728

2829
if( $ResolveSRV )
2930
{
3031
$this->ResolveSRV( $Ip, $Port );
3132
}
3233

33-
$this->Socket = @\fsockopen( 'udp://' . $Ip, (int)$Port, $ErrNo, $ErrStr, (float)$Timeout );
34+
$Socket = @\fsockopen( 'udp://' . $Ip, $Port, $ErrNo, $ErrStr, $Timeout );
3435

35-
if( $ErrNo || $this->Socket === false )
36+
if( $ErrNo || $Socket === false )
3637
{
3738
throw new MinecraftQueryException( 'Could not create socket: ' . $ErrStr );
3839
}
3940

40-
\stream_set_timeout( $this->Socket, $Timeout );
41+
$this->Socket = $Socket;
42+
43+
\stream_set_timeout( $this->Socket, (int)$Timeout );
4144
\stream_set_blocking( $this->Socket, true );
4245

4346
try
@@ -48,13 +51,13 @@ public function Connect( $Ip, $Port = 25565, $Timeout = 3, $ResolveSRV = true )
4851
}
4952
finally
5053
{
51-
\fclose( $this->Socket );
54+
\fclose( $Socket );
5255
}
5356
}
5457

55-
public function ConnectBedrock( $Ip, $Port = 19132, $Timeout = 3, $ResolveSRV = true )
58+
public function ConnectBedrock( string $Ip, int $Port = 19132, float $Timeout = 3, bool $ResolveSRV = true ) : void
5659
{
57-
if( !is_int( $Timeout ) || $Timeout < 0 )
60+
if( $Timeout < 0 )
5861
{
5962
throw new \InvalidArgumentException( 'Timeout must be an integer.' );
6063
}
@@ -64,14 +67,16 @@ public function ConnectBedrock( $Ip, $Port = 19132, $Timeout = 3, $ResolveSRV =
6467
$this->ResolveSRV( $Ip, $Port );
6568
}
6669

67-
$this->Socket = @\fsockopen( 'udp://' . $Ip, (int)$Port, $ErrNo, $ErrStr, (float)$Timeout );
70+
$Socket = @\fsockopen( 'udp://' . $Ip, $Port, $ErrNo, $ErrStr, $Timeout );
6871

69-
if( $ErrNo || $this->Socket === false )
72+
if( $ErrNo || $Socket === false )
7073
{
7174
throw new MinecraftQueryException( 'Could not create socket: ' . $ErrStr );
7275
}
7376

74-
\stream_set_timeout( $this->Socket, $Timeout );
77+
$this->Socket = $Socket;
78+
79+
\stream_set_timeout( $this->Socket, (int)$Timeout );
7580
\stream_set_blocking( $this->Socket, true );
7681

7782
try
@@ -80,23 +85,25 @@ public function ConnectBedrock( $Ip, $Port = 19132, $Timeout = 3, $ResolveSRV =
8085
}
8186
finally
8287
{
83-
\fclose( $this->Socket );
88+
\fclose( $Socket );
8489
}
8590
}
8691

87-
public function GetInfo( )
92+
/** @return array|false */
93+
public function GetInfo( ) : array|bool
8894
{
8995
return isset( $this->Info ) ? $this->Info : false;
9096
}
9197

92-
public function GetPlayers( )
98+
/** @return array|false */
99+
public function GetPlayers( ) : array|bool
93100
{
94101
return isset( $this->Players ) ? $this->Players : false;
95102
}
96103

97-
private function GetChallenge( )
104+
private function GetChallenge( ) : string
98105
{
99-
$Data = $this->WriteData( self :: HANDSHAKE );
106+
$Data = $this->WriteData( self::HANDSHAKE );
100107

101108
if( $Data === false )
102109
{
@@ -106,9 +113,9 @@ private function GetChallenge( )
106113
return \pack( 'N', $Data );
107114
}
108115

109-
private function GetStatus( $Challenge )
116+
private function GetStatus( string $Challenge ) : void
110117
{
111-
$Data = $this->WriteData( self :: STATISTIC, $Challenge . \pack( 'c*', 0x00, 0x00, 0x00, 0x00 ) );
118+
$Data = $this->WriteData( self::STATISTIC, $Challenge . \pack( 'c*', 0x00, 0x00, 0x00, 0x00 ) );
112119

113120
if( !$Data )
114121
{
@@ -198,8 +205,13 @@ private function GetStatus( $Challenge )
198205
}
199206
}
200207

201-
private function GetBedrockStatus( )
208+
private function GetBedrockStatus( ) : void
202209
{
210+
if( $this->Socket === null )
211+
{
212+
throw new MinecraftQueryException( 'Socket is not open.' );
213+
}
214+
203215
// hardcoded magic https://github.com/facebookarchive/RakNet/blob/1a169895a900c9fc4841c556e16514182b75faf8/Source/RakPeer.cpp#L135
204216
$OFFLINE_MESSAGE_DATA_ID = \pack( 'c*', 0x00, 0xFF, 0xFF, 0x00, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, 0xFD, 0xFD, 0xFD, 0x12, 0x34, 0x56, 0x78 );
205217

@@ -255,8 +267,14 @@ private function GetBedrockStatus( )
255267
$this->Players = null;
256268
}
257269

258-
private function WriteData( $Command, $Append = "" )
270+
/** @return string|false */
271+
private function WriteData( int $Command, string $Append = "" ) : string|bool
259272
{
273+
if( $this->Socket === null )
274+
{
275+
throw new MinecraftQueryException( 'Socket is not open.' );
276+
}
277+
260278
$Command = \pack( 'c*', 0xFE, 0xFD, $Command, 0x01, 0x02, 0x03, 0x04 ) . $Append;
261279
$Length = \strlen( $Command );
262280

@@ -280,7 +298,7 @@ private function WriteData( $Command, $Append = "" )
280298
return \substr( $Data, 5 );
281299
}
282300

283-
private function ResolveSRV( &$Address, &$Port )
301+
private function ResolveSRV( string &$Address, int &$Port ) : void
284302
{
285303
if( \ip2long( $Address ) !== false )
286304
{
@@ -301,7 +319,7 @@ private function ResolveSRV( &$Address, &$Port )
301319

302320
if( isset( $Record[ 0 ][ 'port' ] ) )
303321
{
304-
$Port = $Record[ 0 ][ 'port' ];
322+
$Port = (int)$Record[ 0 ][ 'port' ];
305323
}
306324
}
307325
}

0 commit comments

Comments
 (0)