Archive for September, 2005

Up next: PHP Game Framework v0.10

It’s been little over a year since the idea of creating a PHP Game library was born. At long last its looking like the very first pre-alpha true release is nearing completion (we’ll ignore any previous development versions from CVS).

The PHP Game Framework is a mix of a standard drop in Application Backend, and an easy to manage light weight CMS. The basic goal of the full framework is to offer something very similar in part to a PHP Application Framework but with a more focused and limited scope – just enough in fact to support PHP Game Development. It’s not restricted to just Games – but hey, its our market niche…;-)

The project is largely the result of my and Mibocote’s (aka ProgrammerMatt) work on Shadows Rising RPG and Quantum Star SE. Both of these projects (plus Blue Sea World) will be using the same basic framework which largely explains how I can work on three games at the same time.

This framework will be a joining of two sub-projects: Q-LIB and Q-CMS; both of which have been experimented on over the past year. Q-CMS is currently MIA while we look into a final structure for the CMS. It’s simple enough to be completed within months, and is not yet an essential feature of the framework that is at this moment being actively used in my game projects.

0.10 – when released will still require substantial development to reach our final goals – but this seemingly small step is one huge leap for the project as a whole. It’s so important to my current game developments that its version is actually shared by Quantum Star SE!

Huge thanks to Matt who kept the project moving forward during a large part of the year while I was spending so much time attending lectures in anticipation of my Final Admitting Exams (yes, even at 26 you may still have exams).

The framework will be dual licensed under the GPL for the forseeable future with a dual license of AGPL to allow its use within the stricter Affero license (which QS and SR use). The release will be made in the near future at an SF project near you…

Copyright Breaches

Its amazing you know. You create an open source game, release, and get riddled with claims of license breaches and copyright infringements.

Today I decided to go all out and send a reply to one such claim by a not-to-be-named RPG game developer in PHP.

His original email was a classic example of what I receive – unresearched, unprovable, absolutely no evidence, and enough misconceptions to sink the good ship FSF. ;-) In short, that this email was ever sent is a miracle. It’s pretty disgraceful in fact.

I admit to be suffering a growing case of paranoia – I get this ugly feeling reading such emails that they are being addressed to a presumably uninformed newbie who should shut up shop and stop developing what could be a good PHP game. It must be paranoia – I’ve still yet to release a half decent version of SR or QS (been a year in the waiting). And I’m pretty sure I’m not a newbie.

Sometimes I think people just don’t really think before they send out these emails – it would at the very least explain a few things – like a well known developer claiming a license breach without even bothering to *read* my source code!!!

Must stop giggling…;-)

Quantum Star SE 3.1.0

I can just see the funny looks at the minor increment – actually 3.1.0 is not due for release any time soon. This is a short thought summary on its goals – namely to extend Gameplay.

QS and its parent, SE, are fairly simple strategic games. Recent years have thrown development off course, or in many regards simply stopped any form of forward evolution. This was a shame in many ways – since the original debut of Solar Empire, PHP games have continued to gain in complexity, popularity, and the fun-factor. Unfortunately SE’s early development issues (i.e. the Light/Dark faction in-fighting) and often it’s lack of any revolutionary development, has left SE way behind of the pack.

Now the last two years has seen a lot of improvement. There a few good developers working on the original SE project and Solar Empire 2. Djcapelis has a none too often mentioned project referred to in his blog as WAR. Even Quantum Star SE is finally hitting its stride with the newly committed (to CVS) v3-0.10. But this is all just a first baby step. QS 3.0.0 is being targeted at duplicating QS2 – not advancing any major gameplay changes. We do have such changes planned – but my lack of development time in the last year has left QS3 with 8 weeks development to date. Still, I’ve done a lot in those 8 weeks as the CVS commit shows.

So what is 3.1.0 all about?

The next version update (after we release 3.0.0) will move towards far more complex and involving gameplay. Although QS will remain set in an SE like scenario – it will have significant gameplay changes. The basis for these changes are what I call Game Assumptions (I’m sure there’s a more technical term – but this works). SE has really simple (and often illogical) Game Assumptions. For example, the implementation of Planets in Solar Empire makes an inherent assumption that a Planet can prevent a Player from viewing a Star System. If that’s not illogical, I don’t know what is…;-)

