Advertisement
Guest User

Untitled

a guest
Jun 20th, 2013
52
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 5.34 KB | None | 0 0
  1. <?php
  2. class WidgetFramework_WidgetRenderer_MCStats extends WidgetFramework_WidgetRenderer {
  3.     protected function _getConfiguration() {
  4.         return array(
  5.             'name' => 'MineCraft Stats',
  6.             'options' => array(
  7.                 'Server' => XenForo_Input::STRING,
  8.                 'Port' => XenForo_Input::UINT,
  9.             )
  10.         );
  11.     }
  12.    
  13.     protected function _getOptionsTemplate() {
  14.         return "mc_options";
  15.     }
  16.    
  17.     protected function _getRenderTemplate(array $widget, $positionCode, array $params) {
  18.         return 'mc_stats';
  19.     }
  20.    
  21.     protected function _render(array $widget, $positionCode, array $params, XenForo_Template_Abstract $renderTemplateObject) {
  22.         $Query = new MinecraftQuery( );
  23.         $mcdata = "";
  24.         $players = "";
  25.         $status = "Online";
  26.             try
  27.             {
  28.                 $Query->Connect( $widget['options']['Server'], $widget['options']['Port'] );
  29.  
  30.                 $mcdata = $Query->GetInfo( );
  31.                 $players = $Query->GetPlayers( );
  32.             }
  33.             catch( MinecraftQueryException $e )
  34.             {
  35.                 $status = "Offline";
  36.             }
  37.        
  38.  
  39.         $renderTemplateObject->setParam('offline', $status);
  40.         $renderTemplateObject->setParam('mcdata', $mcdata);
  41.         $renderTemplateObject->setParam('players', $players);
  42.        
  43.         return $renderTemplateObject->render();
  44.     }
  45. }
  46.  
  47.  
  48.  
  49. class MinecraftQueryException extends Exception
  50. {
  51.     // Exception thrown by MinecraftQuery class
  52. }
  53.  
  54. class MinecraftQuery
  55. {
  56.     /*
  57.      * Class written by xPaw
  58.      *
  59.      * Website: http://xpaw.ru
  60.      * GitHub: https://github.com/xPaw/PHP-Minecraft-Query
  61.      */
  62.    
  63.     const STATISTIC = 0x00;
  64.     const HANDSHAKE = 0x09;
  65.    
  66.     private $Socket;
  67.     private $Players;
  68.     private $Info;
  69.    
  70.     public function Connect( $Ip, $Port = 25565, $Timeout = 3 )
  71.     {
  72.         if( !is_int( $Timeout ) || $Timeout < 0 )
  73.         {
  74.             throw new InvalidArgumentException( 'Timeout must be an integer.' );
  75.         }
  76.        
  77.         $this->Socket = @FSockOpen( 'udp://' . $Ip, (int)$Port, $ErrNo, $ErrStr, $Timeout );
  78.        
  79.         if( $ErrNo || $this->Socket === false )
  80.         {
  81.             throw new MinecraftQueryException( 'Could not create socket: ' . $ErrStr );
  82.         }
  83.        
  84.         Stream_Set_Timeout( $this->Socket, $Timeout );
  85.         Stream_Set_Blocking( $this->Socket, true );
  86.        
  87.         try
  88.         {
  89.             $Challenge = $this->GetChallenge( );
  90.            
  91.             $this->GetStatus( $Challenge );
  92.         }
  93.         // We catch this because we want to close the socket, not very elegant
  94.         catch( MinecraftQueryException $e )
  95.         {
  96.             FClose( $this->Socket );
  97.            
  98.             throw new MinecraftQueryException( $e->getMessage( ) );
  99.         }
  100.        
  101.         FClose( $this->Socket );
  102.     }
  103.    
  104.     public function GetInfo( )
  105.     {
  106.         return isset( $this->Info ) ? $this->Info : false;
  107.     }
  108.    
  109.     public function GetPlayers( )
  110.     {
  111.         return isset( $this->Players ) ? $this->Players : false;
  112.     }
  113.    
  114.     private function GetChallenge( )
  115.     {
  116.         $Data = $this->WriteData( self :: HANDSHAKE );
  117.        
  118.         if( $Data === false )
  119.         {
  120.             throw new MinecraftQueryException( "Failed to receive challenge." );
  121.         }
  122.        
  123.         return Pack( 'N', $Data );
  124.     }
  125.    
  126.     private function GetStatus( $Challenge )
  127.     {
  128.         $Data = $this->WriteData( self :: STATISTIC, $Challenge . Pack( 'c*', 0x00, 0x00, 0x00, 0x00 ) );
  129.        
  130.         if( !$Data )
  131.         {
  132.             throw new MinecraftQueryException( "Failed to receive status." );
  133.         }
  134.        
  135.         $Last = "";
  136.         $Info = Array( );
  137.        
  138.         $Data    = SubStr( $Data, 11 ); // splitnum + 2 int
  139.         $Data    = Explode( "\x00\x00\x01player_\x00\x00", $Data );
  140.         $Players = SubStr( $Data[ 1 ], 0, -2 );
  141.         $Data    = Explode( "\x00", $Data[ 0 ] );
  142.        
  143.         // Array with known keys in order to validate the result
  144.         // It can happen that server sends custom strings containing bad things (who can know!)
  145.         $Keys = Array(
  146.             'hostname'   => 'HostName',
  147.             'gametype'   => 'GameType',
  148.             'version'    => 'Version',
  149.             'plugins'    => 'Plugins',
  150.             'map'        => 'Map',
  151.             'numplayers' => 'Players',
  152.             'maxplayers' => 'MaxPlayers',
  153.             'hostport'   => 'HostPort',
  154.             'hostip'     => 'HostIp'
  155.         );
  156.        
  157.         foreach( $Data as $Key => $Value )
  158.         {
  159.             if( ~$Key & 1 )
  160.             {
  161.                 if( !Array_Key_Exists( $Value, $Keys ) )
  162.                 {
  163.                     $Last = false;
  164.                     continue;
  165.                 }
  166.                
  167.                 $Last = $Keys[ $Value ];
  168.                 $Info[ $Last ] = "";
  169.             }
  170.             else if( $Last != false )
  171.             {
  172.                 $Info[ $Last ] = $Value;
  173.             }
  174.         }
  175.        
  176.         // Ints
  177.         $Info[ 'Players' ]    = IntVal( $Info[ 'Players' ] );
  178.         $Info[ 'MaxPlayers' ] = IntVal( $Info[ 'MaxPlayers' ] );
  179.         $Info[ 'HostPort' ]   = IntVal( $Info[ 'HostPort' ] );
  180.        
  181.         // Parse "plugins", if any
  182.         if( $Info[ 'Plugins' ] )
  183.         {
  184.             $Data = Explode( ": ", $Info[ 'Plugins' ], 2 );
  185.            
  186.             $Info[ 'RawPlugins' ] = $Info[ 'Plugins' ];
  187.             $Info[ 'Software' ]   = $Data[ 0 ];
  188.            
  189.             if( Count( $Data ) == 2 )
  190.             {
  191.                 $Info[ 'Plugins' ] = Explode( "; ", $Data[ 1 ] );
  192.             }
  193.         }
  194.         else
  195.         {
  196.             $Info[ 'Software' ] = 'Vanilla';
  197.         }
  198.        
  199.         $this->Info = $Info;
  200.        
  201.         if( $Players )
  202.         {
  203.             $this->Players = Explode( "\x00", $Players );
  204.         }
  205.     }
  206.    
  207.     private function WriteData( $Command, $Append = "" )
  208.     {
  209.         $Command = Pack( 'c*', 0xFE, 0xFD, $Command, 0x01, 0x02, 0x03, 0x04 ) . $Append;
  210.         $Length  = StrLen( $Command );
  211.        
  212.         if( $Length !== FWrite( $this->Socket, $Command, $Length ) )
  213.         {
  214.             throw new MinecraftQueryException( "Failed to write on socket." );
  215.         }
  216.        
  217.         $Data = FRead( $this->Socket, 2048 );
  218.        
  219.         if( $Data === false )
  220.         {
  221.             throw new MinecraftQueryException( "Failed to read from socket." );
  222.         }
  223.        
  224.         if( StrLen( $Data ) < 5 || $Data[ 0 ] != $Command[ 2 ] )
  225.         {
  226.             return false;
  227.         }
  228.        
  229.         return SubStr( $Data, 5 );
  230.     }
  231. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement