<?PHP
/**
* This API connects directly to the server, without any need for any
* middlemen connections.
* Your server must have fsockopen enabled in order to access the
* functions that have been made available from this.
*
* @package sampAPI
* @version 1.1
* @author David Weston <westie@typefish.co.uk>
* @copyright 2010; http://www.typefish.co.uk/licences/
*/
class SampQueryAPI
{
/**
* @ignore
*/
private $rSocket = false;
/**
* @ignore
*/
private $aServer = array();
/**
* Creation of the server class.
*
* @param string $sServer Server IP, or hostname.
* @param integer $iPort Server port
*/
public function __construct($sServer, $iPort = 7777)
{
/* Fill some arrays. */
$this->aServer[0] = $sServer;
$this->aServer[1] = $iPort;
/* Start the connection. */
$this->rSocket = @fsockopen('udp://'.$this->aServer[0
], $this->aServer[1
], $iError, $sError, 2
);
if(!$this->rSocket)
{
$this->aServer[4] = false;
return;
}
$sPacket = 'SAMP';
$sPacket .= chr(strtok($this->aServer[0], '.')); $sPacket .= chr($this->aServer[1
] & 0xFF
); $sPacket .= chr($this->aServer[1
] >> 8
& 0xFF
); $sPacket .= 'p4150';
fwrite($this->rSocket, $sPacket);
if(fread($this->rSocket, 15
)) {
$this->aServer[4] = true;
}
else
{
$this->aServer[4] = false;
}
}
/**
* @ignore
*/
public function __destruct()
{
}
/**
* Used to tell if the server is ready to accept queries.
*
* If false is returned, then it is suggested that you remove the
* class from active use, so that you can reload the class if needs
* be.
*
* @return bool true if success, false if failure.
*/
public function isOnline()
{
return isset($this->aServer[4
]) ?
$this->aServer[4
] : false; }
/**
* This function is used to get the server information.
*
* <code>
* Array
* (
* [password] => 0
* [players] => 9
* [maxplayers] => 500
* [hostname] => Everystuff Tr3s [MAD]oshi (03a Final) [FIXED]
* [gamemode] => Stunt/Race/DM/FR Everystuff
* [mapname] => Everystuff
* )
* </code>
*
* @return array Array of server information.
*/
public function getInfo()
{
@fwrite($this->rSocket, $this->createPacket('i'));
fread($this->rSocket, 11
);
$aDetails['password'] = (integer
) ord(fread($this->rSocket, 1
));
$aDetails['players'] = (integer
) $this->toInteger(fread($this->rSocket, 2
));
$aDetails['maxplayers'] = (integer
) $this->toInteger(fread($this->rSocket, 2
));
$iStrlen = ord(fread($this->rSocket, 4
)); if(!$iStrlen) return -1;
$aDetails['hostname'] = (string
) fread($this->rSocket, $iStrlen);
$iStrlen = ord(fread($this->rSocket, 4
)); $aDetails['gamemode'] = (string
) fread($this->rSocket, $iStrlen);
$iStrlen = ord(fread($this->rSocket, 4
)); $aDetails['mapname'] = (string
) fread($this->rSocket, $iStrlen);
return $aDetails;
}
/**
* This function gets a basic list of all the players on the server.
*
* Note as of 0.3.0, the amount of players that can be retrieved is
* limited to 100. This means if there are more players than 100,
* then no data will be returned, and it will be a blank array.
*
* <code>
* Array
* (
* [0] => Array
* (
* [nickname] => K1nNngO
* [score] => 72
* )
*
* [1] => Array
* (
* [nickname] => [kikOo]
* [score] => 150
* )
*
* [and so on...]
* )
* </code>
*
* @return array Array of player information.
*/
public function getBasicPlayers()
{
@fwrite($this->rSocket, $this->createPacket('c')); fread($this->rSocket, 11
);
$iPlayerCount = ord(fread($this->rSocket, 2
));
if($iPlayerCount > 0)
{
for($iIndex = 0; $iIndex < $iPlayerCount; ++$iIndex)
{
$iStrlen = ord(fread($this->rSocket, 1
)); (
"nickname" => (string
) fread($this->rSocket, $iStrlen), "score" => (integer
) $this->toInteger(fread($this->rSocket, 4
)), );
}
}
return $aDetails;
}
/**
* This function gets a detailed list of all the players on the server.
*
* Note as of 0.3.0, the amount of players that can be retrieved is
* limited to 100. This means if there are more players than 100,
* then no data will be returned, and it will be a blank array.
*
* <code>
* Array
* (
* [0] => Array
* (
* [playerid] => 0
* [nickname] => K1nNngO
* [score] => 72
* [ping] => 195
* )
*
* [1] => Array
* (
* [playerid] => 1
* [nickname] => [kikOo]
* [score] => 150
* [ping] => 375
* )
*
* [and so on...]
* )
* </code>
*
* @return array Array of player information.
*/
public function getDetailedPlayers()
{
@fwrite($this->rSocket, $this->createPacket('d')); fread($this->rSocket, 11
);
$iPlayerCount = ord(fread($this->rSocket, 2
));
for($iIndex = 0; $iIndex < $iPlayerCount; ++$iIndex)
{
$aPlayer['playerid'] = (integer
) ord(fread($this->rSocket, 1
));
$iStrlen = ord(fread($this->rSocket, 1
)); $aPlayer['nickname'] = (string
) fread($this->rSocket, $iStrlen);
$aPlayer['score'] = (integer
) $this->toInteger(fread($this->rSocket, 4
)); $aPlayer['ping'] = (integer
) $this->toInteger(fread($this->rSocket, 4
));
$aDetails[] = $aPlayer;
}
return $aDetails;
}
/**
* This function gets all the server rules from the server.
*
* Rules in this context are not player rules, they are client rules,
* like the weather of the server, time, and so on. (Custom rules,
* when supported by a SA-MP plugin, will be included here.)
*
* <code>
* Array
* (
* [gravity] => 0.007900
* [mapname] => Everystuff
* [version] => 0.3a
* [weather] => 0
* [weburl] => samp.madoshi.net
* [worldtime] => 12:00
* )
* </code>
*
* @return array Array of server rules.
*/
public function getRules()
{
@fwrite($this->rSocket, $this->createPacket('r')); fread($this->rSocket, 11
);
$iRuleCount = ord(fread($this->rSocket, 2
));
for($iIndex = 0; $iIndex < $iRuleCount; ++$iIndex)
{
$iStrlen = ord(fread($this->rSocket, 1
)); $sRulename = (string
) fread($this->rSocket, $iStrlen);
$iStrlen = ord(fread($this->rSocket, 1
)); $aDetails[$sRulename] = (string
) fread($this->rSocket, $iStrlen); }
return $aDetails;
}
/**
* @ignore
*/
private function toInteger($sData)
{
$iInteger = 0;
$iInteger += (ord($sData[0
]));
{
$iInteger += (ord($sData[1
]) << 8
); }
{
$iInteger += (ord($sData[2
]) << 16
); }
{
$iInteger += (ord($sData[3
]) << 24
); }
if($iInteger >= 4294967294)
{
$iInteger -= 4294967296;
}
return $iInteger;
}
/**
* @ignore
*/
private function createPacket($sPayload)
{
$sPacket = 'SAMP';
$sPacket .= chr(strtok($this->aServer[0], '.')); $sPacket .= chr($this->aServer[1
] & 0xFF
); $sPacket .= chr($this->aServer[1
] >> 8
& 0xFF
); $sPacket .= $sPayload;
return $sPacket;
}
}