Language: EN FR PT ES NL DE SV RU
<?php

 
declare(ticks 1);
if (! 
function_exists('pcntl_fork')) die('PCNTL functions not available on this PHP installation');
echo 
"Start of program!\n";
if (isset(
$argv[1])) {
    if (
$argv[1] == 'verbose' || $argv[1] == '-v') {
        
$verbose 1;
    } elseif (
$argv[1] == 'vv' || $argv[1] == '-vv') {
        
$verbose 2;
    } else {
        
$verbose 0;
    }
} else {
    
$verbose 0;
}


require_once(
"/home/pugbot/tracker/q3query.php");
require_once(
"/home/pugbot/tracker/align.php");
include(
"/home/pugbot/tracker/dbconfig.php");

// connect to db

function mcrypt($data) {
    
$key 'ASsadfEYHr345REtrte74hHFGDsret7245dFDGDFer3D7hhs4467H85p';
    
$iv '82952684';
    
$todec base64_decode($data);
    
$decrypted mcrypt_decryptMCRYPT_BLOWFISH$key$todecMCRYPT_MODE_CBC$iv );
    return 
$decrypted;
}

function 
send_rcon($command$server_host$server_port$rcon_pass) {
    
    if (
$server_host == "" || !isset($server_host)) {
        return 
FALSE;
    }
    
    
// Set server, port and RCON for server to be used.
    
$q = new q3query($server_host$server_port);
    
$q->set_rconpassword($rcon_pass);

    
// Make sure variables are clean.
    
$failed 0;
    
$rconresponse 0;
    while (
$failed != && !($rconresponse)) {
        
$q->rcon($command);
        
$rconresponse $q->get_response();
        
//echo $rconresponse;
        
$failed++;
        if (!(
$rconresponse)) { sleep(1); }
    }
    if (
$failed == 8) {
        return 
FALSE;
    } else {
        return 
$rconresponse;
    }
}

function 
sig_handler($signo) {
    if(
$signo == SIGUSR1) {
        
// Handle SIGUSR1
        
echo "SIG: ".$signo."\n";
    } elseif(
$signo == SIGTERM) {
        
// Handle SIGTERM
        
echo "SIG: ".$signo."\n";
        
$sigterm true;
    } elseif(
$signo == SIGHUP) {
        
// Handle SIGHUP
        
echo "SIG: ".$signo."\n";
        
$sighup true;
    }
}