So we’re talking assumptions. Here’s an example of one planned change. In SE we assume that travel must be done only between Warp Points. Of which there is one Warp Point per system. Now this inevitably raises numerous issues. Worse it immediately places a constraint on our source code – which leads to an exponential increase in processing requirements in some functions. A revised assumption might do away with the idea (or at least the sole travel method) of Warp Points – and instead assume travel through any portion of space, in any direction, is equally valid. Following this we start get getting some pretty complex ideas – if a player can travel literally anywhere in a 3D volume of space (yes, 3D), how are opposing players going to find the buggers? After all a 100×100 pixel map would have an area of (gasp!) 10,000 pixels (one pixel per coordinate). Worse, with 3D, that same map would have a volume of 1,000,000,000 pixel points. Talk about big…;-).

That’s what QS 3.1.0 is all about. We take any SE assumption, turn it on its head, find a new potential direction to evolve, and try it out. Why not have 1 Billion points? Without warp links getting in the way you get a lot of freedom. It opens a more elaborate, yet code simple, game arena.

It for things like this that QS3 was designed. To assure some people – such a move does not necessitate the removal of the old system ;-). With QS3, both can co-exist as discrete code (typically a set of related CommandObjects – and a few minor database tweaks) because QS3 works separates all layers of the application to such an extent, that features are virtually interchangeable. For example lets say I create a new Planet Model. I could combine the 3D-Universe Model, and the Planet Model into one game, the 2D-Universe Model and SE Planets in another. There’s nothing stopping such a approach in QS3.

So the moral of the story is: QS 3.0.0 will duplicate QS2 – but don’t place bets on the follow up versions…;-)

MVC and FrontController: QS 3-0.10

Quantum Star SE 3.0.0 – the tenth revision

During the next 2-3 weeks, QS3 will hit its first major milestone (set way back in January 2005). The tenth revision (v3-0.10) brings together numerous ideas, plans and test code which have been hanging in limbo for months. In short it shows the future face of v3.0.0 – and what sort of mutated beast it will be ;-).

The primary idea to keep in mind is that QS does a fair job at separating data, business logic, client code, and presentation. The original pre-alpha back in April was not quite so clean – it integrated everything into a ad-hoc hodge podge. v0.10 however handles things quite different.

The primary “structure” being used is one based on the Model-View-Controller design pattern. For those not familiar with the concept – MVC describes an object oriented class structure which separates certain broad tasks – typically Controller, Views, Business Logic and Data Access.

The advantages of the above is that it maximises code reuse, and minimises code duplication (the major banes of QS2). In doing so it breaks down many aggregate tasks into their individual tasks – and sets each as a object method. Doing so allows far simpler maintenance and debugging. There are other advantages (but I’m trying to limit this entry!).

For QS3 the MVC implements a Business Logic Layer, a Data Access Layer, a Presentation Layer, and a Controller (the Controller is yet to be added – since all layers are independent, changes to one do NOT effect another – basically its made of a Front Controller, which makes calls on various Page Controllers). The Data Access Layer handles all SQL queries, and their results. The Presentation Layer (simple Smarty-Lite) prints parsed templates to the browser. The Business Logic (or Model) layer handles any internal logic operations – e.g. deducting credits, adding turns, checking if a ship belongs to a fleets, etc. The Front Controller handles incoming requests, and based on those requests accesses the Model Layer to perform the requested action.

As an example:

Player A wishes to Warp to SS#2 from SS#1. He clicks a url of the form (http://www.example.com/index.php?action=location.navigate&starid=2. The Front Controller will immediately parse the action value – in this case it refers to the Navigate command of the Location module. On this basis, it will search for the relevant Page Controller (/Modules/Location/NavigateCommand.php). The Navigate Class will contain the simple methods (common to all Commands) of execute() and render(). execute() will make calls to the Business Logic Layer to update locations of User and Fleet (in QS3 a Ship’s location is taken from it’s parent Fleet) while render() will parse the relevant Smarty Template and output the result to browser.

