<?php 
// error_reporting( 0 ); //dont show any errors
/**
 * Filename: checkserver.php
 * Version: 1.5
 * 1.5
 * if RunUO server, determines number of players online
 * 1.0
 * Initial Release, pinged server for online status
 * Description: This script determines if a server is currently online by pinging the server and then caching the result
 * for the time period given.
 * Author: mordero (mordero@gmail.com)
 * Usage:
 * include "checkserver.php";
 * $defaults = array('host' => "127.0.0.1",
 * 'link' => "7E51EA873A8989EA32F1742DA37CEE31",
 * );
 * $checkserver = new checkserver($defaults);
 * print $checkserver->statusCheck();
 * Outputs: Status [playersonline]
 * 
 * To get just number of players online
 * include "checkserver.php";
 * $defaults = array('host' => "127.0.0.1",
 * 'link' => "7E51EA873A8989EA32F1742DA37CEE31",
 * );
 * $checkserver = new checkserver($defaults);
 * print $checkserver->status; //the status, 0 offline, 1 online
 * print $checkserver->playersOnline;//number of players online, 0 if webserver
 */

class checkserver {
    var $defaults = array( 'host' => "crowskingdom.no-ip.info", // the IP or URL of the server, if it is a website, do not include http://
        'port' => 2593, // the port to ping, defaults: RunUO : 2593, Website: 80
        'link' => "98BAFAB57E5528B0A8CEE07D0246A494", // the URL or UOGateway ID for the site or server, do not include uog or http
        'RunUO' => true, // true if it is a RunUO server, false if it isnt
        'cacheName' => "servcheck", // this is the name of the file where the status will be store, dont include ".txt"
        'interval' => 1800, // the time between checks, in seconds, default is 30 minutes and if set to 0, no cache will be made
        );
    var $absCacheName;
    var $status;
    var $playersOnline;
    function checkserver ( $new_systemOptions = false )
    {
        if ( $new_systemOptions != false && is_array( $new_systemOptions ) ) {
            foreach( $new_systemOptions as $key => $value ) {
                if ( isset( $this->defaults[$key] ) ) { // this makes sure that it only cycles through the options that are given as an arguement
                    $this->defaults[$key] = $value;
                } 
            } 
        } 
        if ( !isset( $new_systemOptions['RunUO'] ) || $new_systemOptions == "" ) { // this determines if it is a RunUO server by default
            if ( $this->defaults['port'] == 2593 ) {
                $this->defaults['RunUO'] = true;
            } else {
                $this->defaults['RunUO'] = false;
            } 
        } 
        if ( $this->defaults['interval'] > 0 ) { // if it is set to 0, no need to do this since there will be no cache
            // assign the absCachename variable
            $absolute = $_SERVER['SCRIPT_FILENAME'];
            $absolute = explode( "/", $absolute );
            $absolute = array_reverse( $absolute );
            array_shift( $absolute );
            $absolute = array_reverse( $absolute );
            $absolute = implode( "/", $absolute );
            $this->absCacheName = $absolute . "/" . $this->defaults['cacheName'] . ".txt";
        } 
    } 
    function statusCheck()
    {
        if ( $this->defaults['interval'] > 0 ) { // if the interval is anything but 0, then check the cache
            $readCache = $this->readCache();
            $status = $readCache[0];
            $playersOnline = $readCache[1];
            if ( $status == -1 ) { // file doesnt exist or too much time passed
                $ping = $this->pingServer(); //reset the value from the this ping
                $this->writeCache( $ping[0], $ping[1] ); //write the file with the new status
                $status = $status[0];
                $playersOnline = $ping[1];
            } 
        } else { // if it is 0, then no need to cache, just ping
            $ping = $this->pingServer();
            $status = $ping[0];
            $playersOnline = $ping[1];
        } 
        if ( $status == 1 ) { // online
            if ( $this->defaults['link'] != "" ) { // if it has something in it to allow for a link
                $protocol = ( $this->defaults['RunUO'] == true )? "uog" : "http";
                $newWindow = ( $this->defaults['RunUO'] == true ) ? "" : " target=\"blank\"";
                $playersOnlineString = ( $this->defaults['RunUO'] == true )? " [" . $playersOnline . "]" : "";
                $result = "<a href=\"" . $protocol . "://" . $this->defaults['link'] . "\"" . $newWindow . ">Online</a>" . $playersOnlineString;
            } else {
                $playersOnlineString = ( $this->defaults['RunUO'] == true )? " [" . $playersOnline . "]" : "";
                $result = "Online" . $playersOnlineString;
            } 
        } else { // offline
            $playersOnline = -1; //if the server is off, then return -1 for players online
            $result = "Offline";
        } 
        $this->status = $status;
        $this->playersOnline = $playersOnline;
        return $result;
    } 
    function pingServer()
    { 
        // $result is an array containing current status and number online
        $result = array();
        if ( @!$sock = fsockopen( $this->defaults['host'], $this->defaults['port'], $num, $error, 5 ) ) { // if it cannot connect set the result to 0
            $result[0] = 0;
        } else { // if it did connect, set result to 1 and close the socket
            $result[0] = 1;
            if ( $this->defaults['RunUO'] == true ) {
                fwrite( $sock, "\x7f\x00\x00\x01" );
                fwrite( $sock, "\xf1\x00\x04\xff" ); //these two value will get the number of players currently online
                $contents = fgets( $sock ); //receive that information
                preg_match( '/(Clients=)([0-9]{1,}),/', $contents, $playersOnline ); //we get a lot more other than just the number online, so just grap that
                $result[1] = $playersOnline[2] - 1; //however, when we connect, the servers counts us as a user, so we need to subtract one
            } else {
                $result[1] = 0; //just return 0 if it isnt a RunUO server
            } 
            fclose( $sock ); //close the socket
        } 
        return $result;
    } 
    function readCache()
    {
        if ( !file_exists( $this->absCacheName ) || filesize( $this->absCacheName ) == 0 ) { // if the file doesnt exist or doesnt have any data in it
            $result[0] = -1; //returning -1 tells the status checker it needs to ping the server again
            $result[1] = 0;
            return $result;
            break;
        } else { // however, if it does exists read it
            $handle = fopen( $this->absCacheName, "r" ); //open the file to read
            $contents = file_get_contents( $this->absCacheName ); //get all of its contents
            fclose( $handle ); //close the file
            $contents = explode( "|", $contents ); //split up the contents into an array, first key holds time in seconds of last read, second holds the status
            $time_passed = time() - $contents[0]; //number of seconds since last check
            if ( $time_passed < $this->defaults['interval'] ) { // if the time that has passed was less than was is specified in the interval
                $result[0] = $contents[1];
                $result[1] = $contents[2] ; //the first one contains the status, the second is number of players online
                return $result; //return the current status of the server, 1 is for up, 0 is for down and number of players
                break;
            } else { // if more time has passed
                $result[0] = -1; //returning -1 tells the status checker that it needs to ping the server again
                $result[1] = 0;
                return $result;
                break;
            } 
        } 
    } 
    function writeCache( $status, $playersOnline )
    {
        $contents = array( time(), $status, $playersOnline ); //create array with the current time and status and players online
        $contents = implode( "|", $contents ); //make it into a string
        umask( 0 );
        $handle = fopen( $this->absCacheName, "w" ); // open the file for writing
        chmod( $this->absCacheName, 0777 ); //makes sure the file is writable and readable
        fwrite( $handle, $contents ); // write it to the file
        fclose( $handle ); //close the file
    } 
} 

?>