Basically the problem lies within connecting or writing using sockets. Here's the weird thing, this works perfectly on windows based server, but when I use it on a linux server, it's like linux doesn't even want to work with UDP stuff.
I'm very frusted and been pulling hairs out for 5 hours now...
Hopefully someone can help.
This connects to a Half-Life 2 server and pulls data like (server name, max players, current players, etc).
index.php
<?
require("CServerInfo.php");
$sinfo = array();
$sinfo = $ServerInfo->getInfo("66.55.154.167","27015");
?>
CServerInfo.php
<?php
if(!isset($_SESSION)) // We are using AJAX so need a new session, as we bypass some stuff before
session_start();
define('INFO_RESPONSE_HL1',0x6D);
define('CHALLENGE_RESPONSE',0x41);
include 'hexdump.php';
class CServerInfo
{
var $raw;
function getInfo($address,$port)
{
if (isset($_SESSION['getInfo.' . $address . '.' . $port]) && is_array($_SESSION['getInfo.' . $address . '.' . $port]))
{
return $_SESSION['getInfo.' . $address . '.' . $port];
}
$ret = array();
$s = fsockopen("udp://".$address,$port,$errno,$errstring,1);
if (!$s) echo "$errstring ($errno)<br />\n";
stream_set_timeout($s,1);
if(!fwrite($s,"\xFF\xFF\xFF\xFF\x54Source Engine Query",39))
{
echo "Error Writing Data. $errstring ($errno)";
}
$packet = fread($s,1024);
echo "Packet: $packet";
if(empty($packet))
{
$_SESSION['getInfo.' . $address . '.' . $port] = $this->getInfoProxy($address, $port);
return $this->getInfoProxy($address, $port);
}
$parr = explode("\x00",substr($packet,6));
if(!isset($packet[4])) {
$_SESSION['getInfo.' . $address . '.' . $port] = array();
return $_SESSION['getInfo.' . $address . '.' . $port];
}
if (ord($packet[4]) == INFO_RESPONSE_HL1)
{ //HL1 Response
$packet = substr($packet,strpos($packet,"\x00")+1);
$parr = explode("\x00",$packet);
$ret['hostname'] = $parr[0];
$ret['map'] = $parr[1];
$ret['gamename'] = $parr[2];
$ret['gamedesc'] = $parr[3];
$packet = substr($packet,strlen($ret['hostname'])+1+strlen($ret['map'])+1+strlen($ret['gamename'])+1+strlen($ret['gamedesc'])+1);
$ret['numplayers'] = ord($packet[0]);
$ret['maxplayers'] = ord($packet[1]);
//$version = ord($packet[2]);
$ret['dedicated'] = $packet[3];
$ret['os'] = $packet[4];
$ret['password'] = ord($packet[5]);
if (ord($packet[6]))
{ //Skip mod info
$packet = substr($packet,strpos($packet,"\x00")+1);
$packet = substr($packet,strpos($packet,"\x00")+3);
}
else
{
$packet = substr($packet,6);
}
$ret['secure'] = ord($packet[0]);
$ret['botcount'] = ord($packet[1]);
}
else
{ //HL2 Response
$ret['hostname'] = $parr[0];
$ret['map'] = $parr[1];
$ret['gamename'] = $parr[2];
$ret['gamedesc'] = $parr[3];
$packet = substr($packet,6+strlen($ret['hostname'])+1+strlen($ret['map'])+1+strlen($ret['gamename'])+1+strlen($ret['gamedesc'])+1+2);
$ret['numplayers'] = ord($packet[0]);
$ret['maxplayers'] = ord($packet[1]);
$ret['botcount'] = ord($packet[2]);
$ret['dedicated'] = ord($packet[3]);
$ret['os'] = $packet[4];
$ret['password'] = ord($packet[5]);
$ret['secure'] = $packet[6];
}
$_SESSION['getInfo.' . $address . '.' . $port] = $ret;
return $ret;
}
function getPlayers($address,$port)
{
set_magic_quotes_runtime(0);
$ret = array();
$s = fsockopen("udp://".$address,$port,$errno,$errstring,1);
stream_set_timeout($s,1); // 1 second timeout on read/write operations
fwrite($s,"\xFF\xFF\xFF\xFF\x57"); //Get challenge #
$packet = fread($s,1024);
$chalId = $this->getChallenge($packet);
fwrite($s,"\xFF\xFF\xFF\xFF\x55".$chalId);
$packet = fread($s,2048);
if(empty($packet))
{
return $this->getPlayersProxy($address, $port);
}
$packet = substr($packet,5);
$nump = ord($packet[0]);
$packet = substr($packet,1);
$this->raw = $packet;
for ($i=0;$i<$nump;$i++)
{
$temp = array();
$temp['index'] = $this->_getbyte();
$temp['name']= $this->_getnullstr();
$temp['kills']= $this->_getlong();
$temp['time']= SecondsToString((int)$this->_getfloat(),true);
if(!empty($temp['name']))
array_push($ret,$temp);
}
array_qsort($ret, 'kills', SORT_DESC);
return $ret;
}
function getChallenge($packet)
{
if(isset($packet[4]) && ord($packet[4]) == CHALLENGE_RESPONSE)
{
return substr($packet,5);
}
return "\xFF\xFF\xFF\xFF";
}
/*
Proxy functions are used when there is a problem with blocked ports,
or firewalls like with some webhosts.
*/
function getInfoProxy($address,$port)
{
if(!(isset($address) && isset($port)))
return false;
$ret = array();
$info = @file_get_contents(SERVER_QUERY . "?ip=" . $address . "&port=" .$port."&type=info");
if(strstr($info, "Page not found"))
return false;
if($info)
{
$inf = explode("\t", $info);
$ret['hostname'] = $inf[0];
$ret['numplayers'] = $inf[1];
$ret['maxplayers'] = $inf[2];
$ret['map'] = $inf[3];
$_SESSION['getInfo.' . $address . '.' . $port] = $ret;
return $ret;
}
else
return false;
}
function getPlayersProxy($address,$port)
{
if(!(isset($address) && isset($port)))
return false;
$ret = array();
$players = @file_get_contents(SERVER_QUERY . "?ip=" . $address . "&port=" .$port."&type=players");
if(strstr($players, "Page not found"))
return false;
if($players)
{
$plr = explode("\n", $players);
foreach($plr AS $player)
{
$items = explode("\t", $player);
if(!isset($items[1])) {
continue;
}
$row = array();
$row['index'] = $items[0];
$row['name'] = $items[1];
$row['kills'] = $items[2];
$row['time'] = $items[3];
array_push($ret, $row);
}
return $ret;
}
else
return false;
}
function _getnullstr()
{
if (empty($this->raw))
return '';
$end = strpos($this->raw, "\0");
$str = substr($this->raw, 0, $end);
$this->raw = substr($this->raw, $end+1);
return $str;
}
function _getchar()
{
return sprintf("%c", $this->_getbyte());
}
function _getbyte()
{
$byte = substr($this->raw, 0, 1);
$this->raw = substr($this->raw, 1);
return ord($byte);
}
function _getshort()
{
$lo = $this->_getbyte();
$hi = $this->_getbyte();
$short = ($hi << | $lo;
return $short;
}
function _getlong()
{
$lo = $this->_getshort();
$hi = $this->_getshort();
$long = ($hi << 16) | $lo;
return $long;
}
function _getfloat()
{
$f = @unpack("f1float", $this->raw);
$this->raw = substr($this->raw, 4);
return $f['float'];
}
}
$ServerInfo = new CServerInfo();
?>
hexdump.php
<?php
function hexdump ($data, $htmloutput = true, $uppercase = false, $return = false)
{
// Init
$hexi = '';
$ascii = '';
$dump = ($htmloutput === true) ? '<pre>' : '';
$offset = 0;
$len = strlen($data);
// Upper or lower case hexidecimal
$x = ($uppercase === false) ? 'x' : 'X';
// Iterate string
for ($i = $j = 0; $i < $len; $i++)
{
// Convert to hexidecimal
$hexi .= sprintf("%02$x ", ord($data[$i]));
// Replace non-viewable bytes with '.'
if (ord($data[$i]) >= 32) {
$ascii .= ($htmloutput === true) ?
htmlentities($data[$i]) :
$data[$i];
} else {
$ascii .= '.';
}
// Add extra column spacing
if ($j === 7) {
$hexi .= ' ';
$ascii .= ' ';
}
// Add row
if (++$j === 16 || $i === $len - 1) {
// Join the hexi / ascii output
$dump .= sprintf("%04$x %-49s %s", $offset, $hexi, $ascii);
// Reset vars
$hexi = $ascii = '';
$offset += 16;
$j = 0;
// Add newline
if ($i !== $len - 1) {
$dump .= "\n";
}
}
}
// Finish dump
$dump .= $htmloutput === true ?
'</pre>' :
'';
$dump .= "\n";
// Output method
if ($return === false) {
echo $dump;
} else {
return $dump;
}
}
?>