SRCDS Steam group


Querying a Server With PHP
#1
I know that everyone has their own method of doing things. I thought it would be a cool idea to to do it myself and add a bit more functionality to the script itself. I've never messed with sockets in PHP before but here is my take on it:

PHP Code:
class serverQuery{
    
// Server Info
    
private $serverIp NULL;
    private 
$serverPort NULL;

    
// Server Connection / Query
    
private $serverConnection NULL;
    private 
$serverResponse NULL;
    private 
$players NULL;

    
// Server Information
    
private $serverInformation = array();
    private 
$challengeCode NULL;
    private 
$playerData = array();
    private 
$serverSettings = array();

    public function 
__construct($server){
        
$server explode(":"$server);
        
$this->serverIp $server[0];
        
$this->serverPort $server[1];
        
$this->queryServer();
        
$this->parseServerResponse();
    }

    public function 
queryServer(){
        
// Open a Connection to the Server
        
$this->serverConnection pfsockopen("udp://" $this->serverIp$this->serverPort$errorNumber$errorString1);
        
stream_set_blocking($this->serverConnection1);
        if(!
$this->serverConnection){
            return 
false;
        } else {
            
// Send Query to Server For General Details
            
$this->serverResponse substr($this->query("\xFF\xFF\xFF\xFF\x54Source Engine Query\0"), 2);
            
// Get the Challenge Code for a Player and Rules Query
            
$this->challengeCode substr($this->query("\xFF\xFF\xFF\xFF\x57"), 1);
            
$this->players $this->query("\xFF\xFF\xFF\xFF\x55" $this->challengeCode);
            
$this->serverSettings $this->parseRules($this->query("\xFF\xFF\xFF\xFF\x56" $this->challengeCode));
            
fclose($this->serverConnection);
            return 
true;
        }
    }

    private function 
query($queryData){
        
// Query Function -- Removes 'Junk' [\xFF\xFF\xFF\xFF] -- Returns Data
        
fwrite($this->serverConnection$queryData);
        
fread($this->serverConnection4);
        
$serverStatus stream_get_meta_data($this->serverConnection);
        return 
fread($this->serverConnection$serverStatus['unread_bytes']);
    }

    public function 
parseServerResponse(){
        
/*
            All of These Values are directory from the Developer Wiki
            (http://developer.valvesoftware.com/wiki/Server_Queries)
        */
        
$this->serverInformation['hostname'] = trim(str_replace("\x01"""$this->getString($this->serverResponse)));
        
$this->serverInformation['map'] = $this->getString($this->serverResponse);
        
$this->serverInformation['dir'] = $this->getString($this->serverResponse);
        
$this->serverInformation['description'] = $this->getString($this->serverResponse);
        
$this->serverInformation['appid'] = $this->getShort($this->serverResponse);
        
$this->serverInformation['players'] = $this->getByte($this->serverResponse);
        
$this->serverInformation['maxplayers'] = $this->getByte($this->serverResponse);
        
$this->serverInformation['bots'] = $this->getByte($this->serverResponse);
        
$this->serverInformation['type'] = (chr($this->getByte($this->serverResponse)) == "d") ? "Dedicated" "Listen";
        
$this->serverInformation['os'] = (chr($this->getByte($this->serverResponse)) == "l") ? "Linux" "Windows";
        
$this->serverInformation['pass'] = $this->getByte($this->serverResponse);
        
$this->serverInformation['vac'] = $this->getByte($this->serverResponse);
        
$this->serverInformation['version'] = $this->getString($this->serverResponse);

        
// Removes First Byte of Player Response and Uses The Next Byte as the Counter
        
$this->getByte($this->players);
        
$count $this->getByte($this->players);

        
// Itterate Through and Get Cooresponding Values
        
for($x 0$x $count$x++){
            
$this->playerData[$x]['id'] = $this->getByte($this->players);
            
$this->playerData[$x]['name'] = $this->getString($this->players);
            
$this->playerData[$x]['kills'] = $this->getLong($this->players);
            
$playerTime round($this->getFloat($this->players));
            
$this->playerData[$x]['time'] = round($playerTime 3600) . ":" round(($playerTime 3600) / 60) . ":" round($playerTime 60);
        }
        return 
true;
    }

    private function 
getByte(&$source){
        
$byte ord(substr($source01));
        
$source substr($source1);
        return 
$byte;
    }

    private function 
getLong(&$source){
        
$long unpack("L"substr($source04));
        
$source substr($source4);
        return 
$long[1];
    }

    private function 
getShort(&$source){
        
$short unpack("S"substr($source02));
        
$source substr($source2);
        return 
$short[1];
    }

    private function 
getChar(&$source){
        
$char substr($source01);
        
$source substr($source1);
        return 
$char;
    }

