A simple and flexible PHP middleware dispatcher based on PSR-7, PSR-11, and PSR-15


Woohoo Labs. Harmony

Latest Version on Packagist Software License Build Status Coverage Status Quality Score Total Downloads Gitter

Woohoo Labs. Harmony is a PSR-15 compatible middleware dispatcher.

Harmony was born to be a totally flexible and almost invisible framework for your application. That's why Harmony supports the PSR-7, PSR-11, as well as the PSR-15 standards.

Table of Contents



This blog post explains the idea best why Harmony was started back in 2014: http://www.catonmat.net/blog/frameworks-dont-make-sense/


  • High performance due to Harmony's simplicity
  • High flexibility thanks to the vast middleware ecosystem of PSR-15
  • Full control over HTTP messages via PSR-7
  • Support for many DI Containers via PSR-11 (formerly known as Container-Interop)

Why Harmony?

There are a lot of very similar middleware dispatcher libraries out there, like Laminas-Stratigility, Slim Framework 3 or Relay. You might ask yourself, what is the purpose of yet another library with the same functionality?

We believe Harmony offers two key features which justify its existence:

  • It is the most simple library of all. Although simplicity is subjective, one thing is certain: Harmony offers the bare minimum functionality of what a library like this would need. That's why Harmony itself fits into a single class of ~140 lines.

  • As of version 3, Harmony natively supports the concept of Conditions which is a rare feature for middleware dispatchers. This eases dealing with a major weakness of the middleware-oriented approach, namely, the ability to invoke middleware conditionally.

Use cases

Certainly, Harmony won't suit the needs of all projects and teams: this framework works best for an experienced team with a longer term project. Less experienced teams - especially if they have short deadlines - should probably choose a framework with more features - working out-of-the box - in order to speed up development in its initial phase. Harmony's flexibility is the most advantageous when your software should be supported for a longer time.


Woohoo Labs. Harmony is built upon two main concepts: middleware, which promote separation of concerns, and common interfaces, making it possible to rely on loosely coupled components.

By using middleware, you can easily take hands on the course of action of the request-response lifecycle: you can authenticate before routing, do some logging after the response has been sent, or you can even dispatch multiple routes in one request. This all can be achieved because everything in Harmony is a middleware, so the framework itself only consists of cc. 140 lines of code. This is why there is no framework-wide configuration, only middleware can be configured. What you do with Harmony depends only on your imagination and needs.

But middleware must work in cooperation (the router and the dispatcher are particularly tightly coupled to each other). That's why it is also important to provide common interfaces for the distinct components of the framework.

Naturally, we decided to use PSR-7 for modelling the HTTP request and response. In order to facilitate the usage of different DI Containers, we adapted PSR-11 (former Container-Interop) which is supported by various containers out of the box.

Middleware interface design

Woohoo Labs. Harmony's middleware interface design is based on the the PSR-15 de-facto standard.

If you want to learn about the specifics of this style, please refer to the following articles which describe the very concept:


The only thing you need before getting started is Composer.

Install a PSR-7 implementation:

Because Harmony requires a PSR-7 implementation (a package which provides the psr/http-message-implementation virtual package), you must install one first. You may use Laminas Diactoros or any other library of your preference:

$ composer require laminas/laminas-diactoros

Install Harmony:

To install the latest version of this library, run the command below:

$ composer require woohoolabs/harmony

Note: The tests and examples won't be downloaded by default. You have to use composer require woohoolabs/harmony --prefer-source or clone the repository if you need them.

Harmony 6.2+ requires PHP 7.4 at least, but you may use Harmony 6.1 for PHP 7.1+.

Install the optional dependencies:

If you want to use the default middleware stack then you have to require the following dependencies too:

$ composer require nikic/fast-route # FastRouteMiddleware needs it
$ composer require laminas/laminas-httphandlerrunner # LaminasEmitterMiddleware needs it

Basic Usage

Define your endpoints:

The following example applies only if you use the default dispatcher middleware. There are two important things to note here: first, each dispatchable endpoint receives a Psr\Http\Message\ServerRequestInterface and a Psr\Http\Message\ResponseInterface object as parameter and the latter is expected to be manipulated and returned. Secondly, you can not only use class methods as endpoints, it is possible to define other callables too (see below in the routing section).

namespace App\Controllers;

use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;

