• I need some PHP help.
    6 replies, posted
Well I found a few scripts online to query source servers, none of them worked but with a few modifications I got it to spit out the info I want. I'm attempting to get the list of players on the server. (I've found a way to correctly parse their names and score, but fail to understand how to parse their time connected) Here is my current code: [PHP]<?php //header('Content-Type: text/plain'); function query_source($address) { $array = explode(":", $address); $server['status'] = 0; $server['ip'] = $array[0]; $server['port'] = $array[1]; if (!$server['ip'] || !$server['port']) { exit("EMPTY OR INVALID ADDRESS"); } $socket = @fsockopen("udp://{$server['ip']}", $server['port'], $errno, $errstr, 1); if (!$socket) { return $server; } stream_set_timeout($socket, 1); stream_set_blocking($socket, TRUE); fwrite($socket, "\xFF\xFF\xFF\xFF\x54Source Engine Query\x00"); $packet = fread($socket, 4096); @fclose($socket); if (!$packet) { return $server; } $header = substr($packet, 0, 4); $response_type = substr($packet, 4, 1); $network_version = ord(substr($packet, 5, 1)); if ($response_type != "I") { exit("NOT A SOURCE SERVER"); } $packet_array = explode("\x00", substr($packet, 6), 5); $server['name'] = $packet_array[0]; $server['map'] = $packet_array[1]; $server['game'] = $packet_array[2]; $server['description'] = $packet_array[3]; $packet = $packet_array[4]; $app_id = array_pop(unpack("S", substr($packet, 0, 2))); $server['players'] = ord(substr($packet, 2, 1)); $server['playersmax'] = ord(substr($packet, 3, 1)); $server['bots'] = ord(substr($packet, 4, 1)); $server['status'] = 1; $server['dedicated'] = substr($packet, 5, 1); $server['os'] = substr($packet, 6, 1); $server['password'] = ord(substr($packet, 7, 1)); $server['vac'] = ord(substr($packet, 8, 1)); return $server; } $query = query_source("208.115.219.59:27015"); echo $query['name'] . PHP_EOL; echo $query['map'] . PHP_EOL; echo $query['description'] . PHP_EOL; echo $query['players'] . "/" . $query['playersmax'] . " players" . PHP_EOL; function source_clg($address) { $array = explode(":", $address); $server['status'] = 0; $server['ip'] = $array[0]; $server['port'] = $array[1]; if (!$server['ip'] || !$server['port']) { exit("EMPTY OR INVALID ADDRESS"); } $socket = @fsockopen("udp://{$server['ip']}", $server['port'], $errno, $errstr, 1); if (!$socket) { return $server; } stream_set_timeout($socket, 1); stream_set_blocking($socket, TRUE); fwrite($socket, "\xFF\xFF\xFF\xFF\x55\xFF\xFF\xFF\xFF"); $packet = fread($socket, 4096); @fclose($socket); if (!$packet) { return $server; } $header = substr($packet, 0, 4); $response_type = substr($packet, 4, 1); $network_version = ord(substr($packet, 5, 1)); return substr($packet, 5); } $c = source_clg("208.115.219.59:27015"); function source_players($address, $ch) { $array = explode(":", $address); $server['status'] = 0; $server['ip'] = $array[0]; $server['port'] = $array[1]; if (!$server['ip'] || !$server['port']) { exit("EMPTY OR INVALID ADDRESS"); } $socket = @fsockopen("udp://{$server['ip']}", $server['port'], $errno, $errstr, 1); if (!$socket) { return $server; } stream_set_timeout($socket, 1); stream_set_blocking($socket, TRUE); fwrite($socket, "\xFF\xFF\xFF\xFF\x55" . $ch); $packet = fread($socket, 4096); @fclose($socket); if (!$packet) { return $server; } $header = substr($packet, 0, 4); $response_type = substr($packet, 4, 1); $network_version = ord(substr($packet, 5, 1)); return explode("%00", urlencode($packet)); } function lastIndexOf($haystack, $needle) { $index = strpos(strrev($haystack), strrev($needle)); $index = strlen($haystack) - strlen(index) - $index; return $index; } $plys = source_players("208.115.219.59:27015", $c); foreach ($plys as $ply){ echo '<br>'; echo $ply . '<br>'; // . ' - ' . hexdec($ss) . '<br>'; //echo hexdec(substr($ply, -2)) . '<br>'; } ?>[/PHP] It outputs stuff like this: [CODE]%01%7C-D DAFT+%7C+Zarmeck %02[/CODE] Where I've come to the conclusion that the top line is how long they've been connected. The second line is their name (URLEncoded). And the bottom line is their score in HEX. I can't find an easy way to parse all these details, also, if their score is 0 it doesn't show anything for score.
Do you think you could post a couple more examples of things it outputs?
Try urldecode() or rawurldecode()
Apologies that I can't help with the funky character issue, but [url=https://github.com/yannickcr/SourceQuery]here's[/url] a PHP class that accomplishes what you're trying to do with only a few lines on your part. [PHP] <?php require_once 'SourceQuery.php'; $ip = explode(":",$_GET['ip']); $server = new SourceQuery($ip[0], $ip[1]); $players = $server->getPlayers(); foreach ($players as $player){ echo "<div style='outline:1px solid black;width:300px;'>"; echo "<b>Name:</b> ".$player['name']."<br>"; echo "<b>Score:</b> ".$player['score']."<br>"; echo "<b>Time connected:</b> ".$player['time']."</div><p>"; } ?> [/PHP] [url=http://gksudoku.com/servers.php?ip=216.157.110.213:27015]Here's a live example of the above.[/url]
[QUOTE=mechanicalocean;37079167]Apologies that I can't help with the funky character issue, but [url=https://github.com/yannickcr/SourceQuery]here's[/url] a PHP class that accomplishes what you're trying to do with only a few lines on your part. [PHP] <?php require_once 'SourceQuery.php'; $ip = explode(":",$_GET['ip']); $server = new SourceQuery($ip[0], $ip[1]); $players = $server->getPlayers(); foreach ($players as $player){ echo "<div style='outline:1px solid black;width:300px;'>"; echo "<b>Name:</b> ".$player['name']."<br>"; echo "<b>Score:</b> ".$player['score']."<br>"; echo "<b>Time connected:</b> ".$player['time']."</div><p>"; } ?> [/PHP] [url=http://gksudoku.com/servers.php?ip=216.157.110.213:27015]Here's a live example of the above.[/url][/QUOTE] Thank you so much. :) EDIT: Maybe I'm doing something wrong, I copied the source from GitHub and I got this error: [CODE]Parse error: syntax error, unexpected T_FUNCTION, expecting ')' in /home/aftermat/public_html/labs/community/codydev/AMadmin/steam/SourceQuery.php on line 78[/CODE] [editline]4th August 2012[/editline] I fixed it! After some googling I found the issue was I'm using php 5.2, which doesn't support anonymous functions. All I had to do was declare the function separately and call it in the array_map. Here is the fixed SourceQuery.php for PHP 5.2. [php] <?php class SourceQuery { public function __construct($ip, $port=27015) { $this->ip = $ip; $this->port = $port; } protected function query($query) { $fp = fsockopen('udp://' . $this->ip, $this->port, $errno, $errstr, 2); if (!$fp) { trigger_error('The server does not respond', E_USER_NOTICE); return false; } else { fwrite($fp, $query); stream_set_timeout($fp, 2); $result = ''; do { $result .= fread ($fp, 1); $fpstatus = socket_get_status($fp); } while ($fpstatus['unread_bytes']); fclose($fp); return $result; } } protected function getChallenge() { $challenge = $this->query("\xFF\xFF\xFF\xFFU\xFF\xFF\xFF\xFF"); return substr($challenge, 5); } // Hex to Signed Dec http://fr2.php.net/manual/en/function.hexdec.php#97172 private function hexdecs($hex){ $dec = hexdec($hex); $max = pow(2, 4 * (strlen($hex) + (strlen($hex) % 2))); $_dec = $max - $dec; return $dec > $_dec ? -$_dec : $dec; } public function getInfos() { $infos = $this->query("\xFF\xFF\xFF\xFFTSource Engine Query\x00"); // Détermine le protocole utilisé $protocol = hexdec(substr(bin2hex($infos), 8, 2)); if($protocol == 109) return $this->getInfos1($infos); else if($protocol == 73) return $this->getInfos2($infos); trigger_error('Unknown server type', E_USER_NOTICE); return false; } protected function getInfos1($infos) { // Split informations $infos = chunk_split(substr(bin2hex($infos), 10), 2, '\\'); @list($serveur['ip'], $serveur['name'], $serveur['map'], $serveur['mod'], $serveur['modname'], $serveur['params']) = explode('\\00', $infos); // Split parameters $serveur['params'] = substr($serveur['params'],0,18); $serveur['params'] = chunk_split(str_replace('\\', '', $serveur['params']), 2, ' '); list($params['players'], $params['places'], $params['protocol'], $params['dedie'], $params['os'], $params['pass']) = explode(' ', $serveur['params']); $params = array( 'id' => 0, // Unsupported 'bots' => 0, // Unsupported 'ip' => $this->ip, 'port' => $this->port, 'players' => hexdec($params['players']), 'places' => hexdec($params['places']), 'protocol' => hexdec($params['protocol']), 'dedie' => chr(hexdec($params['dedie'])), 'os' => chr(hexdec($params['os'])), 'pass' => hexdec($params['pass']) ); unset($serveur['ip']); unset($serveur['params']); $serveur = array_map('funcarray', $serveur); $infos = ($params + $serveur); return $infos; } function funcarray($item){ return pack("H*", str_replace('\\', '', $item)); } protected function getInfos2($infos) { // Split informations $infos = chunk_split(substr(bin2hex($infos), 12), 2, '\\'); @list($serveur['name'], $serveur['map'], $serveur['mod'], $serveur['modname'], $serveur['params']) = explode('\\00', $infos, 5); // Split parameters $serveur['params'] = substr($serveur['params'], 0); $serveur['params'] = chunk_split(str_replace('\\', '', $serveur['params']), 2, ' '); list($params['id1'], $params['id2'], $params['players'], $params['places'], $params['bots'], $params['dedie'], $params['os'], $params['pass']) = explode(' ', $serveur['params']); $params=array( 'id' => hexdec($params['id2'] . $params['id1']), 'ip' => $this->ip, 'port' => $this->port, 'players' => hexdec($params['players']), 'places' => hexdec($params['places']), 'bots' => hexdec($params['bots']), 'protocol' => 73, 'dedie' => chr(hexdec($params['dedie'])), 'os' => chr(hexdec($params['os'])), 'pass' => hexdec($params['pass']) ); unset($serveur['params']); $serveur = array_map('funcarray', $serveur); $infos = ($serveur + $params); return $infos; } public function getPlayers() { $challenge = $this->getChallenge(); $infos = $this->query("\xFF\xFF\xFF\xFFU" . $challenge); $infos = chunk_split(substr(bin2hex($infos), 12), 2, '\\'); $infos = explode('\\', $infos); $players = array(); for ($i = 0; isset($infos[$i + 1]); $i = $j + 9) { // Player name $name = ''; for ($j = $i + 1; isset($infos[$j]) && $infos[$j] != '00'; $j++) $name .= chr(hexdec($infos[$j])); if (!isset($infos[$j + 8])) break; // Gametime eval('$time="\x'.trim(chunk_split($infos[$j + 5] . $infos[$j + 6] . $infos[$j + 7] . $infos[$j + 8], 2,"\x"), "\x") . '";'); list(,$time) = unpack('f', $time); // Score $score = ltrim($infos[$j + 4] . $infos[$j + 3] . $infos[$j + 2] . $infos[$j + 1], '0'); $players[] = array( 'id' => hexdec($infos[$i]), 'name' => $name, 'score' => empty($score)? 0 : $this->hexdecs($score), 'time' => $time ); } return $players; } } ?> [/php] Thanks again!
how do I use this class to query a server ? Thanks
[QUOTE=reboot;49855400]how do I use this class to query a server ? Thanks[/QUOTE] 1. Dont bump an old thread. 2. Go to [url]https://github.com/xPaw/PHP-Source-Query[/url] 3. Open the Examples folder. 4. Read thru them and you will have a ton of example code. If that is not enough, look thru the files in the SourceQuery folder and read the comments
Sorry, you need to Log In to post a reply to this thread.