The old SourceQuery library has been removed

This commit is contained in:
Sergei Solovev 2023-12-10 00:18:04 +03:00
parent cf70b5dd43
commit 3405e159ab
6 changed files with 0 additions and 829 deletions

View file

@ -1,94 +0,0 @@
<?php
if (!DEFINED('EGP'))
exit(header('Refresh: 0; URL=http://' . $_SERVER['SERVER_NAME'] . '/404'));
abstract class BaseSocket
{
public $Socket;
public $Engine;
public $Address;
public $Port;
public $Timeout;
public function __destruct()
{
$this->Close();
}
abstract public function Close();
abstract public function Open($Address, $Port, $Timeout, $Engine);
abstract public function Write($Header, $String = '');
abstract public function Read($Length = 1400);
protected function ReadInternal($Buffer, $Length, $SherlockFunction)
{
if ($Buffer->Remaining() === 0)
return false;
if ($Buffer->Remaining() === 0)
return false;
$Header = $Buffer->GetLong();
if ($Header === -2) {
$Packets = [];
$IsCompressed = false;
$ReadMore = false;
do {
$RequestID = $Buffer->GetLong();
switch ($this->Engine) {
case SourceQuery::GOLDSOURCE:
{
$PacketCountAndNumber = $Buffer->GetByte();
$PacketCount = $PacketCountAndNumber & 0xF;
$PacketNumber = $PacketCountAndNumber >> 4;
break;
}
case SourceQuery::SOURCE:
{
$IsCompressed = ($RequestID & 0x80000000) !== 0;
$PacketCount = $Buffer->GetByte();
$PacketNumber = $Buffer->GetByte() + 1;
if ($IsCompressed) {
$Buffer->GetLong();
$PacketChecksum = $Buffer->GetUnsignedLong();
} else
$Buffer->GetShort();
break;
}
}
$Packets[$PacketNumber] = $Buffer->Get();
$ReadMore = $PacketCount > sizeof($Packets);
} while ($ReadMore && $SherlockFunction($Buffer, $Length));
$Data = Implode($Packets);
if ($IsCompressed) {
if (!Function_Exists('bzdecompress'))
return false;
$Data = bzdecompress($Data);
if (CRC32($Data) !== $PacketChecksum)
return false;
}
$Buffer->Set(SubStr($Data, 4));
} else
return false;
return $Buffer;
}
}

View file

@ -1,102 +0,0 @@
<?php
if (!DEFINED('EGP'))
exit(header('Refresh: 0; URL=http://' . $_SERVER['SERVER_NAME'] . '/404'));
class Buffer
{
private $Buffer;
private $Length;
private $Position;
public function Set($Buffer)
{
$this->Buffer = $Buffer;
$this->Length = StrLen($Buffer);
$this->Position = 0;
}
public function Remaining()
{
return $this->Length - $this->Position;
}
public function Get($Length = -1)
{
if ($Length === 0)
return '';
$Remaining = $this->Remaining();
if ($Length === -1)
$Length = $Remaining;
else if ($Length > $Remaining)
return '';
$Data = SubStr($this->Buffer, $this->Position, $Length);
$this->Position += $Length;
return $Data;
}
public function GetByte()
{
return Ord($this->Get(1));
}
public function GetShort()
{
if ($this->Remaining() < 2)
return false;
$Data = UnPack('v', $this->Get(2));
return $Data[1];
}
public function GetLong()
{
if ($this->Remaining() < 4)
return false;
$Data = UnPack('l', $this->Get(4));
return $Data[1];
}
public function GetFloat()
{
if ($this->Remaining() < 4)
return false;
$Data = UnPack('f', $this->Get(4));
return $Data[1];
}
public function GetUnsignedLong()
{
if ($this->Remaining() < 4)
return false;
$Data = UnPack('V', $this->Get(4));
return $Data[1];
}
public function GetString()
{
$ZeroBytePosition = StrPos($this->Buffer, "\0", $this->Position);
if ($ZeroBytePosition === false)
return '';
$String = $this->Get($ZeroBytePosition - $this->Position);
$this->Position++;
return $String;
}
}

