SRCDS Steam group


Tutorial: Send a RCON command to a server with PHP
#1
Here's a quick php code which allows you to send a rcon command to a source server.
It's not perfect, as the scripts seems to crash when you send a command responding with lots of data (like cvar list). But with a small command like a change map, no problem!

Code:
<?php

/**
     * Return a byte and split it out of the string
     *  - unsigned char
     *
     * @param string    $string String
     */
    function getByte(&$string)
    {
        $data = substr($string, 0, 1);

        $string = substr($string, 1);

        $data = unpack('Cvalue', $data);

        return $data['value'];
    }

    /**
     * Return an unsigned short and split it out of the string
     *  - unsigned short (16 bit, big endian byte order)
     *
     * @param string    $string String
     */
    function getShortUnsigned(&$string)
    {
        $data = substr($string, 0, 2);

        $string = substr($string, 2);

        $data = unpack('nvalue', $data);

        return $data['value'];
    }

    /**
     * Return a signed short and split it out of the string
     *  - signed short (16 bit, machine byte order)
     *
     * @param string    $string String
     */
    function getShortSigned(&$string)
    {
        $data = substr($string, 0, 2);

        $string = substr($string, 2);

        $data = unpack('svalue', $data);

        return $data['value'];
    }

    /**
     * Return a long and split it out of the string
     *  - unsigned long (32 bit, little endian byte order)
     *
     * @param string    $string String
     */
    function getLong(&$string)
    {
        $data = substr($string, 0, 4);

        $string = substr($string, 4);

        $data = unpack('Vvalue', $data);

        return $data['value'];
    }

    /**
     * Return a float and split it out of the string
     *
     * @param string    $string String
     */
    function getFloat(&$string)
    {
        $data = substr($string, 0, 4);

        $string = substr($string, 4);

        $array = unpack("fvalue", $data);

        return $array['value'];
    }

    /**
     * Return a string and split it out of the string
     *
     * @param string    $string String
     */
    function getString(&$string)
    {
        $data = "";

        $byte = substr($string, 0, 1);

        $string = substr($string, 1);

        while (ord($byte) != "0")
        {
                $data .= $byte;
                $byte = substr($string, 0, 1);
                $string = substr($string, 1);
        }

        return $data;
    }
// Constant
define('PACKET_SIZE', '1400');
define('SERVERQUERY_INFO', "\xFF\xFF\xFF\xFFTSource Engine Query");
define ('REPLY_INFO', "\x49");
define('SERVERQUERY_GETCHALLENGE', "\xFF\xFF\xFF\xFF\x57");
define ('REPLY_GETCHALLENGE', "\x41");
define('SERVERDATA_AUTH', 3) ;
define ('SERVERDATA_EXECCOMMAND', 2) ;

// Ip address and port
$_ip = '123.234.012.234' ; // server ip
$_port = '27015'; // server port
$_password = 'MyP@ssw0rd!' ; // your rcon password
$s2 = '';
$command = 'map tc_hydro'; // the rcon command! Put the command you want here
$requestId = 1;

// open connection with server
$socket = fsockopen ('tcp://'.$_ip, $_port, $errno, $errstr, 30) ;

// Send auth packet

// Construct packet
$data = pack("VV", $requestId, SERVERDATA_AUTH).$_password.chr(0).$s2.chr(0);

// Prefix the packet by its size
$data = pack("V",strlen($data)).$data;

// Send packet
fwrite ($socket, $data, strlen($data)) ;

$requestId++ ;

// Check if auth is successful
$junk = fread ($socket, PACKET_SIZE) ;

$string = fread ($socket, PACKET_SIZE) ;
$size = getLong($string) ;
$id = getLong ($string) ;

if ($id == -1)
{
  // Error
  die ('Auth failed: bad password !') ;
}

// Sending the command and getting the answer
$data = pack ("VV", $requestId, SERVERDATA_EXECCOMMAND).$command.chr(0).$s2.chr(0) ;

// Prefix the packet by its size
$data = pack ("V", strlen ($data)).$data ;

// Send packet
fwrite ($socket, $data, strlen($data)) ;

$requestId++ ;

// Read response
$i = 0 ;
$text = '' ;
while ($string = fread($socket, 4))
{
  $info[$i]['size'] = getLong($string) ;
  $string = fread($socket, $info[$i]['size']) ;
  $info[$i]['id'] = getLong ($string) ;
  $info[$i]['type'] = getLong ($string) ;
  $info[$i]['s1'] = getString ($string) ;
  $info[$i]['s2'] = getString ($string) ;
  $text .= $info[$i]['s1'] ;
  $i++ ;
}
?>

Feel free to use this to a great web admin page, but if you do, please post your modifications to allow others to use them!
Reply
#2
Wow thank you so much.
realchamp Wrote:
Hazz Wrote:Has someone helped you on these forums? If so, help someone else
Mooga Wrote:OrangeBox is a WHORE.
Reply
#3
This is wonderful, thank you!
Reply
#4
Sounds interesting, will try it out sometime!
Reply
#5
Thanks!
Read this for more PHP scripts sending requests to a source server:

