Browse code

Changed README.md and added shas-probe-5.png.

DoubleBastionAdmin authored on 28/11/2024 17:26:49
Showing 1 changed files
1 1
old mode 100755
2 2
new mode 100644
... ...
@@ -1333,7 +1333,7 @@ if (file_exists(dirname(__FILE__) . '/shsp-config.php')) {
1333 1333
  <div style='background-color:#f1f9ff;padding:4px 8px;'>
1334 1334
  <div style='display: block; margin: 6px auto; width: 229px; height: 170px;'><img src='cid:logo-". $separator ."'></div>
1335 1335
  <p>Hello,</p>
1336
- <p>This is an automated message sent by System Health and Security Probe v. 1.0.4. Host: " . $nameofhost  . ".<br><br>
1336
+ <p>This is an automated message sent by System Health and Security Probe v. 1.0.5. Host: " . $nameofhost  . ".<br><br>
1337 1337
  System Health and Security Probe runs regularly and investigates if any service running on the server is in failed state, if ClamAV
1338 1338
  antivirus has detected any virus in the incoming emails or in the files uploaded to Nextcloud, if any IP address has been banned due to repeated
1339 1339
  failed log in attempts against one of the applications monitored by Fail2ban, if the free storage space on all partitions is under a certain
Browse code

changed img/shas-probe-2.png img/shas-probe-3.png img/shas-probe-4.png CHANGELOG.txt system-health-and-security-probe.php

DoubleBastionAdmin authored on 28/11/2024 04:13:47
Showing 1 changed files
... ...
@@ -1333,7 +1333,7 @@ if (file_exists(dirname(__FILE__) . '/shsp-config.php')) {
1333 1333
  <div style='background-color:#f1f9ff;padding:4px 8px;'>
1334 1334
  <div style='display: block; margin: 6px auto; width: 229px; height: 170px;'><img src='cid:logo-". $separator ."'></div>
1335 1335
  <p>Hello,</p>
1336
- <p>This is an automated message sent by System Health and Security Probe v. 1.0.3. Host: " . $nameofhost  . ".<br><br>
1336
+ <p>This is an automated message sent by System Health and Security Probe v. 1.0.4. Host: " . $nameofhost  . ".<br><br>
1337 1337
  System Health and Security Probe runs regularly and investigates if any service running on the server is in failed state, if ClamAV
1338 1338
  antivirus has detected any virus in the incoming emails or in the files uploaded to Nextcloud, if any IP address has been banned due to repeated
1339 1339
  failed log in attempts against one of the applications monitored by Fail2ban, if the free storage space on all partitions is under a certain
Browse code

changed README.md CHANGELOG.txt and system-health-and-security-probe.php

DoubleBastionAdmin authored on 28/11/2024 03:42:10
Showing 1 changed files
1 1
old mode 100644
2 2
new mode 100755
... ...
@@ -1333,7 +1333,7 @@ if (file_exists(dirname(__FILE__) . '/shsp-config.php')) {
1333 1333
  <div style='background-color:#f1f9ff;padding:4px 8px;'>
1334 1334
  <div style='display: block; margin: 6px auto; width: 229px; height: 170px;'><img src='cid:logo-". $separator ."'></div>
1335 1335
  <p>Hello,</p>
1336
- <p>This is an automated message sent by System Health and Security Probe v. 1.0.2. Host: " . $nameofhost  . ".<br><br>
1336
+ <p>This is an automated message sent by System Health and Security Probe v. 1.0.3. Host: " . $nameofhost  . ".<br><br>
1337 1337
  System Health and Security Probe runs regularly and investigates if any service running on the server is in failed state, if ClamAV
1338 1338
  antivirus has detected any virus in the incoming emails or in the files uploaded to Nextcloud, if any IP address has been banned due to repeated
1339 1339
  failed log in attempts against one of the applications monitored by Fail2ban, if the free storage space on all partitions is under a certain
Browse code

added system-health-and-security-probe.php

DoubleBastionAdmin authored on 28/11/2024 03:37:42
Showing 1 changed files
1 1
old mode 100755
2 2
new mode 100644
Browse code

Added logo png and fixed images display issues.

DoubleBastionAdmin authored on 28/11/2024 02:50:16
Showing 1 changed files
1 1
old mode 100644
2 2
new mode 100755
... ...
@@ -1333,7 +1333,7 @@ if (file_exists(dirname(__FILE__) . '/shsp-config.php')) {
1333 1333
  <div style='background-color:#f1f9ff;padding:4px 8px;'>
1334 1334
  <div style='display: block; margin: 6px auto; width: 229px; height: 170px;'><img src='cid:logo-". $separator ."'></div>
1335 1335
  <p>Hello,</p>
1336
- <p>This is an automated message sent by System Health and Security Probe v. 1.0.1. Host: " . $nameofhost  . ".<br><br>
1336
+ <p>This is an automated message sent by System Health and Security Probe v. 1.0.2. Host: " . $nameofhost  . ".<br><br>
1337 1337
  System Health and Security Probe runs regularly and investigates if any service running on the server is in failed state, if ClamAV
1338 1338
  antivirus has detected any virus in the incoming emails or in the files uploaded to Nextcloud, if any IP address has been banned due to repeated
1339 1339
  failed log in attempts against one of the applications monitored by Fail2ban, if the free storage space on all partitions is under a certain
Browse code

added system-health-and-security-probe.php

DoubleBastionAdmin authored on 28/11/2024 02:45:55
Showing 1 changed files
1 1
old mode 100755
2 2
new mode 100644
Browse code

Changed three file names and added four images.

DoubleBastionAdmin authored on 28/11/2024 02:16:32
Showing 1 changed files
... ...
@@ -1333,7 +1333,7 @@ if (file_exists(dirname(__FILE__) . '/shsp-config.php')) {
1333 1333
  <div style='background-color:#f1f9ff;padding:4px 8px;'>
1334 1334
  <div style='display: block; margin: 6px auto; width: 229px; height: 170px;'><img src='cid:logo-". $separator ."'></div>
1335 1335
  <p>Hello,</p>
1336
- <p>This is an automated message sent by System Health and Security Probe v. 1.0.0. Host: " . $nameofhost  . ".<br><br>
1336
+ <p>This is an automated message sent by System Health and Security Probe v. 1.0.1. Host: " . $nameofhost  . ".<br><br>
1337 1337
  System Health and Security Probe runs regularly and investigates if any service running on the server is in failed state, if ClamAV
1338 1338
  antivirus has detected any virus in the incoming emails or in the files uploaded to Nextcloud, if any IP address has been banned due to repeated
1339 1339
  failed log in attempts against one of the applications monitored by Fail2ban, if the free storage space on all partitions is under a certain
Browse code

added system-health-and-security-probe.php

DoubleBastionAdmin authored on 28/11/2024 01:35:21
Showing 1 changed files
1 1
old mode 100644
2 2
new mode 100755
Browse code

modified system-health-and-security-probe.php

DoubleBastionAdmin authored on 28/11/2024 01:33:13
Showing 1 changed files
1 1
old mode 100755
2 2
new mode 100644
Browse code

Created repository.

DoubleBastionAdmin authored on 28/11/2024 01:19:39
Showing 1 changed files
1 1
new file mode 100755
... ...
@@ -0,0 +1,1487 @@
1
+<?php
2
+
3
+/**
4
+ * "System Health and Security Probe" is a program that runs periodically to
5
+ * investigate general system health and security problems and to send report
6
+ * emails to admins. It's designed to be used as part of RED SCARF Suite.
7
+ * It requires at least an abridged version of RED SCARF Suite and Postfix,
8
+ * installed and configured on a Debian server as described in the Complete
9
+ * Guide to a Complete Linux Server. For more details, please see the
10
+ * README.txt file.
11
+ *
12
+ * Copyright (C) 2024  Double Bastion LLC <www.doublebastion.com>
13
+ *
14
+ * This file is part of "System Health and Security Probe".
15
+ *
16
+ * "System Health and Security Probe" is free software: you can redistribute
17
+ * it and/or modify it under the terms of the GNU General Public License as
18
+ * published by the Free Software Foundation, either version 3 of the License,
19
+ * or (at your option) any later version.
20
+ *
21
+ * This program is distributed in the hope that it will be useful,
22
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
+ * GNU General Public License for more details.
25
+ *
26
+ * You should have received a copy of the GNU General Public License
27
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
28
+ */
29
+
30
+
31
+if (file_exists(dirname(__FILE__) . '/shsp-config.php')) {
32
+
33
+ require(dirname(__FILE__) . '/shsp-config.php');
34
+
35
+ if (preg_match('/^[0-9]+$/', $time_in_hours)) { $runinterval = $time_in_hours * 3600; } else { exit("Error. 'System Health and Security Probe' needs a valid \$time_in_hours parameter.\n"); }
36
+ if (!empty($db_name)) { $bannedipsdb = $db_name; } else { exit("Error. 'System Health and Security Probe' needs a valid \$db_name parameter.\n"); }
37
+ if (!empty($db_user)) { $bannedipsuser = $db_user; } else { exit("Error. 'System Health and Security Probe' needs a valid \$db_user parameter.\n"); }
38
+ if (!empty($db_password)) { $bannedipspswd = $db_password; } else { exit("Error. 'System Health and Security Probe' needs a valid \$db_password parameter.\n"); }
39
+ if (!empty($report_from)) { $emailsender = $report_from; } else { exit("Error. 'System Health and Security Probe' needs a valid \$report_from parameter.\n"); }
40
+ if (!empty($report_to)) {
41
+      $emailto = str_replace(" ", "", $report_to);
42
+      $emailtoarr = explode(",", $emailto);
43
+      $emailtofirst = $emailtoarr[0];
44
+ } else { exit("Error. 'System Health and Security Probe' needs a valid \$report_to parameter.\n"); }
45
+ if (!empty($report_subject)) { $subject = $report_subject; } else { $subject = "System Health and Security Report"; }
46
+ if (!empty($phpmyadmin_log)) { $phpmyadminlog = $phpmyadmin_log; $phpmyadminlogsec = $phpmyadminlog . ".1"; } else { $phpmyadminlog = ""; $phpmyadminlogsec = ""; }
47
+ if (!empty($mailman_log)) { $mailmanlog = $mailman_log; $mailmanlogsec = $mailmanlog . ".1"; } else { $mailmanlog = ""; $mailmanlogsec = ""; }
48
+ if (!empty($dolibarr_log)) { $dolibarrlog = $dolibarr_log; $dolibarrlogsec = $dolibarrlog . ".1"; } else { $dolibarrlog = ""; $dolibarrlogsec = ""; }
49
+ if (!empty($phplist_log)) { $phplistlog = $phplist_log; $phplistlogsec = $phplistlog . ".1"; } else { $phplistlog = ""; $phplistlogsec = ""; }
50
+ if (!empty($roundcube_log)) { $roundcubelog = $roundcube_log; $roundcubelogsec = $roundcubelog . ".1"; } else { $roundcubelog = ""; $roundcubelogsec = ""; }
51
+ if (!empty($matomo_log)) { $matomolog = $matomo_log; $matomologsec = $matomolog . ".1"; } else { $matomolog = ""; $matomologsec = ""; }
52
+ if (!empty($looladmin_log)) { $looladminlog = $looladmin_log; $looladminlogsec = $looladminlog . ".1"; } else { $looladminlog = ""; $looladminlogsec = ""; }
53
+ if (!empty($wordpress_log)) {
54
+      $wprexpl = explode(",", $wordpress_log);
55
+      $wordpresslog = array_filter(array_map('trim', $wprexpl));
56
+      $wordpresslogsec = array_map(function($wplog) { return $wplog . ".1"; }, $wordpresslog);
57
+ } else { $wordpresslog = []; $wordpresslogsec = []; }
58
+ if (!empty($asterisk_log)) { $asterisklog = $asterisk_log; $asterisklogsec = $asterisklog . ".1"; } else { $asterisklog = ""; $asterisklogsec = ""; }
59
+ if (!empty($bind_log)) { $bindlog = $bind_log; $bindlogsec = $bindlog . ".0"; } else { $bindlog = ""; $bindlogsec = ""; }
60
+ if (!empty($nextcloud_log)) { $nextcloudlog = $nextcloud_log; $nextcloudlogsec = $nextcloudlog . ".1"; } else { $nextcloudlog = ""; $nextcloudlogsec = ""; }
61
+ if (!empty($dovecot_log)) { $dovecotlog = $dovecot_log; $dovecotlogsec = $dovecotlog . ".1"; } else { $dovecotlog = ""; $dovecotlogsec = ""; }
62
+ if (!empty($postfix_log)) { $postfixlog = $postfix_log; $postfixlogsec = $postfixlog . ".1"; } else { $postfixlog = ""; $postfixlogsec = ""; }
63
+ if (!empty($postfix_sasl_log)) { $postfixsasllog = $postfix_sasl_log; $postfixsasllogsec = $postfixsasllog . ".1"; } else { $postfixsasllog = ""; $postfixsasllogsec = ""; }
64
+ if (!empty($proftpd_log)) { $proftpdlog = $proftpd_log; $proftpdlogsec = $proftpdlog . ".1"; } else { $proftpdlog = ""; $proftpdlogsec = ""; }
65
+ if (!empty($sshd_log)) { $sshdlog = $sshd_log; $sshdlogsec = $sshdlog . ".1"; } else { $sshdlog = ""; $sshdlogsec = ""; }
66
+ if (!empty($openvpn_log)) { $openvpnlog = $openvpn_log; $openvpnlogsec = $openvpnlog . ".1"; } else { $openvpnlog = ""; $openvpnlogsec = ""; }
67
+ if (!empty($postfix_admin_log)) { $postfixadminlog = $postfix_admin_log; $postfixadminlogsec = $postfixadminlog . ".1"; } else { $postfixadminlog = ""; $postfixadminlogsec = ""; }
68
+ if (!empty($roundpin_log)) { $roundpinlog = $roundpin_log; $roundpinlogsec = $roundpinlog . ".1"; } else { $roundpinlog = ""; $roundpinlogsec = ""; }
69
+ if (!empty($mybb_log)) { $mybblog = $mybb_log; $mybblogsec = $mybblog . ".1"; } else { $mybblog = ""; $mybblogsec = ""; }
70
+ if (!empty($friendica_log)) { $friendicalog = $friendica_log; $friendicalogsec = $friendicalog . ".1"; } else { $friendicalog = ""; $friendicalogsec = ""; }
71
+ if (!empty($redscarfsuite_panel_log)) { $redscarfsuitepanellog = $redscarfsuite_panel_log; $redscarfsuitepanellogsec = $redscarfsuitepanellog . ".1"; } else { $redscarfsuitepanellog = ""; $redscarfsuitepanellogsec = ""; }
72
+
73
+ if (!empty($disk_threshold)) { $diskthreshold = $disk_threshold; } else { $diskthreshold = "3145728"; }
74
+ if (!empty($clamav_report_dir)) {
75
+      if (mb_substr($clamav_report_dir, -1) == "/") {
76
+          $clamavreportdir = substr($clamav_report_dir, 0, -1);
77
+      } else { $clamavreportdir = $clamav_report_dir; }
78
+ } else { $clamavreportdir = ""; }
79
+ if (!empty($backup_directory)) {
80
+      if (mb_substr($backup_directory, -1) == "/") {
81
+          $backupdirectory = substr($backup_directory, 0, -1);
82
+      } else { $backupdirectory = $backup_directory; }
83
+ } else { $backupdirectory = ""; }
84
+ if (!empty($automatic_emails_to_isp)) { $automaticemail = $automatic_emails_to_isp; } else { $automaticemail = "no"; }
85
+ if (!empty($excluded_jails)) { $excludedjails = $excluded_jails; } else { $excludedjails = []; }
86
+ if (!empty($excluded_ips)) { $excludedips = str_replace(" ", "", $excluded_ips); } else { $excludedips = ""; }
87
+ if (!empty($sysadmin_name)) { $sysadminname = $sysadmin_name; } else { $sysadminname = ""; }
88
+ if (!empty($abuse_reports_to_admin)) { $abusereportstoadmin = $abuse_reports_to_admin; } else { $abusereportstoadmin = "no"; }
89
+
90
+ if (count($wordpresslog) > 1) {
91
+     $wordpressfirst = implode(' or ', $wordpresslog);
92
+     $wordpresssec = implode(' or ', $wordpresslogsec);
93
+ } else {
94
+     $wordpressfirst = $wordpresslog[0];
95
+     $wordpresssec = $wordpresslogsec[0];
96
+ }
97
+
98
+ // Log paths
99
+ $jaillogarr = ['asterisk' => $asterisklog, 'named-refused' => $bindlog, 'dovecot' => $dovecotlog, 'looladmin' => $looladminlog, 'mailman' => $mailmanlog,
100
+	        'nextcloud' => $nextcloudlog, 'dolibarr' => $dolibarrlog, 'phplist' => $phplistlog, 'phpmyadmin' => $phpmyadminlog,
101
+	        'postfix' => $postfixlog, 'postfix-sasl' => $postfixsasllog, 'proftpd' => $proftpdlog, 'roundcube' => $roundcubelog, 'sshd' => $sshdlog,
102
+	        'openvpn' => $openvpnlog, 'postfixadmin' => $postfixadminlog, 'roundpin' => $roundpinlog, 'mybb' => $mybblog, 'matomo' => $matomolog, 
103
+                'friendica' => $friendicalog, 'redscarfsuitepanel' => $redscarfsuitepanellog,'wordpress' => [$wordpressfirst, $wordpresssec]];
104
+
105
+ $jaillogarrsec = ['asterisk' => $asterisklogsec, 'named-refused' => $bindlogsec, 'dovecot' => $dovecotlogsec, 'looladmin' => $looladminlogsec,
106
+	           'mailman' => $mailmanlogsec, 'nextcloud' => $nextcloudlogsec, 'dolibarr' => $dolibarrlogsec, 'phplist' => $phplistlogsec,
107
+	           'phpmyadmin' => $phpmyadminlogsec, 'postfix' => $postfixlogsec, 'postfix-sasl' => $postfixsasllogsec,
108
+	           'proftpd' => $proftpdlogsec, 'roundcube' => $roundcubelogsec, 'matomo' => $matomologsec, 'sshd' => $sshdlogsec, 'openvpn' => $openvpnlogsec, 
109
+                   'postfixadmin' => $postfixadminlogsec, 'roundpin' => $roundpinlogsec, 'mybb' => $mybblogsec, 'friendica' => $friendicalogsec,
110
+                   'redscarfsuitepanel' => $redscarfsuitepanellogsec];
111
+
112
+ // Jail ports
113
+ $jailsports = ['asterisk' => '5060', 'named-refused' => '53', 'dovecot' => '143', 'looladmin' => '443', 'mailman' => '443', 'nextcloud' => '443', 'dolibarr' => '443',
114
+	        'phplist' => '443', 'phpmyadmin' => '443', 'postfix' => '25', 'postfix-sasl' => '25', 'proftpd' => '21', 'roundcube' => '443',
115
+	        'matomo' => '443', 'sshd' => '22', 'openvpn' => '1194', 'postfixadmin' => '443', 'roundpin' => '443', 'wordpress' => '443'];
116
+
117
+ // Connect to the database
118
+ mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
119
+ $mysqli = new mysqli('localhost', $bannedipsuser, $bannedipspswd, $bannedipsdb);
120
+ if ($mysqli->connect_error) { exit('Error connecting to the database !'); }
121
+ $mysqli->set_charset("utf8mb4");
122
+
123
+ $query0 = "SHOW TABLES LIKE 'bannedipstable';";
124
+ $result0 = $mysqli->query($query0);
125
+
126
+ // Create the 4 tables if it's the first run of this script
127
+ if (mysqli_num_rows($result0) == 0) {
128
+
129
+     // Create the table for the IPs banned by Fail2ban
130
+     $query1 = " CREATE TABLE IF NOT EXISTS bannedipstable (
131
+			id          INT UNSIGNED   AUTO_INCREMENT  PRIMARY KEY,
132
+			IP          VARCHAR (400)  DEFAULT NULL,
133
+			jail        VARCHAR (300)  DEFAULT NULL,
134
+			first_ban   DATETIME       DEFAULT NULL,
135
+			last_ban    DATETIME       DEFAULT NULL,
136
+			ban_number  INT            DEFAULT NULL,
137
+			emails_isp  INT            DEFAULT 0
138
+		 ); ";
139
+     $result1 = $mysqli->query($query1);
140
+
141
+     // Create the table for the last sent email
142
+     $query2 = " CREATE TABLE IF NOT EXISTS lastsentemail (
143
+			id           INT UNSIGNED  AUTO_INCREMENT  PRIMARY KEY,
144
+			old_message  LONGTEXT      DEFAULT NULL
145
+		 ); ";
146
+     $result2 = $mysqli->query($query2);
147
+
148
+     /**
149
+      * Create the table for the last sent Nextcloud and mail log lines containing virus detections ('mail_loglines' and 'nextcloud_loglines'), and the last
150
+      * read log lines ('lastmailline' and 'lastnextline')
151
+      */
152
+     $query3 = " CREATE TABLE IF NOT EXISTS sentreadlines (
153
+			id                  INT UNSIGNED  AUTO_INCREMENT  PRIMARY KEY,
154
+			mail_loglines       TEXT  DEFAULT NULL,
155
+			nextcloud_loglines  TEXT  DEFAULT NULL,
156
+			lastmailline        TEXT  DEFAULT NULL,
157
+			lastnextline        TEXT  DEFAULT NULL,
158
+			lastpersdetmail     TEXT  DEFAULT NULL,
159
+			lastpersdetnext     TEXT  DEFAULT NULL
160
+		 ); ";
161
+     $result3 = $mysqli->query($query3);
162
+
163
+     // Create the table to store the jails and their respective banned IPs sent in the last email or banned in the past
164
+     $query4 = " CREATE TABLE IF NOT EXISTS jailsandips (
165
+		        id         INT            UNSIGNED AUTO_INCREMENT  PRIMARY KEY,
166
+		        jail       VARCHAR (300)  DEFAULT NULL,
167
+		        bannedips  LONGTEXT       DEFAULT NULL
168
+		 ); ";
169
+     $result4 = $mysqli->query($query4);
170
+ }
171
+
172
+ // Search for failed processes and format the data
173
+ $getfailedservinit = shell_exec('systemctl --failed --all');
174
+ $getfailedservsec = str_replace("To show all installed unit files use 'systemctl list-unit-files'.", "", $getfailedservinit);
175
+ $failedservsplit = preg_split('/\r\n|\r|\n/', $getfailedservsec);
176
+ $countlines = count($failedservsplit);
177
+ $getfailedservbr = implode("<br>", $failedservsplit);
178
+ $getfailedservtert = $failedservsplit[$countlines - 3];
179
+
180
+ // If there are failed processes, list them in a paragraph in the email to be sent
181
+ if ($getfailedservtert[0] != 0) {
182
+     $getfailedserv = "<ul><li style='color:#225aad;font-weight:700;'>The following services are in failed state:</li><br><br>" . $getfailedservbr . "</ul>";
183
+ } else { $getfailedserv = null; }
184
+
185
+
186
+ /**
187
+  * Read the periodic virus scanning reports to see if there were any detections during the last scan
188
+  */
189
+
190
+ // Create the ClamAV reports directory if it hasn't been already created
191
+ if (!is_dir($clamavreportdir)) {
192
+      exec("mkdir -p " . $clamavreportdir);
193
+ }
194
+
195
+ $maildetectrep = $clamavreportdir . "/clamav_mail_report";
196
+ $nextdetectrep = $clamavreportdir . "/clamav_nextcloud_report";
197
+ $targetstr = "Infected files: ";
198
+
199
+ // Search for the infected files lines in the mail scan report
200
+ if (is_file($maildetectrep)) {
201
+     $readmaildetrep = file_get_contents($maildetectrep);
202
+     $infectedfl = strstr($readmaildetrep, $targetstr);
203
+     $txtbreakline = preg_split('/\r\n|\r|\n/', $infectedfl);
204
+     $nbofinfectfls = explode("Infected files: ", $txtbreakline[0]);
205
+     $nbinfctdflsmail = $nbofinfectfls[1];
206
+
207
+     if ($nbinfctdflsmail != 0) {
208
+
209
+	 $getdetlines = explode("\n", $readmaildetrep);
210
+	 $getdetmaillnarr = [];
211
+	 $gosel = false;
212
+	 $p = 0;
213
+	 foreach ($getdetlines as $lnkey => $lnvalue) {
214
+
215
+	      if (strpos($lnvalue, "SCAN SUMMARY") !== false) {
216
+	          $gosel = false;
217
+	      }
218
+	      if ($gosel) {
219
+	          $getdetmaillnarr[$p] = $lnvalue;
220
+	          $p++;
221
+	      }
222
+	      if (strpos($lnvalue, "---------------------------") !== false) {
223
+	          $gosel = true;
224
+	      }
225
+
226
+	 }
227
+	 $maildetlnbr = implode("<br><br>", $getdetmaillnarr);
228
+	 $maildetlnbr_enc = base64_encode($maildetlnbr);
229
+     } else { $maildetlnbr_enc = null; }
230
+
231
+ } else {
232
+      $nbinfctdflsmail = 0;
233
+      $maildetlnbr_enc = null;
234
+ }
235
+
236
+ // Search for the infected files lines in the Nextcloud scan report
237
+ if (is_file($nextdetectrep)) {
238
+     $readnextdetrep = file_get_contents($nextdetectrep);
239
+     $infectedfltxt = strstr($readnextdetrep, $targetstr);
240
+     $txtbreakln = preg_split('/\r\n|\r|\n/', $infectedfltxt);
241
+     $nbofinfectedinit = explode("Infected files: ", $txtbreakln[0]);
242
+     $nbinfctdflsnext = $nbofinfectedinit[1];
243
+
244
+     if ($nbinfctdflsnext != 0) {
245
+
246
+	 $getdetnextlines = explode("\n", $readnextdetrep);
247
+	 $getdetnextlinesarr = [];
248
+	 $goselnext = false;
249
+	 $b = 0;
250
+	 foreach ($getdetnextlines as $lnextkey => $lnextvalue) {
251
+
252
+	      if (strpos($lnextvalue, "SCAN SUMMARY") !== false) {
253
+	          $goselnext = false;
254
+	      }
255
+	      if ($goselnext) {
256
+	          $getdetnextlinesarr[$b] = $lnextvalue;
257
+	          $b++;
258
+	      }
259
+	      if (strpos($lnextvalue, "---------------------------") !== false) {
260
+	          $goselnext = true;
261
+	      }
262
+	 }
263
+	 $nextdetlnbr = implode("<br><br>", $getdetnextlinesarr);
264
+	 $nextdetlnbr_enc = base64_encode($nextdetlnbr);
265
+     } else { $nextdetlnbr_enc = null; }
266
+
267
+ } else {
268
+       $nbinfctdflsnext = 0;
269
+       $nextdetlnbr_enc = null;
270
+ }
271
+
272
+ // Get the last sent Nextcloud log lines and mail log lines containing virus detections, the last mail log line and Nextcloud log line read by the script in the previous run
273
+ // and the last sent mail virus detections and Nextcloud virus detections
274
+ $queryvr = "SELECT id, mail_loglines, nextcloud_loglines, lastmailline, lastnextline, lastpersdetmail, lastpersdetnext FROM sentreadlines WHERE id = 1;";
275
+ $resultvr = $mysqli->query($queryvr);
276
+ $result_fetchvr = $resultvr->fetch_array();
277
+ $old_maildetections_enc = $result_fetchvr[1];
278
+ $old_nextdetections_enc = $result_fetchvr[2];
279
+ $lastreadmaillineinit = $result_fetchvr[3];
280
+ $lastreadnextlineinit = $result_fetchvr[4];
281
+ $old_mailvirdetect_enc = $result_fetchvr[5];
282
+ $old_nextvirdetect_enc = $result_fetchvr[6];
283
+ $lastreadmailline = base64_decode($lastreadmaillineinit);
284
+ $lastreadnextline = base64_decode($lastreadnextlineinit);
285
+
286
+ if ($nbinfctdflsmail != 0 && $nbinfctdflsnext != 0 && $maildetlnbr_enc != $old_mailvirdetect_enc && $nextdetlnbr_enc != $old_nextvirdetect_enc) {
287
+     $clamavperiodicdetect = "<ul><li style='color:#225aad;font-weight:700;'>ClamAV antivirus has made the following detections by periodic scanning:</li><br>
288
+	                      <br><ul><li><b>Viruses detected in emails directories (You should remove them manually):</b><br><br>" . $maildetlnbr . "</li></ul><br>
289
+	                      <ul><li><b>Viruses detected in Nextcloud directories (You should remove them manually):</b><br><br>" . $nextdetlnbr . "</li></ul></ul><br>";
290
+ } elseif ($nbinfctdflsmail != 0 && $nbinfctdflsnext == 0 && $maildetlnbr_enc != $old_mailvirdetect_enc) {
291
+     $clamavperiodicdetect = "<ul><li style='color:#225aad;font-weight:700;'>ClamAV antivirus has made the following detections by periodic scanning:</li><br>
292
+	                      <br><ul><li><b>Viruses detected in emails directories (You should remove them manually):</b><br><br>" . $maildetlnbr . "</li></ul></ul><br>";
293
+ } elseif ($nbinfctdflsmail == 0 && $nbinfctdflsnext != 0 && $nextdetlnbr_enc != $old_nextvirdetect_enc) {
294
+     $clamavperiodicdetect = "<ul><li style='color:#225aad;font-weight:700;'>ClamAV antivirus has made the following detections by periodic scanning:</li><br>
295
+	                      <br><ul><li><b>Viruses detected in Nextcloud directories (You should remove them manually):</b><br><br>" . $nextdetlnbr . "</li></ul></ul><br>";
296
+ } else { $clamavperiodicdetect = null; }
297
+
298
+ // Get the log lines that contain virus detections in emails
299
+ $mailstring = ' milter-hold: ';
300
+
301
+ $maillog1init = $postfixlog;
302
+ $maillog2init = $postfixlogsec;
303
+
304
+ if (is_file($maillog1init)) {
305
+     $maillog1sec = file_get_contents($maillog1init);
306
+ } else { $maillog1sec = ''; }
307
+
308
+ if (is_file($maillog2init)) {
309
+     $maillog2sec = file_get_contents($maillog2init);
310
+ } else  { $maillog2sec = ''; }
311
+
312
+ if ($lastreadmaillineinit != '') {
313
+
314
+   if (strpos($maillog1sec, $lastreadmailline)  !== false) {
315
+
316
+      $maillog1tert = strstr($maillog1sec, $lastreadmailline);
317
+      $maillog1fourth = preg_split('/\r\n|\r|\n/', $maillog1tert);
318
+      $maillogexplall = $maillog1fourth;
319
+
320
+      array_pop($maillog1fourth);
321
+      $endoflstrdmlln = end($maillog1fourth);
322
+      $reset1 = reset($maillog1fourth);
323
+      $newlastreadmailline = base64_encode($endoflstrdmlln);
324
+
325
+   } else {
326
+
327
+      $maillog2tert = strstr($maillog2sec, $lastreadmailline);
328
+      $maillog2fourth = preg_split('/\r\n|\r|\n/', $maillog2tert);
329
+
330
+      $maillog2fifth = implode("\n", $maillog2fourth);
331
+      $maillog2sixth = $maillog2fifth . $maillog1sec;
332
+      $maillog2expl = preg_split('/\r\n|\r|\n/', $maillog2sixth);
333
+      $maillogexplall = $maillog2expl;
334
+
335
+      array_pop($maillog2expl);
336
+      $endoflstrdmlln2 = end($maillog2expl);
337
+      $reset2 = reset($maillog2expl);
338
+      $newlastreadmailline = base64_encode($endoflstrdmlln2);
339
+    }
340
+
341
+ } else {
342
+
343
+     if ($maillog1sec != '' || $maillog2sec != '') {
344
+	 $maillogconc = $maillog2sec . $maillog1sec;
345
+	 $maillogexplall = preg_split('/\r\n|\r|\n/', $maillogconc);
346
+
347
+	 if ($maillogexplall[0] == '') {
348
+	     $newlastreadinit = $maillogexplall[1];
349
+	 } else { $newlastreadinit = $maillogexplall[0]; }
350
+
351
+	 $newlastreadmailline = base64_encode($newlastreadinit);
352
+
353
+      } else { $newlastreadmailline = ''; $maillogexplall = []; }
354
+   }
355
+
356
+  $mailloglines = [];
357
+
358
+  foreach($maillogexplall as $key => $value) {
359
+      if (strpos($value, $mailstring) !== false) {
360
+	  $mailloglines[] = htmlentities($value);
361
+      }
362
+  }
363
+
364
+ $maildetections = implode("<br><br>", $mailloglines);
365
+ $maildetections_enc = base64_encode($maildetections);
366
+
367
+ // Get the log lines that contain virus detections in files uploaded to Nextcloud
368
+ $nextstring = 'Infected file deleted';
369
+
370
+ if (is_file($nextcloudlog)) {
371
+     $nextlog1sec = file_get_contents($nextcloudlog);
372
+ } else { $nextlog1sec = ''; }
373
+
374
+ if (is_file($nextcloudlogsec)) {
375
+     $nextlog2sec = file_get_contents($nextcloudlogsec);
376
+ } else { $nextlog2sec = ''; }
377
+
378
+ if ($lastreadnextlineinit != '') {
379
+
380
+     if (strpos($nextlog1sec, $lastreadnextline) !== false) {
381
+
382
+         $nextlog1tert = strstr($nextlog1sec, $lastreadnextline);
383
+         $nextlog1fourth = preg_split('/\r\n|\r|\n/', $nextlog1tert);
384
+         $nextlogexplall = $nextlog1fourth;
385
+
386
+         array_pop($nextlog1fourth);
387
+         $endoflstrdmlln = end($nextlog1fourth);
388
+         $newlastreadnextline = base64_encode($endoflstrdmlln);
389
+
390
+     } else {
391
+
392
+         $nextlog2tert = strstr($nextlog2sec, $lastreadnextline);
393
+         $nextlog2fourth = preg_split('/\r\n|\r|\n/', $nextlog2tert);
394
+
395
+         $nextlog2fifth = implode("\n", $nextlog2fourth);
396
+         $nextlog2sixth = $nextlog2fifth . $nextlog1sec;
397
+         $nextlog2expl = preg_split('/\r\n|\r|\n/', $nextlog2sixth);
398
+         $nextlogexplall = $nextlog2expl;
399
+
400
+         array_pop($nextlog2expl);
401
+         $endoflstrdmlln2 = end($nextlog2expl);
402
+         $newlastreadnextline = base64_encode($endoflstrdmlln2);
403
+     }
404
+
405
+ } else {
406
+
407
+        if ($nextlog1sec != '' || $nextlog2sec != '') {
408
+	    $nextlogconc = $nextlog2sec . $nextlog1sec;
409
+	    $nextlogexplall = preg_split('/\r\n|\r|\n/', $nextlogconc);
410
+
411
+	    if ($nextlogexplall[0] == '') {
412
+	        $newlastreadinit = $nextlogexplall[1];
413
+	    } else {
414
+                $newlastreadinit = $nextlogexplall[0];
415
+            }
416
+
417
+	    $newlastreadnextline = base64_encode($newlastreadinit);
418
+
419
+        } else {
420
+            $newlastreadnextline = ''; $nextlogexplall = [];
421
+        }
422
+ }
423
+
424
+ $nextloglines = [];
425
+
426
+ foreach ($nextlogexplall as $key2 => $value2) {
427
+        if (strpos($value2, $nextstring) !== false) {
428
+	    $nextloglines[] = htmlentities($value2);
429
+        }
430
+ }
431
+
432
+ $nextdetections = implode("<br><br>", $nextloglines);
433
+ $nextdetections_enc = base64_encode($nextdetections);
434
+
435
+ // Decide how the virus detections paragraph will look like
436
+ if (count($mailloglines) != 0 && count($nextloglines) != 0 && $maildetections_enc != $old_maildetections_enc && $nextdetections_enc != $old_nextdetections_enc) {
437
+     $clamavdetections = "<ul><li><span style='color:#225aad;font-weight:700;'>The logs show the following ClamAV recent detections:</span></span></li><br>
438
+	                  <br><ul><li><b>Viruses detected in emails (they have been already removed):</b><br><br>" . $maildetections . "</li></ul><br>
439
+	                  <ul><li><b>Viruses detected in files uploaded to Nextcloud (they have been already removed):</b><br><br>" . $nextdetections . "<br>
440
+	                  </li></ul></ul><br>";
441
+ } elseif (count($mailloglines) != 0 && count($nextloglines) == 0 && $maildetections_enc != $old_maildetections_enc) {
442
+     $clamavdetections = "<ul><li><span style='color:#225aad;font-weight:700;'>The logs show the following ClamAV recent detections:</span></span></li><br>
443
+	                  <br><ul><li><b>Viruses detected in emails (they have been already removed):</b><br><br>" . $maildetections . "<br>
444
+	                  </li></ul></ul><br>";
445
+ } elseif (count($mailloglines) == 0 && count($nextloglines) != 0 && $nextdetections_enc != $old_nextdetections_enc) {
446
+     $clamavdetections = "<ul><li><span style='color:#225aad;font-weight:700;>The logs show the following ClamAV recent detections:</span></span></li><br>
447
+	                  <br><ul><li><b>Viruses detected in files uploaded to Nextcloud (they have been already removed):</b><br><br>" . $nextdetections . "<br>
448
+	                  </li></ul></ul><br>";
449
+ } else { $clamavdetections = null; }
450
+
451
+
452
+ // Get all the IPs banned by Fail2ban and their respective jails and clean the data
453
+ $bannedipslist = ` fail2ban-client status | grep "Jail list:" | sed "s/ //g" | awk '{split($2,a,",");for(i in a) system("fail2ban-client status " a[i])}' | grep "Status\|IP list" `;
454
+ $bannedipslistesc = escapeshellarg($bannedipslist);
455
+ $getblockedipsfirst = str_replace("'", "", $bannedipslistesc);
456
+ $getblockedipssec = str_replace("Status for the jail:", "@", $getblockedipsfirst);
457
+ $getblockedipthird = str_replace(array("  `- Banned IP list:"), "", $getblockedipssec);
458
+ $getblockedipfourth = str_replace(array("\r\n", "\r", "\n", "\t", "  ", "   ", "    "), " ", $getblockedipthird);
459
+ $getblockedipfifth = str_replace("  ", " ", $getblockedipfourth);
460
+ $getblockedipsixth = explode("@", $getblockedipfifth);
461
+ array_shift($getblockedipsixth);
462
+
463
+ // Collect the banned IPs
464
+ $jailsarr = [];
465
+ $allipsintotal = [];
466
+ $allipsperjail = [];
467
+ foreach ($getblockedipsixth as $key => $value) {
468
+    $expldval = explode(" ", $value);
469
+    if (count($expldval) > 3) {
470
+        $jailsarr[] = $expldval[1];
471
+        for ($j = 2; $j < count($expldval)-1; $j++) {
472
+	     $allipsperjail[] = $expldval[$j];
473
+        }
474
+        $allipsintotal[] = array($expldval[1] => $allipsperjail);
475
+    }
476
+    unset($expldval, $allipsperjail);
477
+ }
478
+
479
+ // Get the hostname
480
+ $nameofhost = exec("hostname");
481
+
482
+ // Loop through all the currently banned IPs and get all the necessary details about each, so that they can be inserted into the database and in the email report
483
+ $blockedipsrows = [];
484
+ $ipsfreqban = [];
485
+ $whoisinfo = [];
486
+ $ipstimespans = [];
487
+ $finwhoisdata = [];
488
+ $banipschck = 0;
489
+ $abreportsentcheck = 0;
490
+
491
+ // Set the default timezone for the date/time functions in this script
492
+ $systemTime = trim(file_get_contents("/etc/timezone"));
493
+ if ($systemTime == 'Etc/UTC') { $systemTime = 'UTC'; }
494
+ date_default_timezone_set($systemTime);
495
+
496
+ if (count($jailsarr) != 0) {
497
+   $j = 1;
498
+   $date1 = date("Y-m-d H:i:s");
499
+
500
+   // Get the data from the Fail2ban logs
501
+   $logonefl = explode("\n", file_get_contents("/var/log/fail2ban.log"));
502
+   $logtwofl = explode("\n", file_get_contents("/var/log/fail2ban.log.1"));
503
+
504
+   $log1data = array_reverse($logonefl);
505
+   $log2data = array_reverse($logtwofl);
506
+
507
+   foreach ($allipsintotal as $key => $value) {
508
+      if (is_array($value)) {
509
+	  foreach ($value as $key2 => $value2) {
510
+
511
+	     $ipsforjail = [];
512
+	     $restartcheck = 0;
513
+	     $getjail = $key2;
514
+
515
+	     // Get the current jail ban time, as it is set in '/etc/fail2ban/jail.local'
516
+	     $jail = "[" . $getjail . "]";
517
+	     $procjail = "@" . $jail;
518
+	     $logdata = file_get_contents('/etc/fail2ban/jail.local');
519
+
520
+	     if (strpos($logdata, $jail) !== false) {
521
+
522
+	         $preproc = str_replace("\n", "@", $logdata);
523
+	         $firstsplit = explode("@# JAILS", $preproc);
524
+	         $splitdata = explode($procjail, $firstsplit[1]);
525
+	         $splitdatasec = strstr($splitdata[1], "@bantime");
526
+	         $splitdatatert = explode("@", $splitdatasec);
527
+	         $jailbantime = filter_var($splitdatatert[1], FILTER_SANITIZE_NUMBER_INT);
528
+
529
+	     } else { $jailbantime = null; }
530
+
531
+	     // Get the last date when Fail2ban was restarted, from the logs
532
+	     $lastrestart = '';
533
+	     foreach ($log1data as $key => $value) {
534
+	          if (strpos($value, "Stopping all jails") !== false) {
535
+	              $restartlinesplit = explode(",", $value);
536
+	              $lastrestart = $restartlinesplit[0];
537
+	              break 1;
538
+	          }
539
+	     }
540
+
541
+	     if ($lastrestart == '') {
542
+	         foreach ($log2data as $keylog => $valuelog) {
543
+	              if (strpos($valuelog,  "Stopping all jails") !== false) {
544
+	                  $restartlinesplit2 = explode(",", $valuelog);
545
+	                  $lastrestart = $restartlinesplit2[0];
546
+	                  break 1;
547
+	              }
548
+	         }
549
+	     }
550
+
551
+	     // Calculate the timespan (in seconds) between the date of the last Fail2ban restart as found in logs and the current date
552
+	     if ($lastrestart != '') {
553
+	         $lastresdate = new DateTime($lastrestart);
554
+	         $currentdate = new DateTime($date1);
555
+	         $datesubtr = $currentdate->getTimestamp() - $lastresdate->getTimestamp();
556
+	         $restartspan = round($datesubtr);
557
+
558
+	     } else { $restartspan = 10 * $jailbantime; }
559
+
560
+	     /**
561
+	      * Decide if the last Fail2ban restart happened recently enough to trigger a false positive when updating the database with the total number
562
+	      * of bans for each IP
563
+	      */
564
+	     if ($restartspan < $jailbantime) {
565
+	         $restartcheck = 1;
566
+	     }
567
+
568
+	     // Get the data from the current jail log files
569
+	     $getlogdata1 = [];
570
+	     $getlogdata1sec = [];
571
+	     $getlogdata2 = [];
572
+	     $getlogdata2sec = [];
573
+
574
+	     if ($getjail == 'wordpress') {
575
+
576
+	         foreach ($wordpresslog as $wkey => $wvalue) {
577
+	             if (is_file($wvalue)) {
578
+	                 $getwplogarr = explode("\n", file_get_contents("$wvalue"));
579
+	                 $getlogdata1[] = array_reverse($getwplogarr);
580
+	             }
581
+	         }
582
+
583
+	         foreach ($wordpresslogsec as $wkeysec => $wvaluesec) {
584
+	             if (is_file($wvaluesec)) {
585
+	                 $getwplogarrsec = explode("\n", file_get_contents("$wvaluesec"));
586
+	                 $getlogdata1sec[] = array_reverse($getwplogarrsec);
587
+	             }
588
+	         }
589
+
590
+	     } else {
591
+
592
+	             if (is_file($jaillogarr[$getjail])) {
593
+	                 $getjaillogarr = explode("\n", file_get_contents($jaillogarr[$getjail]));
594
+	                 $getlogdata2 = array_reverse($getjaillogarr);
595
+	             }
596
+
597
+	             if (is_file($jaillogarrsec[$getjail])) {
598
+	                 $getjaillogarrsec = explode("\n", file_get_contents($jaillogarrsec[$getjail]));
599
+	                 $getlogdata2sec = array_reverse($getjaillogarrsec);
600
+	             }
601
+	     }
602
+
603
+
604
+	     if (is_array($value2)) {
605
+	         foreach ($value2 as $key3 => $value3) {
606
+	             $getip = $value3;
607
+	             $ipsforjail[] = $value3;
608
+
609
+	             /**
610
+	              * Check if the current IP associated to the current jail is already in the database and get the first ban date, the last ban date and the total
611
+	              * number of bans for this IP from the database
612
+	              */
613
+	             $queryipj = $mysqli->prepare("SELECT id, IP, jail, first_ban, last_ban FROM bannedipstable WHERE IP = ? AND jail = ?");
614
+                     $queryipj->bind_param("ss", $getip, $getjail);
615
+                     $queryipj->execute();
616
+                     $fetchipj = $queryipj->get_result();
617
+                     $fetchipjres = $fetchipj->fetch_row();
618
+                     $queryipj->close();
619
+                     if ($fetchipjres) {
620
+	                 $ipisindatabase = $fetchipjres[0];
621
+	                 $firstbandate = $fetchipjres[3];
622
+	                 $lastbandate = $fetchipjres[4];
623
+                     } else {
624
+	                 $ipisindatabase = '';
625
+	                 $firstbandate = '';
626
+	                 $lastbandate = '';
627
+                     }
628
+
629
+	             // Get the last ban date from '/var/log/fail2ban.log' or '/var/log/fail2ban.log.1', for the current IP
630
+	             $date_last_b = '';
631
+	             foreach ($log1data as $key => $value) {
632
+	                 if (str_contains($value, "[". $getjail ."] Ban ". $getip) && (str_ends_with($value, $getip))) {
633
+	                     $lastbanline = $value;
634
+	                     $banlinesplit = explode(",", $lastbanline);
635
+	                     $date_last_b = $banlinesplit[0];
636
+	                     break 1;
637
+	                 }
638
+	             }
639
+
640
+	             if ($date_last_b == '') {
641
+	                foreach ($log2data as $key2 => $value2) {
642
+	                   if (str_contains($value2, "[". $getjail ."] Ban ". $getip) && (str_ends_with($value2, $getip))) {
643
+	                       $lastbanline2 = $value2;
644
+	                       $banlinesplit2 = explode(",", $lastbanline2);
645
+	                       $date_last_b = $banlinesplit2[0];
646
+	                       break 1;
647
+	                   }
648
+	                }
649
+	             }
650
+
651
+	             if (($date_last_b == '') && ($lastbandate != '')) {
652
+	                  $date_last_b = $lastbandate;
653
+	             }
654
+
655
+	             if (($date_last_b == '') && ($lastbandate == '')) {
656
+	                  $date_last_b = $date1;
657
+	             }
658
+
659
+	             if ($firstbandate == '') {
660
+	                 $first_ban_proc = $date_last_b;
661
+	             } else { $first_ban_proc = $firstbandate; }
662
+
663
+	             // Calculate the timespan (in seconds) between the last ban date found in logs and the current date
664
+	             $datedifference2 = strtotime($date1) - strtotime($date_last_b);
665
+	             $logspantime = intval($datedifference2);
666
+
667
+	             $ipstimespans[] = $logspantime;
668
+
669
+	             // If the IP is not in the database, insert it with all the necessary details
670
+	             if ($ipisindatabase == '') {
671
+                         $crid = 1;
672
+	                 $queryinsip = $mysqli->prepare("INSERT INTO bannedipstable (IP, jail, first_ban, last_ban, ban_number) VALUES (?, ?, ?, ?, ?);");
673
+	                 $queryinsip->bind_param("ssssi", $getip, $getjail, $date_last_b, $date_last_b, $crid);
674
+	                 $queryinsip->execute();
675
+	                 $queryinsip->close();
676
+
677
+	             /**
678
+	              *  If the IP is already in the database, update its record with the number of bans and the last ban date, but only if the current IP has been
679
+	              *  banned in the last run interval and only if the timespan between the last Fail2ban restart and the current time is greater than the current
680
+	              *  jail ban time. Otherwise, the IPs record shouldn't be updated because it means that either the current IP has been banned before the last
681
+	              *  script run, so, the ban has been already processed and the IP's record has been already updated, or that the IP is currently banned only
682
+	              *  because Fail2ban has been restarted in the recent past, since by default Fail2ban bans again all the IPs that were banned at the time of restart.
683
+	              */
684
+	             } elseif (($ipisindatabase != '') && ($logspantime <= $runinterval) && ($logspantime != 0) && ($restartcheck == 0) && ($date_last_b != $firstbandate)) {
685
+
686
+	                        $upbandt = $mysqli->prepare("UPDATE bannedipstable SET ban_number = ban_number + 1, last_ban = ? WHERE IP = ? AND jail = ?");
687
+                                $upbandt->bind_param("sss", $date_last_b, $getip, $getjail);
688
+                                $upbandt->execute();
689
+                                $upbandt->close();
690
+	             }
691
+
692
+	             // Get the total number of bans, the first ban date and the last ban date for the current IP, as they are after updating the database
693
+	             $getbnbfl = $mysqli->prepare("SELECT IP, jail, first_ban, last_ban, ban_number FROM bannedipstable WHERE IP = ? AND jail = ?");
694
+                     $getbnbfl->bind_param("ss", $getip, $getjail);
695
+                     $getbnbfl->execute();
696
+                     $fetchbnfl = $getbnbfl->get_result();
697
+                     $resfetchbnfl = $fetchbnfl->fetch_row();
698
+	             $firstbandatesec = $resfetchbnfl[2];
699
+	             $lastbandatesec = $resfetchbnfl[3];
700
+	             $totalbanspr = $resfetchbnfl[4];
701
+                     $getbnbfl->close();
702
+
703
+	             // Calculate the timespan (in days) between the first ban date and the last ban date as found in the database, for the current IP
704
+	             $first_ban_date = new DateTime($firstbandatesec);
705
+	             $last_ban_date = new DateTime($lastbandatesec);
706
+	             $datediff = $last_ban_date->getTimestamp() - $first_ban_date->getTimestamp();
707
+	             $timespanall = round($datediff / (60 * 60 * 24));
708
+
709
+
710
+	             // Write the paragraph with information about the current IP, if it has been banned more than once
711
+	             if ($totalbanspr > 1) {
712
+
713
+	                $loglinearrcount = 0;
714
+
715
+	                /**
716
+	                 * Get the last 20 log lines containing the failed log in attempts of the current IP from all the WordPress, Nextcloud, ProFTPD, Asterisk,
717
+	                 * Bind or OpenVPN logs
718
+	                 */
719
+	                if ($getjail == 'wordpress' || $getjail == 'nextcloud' || $getjail == 'proftdp' || $getjail == 'asterisk' || $getjail == 'named-refused' || $getjail == 'openvpn') {
720
+
721
+	                   /**
722
+	                    * Set the regex expressions that will allow correct identification of failed log in attepts against WordPress, Nextcloud, ProFTPD,
723
+	                    * Asterisk, Bind and OpenVPN
724
+	                    */
725
+	                   if ($getjail == 'wordpress') {
726
+	                       $regpattern = '/^(?=.*?\b'.$getip.'\b)(?=.*?\b(POST)\b).*$/';
727
+	                   } elseif ($getjail == 'nextcloud') {
728
+	                       $regpattern = '/^(?=.*?\b'.$getip.'\b)(?=.*?\b(Login failed)\b).*$/';
729
+	                   } elseif ($getjail == 'proftdp') {
730
+	                       $regpattern = '/^(?=.*?\b'.$getip.'\b)(?=.*?\b(no such user found|Login failed|SECURITY VIOLATION|Maximum login attempts)\b).*$/';
731
+	                   } elseif ($getjail == 'asterisk') {
732
+	                       $regpattern = '/^(?=.*?\b'.$getip.'\b)(?=.*?\b(failed for|PJSIP syntax error)\b).*$/';
733
+	                   } elseif ($getjail == 'named-refused') {
734
+	                       $regpattern = '/^(?=.*?\b'.$getip.'\b)(?=.*?\b(denied)\b).*$/';
735
+	                   } elseif ($getjail == 'openvpn') {
736
+	                       $regpattern = '/^(?=.*?\b'.$getip.'\b)(?=.*?\b(Connection reset, restarting|TLS Error: TLS handshake failed|Fatal TLS error|VERIFY ERROR|WARNING: Bad encapsulated packet length)\b).*$/';
737
+	                   }
738
+
739
+	                   if ($getjail == 'wordpress') {
740
+
741
+	                       $loglinearr1 = [];
742
+	                       $reslinesarr = [];
743
+	                       foreach ($getlogdata1 as $getwkey => $getwvalue) {
744
+	                           if (is_array($getwvalue)) {
745
+	                              foreach ($getwvalue as $lkey1 => $lvalue1) {
746
+	                                  preg_match_all($regpattern, $lvalue1, $reslinesarr);
747
+	                                  if (isset($reslinesarr[0][0]) && $reslinesarr[0][0] != '') {
748
+	                                      $loglinearr1[] = $reslinesarr[0][0];
749
+	                                  }
750
+	                              }
751
+	                           }
752
+	                       }
753
+
754
+	                   } elseif ($getjail == 'nextcloud' || $getjail == 'proftdp' || $getjail == 'asterisk' || $getjail == 'named-refused' || $getjail == 'openvpn') {
755
+	                             $loglinearr1 = [];
756
+	                             $reslinesarr = [];
757
+	                             foreach ($getlogdata2 as $lkey2 => $lvalue2) {
758
+	                                  preg_match_all($regpattern, $lvalue2, $reslinesarr);
759
+	                                  if (isset($reslinesarr[0][0]) && $reslinesarr[0][0] != '') {
760
+	                                      $loglinearr1[] = $reslinesarr[0][0];
761
+	                                  }
762
+	                             }
763
+	                   }
764
+
765
+
766
+	                   // If at least 20 log entries were found for the current IP, collect the last 20 log entries and don't search in the rotated log file
767
+	                   if (count($loglinearr1) > 19) {
768
+	                          $loglinearrauxinit = array_slice($loglinearr1, 0, 20);
769
+	                          $loglinearraux = array_reverse($loglinearrauxinit);
770
+	                          $loglinearrfin = implode("<br></b>", $loglinearraux);
771
+                                  $loglinearrfinpt = implode("\n ", $loglinearraux);
772
+
773
+	                   // If less than 20 log entries were found in the current log file, search for the current IP in the rotated log file
774
+	                   } else {
775
+	                           if ($getjail == 'wordpress') {
776
+	                               $resloglsec = [];
777
+	                               foreach ($getlogdata1sec as $getwkeysec => $getwvaluesec) {
778
+	                                  if (is_array($getwvaluesec)) {
779
+	                                     foreach ($getwvaluesec as $lkey1sec => $lvalue1sec) {
780
+	                                        preg_match_all($regpattern, $lvalue1sec, $resloglsec);
781
+	                                        if (isset($resloglsec[0][0]) && $resloglsec[0][0] != '') {
782
+	                                            $loglinearr1[] = $resloglsec[0][0];
783
+	                                        }
784
+	                                     }
785
+	                                  }
786
+	                               }
787
+	                           } elseif ($getjail == 'nextcloud' || $getjail == 'proftdp' || $getjail == 'asterisk' || $getjail == 'named-refused' || $getjail == 'openvpn') {
788
+	                                  $resloglsec = [];
789
+	                                  foreach ($getlogdata2sec as $getwkeysec => $getwvaluesec) {
790
+	                                         preg_match_all($regpattern, $getwvaluesec, $resloglsec);
791
+	                                         if (isset($resloglsec[0][0]) && $resloglsec[0][0] != '') {
792
+	                                             $loglinearr1[] = $resloglsec[0][0];
793
+	                                         }
794
+	                                  }
795
+	                           }
796
+
797
+	                          // Collect only the last 20 entries if there are more
798
+	                          if (count($loglinearr1) > 19) {
799
+	                              $loglinearrauxinit = array_slice($loglinearr1, 0, 20);
800
+	                              $loglinearraux = array_reverse($loglinearrauxinit);
801
+	                              $loglinearrfin = implode("<br></b>", $loglinearraux);
802
+                                      $loglinearrfinpt = implode("\n ", $loglinearraux);
803
+	                          } else {
804
+	                              $loglinearrsec = array_reverse($loglinearr1);
805
+	                              $loglinearrfin = implode("<br></b>", $loglinearrsec);
806
+                                      $loglinearrfinpt = implode("\n ", $loglinearrsec);
807
+	                          }
808
+	                   }
809
+	                   $loglinearrcount = count($loglinearr1);
810
+
811
+
812
+	                // If the current jail is different from 'wordpress', 'nextcloud', 'proftpd', 'asterisk', 'named-refused' or 'openvpn', get the last 20 log entries containing the current IP
813
+	                } else {
814
+	                      $loglinearr2 = [];
815
+	                      foreach ($getlogdata2 as $lkey2 => $lvalue2) {
816
+	                          if (strpos($lvalue2, $getip) !== false) {
817
+	                              $loglinearr2[] = $lvalue2;
818
+	                          }
819
+	                      }
820
+
821
+	                      if (count($loglinearr2) > 19) {
822
+	                          $loglinearruninit = array_slice($loglinearr2, 0, 20);
823
+	                          $loglinearrun = array_reverse($loglinearruninit);
824
+	                          $loglinearrfin = implode("<br></b>", $loglinearrun);
825
+                                  $loglinearrfinpt = implode("\n ", $loglinearrun);
826
+
827
+	                      // If less than 20 log entries were found in the current log file, search for the current IP in the rotated log file
828
+	                      } else {
829
+	                             foreach ($getlogdata2sec as $lkey2sec => $lvalue2sec) {
830
+	                                  if (strpos($lvalue2sec, $getip) !== false) {
831
+	                                      $loglinearr2[] = $lvalue2sec;
832
+	                                  }
833
+	                             }
834
+	                             // Collect only the last 20 entries and remove the rest if there are more
835
+	                             if (count($loglinearr2) > 19) {
836
+	                                 $loglinearrun = array_slice($loglinearr2, 0, 20);
837
+	                                 $loglinearrot = array_reverse($loglinearrun);
838
+	                                 $loglinearrfin = implode("<br></b>", $loglinearrot);
839
+                                         $loglinearrfinpt = implode("\n ", $loglinearrot);
840
+	                             } else {
841
+	                                 $loglinearruts = array_reverse($loglinearr2);
842
+	                                 $loglinearrfin = implode("<br></b>", $loglinearruts);
843
+                                         $loglinearrfinpt = implode("\n ", $loglinearruts);
844
+	                             }
845
+	                      }
846
+	                      $loglinearrcount = count($loglinearr2);
847
+	                }
848
+
849
+	                // Get the 'whois' data for the current IP
850
+	                $whoisinfo = shell_exec("whois " . $getip);
851
+	                $whoisexpl = preg_split('/\r\n|\r|\n/', $whoisinfo);
852
+
853
+	                // Extract all the email addresses from the 'whois' data
854
+	                $whoisimplinit = implode(" ", $whoisexpl);
855
+
856
+			$emregpattern = "/[\._a-zA-Z0-9-]+@[\._a-zA-Z0-9-]+/i";
857
+			preg_match_all($emregpattern, $whoisinfo, $ematches);
858
+
859
+	                $allemailsarr = [];
860
+			foreach ($ematches[0] as $thisemail) {
861
+				 $allemailsarr[] = $thisemail;
862
+			}
863
+
864
+	                $finemailarray = array_unique($allemailsarr);
865
+	                $finemails = array_values($finemailarray);
866
+
867
+	                $whoisimpl = implode("<br></b>", $whoisexpl);
868
+
869
+	                // Search for the 'abuse' email address in the 'whois' data
870
+	                $foundabusemail = '';
871
+
872
+	                foreach ($whoisexpl as $whkey => $whvalue) {
873
+	                    if (($foundabusemail == '') && (strpos($whvalue, 'Abuse contact for') !== false)) {
874
+
875
+	                        $wfirstextr = strstr($whvalue, 'Abuse contact for');
876
+	                        $wlinesplit = explode("'", $wfirstextr);
877
+	                        $whotrimmed = array_filter(array_map('trim', $wlinesplit));
878
+	                        $whoreverse = array_reverse($whotrimmed);
879
+	                        if ($whoreverse[0] != 'abuse@ripe.net' && $whoreverse[0] != 'no-email@apnic.net') {
880
+	                            $foundabusemail = $whoreverse[0];
881
+	                        }
882
+	                        break;
883
+	                    }
884
+	                }
885
+
886
+	                if (($foundabusemail == '') && (strpos($whoisinfo, 'abuse-mailbox') !== false)) {
887
+
888
+	                    $wfirstextr = strstr($whoisinfo, 'abuse-mailbox');
889
+	                    $wextsplit = preg_split('/\r\n|\r|\n/', $wfirstextr);
890
+	                    $wlinesplit = explode(' ', $wextsplit[0]);
891
+	                    $whotrimmed = array_filter(array_map('trim', $wlinesplit));
892
+	                    $whoreverse = array_reverse($whotrimmed);
893
+	                    if ($whoreverse[0] != 'abuse@ripe.net' && $whoreverse[0] != 'no-email@apnic.net') {
894
+	                        $foundabusemail = $whoreverse[0];
895
+	                    }
896
+	                }
897
+
898
+	                if (($foundabusemail == '') && (strpos($whoisinfo, 'OrgAbuseEmail') !== false)) {
899
+
900
+	                    $wfirstextr = strstr($whoisinfo, 'OrgAbuseEmail');
901
+	                    $wextsplit = preg_split('/\r\n|\r|\n/', $wfirstextr);
902
+	                    $wlinesplit = explode(' ', $wextsplit[0]);
903
+	                    $whotrimmed = array_filter(array_map('trim', $wlinesplit));
904
+	                    $whoreverse = array_reverse($whotrimmed);
905
+	                    if ($whoreverse[0] != 'abuse@ripe.net' && $whoreverse[0] != 'no-email@apnic.net') {
906
+	                        $foundabusemail = $whoreverse[0];
907
+	                    }
908
+	                }
909
+
910
+	                if ($foundabusemail == '') {
911
+	                    foreach ($finemails as $finkey => $finvalue) {
912
+	                         if (strpos($finvalue, "abuse@") !== false && $finvalue != "abuse@ripe.net" && $finvalue != "no-email@apnic.net") {
913
+	                             $foundabusemail = $finvalue;
914
+	                             break 1;
915
+	                         }
916
+	                    }
917
+	                }
918
+
919
+	                // If no log entries were found for the current IP, include an explanation in the email
920
+	                if ($loglinearrcount != 0) {
921
+	                    $foundlglnchck = null;
922
+	                } else {
923
+	                    $logdirectoryinit = explode("/", $jaillogarr[$getjail]);
924
+	                    array_pop($logdirectoryinit);
925
+	                    $logdirectory = implode("/", $logdirectoryinit);
926
+
927
+	                    $foundlglnchck = "(No log entries were included in the draft email because no entries could be found for this IP
928
+	                                      in the current log and in the most recent rotated log file. If you want to send an abuse report for
929
+	                                      this IP, you will have to search for these log entries manually in the archived log files located
930
+	                                      in '" . $logdirectory . "'.)";
931
+	                }
932
+
933
+	                /**
934
+	                 * Get the ban moment that will be displayed in the draft abuse report email. It's better to take this timestamp from the last
935
+	                 * found log line containing the current IP, which will also be listed at the end of the email.
936
+	                 */
937
+	                $gmtindinit = "UTC " . shell_exec('date +\'%:z\''); // UTC time offset
938
+                        $gmtind = str_replace("\n", "", $gmtindinit);
939
+
940
+	                // Extract the timestamp differently, according to the log format
941
+	                if ($loglinearrcount != 0) {
942
+
943
+	                    if ($getjail == 'postfix' || $getjail == 'postfix-sasl' || $getjail == 'sshd') {
944
+	                        $exploglinesinit = explode("<br></b>", $loglinearrfin);
945
+	                        $exploglines = array_reverse($exploglinesinit);
946
+	                        $firstlinelg = $exploglines[0];
947
+	                        $getdatexpinit = explode(".", $firstlinelg);
948
+	                        $getdatefrlinit = array_filter(array_map('trim', $getdatexpinit));
949
+	                        $getdatefrl = array_values($getdatefrlinit);
950
+	                        $getdatexp = explode("T", $getdatefrl[0]);
951
+	                        $lastbandateproc = $getdatexp[0] . ", " . $getdatexp[1] . ", " . $gmtind;
952
+	                    } elseif ($getjail == 'dovecot') {
953
+	                        $exploglinesinit = explode("<br></b>", $loglinearrfin);
954
+	                        $exploglines = array_reverse($exploglinesinit);
955
+	                        $firstlinelg = $exploglines[0];
956
+	                        $getdatexp = explode(" ", $firstlinelg);
957
+	                        $getdatefrlinit = array_filter(array_map('trim', $getdatexp));
958
+	                        $getdatefrl = array_values($getdatefrlinit);
959
+	                        $lastbandateproc = $getdatefrl[0] . ", " . $getdatefrl[1] . ", " . $gmtind;
960
+	                    } elseif ($getjail == 'named-refused') {
961
+	                        $exploglinesinit = explode("<br></b>", $loglinearrfin);
962
+	                        $exploglines = array_reverse($exploglinesinit);
963
+	                        $firstlinelg = $exploglines[0];
964
+	                        $getdatexp = explode(" ", $firstlinelg);
965
+	                        $getdatefrlinit = array_filter(array_map('trim', $getdatexp));
966
+	                        $getdatefrl = array_values($getdatefrlinit);
967
+	                        $lastbandateproc = $getdatefrl[0] . ", " . $getdatefrl[1] . ", " . $gmtind;
968
+	                    } elseif ($getjail == 'wordpress' || $getjail == 'mailman' || $getjail == 'dolibarr' || $getjail == 'phplist' ||
969
+	                              $getjail == 'phpmyadmin' || $getjail == 'looladmin' || $getjail == 'matomo') {
970
+	                        $exploglinesinit = explode("<br></b>", $loglinearrfin);
971
+	                        $exploglines = array_reverse($exploglinesinit);
972
+	                        $firstlinelg = $exploglines[0];
973
+	                        $getdatefrl = explode("[", $firstlinelg);
974
+	                        $getdatefrlsec = explode("]", $getdatefrl[1]);
975
+	                        $getdatefrlthird = explode(" ", $getdatefrlsec[0]);
976
+	                        $lastbandateproc = $getdatefrlthird[0] . ", " . $gmtind;
977
+	                    } elseif ($getjail == 'asterisk') {
978
+	                        $exploglinesinit = explode("<br></b>", $loglinearrfin);
979
+	                        $exploglines = array_reverse($exploglinesinit);
980
+	                        $firstlinelg = $exploglines[0];
981
+	                        $getdatefrl = explode("[", $firstlinelg);
982
+	                        $getdatefrlsec = explode("]", $getdatefrl[1]);
983
+	                        $lastbandateproc = $getdatefrlsec[0] . ", " . $gmtind;
984
+	                    } elseif ($getjail == 'roundcube') {
985
+	                        $exploglinesinit = explode("<br></b>", $loglinearrfin);
986
+	                        $exploglines = array_reverse($exploglinesinit);
987
+	                        $firstlinelg = $exploglines[0];
988
+	                        $getdatefrl = explode("[", $firstlinelg);
989
+	                        $getdatefrlsec = explode("]", $getdatefrl[1]);
990
+	                        $getdatefrlthird = explode(" ", $getdatefrlsec[0]);
991
+	                        $lastbandateproc = $getdatefrlthird[0] . ", " . $getdatefrlthird[1] . ", " . $gmtind;
992
+	                    } elseif ($getjail == 'nextcloud') {
993
+	                        $exploglinesinit = explode("<br></b>", $loglinearrfin);
994
+	                        $exploglines = array_reverse($exploglinesinit);
995
+	                        $firstlinelg = $exploglines[0];
996
+	                        $getdatefrl = explode("\"time\":", $firstlinelg);
997
+	                        $getdatefrlsec = explode("\"", $getdatefrl[1]);
998
+	                        $getdatefrlthird = explode("+", $getdatefrlsec[1]);
999
+	                        $getdatefrlfourth = explode("T", $getdatefrlthird[0]);
1000
+	                        $lastbandateproc = $getdatefrlfourth[0] . ", " . $getdatefrlfourth[1] . ", " . $gmtind;
1001
+	                    } elseif ($getjail == 'proftpd') {
1002
+	                        $exploglinesinit = explode("<br></b>", $loglinearrfin);
1003
+	                        $exploglines = array_reverse($exploglinesinit);
1004
+	                        $firstlinelg = $exploglines[0];
1005
+	                        $getdatefrl = explode(",", $firstlinelg);
1006
+	                        $getdatefrlsec = explode(" ", $getdatefrl[0]);
1007
+	                        $lastbandateproc = $getdatefrlsec[0] . ", " . $getdatefrlsec[1] . ", " . $gmtind;
1008
+	                    } elseif ($getjail == 'openvpn') {
1009
+	                        $exploglinesinit = explode("<br></b>", $loglinearrfin);
1010
+	                        $exploglines = array_reverse($exploglinesinit);
1011
+	                        $firstlinelg = $exploglines[0];
1012
+	                        $getdatefrl = explode(" us=", $firstlinelg);
1013
+	                        $getdatefrlsec = explode(" ", $getdatefrl[0]);
1014
+	                        $lastbandateproc = $getdatefrlsec[0] . ", " . $getdatefrlsec[1] . ", " . $gmtind;
1015
+	                    }
1016
+	                } else  $lastbandateproc = $lastbandatesec;
1017
+
1018
+	                // Add a warning about the possibility of disclosing sensitive information in the log lines included in the abuse report email
1019
+	                if ($loglinearrcount != 0) {
1020
+	                    $senswarn = "It's recommended to check if the log lines included in the draft email from below contain sensitive information, such as custom
1021
+	                                 WordPress login URLs, usernames used for HTTP authentication, etc. If such information exists, you can replace it with asterisks or
1022
+	                                 other placeholders before sending the email.";
1023
+	                } else { $senswarn = null; }
1024
+
1025
+	                // If the 'abuse' email address has been found in the 'whois' database, include a warning text in the email
1026
+	                if ($foundabusemail != '') {
1027
+	                    $foundornotinfo = "The 'abuse' email address for this IP has been found in the data output of the 'whois ip' command. It is:<br><br><b>" .
1028
+	                                       $foundabusemail . "</b><br><br>This address was found automatically and <b>may be incorrect</b>. You can verify it
1029
+	                                       against the 'whois' data from above before sending the abuse notification.<br>" . $foundlglnchck . "<br>" . $senswarn . "<br>";
1030
+
1031
+	                // If no 'abuse' email address has been found, include an explanation in the email
1032
+	                } else {
1033
+	                     $foundornotinfo = "System Health and Security Probe couldn't find the 'abuse' email address for this IP. You can look again at the
1034
+	                                        'whois' data for this IP from above, and try to identify the 'abuse' email address which may have a different
1035
+	                                        format than the standard 'abuse@...'. <br>" . $foundlglnchck . "<br>" . $senswarn . "<br>";
1036
+	                }
1037
+
1038
+	                // HTML version of the email that can be sent to the 'abuse' email address for the current IP
1039
+	                $abusereportemail = "<!DOCTYPE html>
1040
+					     <html>
1041
+					       <head>
1042
+					         <meta http-equiv='content-type' content='text/html; charset=UTF-8'>
1043
+					       </head>
1044
+					       <body text='#000000' bgcolor='#FFFFFF'>
1045
+					         <br>Hello,<br><br>
1046
+	                                         The machine with the IP  <b>" . $getip . "</b>  has attacked our server on the service " . $getjail . ", <br>
1047
+	                                         on port " . $jailsports[$getjail]  . ", on  " . $lastbandateproc . " . The IP was blocked automatically.<br><br>
1048
+
1049
+	                                         Please check the machine with the IP  <b>" . $getip . "</b>  to fix this problem.<br><br>
1050
+
1051
+	                                         Below you can find the log lines showing the failed log in attempts on our system.<br><br>
1052
+
1053
+	                                         Lines containing  <b>" . $getip . "</b>  :<br><br>"  . $loglinearrfin . "<br><br>
1054
+
1055
+	                                         You can contact us at " . $emailtofirst . "<br><br>
1056
+
1057
+	                                         Thank you,<br>
1058
+                                                 " . $sysadminname . "<br>
1059
+	                                         The System Administrator <br>
1060
+					       </body>
1061
+					     </html>";
1062
+
1063
+	                // Plain text version of the email that can be sent to the 'abuse' email address for the current IP
1064
+	                $abusereportemailpt = "\n Hello,\n\n The machine with the IP  " . $getip . "  has attacked our server on the service " . $getjail . ", \n on port " . $jailsports[$getjail]  . ", on " . $lastbandateproc . ". The IP was blocked automatically. \n\n Please check the machine with the IP  " . $getip . "  to fix this problem. \n\n Below you can find the log lines showing the failed log in attempts on our system. \n\n Lines containing  " . $getip . " : \n\n " . $loglinearrfinpt . " \n\n You can contact us at " . $emailtofirst . " \n\n Thank you, \n " . $sysadminname . " \n The System Administrator \n";
1065
+
1066
+	                // Write the paragraph containing the email that can be sent to the 'abuse' email address for the current IP
1067
+	                if ($getjail != 'wordpress') {
1068
+	                    if ($getjail != 'named-refused') {
1069
+	                        $jaillognamefirst = $jaillogarr[$getjail];
1070
+	                        $jaillognamesec = $jaillognamefirst . ".1";
1071
+	                    } else {
1072
+	                        $jaillognamefirst = $jaillogarr['named-refused'];
1073
+	                        $jaillognamesec = $jaillognamefirst . ".0";
1074
+	                    }
1075
+	                } else {
1076
+	                    $jaillognamefirst = $jaillogarr['wordpress'][0];
1077
+	                    $jaillognamesec = $jaillogarr['wordpress'][1];
1078
+	                }
1079
+
1080
+	                if ($loglinearrcount != 0) {
1081
+			          $variantabmail = "</b><br>
1082
+			                            If you haven't enabled automatic sending of abuse reports, you can send manually an abuse report to the entity that owns
1083
+			                            this offending IP. Below is a draft of the abuse report that you can send for this IP. " . $foundornotinfo . "</b><br>
1084
+
1085
+			                            <p style='border:2px; border-style:solid; border-color:#19aa64; padding: 1em; word-wrap: break-word;'> " . $abusereportemail . "</p></b><br>";
1086
+	                } else {
1087
+	                         $variantabmail = "Unfortunately, the repeated attacks of " . $getip . " couldn't be found in the most recent log files: '" . $jaillognamefirst . "'
1088
+	                                           and '" . $jaillognamesec . "'. It seems that these attacks took place some time ago and the log files in which they were
1089
+	                                           recorded have been already archived.<br><br>";
1090
+	                }
1091
+
1092
+	                // Write the 'information about IP' paragraph
1093
+	                $finwhoisdata[] = "<b><h3>Information about  " . $getip . "</h3></b><b><br><br>" . $getip . " has been banned by Fail2ban " . $totalbanspr .
1094
+	                                  " times in the timespan of " . $timespanall . " days (between " . $firstbandatesec . " and " . $lastbandatesec . ")
1095
+	                                  due to repeated failed log in attempts against '" . $getjail . "'. As a rule, these attempts can be found in '" . $jaillognamefirst . "' or
1096
+	                                  in '" . $jaillognamesec . "'.<br><br>'Whois' data for " . $getip . " :</b><br><br>
1097
+	                                  <p style='border:2px; border-style:solid; border-color:#0393bf; padding: 1em; word-wrap: break-word;'>" . $whoisimpl . "</p><br><br>" . $variantabmail;
1098
+
1099
+	                // If the settings in the 'config' file require it, send the abuse report email to the ISP of the current offending IP
1100
+	                $automaticemailproc = strtolower($automaticemail);
1101
+	                $excludedipsarr = explode(",", $excludedips);
1102
+
1103
+	                if ($automaticemailproc == 'yes' && $foundabusemail != '' && $loglinearrcount != 0) {
1104
+	                    if (($ipisindatabase != '') && ($logspantime <= $runinterval) && ($restartcheck == 0)) {
1105
+	                         if (!in_array($jaillogarr[$getjail], $excludedjails)) {
1106
+	                             if (!in_array($getip, $excludedipsarr)) {
1107
+
1108
+                                         if ($abusereportstoadmin == "yes") {
1109
+                                             $toisp = $foundabusemail . "," . implode(",", $emailtoarr);
1110
+                                         } else { $toisp = $foundabusemail; }
1111
+
1112
+	                                 $subjectisp = 'Abuse Report';
1113
+
1114
+				         // Create a unique alphanumeric string to use as a boundary
1115
+					 $msgboundary = bin2hex(openssl_random_pseudo_bytes(16));
1116
+
1117
+					 // Add the headers
1118
+					 $headersisp = "MIME-Version: 1.0" . "\r\n";
1119
+					 $headersisp .= "From: " . $emailsender . "\r\n";
1120
+					 $headersisp .= "To: " . $toisp . "\r\n";
1121
+					 $headersisp .= "Content-Type: multipart/alternative;boundary=" . $msgboundary . "\r\n";
1122
+
1123
+                                         $messageisp = "This is a MIME encoded message." . "\r\n\r\n";
1124
+                                         $messageisp .= "--". $msgboundary ."\r\n";
1125
+                                         $messageisp .= "Content-type: text/plain;charset=utf-8" . "\r\n";
1126
+					 $messageisp .= "Content-Transfer-Encoding: 7bit" . "\r\n\r\n";
1127
+                                         // Plain text message body
1128
+					 $messageisp .= $abusereportemailpt . "\r\n\r\n";
1129
+					 $messageisp .= "--". $msgboundary ."\r\n";
1130
+
1131
+					 $messageisp .= "Content-Type: text/html;charset=UTF-8" . "\r\n";
1132
+					 $messageisp .= "Content-Transfer-Encoding: 7bit" . "\r\n\r\n";
1133
+                                         // HTML message body
1134
+					 $messageisp .= $abusereportemail . "\r\n\r\n";
1135
+					 $messageisp .= "--". $msgboundary ."--";
1136
+
1137
+					 // Send the abuse report email
1138
+					 mail('', $subjectisp, $messageisp, $headersisp, "-f " . $emailsender . "");
1139
+
1140
+	                                 $abreportsentcheck = 1;
1141
+
1142
+	                                 // Increment the number of sent abuse report emails for the current IP, in the 'bannedipstable'
1143
+	                                 $updateabno = $mysqli->prepare("UPDATE bannedipstable SET emails_isp = emails_isp + 1 WHERE IP = ? AND jail = ?");
1144
+                                         $updateabno->bind_param("ss",$getip, $getjail);
1145
+                                         $updateabno->execute();
1146
+                                         $updateabno->close();
1147
+	                             }
1148
+	                         }
1149
+	                    }
1150
+	                }
1151
+	             }
1152
+
1153
+	             // Color the total number of bans for the current IP in red if it exceeds 1
1154
+	             if ($totalbanspr == 1) {
1155
+	                 $totalbanscolored = "<td align='center' style='color:#000000;'><b>1</b></td>";
1156
+	             } else $totalbanscolored = "<td align='center'><b><font style='color:#ff0000;'>" . $totalbanspr . "</font></b></td>";
1157
+
1158
+	             // Get from the database the number of abuse report emails that were sent to the ISP of the current IP
1159
+		     $getispemailsno = $mysqli->prepare("SELECT IP, jail, emails_isp FROM bannedipstable WHERE IP = ? AND jail = ?");
1160
+                     $getispemailsno->bind_param("ss", $getip, $getjail);
1161
+                     $getispemailsno->execute();
1162
+                     $resgetispml = $getispemailsno->get_result();
1163
+                     $fetchresispml = $resgetispml->fetch_row();
1164
+		     $totalispemails = $fetchresispml[2];
1165
+                     $getispemailsno->close();
1166
+
1167
+	             // Add a row corresponding to the current IP and jail, to the blocked IPs table
1168
+	             $blockedipsrows[] = "<tr>
1169
+	                                  <td>" . $j . "</td>
1170
+	                                  <td style='padding-left: 7px;'>" . $getip . "</td>
1171
+	                                  <td style='padding-left: 4px;'>" . $getjail . "</td>
1172
+	                                  <td style='padding-left: 4px;'>" . $first_ban_proc . "</td>
1173
+	                                  <td style='padding-left: 4px;'>" . $lastbandatesec . "</td>
1174
+	                                  <td align='center'>" . $timespanall . "</td>" . $totalbanscolored . "<td align='center'>" . $totalispemails . "</td>
1175
+	                                  </tr>";
1176
+	             $j++;
1177
+	         }
1178
+	         unset($jailbantime, $totalbanscolored, $loglinearrfin, $loglinearrfinpt);
1179
+	     }
1180
+
1181
+	     // Get from the database all the banned IPs for the current jail that were banned when the script ran last time
1182
+	     $getbrl = $mysqli->prepare("SELECT id, jail, bannedips FROM jailsandips WHERE jail = ?");
1183
+             $getbrl->bind_param("s", $getjail);
1184
+             $getbrl->execute();
1185
+             $resgetbrl = $getbrl->get_result();
1186
+             $fetchgetbrl = $resgetbrl->fetch_row();
1187
+	     $lastsentipsperjail = $fetchgetbrl[2];
1188
+	     $lastsentipsarr = explode("|", $lastsentipsperjail);
1189
+             $getbrl->close();
1190
+
1191
+	     /**
1192
+	      * Compare the IPs that were banned last time the script ran with the IPs that are banned now. If the IPs banned now are among those banned last
1193
+	      * time, then the check counter will remain as it is, otherwise the counter will be increased to signal that new IPs were banned since the last
1194
+	      * script run
1195
+	      */
1196
+	     if ($lastsentipsperjail != '') {
1197
+	         $arrintersect = array_intersect($lastsentipsarr, $ipsforjail);
1198
+	         $countarrintersect = count($arrintersect);
1199
+	         $countipsforjail = count($ipsforjail);
1200
+
1201
+	         if ($countarrintersect != $countipsforjail) {
1202
+	             $banipschck++;
1203
+	         }
1204
+
1205
+	     } else { $banipschck++; }
1206
+
1207
+	     // Insert into the 'jailsandips' table all the banned IPs for the current jail
1208
+	     $ipsforjailimpl = implode("|", $ipsforjail);
1209
+
1210
+             if ($fetchgetbrl) {
1211
+
1212
+	         $upbanips = $mysqli->prepare("UPDATE jailsandips SET bannedips = ? WHERE jail = ?");
1213
+                 $upbanips->bind_param("ss", $ipsforjailimpl, $getjail);
1214
+                 $upbanips->execute();
1215
+                 $upbanips->close();
1216
+
1217
+	     } else {
1218
+
1219
+	         $insbanips = "INSERT INTO jailsandips (jail, bannedips) VALUES (?, ?);";
1220
+	         $insbanips->bind_param("ss", $getjail, $ipsforjailimpl);
1221
+                 $insbanips->execute();
1222
+                 $insbanips->close();
1223
+	     }
1224
+	  }
1225
+      }
1226
+   }
1227
+
1228
+   // List the whois data for the IPs that were banned more than once, in the appropriate paragraph of the email
1229
+   if (count($finwhoisdata) != 0) {
1230
+       $whoisdataforips = implode("<br><br>", $finwhoisdata);
1231
+
1232
+       $ipsbmrthrtms = "<br><br><b><h2>Information about the IPs that were banned more than once</h2></b><br>
1233
+	                If you consider sending abuse reports to the organizations that own the IPs that are currently banned and were also banned
1234
+	                at least once in the past, you can find draft emails under the 'whois' information for each IP, below:<br><br>" . $whoisdataforips;
1235
+
1236
+  } else { $ipsbmrthrtms = null; }
1237
+
1238
+  // Create the blocked IPs paragraph of the email
1239
+  $blockedipstable = implode("", $blockedipsrows);
1240
+  $getblockedips = "<ul><li style='color:#225aad;font-weight:700;'>The following IP addresses <u>are currently banned</u> by Fail2ban due to repeated failed log in
1241
+	            attempts against the services displayed in the 'Jail' column:</li><br><br>
1242
+	            <table bgcolor='#f1f9ff' border='1' style='border-collapse:collapse;' width='100%' cellpadding='2'>
1243
+	            <tr>
1244
+	            <th style='text-align:center;'>No.</th>
1245
+	            <th style='text-align:center;'>IP</th>
1246
+	            <th style='text-align:center;'>Jail</th>
1247
+	            <th style='text-align:center;'>First<br>Ban Date</th>
1248
+	            <th style='text-align:center;'>Last<br>Ban Date</th>
1249
+	            <th style='text-align:center;'>Days<br>between<br>first and<br>last ban</th>
1250
+	            <th style='text-align:center;'>Total Number<br>of Bans</th>
1251
+	            <th style='text-align:center;'>Total Number<br>of Emails<br>Automatically<br>Sent to ISP</th>
1252
+	            </tr>" . $blockedipstable . "</table>" . $ipsbmrthrtms . "</ul>";
1253
+
1254
+ } else { $getblockedips = null; }
1255
+
1256
+
1257
+ // Get the total free storage space (in kibibytes) and if it is below the threshold specified in the 'config' file (in kibibytes), include a warning in the email
1258
+ $freedisk = exec("df -x tmpfs --total | awk '{print $4}' | tail -1");
1259
+ $totalspace = exec("df -x tmpfs --total | awk '{print $2}' | tail -1");
1260
+ $freediskgb = round($freedisk / 1048576);
1261
+ $totaldiskgb = round($totalspace / 1048576);
1262
+
1263
+ if ($freedisk <= $diskthreshold){
1264
+     $diskwarn = "<ul><li style='color:#225aad;font-weight:700;'>The total free storage space on all partitions of your system is
1265
+	          (approximately): " . $freediskgb . " gibibytes from a total of " . $totaldiskgb . " gibibytes.</li> You may consider
1266
+	          removing unnecessary files and directories, optimizing data storage processes, upgrading your server's storage or upgrading your server.</ul><br><br>";
1267
+ } else { $diskwarn = null; }
1268
+
1269
+ // Include an info line about the free storage space in the email
1270
+ $infodisk = "• The total free storage space on all partitions of your system is (approximately): " . $freediskgb . " gibibytes from a total
1271
+	      of " . $totaldiskgb . " gibibytes.</b>";
1272
+
1273
+ // Get the system uptime and the average CPU load in the last 15 minutes
1274
+ $uptimeinit = exec("uptime | awk '{print $3,$4}'");
1275
+ $uptimesplit = explode(" ", $uptimeinit);
1276
+
1277
+ if ($uptimesplit[1] == 'days,') {
1278
+     $uptimefin = $uptimesplit[0] . " days.";
1279
+ } elseif ($uptimesplit[1] == 'min,') {
1280
+	   $uptimefin = $uptimesplit[0] . " min.";
1281
+ } elseif ($uptimesplit[1] == 'day,') {
1282
+	   $uptimefin = $uptimesplit[0] . " day.";
1283
+ } elseif (strpos($uptimeinit, ':') !== false) {
1284
+	          $uptimesec = explode(":", $uptimesplit[0]);
1285
+	          $uptimefin = $uptimesec[0] . " hours.";
1286
+ }
1287
+
1288
+ $updaystext = "• The system has been up for " . $uptimefin;
1289
+ $averageload = exec("awk '{print $3}'< /proc/loadavg");
1290
+ $cpunumber = exec("cat /proc/cpuinfo | awk '/^processor/{print $3}' | wc -l");
1291
+
1292
+ /**
1293
+  *  If the average CPU load in the last 15 minutes is greater than 1 x (the number of CPU's), or if there are any other problems detected,
1294
+  *  list the average load in a paragraph of the email
1295
+  */
1296
+ $sortedbanspans = sort($ipstimespans);
1297
+
1298
+ if ($averageload > $cpunumber) {
1299
+     $averageloadwarn = "<ul><li style='color:#225aad;font-weight:700;'>• The average CPU load in the last 15 minutes is: " . $averageload . "  (The average
1300
+	                 CPU load is considered high if it stays constantly over " . $cpunumber . " )</li></ul>";
1301
+   } else { $averageloadwarn = null; }
1302
+
1303
+ // Include an info line about the average CPU load in the last 15 minutes in the 'General System Information' paragraph of the email
1304
+ $averageloadgen = "• The average CPU load in the last 15 minutes is: " . $averageload . "  (The average CPU load is considered high only if it stays
1305
+	            constantly over " . $cpunumber . ")";
1306
+
1307
+ // Get the base64 encoded logo
1308
+ $base64Logo = file_get_contents(dirname(__FILE__) . "/img/base64LogoImg.txt");
1309
+
1310
+ // Create a boundary string for the email report
1311
+ $separator = bin2hex(openssl_random_pseudo_bytes(16));
1312
+
1313
+ // Set the email headers
1314
+ $headers = "MIME-Version: 1.0" . "\r\n";
1315
+ $headers .= "From: " . $emailsender . "\r\n";
1316
+ $headers .= "Return-Path: " . $emailsender . "\r\n";
1317
+ $headers .= "Reply-To: " . $emailsender . "\r\n";
1318
+
1319
+ $headers .= "Content-Type: multipart/related;" . "\r\n";
1320
+ $headers .= " boundary=------------". $separator . "\r\n";
1321
+ $headers .= "--------------". $separator . "\r\n";
1322
+ $headers .= "Content-Type: text/html; charset=UTF-8" . "\r\n";
1323
+ $headers .= "Content-Transfer-Encoding: 7bit" . "\r\n";
1324
+
1325
+ // Write the email to report the problems found
1326
+ $message = "
1327
+ <!DOCTYPE html>
1328
+ <html>
1329
+ <head>
1330
+ <title>System Health and Security Report</title>
1331
+ </head>
1332
+ <body bgcolor='#f1f9ff'>
1333
+ <div style='background-color:#f1f9ff;padding:4px 8px;'>
1334
+ <div style='display: block; margin: 6px auto; width: 229px; height: 170px;'><img src='cid:logo-". $separator ."'></div>
1335
+ <p>Hello,</p>
1336
+ <p>This is an automated message sent by System Health and Security Probe v. 1.0.0. Host: " . $nameofhost  . ".<br><br>
1337
+ System Health and Security Probe runs regularly and investigates if any service running on the server is in failed state, if ClamAV
1338
+ antivirus has detected any virus in the incoming emails or in the files uploaded to Nextcloud, if any IP address has been banned due to repeated
1339
+ failed log in attempts against one of the applications monitored by Fail2ban, if the free storage space on all partitions is under a certain
1340
+ threshold, and if the average CPU load in the last 15 minutes exceeds 100% utilization of all the CPU cores. <br><br>
1341
+ The problems currently detected are listed below:<br><br></p>
1342
+
1343
+ <p>$getfailedserv</p>
1344
+
1345
+ <p>$clamavperiodicdetect</p>
1346
+
1347
+ <p>$clamavdetections</p>
1348
+
1349
+ <p>$getblockedips</p>
1350
+
1351
+ <p>$diskwarn</p>
1352
+
1353
+ <p>$averageloadwarn</p>
1354
+
1355
+ <h4>General System Information:</h4>
1356
+
1357
+ <p>$infodisk</p>
1358
+
1359
+ <p>$averageloadgen</p>
1360
+
1361
+ <p>$updaystext</p>
1362
+
1363
+ <br>Yours,<br>
1364
+ System Health and Security Probe<br>
1365
+ Host: " . $nameofhost . "<br><br>
1366
+ </div>
1367
+ </body>
1368
+ </html>
1369
+--------------". $separator ."
1370
+Content-Type: image/svg+xml; name='k9zg7dfQsjhcrp1lr.svg'
1371
+Content-Disposition: inline; filename='k9zg7dfQsjhcrp1lr.svg'
1372
+Content-Id: <logo-". $separator .">
1373
+Content-Transfer-Encoding: base64
1374
+
1375
+". $base64Logo ."
1376
+
1377
+--------------". $separator ."--
1378
+
1379
+";
1380
+
1381
+ /**
1382
+  * Extract a fragment from the newly created email, excluding some elements which almost always change from one script run to the other. This fragment will be stored in the
1383
+  * database to be compared with every similar fragment in the future emails prepared to be sent. If the fragment in the new email is identical with the one stored in the
1384
+  * database, in certain situations the new message will not be sent because all the data it contains has been already included in the previous email(s). The new message will
1385
+  * be always sent if the average CPU load in the last 15 minutes exceeds 100% utilization of all the CPU cores, or if the free storage space is below the critical threshold.
1386
+  */
1387
+ $message_light = "
1388
+
1389
+ <p>$getfailedserv</p>
1390
+
1391
+ <p>$clamavperiodicdetect</p>
1392
+
1393
+ <p>$clamavdetections</p>
1394
+
1395
+ <p>$diskwarn</p>
1396
+
1397
+ <p>$averageloadwarn</p>
1398
+
1399
+ ";
1400
+
1401
+  $new_message_enc = base64_encode($message_light);
1402
+
1403
+  // Get the last sent email from the 'lastsentemail' table
1404
+  $getlsml = "SELECT id, old_message FROM lastsentemail WHERE id = 1;";
1405
+  $resgetlsml = $mysqli->query($getlsml);
1406
+  $resfetchlsml = $resgetlsml->fetch_array();
1407
+  $old_message_enc = $resfetchlsml[1];
1408
+
1409
+
1410
+ /**
1411
+  * Send the current email if any new IP has been banned since the last run, or if the average CPU load in the last 15 minutes exceeds 100% utilization of all the
1412
+  * CPU cores, or if the free storage space is below the critical threshold, or if ClamAV detected any viruses in emails or in the files uploaded to Nextcloud.
1413
+  * If the timespan between the last IP ban and the current time is longer than the run interval and the banned IPs are the only problem the system has, then the
1414
+  * email shouldn't be sent, because the report about all the currently banned IPs has been already sent on the previous script run.
1415
+  */
1416
+ if (($banipschck != 0) || ($averageload > $cpunumber) || ($freedisk <= $diskthreshold) || ($abreportsentcheck != 0) || ((strcmp($new_message_enc, $old_message_enc) !== 0) &&
1417
+    (($getfailedservtert[0] != 0) || (($nbinfctdflsmail != 0) && ($maildetlnbr_enc != $old_mailvirdetect_enc)) || (($nbinfctdflsnext != 0) &&
1418
+    ($nextdetlnbr_enc != $old_nextvirdetect_enc)) || (count($mailloglines) != 0) || (count($nextloglines) != 0) || ((count($jailsarr) != 0) && ($ipstimespans[0] <= $runinterval))))) {
1419
+
1420
+    mail($emailto, $subject, $message, $headers, "-f " . $emailsender . "");
1421
+
1422
+    // Store the 'light' version of the last sent email in the 'lastsentemail' table
1423
+    $nmid = 1;
1424
+    $rplnmenc = $mysqli->prepare("REPLACE INTO lastsentemail (id, old_message) VALUES (?, ?);");
1425
+    $rplnmenc->bind_param("is", $nmid, $new_message_enc);
1426
+    $rplnmenc->execute();
1427
+    $rplnmenc->close();
1428
+
1429
+    /**
1430
+     * From the email that has just been sent, take the log lines and report lines containing virus detections, take the last read log lines and store them
1431
+     * in the appropriate fields, in the 'sentreadlines' table
1432
+     */
1433
+    $strlglns = $mysqli->prepare("REPLACE INTO sentreadlines (id, mail_loglines, nextcloud_loglines, lastmailline, lastnextline, lastpersdetmail, lastpersdetnext) VALUES
1434
+	        (?, ?, ?, ?, ?, ?, ?);");
1435
+    $strlglns->bind_param("issssss", $nmid, $maildetections_enc, $newlastreadmailline, $nextdetections_enc, $newlastreadnextline, $maildetlnbr_enc, $nextdetlnbr_enc);
1436
+    $strlglns->execute();
1437
+    $strlglns->close();
1438
+ }
1439
+
1440
+  $getlsml = "SELECT id, old_message FROM lastsentemail WHERE id = 1;";
1441
+  $resgetlsml = $mysqli->query($getlsml);
1442
+  $resfetchlsml = $resgetlsml->fetch_array();
1443
+  $old_message_enc = $resfetchlsml[1];
1444
+
1445
+ // Update the last read log lines at every script run, even if the current email hasn't been sent because it was identical with the last sent one
1446
+ $chcklstl = "SELECT * FROM sentreadlines;";
1447
+ $reschcklstl = $mysqli->query($chcklstl);
1448
+ $fetchchcklstl = $reschcklstl->fetch_array();
1449
+
1450
+ if ($fetchchcklstl) {
1451
+     $lnid = 1;
1452
+     $upnlmnln = $mysqli->prepare("UPDATE sentreadlines SET lastmailline = ?, lastnextline = ? WHERE id = ?");
1453
+     $upnlmnln->bind_param("ssi", $newlastreadmailline, $newlastreadnextline, $lnid);
1454
+     $upnlmnln->execute();
1455
+     $upnlmnln->close();
1456
+ }
1457
+
1458
+ /**
1459
+  * If the 'bannedipstable' table has more than 100000000 rows, first backup the current database, then remove the first 5000000 rows, so as to avoid working with an
1460
+  * excessively large database. If you want to save the backup in a directory different from '/srv/shas-probe-db-backup', then specify it in the 'config' file, in the
1461
+  * $backup_directory parameter
1462
+  */
1463
+ $bptcount = "SELECT COUNT(id) FROM bannedipstable";
1464
+ $resbptcount = $mysqli->query($bptcount);
1465
+ $fetchbpt = $resbptcount->fetch_array();
1466
+ $rownb = $fetchbpt[0];
1467
+
1468
+ if ($rownb > 100000000) {
1469
+
1470
+     $date2 = date("Y-m-d");
1471
+
1472
+     if (!is_dir($backupdirectory)) {
1473
+	 exec("mkdir -p " . $backupdirectory);
1474
+     }
1475
+
1476
+     $backupname = "bannedipsdb-" . $date2 . ".sql";
1477
+
1478
+     $dbbackup =  'mysqldump --user=' . $bannedipsuser . ' --password=' . $bannedipspswd . ' --databases ' . $bannedipsdb . ' > ' . $backupdirectory . '/' . $backupname . '';
1479
+     $runcommand = exec($dbbackup);
1480
+
1481
+     $dlrows = "DELETE FROM bannedipstable ORDER BY id ASC limit 5000000";
1482
+     $resdlrows = $mysqli->query($dlrows);
1483
+ }
1484
+
1485
+} else { exit("Error. No configuration file."); }
1486
+
1487
+?>