Version: 0.4.0 class
Type: Class
Category: Games
License: GNU General Public License
Description: gQuery// is a game server query tool for PHP. It works in many ways in the same manner as qStat but by using PHP instead of C it allows much easyer intergration into the web along with overall flexibility. It supports Quake2, Quake3, Half-Life and Unreal Tournament servers & more. Visit the homepage at http://gdome.sourceforge.net/
<?php
/*
+------------------------------------------------------------------------+
| gQuery// version 0.4.0 beta |
| Copyright (c) 2001 Jon Gretar Borgthorsson. All rights reserved. |
+------------------------------------------------------------------------+
| gQuery// is a part of the gDome// project. Find more information |
| about gDome// and related projects at http://gdome.sourcefoge.net/ |
+------------------------------------------------------------------------+
| |
| This program is free software; you can redistribute it and/or |
| modify it under the terms of the GNU General Public License version 2 |
| as published by the Free Software Foundation |
| |
| Software distributed under the License is distributed on an "AS IS" |
| basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. |
| See the GNU General Public License in License.html for more details. |
| |
+------------------------------------------------------------------------+
| Website: http://gdome.sourceforge.net/ |
+------------------------------------------------------------------------+
| Authors: |
| Jon Gretar Borgthorsson <jongretar@users.sourceforge.net> |
+------------------------------------------------------------------------+
*/
class gQuery
{
// gQuery system variables
var $errors = array(); // Errors in the script
var $fp; // File pointer
// The info you give the script
var $cgametype; // Type of game
var $caddress; // Connection address
var $cport; // Connection port
// Responders
var $serverinfo; // Server info array
var $playerinfo; // Player info array
var $systeminfo; // System info array
var $pcount = 0; // Player count
// Debug variables
var $DEBUG; // DEBUG
var $DEBUG2; // DEBUG
// Types of games
var $gametypes = array(
"HL" => "Half-Life",
"HL2" => "Half-Life 2",
"Q1" => "Quake",
"Q2" => "Quake 2",
"Q3" => "Quake: Arena",
"QW" => "Quake World",
"UT" => "Unreal Tournament",
"TB2" => "Tribes 2"
);
// default ports for games
var $defaultports = array(
"HL" => "27015",
"HL2" => "27015",
"Q1" => "26000",
"Q2" => "27910",
"Q3" => "27960",
"QW" => "27500",
"UT" => "7777",
"TB2" => "28000"
);
// Activation commands
var $commands = array(
"HL" => array(
"Serverinfo" => "details\x00",
"Playerlist" => "players\x00"
),
"Q2" => array(
"Serverinfo" => "status\x00"
),
"Q3" => array(
"Serverinfo" => "getstatus\x00"
),
"UT" => array(
"Serverinfo" => "\\status\\",
"Playerlist" => "\\status\\",
"TheEnd" => "\\final\\"
)
);
/**
* Function gameinfo(GAMETYPE=string, ADDRESS=string, [PORT=string])
* The main function. Loads info on the server
*/
function gQuery($gametype ,$address, $port = "")
{
// Set the user provided connection settings
$this->cgametype = $gametype;
$this->caddress = $address;
// Set the port to default if not defined
if ($ports != "")
{
$this->cport = $this->defaultports[$this->cgametype];
}
else
{
$this->cport = $port;
}
// Make the connection
$this->fp = fsockopen("udp://" . $this->caddress, $this->cport, &$errno, &$errstr, 4);
if (!$this->fp)
{
//unable to connect to host
$this->serverinfo["name"] = "Error connecting to server";
$this->serverinfo["address"] = $this->caddress;
$this->addError("gQuery// had an error connecting to " . $this->caddress . ":" . $this->cport . "($errno - $errstr)");
}
else
{
// Run the appropriate parser.
eval("\$this->parseServerstat" . $this->cgametype . "();");
// Close the connection
fclose($this->fp);
}
// Put up the list of variabes so ppl can see what info is available
$this->systeminfo["gamevariables_count"] = 0;
while (list($key) = each ($this->serverinfo))
{
if ($this->systeminfo["gamevariables_count"] != 0) $this->systeminfo["gamevariables"] .= ", ";
$this->systeminfo["gamevariables"] .= $key;
$this->systeminfo["gamevariables_count"]++;
}
$this->systeminfo["playervariables_count"] = 0;
if ( $this->serverinfo["player"] != 0 )
{
while (list($key) = each ($this->playerinfo[0]))
{
if ($this->systeminfo["playervariables_count"] != 0) $this->systeminfo["playervariables"] .= ", ";
$this->systeminfo["playervariables"] .= $key;
$this->systeminfo["playervariables_count"]++;
}
}
}
/**
* Function about()
* Displays info about this class.
*/
function about()
{
echo "<P><B>gQuery// gameserver info class. Version 0.4.0. \n";
echo "<BR>© 2001 tar Borgrsson <I>(jongretar@users.sourceforge.net)</I> \n";
echo "<BR>http://gdome.sourceforge.net/</B></P> \n";
}
/**
* Function debug()
* Mostly just for debugging. Displays all kinds of info.
*/
function debug()
{
echo "<TABLE cellspacing='1' cellpadding='10'><TR><TD bgcolor='lightgreen'>";
echo "<B>Debug Info:</B><BLOCKQUOTE>";
echo "Address: " . $this->caddress . "<BR>\n";
echo "Port: " . $this->cport . "<BR>\n";
echo "Gametype: " . $this->cgametype . " <I>(" . $this->gametypes[$this->cgametype] . ")</I><BR>\n";
echo "Server Vars: " . $this->systeminfo["gamevariables_count"] . " vars <I>(" . $this->systeminfo["gamevariables"] . ")</I><BR>\n";
echo "Player Vars: " . $this->systeminfo["playervariables_count"] . " vars <I>(" . $this->systeminfo["playervariables"] . ")</I><BR>\n";
echo "<B>Errors:</B><OL>";
for ($i = 0; $i <= sizeof($this->errors)-1; $i++)
{
echo "<LI> " . $this->errors[$i] . "\n";
}
echo "</OL>";
echo "</BLOCKQUOTE>";
echo "</TD></TR></TABLE>";
}
/**
* Function addError(ERRORMSG=string, [HALT=bool])
* Adds an error into the error array
*/
function addError($errorMsg, $halt = false)
{
// Check wether to stop the script or not
if (!$halt)
{
$this->errors[count($this->errors)] = "WARNING: " . $errorMsg;
}
else
{
$this->errors[count($this->errors)] = "ERROR: " . $errorMsg;
exit;
}
}
/**
* Function parseServerstatHL()
* Requests the server info from the server and parses it down
*/
function parseServerstatHL()
{
fwrite($this->fp,$this->commands[$this->cgametype]["Serverinfo"]);
// Get rid of the header
$header = fread($this->fp,5);
// Get server address and Port
$do = true;
$result = "";
while($do)
{
$str = fread($this->fp,1);
$result .= $str;
if ($str == "\x00") $do = false;
}
$this->serverinfo["address"] = $result;
// Get server name
$do = true;
$result = "";
while($do)
{
$str = fread($this->fp,1);
$result .= $str;
if ($str == "\x00") $do = false;
}
$this->serverinfo["name"] = $result;
// Get server map
$do = true;
$result = "";
while($do)
{
$str = fread($this->fp,1);
$result .= $str;
if ($str == "\x00") $do = false;
}
$this->serverinfo["map"] = $result;
// Get server moddir
$do = true;
$result = "";
while($do)
{
$str = fread($this->fp,1);
$result .= $str;
if ($str == "\x00") $do = false;
}
$this->serverinfo["moddir"] = $result;
// Get server modname
$do = true;
$result = "";
while($do)
{
$str = fread($this->fp,1);
$result .= $str;
if ($str == "\x00") $do = false;
}
$this->serverinfo["modname"] = $result;
// Get number of players online
$str = fread($this->fp,1);
$this->serverinfo["players"] = ord($str);
// Get maximum number of online player
$str = fread($this->fp,1);
$this->serverinfo["maxplayers"] = ord($str);
// Get server protocol
$str = fread($this->fp,1);
$this->serverinfo["protocol"] = ord($str);
// Get Type of server
$str = fread($this->fp,1);
if ($str == "l")
{
$this->serverinfo["typeofserver"] = "Listen";
}
else if ($str == "d")
{
$this->serverinfo["typeofserver"] = "Deticated";
}
else
{
$this->serverinfo["typeofserver"] = "Unknown";
}
// Get server OS
$str = fread($this->fp,1);
if ($str == "l")
{
$this->serverinfo["serveros"] = "Linux";
}
else if ($str == "w")
{
$this->serverinfo["serveros"] = "Win32";
}
else
{
$this->serverinfo["serveros"] = "Unknown";
}
// Get wether server locked or not
$str = fread($this->fp,1);
if (ord($str) == 1)
{
$this->serverinfo["locked"] = "true";
}
else
{
$this->serverinfo["locked"] = "false";
}
// Get the unknown thing
// Don't know what this variable stands for
// Please send me info if you find out
$str = fread($this->fp,1);
$this->serverinfo["unknown"] = ord($str);
// Get the URL of the mod
$do = true;
$result = "";
while($do)
{
$str = fread($this->fp,1);
$result .= $str;
if ($str == "\x00") $do = false;
}
$this->serverinfo["modurl"] = $result;
// Then get the Playerinfo
// We will trust that the connection is ok.
fclose($this->fp);
$this->fp = fsockopen("udp://" . $this->caddress, $this->cport, &$errno, &$errstr, 4);
fwrite($this->fp,$this->commands[$this->cgametype]["Playerlist"]);
//wait till we receive a header and store it (isn't used at the moment)
$str = fread($this->fp, 6);
$top = ord($str[5]);
$this->pcount = $top;
//socket_set_blocking($this->fp,0);
for($usr = 0; $usr <= ($top-1); $usr++)
{
$do = true;
// Get player id
$str = fread($this->fp, 1);
$this->playerinfo[$usr]["index"] = ord($str);
// Get player name
$temp = "";
while($do)
{
$str = fread($this->fp,1);
if($str == "\x00")
{
$do = false;
}
else
{
$temp .= $str;
}
}
$this->playerinfo[$usr]["name"] = $temp;
// Get player frags
$tot = 0;
$str = fread($this->fp, 1);
$tot += ord($str);
$str = fread($this->fp, 1);
$tot += ord($str) * 256;
$str = fread($this->fp, 1);
$tot += ord($str) * 65536;
$str = fread($this->fp, 1);
$tot += ord($str) * 16777216;
if($tot >= 16777216)
{ // ie is negative
$tot -= (4294967296);
}
$this->playerinfo[$usr]["frags"] = $tot;
// Get player time
$bin = '';
for($loop = 0; $loop <= 3; $loop++)
{
$bin = str_pad(decbin(ord(fread($this->fp, 1))), 8, '0', STR_PAD_LEFT).$bin;
}
// get sign
$sign = bindec(substr($bin, 0, 1));
// get exponent and adjust for special case and bias
$exponent = bindec(substr($bin, 1, 8));
$exponent = ($exponent)? $exponent - 127 : $exponent;
if($exponent) {
// get the binary number of the mantissa
$int = bindec('1'.substr($bin, 9, $exponent));
$dec = bindec(substr($bin, 9 + $exponent));
$time = "$int.$dec";
$this->playerinfo[$usr]["time"] = number_format($time / 60, 2);
}
else
{
$this->playerinfo[$usr]["time"] = "0.0";
}
}
}
/**
* Function parseServerstatQ2()
* Requests the server info from the server and parses it down
*/
function parseServerstatQ2()
{
fwrite($this->fp,$this->commands[$this->cgametype]["Serverinfo"]);
// Get rid of the header
$header = fread($this->fp,10);
// Read in the info from the server.
$do = true;
$result = "";
while($do)
{
$str = fread($this->fp,1);
$result .= $str;
if ( $str == "\n" ) $do = false;
}
$this->serverinfo["allinfo"] = $result;
// Now recieve the player info
socket_set_blocking($this->fp,0);
echo $temp;
$do = true;
$i = 0;
while ($do)
{
$temp = fgets($this->fp, 100);
if ($temp == "")
{
$do = false;
}
else
{
$tempplayers[$i] = $temp;
}
$i++;
}
$this->pcount = sizeof($tempplayers);
$this->serverinfo["players"] = sizeof($tempplayers);
// Now resolve the server info
$temparray = explode ("\\", $this->serverinfo["allinfo"]);
$i = 1;
while($i <= sizeof($temparray))
{
$this->serverinfo[$temparray[$i++]] = $temparray[$i++];
}
// Resolve the player info
$i = 0;
while($i <= $this->pcount-1)
{
$this->playerinfo[$i]["index"] = "$i";
$temparray = explode ("\"", $tempplayers[$i]);
$this->playerinfo[$i]["name"] = $temparray[1];
/*
$this->playerinfo[$i]["namecolored"] = $temparray[1];
//Remove colortags
$result = "";
$b = 0;
while($b <= strlen($temparray[1]))
{
$str = substr($temparray[1], $b, 1);
if ($str == "^")
{
$b++;
}
else
{
$result .= $str;
}
$b++;
}
$this->playerinfo[$i]["name"] = $result;
*/
$temparray2 = explode (" ", $temparray[0]);
$this->playerinfo[$i]["frags"] = $temparray2[0];
$this->playerinfo[$i]["ping"] = $temparray2[1];
$i++;
}
// Standardize. For easyer info.
$this->serverinfo["address"] = $this->caddress . ":" . $this->cport;
$this->serverinfo["name"] = $this->serverinfo["hostname"];
$this->serverinfo["moddir"] = $this->serverinfo["gamename"];
$this->serverinfo["maxplayers"] = $this->serverinfo["maxclients"];
$this->serverinfo["map"] = $this->serverinfo["mapname"];
$this->serverinfo["typeofserver"] = "Unknown";
$this->serverinfo["serveros"] = "Unknown";
if ($this->serverinfo["needpass"] == 1) { $this->serverinfo["locked"] = "true"; }
else { $this->serverinfo["locked"] = "false"; }
}
/**
* Function parseServerstatQ3()
* Requests the server info from the server and parses it down
*/
function parseServerstatQ3()
{
fwrite($this->fp,$this->commands[$this->cgametype]["Serverinfo"]);
$header=fgets($this->fp, 20);
//now we get the the servers statusdata in one line
$this->serverinfo["allinfo"] = fgets($this->fp, 1500);
// echo $returnstring; // DEBUG
$temparray = explode ("\\", $this->serverinfo["allinfo"]);
$i = 1;
while($i <= sizeof($temparray))
{
$this->serverinfo[$temparray[$i++]] = $temparray[$i++];
}
// Now recieve the player info
socket_set_blocking($this->fp,0);
$do = true;
$i = 0;
while ($do)
{
$temp = fgets($this->fp, 100);
if ($temp == "")
{
$do = false;
}
else
{
$tempplayers[$i] = $temp;
}
$i++;
}
$this->pcount = sizeof($tempplayers);
// Resolve the player info
$i = 0;
while($i <= $this->pcount-1)
{
$this->playerinfo[$i]["index"] = "$i";
$temparray = explode ("\"", $tempplayers[$i]);
$this->playerinfo[$i]["namecolored"] = $temparray[1];
//Remove colortags
$result = "";
$b = 0;
while($b <= strlen($temparray[1]))
{
$str = substr($temparray[1], $b, 1);
if ($str == "^")
{
$b++;
}
else
{
$result .= $str;
}
$b++;
}
$this->playerinfo[$i]["name"] = $result;
$temparray2 = explode (" ", $temparray[0]);
$this->playerinfo[$i]["frags"] = $temparray2[0];
$this->playerinfo[$i]["ping"] = $temparray2[1];
$i++;
}
// Standardize. For easyer info.
$this->serverinfo["address"] = $this->caddress . ":" . $this->cport;
$this->serverinfo["name"] = $this->serverinfo["sv_hostname"];
$this->serverinfo["moddir"] = $this->serverinfo["gamename"];
$this->serverinfo["players"] = $this->serverinfo["sv_privateClients"];
$this->serverinfo["maxplayers"] = $this->serverinfo["sv_maxclients"];
$this->serverinfo["map"] = $this->serverinfo["mapname"];
$this->serverinfo["typeofserver"] = "Unknown";
$this->serverinfo["serveros"] = "Unknown";
$this->serverinfo["players"] = $this->pcount;
if ($this->serverinfo["g_needpass"] == 1) { $this->serverinfo["locked"] = "true"; }
else { $this->serverinfo["locked"] = "false"; }
}
/**
* Function parseServerstatUT()
* Requests the server info from the server and parses it down
*/
function parseServerstatUT()
{
fwrite($this->fp,$this->commands[$this->cgametype]["Serverinfo"]);
// Get server address and Port
$do = true;
$result = "";
while($do)
{
$str = fread($this->fp,1);
$result .= $str;
if ( substr($result,strlen($result)-7) == $this->commands[$this->cgametype]["TheEnd"] ) $do = false;
}
$this->serverinfo["allinfo"] = $result;
// Remove the \final\ from the var list
$this->serverinfo["allinfo"] = substr($this->serverinfo["allinfo"],0,strlen($this->serverinfo["allinfo"])-7);
// Now resolve the info
$temparray = explode ("\\", $this->serverinfo["allinfo"]);
$i = 1;
while($i <= sizeof($temparray))
{
$this->serverinfo[$temparray[$i++]] = $temparray[$i++];
}
// Standardize. For easyer info.
$this->serverinfo["address"] = $this->caddress . ":" . $this->cport;
$this->serverinfo["name"] = $this->serverinfo["hostname"];
$this->serverinfo["modname"] = $this->serverinfo["gamename"];
$this->serverinfo["players"] = $this->serverinfo["numplayers"];
$this->serverinfo["map"] = strtolower($this->serverinfo["mapname"]);
$this->serverinfo["version"] = $this->serverinfo["gamever"];
$this->serverinfo["typeofserver"] = "Unknown";
$this->serverinfo["serveros"] = "Unknown";
if ($this->serverinfo["password"] != "False") { $this->serverinfo["locked"] = "true"; }
else { $this->serverinfo["locked"] = "false"; }
// Get those users fixed up
for($i=0; $i <= $this->serverinfo["numplayers"]; $i++)
{
$this->playerinfo[$i]["index"] = $i;
$this->playerinfo[$i]["name"] = $this->serverinfo["player_".$i];
$this->playerinfo[$i]["ping"] = $this->serverinfo["ping_".$i];
$this->playerinfo[$i]["frags"] = $this->serverinfo["frags_".$i];
$this->playerinfo[$i]["team"] = $this->serverinfo["team_".$i];
$this->playerinfo[$i]["skin"] = $this->serverinfo["skin_".$i];
$this->playerinfo[$i]["mesh"] = $this->serverinfo["mesh_".$i];
$this->playerinfo[$i]["face"] = $this->serverinfo["face_".$i];
$this->playerinfo[$i]["ngsecret"] = $this->serverinfo["ngsecret_".$i];
//Unset those variables so the will stop being in the way.
unset( $this->serverinfo["player_".$i] );
unset( $this->serverinfo["ping_".$i] );
unset( $this->serverinfo["frags_".$i] );
unset( $this->serverinfo["team_".$i] );
unset( $this->serverinfo["skin_".$i] );
unset( $this->serverinfo["mesh_".$i] );
unset( $this->serverinfo["face_".$i] );
unset( $this->serverinfo["ngsecret_".$i] );
unset( $this->serverinfo[""] );
}
}
}
?>