Skip to content

Instantly share code, notes, and snippets.

@belak
Last active August 29, 2015 14:00
Show Gist options
  • Save belak/0cbe585dc8736800b6f4 to your computer and use it in GitHub Desktop.
Save belak/0cbe585dc8736800b6f4 to your computer and use it in GitHub Desktop.
Minecraft Stats Query
<?php
// Settings
$hostname = "66.240.202.11";
$port = 25565;
// Based off of https://github.com/winny-/mcstat/blob/master/mcstat.php
// with updated reading of the key-value and username portions.
$sess_id = rand(1, 0xFFFFFFFF) & 0x0F0F0F0F;
// Set up a UDP socket
$fp = stream_socket_client('udp://' . $hostname . ':' . $port, $errno, $errmsg);
stream_set_timeout($fp, 5);
// Set initial time
$time = microtime(true);
// Handshake
$req = pack('cccN', 0xFE, 0xFD, 9, $sess_id);
fwrite($fp, $req);
// Read handshake response and get the token
$resp = fread($fp, 2048);
if (strpos($resp, 9) !== 0 && (int)substr($resp, 1, 4) === $sess_id) {
error_log("Invalid handshake response");
exit(1);
}
// The chalenge token will be found here
$token = substr($resp, 5, -1);
// Update time
$time = round((microtime(true)-$time)*1000);
// Issue request
$stat_req = pack('cccNNN', 0xFE, 0xFD, 0, $sess_id, $token, 0);
fwrite($fp, $stat_req);
$stat_header = fread($fp, 5);
if (strpos($resp, 0) !== 0 && (int)substr($resp, 1, 4) === $sess_id) {
error_log("Invalid stat header response");
exit(1);
}
fread($fp, 11);
// Set default values
$stats = array();
$stats['players'] = array();
$stats['latency'] = $time;
$stats['numplayers'] = 0;
$stats['maxplayers'] = 20;
// This data comes as follows:
// key1\0val1\0key2\0val2\0\0
//
// States:
// 0: reading key
// 1: reading val
// 2: done
$state = 0;
$key = '';
$val = '';
while ($state < 2) {
$c = fread($fp, 1);
if ($state == 0) {
if ($c === chr(0) || $c === false) {
if (strlen($key) == 0) {
$state = 2;
} else {
$state = 1;
}
} else {
$key .= $c;
}
} else {
if ($c === chr(0) || $c === false) {
if ($key == 'port') {
$val = (string)$val;
}
$stats[$key] = $val;
$key = '';
$val = '';
$state = 0;
} else {
$val .= $c;
}
}
}
// Skip the 10 bytes of padding
fread($fp, 10);
// This data comes as follows:
// player1\0player2\0\0
$state = 0;
$val = '';
while ($state < 1) {
$c = fread($fp, 1);
if ($c === chr(0) || $c === false) {
if (strlen($val) == 0) {
$state = 2;
} else {
$stats['players'][] = $val;
$val = '';
}
} else {
$val .= $c;
}
}
foreach ($stats['players'] as $player) {
echo $player . "\n";
}
echo $stats['numplayers'] . " of " . $stats['maxplayers'] . " connected\n";
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment