Socket = $Socket; } /** * Close */ public function Close(): void { $this->RconChallenge = ''; $this->RconPassword = ''; } /** * Open */ public function Open(): void { } /** * @param string $String * * @return bool */ public function Write(string $String = ''): bool { $Command = pack('cccca*', 0xFF, 0xFF, 0xFF, 0xFF, $String); $Length = strlen($Command); return $Length === fwrite($this->Socket->Socket, $Command, $Length); } /** * @throws AuthenticationException * @throws InvalidPacketException * * @return Buffer */ public function Read(): Buffer { // GoldSource RCON has same structure as Query $Buffer = $this->Socket->Read(); $StringBuffer = ''; // There is no indentifier of the end, so we just need to continue reading do { $ReadMore = $Buffer->Remaining() > 0; if ($ReadMore) { if ($Buffer->GetByte() !== SourceQuery::S2A_RCON) { throw new InvalidPacketException('Invalid rcon response.', InvalidPacketException::PACKET_HEADER_MISMATCH); } $Packet = $Buffer->Get(); $StringBuffer .= $Packet; //$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? if ($ReadMore) { $Buffer = $this->Socket->Read(); } } } while ($ReadMore); $Trimmed = trim($StringBuffer); if ($Trimmed === 'Bad rcon_password.') { throw new AuthenticationException($Trimmed, AuthenticationException::BAD_PASSWORD); } elseif ($Trimmed === 'You have been banned from this server.') { throw new AuthenticationException($Trimmed, AuthenticationException::BANNED); } $Buffer->Set($Trimmed); 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('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('challenge rcon'); $Buffer = $this->Socket->Read(); if ($Buffer->Get(14) !== 'challenge rcon') { throw new AuthenticationException('Failed to get RCON challenge.', AuthenticationException::BAD_PASSWORD); } $this->RconChallenge = trim($Buffer->Get()); } }