laikait/laika-shield is a firewall middleware: country/IP blocking, rate limiting, SQL injection & XSS detection, and general request filtering. laikait/laika-core requires it, so it is already installed in every Laika project — there is nothing to add. It does nothing until you wire it in, which is what the rest of this page covers.
There is no config file to publish — every option carries its own default. Create one only if you want your settings in a file, returning the keys you wish to override:
// lf-storage/shield.config.php
return [
'ip' => [
'blocklist' => ['1.2.3.4', '192.168.100.0/24'],
'allowlist' => [],
],
'rate.limit' => [
'max.hits' => 60,
'window' => 60,
],
'sql.injection' => ['skip.keys' => [], 'scan.body' => true, 'strict' => true],
'xss' => ['skip.keys' => [], 'scan.body' => true],
'request.filter' => [
'blocked.methods' => ['TRACE', 'CONNECT'],
],
];
See the laika-shield README for every available key, including MaxMind GeoLite2 country blocking.
Shield::boot()/run() throw Laika\Shield\Exceptions\FirewallException when a rule blocks the request (after already setting the appropriate HTTP status code). The natural integration point is a global pipeline that catches it and turns it into a response:
php laika pipeline:make Shield
namespace App\Pipeline;
use Laika\Shield\Shield;
use Laika\Shield\Exceptions\FirewallException;
use Laika\Route\Contracts\PipelineInterface;
class Shield implements PipelineInterface
{
public function handle(callable $next, array &$params): ?string
{
try {
// boot() takes no arguments and reads the shared ShieldConfig.
// To apply an array, hand it to fromConfig() instead:
Shield::fromConfig(require APP_PATH . '/lf-storage/shield.config.php')->run();
} catch (FirewallException $e) {
// Status code is already set by Shield; just supply a body.
return $e->getMessage();
}
return $next();
}
}
// lf-routes/web.php or a dedicated bootstrap file
Url::globalPipeline(['Shield']);
Running it as a global pipeline means every request is checked before any route-specific pipeline or controller runs.
For programmatic configuration instead of a config file:
use Laika\Shield\Shield;
(new Shield())
->trustProxy()
->blockIps(['1.2.3.4', '10.10.0.0/16'])
->rateLimit(maxHits: 100, windowSecs: 60)
->detectSqlInjection(skipKeys: ['password'])
->detectXss(skipKeys: ['html_content'])
->run(); // throws FirewallException on a match
Laika\Shield\ShieldConfig gives dot-notation access without touching the config file directly:
use Laika\Shield\ShieldConfig;
ShieldConfig::add('rate.limit', 'max.hits', 30);
ShieldConfig::add('sql.injection', 'skip.keys', ['password', 'token']);
Shield::boot(); // no arguments - always reads the shared ShieldConfig
use Laika\Shield\Contract\RuleInterface;
class BlockBadReferrer implements RuleInterface
{
public function passes(): bool { /* ... */ return true; }
public function message(): string { return 'Access Denied.'; }
public function statusCode(): int { return 403; }
public function additionalHeader(): void {}
}
(new Shield())->addRule(new BlockBadReferrer())->run();
See the laika-shield README for the complete rule set (IpRule, IpVersionRule, RateLimitRule, CountryRule, SqlInjectionRule, XssRule, RequestFilterRule), the IpHelper utility class, and architecture overview.