Guest User

Untitled

a guest
May 6th, 2016
66
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 8.56 KB | None | 0 0
  1. <?php
  2. /*********************************************
  3. *
  4. * SA-MP Query Server Version 0.3
  5. *
  6. * This class provides you with an easy to use interface to query
  7. * your SA-MP 0.2 servers. Usage is simple, but has changed a bit
  8. * since the last version, so be sure to check out the examples
  9. * that come along with this script. It is updated with some of
  10. * the new SA-MP 0.2 query-techniques that can be used.
  11. *
  12. * Author: Peter Beverloo
  13. *     peter@dmx-network.com
  14. *     Ex SA-MP Developer
  15. *
  16. * Updated: Wouter van Eekelen
  17. *     wouter.van.eekelen@serverffs.com
  18. *     SA-MP Betatester
  19. *********************************************/
  20.  
  21. class QueryServer
  22. {
  23.   // Private variables used for the query-ing.
  24.   private $szServerIP;
  25.   private $iPort;
  26.   private $rSocketID;
  27.  
  28.   private $bStatus;
  29.  
  30.   // The __construct function gets called automatically
  31.   // by PHP once the class gets initialized.
  32.   function __construct( $szServerIP, $iPort )
  33.   {
  34.       $this->szServerIP = $this->VerifyAddress( $szServerIP );
  35.       $this->iPort = $iPort;
  36.  
  37.       if (empty( $this->szServerIP ) || !is_numeric( $iPort )) {
  38.           throw new QueryServerException( 'Either the ip-address or the port isn\'t filled in correctly.' );
  39.       }
  40.  
  41.       $this->rSocketID = @fsockopen( 'udp://' . $this->szServerIP, $iPort, $iErrorNo, $szErrorStr, 5 );
  42.       if (!$this->rSocketID) {
  43.           throw new QueryServerException( 'Cannot connect to the server: ' . $szErrorStr );
  44.       }
  45.  
  46.       socket_set_timeout( $this->rSocketID, 0, 500000 );
  47.       $this->bStatus = true;
  48.   }
  49.  
  50.   // The VerifyAddress function verifies the given hostname/
  51.   // IP address and returns the actual IP Address.
  52.   function VerifyAddress( $szServerIP )
  53.   {
  54.       if (ip2long( $szServerIP ) !== false &&
  55.         long2ip( ip2long( $szServerIP ) ) == $szServerIP ) {
  56.           return $szServerIP;
  57.       }
  58.  
  59.       $szAddress = gethostbyname( $szServerIP );
  60.       if ($szAddress == $szServerIP) {
  61.           return "";
  62.       }
  63.  
  64.       return $szAddress;
  65.   }
  66.  
  67.   // The SendPacket function sends a packet to the server which
  68.   // requests information, based on the type of packet send.
  69.   function SendPacket( $cPacket )
  70.   {
  71.       $szPacket = 'SAMP';
  72.       $aIpChunks = explode( '.', $this->szServerIP );
  73.  
  74.       foreach( $aIpChunks as $szChunk ) {
  75.           $szPacket .= chr( $szChunk );
  76.       }
  77.  
  78.       $szPacket .= chr( $this->iPort & 0xFF );
  79.       $szPacket .= chr( $this->iPort >> 8 & 0xFF );
  80.       $szPacket .= $cPacket;
  81.  
  82.       return fwrite( $this->rSocketID, $szPacket, strlen( $szPacket ) );
  83.   }
  84.  
  85.   // The GetPacket() function returns a specific number of bytes
  86.   // read from the socket. This uses a special way of getting stuff.
  87.   function GetPacket( $iBytes )
  88.   {
  89.       $iResponse = fread( $this->rSocketID, $iBytes );
  90.       if ($iResponse === false) {
  91.           throw new QueryServerException( 'Connection to ' . $this->szServerIP . ' failed or has dropped.' );
  92.       }
  93.  
  94.       $iLength = ord( $iResponse );
  95.       if ($iLength > 0)
  96.           return fread( $this->rSocketID, $iLength );
  97.  
  98.       return "";
  99.   }
  100.  
  101.   // After we're done, the connection needs to be closed using
  102.   // the Close() function. Otherwise stuff might go wrong.
  103.   function Close( )
  104.   {
  105.       if ($this->rSocketID !== false) {
  106.           fclose( $this->rSocketID );
  107.       }
  108.   }
  109.  
  110.   // A little function that's needed to properly convert the
  111.   // four bytes we're recieving to integers to an actual PHP
  112.   // integer. ord() can't handle value's higher then 255.
  113.   function toInteger( $szData )
  114.   {
  115.       $iInteger = 0;
  116.  
  117.       $iInteger += ( ord( @$szData[ 0 ] ) );
  118.       $iInteger += ( ord( @$szData[ 1 ] ) << 8 );
  119.       $iInteger += ( ord( @$szData[ 2 ] ) << 16 );
  120.       $iInteger += ( ord( @$szData[ 3 ] ) << 24 );
  121.  
  122.       if( $iInteger >= 4294967294 )
  123.           $iInteger -= 4294967296;
  124.  
  125.       return $iInteger;
  126.   }
  127.  
  128.   // The GetInfo() function returns basic information about the
  129.   // server, like the hostname, number of players online etc.
  130.   function GetInfo( )
  131.   {
  132.       if ($this->SendPacket('i') === false) {
  133.           throw new QueryServerException( 'Connection to ' . $this->szServerIP . ' failed or has dropped.' );
  134.       }
  135.  
  136.       $szFirstData = fread( $this->rSocketID, 4 );
  137.       if (empty( $szFirstData ) || $szFirstData != 'SAMP') {
  138.           throw new QueryServerException( 'The server at ' . $this->szServerIP . ' is not an SA-MP Server.' );
  139.       }
  140.  
  141.       // Pop the first seven characters returned.
  142.       fread( $this->rSocketID, 7 );
  143.  
  144.       return array (
  145.           'Password'  =>  ord( fread( $this->rSocketID, 1 ) ),
  146.           'Players'  =>  $this->toInteger( fread( $this->rSocketID, 2 ) ),
  147.           'MaxPlayers' =>  $this->toInteger( fread( $this->rSocketID, 2 ) ),
  148.           'Hostname'  =>  $this->GetPacket( 4 ),
  149.           'Gamemode'  =>  $this->GetPacket( 4 ),
  150.           'Map'    =>  $this->GetPacket( 4 )
  151.       );
  152.   }
  153.  
  154.   // The GetRules() function returns the rules which are set
  155.   // on the server, e.g. the gravity, version etcetera.
  156.   function GetRules( )
  157.   {
  158.       if ($this->SendPacket('r') === false) {
  159.           throw new QueryServerException( 'Connection to ' . $this->szServerIP . ' failed or has dropped.' );
  160.       }
  161.  
  162.       // Pop the first 11 bytes from the response;
  163.       fread( $this->rSocketID, 11 );
  164.  
  165.       $iRuleCount = ord( fread( $this->rSocketID, 2 ) );
  166.       $aReturnArray = array( );
  167.  
  168.       for( $i = 0; $i < $iRuleCount; $i ++ ) {
  169.           $szRuleName = $this->GetPacket( 1 );
  170.           $aReturnArray[ $szRuleName ] = $this->GetPacket( 1 );
  171.       }
  172.  
  173.       return $aReturnArray;
  174.   }
  175.  
  176.   // The GetPlayers() function is pretty much simelar to the
  177.   // detailed function, but faster and contains less information.
  178.   function GetPlayers( )
  179.   {
  180.       if ($this->SendPacket('c') === false) {
  181.           throw new QueryServerException( 'Connection to ' . $this->szServerIP . ' failed or has dropped.' );
  182.       }
  183.  
  184.       // Again, pop the first eleven bytes send;
  185.       fread( $this->rSocketID, 11 );
  186.  
  187.       $iPlayerCount = ord( fread( $this->rSocketID, 2 ) );
  188.       $aReturnArray = array( );
  189.  
  190.       for( $i = 0; $i < $iPlayerCount; $i ++ )
  191.       {
  192.           $aReturnArray[ ] = array (
  193.               'Nickname' => $this->GetPacket( 1 ),
  194.               'Score'  => $this->toInteger( fread( $this->rSocketID, 4 ) )
  195.           );
  196.       }
  197.  
  198.       return $aReturnArray;
  199.   }
  200.  
  201.   // The GetDetailedPlayers() function returns the player list,
  202.   // but in a detailed form inclusing the score and the ping.
  203.   function GetDetailedPlayers( )
  204.   {
  205.       if ($this->SendPacket('d') === false) {
  206.           throw new QueryServerException( 'Connection to ' . $this->szServerIP . ' failed or has dropped.' );
  207.       }
  208.  
  209.       // Skip the first 11 bytes of the response;
  210.       fread( $this->rSocketID, 11 );
  211.  
  212.       $iPlayerCount = ord( fread( $this->rSocketID, 2 ) );
  213.       $aReturnArray = array( );
  214.  
  215.       for( $i = 0; $i < $iPlayerCount; $i ++ ) {
  216.           $aReturnArray[ ] = array(
  217.               'PlayerID'  => $this->toInteger( fread( $this->rSocketID, 1 ) ),
  218.               'Nickname'  => $this->GetPacket( 1 ),
  219.               'Score'   => $this->toInteger( fread( $this->rSocketID, 4 ) ),
  220.               'Ping'    => $this->toInteger( fread( $this->rSocketID, 4 ) )
  221.           );
  222.       }
  223.  
  224.       return $aReturnArray;
  225.   }
  226.  
  227. function RCON($rcon, $command)
  228.   {
  229.       echo 'Password '.$rcon.' with '.$command;
  230.       if ($this->SendPacket('x '.$rcon.' '.$command) === false) {
  231.           throw new QueryServerException( 'Connection to ' . $this->szServerIP . ' failed or has dropped.' );
  232.       }
  233.  
  234.       // Pop the first 11 bytes from the response;
  235.       $aReturnArray = fread( $this->rSocketID, 11 );
  236.  
  237.       echo fread( $this->rSocketID, 11 );
  238.  
  239.       return $aReturnArray;
  240.   }
  241.  
  242. }
  243.  
  244. /*********************************************
  245. *
  246. * The QueryServerException is used to throw errors when querying
  247. * a specific server. That way we force the user to use proper
  248. * error-handling, and preferably even a try-/catch statement.
  249. *
  250. **********************************************/
  251.  
  252. class QueryServerException extends Exception
  253. {
  254.   // The actual error message is stored in this variable.
  255.   private $szMessage;
  256.  
  257.   // Again, the __construct function gets called as soon
  258.   // as the exception is being thrown, in here we copy the message.
  259.   function __construct( $szMessage )
  260.   {
  261.       $this->szMessage = $szMessage;
  262.   }
  263.  
  264.   // In order to read the exception being thrown, we have
  265.   // a .NET-like toString() function, which returns the message.
  266.   function toString( )
  267.   {
  268.       return $this->szMessage;
  269.   }
  270. }
  271. ?>
Add Comment
Please, Sign In to add comment