Dateien nach "rcon" hochladen

This commit is contained in:
2025-11-22 16:56:33 +00:00
parent e894e952cf
commit 89916691fd

102
rcon/Rcon.php Normal file
View File

@@ -0,0 +1,102 @@
<?php
/**
* Compact RCON client for Minecraft with improved read loop & timeouts.
*/
class Rcon {
private $host;
private $port;
private $password;
private $socket;
private $req_id;
private $timeout;
const SERVERDATA_AUTH = 3;
const SERVERDATA_EXECCOMMAND = 2;
public function __construct($host, $port, $password, $timeout = 3) {
$this->host = $host;
$this->port = intval($port);
$this->password = $password;
$this->timeout = $timeout;
$this->socket = null;
$this->req_id = random_int(1, 0x7fffffff);
}
public function connect() {
$this->socket = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout);
if (!$this->socket) return false;
stream_set_timeout($this->socket, $this->timeout);
stream_set_blocking($this->socket, true);
$pkt = $this->buildPacket($this->req_id, self::SERVERDATA_AUTH, $this->password);
fwrite($this->socket, $pkt);
$resp = $this->readPacket();
if ($resp === false) { $this->disconnect(); return false; }
if (isset($resp['id']) && intval($resp['id']) == -1) { $this->disconnect(); return false; }
return true;
}
public function disconnect() {
if ($this->socket) { fclose($this->socket); $this->socket = null; }
}
public function sendCommand($command) {
if (!$this->socket) return false;
$this->req_id = ($this->req_id + 1) & 0x7fffffff;
$pkt = $this->buildPacket($this->req_id, self::SERVERDATA_EXECCOMMAND, $command);
fwrite($this->socket, $pkt);
$out = '';
$start = time();
while (true) {
$resp = $this->readPacket();
if ($resp === false) break;
if (isset($resp['body'])) $out .= $resp['body'];
$meta = stream_get_meta_data($this->socket);
if ($meta['timed_out']) break;
if (time() - $start > $this->timeout) break;
if (strlen($resp['body']) < 4096) break;
}
return $out;
}
private function buildPacket($id, $type, $body) {
$payload = pack('V', $id) . pack('V', $type) . $body . "\x00\x00";
$size = strlen($payload);
return pack('V', $size) . $payload;
}
private function readPacket() {
$sizeData = $this->fread_all(4);
if ($sizeData === false) return false;
$sizeArr = unpack('Vsize', $sizeData);
$size = $sizeArr['size'];
if ($size <= 0) return false;
$payload = $this->fread_all($size);
if ($payload === false) return false;
$id = unpack('Vid', substr($payload, 0, 4))['id'] ?? 0;
$type = unpack('Vtype', substr($payload, 4, 4))['type'] ?? 0;
$body = substr($payload, 8, $size - 10);
return ['id' => $id, 'type' => $type, 'body' => $body];
}
private function fread_all($len) {
$data = '';
$read = 0;
$start = time();
while ($read < $len) {
$chunk = @fread($this->socket, $len - $read);
if ($chunk === false) return false;
if ($chunk === '') {
$meta = stream_get_meta_data($this->socket);
if ($meta['timed_out'] || (time() - $start) > $this->timeout) return false;
usleep(10000);
continue;
}
$data .= $chunk;
$read += strlen($chunk);
}
return $data;
}
}