Its worth noting that the Business Layer contains delegating functions to the Data Access Layer (in effect, a Command class developer would only need to know the BL API – as the BL will pass off to the DAO layer methods, i.e. it handles any other related classes). I also note that data is passed between all layers as a Transfer Object (i.e. an object with properties populated from the data source with simple get/set methods for each property – TOs are passed to the Data Access layer for writing to the data source is needed).

Now to all reading, this may seem horribly complex (and it can be!), but one thing that should be noted is that all this separation and complex contortions results in very fine grained separation of tasks – leaving (of course) many more discrete files, but which are organised by task and module, and are open to editing without disrupting any other code. It comes at the price of intuitive understanding – but I think its a solid step forward.

So what about the game!!!

The impact on QS3 play is not a huge one (at least compared to the 3-0.6 pre-alpha). The game still does the same things – but it does them faster and more efficiently. There’s been added a certain openess which will allow complex plugins and game modules. Single entry points into the game allow centralised controls over input data, url validation, etc – adding security, and removing any alternate entry paths. It also allows a neater method of developer’s authorising valid url’s in response to any request – i.e. restricting pageflow.

You thoughts are welcome.

PHP Input Filtering (the Q-Site Q_InputFilter Class)

1. Introduction
2. Duties of an Input Filter
3. Operation of Input Filter
4. Source Code (v0.1)
5. Future Considerations

1. Introduction
—————

One of the major shortfalls in all SR/QS code to date (perhaps not Q-Site) is that they continually ignore implementing a clear specific method of filtering input, and escaping data. It’s one of the shortfalls identified in my May review of QS (along with the interlinked OO design, memory usage, and global objects – there are others).

The basis of Input Filtering is simply that you cannot under any circumstances trust any data sourced by any user. This extends to GET, POST, COOKIE and some elements of the SERVER superglobals. At present all input data is subject to testing on the data we expect to receive – this ignores any possible other data which applications may not expect. Even the testing is largely ad-hoc, and may or may not check on data type.