View file

@ -1,101 +0,0 @@
<?php
if (!DEFINED('EGP'))
exit(header('Refresh: 0; URL=http://' . $_SERVER['SERVER_NAME'] . '/404'));
class GoldSourceRcon
{
private $Socket;
private $RconPassword;
private $RconRequestId;
private $RconChallenge;
public function __construct($Socket)
{
$this->Socket = $Socket;
}
public function Close()
{
$this->RconChallenge = 0;
$this->RconRequestId = 0;
$this->RconPassword = 0;
}
public function Open()
{
//
}
public function Write($Header, $String = '')
{
$Command = Pack('cccca*', 0xFF, 0xFF, 0xFF, 0xFF, $String);
$Length = StrLen($Command);
return $Length === FWrite($this->Socket->Socket, $Command, $Length);
}
public function Read($Length = 1400)
{
$Buffer = $this->Socket->Read();
$StringBuffer = '';
$ReadMore = false;
do {
$ReadMore = $Buffer->Remaining() > 0;
if ($ReadMore) {
if ($Buffer->GetByte() !== SourceQuery::S2A_RCON)
sys::outjs(array('e' => 'неправильный rcon запрос.'));
$Packet = $Buffer->Get();
$StringBuffer .= $Packet;
$ReadMore = StrLen($Packet) > 1000;
if ($ReadMore)
$Buffer = $this->Socket->Read();
}
} while ($ReadMore);
$Trimmed = trim($StringBuffer);
if ($Trimmed === 'Bad rcon_password.')
sys::outjs(array('e' => 'rcon_password из server.cfg не подходит.'));
else if ($Trimmed === 'You have been banned from this server.')
sys::outjs(array('e' => 'Игровой сервер заблокировал доступ.'));
$Buffer->Set($Trimmed);
return $Buffer;
}
public function Command($Command)
{
if (!$this->RconChallenge)
return false;
$this->Write(0, 'rcon ' . $this->RconChallenge . ' "' . $this->RconPassword . '" ' . $Command . "\0");
$Buffer = $this->Read();
if ($Buffer)
return $Buffer->Get();
return $Buffer;
}
public function Authorize($Password)
{
$this->RconPassword = $Password;
$this->Write(0, 'challenge rcon');
$Buffer = $this->Socket->Read();
if ($Buffer->Get(14) !== 'challenge rcon')
sys::outjs(array('e' => 'Не удалось выполнить rcon запрос.'));
$this->RconChallenge = Trim($Buffer->Get());
}
}

View file

@ -1,61 +0,0 @@
<?php
if (!DEFINED('EGP'))
exit(header('Refresh: 0; URL=http://' . $_SERVER['SERVER_NAME'] . '/404'));
class Socket extends BaseSocket
{
public function Close()
{
if ($this->Socket) {
FClose($this->Socket);
$this->Socket = null;
}
}
public function Open($Address, $Port, $Timeout, $Engine)
{
$this->Timeout = $Timeout;
$this->Engine = $Engine;
$this->Port = $Port;
$this->Address = $Address;
$this->Socket = @FSockOpen('udp://' . $Address, $Port, $ErrNo, $ErrStr, $Timeout);
if ($ErrNo || $this->Socket === false)
return false;
Stream_Set_Timeout($this->Socket, $Timeout);
Stream_Set_Blocking($this->Socket, true);
}
public function Write($Header, $String = '')
{
$Command = Pack('ccccca*', 0xFF, 0xFF, 0xFF, 0xFF, $Header, $String);
$Length = StrLen($Command);
return $Length === FWrite($this->Socket, $Command, $Length);
}
public function Read($Length = 1400)
{
$Buffer = new Buffer();
$Buffer->Set(FRead($this->Socket, $Length));
$this->ReadInternal($Buffer, $Length, [$this, 'Sherlock']);
return $Buffer;
}
public function Sherlock($Buffer, $Length)
{
$Data = FRead($this->Socket, $Length);
if (StrLen($Data) < 4)
return false;
$Buffer->Set($Data);
return $Buffer->GetLong() === -2;
}
}

View file

