Querying Source Servers with PHP : Part 2

So I have my JSON data which contains all the query information which was returned from the Source Query Protocol. I’m storing it as a flat JSON file – the reason being (as discussed in my last post) is simply due to speed (or the assumption it would be faster). I don’t want to be getting into caching database queries, optimising the indexes, normalisation etc… As this project is for fun, let’s just store the JSON on the file system, and pull the data out when we need it.

What should I do with this data?

Well, that’s easy! Let’s create a website, and display it! I admit, I’m no front-end developer. So I chose to use a simple PHP Framework I wrote about 8 years ago. It’s a very simple MVC Framework, which consists of 10 files.

Without going into too much detail (maybe this is a topic for another blog post), here’s the file structure:

/config - Configuration Files

/content - Views

/data - Storage (JSON in this example)

/includes - Controllers

/models - Models

Very simple, but why spend time setting up and configuring something like Laravel or CodeIgnitor, when I can copy/paste my old code, and get cracking? I wrote a controller to loop through my list of servers, pull the data from each of the JSON files, then pass it to the view to be displayed.

CSS & HTML Framework

I decided to use Good old faithful Bootstrap (version 3), and customised some of the basic elements. Again, nothing special, just a quick and easy setup, and throwing together code in minutes!

No npm, grunt, composer, gulp or any other technology! Just raw PHP, CSS and HTML.

Here’s the finished design.

As you can see, I’m displaying information such as the Name, IP, Players and giving the user options to connect (or purchase their own, wink, wink). It’s just a simple “col-md-6” <div>. Nothing fancy, but it means when I add more servers, they can just drop in, and look apart of the page. There’s a few situations, where the divs don’t line up – mainly when there are many players online. However I could resolve this by adding an ellipsis to the players text – one for another time!

What about the Graph?

Ok I added the data used in the graph after my previous post. I simply added integer variable to the foreach loop, which I collate the number of players on each server together. I’m then throwing this data into another flat file with a timestamp.

<datetime>,<number of players>
<datetime>,<number of players>

