Installation#
This page gets you from zero to a working Webrick install. The router targets PHP 8.4+ and ships as a Composer library.
Requirements
PHP: 8.4+
Extensions:
mbstring,json,zlib(optionallybrotli/zstdif you want those codecs)Composer: latest stable
Web server (prod): Nginx → PHP-FPM (Apache optional in front)
1) Install via Composer#
composer require infocyph/webrick
This will install the core package and its dependencies (infocyph/arraykit, infocyph/intermix).
2) Minimal project layout#
You can choose any layout; just keep the route cache path writable by your deploy user.
your-app/
├─ public/
│ └─ index.php # front controller
├─ routes/
│ └─ web.php # your routes (or use attribute routes)
├─ src/ # controllers, services
├─ var/
│ └─ cache/routes/ # route cache (sharded dir) or a single fused file
└─ vendor/
3) Environment keys#
Set secrets via environment variables or your config layer:
WEBRICK_SIGN_KEY: secret used for signed/temporary URLs. Any reasonably long random string is fine; rotate if leaked.WEBRICK_SIGN_TTL: default TTL (seconds) for temporary URLs, e.g.,900.WEBRICK_COOKIE_KEYS(optional): a comma‑separated list of 32‑byte raw keys for cookie encryption (AES‑256‑GCM). The index in the list is the active Key ID (KID) you pass to the middleware.
Example .env:
WEBRICK_SIGN_KEY="base64:KJ9r...replace_me...kQ="
WEBRICK_SIGN_TTL=900
WEBRICK_COOKIE_KEYS="hex:001122... (32 bytes),hex:8899aa... (32 bytes)"
Cookie encryption is optional. If you enable it, supply at least one 32‑byte key; add more for rotation.
4) Web server setup (production)#
Use your preferred stack. A typical Nginx → PHP‑FPM setup serves static assets directly and forwards everything else to the front controller.
Key points
Ensure your front controller (e.g.,
public/index.php) receives all non‑existing paths.Do not enable double compression at the edge if you use Webrick’s CompressionMiddleware.
Make the route cache path (
.route-cacheor fused file) writable during deploys.
See Deployments → Nginx/Apache/PHP‑FPM for copy‑paste configs and tuning.
5) Troubleshooting Installation#
Common Issues#
Extension Not Found#
Error: PHP Fatal error: Uncaught Error: Call to undefined function zstd_compress()
Solution:
# Install zstd extension
pecl install zstd
# Enable in php.ini
echo "extension=zstd.so" >> /etc/php/8.4/cli/php.ini
echo "extension=zstd.so" >> /etc/php/8.4/fpm/php.ini
# Restart PHP-FPM
systemctl restart php8.4-fpm
Composer Memory Limit#
Error: Fatal error: Allowed memory size exhausted
Solution:
# Increase memory limit for this command
php -d memory_limit=-1 /usr/local/bin/composer install
Permission Denied on Cache Directory#
Error: Unable to create directory .route-cache
Solution:
# Create directory with correct permissions
mkdir -p .route-cache
chown -R www-data:www-data .route-cache
chmod -R 775 .route-cache
# Or for development
chmod -R 777 .route-cache # ⚠️ Dev only!
Autoload Not Working#
Error: Class 'Infocyph\Webrick\Router\Kernel\RouterKernel' not found
Solution:
# Regenerate autoload
composer dump-autoload
# Or reinstall
rm -rf vendor/
composer install
Route Cache Build Fails#
Error: Route cache build failed - check for conflicts
Causes:
Duplicate route names
Invalid parameter constraints
Syntax errors in route files
Debug:
# Run with verbose output
php ./webrick route:cache --cache=.route-cache --routes=routes.php
# Check for duplicate names
grep -r "->withName(" routes/ | sort | uniq -d
# Validate route syntax
php -l routes.php
6) Verify Installation#
Create a simple test script:
<?php
// test-install.php
require __DIR__ . '/vendor/autoload.php';
use Infocyph\Webrick\Router\Kernel\RouterKernel;
use Infocyph\Webrick\Router\Definition\Registrar;
use Infocyph\Webrick\Router\Matching\ShardedMatcher;
use Infocyph\Webrick\Request\Request;
use Infocyph\Webrick\Response\Response;
use Psr\Log\NullLogger;
echo "Testing Webrick installation...\n\n";
// Test 1: Kernel boots
try {
$kernel = RouterKernel::bootWithRegistrar(
log: new NullLogger(),
matcher: ShardedMatcher::make(__DIR__ . '/.route-cache'),
register: static function (Registrar $r): void {
unset($r);
\Infocyph\Webrick\Router\Facade\Router::get(
'/test',
fn() => Response::plaintext('OK', 200),
);
},
);
echo "✅ Kernel boots successfully\n";
} catch (Throwable $e) {
echo "❌ Kernel boot failed: {$e->getMessage()}\n";
exit(1);
}
echo "✅ Route registration works\n";
// Test 3: Request handling
try {
$request = Request::fake(method: 'GET', uri: '/test');
$response = $kernel->handle($request);
if ($response->getStatusCode() === 200 && (string)$response->getBody() === 'OK') {
echo "✅ Request handling works\n";
} else {
echo "❌ Request handling failed: unexpected response\n";
exit(1);
}
} catch (Throwable $e) {
echo "❌ Request handling failed: {$e->getMessage()}\n";
exit(1);
}
// Test 4: Response helpers
try {
$json = Response::json(['test' => true]);
if ($json->getHeaderLine('Content-Type') === 'application/json; charset=UTF-8') {
echo "✅ Response helpers work\n";
} else {
echo "❌ Response helpers failed: wrong content-type\n";
exit(1);
}
} catch (Throwable $e) {
echo "❌ Response helpers failed: {$e->getMessage()}\n";
exit(1);
}
// Test 5: Compression available
$compressionAvailable = [];
if (function_exists('zstd_compress')) {
$compressionAvailable[] = 'zstd';
}
if (function_exists('brotli_compress')) {
$compressionAvailable[] = 'brotli';
}
if (function_exists('gzencode')) {
$compressionAvailable[] = 'gzip';
}
if (!empty($compressionAvailable)) {
echo "✅ Compression available: " . implode(', ', $compressionAvailable) . "\n";
} else {
echo "⚠️ No compression extensions found (optional)\n";
}
echo "\n✨ All tests passed! Webrick is ready.\n";
Run the test:
php test-install.php
Expected output:
Testing Webrick installation...
✅ Kernel boots successfully
✅ Route registration works
✅ Request handling works
✅ Response helpers work
✅ Compression available: zstd, brotli, gzip
✨ All tests passed! Webrick is ready.
7) Next Steps#
📖 Read the Quick Start Guide for a full example
🚀 Check Deployments for production setup
🔧 Review Middleware for available components
📚 Explore Guides for common patterns