Laika Shield is a powerful, zero-dependency firewall middleware for the Laika PHP Framework.
| Feature | Description |
|---|---|
| π Country Blocking | Block or allowlist entire countries via MaxMind GeoLite2 |
| π« IP Blocking | Block individual IPs or CIDR ranges |
| β IP Allowlisting | Restrict access to specific IPs/ranges only |
| π’ IP Version Filtering | Allow only IPv4 or only IPv6 connections |
| β±οΈ Rate Limiting | Limit requests per IP per time window |
| π SQL Injection Detection | Block common SQLi attack payloads |
| π XSS Detection | Block cross-site scripting attempts |
| π Request Filtering | Filter by HTTP method, URI, User-Agent, headers, and body size |
composer require laikait/laika-shieldCopy vendor/laikait/laika-shield/src/Storage/config.sample.php to your project's Storage/ directory.
In your Laika application bootstrap or middleware pipeline:
use Laika\Shield\Http\ShieldMiddleware;
$config = require __DIR__ . '/../Storage/config.sample.php';
$middleware = new ShieldMiddleware($config);
$middleware->handle(function () {
// Your controller / next middleware
});use Laika\Shield\Shield;
use Laika\Shield\Config;
// Auto-loads defaults from Config β no argument needed
Shield::boot();
// Or pass a custom config array
Shield::boot(Config::get());use Laika\Shield\Shield;
(new Shield())
->trustProxy()
->blockCountries('/path/to/GeoLite2-Country.mmdb', blocklist: ['CN', 'RU'])
->blockIps(['1.2.3.4', '10.10.0.0/16'])
->allowIps(['203.0.113.0/24'])
->requireIpVersion(4) // IPv4 only
->rateLimit(maxHits: 100, windowSecs: 60)
->detectSqlInjection(skipKeys: ['password'])
->detectXss(skipKeys: ['html_content'])
->filterRequests(
blockedMethods: ['TRACE', 'CONNECT'],
blockedUserAgentPatterns: ['/sqlmap/i', '/nikto/i'],
)
->run();// Storage/config.sample.php
return [
// Country blocking (requires MaxMind GeoLite2-Country.mmdb)
'country' => [
'db' => '/path/to/GeoLite2-Country.mmdb',
'blocklist' => ['CN', 'RU'], // block these countries
'allowlist' => [], // when non-empty, ONLY these countries allowed
],
// Trust proxy headers (X-Forwarded-For, CF-Connecting-IP, etc.)
'trust.proxy' => false,
// IP blocking and allowlisting
'ip' => [
'blocklist' => ['1.2.3.4', '192.168.100.0/24'],
'allowlist' => [], // when non-empty, ONLY these IPs are allowed
],
// Only allow IPv4 (4) or IPv6 (6). null = both allowed.
'ip.version' => null,
// Rate limiting
'rate.limit' => [
'max.hits' => 60, // requests
'window' => 60, // seconds
'storage.dir' => null, // defaults to sys_get_temp_dir()
],
// SQL injection detection
'sql.injection' => [
'skip.keys' => [], // input keys to skip
'scan.body' => true, // also scan raw body (JSON, XML)
'strict' => true, // also block standalone DML (SELECT/INSERT/UPDATE/DELETE/DROP)
],
// XSS detection
'xss' => [
'skip.keys' => [],
'scan.headers' => false,
'scan.body' => true,
],
// Request filtering
'request.filter' => [
'blocked.methods' => ['TRACE', 'CONNECT'],
'blocked.uri.patterns' => ['/\/\.env$/i'],
'blocked.user.agents' => ['/sqlmap/i', '/nikto/i'],
'headers.required' => [],
'blocked.header.values' => [],
'content.length.max' => null,
'content.length.min' => null,
],
];The Config class provides a fluent API to load and modify the default configuration at runtime β without editing the config file directly.
use Laika\Shield\Config;
use Laika\Shield\Shield;
// Top-level scalar
Config::add('trust.proxy', true);
// Top-level array merge
Config::add('ip', ['blocklist' => ['1.2.3.4', '10.0.0.0/8']]);
// Sub-key update (simplest way to change a nested value)
Config::add('rate.limit', 'max.hits', 30);
Config::add('sql.injection', 'skip.keys', ['password', 'token']);
Config::add('xss', 'skip.keys', ['content', 'body']);
Config::add('request.filter', 'content.length.max', 2048);
// Boot uses Config automatically when no array is passed
Shield::boot();| Method | Description |
|---|---|
Config::add(string $key, mixed $value) |
Set or merge a top-level config key |
Config::add(string $key, string $subKey, mixed $value) |
Set or merge a specific sub-key |
Config::get() |
Return the full config array |
Config::get(string $key) |
Return the value of a single key |
Config::has(string $key) |
Check if a key exists |
Config::keys() |
Return all top-level config keys |
Config::reset() |
Reset the singleton (useful in tests) |
src/
βββ Shield.php # Main firewall engine (static + fluent API)
βββ Config.php # Runtime configuration manager
βββ Interfaces/
β βββ FirewallInterface.php # Core Firewall Interface
β βββ RuleInterface.php # Individual Rule Interface
β βββ DetectorInterface.php # Pattern Detector Interface
βββ Rules/
β βββ IpRule.php # IP blocking / allowlisting
β βββ IpVersionRule.php # IPv4 / IPv6 enforcement
β βββ RateLimitRule.php # Rate limiting
β βββ CountryRule.php # Country blocking / allowlisting
β βββ SqlInjectionRule.php # SQL injection protection
β βββ XssRule.php # XSS protection
β βββ RequestFilterRule.php # General request filtering
βββ Detectors/
β βββ GeoIpDetector.php # MaxMind GeoLite2 country resolver
β βββ SqlInjectionDetector.php # SQLi regex patterns engine
β βββ XssDetector.php # XSS regex patterns engine
βββ Http/
β βββ ShieldMiddleware.php # Laika MMC middleware integration
βββ Support/
β βββ IpHelper.php # IP validation, CIDR, version detection
β βββ RateLimiter.php # File-based rate limit store
β βββ RequestHelper.php # Request data extraction helpers
βββ Exceptions/
β βββ FirewallException.php # Base firewall exception (HTTP 403)
β βββ RateLimitExceededException.php # Rate limit exception (HTTP 429)
βββ Storage/
βββ config.sample.php # Default configuration template
Implement RuleInterface to create your own firewall rules:
use Laika\Shield\Interfaces\RuleInterface;
class CountryBlockRule implements RuleInterface
{
public function passes(): bool
{
// Your logic here
return true;
}
public function message(): string
{
return 'Access Denied From Your Country.';
}
public function statusCode(): int
{
return 403;
}
public function additionalHeader(): void
{
return;
}
}
// Register it
(new Shield())
->addRule(new CountryBlockRule())
->run();composer install
vendor/bin/phpunitShield exposes IpHelper for standalone IP utilities:
use Laika\Shield\Support\IpHelper;
IpHelper::version('8.8.8.8'); // 4
IpHelper::version('2001:db8::1'); // 6
IpHelper::version('invalid'); // null
IpHelper::isV4('192.168.1.1'); // true
IpHelper::isV6('::1'); // true
IpHelper::isPrivate('10.0.0.1'); // true
IpHelper::isLoopback('127.0.0.1'); // true
IpHelper::inCidr('192.168.1.5', '192.168.1.0/24'); // true
// Resolve real client IP (proxy-aware)
$ip = IpHelper::resolve(trustProxy: true);MIT Β© Laika IT