@ -1,331 +0,0 @@
<?php
if (!DEFINED('EGP'))
exit(header('Refresh: 0; URL=http://' . $_SERVER['SERVER_NAME'] . '/404'));
class SourceQuery
{
const GOLDSOURCE = 0;
const SOURCE = 1;
const A2S_PING = 0x69;
const A2S_INFO = 0x54;
const A2S_PLAYER = 0x55;
const A2S_RULES = 0x56;
const A2S_SERVERQUERY_GETCHALLENGE = 0x57;
const S2A_PING = 0x6A;
const S2A_CHALLENGE = 0x41;
const S2A_INFO = 0x49;
const S2A_INFO_OLD = 0x6D;
const S2A_PLAYER = 0x44;
const S2A_RULES = 0x45;
const S2A_RCON = 0x6C;
const SERVERDATA_EXECCOMMAND = 2;
const SERVERDATA_AUTH = 3;
const SERVERDATA_RESPONSE_VALUE = 0;
const SERVERDATA_AUTH_RESPONSE = 2;
private $Rcon;
private $Socket;
private $Connected;
private $Challenge;
private $UseOldGetChallengeMethod;
public function __construct(BaseSocket $Socket = null)
{
$this->Socket = $Socket ?: new Socket();
}
public function __destruct()
{
$this->Disconnect();
}
public function Connect($Address, $Port, $Timeout = 3, $Engine = self::SOURCE)
{
$this->Disconnect();
if (!is_int($Timeout) || $Timeout < 0)
return false;
$this->Socket->Open($Address, (int)$Port, $Timeout, (int)$Engine);
$this->Connected = true;
}
public function SetUseOldGetChallengeMethod($Value)
{
$Previous = $this->UseOldGetChallengeMethod;
$this->UseOldGetChallengeMethod = $Value === true;
return $Previous;
}
public function Disconnect()
{
$this->Connected = false;
$this->Challenge = 0;
$this->Socket->Close();
if ($this->Rcon) {
$this->Rcon->Close();
$this->Rcon = null;
}
}
public function Ping()
{
if (!$this->Connected)
return false;
$this->Socket->Write(self::A2S_PING);
$Buffer = $this->Socket->Read();
return $Buffer->GetByte() === self::S2A_PING;
}
public function GetInfo()
{
if (!$this->Connected)
return false;
$this->Socket->Write(self::A2S_INFO, "Source Engine Query\0");
$Buffer = $this->Socket->Read();
$Type = $Buffer->GetByte();
if ($Type === self::S2A_INFO_OLD && $this->Socket->Engine === self::GOLDSOURCE) {
$Server['Address'] = $Buffer->GetString();
$Server['HostName'] = $Buffer->GetString();
$Server['Map'] = $Buffer->GetString();
$Server['ModDir'] = $Buffer->GetString();
$Server['ModDesc'] = $Buffer->GetString();
$Server['Players'] = $Buffer->GetByte();
$Server['MaxPlayers'] = $Buffer->GetByte();
$Server['Protocol'] = $Buffer->GetByte();
$Server['Dedicated'] = Chr($Buffer->GetByte());
$Server['Os'] = Chr($Buffer->GetByte());
$Server['Password'] = $Buffer->GetByte() === 1;
$Server['IsMod'] = $Buffer->GetByte() === 1;
if ($Server['IsMod']) {
$Mod['Url'] = $Buffer->GetString();
$Mod['Download'] = $Buffer->GetString();
$Buffer->Get(1);
$Mod['Version'] = $Buffer->GetLong();
$Mod['Size'] = $Buffer->GetLong();
$Mod['ServerSide'] = $Buffer->GetByte() === 1;
$Mod['CustomDLL'] = $Buffer->GetByte() === 1;
}
$Server['Secure'] = $Buffer->GetByte() === 1;
$Server['Bots'] = $Buffer->GetByte();
if (isset($Mod))
$Server['Mod'] = $Mod;
return $Server;
}
if ($Type !== self::S2A_INFO)
return false;
if ($Type !== self::S2A_INFO)
return false;
$Server['Protocol'] = $Buffer->GetByte();
$Server['HostName'] = $Buffer->GetString();
$Server['Map'] = $Buffer->GetString();
$Server['ModDir'] = $Buffer->GetString();
$Server['ModDesc'] = $Buffer->GetString();
$Server['AppID'] = $Buffer->GetShort();
$Server['Players'] = $Buffer->GetByte();
$Server['MaxPlayers'] = $Buffer->GetByte();
$Server['Bots'] = $Buffer->GetByte();
$Server['Dedicated'] = Chr($Buffer->GetByte());
$Server['Os'] = Chr($Buffer->GetByte());
$Server['Password'] = $Buffer->GetByte() === 1;
$Server['Secure'] = $Buffer->GetByte() === 1;
if ($Server['AppID'] === 2400) {
$Server['GameMode'] = $Buffer->GetByte();
$Server['WitnessCount'] = $Buffer->GetByte();
$Server['WitnessTime'] = $Buffer->GetByte();
}
$Server['Version'] = $Buffer->GetString();
if ($Buffer->Remaining() > 0) {
$Server['ExtraDataFlags'] = $Flags = $Buffer->GetByte();
if ($Flags & 0x80)
$Server['GamePort'] = $Buffer->GetShort();
if ($Flags & 0x10) {
$SteamIDLower = $Buffer->GetUnsignedLong();
$SteamIDInstance = $Buffer->GetUnsignedLong();
$SteamID = 0;
if (PHP_INT_SIZE === 4) {
if (extension_loaded('gmp')) {
$SteamIDLower = gmp_abs($SteamIDLower);
$SteamIDInstance = gmp_abs($SteamIDInstance);
$SteamID = gmp_strval(gmp_or($SteamIDLower, gmp_mul($SteamIDInstance, gmp_pow(2, 32))));
} else
return false;
} else
$SteamID = $SteamIDLower | ($SteamIDInstance << 32);
$Server['SteamID'] = $SteamID;
unset($SteamIDLower, $SteamIDInstance, $SteamID);
}
if ($Flags & 0x40) {
$Server['SpecPort'] = $Buffer->GetShort();
$Server['SpecName'] = $Buffer->GetString();
}
if ($Flags & 0x20)
$Server['GameTags'] = $Buffer->GetString();
if ($Flags & 0x01)
$Server['GameID'] = $Buffer->GetUnsignedLong() | ($Buffer->GetUnsignedLong() << 32);
if ($Buffer->Remaining() > 0)
return false;
}
return $Server;
}
public function GetPlayers()
{
if (!$this->Connected)
return false;
$this->GetChallenge(self::A2S_PLAYER, self::S2A_PLAYER);
$this->Socket->Write(self::A2S_PLAYER, $this->Challenge);
$Buffer = $this->Socket->Read(14000);
$Type = $Buffer->GetByte();
if ($Type !== self::S2A_PLAYER)
return false;
$Players = [];
$Count = $Buffer->GetByte();
while ($Count-- > 0 && $Buffer->Remaining() > 0) {
$Player['Id'] = $Buffer->GetByte();
$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']);
$Players[] = $Player;
}
return $Players;
}
public function GetRules()
{
if (!$this->Connected)
return false;
$this->GetChallenge(self::A2S_RULES, self::S2A_RULES);
$this->Socket->Write(self::A2S_RULES, $this->Challenge);
$Buffer = $this->Socket->Read();
$Type = $Buffer->GetByte();
if ($Type !== self::S2A_RULES)
return false;
$Rules = [];
$Count = $Buffer->GetShort();
while ($Count-- > 0 && $Buffer->Remaining() > 0) {
$Rule = $Buffer->GetString();
$Value = $Buffer->GetString();
if (!empty($Rule))
$Rules[$Rule] = $Value;
}
return $Rules;
}
private function GetChallenge($Header, $ExpectedResult)
{
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::S2A_CHALLENGE:
{
$this->Challenge = $Buffer->Get(4);
return;
}
case $ExpectedResult:
{
return;
}
case 0:
{
return;
}
default:
{
return;
}
}
}
public function SetRconPassword($Password)
{
if (!$this->Connected) {
return false;
}
switch ($this->Socket->Engine) {
case SourceQuery::GOLDSOURCE:
{
$this->Rcon = new GoldSourceRcon($this->Socket);
break;
}
case SourceQuery::SOURCE:
{
$this->Rcon = new SourceRcon($this->Socket);
break;
}
}
$this->Rcon->Open();
$this->Rcon->Authorize($Password);
}
public function Rcon($Command)
{
if (!$this->Connected) {
return false;
}
if ($this->Rcon === null) {
return false;
}
return $this->Rcon->Command($Command);
}
}

