rules.php - index








































































































































































































































<?php

/* RULES.PHP - website "rules" manager/handler 

See file RULES for an explanation of the how and the why of this code.
See file MODULES for information about THIS modules.
*/

setmodule();
_rules_config();


/* rules - return the rules array */

function rules() {
    global 
$rules;

    return 
$rules;
}


/* do_rules - this function runs the site */

function do_rules($rule) {
    global 
$rules;

    
debug("'$rule'");

    if (!isset(
$rules[$rule])) {
        
error("rule '$rule' not found");
        return;
    }

    foreach (
$rules[$rule] as $rulestr) {

        
// substitute any $vars with $_GETs

        
$rulestr _getargs($rulestr);

        
// convert any super globals

                
if (preg_match('/{\$[_A-Z]*\[/',$rulestr)) {
                        
$rulestr "\$rulestr = \"$rulestr\";";
                        eval(
$rulestr);
                }

        
// get function name and any argument(s)

        
$args explode(" ",$rulestr);
        
$name $args[0];
        
array_shift($args);

        
debug("rule '$name'");
        
debug($args);

        
// and call the function

        
if (function_exists($name))
            
call_user_func_array($name,$args);
        else
            
error("in rule '$rule', function '$name' not found");

// If an error occurs here it would be due to a function name mis-match; i.e. 
// someone changed a function name and did not change the RULES.INI file, or
// typo...

// RULES.PHP/.INI are limited to code execution paths -- no data is shared 
// between this module and any other module. There are only two entry points 
// to this module; when it gets included it self-initializes (and does 
// nothing else) and there is one function called: this one (do_rules).

// There is a complete separation of code and data. This module knows nothing 
// about the architecture of the website, and only INDEX.PHP includes it and 
// calls this function.

// Well, the above two paragraphs were true until we added GET argument 
// handling, so there is the default rule argument of 'op'.

    
}
}


/* _loadrules - the rules array is an associative array of arrays */

// The RULES.INI file is like:
//
//      [read]
//      function argument
//      ...
//
// and is read into the $rules array.

function _loadrules($file$replace TRUE) {
    global 
$rules;

    if (!(
$data = @file($file))) {
        
error(htmlgeterror('RULES'),'fatal');
        return;
    }

    
$data _readrules($data);

    foreach (
$data as $rule => $value) {
        if (
$replace)
            unset(
$rules[$rule]);

        if (!
is_array($value))
            
$rules[$rule] = $value;

        else
        foreach (
$value as $_)
            
$rules[$rule][] = $_;
    }
}


/* _readrules - parse the RULES data file */

function _readrules($file) {

    
$section "";

    while (list (, 
$l) = each ($file)) {
        
$l chop($l);
        if (
preg_match('/^;/',$l) || $l == '')
            continue;

        if (
preg_match('/^\[(.*)\]/',$l,$res)) {
            
$section $res[1];
            continue;
        }

        if (!
$section) {
            
preg_match('/(.*)\s*=\s*(.*)/',$l,$res);
            
$data[trim($res[1])] = $res[2];
        }
        else
            
$data[$section][] = $l;
    }

    return 
$data;
}


/* _getargs - convert arguments */

// replace '$var' with "$_GET['var']" - var must be as the RE

function _getargs($_) {

    
$re '/\$([a-zA-Z]+)/';
    if (
preg_match_all($re,$_,$res)) {
        foreach (
$res[0] as $k => $v) {
            
$t = @$_GET[$res[1][$k]];
            
$_ str_replace($v,$t,$_);
        }
    }

    return 
$_;
}

/*
Validate all inputs - the $rules array is a list of "op", for operation - and 
we do as much validation as we can here, before any of the other code even 
runs. We can't do it all, like for "out of range" values like a page number 
for example because we are not fully configured (can't query the database), so 
we just make sure numbers are numbers and things like that.

Ideally, there should be a "rules validation list" in some kind of INI file 
format, e.g. "id = [0-9]+" or something. But for right now let's just hardcode 
some stuff.
*/

function _rules_config() {
    global 
$rules;

    
// first, load the rules list

    
_loadrules("rules.ini");

    
// check for invalid 'op' 

    
if (!isset($_GET['op']) || !isset($rules[$_GET['op']]))
        
$_GET['op'] = $rules['default'];

    if (
$_GET['op'] == 'preview')            // internal only
        
$_GET['op'] = $rules['default'];

    
// 'arg' is checked by the CONFIG.PHP code

/*
This is one way to validate the GET data: do it all here and "change the rule" 
if something is weird... the other way, as for 'page', is to do it where the 
action occurs (for example, see displaypage() in DISPLAY.PHP).

The benefit of doing things here is that the validation code is "all in one 
place", and it can reduce overall code size and complexity (in that there are 
not disparate validation coding spread throughout the code).

The benefit of doing validation "where is as needed" is that you have more 
control and you can have more specific error handling (and error messages).

Also, for this code, we try to do all the validations at one or two particular 
points in the code path: i.e. here at the start of the code, or in the 
display functions in DISPLAY.PHP -- again, trying "catch" invalid data early 
and in obvious places.
*/
    
$op $_GET['op'];

    if (
$op == 'grok' || $op == 'submit') {
        if (!isset(
$_GET['id']) || !is_numeric($_GET['id']))
            
$_GET['op'] = $rules['default'];
    }

// it would be better to just always reset if 'id' is not right, except that:

// 'page' is separate because it's 'id' can be alpha-numeric; also, we like it 
// better validated right before the page is to be displayed...

// if we made all pages numeric, we'd still like to keep it separate

/*
    if ($_GET['op'] == 'page') {
        if (!($id = @$_GET['id']) || preg_match('/[^a-zA-Z0-9]+/',$id))
            $_GET['op'] = $rules['default'];
    }
*/
}

?>