    private function 
getFloat(&$source){
        
$float unpack("f"substr($source04));
        
$source substr($source4);
        return 
$float[1];
    }

    private function 
getString(&$source){
        
$string "";
        
$loop true;
        while(
$loop){
            
$stringPart $this->getChar($source);
            if(
ord($stringPart) != 0){
                
$string .= $stringPart;
            } else {
                
$loop false;
            }
        }
        return 
$string;
    }

    private function 
parseRules($rules){
        
$newRules = array();

        
$this->getByte($rules);

        if(
$this->getByte($rules) != 0){
            
$rules explode(chr(0), $rules);
            for(
$x 1$x count($rules) - 1$x += 2){
                
$newRules[$rules[$x]] = $rules[$x 1];
            }
        }
        return 
$newRules;
    }

    
// Data access Functions
    
public function getServerInformation(){
        return 
$this->serverInformation;
    }

    public function 
getPlayerInformation(){
        return 
$this->playerData;
    }

    public function 
getServerSettings(){
        return 
$this->serverSettings;
    }


Using the Class:
PHP Code:
$serverQuery = new serverQuery($_GET['s']);
    
print_r(array("Server Information" => $serverQuery->getServerInformation(), "Player Information" => $serverQuery->getPlayerInformation(), "Server Settings" => $serverQuery->getServerSettings())); 

The information that it retrieves is the following:
Code:
Array
(
    [Server Information] => Array
        (
            [hostname] => SourceOP.com TF2 24/7 2fort [INSTANT RESPAWN]
            [map] => ctf_2fort
            [dir] => tf
            [description] => Team Fortress
            [appid] => 440
            [players] => 33
            [maxplayers] => 33
            [bots] => 0
            [type] => Dedicated
            [os] => Linux
            [pass] => 0
            [vac] => 1
            [version] => 1.0.7.8
        )

    [Player Information] => Array
        (
            [0] => Array
                (
                    [id] => 1
                    [name] => Scofield
                    [kills] => 0
                    [time] => 0:12:19
                )

            [1] => Array
                (
                    [id] => 2
                    [name] => Nazaire
                    [kills] => 13
                    [time] => 0:14:17
                )

            [2] => Array
                (
                    [id] => 3
                    [name] => Cpt. Respawn
                    [kills] => 25
                    [time] => 1:44:32
                )

            [3] => Array
                (
                    [id] => 4
                    [name] => You Shall Not Pass
                    [kills] => 35
                    [time] => 1:46:13
                )

            [4] => Array
                (
                    [id] => 5
                    [name] => Jackass
                    [kills] => 21
                    [time] => 0:23:49
                )

            [5] => Array
                (
                    [id] => 6
                    [name] => king.adnu
                    [kills] => 17
                    [time] => 1:38:37
                )

            [6] => Array
                (
                    [id] => 7
                    [name] => lansky›
                    [kills] => 1
                    [time] => 0:4:46
                )

            [7] => Array
                (
                    [id] => 8
                    [name] => Manhunt
                    [kills] => 3
                    [time] => 0:4:32
                )

            [8] => Array
                (
                    [id] => 9
                    [name] => Sable
                    [kills] => 24
                    [time] => 1:11:18
                )

            [9] => Array
                (
                    [id] => 10
                    [name] => Mashi
                    [kills] => 1
                    [time] => 0:5:45
                )

            [10] => Array
                (
                    [id] => 11
                    [name] => 小銀狐
                    [kills] => 15
                    [time] => 0:9:32
                )

            [11] => Array
                (
                    [id] => 12
                    [name] => PQTHED420
                    [kills] => 8
                    [time] => 1:47:4
                )

            [12] => Array
                (
                    [id] => 13
                    [name] => ScribbleNauts
                    [kills] => 13
                    [time] => 1:32:27
                )

            [13] => Array
                (
                    [id] => 14
                    [name] => Bingell
                    [kills] => 24
                    [time] => 0:29:16
                )

            [14] => Array
                (
                    [id] => 15
                    [name] => =UO= Gun-4-Hire
                    [kills] => 49
                    [time] => 1:39:13
                )

            [15] => Array
                (
                    [id] => 16
                    [name] => ¿Super Cheese?
                    [kills] => 99
                    [time] => 1:57:29
                )

            [16] => Array
                (
                    [id] => 17
                    [name] => The Dude
                    [kills] => 47
                    [time] => 2:7:31
                )

            [17] => Array
                (
                    [id] => 18
                    [name] => Tony-C
                    [kills] => 0
                    [time] => 0:1:18
                )

            [18] => Array
                (
                    [id] => 19
                    [name] => BDX
                    [kills] => 6
                    [time] => 0:7:27
                )

            [19] => Array
                (
                    [id] => 20
                    [name] => Scooty Puff Sr.
                    [kills] => 116
                    [time] => 1:16:48
                )

            [20] => Array
                (
                    [id] => 21
                    [name] => FF|Skyrider
                    [kills] => 18
                    [time] => 0:13:40
                )

            [21] => Array
                (
                    [id] => 22
                    [name] => Volcoff
                    [kills] => 1
                    [time] => 1:32:23
                )

            [22] => Array
                (
                    [id] => 23
                    [name] => Kurt
                    [kills] => 80
                    [time] => 1:21:37
                )

            [23] => Array
                (
                    [id] => 24
                    [name] => raidian
                    [kills] => 9
                    [time] => 0:14:40
                )

            [24] => Array
                (
                    [id] => 25
                    [name] => IceTea
                    [kills] => 13
                    [time] => 1:43:9
                )

            [25] => Array
                (
                    [id] => 26
                    [name] => hurtmypony
                    [kills] => 69
                    [time] => 1:14:2
                )

            [26] => Array
                (
                    [id] => 27
                    [name] => PMS ♥ SakurA 王女
                    [kills] => 84
                    [time] => 1:51:3
                )

            [27] => Array
                (
                    [id] => 28
                    [name] => ho man...
                    [kills] => 4
                    [time] => 0:14:34
                )

            [28] => Array
                (
                    [id] => 29
                    [name] => MR. CERVANTES
                    [kills] => 32
                    [time] => 1:18:45
                )

            [29] => Array
                (
                    [id] => 30
                    [name] => Jenkus Invictus
                    [kills] => 14
                    [time] => 0:19:1
                )

            [30] => Array
                (
                    [id] => 31
                    [name] => $tinky$hot The Grate
                    [kills] => 0
                    [time] => 0:10:34
                )

            [31] => Array
                (
                    [id] => 0
                    [name] => Dr.Deflog
                    [kills] => 0
                    [time] => 0:0:15
                )

        )

    [Server Settings] => Array
        (
            [DF_radio_on] => 0
            [DF_jetpack_on] => 0
            [DF_hook_on] => 0
            [DF_sop_version] => SourceOP Internal Test Version 0.9.1
            [tf_weapon_criticals] => 1
            [tf_damage_disablespread] => 0
            [tf_playergib] => 1
            [tf_allow_player_use] => 0
            [tf_force_holidays_off] => 0
            [tf_birthday] => 0
            [mp_tournament_stopwatch] => 1
            [mp_windifference] => 0
            [tf_arena_force_class] => 0
            [tf_arena_change_limit] => 1
            [tf_arena_override_cap_enable_time] => -1
            [tf_arena_first_blood] => 1
            [tf_gamemode_arena] => 0
            [tf_gamemode_cp] => 0
            [tf_gamemode_ctf] => 1
            [tf_gamemode_payload] => 0
            [tf_teamtalk] => 0
            [tf_ctf_bonus_time] => 10
            [tf_maxspeed] => 400
            [tf_use_fixed_weaponspreads] => 0
            [mp_respawnwavetime] => -20
            [mp_tournament] => 0
            [tf_arena_preround_time] => 10
            [tf_arena_round_time] => 0
            [tf_arena_max_streak] => 3
            [tf_arena_use_queue] => 1
            [mp_teams_unbalance_limit] => 1
            [mp_maxrounds] => 6
            [mp_winlimit] => 5
            [mp_disable_respawn_times] => 0
            [mp_autoteambalance] => 1
            [mp_stalemate_enable] => 0
            [mp_match_end_at_timelimit] => 0
            [tf_overtime_nag] => 0
            [sv_alltalk] => 0
            [mp_timelimit] => 180
            [mp_fraglimit] => 0
            [nextlevel] =>
            [sv_gravity] => 800
            [sv_stopspeed] => 100
            [sv_noclipaccelerate] => 5
            [sv_noclipspeed] => 5
            [sv_specaccelerate] => 5
            [sv_specspeed] => 3
            [sv_specnoclip] => 1
            [sv_maxspeed] => 320
            [sv_accelerate] => 10
            [sv_airaccelerate] => 10
            [sv_wateraccelerate] => 10
            [sv_waterfriction] => 1
            [sv_footsteps] => 1
            [sv_rollspeed] => 200
            [sv_rollangle] => 0
            [sv_friction] => 4
            [sv_bounce] => 0
            [sv_stepsize] => 18
            [r_VehicleViewDampen] => 1
            [r_JeepViewDampenFreq] => 7.0
        )

)

If you need any help, just leave a comment and I'll give you a hand.

Note:
This will not work on a web server unless you own your own because of the firewall that they use and the fact that the connection is UDP. This goes for all of these scripts. The firewall blocks the UDP packets the server returns because the connection in the PHP is not persistent.
Download My Dedicated Server Installer! - Click Here
Did I help? 'Reputation' Me! - Click Here
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)