diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 00ebc1c..ff16c51 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,5 +14,7 @@ jobs: run: composer install --no-interaction --no-progress - name: Run tests run: php${{ matrix.php }} vendor/bin/phpunit --configuration Tests/phpunit.xml --verbose --fail-on-warning + - name: Run phpstan + run: php${{ matrix.php }} vendor/bin/phpstan - name: Run psalm run: php${{ matrix.php }} vendor/bin/psalm diff --git a/Examples/Example.php b/Examples/Example.php index 7e40f03..caa7efb 100644 --- a/Examples/Example.php +++ b/Examples/Example.php @@ -4,8 +4,8 @@ use xPaw\SourceQuery\SourceQuery; // For the sake of this example - Header( 'Content-Type: text/plain' ); - Header( 'X-Content-Type-Options: nosniff' ); + header( 'Content-Type: text/plain' ); + header( 'X-Content-Type-Options: nosniff' ); // Edit this -> define( 'SQ_SERVER_ADDR', 'localhost' ); diff --git a/Examples/RconExample.php b/Examples/RconExample.php index 7d96c66..5888415 100644 --- a/Examples/RconExample.php +++ b/Examples/RconExample.php @@ -4,8 +4,8 @@ use xPaw\SourceQuery\SourceQuery; // For the sake of this example - Header( 'Content-Type: text/plain' ); - Header( 'X-Content-Type-Options: nosniff' ); + header( 'Content-Type: text/plain' ); + header( 'X-Content-Type-Options: nosniff' ); // Edit this -> define( 'SQ_SERVER_ADDR', 'localhost' ); diff --git a/Examples/View.php b/Examples/View.php index d6e764d..11cb15e 100644 --- a/Examples/View.php +++ b/Examples/View.php @@ -10,13 +10,13 @@ define( 'SQ_ENGINE', SourceQuery::SOURCE ); // Edit this <- - $Timer = MicroTime( true ); + $Timer = microtime( true ); $Query = new SourceQuery( ); - $Info = Array( ); - $Rules = Array( ); - $Players = Array( ); + $Info = []; + $Rules = []; + $Players = []; $Exception = null; try @@ -37,7 +37,7 @@ $Query->Disconnect( ); } - $Timer = Number_Format( MicroTime( true ) - $Timer, 4, '.', '' ); + $Timer = number_format( microtime( true ) - $Timer, 4, '.', '' ); ?> @@ -103,12 +103,12 @@ - + $InfoValue ): ?> "; print_r( $InfoValue ); @@ -176,7 +176,7 @@ - + $Value ): ?> diff --git a/SourceQuery/BaseSocket.php b/SourceQuery/BaseSocket.php index 33fa9c4..1ce405e 100644 --- a/SourceQuery/BaseSocket.php +++ b/SourceQuery/BaseSocket.php @@ -25,7 +25,7 @@ */ abstract class BaseSocket { - /** @var resource */ + /** @var ?resource */ public $Socket; public int $Engine; @@ -108,30 +108,30 @@ } while( $ReadMore && $SherlockFunction( $Buffer, $Length ) ); - $Data = Implode( $Packets ); + $Data = implode( $Packets ); // TODO: Test this if( $IsCompressed ) { // Let's make sure this function exists, it's not included in PHP by default - if( !Function_Exists( 'bzdecompress' ) ) + if( !function_exists( 'bzdecompress' ) ) { throw new \RuntimeException( 'Received compressed packet, PHP doesn\'t have Bzip2 library installed, can\'t decompress.' ); } $Data = bzdecompress( $Data ); - if( !is_string( $Data ) || CRC32( $Data ) !== $PacketChecksum ) + if( !is_string( $Data ) || crc32( $Data ) !== $PacketChecksum ) { throw new InvalidPacketException( 'CRC32 checksum mismatch of uncompressed packet data.', InvalidPacketException::CHECKSUM_MISMATCH ); } } - $Buffer->Set( SubStr( $Data, 4 ) ); + $Buffer->Set( substr( $Data, 4 ) ); } else { - throw new InvalidPacketException( 'Socket read: Raw packet header mismatch. (0x' . DecHex( $Header ) . ')', InvalidPacketException::PACKET_HEADER_MISMATCH ); + throw new InvalidPacketException( 'Socket read: Raw packet header mismatch. (0x' . dechex( $Header ) . ')', InvalidPacketException::PACKET_HEADER_MISMATCH ); } return $Buffer; diff --git a/SourceQuery/Buffer.php b/SourceQuery/Buffer.php index 6112016..2452c99 100644 --- a/SourceQuery/Buffer.php +++ b/SourceQuery/Buffer.php @@ -44,7 +44,7 @@ public function Set( string $Buffer ) : void { $this->Buffer = $Buffer; - $this->Length = StrLen( $Buffer ); + $this->Length = strlen( $Buffer ); $this->Position = 0; } @@ -81,7 +81,7 @@ return ''; } - $Data = SubStr( $this->Buffer, $this->Position, $Length ); + $Data = substr( $this->Buffer, $this->Position, $Length ); $this->Position += $Length; @@ -93,7 +93,7 @@ */ public function GetByte( ) : int { - return Ord( $this->Get( 1 ) ); + return ord( $this->Get( 1 ) ); } /** @@ -106,7 +106,7 @@ throw new InvalidPacketException( 'Not enough data to unpack a short.', InvalidPacketException::BUFFER_EMPTY ); } - $Data = UnPack( 'v', $this->Get( 2 ) ); + $Data = unpack( 'v', $this->Get( 2 ) ); return (int)$Data[ 1 ]; } @@ -121,7 +121,7 @@ throw new InvalidPacketException( 'Not enough data to unpack a long.', InvalidPacketException::BUFFER_EMPTY ); } - $Data = UnPack( 'l', $this->Get( 4 ) ); + $Data = unpack( 'l', $this->Get( 4 ) ); return (int)$Data[ 1 ]; } @@ -136,7 +136,7 @@ throw new InvalidPacketException( 'Not enough data to unpack a float.', InvalidPacketException::BUFFER_EMPTY ); } - $Data = UnPack( 'f', $this->Get( 4 ) ); + $Data = unpack( 'f', $this->Get( 4 ) ); return (float)$Data[ 1 ]; } @@ -151,7 +151,7 @@ throw new InvalidPacketException( 'Not enough data to unpack an usigned long.', InvalidPacketException::BUFFER_EMPTY ); } - $Data = UnPack( 'V', $this->Get( 4 ) ); + $Data = unpack( 'V', $this->Get( 4 ) ); return (int)$Data[ 1 ]; } @@ -161,7 +161,7 @@ */ public function GetString( ) : string { - $ZeroBytePosition = StrPos( $this->Buffer, "\0", $this->Position ); + $ZeroBytePosition = strpos( $this->Buffer, "\0", $this->Position ); if( $ZeroBytePosition === false ) { diff --git a/SourceQuery/GoldSourceRcon.php b/SourceQuery/GoldSourceRcon.php index ceb7270..ec9f763 100644 --- a/SourceQuery/GoldSourceRcon.php +++ b/SourceQuery/GoldSourceRcon.php @@ -53,10 +53,10 @@ public function Write( int $Header, string $String = '' ) : bool { - $Command = Pack( 'cccca*', 0xFF, 0xFF, 0xFF, 0xFF, $String ); - $Length = StrLen( $Command ); + $Command = pack( 'cccca*', 0xFF, 0xFF, 0xFF, 0xFF, $String ); + $Length = strlen( $Command ); - return $Length === FWrite( $this->Socket->Socket, $Command, $Length ); + return $Length === fwrite( $this->Socket->Socket, $Command, $Length ); } /** @@ -89,7 +89,7 @@ //$StringBuffer .= SubStr( $Packet, 0, -2 ); // Let's assume if this packet is not long enough, there are no more after this one - $ReadMore = StrLen( $Packet ) > 1000; // use 1300? + $ReadMore = strlen( $Packet ) > 1000; // use 1300? if( $ReadMore ) { @@ -140,6 +140,6 @@ throw new AuthenticationException( 'Failed to get RCON challenge.', AuthenticationException::BAD_PASSWORD ); } - $this->RconChallenge = Trim( $Buffer->Get( ) ); + $this->RconChallenge = trim( $Buffer->Get( ) ); } } diff --git a/SourceQuery/Socket.php b/SourceQuery/Socket.php index 00f9325..726a4d1 100644 --- a/SourceQuery/Socket.php +++ b/SourceQuery/Socket.php @@ -29,7 +29,7 @@ { if( $this->Socket !== null ) { - FClose( $this->Socket ); + fclose( $this->Socket ); $this->Socket = null; } @@ -42,7 +42,7 @@ $this->Port = $Port; $this->Address = $Address; - $Socket = @FSockOpen( 'udp://' . $Address, $Port, $ErrNo, $ErrStr, $Timeout ); + $Socket = @fsockopen( 'udp://' . $Address, $Port, $ErrNo, $ErrStr, $Timeout ); if( $ErrNo || $Socket === false ) { @@ -50,16 +50,16 @@ } $this->Socket = $Socket; - Stream_Set_Timeout( $this->Socket, $Timeout ); - Stream_Set_Blocking( $this->Socket, true ); + stream_set_timeout( $this->Socket, $Timeout ); + stream_set_blocking( $this->Socket, true ); } public function Write( int $Header, string $String = '' ) : bool { - $Command = Pack( 'ccccca*', 0xFF, 0xFF, 0xFF, 0xFF, $Header, $String ); - $Length = StrLen( $Command ); + $Command = pack( 'ccccca*', 0xFF, 0xFF, 0xFF, 0xFF, $Header, $String ); + $Length = strlen( $Command ); - return $Length === FWrite( $this->Socket, $Command, $Length ); + return $Length === fwrite( $this->Socket, $Command, $Length ); } /** @@ -72,7 +72,7 @@ public function Read( int $Length = 1400 ) : Buffer { $Buffer = new Buffer( ); - $Buffer->Set( FRead( $this->Socket, $Length ) ); + $Buffer->Set( fread( $this->Socket, $Length ) ); $this->ReadInternal( $Buffer, $Length, [ $this, 'Sherlock' ] ); @@ -81,9 +81,9 @@ public function Sherlock( Buffer $Buffer, int $Length ) : bool { - $Data = FRead( $this->Socket, $Length ); + $Data = fread( $this->Socket, $Length ); - if( StrLen( $Data ) < 4 ) + if( strlen( $Data ) < 4 ) { return false; } diff --git a/SourceQuery/SourceQuery.php b/SourceQuery/SourceQuery.php index b4652fb..74f7f57 100644 --- a/SourceQuery/SourceQuery.php +++ b/SourceQuery/SourceQuery.php @@ -240,8 +240,8 @@ $Server[ 'Players' ] = $Buffer->GetByte( ); $Server[ 'MaxPlayers' ] = $Buffer->GetByte( ); $Server[ 'Protocol' ] = $Buffer->GetByte( ); - $Server[ 'Dedicated' ] = Chr( $Buffer->GetByte( ) ); - $Server[ 'Os' ] = Chr( $Buffer->GetByte( ) ); + $Server[ 'Dedicated' ] = chr( $Buffer->GetByte( ) ); + $Server[ 'Os' ] = chr( $Buffer->GetByte( ) ); $Server[ 'Password' ] = $Buffer->GetByte( ) === 1; $Server[ 'IsMod' ] = $Buffer->GetByte( ) === 1; @@ -266,7 +266,7 @@ if( $Type !== self::S2A_INFO_SRC ) { - throw new InvalidPacketException( 'GetInfo: Packet header mismatch. (0x' . DecHex( $Type ) . ')', InvalidPacketException::PACKET_HEADER_MISMATCH ); + throw new InvalidPacketException( 'GetInfo: Packet header mismatch. (0x' . dechex( $Type ) . ')', InvalidPacketException::PACKET_HEADER_MISMATCH ); } $Server[ 'Protocol' ] = $Buffer->GetByte( ); @@ -278,8 +278,8 @@ $Server[ 'Players' ] = $Buffer->GetByte( ); $Server[ 'MaxPlayers' ] = $Buffer->GetByte( ); $Server[ 'Bots' ] = $Buffer->GetByte( ); - $Server[ 'Dedicated' ] = Chr( $Buffer->GetByte( ) ); - $Server[ 'Os' ] = Chr( $Buffer->GetByte( ) ); + $Server[ 'Dedicated' ] = chr( $Buffer->GetByte( ) ); + $Server[ 'Os' ] = chr( $Buffer->GetByte( ) ); $Server[ 'Password' ] = $Buffer->GetByte( ) === 1; $Server[ 'Secure' ] = $Buffer->GetByte( ) === 1; @@ -390,7 +390,7 @@ if( $Type !== self::S2A_PLAYER ) { - throw new InvalidPacketException( 'GetPlayers: Packet header mismatch. (0x' . DecHex( $Type ) . ')', InvalidPacketException::PACKET_HEADER_MISMATCH ); + throw new InvalidPacketException( 'GetPlayers: Packet header mismatch. (0x' . dechex( $Type ) . ')', InvalidPacketException::PACKET_HEADER_MISMATCH ); } $Players = []; @@ -403,7 +403,7 @@ $Player[ 'Name' ] = $Buffer->GetString( ); $Player[ 'Frags' ] = $Buffer->GetLong( ); $Player[ 'Time' ] = (int)$Buffer->GetFloat( ); - $Player[ 'TimeF' ] = GMDate( ( $Player[ 'Time' ] > 3600 ? "H:i:s" : "i:s" ), $Player[ 'Time' ] ); + $Player[ 'TimeF' ] = gmdate( ( $Player[ 'Time' ] > 3600 ? 'H:i:s' : 'i:s' ), $Player[ 'Time' ] ); $Players[ ] = $Player; } @@ -435,7 +435,7 @@ if( $Type !== self::S2A_RULES ) { - throw new InvalidPacketException( 'GetRules: Packet header mismatch. (0x' . DecHex( $Type ) . ')', InvalidPacketException::PACKET_HEADER_MISMATCH ); + throw new InvalidPacketException( 'GetRules: Packet header mismatch. (0x' . dechex( $Type ) . ')', InvalidPacketException::PACKET_HEADER_MISMATCH ); } $Rules = []; @@ -446,7 +446,7 @@ $Rule = $Buffer->GetString( ); $Value = $Buffer->GetString( ); - if( !Empty( $Rule ) ) + if( !empty( $Rule ) ) { $Rules[ $Rule ] = $Value; } @@ -497,7 +497,7 @@ } default: { - throw new InvalidPacketException( 'GetChallenge: Packet header mismatch. (0x' . DecHex( $Type ) . ')', InvalidPacketException::PACKET_HEADER_MISMATCH ); + throw new InvalidPacketException( 'GetChallenge: Packet header mismatch. (0x' . dechex( $Type ) . ')', InvalidPacketException::PACKET_HEADER_MISMATCH ); } } } diff --git a/SourceQuery/SourceRcon.php b/SourceQuery/SourceRcon.php index e6d2566..56919e0 100644 --- a/SourceQuery/SourceRcon.php +++ b/SourceQuery/SourceRcon.php @@ -32,7 +32,7 @@ */ private BaseSocket $Socket; - /** @var resource */ + /** @var ?resource */ private $RconSocket; private int $RconRequestId = 0; @@ -45,7 +45,7 @@ { if( $this->RconSocket ) { - FClose( $this->RconSocket ); + fclose( $this->RconSocket ); $this->RconSocket = null; } @@ -57,7 +57,7 @@ { if( !$this->RconSocket ) { - $RconSocket = @FSockOpen( $this->Socket->Address, $this->Socket->Port, $ErrNo, $ErrStr, $this->Socket->Timeout ); + $RconSocket = @fsockopen( $this->Socket->Address, $this->Socket->Port, $ErrNo, $ErrStr, $this->Socket->Timeout ); if( $ErrNo || !$RconSocket ) { @@ -65,27 +65,27 @@ } $this->RconSocket = $RconSocket; - Stream_Set_Timeout( $this->RconSocket, $this->Socket->Timeout ); - Stream_Set_Blocking( $this->RconSocket, true ); + stream_set_timeout( $this->RconSocket, $this->Socket->Timeout ); + stream_set_blocking( $this->RconSocket, true ); } } public function Write( int $Header, string $String = '' ) : bool { // Pack the packet together - $Command = Pack( 'VV', ++$this->RconRequestId, $Header ) . $String . "\x00\x00"; + $Command = pack( 'VV', ++$this->RconRequestId, $Header ) . $String . "\x00\x00"; // Prepend packet length - $Command = Pack( 'V', StrLen( $Command ) ) . $Command; - $Length = StrLen( $Command ); + $Command = pack( 'V', strlen( $Command ) ) . $Command; + $Length = strlen( $Command ); - return $Length === FWrite( $this->RconSocket, $Command, $Length ); + return $Length === fwrite( $this->RconSocket, $Command, $Length ); } public function Read( ) : Buffer { $Buffer = new Buffer( ); - $Buffer->Set( FRead( $this->RconSocket, 4 ) ); + $Buffer->Set( fread( $this->RconSocket, 4 ) ); if( $Buffer->Remaining( ) < 4 ) { @@ -94,23 +94,21 @@ $PacketSize = $Buffer->GetLong( ); - $Buffer->Set( FRead( $this->RconSocket, $PacketSize ) ); + $Buffer->Set( fread( $this->RconSocket, $PacketSize ) ); $Data = $Buffer->Get( ); - $Remaining = $PacketSize - StrLen( $Data ); + $Remaining = $PacketSize - strlen( $Data ); while( $Remaining > 0 ) { - $Data2 = FRead( $this->RconSocket, $Remaining ); + $Data2 = fread( $this->RconSocket, $Remaining ); - $PacketSize = StrLen( $Data2 ); + $PacketSize = strlen( $Data2 ); if( $PacketSize === 0 ) { throw new InvalidPacketException( 'Read ' . strlen( $Data ) . ' bytes from socket, ' . $Remaining . ' remaining', InvalidPacketException::BUFFER_EMPTY ); - - break; } $Data .= $Data2; @@ -144,7 +142,7 @@ // We do this stupid hack to handle split packets // See https://developer.valvesoftware.com/wiki/Source_RCON_Protocol#Multiple-packet_Responses - if( StrLen( $Data ) >= 4000 ) + if( strlen( $Data ) >= 4000 ) { $this->Write( SourceQuery::SERVERDATA_REQUESTVALUE ); diff --git a/Tests/Tests.php b/Tests/Tests.php index dc0ebda..1453554 100644 --- a/Tests/Tests.php +++ b/Tests/Tests.php @@ -6,10 +6,12 @@ class TestableSocket extends BaseSocket { + /** @var \SplQueue */ private \SplQueue $PacketQueue; public function __construct( ) { + /** @var \SplQueue */ $this->PacketQueue = new \SplQueue(); $this->PacketQueue->setIteratorMode( \SplDoublyLinkedList::IT_MODE_DELETE ); @@ -41,7 +43,7 @@ public function Read( int $Length = 1400 ) : Buffer { $Buffer = new Buffer( ); - $Buffer->Set( (string)$this->PacketQueue->shift() ); + $Buffer->Set( $this->PacketQueue->shift() ); $this->ReadInternal( $Buffer, $Length, [ $this, 'Sherlock' ] ); @@ -55,7 +57,7 @@ return false; } - $Buffer->Set( (string)$this->PacketQueue->shift() ); + $Buffer->Set( $this->PacketQueue->shift() ); return $Buffer->GetLong( ) === -2; } @@ -245,6 +247,7 @@ /** * @dataProvider RulesProvider + * @param array $RawInput */ public function testGetRules( array $RawInput, array $ExpectedOutput ) : void { @@ -280,6 +283,7 @@ /** * @dataProvider PlayersProvider + * @param array $RawInput */ public function testGetPlayers( array $RawInput, array $ExpectedOutput ) : void { diff --git a/composer.json b/composer.json index 1d5e393..5a2d346 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,8 @@ "require-dev": { "phpunit/phpunit": "^9.5", - "vimeo/psalm": "^4.7" + "vimeo/psalm": "^4.7", + "phpstan/phpstan": "^0.12.83" }, "autoload": { diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..0deb5a0 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,8 @@ +parameters: + checkMissingIterableValueType: false + checkFunctionNameCase: true + level: 6 + paths: + - . + excludes_analyse: + - vendor