<?php /* 
 
License details
---------------
 
AUTHOR(S):      David Weston (dweston@hotmail.co.uk)
 
LICENCE:        This program is free software; you can redistribute it and/or
                modify it under the terms of the GNU General Public License
                as published by the Free Software Foundation; either version 2
                of the License, or (at your option) any later version.
 
                This program is distributed in the hope that it will be useful,
                but WITHOUT ANY WARRANTY; without even the implied warranty of
                MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                GNU General Public License for more details.
 
                You should have received a copy of the GNU General Public License
                along with this program; if not, write to the Free Software
                Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
                MA 02110-1301, USA.
            
OTHER INFO:     Enjoy using my RCON/PHP script, this will help you a lot! :3
    
    []
    ||_______
    /_________\
    | F  M  N |
    -----------
    
*/
session_start();
 
/* Configuration */
define("ONEHOSTONLY", true);                   // Set this to true if you would use a username instead of server IP
 
define("DEFAULT_HOST", "localhost");           // If 'ONEHOSTONLY' is true, the hostname/IP.
define("DEFAULT_PORT", "7777");                // If 'ONEHOSTONLY' is true, the server's port.
define("DEFAULT_PASS", "changeme");            // If 'ONEHOSTONLY' is true, the RCON password.
define("USERNAME", "rcon");                    // If 'ONEHOSTONLY' is true, the username to login.
define("PASSWORD", md5("ohai"));               // If 'ONEHOSTONLY' is true, the password to login. [MD5]
 
/**********************************************************************/
?>
 
<style>
<!--
 
.navbar
{
    background-color: #AAA;
    padding-top: 4px;
    padding-bottom: 4px;
    font-family: 'Segoe UI', 'Verdana';
    font-size: 11px;
}
 
.navbar a:link, a:visited, a:active a:hover
{
    padding: 4px;
    text-decoration: none;
    background-color: #AAA;
    color: #DDD;
    border-left: 1px solid #AAA;
    border-right: 1px solid #AAA;
}
 
.navbar a:hover
{
    padding: 4px;
    text-decoration: none;
    background-color: #999;
    color: #FFF;
    border-left: 1px solid #CCC;
    border-right: 1px solid #CCC;
}
 
.sh_textbar
{
    background-color: #000000;
    color: #FFFF00;
    border: 0px;
    text-decoration: none;
    font-family: "Tahoma";
    font-size: 11px;
}
 
.sh_submitbutton
{
    background-color: #000000;
    color: #999999;
    border: 1px solid #666666;
    text-decoration: none;
    font-family: "Tahoma";
    font-size: 11px;
}
 
!-->
</style>
<title>SA:MP RCON Panel - created by Westie</title>
 
<?php
/**********************************************************************/
 
$stats = new SampStatsCore;
 
if(!isset($_SESSION['tmp_data']))
{
    if(ONEHOSTONLY == false)
    {
        $_SESSION['tmp_data'] = array
        (
            "logged_in"    => false,
            "serverip"    => "255.255.255.255",
            "servport"    => "1024",
            "servpass"    => "changeme",
            "history"    => array(),
            "connect"    => mktime()
        );
    }
    
    elseif(ONEHOSTONLY == true)
    {
        $_SESSION['tmp_data'] = array
        (
            "logged_in"    => false,
            "serverip"    => DEFAULT_HOST,
            "servport"    => DEFAULT_PORT,
            "servpass"    => DEFAULT_PASS,
            "history"    => array(),
            "connect"    => mktime()
        );
    }
}
 
if(ONEHOSTONLY == false)
{
    if(isset($_POST['serverip']))
    {
        $_SESSION['tmp_data']['logged_in'] = true;
        $_SESSION['tmp_data']['serverip'] = $_POST['serverip'];
        $_SESSION['tmp_data']['servport'] = $_POST['servport'];
        $_SESSION['tmp_data']['servpass'] = $_POST['servpass'];
        $_SESSION['tmp_data']['history'][] = "Logged on to ".$_SESSION['tmp_data']['serverip'].":"
                                            .$_SESSION['tmp_data']['servport']." at ".
                                            date("F j, Y, H:i", $_SESSION['tmp_data']['connect']).".";
    }
}
 
