Author Topic: PHP ASE parser  (Read 13003 times)

0 Members and 1 Guest are viewing this topic.

Offline FliesLikeABrick

  • Administrator
  • Flamebow Warrior
  • *****
  • Posts: 6144
    • Ultimate 13 Soldat
PHP ASE parser
« on: March 25, 2007, 09:57:35 pm »
here's another PHP one I just wrote, I think it is a bit more efficient, and a bit more featureful than Frenchie's is.  It provides some "fixed" versions of things like time remaining, time limit, and other values (strips text so they're int-only and ready for use)

The section that "fixes" the output to make it more readily usable is labelled with a comment and can be removed.


Code: [Select]
<?php
// PHP ASE parser for Soldat by FliesLikeABrick
// May be used for other games with a few slight modifications
// (mainly removing the part that pretties up the output)
// You are free to use this code for anything you want and redistribute/modify at will

function readASEString($sock,$length false) {
    
$length $length $length ord(fread($sock,1));
    return 
fread($sock,$length-1);
}

function 
ASE($host,$port) {
    
$info = Array();
    
$s fsockopen("udp://$host",$port+123);
    
fwrite($s,"s");
    
fread($s,4);
    
readASEString($s);
    
$info['port'] = readASEString($s);
    
$info['servername'] = readASEString($s);
    
$info['ip'] = gethostbyname($host);
    
$info['mode'] = readASEString($s);
    
$info['map'] = readASEString($s);
    
$info['version'] = readASEString($s);
    
$info['passworded'] = readASEString($s);
    
$info['numplayers'] = readASEString($s);
    
$info['maxplayers'] = readASEString($s);

    
// prime the loop conditional
    
$lengthstring fread($s,1);
    
$length ord($lengthstring);

    
// loop through the key/value pairs and set them
    
    
while($length != 1) {
        
$info[readASEString($s,$length)] = readASEString($s);
        
$lengthstring fread($s,1);
        
$length ord($lengthstring);
    }

    
// this entire section can be removed if you don't use them
    
$info['survival'] = $info['Survival'] == 'No' false:true;
    
$info['realistic'] = $info['Realistic'] == 'No' false:true;
    
$info['remaining'] = explode(' ',$info['Time Left']);
    
$info['remaining'] = $info['remaining'][0];
    
$info['minutes'] = explode(':',$info['remaining']);
    
$info['seconds'] = $info['minutes'][1];
    
$info['minutes'] = $info['minutes'][0];
    
$info['timelimit'] = explode(' ',$info['Time Limit']);
    
$info['timelimit'] = $info['timelimit'][0];
    
$info['protected'] = $info['Protected'] == 'No' false:true;
    
// end removable section

    
$info['players'] = Array();
    for(
$i=0;$i<$info['numplayers'];$i++) {
        
$info['players'][$i] = Array();
        
fread($s,1);
        
$info['players'][$i]['name'] = readASEString($s);
        
$info['players'][$i]['team'] = readASEString($s);
        
$info['players'][$i]['skin'] = readASEString($s);
        
$info['players'][$i]['score'] = readASEString($s);
        
$info['players'][$i]['ping'] = readASEString($s);
        
$info['players'][$i]['time'] = readASEString($s);
    }    
    return 
$info;
}

?>




It just returns an array with all of the information, as follows when used as ASE('u13.net',23073):
Code: [Select]
Array
(
    [port] => 23073
    [servername] => U13 CTF Public [Chicago]
    [ip] => 67.106.77.193
    [mode] => Capture the Flag
    [map] => ctf_Equinox
    [version] => 1.3.1
    [passworded] => 0
    [numplayers] => 12
    [maxplayers] => 12
    [Respawn Time] => 5 Secs
    [Bonus Frequency] => None
    [Survival] => No
    [Realistic] => No
    [System] => Linux
    [Time Left] => 16:32 Minutes
    [Time Limit] => 20 Minutes
    [Next Map] => ctf_Kampf
    [Protected] => No
    [respawntime] => 5 Secs
    [bonusfreq] => None
    [survival] =>
    [realistic] =>
    [os] => Linux
    [remaining] => 16:32
    [minutes] => 16
    [seconds] => 32
    [timelimit] => 20
    [nextmap] => ctf_Kampf
    [protected] =>
    [players] => Array
        (
            [0] => Array
                (
                    [name] => mr.ming
                    [team] => Bravo
                    [skin] => Bravo
                    [score] => 9
                    [ping] => 116
                    [time] => 3m
                )

            [1] => Array
                (
                    [name] => Kastor
                    [team] => Alpha
                    [skin] => Alpha
                    [score] => 7
                    [ping] => 16
                    [time] => 36m
                )

            [2] => Array
                (
                    [name] => El Padre
                    [team] => Bravo
                    [skin] => Bravo
                    [score] => 5
                    [ping] => 33
                    [time] => 55m
                )

            [3] => Array
                (
                    [name] => DI
                    [team] => Bravo
                    [skin] => Bravo
                    [score] => 7
                    [ping] => 83
                    [time] => 12m
                )

            [4] => Array
                (
                    [name] => Playing Soldat on my PSP
                    [team] => Alpha
                    [skin] => Alpha
                    [score] => 1
                    [ping] => 50
                    [time] => 3m
                )

            [5] => Array
                (
                    [name] => Sniper(1)
                    [team] => Bravo
                    [skin] => Bravo
                    [score] => 6
                    [ping] => 83
                    [time] => 17m
                )

            [6] => Array
                (
                    [name] => Diss
                    [team] => Alpha
                    [skin] => Alpha
                    [score] => 6
                    [ping] => 16
                    [time] => 79m
                )

            [7] => Array
                (
                    [name] => Milf.Hunter
                    [team] => Alpha
                    [skin] => Alpha
                    [score] => 2
                    [ping] => 50
                    [time] => 6m
                )

            [8] => Array
                (
                    [name] => Corsair
                    [team] => Bravo
                    [skin] => Bravo
                    [score] => 22
                    [ping] => 33
                    [time] => 10m
                )

            [9] => Array
                (
                    [name] => K-Vader
                    [team] => Alpha
                    [skin] => Alpha
                    [score] => 4
                    [ping] => 16
                    [time] => 9m
                )

            [10] => Array
                (
                    [name] => ==Gordon Freeman==
                    [team] => Alpha
                    [skin] => Alpha
                    [score] => 26
                    [ping] => 183
                    [time] => 16m
                )

            [11] => Array
                (
                    [name] => [Legends]--->Eclipse
                    [team] => Bravo
                    [skin] => Bravo
                    [score] => 26
                    [ping] => 16
                    [time] => 9m
                )

        )

)

« Last Edit: March 25, 2007, 10:43:50 pm by FliesLikeABrick »

Offline mikembm

  • Soldier
  • **
  • Posts: 210
Re: PHP ASE parser
« Reply #1 on: March 25, 2007, 10:06:54 pm »
Nice. A lot better than what I'm using currently. :D

Offline jrgp

  • Administrator
  • Flamebow Warrior
  • *****
  • Posts: 5036
Re: PHP ASE parser
« Reply #2 on: March 25, 2007, 10:18:00 pm »
Thank you Flies!

This will be perfect for building a server status panel on my soldat site.
There are other worlds than these

Offline FliesLikeABrick

  • Administrator
  • Flamebow Warrior
  • *****
  • Posts: 6144
    • Ultimate 13 Soldat
Re: PHP ASE parser
« Reply #3 on: March 25, 2007, 10:35:49 pm »
You should note that this code will just hang if a server is offline, I don't think it'll ever give an error.  If you want to check for a server to be online first, use some other method.

Offline Frenchie

  • Camper
  • ***
  • Posts: 358
  • SoldatHQ
Re: PHP ASE parser
« Reply #4 on: March 26, 2007, 01:10:39 am »
Wow cool just when I login I see this thread.
Good work looks good ;D

Except
Code: [Select]
Array
(
    [Survival] => No
    [Realistic] => No
    [Protected] => No
    [survival] =>
    [realistic] =>
    [protected] =>
The lowercase versions are empty..

When I get the time I'll try it out. :)
Soldat Lobby Avec Players -New Release! - Updated AGAIN!


Offline FliesLikeABrick

  • Administrator
  • Flamebow Warrior
  • *****
  • Posts: 6144
    • Ultimate 13 Soldat
Re: PHP ASE parser
« Reply #5 on: March 26, 2007, 01:16:03 am »
Wow cool just when I login I see this thread.
Good work looks good ;D

Except
Code: [Select]
Array
(
    [Survival] => No
    [Realistic] => No
    [Protected] => No
    [survival] =>
    [realistic] =>
    [protected] =>
The lowercase versions are empty..

When I get the time I'll try it out. :)

They aren't empty, they actually contain the boolean "false" value (since for the lowercase versions I translated Yes/No to true/false), that is just how print_r shows false.

Offline mikembm

  • Soldier
  • **
  • Posts: 210
Re: PHP ASE parser
« Reply #6 on: March 26, 2007, 02:05:37 am »
Too make it sort the players by score add this code right before the return $info line:

Code: [Select]
$sort = array();
foreach($info['players'] as $res)
$sort[] = $res['score'];
array_multisort($sort, SORT_DESC, $info['players']);

Offline mar77a

  • Global Moderator
  • Veteran
  • *****
  • Posts: 1295
  • mad
    • random stuffs
Re: PHP ASE parser
« Reply #7 on: March 26, 2007, 03:55:11 pm »
love the compact conditional

great work

Offline Laser Guy

  • Veteran
  • *****
  • Posts: 1679
Re: PHP ASE parser
« Reply #8 on: March 26, 2007, 04:02:25 pm »
and how do u use that?? (sry, but i never really was interested in that)
Text goes here...

Offline FliesLikeABrick

  • Administrator
  • Flamebow Warrior
  • *****
  • Posts: 6144
    • Ultimate 13 Soldat
Re: PHP ASE parser
« Reply #9 on: March 26, 2007, 04:37:42 pm »
and how do u use that?? (sry, but i never really was interested in that)

the compact conditional or the whole parser?

Offline Laser Guy

  • Veteran
  • *****
  • Posts: 1679
Re: PHP ASE parser
« Reply #10 on: March 26, 2007, 04:55:21 pm »
both
Text goes here...

Offline Trututu

  • Major(1)
  • Posts: 1
Re: PHP ASE parser
« Reply #11 on: March 29, 2007, 07:31:01 am »
Where do I have to change port and ip?

Offline mikembm

  • Soldier
  • **
  • Posts: 210
Re: PHP ASE parser
« Reply #12 on: March 29, 2007, 12:04:15 pm »
Can somebody make this using socket_create instead of fsockopen?

I ask this because most hosts have fsockopen disabled for security reasons.

Offline Thomas

  • Major
  • *
  • Posts: 76
    • mnus.de
Re: PHP ASE parser
« Reply #13 on: May 05, 2007, 04:01:32 pm »
With socket-functions.
The server sends the whole packet in one and you cannot read parts from it with socket functions.
So i connect with socket functions, get the whole thing, and continue with "virtual socket functions".
Works fine :)

Code is some posts below
« Last Edit: May 07, 2007, 07:59:55 am by Thomas »

Offline chrisgbk

  • Inactive Staff
  • Veteran
  • *****
  • Posts: 1739
Re: PHP ASE parser
« Reply #14 on: May 05, 2007, 11:20:28 pm »
With socket-functions.
The server sends the whole packet in one and you cannot read parts from it with socket functions.
So i connect with socket functions, get the whole thing, and continue with "virtual socket functions".
Works fine :)
Code: [Select]
<?php
// PHP ASE parser for Soldat by FliesLikeABrick
// changed from fsockopen to socket_* functions by minus
// May be used for other games with a few slight modifications
// (mainly removing the part that pretties up the output)
// You are free to use this code for anything you want and redistribute/modify at will

function readASEString($sock,$length false) {
    $length $length $length ord(vsocket_read($sock,1));
    return vsocket_read($sock,$length-1);
}

function 
ASE($host,$port) {
    $info = Array();
    // Using Socketfunctions
    $s socket_create(AF_INETSOCK_DGRAMSOL_UDP);
    socket_connect($s$host$port+123);
    socket_write($s,"s");
    $vsock socket_read($s,512); // read to "virtual socket"
    $vpos 0// virtual socket "pointer"
    socket_close($s);
    $s = &$vsock;
    vsocket_read($s,4);
    
    readASEString
($s);
    $info['port'] = readASEString($s);
    $info['servername'] = readASEString($s);
    $info['ip'] = gethostbyname($host);
    $info['mode'] = readASEString($s);
    $info['map'] = readASEString($s);
    $info['version'] = readASEString($s);
    $info['passworded'] = readASEString($s);
    $info['numplayers'] = readASEString($s);
    $info['maxplayers'] = readASEString($s);

    // prime the loop conditional
    $lengthstring vsocket_read($s,1);
    $length ord($lengthstring);

    // loop through the key/value pairs and set them
    
    
while($length != 1) {
        $info[readASEString($s,$length)] = readASEString($s);
        $lengthstring vsocket_read($s,1);
        $length ord($lengthstring);
    }

    // this entire section can be removed if you don't use them
    $info['survival'] = $info['Survival'] == 'No' false:true;
    $info['realistic'] = $info['Realistic'] == 'No' false:true;
    $info['remaining'] = explode(' ',$info['Time Left']);
    $info['remaining'] = $info['remaining'][0];
    $info['minutes'] = explode(':',$info['remaining']);
    $info['seconds'] = $info['minutes'][1];
    $info['minutes'] = $info['minutes'][0];
    $info['timelimit'] = explode(' ',$info['Time Limit']);
    $info['timelimit'] = $info['timelimit'][0];
    $info['protected'] = $info['Protected'] == 'No' false:true;
    // end removable section

    $info['players'] = Array();
    for($i=0;$i<$info['numplayers'];$i++) {
        $info['players'][$i] = Array();
        vsocket_read($s,1);
        $info['players'][$i]['name'] = readASEString($s);
        $info['players'][$i]['team'] = readASEString($s);
        $info['players'][$i]['skin'] = readASEString($s);
        $info['players'][$i]['score'] = readASEString($s);
        $info['players'][$i]['ping'] = readASEString($s);
        $info['players'][$i]['time'] = readASEString($s);
    }    
    
return $info;
}

function 
vsocket_read($vsock$length)
{
    global $vpos;
    $str substr($vsock$vpos$length);
    $vpos += $length;
    return $str;
}

?>

You read a maximum of 512 bytes; wouldn't that cause problems given the size of a packet is 1188?

Offline Thomas

  • Major
  • *
  • Posts: 76
    • mnus.de
Re: PHP ASE parser
« Reply #15 on: May 06, 2007, 03:24:44 am »
1188 is the size of the REFRESH packet, not of the ASE packet.
Anyways, i changed it to 2048 to avoid errors.
« Last Edit: May 06, 2007, 03:39:32 am by Thomas »

Offline chrisgbk

  • Inactive Staff
  • Veteran
  • *****
  • Posts: 1739
Re: PHP ASE parser
« Reply #16 on: May 06, 2007, 01:40:37 pm »
1188 is the size of the REFRESH packet, not of the ASE packet.
Anyways, i changed it to 2048 to avoid errors.

Whoops, don't know where my head was heh :-[

Anyhow, what you should do is loop until the socket doesn't return any more data (either it will return "" or FALSE) to ensure you read it all.

Offline mikembm

  • Soldier
  • **
  • Posts: 210
Re: PHP ASE parser
« Reply #17 on: May 06, 2007, 07:32:08 pm »
Thomas, can you also make it timeout if the server doesn't exist?

Offline Thomas

  • Major
  • *
  • Posts: 76
    • mnus.de
Re: PHP ASE parser
« Reply #18 on: May 07, 2007, 07:32:51 am »
Anyhow, what you should do is loop until the socket doesn't return any more data (either it will return "" or FALSE) to ensure you read it all.
Nope, if i don't read everything at once i get an error that wheather the packet is too big or what i want to read is too less.
I'll go check how big it is on a full server.

mikembm: yeah

--------------
I tried to use socket_get_option($s, getprotobyname('UDP'), SO_RCVBUF); to get the size of the buffer but it didn't work.

Now tested with 25 Players - about 900 Byte.
I set it to 4096 which should be fine.
--------------
Here it is: (with "server down" message (also returns false))
Code: [Select]
<?php
// PHP ASE parser for Soldat by FliesLikeABrick
// changed from fsockopen to socket_* functions by minus
// May be used for other games with a few slight modifications
// (mainly removing the part that pretties up the output)
// You are free to use this code for anything you want and redistribute/modify at will

function readASEString($sock,$length false) {
    
$length $length $length ord(vsocket_read($sock,1));
    return 
vsocket_read($sock,$length-1);
}

function 
ASE($host,$port) {
    
$info = Array();
    
// Using Socketfunctions
    
$s socket_create(AF_INETSOCK_DGRAMSOL_UDP);
    
socket_connect($s$host$port+123);
    if(
socket_last_error() == 10054)
    {
echo 'Server not running';
return false;
    }
    
socket_write($s,"s");
    
$vsock socket_read($s4096); // read to "virtual socket"
    
$vpos 0// virtual socket "pointer"
    
socket_close($s);
    
$s $vsock;
    
vsocket_read($s,4);
    
    
readASEString($s);
    
$info['port'] = readASEString($s);
    
$info['servername'] = readASEString($s);
    
$info['ip'] = gethostbyname($host);
    
$info['mode'] = readASEString($s);
    
$info['map'] = readASEString($s);
    
$info['version'] = readASEString($s);
    
$info['passworded'] = readASEString($s);
    
$info['numplayers'] = readASEString($s);
    
$info['maxplayers'] = readASEString($s);

    
// prime the loop conditional
    
$lengthstring vsocket_read($s,1);
    
$length ord($lengthstring);

    
// loop through the key/value pairs and set them
    
    
while($length != 1) {
        
$info[readASEString($s,$length)] = readASEString($s);
        
$lengthstring vsocket_read($s,1);
        
$length ord($lengthstring);
    }

    
// this entire section can be removed if you don't use them
    
$info['survival'] = $info['Survival'] == 'No' false:true;
    
$info['realistic'] = $info['Realistic'] == 'No' false:true;
    
$info['remaining'] = explode(' ',$info['Time Left']);
    
$info['remaining'] = $info['remaining'][0];
    
$info['minutes'] = explode(':',$info['remaining']);
    
$info['seconds'] = $info['minutes'][1];
    
$info['minutes'] = $info['minutes'][0];
    
$info['timelimit'] = explode(' ',$info['Time Limit']);
    
$info['timelimit'] = $info['timelimit'][0];
    
$info['protected'] = $info['Protected'] == 'No' false:true;
    
// end removable section

    
$info['players'] = Array();
    for(
$i=0;$i<$info['numplayers'];$i++) {
        
$info['players'][$i] = Array();
        
vsocket_read($s,1);
        
$info['players'][$i]['name'] = readASEString($s);
        
$info['players'][$i]['team'] = readASEString($s);
        
$info['players'][$i]['skin'] = readASEString($s);
        
$info['players'][$i]['score'] = readASEString($s);
        
$info['players'][$i]['ping'] = readASEString($s);
        
$info['players'][$i]['time'] = readASEString($s);
    }    
    return 
$info;
}

function 
vsocket_read($vsock$length)
{
    global 
$vpos;
    
$str substr($vsock$vpos$length);
    
$vpos += $length;
    return 
$str;
}

?>
« Last Edit: May 07, 2007, 07:54:54 am by Thomas »

Offline mikembm

  • Soldier
  • **
  • Posts: 210
Re: PHP ASE parser
« Reply #19 on: May 07, 2007, 11:41:23 am »
The Server not running part doesn't seem to be working for me.. it just stays on loading.
« Last Edit: May 07, 2007, 11:53:10 am by mikembm »