Install via Composer
composer require cleentfaar/tissue-bundle
Ensure symfony/flex is configured to auto-load bundles (default in Laravel/Symfony 5.1+).
Enable the Bundle
Add to config/bundles.php (Symfony) or config/app.php (Laravel via extra.bundles):
Cleentfaar\TissueBundle\CLTissueBundle::class => ['all' => true],
Configure Tissue Publish the default config:
php artisan vendor:publish --tag=tissue-config
Edit config/tissue.php to specify:
scanner (e.g., clamav, fprot)scan_paths (directories/files to monitor)excluded_paths (ignored files/dirs)threshold (max allowed infections before blocking)First Scan Trigger a manual scan via CLI:
php artisan tissue:scan
Or integrate into a Laravel job/queue for async processing.
Hook into Upload Logic Use middleware or a service to scan files before saving:
use Cleentfaar\TissueBundle\Scanner;
class UploadController extends Controller {
public function store(Request $request) {
$scanner = app(Scanner::class);
$file = $request->file('document');
if ($scanner->scan($file->getPathname())) {
throw new \Exception("Malware detected!");
}
// Save file...
}
}
Log Results
Enable logging in tissue.php:
'log_results' => true,
Check storage/logs/tissue.log for scan reports.
Cron Job Integration
Add to app/Console/Kernel.php:
protected function schedule(Schedule $schedule) {
$schedule->command('tissue:scan')->dailyAt('2:00');
}
Or use Laravel’s task scheduler:
php artisan schedule:run
Batch Processing For large directories, chunk scans:
$scanner->scanDirectory('/path/to/files', 100); // Scan 100 files at a time
Laravel Filesystem
Scan files stored in storage/app:
use Illuminate\Support\Facades\Storage;
$path = Storage::path('uploads/document.pdf');
$scanner->scan($path);
Event-Driven Scans Trigger scans on file uploads via events:
// In EventServiceProvider
protected $listen = [
'file.uploaded' => [Scanner::class, 'scanFile'],
];
Custom Actions on Infection
Extend the ScanResult object to add logic:
$result = $scanner->scan($file);
if ($result->isInfected()) {
$this->quarantine($file); // Custom method
}
Dependency Injection
Bind the scanner in config/services.php (Laravel) or services.yaml (Symfony):
'scanner' => Cleentfaar\TissueBundle\Scanner::class,
Inject via constructor:
public function __construct(private Scanner $scanner) {}
Twig Integration (Symfony) Pass scan results to templates:
{% if scanResult.isInfected %}
<div class="alert">⚠️ Malware detected!</div>
{% endif %}
Scanner Dependencies
clamav-daemon) is installed and running.
sudo apt-get install clamav).tissue.php for scanner config and verify the binary path.Performance Overhead
storage/app/public) can be slow.
scanDirectory() with batch sizes or offload to a queue.False Positives
threshold or whitelist paths in excluded_paths.File Locking
Verbose Logging
Enable debug mode in tissue.php:
'debug' => true,
Logs will include scanner commands and file paths.
Manual Scanner Test Run the scanner directly to verify:
clamscan /path/to/file # Replace with your scanner command
Artisan Commands
php artisan tissue:scan --path=/custom/path (scan specific dir)php artisan tissue:update (update scanner definitions)Custom Scanners
Implement Cleentfaar\TissueBundle\ScannerInterface:
class MyScanner implements ScannerInterface {
public function scan(string $file): ScanResult {
// Custom logic (e.g., API call to a cloud scanner)
}
}
Register in tissue.php:
'scanner' => MyScanner::class,
Post-Scan Actions
Extend ScanResult to add metadata:
$result->setCustomData(['user_id' => auth()->id(), 'action' => 'quarantine']);
Database Integration Store results in a table:
$scanner->scan($file)->saveToDatabase(); // Hypothetical method
Tip: Use Laravel’s observers or events to sync with a scan_results table.
Case-Sensitive Paths
Ensure scan_paths and excluded_paths use consistent slashes (/ or \) based on your OS.
Symlinks Scanning symlinked directories may cause infinite loops.
follow_symlinks: false to tissue.php.Environment-Specific Config
Use Laravel’s .env or Symfony’s %kernel.environment% to switch scanners:
'scanner' => env('TISSUE_SCANNER', 'clamav'),
How can I help you explore Laravel packages today?