elseif(ONEHOSTONLY == true)
{
    if($_POST['username'] == USERNAME && md5($_POST['password']) == PASSWORD)
    {
        $_SESSION['tmp_data']['history'][] = "Logged on to ".$_SESSION['tmp_data']['serverip'].":"
                                            .$_SESSION['tmp_data']['servport']." at ".
                                            date("F j, Y, H:i", $_SESSION['tmp_data']['connect']).".";
        $_SESSION['tmp_data']['logged_in'] = true;
        $_SESSION['tmp_data']['serverip'] = DEFAULT_HOST;
        $_SESSION['tmp_data']['servport'] = DEFAULT_PORT;
        $_SESSION['tmp_data']['servpass'] = DEFAULT_PASS;
    }
}
 
if($_SESSION['tmp_data']['logged_in'] == false) { DisplayLoginForm(); exit; }
GetMain();
 
/**********************************************************************/
 
$_SESSION['tmp_env']['allowprint'] = array
(
    "cmdlist",
    "varlist"
);
 
$_SESSION['tmp_env']['printkey'] = array
(
    "loadfs", "unloadfs", "reloadfs", "kick", "ban", "unbanip", "banip", "echo",
    "gmx", "reloadbans", "reloadlogs", "gravity", "weather", "say", "changemode",
    "hostname", "password", "rcon_password"
);
 
$_SESSION['tmp_env']['printmessage'] = array
(
    "loadfs"        => "fs> %1 has been loaded.",
    "unloadfs"        => "fs> %1 has been unloaded.",
    "reloadfs"        => "fs> %1 has been reloaded.",
 
    "kick"            => "kick> %1 has been kicked from the server.",
    "ban"            => "ban> %1 has been banned from the server.",
    "banip"            => "ban> The IP '%1' has been banned from the server.",
    "banip"            => "ban> The IP '%1' has been unbanned from the server.",
 
    "changemode"    => "gm> The mode has been changed to '%1'.",
    "gmx"            => "gm> The current mode has been restarted.",
 
    "reloadbans"    => "serv> The bans file has been reloaded.",
    "reloadlogs"    => "serv> The logs file has been reloaded.",
 
    "gravity"        => "env> The server's gravity has been changed to %1.",
    "weather"        => "env> The server's weather has been changed to %1.",
 
    "say"            => "say> %1",
    "echo"            => "%1",
    
    "hostname"        => "serv> The server's name has been changed to '%1'.",
    "password"        => "serv> The server's password has been changed to '%1'",
    "rcon_password"    => "serv> The RCON password has been changed. Now, please "
                       ."log back in with the new RCON password."
);
 
/**********************************************************************/
 
function RawRCON($ip, $port, $password, $command, $return = true)
{
    $packet = 'SAMP';
    $packet .= chr(strtok($ip, '.'));
    $packet .= chr(strtok('.'));
    $packet .= chr(strtok('.'));
    $packet .= chr(strtok('.'));
    $packet .= chr($port & 0xFF);
    $packet .= chr($port >> 8 & 0xFF);
    $packet .= 'x';
    $packet .= chr(strlen($password) & 0xFF);
    $packet .= chr(strlen($password) >> 8 & 0xFF);
    $packet .= $password;
    $packet .= chr(strlen($command) & 0xFF);
    $packet .= chr(strlen($command) >> 8 & 0xFF);
    $packet .= $command;
 
    $sock = fsockopen('udp://'.$ip, $port, $errno, $errstr, 0);
    fwrite($sock, $packet);
    $returnstr = "";
    $cmd = explode(" ", $command, 2);
 
    if($return && in_array($cmd[0], $_SESSION['tmp_env']['allowprint']))
    {
        while(!feof($sock))
        {
            $str = fread($sock,128);
            $str = substr($str,13,strlen($str)-13);
            if(!$str) break;
            $returnstr .= $str."\r\n";
            $_SESSION['tmp_data']['history'][] = $str;
        }
    }
    elseif($return && in_array($cmd[0], $_SESSION['tmp_env']['printkey']))
    {
        $find = array("%0", "%1");
        $repl = array($cmd[0], $cmd[1]);
        $str = str_replace($find, $repl, $_SESSION['tmp_env']['printmessage'][$cmd[0]]);
        $returnstr .= $str;
        $_SESSION['tmp_data']['history'][] = $returnstr;
    }
    else
    {
        $find = array("%0", "%1");
        $repl = array($cmd[0], $cmd[1]);
        $returnstr = str_replace($find, $repl, "misc> Command has been sent, may be invalid. (".$cmd[0]." ".$cmd[1].")");
        $_SESSION['tmp_data']['history'][] = $returnstr;
    }
    
    fclose($sock);
    $returnstr .= "\r\n";
    return $returnstr;
}
 
