Display a site-offline page

I want to implement a sort of maintenance mode for a site that I’m building on Slim/Twig. I want to be able to change a flag and have the site become offline for everyone except the people in our office.

I have set an environment variable called SITE_OFFLINE which can be changed in the application (running in Docker on local and Elastic Beanstalk in production) and have created a small middleware to check that setting as follows:

$app->add(function (Request $request, Response $response, callable $next) : Response
{
    if ($this->get('settings')['offline']) {
        return $response->withStatus(503)->withHeader('Retry-After', 3600); // Retry in an hour please :)
    }
    return $next($request, $response);
});

So far, so good. I just need to add an IP check to determine that we’re coming from our office and to not appear offline.

The problem that I’ve got is that I don’t know how to display the offline message. I’m using Twig for the rest of the site, but I just wanted to import a static HTML page instead for the sake of the offline message. Presumably I need something like:

return $response->withStatus(503)->withHeader('Retry-After', 3600)->withBody(
    // What goes here?
);

Any guidance? I didn’t want to run it through Twig if I could afford it, and I definitely don’t want to redirect; it should display the offline message on the same URL.

Thanks :slight_smile:

1 Like

This should work for you:

function (Request $request, Response $response, callable $next) {
    if ($this->get('settings')['offline']) {
        $response = $response->withStatus(503)->withHeader('Retry-After', 3600);
        return $this->view->render($response, 'offline.twig');
    }
    return $next($request, $response);
}
3 Likes

Wow, it’s actually that simple? I mean, I wasn’t wanting to use Twig for this page (would’ve been quite happy to just give it a simple, static HTML page for the sake of simplicity) but this does the job really easily. Yeah, happy with that, thanks @RikuS

It is simple :slight_smile:

If you want to view a simple html page, you can also read that file content on var $body and use

$response = $response->withStatus(503)->withHeader('Retry-After', 3600)->withBody($body);

Does withBody() not require an object implementing Psr\Http\Message\StreamInterface though?

Oh yes that is true, so you can do this:

$body = new \Slim\Http\Body(fopen('php://temp', 'r+'));
$content = file_get_contents('offline.html');
$body->write($content);
$response = $response->withStatus(503)->withHeader('Retry-After', 3600)->withBody($body);

Interesting… this works

$handle = fopen('offline.html', 'r');
return $response->withStatus(503)->withHeader('Retry-After', 86400)->withBody(
    new \Slim\Http\Body($handle)
);

Yes, basically that’s the same thing :slight_smile:

Indeed :slight_smile: Just figured it was simpler to follow.

Thanks a lot for your help though; it’s greatly appreciated. I can definitely work with this now :slight_smile:

Where do you put that piece of code?

$body = new \Slim\Http\Body(fopen(‘php://temp’, ‘r+’));
$content = file_get_contents(‘offline.html’);
$body->write($content);
$response = $response->withStatus(503)->withHeader(‘Retry-After’, 3600)->withBody($body);

It looks like middleware. Do you create a middleware page?