// Function for thread to track each server
function track_server($server_to$pid$verbose) {
    
    
// Setup the align class for thread
    
$align = new align($verbose);

    
// Include DB info
    
include("/home/pugbot/tracker/dbconfig.php");
    
    
//$align->align_d_echo_a($db);
    
    // Make the database connection for this thread.
    
$server_connection mysql_connect($db['host'], $db['user'], $db['pass'], TRUE) or die ("Unable to connect!");
    
mysql_select_db($db['db']) or die ("Unable to select database!");
    
    
startserver:
    
// setup the vars
    
$server_id     $server_to;
    
$server_query  mysql_query("SELECT * FROM `servers` WHERE `server_id`='$server_id' AND `status`!='RCONFAIL'") or die("unable to query table! track_server, line: 84 ".$server_id);
    
$server        mysql_fetch_array($server_query);

    
$align->align_s_echo_a(array("SERVER_ID"=>$server_id,"TRACKING!"=>"STARTED!"));    
    
    if (!
$server) {
        
$align->align_s_echo_a(array("SERVER_ID"=>$server_id,"RCON!"=>"FAILED!"));    
    } else {
    
    
$server_host   gethostbyname($server['host']);
    
$server_port   $server['port'];
    
$rcon_pass_enc $server['rcon'];
    
$rcon_pass     mcrypt($rcon_pass_enc);
    
$rcon_pass     trim($rcon_pass,"\0");
    
$thread_name   "Thread for server ID ".$server_id;
    
    
// Set the process title (shows up in "ps aux")
    
setproctitle($thread_name);
    
    
// Infinite tracking loop, never stop, at least try not to.
    
while (TRUE) {
        
        
// Like to sleep a lot with urt rcon commands to help prevent rcon flood conditions.
        
sleep(1);

        
// Set the pid in the servers table
        
mysql_query("UPDATE `servers` SET `tracker_pid`=0 WHERE `server_id`='$server_id' ");
        
        
// Echo to console some basic status information.
        
$align->align_d_echo_a(array("SERVER_ID"=>$server_id,"UPDATING!"=>"STARTED!"));
        
        
// Set the time for this pass on tracking
        
$start_time time();
        
        
// fetch connected players via rcon
        
$command         "status";
        
$status_response send_rcon($command$server_host$server_port$rcon_pass);
        
        
/* If statements for checking $status_response */
        
if (isset($status_response)) {
            if (
$status_response === FALSE || $status_response == FALSE) {
                
mysql_query("UPDATE `servers` SET `status`=\"RCONFAIL\" WHERE `server_id`='$server_id' ");
                
// Some debug output
                
$align->align_s_echo_a(array("SERVER_ID"=>$server_id,"STATUS!"=>"FAILED!"));
                goto 
startserver;
            } else {
                
// Some debug output
                
$align->align_s_echo_a(array("SERVER_ID"=>$server_id,"STATUS!"=>"SUCCEEDED!"));
                
//echo $status_response;
            
}
        } else {
            
// Some debug output
            
$align->align_s_echo_a(array("SERVER_ID"=>$server_id,"STATUS!"=>"FAILED!"));
            goto 
startserver;
        }
            
        
// Like to sleep a lot with urt rcon commands to help prevent rcon flood conditions.
        
sleep(1);
        
        
// Some magic TheRick found/came up with.
        
preg_match_all('/^\s+(\S{1,2}?)\s+(\S{1,4})\s+(\S{1,3})\s+(.*)\^7\s+(\S+)\s+(\S+):(\S+)\s+(\S+)\s+(\S+)$/m'$status_response,$type);
        
preg_match('/^map:\s+(.*)$/m'$status_response$aMap);
        
        
// This line sets the map on the server from the rcon status
        
if (isset($aMap[1])) {
            
$map $aMap[1];
            
mysql_query(" UPDATE `servers` SET `current_map`='$map' WHERE `server_id`='$server_id' ");
        } else {
            
$align->align_v_echo_a($aMap);
            
$align->align_v_echo_a(array("SERVER_ID"=>$server_id,"STATUS"=>$status_response));
        }

        
// Setup rcon to grab sv_hostname
        
$command "sv_hostname";
        
        
// Send sv_hostname command
        
$sv_hostname_response send_rcon($command$server_host$server_port$rcon_pass);
        
        
sleep(1);
        
        
$sv_first_split split("is:\""$sv_hostname_response);
        if (isset(
$sv_first_split[1])) { 
            
$sv_second_split split("\^7\" default:",$sv_first_split[1]);
            
$sv_hostname mysql_real_escape_string($sv_second_split[0]);
            
$align->align_v_echo_a(array("SERVER_ID"=>$server_id,"sv_hostname"=>$sv_hostname_response));
        } else {
            
$align->align_v_echo_a(array("SERVER_ID"=>$server_id,"sv_hostname"=>$sv_hostname_response));
            
$sv_hostname "Bad server name query";
            
// Set num players and sv_hostname in servers database
            
mysql_query("UPDATE `servers` SET `name`='$sv_hostname' WHERE `server_id`='$server_id'");
            goto 
startserver;
        }
                
        
// Setup rcon to grab sv_hostname
        
$command "g_gametype";
        
        
// Send sv_hostname command
        
$gametype_response send_rcon($command$server_host$server_port$rcon_pass);
        
        
sleep(1);
        
        
$gametype_first_split split("is:\""$gametype_response);
        if (isset(
$gametype_first_split[1])) {
            
$gametype_second_split split("\^7",$gametype_first_split[1]);
            
$gametype $gametype_second_split[0];
        } else {
            
$align->align_v_echo_a(array("SERVER_ID"=>$server_id,"g_gametype"=>$gametype_response));
            
$gametype 0;
            
// Set num players and sv_hostname in servers database
            
mysql_query("UPDATE `servers` SET `gametype`='$gametype' WHERE `server_id`='$server_id'");
            goto 
startserver;
        }
            
        
// Clear the user records from temp table
        
mysql_query"DELETE FROM `tracker_active` WHERE `server_id`='$server_id'" );
            
        
// Count the number of players in server, by counting the number of pids
        
$count count($type[1]);
        
        
// Loop for each player found
        
for( $i=1$i<=$count ;$i++ ) {
                
            
// Player slots start at zero, but loop starts at 1, subtract 1.
            
$num     $i-1;
                
            
// Player pid
            
$pid     $type[1][$num];
                
            
// Player score
            
$score   $type[2][$num];
                
            
// Player ping
            
$ping    $type[3][$num];
                
            
// Player name, must be mysql escaped as a name could actually be an injection point
            
$name    mysql_real_escape_string($type[4][$num]);
                
            
// Lastmsg
            
$lastmsg $type[5][$num];
                
            
// Player's IP
            
$ip      $type[6][$num];
                
            
// Players net_port
            
$port    $type[7][$num];
                
            
// Players qport
            
$qport   $type[8][$num];
                
            
// Players connected rate
            
$rate    $type[9][$num];

            
// split up the IP into 4 parts (octets)
            
$ip_array explode(".",$ip);
            
$ip1 $ip_array[0];
            
$ip2 $ip_array[1];
            
$ip3 $ip_array[2];
            
$ip4 $ip_array[3];

            
// get the ipkey of IP
            
$ipkey = (($ip1*256+$ip2)*256+$ip3)*256 $ip4;
            
$truename stripslashes($name);
            
// Setup the rcon dumpuser for this pid
            
$command "dumpuser \"".$truename."\"";
                
            
// Send dumpuser rcon command
            
$dump_response send_rcon($command$server_host$server_port$rcon_pass);
                
            
// Sleep some more after rcon command
            
sleep(1);
                
            
// Set guid blank to make sure there isn't a left over in memory
            
$guid "";
            
            
// Do the same for sacc_maxpackets
            
$sacc_maxpackets 0;
            
            
// Split the rcon response from the dumpuser command
            
$peices preg_split("/[\s,]+/"$dump_response, -1PREG_SPLIT_NO_EMPTY);

            
// Foreach piece in $pieces, run this loop, which gets guid and sacc_maxpackets from dumpuser
            
foreach ($peices as $key=>$piece) {
                
                
// If the piece == guid then set the guid
                
if ($piece == "cl_guid") {
                
                    
// Make sure to escape the guid, adding +1 to the key to get the value
                    
$guid mysql_real_escape_string($peices[($key 1)]);
                
                    
// Some debug output
                    //echo $align->left("SERVER_ID", 10).": ".$align->left($server_id, 7).$align->left("NAME",15).": ".$align->left($name, 0).$align->left("GUID FOUND", 0).": ".$guid."\n";
                
}
            
                
// If the piece == sacc_maxpackets then set the variable
                
if ($piece == "sacc_maxpackets") {
            
                    
// Set maxpackets, adding +1 to the key to get the value
                    
$sacc_maxpackets $peices[($key 1)];
                
                    
// Some debug output
                    
$align->align_s_echo_a(array("SERVER_ID"=>$server_id,"SACC FOUND"=>$name));
                }
            }
            
            if (!
strpos($dump_response,"is not on the") && $guid != "") {
                    
// If the IP != the ip of the GTV bot then add to the database
                
if ($ip != "208.93.223.133") {
                
                    
// Some debug output
                    
$align->align_d_echo_a(array("SERVER_ID"=>$server_id,"NAME"=>$name,"ADDING IP TO DB"=>$ip));
                
                    
// Make the mysql query to add the player to the database
                    
mysql_query(" INSERT INTO `ircpug`.`tracker_active` (`key`, `server_id`, `pid`, `score`, `ping`, `name`, `lastmsg`, `ip`,`ipkey`, `port`, `qport`, `rate`, `GUID`, `sacc_maxpackets`) VALUES (NULL, '$server_id', '$pid', '$score', '$ping', '$name', '$lastmsg', '$ip','$ipkey', '$port', '$qport', '$rate', '$guid', '$sacc_maxpackets'); ");
                
                } else {
                
                    
// Some debug output
                    
$align->align_d_echo_a(array("SERVER_ID"=>$server_id,"NAME"=>$name,"*NOT ADDING IP TO DB"=>$ip));
                }
            } elseif (
$guid == "") { 
                if (!isset(
$sacc)) { $sacc 0; }
                
$align->align_v_echo_a(array("SERVER_ID"=>$server_id,"NAME"=>$name,"SACC"=>$sacc,"SLOT"=>$pid,"GUID BLANK"=>$dump_response));
            } else { 
                if (!isset(
$sacc)) { $sacc 0; }
                
$align->align_v_echo_a(array("SERVER_ID"=>$server_id,"NAME"=>$name,"SACC"=>$sacc,"SLOT"=>$pid,"GUID NOT"=>$dump_response));
            }
        }
            
        
// Select all the players we just added to the temp database table for this server
        
$update_players mysql_query("SELECT * FROM `tracker_active` WHERE `server_id`='$server_id'");
    
        
// Get num players in server
        
$server_num_players mysql_num_rows($update_players);
    
        
// Set num players and sv_hostname in servers database
        
mysql_query("UPDATE `servers` SET `gametype`='$gametype',`name`='$sv_hostname',`players`='$server_num_players' WHERE `server_id`='$server_id'");
    
        
// If the query failed, output some debug info, else query successful update the new temp table
        
if (!$update_players) {
        
            
// Output some debug info
            
$align->align_s_echo("FAILED SERVER_ID",$server_id);
        
        } else {
        
            
// Delete all players from the second temp table for this server
            
mysql_query"DELETE FROM `tracker_status` WHERE `server_id`='$server_id'" );
        
            
// Run this loop for each player, inserting them into the second temp table
            
while ($player_info mysql_fetch_array($update_players)) {
            
                
//$align->align_d_echo_a($player_info);
                // Set the variables to be set in the second temp table
                
$name            mysql_real_escape_string($player_info['name']);
                
$server_id       $player_info['server_id'];
                
$pid             $player_info['pid'];
                
$score           $player_info['score'];
                
$ping            $player_info['ping'];
                
$lastmsg         $player_info['lastmsg'];
                
$ip              $player_info['ip'];
                
$ipkey           $player_info['ipkey'];
                
$port            $player_info['port'];
                
$qport           $player_info['qport'];
                
$rate            $player_info['rate'];
                
$guid            mysql_real_escape_string($player_info['GUID']);
                
$sacc_maxpackets $player_info['sacc_maxpackets'];
            
                
// Add the player to the second temp table here, second temp table gets handled by main thread from here
                
mysql_query(" INSERT INTO `ircpug`.`tracker_status` (`key`, `server_id`, `pid`, `score`, `ping`, `name`, `lastmsg`, `ip`,`ipkey`, `port`, `qport`, `rate`, `GUID`, `sacc_maxpackets`) VALUES (NULL, '$server_id', '$pid', '$score', '$ping', '$name', '$lastmsg', '$ip','$ipkey', '$port', '$qport', '$rate', '$guid', '$sacc_maxpackets'); ");
            }
        }
    
        
// Count how long it took to track all players on server
        
$total_time time() - $start_time;
    
        
// Some debug output
        
$align->align_d_echo_a(array("SERVER_ID"=>$server_id,"DONE UPDATING!"=>"TOOK:","TIME"=>$total_time));
    }
    }
}

