slim/extras
Optional extras for the Slim PHP framework, bundling useful middleware and view integrations such as CSRF protection, HTTP basic auth, flash messages, sessions, Twig, Smarty, and Mustache. A convenient way to add common features to Slim applications without writing them from scratch.
slim/extras is a grab-bag of add-ons for Slim 2.x: view adapters (Twig, Mustache, Smarty, Haml), middleware (CSRF guard, HTTP Basic auth, encrypted session cookie), HTTP helpers (cookies, request/response subclasses), a file logger, a session handler, and a password-strength helper. It is deprecated and unmaintained, so treat it as "leverage what already exists in a legacy Slim 2 codebase" rather than "start something new here."
Minimal steps
composer require slim/slim:~2.6 slim/extras
<?php
require 'vendor/autoload.php';
$app = new \Slim\Slim();
// 1. Views: swap the default PHP view for Twig
$view = new \Slim\Extras\Views\Twig();
$view->setTemplatesDirectory(__DIR__ . '/templates');
$app->view($view);
// 2. Middleware: encrypted session cookie + CSRF
$app->add(new \Slim\Extras\Middleware\CsrfGuard());
$app->add(new \Slim\Extras\Middleware\SessionCookie([
'secret' => getenv('APP_SECRET'),
'expires' => '20 minutes',
'name' => 'slim_session',
]));
$app->get('/', function () use ($app) {
$app->render('home.html.twig', ['title' => 'Hello']);
});
$app->run();
Where to look first — the source tree is the documentation (there are no per-class docs):
src/Slim/Extras/
├── Http/ Cookie.php, Cookies.php, Request.php, Response.php
├── Log/ Logger.php, DateTimeFileWriter.php
├── Middleware/ CsrfGuard.php, HttpBasicAuth.php, SessionCookie.php, StrongAuth.php
├── Session/ Session.php, SessionCookie.php, SessionHandler.php
├── Strong/ Strong.php
└── Views/ Twig.php, Mustache.php, Smarty.php, Haml.php
Read Views/Twig.php and Middleware/CsrfGuard.php first — they are the two files that deliver the most value per line.
First use case: a small admin area. SessionCookie gives you signed/encrypted sessions with zero config, HttpBasicAuth gates /admin, CsrfGuard protects the login POST, and the Twig view renders the pages. That combination is the package's sweet spot and can be wired up in about 20 lines.
All view adapters extend \Slim\View, so the standard Slim 2 API (setTemplatesDirectory, appendData, render) keeps working.
$view = new \Slim\Extras\Views\Twig();
$view->setTemplatesDirectory(__DIR__ . '/templates');
$app->view($view);
// Globals survive every render
$app->view->appendData(['site_name' => 'Acme']);
$app->render('dashboard.html.twig', ['user' => $user]);
Mustache/Smarty/Haml follow the same shape — construct, set directory, $app->view($view). Keep the adapter selection in one bootstrap file so a future migration to Slim 4's slim/twig-view is a one-file change.
$app->add(new \Slim\Extras\Middleware\CsrfGuard());
The middleware exposes csrf_key and csrf_value to the view for the current request; emit them as hidden inputs and the middleware validates the POST on the next request automatically (failing with a 400).
<form method="post" action="/account/save">
<input type="hidden" name="{{ csrf_key }}" value="{{ csrf_value }}">
<input type="email" name="email">
<button type="submit">Save</button>
</form>
If you have partials or AJAX forms, add the hidden pair to a shared _csrf.html.twig and {% include %} it — the token is per-session, not per-request, so one include covers the whole app.
$app->add(new \Slim\Extras\Middleware\HttpBasicAuth($app, 'Admin Area', [
'admin' => getenv('ADMIN_PASSWORD'),
]));
Add it after SessionCookie and before CSRF in the file if you want the auth challenge to fire before anything else writes headers. For hashed passwords, don't rely on the array form — pass a callback that does password_verify() against your user store, or subclass the middleware and override the comparison.
Once SessionCookie middleware is registered, $_SESSION is transparently encrypted into a cookie — no session_start(), no server-side store.
$app->add(new \Slim\Extras\Middleware\SessionCookie([
'secret' => getenv('APP_SECRET'), // required, rotate with care
'expires' => '20 minutes',
'path' => '/',
'secure' => true, // behind TLS
'httponly'=> true,
'name' => 'slim_session',
]));
For one-off values outside the session, use the cookie helpers:
use Slim\Extras\Http\Cookies;
Cookies::set('theme', 'dark', time() + 86400, '/');
$theme = Cookies::get('theme', 'light');
Cookies::delete('theme');
The encrypted variants (setEncrypted / getEncrypted) share the package's secret-key mechanism — set the key once in bootstrap and never inline it in the route file.
$writer = new \Slim\Extras\Log\DateTimeFileWriter();
$writer->setPath(__DIR__ . '/logs');
$app->log = new \Slim\Extras\Log\Logger($writer);
$app->get('/orders/:id', function ($id) use ($app) {
$app->log->info('Fetching order', ['id' => $id]);
// ...
});
This plugs straight into Slim's $app->log slot, so existing $app->log->debug() calls keep working and now land in dated files instead of stderr.
use Slim\Extras\Strong\Strong;
if (Strong::clean($password, Strong::STRONG_MEDIUM) === false) {
$app->flash('error', 'Password is too weak');
$app->redirect('/register');
}
Strong::getStrength($password) returns the graded level; use it to drive a UI meter while clean() remains the server-side gate.
Slim 2 executes the last-added middleware first. Read your $app->add() block top-to-bottom and remember it runs bottom-to-top:
$app->add(new \Slim\Extras\Middleware\CsrfGuard()); // runs 3rd
$app->add(new \Slim\Extras\Middleware\HttpBasicAuth(...)); // runs 2nd
$app->add(new \Slim\Extras\Middleware\SessionCookie([...])); // runs 1st
It is dead code. The repo is archived, 0 dependents, and there will be no security patches. Before adding it to a new project, price the migration: slim/twig-view + slim/csrf + middlewares/http-authentication + Monolog covers ~90% of what this package does on Slim 4.
PHP and library version walls. The package targets Slim 2 and old Twig 1.x. On PHP 8 you will hit mcrypt_* references in Strong and SessionCookie, plus Twig 1.x deprecations. composer install --ignore-platform-reqs works only inside an isolated legacy environment — never as a workaround on a modern runtime stack.
PSR-0 autoloading. Names map literally to the src/ path. If a class "cannot be found," check the exact casing of the directory (Views/Twig.php → Slim\Extras\Views\Twig) before hunting further; on case-sensitive filesystems a stray lowercase directory breaks everything.
CSRF needs a session first. CsrfGuard stores its token in $_SESSION. If you register it without SessionCookie (or a native session_start()), every POST fails validation and it looks like a token bug rather than a missing session.
Rotating the session secret logs everyone out — that's correct. Do it on a schedule, keep the secret in env vars, and never commit it. The encrypted-cookie design means a leaked secret is a full session-forgery vector.
Middleware ordering is the #1 debugging trap. Symptoms like "auth prompt appears after the 404 page" or "CSRF rejects before the session exists" are always ordering. When in doubt, temporarily log $app->request->getPath() at the top of each middleware's call().
Debugging the logger. If log lines vanish, check directory permissions on setPath() — DateTimeFileWriter fails quietly in some versions rather than throwing. Verify with $app->log->getWriter() and a manual $app->log->info('test') in index.php before blaming your route code.
Extension points are plain inheritance. Every middleware extends \Slim\Middleware and implements call(); every view extends \Slim\View and implements render(). Subclass and override rather than forking the package — e.g. class MyCsrf extends \Slim\Extras\Middleware\CsrfGuard to change the field names or the failure response.
Hashed passwords in HttpBasicAuth. The array form is a plaintext comparison in the shipped source. If your review flags that, switch to the callback form or override the credential check — this is the one place where "it works" and "it's safe" diverge.
Pin the version. Without a lockfile constraint ("slim/extras": "0.1.*" or a specific commit), a stale Packagist mirror or a partial install gives you half a package with no error signal. Commit composer.lock and mirror the package into your own VCS if the repo disappears entirely.
How can I help you explore Laravel packages today?