Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
 * Base class for antivirus integration.
 *
 * @package    core_antivirus
 * @copyright  2015 Ruslan Kabalin, Lancaster University.
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

namespace core\antivirus;

defined('MOODLE_INTERNAL') || die();
> require_once($CFG->dirroot . '/iplookup/lib.php');
/** * Base abstract antivirus scanner class. * * @package core * @subpackage antivirus * @copyright 2015 Ruslan Kabalin, Lancaster University. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ abstract class scanner { /** Scanning result indicating no virus found. */ const SCAN_RESULT_OK = 0; /** Scanning result indicating that virus is found. */ const SCAN_RESULT_FOUND = 1; /** Scanning result indicating the error. */ const SCAN_RESULT_ERROR = 2; /** @var stdClass the config for antivirus */ protected $config; /** @var string scanning notice */ protected $scanningnotice = '';
> /** @var array any admin messages generated by a plugin. */ > protected $messages = [];
/** * Class constructor. * * @return void. */ public function __construct() { // Populate config variable, inheriting class namespace is matching // full plugin name, so we can use it directly to retrieve plugin // configuration. $ref = new \ReflectionClass(get_class($this)); $this->config = get_config($ref->getNamespaceName()); } /** * Config get method. * * @param string $property config property to get. * @return mixed * @throws \coding_exception */ public function get_config($property) { if (property_exists($this->config, $property)) { return $this->config->$property; } throw new \coding_exception('Config property "' . $property . '" doesn\'t exist'); } /** * Get scanning notice. * * @return string */ public function get_scanning_notice() { return $this->scanningnotice; } /** * Set scanning notice. * * @param string $notice notice to set. * @return void */ protected function set_scanning_notice($notice) { $this->scanningnotice = $notice; } /** * Are the antivirus settings configured? * * @return bool True if plugin has been configured. */ public abstract function is_configured(); /** * Scan file. * * @param string $file Full path to the file. * @param string $filename Name of the file (could be different from physical file if temp file is used). * @return int Scanning result constants. */ public abstract function scan_file($file, $filename); /** * Scan data. * * By default it saves data variable content to file and then scans it using * scan_file method, however if antivirus plugin permits scanning data directly, * the method can be overridden. * * @param string $data The variable containing the data to scan. * @return int Scanning result constants. */ public function scan_data($data) { // Prepare temp file. $tempdir = make_request_directory(); $tempfile = $tempdir . DIRECTORY_SEPARATOR . rand(); file_put_contents($tempfile, $data); // Perform a virus scan now. return $this->scan_file($tempfile, get_string('datastream', 'antivirus')); } /**
< * Email admins about antivirus scan outcomes.
> * This function pushes given messages into the message queue, which will be sent by the antivirus manager.
* * @param string $notice The body of the email to be sent.
> * @param string $format The body format. * @return void > * @param string $eventname event name
*/
> * @throws \coding_exception public function message_admins($notice) { > * @throws \moodle_exception
< public function message_admins($notice) { <
> public function message_admins($notice, $format = FORMAT_PLAIN, $eventname = 'errors') { > $noticehtml = $format !== FORMAT_PLAIN ? format_text($notice, $format) : '';
$subject = get_string('emailsubject', 'antivirus', format_string($site->fullname));
> $notifyemail = get_config('antivirus', 'notifyemail'); $admins = get_admins(); > // If one email address is specified, construct a message to fake account. foreach ($admins as $admin) { > if (!empty($notifyemail)) { $eventdata = new \core\message\message(); > $user = new \stdClass(); $eventdata->courseid = SITEID; > $user->id = -1; $eventdata->component = 'moodle'; > $user->email = $notifyemail; $eventdata->name = 'errors'; > $user->mailformat = 1; $eventdata->userfrom = get_admin(); > $admins = [$user]; $eventdata->userto = $admin; > } else { $eventdata->subject = $subject; > // Otherwise, we message all admins.
$eventdata->fullmessage = $notice;
> } $eventdata->fullmessageformat = FORMAT_PLAIN; >
< $eventdata->name = 'errors';
> $eventdata->name = $eventname;
< $eventdata->fullmessageformat = FORMAT_PLAIN; < $eventdata->fullmessagehtml = '';
> $eventdata->fullmessageformat = $format; > $eventdata->fullmessagehtml = $noticehtml;
< message_send($eventdata);
> > // Now add the message to an array to be sent by the antivirus manager. > $this->messages[] = $eventdata; > } > } > > /** > * Return incident details > * > * @param string $file full path to the file > * @param string $filename original name of the file > * @param string $notice notice from antivirus > * @param string $virus if this template is due to a virus found. > * @return string the incident details > * @throws \coding_exception > */ > public function get_incident_details($file = '', $filename = '', $notice = '', $virus = true) { > global $OUTPUT, $USER; > if (empty($notice)) { > $notice = $this->get_scanning_notice(); > } > $classname = get_class($this); > $component = explode('\\', $classname)[0]; > > $content = new \stdClass(); > $unknown = get_string('unknown', 'antivirus'); > $content->header = get_string('emailinfectedfiledetected', 'antivirus'); > $content->filename = !empty($filename) ? $filename : $unknown; > $content->scanner = $component; > // Check for empty file, or file not uploaded. > if (!empty($file) && filesize($file) !== false) { > $content->filesize = display_size(filesize($file)); > $content->contenthash = \file_storage::hash_from_path($file); > $content->contenttype = mime_content_type($file); > } else { > $content->filesize = $unknown; > $content->contenthash = $unknown; > $content->contenttype = $unknown; > } > > $content->author = \core_user::is_real_user($USER->id) ? fullname($USER) . " ($USER->username)" : $unknown; > $content->ipaddress = getremoteaddr(); > $geoinfo = iplookup_find_location(getremoteaddr()); > $content->geoinfo = $geoinfo['city'] . ', ' . $geoinfo['country']; > $content->date = userdate(time(), get_string('strftimedatetimeshort')); > $content->referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : $unknown; > $content->notice = $notice; > $report = new \moodle_url('/report/infectedfiles/index.php'); > $content->report = $report->out(); > > // If this is not due to a virus, we need to change the header line. > if (!$virus) { > $content->header = get_string('emailscannererrordetected', 'antivirus'); > } > > return $OUTPUT->render_from_template('core/infected_file_email', $content);
}
> }> /** > * Getter method for messages queued by the antivirus scanner. > * > * @return array > */ > public function get_messages() : array { > return $this->messages;