jenssegers/optimus
Optimus obfuscates internal numeric IDs using Knuth’s integer hash. Like Hashids but returns fast, reversible integers (not strings). Generate prime/inverse/random via a CLI command, then encode/decode IDs consistently across your app.
Install the Package:
composer require jenssegers/optimus
For 32-bit systems, install the GMP extension:
apt-get install php8.1-gmp # Adjust version as needed
Generate Keys: Run the Artisan command to generate a prime, inverse, and random number:
php artisan optimus:spark
Example output:
Prime: 2123809381
Inverse: 1885413229
Random: 146808189
Save these values for use in your application.
Register the Service Provider:
Add the following to config/app.php:
App\Providers\OptimusServiceProvider::class,
Create the provider:
namespace App\Providers;
use Jenssegers\Optimus\Optimus;
use Illuminate\Support\ServiceProvider;
class OptimusServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton(Optimus::class, function ($app) {
return new Optimus(2123809381, 1885413229, 146808189); // Replace with your generated values
});
}
}
First Use Case: Encode and decode an ID in a controller:
use Jenssegers\Optimus\Optimus;
class UserController extends Controller
{
public function show($id, Optimus $optimus)
{
$originalId = $optimus->decode($id);
$user = User::find($originalId);
return view('user.show', compact('user'));
}
}
Leverage Laravel’s DI to inject Optimus into controllers, services, or middleware:
// Controller
public function index(Optimus $optimus) {
$encodedIds = $optimus->encode(1); // Example
return response()->json(['encoded_id' => $encodedIds]);
}
Create middleware to decode IDs in routes:
namespace App\Http\Middleware;
use Closure;
use Jenssegers\Optimus\Optimus;
class DecodeIdMiddleware
{
public function __construct(protected Optimus $optimus) {}
public function handle($request, Closure $next)
{
$id = $request->route('id');
$request->merge(['id' => $this->optimus->decode($id)]);
return $next($request);
}
}
Register in app/Http/Kernel.php:
protected $middleware = [
\App\Http\Middleware\DecodeIdMiddleware::class,
];
Extend Eloquent models to auto-encode IDs in responses:
use Jenssegers\Optimus\Optimus;
class User extends Model
{
public function getIdAttribute($value)
{
return app(Optimus::class)->encode($value);
}
}
Use Laravel’s App\Services\ResolvesApplication to encode IDs in API responses:
namespace App\Services;
use Jenssegers\Optimus\Optimus;
use Illuminate\Http\Resources\Json\JsonResource;
class EncodeIds extends JsonResource
{
public function toArray($request)
{
$array = parent::toArray($request);
$optimus = app(Optimus::class);
if (isset($array['id'])) {
$array['id'] = $optimus->encode($array['id']);
}
return $array;
}
}
Decode/encode IDs in bulk for migrations or data exports:
use Jenssegers\Optimus\Optimus;
$optimus = app(Optimus::class);
$users = User::all()->pluck('id');
$encodedIds = $users->map(fn($id) => $optimus->encode($id));
Prime/Inverse Consistency:
.env or a secure config file:
OPTIMUS_PRIME=2123809381
OPTIMUS_INVERSE=1885413229
OPTIMUS_RANDOM=146808189
OptimusServiceProvider:
return new Optimus(
config('optimus.prime'),
config('optimus.inverse'),
config('optimus.random')
);
ID Range Limits:
2147483647. Negative IDs or zero will fail.if ($id <= 0 || $id >= 2147483647) {
throw new \InvalidArgumentException('ID out of range');
}
32-bit Systems:
README or DEPLOYMENT.md:
## Requirements
- PHP GMP extension (for 32-bit systems)
Collision Risk:
$maxId = User::max('id');
$encoded = $optimus->encode($maxId);
$decoded = $optimus->decode($encoded);
assert($maxId === $decoded);
Logging Original IDs:
\Log::debug('Original ID', ['original' => $originalId, 'encoded' => $encodedId]);
Validate Keys:
spark command in a test environment:
php artisan optimus:spark --verify
Check for Middleware Conflicts:
// Debug middleware
\Log::debug('Raw ID', [$request->route('id')]);
\Log::debug('Decoded ID', [$this->optimus->decode($request->route('id'))]);
Performance Bottlenecks:
$start = microtime(true);
$optimus->encode($id);
$time = microtime(true) - $start;
\Log::debug('Encoding time', [$time]);
Custom Prime Generation:
spark command to generate tenant-specific primes:
// app/Console/Commands/GenerateTenantPrimes.php
use Jenssegers\Optimus\Optimus;
class GenerateTenantPrimes extends Command
{
public function handle()
{
$tenants = Tenant::all();
foreach ($tenants as $tenant) {
$prime = $this->generatePrimeForTenant($tenant->id);
Tenant::where('id', $tenant->id)->update(['optimus_prime' => $prime]);
}
}
protected function generatePrimeForTenant(int $tenantId): int
{
// Custom logic to generate tenant-specific primes
return 1580030173 + $tenantId; // Example
}
}
Fallback for Invalid IDs:
try {
$id = $optimus->decode($request->id);
} catch (\InvalidArgumentException $e) {
\Log::warning('Invalid obfuscated ID', ['id' => $request->id]);
return response()->json(['error' => 'Invalid ID'], 400);
}
Multi-Tenant Support:
TenantOptimus facade to switch primes per tenant:
// app/Facades/TenantOptimus.php
use Illuminate\Support\Facades\Facade;
class TenantOptimus extends Facade
{
protected static function getFacadeAccessor()
{
return 'tenant.optimus';
}
}
OptimusServiceProvider:
$this->app->bind('tenant.optimus', function ($app) {
$tenant
How can I help you explore Laravel packages today?