Scan for Malware with PHP
Use AttachmentScanner to scan files and URLs for viruses and malware using GuzzleHttp.
Scan a URL
The simplest way to scan — pass a URL and get back a result:
<?php
require __DIR__ . '/vendor/autoload.php';
use GuzzleHttp\Client;
$client = new Client([
'base_uri' => getenv('ATTACHMENT_SCANNER_URL'),
'headers' => [
'Authorization' => 'Bearer ' . getenv('ATTACHMENT_SCANNER_API_TOKEN'),
],
]);
$response = $client->post('/v1.0/scans', [
'json' => ['url' => 'https://www.attachmentscanner.com/eicar.com'],
]);
$result = json_decode($response->getBody(), true);
echo $result['status']; // "found"
print_r($result['matches']); // ["Eicar-Test-File-Signature"]
Scan a File
Upload a file directly from disk:
<?php
$response = $client->post('/v1.0/scans', [
'multipart' => [
[
'name' => 'file',
'contents' => fopen('/path/to/file.pdf', 'r'),
'filename' => 'file.pdf',
],
],
]);
$result = json_decode($response->getBody(), true);
echo $result['status']; // "ok" if clean, "found" if malware detected
Async Scan with Callback
For large files or non-blocking workflows, use async: true with a callback URL.
The API returns immediately with a pending status and POSTs the result to your callback
when the scan completes:
<?php
// 1. Submit the scan
$response = $client->post('/v1.0/scans', [
'json' => [
'url' => 'https://example.com/large-file.zip',
'async' => true,
'callback' => 'https://your-app.com/webhooks/scan-complete',
],
]);
$scan = json_decode($response->getBody(), true);
echo $scan['id']; // "a1b2c3d4-..."
echo $scan['status']; // "pending"
<?php
// 2. Handle the callback
$result = json_decode(file_get_contents('php://input'), true);
if ($result['status'] === 'found') {
// quarantine or delete the file
}
echo json_encode(['received' => true]);
Or poll for results instead:
<?php
// Poll for results (alternative to callback)
$response = $client->get('/v1.0/scans/' . $scan['id']);
$result = json_decode($response->getBody(), true);
echo $result['status']; // "ok", "found", "pending", etc.
Laravel
A Laravel controller that accepts file uploads and scans them:
<?php
namespace App\Http\Controllers;
use GuzzleHttp\Client;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
class ScanController extends Controller
{
private Client $client;
public function __construct()
{
$this->client = new Client([
'base_uri' => env('ATTACHMENT_SCANNER_URL'),
'headers' => [
'Authorization' => 'Bearer ' . env('ATTACHMENT_SCANNER_API_TOKEN'),
],
]);
}
public function scanUrl(Request $request): JsonResponse
{
$response = $this->client->post('/v1.0/scans', [
'json' => ['url' => $request->input('url')],
]);
return response()->json(
json_decode($response->getBody(), true)
);
}
public function scanFile(Request $request): JsonResponse
{
$file = $request->file('file');
$response = $this->client->post('/v1.0/scans', [
'multipart' => [
[
'name' => 'file',
'contents' => fopen($file->getPathname(), 'r'),
'filename' => $file->getClientOriginalName(),
],
],
]);
return response()->json(
json_decode($response->getBody(), true)
);
}
// Webhook callback handler
public function scanCallback(Request $request): JsonResponse
{
$result = $request->all();
if ($result['status'] === 'found') {
// quarantine or delete the file
} elseif ($result['status'] === 'ok') {
// file is clean — move to final storage
}
return response()->json(['received' => true]);
}
}
curl Equivalent
# Scan by URL
curl -X POST https://YOUR_SCANNER_URL/v1.0/scans \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"url": "https://www.attachmentscanner.com/eicar.com"}'
# Scan by file upload
curl -X POST https://YOUR_SCANNER_URL/v1.0/scans \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-F "file=@/path/to/file.pdf"
# Async scan with callback
curl -X POST https://YOUR_SCANNER_URL/v1.0/scans \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/file.zip", "async": true, "callback": "https://your-app.com/webhooks/scan-complete"}'