## Getting Started
### Minimal Setup
1. **Installation**:
```bash
composer require plank/laravel-mediable:^7.0
Publish the config and migrations:
php artisan vendor:publish --provider="Plank\Mediable\MediableServiceProvider"
php artisan migrate
First Use Case (Updated for Security): Upload a file with enhanced security checks:
use Plank\Mediable\HasMediable;
use Plank\Mediable\MediaUploader;
use Plank\Mediable\Enum\OnDuplicateBehaviour;
class Post extends Model
{
use HasMediable;
}
// In your controller:
$post = Post::find(1);
$media = MediaUploader::fromRequest($request, 'image')
->toDestination('public', 'posts/thumbnails')
->onDuplicate(OnDuplicateBehaviour::RENAME) // Use enum instead of constant
->upload();
$post->addMedia($media)->usingCollection('thumbnails')->save();
Key Files (Updated):
config/mediable.php: Configure new security settings (remote hosts, schemes, forbidden extensions/MIME types, sanitizers).app/Models/Media.php: Base model for media records (extend if needed).app/Models/Mediable.php: Trait for polymorphic media relationships.Plank\Mediable\MediaUploaderConfiguration class for cleaner config handling.$media = MediaUploader::fromRequest($request, 'image')
->toDestination('public', 'uploads')
->setForbiddenExtensions(['php', 'exe']) // Block dangerous extensions
->setForbiddenMimeTypes(['text/x-php', 'application/x-httpd-php'])
->upload();
// config/mediable.php
'allowed_remote_hosts' => ['*.example.com', 'cdn.example.org'],
'allowed_remote_schemes' => ['https'],
// In code:
$media = MediaUploader::fromRemoteUrl('https://example.com/image.jpg')
->toDestination('public', 'remote')
->upload(); // Will reject non-whitelisted hosts
config/mediable.php:
'sanitizers' => [
// 'Plank\Mediable\Sanitizers\SvgSanitizer' => false, // Disable
],
$post->addMedia($media)->usingCollection('featured')->save();
$media->tags()->sync(['thumbnail', 'primary']);
$post->getMedia('thumbnails');
$media->getUrl();
$media->generateVariant(['width' => 300, 'height' => 200], 'thumbnail');
$post->deleteMedia($media, 'thumbnails');
Extend the Media model as before.
Use MediaUploaderConfiguration for cleaner config:
$config = new MediaUploaderConfiguration([
'disk' => 's3',
'destination_path' => 'custom/path',
'forbidden_extensions' => ['php', 'exe'],
]);
$uploader = new MediaUploader($config);
$media = $uploader->fromRequest($request, 'file')->upload();
Configure new security settings in config/mediable.php:
'disks' => ['public', 's3'],
'allowed_remote_hosts' => ['*.trusted.com'],
'allowed_remote_schemes' => ['https'],
'forbidden_file_extensions' => ['php', 'exe', 'pl', 'bat'],
'forbidden_mime_types' => ['text/x-php', 'application/x-httpd-php'],
'sanitizers' => [
'Plank\Mediable\Sanitizers\SvgSanitizer' => true,
],
Serialize media with relationships as before.
Test security restrictions:
// Test forbidden extension rejection
$this->expectException(\Plank\Mediable\Exceptions\ForbiddenFileExtension::class);
MediaUploader::fromSource(fake()->createFile('script.php.jpg'))
->toDestination('public', 'test')
->upload();
SSRF Protection (New)
allowed_remote_hosts to whitelist trusted domains:
'allowed_remote_hosts' => ['*.yourdomain.com'],
*.sub.example.com.Directory Traversal (Fixed)
. characters (CVE-2026-49970).../../evil.php → evil.php (blocked).../ or hidden files.Forbidden Extensions/MIME Types (New)
php, exe, pl, bat, etc.script.php.jpg → script-php.jpg.config/mediable.php:
'forbidden_file_extensions' => ['php', 'exe', 'phtml'],
'forbidden_mime_types' => ['text/x-php', 'application/x-httpd-php'],
SVG Sanitization (New)
config/mediable.php if needed (not recommended):
'sanitizers' => [
'Plank\Mediable\Sanitizers\SvgSanitizer' => false,
],
Breaking Changes
ON_DUPLICATE_* constants → Plank\Mediable\Enum\OnDuplicateBehaviour enum.
Update calls like:
// Old:
->onDuplicate(MediaUploader::ON_DUPLICATE_RENAME)
// New:
->onDuplicate(OnDuplicateBehaviour::RENAME)
MediaUploader now accepts MediaUploaderConfiguration instead of raw arrays.Large Files (Unchanged)
php.ini (upload_max_filesize, post_max_size) and Laravel’s MAX_FILE_SIZE in forms.Tagging Quirks (Unchanged)
Log Security Rejections Add logging for blocked uploads:
$uploader->beforeUpload(function ($file) {
if ($file->isValid()) {
\Log::debug('Upload allowed', ['file' => $file->getClientOriginalName()]);
} else {
\Log::warning('Upload blocked', [
'file' => $file->getClientOriginalName(),
'reason' => $file->getError(),
]);
}
});
Check Remote URL Restrictions
Verify allowed_remote_hosts and allowed_remote_schemes:
$uploader = MediaUploader::fromRemoteUrl('https://untrusted.com/file.jpg');
// Will throw \Plank\Mediable\Exceptions\ForbiddenRemoteHost if untrusted.
Inspect Sanitized Paths Debug path sanitization:
$path = $uploader->getDestinationPath();
\Log::debug('Sanitized path', ['path' => $path]);
Validate Forbidden Extensions Test extension blocking
How can I help you explore Laravel packages today?