See Release Notes
Long Term Support Release
<?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; > } > > /** > * Getter method for the antivirus message displayed in the exception. > * > * @return array array of string and component to pass to exception constructor. > */ > public function get_virus_found_message() { > // Base antivirus found string. > return ['string' => 'virusfound', 'component' => 'antivirus', 'placeholders' => []];