PHP Classes

PHP AJAX Response Handler: Process AJAX requests with response handlers

Recommend this page to a friend!
  Info   Documentation   View files Files   Install with Composer Install with Composer   Download Download   Reputation   Support forum   Blog    
Ratings Unique User Downloads Download Rankings
Not yet rated by the usersTotal: 118 All time: 9,533 This week: 206Up
Version License PHP version Categories
ajax-dispatcher 1.0.0MIT/X Consortium ...5.6PHP 5, AJAX
Description 

Author

This package can process AJAX requests with response handlers.

It provides a dispatcher class that can register URL patterns of requests processed with different handlers.

The package can handle the requests using given controller classes, closure functions, or handler scripts loaded from a given directory.

Picture of Shakir El Amrani
  Performance   Level  
Name: Shakir El Amrani <contact>
Classes: 3 packages by
Country: Morocco Morocco
Innovation award
Innovation award
Nominee: 2x

Winner: 1x

Documentation

<?php declare(strict_types=1); ob_start(); $root = dirname(dirname(__DIR__)); require $root . '/vendor/autoload.php'; require __DIR__ . '/app/controllers/PostController.php'; use AmraniCh\AjaxDispatcher\Http\Request; use AmraniCh\AjaxDispatcher\Http\Response; use AmraniCh\AjaxDispatcher\Handler\HandlerCollection; use AmraniCh\AjaxDispatcher\Router; use AmraniCh\AjaxDispatcher\Dispatcher; try { $request = new Request($_SERVER); $handlers = new HandlerCollection(require __DIR__ . '/handlers.php'); $router = new Router($request, 'handler', $handlers); $dispatcher = new Dispatcher($router); $router->registerControllers([ PostController::class ]); $dispatcher ->cleanBuffer() ->dispatch() ->stop(); } catch (\Throwable $ex) { Response::json(['error' => $ex->getMessage()], $ex->getCode())->send(); exit(); }

Details

