generated from smedev/Template-for-SMEServer-Contribs-Package
Add in software files and templates
This commit is contained in:
271
root/opt/dmarc-srg/utils/check_config.php
Normal file
271
root/opt/dmarc-srg/utils/check_config.php
Normal file
@@ -0,0 +1,271 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dmarc-srg - A php parser, viewer and summary report generator for incoming DMARC reports.
|
||||
* Copyright (C) 2023 Aleksey Andreev (liuch)
|
||||
*
|
||||
* Available at:
|
||||
* https://github.com/liuch/dmarc-srg
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* =========================
|
||||
*
|
||||
* This script is for checking configuration.
|
||||
*
|
||||
* The script can be useful for checking your configuration.
|
||||
* Note: the current directory must be the one containing the classes directory.
|
||||
*
|
||||
* @category Utilities
|
||||
* @package DmarcSrg
|
||||
* @author Aleksey Andreev (liuch)
|
||||
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU/GPLv3
|
||||
*/
|
||||
|
||||
namespace Liuch\DmarcSrg;
|
||||
|
||||
use Liuch\DmarcSrg\Core;
|
||||
use Liuch\DmarcSrg\Mail\MailBoxes;
|
||||
use Liuch\DmarcSrg\Directories\DirectoryList;
|
||||
use Liuch\DmarcSrg\Exception\SoftException;
|
||||
use Liuch\DmarcSrg\Exception\RuntimeException;
|
||||
|
||||
require 'init.php';
|
||||
|
||||
if (php_sapi_name() !== 'cli') {
|
||||
echo 'Forbidden';
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const RESULT_SUCCESS = 1;
|
||||
const RESULT_WARNING = 2;
|
||||
const RESULT_ERROR = 3;
|
||||
const RESULT_FATAL = 4;
|
||||
|
||||
const CONFIG_FILE = 'config/conf.php';
|
||||
|
||||
$e_cnt = 0;
|
||||
$w_cnt = 0;
|
||||
$m_str = '';
|
||||
|
||||
$startChecking = function (string $message, int $margin = 0) use (&$m_str): void {
|
||||
$col_w = 35;
|
||||
$m_str = str_repeat(' ', $margin);
|
||||
$s = "{$m_str} * {$message}";
|
||||
echo $s, str_repeat('.', max($col_w - strlen($s), 0)), ' ';
|
||||
};
|
||||
|
||||
$endChecking = function (string $message = '', int $result = 0) use (&$e_cnt, &$w_cnt, &$m_str): void {
|
||||
if ($result === 0) {
|
||||
$result = empty($message) ? RESULT_SUCCESS : RESULT_ERROR;
|
||||
}
|
||||
switch ($result) {
|
||||
case RESULT_SUCCESS:
|
||||
echo 'Ok', PHP_EOL;
|
||||
break;
|
||||
case RESULT_WARNING:
|
||||
++$w_cnt;
|
||||
echo 'Warning', PHP_EOL;
|
||||
break;
|
||||
case RESULT_ERROR:
|
||||
++$e_cnt;
|
||||
echo 'Fail', PHP_EOL;
|
||||
break;
|
||||
case RESULT_FATAL:
|
||||
echo 'Fail', PHP_EOL;
|
||||
throw new SoftException($message);
|
||||
}
|
||||
if (!empty($message)) {
|
||||
echo "{$m_str} Message: ", $message, PHP_EOL;
|
||||
}
|
||||
};
|
||||
|
||||
$core = Core::instance();
|
||||
|
||||
ob_start(null, 0, PHP_OUTPUT_HANDLER_FLUSHABLE | PHP_OUTPUT_HANDLER_REMOVABLE);
|
||||
$core->config('debug'); // Just in order to load the config file
|
||||
$empty_buf = empty(ob_get_flush());
|
||||
|
||||
try {
|
||||
echo '=== GENERAL INFORMATION ===', PHP_EOL;
|
||||
$uname = implode(' ', array_map(function ($mode) {
|
||||
return php_uname($mode);
|
||||
}, [ 's', 'r', 'v', 'm' ]));
|
||||
echo ' * OS information: ', $uname, PHP_EOL;
|
||||
echo ' * PHP version: ', phpversion(), PHP_EOL;
|
||||
|
||||
echo PHP_EOL, '=== EXTENSIONS ===', PHP_EOL;
|
||||
foreach ([ 'pdo_mysql', 'xmlreader', 'zip', 'json' ] as $ext) {
|
||||
$startChecking($ext);
|
||||
if (extension_loaded($ext)) {
|
||||
$endChecking();
|
||||
} else {
|
||||
$endChecking('The extension is not loaded');
|
||||
}
|
||||
}
|
||||
|
||||
echo PHP_EOL, '=== CONFIG FILE ===', PHP_EOL;
|
||||
$startChecking('Checking if the file exists');
|
||||
if (is_file(CONFIG_FILE)) {
|
||||
$endChecking();
|
||||
} else {
|
||||
$endChecking('The configuration file `config/conf.php` not found', RESULT_FATAL);
|
||||
}
|
||||
$startChecking('Checking read permission');
|
||||
if (is_readable(CONFIG_FILE)) {
|
||||
$endChecking();
|
||||
} else {
|
||||
$endChecking('The configuration file is not readable', RESULT_FATAL);
|
||||
}
|
||||
$startChecking('Checking write permission');
|
||||
if (!is_writable(CONFIG_FILE)) {
|
||||
$endChecking();
|
||||
} else {
|
||||
$endChecking('The configuration file is writable', RESULT_WARNING);
|
||||
}
|
||||
$startChecking('Checking access by other users');
|
||||
$r = fileperms(CONFIG_FILE);
|
||||
if ($r !== false) {
|
||||
if (($r & 0x6) !== 0) {
|
||||
$endChecking('The configuration file is accessible to other users', RESULT_WARNING);
|
||||
} else {
|
||||
$endChecking();
|
||||
}
|
||||
} else {
|
||||
$endChecking('Fileperms failed', RESULT_ERROR);
|
||||
}
|
||||
$startChecking('Checking the output buffer');
|
||||
if ($empty_buf) {
|
||||
$endChecking();
|
||||
} else {
|
||||
$endChecking('There are extra characters before the "<?php" string');
|
||||
}
|
||||
|
||||
echo PHP_EOL, '=== DATABASE ===', PHP_EOL;
|
||||
$startChecking('Accessibility check');
|
||||
try {
|
||||
$db_s = $core->database()->state();
|
||||
$endChecking();
|
||||
} catch (RuntimeException $e) {
|
||||
$db_s = null;
|
||||
$endChecking($e->getMessage());
|
||||
}
|
||||
if ($db_s) {
|
||||
$startChecking('Checking for integrity');
|
||||
if ($db_s) {
|
||||
$endChecking();
|
||||
} else {
|
||||
$endChecking($db_s['message'], ($db_s['needs_upgrade'] ?? false) ? RESULT_WARNING : RESULT_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
echo PHP_EOL, '=== MAILBOXES ===', PHP_EOL;
|
||||
$startChecking('Checking mailboxes config');
|
||||
try {
|
||||
$mb_list = new MailBoxes();
|
||||
$mb_lcnt = $mb_list->count();
|
||||
if ($mb_lcnt === 0) {
|
||||
$endChecking('No mailboxes found', RESULT_SUCCESS);
|
||||
} else {
|
||||
$endChecking("{$mb_lcnt} mailbox" . ($mb_lcnt > 1 ? 'ex' : '') . ' found', RESULT_SUCCESS);
|
||||
$startChecking('Imap extension');
|
||||
if (extension_loaded('imap')) {
|
||||
$endChecking();
|
||||
echo " * Checking mailboxes ({$mb_lcnt})", PHP_EOL;
|
||||
for ($mb_num = 1; $mb_num <= $mb_lcnt; ++$mb_num) {
|
||||
$mb = $mb_list->mailbox($mb_num);
|
||||
echo " - {$mb->name()}", PHP_EOL;
|
||||
$startChecking('Accessibility', 2);
|
||||
$res = $mb->check();
|
||||
if (!$res['error_code']) {
|
||||
$endChecking();
|
||||
} else {
|
||||
$endChecking($res['message'] ?? null);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$endChecking('The extension is not loaded');
|
||||
}
|
||||
}
|
||||
} catch (RuntimeException $e) {
|
||||
$endChecking($e->getMessage());
|
||||
}
|
||||
|
||||
echo PHP_EOL, '=== DIRECTORIES ===', PHP_EOL;
|
||||
$startChecking('Checking directories config');
|
||||
try {
|
||||
$dir_list = (new DirectoryList())->list();
|
||||
$dir_lcnt = count($dir_list);
|
||||
if ($dir_lcnt === 0) {
|
||||
$endChecking('No directories found', RESULT_SUCCESS);
|
||||
} else {
|
||||
$endChecking("{$dir_lcnt} director" . ($dir_lcnt > 1 ? 'ies' : 'y') . ' found', RESULT_SUCCESS);
|
||||
echo " * Checking directories ({$dir_lcnt})", PHP_EOL;
|
||||
foreach ($dir_list as $dir) {
|
||||
$dir_a = $dir->toArray();
|
||||
echo " - {$dir_a['name']}", PHP_EOL;
|
||||
$startChecking('Accessibility', 2);
|
||||
$res = $dir->check();
|
||||
if (!$res['error_code']) {
|
||||
$endChecking();
|
||||
$startChecking('Security', 2);
|
||||
try {
|
||||
$perms = fileperms($dir_a['location']);
|
||||
if ($perms === false) {
|
||||
throw new RuntimeException('Fileperms failed', RESULT_ERROR);
|
||||
}
|
||||
if ($perms & 0x2) {
|
||||
throw new RuntimeException(
|
||||
'Other users have write access to the directory',
|
||||
RESULT_WARNING
|
||||
);
|
||||
}
|
||||
$endChecking();
|
||||
} catch (RuntimeException $e) {
|
||||
$endChecking($e->getMessage(), $e->getCode());
|
||||
} catch (\ErrorException $e) {
|
||||
$endChecking($e->getMessage());
|
||||
}
|
||||
} else {
|
||||
$endChecking($res['message'] ?? null);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SoftException $e) {
|
||||
$endChecking($e->getMessage());
|
||||
}
|
||||
|
||||
echo PHP_EOL, '===', PHP_EOL;
|
||||
if ($e_cnt === 0 && $w_cnt === 0) {
|
||||
echo 'Success!', PHP_EOL;
|
||||
} else {
|
||||
echo 'There ', $e_cnt + $w_cnt === 1 ? 'is' : 'are', ' ';
|
||||
$strs = [];
|
||||
foreach ([ [$e_cnt, 'error' ], [ $w_cnt, 'warning' ] ] as &$it) {
|
||||
$cnt = $it[0];
|
||||
if ($cnt > 0) {
|
||||
$strs[] = $cnt . ' ' . $it[1] . ($cnt > 1 ? 's' : '');
|
||||
}
|
||||
}
|
||||
unset($it);
|
||||
echo implode(' and ', $strs), '!', PHP_EOL;
|
||||
}
|
||||
} catch (SoftException $e) {
|
||||
echo 'Fatal error: ', $e->getMessage(), PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ($e_cnt > 0) {
|
||||
exit(2);
|
||||
}
|
||||
exit(0);
|
117
root/opt/dmarc-srg/utils/database_admin.php
Normal file
117
root/opt/dmarc-srg/utils/database_admin.php
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dmarc-srg - A php parser, viewer and summary report generator for incoming DMARC reports.
|
||||
* Copyright (C) 2020 Aleksey Andreev (liuch)
|
||||
*
|
||||
* Available at:
|
||||
* https://github.com/liuch/dmarc-srg
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* =========================
|
||||
*
|
||||
* This script performs some administration functions with the database.
|
||||
* It has one required parameter, it can has follow values: `status`, `init`, `upgrade`, `drop`.
|
||||
* `status` - Will display the database status.
|
||||
* `init` - Will create all the required tables in the database.
|
||||
* The database must contain no tables.
|
||||
* `upgrade` - Will upgrade the database structure if it is necessary.
|
||||
* `drop` - Will remove all tables from the database.
|
||||
*
|
||||
* @category Utilities
|
||||
* @package DmarcSrg
|
||||
* @author Aleksey Andreev (liuch)
|
||||
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU/GPLv3
|
||||
*/
|
||||
|
||||
namespace Liuch\DmarcSrg;
|
||||
|
||||
use Liuch\DmarcSrg\Database\Database;
|
||||
use Liuch\DmarcSrg\Database\DatabaseUpgrader;
|
||||
use Liuch\DmarcSrg\Settings\SettingString;
|
||||
use Liuch\DmarcSrg\Exception\RuntimeException;
|
||||
|
||||
require 'init.php';
|
||||
|
||||
if (php_sapi_name() !== 'cli') {
|
||||
echo 'Forbidden';
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$action = $argv[1] ?? '';
|
||||
$res = null;
|
||||
try {
|
||||
switch ($action) {
|
||||
case 'status':
|
||||
$res = Core::instance()->database()->state();
|
||||
$tcn = 0;
|
||||
if (isset($res['tables'])) {
|
||||
foreach ($res['tables'] as &$t) {
|
||||
if (isset($t['exists']) && $t['exists'] === true) {
|
||||
++$tcn;
|
||||
}
|
||||
}
|
||||
unset($t);
|
||||
}
|
||||
echo 'Version: ', ($res['version'] ?? 'n/a'), PHP_EOL;
|
||||
echo 'Tables: ', $tcn, PHP_EOL;
|
||||
break;
|
||||
case 'init':
|
||||
$res = Core::instance()->database()->initDb();
|
||||
break;
|
||||
case 'upgrade':
|
||||
$cur_ver = (new SettingString('version'))->value();
|
||||
if ($cur_ver === '') {
|
||||
$cur_ver = 'n/a';
|
||||
}
|
||||
$db = Core::instance()->database();
|
||||
echo "Current version: {$cur_ver}", PHP_EOL;
|
||||
echo 'Required version: ', $db::REQUIRED_VERSION, PHP_EOL;
|
||||
if ($cur_ver !== $db::REQUIRED_VERSION) {
|
||||
$db->getMapper('upgrader')->go($db::REQUIRED_VERSION);
|
||||
$res = [
|
||||
'error_code' => 0,
|
||||
'message' => 'Upgrated successfully'
|
||||
];
|
||||
} else {
|
||||
$res = [
|
||||
'error_code' => 0,
|
||||
'message' => 'No upgrade required'
|
||||
];
|
||||
}
|
||||
break;
|
||||
case 'drop':
|
||||
$res = Core::instance()->database()->cleanDb();
|
||||
break;
|
||||
default:
|
||||
echo "Usage: {$argv[0]} status|init|upgrade|drop", PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
} catch (RuntimeException $e) {
|
||||
$res = ErrorHandler::exceptionResult($e);
|
||||
}
|
||||
|
||||
$error = ($res['error_code'] ?? 0) ? 'Error! ' : '';
|
||||
echo "Message: {$error}{$res['message']}", PHP_EOL;
|
||||
|
||||
if (isset($res['debug_info'])) {
|
||||
$debug_info = $res['debug_info'];
|
||||
echo "Debug info:", PHP_EOL;
|
||||
echo '-----', PHP_EOL;
|
||||
echo "[{$debug_info['code']}]", PHP_EOL;
|
||||
echo '-----', PHP_EOL;
|
||||
echo "{$debug_info['content']}", PHP_EOL;
|
||||
}
|
||||
|
||||
exit(0);
|
225
root/opt/dmarc-srg/utils/fetch_reports.php
Normal file
225
root/opt/dmarc-srg/utils/fetch_reports.php
Normal file
@@ -0,0 +1,225 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dmarc-srg - A php parser, viewer and summary report generator for incoming DMARC reports.
|
||||
* Copyright (C) 2020 Aleksey Andreev (liuch)
|
||||
*
|
||||
* Available at:
|
||||
* https://github.com/liuch/dmarc-srg
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* =========================
|
||||
*
|
||||
* This script fetches DMARC reports from mailboxes and server local directories and saves them to the DB.
|
||||
* The parameters of mailboxes and directories must be specified in the configuration file.
|
||||
* The mailboxes and directories accessibility can be checked on the administration page in the web interface.
|
||||
* The script has one optional parameter: `source` - the type of the source. The valid types are `email`, `directory`.
|
||||
*
|
||||
* Some examples:
|
||||
* $ utils/fetch_reports
|
||||
* will fetch reports from both the mailboxes and the local server directories.
|
||||
*
|
||||
* $ utils/fetch_reports source=email
|
||||
* will only fetch reports from the mailboxes.
|
||||
*
|
||||
* The best place to use it is cron.
|
||||
* Note: the current directory must be the one containing the classes directory.
|
||||
*
|
||||
* @category Utilities
|
||||
* @package DmarcSrg
|
||||
* @author Aleksey Andreev (liuch)
|
||||
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU/GPLv3
|
||||
*/
|
||||
|
||||
namespace Liuch\DmarcSrg;
|
||||
|
||||
use Liuch\DmarcSrg\Mail\MailBoxes;
|
||||
use Liuch\DmarcSrg\Report\ReportFetcher;
|
||||
use Liuch\DmarcSrg\Sources\Source;
|
||||
use Liuch\DmarcSrg\Sources\MailboxSource;
|
||||
use Liuch\DmarcSrg\Sources\DirectorySource;
|
||||
use Liuch\DmarcSrg\Directories\DirectoryList;
|
||||
use Liuch\DmarcSrg\Exception\RuntimeException;
|
||||
|
||||
require 'init.php';
|
||||
|
||||
if (php_sapi_name() !== 'cli') {
|
||||
echo 'Forbidden';
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$usage = false;
|
||||
$source = null;
|
||||
if (isset($argv)) {
|
||||
for ($i = 1; $i < count($argv); ++$i) {
|
||||
$av = explode('=', $argv[$i]);
|
||||
if (count($av) !== 2) {
|
||||
echo 'Invalid parameter format' . PHP_EOL;
|
||||
$usage = true;
|
||||
break;
|
||||
}
|
||||
switch ($av[0]) {
|
||||
case 'source':
|
||||
$source = $av[1];
|
||||
break;
|
||||
default:
|
||||
echo 'Unknown parameter "' . $av[0] . '"' . PHP_EOL;
|
||||
$usage = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($source && $source !== 'email' && $source !== 'directory') {
|
||||
echo 'Invalid source type "' . $source . '". "email" or "directory" expected.' . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if ($usage) {
|
||||
echo PHP_EOL;
|
||||
echo 'Usage: ' . basename(__FILE__) . ' [source=email|directory]' . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$sou_list = [];
|
||||
$problems = [];
|
||||
$addError = function (\Throwable $e, array &$errors): void {
|
||||
$err_r = ErrorHandler::exceptionResult($e);
|
||||
$errors['messages'][] = $err_r['message'];
|
||||
if (!$errors['debug_info'] && isset($err_r['debug_info'])) {
|
||||
$errors['debug_info'] = $err_r['debug_info']['content'];
|
||||
}
|
||||
};
|
||||
|
||||
const MAILBOX_LIST = 1;
|
||||
const DIRECTORY_LIST = 2;
|
||||
const FETCHER = 3;
|
||||
|
||||
$state = MAILBOX_LIST;
|
||||
if (!$source || $source === 'email') {
|
||||
$errors = [ 'messages' => [], 'debug_info' => null ];
|
||||
$mb_list = new MailBoxes();
|
||||
for ($mb_num = 1; $mb_num <= $mb_list->count(); ++$mb_num) {
|
||||
try {
|
||||
$sou_list[] = new MailboxSource($mb_list->mailbox($mb_num));
|
||||
} catch (RuntimeException $e) {
|
||||
$addError($e, $errors);
|
||||
}
|
||||
}
|
||||
if (count($errors['messages']) > 0) {
|
||||
$problems[] = [
|
||||
'state' => $state,
|
||||
'messages' => $errors['messages'],
|
||||
'debug_info' => $errors['debug_info']
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$state = DIRECTORY_LIST;
|
||||
if (!$source || $source === 'directory') {
|
||||
$errors = [ 'messages' => [], 'debug_info' => null ];
|
||||
foreach ((new DirectoryList())->list() as $dir) {
|
||||
try {
|
||||
$sou_list[] = new DirectorySource($dir);
|
||||
} catch (RuntimeException $e) {
|
||||
$addError($e, $errors);
|
||||
}
|
||||
}
|
||||
if (count($errors['messages']) > 0) {
|
||||
$problems[] = [
|
||||
'state' => $state,
|
||||
'messages' => $errors['messages'],
|
||||
'debug_info' => $errors['debug_info']
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$state = FETCHER;
|
||||
try {
|
||||
foreach ($sou_list as $source) {
|
||||
$results = (new ReportFetcher($source))->fetch();
|
||||
foreach ($results as &$res) {
|
||||
$messages = [];
|
||||
if (isset($res['source_error'])) {
|
||||
$messages[] = $res['source_error'];
|
||||
}
|
||||
if (isset($res['post_processing_message'])) {
|
||||
$messages[] = $res['post_processing_message'];
|
||||
}
|
||||
if (isset($res['error_code']) && $res['error_code'] !== 0 && isset($res['message'])) {
|
||||
$messages[] = $res['message'];
|
||||
}
|
||||
if (count($messages) > 0) {
|
||||
$pr = [ 'state' => $state, 'messages' => $messages ];
|
||||
foreach ([ 'report_id', 'emailed_from', 'emailed_date' ] as $it) {
|
||||
if (isset($res[$it])) {
|
||||
$pr[$it] = $res[$it];
|
||||
}
|
||||
}
|
||||
if ($source->type() === Source::SOURCE_MAILBOX) {
|
||||
$cont = $source->container();
|
||||
$pr['mailbox'] = $cont->mailbox() . ' (' . $cont->name() . ')';
|
||||
}
|
||||
$problems[] = $pr;
|
||||
}
|
||||
}
|
||||
unset($res);
|
||||
}
|
||||
} catch (RuntimeException $e) {
|
||||
$problems[] = [ 'state' => $state, 'messages' => [ $e->getMessage() ] ];
|
||||
}
|
||||
|
||||
if (count($problems) > 0) {
|
||||
$debug_info = null;
|
||||
foreach ($problems as $i => $pr) {
|
||||
if ($i > 0) {
|
||||
echo PHP_EOL;
|
||||
}
|
||||
switch ($pr['state']) {
|
||||
case MAILBOX_LIST:
|
||||
echo 'Failed to get mailbox list:';
|
||||
break;
|
||||
case DIRECTORY_LIST:
|
||||
echo 'Failed to get directory list:';
|
||||
break;
|
||||
case FETCHER:
|
||||
echo 'Failed to get incoming report:';
|
||||
break;
|
||||
}
|
||||
echo PHP_EOL;
|
||||
echo ' Error message:', PHP_EOL;
|
||||
$messages = array_map(function ($msg) {
|
||||
return " - {$msg}";
|
||||
}, $pr['messages']);
|
||||
echo implode(PHP_EOL, $messages), PHP_EOL;
|
||||
if (isset($pr['report_id'])) {
|
||||
echo " Report ID: {$pr['report_id']}", PHP_EOL;
|
||||
}
|
||||
if (isset($pr['emailed_from']) || isset($pr['emailed_date']) || isset($pr['mailbox'])) {
|
||||
echo ' Email message metadata:', PHP_EOL;
|
||||
echo ' - From: ' . ($pr['emailed_from'] ?? '-'), PHP_EOL;
|
||||
echo ' - Date: ' . ($pr['emailed_date'] ?? '-'), PHP_EOL;
|
||||
echo ' - Mailbox: ' . ($pr['mailbox'] ?? '-'), PHP_EOL;
|
||||
}
|
||||
if (!$debug_info && !empty($pr['debug_info'])) {
|
||||
$debug_info = $pr['debug_info'];
|
||||
}
|
||||
}
|
||||
if ($debug_info) {
|
||||
echo PHP_EOL;
|
||||
echo 'Debug information:', PHP_EOL, $debug_info, PHP_EOL;
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
exit(0);
|
163
root/opt/dmarc-srg/utils/mailbox_cleaner.php
Normal file
163
root/opt/dmarc-srg/utils/mailbox_cleaner.php
Normal file
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dmarc-srg - A php parser, viewer and summary report generator for incoming DMARC reports.
|
||||
* Copyright (C) 2020 Aleksey Andreev (liuch)
|
||||
*
|
||||
* Available at:
|
||||
* https://github.com/liuch/dmarc-srg
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* =========================
|
||||
*
|
||||
* This script deletes old DMARC report email messages in mailboxes.
|
||||
* The mailbox parameters and conditions for removal must be specified
|
||||
* in the configuration file. The mailbox accessibility can be checked
|
||||
* on the administration page in the web interface.
|
||||
* The best place to use it is cron.
|
||||
* Note: the current directory must be the one containing the classes directory.
|
||||
*
|
||||
* @category Utilities
|
||||
* @package DmarcSrg
|
||||
* @author Aleksey Andreev (liuch)
|
||||
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU/GPLv3
|
||||
*/
|
||||
|
||||
namespace Liuch\DmarcSrg;
|
||||
|
||||
use Liuch\DmarcSrg\Mail\MailBoxes;
|
||||
use Liuch\DmarcSrg\Sources\SourceAction;
|
||||
use Liuch\DmarcSrg\Exception\RuntimeException;
|
||||
|
||||
require 'init.php';
|
||||
|
||||
if (php_sapi_name() !== 'cli') {
|
||||
echo 'Forbidden';
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$core = Core::instance();
|
||||
|
||||
$days = $core->config('cleaner/mailboxes/days_old', -1);
|
||||
if (gettype($days) !== 'integer' || $days < 0) {
|
||||
exit(0);
|
||||
}
|
||||
$days_date = (new DateTime())->sub(new \DateInterval("P{$days}D"));
|
||||
|
||||
$maximum = $core->config('cleaner/mailboxes/delete_maximum', 0);
|
||||
if (gettype($maximum) !== 'integer' || $maximum < 0) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
$leave = $core->config('cleaner/mailboxes/leave_minimum', 0);
|
||||
if (gettype($leave) !== 'integer' || $leave < 0) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Get a list of the configured email boxes
|
||||
$mb_list = new MailBoxes();
|
||||
$mb_cnt = $mb_list->count();
|
||||
if ($mb_cnt === 0) {
|
||||
// There are no configured mailboxes
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Get the names of mailboxes where processed messages are moved to.
|
||||
$dirs = [];
|
||||
foreach ([ [ 'done', '', 1 ], [ 'failed', 'failed', 0 ] ] as $it) {
|
||||
$opt_nm = $it[0];
|
||||
$def_opt = $it[1];
|
||||
$def_cri = $it[2];
|
||||
$actions = SourceAction::fromSetting($core->config("fetcher/mailboxes/when_{$opt_nm}", ''), 0, '');
|
||||
if (count($actions) === 0) {
|
||||
$dir = $def_opt;
|
||||
} else {
|
||||
$dir = null;
|
||||
foreach ($actions as $act) {
|
||||
if ($act->type === SourceAction::ACTION_MOVE) {
|
||||
$dir = $act->param;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_null($dir)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
switch (strtolower($core->config("cleaner/mailboxes/{$opt_nm}", ''))) {
|
||||
case 'any':
|
||||
$cri = 2;
|
||||
break;
|
||||
case 'seen':
|
||||
$cri = 1;
|
||||
break;
|
||||
case '':
|
||||
$cri = $def_cri;
|
||||
break;
|
||||
default:
|
||||
$cri = 0;
|
||||
break;
|
||||
}
|
||||
if (empty($dir) && $cri > 1) {
|
||||
$cri = 1;
|
||||
}
|
||||
$dirs[$dir] = min(($dirs[$dir] ?? $cri), $cri);
|
||||
}
|
||||
|
||||
try {
|
||||
for ($mb_idx = 1; $mb_idx <= $mb_cnt; ++$mb_idx) {
|
||||
foreach ($dirs as $dir_name => $i_criteria) {
|
||||
if ($i_criteria > 0) {
|
||||
$criteria = $i_criteria === 2 ? 'ALL' : 'SEEN';
|
||||
$mbox = $mb_list->mailbox($mb_idx);
|
||||
if (!empty($dir_name)) {
|
||||
if (!($mbox = $mbox->childMailbox($dir_name))) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$s_res = $mbox->sort(SORTDATE, $criteria, false);
|
||||
$max = $maximum > 0 ? $maximum : -1;
|
||||
$lv = $leave === 0 ? count($s_res) : count($s_res) - $leave;
|
||||
$i = 0;
|
||||
while ($lv-- > 0) {
|
||||
$m_num = $s_res[$i++];
|
||||
$msg = $mbox->message($m_num);
|
||||
$mo = $msg->overview();
|
||||
if (isset($mo->date)) {
|
||||
try {
|
||||
$md = new DateTime($mo->date);
|
||||
} catch (\Exception $e) {
|
||||
$md = false;
|
||||
}
|
||||
if ($md !== false) {
|
||||
if ($md > $days_date) {
|
||||
break;
|
||||
}
|
||||
$mbox->deleteMessage($m_num);
|
||||
if ($max > 0) {
|
||||
if (--$max === 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (RuntimeException $e) {
|
||||
echo ErrorHandler::exceptionText($e);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
exit(0);
|
84
root/opt/dmarc-srg/utils/reportlog_cleaner.php
Normal file
84
root/opt/dmarc-srg/utils/reportlog_cleaner.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dmarc-srg - A php parser, viewer and summary report generator for incoming DMARC reports.
|
||||
* Copyright (C) 2020 Aleksey Andreev (liuch)
|
||||
*
|
||||
* Available at:
|
||||
* https://github.com/liuch/dmarc-srg
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* =========================
|
||||
*
|
||||
* This script deletes old log entries from the database.
|
||||
* The conditions for removal must be specified in the configuration file.
|
||||
* The best place to use it is cron.
|
||||
* Note: the current directory must be the one containing the classes directory.
|
||||
*
|
||||
* @category Utilities
|
||||
* @package DmarcSrg
|
||||
* @author Aleksey Andreev (liuch)
|
||||
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU/GPLv3
|
||||
*/
|
||||
|
||||
namespace Liuch\DmarcSrg;
|
||||
|
||||
use Liuch\DmarcSrg\ReportLog\ReportLog;
|
||||
use Liuch\DmarcSrg\Exception\RuntimeException;
|
||||
|
||||
require 'init.php';
|
||||
|
||||
if (php_sapi_name() !== 'cli') {
|
||||
echo 'Forbidden';
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$core = Core::instance();
|
||||
|
||||
$days = $core->config('cleaner/reportlog/days_old', -1);
|
||||
if (gettype($days) !== 'integer' || $days < 0) {
|
||||
exit(0);
|
||||
}
|
||||
$days_date = (new DateTime())->sub(new \DateInterval("P{$days}D"));
|
||||
|
||||
$maximum = $core->config('cleaner/reportlog/delete_maximum', 0);
|
||||
if (gettype($maximum) !== 'integer' || $maximum < 0) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
$leave = $core->config('cleaner/reportlog/leave_minimum', 0);
|
||||
if (gettype($leave) !== 'integer' || $leave < 0) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
try {
|
||||
$log = new ReportLog(null, null);
|
||||
$cnt = $log->count() - $leave;
|
||||
if ($cnt > 0) {
|
||||
$log = new ReportLog(null, $days_date);
|
||||
if ($leave * $maximum !== 0) {
|
||||
if ($maximum > 0 && $cnt > $maximum) {
|
||||
$cnt = $maximum;
|
||||
}
|
||||
$log->setOrder(ReportLog::ORDER_ASCENT);
|
||||
$log->setMaxCount($cnt);
|
||||
}
|
||||
$log->delete();
|
||||
}
|
||||
} catch (RuntimeException $e) {
|
||||
echo ErrorHandler::exceptionText($e);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
exit(0);
|
85
root/opt/dmarc-srg/utils/reports_cleaner.php
Normal file
85
root/opt/dmarc-srg/utils/reports_cleaner.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dmarc-srg - A php parser, viewer and summary report generator for incoming DMARC reports.
|
||||
* Copyright (C) 2020 Aleksey Andreev (liuch)
|
||||
*
|
||||
* Available at:
|
||||
* https://github.com/liuch/dmarc-srg
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* =========================
|
||||
*
|
||||
* This script deletes old reports from DB.
|
||||
* The conditions for removal must be specified in the configuration file.
|
||||
* The best place to use it is cron.
|
||||
* Note: You must leave enough reports if you want to get correct summary report.
|
||||
* Note: the current directory must be the one containing the classes directory.
|
||||
*
|
||||
* @category Utilities
|
||||
* @package DmarcSrg
|
||||
* @author Aleksey Andreev (liuch)
|
||||
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU/GPLv3
|
||||
*/
|
||||
|
||||
namespace Liuch\DmarcSrg;
|
||||
|
||||
use Liuch\DmarcSrg\Report\ReportList;
|
||||
use Liuch\DmarcSrg\Exception\RuntimeException;
|
||||
|
||||
require 'init.php';
|
||||
|
||||
if (php_sapi_name() !== 'cli') {
|
||||
echo 'Forbidden';
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$core = Core::instance();
|
||||
|
||||
$days = $core->config('cleaner/reports/days_old', -1);
|
||||
if (gettype($days) !== 'integer' || $days < 0) {
|
||||
exit(0);
|
||||
}
|
||||
$days_date = (new DateTime())->sub(new \DateInterval("P{$days}D"));
|
||||
|
||||
$maximum = $core->config('cleaner/reports/delete_maximum', 0);
|
||||
if (gettype($maximum) !== 'integer' || $maximum < 0) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
$leave = $core->config('cleaner/reports/leave_minimum', 0);
|
||||
if (gettype($leave) !== 'integer' || $leave < 0) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
try {
|
||||
$rl = new ReportList();
|
||||
$cnt = $rl->count() - $leave;
|
||||
if ($cnt > 0) {
|
||||
$rl->setFilter([ 'before_time' => $days_date ]);
|
||||
if ($leave * $maximum !== 0) {
|
||||
if ($maximum > 0 && $cnt > $maximum) {
|
||||
$cnt = $maximum;
|
||||
}
|
||||
$rl->setMaxCount($cnt);
|
||||
$rl->setOrder(ReportList::ORDER_BEGIN_TIME, ReportList::ORDER_ASCENT);
|
||||
}
|
||||
$rl->delete();
|
||||
}
|
||||
} catch (RuntimeException $e) {
|
||||
echo ErrorHandler::exceptionText($e);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
exit(0);
|
210
root/opt/dmarc-srg/utils/summary_report.php
Normal file
210
root/opt/dmarc-srg/utils/summary_report.php
Normal file
@@ -0,0 +1,210 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dmarc-srg - A php parser, viewer and summary report generator for incoming DMARC reports.
|
||||
* Copyright (C) 2020 Aleksey Andreev (liuch)
|
||||
*
|
||||
* Available at:
|
||||
* https://github.com/liuch/dmarc-srg
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* =========================
|
||||
*
|
||||
* This script creates a summary report and sends it by email.
|
||||
* The email addresses must be specified in the configuration file.
|
||||
* The script have two required parameters: `domain` and `period`, and two optional: `emailto` and `format`.
|
||||
* The `domain` parameter must contain a domain name, a comma-separated list of domains, or `all`.
|
||||
* The `period` parameter must have one of these values:
|
||||
* `lastmonth` - to make a report for the last month;
|
||||
* `lastweek` - to make a report for the last week;
|
||||
* `lastndays:N` - to make a report for the last N days;
|
||||
* The `emailto` parameter is optional. Set it if you want to use a different email address to sent the report to.
|
||||
* The `format` parameter is optional. It provides the ability to specify the email message format.
|
||||
* Possible values are: `text`, `html`, `text+html`. The default value is `text`.
|
||||
*
|
||||
* Some examples:
|
||||
*
|
||||
* $ php utils/summary_report.php domain=example.com period=lastweek
|
||||
* will send a weekly summary report by email for the domain example.com
|
||||
*
|
||||
* $ php utils/summary_report.php domain=example.com period=lastndays:10
|
||||
* will send a summary report by email for last 10 days for the domain example.com
|
||||
*
|
||||
* The best place to use it is cron.
|
||||
* Note: the current directory must be the one containing the classes directory.
|
||||
*
|
||||
* @category Utilities
|
||||
* @package DmarcSrg
|
||||
* @author Aleksey Andreev (liuch)
|
||||
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU/GPLv3
|
||||
*/
|
||||
|
||||
namespace Liuch\DmarcSrg;
|
||||
|
||||
use Liuch\DmarcSrg\Mail\MailBody;
|
||||
use Liuch\DmarcSrg\Domains\Domain;
|
||||
use Liuch\DmarcSrg\Domains\DomainList;
|
||||
use Liuch\DmarcSrg\Report\SummaryReport;
|
||||
use Liuch\DmarcSrg\Exception\SoftException;
|
||||
use Liuch\DmarcSrg\Exception\RuntimeException;
|
||||
|
||||
require 'init.php';
|
||||
|
||||
if (php_sapi_name() !== 'cli') {
|
||||
echo 'Forbidden' . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$domain = null;
|
||||
$period = null;
|
||||
$emailto = null;
|
||||
$format = 'text';
|
||||
for ($i = 1; $i < count($argv); ++$i) {
|
||||
$av = explode('=', $argv[$i]);
|
||||
if (count($av) == 2) {
|
||||
switch ($av[0]) {
|
||||
case 'domain':
|
||||
$domain = $av[1];
|
||||
break;
|
||||
case 'period':
|
||||
$period = $av[1];
|
||||
break;
|
||||
case 'emailto':
|
||||
$emailto = $av[1];
|
||||
break;
|
||||
case 'format':
|
||||
$format = $av[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (!$domain) {
|
||||
throw new SoftException('Parameter "domain" is not specified');
|
||||
}
|
||||
if (!$period) {
|
||||
throw new SoftException('Parameter "period" is not specified');
|
||||
}
|
||||
if (!in_array($format, [ 'text', 'html', 'text+html' ], true)) {
|
||||
throw new SoftException('Unknown email message format: ' . $format);
|
||||
}
|
||||
if (!$emailto) {
|
||||
$emailto = Core::instance()->config('mailer/default');
|
||||
}
|
||||
|
||||
if ($domain === 'all') {
|
||||
$domains = (new DomainList())->getList()['domains'];
|
||||
} else {
|
||||
$domains = array_map(function ($d) {
|
||||
return new Domain($d);
|
||||
}, explode(',', $domain));
|
||||
}
|
||||
|
||||
$rep = new SummaryReport($period);
|
||||
switch ($format) {
|
||||
case 'text':
|
||||
$text = [];
|
||||
$html = null;
|
||||
break;
|
||||
case 'html':
|
||||
$text = null;
|
||||
$html = [];
|
||||
break;
|
||||
default:
|
||||
$text = [];
|
||||
$html = [];
|
||||
break;
|
||||
}
|
||||
if (!is_null($html)) {
|
||||
$html[] = '<html><body>';
|
||||
}
|
||||
$dom_cnt = count($domains);
|
||||
for ($i = 0; $i < $dom_cnt; ++$i) {
|
||||
if ($i > 0) {
|
||||
if (!is_null($text)) {
|
||||
$text[] = '-----------------------------------';
|
||||
$text[] = '';
|
||||
}
|
||||
if (!is_null($html)) {
|
||||
$html[] = '<hr style="margin:2em 0;" />';
|
||||
}
|
||||
}
|
||||
|
||||
$domain = $domains[$i];
|
||||
if ($domain->exists()) {
|
||||
$rep->setDomain($domain);
|
||||
if (!is_null($text)) {
|
||||
foreach ($rep->text() as &$row) {
|
||||
$text[] = $row;
|
||||
}
|
||||
unset($row);
|
||||
}
|
||||
if (!is_null($html)) {
|
||||
foreach ($rep->html() as &$row) {
|
||||
$html[] = $row;
|
||||
}
|
||||
unset($row);
|
||||
}
|
||||
} else {
|
||||
$nf_message = "Domain \"{$domain->fqdn()}\" does not exist";
|
||||
if ($dom_cnt === 1) {
|
||||
throw new SoftException("Domain \"{$domain->fqdn()}\" does not exist");
|
||||
}
|
||||
if (!is_null($text)) {
|
||||
$text[] = "# {$nf_message}";
|
||||
$text[] = '';
|
||||
}
|
||||
if (!is_null($html)) {
|
||||
$html[] = '<h2>' . htmlspecialchars($nf_message) . '</h2>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($dom_cnt === 1) {
|
||||
$subject = "{$rep->subject()} for {$domain->fqdn()}";
|
||||
} else {
|
||||
$subject = "{$rep->subject()} for {$dom_cnt} domains";
|
||||
}
|
||||
|
||||
$mbody = new MailBody();
|
||||
if (!is_null($text)) {
|
||||
$mbody->setText($text);
|
||||
}
|
||||
if (!is_null($html)) {
|
||||
$html[] = '</body></html>';
|
||||
$mbody->setHtml($html);
|
||||
}
|
||||
|
||||
$headers = [
|
||||
'From' => Core::instance()->config('mailer/from'),
|
||||
'MIME-Version' => '1.0',
|
||||
'Content-Type' => $mbody->contentType()
|
||||
];
|
||||
|
||||
mail(
|
||||
$emailto,
|
||||
mb_encode_mimeheader($subject, 'UTF-8'),
|
||||
implode("\r\n", $mbody->content()),
|
||||
$headers
|
||||
);
|
||||
} catch (SoftException $e) {
|
||||
echo 'Error: ' . $e->getMessage() . PHP_EOL;
|
||||
exit(1);
|
||||
} catch (RuntimeException $e) {
|
||||
echo ErrorHandler::exceptionText($e);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
exit(0);
|
Reference in New Issue
Block a user