<?php
require('SoldatPlayer.php');
/**
* SoldatServer class
*
* Stores Soldat server information.
*
* @copyright 2009 Tomaž Muraus
* @license http://www.gnu.org/copyleft/gpl.html GPL License
* @version Release: 1.0
* @link http://www.tomaz-muraus.info
*/
class SoldatServer
{
protected $_ip;
protected $_port;
protected $_timeout;
protected $_socket = null;
protected $_command = "s";
protected $_ping;
protected $_version;
protected $_name;
protected $_map;
protected $_gametype;
protected $_playerCount;
protected $_maxPlayers;
protected $_rules = array();
protected $_players = array();
/**
* Constructor.
*
* @param string $ip Server IP address.
* @param int $port Server port.
* @param int $timeout Connection and socket read/write timeout in seconds.
*/
public function __construct($ip, $port = 23073, $timeout = 2)
{
$this->_ip = $ip;
$this->_port = $port + 123;
$this->_timeout = $timeout;
}
public function getIp()
{
return $this->_ip;
}
public function getPort()
{
return $this->_port;
}
public function getPing()
{
return $this->_ping;
}
public function getVersion()
{
return $this->_version;
}
public function getName()
{
return $this->_name;
}
public function getMap()
{
return $this->_map;
}
public function getGametype()
{
return $this->_gametype;
}
public function getRules()
{
return $this->_rules;
}
public function getPlayerCount()
{
return $this->_playerCount;
}
public function getMaxPlayers()
{
return $this->_maxPlayers;
}
public function getPlayers()
{
return $this->_players;
}
/**
* Opens a socket and requests server information.
*
* @return boolean TRUE on success, FALSE otherwise.
*/
public function queryServer()
{
// Creates a socket and connects to it
$this->_socket = stream_socket_client('udp://' . $this->_ip . ':' . $this->_port, $errno, $errstr, $this->_timeout);
// Stream (read/write) timeout
stream_set_timeout($this->_socket, $this->_timeout);
if ($this->_socket !== FALSE)
{
$start = microtime(TRUE);
// Sends the status command and reads the response
fwrite($this->_socket, $this->_command);
$response = fread($this->_socket, 16384);
$end = microtime(TRUE);
if ($response)
{
// Ping in ms (response time - request time) * 1000 (1 ms = 1000 us)
$this->_ping = round((($end - $start) * 1000));
// Parses the server response
$this->_parseServerResponse($response);
// Closes a socket resource
fclose($this->_socket);
return TRUE;
}
else
{
// Closes a socket resource
fclose($this->_socket);
return FALSE;
}
}
else
{
return FALSE;
}
}
/**
* Parses the server response and saves the result into the class variables.
*
* @param string $response Server response delimited with ASCII characters.
*
* @return void
*/
protected function _parseServerResponse($response)
{
// Cut the first 4 characters (EYE1)
$response = substr($response, 4);
// General server information
$this->_readString($response);
$this->_readString($response);
$this->_name = $this->_readString($response);
$this->_gametype = $this->_readString($response);
$this->_map = $this->_readString($response);
$this->_version = $this->_readString($response);
$this->_readString($response);
$this->_playerCount = $this->_readString($response);
$this->_maxPlayers = $this->_readString($response);
// Server rules
while (ord(substr($response, 0, 1)) > 1)
{
$this->_rules[$this->_readString($response)] = $this->_readString($response);
}
// Players
if (strlen(substr($response, 1)) > 0)
{
$this->_parsePlayerData(substr($response, 2));
}
}
/**
* Parses the player data and saves the response into the class variable $_players.
*
* @param string $data Player list delimited with ASCII characters.
*
* @return void
*/
protected function _parsePlayerData($data)
{
$matches = array();
preg_match_all('/
[\x00-\xff|\s](.*?) # player name
[\x00-\xff](Alpha|Bravo|Charlie|Delta|N\/A|Spectator) # team
[\x00-\xff](Alpha|Bravo|Charlie|Delta|N\/A|Spectator) # skin
[\x00-\xff](\d+) # score (kills)
[\x00-\xff](\d+) # ping
[\x00-\xff](.*?)m\?{0,1} # time
/ix', $data, $matches);
for ($i = 0; $i < count($matches[0]); $i++)
{
$this->_players[] = new SoldatPlayer($matches[1][$i], $matches[2][$i], $matches[4][$i], $matches[5][$i], $matches[6][$i]);
}
}
/**
* Reads and removes a single information from the response string.
*
* @param string $response Server response delimited with ASCII characters.
*
* @return string
*/
protected function _readString(&$response)
{
// Length of the information following this ASCII character
$length = ord(substr($response, 0, 1));
if ($length > 0)
{
$value = substr($response, 1, $length - 1);
}
else
{
$value = NULL;
}
$response = substr($response, $length);
return $value;
}
}
/* End of file SoldatServer.php */
/* Location: ./SoldatServer.php */