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 ); return unpack( 'V1id/V1type/a*body', $packet_data ); } }