mirror of
https://github.com/xPaw/PHP-Source-Query.git
synced 2026-06-10 23:03:15 +02:00
PHPStan max level (improved error handling).
This commit is contained in:
+20
-4
@@ -113,7 +113,11 @@ final class Buffer
|
||||
|
||||
$data = unpack('v', $this->get(2));
|
||||
|
||||
return (int)$data[ 1 ];
|
||||
if (!$data) {
|
||||
throw new InvalidPacketException('Empty data from packet.');
|
||||
}
|
||||
|
||||
return (int) $data[1];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -129,7 +133,11 @@ final class Buffer
|
||||
|
||||
$data = unpack('l', $this->get(4));
|
||||
|
||||
return (int)$data[ 1 ];
|
||||
if (!$data) {
|
||||
throw new InvalidPacketException('Empty data from packet.');
|
||||
}
|
||||
|
||||
return (int) $data[1];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,7 +153,11 @@ final class Buffer
|
||||
|
||||
$data = unpack('f', $this->get(4));
|
||||
|
||||
return (float)$data[ 1 ];
|
||||
if (!$data) {
|
||||
throw new InvalidPacketException('Empty data from packet.');
|
||||
}
|
||||
|
||||
return (float) $data[1];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -161,7 +173,11 @@ final class Buffer
|
||||
|
||||
$data = unpack('V', $this->get(4));
|
||||
|
||||
return (int)$data[ 1 ];
|
||||
if (!$data) {
|
||||
throw new InvalidPacketException('Empty data from packet.');
|
||||
}
|
||||
|
||||
return (int) $data[1];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -173,8 +173,18 @@ final class SourceRcon extends AbstractRcon
|
||||
*/
|
||||
protected function read(): Buffer
|
||||
{
|
||||
if (!$this->rconSocket) {
|
||||
throw new InvalidPacketException('Rcon socket not open.');
|
||||
}
|
||||
|
||||
$buffer = new Buffer();
|
||||
$buffer->set(fread($this->rconSocket, 4));
|
||||
$socketData = fread($this->rconSocket, 4);
|
||||
|
||||
if (!$socketData) {
|
||||
throw new InvalidPacketException('Empty data from packet.');
|
||||
}
|
||||
|
||||
$buffer->set($socketData);
|
||||
|
||||
if ($buffer->remaining() < 4) {
|
||||
throw new InvalidPacketException('Rcon read: Failed to read any data from socket', InvalidPacketException::BUFFER_EMPTY);
|
||||
@@ -182,7 +192,13 @@ final class SourceRcon extends AbstractRcon
|
||||
|
||||
$packetSize = $buffer->getLong();
|
||||
|
||||
$buffer->set(fread($this->rconSocket, $packetSize));
|
||||
$socketData = fread($this->rconSocket, $packetSize);
|
||||
|
||||
if (!$socketData) {
|
||||
throw new InvalidPacketException('Empty data from packet.');
|
||||
}
|
||||
|
||||
$buffer->set($socketData);
|
||||
|
||||
$data = $buffer->get();
|
||||
|
||||
@@ -191,9 +207,13 @@ final class SourceRcon extends AbstractRcon
|
||||
while ($remaining > 0) {
|
||||
$data2 = fread($this->rconSocket, $remaining);
|
||||
|
||||
if (!$data2) {
|
||||
throw new InvalidPacketException('Empty data from packet.');
|
||||
}
|
||||
|
||||
$packetSize = strlen($data2);
|
||||
|
||||
if ($packetSize === 0) {
|
||||
if ($packetSize <= 0) {
|
||||
throw new InvalidPacketException('Read ' . strlen($data) . ' bytes from socket, ' . $remaining . ' remaining', InvalidPacketException::BUFFER_EMPTY);
|
||||
}
|
||||
|
||||
@@ -211,9 +231,15 @@ final class SourceRcon extends AbstractRcon
|
||||
* @param string $string
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @throws InvalidPacketException
|
||||
*/
|
||||
protected function write(?int $header, string $string = ''): bool
|
||||
{
|
||||
if (!$this->rconSocket) {
|
||||
throw new InvalidPacketException('Rcon socket not open.');
|
||||
}
|
||||
|
||||
// Pack the packet together.
|
||||
$command = pack('VV', ++$this->rconRequestId, $header) . $string . "\x00\x00";
|
||||
|
||||
|
||||
@@ -137,6 +137,10 @@ abstract class AbstractSocket implements SocketInterface
|
||||
*/
|
||||
public function read(int $length = 1400): Buffer
|
||||
{
|
||||
if (!$this->socket) {
|
||||
throw new InvalidPacketException('Socket not open.');
|
||||
}
|
||||
|
||||
$buffer = new Buffer();
|
||||
$data = fread($this->socket, $length);
|
||||
|
||||
@@ -156,9 +160,15 @@ abstract class AbstractSocket implements SocketInterface
|
||||
* @param string $string
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @throws InvalidPacketException
|
||||
*/
|
||||
public function write(int $header, string $string = ''): bool
|
||||
{
|
||||
if (!$this->socket) {
|
||||
throw new InvalidPacketException('Socket not open.');
|
||||
}
|
||||
|
||||
$command = pack('ccccca*', 0xFF, 0xFF, 0xFF, 0xFF, $header, $string);
|
||||
$length = strlen($command);
|
||||
|
||||
@@ -175,8 +185,16 @@ abstract class AbstractSocket implements SocketInterface
|
||||
*/
|
||||
public function sherlock(Buffer $buffer, int $length): bool
|
||||
{
|
||||
if (!$this->socket) {
|
||||
throw new InvalidPacketException('Socket not open.');
|
||||
}
|
||||
|
||||
$data = fread($this->socket, $length);
|
||||
|
||||
if (!$data) {
|
||||
throw new InvalidPacketException('Empty data from packet.');
|
||||
}
|
||||
|
||||
if (strlen($data) < 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
+63
-63
@@ -127,22 +127,6 @@ final class SourceQuery
|
||||
$this->connected = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces GetChallenge to use old method for challenge retrieval because some games use outdated protocol (e.g Starbound)
|
||||
*
|
||||
* @param bool $value Set to true to force old method
|
||||
*
|
||||
* @return bool Previous value
|
||||
*/
|
||||
public function SetUseOldGetChallengeMethod(bool $value): bool
|
||||
{
|
||||
$previous = $this->useOldGetChallengeMethod;
|
||||
|
||||
$this->useOldGetChallengeMethod = $value === true;
|
||||
|
||||
return $previous;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes all open connections
|
||||
*/
|
||||
@@ -160,6 +144,22 @@ final class SourceQuery
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces GetChallenge to use old method for challenge retrieval because some games use outdated protocol (e.g Starbound)
|
||||
*
|
||||
* @param bool $value Set to true to force old method
|
||||
*
|
||||
* @return bool Previous value
|
||||
*/
|
||||
public function SetUseOldGetChallengeMethod(bool $value): bool
|
||||
{
|
||||
$previous = $this->useOldGetChallengeMethod;
|
||||
|
||||
$this->useOldGetChallengeMethod = $value === true;
|
||||
|
||||
return $previous;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends ping packet to the server
|
||||
* NOTE: This may not work on some games (TF2 for example)
|
||||
@@ -279,7 +279,7 @@ final class SourceQuery
|
||||
$server[ 'Version' ] = $buffer->getString();
|
||||
|
||||
// Extra Data Flags.
|
||||
if (!$buffer->isEmpty()) {
|
||||
if ($buffer->remaining() > 0) {
|
||||
$server[ 'ExtraDataFlags' ] = $Flags = $buffer->getByte();
|
||||
|
||||
// S2A_EXTRA_DATA_HAS_GAME_PORT - Next 2 bytes include the game port.
|
||||
@@ -421,52 +421,6 @@ final class SourceQuery
|
||||
return $rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get challenge (used for players/rules packets)
|
||||
*
|
||||
* @param int $header
|
||||
* @param int $expectedResult
|
||||
*
|
||||
* @throws InvalidPacketException
|
||||
*/
|
||||
private function getChallenge(int $header, int $expectedResult): void
|
||||
{
|
||||
if ($this->challenge) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->useOldGetChallengeMethod) {
|
||||
$header = self::A2S_SERVERQUERY_GETCHALLENGE;
|
||||
}
|
||||
|
||||
$this->socket->write($header, "\xFF\xFF\xFF\xFF");
|
||||
$buffer = $this->socket->read();
|
||||
|
||||
$type = $buffer->getByte();
|
||||
|
||||
switch ($type) {
|
||||
case self::S2C_CHALLENGE:
|
||||
{
|
||||
$this->challenge = $buffer->get(4);
|
||||
|
||||
return;
|
||||
}
|
||||
case $expectedResult:
|
||||
{
|
||||
// Goldsource (HLTV).
|
||||
return;
|
||||
}
|
||||
case 0:
|
||||
{
|
||||
throw new InvalidPacketException('GetChallenge: Failed to get challenge.');
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new InvalidPacketException('GetChallenge: Packet header mismatch. (0x' . dechex($type) . ')', InvalidPacketException::PACKET_HEADER_MISMATCH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets rcon password, for future use in Rcon()
|
||||
*
|
||||
@@ -528,4 +482,50 @@ final class SourceQuery
|
||||
|
||||
return $this->rcon->command($command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get challenge (used for players/rules packets)
|
||||
*
|
||||
* @param int $header
|
||||
* @param int $expectedResult
|
||||
*
|
||||
* @throws InvalidPacketException
|
||||
*/
|
||||
private function getChallenge(int $header, int $expectedResult): void
|
||||
{
|
||||
if ($this->challenge) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->useOldGetChallengeMethod) {
|
||||
$header = self::A2S_SERVERQUERY_GETCHALLENGE;
|
||||
}
|
||||
|
||||
$this->socket->write($header, "\xFF\xFF\xFF\xFF");
|
||||
$buffer = $this->socket->read();
|
||||
|
||||
$type = $buffer->getByte();
|
||||
|
||||
switch ($type) {
|
||||
case self::S2C_CHALLENGE:
|
||||
{
|
||||
$this->challenge = $buffer->get(4);
|
||||
|
||||
return;
|
||||
}
|
||||
case $expectedResult:
|
||||
{
|
||||
// Goldsource (HLTV).
|
||||
return;
|
||||
}
|
||||
case 0:
|
||||
{
|
||||
throw new InvalidPacketException('GetChallenge: Failed to get challenge.');
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new InvalidPacketException('GetChallenge: Packet header mismatch. (0x' . dechex($type) . ')', InvalidPacketException::PACKET_HEADER_MISMATCH);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user