Some time ago someone here advised me to move my script's action parsing away from using $_REQUEST for security reasons. I initially chaffed at the idea. I did however study the reasoning and came across reasons to make the switch. Along the way I picked up an interesting trick.
My controllers are now structured such that post actions are implicitly write oriented actions, and get actions are reads. I'm trying to avoid having an exception. This sorting does however help with form organization. Take a basic login form. Now that I've separated POST and GET out I use the source array as part of the actions name. For example
$_GET['action'] = 'login' sets the system to fetch the login form while
$_POST['action'] = 'login' actually executes the login.
These pairs come up quite a bit and there is an elegance to this that having an actions named 'login' and 'doLogin' respectively lack.
Here's the code block for the curious.
PHP Code:/**
* Search the $_POST array, then the $_GET array for an action to take.
* If neither is set fall to the default (which must be a $_GET action).
* $_POST actions require a table to be specified, $_GET actions can
* set a table if desired, else the system will default to the first table
* listed for the controller.
*
* @throws RequestException
*/
protected function parseAction() {
/**
* $_POST actions. These actions write to the database.
*/
if (isset($_POST['action'])) {
if ( array_key_exists($_POST['action'], $this->postActions) &&
$this->parseTable($_POST, $this->postActions[$_POST['action']]) &&
$this->table // POST actions require a table.
) {
$this->actionType = 'post';
$this->action = $this->postActions[$_POST['action']]['method'];
} else {
throw new PAMWF_RequestException();
}
}
/**
* $_GET actions. These actions read from the database.
*/
else if (isset($_GET['action'])) {
if ( array_key_exists($_GET['action'], $this->getActions) &&
$this->parseTable($_GET, $this->postActions[$_GET['action']])
) {
$this->actionType = 'get';
$this->action = $this->getActions[$_GET['action']]['method'];
} else {
throw new PAMWF_RequestException();
}
}
/**
* The default action - which MUST be one of the $_GET actions.
*/
else {
$this->action = $this->getActions[$this->defaultAction]['method'];
}
}
/**
* Parse the table for the action. Return true on success or false on fail.
*
* @param array $input Get or Post (process same for both)
* @param array $action The action we are checking for.
*
* @return boolean
*/
protected function parseTable( $request, $action ) {
/**
* If neither the action nor the request specifies a table
* return true but don't set a table. This is the reason
* the $_POST actions check for a table after calling this
* function in the code below.
*/
if ((!isset($action['tables']) || empty($action['tables'])) && !isset($request['table'])) {
return true;
} else if (isset($action['tables'])) {
$actionTables = explode(',', $action['tables']);
} else {
$actionTables = array();
}
/**
* If no table was specified but the action only has one table
* we set that table.
*/
if (!isset($request['table']) && count($actionTables) == 1 ) {
$this->table = array_pop($actionTables);
}
/**
* If a table was specified and is allowed for the action set
* that table.
*/
else if (isset($request['table']) && in_array($request['table'], $actionTables)) {
$this->table = $request['table'];
}
/**
* All other situations are invalid.
*/
else {
return false;
}
/**
* Now a sanity check to make sure the action is valid for the controller.
* This error should only happen during coding so we'll use assert.
*/
assert(isset($this->tables[$this->table]));
return true;
}









Bookmarks