Installation
composer require baks-dev/files-cdn
Ensure your server meets PHP 8.4+ requirements.
Directory Setup
mkdir -p public/upload && chown -R unit:unit public/upload
Configure the public/upload directory as the upload root.
Security Configuration Generate a hashed password:
php bin/console security:hash-password
Update config/packages/security.php with your UUIDv7 user and hashed password.
Environment Configuration
Add to your .env:
CDN_HOST=cdn.example.host
CDN_USER=<your-uuidv7-user>
CDN_PASS=<plaintext-password>
First Use Case
Upload a file via HTTP Basic Auth to https://cdn.example.host/cdn/upload.
Example using Laravel HTTP client:
$response = Http::withHeaders([
'Authorization' => 'Basic ' . base64_encode("{$env('CDN_USER')}:{$env('CDN_PASS')}")
])->attach('file', fopen('path/to/file.jpg', 'r'))
->post("https://{$env('CDN_HOST')}/cdn/upload");
File Upload Workflow
// app/Http/Middleware/ValidateCdnUpload.php
public function handle(Request $request, Closure $next) {
if ($request->isMethod('post') && $request->hasFile('file')) {
$response = Http::withHeaders([
'Authorization' => 'Basic ' . base64_encode("{$env('CDN_USER')}:{$env('CDN_PASS')}")
])->attach('file', $request->file('file'))
->post("https://{$env('CDN_HOST')}/cdn/upload");
return response()->json($response->json());
}
return $next($request);
}
app/Http/Kernel.php:
protected $routeMiddleware = [
'cdn.upload' => \App\Http\Middleware\ValidateCdnUpload::class,
];
URL Generation Dynamically generate CDN URLs for uploaded files:
public function getCdnUrl(string $filename): string {
return "https://{$this->cdnHost}/uploads/{$filename}";
}
Batch Processing Use Laravel queues to handle bulk uploads asynchronously:
// app/Jobs/UploadToCdn.php
public function handle() {
foreach ($this->files as $file) {
Http::post("https://{$env('CDN_HOST')}/cdn/upload", [
'file' => fopen($file->path, 'r')
]);
}
}
Filesystem to proxy requests to the CDN.
// app/Providers/AppServiceProvider.php
public function register() {
$this->app->singleton(\Illuminate\Contracts\Filesystem\Filesystem::class, function () {
return new CdnFilesystem(
new FilesystemAdapter(new CdnClient())
);
});
}
$request->validate([
'file' => 'required|file|mimes:jpg,png,pdf|max:10240',
]);
$response = Http::withOptions(['debug' => true])->post(...);
Authentication Failures
.env CDN_PASS matches the plaintext password used in security:hash-password.CDN_USER UUIDv7 is consistent across configurations.File Permissions
public/upload directory must be writable by the web server user (e.g., unit:unit).ls -la public/upload to confirm permissions.CORS Issues
add_header 'Access-Control-Allow-Origin' 'https://your-app.com';
Rate Limiting
use Symfony\Component\Mime\Part\DataPart;
use Illuminate\Support\Facades\Http;
$attempts = 0;
$maxAttempts = 3;
$delay = 100; // ms
while ($attempts < $maxAttempts) {
try {
$response = Http::post(...);
break;
} catch (\Exception $e) {
$attempts++;
usleep($delay * pow(2, $attempts));
}
}
/var/log/nginx/error.log or similar) for failed requests.curl -u "$CDN_USER:$CDN_PASS" "https://$CDN_HOST/cdn/upload"
// Test if password matches
$hasher = new Symfony\Component\PasswordHasher\Hasher\UserPasswordHasher();
$isValid = $hasher->isPasswordValid(
new User(['password' => $hashedPassword]),
$plainPassword
);
Custom Storage Adapter Extend the CDN client to support additional features (e.g., presigned URLs):
class CustomCdnClient extends \BaksDev\FilesCdn\Client {
public function generatePresignedUrl(string $filename, int $expiry = 3600): string {
// Implement logic to generate a presigned URL
}
}
Webhook Integration Listen for file upload events via webhooks (if the CDN supports them) to trigger Laravel jobs:
// routes/web.php
Route::post('/cdn/webhook', function (Request $request) {
UploadEvent::dispatch($request->json());
});
Fallback Mechanism Implement a fallback to local storage if the CDN is unavailable:
public function getFileUrl(string $filename): string {
try {
return $this->cdn->getUrl($filename);
} catch (\Exception $e) {
return Storage::url("fallback/{$filename}");
}
}
Configuration Overrides Override CDN settings dynamically (e.g., per-environment):
// config/cdn.php
return [
'host' => env('CDN_HOST', 'cdn.default.host'),
'timeout' => env('CDN_TIMEOUT', 30),
];
How can I help you explore Laravel packages today?