/**********************************************************************/
 
function DisplayLoginForm()
{
    echo '<form name="form1" method="post" action="">';
    echo '<div align="center" style="font-family: \'Segoe UI\', \'Verdana\';">';
    echo '<div style="border: 1px solid #000; width: 500px;">';
    echo '<h3>Server RCON Panel</h3><div class="navbar">';
    echo '<strong><a href="'.$_SERVER['PHP_SELF'].'">Home</a> <a href="?action=history">History</a> <a href="?action=console">';
    echo 'RCON Console</a> <a href="?action=details">Details</a> <a href="?action=logout">Logout</a> <a href="?action=stats">';
    echo 'Server Stats</a></strong></div><div style="padding: 7px; font-family: \'Segoe UI\', \'Verdana\';';
    echo 'font-size: 12px;"><br />';
    
    echo $_SESSION['error']; $_SESSION['error'] = "";
    
    echo '<table width="295" border="0" cellpadding="3" cellspacing="3">';
    echo '<tr>';
    if(ONEHOSTONLY == false)
    {
        echo '<td width="136">Server IP</td>';
        echo '<td width="138"><input name="serverip" type="text" id="serverip"></td>';
        echo '</tr>';
        echo '<tr>';
        echo '<td width="136">Server Port</td>';
        echo '<td width="138"><input name="servport" type="text" id="servport"></td>';
        echo '</tr>';
        echo '<tr>';
        echo '<td width="136">Server Password</td>';
        echo '<td width="138"><input name="servpass" type="password" id="servpass"></td>';
        echo '</tr>';
    }
    elseif(ONEHOSTONLY == true)
    {
        echo "<span style=\"font-size: 11px;\">Pre-configured mode.</span>";
        echo '<td width="136">Username</td>';
        echo '<td width="138"><input name="username" type="text" id="username"></td>';
        echo '</tr>';
        echo '<tr>';
        echo '<td width="136">Password</td>';
        echo '<td width="138"><input name="password" type="password" id="password"></td>';
        echo '</tr>';
    }
    echo '<tr>';
    echo '<td>&nbsp;</td>';
    echo '<td>&nbsp;</td>';
    echo '</tr>';
    echo '<tr>';
    echo '<td colspan="2" align="center"><input name="connect" type="submit" id="connect" value="Connect to RCON"></td>';
    echo '</tr>';
    echo '</table>';
    echo '<br /><span style="font-size: 11px;">Created by <a href="http://www.westie-cat.co.cc">Westie</a>!</span></div></div>';
    echo '</form>';
}
 
/**********************************************************************/
 
