You set the wrong locale. Right now you set it to ISRO's (18), which is why you see Ratio and Country. Change it to the correct locale (22) and it should display correctly.Quote:
Array ( [0] => [1] => Warning: fsockopen() has been disabled for security reasons in /users/srstats/www/ServerStats.php on line 59 [2] => Error [3] => A connection could not be established: [: ] )
Array ( [0] => Error [1] => The version packet was rejected because a manual patch is needed. [2] =>Quote:
HOW I FIX THAT PLÝZZ??
Making your text won't make anyone answer it faster. We can read text like THIS just normally. The error is probably a wrong configured server/config file.
$_REQUEST["locale"] = 49; $_REQUEST["version"] = 130;
VSRO Locale is 22, and version is the client of the version. If It's default it will be 088.Quote:
Hi Im running a VSRO Server. what sould i write in these lines?
were can i find it out? i use these serverfiles:Code:$_REQUEST["locale"] = 49; $_REQUEST["version"] = 130;
[Only registered and activated users can see links. Click Here To Register...]
Thanks alot for any help...
<?php
class silkroadAPI
{
private $host;
private $port;
private $locale;
private $version;
private $timeout;
private $s; //SilkroadSecurity
private $socket;
private $response;
private $connected;
private $big_packet;
private $big_opcode;
private $big_count;
private $big_data;
public $serverList;
function __construct($host, $port, $locale, $version, $timeout)
{
$this->host = $host;
$this->port = $port;
$this->locale = $locale;
$this->version = $version;
$this->timeout = $timeout;
$this->s = new SilkroadSecurity();
}
function Send( $socket, $buffer )
{
if( !socket_send_buffer( $socket, $buffer, strlen( $buffer ) ) )
{
@socket_close( $socket );
echo( "Error" . PHP_EOL . "<br />" . PHP_EOL . "Could not send data." );
return false;
}
return true;
}
/*
* Connect to the Joymax server
*/
function connect()
{
$this->socket = @socket_create( AF_INET, SOCK_STREAM, 0 );
if( $this->socket === false )
{
throw new Exception('Could not create the socket');
return;
}
@socket_set_nonblock( $this->socket );
@socket_connect( $this->socket, $this->host, $this->port );
@socket_set_block( $this->socket );
$r = array( $this->socket );
$w = array( $this->socket );
$e = array( $this->socket );
if( false === @socket_select( $r, $w, $e, $this->timeout ) )
{
@socket_close( $this->socket );
throw new Exception( "A connection could not be established." );
return;
}
if( count( $w ) != 1 || count( $e ) == 1 )
{
@socket_close( $this->socket );
throw new Exception( "A connection could not be established." );
return;
}
$this->connected = true;
$this->big_packet = false;
$this->big_opcode = 0;
$big_count = 0;
$big_data = "";
while( $this->connected )
{
$r = array( $this->socket );
$w = NULL;
$e = NULL;
if( false === @socket_select( $r, $w, $e, $this->timeout ) )
{
@socket_close( $this->socket );
echo( "Error" . PHP_EOL . "<br />" . PHP_EOL . "There was an error with the connection." );
return;
}
if( count( $r ) != 1 )
{
@socket_close( $this->socket );
throw new Exception( "No more data was received on the socket." );
return;
}
$this->response = socket_recv_buffer( $this->socket, 2 );
if( $this->response == false )
{
@socket_close( $this->socket );
throw new Exception( "Could not receive data." );
return;
}
$header = "";
$array = unpack( "vsize", $this->response );
$this->response = "";
$size = (int)$array["size"];
if( bcand( $size, 0x8000 ) > 0 )
{
$expected_size = 0;
$input_size = bcadd( 4, bcand( $size, 0x7FFF ) );
$lVal = bcmod( $input_size, 8 );
if( $lVal != 0 )
{
$expected_size = bcsub( bcadd( $input_size, 8 ), $lVal );
}
else
{
$expected_size = $input_size;
}
$enc_payload = socket_recv_buffer( $this->socket, $expected_size );
$enc_payload_tmp = "";
while( strlen( $enc_payload ) > 0 )
{
$val = unpack( "N", $enc_payload );
$enc_payload = substr( $enc_payload, 4 );
$enc_payload_tmp .= bcbytearray( hexdec( dechex( $val[1] ) ), 4 );
}
$dec_payload = mcrypt_ecb( MCRYPT_BLOWFISH, bcbytearray( $this->s->m_handshake_blowfish_key, 8 ), $enc_payload_tmp, MCRYPT_DECRYPT );
$dec_payload_arr = array();
while( strlen( $dec_payload ) > 0 )
{
$val = unpack( "N", $dec_payload );
$dec_payload = substr( $dec_payload, 4 );
$val = hexdec( dechex( $val[1] ) );
$m = bcbytearray( $val , 4 );
$m = unpack( "C*", $m );
for( $x = 1; $x <= 4; ++$x )
{
array_push( $dec_payload_arr, $m[$x] );
}
}
$payload = "";
$dec_payload_arr = array_splice( $dec_payload_arr, 0, $input_size );
for( $x = 0; $x < count( $dec_payload_arr ); ++$x )
{
$payload .= pack( "C", bchexdec( bcdechex( $dec_payload_arr[$x] ) ) );
}
$header = unpack( "vopcode/vsecurity", $payload );
$header["size"] = bcsub( $input_size, 4 );
$header["encrypted"] = true;
if( $header["size"] > 0 )
{
$payload = substr( $payload, 4 );
$header["payload"] = hexdump( $payload );
}
else
{
$payload = "";
}
}
else
{
$header = socket_recv_buffer( $this->socket, 4 );
$header = unpack( "vopcode/vsecurity", $header );
$header["size"] = $size;
$header["encrypted"] = false;
if( $size > 0 )
{
$payload = socket_recv_buffer( $this->socket, $size );
$header["payload"] = hexdump( $payload );
}
}
$this->parsePackets($header,$payload);
}
}
function parsePackets($header,$payload)
{
switch($header["opcode"])
{
case 0x5000:
$this->packetHandShake($header,$payload);
break;
case 0x600D:
$this->packet0x600D($header, $payload);
break;
case 0x2001:
$new_payload = pack( "Cva9V", $this->locale, 9, "SR_Client", $this->version );
$packet_payload = $this->s->format_packet( 0x6100, $new_payload, true );
$this->Send( $this->socket, $packet_payload );
break;
case 0xA107:
$count = unpack_uint8( $payload );
for( $x = 0; $x < $count; ++$x )
{
$id = unpack_uint8( $payload );
$len = unpack_uint16( $payload );
$ip = unpack_ASCII( $payload, $len );
$port = unpack_uint16( $payload );
//echo( "id: $id ip: $ip port: $port<br />" );
}
break;
case 0xA101:
$this->packetServerList($header, $payload);
$this->connected = false;
break;
}
}
function packetServerList($header, $payload)
{
$header = true;
$new_server = unpack_uint8( $payload );
while( $new_server == 1 )
{
$id = unpack_uint8( $payload );
$len = unpack_uint16( $payload );
$name = unpack_ASCII( $payload, $len );
$new_server = unpack_uint8( $payload );
}
$new_server = unpack_uint8( $payload );
while( $new_server == 1 )
{
$id = unpack_uint16( $payload );
$len = unpack_uint16( $payload );
if( $this->locale == 18 )
{
$c = chr( unpack_int8( $payload ) );
if( $c == '1' )
{
$c = "USA";
}
else if( $c == '0' )
{
$c = "Korea";
}
$len--;
$name = unpack_ASCII( $payload, $len );
$ratio = unpack_float( $payload );
}
else
{
$name = unpack_ASCII( $payload, $len );
$cur = unpack_uint16( $payload );
$max = unpack_uint16( $payload );
}
$state = unpack_uint8( $payload );
if( $this->locale == 4 || $this->locale == 23 ) // csro/vsro extra bytes
{
$extra1 = unpack_uint8( $payload );
$extra2 = "";
if( $extra1 == 1 )
{
$extra2 = unpack_uint8( $payload );
}
}
if( $this->locale == 40 ) // russian
{
$name = mb_convert_encoding( $name, "utf-8", "Windows-1251" );
}
else if( $this->locale == 2 ) // korean
{
$name = mb_convert_encoding( $name, "utf-8", "EUC-KR" );
}
else if( $this->locale == 4 ) // chinese
{
$name = mb_convert_encoding( $name, "utf-8", "EUC-CN" );
}
else if( $this->locale == 12 ) // taiwanese
{
$name = mb_convert_encoding( $name, "utf-8", "BIG-5" );
}
else if( $this->locale == 15 ) // japanese
{
$name = mb_convert_encoding( $name, "utf-8", "EUC-JP" ); // not tested, might need to use something else
}
else // everything else that uses default windows codepage
{
$name = mb_convert_encoding( $name, "utf-8", "Windows-1252" );
}
if( $this->locale == 18 )
{
if( $header )
{
//print( "Id|Country|Name|Ratio|State" . PHP_EOL . "<br />" . PHP_EOL );
}
$serverinfo['ID'] = $id;
$serverinfo['country'] = $c;
$serverinfo['name'] = $name;
$serverinfo['currentusers'] = round($ratio * 3500);
$serverinfo['maxusers'] = 3500;
$serverinfo['ratio'] = $ratio;
$serverinfo['state'] = $state;
$this->serverList[] = $serverinfo;
}
else if( $this->locale == 4 || $this->locale == 23 )
{
if( $header )
{
print( "Id|Name|Cur|Max|State|Extra1|Extra2" . PHP_EOL . "<br />" . PHP_EOL );
}
print( "$id|$name|$cur|$max|$state|$extra1|$extra2" . PHP_EOL . "<br />" . PHP_EOL );
}
else
{
if( $header )
{
print( "Id|Name|Cur|Max|State" . PHP_EOL . "<br />" . PHP_EOL );
}
print( "$id|$name|$cur|$max|$state" . PHP_EOL . "<br />" . PHP_EOL );
}
$new_server = unpack_uint8( $payload );
$header = false;
}
}
function packetHandShake($header, $payload)
{
$data = unpack( "Cflag", $payload );
if( $data["flag"] == 0x0E )
{
$data = unpack( "Cflag/Vblowfishlow/Vblowfishhigh/Vseedcount/Vseedcrc/Vhandshakelow/Vhandshakehigh/Vg/Vp/VA", $payload );
$packet_payload = $this->s->Handshake_E( $data );
if( !$this->Send( $this->socket, $packet_payload ) )
return;
}
else if( $data["flag"] == 0x10 )
{
$data = unpack( "Cflag/Vhandshakelow/Vhandshakehigh", $payload );
$packet_payload = $this->s->Handshake_10( $data );
if( !$this->Send( $this->socket, $packet_payload ) )
return;
$new_payload = pack( "va9C", 9, "SR_Client", 0 );
$packet_payload = $this->s->format_packet( 0x2001, $new_payload, true );
if( !$this->Send( $this->socket, $packet_payload ) )
return;
}
else
{
@socket_close( $this->socket );
echo( "Unknown flag: " . dechex( $data["flag"] ) );
return;
}
}
function packet0x600D($header, $payload)
{
$type = unpack_uint8( $payload );
if( $type == 1 ) // header
{
if( $this->big_packet == true )
{
@socket_close( $this->socket );
echo( "Error" . PHP_EOL . "<br />" . PHP_EOL . "Received an invalid 0x600d packet. Duplicate header." );
return;
}
$this->big_count = unpack_uint16( $payload );
$this->big_opcode = unpack_uint16( $payload );
$this->big_packet = true;
}
else if( $type == 0 ) // data
{
if( !$this->big_packet )
{
@socket_close( $this->socket );
echo( "Error" . PHP_EOL . "<br />" . PHP_EOL . "Received an invalid 0x600d packet. Out of order data." );
return;
}
$this->big_data .= $payload; // Append the data
$payload = "";
--$this->big_count; // One less packet chunk to process
if( $this->big_count == 0 ) // The massive packet is complete now
{
$this->big_packet = false;
if( $this->big_opcode == 0xA100 ) // 0x6100 response
{
$res = unpack_uint8( $this->big_data );
if( $res == 1 ) // Success, now request server list
{
if( $this->locale == 18 ) // ISRO has this
{
$new_payload = "";
$packet_payload = $this->s->format_packet( 0x6107, $new_payload, true );
if( !$this->Send( $this->socket, $packet_payload ) )
return;
}
$new_payload = "";
$packet_payload = $this->s->format_packet( 0x6101, $new_payload, true );
if( !$this->Send( $this->socket, $packet_payload ) )
return;
}
else // Error, can be version, GatewayServer being down, etc...
{
print( "Error" . PHP_EOL . "<br />" . PHP_EOL );
$res = unpack_uint8( $this->big_data );
if( $res == 4 )
{
print( "The version packet was rejected because the GatewayServer is closed." . PHP_EOL . "<br />" . PHP_EOL );
}
else if( $res == 2 )
{
print( "The version packet was rejected because it is outdated." . PHP_EOL . "<br />" . PHP_EOL );
$len = unpack_uint16( $this->big_data );
$ip = unpack_ASCII( $this->big_data, $len );
$port = unpack_uint16( $this->big_data );
$new_version = unpack_uint32( $this->big_data );
print( "$ip|$port|$new_version" . PHP_EOL . "<br />" . PHP_EOL );
$new_file = unpack_uint8( $this->big_data );
while( $new_file == 1 )
{
$id = unpack_uint32( $this->big_data );
$len = unpack_uint16( $this->big_data );
$name = unpack_ASCII( $this->big_data, $len );
$len = unpack_uint16( $this->big_data );
$path = unpack_ASCII( $this->big_data, $len );
$size = unpack_uint32( $this->big_data );
$in_pk2 = unpack_uint8( $this->big_data );
$new_file = unpack_uint8( $this->big_data );
print( "$id|$name|$path|$size|$in_pk2" . PHP_EOL . "<br />" . PHP_EOL );
}
break;
}
else if( $res == 1 )
{
print( "The version packet was rejected because the version is too new." . PHP_EOL . "<br />" . PHP_EOL );
}
else if( $res == 5 )
{
print( "The version packet was rejected because the version is too old." . PHP_EOL . "<br />" . PHP_EOL );
}
else if( $res == 6 )
{
print( "The version packet was rejected because a manual patch is needed." . PHP_EOL . "<br />" . PHP_EOL );
}
else
{
print( "The version packet was rejected (Code: $res)." . PHP_EOL . "<br />" . PHP_EOL );
}
print( hexdump( $this->big_data ) );
print( PHP_EOL . "<br />" );
@socket_close( $this->socket );
return;
}
}
else if( $this->big_opcode == 0x2005 ) // server info, ignore
{
}
else if( $this->big_opcode == 0x6005 ) // server info, ignore
{
}
else
{
@socket_close( $this->socket );
echo( "Error" . PHP_EOL . "<br />" . PHP_EOL . "Unknown packet contained in 0x600d: 0x" . dechex( $this->big_opcode ) );
return;
}
$this->big_opcode = 0;
$this->big_data = "";
}
}
else
{
@socket_close( $this->socket );
echo( "Error" . PHP_EOL . "<br />" . PHP_EOL . "Unknown type(" . $type . ") in 0x600d." );
return;
}
}
}
?>
<?php
$cachefile = "cache/serverlist_json.cache";
if(file_exists($cachefile) && (filemtime($cachefile) + (5 * 60) ) > time() )
{
$fh = fopen("cache/serverlist_json.cache", 'r');
$theData = fread($fh, filesize("cache/serverlist_json.cache"));
fclose($fh);
echo $theData;
}else{
require( "SilkroadSecurity.php" );
require( "SocketUtility.php" );
require( "HexDump.php" );
require( "class.silkroadAPI.php" );
$api = new silkroadAPI("gwgt1.joymax.com",15779,18,364,5);
$api->connect();
$fh = fopen($cachefile, 'w') or die("can't open file");
fwrite($fh, json_encode($api->serverList));
fclose($fh);
echo json_encode($api->serverList);
}
?>
Very nice good jobQuote:
Short and sweet: this project allows you to have native server stats via PHP without having to use an external program to collect the server stats.
In other words, everyone should be able to host their own server stats on their site as long as they have a capable web server. I've tested locally and on a remote host, so it should be fine with most modern hosts. Unfortunately, as tricky as this code was to write, there is nothing that can be done if your server does not support all the components.
This is a bare minimal release, so you will need some web designing skills to make it look "pretty" or additional php/database skills to enhance it more.
readme.txt
Just a helpful hint: if you wonder how to "loop" updates, take a look into CRON jobs (your web host must support them!). If not, you will have to come up with another solution (such as using a program that always runs to force the refresh).
Also, using these concepts, you can use this code for other games and projects in a similar fashion! PHP is quite capable afterall.
Enjoy! :)
Troubleshooting:
Make a test page with the following code:
Upload the page, run the script, and save the results. Delete the page afterwards.Code:<?php phpinfo(); ?>
Q. Why do I see an empty page when I try to use the server stats?
A. This usually means a needed php component is not there. Check for the following strings in "Configure Command": '--enable-sockets', '--with-mcrypt=', and '--enable-bcmath'.
Look for each section in the configuration. It should look something like the following.
BCMath: [Only registered and activated users can see links. Click Here To Register...]
mcrypt: [Only registered and activated users can see links. Click Here To Register...]
sockets: [Only registered and activated users can see links. Click Here To Register...]
Q. Can more/less debugging information be provided for PHP errors?
A. In short, no. It all depends on how PHP is configured and most hosts are really restrictive to changes made to PHP. Unless you are running your own server where you can reconfigure PHP!
Q. What do the different errors mean?
A. Most errors should be self descriptive. Try to search the text in the php files to see what they are associated with.
Q. I get a bunch of MCRYPT warnings when trying to run the stats?
A. Please see [Only registered and activated users can see links. Click Here To Register...].
More Q/A will be added as they arise.
Try this: [Only registered and activated users can see links. Click Here To Register...]Quote:
Very nice good job
but the MCRYPT has a discontinued feature in the newest PHP Versions