0); protected $taskTypeCode = TaskTypeCodesCodes::CLEANER; public function mainDescription() { return 'Cleaner'; } public function main($params) { $this->setStatus(task\TaskStatusEnum::IN_PROGRESS); $cron_cleaner_run_each = GlobalSettingHelper::getSetting(GlobalSettingEnum::CRON_CLEANER_RUN_EACH ? : 5); if(!$this->isReadyToRun( $cron_cleaner_run_each )) { return true; } LogHelper::addSuccessLog($this->mainDescription().' ', 'Cron '.$this->mainDescription().' Started'); $last_id = GlobalSettingHelper::getSetting(GlobalSettingEnum::CRON_CLEANER_LAST_ID) ? : 0; $zones_per_run = GlobalSettingHelper::getSetting(GlobalSettingEnum::CRON_CLEANER_ZONES_PER_RUN); $zones_per_run < 1 ? $zones_per_run = 1 : ''; $rep = $this->getZonesRepoWithIDGreaterThan($last_id, $zones_per_run); $count_filtered = $rep->count(); $details = array(); $count_removed = 0; $notify_only = GlobalSettingHelper::getSetting(GlobalSettingEnum::CRON_CLEANER_NOTIFY_ONLY); $notify_only = ($notify_only == 'on' || $notify_only === false) ? true : false; foreach($rep->get() as $zone) { try { $remove = false; $reason = ''; if(GlobalSettingHelper::getSetting(GlobalSettingEnum::CRON_CLEANER_ZONE_NO_PACKAGE_MATCH) == 'on' && $zone->getPackage() === false) { $remove = true; $reason = "There is no matching package"; } $longer_than = GlobalSettingHelper::getSetting(GlobalSettingEnum::CRON_CLEANER_ZONE_UNMODIFIED_LONGER_THAN); if(!$remove && !(empty($longer_than) || $longer_than == 0) && $longer_than <= TimeDiffHelper::diff($zone->updated_at)->minutes) { $remove = true; $reason = "Zone remained unmodified for too long"; } if(!$remove && GlobalSettingHelper::getSetting(GlobalSettingEnum::CRON_CLEANER_ZONE_DOMAIN_NOT_EXIST) == 'on') { $result = main\mgLibs\custom\helpers\WHMCSApiHelper::domainwhois(array( 'domain' => $zone->name, )); if(isset($result['status']) && strtolower($result['status']) == 'available') { $remove = true; $reason = 'Zone domain does not exist'; } } $hostingStatuses = unserialize(GlobalSettingHelper::getSetting(GlobalSettingEnum::CRON_CLEANER_ZONE_INACTIVE_SERVICES)); $domainStatuses = unserialize(GlobalSettingHelper::getSetting(GlobalSettingEnum::CRON_CLEANER_ZONE_INACTIVE_DOMAINS)); //domain and hosting in one zone if(!$remove && !is_null($zone->connectedWithType) && !is_null($zone->connectedWithRelid) && $zone->connectedWithRelid != 0 && !empty($hostingStatuses) && !empty($domainStatuses) ) { $hostingId = null; $domainId = null; if($zone->type == PackageItemTypeEnum::HOSTING) { $hostingId = $zone->relid; $domainId = $zone->connectedWithRelid; } else if($zone->type == PackageItemTypeEnum::DOMAIN) { $domainId = $zone->relid; $hostingId = $zone->connectedWithRelid; } $Hosting = main\models\whmcs\service\repository::factory()->setFilter('id', $hostingId)->one(); if($Hosting === false || in_array($Hosting->status(), $hostingStatuses)) { $removeHosting = true; $reason = 'Assigned service not active'; } $domain = main\models\whmcs\domains\repository::factory()->setFilter('id', $domainId)->one(); if($domain === false || in_array($domain->status(), $domainStatuses)) { $removeDomain = true; } if($removeDomain && $removeHosting) { $remove = true; $reason = 'Assigned domain and service not active'; } if(!$remove) { continue; } } //hosting if(!$remove && $zone->type == PackageItemTypeEnum::PRODUCT && !empty($hostingStatuses)) { $Hosting = main\models\whmcs\service\repository::factory()->setFilter('id', $zone->relid)->one(); if($Hosting === false || in_array($Hosting->status(), $hostingStatuses)) { $remove = true; $reason = 'Assigned service not active'; } } //domain if(!$remove && $zone->type == PackageItemTypeEnum::DOMAIN && !empty($domainStatuses)) { $domain = main\models\whmcs\domains\repository::factory()->setFilter('id', $zone->relid)->one(); if($domain === false || in_array($domain->status(), $domainStatuses)) { $remove = true; $reason = 'Assigned domain not active'; } } $at_least_one = unserialize(GlobalSettingHelper::getSetting(GlobalSettingEnum::CRON_CLEANER_ZONE_AT_LEAST_ONE)); if(!$remove && !empty($at_least_one)) { try { $module = $zone->getModule(); $records = $module->getRecords(); $available_records = $module->getAvailableRecordTypes(); foreach($at_least_one as $record_type) { if(!in_array($record_type, $available_records)) { continue; } foreach($records as $record) { if(strtoupper($record->type) == strtoupper($record_type)) { continue 2; } } $remove = true; $reason = "Zone does not include required records defined in configuration"; break; } } catch(Exception $exc) { \logModuleCall('DNS Manager', 'Cron Cleaner', "Error. When trying to remove dns zone", array($exc->getMessage(), $exc->getTraceAsString())); } } if($remove) { try { if(!$notify_only) { $module = $zone->getModule(); $module->terminateZone(); $zone->remove(); $zoneDataToMail = $zone->toArray()['Zone']; $zoneDataToMail['zone_name'] = $zoneDataToMail['name']; main\mgLibs\custom\manager\EmailNotificationHelper::sendClientNotificationUsingZone(main\mgLibs\custom\manager\DefaultNotifications::GENERAL_ZONE_REMOVED_NOTIFICATION, $zone, $zoneDataToMail); LogHelper::addSuccessLog('Cron Cleaner', 'Remove Zone: '.$zone->name.' Reason: '.$reason); } $count_removed++; $details[$zone->name] = $reason; } catch(Exception $exc) { \logModuleCall('DNS Manager', 'Cron Cleaner', "Error. When trying to remove dns zone", array($exc->getMessage(), $exc->getTraceAsString())); } } $last_id = $zone->id; } catch(Exception $exc) { \logModuleCall('DNS Manager', 'Cron Cleaner', "Error. When trying to remove dns zone", array($exc->getMessage(), $exc->getTraceAsString())); } } if($this->getPtrRemoveSettingsStatus()) { try { list($details, $count_removed) = $this->removePTRs($notify_only, $details, $count_removed); } catch(Exception $exc) { \logModuleCall('DNS Manager', 'Cron Cleaner', "Error. When trying to remove rdns", array($exc->getMessage(), $exc->getTraceAsString())); } } if($count_filtered < $zones_per_run) { $last_id = 0; } GlobalSettingHelper::setSetting(GlobalSettingEnum::CRON_CLEANER_LAST_ID, $last_id); if($count_removed > 0) { EmailNotificationHelper::sendAdminNotification( DefaultNotifications::ADMIN_CRON_CLEANER_NOTIFICATION, array( 'notify_only' => $notify_only, 'zones_removed_count' => $count_removed, 'zones_removed' => $details, ) ); \logModuleCall('DNS Manager', 'Cron Cleaner', $details, array(), array( 'zones_removed_count' => $count_removed, 'zones_removed' => $details, ), array()); $zonesCountWord = $count_removed == 1 ? 'zone' : 'zones'; if($notify_only) { NotificationHelper::addInfoNotification("Cron Cleaner - ".$count_removed." ".$zonesCountWord." should be removed"); LogHelper::addSuccessLog('Cron Cleaner', "End Of Cleaning Run - ".$count_removed." ".$zonesCountWord." should be removed"); } else { NotificationHelper::addInfoNotification("Cron Cleaner - ".$count_removed." ".$zonesCountWord." removed"); LogHelper::addSuccessLog('Cron Cleaner', "End Of Cleaning Run - ".$count_removed." ".$zonesCountWord." removed"); } } $this->setStatus(task\TaskStatusEnum::FINISHED); } private function getZonesRepoWithIDGreaterThan($id, $zones_per_run) { $rep = new main\models\custom\zone\Repository(); $rep->setFilter(0, array( 'customQuery' => 'id > :last_id ', 'params' => array('last_id' => $id) )); $rep->limit($zones_per_run); return $rep; } private function removePTRs($notify_only, $details = array(), $count_removed = 0) { $ptrs = query::query( "SELECT ptrs.*, h.`id` as `hid`, h.`userid` as `hosuid`, h.`domain`, h.`domainstatus` as `hstatus` " . "FROM `dns_manager2_reverse` ptrs " . "LEFT JOIN `tblhosting` h ON (ptrs.`ip` = h.`dedicatedip` OR h.`assignedips` LIKE CONCAT('%', ptrs.`ip`, '%'))" )->fetchAll(); foreach($ptrs as $ptr) { $reverse = new reverse\Reverse($ptr['id']); $delete = false; $reason = ''; try { $ip = new IP($ptr['ip']); $intIp = 0; if($ip->isIPv6()) { $intIp = IPv6::inet_ptoi((string) $ip); $shortIP = IPv6::inet_itop($intIp); $hosting = query::query("SELECT `id`, `domainstatus`, `userid` FROM `tblhosting` WHERE `dedicatedip` = :sip OR `assignedips` LIKE CONCAT('%', :sip2, '%')", array('sip' => $shortIP, 'sip2' => $shortIP))->fetch(); $ptr['hid'] = $hosting['id']; $ptr['hstatus'] = $hosting['domainstatus']; $ptr['hosuid'] = $hosting['userid']; } } catch(Exception $exc) { \logModuleCall('DNS Manager', 'Cron Cleaner', "Error. When trying to remove rdns", array($exc->getMessage(), $exc->getTraceAsString())); continue; } if(!$ptr['hid'] && GlobalSettingHelper::getSetting(GlobalSettingEnum::RDNS_CUSTOM_IP) == 'on' && IPManagerIntegration::check()) { $ipFromIPM = query::query( "SELECT * " . "FROM `ip_manager_ips` " . "WHERE " . (isset($intIp) && is_string($intIp) && $intIp != 0 ? ("`ip_v6` = " . $intIp) : "`ip` = :ip") . " ;" , array('ip' => $ptr['ip']) )->fetch(); if(!empty($ipFromIPM)) { $delete = true; $reason = 'IP Exist in IP Manager pools but not Active!'; } } if(empty($ipFromIPM)) { if(!$ptr['hid']) { $delete = true; $reason = 'Service #'. $ptr['hid'] .' Not Found!'; } elseif($ptr['hid'] && $ptr['hstatus'] !== 'Active') { switch( $ptr['hstatus'] ) { case 'Cancelled': if( (string)GlobalSettingHelper::getSetting(GlobalSettingEnum::CRON_CLEANER_PTR_SERVICE_CANCELED) === 'on' ) { $reason = 'Service #' . $ptr['hid'] . ' is Cancelled!'; $delete = true; } break; case 'Terminated': if( (string)GlobalSettingHelper::getSetting(GlobalSettingEnum::CRON_CLEANER_PTR_SERVICE_TERMINATED) === 'on' ) { $reason = 'Service #' . $ptr['hid'] . ' is Terminated!'; $delete = true; } break; case 'Suspended': if( (string)GlobalSettingHelper::getSetting(GlobalSettingEnum::CRON_CLEANER_PTR_SERVICE_SUSPENDED) === 'on' ) { $reason = 'Service #' . $ptr['hid'] . ' is Suspended!'; $delete = true; } break; } } elseif($ptr['clientid'] != $ptr['hosuid']) { $delete = true; $reason = 'Service #' . $ptr['hid'] . ' Not Belong to Clients PTR!'; } } if($delete === true) { try { if(!$notify_only) { $helper = new main\mgLibs\custom\reverse\ReverseDNS($reverse); $zone = new Zone(); $zone->name = $reverse->name; $zone->serverid = $reverse->serverid; $module = $zone->getModule(); $helper->cleanRemove(); if($module->zoneExists() && count($module->getRDNSRecord($reverse->ip)) <= 1 && (string)GlobalSettingHelper::getSetting(GlobalSettingEnum::DO_NOT_REMOVE_EMPTY_PTR_ZONES) !== 'on') { $module->terminateZone(); } LogHelper::addSuccessLog('Cron Cleaner', 'Remove PTR record: '.$reverse->name.' Reason: '.$reason); } $count_removed++; $details["RDNS " . $reverse->name] = "" . $reason; } catch(Exception $exc) { \logModuleCall('DNS Manager', 'Cron Cleaner', "Error. When trying to remove rdns", array($exc->getMessage(), $exc->getTraceAsString())); } } } return array($details, $count_removed); } /** * @return bool */ private function getPtrRemoveSettingsStatus() { $settings = [ GlobalSettingEnum::CRON_CLEANER_PTR_SERVICE_CANCELED, GlobalSettingEnum::CRON_CLEANER_PTR_SERVICE_TERMINATED, GlobalSettingEnum::CRON_CLEANER_PTR_SERVICE_SUSPENDED ]; foreach( $settings as $value ) { if( (string)GlobalSettingHelper::getSetting($value) === 'on' ) { return true; } } return false; } }