<?php
class ServerQuery
{
var $challenge_number;
var $connected;
var $server_ip;
var $server_port;
var $socket;
function ServerQuery()
{
$this->challenge_number = 0;
$this->connected = true;
$this->server_ip = "";
$this->server_port = "";
}
function Connect($server_ip, $server_port)
{
$this->server_ip = gethostbyname($server_ip);
$this->server_port = $server_port;
$fp = fsockopen("udp://" . $this->server_ip, $this->server_port, $errno, $errstr, 2);
stream_set_timeout($fp, 2);
if($fp)
$this->connected = true;
else
{
$this->connected = false;
return false;
}
$this->socket = $fp;
return true;
}
function Disconnect()
{
@fclose($this->socket);
$connected = false;
}
function IsConnected()
{
return $this->connected;
}
function queryServers($servers)
{
$server_array = array();
foreach($servers as $key => $s)
{
$this->Connect($s[0], $s[1]);
if($infos = $this->Info())
{
$server_info = array(
"sid" => $key,
"status" => "1",
"type" => $infos['type'],
"version" => $infos['version'],
"hostname" => $infos['name'],
"map" => $infos['map'],
"mod" => $infos['mod'],
"game" => $infos['game'],
"appid" => $infos['appid'],
"cur_players" => $infos['activeplayers'],
"max_players" => $infos['maxplayers'],
"bot_players" => $infos['botplayers'],
"dedicated" => ($infos['dedicated']=="d")?"Dedicated":"Listen",
"os" => ($infos['os']=="l")?"Linux":"Windows",
"password" => $infos['password'],
"secure" => $infos['secure'],
"sversion" => $infos['sversion'],
"address" => $s[0].":".$s[1],
"players" => ""
);
$server_info['players'] = $this->Players();
}
else
{
$server_info = array(
"sid" => $key,
"status" => "0",
"type" => "",
"version" => "",
"hostname" => $key,
"map" => "",
"mod" => '',
"game" => "",
"appid" => "",
"cur_players" => "0",
"max_players" => "0",
"bot_players" => "0",
"dedicated" => "",
"os" => "",
"password" => "",
"secure" => "",
"sversion" => "",
"address" => $s[0].":".$s[1],
"players" => ""
);
}
$server_array[] = $server_info;
$this->Disconnect();
}
return $server_array;
}
private function get_challenge()
{
if($this->challenge_number == "")
{
$challenge = "\xff\xff\xff\xffchallenge rcon\n";
$buffer = $this->Communicate($challenge);
if(trim($buffer) == "")
{
$this->connected = false;
return false;
}
$this->challenge_number = trim(substr($buffer,15));
}
}
function Info()
{
if(!$this->connected)
return $this->connected;
$command = "\xff\xff\xff\xffTSource Engine Query\x00";
$buffer = $this->Communicate($command);
if(trim($buffer) == "")
{
$this->connected = false;
return false;
}
$pos=0;
$result["type"] = $this->parse_buffer($buffer,$pos,"bytestr");
$result["version"] = $this->parse_buffer($buffer,$pos,"byte");
$result["name"] = $this->parse_buffer($buffer,$pos,"string");
$result["map"] = $this->parse_buffer($buffer,$pos,"string");
$result["mod"] = $this->parse_buffer($buffer,$pos,"string");
$result["game"] = $this->parse_buffer($buffer,$pos,"string");
$result["appid"] = $this->parse_buffer($buffer,$pos,"short");
$result["activeplayers"] = $this->parse_buffer($buffer,$pos,"byte");
$result["maxplayers"] = $this->parse_buffer($buffer,$pos,"byte");
$result["botplayers"] = $this->parse_buffer($buffer,$pos,"byte");
$result["dedicated"] = $this->parse_buffer($buffer,$pos,"bytestr");
$result["os"] = $this->parse_buffer($buffer,$pos,"bytestr");
$result["password"] = $this->parse_buffer($buffer,$pos,"byte");
$result["secure"] = $this->parse_buffer($buffer,$pos,"byte");
$result["sversion"] = $this->parse_buffer($buffer,$pos,"string");
$result["edf"] = $this->parse_buffer($buffer,$pos,"byte");
switch ($result["edf"])
{
case '\x80':
$result["port"]= $this->parse_buffer($buffer,$pos,"short");
break;
case '\x40':
$result["specport"]= $this->parse_buffer($buffer,$pos,"short");
$result["specservername"] = $this->parse_buffer($buffer,$pos,"string");
break;
case '\x20':
$result["gametagdata"] = $this->parse_buffer($buffer,$pos,"string");
}
return $result;
}
function parse_buffer($buffer,&$pos,$type)
{
$result = NULL;
switch ($type)
{
case 'string':
while ( substr($buffer, $pos,1) !== "\x00" )
{
$result .= substr($buffer, $pos,1);
$pos++;
}
break;
case 'short':
$result = ord(substr($buffer, $pos,1)) + (ord(substr($buffer, $pos+1,1)) << 8);
$pos++;
break;
case 'long':
$result = ord($buffer[$pos]) + (ord($buffer[$pos + 1]) << 8) + (ord($buffer[$pos + 2]) << 16) + (ord($buffer[$pos + 3]) << 24);
$pos+=3;
break;
case 'byte':
$result = ord(substr($buffer, $pos,1));
break;
case 'bytestr':
$result = substr($buffer, $pos,1);
break;
case 'float':
$tmptime = @unpack('ftime', substr($buffer, $pos, 4));
$result = date('H:i:s', round($tmptime['time'], 0) + 82800);
$pos+=3;
break;
}
$pos++;
return $result;
}
function Players()
{
if(!$this->connected)
return $this->connected;
$challenge = "\xff\xff\xff\xff\x55\xff\xff\xff\xff";
$buffer = $this->Communicate($challenge);
if(trim($buffer) == "")
{
$this->connected = false;
return false;
}
$this->challenge_number = substr($buffer,1,4);
$command = "\xff\xff\xff\xff\x55$this->challenge_number";
$buffer = $this->Communicate($command);
if(trim($buffer) == "")
{
$this->connected = false;
return false;
}
#$buffer = substr($buffer, 1);
$pos=0;
$header = $this->parse_buffer($buffer,$pos,"bytestr");
$numpl = $this->parse_buffer($buffer,$pos,"byte");
if($header!='D') return;
$result=array();
for($i = 0; $i < $numpl; $i++)
{
$result[$i]["index"] = $this->parse_buffer($buffer,$pos,"byte");
$result[$i]["name"] = $this->parse_buffer($buffer,$pos,"string");
$result[$i]["frag"] = $this->parse_buffer($buffer,$pos,"long");
$result[$i]["time"] = $this->parse_buffer($buffer,$pos,"float");
}
return $result;
}
function Communicate($command)
{
if(!$this->connected)
return $this->connected;
if($command != "")
fputs($this->socket, $command, strlen($command));
$buffer = fread ($this->socket, 1);
$status = socket_get_status($this->socket);
if ($status["unread_bytes"] > 0)
$buffer .= fread($this->socket, $status["unread_bytes"]);
if(substr($buffer, 0, 4) == "\xfe\xff\xff\xff")
{
$requestid=substr($buffer,4,4);
$po=ord(substr($buffer,8,1));
$panum=($po & 1) + ($po & 2) + ($po & 4) + ($po & 8);
$po=$po >> 4;
$pacur=($po & 1) + ($po & 2) + ($po & 4) + ($po & 8);
if($pacur==($panum-1)) {
$splitbuffer[$pacur]=substr($buffer,9);
} else {
$splitbuffer[$pacur]=substr($buffer,14);
}
for ($i=1;$i<$panum;$i++)
{
$buffer2 = fread ($this->socket, 1);
$status = socket_get_status($this->socket);
$buffer2 .= fread($this->socket, $status["unread_bytes"]);
$requestid2=substr($buffer,4,4);
$po=ord(substr($buffer2,8,1));
$po=$po >> 4;
$pacur=($po & 1) + ($po & 2) + ($po & 4) + ($po & 8);
if($requestid==$requestid2) {
if($pacur==($panum-1))
$splitbuffer[$pacur]=substr($buffer2,9);
else
$splitbuffer[$pacur]=substr($buffer2,14);
}
}
for($i=0;$i<$panum;$i++) $bufferret.=$splitbuffer[$i];
}
else
$bufferret = substr($buffer, 4);
return $bufferret;
}
}
?>