Advertisement
Calgon

Westie's PHP SA-MP Query API

Apr 4th, 2011
1,347
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 7.69 KB | None | 0 0
  1. <?php
  2. /**
  3.  *  This API connects directly to the server, without any need for any
  4.  *  middlemen connections.
  5.  *  Your server must have fsockopen enabled in order to access the
  6.  *  functions that have been made available from this.
  7.  *
  8.  *  @package sampAPI
  9.  *  @version 1.2
  10.  *  @author David Weston <westie@typefish.co.uk>
  11.  *  @copyright 2010; http://www.typefish.co.uk/licences/
  12.  */
  13.  
  14.  
  15. class SampQueryAPI
  16. {
  17.     /**
  18.      *  @ignore
  19.      */
  20.     private $rSocket = false;
  21.    
  22.    
  23.     /**
  24.      *  @ignore
  25.      */
  26.     private $aServer = array();
  27.    
  28.    
  29.     /**
  30.      *  Creation of the server class.
  31.      *
  32.      *  @param string $sServer Server IP, or hostname.
  33.      *  @param integer $iPort Server port
  34.      */
  35.     public function __construct($sServer, $iPort = 7777)
  36.     {
  37.         /* Fill some arrays. */
  38.         $this->aServer[0] = $sServer;
  39.         $this->aServer[1] = $iPort;
  40.        
  41.         /* Start the connection. */
  42.         $this->rSocket = fsockopen('udp://'.$this->aServer[0], $this->aServer[1], $iError, $sError, 2);
  43.        
  44.         if(!$this->rSocket)
  45.         {
  46.             $this->aServer[4] = false;
  47.             return;
  48.         }
  49.        
  50.         socket_set_timeout($this->rSocket, 2);
  51.        
  52.         $sPacket = 'SAMP';
  53.         $sPacket .= chr(strtok($this->aServer[0], '.'));
  54.         $sPacket .= chr(strtok('.'));
  55.         $sPacket .= chr(strtok('.'));
  56.         $sPacket .= chr(strtok('.'));
  57.         $sPacket .= chr($this->aServer[1] & 0xFF);
  58.         $sPacket .= chr($this->aServer[1] >> 8 & 0xFF);
  59.         $sPacket .= 'p4150';
  60.        
  61.         fwrite($this->rSocket, $sPacket);
  62.        
  63.         if(fread($this->rSocket, 10))
  64.         {
  65.             if(fread($this->rSocket, 5) == 'p4150')
  66.             {
  67.                 $this->aServer[4] = true;
  68.                 return;
  69.             }
  70.         }
  71.        
  72.         $this->aServer[4] = false;
  73.     }
  74.    
  75.    
  76.     /**
  77.      *  @ignore
  78.      */
  79.     public function __destruct()
  80.     {
  81.         @fclose($this->rSocket);
  82.     }
  83.    
  84.    
  85.     /**
  86.      *  Used to tell if the server is ready to accept queries.
  87.      *
  88.      *  If false is returned, then it is suggested that you remove the
  89.      *  class from active use, so that you can reload the class if needs
  90.      *  be.
  91.      *
  92.      *  @return bool true if success, false if failure.
  93.      */
  94.     public function isOnline()
  95.     {
  96.         return isset($this->aServer[4]) ? $this->aServer[4] : false;
  97.     }
  98.    
  99.    
  100.     /**
  101.      *  This function is used to get the server information.
  102.      *
  103.      *  <code>
  104.      *  Array
  105.      *  (
  106.      *      [password] => 0
  107.      *      [players] => 9
  108.      *      [maxplayers] => 500
  109.      *      [hostname] => Everystuff Tr3s [MAD]oshi (03a Final) [FIXED]
  110.      *      [gamemode] => Stunt/Race/DM/FR Everystuff
  111.      *      [mapname] => Everystuff
  112.      *  )
  113.      *  </code>
  114.      *
  115.      *  @return array Array of server information.
  116.      */
  117.     public function getInfo()
  118.     {
  119.         @fwrite($this->rSocket, $this->createPacket('i'));
  120.        
  121.         fread($this->rSocket, 11);
  122.    
  123.         $aDetails['password'] = (integer) ord(fread($this->rSocket, 1));
  124.        
  125.         $aDetails['players'] = (integer) $this->toInteger(fread($this->rSocket, 2));
  126.        
  127.         $aDetails['maxplayers'] = (integer) $this->toInteger(fread($this->rSocket, 2));
  128.        
  129.         $iStrlen = ord(fread($this->rSocket, 4));
  130.         if(!$iStrlen) return -1;
  131.        
  132.         $aDetails['hostname'] = (string) fread($this->rSocket, $iStrlen);
  133.        
  134.         $iStrlen = ord(fread($this->rSocket, 4));
  135.         $aDetails['gamemode'] = (string) fread($this->rSocket, $iStrlen);
  136.        
  137.         $iStrlen = ord(fread($this->rSocket, 4));
  138.         $aDetails['mapname'] = (string) fread($this->rSocket, $iStrlen);
  139.        
  140.         return $aDetails;
  141.     }
  142.    
  143.    
  144.     /**
  145.      *  This function gets a basic list of all the players on the server.
  146.      *
  147.      *  Note as of 0.3.0, the amount of players that can be retrieved is
  148.      *  limited to 100. This means if there are more players than 100,
  149.      *  then no data will be returned, and it will be a blank array.
  150.      *
  151.      *  <code>
  152.      *  Array
  153.      *  (
  154.      *      [0] => Array
  155.      *          (
  156.      *              [nickname] => K1nNngO
  157.      *              [score] => 72
  158.      *          )
  159.      *     
  160.      *      [1] => Array
  161.      *          (
  162.      *              [nickname] => [kikOo]
  163.      *              [score] => 150
  164.      *          )
  165.      *
  166.      *      [and so on...]
  167.      *  )
  168.      *  </code>
  169.      *
  170.      *  @return array Array of player information.
  171.      */
  172.     public function getBasicPlayers()
  173.     {
  174.         @fwrite($this->rSocket, $this->createPacket('c'));
  175.         fread($this->rSocket, 11);
  176.        
  177.         $iPlayerCount = ord(fread($this->rSocket, 2));
  178.         $aDetails = array();
  179.        
  180.         if($iPlayerCount > 0)
  181.         {
  182.             for($iIndex = 0; $iIndex < $iPlayerCount; ++$iIndex)
  183.             {
  184.                 $iStrlen = ord(fread($this->rSocket, 1));
  185.                 $aDetails[] = array
  186.                 (
  187.                     "nickname" => (string) fread($this->rSocket, $iStrlen),
  188.                     "score" => (integer) $this->toInteger(fread($this->rSocket, 4)),
  189.                 );
  190.             }
  191.         }
  192.        
  193.         return $aDetails;
  194.     }
  195.    
  196.    
  197.     /**
  198.      *  This function gets a detailed list of all the players on the server.
  199.      *
  200.      *  Note as of 0.3.0, the amount of players that can be retrieved is
  201.      *  limited to 100. This means if there are more players than 100,
  202.      *  then no data will be returned, and it will be a blank array.
  203.      *
  204.      *  <code>
  205.      *  Array
  206.      *  (
  207.      *      [0] => Array
  208.      *          (
  209.      *              [playerid] => 0
  210.      *              [nickname] => K1nNngO
  211.      *              [score] => 72
  212.      *              [ping] => 195
  213.      *          )
  214.      * 
  215.      *      [1] => Array
  216.      *          (
  217.      *              [playerid] => 1
  218.      *              [nickname] => [kikOo]
  219.      *              [score] => 150
  220.      *              [ping] => 375
  221.      *          )
  222.      *
  223.      *      [and so on...]
  224.      *  )
  225.      *  </code>
  226.      *
  227.      *  @return array Array of player information.
  228.      */
  229.     public function getDetailedPlayers()
  230.     {
  231.         @fwrite($this->rSocket, $this->createPacket('d'));
  232.         fread($this->rSocket, 11);
  233.    
  234.         $iPlayerCount = ord(fread($this->rSocket, 2));
  235.         $aDetails = array();
  236.        
  237.         for($iIndex = 0; $iIndex < $iPlayerCount; ++$iIndex)
  238.         {
  239.             $aPlayer['playerid'] = (integer) ord(fread($this->rSocket, 1));
  240.            
  241.             $iStrlen = ord(fread($this->rSocket, 1));
  242.             $aPlayer['nickname'] = (string) fread($this->rSocket, $iStrlen);
  243.            
  244.             $aPlayer['score'] = (integer) $this->toInteger(fread($this->rSocket, 4));
  245.             $aPlayer['ping'] = (integer) $this->toInteger(fread($this->rSocket, 4));
  246.            
  247.             $aDetails[] = $aPlayer;
  248.             unset($aPlayer);
  249.         }
  250.        
  251.         return $aDetails;
  252.     }
  253.    
  254.    
  255.     /**
  256.      *  This function gets all the server rules from the server.
  257.      *
  258.      *  Rules in this context are not player rules, they are client rules,
  259.      *  like the weather of the server, time, and so on. (Custom rules,
  260.      *  when supported by a SA-MP plugin, will be included here.)
  261.      *
  262.      *  <code>
  263.      *  Array
  264.      *  (
  265.      *      [gravity] => 0.007900
  266.      *      [mapname] => Everystuff
  267.      *      [version] => 0.3a
  268.      *      [weather] => 0
  269.      *      [weburl] => samp.madoshi.net
  270.      *      [worldtime] => 12:00
  271.      *  )
  272.      *  </code>
  273.      *
  274.      *  @return array Array of server rules.
  275.      */
  276.     public function getRules()
  277.     {
  278.         @fwrite($this->rSocket, $this->createPacket('r'));
  279.         fread($this->rSocket, 11);
  280.        
  281.         $iRuleCount = ord(fread($this->rSocket, 2));
  282.         $aReturn = array();
  283.        
  284.         for($iIndex = 0; $iIndex < $iRuleCount; ++$iIndex)
  285.         {
  286.             $iStrlen = ord(fread($this->rSocket, 1));
  287.             $sRulename = (string) fread($this->rSocket, $iStrlen);
  288.            
  289.             $iStrlen = ord(fread($this->rSocket, 1));
  290.             $aDetails[$sRulename] = (string) fread($this->rSocket, $iStrlen);
  291.         }
  292.        
  293.         return $aDetails;
  294.     }
  295.    
  296.    
  297.     /**
  298.      *  @ignore
  299.      */
  300.     private function toInteger($sData)
  301.     {
  302.         if($sData === "")
  303.         {
  304.             return null;
  305.         }
  306.        
  307.         $iInteger = 0;
  308.         $iInteger += (ord($sData[0]));
  309.  
  310.         if(isset($sData[1]))
  311.         {
  312.             $iInteger += (ord($sData[1]) << 8);
  313.         }
  314.        
  315.         if(isset($sData[2]))
  316.         {
  317.             $iInteger += (ord($sData[2]) << 16);
  318.         }
  319.        
  320.         if(isset($sData[3]))
  321.         {
  322.             $iInteger += (ord($sData[3]) << 24);
  323.         }
  324.        
  325.         if($iInteger >= 4294967294)
  326.         {
  327.             $iInteger -= 4294967296;
  328.         }
  329.        
  330.         return $iInteger;
  331.     }
  332.    
  333.    
  334.     /**
  335.      *  @ignore
  336.      */
  337.     private function createPacket($sPayload)
  338.     {
  339.         $sPacket = 'SAMP';
  340.         $sPacket .= chr(strtok($this->aServer[0], '.'));
  341.         $sPacket .= chr(strtok('.'));
  342.         $sPacket .= chr(strtok('.'));
  343.         $sPacket .= chr(strtok('.'));
  344.         $sPacket .= chr($this->aServer[1] & 0xFF);
  345.         $sPacket .= chr($this->aServer[1] >> 8 & 0xFF);
  346.         $sPacket .= $sPayload;
  347.    
  348.         return $sPacket;
  349.     }
  350. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement