Dieses Script stellt eine Funktion (mit zwei Hilfsfunktionen) bereit, um einen Server nach der Spieleranzahl etc. abzufragen.
Es ist kompatibel mit dem Queryformat von 1.3.2 und älter, sowie der neuen Version von 1.4.
Disclaimer
Dieses Script wird so wie es ist angeboten. Wer nicht weiß was das ist, oder wie man es verwendet, drückt jetzt bitte die Zurücktaste. Alle Posts, die keine direkten Bug-Reports oder relevante Verbesserungsvorschläge sind, werden zumindest von mir nicht beantwortet.
Es ist kompatibel mit dem Queryformat von 1.3.2 und älter, sowie der neuen Version von 1.4.
Disclaimer
Dieses Script wird so wie es ist angeboten. Wer nicht weiß was das ist, oder wie man es verwendet, drückt jetzt bitte die Zurücktaste. Alle Posts, die keine direkten Bug-Reports oder relevante Verbesserungsvorschläge sind, werden zumindest von mir nicht beantwortet.
PHP:
<?php
/**
* Minecraft server query by Zahl
* Works with 1.4 and pre-1.4 servers
* Returns an array on success, string describing the error on failure
*/
function queryServer($address, $port)
{
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
return 'Error creating socket';
}
@socket_set_nonblock($socket);
@socket_connect($socket, $address, $port);
$r = $w = $e = array($socket);
@socket_select($r, $w, $e, 3, 0); // Try connecting for 3 seconds max.
if (count($w) !== 1) {
@socket_close($socket);
return 'offline';
}
@socket_set_block($socket);
$start = microtime(true);
$result = executeQuery($socket);
if (is_array($result)) {
$result['ping'] = round((microtime(true) - $start) * 1000);
}
@socket_close($socket);
return $result;
}
function executeQuery($socket)
{
// Write timeout, so that crashed servers will not make this script hang forever
socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, array('sec' => 2, 'usec' => 0));
// Send query
$ret = socket_write($socket, "\xFE\x01", 2);
if ($ret !== 2) {
return 'Error sending query';
}
// Read timeout, see above
socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array('sec' => 3, 'usec' => 0));
// Wait for reply header
$ret = @socket_recv($socket, $header, 3, MSG_WAITALL);
if ($ret !== 3) {
return 'Reply header incomplete';
}
if (ord($header{0}) != 255) {
return 'Reply has unexpected packet ID ' . ord($header{0});
}
$reportedLen = ((ord($header{1}) << 8) + ord($header{2})) * 2; // in bytes (almost)
if ($reportedLen === 0) {
return 'Reply has no payload';
}
// Decrease timeout even more as this part should already be floating around in the tcp/ip stack
socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array('sec' => 0, 'usec' => 50000));
$payloadLen = @socket_recv($socket, $payload, $reportedLen, MSG_WAITALL);
if ($payloadLen < $reportedLen) {
return 'Reply is shorter than header says! Should be' . $reportedLen . ' but is ' . $payloadLen;
}
// Parse reply
if ($payloadLen > 1 && ord($payload{0}) === 0 && ord($payload{1}) === 0xA7) {
// Server is 1.4+
$data = mb_convert_encoding(substr($payload, 2), 'UTF-8', 'UTF-16BE');
// Above needs the multibyte string functions which should be available on any halfway modern php installation.
// Also, the UTF-16BE encoding must be supported. Get all encodings your installation supports:
//print_r(mb_list_encodings());
$data = explode("\0", $data);
if (count($data) < 6) {
return 'Returned data has less than 6 sections (' . count($data) . "):\n" . $data;
}
//if ($data[0] == 1) <--- data[0] is the query protocol version. currently only 1 exists, might need to check that in the future
return array(
'protocol' => $data[1], // Minecraft protocol version. 1.4.x is 47
'version' => $data[2], // Server version as string, i.e. "1.4.2"
'name' => $data[3], // Server name, might include color/formatting codes
'players' => $data[4], // Number of players online
'maxplayers' => $data[5] // Max number of players
);
}
// ########################
// Server is 1.3.2 or older
$data = mb_convert_encoding($payload, 'UTF-8', 'UTF-16BE');
// Above needs the multibyte string functions which should be available on any halfway modern php installation.
// Also, the UTF-16BE encoding must be supported. Get all encodings your installation supports:
//print_r(mb_list_encodings());
$data = explode('§', $data);
if (count($data) < 3) {
return 'Returned data has less than 3 sections';
}
return array(
'name' => $data[0],
'players' => $data[1],
'maxplayers' => $data[2]
);
}
/**
* Remove color and formatting from a String
* e.g. "§cColorful §fMessage" => "Colorful Message"
*/
function stripFormat($string)
{
return preg_replace('/§./', '', $string);
}
// #######################################
// DEMO PART:
// If you're running via browser rather than command line
if (isset($_SERVER['REMOTE_ADDR'])) Header('Content-Type: text/plain; charset=utf-8');
$servers = array(
'spieleplanet.eu' => 25565,
'S.wbkbuild-mc.de' => 25570,
's.wbkbuild-mc.de' => 25565,
'4.4.4.4' => 25565 // One that is offline for sure...
);
foreach ($servers as $addr => $port) {
$ret = queryServer($addr, $port);
if (is_array($ret)) { // ONLINE
if (isset($ret['version'])) { // version field set - it's 1.4 or newer
$ret['name'] = stripFormat($ret['name']);
echo " :-) $addr:$port is '{$ret['name']}', with {$ret['players']} of {$ret['maxplayers']} players online, Ping: {$ret['ping']}. ({$ret['version']})\n";
} else { // 1.3.2 or older
echo " :-) $addr:$port is '{$ret['name']}', with {$ret['players']} of {$ret['maxplayers']} players online, Ping: {$ret['ping']}.\n";
}
} else { // OFFLINE/ERROR
echo " *** $addr:$port did not reply: $ret\n";
}
}
echo "DONE\n";
exit(0);
Zuletzt bearbeitet: