I made a controller.php file to handle ajax requests, with $_POST parameters action and module
if (isset($_POST["action"])) {
$action = strtolower($_POST["action"]);
if ($action === "get_notification") {
// return session notification messages
//...
} elseif (isset($_POST["module"])) {
require_once("libraries/class.module.php");
$module = new Module;
$moduleName = strtolower($_POST["module"]);
// check if module-name is valid
if ($module->verify($moduleName)) {
// load $modulename class
require_once("libraries/class.".$moduleName.".php");
// factory used to create instance of $moduleName
require_once("libraries/class.factory.php");
// note: moduleName class extends Module class
$module = $Factory->create($moduleName);
// verify method of $moduleName verifies action/method parameter
// using method_exists and cross-checking against a permitted methods list
if ($module->verify($action)) {
$message = $module->$action();
echo json_encode($message);
} else {
// handle invalid requests
echo json_encode(["0", "Invalid request received"]);
}
} else {
// handle invalid requests
echo json_encode(["0", "Invalid request received"]);
}
} else {
// handle invalid requests
echo json_encode(["0", "Invalid request received"]);
}
} else {
// handle invalid requests
echo json_encode(["0", "No request received"]);
}
But I read this post on Stack Overflow which advises against using variable methods. Should I opt for a switch case that checks each $action and calls corresponding method. That will result in a lot more code which was the initial reason I opted for this variable method solution.
It looks like what you really need is a proper routing system. You could make it yourself (as described here). Or use an existing solution, like FastRoute.
As for actually using "variable methods", in general it is a bad idea. But, if those methods are at the beginning of your call-stack (executed from the bootstrap-file), they are a really practical option.
When it comes to security concerns, the only public method in your controller classes should be ones, that you expect to be called. Which mean that you can simply do:
if (method_exists($controller, $action)) {
P.S. You don't have to do strtolower() there, because in PHP the class methods are not case-sensitive (and neither are the class names themselves).
P.P.S. Look into using composer as PSR-4 autoloader
Related
I'm trying to use JWT to create a authentication system using AngularJs and PHP. I understood the concept of JWT, I can modify the headers and send my access token, etc... My doubt is on the logic to elaborate this since I have a lot of different functions.
For example, I have a file called client.php where I have client related functions, such as getClient, updateClient, insertClient, etc.. The same applies for other files, product.php, category.php, filter.php and so on.
So, how am i supposed to do this token validation before actually running any of these functions?
I tought of creating a common function and use it inside each function, for example:
function.php
function checkToken($token) {
$serverToken = //getting server token;
if($token !== $serverToken) {
return false;
}
}
client.php
require_once 'function.php';
$tokenError = array('status' => 'Unauthorized');
function insertClient() {
global $tokenError;
$accessToken = $_SERVER['HTTP_TOKEN'];
if(!checkToken($accessToken)) {
return $tokenError;
} else {
//Proceed with the function
}
}
function getClient() {
//Repeat samething as insertClient
//...
}
But it doesn't feel like the proper way to do this. So, is there a better, or a correct way, to do headers validation/authorization on each http request the user make?
I am creating a custom MVC style framework from scratch and am at the point where I need to implement the code to control what happens on POST.
At the moment I have a main index.php which acts as a controller and passes data to other controllers such as:
profilecontroller.class.php
forumcontroller.class.php
At the moment I see two options as to where the POST controllers can go ..
First Approach
Firstly for site wide posts such as login that can occur on any page I would use something like this in the very first index.php to redirect all POST to a specific POST controller that then sends the data to a model to be processed:
if($_POST)
//post controller, works on specific form id's
Alternate Approach
The other option I see would be to build the POST identifier into the model construction sections but I don't think this would be very manageable/wise as they'd always be checked and resulting in more loaded code?
Are there any good/simple examples out there?
I'm creating my mvc to be as light as possible so that's my reason for going from scratch.
In a RESTful setup, you would normally have a controller for an object, say news, and then actions such as add, edit, delete etc.
Within your actions, you should then assert what HTTP method should be used to access the method, if one should be. For example:
<?php
class NewsController extends AbstractController {
public function save() {
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
header('HTTP/1.1 405 Method Not Allowed');
die('Please use POST.');
}
// carry on knowing we're working with a POST request
}
}
Creating a separate controller for POST requests would, as you say, quickly becoming unruly and unmanageable.
If you're looking for a way of handling requests for different HTTP methods within different controller actions, then maybe check out ToroPHP. It's a lightweight (single file) router, where you map a request to a class that's referred to as a handler, and then that handler has methods for different HTTP methods. A quick example:
<?php
require 'lib/torophp/toro.php';
require 'classes/handlers/HomeHandler.php';
$toro = new ToroApplication(array(
array('/', 'HomeHandler')
));
$toro->serve();
And then your HomeHandler would look as follows:
<?php
class HomeHandler {
public function get() {
echo 'Hello, world!';
}
public function post() {
echo 'Try performing a GET request for the home page, buddy.';
}
// and so on...
}
Hope that helps.
This is my default Controller :
<?php
Class Controller_Home{
public $Registery = null;
final public function __construct($Registery){ $this->Registery = $Registery; }
final public function Init($Method=null){
# Quelle action on fait ?
if($Method){
$Split = explode('_', $Method);
$MethodName = 'Action';
foreach($Split as $Splitted){
$MethodName.= '_'.ucfirst($Splitted);
}
if(method_exists($this, $MethodName)){
$this->$MethodName();
} else {
echo '404';
die;
}
} else {
$this->Action_Default();
}
}
final public function Action_Default(){
$this->Registery->Import('Library.Account');
var_dump($this->Registery->Account);
echo 'Default Home';
}
}
As you can see, once you are in Action_Default, you can do whatever you want based on $_GET, $_POST, whatever you want ...
So with this code :
website.com/home/bob/ will use function Action_Bob inside the controller Home (Home::Action_Bob) ... if you see $_POST just put inside Action_Bob this
public function Action_Bob(){
if($_POST){
$this->Action_Bob_Post();
}
// continue
}
Okay, the best way I know to describe the scenario is to first give the example:
Say I have a page called index.php;
At the very top before the <html> tag, one can find;
<?php session_start();
$_SESSION['user_id'] = 1234;
require_once "db.con.php";
?>
Inside that of the <body> tag, one can find:
<div id="div_ajax">
<?php require_once "ajax.php"; ?>
</div>
Now inside the ajax.php page, there is a single button that when clicked will make an ajax request. After the request is made, a simple Db query statement to select user information based on the user_id will be made. The thing is, after the AJAX request, it seems as if the user_id session and the already included Db connection is "lost".
I know I can use a conditional statement to check for AJAX request and just add the lines...
session_start();
require_once "db.con.php";
..at the top of the ajax.php page, but I'm wondering if there's a better way to do this? I don't want to always have to add those two lines to every ajax called PHP page. It sort of defeats the purpose of having the lines on the master page (index.php) to begin with. I guess I can use one ajax called page and just include a bunch of case statements, but still wondering if there's a better way.
Thanks a lot.
As far as my experience goes, I think your problem can be solved with something called the FrontController pattern.
The basic idea is that you're whole application always calls the same file, index.php for instance (also called the single point of entry).
index.php then performs all the tasks that you need on every single page (like starting the session or including your library classes) and then calls the page you want to requested.
This could look something like this: (Can't test it now)
index.php:
<?php
session_start();
$_SESSION['user_id'] = 1234;
require_once("db.con.php");
if($_REQUEST['Request_Type'] == 'website'){
require_once("header.html");
switch($_REQUEST['Request_Url']){
case 'SomePage':
require('SomePage.php');
break;
case 'SomeOtherPage':
require('SomeOtherPage.php');
break;
default:
require('ajax.php');
}
require_once("footer.html");
}elseif($_REQUEST['Request_Type'] == 'ajax'){
switch($_REQUEST['Ajax_Function']){
case 'ProcessButton':
require('ProcessButton.php');
break;
}
}
?>
ajax.php
echo '<input type="button" onClick="ajaxRequest(\"index.php\",\"ProcessButton\")" Value="ClickMe!" />';
The ajaxRequest() Javascript function would have to send an Ajax Request to index.php setting the parameters
Request_Type = 'ajax'
Ajax_Function = 'ProcessButton'
I don't think that there is a better way, but that doesn't mean that there isn't.
Just a couple of notes from reading your question:
1) Use wrapper files for all of your header information. So, at the beginning of your page, put:
require_once('package.php'); // that's what I call mine
Then in package, I have:
require_once('session.start.php');
require_once('db.con.php');
That way, all your pages are accessing the same thing. If you ever need to change it, it's a lot easier.
There is a speed difference between require_once, include_once, include and require. I don't know how significant it is. Frameworks include like 60+ files when they make a page, so I've always assumed its not too bad.
The session information is stored in a folder on your server. PHP defaults it to /tmp (which you should change to a private folder / not web accessible).
Make sure that you are validating any information sent to the AJAX. Remember that it is just like its own web page, so any permissions or database sensitive information should be protected all the same.
"I guess I can use one ajax called page and just include a bunch of case statements, but still wondering if there's a better way."
The controller pattern is pretty good for this type of thing. Having a bunch of case statements in one file is hard on your maintenance. When you switch to having files that only have 1 or 2 functions in them, your life will get so much simpler.
Depending on the size of your project, you may want to implement a framework. Check out MVC frameworks. If I don't implement a framework, I still implement a controller pattern.
I lifted this from my blog. What I use now doesn't even look like this, but it started here:
In the Presentation layer, I am determining which elements I want to implement. For each element that I want to implement, I initiate the controller, like so:
$controller = new Controller();
$context = $controller->getContext();
$context->addParam('action', 'login');
$template->setContent( $controller->process() );
I am using the Controller from PHP Objects, Patterns, and Practice 3rd Ed by Matt Zandstra with my own modifications.
Here is what happens:
My presentation layer gets a new controller object.
The Controller object's constructor automatically creates a new CommandContext object.
The CommandContext is automatically going to load up the request variables as a Parameter, so I don't even need to worry about form data until I get to the Logic layer and need to validate and process it.
In the presentation layer, I load up any additional context parameters (or the information that I want to pass on to the controller), including most importantly, the action that I want to be taken by the Controller.
To pass the information on, I call $controller->process(). In the Logic layer, I can use a default "execute" or make a different command. So, in the Presentation layer, I set the action to "Login" which forces the login command and login view pages to open, and the command defaults to execute, but it could be anything.
When I call process, it triggers the CommandFacotry. The CommandFactory is going to first initiate a new Template child object, such as a side bar div box or main body context. It makes this determination with an optional flag that I can pass to the Controller.
The CommandFactory is then going to open up the Command file and pass the template and the context as objects to the Logic layer.
abstract class Command {
}
class CommandContext {
private $params = array();
private $error = "";
function __construct(){
$this->params = $_REQUEST;
}
function addParam( $key, $val ){
$this->params[$key] = $val;
}
function get( $key ){
return $this->params[$key];
}
function issetCheck( $key ){
if( ! empty( $this->params[$key] ) ){
return true;
}
return false;
}
function setError( $error ){
$this->error = $error;
}
function getError(){
return $this->error;
}
}
class CommandNotFoundException extends Exception { }
class CommandFactory {
private static $dir = 'include/classes/command/';
static function getCommand( $action = 'Default', $flag = 0 ){
switch( $flag ){
case 1:
$template = new TemplateQuickViewOnly();
break;
case 2:
$template = new TemplateQuickViewToggle();
break;
default:
$template = new TemplateMainBodyOnly();
break;
}
if( preg_match ( '/\W/', $action ) ){
throw new Exception("illegal characters in action");
}
$class = UCFirst(strtolower($action))."Command";
$file = ROOT_PATH."".self::$dir."{$class}.php";
if( ! file_exists( $file ) ){
throw new CommandNotFoundException( "could not find '$file'" );
}
include_once( $file );
if( ! class_exists($class) ){
throw new CommandNotFoundException( "no '$class' class located" );
}
$cmd = new $class( $template );
return array( $cmd, $template );
}
}
class Controller {
private $context;
function __construct(){
$this->context = new CommandContext();
}
function getContext(){
return $this->context;
}
function process( $method = 'execute', $flag = 0 ){
list( $cmd, $template ) = CommandFactory::getCommand( $this->context->get('action'), $flag );
if( ! $cmd->$method( $this->context ) ){
// handle failure
// $template->setMessage( UCFirst($this->context->get('action')).' failed to execute.');
return $template->getMessage();
}else{
// success dispatch view
return $template->getMessage();
}
}
}
The Logic layer is in a fixed directory. An instance of the object has already been instatiated by the Controller layer, which means the constructor has been triggered. Further, the controller layer already called the method "execute" (default) or another method, such as "getLoginForm". Also, note that when the Controller calls the method "execute", it is also passing the CommandContext to the method so we have stuff to work with.
class LoginCommand extends Command {
public function __construct( ){ }
function execute ( CommandContext $context ){
if( $context->get('login_user_name') == 'demo' ){
$this->view->setMessage('Success is true!');
return true;
}
return false;
}
function getLoginForm( CommandContext $context ){
$this->view->setMessage('Second sucess is even more true!');
return true;
}
}
You seem confused.
AJAX requests are separate requests for a webpage, nothing you did in the index.php on the server side will be available in the subsequent requests (except for any variables in the session). It works like this:
Request is sent for index.php from the browser
Server runs index.php (storing user_id in the session) and returns the HTML output to the browser at the end, the PHP script finishes and all resources are freed.
User clicks on button, creating a new request for another PHP file, say ajax.php
Server runs ajax.php and returns whatever is output to the browser. Again the PHP script finishes and all resources are freed.
Another way to think about this: From the server side, an AJAX request is almost the same as if you'd just pointed your browser to ajax.php directly.
I want to make a class in OOP PHP to validate forms. However, I've having trouble structuring this.
Initially I thought of creating individual functions for each type of validation (check length of submitted data, check whether it's a number or not, etc), then another function to check whether data passed the validation tests and pass errors into an array.
I'm getting stuck though as my code is becoming very long and difficult to manage- I'm pretty new, so how would you approach this problem?
As i was reading through your post, a question came into my mind about what you write:
Why, instead of validating a form, dont you validte your model's objects?
I mean, in an OOP way of looking things your model´s object (or domain objects) are the ones who knows what data is valid or not for each of their attributes.
Not doint that, and pushing that logic into the UI makes your design fragile, UI dependant and harder to maintain. If you add a new attribute to one of your model's object, you'll have to modify the form validator as well.
If you go with Objects Validation, the idea is that an object cannot be created in an invalid state. If you try to modify it with invalid data, an exception will be thrown.
This makes easy to work with forms. The only think you have to do is populate your objects and watch for exceptions thrown in that process.
This is only an idea to get you started and see another way of solving this problem.
Regarding your question about Forms Validation, as the other guys said, it is always better not to reinvent the wheel and go for an existing, proven, validation framework.
However, if you are curious about it, here is one of the many ways you can do it:
Let's go through the things you need: you are talking about a form that needs to be validated with one or more validation functions. Then you talk about a function that tells you whether the form passed the validation or not, and as a result you got the list of errors found during the validation phase.
As you talk about OOP, the way to go is to give each concept or idea of your problem domain (the domain of form validation) entity via a class that represents it that model the behavior they have.
So, it is natural to think about a FormValidator class with a list of ValidationRule instances, where each one colaborates in the validation process. This validation process is done by calling the validate function of the FormValidator. Also, each ValidationRule will give, as result of calling it´s own validate method an instance of the ValidationRuleResult class, that tells whether the validation was successful or not, along with an error message and additional data (if needed) about the validation. Once all the validation rules were evaluated, the validate method of the FormValidator class will return an instance of ValidationResult class, that summarizes all the validation results of the rules evaluated providing the list of errors found.
To get this down to earth, here is the sample model we're talking about:
A sample implementation
Disclaimer: please bear in mind that, as any design, it may contains flaws. The following is intended to help you to solve your problem, not to be a complete solution.
class FormValidator {
private $_validationRules;
function __construct() {
$this->_validationRules = array();
}
// Registers a new validation rule
function addRule($aValidationRule) { $this->validationRules[] = $aValidationRule; }
// Validates $aForm, evaluating each of the $_validationRules defined
function validate($aForm) {
$aValidationResult = new ValidationResult();
foreach($this->_validationRules as $aValidationRule) {
$aValidationRuleResult = $aValidationRule->validate($aForm);
$aValidationResult->addResult($aValidationRuleResult);
}
return $aValidationResult;
}
}
abstract class ValidationRule {
private $_fieldName;
// The form's field name to be validated
function __construct($aFieldName) {
$this->_fieldName = $aFieldName;
}
function fieldName() { return $this->_fieldName; }
// Returns an instance of ValidationResult describing the result of evaluating the ValidationRule in $aForm.
abstract public function validate($aForm);
}
class ValidationResult {
private $_validationRuleResults;
function __construct() {
$this->_validationRuleResults = array();
}
// Registers a validation rule result
function addResult($aValidationRuleResult) {
$this->_validationRuleResults[] = $aValidationRuleResult;
}
// Returns the list of the error messages of the validation rule results that did't passed
function errorsFound() {
$errors = array();
foreach($this->validationRuleResults as $aValidationResult) {
if ($aValidationResult->passed()) continue;
$errors[] = $aValidationResult->errorMessage();
}
return $errors;
}
// Tells whether all the validation rule results passed or not
function validationPassed() {
foreach($this->validationRuleResults as $validationResult) {
if ($validationResult->passed() == false) return false;
}
return true;
}
}
class ValidationRuleResult {
private $_passed, $_error_message;
function __construct($passed) {
$this->_passed = $passed;
$this->_error_message = '';
}
// Tells whether the form passed this validation rule or not
public function passed() { return $this->_passed; }
public function
// The error message should be empty if passed to avoid confusion
public function errorMessage { return $this->passed() ? '' : $this->_error_message; }
public function setErrorMessage($anErrorMessage) { $this->_error_message = $anErrorMessage; }
}
You can create a validation rule this way:
class NotEmptyValidationRule extends ValidationRule {
public function validate($aForm) {
$fieldName = $this->fieldName();
$fieldValue = $aForm[$fieldName];
$passed = !empty($fieldValue);
$result = new ValidationRuleResult($passed);
if (!$passed) {
$result->setErrorMessage("$fieldName cannot be empty");
}
return $result;
}
}
Some things to note:
Im assuming that $aForm is an associative array of field name / value
You can note that if a validation rule passes, the result is not used (as the ValidationResult class works only on those results that didn't pass). Remember that this is a sample only for the purpose of helping you, is not a complete solution.
Usage
$rule = new NotEmptyValidationRule('name');
$validator = new FormValidator();
$validator->addRule($rule);
$aForm = $__POST['myForm'];
$validationResult = $validator->validate($aForm);
if ($validationResult->validationPassed()) {
$errorsFound = $validationResult->errorsFound();
// do something with the $errorMessage
$errorMessage = array_join('<br/>', $errorsFound);
}
Normally when an exception is thrown, Error controller takes command and displays error page with regular common header and footer.
This behavior is not wanted in Ajax request. Because in case of error, whole html page is sent over. And in cases where I'm directly loading the content of http response in a div, this is even more unwanted.
Instead in case of Ajax request, I just want to receive 'the actual error' thrown by exception.
How can I do this?
I think, one dirty way could be: set a var in ajax request and process accordingly. Not a good solution.
if you use either the contextSwitch or ajaxContext action helpers to encode your error (possibly turning off autoJsonSerialization) you could just pass the errors back as JSON / XML objects.
http://framework.zend.com/manual/en/zend.controller.actionhelpers.html#zend.controller.actionhelpers.contextswitch
class Error_Controller extends Zend_Controller{
public function errorAction(){
$contextSwitch = $this->_helper->getHelper('contextSwitch');
$contextSwitch->addActionContext($this->getRequest()->getActionName(),'json')
->initContext();
$errors = $this->_getParam('error_handler');
$this->view->exception = $errors->exception;
}
}
From there you have to either pass a format=json parameter which each AJAX request or setup a routing chain that automatically appends it.
For a 'slightly' more secure setup you could use ajaxContext as your helper and only requests that have the XMLHttpRequest header will be served json.
I played with both of the previous answers but kept running into problems. There are a few reasons I had trouble, one of them is that I wanted to be able to return raw HTML from my regular controller when things went well.
This is the solution I eventually came up with:
class ErrorController extends Zend_Controller_Action
{
public function init()
{
// Add the context to the error action
$this->_helper->contextSwitch()->addActionContext('error', 'json');
}
public function errorAction()
{
// Check if this is an Ajax request
if ($this->getRequest()->isXmlHttpRequest()) {
// Force to use the JSON context, which will disable the layout.
$this->_helper->contextSwitch()->initContext('json');
// Note: Using the 'json' parameter is required here unless you are
// passing '/format/json' as part of your URL.
}
// ... standard ErrorController code, cont'd ...
The code I use preserves error handling for non-Ajax requests, while keeping the 'displayExceptions' option intact. It is exactly like the regular error handler, in that the stack trace, and request params are also sent back when 'displayExceptions' is active within your application.ini file. There's a lot of flexibility as far as sending back the JSON data - you could create a custom class, use a view with the JSON view helper, etc.
class ErrorController extends Zend_Controller_Action
{
public function errorAction()
{
$errors = $this->_getParam('error_handler');
if ($this->getRequest()->isXmlHttpRequest()) {
$this->_helper->contextSwitch()->initJsonContext();
$response = array('success' => false);
if ($this->getInvokeArg('displayExceptions') == true) {
// Add exception error message
$response['exception'] = $errors->exception->getMessage();
// Send stack trace
$response['trace'] = $errors->exception->getTrace();
// Send request params
$response['request'] = $this->getRequest()->getParams();
}
echo Zend_Json::encode($response);
return;
}
switch ($errors->type) {
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE:
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
// 404 error -- controller or action not found
$this->getResponse()->setHttpResponseCode(404);
$this->view->message = 'Page not found';
break;
default:
// application error
$this->getResponse()->setHttpResponseCode(500);
$this->view->message = 'Application error';
break;
}
// conditionally display exceptions
if ($this->getInvokeArg('displayExceptions') == true) {
$this->view->exception = $errors->exception;
}
$this->view->request = $errors->request;
}
}