diff --git a/Examples/View.php b/Examples/View.php index fb21e20..9ecaa47 100644 --- a/Examples/View.php +++ b/Examples/View.php @@ -39,7 +39,7 @@ $Timer = number_format(microtime(true) - $Timer, 4, '.', ''); ?> - +
";
print_r($InfoValue);
echo "";
+ } elseif ($InfoValue === true) {
+ echo 'true';
+ } elseif ($InfoValue === false) {
+ echo 'false';
} else {
- if ($InfoValue === true) {
- echo 'true';
- } elseif ($InfoValue === false) {
- echo 'false';
- } else {
- echo htmlspecialchars($InfoValue);
- }
+ echo htmlspecialchars($InfoValue);
}
?>
diff --git a/SourceQuery/BaseSocket.php b/SourceQuery/BaseSocket.php
index 5909f48..f1a98dc 100644
--- a/SourceQuery/BaseSocket.php
+++ b/SourceQuery/BaseSocket.php
@@ -23,29 +23,82 @@ use xPaw\SourceQuery\Exception\SocketException;
*
* @package xPaw\SourceQuery
*
- * @uses xPaw\SourceQuery\Exception\InvalidPacketException
- * @uses xPaw\SourceQuery\Exception\SocketException
+ * @uses InvalidPacketException
+ * @uses SocketException
*/
abstract class BaseSocket
{
- /** @var ?resource */
+ /**
+ * @var resource
+ */
public $Socket;
- public int $Engine;
-
- public string $Address;
- public int $Port;
- public int $Timeout;
+ /**
+ * @var int $Engine
+ */
+ public int $Engine = SourceQuery::SOURCE;
+
+ /**
+ * @var string $Address
+ */
+ public string $Address = '';
+
+ /**
+ * @var int $Port
+ */
+ public int $Port = 0;
+
+ /**
+ * @var int $Timeout
+ */
+ public int $Timeout = 0;
+
+ /**
+ * Destructor
+ */
public function __destruct()
{
$this->Close();
}
+ /**
+ * Close
+ */
abstract public function Close(): void;
+
+ /**
+ * @param string $Address
+ * @param int $Port
+ * @param int $Timeout
+ * @param int $Engine
+ */
abstract public function Open(string $Address, int $Port, int $Timeout, int $Engine): void;
+
+ /**
+ * @param int $Header
+ * @param string $String
+ *
+ * @return bool
+ */
abstract public function Write(int $Header, string $String = ''): bool;
+
+ /**
+ * @param int $Length
+ *
+ * @return Buffer
+ */
abstract public function Read(int $Length = 1400): Buffer;
+ /**
+ * @param Buffer $Buffer
+ * @param int $Length
+ * @param callable $SherlockFunction
+ *
+ * @return Buffer
+ *
+ * @throws InvalidPacketException
+ * @throws SocketException
+ */
protected function ReadInternal(Buffer $Buffer, int $Length, callable $SherlockFunction): Buffer
{
if ($Buffer->Remaining() === 0) {
@@ -54,12 +107,14 @@ abstract class BaseSocket
$Header = $Buffer->GetLong();
- if ($Header === -1) { // Single packet
- // We don't have to do anything
- } elseif ($Header === -2) { // Split packet
+ // Single packet, do nothing.
+ if ($Header === -1) {
+ return $Buffer;
+ }
+
+ if ($Header === -2) { // Split packet
$Packets = [];
$IsCompressed = false;
- $ReadMore = false;
$PacketChecksum = null;
do {
@@ -98,18 +153,13 @@ abstract class BaseSocket
$Packets[ $PacketNumber ] = $Buffer->Get();
- $ReadMore = $PacketCount > sizeof($Packets);
+ $ReadMore = $PacketCount > count($Packets);
} while ($ReadMore && $SherlockFunction($Buffer, $Length));
$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')) {
- 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) {
diff --git a/SourceQuery/Buffer.php b/SourceQuery/Buffer.php
index 1896261..7eb911e 100644
--- a/SourceQuery/Buffer.php
+++ b/SourceQuery/Buffer.php
@@ -22,7 +22,7 @@ use xPaw\SourceQuery\Exception\InvalidPacketException;
*
* @package xPaw\SourceQuery
*
- * @uses xPaw\SourceQuery\Exception\InvalidPacketException
+ * @uses InvalidPacketException
*/
final class Buffer
{
@@ -43,6 +43,8 @@ final class Buffer
/**
* Sets buffer
+ *
+ * @param string $Buffer
*/
public function Set(string $Buffer): void
{
@@ -61,10 +63,20 @@ final class Buffer
return $this->Length - $this->Position;
}
+ /**
+ * @return bool
+ */
+ public function isEmpty(): bool
+ {
+ return $this->Remaining() <= 0;
+ }
+
/**
* Gets data from buffer
*
* @param int $Length Bytes to read
+ *
+ * @return string
*/
public function Get(int $Length = -1): string
{
@@ -97,6 +109,8 @@ final class Buffer
/**
* Get short from buffer
+ *
+ * @throws InvalidPacketException
*/
public function GetShort(): int
{
@@ -111,6 +125,8 @@ final class Buffer
/**
* Get long from buffer
+ *
+ * @throws InvalidPacketException
*/
public function GetLong(): int
{
@@ -125,6 +141,8 @@ final class Buffer
/**
* Get float from buffer
+ *
+ * @throws InvalidPacketException
*/
public function GetFloat(): float
{
@@ -139,6 +157,8 @@ final class Buffer
/**
* Get unsigned long from buffer
+ *
+ * @throws InvalidPacketException
*/
public function GetUnsignedLong(): int
{
diff --git a/SourceQuery/Exception/SourceQueryException.php b/SourceQuery/Exception/SourceQueryException.php
index 7c8bce0..965968a 100644
--- a/SourceQuery/Exception/SourceQueryException.php
+++ b/SourceQuery/Exception/SourceQueryException.php
@@ -15,7 +15,9 @@ declare(strict_types=1);
namespace xPaw\SourceQuery\Exception;
-abstract class SourceQueryException extends \Exception
+use Exception;
+
+abstract class SourceQueryException extends Exception
{
// Base exception class
}
diff --git a/SourceQuery/GoldSourceRcon.php b/SourceQuery/GoldSourceRcon.php
index f3cd2c2..dd43294 100644
--- a/SourceQuery/GoldSourceRcon.php
+++ b/SourceQuery/GoldSourceRcon.php
@@ -33,28 +33,48 @@ final class GoldSourceRcon
*
* @var BaseSocket
*/
- private $Socket;
+ private BaseSocket $Socket;
+ /**
+ * @var string $RconPassword
+ */
private string $RconPassword = '';
+
+ /**
+ * @var string $RconChallenge
+ */
private string $RconChallenge = '';
+ /**
+ * @param BaseSocket $Socket
+ */
public function __construct(BaseSocket $Socket)
{
$this->Socket = $Socket;
}
+ /**
+ * Close
+ */
public function Close(): void
{
$this->RconChallenge = '';
$this->RconPassword = '';
}
+ /**
+ * Open
+ */
public function Open(): void
{
- //
}
- public function Write(int $Header, string $String = ''): bool
+ /**
+ * @param string $String
+ *
+ * @return bool
+ */
+ public function Write(string $String = ''): bool
{
$Command = pack('cccca*', 0xFF, 0xFF, 0xFF, 0xFF, $String);
$Length = strlen($Command);
@@ -63,17 +83,17 @@ final class GoldSourceRcon
}
/**
- * @param int $Length
* @throws AuthenticationException
+ * @throws InvalidPacketException
+ *
* @return Buffer
*/
- public function Read(int $Length = 1400): Buffer
+ public function Read(): Buffer
{
// GoldSource RCON has same structure as Query
$Buffer = $this->Socket->Read();
$StringBuffer = '';
- $ReadMore = false;
// There is no indentifier of the end, so we just need to continue reading
do {
@@ -110,23 +130,36 @@ final class GoldSourceRcon
return $Buffer;
}
+ /**
+ * @param string $Command
+ *
+ * @return string
+ *
+ * @throws AuthenticationException
+ * @throws InvalidPacketException
+ */
public function Command(string $Command): string
{
if (!$this->RconChallenge) {
throw new AuthenticationException('Tried to execute a RCON command before successful authorization.', AuthenticationException::BAD_PASSWORD);
}
- $this->Write(0, 'rcon ' . $this->RconChallenge . ' "' . $this->RconPassword . '" ' . $Command . "\0");
+ $this->Write('rcon ' . $this->RconChallenge . ' "' . $this->RconPassword . '" ' . $Command . "\0");
$Buffer = $this->Read();
return $Buffer->Get();
}
+ /**
+ * @param string $Password
+ *
+ * @throws AuthenticationException
+ */
public function Authorize(string $Password): void
{
$this->RconPassword = $Password;
- $this->Write(0, 'challenge rcon');
+ $this->Write('challenge rcon');
$Buffer = $this->Socket->Read();
if ($Buffer->Get(14) !== 'challenge rcon') {
diff --git a/SourceQuery/Socket.php b/SourceQuery/Socket.php
index f5d8bb5..05489e3 100644
--- a/SourceQuery/Socket.php
+++ b/SourceQuery/Socket.php
@@ -28,15 +28,26 @@ use xPaw\SourceQuery\Exception\SocketException;
*/
final class Socket extends BaseSocket
{
+ /**
+ * Close
+ */
public function Close(): void
{
if ($this->Socket !== null) {
fclose($this->Socket);
- $this->Socket = null;
+ $this->Socket = 0;
}
}
+ /**
+ * @param string $Address
+ * @param int $Port
+ * @param int $Timeout
+ * @param int $Engine
+ *
+ * @throws SocketException
+ */
public function Open(string $Address, int $Port, int $Timeout, int $Engine): void
{
$this->Timeout = $Timeout;
@@ -55,6 +66,12 @@ final class Socket extends BaseSocket
stream_set_blocking($this->Socket, true);
}
+ /**
+ * @param int $Header
+ * @param string $String
+ *
+ * @return bool
+ */
public function Write(int $Header, string $String = ''): bool
{
$Command = pack('ccccca*', 0xFF, 0xFF, 0xFF, 0xFF, $Header, $String);
@@ -66,9 +83,13 @@ final class Socket extends BaseSocket
/**
* Reads from socket and returns Buffer.
*
- * @throws InvalidPacketException
+ * @param int $Length
*
* @return Buffer Buffer
+ *
+ * @throws InvalidPacketException
+ * @throws SocketException
+ *
*/
public function Read(int $Length = 1400): Buffer
{
@@ -80,6 +101,14 @@ final class Socket extends BaseSocket
return $Buffer;
}
+ /**
+ * @param Buffer $Buffer
+ * @param int $Length
+ *
+ * @return bool
+ *
+ * @throws InvalidPacketException
+ */
public function Sherlock(Buffer $Buffer, int $Length): bool
{
$Data = fread($this->Socket, $Length);
diff --git a/SourceQuery/SourceQuery.php b/SourceQuery/SourceQuery.php
index f1a895b..4d0d037 100644
--- a/SourceQuery/SourceQuery.php
+++ b/SourceQuery/SourceQuery.php
@@ -15,6 +15,7 @@ declare(strict_types=1);
namespace xPaw\SourceQuery;
+use RuntimeException;
use xPaw\SourceQuery\Exception\AuthenticationException;
use xPaw\SourceQuery\Exception\InvalidArgumentException;
use xPaw\SourceQuery\Exception\InvalidPacketException;
@@ -98,11 +99,17 @@ final class SourceQuery
*/
private bool $UseOldGetChallengeMethod = false;
+ /**
+ * @param BaseSocket|null $Socket
+ */
public function __construct(BaseSocket $Socket = null)
{
$this->Socket = $Socket ?: new Socket();
}
+ /**
+ * Destructor
+ */
public function __destruct()
{
$this->Disconnect();
@@ -137,7 +144,7 @@ final class SourceQuery
*
* @param bool $Value Set to true to force old method
*
- * @returns bool Previous value
+ * @return bool Previous value
*/
public function SetUseOldGetChallengeMethod(bool $Value): bool
{
@@ -299,7 +306,6 @@ final class SourceQuery
if ($Flags & 0x10) {
$SteamIDLower = $Buffer->GetUnsignedLong();
$SteamIDInstance = $Buffer->GetUnsignedLong(); // This gets shifted by 32 bits, which should be steamid instance
- $SteamID = 0;
if (PHP_INT_SIZE === 4) {
if (extension_loaded('gmp')) {
@@ -307,7 +313,7 @@ final class SourceQuery
$SteamIDInstance = gmp_abs($SteamIDInstance);
$SteamID = gmp_strval(gmp_or($SteamIDLower, gmp_mul($SteamIDInstance, gmp_pow(2, 32))));
} else {
- throw new \RuntimeException('Either 64-bit PHP installation or "gmp" module is required to correctly parse server\'s steamid.');
+ throw new RuntimeException('Either 64-bit PHP installation or "gmp" module is required to correctly parse server\'s steamid.');
}
} else {
$SteamID = $SteamIDLower | ($SteamIDInstance << 32);
@@ -334,7 +340,7 @@ final class SourceQuery
$Server[ 'GameID' ] = $Buffer->GetUnsignedLong() | ($Buffer->GetUnsignedLong() << 32);
}
- if ($Buffer->Remaining() > 0) {
+ if (!$Buffer->isEmpty()) {
throw new InvalidPacketException(
'GetInfo: unread data? ' . $Buffer->Remaining() . ' bytes remaining in the buffer. Please report it to the library developer.',
InvalidPacketException::BUFFER_NOT_EMPTY
@@ -431,7 +437,11 @@ final class SourceQuery
/**
* Get challenge (used for players/rules packets)
*
+ * @param int $Header
+ * @param int $ExpectedResult
+ *
* @throws InvalidPacketException
+ * @throws SocketException
*/
private function GetChallenge(int $Header, int $ExpectedResult): void
{
@@ -488,13 +498,13 @@ final class SourceQuery
}
switch ($this->Socket->Engine) {
- case SourceQuery::GOLDSOURCE:
+ case self::GOLDSOURCE:
{
$this->Rcon = new GoldSourceRcon($this->Socket);
break;
}
- case SourceQuery::SOURCE:
+ case self::SOURCE:
{
$this->Rcon = new SourceRcon($this->Socket);
diff --git a/SourceQuery/SourceRcon.php b/SourceQuery/SourceRcon.php
index 88625b9..d080db7 100644
--- a/SourceQuery/SourceRcon.php
+++ b/SourceQuery/SourceRcon.php
@@ -35,15 +35,27 @@ final class SourceRcon
*/
private BaseSocket $Socket;
- /** @var ?resource */
+ /**
+ * @var ?resource
+ */
private $RconSocket;
+
+ /**
+ * @var int $RconRequestId
+ */
private int $RconRequestId = 0;
+ /**
+ * @param BaseSocket $Socket
+ */
public function __construct(BaseSocket $Socket)
{
$this->Socket = $Socket;
}
+ /**
+ * Close
+ */
public function Close(): void
{
if ($this->RconSocket) {
@@ -55,6 +67,9 @@ final class SourceRcon
$this->RconRequestId = 0;
}
+ /**
+ * @throws SocketException
+ */
public function Open(): void
{
if (!$this->RconSocket) {
@@ -70,6 +85,12 @@ final class SourceRcon
}
}
+ /**
+ * @param int $Header
+ * @param string $String
+ *
+ * @return bool
+ */
public function Write(int $Header, string $String = ''): bool
{
// Pack the packet together
@@ -82,6 +103,11 @@ final class SourceRcon
return $Length === fwrite($this->RconSocket, $Command, $Length);
}
+ /**
+ * @return Buffer
+ *
+ * @throws InvalidPacketException
+ */
public function Read(): Buffer
{
$Buffer = new Buffer();
@@ -117,6 +143,14 @@ final class SourceRcon
return $Buffer;
}
+ /**
+ * @param string $Command
+ *
+ * @return string
+ *
+ * @throws AuthenticationException
+ * @throws InvalidPacketException
+ */
public function Command(string $Command): string
{
$this->Write(SourceQuery::SERVERDATA_EXECCOMMAND, $Command);
@@ -161,6 +195,12 @@ final class SourceRcon
return rtrim($Data, "\0");
}
+ /**
+ * @param string $Password
+ *
+ * @throws AuthenticationException
+ * @throws InvalidPacketException
+ */
public function Authorize(string $Password): void
{
$this->Write(SourceQuery::SERVERDATA_AUTH, $Password);
diff --git a/Tests/Tests.php b/Tests/Tests.php
index 556bd47..f1c7d6e 100644
--- a/Tests/Tests.php
+++ b/Tests/Tests.php
@@ -6,28 +6,48 @@ use PHPUnit\Framework\TestCase;
use xPaw\SourceQuery\BaseSocket;
use xPaw\SourceQuery\SourceQuery;
use xPaw\SourceQuery\Buffer;
+use xPaw\SourceQuery\Exception\AuthenticationException;
+use xPaw\SourceQuery\Exception\InvalidArgumentException;
+use xPaw\SourceQuery\Exception\InvalidPacketException;
+use xPaw\SourceQuery\Exception\SocketException;
final class TestableSocket extends BaseSocket
{
- /** @var \SplQueue