http://forums.srcds.com/viewtopic/6446
Reply
#6
This is sexy, I want more work from you.
Reply
#7
Question 
hello, i tried to use this code but i'm always getting an timeout, seems my server doesn't like tcp connects.


udp connects don't cause any problems but getting an tcp connection to execute rcon commands won't realy work.


hlsw is working so i don't get it Sad


any ideas?


greetings
Reply
#8
Have you forwarded the port?
~ trewq
Reply
#9
I wander if this is hack proof
Reply
#10
on my local machine or on my linux host?

well i haven't forewarded anything special, because hlsw is working and i can connect and play on the server.. its just the php script which doesn't establish a tcp connection, could this realy be a port-foreward issue ?
wouldn't hlsw be able to connect to the server aswell to drop rcon commands?

greetings
Reply
#11
hi,

well i just installed a hl2 server and its working.

but its still not working for my halflife1 servers Sad

don't hlds and srcds server use the same protocol since 2006?


greetings
Reply
#12
Nope, please take a look at this page:

http://developer.valvesoftware.com/wiki/Server_Queries
Join the Source Dedicated Server Support Group on Steam Community!
Source Dedicated Server (SRCDS)
Free to join, Live support! (When available)

http://forums.srcds.com/viewtopic/5114
Reply
#13
I made it to a class so its easier to use Big Grin
Code:
<?php

    define('PACKET_SIZE', '1400');
    define('SERVERQUERY_INFO', "\xFF\xFF\xFF\xFFTSource Engine Query");
    define ('REPLY_INFO', "\x49");
    define('SERVERQUERY_GETCHALLENGE', "\xFF\xFF\xFF\xFF\x57");
    define ('REPLY_GETCHALLENGE', "\x41");
    define('SERVERDATA_AUTH', 3) ;
    define ('SERVERDATA_EXECCOMMAND', 2) ;
    
    class srcds_rcon
    {
                        
        private function getByte(&$string)
        {
            $data = substr($string, 0, 1);
            $string = substr($string, 1);
            $data = unpack('Cvalue', $data);
            return $data['value'];
        }
    
        private function getShortUnsigned(&$string)
        {
            $data = substr($string, 0, 2);
            $string = substr($string, 2);
            $data = unpack('nvalue', $data);
            return $data['value'];
        }
    
        private function getShortSigned(&$string)
        {
            $data = substr($string, 0, 2);
            $string = substr($string, 2);
            $data = unpack('svalue', $data);
            return $data['value'];
        }
    
        private function getLong(&$string)
        {
            $data = substr($string, 0, 4);
            $string = substr($string, 4);
            $data = unpack('Vvalue', $data);
            return $data['value'];
        }
    
        private function getFloat(&$string)
        {
            $data = substr($string, 0, 4);
            $string = substr($string, 4);
            $array = unpack("fvalue", $data);
            return $array['value'];
        }
    
        private function getString(&$string)
        {
            $data = "";
            $byte = substr($string, 0, 1);
            $string = substr($string, 1);
            while (ord($byte) != "0")
            {
                    $data .= $byte;
                    $byte = substr($string, 0, 1);
                    $string = substr($string, 1);
            }
            return $data;
        }
    
        public function rcon_command($ip, $port, $password, $command)
        {
            $requestId = 1;
            $s2 = '';
            $socket = @fsockopen ('tcp://'.$ip, $port, $errno, $errstr, 30);
            if (!$socket)
                die('Unable to connect!');
            $data = pack("VV", $requestId, SERVERDATA_AUTH).$password.chr(0).$s2.chr(0);
            $data = pack("V",strlen($data)).$data;        
            fwrite ($socket, $data, strlen($data));
            
            $requestId++ ;
            $junk = fread ($socket, PACKET_SIZE);
            $string = fread ($socket, PACKET_SIZE);
            $size = $this->getLong($string);
            $id = $this->getLong($string) ;
            
            if ($id == -1)
            {
              return 'Authentication Failed!';
            }
            
            $data = pack ("VV", $requestId, SERVERDATA_EXECCOMMAND).$command.chr(0).$s2.chr(0) ;
            $data = pack ("V", strlen ($data)).$data ;
            fwrite ($socket, $data, strlen($data)) ;
            $requestId++ ;
            $i = 0 ;
            $text = '' ;
            
            while ($string = fread($socket, 4))
            {
              $info[$i]['size'] = $this->getLong($string) ;
              $string = fread($socket, $info[$i]['size']) ;
              $info[$i]['id'] = $this->getLong ($string) ;
              $info[$i]['type'] = $this->getLong ($string) ;
              $info[$i]['s1'] = $this->getString ($string) ;
              $info[$i]['s2'] = $this->getString ($string) ;
              $text .= $info[$i]['s1'];
              $i++ ;
              return $text;
            }    
        }                
    }

?>

Example
Code:
<?php

    require_once("srcds_rcon.php");

    $srcds_rcon = new srcds_rcon();
    echo $srcds_rcon->rcon_command("XXX.XXX.XXX", "27015", "<- RCON Password ->", "stats");

?>
Reply
#14
Here is a little front end i threw together:

http://ruckman.net/blog/download.php?view.4
Reply
#15
Wow, from the screenshots that does look like a great implementation!
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)