PHP-cli-factorio-updater/scripts/class.ValveRcon.php

206 lines
5.6 KiB
PHP
Raw Normal View History

2024-11-10 03:40:05 +01:00
<?php
/**
* Namespace for Valve RCON related classes and functions.
* @package NAE\Valve\Rcon
*/
2024-11-10 03:40:05 +01:00
namespace NAE\Valve\Rcon;
/**
* A Class to interact with a Valve RCON server.
* @author "Marcel Naeve" <php@naeve.info>
* @license MIT License (http://www.opensource.org/licenses/mit)
*/
2024-11-10 03:40:05 +01:00
class ValveRcon {
/**
* @var string IP address of the RCON server
*/
2024-11-10 03:40:05 +01:00
private $ip;
/**
* @var int Port number of the RCON server
*/
2024-11-10 03:40:05 +01:00
private $port;
/**
* @var string Password to authenticate with the RCON server
*/
2024-11-10 03:40:05 +01:00
private $password;
/**
* @var int Timeout for socket operations in seconds
*/
2024-11-10 03:40:05 +01:00
private $timeout;
/**
* @var resource Socket resource for RCON communication
*/
2024-11-10 03:40:05 +01:00
private $socket;
/**
* @var array Error details if any occurs during communication
*/
2024-11-10 03:40:05 +01:00
private $err;
/**
* Constructor, setting variables.
* @param string $ip IP address of the RCON server
* @param int $port Port number of the RCON server
* @param string $password Password to authenticate with the RCON server
* @param int $timeout Timeout for socket operations in seconds (default: 2 seconds)
*/
2024-11-10 03:40:05 +01:00
public function __construct(string $ip, int $port, string $password, int $timeout=2) {
$this->ip = $ip;
$this->port = $port;
$this->password = $password;
$this->timeout = $timeout;
}
/**
* Establishes a connection to the RCON server.
* @return bool Connection established successfully?
*/
2024-11-10 03:40:05 +01:00
private function connect() : bool {
// prepare variables for error handling
2024-11-10 03:40:05 +01:00
$errno = null;
$errmsg = "";
$this->socket = fsockopen( // connect to RCON server
2024-11-10 03:40:05 +01:00
"udp://{$this->ip}",
$this->port,
$errno,
$errmsg,
$this->timeout
);
if(!$this->socket) { // connection failed?
2024-11-10 03:40:05 +01:00
$this->err = [
"code" => $errno,
"message" => "Socket connection failed: $errmsg"
];
return false;
}
return true;
}
/**
* Closes the connection to the RCON server
*/
2024-11-10 03:40:05 +01:00
private function disconnect() : void {
if ( $this->isConnected() ) {
fclose($this->socket);
$this->socket = NULL;
}
}
/**
* Checks if the connection to the RCON server is established.
*/
2024-11-10 03:40:05 +01:00
private function isConnected() : bool {
return ( get_resource_type($this->socket) !== null ); // check if socket is resource type, as it should be
}
/**
* Receives data from the RCON server.
* @return string|null Received data or null if no data is available
*/
2024-11-10 03:40:05 +01:00
private function read() : ?string {
if (!$this->isConnected()) {
return null;
}
stream_set_timeout($this->socket, 0, $this->timeout * 100000); // set timeout
$response = '';
while ($buffer = fread($this->socket, 4096)) { // loop while there's more data
list($header, $content) = explode("\n", $buffer, 2); // split into header and content
$response .= $content; // append content to response
}
$response = trim($response); // remove whitespaces around the response
if (empty($response)) // no data received, return null
return null;
return preg_replace("/\^./","", $response); // return response without prefix
}
/**
* Writes a command to the RCON server.
* @return bool $cmd Command writen successfully?
*/
2024-11-10 03:40:05 +01:00
private function write(string $cmd) : bool {
if (!$this->isConnected()) {
return false;
}
if( false === fwrite($this->socket, str_repeat(chr(255), 4) . "rcon {$this->password} {$cmd}\n") ) {
return false;
}
return true;
}
/**
* Sends a command to the RCON server and optionally reads the response.
* @param string $cmd Command to send to the RCON server
* @param bool $read Should the response be read from the RCON server? (default: false)
* @return string|null Response from the RCON server or null if no response is expected or read fails
*/
2024-11-10 03:40:05 +01:00
public function sendCommand(string $cmd, bool $read=false) : ?string {
$this->connect();
if(!$this->write($cmd)) { // sending the command
$this->err = [
"code" => 0,
"message" => "Command could not be sent"
];
$this->disconnect();
return null;
}
if (!$read) {
$this->disconnect();
return null;
}
if(!$res = $this->read()) { // reading the response
$this->err = [
"code" => 0,
"message" => "Response could not be read"
];
}
$this->disconnect();
return $res;
}
/**
* Returns the last error details if any occurred during communication.
* @return object|null Last error details or null if no error has occurred (error object contains code and message as properties)
*/
2024-11-10 03:40:05 +01:00
public function getError() :?object {
if($this->err === null) {
return null; // no error has occurred, return null
}
return json_decode(json_encode($this->err)); // return last error as object
}
}