| Current Path : /home/smartconb/www/armencom33/administrator/components/com_eyesite/helpers/ |
| Current File : /home/smartconb/www/armencom33/administrator/components/com_eyesite/helpers/eyesite_scanner.php |
<?php
/********************************************************************
Product : Eyesite
Date : 24 June 2024
Copyright : Les Arbres Design 2009-2024
Contact : https://www.lesarbresdesign.info
Licence : GNU General Public License
*********************************************************************/
defined('_JEXEC') or die('Restricted Access');
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Language\Multilanguage;
if (class_exists("LAE_scanner"))
return;
#[\AllowDynamicProperties]
class LAE_scanner
{
//-------------------------------------------------------------------------------
// Initialise and call the main scanning function
//
function scan()
{
$this->app = Factory::getApplication();
$jinput = Factory::getApplication()->input;
$this->source = $jinput->get('source','', 'STRING');
$this->entry = $jinput->get('entry','', 'STRING');
$this->db_model = new LAE_model;
// check the entry requirements
if (!$this->check_entry_requirements())
return;
// handle any errors
$this->history_model = new EyesiteModelHistory; // handle_exception() and handle_error() use this
set_exception_handler(array($this, 'handle_exception'));
set_error_handler(array($this, 'handle_error'));
// try to avoid time-outs
ignore_user_abort(true);
$time_limit = ini_get('max_execution_time');
LAE_trace::trace('Scan started by '.$this->source.', working directory = '.getcwd().", max_execution_time = $time_limit",true);
try {@set_time_limit(0);}
catch (RuntimeException $e) {LAE_trace::trace("set_time_limit() is not allowed");}
try {@ini_set('max_execution_time', 0);}
catch (RuntimeException $e) {LAE_trace::trace("ini_set() is not allowed");}
$time_limit = ini_get('max_execution_time');
LAE_trace::trace("met: $time_limit"); // even if this reports 0, the server will probably ignore it
// more initialisation
$this->sitename = $this->app->get('sitename');
$this->error_count = 0;
$this->change_count = 0;
$this->config_model = new EyesiteModelConfig;
$this->config_data = $this->config_model->getData();
$this->extensions = LAE_helper::expand_cs_list($this->config_data->extensions); // get array of included file extensions
$incdirs = str_replace('%SITE_ROOT%', JPATH_ROOT, $this->config_data->incdirs); // resolve %SITE_ROOT%
$this->incdirs = LAE_helper::expand_cs_list($incdirs); // get array of included directories
$excdirs = str_replace('%SITE_ROOT%', JPATH_ROOT, $this->config_data->excdirs); // resolve %SITE_ROOT%
$this->excdirs = LAE_helper::expand_cs_list($excdirs); // get array of excluded directories
$excfiles = str_replace('%SITE_ROOT%', JPATH_ROOT, $this->config_data->excfiles); // resolve %SITE_ROOT%
$this->excfiles = LAE_helper::expand_cs_list($excfiles); // get array of excluded files
if ($this->config_data->case_sensitive)
$this->query_binary = 'BINARY ';
else
$this->query_binary = '';
$this->load_language($this->config_data->scan_language);
$this->joomla_update = false;
$this->new_extensions = [];
$this->updated_extensions = [];
$scan_start_time = microtime(true);
// purge the history table
$this->db_model->ladb_execute("DELETE FROM `#__eye_site_history` WHERE DATEDIFF(CURDATE(),`datetime`) > ".$this->config_data->days_to_keep);
// accept previous changes and count how many files we are monitoring
$data_model = new EyesiteModelData;
$data_model->accept_all();
$this->initial_count = $this->db_model->ladb_loadResult("SELECT Count(*) From `#__eye_site`");
// create a scan start history record
if ($this->initial_count === false)
{
LAE_trace::trace($this->db_model->ladb_error_text);
$this->add_history($this->db_model->ladb_error_text);
$this->add_history(Text::_('COM_EYESITE_SCANNER_ABANDONING'));
}
if ($this->source == 'plugin')
$started_by = Text::_('COM_EYESITE_STARTED_BY_PLUGIN');
else
$started_by = Text::_('COM_EYESITE_STARTED_BY_ADMIN');
$total_files = Text::_('COM_EYESITE_TOTAL_FILES').': '.$this->initial_count;
$this->history_summary = $started_by.'. '.$total_files;
$this->history_model->store(LAE_HISTORY_SCAN_STARTED, $this->history_summary, '');
if ($this->initial_count === false)
return;
$email_body = $started_by.' @ '.date(LAE_SQL_DATE_FORMAT).'. '.$total_files;
$this->history_details = '';
// call the main scanner function
if ($this->main_scan() == 2) // database error
{
LAE_trace::trace("main_scan returned an error: ".$this->db_model->ladb_error_text);
$this->add_history($this->db_model->ladb_error_text);
$this->add_history(Text::_('COM_EYESITE_SCANNER_ABANDONING'));
$this->error_count ++;
}
$scan_end_time = microtime(true);
$this->scan_runtime = round(($scan_end_time - $scan_start_time),1);
// create history records
$this->history_state = LAE_HISTORY_SCAN_NO_CHANGES;
$this->history_summary = Text::_('COM_EYESITE_SCANNER_NO_NEW');
if ($this->change_count > 0)
{
$this->history_state = LAE_HISTORY_SCAN_CHANGES;
$this->history_summary = Text::sprintf('COM_EYESITE_X_NEW_CHANGES',$this->change_count);
}
if ($this->error_count > 0)
{
$this->history_state = LAE_HISTORY_SCAN_ERROR;
$this->history_summary = Text::_('COM_EYESITE_SCANNER_ERRORS');
}
$this->total_at_end = $this->db_model->ladb_loadResult("SELECT COUNT(*) FROM `#__eye_site` WHERE `state` != ".LAE_STATE_DELETED);
if ($this->total_at_end > 0)
$this->history_summary .= '. '.Text::_('COM_EYESITE_TOTAL_FILES').': '.$this->total_at_end;
if ($this->joomla_update)
{
$joomla_now = Text::_('COM_EYESITE_JOOMLA_NOW').' '.JVERSION;
$this->history_summary .= '. '.$joomla_now;
$this->history_model->store(LAE_HISTORY_UPDATE_JOOMLA, $joomla_now, '');
}
if (!empty($this->new_extensions))
{
$extensions = self::name_version_list($this->new_extensions);
$count = count($extensions);
if ($count < 10)
$summary = implode(', ', $extensions);
else
$summary = $count.' '.Text::_('COM_EYESITE_EXTENSIONS');
$detail = serialize($this->new_extensions);
$this->history_model->store(LAE_HISTORY_NEW_EXTENSION, $summary, $detail);
}
if (!empty($this->updated_extensions))
{
$extensions = self::name_version_list($this->updated_extensions);
$count = count($extensions);
if ($count < 10)
$summary = implode(', ', $extensions);
else
$summary = $count.' '.Text::_('COM_EYESITE_EXTENSIONS');
$detail = serialize($this->updated_extensions);
$this->history_model->store(LAE_HISTORY_UPDATE_EXTENSION, $summary, $detail);
}
$history_with_runtime = $this->history_details.'<br>'.Text::sprintf('COM_EYESITE_SCAN_RUNTIME_X',$this->scan_runtime);
$this->history_model->store($this->history_state, $this->history_summary, $history_with_runtime);
// send an email if we have new changes or any errors
if (($this->config_data->emailto != '') && (($this->change_count > 0) || ($this->error_count > 0)))
$this->send_email($email_body);
else
LAE_trace::trace("No email was sent: emailto=[".$this->config_data->emailto."] changes=".$this->change_count.", error_count=".$this->error_count);
LAE_trace::trace('Scan complete, '.$this->change_count.' changes',true);
$this->scan_unlock();
}
//-------------------------------------------------------------------------------
// Scan the configured directory structures
// Returns 0 if no errors, or 2 for a database error
//
function main_scan()
{
// set all states to RUNNING - any rows still in RUNNING state after the scan were not found in the file system
$query = "UPDATE `#__eye_site` SET `state` = ".LAE_STATE_RUNNING;
LAE_trace::trace($query);
$result = $this->db_model->ladb_execute($query);
if ($result === false)
{
LAE_trace::trace($this->db_model->ladb_error_text);
return 2;
}
$rows_affected = $this->db_model->db->getAffectedRows();
LAE_trace::trace(" - affected $rows_affected rows");
// process all the directories
// this should set all the states to either OK or CHANGED
// and could create some with state NEW
@clearstatcache();
$numIncDirs = count($this->incdirs);
for ($i = 0; $i < $numIncDirs; $i = $i+2)
{
LAE_trace::trace('Scanning directories, starting at: '.$this->incdirs[$i]);
$filelist = $this->dirList($this->incdirs[$i],$this->incdirs[$i+1]);
$this->db_model->ladb_execute("Start Transaction");
$file_count = count($filelist);
LAE_trace::trace("Directory scan found $file_count files. Starting to process...");
foreach ($filelist as $file)
{
$ret = $this->process_file($file);
if ($ret == 2) // if we have a database problem, don't continue
return 2;
if ($ret == 1) // if we have a file error, count it and continue - some files could be locked
$this->error_count ++;
}
LAE_trace::trace("Finished processing $file_count files");
$this->db_model->ladb_execute("Commit");
}
// any records still in state "RUNNING" were not found in the file system and are newly deleted
// log the newly deleted files
$query = "SELECT `filepath` FROM `#__eye_site` WHERE `state` = ".LAE_STATE_RUNNING;
$rows = $this->db_model->ladb_loadObjectList($query);
if ($rows === false)
return 2;
$numrows = count($rows);
$this->change_count += $numrows;
LAE_trace::trace("Found $numrows rows in state RUNNING after the scan");
foreach ($rows as $row)
$this->add_history(Text::_('COM_EYESITE_STATE_DELETED').': '.$row->filepath);
// set the newly deleted files to LAE_STATE_DELETED
$query = "UPDATE `#__eye_site` SET `state` = ".LAE_STATE_DELETED.", `date_checked` = NOW() WHERE `state` = ".LAE_STATE_RUNNING;
LAE_trace::trace("$query");
$result = $this->db_model->ladb_execute($query);
if ($result === false)
{
LAE_trace::trace($this->db_model->ladb_error_text);
return 2;
}
$rows_affected = $this->db_model->db->getAffectedRows();
LAE_trace::trace(" - affected $rows_affected rows");
return 0;
}
//-------------------------------------------------------------------------------
// Process one file
// Returns 0 if no errors, 1 for a file error, or 2 for a database error
//
function process_file($filepath)
{
if (self::_in_arrayi($filepath, $this->excfiles))
{
LAE_trace::trace(" Excluding file: $filepath");
return 0; // this file is excluded
}
$quoted_filepath = $this->db_model->db->quote($filepath);
if (!is_readable($filepath))
{
LAE_trace::trace(" Unreadable file: $filepath");
$this->add_history(Text::_('COM_EYESITE_SCANNER_ERROR_READ').': '.$filepath);
return 1;
}
$hash = md5_file($filepath);
if (!$hash)
{
LAE_trace::trace(" Unable to calculate md5 for: $filepath");
$this->add_history(Text::_('COM_EYESITE_SCANNER_ERROR_MD5').': '.$filepath);
return 1;
}
$query = "SELECT `md5`, `state`, UNIX_TIMESTAMP(`datetime`) AS unix_datetime, `filesize`
FROM `#__eye_site` WHERE `filepath` = ".$this->query_binary.$quoted_filepath;
$row = $this->db_model->ladb_loadObject($query);
if ($row === false)
return 2;
// if the file is not registered in the database, insert it in state NEW
if (empty($row))
{
if (strrchr($filepath, '.') == '.xml')
$this->check_xml_file($filepath, LAE_STATE_NEW);
$this->add_history(Text::_('COM_EYESITE_STATE_NEW').":\t".$filepath);
$filesize = filesize($filepath); // allow zero length files
$unix_filetime = filemtime($filepath); // but not zero time files
if (!$unix_filetime)
{
LAE_trace::trace(" Unable to get modification date for $filepath");
$this->add_history(Text::_('COM_EYESITE_SCANNER_ERROR_DATE').': '.$filepath);
return 1;
}
$sql_filetime = date(LAE_SQL_DATE_FORMAT, $unix_filetime);
$query = "INSERT INTO `#__eye_site` (`filepath`, `md5`, `state`, `datetime`, `filesize`, `new_md5`, `new_datetime`, `new_filesize`, `date_added`, `date_checked`)
VALUES ($quoted_filepath, '$hash', ".LAE_STATE_NEW.", '$sql_filetime', ".intval($filesize).", '', 0, 0, NOW(), 0)";
LAE_trace::trace(' '.$query);
$result = $this->db_model->ladb_execute($query);
if ($result === false)
return 2;
$this->change_count ++;
return 0;
}
// here when the file is in the database
// if it already has a problem flagged, leave it alone
if ($row->state != LAE_STATE_RUNNING)
return 0;
// if the hash value matches, set the state to OK
if ($row->md5 == $hash)
{
$query = "UPDATE `#__eye_site` SET `state` = ".LAE_STATE_OK.", `date_checked` = NOW() WHERE `filepath` = ".$this->db_model->db->quote($filepath);
// LAE_trace::trace("$query"); // not normally needed and creates a huge trace file
$result = $this->db_model->ladb_execute($query);
if ($result === false)
return 2;
return 0;
}
// the hash value doesn't match, so set the state to CHANGED and note the new file details
if (strstr($filepath,'/libraries/src/Version.php')) // if this file got changed, Joomla has been updated
$this->joomla_update = true;
if (strrchr($filepath, '.') == '.xml')
$this->check_xml_file($filepath, LAE_STATE_CHANGED);
$oldfilesize = $row->filesize;
$newfilesize = filesize($filepath);
$new_unix_filetime = filemtime($filepath);
$new_sql_filetime = date(LAE_SQL_DATE_FORMAT, $new_unix_filetime);
$change1 = Text::_('COM_EYESITE_STATE_CHANGED').' '.$filepath;
$change2 = " ".Text::_('COM_EYESITE_SCANNER_ORIG_DATE').' '.date(LAE_SQL_DATE_FORMAT, $row->unix_datetime).', '.Text::_('COM_EYESITE_SCANNER_SIZE').': '.$oldfilesize;
$change3 = " ".Text::_('COM_EYESITE_SCANNER_NEW_DATE').' '.date(LAE_SQL_DATE_FORMAT, $new_unix_filetime).', '.Text::_('COM_EYESITE_SCANNER_SIZE').': '.$newfilesize;
$this->add_history($change1);
$this->add_history($change2);
$this->add_history($change3);
$query = "UPDATE `#__eye_site` SET `state` = ".LAE_STATE_CHANGED.", `new_md5` = '$hash', `new_datetime` = '$new_sql_filetime', `new_filesize` = ".intval($newfilesize)."
WHERE `filepath` = $quoted_filepath";
LAE_trace::trace(' '.$query);
$result = $this->db_model->ladb_execute($query);
if ($result === false)
return 2;
$this->change_count ++;
return 0;
}
//-------------------------------------------------------------------------------
// list matching files in a directory and return as an array
//
function dirList($directory, $recurse)
{
static $depth = 0;
if ($depth <= 2) // only trace two levels deep
LAE_trace::trace(' '.$directory.', '.$recurse);
$results = array();
if (self::_in_arrayi($directory, $this->excdirs))
{
LAE_trace::trace(" Excluding directory: $directory");
$depth --;
return $results; // this directory is excluded
}
if (!is_readable($directory))
{
$this->add_history(Text::_('COM_EYESITE_DIR_INC_ERROR3').' '.$directory);
$this->error_count ++;
$depth --;
return $results;
}
if ($handle = opendir($directory))
{
while ($filename = readdir($handle))
{
if (($filename != '.') && ($filename != '..'))
{
if (is_dir($directory."/".$filename))
{
if ($recurse == "S")
{
$depth ++;
$results = array_merge($results, $this->dirList($directory."/".$filename, $recurse));
}
}
else
{
$ext = pathinfo($filename, PATHINFO_EXTENSION);// get the file extension
if ((empty($this->extensions)) || (self::_in_arrayi($ext,$this->extensions)))
{ // yes...
$filename = $directory."/".$filename; // make full pathname
$results[] = $filename; // and store in results array
}
}
}
}
closedir($handle);
}
$depth --;
return $results;
}
//-------------------------------------------------------------------------------
// Add text to the history buffer
//
function add_history($text)
{
if (!empty($this->history_details))
$this->history_details .= '<br>';
$this->history_details .= $text;
}
//-------------------------------------------------------------------------------
// Case insensitive in_array
//
static function _in_arrayi($needle, $haystack)
{
foreach($haystack as $value)
if (strtolower($value) == strtolower($needle))
return true;
return false;
}
//-------------------------------------------------------------------------------
// check if an xml file is an extension manifest
//
function check_xml_file($filepath, $state)
{
if (strstr($filepath,'administrator/manifests')) // don't check files here, they are copies
return;
$xml_array = Joomla\CMS\Installer\Installer::parseXMLInstallFile($filepath);
if ($xml_array === false)
return;
$xml_array['filepath'] = $filepath;
if ($state == LAE_STATE_NEW)
$this->new_extensions[] = $xml_array;
else
$this->updated_extensions[] = $xml_array;
}
//-------------------------------------------------------------------------------
// make a list of extension names and their versions
//
static function name_version_list($extensions)
{
$name_and_versions = [];
foreach ($extensions as $extension)
$name_and_versions[] = $extension['name'].' '.$extension['version'];
return array_unique($name_and_versions);
}
//-------------------------------------------------------------------------------
// Check that the correct entry parameter was specified
// for admin scans it should be the site secret
// for plugin scans it must be the last runtime
// (the plugin Ajax path is potentially visible externally so the entry parameter must be hard to guess)
//
function check_entry_requirements()
{
if (!$this::scan_lock())
return;
switch ($this->source)
{
case 'admin':
if ($this->entry == $this->app->get('secret'))
return true;
LAE_trace::trace('Scanner stopping because admin entry parameter incorrect: '.$this->entry,true);
return false;
case 'plugin':
$query = "SELECT `params` FROM `#__extensions` WHERE `type` = 'plugin' AND `folder` = 'system' AND `element` = 'eyesite'";
$plugin_params = $this->db_model->ladb_loadResult($query);
if ($plugin_params === false)
{
LAE_trace::trace("Scanner stopping because plugin entry parameter cannot be verified: ".$this->db_model->ladb_error_text);
return false;
}
$plugin_params_object = json_decode($plugin_params);
if (!empty($plugin_params_object->entry_code))
$entry_code = $plugin_params_object->entry_code;
else
$entry_code = 0;
if ($this->entry == $entry_code)
{ // ok, we are going to run so update the entry_code and last_run_time
$plugin_params_object->last_run_time = time();
$plugin_params_object->entry_code = uniqid(rand());
$plugin_params = $this->db_model->db->quote(json_encode($plugin_params_object));
$query = "UPDATE `#__extensions` SET `params` = $plugin_params WHERE `type` = 'plugin' AND `folder` = 'system' AND `element` = 'eyesite'";
$this->db_model->ladb_execute($query);
LAE_trace::trace("Scanner updating plugin last_run_time to ".$plugin_params_object->last_run_time." and entry_code to ".$plugin_params_object->entry_code,true);
return true;
}
LAE_trace::trace('Scanner stopping because plugin entry parameter incorrect: '.$this->entry,true);
return false;
default:
LAE_trace::trace('Scanner stopping because plugin source parameter incorrect: '.$this->source,true);
return false;
}
return false; // cannot get here
}
//-------------------------------------------------------------------------------
// load the scan language file
//
function load_language($scan_language)
{
LAE_trace::trace("load_language ($scan_language)");
$lang = Factory::getLanguage();
if (!empty($this->config_data->scan_language))
{
if (file_exists(JPATH_ADMINISTRATOR."/components/com_eyesite/language/$scan_language/$scan_language.com_eyesite.ini"))
{
LAE_trace::trace(" - loading: administrator/components/com_eyesite/language/$scan_language/$scan_language.com_eyesite.ini");
$lang->load('com_eyesite', JPATH_ADMINISTRATOR.'/components/com_eyesite', $scan_language, true);
return;
}
else
LAE_trace::trace(" - no file: administrator/components/com_eyesite/language/$scan_language/$scan_language.com_eyesite.ini");
}
LAE_trace::trace(" - loading default language");
$lang->load('com_eyesite', JPATH_ADMINISTRATOR.'/components/com_eyesite');
}
//-------------------------------------------------------------------------------
// send a scan report email
//
function send_email($email_body)
{
$subject = Text::_('COM_EYESITE_EMAIL_SUBJECT_CHANGES').' ('.$this->sitename.')';
if ($this->joomla_update)
$subject .= ', '.Text::_('COM_EYESITE_JOOMLA_NOW').' '.JVERSION;
$new_extensions = self::name_version_list($this->new_extensions);
$updated_extensions = self::name_version_list($this->updated_extensions);
$count_new = count($new_extensions);
if ($count_new > 0)
$subject .= ', '.Text::plural('COM_EYESITE_X_EXTENSIONS_NEW',$count_new);
$count_updated = count($updated_extensions);
if ($count_updated > 0)
$subject .= ', '.Text::plural('COM_EYESITE_X_EXTENSIONS_UPDATED',$count_updated);
if (!$this->joomla_update && ($count_new == 0) && ($count_updated == 0))
$subject .= '. '.Text::_('COM_EYESITE_NO_UPDATES');
if ($this->error_count > 0)
$subject = Text::_('COM_EYESITE_EMAIL_SUBJECT_ERRORS').' ('.$this->sitename.')';
$email_body .= '<br>'.Text::_('COM_EYESITE_TOTAL_CHANGES').': '.$this->change_count;
// new extensions added
foreach ($new_extensions as $extension)
$email_body .= '<br>'.Text::_('COM_EYESITE_ADDED').' '.$extension;
// updated extensions
foreach ($updated_extensions as $extension)
$email_body .= '<br>'.Text::_('COM_EYESITE_UPDATED').' '.$extension;
// runtime
$email_body .= '<br>'.Text::sprintf('COM_EYESITE_SCAN_RUNTIME_X',$this->scan_runtime);
// file change details, if any
if ($this->config_data->email_max_size > 0)
{
if (strlen($this->history_details) < $this->config_data->email_max_size)
$email_body .= '<br><br>'.$this->history_details;
else
$email_body .= '<br><br>'.substr($this->history_details, 0, $this->config_data->email_max_size).'<br> -- '.Text::_('COM_EYESITE_TRUNCATED').' --';
}
// send it and log the result
LAE_trace::trace("Sending email to: ".$this->config_data->emailto.", Subject: $subject");
$email_status = LAE_helper::send_email($this->config_data, $subject, $email_body);
if ($email_status == '')
{
LAE_trace::trace("send_email ok");
$this->history_model->store(LAE_HISTORY_EMAIL_OK, $subject, $email_body.'<br><br>'.Text::_('COM_EYESITE_EMAIL_ACCEPTED'));
$this->add_history(Text::_('COM_EYESITE_EMAIL_SENT_TO').' '.$this->config_data->emailto);
}
else
{
LAE_trace::trace("send_email returned $email_status");
$this->history_model->store(LAE_HISTORY_EMAIL_FAILED, $subject, $email_body.'<br><br>'.$email_status);
$this->add_history($email_status);
}
}
//-------------------------------------------------------------------------------
// returns true if we can acquire an exclusive lock on the lock file
// - the file handle cannot be local, because when the handle is destroyed, the file is unlocked
// returns true if the scan can run, false if not
//
function scan_lock()
{
$app = Factory::getApplication();
$tmp_path = $app->get('tmp_path'); // get the site temp directory from Joomla global configuration
$lock_file_path = $tmp_path.'/eyesite.lock';
if (!file_exists($lock_file_path))
{
if (@touch($lock_file_path) === false)
{
LAE_trace::trace("Unable to create lock file $lock_file_path. Scanner cannot run.");
return false;
}
}
$this->lock_handle = @fopen($lock_file_path, 'w');
if ($this->lock_handle === false)
{
LAE_trace::trace("Unable to open lock file $lock_file_path. Scanner cannot run.");
return false;
}
$ret = flock($this->lock_handle, (LOCK_EX | LOCK_NB), $wouldblock); // returns true on success or false on failure
LAE_trace::trace("flock returned ".($ret ? 'true':'false').', '.($wouldblock ? 'true':'false'));
if (!$ret || $wouldblock)
{
LAE_trace::trace("Unable to acquire lock. Scanner cannot run [$ret] [$wouldblock]",true);
return false;
}
LAE_trace::trace("Scanner ok to run",true);
return true;
}
//-------------------------------------------------------------------------------
// delete the scan lock file
//
function scan_unlock()
{
flock ($this->lock_handle, LOCK_UN);
fclose($this->lock_handle);
}
function handle_exception($e)
{
$message = "Scanner exception: ".$e->getMessage();
LAE_trace::trace($message,true);
$this->history_model->store(LAE_HISTORY_SCAN_EXCEPTION, $message, '');
}
function handle_error($errno, $errstr, $errfile, $errline)
{
if ($errno == 8192) // don't report PHP deprecation error
return;
if ($errno == 16384) // don't report Joomla deprecation errors
return;
$message = "Scanner Error $errno [$errstr] line $errline of $errfile";
LAE_trace::trace($message,true);
$this->history_model->store(LAE_HISTORY_SCAN_EXCEPTION, $message, '');
}
}