<?
$osp_colors 
= array(
    
=> "#000000",
    
=> "#ff0000",
    
=> "#00ff00",
    
=> "#ffff00",
    
=> "#0000ff",
    
=> "#00ffff",
    
=> "#ff00ff",
    
=> "#ffffff",
    
=> "#ff7f00",
    
=> "#7f7f7f",
    
10 => "#bfbfbf",
    
11 => "#bfbfbf",
    
12 => "#007f00",
    
13 => "#7f7f00",
    
14 => "#00007f",
    
15 => "#7f0000",
    
16 => "#7f3f00",
    
17 => "#ff9919",
    
18 => "#007f7f",
    
19 => "#7f007f",
    
20 => "#007fff",
    
21 => "#7f00ff",
    
22 => "#3399cc",
    
23 => "#ccffcc",
    
24 => "#006633",
    
25 => "#ff0033",
    
26 => "#b21919",
    
27 => "#993300",
    
28 => "#cc9933",
    
29 => "#999933",
    
30 => "#ffffbf",
    
31 => "#ffff7f"
);

function 
getstatus($server$port 27960)
{
    if (!(
$fd = @fsockopen("udp://$server"$port$errno$errstr3)))
        return 
FALSE;

    
stream_set_timeout($fd30);
    
    
# challenge?
    
    
fwrite($fd"\xff\xff\xff\xffgetstatus " rand());
    
    
# getstatus reply should always come as a single (possibly
    # fragmented) datagram
    
if (!($buf = @fread($fd4096))) {
        echo(
"failed");
        return 
FALSE;
    }

    
$parts explode("\n"$buf);

    if (
$parts[0] != "\xff\xff\xff\xffstatusResponse") {
        echo(
"bad response");
        return 
FALSE;
    }
    
    
# build an array of all the serverinfo keys
    
$infostring explode("\\"$parts[1]);
    
array_shift($infostring);
    
    
$side 0;
    
    while (list(
$idx$str) = each($infostring)) {
        if (
$side == 0)
            
$key $str;
        else
            
$info[$key] = $str;

        
$side ^= 1;
    }
    
    
# build an array of all the players
    # start by shifting off the response header and the serverinfo
    
array_shift($parts);
    
array_shift($parts);
    
    
# and then looping through what's left
    
while (list($idx$str) = each($parts)) {
        if (
$str == "")
            break;

        
$playerparts explode("\""$str);
        
$playerinfo $playerparts[0];
        
$name $playerparts[1];
        
        
$scoreping explode(" "$playerinfo);
        
$score $scoreping[0];
        
$ping $scoreping[1];
        
        
# try to get slot and team info
        
list($slot$team) = correlateplayerinfo($info$idx);

        
$playerlist[$idx]['slot'] = $slot;
        
$playerlist[$idx]['team'] = $team;
        
$playerlist[$idx]['score'] = $score;
        
$playerlist[$idx]['ping'] = $ping;
        
$playerlist[$idx]['name'] = $name;
    }

    return array(
info => $infoplayers => $playerlist);
}

function 
correlateplayerinfo($info$num)
{
    if (
$info['P'] != '') {
        
$infonum 0;
        for (
$x 0$x strlen($info['P']); $x++) {
            
$cur $info['P'][$x];
            
            if (
$cur == '-')
                continue;
            
            if (
$infonum == $num)
                return array(
$x$cur);
            
            
$infonum++;
        }
    } else if (
$info['Players_Allies'] != '' || $info['Players_Axis'] != '') {
        
# This method of listing players isn't accurate.  If a
        # spectator or connecting client is in a slot where players
        # who are actually on a team follow, it'll be impossible to
        # match things up properly.  As such, I can't be arsed to
        # actually support this right now.
    
}
    return array(-
1, -1);
}

function 
colorize($text)
{
    global 
$osp_colors;

    
$curcolor = -1;
    
$nextcolor 7;
    
    for (
$x 0$x strlen($text); $x++) {
        if (
$text[$x] == '^' && $text[$x 1] != '^') {
            
$nextcolor = (ord($text[$x 1]) + 16) & 31;
            
$x++;
            continue;
        }
        if (
$curcolor != $nextcolor) {
            if (
$curcolor != -1)
                
$buf .= "</font>";
            
$curcolor $nextcolor;
            
$buf .= sprintf("<font color=\"%s\">"$osp_colors[$curcolor]);
            
        }
        
$buf .= htmlspecialchars($text[$x]);
    }

    if (
$curcolor != -1)
        
$buf .= "</font>";
    
    return 
$buf;
}

function 
teamname($num)
{
    switch (
$num) {
        case 
0:
            return 
"<font color=\"#ffff00\">Connecting</font>";
        case 
1:
            return 
"<font color=\"#ff0000\">Axis</font>";
        case 
2:
            return 
"<font color=\"#0000ff\">Allies</font>";
        default:
            return 
"<font color=\"#ffff00\">Spectators</font>";
    }
}

function 
sort_by_score_desc($a$b)
{
    if (
$a['score'] == $b['score'])
        return 
0;
    
    return (
$a['score'] > $b['score']) ? -1;
}

function 
sort_by_team($a$b)
{
    if (
$a['team'] == $b['team'])
        return 
0;
    
    return (
$a['team'] > $b['team']) ? : -1;
}

?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
 <title>blah!</title>
 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-15">
</head>
<body bgcolor="#101010" text="#ffffff">
<?

$status 
getstatus($_GET['server'], isset($_GET['port']) ? $_GET['port'] : 27960);

printf("Server: %s<br>\n"colorize($status['info']['sv_hostname']));
printf("Map: %s<br>\n"colorize($status['info']['mapname']));

echo 
"<table>\n";
echo 
"<tr><th>#</th><th>name</th><th>team</th><th>score</th><th>ping</th></tr>\n";

if (
$status['players']) {
    if (
$_GET['sort'] == 'team')
        
uasort($status['players'], sort_by_team);
    else if (
$_GET['sort'] != 'id')
        
uasort($status['players'], sort_by_score_desc);

    while (list(
$idx$curplayer) = each($status['players'])) {
#    echo "Player $idx: " . htmlentities(serialize($curplayer)) . "<br>\n";
        
printf(" <tr><td>%d</td><td>%s</td><td>%s</td><td>%d</td><td>%d</td></tr>\n",
            
$curplayer['slot'], colorize($curplayer['name']),
            
teamname($curplayer['team']), $curplayer['score'],
            
$curplayer['ping']);
    }
}
?>
</table>
</body>
</html>