Reports and Findings API
Scanner::run() returns an stdClass report after a completed scan. Scanner::getReport() returns the same current report shape. On a caught scan failure, run() returns false; inspect getLastError() on the scanner instance.
Top-level report contract
| Property | Type | Meaning |
|---|---|---|
scanned | int | Number of scanned files. |
detected | int | Number of detected malware matches. |
verifiedByChecksum | int | Number of files accepted by checksum verification. |
removed, ignored, edited, quarantine, whitelist | array | Paths or records affected by the matching action. |
infectedFound | array | Infected file paths found during the scan. |
fileHashes | array | File hash metadata collected during scanning. |
findings | array | Canonical finding records from file, integrity, archive, and supplemental analyses. |
coverage | array | Completeness, counts, and skip reasons. |
diagnostics | array, when present | Non-fatal analysis or definition update errors. |
signature_indexes | array | Built-in and optional reputation-index metadata. |
inventory | array, when present | Detected platform component inventory. |
New report fields can be added in a minor release. Consumers should read the fields they need, tolerate unknown fields, and use isset() for optional properties.
Handle success and failure
$report = $scanner->run();
if ($report === false) {
throw new RuntimeException($scanner->getLastError() ?: 'Scan failed.');
}
foreach ($report->findings as $finding) {
if ($finding['severity'] === 'danger') {
// Send the finding to your incident workflow.
}
}
Do not treat a nonzero detected count as an execution failure. Findings identify code or integrity conditions that need review. They do not establish intent or authorize deletion.
Finding record contract
Each canonical finding contains these fields:
| Field | Type | Meaning |
|---|---|---|
id | string | Stable SHA-256 identifier derived from the kind, provider, rule ID, and normalized subject. |
kind | string | Finding category, such as malware, integrity, or a supplemental analysis type. |
subject | string | File path or the scanned subject. |
rule_id | string | Stable identifier for the detecting rule or indicator. |
severity | string | Severity supplied by the detector, commonly warn or danger. |
message | string | Human-readable detection detail. |
status | string | Current finding status. New findings start as open. |
evidence | array | Context such as line, match, or content_hash when available. |
provider | string | Detector source, such as builtin. |
first_seen_at, last_seen_at | string | ISO 8601 timestamps for the finding observation. |
Keep rule_id, subject, and the observed content hash when deduplicating alerts. A line number or a snippet can change when a file changes.
Coverage is part of the result
The report includes coverage counts for discovered, eligible, scanned, skipped, verified, cached, and errors. coverage.reasons separates skipped files by path, extension, oversized, excluded, unreadable, and archive_limit.
Use this check before accepting a scan as complete:
$coverage = $report->coverage;
if (empty($coverage['complete']) || !empty($coverage['errors'])) {
throw new RuntimeException('Scan coverage is incomplete.');
}
Offset and limit batches, unreadable files, file-size limits, and archive limits can make the result incomplete. A complete zero-finding result carries more weight than a partial zero-finding result.
Diagnostics and external data
diagnostics reports non-fatal errors. For example, the scanner can continue with cached Maltrail definitions when an update fails. Persist diagnostics alongside findings so an operator can distinguish a clean result from reduced analysis.
signature_indexes exposes record counts and source hashes for the built-in malware and legacy-core indexes. When an active Maltrail store exists, it also includes domain-index metadata and its update time. Use those values for audit trails, not as a substitute for the finding evidence.
Serializing reports
Use json_encode() with error handling when you store the in-memory report:
$json = json_encode($report, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
if ($json === false) {
throw new RuntimeException('Could not serialize scan report: ' . json_last_error_msg());
}
Use setReportFormat('json') or setReportFormat('sarif') when the scanner should also write a file for external tooling. Choose a directory outside the scanned project for reports, checkpoints, backups, and quarantined files.