PHPackages                             juliangut/janitor - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. juliangut/janitor

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

juliangut/janitor
=================

Effortless maintenance management for PSR7

0.6(10y ago)3281[1 issues](https://github.com/juliangut/janitor/issues)BSD-3-clausePHPPHP &gt;=5.5

Since Sep 27Pushed 9y ago2 watchersCompare

[ Source](https://github.com/juliangut/janitor)[ Packagist](https://packagist.org/packages/juliangut/janitor)[ Docs](http://juliangut.com/janitor)[ RSS](/packages/juliangut-janitor/feed)WikiDiscussions master Synced 2d ago

READMEChangelogDependencies (10)Versions (6)Used By (0)

[![Latest Version](https://camo.githubusercontent.com/5c98f4d8f0c8e7edb92c22b539798840895099ca31f3e70ccb68be29080725dc/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f767072652f6a756c69616e6775742f6a616e69746f722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/juliangut/janitor)[![License](https://camo.githubusercontent.com/955d9b37d50abc62987c76ecc02f9979356abf7dcaaa53a31b8d9c69b597c4ed/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6a756c69616e6775742f6a616e69746f722e7376673f7374796c653d666c61742d737175617265)](https://github.com/juliangut/janitor/blob/master/LICENSE)

[![Build status](https://camo.githubusercontent.com/258a53d146a7a2699305cfbfe2f315b896707c15b8ca153cf706da5833717cbf/68747470733a2f2f696d672e736869656c64732e696f2f7472617669732f6a756c69616e6775742f6a616e69746f722e7376673f7374796c653d666c61742d737175617265)](https://travis-ci.org/juliangut/janitor)[![Style](https://camo.githubusercontent.com/897abdf51ac5793447dfb942afc0edde4acdcb0ab7e7d08da8225efcb57a795f/68747470733a2f2f7374796c6563692e696f2f7265706f732f34333234333135372f736869656c64)](https://styleci.io/repos/43243157)[![Code Quality](https://camo.githubusercontent.com/b5bff44734a3ac2af95425e3e8d61236212f7ef32888812dcca47e5d63b2f066/68747470733a2f2f696d672e736869656c64732e696f2f7363727574696e697a65722f672f6a756c69616e6775742f6a616e69746f722e7376673f7374796c653d666c61742d737175617265)](https://scrutinizer-ci.com/g/juliangut/janitor)[![Code Coverage](https://camo.githubusercontent.com/6655c277181fbf5536004875dac5e4313da2b384ba0127b6338f866b133dcb31/68747470733a2f2f696d672e736869656c64732e696f2f636f766572616c6c732f6a756c69616e6775742f6a616e69746f722e7376673f7374796c653d666c61742d737175617265)](https://coveralls.io/github/juliangut/janitor)[![Total Downloads](https://camo.githubusercontent.com/359a1b8b5d9cf330066735083059f2dde5fe52db689c702ebee3a3904e765a14/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6a756c69616e6775742f6a616e69746f722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/juliangut/janitor)

Janitor
=======

[](#janitor)

Effortless maintenance management for PSR7.

Janitor is a ready to use PSR7 package that provides you with an easy configurable and extensible way to handle maintenance mode on your project, because maintenance handling goes beyond responding to the user with an HTTP 503 code and a simple message.

Set several conditions that will be checked to determine if the maintenance handler should be triggered. This conditions are of two kinds, 'activation' conditions (named `watchers`) and conditions to bypass the normal execution (named `excluders`).

Already builtin watchers and excluders allows you to cover a wide range of situations so you can drop Janitor in and start in no time, but at the same time it's very easy to create your own conditions if needed by implementing the corresponding interface.

Once Janitor has determined maintenance mode is active it let you use your handler to get a response ready for the user or you can let Janitor handle it all by itself (a nicely formatted 503 response).

> Learn more in [Janitor's page](http://juliangut.com/janitor)

Installation
------------

[](#installation)

Best way to install is using Composer:

```
composer require juliangut/janitor

```

Then require the autoload file:

```
require_once './vendor/autoload.php';
```

Usage
-----

[](#usage)

```
use Janitor\Excluder\IP as IPExcluder;
use Janitor\Excluder\Path as PathExcluder;
use Janitor\Runner as Janitor;
use Janitor\Watcher\WatcherInterface;
use Janitor\Watcher\File as FileWatcher;
use Janitor\Watcher\Cron as CronWatcher;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Zend\Diactoros\Response;
use Zend\Diactoros\ServerRequestFactory;

$watchers = [
    new FileWatcher('/tmp/maintenance'),
    new CronWatcher('0 0 * * 0', new \DateInterval('PT2H')),
];
$excluders = [
    new IPExcluder('127.0.0.1'),
    new PathExcluder(['/maintenance', '/^\/admin/']),
];

$handler = function (ServerRequestInterface $request, ResponseInterface $response, WatcherInterface $watcher) {
    $response->getBody()->write('This page is in maintenance mode!');

    return $response;
}

$activeWatcherAttributeName = 'maintenance_watcher'; // Default is 'active_watcher'
$janitor = new Janitor($watchers, $excluders, $handler, $activeWatcherAttributeName);

$response = $janitor(
    ServerRequestFactory::fromGlobals(),
    new Response('php://temp'),
    function ($request, $response) use ($activeHandlerAttributeName) {
        $activeHandler = $request->getAttribute($activeHandlerAttributeName);
        // ...
    }
);
```

> In case a watcher is active at any given point (and so maintenance mode does) it will be attached as an attribute to the request object so it can be retrieved during execution.

Watchers
--------

[](#watchers)

Watchers serve different means to activate maintenance mode by verifying conditions.

- `Manual` Just set it to be active. Useful to be used with a configuration parameter.
- `File` Checks the existence of the provided file(s).
- `Environment` Checks if an environment variable is set to a value.

```
$manualWatcher = new \Janitor\Watcher\Manual(true);
// Always active
$manualWatcher->isActive();

$fileWatcher = new \Janitor\Watcher\File('/tmp/maintenance');
// Active if /tmp/maintenance file exists
$fileWatcher->isActive();

$envWatcher = new \Janitor\Watcher\Environment('maintenance', 'ON');
// Active if 'maintenance' environment variable value is 'ON'
$envWatcher->isActive();
```

#### Scheduled watchers

[](#scheduled-watchers)

Scheduled watchers are a special type of watchers that identify a point in time in the future for a maintenance period.

- `Fixed` Hard set start and/or end times for a scheduled maintenance period.
- `Cron` Set maintenance periods using [cron expression](https://en.wikipedia.org/wiki/Cron#CRON_expression) syntax.

```
$fixedWatcher = new \Janitor\Watcher\Fixed('2026/01/01 00:00:00', '2026/01/01 01:00:00');
// Active only 1st January 2026 at midnight for exactly 1 hour
$fixedWatcher->isActive();

$cronWatcher = new \Janitor\Watcher\Cron('0 0 1 * *', new \DateInterval('PT2H'));
// Active the first day of each month at midnight during 2 hours
$cronWatcher->isActive();
```

From a scheduled watcher you can get a list of upcoming maintenance periods

```
$cronWatcher = new \Janitor\Watcher\Cron('0 0 1 * *', new \DateInterval('PT2H'));
// Array of ['start' => \DateTime, 'end' => \DateTime] of next maintenance periods
$scheduledPeriods = $cronWatcher->getScheduledTimes(10);
```

> Watchers are checked in the order they are added, once a watcher is active the rest won't be checked.

*If you perform maintenance tasks periodically (maybe on the same day of every week) you may want to use either `Cron` watcher to identify the date and the time period needed, or `File` watcher to watch for a file in your system and set your maintenance process to `touch` and `rm` that file as part of the maintenance process.*

*Cron watcher uses Michael Dowling's [cron-expression](https://github.com/mtdowling/cron-expression).*

Excluders
---------

[](#excluders)

Excluders set conditions to bypass maintenance mode in order to allow certain persons through or certain pages to be accessed.

- `IP` Verifies user's IP to allow access.
- `Path` Excludes certain URL paths from maintenance.
- `BasicAuth` Excludes based on request Authorization header.
- `Header` Excludes based on request Header value.

```
$ipExcluder = new \Janitor\Excluder\IP('127.0.0.1');
// Users accessing from IP 127.0.0.1 are excluded
$ipExcluder->isExcluded($request);

$pathExcluder = new \Janitor\Excluder\Path('/maintenance');
// Users accessing 'http://yourdomain.com/maintenance' are excluded
$pathExcluder->isExcluded($request);

$pathExcluderRegex = new \Janitor\Excluder\Path('/^\/admin/');
// Can also be a regex
$pathExcluderRegex->isExcluded($request);

$basicAuthExcluder = new \Janitor\Excluder\BasicAuth(['root' => 'secret']);
// Users accessing with basic authorization 'root' user are excluded
$basicAuthExcluder->isExcluded($request);

$headerExcluder = new \Janitor\Excluder\Header('X-Custom-Header', 'custom');
// Users accessing with 'X-Custom-Header' header's value 'custom' are excluded
$headerExcluder->isExcluded($request);

$headerExcluderRegex = new \Janitor\Excluder\Header('X-Custom-Header', '/^custom/');
// Again a regex can be used
$headerExcluderRegex->isExcluded($request);
```

> When adding excluders consider they are checked in the same order they are included so that when an excluder condition is met the rest of the excluders won't be tested. Add more general excluders first and then more focused ones.

*Tipically you'll want to exclude your team's IPs and certain pages such as maintenance or administration zone.*

Handlers
--------

[](#handlers)

In order to handle maintenance mode any callable can be provided to `setHandler` method given it follows this signature:

```
function (\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, \Janitor\Watcher\WatcherInterface $watcher);
```

Two really basic handlers are suplied by default to cope with maintenance mode.

- `Render` Sets response with 503 code and add basic formatted maintenance output based on request's Accept header.
- `Redirect` Prepares response to be a 302 redirection to a configured URL (typically maintenance page).

Of the two `Render` will be automatically created and used in case none is provided.

Scheduled maintenance service
-----------------------------

[](#scheduled-maintenance-service)

If scheduled watchers are being used they open the option to show a list of future maintenance periods, for example on a page dedicated to inform users about future maintenance actions.

```
use Janitor\Runner as Janitor;
use Janitor\Watcher\Cron;
use Zend\Diactoros\Response;
use Zend\Diactoros\ServerRequestFactory;

$watchers = [new Cron('0 0 1 * *', new \DateInterval('PT2H'));];

$janitor = new Janitor($watchers);

$response = $janitor(
    ServerRequestFactory::fromGlobals(),
    new Response('php://temp'),
    function ($request, $response) use ($janitor) {
        // Array of ['start' => \DateTime, 'end' => \DateTime]
        $scheduledPeriods = $janitor->getScheduledTimes();
    }
);
```

Examples
--------

[](#examples)

### Slim3

[](#slim3)

```
use Janitor\Runner as Janitor;
use Slim\App;

$watchers = [];
$excluders = [];

$app = new App();

// Add middleware (using default Render handler)
$app->add(new Janitor($watchers, $excluders));

$app->run();
```

### Zend Expressive

[](#zend-expressive)

```
use Janitor\Handler\Redirect;
use Janitor\Runner as Janitor;
use Zend\Expresive\AppFactory;

$watchers = [];
$excluders = [];
$handler = new Redirect('/maintenance');

$app = AppFactory::create();

// Add middleware
$app->pipe(new Janitor($watchers, $excluders, $handler));

$app->run();
```

### Symfony's HttpFoundation

[](#symfonys-httpfoundation)

If using Symfony's HttpFoundation you can still add Janitor to your tool belt by using Symfony's [PSR HTTP message bridge](https://github.com/symfony/psr-http-message-bridge)

An example using Silex

```
use Janitor\Runner as Janitor;
use Silex\Application;
use Symfony\Bridge\PsrHttpMessage\Factory\DiactorosFactory;
use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory;
use Symfony\Component\HttpFoundation\Request;
use Zend\Diactoros\Response;

$janitor = new Janitor();

$app = new Application;

$app->before(function (Request $request, Application $app) use ($janitor) {
    $response = $janitor(
        (new DiactorosFactory)->createRequest($request),
        new Response('php://temp'),
        function ($request, $response) {
            return $response;
        }
    );

    return (new HttpFoundationFactory)->createResponse($response);
});

$app->run();
```

Contributing
------------

[](#contributing)

Found a bug or have a feature request? [Please open a new issue](https://github.com/juliangut/janitor/issues). Have a look at existing issues before.

See file [CONTRIBUTING.md](https://github.com/juliangut/janitor/blob/master/CONTRIBUTING.md)

License
-------

[](#license)

See file [LICENSE](https://github.com/juliangut/janitor/blob/master/LICENSE) included with the source code for a copy of the license terms.

###  Health Score

24

—

LowBetter than 31% of packages

Maintenance13

Infrequent updates — may be unmaintained

Popularity11

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~79 days

Total

4

Last Release

3695d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/4c50421f1ab4148354dc2dd5dcaba168656b17ea913b310d112deb39a6f73ca1?d=identicon)[juliangut](/maintainers/juliangut)

---

Top Contributors

[![juliangut](https://avatars.githubusercontent.com/u/1104131?v=4)](https://github.com/juliangut "juliangut (53 commits)")

---

Tags

phpcronmaintenance

###  Code Quality

TestsPHPUnit

Code StylePHP\_CodeSniffer

### Embed Badge

![Health badge](/badges/juliangut-janitor/health.svg)

```
[![Health](https://phpackages.com/badges/juliangut-janitor/health.svg)](https://phpackages.com/packages/juliangut-janitor)
```

###  Alternatives

[aws/aws-sdk-php

AWS SDK for PHP - Use Amazon Web Services in your PHP project

6.3k543.5M2.6k](/packages/aws-aws-sdk-php)[neuron-core/neuron-ai

The PHP Agentic Framework.

2.0k656.1k38](/packages/neuron-core-neuron-ai)[aimeos/aimeos-base

Aimeos base layer for abstracting from host environments

2.2k147.3k3](/packages/aimeos-aimeos-base)[spatie/laravel-export

Create a static site bundle from a Laravel app

674146.0k6](/packages/spatie-laravel-export)[anthropic-ai/sdk

Anthropic PHP SDK

163583.3k17](/packages/anthropic-ai-sdk)[telnyx/telnyx-php

Official Telnyx PHP SDK — APIs for Voice, SMS, MMS, WhatsApp, Fax, SIP Trunking, Wireless IoT, Call Control, and more. Build global communications on Telnyx's private carrier-grade network.

35789.4k2](/packages/telnyx-telnyx-php)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