function GetMain()
{
    global $stats;
    echo '<div align="center" style="font-family: \'Segoe UI\', \'Verdana\';">';
    echo '<div style="border: 1px solid #000; width: 500px;">';
    echo '<h3>Server RCON Panel</h3><div class="navbar">';
    echo '<strong><a href="'.$_SERVER['PHP_SELF'].'">Home</a> <a href="?action=history">History</a> <a href="?action=console">';
    echo 'RCON Console</a> <a href="?action=details">Details</a> <a href="?action=logout">Logout</a> <a href="?action=stats">';
    echo 'Server Stats</a></strong></div><div align="left" style="padding: 7px; font-family: \'Segoe UI\', \'Verdana\';';
    echo 'font-size: 12px;">';
    
    if($_GET['action'] == 'history')
    {
        echo "<strong>History</strong>";
        echo "<pre>";
        foreach($_SESSION['tmp_data']['history'] as $history)
        {
            echo $history.'<br />';
        }
        echo "</pre>";
    }
    elseif($_GET['action'] == 'details')
    {
        echo "<strong>Details</strong><br /><pre>";
        echo "Server IP:       ".$_SESSION['tmp_data']['serverip']."\r\n";
        echo "Server Port:     ".$_SESSION['tmp_data']['servport']."\r\n";
        echo "Connected time:  ".date("F j, Y, H:i", $_SESSION['tmp_data']['connect'])."\r\n";
        echo "\r\n";
        echo "Your IP address: ".$_SERVER['REMOTE_ADDR']."\r\n";
        echo "</pre>";
    }
    elseif($_GET['action'] == 'logout')
    {
        unset($_SESSION['tmp_data']);
        echo "You have been logged out. Please click <a href=\"".$_SERVER['PHP_SELF']."\">here</a> to log back in again.";
    }
    elseif($_GET['action'] == 'stats')
    {
        if(!$stats->IsServerActive($_SESSION['tmp_data']['serverip'], $_SESSION['tmp_data']['servport']))
        {
            echo "Sorry, the server is not online - so you can't use this.";
            echo "</div></div></div>";
            exit;
        }
        echo $stats->GetServerStats($_SESSION['tmp_data']['serverip'], $_SESSION['tmp_data']['servport']);
    }
    elseif($_GET['action'] == 'console')
    {
        if(!$stats->IsServerActive($_SESSION['tmp_data']['serverip'], $_SESSION['tmp_data']['servport']))
        {
            echo "Sorry, the server is not online - so you can't use this.";
            echo "</div></div></div>";
            exit;
        }
        
        if($_POST['shell_submit'])
        {
            $ip = $_SESSION['tmp_data']['serverip'];
            $port = $_SESSION['tmp_data']['servport'];
            $result = RawRCON($ip, $port, $_SESSION['tmp_data']['servpass'], $_POST['shell_textfield']);
            echo "<pre>".$result."</pre>";
        }
        else echo "<pre>I am waiting for your command.</pre>";
        
        echo '<form action="" method="post" name="form1">';
        echo '<input name="shell_textfield" type="text" class="sh_textbar" size="70">';
        echo '<input name="shell_submit" type="submit" id="shell_submit" value="Execute" class="sh_submitbutton">';
        echo '</form>';
    }
    else
    {
        echo "Welcome to your RCON Panel!";
        $result = $stats->IsServerActive($_SESSION['tmp_data']['serverip'], $_SESSION['tmp_data']['servport']);
        $what = $result ? "active" : "down";
        echo "<br />Connection: <strong>".$what."</strong>";
    }
    echo '</div><span style="font-size: 11px;">Created by <a href="http://www.westie-cat.co.cc">Westie</a>!</span></div></div>';
}
 
class SampStatsCore
{
    function IsServerActive($ip, $port)
    {
        $fp = @fsockopen('udp://'.$ip, $port, $errno, $errstr, 0);
        @socket_set_timeout($fp, 1);
        $packet = 'SAMP';
        $packet .= chr(strtok($ip, '.'));
        $packet .= chr(strtok('.'));
        $packet .= chr(strtok('.'));
        $packet .= chr(strtok('.'));
        $packet .= chr($port & 0xFF);
        $packet .= chr($port >> 8 & 0xFF);
        
        @fwrite($fp, $packet.'i');
        if(@fread($fp, 11)) { fclose($fp); return true; }
        else { fclose($fp); return false; }
    }
        
