I want to create a filter for my add, update, and delete actions in my controllers to automatically check if they
- were called in a POST, as opposed to GET or some other method
- and have the pageInstanceIDs which I set in the forms on my views
- protects against xss
- protects against double submission of a form
- from submit button double click
- from back button pressed after a submision
- from a url being saved or bookmarked
Currently I extended \lithium\action\Controller using an AppController and have my add, update, and delete actions defined in there. I also have a boolean function in my AppController that checks if the appropriate pageInstanceIDs are in session or not.
Below is my code:
public function isNotPostBack() {
// pull in the session
$pageInstanceIDs = Session::read('pageInstanceIDs');
$pageInstanceID = uniqid('', true);
$this->set(compact('pageInstanceID'));
$pageInstanceIDs[] = $pageInstanceID;
Session::write('pageInstanceIDs', $pageInstanceIDs);
// checks if this is a save operation
if ($this->request->data){
$pageInstanceIDs = Session::read('pageInstanceIDs');
$pageIDIndex = array_search($this->request->data['pageInstanceID'], $pageInstanceIDs);
if ($pageIDIndex !== false) {
// remove the key
unset($pageInstanceIDs[$pageIDIndex]);
Session::write('pageInstanceIDs', $pageInstanceIDs);
return true;
}
else
return false;
} else {
return true;
}
}
public function add() {
if (!$this->request->is('post') && exist($this->request->data())) {
$msg = "Add can only be called with http:post.";
throw new DispatchException($msg);
}
}
Then in my controllers I inherit from AppController and implement the action like so:
public function add() {
parent::add();
if (parent::isNotPostBack()){
//do work
}
return $this->render(array('layout' => false));
}
which will ensure that the form used a POST and was not double submitted (back button or click happy users). This also helps protect against XSS.
I'm aware there is a plugin for this, but I want to implement this as a filter so that my controller methods are cleaner. Implented this way, the only code in my actions are the //do work portion and the return statement.