To resolve this problem, the Q_InputFilter class has been written (this is not complete as yet, but it gives some idea of how it works. It is to be included in the Q-Site base libraries.

2. Duties of an Input Filter
—————————-

Full complete input filtering at the end of the day, is going to done by client code. However the primary steps can be retained in the Q_InputFilter class. These duties include:

- Deletion of unexpected data
- Checking of data type/content
- Overwriting of Superglobal arrays
- Logging of unexpected data, and data origin

3. Operation of an Input Filter
——————————-

Simply put, we start comparing input data to a template of what any one particular part of our application expects. This typically involves a whitelist approach (since attempting to blacklist potential problems would be a hugely unreliable approach). The developer basically writes their code, then adds a template (a class) which specifies exactly the keys and value type/content of the input data the script expects. What should happen, is that any input data which breaks these pre-defined rules will immediately result in two outcomes:

a. The data is deleted
b. The data (and user) get logged

In summary:

1. Create a template of all expected input data (a whitelist)
2. Search the Superglobals for unexpected data
3. Delete the unexpected data
4. Log any unexpected data, and the origin of that data

4. Source Code (v0.1)
———————

As the class is still in writing, don’t view this as a final version. I also don’t claim credit for the process, which is based on a set of articles by Ben Ramsey.

The example below uses the QS3 location.php base file in showing a template.

The InputFilterData Class (for location.php):

/*
* @copyright © 2005 Padraic Brady
*/

class Location_InputFilterData {

var $post;
var $get;

function Location_InputFilterData() {
$this->post = array(
‘ss_op’=>’string’
);
$this->get = array(
‘toloc’=>’integer’,
‘fid’=>’integer’
);
}

function getPost() {
return $this->post;
}

function getGet() {
return $this->get;
}

}

?>

Typically (under php5) the properties of this class would be type ‘private’. Hence the use of getters.

The above shows a simple definition of expected input data, it includes the expected key names, the format of the data, and differentiates between POST/GET/COOKIE. It does not include $_REQUEST (I prefer not using it). If any user were to pass a GET value of $_GET['admin'], this would be found by the InputFilter class (below) and since it does not match the whitelist of expected GET keys, it would be deleted. Similarly, if a GET value for (‘fid’) of ‘gohome’ were sent, it too would be deleted, since as above our template file indicates that $_GET['fid'] should be an number. (ed: use of integer above is not entirely accurate.)

In this way, if we don’t expect a value, it will not survive passage through the filter.

The Q_InputFilter Class looks like (for the moment):

<?php

/*
* @copyright &copy; 2005 Padraic Brady
*/

class Q_InputFilter {
       
        // constructor (not to be instantiated directly)
        function Q_InputFilter(){
                $error = new Q_FatalError(debug_backtrace());
                $error->reportError(‘The Q_InputFilter() Class cannot be directly instantiated.’);
        }

        // static function
        function filter(&$input, $allowed){
                $filtered = array();
                foreach($inputas$key => $value){
                        if(array_key_exists($key, $allowed))
                        {
                                $keyset = (isset($allowed[$key])&& !empty($allowed[$key])) ? true : false;
                                switch($allowed[$key]){
                                        case‘string’:
                                                $value = (ctype_print($value)) ? $value : null;
                                                break;
                                        case‘integer’:
                                                $value = (ctype_digit($value)) ? $value : null;
                                                break;
                                        case‘alphanumeric’:
                                                $value = (ctype_alnum($value)) ? $value : null;
                                                break;
                                        case‘alphabetic’:
                                                $value = (ctype_alpha($value)) ? $value : null;
                                                break;
                                        case‘lowercase’:
                                                $value = (ctype_lower($value)) ? $value : null;
                                                break;
                                        case‘uppercase’:
                                                $value = (ctype_upper($value)) ? $value : null;
                                                break;
                                        case‘nospaces’:
                                                $value = (ctype_graph($value)) ? $value : null;
                                                break;
                                        default:
                                                $error = new Q_FatalError(debug_backtrace());
                                                $error->reportError(‘Invalid option set for the value type of a $allowed array parameter value. The type of any expected input data key must be one of: string, integer, alphanumeric, alphabetic, lowercase, uppercase or nospaces.’);
                                               
                                }
                                $filtered[$key] = $value;
                                if($keyset === true&& $value == )
                                {
                                        // in this case, a non-empty value existed for a key, but was blanked by the filter
                                        // this may indicate user intentionally passed own data – should be logged to Audit Trail
                                }
                        }
                }
                unset($input);
                return$filtered;
        }

}

?>

The above class contains a simple static method for searching a superglobal array. It should be noted that the InputFilter is the first item to be called prior to including any other code, e.g. the initiation file for QS3, core.inc.php. It’s use for say location.php would be as folows:

<?php

require_once(‘inputfilters/Location.php’);

$filterdata = new Location_InputFilterData();

// this section would typically be included in core.inc.php (done without specifying in client code)
require_once(‘../qlib/classes/inputfilter/InputFilter.php’);
$_GET = Q_InputFilter::filter($_GET, $filterdata->getGet());
$_POST = Q_InputFilter::filter($_POST, $filterdata->getPost());

require_once(‘core.inc.php’);

// … other file code …

?>

5. Future Considerations
————————

At present the class is limited to applying logic on key names, and value types. It is being planned to add certain specialised cases, e.g. email, username, url, publictext, etc.

It is also expected that the class will at least partially integrate with the htmlSafe library to enable checking of certain data input for XSS and other vulnerabilies. The final version will also integrate with the Q_Error, and Q_Log classes, which will enable the above error reporting, and the logging of unexpected input data (makes sense to keep track of potential cheaters or scriptkiddies).

Also, another objective is to expand on the data checking to include string lengths, integer max/min value, etc. Although these will still largely be checked by the client code. The class is meant as a set of standard pre-processing tasks – further input checking will obviously be necessary that is specific to the code at hand.