loguard / loguard-sdk
Official LoGuard SDK for PHP, with first-class Laravel integration.
Requires
- php: ^8.1
- ext-curl: *
- ext-json: *
- ext-mbstring: *
Requires (Dev)
- laravel/framework: ^10.0 || ^11.0
- orchestra/testbench: ^8.0 || ^9.0
- phpstan/phpstan: ^1.11
- phpunit/phpunit: ^10.5
Suggests
- laravel/framework: Required to use the Laravel integration (LoGuard\Sdk\Laravel\*).
Provides
None
Conflicts
None
Replaces
None
This package is not auto-updated.
Last update: 2026-09-20 03:53:14 UTC
README
Official PHP SDK for LoGuard security monitoring and threat detection, with first-class Laravel integration. Framework-agnostic core — works in plain PHP, Laravel, Symfony, or any other stack.
Built to be behaviorally consistent with the existing LoGuard SDKs (Python, Node.js, Go, C#): same wire protocol, same validation rules, same error taxonomy, same retry/backoff behavior. If you already use LoGuard from another service in a polyglot stack, this SDK will feel identical.
Installation
composer require loguard/loguard-sdk
Requires PHP 8.1+, ext-curl, ext-json, ext-mbstring (all part of
a standard PHP install). No other runtime dependencies.
Quick start (plain PHP)
use LoGuard\Sdk\Client; use LoGuard\Sdk\Config; $loguard = new Client(new Config( apiKey: getenv('LOGUARD_API_KEY'), baseUrl: getenv('LOGUARD_BASE_URL') ?: 'https://api.loguard.org', env: getenv('LOGUARD_ENV') ?: 'production', )); // Blocking — waits for the LoGuard API response. $result = $loguard->event( type: 'login_failed', ip: '1.2.3.4', path: '/api/login', statusCode: 401, userId: 'user_123', meta: ['method' => 'POST'], ); echo $result->inserted, ' accepted, ', $result->alertsFired, ' alerts fired', PHP_EOL; // Non-blocking — buffered in memory, flushed automatically at // process shutdown (or call $loguard->flush() explicitly). $loguard->eventAsync( type: 'http_request', ip: '1.2.3.4', path: '/api/users', statusCode: 200, ); // Multiple events in one request. $result = $loguard->eventBatch([ ['type' => 'http_request', 'ip' => '1.2.3.4', 'path' => '/', 'status_code' => 200], ['type' => 'login_failed', 'ip' => '1.2.3.4', 'path' => '/login', 'status_code' => 401], ['type' => 'http_request', 'ip' => '5.6.7.8', 'path' => '/.env', 'status_code' => 404], ]);
Event types
| Type | Description |
|---|---|
http_request |
Incoming HTTP request |
login_failed |
Failed authentication |
login_success |
Successful login |
forbidden |
Access denied |
waf_block |
Request blocked by a WAF |
bot_detected |
Bot traffic detected |
Laravel
The service provider is auto-discovered — nothing to register manually.
1. Configure
php artisan vendor:publish --tag=loguard-config
LOGUARD_API_KEY=lg_live_xxx LOGUARD_ENV=production LOGUARD_QUEUE_EVENTS=true
2. Add the middleware
Laravel 11+ (bootstrap/app.php):
use LoGuard\Sdk\Laravel\Http\Middleware\LoGuardMiddleware; ->withMiddleware(function (Middleware $middleware) { $middleware->append(LoGuardMiddleware::class); })
Laravel 10 and earlier (app/Http/Kernel.php):
protected $middleware = [ // ... \LoGuard\Sdk\Laravel\Http\Middleware\LoGuardMiddleware::class, ];
This tracks HTTP error responses (configurable via loguard.middleware.track_statuses,
default 400,401,403,404,429,500,502,503) as LoGuard events automatically.
3. Use directly (facade or DI)
use LoGuard\Sdk\Laravel\Facades\LoGuard; LoGuard::event( type: 'waf_block', ip: $request->ip(), path: $request->path(), statusCode: 403, );
Or inject LoGuard\Sdk\Client like any other service.
Queue-backed delivery (recommended for production)
Set LOGUARD_QUEUE_EVENTS=true and run a queue worker. Events captured
by the middleware are then dispatched as a real Laravel job
(LoGuard\Sdk\Laravel\Jobs\SendLoGuardEvents) instead of being flushed
inline at request end — delivery survives worker restarts, gets
Laravel's own retry/backoff, and adds zero latency to the HTTP
response, at the cost of needing a running queue worker.
Without queueing, delivery happens from terminate(), which (on
PHP-FPM, via fastcgi_finish_request) still runs after the response
has been sent to the browser — but it runs inside the same web worker
process, so a slow/unreachable LoGuard API can hold that worker for up
to timeout * retries seconds. Queueing avoids that entirely.
Forwarding request headers (optional, off by default)
A handful of severe vulnerabilities (ShellShock, ProxyLogon) only show
up inside specific HTTP headers. By default, nothing beyond what the
SDK needs internally (X-Forwarded-For, only to resolve the real
client IP, never forwarded as data) is sent to LoGuard.
// config/loguard.php 'middleware' => [ 'track_headers' => \LoGuard\Sdk\Http\HeaderPolicy::KNOWN_EXPLOIT_HEADERS, // or your own list, e.g. ['User-Agent', 'Referer', 'X-My-Header'], ],
Authorization, Cookie, Set-Cookie, X-Api-Key, X-Auth-Token,
and Proxy-Authorization are never forwarded, even if listed here —
enforced in code (HeaderPolicy::FORBIDDEN_HEADERS), not just documented.
Trusting a reverse proxy
X-Forwarded-For is ignored unless the direct TCP peer is a proxy you
explicitly name (secure-by-default — otherwise any visitor could spoof
their tracked IP):
LOGUARD_TRUSTED_PROXIES=10.0.0.0/8,203.0.113.5
Error handling
All SDK errors extend LoGuard\Sdk\Exceptions\LoGuardException:
use LoGuard\Sdk\Exceptions\{ LoGuardAuthException, // invalid API key / expired subscription LoGuardQuotaException, // monthly event quota exceeded LoGuardConnectionException,// network/server error, retries exhausted LoGuardValidationException,// malformed event data LoGuardNotFoundException, LoGuardConflictException, }; try { $loguard->event(type: 'login_failed', ip: $ip, path: $path, statusCode: 401); } catch (LoGuardQuotaException $e) { // upgrade prompt, or just stop sending until next month } catch (LoGuardConnectionException $e) { // LoGuard is unreachable — this is not your app's fault, log and move on }
eventAsync() never throws — failures are dropped silently (matching
every other LoGuard SDK's fire-and-forget semantics), which is why the
queue-backed Laravel path is preferable when you need delivery
guarantees.
Retry behavior
Requests retry on 500, 502, 503, 504 and connection-level
failures (DNS, TLS, timeout, reset), up to retries attempts
(default 3) with linear backoff (0.4s * attempt). 429 is mapped to
LoGuardQuotaException (quota) or treated as a non-retried rate-limit
error, matching the other SDKs — LoGuard's own backend is responsible
for rate-limit pacing, not client-side retry-until-success.
Performance
- Zero HTTP dependency: built on
ext-curl, already present in nearly every PHP install. event()/eventBatch()are the only blocking calls;eventAsync()never blocks the caller.- Response bodies are capped at 5 MiB and streamed via a curl write callback — a misbehaving or malicious server response can't exhaust your worker's memory.
- No autoloading of the Laravel integration unless Laravel is present
(separate namespace, no
requirefrom the core classes).
Security
See docs/SECURITY.md for the full audit notes —
attack classes considered, what's mitigated, and what's out of scope
for a client SDK.
Troubleshooting
| Symptom | Likely cause |
|---|---|
LoGuardValidationException: base_url must use https:// |
You passed a non-HTTPS base_url without allowInsecureTransport: true. Only use that flag for local development. |
Events silently not arriving via eventAsync()/middleware |
Check loguard.enabled (is an API key configured?), then check application logs — failures are swallowed by design but still report()-ed in the Laravel middleware. |
LoGuardAuthException: Invalid API key |
Confirm LOGUARD_API_KEY in the environment actually reaching your app matches the dashboard value (no leading/trailing whitespace — Config trims it, but double check .env quoting). |
| Slow responses after adding the middleware | You're not on LOGUARD_QUEUE_EVENTS=true and either PHP-FPM isn't finishing the request before terminate() runs, or LoGuard itself is slow — lower LOGUARD_TIMEOUT/LOGUARD_RETRIES or switch to queueing. |
Production deployment checklist
-
LOGUARD_API_KEYset via secret manager / environment, never committed. -
LOGUARD_BASE_URLishttps://(default) — do not setLOGUARD_ALLOW_INSECURE_TRANSPORTin production. -
LOGUARD_QUEUE_EVENTS=truewith a supervised queue worker, so LoGuard delivery never competes with request latency. -
LOGUARD_TRUSTED_PROXIESset to your actual load balancer/proxy IPs if you're behind one — otherwise IP-based alerting can be trivially spoofed. -
track_headersleft empty unless you've reviewed exactly which headers you're opting in to forward.