| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- <?php
- /**
- * See https://developer.valvesoftware.com/wiki/Source_RCON_Protocol for
- * more information about Source RCON Packets
- *
- * PHP Version 7
- *
- * @copyright 2013-2017 Chris Churchwell
- * @author thedudeguy
- * @link https://github.com/thedudeguy/PHP-Minecraft-Rcon
- */
-
- class Rcon
- {
- private $host;
- private $port;
- private $password;
- private $timeout;
-
- private $socket;
-
- private $authorized = false;
- private $lastResponse = '';
-
- const PACKET_AUTHORIZE = 5;
- const PACKET_COMMAND = 6;
-
- const SERVERDATA_AUTH = 3;
- const SERVERDATA_AUTH_RESPONSE = 2;
- const SERVERDATA_EXECCOMMAND = 2;
- const SERVERDATA_RESPONSE_VALUE = 0;
-
- /**
- * Create a new instance of the Rcon class.
- *
- * @param string $host
- * @param integer $port
- * @param string $password
- * @param integer $timeout
- */
- public function __construct($host, $port, $password, $timeout)
- {
- $this->host = $host;
- $this->port = $port;
- $this->password = $password;
- $this->timeout = $timeout;
- }
-
- /**
- * Get the latest response from the server.
- *
- * @return string
- */
- public function getResponse()
- {
- return $this->lastResponse;
- }
-
- /**
- * Connect to a server.
- *
- * @return boolean
- */
- public function connect()
- {
- $this->socket = fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout);
-
- if (!$this->socket) {
- $this->lastResponse = $errstr;
- return false;
- }
-
- //set timeout
- stream_set_timeout($this->socket, 3, 0);
-
- // check authorization
- return $this->authorize();
- }
-
- /**
- * Disconnect from server.
- *
- * @return void
- */
- public function disconnect()
- {
- if ($this->socket) {
- fclose($this->socket);
- }
- $this->authorized = false;
- }
-
- /**
- * True if socket is connected and authorized.
- *
- * @return boolean
- */
- public function isConnected()
- {
- return $this->authorized;
- }
-
- /**
- * Send a command to the connected server.
- *
- * @param string $command
- *
- * @return boolean|mixed
- */
- public function sendCommand($command)
- {
- if (!$this->isConnected()) {
- return false;
- }
-
- // send command packet
- $this->writePacket(self::PACKET_COMMAND, self::SERVERDATA_EXECCOMMAND, $command);
-
- // get response
- $response_packet = $this->readPacket();
- if ($response_packet['id'] == self::PACKET_COMMAND) {
- if ($response_packet['type'] == self::SERVERDATA_RESPONSE_VALUE) {
- $this->lastResponse = $response_packet['body'];
-
- return $response_packet['body'];
- }
- }
-
- return false;
- }
-
- /**
- * Log into the server with the given credentials.
- *
- * @return boolean
- */
- private function authorize()
- {
- $this->writePacket(self::PACKET_AUTHORIZE, self::SERVERDATA_AUTH, $this->password);
- $response_packet = $this->readPacket();
-
- if ($response_packet['type'] == self::SERVERDATA_AUTH_RESPONSE) {
- if ($response_packet['id'] == self::PACKET_AUTHORIZE) {
- $this->authorized = true;
-
- return true;
- }
- }
-
- $this->disconnect();
- return false;
- }
-
- /**
- * Writes a packet to the socket stream.
- *
- * @param $packetId
- * @param $packetType
- * @param string $packetBody
- *
- * @return void
- */
- private function writePacket($packetId, $packetType, $packetBody)
- {
- /*
- Size 32-bit little-endian Signed Integer Varies, see below.
- ID 32-bit little-endian Signed Integer Varies, see below.
- Type 32-bit little-endian Signed Integer Varies, see below.
- Body Null-terminated ASCII String Varies, see below.
- Empty String Null-terminated ASCII String 0x00
- */
-
- //create packet
- $packet = pack('VV', $packetId, $packetType);
- $packet = $packet.$packetBody."\x00";
- $packet = $packet."\x00";
-
- // get packet size.
- $packet_size = strlen($packet);
-
- // attach size to packet.
- $packet = pack('V', $packet_size).$packet;
-
- // write packet.
- fwrite($this->socket, $packet, strlen($packet));
- }
-
- /**
- * Read a packet from the socket stream.
- *
- * @return array
- */
- private function readPacket()
- {
- //get packet size.
- $size_data = fread($this->socket, 4);
- $size_pack = unpack('V1size', $size_data);
- $size = $size_pack['size'];
-
- // if size is > 4096, the response will be in multiple packets.
- // this needs to be address. get more info about multi-packet responses
- // from the RCON protocol specification at
- // https://developer.valvesoftware.com/wiki/Source_RCON_Protocol
- // currently, this script does not support multi-packet responses.
-
- $packet_data = fread($this->socket, $size);
- $packet_pack = unpack('V1id/V1type/a*body', $packet_data);
-
- return $packet_pack;
- }
- }
|