View file

@ -1,140 +0,0 @@
<?php
if (!DEFINED('EGP'))
exit(header('Refresh: 0; URL=http://' . $_SERVER['SERVER_NAME'] . '/404'));
class SourceRcon
{
private $Socket;
private $RconSocket;
private $RconRequestId;
public function __construct($Socket)
{
$this->Socket = $Socket;
}
public function Close()
{
if ($this->RconSocket) {
FClose($this->RconSocket);
$this->RconSocket = null;
}
$this->RconRequestId = 0;
}
public function Open()
{
if (!$this->RconSocket) {
$this->RconSocket = @FSockOpen($this->Socket->Address, $this->Socket->Port, $ErrNo, $ErrStr, $this->Socket->Timeout);
if ($ErrNo || !$this->RconSocket)
return false;
Stream_Set_Timeout($this->RconSocket, $this->Socket->Timeout);
Stream_Set_Blocking($this->RconSocket, true);
}
}
public function Write($Header, $String = '')
{
$Command = Pack('VV', ++$this->RconRequestId, $Header) . $String . "\x00\x00";
$Command = Pack('V', StrLen($Command)) . $Command;
$Length = StrLen($Command);
return $Length === FWrite($this->RconSocket, $Command, $Length);
}
public function Read()
{
$Buffer = new Buffer();
$Buffer->Set(FRead($this->RconSocket, 4));
if ($Buffer->Remaining() < 4)
return false;
$PacketSize = $Buffer->GetLong();
$Buffer->Set(FRead($this->RconSocket, $PacketSize));
$Data = $Buffer->Get();
$Remaining = $PacketSize - StrLen($Data);
while ($Remaining > 0) {
$Data2 = FRead($this->RconSocket, $Remaining);
$PacketSize = StrLen($Data2);
if ($PacketSize === 0)
return false;
$Data .= $Data2;
$Remaining -= $PacketSize;
}
$Buffer->Set($Data);
return $Buffer;
}
public function Command($Command)
{
$this->Write(SourceQuery::SERVERDATA_EXECCOMMAND, $Command);
$Buffer = $this->Read();
$Buffer->GetLong();
$Type = $Buffer->GetLong();
if ($Type === SourceQuery::SERVERDATA_AUTH_RESPONSE)
return false;
if ($Type !== SourceQuery::SERVERDATA_RESPONSE_VALUE)
return false;
$Data = $Buffer->Get();
if (StrLen($Data) >= 4000) {
do {
$this->Write(SourceQuery::SERVERDATA_RESPONSE_VALUE);
$Buffer = $this->Read();
$Buffer->GetLong();
if ($Buffer->GetLong() !== SourceQuery::SERVERDATA_RESPONSE_VALUE)
break;
$Data2 = $Buffer->Get();
if ($Data2 === "\x00\x01\x00\x00\x00\x00")
break;
$Data .= $Data2;
} while (true);
}
return rtrim($Data, "\0");
}
public function Authorize($Password)
{
$this->Write(SourceQuery::SERVERDATA_AUTH, $Password);
$Buffer = $this->Read();
$RequestID = $Buffer->GetLong();
$Type = $Buffer->GetLong();
if ($Type === SourceQuery::SERVERDATA_RESPONSE_VALUE) {
$Buffer = $this->Read();
$RequestID = $Buffer->GetLong();
$Type = $Buffer->GetLong();
}
if ($RequestID === -1 || $Type !== SourceQuery::SERVERDATA_AUTH_RESPONSE)
return false;
}
}