    function GetServerStats($ip, $port)
    {
        if($this->IsServerActive($ip, $port)) { $return = "I can't connect to the server. Please check the configuration."; return $return; }
        $return .= '<table width="350" bgcolor="#000000" cellpadding="4" cellspacing="1" align="center" style="font-size: 11px;">';
 
        $fp = @fsockopen('udp://'.$ip, $port, $errno, $errstr, 0);
        socket_set_timeout($fp, 1);
        
        if(!$fp)
        {
            $return .= '<tr><td bgcolor="#CCCCCC">Socket Error: '.$errno.' - '.$errstr.'</td></tr>\n';
        }
        else
        {
            $packet = 'SAMP';
            $packet .= chr(strtok($ip, '.'));
            $packet .= chr(strtok('.'));
            $packet .= chr(strtok('.'));
            $packet .= chr(strtok('.'));
            $packet .= chr($port & 0xFF);
            $packet .= chr($port >> 8 & 0xFF);
 
            fwrite($fp, $packet.'i');
            fread($fp, 11);
            $is_passworded = ord(fread($fp, 1));
            $plr_count     = ord(fread($fp, 2));
            $max_plrs      = ord(fread($fp, 2));
            $strlen        = ord(fread($fp, 4));
            $hostname      = fread($fp, $strlen);
            $strlen        = ord(fread($fp, 4));
            $gamemode      = fread($fp, $strlen);
            $strlen        = ord(fread($fp, 4));
            $mapname       = fread($fp, $strlen);
 
            $return .= '      <tr><td bgcolor="#CCCCCC" colspan="2" align="center"><b>'.$hostname.'</b></td></tr>'."\r\n";
            $return .= '      <tr><td bgcolor="#CCCCCC" width="100">Players: </td><td bgcolor="#CCCCCC" width="250">'.$plr_count.' / '.$max_plrs.'</td></tr>'."\r\n";
            $return .= '      <tr><td bgcolor="#CCCCCC">GameMode: </td><td bgcolor="#CCCCCC">'.$gamemode.'</td></tr>'."\r\n";
            $return .= '      <tr><td bgcolor="#CCCCCC">MapName: </td><td bgcolor="#CCCCCC">'.$mapname.'</td></tr>'."\r\n";
            if($is_passworded) $return .= '<tr><td bgcolor="#CCCCCC">Passworded: </td><td bgcolor="#CCCCCC">Yes</td></tr>'."\r\n";
            else $return .= '      <tr><td bgcolor="#CCCCCC">Passworded: </td><td bgcolor="#CCCCCC">No</td></tr>'."\r\n";
 
            fwrite($fp, $packet.'c');
            fread($fp, 11);
            $plr_count = ord(fread($fp, 2));
            if($plr_count > 0)
            {
                $return .= '    </table><br>'."\r\n";
                $return .= '    <table width="350" bgcolor="#000000" cellpadding="4" cellspacing="1" align="center">'."\r\n";
                $return .= '      <tr><td bgcolor="#CCCCCC" align="center" width="250"><b>Player</b></td><td bgcolor="#CCCCCC" align="center" width="100"><b>Score</b></td></tr>'."\r\n";
                for($i=0; $i<$plr_count; $i++)
                {
                    $strlen = ord(fread($fp, 1));
                    $plrname = fread($fp, $strlen);
                    $score = $this->GetLong(fread($fp, 4));
                    
                    $return .= '      <tr><td bgcolor="#CCCCCC">'.$plrname.'</td><td bgcolor="#CCCCCC">'.$score.'</td></tr>'."\r\n";
                }
            }
            fclose($fp);
        }
        $return .= "</table><br />";
        return $return;
    }
    
    function GetLong($dat)
    {
        $num=0;
        if((ord(substr($dat,3,1)) & 128) > 0)
        {
            for($i = 0; $i < strlen($dat); $i++) $num -= ((255 - ord(substr($dat, $i, 1))) << 8 * $i);
            $num--;
        }
        else for($i = 0; $i < strlen($dat); $i++) $num += (ord(substr($dat, $i, 1)) << 8 * $i);
        return $num;
    }
}
?>