Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <?php
- // A simple version of server query.
- // Only returns the MOTD and the number of players and max players.
- // Should work even when enable-query=false in the server.properties
- function ping($host, $port = 25565, $timeout_s = 1, $timeout_us = 0)
- {
- $errno = 0;
- $errstr = "";
- //Set up our socket
- $fp = @fsockopen("tcp://" . $host, $port, $errno, $errstr);
- if(!$fp)
- {
- //echo "no socket!<br />\n";
- return array();
- }
- //Send 0xFE: Server list ping
- fwrite($fp, "\xFE");
- // Set the time out limit
- stream_set_timeout($fp, $timeout_s, $timeout_us);
- $arr = stream_get_meta_data($fp);
- if($arr['timed_out'])
- {
- //echo "timed out!<br />\n";
- return array();
- }
- //Read as much data as we can (max packet size: 241 bytes)
- $d = fread($fp, 256);
- //Check we've got a 0xFF Disconnect
- if($d[0] != "\xFF")
- {
- //echo "not a disconnect!<br />\n";
- return array();
- }
- //Remove the packet ident (0xFF) and the short containing the length of the string
- $d = substr($d, 3);
- //Decode UCS-2 string
- $d = mb_convert_encoding($d, 'auto', 'UCS-2');
- //Split into array
- $d = explode("\xA7", $d);
- //Return an associative array of values
- return array(
- 'motd' => $d[0],
- 'players' => intval($d[1]),
- 'max_players' => intval($d[2])
- );
- }
- // A verbose version of server query. Requires enable-query=true in server.properties
- function full_stat($host, $port = 25565, $timeout_s = 1, $timeout_us = 0)
- {
- $errno = 0;
- $errstr = "";
- //Set up our socket
- $fp = @fsockopen("udp://" . $host, $port, $errno, $errstr);
- if(!$fp)
- {
- //echo "no socket!<br />\n";
- return array();
- }
- // Handshake:
- // Get the challenge token; send 0xFE 0xFD 0x09 and a 4-byte session id
- $str1 = "\xFE\xFD\x09\x00\x00\x00\x01"; // Arbitrary session id at the end (4 bytes) (we use 00 00 00 01 here)
- fwrite($fp, $str1);
- // Set the time out limit
- stream_set_timeout($fp, $timeout_s, $timeout_us);
- $arr = stream_get_meta_data($fp);
- if($arr['timed_out'])
- {
- //echo "timed out!<br />\n";
- return array();
- }
- $resp = fread($fp, 4096);
- // Check that we got something back
- if(strlen($resp) == 0)
- {
- //echo "empty response!<br />\n";
- return array();
- }
- // Check for a valid response
- if($resp[0] != "\x09")
- {
- //echo "not a valid response!<br />\n";
- return array();
- }
- // Parse the challenge token from string to integer
- $token = 0;
- for($i = 5; $i < (strlen($resp) - 1); $i++)
- {
- $token *= 10;
- $token += $resp[$i];
- }
- // Divide the int32 into 4 bytes
- $token_arr = array( 0 => ($token / (256*256*256)) % 256,
- 1 => ($token / (256*256)) % 256,
- 2 => ($token / 256) % 256,
- 3 => ($token % 256)
- );
- // Note that the challenge token is bound to your IP and port (as opposed to the [session ID]), and
- // lasts up to 30 seconds. You read that right, it's up to; it's not "your token will expire
- // after 30 seconds", it's "every token ever" is expired every 30 seconds. This means it's entirely
- // possible that you may get a token and use it within the same second and have it expire.
- // Get the full version of server status
- // Session ID and challenge tokens appended to magic header 0xFE 0xFD and command byte 0x00
- // Payload padded to 8 bytes
- $str = "\xFE\xFD\x00\x00\x00\x00\x01"
- . chr($token_arr[0]) . chr($token_arr[1]) . chr($token_arr[2]) . chr($token_arr[3])
- . "\x00\x00\x00\x00";
- fwrite($fp, $str);
- $data = fread($fp, 4096);
- $full_stat = substr($data, 16); // Strip the crap from the start
- $tmp = explode("\x00\x01player_\x00\x00", $full_stat); // First, split the payload in two parts
- $keysvalues = explode("\x00", $tmp[0]); // Divide the first part from every NULL-terminated string end into key1 val1 key2 val2...
- unset($keysvalues[count($keysvalues) - 1]); // Unset the last entry, because the are two 0x00 bytes at the end
- // Strip all the NULL-bytes from the end of the player list
- $tmp = $tmp[1];
- $i = strlen($tmp) - 1;
- while($i >= 0)
- {
- if(ord($tmp[$i]) != 0)
- {
- break;
- }
- $i--;
- }
- // Split the player information (if any)
- if($i > 0)
- {
- $tmp = substr($tmp, 0, $i + 1);
- $players = explode("\x00", $tmp); // Explode the player information from the NULL-byte positions
- }
- else
- {
- $tmp = FALSE;
- }
- // Arrange the key => value pairs into an array
- $info = array();
- for($i = 0; $i < count($keysvalues); $i += 2)
- {
- if($keysvalues[$i] == "")
- break;
- $info[$keysvalues[$i]] = $keysvalues[$i + 1];
- }
- // Collect all the information into one array
- $full_stat = $info;
- $full_stat['players'] = $players;
- return $full_stat;
- }
- // -----------------------------------------------------------------------------------------
- // These are here as an example and to test that the query works. You can edit the addresses to match
- // your server, and have the script dump the "raw" arrays with all the data.
- // If you only have one server, an easy example of usage would be:
- // $data = full_stat("some.addre.ss", 25565);
- // Just change the address and port to match your server.
- // You can add timeout values after the port, the default timeout is 1 second:
- // $data = full_stat("some.addre.ss", 25565, 0, 300000);
- // The first value is in seconds and the second is in microseconds. So the example above
- // would timeout after 300 000 microseconds = 300 milliseconds = 0.3 seconds
- // Note that the full_stat() function will only work if the server has query enabled
- // ie. enable-query=true in server.properties file.
- // The ping() function should always work, as it uses the same method that the client does
- // in the server list menu (and thus only has the same data to display, MOTD and players/max players).
- // After you have your data, for example in the $data variable as in the example above, you
- // can then print what you want from it. The possible keys are easily seen if running
- // the test below, as it dumps the full arrays.
- // The keys are in brackets (for example [hostname]), so when you want
- // to print it, use some of PHP's print methods, for example echo:
- // echo $data['hostname'];
- // or printf:
- // printf("Hostname follows this example: %s\n", $data['hostname']);
- // To recap: to test this script for your server:
- // 1. Save this script to your web server, for example as a test.php
- // 2. Edit the array below to include your server (address and port).
- // You can delete the rest of the example servers.
- // Use either full_stat, if you have enable-query=true, or ping, if you have enable-query=false.
- // Ping will of course work also when enable-query=true.
- // 3. Load the page in your web browser. If everything works, you should see an array with
- // some data about you server. You can use the keys shown in brackets to print only
- // the data you want in your final page.
- // echo $data['hostname']; if using the example above or
- // echo $servers['foo']['hostname']; if using the array below (foo is just a key/index in the array for the given server)
- // Put your server(s) here to test the query:
- $servers = array(
- 'server1' => full_stat("some.addre.ss", 25565),
- 'server2' => full_stat("some.addre.ss", 25590),
- 'foo' => full_stat("some.addre.ss", 25565, 2, 0), // An example with a 2 second timeout
- 'pingserver' => ping("some.addre.ss", 25585, 2, 0)
- );
- // Dump all the test data:
- echo "<pre>\n";
- foreach($servers as $server => $data)
- {
- echo "$server:\n";
- print_r($data);
- }
- echo "</pre>\n";
- ?>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement