0

I'm running into an issue where I get a rather irregular string output from an RCON script on a server. When I send a command for returning players on a server, I get a string that looks like this:

rcon->get_players();

Players on server: [#] [IP Address]:[Port] [Ping] [GUID] [Name] -------------------------------------------------- 0 1.1.1.1:2 46 654321(OK) Player Name1 1 2.2.2.2:2 47 123456(OK) Player Name2 (2 players in total)

Here's what it looks like formatted if that helps:

Players on server: 
[#] [IP Address]:[Port] [Ping] [GUID] [Name] 
-------------------------------------------------- 
0 1.1.1.1:2 46 654321(OK) Player Name1 
1 2.2.2.2:2 47 123456(OK) Player Name2 
(2 players in total)

So the first 0 is their key id on the server (0-however many players), the second is their IP and PORT, the 47 is the ping, playerguid is their battleye guid, then their name inthe game, and then a total of the players returned.

However, it returns as one big string. I'm trying to figure out how to feed this into an array. So I get something like this:

array("id"=>"0", "Connection"=>"1.1.1.1:2", "ping"=>"46", "guid"=>"654321", "name"=>"Player Name1");

Any way I can achieve this, considering how irregular the output is? Having the headers in the string is throwing me off.

I followed Don't Panic's advice and it's close: UPDATED

echo "Player List:<br />";
$raw_players = $rcon->get_players();
$lines = explode("\n", $raw_players);
$end = count($lines)-1;
$keys = array('id','connection','ping','guid','name');
$regex = '/(\d+)\s+([\d\.\:]+)\s+(\d+)\s+(\d+)\(OK\)\s+(.+)/';
for ($i=3; $i < $end; $i++) {
    echo($lines[$i]);
    preg_match($regex, $lines[$i], $matches);
    unset($matches[0]);
    echo(var_dump($matches));
    $players[] = array_combine($keys, $matches);
}

And I get:

Player List:
0 98.193.210.251:2304 47 e0b29e3c7122bda33b5391c22594c776(OK) Colin Fox
array (size=0)
  empty
5
  • Could you give a longer excerpt of the real data? Just replace ip addresses and usernames. This one line is not very helpful. Commented Feb 8, 2016 at 19:04
  • that one line is two players that are connected, if I were to add more it would just look like this "2 1.1.1.1:2 46 654321(OK) Player Name3 " and keep repeating like that. Commented Feb 8, 2016 at 19:17
  • I formatted the table if that helps, it outputs as a runnon string, but I added line breaks to make it easier to see what it's writing out Commented Feb 8, 2016 at 19:19
  • How are you seeing the ouput of get_players()? If you're just echoing it to a browser screen, you probably won't see any line breaks that are there. Commented Feb 8, 2016 at 19:29
  • So if I do a var_dump, I get line breaks, if I don't and just echo it, it's a long string. Commented Feb 8, 2016 at 19:48

3 Answers 3

1

First, explode based on newlines to get an array of each line.

$lines = explode("\n", $string);

then you can construct a for loop excluding the header and footer like this:

$end = count($lines) - 1; // this will exclude the last line
for ($i=3; $i < $end; $i++) { // this will start at the fourth line

inside the loop, you can use explode again, with space as the delimiter, to get an array for every line.

$players[] = explode(' ', $lines[$i], 5);

This should work, because it looks like all the values at the beginning of each line do not have spaces. The third argument (5) will prevent the player name from being split on space (if it contains a space) because it restricts the size of the array generated by explode to 5 elements.

If you want the resulting array to have string keys, you can define an array of keys (before your loop):

$keys = array('id', 'connection', 'ping', 'guid', 'name');

And then use array_combine in your loop to create each player array.

$players[] = array_combine($keys, explode(' ', $lines[$i], 5));

With some new info about this string, it seems that some of the columns are separated by more than one space (and not the same number of spaces), so explode will not work for this. You can use a regular expression match in your loop instead.

$keys = array('id', 'connection', 'ping', 'guid', 'name');
$regex = '/(\d+)\s+([\d\.\:]+)\s+(\d+)\s+(\w+)\(OK\)\s+(.+)/';
for ($i=3; $i < $end; $i++) {
    preg_match($regex, $lines[$i], $matches);
    unset($matches[0]);
    $players[] = array_combine($keys, $matches);
}

The unset($matches[0]); is because the first element in the preg_match matches will be the entire string. Each of the subsequent values in $matches will be the contents of the capture groups. Here is an explanation of the regex:

/            begin pattern
(\d+)        capture one or more digits (id)
\s+          skip one or more spaces
([\d\.\:]+)  capture one or more characters either digit, dot, or colon (ip/port)
\s+          skip one or more spaces
(\d+)        capture one or more digits (ping)
\s+          skip one or more spaces
(\w+)        capture one or more alphanumeric characters (guid)
\(OK\)\s+    skip the (OK) and one or more spaces
(.+)         capture everything else (player name)
/            end pattern
Sign up to request clarification or add additional context in comments.

11 Comments

My problem is I don't get regex and I can never figure out how to use the stupid things. How do I regex three spaces and "(OK) "
for some reason matches is turning up empty
added the dump outputs above
@Flynn I made one more update, it wasn't matching because the guid actually isn't just digits.
woop there it is! this works perfectly, now I can just write error handlers and I'm good to go. Thank you very much!
|
0

You could easily use the explode() function on the string using the spaces as delimiters. From there just only use the second half of the array.

Alternatively use explode(), but set a limit such that the final element in the array can then be broken up into a second array.

2 Comments

So you're saying use explode and keep track of how many wasted array values there are and always start with the beginning of the list after the wasted values? Because the other part is that I'll need to get rid of the (total of blah players) statement at the end too.
If the format of the output string is always the same, once you run it and print the output a single time, you will be able to know which elements are relevant.
0

I would use a regular expression on that, that looks like this:

(\d+) ([\d.:]+) (\d+) (\d+)\([^)]+\) (.*)

combined with preg_match_all in PHP like that:

preg_match_all('#(\d+) ([\d.:]+) (\d+) (\d+)\([^)]+\) (.*)#', $players, $matches);

2 Comments

Ok I'm sorry, what? I suck with regular expressions, could you break that down barney style for me?
You could checkout for yourself at regex101.com. The regex matches digits, then digits, dot and colon, then digits, then digits followed by stuff inside (), then rest of line.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.