If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

Antivirus plugins

From MoodleDocs

This content of this page has been updated and migrated to the new Moodle Developer Resources. The information contained on the page should no longer be seen up-to-date.

Why not view this page on the new site and help us to migrate more content to the new site!

Moodle 3.1


Antivirus plugins implement virus scanning functionality in Moodle. This allows external contributor to develop plugins for different antivirus products and extend existing antivirus functionality to different areas of Moodle. The plugin for ClamAV antivirus tool is included in the core.


Antivirus scanning using ClamAV has been initially introduced in Moodle 1.3 in the patchset committed by Penny Leach. Since that time, the code has been refactored a number of times to match File and Repository API changes, however always remained limited to ClamAV antivirus product. In Moodle 3.1 antivirus scanning has been re-introduced as a separate plugin type with ClamAV plugin included in the core.

Current status

The antivirus functionality is ongoing work, covered in MDL-50886. It most likely there will be some more API changes in upcoming release.


The best example of antivirus plugin is ClamAV antivirus scanner plugin included in the core (/lib/antivirus/clamav).

File structure

All files for an antivirus plugin go within /lib/antivirus/name, where name is the name of the antivirus plugin, e.g. for ScanMyFile plugin used in examples below, the file structure will be as follows:

 |-- classes
 |   `-- scanner.php
 |-- db
 |   `-- upgrade.php
 |-- lang
 |   `-- en
 |       `-- antivirus_scanmyfile.php
 |-- settings.php
 |-- tests
 |   `-- scanner_test.php
 `-- version.php


Standard version.php for the plugin.


Standard Admin_settings for the plugin configuration, make sure plugin configuration is stored in config_plugins table.


if ($ADMIN->fulltree) {
    $settings->add(new admin_setting_configexecutable('antivirus_scanmyfile/pathtoscanner',
            new lang_string('pathtoscanner', 'antivirus_scanmyfile'), new lang_string('configpathtoscanner', 'antivirus_scanmyfile'), ''));


Language strings for the plugin. Required strings:

  • pluginname - name of plugin.


$string['pluginname'] = 'SanMyFile antivirus';
$string['pathtoscanner'] = 'Path to scanner';
$string['configpathtoscanner'] = 'Define full path to scanner';

You will usually need to add your own strings for two main purposes:

  • Adding configuration settings.
  • Displaying information about scanning errors.

db (directory)

Standard upgrade/install routines for plugin.


The file contains scanner class defined in antivirus_name namespace, that extends \core\antivirus\scanner class and implements the back-end for the antivirus scanning. It is expected that the class will contain at least two methods:

  • is_configured() - returns true, if this antivirus plugin is configured.
  • scan_file($file, $filename, $deleteinfected) - performs the $file scanning using antivirus functionality, using $filename as filename string in any reporting, deletes infected file if $deleteinfected is true.

It is expected that scan_file() function will throw exception of \core\antivirus\scanner_exception type if virus is found, otherwise will return void.

The simplified example of scanner.php is shown below:

// You must use the right namespace (matching your plugin antivirus name).
namespace antivirus_scanmyfile;

defined('MOODLE_INTERNAL') || die();

class scanner extends \core\antivirus\scanner {

    public function is_configured() {
        // Parent's get_config() function is effectively a wrapper of get_config('antivirus_scanmyfile', 'somesettingname') call.
        return (bool)$this->get_config('pathtoscanner');

    public function scan_file($file, $filename, $deleteinfected) {
        if (!is_readable($file)) {
            // This should not happen.
            debugging('File is not readable.');

        // Execute the scan using antivirus own scanning tool, we assume it returns 0 if no virus is found, 1 if file is infected, any other number on error.
        $return = $this->scan_file_using_scanmyfile_scanner_tool($file);

        if ($return == 0) {
            // Perfect, no problem found, file is clean.
        } else if ($return == 1) {
            // Infection found.
            if ($deleteinfected) {
            throw new \core\antivirus\scanner_exception('virusfounduser', '', array('filename' => $filename));
        } else {
            // Unknown problem.
            debugging('Error occurred during file scanning.');

    public function scan_file_using_scanmyfile_scanner_tool($file) {
        // Scanning routine using antivirus own tool goes here.
        // ...
        // For example purposes, we assume it returns 0 if no virus is found, 1 if file is infected, any other number on error.
        return $return;

tests/scanner_test.php (optional)

Normally you would write a unit test for the antivirus plugin inside this file. Since plugin rely on external tool, it might be a good idea to replace real component with "double". See ClamAV plugin for example and PHPUnit manual section.