function 
keep_tracking($verbose) {
    include(
"/home/pugbot/tracker/dbconfig.php");
    
$align = new align($verbose);
    while (
TRUE) {
        
$start_time time();

        
$align->align_s_echo("STARTING SERVERS!",$start_time);
        
        
$connection mysql_connect($db['host'], $db['user'], $db['pass'], TRUE) or die ("Unable to connect!");
        
mysql_select_db($db['db']) or die ("Unable to select database! keep_tracking".$db['db']);
        
        
// grab players in servers
        
$status_q mysql_query(" SELECT * FROM `tracker_status` ");
        
        
// Get all servers and try to check on the pid
        
$servers_q mysql_query(" SELECT * FROM `servers` WHERE `status`!='RCONFAIL'");
        
        
// For each server get pid n check
        
while ($server mysql_fetch_array($servers_q)) {
            
            
// Set the $pid
            
$pid_count $server['tracker_pid'];
            
            
// Set server_id
            
$server_id $server['server_id'];
            
            if (
$pid_count 20) {
                
                
$pid pcntl_fork();
                if (
$pid == 0) {
                    
$align->align_s_echo("Forked child",$pid);
                } elseif (
$pid == -1) {
                    
$align->align_s_echo("Failed to fork!",$pid);
                } else {
                    
$align->align_s_echo("Child started!",$pid);
                    
track_server($server_id$pid$verbose);
                exit(
35);
                }
                
$pid_count 0;
            } else {
                
// add +1 to the pid
                
$pid_count++;
            }
            
            
// update the pid in the servers table
            
mysql_query("UPDATE `servers` SET `tracker_pid`='$pid_count' WHERE `server_id`='$server_id'");

            
// Output some debug info
            
$align->align_s_echo("TRACKER CHECKING!",$server_id);
            
//$align->align_d_echo_a(array("SERVER_ID"=>$server_id,"TRACKER CHECKING!"=>"COMPLETE!"));
        
}

        
// start timer
        
$timer_start_urtplayers time();

        
// for each player, do the following
        
while ($status mysql_fetch_array($status_q)) {
            
// setup the vars
            
$name            mysql_real_escape_string($status['name']);
            
$server_id       $status['server_id'];
            
$pid             $status['pid'];
            
$score           $status['score'];
            
$ping            $status['ping'];
            
$lastmsg         $status['lastmsg'];
            
$ip              $status['ip'];
            
$ipkey           $status['ipkey'];
            
$port            $status['port'];
            
$qport           $status['qport'];
            
$rate            $status['rate'];
            
$guid            mysql_real_escape_string($status['GUID']);
            
$sacc_maxpackets $status['sacc_maxpackets'];
            
$ip_search       mysql_query(" SELECT `tuser_id` FROM `tracker_aliases` WHERE `ip`='$ip'  AND `alias`='$name' AND `GUID`='$guid' AND `server_id`='$server_id'");
            
$user_array      mysql_fetch_array($ip_search);
            
$tuser           $user_array[0];
            
$rows            mysql_num_rows($ip_search);
            
$align->align_d_echo_a(array("SERVER_ID"=>$server_id,"TRACKER UPDATING!"=>"STARTING!"));
            
            
// if it matches then do this stuff
            
if ($rows != 0) {
                
// check if alias has been on this IP before
                
$alias_check mysql_query(" SELECT * FROM `tracker_aliases` WHERE `alias`='$name' AND `ip`='$ip' AND `GUID`='$guid' AND `server_id`='$server_id'");

                
// if it has then update the counter
                
$rows mysql_num_rows($alias_check);
                if (
$rows 0) {
                    
mysql_query(" UPDATE `tracker_aliases` SET `counter`=`counter`+1 , `last_time`='$start_time' WHERE `tuser_id`='$tuser' ");
                } elseif (
$rows == && $guid != "") {
                    
mysql_query(" INSERT INTO `tracker_aliases`(`alias`,`ipkey`,`counter`,`ip`,`GUID`,`sacc_maxpackets`,`server_id`,`first_time`) VALUES('$name','$ipkey','0','$ip','$guid','$sacc_maxpackets','$server_id','$start_time') ");
                }
            } elseif (
$rows == 0) {
                
mysql_query(" INSERT INTO `tracker_aliases`(`alias`,`ipkey`,`counter`,`ip`,`GUID`,`sacc_maxpackets`,`server_id`,`first_time`) VALUES('$name','$ipkey','0','$ip','$guid','$sacc_maxpackets','$server_id','$start_time') ");
            }
        }
        
$total_time time() - $start_time;
        
$align->align_d_echo_a(array("SERVER_ID"=>$server_id,"TRACKER UPDATING!"=>"STARTING!","TIME"=>$total_time));
        
sleep(5);
        
mysql_close($connection);
    }
}


pcntl_signal(SIGUSR1"sig_handler");
pcntl_signal(SIGTERM"sig_handler");
pcntl_signal(SIGHUP"sig_handler");

//$connection = mysql_connect($db['host'], $db['user'], $db['pass']) or die ("Unable to connect!");
//mysql_select_db($db['db']) or die ("Unable to select database!");

/*
// grab server information
$server_q = mysql_query(" SELECT * FROM `servers` WHERE `status`<>'badpass' ");

$server_id = array();
// for each server, do the following
while ($server = mysql_fetch_array($server_q)) {
    $server_id[] = $server['server_id'];
}
mysql_close($connection);
*/
/* foreach ($server_id as $server_to) {
    $pid = pcntl_fork();

    if ($pid == 0) {
        echo "Forked child #{$pid}\n\n";
    } elseif ($pid == -1) {
        echo "Failed to fork! #{$pid}\n\n";
    } else {
        echo "Child! {$pid} =====================================================\n";
        track_server($server_to, $pid);
           exit(35);
    }
    
} */
setproctitle  "Slacks multithreaded tracker"  );
keep_tracking($verbose);

print 
"Done! :^) PID: {$pid} \n\n";
?>