I then pull this data back in the front end via the controller, and use ChartJS to display it.

 var ctx = document.getElementById("myChart");
 var data = {
 labels: ["04:20","04:25","04:30","04:35","04:40","04:45","04:50","04:55","05:00","05:05","05:10","05:15","05:20","05:25","05:30","05:35","05:40","05:45","05:50","05:55","06:00","06:05","06:10","06:15","06:20","06:25","06:30","06:35","06:40","06:45","06:50","06:55","07:00","07:05","07:10","07:15","07:20","07:25","07:30","07:35","07:40","07:45","07:50","07:55","08:00","08:05","08:10","08:15","08:20","08:25","08:30","08:35","08:40","08:45","08:50","08:55","09:00","09:05","09:10","09:15",],
 datasets: [
 label: "Players",
 fill: true,
 lineTension: 0,
 backgroundColor: "rgba(187,255,0, 0.09)",
 borderColor: "rgba(187,255,0,1)",
 borderCapStyle: 'butt',
 borderDash: [],
 borderDashOffset: 0.0,
 borderJoinStyle: 'miter',
 pointBorderColor: "rgba(187,255,0,1)",
 pointBackgroundColor: "#fff",
 pointBorderWidth: 0,
 pointHoverRadius: 5,
 pointHoverBackgroundColor: "rgba(187,255,0,1)",
 pointHoverBorderColor: "rgba(187,255,0,1)",
 pointHoverBorderWidth: 2,
 pointRadius: 0,
 pointHitRadius: 10,
 data: [2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,5,5,8,4,4,4,4,4,4,4,4,5,6,6,6,6,6,6,6,6,4,4,5,5,5,5,5,4,4,5,6,5,4,5,6,7,8,8,8,9,8,8,8],
 spanGaps: false,
 var myChart = new Chart(ctx, {
 type: 'line',
 data: data,
 options: {
 legend: {
 display: false
 responsive : true,
 scaleShowLabels : false,
 scales: {
 yAxes: [{
 display: true,
 ticks: {
 stepSize: 1,
 beginAtZero: true
 xAxes: [{
 display: false

As the cron is running every 5 minutes, the graph is showing the number of players, every 5 minutes. Really simple, but a nice addition to the page.

I’d imagine, when I add more servers, I could add options to the graph for different time periods (hour, day, month). This will allow me to see the peak times players are online.

Around this page, I’ve started to build up other pages, and more elements I can use. I’ll leave this blog post here, and maybe continue in another.

It’s been a very fun experience so far, and even though I’m not using any bleeding edge/funky languages or technologies. It’s been nice to refresh my knowledge of Bootstrap, CSS, jQuery, and also learn how Source Query Protocol works!

Here’s where I’ve left the website so far:

Hopefully as time allows, I’ll begin to build it up, and add more pages and servers!

Querying Source Servers with PHP : Part 1

Over the Christmas Period, I decided to develop a website to monitor the multitude of gaming servers that I host. As a game server provider, I’ve often wondered how many players are actively playing across the network.

For this, I decided to use a simple LEMP (Linux, NGINX, MySQL, PHP) environment. Furthermore, I wanted this website to be heavily reliant on JSON data, and would try to avoid pulling data from MySQL where possible – as I’m assuming pulling from a JSON file (using caching), is faster than from MySQL.

The first task was to obtain a list of the game servers on our network. This was quite easy, due to the fact our billing system already contains this information.

I built a JSON string containing an array of the servers:


{"1":{"id": "1", "protocol":"steam", "game": "Rust","ip":"", "port": "28015"},"2":{"id": "2", "protocol":"steam", "game": "Rust","ip":"", "port": "28015"}}

Lovely and simple!

ID: Unique Primary Key
Protocol: Steam
Game: The game!
IP: Servers IP
Port: Servers Port


Now, I have my list of servers. Next it to query them for the data! To do this, we need to interrogate the Source Query Protocol. There’s many open source examples of this out there. I found one by xPaw at https://github.com/xPaw/PHP-Source-Query – It’s very well coded class, and rather than reinventing the wheel, I choose to use his class.

So, I create a cron, to query the server list on a predefined interval.

Here’s the code.

It’s a proof of concept, so don’t judge the coding standards!


require __DIR__ . '/SourceQuery/bootstrap.php';
use xPaw\SourceQuery\SourceQuery;

define('SQ_TIMEOUT', 1);
define('SQ_ENGINE', SourceQuery::SOURCE);

$servers = json_decode(file_get_contents('servers.json'));

foreach ($servers as $server) {
 switch ($server->protocol) {
 case 'steam':
 $data = fetchSteam($server->id, $server->ip, $server->port, $server->game);

function fetchSteam($id, $ip, $port, $game)

 $Query = new SourceQuery();

 try {
 $Query->Connect($ip, $port, SQ_TIMEOUT, SQ_ENGINE);

 $data["info"] = $Query->GetInfo();
 $data["info"]["Game"] = $game;
 $data["info"]["IP"] = $ip;
 $data["info"]["Port"] = $port;
 $data["players"] = $Query->GetPlayers();
 $data["rules"] = $Query->GetRules();

 file_put_contents('servers/' . $id . '.json', json_encode($data));
 } catch (Exception $e) {
 echo $e->getMessage();
 } finally {

I’m looping through the list of servers, querying each one – then storing the returned data in a separate JSON file (1.json, 2.json etc).

Why the switch statement? Well, not every game server we host is powered by Steam, eventually I plan to add more protocols…

So, what data can we pull back from the Source Query Protocol?

Well, here’s the JSON decoded (pretty format thanks to http://jsonviewer.stack.hu/)




As you can see, we get quite a fair amount of information back from the Source Query Protocol. The only thing I’m struggling to get is the Players SteamID. However, I have no requirement for it, so it’s not a pressing issue – If I wanted to display or track players in more depth across the network, I would need the SteamID.

I’ll leave this blog post here for now, and write Part 2 with the details of what I did next (The interface & graphing).

Shorthand If/Else (ternary) Statements – C#, C++, Python & PHP

I’ve been going through the multiple languages I know recently, and refreshing my knowledge. After working with Python for a few months, I found going back to C# very easy.

I’ve noticed many similarities except for a few; In my opinion the ternary operator slightly differs from each language. So I’d thought I’d write these findings down for future use.

C# & C++

variable = (input > 0) ? 'true' : 'false';


variable = 'true' if input > 0 else 'false'


$variable = ($input > 0) ? 'true' : 'false';

R1Soft : GC overhead limit exceeded

I encountered this issue on the R1Soft Web Interface last week, which I had to open a support ticket for with R1Soft’s brilliant support.


When trying to run tasks like a backup, run, or restore I would encounter the error messages as seen above.

The error was down to the maximum amount of memory which was assigned to the Java Heap and PermGen. After contacting R1Soft’s support, I was pointed to a config file where you can adjust the java heap and permgen values.

To increase the java heap:

# Edit /usr/sbin/r1soft/conf/server.conf

  1. Locate the following line at the top: “compute.maxmemory=true” and change it to… “compute.maxmemory=false
  2. Locate the following line: “#maxmemory=” and remove the hash symbol. Set it to use 8192 (in MB). It should now read… “maxmemory=8192
  3. Save the server.conf file.

# Now restart the CDP Server Service.

  1. /etc/init.d/cdp-server stop
  2. /etc/init.d/cdp-server restart


To increase the PermGen Space:

# Edit /usr/sbin/r1soft/conf/server.conf

  1. Locate the following line “additional.10=-XX:MaxPermSize=256m” and change it to… “additional.10=-XX:MaxPermSize=1024m
  2. Save the server.conf file.

# Now restart the CDP Server Service

  1. /etc/init.d/cdp-server stop
  2. /etc/init.d/cdp-server restart


With browsers such as Google Chrome and Mozilla Firefox forcing websites to use better ciphers, along with websites such as PayPal no longer support older versions of TLS it’s time to update your NGINX installations with the latest version of OpenSSL (TLS 1.2+) and set some decent ciphers.

I’m finding the following cipher set are passing tests such as SSL Labs and CryptoReport – this could change in the future.


Add those to your NGINX configuration files (usually in /etc/nginx/conf.d/ on CentOS), and restart NGINX.

Please be aware at the time of writing this article, the ciphers in the list were passing SSL tests, however as these requirements change and new exploits are released, this may change. I’ll try to update the blog with any such changes.

At the time of writing, the ciphers were secure against the following vulnerabilities:

  • Poodle (TLS)
  • Poodle (SSLv3)

OpenVZ IO Limits

OpenVZ has had IO limits for years, but I’ve never really had opportunity to implement them, especially with SSD disks becoming cheaper and the standard.

However in some cases implementing IO Limits on your OpenVZ VMs can be a good practice. Especially on Database servers (High usage MySQL/MariaDB) or Mail servers (Exim on cPanel can be an IO hog at times).

Depending on your disks, and how many OpenVZ containers live on your host, you may wish to adjust the following to better suited values.

vzctl set 100 --iolimit 10M --save

10MB/s seems to be the perfect value for my requirements. It doesn’t over limit IO usage, but if a VM is behaving badly, it limits the impact on the other VMs. IO Limiting effects both read and write, and there is also an option to allow bursts of up to 3x.


  • Kernel Version: 2.6.32-042stab084.3 or higher
  • VZCTL Version: 4.6 or higher

Further information can be found on the OpenVZ Wiki.

Knapsack Problem (0-1 solution) – Dynamic Algorithm

I’ve recently dug up old code from my University days, which I thought I’d share for the benefit/misfortune of others.

There’s a common problem in programming called the knapsack problem. Here was my solution based on the dynamic algorithm.

# Math is used to floor/round the floats to an interger and back!
import math
# Total allowed weight
totalWeight = 2392;

# Define the items name, Weight, Profit
items = (("Weapon and Ammunition",    4.13, 1.4),
         ("Water", 2.13, 2.74),
         ("Pith Helmet", 3.03, 1.55),
         ("Sun Cream", 2.26, 0.82),
         ("Tent", 3.69, 2.38),
         ("Flare Gun", 3.45, 2.93),
         ("Olive Oil", 1.09, 1.77),
         ("Firewood", 2.89, 0.53),
         ("Kendal Mint Cake", 1.08, 2.77),
         ("Snake Repellant Spray", 3.23, 4.29),
         ("Bread", 2.29, 2.85),
         ("Pot Noodles", 0.55, 0.34),
         ("Software Engineering Textbook", 2.82, -0.45),
         ("Tinned Food", 2.31, 2.17),
         ("Pork Pie", 1.63, 1.62))

# Get the total of bagged items.
def totalvalue(comb):
    totwt = totval = 0
    for item, wt, val in comb:
        totwt  += wt
        totval += val
    return (totval, -totwt) if totwt <= totalWeight else (0, 0)

# The knapsack 0-1 Dynamic Programming Algorithm.
def knapsack(items, limit):
    table = [[0 for w in range(limit + 1)] for j in xrange(len(items) + 1)]

    for j in xrange(1, len(items) + 1):
        item, wt, val = items[j-1]
        wt = int(wt * 100)
        val = int(val * 100)
        for w in xrange(1, limit + 1):
            if wt > w:
                table[j][w] = table[j-1][w]
                table[j][w] = max(table[j-1][w],
                                  table[j-1][w-wt] + val)

    result = []
    w = limit
    for j in range(len(items), 0, -1):
        was_added = table[j][w] != table[j-1][w]

        if was_added:
            item, wt, val = items[j-1]
            wt = int(wt * 100)
            val = int(val * 100)
            w -= wt

    return result

# Bag the items
bagged = knapsack(items, totalWeight)

# Print the results
print("Bagged the following items\n  " +
      '\n  '.join(sorted(item for item,_,_ in bagged)))
val, wt = totalvalue(bagged)

print("Total Value: %f - Total Weight: %f" % (float(val), float(-wt)))


Knapsack Problem (0-1 solution) – Greedy Algorithm

I’ve recently dug up old code from my University days, which I thought I’d share for the benefit/misfortune of others.

There’s a common problem in programming called the knapsack problem. Here was my solution based on the greedy algorithm.

# Name, Weight and Value of Items
items = [("Weapon and Ammunition",    4.13, 1.4),
         ("Water", 2.13, 2.74),
         ("Pith Helmet", 3.03, 1.55),
         ("Sun Cream", 2.26, 0.82),
         ("Tent", 3.69, 2.38),
         ("Flare Gun", 3.45, 2.93),
         ("Olive Oil", 1.09, 1.77),
         ("Firewood", 2.89, 0.53),
         ("Kendal Mint Cake", 1.08, 2.77),
         ("Snake Repellant Spray", 3.23, 4.29),
         ("Bread", 2.29, 2.85),
         ("Pot Noodles", 0.55, 0.34),
         ("Software Engineering Textbook", 2.82, -0.45),
         ("Tinned Food", 2.31, 2.17),
         ("Pork Pie", 1.63, 1.62)]

# Maximum Weight Allowed.
MAXIMUM = 15.0

# Sort items based on effeciency (value/weight).
sorted_items = sorted(((value/amount, amount, name)
                       for name, amount, value in items),
                      reverse = True)

# Define the total weight and value.
wt = val = 0
# Define an array for the items which are bagged.
bagged = []

# Loop through the item array and bag items until full
for unit_value, amount, name in sorted_items:
    weight = min(MAXIMUM - wt, amount)
    wt     += weight
    addval  = weight * unit_value
    val    += addval
    bagged += [(name, weight, addval)]
    if wt >= MAXIMUM:

# Print results!
print("    ITEM   WEIGHT  VALUE")
print("\n".join("%10s %6.2f %6.2f" % item for item in bagged))
print("\nTotal Bagged Weight: %5.2f\nTotal Bagged Value: %5.2f" % (wt, val))

New Website/Blog Thing

So, for a few years I’ve had a static landing page as my website. I thought it was time for a makeover. This time, rather than posting absolutely anything, I’m going to keep it strictly about coding, development, and tech.

On a side note. I’m slowly opening up more of my GitHub repositories to the public. I’ve got many private repositories, which I started with the intention of releasing as an Open Source projects. I’ll try and post about it on here when I do!

1 2