IPv4 Fremnet Logo
TOOLS, TINKERINGS & CODE

Help me help you

Source RCON Class · Jun 14, 08:20 by Shannon Wynter

A while back (ok, so a long time ago) I wrote a Source RCON class in php for accessing the rcon on Source based dedicated servers.

I put it up here on PHP Classes.org and forgot about it until recently when someone came to me asking how to perform server query commands with it. Well in short you can’t.

I’m about to start work on another pair of classes that’ll let you do server queries and master server queries. To be consistent, I’ll design these classes around PHP4. Then a bit later, I’ll re-do them all specificly for PHP5.

But without further delay – here is the class (and below it is an example script)

This class implements a TCP based client that acts as a remote console – RCON – class for sending commands to control game variables of Counter-String Source and other games using a Source Dedicated Server – SRCDS .

  1. <?php  
  2. /*  
  3. Basic CS:S Rcon class by Freman.  (V1.00)  
  4. ----------------------------------------------  
  5. Ok, it's a completely working class now with with multi-packet responses  
  6.   
  7. Contact: printf("%s%s%s%s%s%s%s%s%s%d%s%s%s","rc","on",chr(46),"cl","ass",chr(64),"pri","ya",chr(46),2,"y",chr(46),"net")  
  8.   
  9. Behaviour I've noticed:  
  10.   rcon is not returning the packet id.  
  11. */  
  12.   
  13. define("SERVERDATA_EXECCOMMAND",2);  
  14. define("SERVERDATA_AUTH",3);  
  15.   
  16. class RCon {  
  17. var $Password;  
  18. var $Host;  
  19. var $Port = 27015;  
  20. var $_Sock = null;  
  21. var $_Id = 0;  
  22.   
  23. function RCon ($Host,$Port,$Password) {  
  24.   $this->Password = $Password;  
  25.   $this->Host = $Host;  
  26.   $this->Port = $Port;  
  27.   $this->_Sock = @fsockopen($this->Host,$this->Port, $errno, $errstr, 30) or  
  28.       die("Unable to open socket: $errstr ($errno)\n");  
  29.   $this->_Set_Timeout($this->_Sock,2,500);  
  30.     }  
  31.   
  32. function Auth () {  
  33.   $PackID = $this->_Write(SERVERDATA_AUTH,$this->Password);  
  34.   
  35.   // Real response (id: -1 = failure)  
  36.   $ret = $this->_PacketRead();  
  37.   if ($ret[1]['id'] == -1) {  
  38.   die("Authentication Failure\n");  
  39.   }  
  40. }  
  41.   
  42. function _Set_Timeout(&$res,$s,$m=0) {  
  43.   if (version_compare(phpversion(),'4.3.0','<')) {  
  44.   return socket_set_timeout($res,$s,$m);  
  45.   }  
  46.   return stream_set_timeout($res,$s,$m);  
  47. }  
  48.   
  49. function _Write($cmd, $s1='', $s2='') {  
  50.   // Get and increment the packet id  
  51.   $id = ++$this->_Id;  
  52.   
  53.   // Put our packet together  
  54.   $data = pack("VV",$id,$cmd).$s1.chr(0).$s2.chr(0);  
  55.   
  56.   // Prefix the packet size  
  57.   $data = pack("V",strlen($data)).$data;  
  58.   
  59.   // Send packet  
  60.   fwrite($this->_Sock,$data,strlen($data));  
  61.   
  62.   // In case we want it later we'll return the packet id  
  63.   return $id;  
  64. }  
  65.   
  66. function _PacketRead() {  
  67.   //Declare the return array  
  68.   $retarray = array();  
  69.   //Fetch the packet size  
  70.   while ($size = @fread($this->_Sock,4)) {  
  71.   $size = unpack('V1Size',$size);  
  72.   //Work around valve breaking the protocol  
  73.   if ($size["Size"] > 4096) {  
  74.     //pad with 8 nulls  
  75.     $packet = "\x00\x00\x00\x00\x00\x00\x00\x00".fread($this->_Sock,4096);  
  76.   } else {  
  77.     //Read the packet back  
  78.     $packet = fread($this->_Sock,$size["Size"]);  
  79.   }  
  80.   array_push($retarray,unpack("V1ID/V1Response/a*S1/a*S2",$packet));  
  81.   }  
  82.   return $retarray;  
  83. }  
  84.   
  85. function Read() {  
  86.   $Packets = $this->_PacketRead();  
  87.   
  88.   foreach($Packets as $pack) {  
  89.   if (isset($ret[$pack['ID']])) {  
  90.     $ret[$pack['ID']]['S1'] .= $pack['S1'];  
  91.     $ret[$pack['ID']]['S2'] .= $pack['S1'];  
  92.   } else {  
  93.     $ret[$pack['ID']] = array(  
  94.     'Response' => $pack['Response'],  
  95.     'S1' => $pack['S1'],  
  96.     'S2' =>$pack['S2'],  
  97.     );  
  98.   }  
  99.   }  
  100.   return $ret;  
  101. }  
  102.   
  103. function sendCommand($Command) {  
  104.   $Command = '"'.trim(str_replace(' ','" "', $Command)).'"';  
  105.   $this->_Write(SERVERDATA_EXECCOMMAND,$Command,'');  
  106. }  
  107.   
  108. function rconCommand($Command) {  
  109.   $this->sendcommand($Command);  
  110.   
  111.   $ret = $this->Read();  
  112.   
  113.   //ATM: Source servers don't return the request id, but if they fix this the code below should read as  
  114.   // return $ret[$this->_Id]['S1'];  
  115.   return $ret[0]['S1'];  
  116. }  
  117. }  
  118. ?>
  119. Download this code: rcon.class.php (Downloaded 6204 time(s))
  1. <?php  
  2.   
  3. include_once("rcon.class.php");  
  4.   
  5. $r = new rcon("127.0.0.1",27015,"testme");  
  6. $r->Auth();  
  7.   
  8. echo "Authenticated\n";  
  9.   
  10. //Send a request  
  11. var_dump($r->rconCommand("cvarlist"));  
  12.   
  13.   
  14. ?>
  15. Download this code: example.php (Downloaded 4686 time(s))
Comments

Spam no more - rel=nofollow is active here, spamming my comments will not help your page rank.

  Textile help
---== Copyright Shannon Wynter - All rights reserved - All wrongs avenged ==--- email