class UserController
    public function getUsers(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
        $users = ["Steve", "Arnie", "Jason", "Bud"];

        return $response;

    public function updateUser(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
        $userId = $request->getAttribute("id");
        $userData = $request->getParsedBody();

        // Updating user...

        return $response;

Define your routes:

The following example applies only if you use the default router middleware which is based on FastRoute, the library of Nikita Popov. We chose to use it by default because of its performance and simplicity. You can read more about it in Nikita's blog.

Let's add the routes for the aforementioned endpoints to FastRoute:

use App\Controllers\UserController;

$router = FastRoute\simpleDispatcher(function (FastRoute\RouteCollector $r) {
    // An anonymous function endpoint
    $r->addRoute("GET", "/me", function (ServerRequestInterface $request, ResponseInterface $response) {
            // ...

    // Class method endpoints
    $r->addRoute("GET", "/users", [UserController::class, "getUsers"]);
    $r->addRoute("POST", "/users/{id}", [UserController::class, "updateUser"]);

Finally, launch the app:

use Laminas\Diactoros\Response;
use Laminas\Diactoros\ServerRequestFactory;
use Laminas\HttpHandlerRunner\Emitter\SapiEmitter;
use WoohooLabs\Harmony\Harmony;
use WoohooLabs\Harmony\Middleware\DispatcherMiddleware;
use WoohooLabs\Harmony\Middleware\FastRouteMiddleware;
use WoohooLabs\Harmony\Middleware\LaminasEmitterMiddleware;

$harmony = new Harmony(ServerRequestFactory::fromGlobals(), new Response());
    ->addMiddleware(new LaminasEmitterMiddleware(new SapiEmitter()))
    ->addMiddleware(new FastRouteMiddleware($router))
    ->addMiddleware(new DispatcherMiddleware())

You have to register all the prior middleware in order for the framework to function properly:

  • HttpHandlerRunnerMiddleware sends the response to the ether via laminas-httphandlerrunner
  • FastRouteMiddleware takes care of routing ($router was configured in the previous step)
  • DispatcherMiddleware dispatches a controller which belongs to the request's current route

Note that there is a second optional argument of Harmony::addMiddleware() with which you can define the ID of a middleware (doing so is necessary if you want to call Harmony::getMiddleware() somewhere in your code).

Of course, it is completely up to you how you add additional middleware or how you replace them with your own implementations. When you'd like to go live, call $harmony->run()!

Advanced Usage

Using invokable class controllers

Most of the time, you will define your endpoints (~controller actions) as regular callables as shown in the section about the default router:

$router->addRoute("GET", "/users/me", [\App\Controllers\UserController::class, "getMe"]);

Nowadays, there is an increasing popularity of controllers containing only one action. In this case it is a general practice to implement the __invoke() magic method. When following this school of thought, your route definition can be simplified as seen below:

$router->addRoute("GET", "/users/me", \App\Controllers\GetMe::class);

Note: In case you use a different router or dispatcher than the default ones, please make sure if the feature is available for you.

If you are interested in how you could benefit from invokable controllers in the context of the Action-Domain-Responder pattern, you can find an insightful description in Paul M. Jones' blog post.

Using your favourite DI Container with Harmony

The motivation of creating Woohoo Labs. Harmony was to become able to change every single aspect of the framework. That's why you can use any DI Container you want.

For this purpose, we chose to build upon PSR-11 - the most widespread common interface for DI Containers - in the built-in DispatcherMiddleware.

It's also important to know that the DispatcherMiddleware uses the BasicContainer by default. It's nothing more than a very silly DIC which tries to create objects based on their class name (so calling $basicContainer->get(Foo::class) would create a new Foo instance).

But if you provide an argument to the middleware's constructor, you can use your favourite PSR-11 compliant DI Container too. Let's have a look at an example where one would like to swap BasicContainer with Zen:

$container = new MyContainer();
$harmony->addMiddleware(new DispatcherMiddleware($container));

Creating custom middleware

New middleware also has to implement the PSR-15 MiddlewareInterface. Let's see an example:

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Psr\Log\LoggerInterface;

class LoggerMiddleware implements MiddlewareInterface
    private LoggerInterface $logger;

    public function __construct(LoggerInterface $logger)
        $this->logger = $logger;

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
        // Perform logging before handling the request
        $this->logger->info("Request needs to be handled");

        // Invoking the remaining middleware
        $response = $handler->handle($request);

        // Perform logging after the request has been handled
        $this->logger->info("Request was successfully handled");

        // Return the response
        return $response;

And when you are ready, attach it to Harmony:

$harmony->addMiddleware(new LoggerMiddleware(new Logger()));

What to do if you do not want to invoke the remaining middleware (possibly because of an error)? Then you can simply manipulate and return a response whose "prototype" was passed to the middleware in its constructor. You can see this in action in the following example:

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class AuthenticationMiddleware implements MiddlewareInterface
    protected string $apiKey;
    protected ResponseInterface $errorResponsePrototype;

    public function __construct(string $apiKey, ResponseInterface $errorResponsePrototype)
        $this->apiKey = $apiKey;
        $this->errorResponsePrototype = $errorResponsePrototype;

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
        // Return Error 401 "Unauthorized" if the provided API key doesn't match the expected one
        if ($request->getHeader("x-api-key") !== [$this->apiKey]) {
            return $this->errorResponsePrototype->withStatusCode(401);

        // Invoke the remaining middleware if authentication was successful
        return $handler->handle($request);


$harmony->addMiddleware(new AuthenticationMiddleware("123"), new Response());

Defining conditions

Non-trivial applications often need some kind of branching during the execution of their middleware pipeline. A possible use-case is when they want to perform authentication only for some of their endpoints or when they want to check for a CSRF token if the request method is POST. With Harmony 2 branching was also easy to handle, but Harmony 3+ helps you to optimize the performance of conditional logic in your middleware.

Let's revisit our authentication middleware example from the last section! This time, we only want to authenticate endpoints below the /users path. In Harmony 2, we had to achieve it with something like this:

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class AuthenticationMiddleware implements MiddlewareInterface
    protected string $securedPath;
    protected MyAuthenticatorInterface $authenticator;
    protected ResponseInterface $errorResponsePrototype;

    public function __construct(string $securedPath, MyAuthenticatorInterface $authenticator, ResponseInterface $errorResponsePrototype)
        $this->securedPath = $securedPath;
        $this->authenticator = $authenticator;
        $this->errorResponsePrototype = $errorResponsePrototype;

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
        // Invoke the remaining middleware and cancel authentication if the current URL is for a public endpoint
        if (substr($request->getUri()->getPath(), 0, strlen($this->securedPath)) !== $this->securedPath) {
            return $handler->handle($request);

        // Return Error 401 "Unauthorized" if authentication fails
        if ($this->authenticator->authenticate($request) === false) {
            return $this->errorResponsePrototype->withStatusCode(401);

        // Invoke the remaining middleware otherwise
        return $handler->handle($request);

And finally attach the middleware to Harmony:

$harmony->addMiddleware(new AuthenticationMiddleware("/users", new ApiKeyAuthenticator("123"), new Response()));

You had to check the current URI inside the middleware and the problem was solved. The downside of doing this is that AuthenticationMiddleware and all its dependencies are instantiated for each request even though authentication is not needed at all! This can be a major inconvenience if you depend on a big object graph.

In Harmony 3+, however, you are able to use conditions in order to optimize the number of invoked middleware. In this case you can utilize the built-in PathPrefixCondition. You only have to attach it to Harmony:

    new PathPrefixCondition(["/users"]),
    static function (Harmony $harmony) {
        $harmony->addMiddleware(new AuthenticationMiddleware(new ApiKeyAuthenticator("123")));

This way, AuthenticationMiddleware will only be instantiated when PathPrefixCondition evaluates to true (when the current URI path starts with /users). Furthermore, you are able to attach more middleware to Harmony in the anonymous function. They will be executed together, as if they were part of a containing middleware.

Here is the complete list of the built-in conditions:

  • ExactPathCondition: Evaluates to true if the current URI path exactly matches any of the allowed paths.

  • PathPrefixCondition: Evaluates to true if the current URI path starts with any of the allowed path prefixes.

  • HttpMethodCondition: Evaluates to true if the current HTTP method matches any of the allowed HTTP methods.


If you want to see a really basic application structure in action, have a look at the examples. If docker-compose and make is available on your system, then run the following commands in order to try out the example app:

cp .env.dist .env      # You can now edit the settings in the .env file
make composer-install  # Install the Composer dependencies
make up                # Start the webserver

If you don't have make, you can copy the underlying commands, and directly use them in your terminal.

Finally, the example app is available at localhost:8080.

If you modified the .env file, you should change the port to the value of the HOST_WEB_PORT variable.

Example URIs:

  • GET /books/1
  • GET /users/1
  • GET /me

When you finished your work, simply stop the webserver:

make down

If the prerequisites are not available for you, you have to set up a webserver on your host, install PHP, as well as the dependencies via Composer.


This library follows SemVer v2.0.0.

Change Log

Please see CHANGELOG for more information on what has changed recently.


Harmony has a PHPUnit test suite. To run the tests, run the following command from the project folder:

$ phpunit

Additionally, you may run docker-compose up or make test to execute the tests.


Please see CONTRIBUTING for details.


Please see SUPPORT for details.



The MIT License (MIT). Please see the License File for more information.

  • A few travis config observations

    A few travis config observations

    1. As @xabbuh pointed somewhere, caching $HOME/.composer/cache/files is better. I think the reasoning was related to repository file caching which might delay updated package installation.
    2. Since the composer packages are cached (and installed from dist, not git repo) caching vendor is pointless IMO.
    3. What's the reason for installing "nikic/fast-route zendframework/zend-diactoros" in travis and not as dev deps in composer?
    4. To remove some branching and make things more linear, see this solution for running tests with or without coverage
    opened by sagikazarmark 11
  • Return a Response object for all the middlewares.

    Return a Response object for all the middlewares.

    I really like the simplicity of this framework.

    Recently I play around with some third party middlewares like the CORS middleware from oscarotero/psr7-middlewares. It does not work with the harmony framework.

    I found it is because harmony do not care whether middlewares return the Response object. But nearly all the other middlewares follow this rule:

    It can do whatever is appropriate with these objects. The only hard requirement is that a middleware MUST return an instance of \Psr\Http\Message\ResponseInterface. Each middleware SHOULD invoke the next middleware and pass it Request and Response objects as arguments.

    which is quoted from the documentation of slimframework: http://www.slimframework.com/docs/concepts/middleware.html

    Is this mechanism by design?

    I think it would be nice that harmony framework can work with most of the third party middlewares out there.

    opened by superbull 6
  • Middleware interface design

    Middleware interface design

    Playing around with harmony, ideas behind it are really promising. However, I can see one major problem in the design. Harmony defines following interface for middleware:

    interface MiddlewareInterface
         * @return string
        public function getId();
         * @param \WoohooLabs\Harmony\Harmony $harmony
        public function execute(Harmony $harmony);

    I think the main problem with such an approach is that middleware written for Harmony can't be used for anything else without a bridge class, neglecting idea of interoperability between frameworks. I know that there is no official standard for middleware, but what you can find usually looks like that:

    class Middleware
        public function __invoke(ServerRequestInterface $request, ResponseInterface $response) {...}

    What's the reason for using different interface?

    opened by mtymek 6
  • Add better support for dispatching middleware conditionally

    Add better support for dispatching middleware conditionally

    After a discussion in https://github.com/php-http/http-kernel/pull/1, I'd want to add native support for dispatching middleware conditionally in Harmony 3.0.

    After experimenting a little bit with the idea, I found that a really elegant way to enable this functionality is to use a Condition object - a special kind of middleware - which is responsible for invoking a callable if a certain condition is met. When invoked, this callable receives the current instance of the framework (Harmony class) as its single parameter. This looks like the following:

    $harmony = new Harmony($request, $response);
            new HttpMethodCondition(
                ["DELETE", "PATCH", "POST", "PUT"],
                function (Harmony $harmony) {
                    $harmony->insert(new CsrfMiddleware());
        ->add(new FastRouteMiddleware($router))
        ->add(new DispatcherMiddleware())
        ->addFinal(new DiactorosResponderMiddleware(new SapiEmitter()));

    What exactly happens here? First, all the middleware are added to Harmony via the add() and addFinal() methods. Then, they are executed each after each: as the first middleware is a Condition, it evaluates first whether the current HTTP method has side-effects. If so, the CsrfMiddleware gets inserted via the insert() method right after the currently evaluated middleware (which is now the CsrfMiddleware).

    Then the execution is continued either with CsrfMiddleware or FastRouteMiddleware, and then with DispatcherMiddleware. Finally, the HTTP response gets emitted by DiactorosResponderMiddleware.

    With this implementation, you can even remove middleware at your own will or do other nasty tricks (however I am not sure it is a really good idea to do such things):

    $apiMiddleware = new PathCondition(["/api/*"], function (Harmony $harmony) {
            ->insert(new BasicAuthenticationMiddleware())
            ->add(new CorsMiddleware());
    $frontendMiddleware = new PathCondition(["/frontend/*"], function (Harmony $harmony) {
            ->insert(new SessionAuthenticationMiddleware());
    $harmony = new Harmony($request, $response);
        ->add(new FastRouteMiddleware($router))
        ->add(new CsrfMiddleware(), "csrf_middleware");
        ->add(new DispatcherMiddleware())
        ->addFinal(new DiactorosResponderMiddleware(new SapiEmitter()));

    The advantages of this idea is that it is very easy to implement, it is trivial to define custom and complex conditions, and none of the unneeded middleware will be instantiated. The only downside I can see is that the API of the framework becomes a little bit more complex: we have both an add() and an insert() methods (or methods with more intention-revealing names).

    So now, I'd like to gather some feedback about my idea, so I would be happy if you could provide your possible use-cases or collect some pros and cons :)

    opened by kocsismate 4
  • Fix the composer provide rule

    Fix the composer provide rule

    This package does not provide the code of the psr/http-server-handler package (which defines interfaces). It provides psr/http-server-handler-implementation which is the virtual package representing implementations of the interface. Providing the wrong package while also requiring it creates issues with Composer 2, because the solver will consider that install psr/http-server-handler is not necessary as it is already provided.

    Refs composer/composer#9316

    opened by stof 2
  • new install error

    new install error

    I have been using this package for a few months now but as of two days ago, this is what I get when I try to install it via composer:

    - Installation request for woohoolabs/harmony ^5.0 -> satisfiable by woohoolabs/harmony[5.0.0].
    - woohoolabs/harmony 5.0.0 requires psr/http-message-implementation ^1.0.0 -> no matching package found.

    Any suggestions?

    opened by persianphilosopher 2
  • LaminasEmitterMiddleware not available in the middleware

    LaminasEmitterMiddleware not available in the middleware

    LaminasEmitterMiddleware not available in the middleware. Please, replace in example "Finally, launch the app:":

    1. use WoohooLabs\Harmony\Middleware\LaminasEmitterMiddleware; => use WoohooLabs\Harmony\Middleware\HttpHandlerRunnerMiddleware;

    2. ->addMiddleware(new LaminasEmitterMiddleware(new SapiEmitter())) => ->addMiddleware(new HttpHandlerRunnerMiddleware(new SapiEmitter()))

    opened by dewelopinweb 1
  • SapiEmitter


    Diactoros deprecated SapiEmitter in 1.8. But since it's such a widely used package, I suggest having this and the Diactoros middlewares for at least a little while.

    opened by persianphilosopher 1
  • Use StyleCI for CS checks AND fix

    Use StyleCI for CS checks AND fix

    It's an awesome (and free) CI service for code style. It closely follows php-cs-fixer fixers. As a general thumb rule, it's not a good practice to make a build fail because of CS.

    See an example config here:


    opened by sagikazarmark 1
  • Pass path part to FastRoute dispatcher

    Pass path part to FastRoute dispatcher

    Currently FastRouteMiddleware passes UriInterface to FastRoute\Dispatcher::dispatch method, while it accepts a string, representing path part of the URI.

    opened by mtymek 1
  • Bump laminas/laminas-diactoros from 2.8.0 to 2.11.1

    Bump laminas/laminas-diactoros from 2.8.0 to 2.11.1

    Bumps laminas/laminas-diactoros from 2.8.0 to 2.11.1.

    Release notes

    Sourced from laminas/laminas-diactoros's releases.


    Release Notes for 2.11.1

    This is a SECURITY release. All users are encouraged to upgrade immediately.


    This release adds features to allow filtering a ServerRequest as generated by Laminas\Diactoros\ServerRequestFactory::fromGlobals() for the purposes of initialization. Examples include:

    • Adding a request identifier.
    • Using X-Forwarded-* headers to modify the URL to represent the original client request.

    The features are based on a new interface, Laminas\Diactorors\ServerRequestFilter\FilterServerRequestInterface, which defines a single method:

    public function __invoke(
        \Psr\Http\Message\ServerRequestInterface $request
    ): \Psr\Http\Message\ServerRequestInterface

    We provide two implementations, as follows:

    • Laminas\Diactoros\ServerRequestFilter\DoNotFilter will return the provided request verbatim.
    • Laminas\Diactoros\ServerRequestFilter\FilterUsingXForwardedHeaders has named constructors that allow you to define how and when X-Forwarded-* headers are used to modify the URI instance associated with the request. These methods are:
      • trustAny(): this method generates a filter instance that will trust all X-Forwarded-* headers from any source.
      • trustReservedSubnets(array $trustedHeaders = ?): this method generates a filter instance that only modifies the URL if the IP address of the requesting server is from a reserved, private subnet (localhost; classes A, B, and C subnets; and IPv6 private and local-link subnets). By default, it will trust all X-Forwarded-* headers from these sources, but you may specify a list to allow via the $trustedHeaders argument.
      • trustProxies(array $proxyCIDRList, array $trustedHeaders = ?): this method will generate a filter instance that only modifies the URL if the requesting server matches an entry in the $proxyCIDRList. These entries may be IP addresses, or any IPv4 or IPv6 CIDR subnets. By default, it will trust all X-Forwarded-* headers from these sources, but you may specify a list to allow via the $trustedHeaders argument.

    ServerRequestFactory::fromGlobals() now accepts a FilterServerRequestInterface instance as the optional argument $requestFilter. If none is provided, it uses one as produced by FilterUsingXForwardedHeaders::trustReservedSubnets().


    • The function Laminas\Diactoros\marshalUriFromSapi() is deprecated, and no longer used internally.


    Laminas\Diactoros\ServerRequestFactory::fromGlobals() no longer consumes marshalUriFromSapi(), and instead inlines an alternate implementation. The new implementation does not consider X-Forwarded-* headers by default when generating the associated URI instance. Internally, if no FilterServerRequestInterface implementation is provided, it defaults to using an instance returned by FilterUsingXForwardeHeaders::trustReservedSubnets(). If you previously relied on X-Forwarded-* headers, you MAY need to update your code to use either the FilterUsingXForwardedHeaders::trustAny() or FilterUsingXForwardedHeaders::trustProxies() methods to generate a filter to use with ServerRequestFactory::fromGlobals().


    • Fixes CVE-2022-31109


    • Total issues resolved: 0
    • Total pull requests resolved: 0
    • Total contributors: 0


    Release Notes for 2.11.0

    ... (truncated)

    • 25b11d4 Merge pull request from GHSA-8274-h5jp-97vr
    • 4b5d1ad qa: apply Psalm rules and update baseline
    • 4d0cf3e docs: remove references to new major v3 and changes to server request filtering
    • d94d8a8 refactor: remove trustNone() method
    • 5c40729 docs: update documentation to reflect changes following refactoring
    • 83a7fc5 refactor: mark IPRange class internal
    • 73dffa8 refactor: remove X-Forwarded filter factory
    • 0aa29ba qa: fixes as proposed by Marco
    • 80fc3de refactor: default FilterServerRequestInterface instance is now FilterUsingXFo...
    • dcaf760 feature: adds trustReservedSubnets(array $trustedHeaders = [])
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.

    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    opened by dependabot[bot] 1
  • 7.1.3(Oct 22, 2020)

  • 7.1.2(Jun 23, 2020)

  • 7.1.1(Apr 29, 2020)

  • 7.1.0(Jan 6, 2020)

  • 7.0.0(Dec 29, 2019)

  • 6.2.2(Oct 4, 2019)

  • 6.2.1(Aug 21, 2019)

  • 6.2.0(Aug 14, 2019)

  • 6.1.0(Jun 6, 2019)

  • 6.0.2(Jan 11, 2019)

  • 6.0.1(Dec 21, 2018)

  • 6.0.0(Oct 18, 2018)


    • Support for Zend Diactoros 2.0


    • Run tests on PHP 7.3


    • DiactorosResponderMiddleware as it has been deprecated since Harmony 5.1.0 (breaking change)
    Source code(tar.gz)
    Source code(zip)
  • 5.1.0(Jul 30, 2018)


    • HttpHandlerRunnerMiddleware in order to be able to easily use Zend's Http Handler Runner package


    • Deprecated DiactorosResponderMiddleware because the default HTTP response emitters were deprecated as of Diactoros v1.8.0. You can use HttpHandlerRunnerMiddleware instead.
    Source code(tar.gz)
    Source code(zip)
  • 5.0.0(Feb 2, 2018)


    • Support for PSR-15 (breaking change)


    • Adapted the PSR-15 MiddlewareInterface
    • Harmony::__invoke() accepts no arguments
    • Condition callables receive the request (ServerRequestInterface) as a second parameter
    • PHPUnit 7 is minimally required to run tests


    • HarmonyMiddlewareInterface (breaking change)
    • Harmony::getResponse() (breaking change)
    • Harmony::removeMiddleware() (breaking change)
    Source code(tar.gz)
    Source code(zip)
  • 4.1.1(Nov 4, 2017)

  • 4.1.0(Sep 5, 2017)

  • 4.0.0(Feb 14, 2017)


    • Support for PSR-11


    • Better exception message for DispatcherException
    • Tests namespace became WoohooLabs\Harmony\Tests


    • Support for Container-Interop


    • DiactorosResponderMiddleware passes the request and response to the next middleware
    Source code(tar.gz)
    Source code(zip)
  • 3.1.0(Oct 18, 2016)


    • Docker Compose file to run tests more easily


    • Updated minimum PHP version requirement to 7.0
    • Fixed stylistic errors in the documentation
    Source code(tar.gz)
    Source code(zip)
  • 3.0.1(Jun 13, 2016)


    • Getters for MethodNotAllowed, MiddlewareNotExists and RouteNotFound exceptions
    • Exception message for MethodNotAllowed and RouteNotFound exceptions
    Source code(tar.gz)
    Source code(zip)
  • 3.0.0(May 22, 2016)


    • Support for conditional middleware
    • Some basic built-in conditions (e.g.: ExactPathCondition)
    • Support for PHPUnit 5.0


    • #8: Use StyleCI for CS checks
    • #9: Improved Travis config
    • Middleware returning null will throw MiddlewareWrongReturnType
    • Providing an ID for middleware became optional
    • Exception names became shorter
    • A MiddlewareNotFound exception will be thrown when removing a non-existent middleware with Harmony::removeMiddleware()
    • Renamed MiddlewareInterface to HarmonyMiddlewareInterface


    • @return PHPDoc comments for middleware were missing
    • DiactorosResponderMiddleware uses SapiEmitter by default
    • DiactorosResponderMiddleware used to be only usable as a final middleware
    Source code(tar.gz)
    Source code(zip)
  • 2.3.1(Mar 6, 2016)

  • 2.3.0(Mar 1, 2016)


    • #5: Return a Response object for all the middlewares
    • Deprecated middlewares returning null
    • Middlewares must return a ResponseInterface instance, otherwise an exception will be thrown
    • Running tests on PHP 5.6 (code style) and PHP 7 (PHPUnit) instead of PHP 5.5 and PHP 5.6
    • Improved test coverage
    Source code(tar.gz)
    Source code(zip)
  • 2.2.0(Dec 16, 2015)

    The release contains breaking changes


    • Support for multiple final middlewares
    • Configuration option for DiactorosResponderMiddleware to not respond when headers have already been sent
    • Added middlewares to support output buffering
    • Example application


    • Final middlewares are integrated with the normal ones


    • PHP version constraint in composer.json to correctly support PHP 7
    Source code(tar.gz)
    Source code(zip)
  • 2.1.0(Nov 6, 2015)


    • Made the ServerRequestInterface attribute name storing the request handler configurable
    • Simplified router definition of invokable controller classes
    • Improved and more extensive documentation


    • Made default middlewares compatible with other frameworks
    Source code(tar.gz)
    Source code(zip)
  • 2.0.1(Aug 27, 2015)

  • 2.0.0-beta1(Jul 9, 2015)

Woohoo Labs.
Woohoo Labs.
Tukio is a complete and robust implementation of the PSR-14 Event Dispatcher specification

Tukio is a complete and robust implementation of the PSR-14 Event Dispatcher specification. It supports normal and debug Event Dispatchers, both runtime and compiled Providers, complex ordering of Listeners, and attribute-based registration on PHP 8.

Larry Garfield 70 Dec 19, 2022
Disable Google's FLoC with help of PSR-15 middleware

Disable Google's FLoC with PSR-15 middleware This package will help you disable Google's FLoC. Installation You can install the package via composer:

P7V 9 Dec 14, 2022
PSR-15 middleware to geolocate the client using the ip address

middlewares/geolocation ![SensioLabs Insight][ico-sensiolabs] Middleware to geolocate the client using the ip address and Geocoder and save the result

Middlewares 10 Mar 22, 2022
A PSR-15 middleware adapter for react/http

A PSR-15 middleware adapter for react/http Wraps PSR-15 middleware into coroutines using RecoilPHP making them usable within react/http as middleware.

Friends of ReactPHP 22 Nov 12, 2022
PSR-15 middleware to use Whoops as error handler

middlewares/whoops Middleware to use Whoops as error handler. Requirements PHP >= 7.2 A PSR-7 http library A PSR-15 middleware dispatcher Installation

Middlewares 31 Jun 23, 2022
A PSR-15 middleware to handle content negotiation

Content negotiation middleware Motivation Packages like middlewares/negotiation do a very good job to detect the correct content type based on the Acc

Luís Cobucci 47 Nov 16, 2022
PSR-15 compatible middleware for Whoops, the pretty error handler

PSR-15 middleware for Whoops A PSR-15 compatible middleware for Whoops, the fantastic pretty error handler for PHP. Installation You can install the l

Franz Liedke 25 May 20, 2022
An internal redirect mechanism for PSR-15 middleware stacks

HTTP Request Forwarder The aim of this library is to make it possible to pass the HTTP request to another handler, creating a so-called internal redir

Zoltan Kovago 0 Jul 27, 2022
Provides a Middleware to integration Tideways into Symfony Messenger Processing

Tideways Middleware for Symfony Messenger This package is currently under development and might be moved into the Tideways PHP Extension or stay indep

Tideways 6 Jul 5, 2022
A lightweight middleware to make api routing session capable.

Laravel stateless session A lightweight middleware to make api routing session capable. Installing $ composer require overtrue/laravel-stateless-sessi

安正超 17 Jul 6, 2022
Use middleware to decorate method calls within your application code.

Laravel Middlewarize ?? Chain of Responsibility Design Pattern In Laravel Apps ?? You can use middlewares to decorate any method calls on any object.

Iman 99 Jan 1, 2023
Stepup Middleware - This component is part of "Step-up Authentication as-a Service".

Step-up Middleware This component is part of "Step-up Authentication as-a Service". See Stepup-Deploy for an overview and installation instructions fo

OpenConext 4 Nov 2, 2022
Middleware to provide IP filtering

middlewares/firewall Middleware to provide IP filtering using M6Web/Firewall. Requirements PHP >= 7.2 A PSR-7 http library A PSR-15 middleware dispatc

Middlewares 10 Dec 1, 2022
A based PSR-15 microframework that also sets maximum flexibility with minimum complexity and easy replaceability of the individual components, but also of the framework.

chubbyphp-framework Description A based PSR-15 microframework that also sets maximum flexibility with minimum complexity and easy replaceability of th

chubbyphp 106 Dec 9, 2022
PHP & MySQL Based Simple Application

Al Quran Technology Pages localhost/index.php Single Surah Page localhost/pages/single.php?no=1&name=আল%20ফাতিহা&ty=7 Data Source MySQL Database Local

Mejanur Rahman Mezan 3 Oct 19, 2022
The efficient and elegant, PSR-7 compliant JSON:API 1.1 client library for PHP

Woohoo Labs. Yang Woohoo Labs. Yang is a PHP framework which helps you to communicate with JSON:API servers more easily. Table of Contents Introductio

Woohoo Labs. 160 Oct 16, 2022
OpenAPI(v3) Validators for Symfony http-foundation, using `league/openapi-psr7-validator` and `symfony/psr-http-message-bridge`.

openapi-http-foundation-validator OpenAPI(v3) Validators for Symfony http-foundation, using league/openapi-psr7-validator and symfony/psr-http-message

n1215 2 Nov 19, 2021
It validates PSR-7 messages (HTTP request/response) against OpenAPI specifications

OpenAPI PSR-7 Message (HTTP Request/Response) Validator This package can validate PSR-7 messages against OpenAPI (3.0.x) specifications expressed in Y

The League of Extraordinary Packages 421 Jan 3, 2023
Php API based in clean architecture

Clean Arch API 1.1 Run docker-compose command: $ docker-compose up -d 1.2 Install dependencies: $ docker exec -it clean-arch-api composer install 1.3

Pedro Amaral 6 Sep 27, 2021