A small reference to the APIs of this website.
Under construction.
Under construction.
A bit delayed for the new font.
In meanwhile take a look at open source fancy fonts by Camel-XP
http://aim-plus.com/article.php?id=23
get the source file here: link
Under construction.
Here is an sample class to access the Server Spider data.
Use the following PHP code to display a list of all available servers.
example_list.php
<?php // css style print('<style type="text/css"> body { color: silver; background: black; } /* quake colors */ .q3-black { color: gray } .q3-red { color: red } .q3-green { color: lime } .q3-yellow { color: yellow } .q3-blue { color: blue } .q3-cyan { color: cyan } .q3-pink { color: fuchsia } .q3-white { color: white } </style>'); // init require('spider.class.php'); $spider = new spider(); // display time of last cache printf('<p>Cache date: %s</p>', date('r', $spider->cache_time)); // display internal structure of cache array printf('<p>Data structure: <pre>%s</pre></p>', htmlentities(print_r(current($spider->cache), true))); // access a specific server printf('<p>Server BEER.FREEZER is %s</p>', isset($spider->cache['193.200.57.36:27960']) ? 'online' : 'offline'); // output all servers foreach ( $spider->cache as $server ) { printf('<p>%s %d/%d(%d) <b>%s</b> %dms %s</p>', $server['host'], $server['clients'], $server['clients_max'], $server['clients_bot'], $server['map'], $server['ping'], $server['name']); }
If you need to query and display a single server.
example_query.php
<?php // init require('spider.class.php'); $spider = new spider(); if ( $query = $spider->query('193.200.57.36:27960') ) { foreach ( $query['cvars'] as $cvar ) { // do not display our private cvars if ( !isset($cvar['key']) ) { continue; } printf('<strong>%s</strong>: %s<br />', htmlentities($cvar['key']), htmlentities($cvar['value'])); } // there are some private cvars available: ping, map_time, map_status, score_red, score_blue printf('<p>Ping: %dms</p>', $query['cvars']['ping']['value']); printf('<p>Red score: %d<br />Blue score: %d</p>', $query['cvars']['score_red']['value'], $query['cvars']['score_blue']['value']); // player list $teams = array('Free', 'Red', 'Blue', 'Spec'); foreach ( $query['players'] as $player ) { printf('<p>Name: %s<br />TLD: %s<br />Score: %d<br />Ping: %dms<br />Team: %s<br />Frozen: %s</p>', $player['name'], $player['tld'], $player['score'], $player['ping'], $teams[ $player['team'] ], $player['flags'] & SPIDER_PLAYER_FROZEN ? 'yes' : 'no'); } } else { print('<p>Server is offline</p>'); }
spider.class.php
<?php define('SPIDER_VERSION', 1.0); define('SPIDER_PLAYER_FROZEN', 4); define('SPIDER_PLAYER_RED_FLAG', 8); define('SPIDER_PLAYER_BLUE_FLAG', 16); define('SPIDER_PLAYER_NEUTRAL_FLAG', 32); // php5 class class spider { // settings start private $url = 'http://www.excessiveplus.net/api/spider/getservers.csv'; private $cache_file = 'spider.db'; private $cache_timeout = 60; // settings end public $cache = array(); public $cache_time = 0; function __construct( $filename = false ) { if ( $filename !== false ) { $this->cache_file = $filename; } $this->update_cache(); } function sort_server( $server1 = NULL, $server2 = NULL ) { if ( $server1 === NULL || $server2 === NULL ) { return uasort($this->cache, array($this, 'sort_server')); } // sort by players, desc $result = -1 * bccomp($server1['clients'] - $server1['clients_bot'], $server2['clients'] - $server2['clients_bot']); // sort by clients, desc if ( !$result ) { $result = -1 * bccomp($server1['clients'], $server2['clients']); } // sort by ping, asc if ( !$result ) { $result = bccomp($server1['ping'], $server2['ping']); } return $result; } function load_cache() { if ( file_exists($this->cache_file) ) { $this->cache = unserialize(file_get_contents($this->cache_file)); return true; } return false; } function update_cache() { if ( !is_writable($this->cache_file) ) { trigger_error('Cache file is not writable: '. $this->cache_file, E_USER_ERROR); } // use our cache until it timeout $this->cache_time = @filemtime($this->cache_file); if ( $this->cache_timeout >= time() - $this->cache_time ) { $this->load_cache(); return false; } // try to update if ( $fp = @fopen($this->url, 'r') ) { $version = fgetcsv($fp); if ( $version[0] == 'spider' ) { if ( $version[1] != 100 ) { trigger_error('Server spider protocol does not match', E_USER_ERROR); } $header = fgetcsv($fp); while ( $line = fgetcsv($fp) ) { $server = array_combine($header, $line); $server['name_plain'] = strip_tags($server['name']); $this->cache[ $server['host'] ] = $server; } fclose($fp); $this->sort_server(); file_put_contents($this->cache_file, serialize($this->cache)); return true; } } // service is down, issue a notice and use the cache trigger_error('Could not update the server spider cache'); $this->load_cache(); return false; } // functions to query a single server function sort_player( &$player1 = NULL, $player2 = NULL ) { if ( $player2 === NULL ) { return uasort($player1, array($this, 'sort_player')); } // sort by team, asc $result = bccomp($player1['team'], $player2['team']); // sort by score, desc if ( !$result ) { $result = -1 * bccomp($player1['score'], $player2['score']); } return $result; } function query( $host, $timeout = 500 ) { list($host, $port) = explode(':', $host); if ( !$port ) { $port = 27960; } if ( $fp = @fsockopen('udp://'. $host, $port, $errno, $errstr, $timeout / 1000) ) { stream_set_timeout($fp, 0, $timeout * 1000); fwrite($fp, "\xFF\xFF\xFF\xFFgetstatus\n"); $ping = microtime(true); if ( !fgets($fp, 20) ) { fclose($fp); return false; } $ping = (microtime(true) - $ping) * 1000; // non blocking from here on, we've already got the response stream_set_blocking($fp, false); $info = fgets($fp); $players = array(); while ( $player = fgetcsv($fp, 1024, ' ', '"') ) { $players[] = array( 'name' => $player[2], 'score' => $player[0], 'ping' => $player[1] ); } fclose($fp); // parse server info cvars if ( preg_match_all('/\\\\([^\\\\]+)\\\\([^\\\\]+)/', $info, $matches, PREG_SET_ORDER) ) { foreach ( $matches as $match ) { $key = strtolower($match[1]); $cvars[$key] = array( 'key' => $match[1], 'value' => $match[2] ); } ksort($cvars); } // server ping $cvars['ping']['value'] = $ping; // parse Excessive Plus compressed info if ( isset($cvars['info']) && ($matches = explode("\t", $cvars['info']['value'])) ) { $i = 0; // map info $cvars['map_time']['value'] = $this->unpack_int($matches[$i++]); $cvars['map_status']['value'] = $this->unpack_int($matches[$i++]); // team info if ( $cvars['g_gametype']['value'] >= 3 ) { $match = explode(' ', $matches[$i++]); $cvars['score_red']['value'] = $this->unpack_int($match[0]); $cvars['score_blue']['value'] = $this->unpack_int($match[1]); } // player team + flags $info_flags = explode(' ', $matches[$i++]); @array_pop($info_flags); foreach ( (array)$info_flags as $id => $info_flag ) { $info_flag = $this->unpack_int($info_flag); $info_team = $info_flag & ~(4 | 8 | 16 | 32); $info_flag -= $info_team; $players[$id]['team'] = $info_team; $players[$id]['flags'] = $info_flag; } // player tld $info_tlds = explode(' ', $matches[$i++]); @array_pop($info_tlds); foreach ( (array)$info_tlds as $id => $info_tld ) { $players[$id]['tld'] = strtolower($info_tld); } // player time $info_times = explode(' ', $matches[$i++]); @array_pop($info_times); foreach ( (array)$info_times as $id => $info_time ) { $players[$id]['time'] = $this->unpack_int($info_time); } // unset the cvar, it does not contain any "human readable" information unset($cvars['info']); } $this->sort_player($players); return array('cvars' => $cvars, 'players' => $players); } return false; } function unpack_int( $packed_int ) { static $chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#$&()*+,-./:<=>?@[]^_{|}\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"; $len = strlen($packed_int) - 1; $result = 0; for ( $i = 0; $i <= $len; $i++ ) { $result += strpos($chars, $packed_int[$i]) * pow(62, $len - $i); } return $result; } }