<?
//    **********************************************************************************************
//    Class Quake3
//    Author : Henrik Schack ( http://henrik.schack.dk/ )
// 
//    Changelog:
//     Version 1.00        03/13/2001 Initial release
//    A utilityclass (PHP4 only) to do serverstatus-queries against Quake3Arena servers
//
//    Syntax:
// 
//    Function getServerStatus(serveraddress,serverport,timeout)
//    Get player/servervar info from server
//
//    All results are returned in membervariables:
//
//
//    Demosource is available at http://www.gameserver.dk/
//    **********************************************************************************************


//
//    Function used to sort players by frags
//    Needs to be defined globally in order for usort to call it
//     

function fragsort ($a$b) {   
    if (
$a["frags"] == $b["frags"]) return 0;
    if (
$a["frags"] > $b["frags"]) {
        return -
1;
    } else {
        return 
1;
    }
}    

Class 
Quake3 {
    var 
$m_playerinfo        ="";        // Info about players
    
var $m_servervars        ="";        // Info about the server 
    
    //
    // Get exact time, used for timeout counting
    //
    
function timenow() {
        return 
doubleval(ereg_replace('^0\.([0-9]*) ([0-9]*)$','\\2.\\1',microtime()));
    }    
    
    
//
    // Function to remove funny characters from playernames
    //
    
function removefunchars($data) {
        
$result="";
        
$skipnextchar=false;
        for (
$i=0;$i<strlen($data);$i++) {
            if (!
$skipnextchar) {
                
$currentchar=ord(substr($data,$i,1));
                if ((
$currentchar==27) || ($currentchar==94)) {
                    
$skipnextchar=true;
                } else {
                    if ((
$currentchar>=32) && ($currentchar<=127)) $result=$result.chr($currentchar);
                    if ((
$currentchar>=160) && ($currentchar<=255)) $result=$result.chr($currentchar-128);
                }
            } else {
                
$skipnextchar=false;
            }
        }
        return 
$result;
    }

    
//
    // Read raw data from server
    //
    
function getServerData($command,$serveraddress,$portnumber,$waittime) {
        
$serverdata        ="";
        
$serverdatalen=0;
        
        if (
$waittime500$waittime500;
        if (
$waittime>2000$waittime=2000;
        
$waittime=doubleval($waittime/1000.0);

        if (!
$cssocket=fsockopen("udp://".$serveraddress,$portnumber,$errnr)) {
            
$this->errmsg="No connection";
            return 
"";
        }
        
socket_set_blocking($cssocket,true);
        
socket_set_timeout($cssocket,0,500000);
        
fwrite($cssocket,$command,strlen($command));    
        
// Mark
        
$starttime=$this->timenow();
        do {
            
$serverdata.=fgetc($cssocket);
            
$serverdatalen++;
            
$socketstatus=socket_get_status($cssocket);
            if (
$this->timenow()>($starttime+$waittime)) {
                
$this->errmsg="Connection timed out";
                
fclose($cssocket);
                return 
"";
            }
        } while (
$socketstatus["unread_bytes"] );
        
fclose($cssocket);
        return 
$serverdata;        
    }    


    
// **********************************************************************
    // getServerStatus
    // Read rules/setup from the gameserver into m_servervars
    // Return true if successful
    // **********************************************************************    
    
function getServerStatus($serveraddress,$portnumber,$timeout) {
        
        
$cmd="\xFF\xFF\xFF\xFFgetstatus\n";        
        
$serverdata=$this->getServerData($cmd,$serveraddress,$portnumber,$timeout);
        if (
strlen($serverdata)>20) {
            
$serverdata=substr($serverdata,20);
        } else {
            return 
false;
        }

        
$srvvars=substr($serverdata,0,strpos($serverdata,"\n"))."\\";
        
$players=substr($serverdata,strpos($serverdata,"\n")+1);
        
        
// Skip the last linefeed
        
$players=substr($players,0,strlen($players)-1);
        
        
// Split playerinfo and fill into array
        
$playercount=0;
        if (
strlen($players)) {
            
$playercollection=explode("\n",$players);
            while (list(
$key,$data) = each ($playercollection)) {
                
eregi("^([-0-9]+) ([-0-9]+) \"(.*)\"",$data,$player);
                
$this->m_playerinfo[$key]=array("frags"=>$player[1],"ping"=>$player[2],"name"=>$this->removefunchars($player[3]));
                
$playercount++;
            }
        }
        
// Fake servervar containing number of current players
        
$this->m_servervars["sv_currentclients"]=$playercount;
        
        if (
$playercount>0usort($this->m_playerinfo,"fragsort");

        
// Split servervars and fill into array
        
$name_tok strtok ($srvvars,"\\");
        
$val_tok  strtok ("\\");
        while (
strlen($name_tok)) {
            
$this->m_servervars[$name_tok]=$val_tok;
            
$name_tok strtok ("\\");
            
$val_tok  strtok ("\\");
        }
        return 
true;
    }    
}
?>