Secure Uploads - v1.0.0
Scanner Setup
Three shipped scanner implementations satisfy MalwareScannerInterface. Pick one by setting SECURE_UPLOADS_MALWARE_DRIVER (or config('artisanpack.secure-uploads.malwareScanning.driver')).
null (default)
No-op scanner. Every scan returns "clean". Use in dev, CI, and as a kill-switch.
SECURE_UPLOADS_MALWARE_DRIVER=null
SECURE_UPLOADS_MALWARE_SCANNING_ENABLED=false # or true; either works
isAvailable() always returns true, so failOnScanError is irrelevant.
clamav
Runs against a local ClamAV install. Socket-first with binary fallback.
SECURE_UPLOADS_MALWARE_SCANNING_ENABLED=true
SECURE_UPLOADS_MALWARE_DRIVER=clamav
CLAMAV_SOCKET_PATH=/var/run/clamav/clamd.sock
CLAMAV_BINARY_PATH=/usr/bin/clamscan
The scanner tries the socket first. If the socket doesn't exist or can't connect, it falls back to invoking the binary. Socket is dramatically faster (no process spawn + signature DB stays loaded) — prefer it for production.
Operational notes
- Keep
freshclamrunning. The signature DB rots quickly. On Debian / Ubuntu theclamav-freshclamservice handles this. - The socket needs filesystem-level access. Add your web server / queue worker user to the
clamavgroup, or runclamdwith a socket path your app user can read. isAvailable()returns false when neither the socket nor the binary works. Pair withfailOnScanError => truein production to fail closed.timeout(default 30s) applies to both socket and binary modes. Files larger than your typical scan time should bump this.
Testing your install
use ArtisanPackUI\SecureUploads\Services\Scanners\ClamAvScanner;
$scanner = new ClamAvScanner();
dump($scanner->isAvailable()); // true if socket or binary responds
$result = $scanner->scan('/path/to/eicar.com.txt'); // EICAR test file
dump($result->infected, $result->signature);
Download the EICAR test file from https://www.eicar.org/ — it triggers every legitimate AV without being malicious itself.
virustotal
Runs against the VirusTotal cloud service.
SECURE_UPLOADS_MALWARE_SCANNING_ENABLED=true
SECURE_UPLOADS_MALWARE_DRIVER=virustotal
VIRUSTOTAL_API_KEY=your_key_here
The scanner first computes the file's SHA-256 hash and calls scanByHash() to check if VirusTotal has already analyzed an identical file. If a result is cached at VirusTotal, no upload happens — the cached verdict is used. Only previously-unseen files are uploaded.
Operational notes
- API quota. The free tier is ~4 requests / minute. Production uploads at any meaningful volume need the paid tier.
- Privacy. Files are sent to a third-party service. Don't use VirusTotal for confidential / regulated data.
- Latency. Cold-path scans (file unknown to VirusTotal) involve an upload + a wait for analysis. The default
timeoutis 60 seconds; bump it for large files. isAvailable()checks that the API key is set and the VirusTotal API responds.
Testing your install
use ArtisanPackUI\SecureUploads\Services\Scanners\VirusTotalScanner;
$scanner = new VirusTotalScanner();
dump($scanner->isAvailable()); // true if API responds
// EICAR's SHA-256 is well-known and pre-classified at VirusTotal
$result = $scanner->scan('/path/to/eicar.com.txt');
Building your own
Implement MalwareScannerInterface (3 methods: scan, isAvailable, getName) and bind it in a service provider. See Custom scanners for the contract details and a worked example.