![[preview]](https://socialify.git.ci/AmraniCh/ajax-dispatcher/image?description=1&descriptionEditable=Handle%20AJAX%20requests%20and%20send%20them%20to%20an%20appropriate%20handler.%20Also%20provides%20helper%20classes%20to%20simulate%20HTTP%20requests%20and%20responses.&font=Raleway&owner=1&pattern=Charlie%20Brown&theme=Light)

packagist tests coverage Scrutinizer Code Quality

Getting Started

composer require amranich/ajax-dispatcher:v1.0.0-beta2

You can copy/paste this code snippet for a quick start.

<?php

require __DIR__ . '/vendor/autoload.php';

use AmraniCh\AjaxDispatcher\Http\Request;
use AmraniCh\AjaxDispatcher\Handler\HandlerCollection;
use AmraniCh\AjaxDispatcher\Handler\Handler;
use AmraniCh\AjaxDispatcher\Http\Response;
use AmraniCh\AjaxDispatcher\Router;
use AmraniCh\AjaxDispatcher\Dispatcher;

try {
    $request = new Request($_SERVER);

    $handlers = new HandlerCollection([
        
        // ?handler=hello&name=john
        Handler::get('hello', function (Request $request) {
            return Response::raw("Hello $request->name!!");
        }),
    ]);

    $router     = new Router($request, 'handler', $handlers);
    $dispatcher = new Dispatcher($router);

    $dispatcher
        ->cleanBuffer()
        ->dispatch()
        ->stop();

} catch (\Exception $ex) {
    Response::json(['error' => $ex->getMessage()], $ex->getCode())->send();
    exit();
}

Usage

Route to controller/class method

If you like to put the business logic in a separate class or in a controller, you can route your requests to them like this :

Handler::get('getProfile', [UserManager::class, 'getProfile']),

Or :

Handler::get('getProfile', 'UserManager@getProfile')

But you have after to register the controller namespace/instance in the router, like this :

$router->registerControllers([
    UserManager::class,
]);

If the controller/class has some dependencies that must be passed within the constructor, you can still instantiate the controller on yourself :

$router->registerControllers([
    new UserManager($dependencyOne, $dependencyTwo)
]);

Catch handlers exceptions

*I want to catch exceptions that only occurs from my AJAX handlers, and not those thrown by the library or somewhere else, how I can do that ?*

Answer :

$dispatcher->onException(function (\Exception $ex) {
    // $ex exception thrown by a handler
});

Clean output buffer before calling requests handlers (Recommended)

To be sure that the response (output) for the ajax request it comes only from the defined handlers, and prevent unexpected echos from sending their content earlier to the browser use the cleanBuffer method :

$dispatcher
    ->cleanBuffer()
    ->dispatch();

Exit the script after dispatching the request (Recommended)

Use stop() to tell the dispatcher to exit the script right after the handler execution, this can be useful to ensure that the response (output) generated by your handlers will not be altered or modified after :

$dispatcher
    ->dispatch()
    ->stop();

<hr>

Security tips for production servers

1. Check for the request if it is an "AJAX request"

if (!$request->isAjaxRequest()) {
    Response::raw('bad request.', 400)->send();
    exit();
}

Note : The isAjaxRequest method will look for the X-REQUESTED-WITH header in the coming request headers, which obviously can be spoofed. AJAX requests can be emulated very easily and there is a sure way to know that the request is definitely an "AJAX request", however, it recommended doing this check.

2. Check for your own URL

If you want to add an extra layer of security to your application, you can check for the HTTP_PREFER header that hold the address of the page that the request coming from.

if (!array_key_exists('HTTP_REFERER', $request->getHeaders())
    || $request->getHeaderValue('HTTP_REFERER') !== 'https://www.yourdomain.com') {
    Response::raw('bad request.', 400)->send();
    exit();
}

Note : HTTP headers can be spoofed, that means the content of the HTTP_PREFER header cannot be trusted.

3. Using CRSF tokens

Generate the CRSF token :

session_start();

if (!isset($_SESSION['CSRF_TOKEN'])) {
    // random_bytes function introduced as of PHP 7
    $_SESSION['CSRF_TOKEN'] = bin2hex(random_bytes(32));
}

Inject the token somewhere in your page, for example in a meta tag :

<meta name="csrf-token" content="<?= $_SESSION['CSRF_TOKEN'] ?>">

Send the token in every AJAX request that you made :

$.ajaxSetup({
    headers: { 'X-CSRF-TOKEN':  $('meta[name="csrf-token"]').attr('content') },
});

Complete example for production usage

I already implemented all these security tips in one example, if you want to check it out see the examples/production folder.

<hr>

Background

The idea of the library came to my mind a long time ago when I was mostly developing web applications using just plain PHP, some of these applications were performing a lot of AJAX requests into a single PHP file, that file can have a hundred lines of code that process these requests depending on a function/method name that send along with the request, so I started to think of ways to clean up this file to improve the readability and maintainability of the code.

Buy me a coffee

<a href="https://www.buymeacoffee.com/AmraniCh" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>

They support me

A special thanks to JetBrains company for their support to my OSS contributions.

<img width="150px" src="https://resources.jetbrains.com/storage/products/company/brand/logos/jb_square.png"/>

LICENSE

The library is licensed under the open source MIT licence.


  Files folder image Files (38)  
File Role Description
Files folder image.github (1 directory)
Files folder imageexamples (2 directories)
Files folder imagesrc (3 files, 4 directories)
Files folder imagetests (1 directory)
Accessible without login Plain text file CHANGELOG.md Data Auxiliary data
Accessible without login Plain text file composer.json Data Auxiliary data
Accessible without login Plain text file LICENSE Lic. License text
Accessible without login Plain text file phpunit.xml Data Auxiliary data
Accessible without login Plain text file README.md Doc. Documentation

  Files folder image Files (38)  /  .github  
File Role Description
Files folder imageworkflows (1 file)

  Files folder image Files (38)  /  .github  /  workflows  
File Role Description
  Accessible without login Plain text file tests.yml Data Auxiliary data

  Files folder image Files (38)  /  examples  
File Role Description
Files folder imagedevelopment (3 files, 1 directory)
Files folder imageproduction (4 files, 1 directory)

  Files folder image Files (38)  /  examples  /  development  
File Role Description
Files folder imageapp (1 directory)
  Accessible without login Plain text file ajax_handler.php Doc. Class source
  Accessible without login Plain text file handlers.php Aux. Auxiliary script
  Accessible without login Plain text file index.php Aux. Auxiliary script

  Files folder image Files (38)  /  examples  /  development  /  app  
File Role Description
Files folder imagecontrollers (1 file)

  Files folder image Files (38)  /  examples  /  development  /  app  /  controllers  
File Role Description
  Plain text file PostController.php Class Class source

  Files folder image Files (38)  /  examples  /  production  
File Role Description
Files folder imageapp (1 directory)
  Plain text file ajax_handler.php Class Class source
  Accessible without login Plain text file config.php Aux. Auxiliary script
  Accessible without login Plain text file handlers.php Aux. Auxiliary script
  Accessible without login Plain text file index.php Aux. Auxiliary script

  Files folder image Files (38)  /  examples  /  production  /  app  
File Role Description
Files folder imagecontrollers (1 file)

  Files folder image Files (38)  /  examples  /  production  /  app  /  controllers  
File Role Description
  Plain text file PostController.php Class Class source

  Files folder image Files (38)  /  src  
File Role Description
Files folder imageException (7 files)
Files folder imageHandler (2 files)
Files folder imageHttp (2 files)
Files folder imageInternal (1 file)
  Plain text file Dispatcher.php Class Class source
  Plain text file HandlerResolver.php Class Class source
  Plain text file Router.php Class Class source

  Files folder image Files (38)  /  src  /  Exception  
File Role Description
  Plain text file AjaxDispatcherException.php Class Class source
  Plain text file BadRequestException.php Class Class source
  Plain text file HandlerNotFoundException.php Class Class source
  Plain text file InvalidArgumentException.php Class Class source
  Plain text file LogicException.php Class Class source
  Plain text file MethodNotAllowedException.php Class Class source
  Plain text file RuntimeException.php Class Class source

  Files folder image Files (38)  /  src  /  Handler  
File Role Description
  Plain text file Handler.php Class Class source
  Plain text file HandlerCollection.php Class Class source

  Files folder image Files (38)  /  src  /  Http  
File Role Description
  Plain text file Request.php Class Class source
  Plain text file Response.php Class Class source

  Files folder image Files (38)  /  src  /  Internal  
File Role Description
  Plain text file ControllerMethod.php Class Class source

  Files folder image Files (38)  /  tests  
File Role Description
Files folder imageUnit (3 files, 3 directories)

  Files folder image Files (38)  /  tests  /  Unit  
File Role Description
Files folder imageHandler (2 files)
Files folder imageHttp (2 files)
Files folder imageInternal (1 file)
  Plain text file DispatcherTest.php Class Class source
  Plain text file HandlerResolverTest.php Class Class source
  Plain text file RouterTest.php Class Class source

  Files folder image Files (38)  /  tests  /  Unit  /  Handler  
File Role Description
  Plain text file HandlerCollectionTest.php Class Class source
  Plain text file HandlerTest.php Class Class source

  Files folder image Files (38)  /  tests  /  Unit  /  Http  
File Role Description
  Plain text file RequestTest.php Class Class source
  Plain text file ResponseTest.php Class Class source

  Files folder image Files (38)  /  tests  /  Unit  /  Internal  
File Role Description
  Plain text file ControllerMethodTest.php Class Class source

The PHP Classes site has supported package installation using the Composer tool since 2013, as you may verify by reading this instructions page.
Install with Composer Install with Composer
 Version Control Unique User Downloads Download Rankings  
 0%
Total:118
This week:0
All time:9,533
This week:206Up