removed ticketsystem; lots of work on cron stuff
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
if (! defined('MASTER_CRONJOB'))
|
||||
die('You cannot access this file directly!');
|
||||
namespace Froxlor\Cron\Dns;
|
||||
|
||||
use Froxlor\Settings;
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
@@ -14,9 +15,9 @@ if (! defined('MASTER_CRONJOB'))
|
||||
* @author Froxlor team <team@froxlor.org> (2016-)
|
||||
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
|
||||
* @package Cron
|
||||
*
|
||||
*
|
||||
*/
|
||||
class bind extends DnsBase
|
||||
class Bind extends DnsBase
|
||||
{
|
||||
|
||||
private $_bindconf_file = "";
|
||||
@@ -30,9 +31,9 @@ class bind extends DnsBase
|
||||
$this->_cleanZonefiles();
|
||||
|
||||
// check for subfolder in bind-config-directory
|
||||
if (! file_exists(makeCorrectDir(Settings::Get('system.bindconf_directory') . '/domains/'))) {
|
||||
if (! file_exists(\Froxlor\FileDir::makeCorrectDir(Settings::Get('system.bindconf_directory') . '/domains/'))) {
|
||||
$this->_logger->logAction(CRON_ACTION, LOG_NOTICE, 'mkdir ' . escapeshellarg(makeCorrectDir(Settings::Get('system.bindconf_directory') . '/domains/')));
|
||||
safe_exec('mkdir -p ' . escapeshellarg(makeCorrectDir(Settings::Get('system.bindconf_directory') . '/domains/')));
|
||||
safe_exec('mkdir -p ' . escapeshellarg(\Froxlor\FileDir::makeCorrectDir(Settings::Get('system.bindconf_directory') . '/domains/')));
|
||||
}
|
||||
|
||||
$domains = $this->getDomainList();
|
||||
@@ -42,7 +43,7 @@ class bind extends DnsBase
|
||||
return;
|
||||
}
|
||||
|
||||
$bindconf_file = '# ' . Settings::Get('system.bindconf_directory') . 'froxlor_bind.conf' . "\n" . '# Created ' . date('d.m.Y H:i') . "\n" . '# Do NOT manually edit this file, all changes will be deleted after the next domain change at the panel.' . "\n\n";
|
||||
$this->_bindconf_file = '# ' . Settings::Get('system.bindconf_directory') . 'froxlor_bind.conf' . "\n" . '# Created ' . date('d.m.Y H:i') . "\n" . '# Do NOT manually edit this file, all changes will be deleted after the next domain change at the panel.' . "\n\n";
|
||||
|
||||
foreach ($domains as $domain) {
|
||||
if ($domain['ismainbutsubto'] > 0) {
|
||||
@@ -52,7 +53,7 @@ class bind extends DnsBase
|
||||
$this->walkDomainList($domain, $domains);
|
||||
}
|
||||
|
||||
$bindconf_file_handler = fopen(makeCorrectFile(Settings::Get('system.bindconf_directory') . '/froxlor_bind.conf'), 'w');
|
||||
$bindconf_file_handler = fopen(\Froxlor\FileDir::makeCorrectFile(Settings::Get('system.bindconf_directory') . '/froxlor_bind.conf'), 'w');
|
||||
fwrite($bindconf_file_handler, $this->_bindconf_file);
|
||||
fclose($bindconf_file_handler);
|
||||
$this->_logger->logAction(CRON_ACTION, LOG_INFO, 'froxlor_bind.conf written');
|
||||
@@ -60,7 +61,6 @@ class bind extends DnsBase
|
||||
$this->_logger->logAction(CRON_ACTION, LOG_INFO, 'Task4 finished');
|
||||
}
|
||||
|
||||
|
||||
private function walkDomainList($domain, $domains)
|
||||
{
|
||||
$zoneContent = '';
|
||||
@@ -78,29 +78,19 @@ class bind extends DnsBase
|
||||
}
|
||||
|
||||
if ($domain['ismainbutsubto'] == 0) {
|
||||
$zoneContent = (string) createDomainZone(($domain['id'] == 'none') ?
|
||||
$domain :
|
||||
$domain['id'],
|
||||
$isFroxlorHostname);
|
||||
$zoneContent = (string) createDomainZone(($domain['id'] == 'none') ? $domain : $domain['id'], $isFroxlorHostname);
|
||||
$domain['zonefile'] = 'domains/' . $domain['domain'] . '.zone';
|
||||
$zonefile_name = makeCorrectFile(Settings::Get('system.bindconf_directory') . '/' .
|
||||
$domain['zonefile']);
|
||||
$zonefile_name = makeCorrectFile(Settings::Get('system.bindconf_directory') . '/' . $domain['zonefile']);
|
||||
$zonefile_handler = fopen($zonefile_name, 'w');
|
||||
fwrite($zonefile_handler, $zoneContent . $subzones);
|
||||
fclose($zonefile_handler);
|
||||
$this->_logger->logAction(CRON_ACTION, LOG_INFO, '`' . $zonefile_name . '` written');
|
||||
$this->_bindconf_file .= $this->_generateDomainConfig($domain);
|
||||
} else {
|
||||
return (string) createDomainZone(($domain['id'] == 'none') ?
|
||||
$domain :
|
||||
$domain['id'],
|
||||
$isFroxlorHostname,
|
||||
true);
|
||||
return (string) createDomainZone(($domain['id'] == 'none') ? $domain : $domain['id'], $isFroxlorHostname, true);
|
||||
}
|
||||
} else {
|
||||
$this->_logger->logAction(CRON_ACTION, LOG_INFO,
|
||||
'Added zonefile ' . $domain['zonefile'] . ' for domain ' . $domain['domain'] .
|
||||
' - Note that you will also have to handle ALL records for ALL subdomains.');
|
||||
$this->_logger->logAction(CRON_ACTION, LOG_INFO, 'Added zonefile ' . $domain['zonefile'] . ' for domain ' . $domain['domain'] . ' - Note that you will also have to handle ALL records for ALL subdomains.');
|
||||
$this->_bindconf_file .= $this->_generateDomainConfig($domain);
|
||||
}
|
||||
}
|
||||
@@ -112,7 +102,7 @@ class bind extends DnsBase
|
||||
$bindconf_file = '# Domain ID: ' . $domain['id'] . ' - CustomerID: ' . $domain['customerid'] . ' - CustomerLogin: ' . $domain['loginname'] . "\n";
|
||||
$bindconf_file .= 'zone "' . $domain['domain'] . '" in {' . "\n";
|
||||
$bindconf_file .= ' type master;' . "\n";
|
||||
$bindconf_file .= ' file "' . makeCorrectFile(Settings::Get('system.bindconf_directory') . '/' . $domain['zonefile']) . '";' . "\n";
|
||||
$bindconf_file .= ' file "' . \Froxlor\FileDir::makeCorrectFile(Settings::Get('system.bindconf_directory') . '/' . $domain['zonefile']) . '";' . "\n";
|
||||
$bindconf_file .= ' allow-query { any; };' . "\n";
|
||||
|
||||
if (count($this->_ns) > 0 || count($this->_axfr) > 0) {
|
||||
@@ -144,7 +134,7 @@ class bind extends DnsBase
|
||||
|
||||
private function _cleanZonefiles()
|
||||
{
|
||||
$config_dir = makeCorrectFile(Settings::Get('system.bindconf_directory') . '/domains/');
|
||||
$config_dir = \Froxlor\FileDir::makeCorrectFile(Settings::Get('system.bindconf_directory') . '/domains/');
|
||||
|
||||
$this->_logger->logAction(CRON_ACTION, LOG_INFO, 'Cleaning dns zone files from ' . $config_dir);
|
||||
|
||||
@@ -152,13 +142,13 @@ class bind extends DnsBase
|
||||
if (@is_dir($config_dir)) {
|
||||
|
||||
// create directory iterator
|
||||
$its = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($config_dir));
|
||||
$its = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($config_dir));
|
||||
|
||||
// iterate through all subdirs, look for zone files and delete them
|
||||
foreach ($its as $it) {
|
||||
if ($it->isFile()) {
|
||||
// remove file
|
||||
safe_exec('rm -f ' . escapeshellarg(makeCorrectFile($its->getPathname())));
|
||||
\Froxlor\FileDir::safe_exec('rm -f ' . escapeshellarg(makeCorrectFile($its->getPathname())));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,8 @@
|
||||
<?php
|
||||
namespace Froxlor\Cron\Dns;
|
||||
|
||||
use Froxlor\Database;
|
||||
use Froxlor\Settings;
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
@@ -8,11 +12,11 @@
|
||||
* file that was distributed with this source code. You can also view the
|
||||
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
|
||||
*
|
||||
* @copyright (c) the authors
|
||||
* @author Froxlor team <team@froxlor.org> (2016-)
|
||||
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
|
||||
* @package Cron
|
||||
*
|
||||
* @copyright (c) the authors
|
||||
* @author Froxlor team <team@froxlor.org> (2016-)
|
||||
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
|
||||
* @package Cron
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -111,7 +115,7 @@ abstract class DnsBase
|
||||
$domains = array();
|
||||
// don't use fetchall() to be able to set the first column to the domain id and use it later on to set the rows'
|
||||
// array of direct children without having to search the outer array
|
||||
while ($domain = $result_domains_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
while ($domain = $result_domains_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
$domains[$domain["id"]] = $domain;
|
||||
}
|
||||
|
||||
@@ -189,14 +193,14 @@ abstract class DnsBase
|
||||
FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `dkim` = '1' ORDER BY `id` ASC
|
||||
");
|
||||
|
||||
while ($domain = $result_domains_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
while ($domain = $result_domains_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
|
||||
$privkey_filename = makeCorrectFile(Settings::Get('dkim.dkim_prefix') . '/dkim_' . $domain['dkim_id']);
|
||||
$pubkey_filename = makeCorrectFile(Settings::Get('dkim.dkim_prefix') . '/dkim_' . $domain['dkim_id'] . '.public');
|
||||
|
||||
if ($domain['dkim_privkey'] == '' || $domain['dkim_pubkey'] == '') {
|
||||
$max_dkim_id_stmt = Database::query("SELECT MAX(`dkim_id`) as `max_dkim_id` FROM `" . TABLE_PANEL_DOMAINS . "`");
|
||||
$max_dkim_id = $max_dkim_id_stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$max_dkim_id = $max_dkim_id_stmt->fetch(\PDO::FETCH_ASSOC);
|
||||
$domain['dkim_id'] = (int) $max_dkim_id['max_dkim_id'] + 1;
|
||||
$privkey_filename = makeCorrectFile(Settings::Get('dkim.dkim_prefix') . '/dkim_' . $domain['dkim_id']);
|
||||
safe_exec('openssl genrsa -out ' . escapeshellarg($privkey_filename) . ' ' . Settings::Get('dkim.dkim_keylength'));
|
||||
@@ -1,6 +1,5 @@
|
||||
<?php
|
||||
if (! defined('MASTER_CRONJOB'))
|
||||
die('You cannot access this file directly!');
|
||||
namespace Froxlor\Cron\Dns;
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
@@ -16,7 +15,7 @@ if (! defined('MASTER_CRONJOB'))
|
||||
* @package Cron
|
||||
*
|
||||
*/
|
||||
class pdns extends DnsBase
|
||||
class PowerDNS extends DnsBase
|
||||
{
|
||||
|
||||
public function writeConfigs()
|
||||
@@ -86,11 +85,11 @@ class pdns extends DnsBase
|
||||
{
|
||||
$this->_logger->logAction(CRON_ACTION, LOG_INFO, 'Cleaning dns zone entries from database');
|
||||
|
||||
$pdns_domains_stmt = PowerDNS::getDB()->prepare("SELECT `id`, `name` FROM `domains` WHERE `name` = :domain");
|
||||
$pdns_domains_stmt = \Froxlor\Dns\PowerDNS::getDB()->prepare("SELECT `id`, `name` FROM `domains` WHERE `name` = :domain");
|
||||
|
||||
$del_rec_stmt = PowerDNS::getDB()->prepare("DELETE FROM `records` WHERE `domain_id` = :did");
|
||||
$del_meta_stmt = PowerDNS::getDB()->prepare("DELETE FROM `domainmetadata` WHERE `domain_id` = :did");
|
||||
$del_dom_stmt = PowerDNS::getDB()->prepare("DELETE FROM `domains` WHERE `id` = :did");
|
||||
$del_rec_stmt = \Froxlor\Dns\PowerDNS::getDB()->prepare("DELETE FROM `records` WHERE `domain_id` = :did");
|
||||
$del_meta_stmt = \Froxlor\Dns\PowerDNS::getDB()->prepare("DELETE FROM `domainmetadata` WHERE `domain_id` = :did");
|
||||
$del_dom_stmt = \Froxlor\Dns\PowerDNS::getDB()->prepare("DELETE FROM `domains` WHERE `id` = :did");
|
||||
|
||||
foreach ($domains as $domain) {
|
||||
$pdns_domains_stmt->execute(array(
|
||||
@@ -119,7 +118,7 @@ class pdns extends DnsBase
|
||||
'domainname' => $domainname,
|
||||
'serial' => $serial
|
||||
));
|
||||
$lastid = PowerDNS::getDB()->lastInsertId();
|
||||
$lastid = \Froxlor\Dns\PowerDNS::getDB()->lastInsertId();
|
||||
return $lastid;
|
||||
}
|
||||
|
||||
@@ -140,7 +139,7 @@ class pdns extends DnsBase
|
||||
");
|
||||
|
||||
foreach ($records as $record) {
|
||||
if ($record instanceof DnsZone) {
|
||||
if ($record instanceof \Froxlor\Dns\DnsZone) {
|
||||
$this->_insertRecords($domainid, $record->records, $record->origin);
|
||||
continue;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,9 @@
|
||||
<?php if (!defined('MASTER_CRONJOB')) die('You cannot access this file directly!');
|
||||
<?php
|
||||
namespace Froxlor\Cron\Http;
|
||||
|
||||
use \Froxlor\Database;
|
||||
use \Froxlor\Settings;
|
||||
use Froxlor\Cron\Http\Php\PhpInterface;
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
@@ -17,7 +22,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
class apache_fcgid extends apache
|
||||
class ApacheFcgi extends Apache
|
||||
{
|
||||
protected function composePhpOptions($domain, $ssl_vhost = false)
|
||||
{
|
||||
@@ -25,7 +30,7 @@ class apache_fcgid extends apache
|
||||
|
||||
if($domain['phpenabled_customer'] == 1 && $domain['phpenabled_vhost'] == '1')
|
||||
{
|
||||
$php = new phpinterface($domain);
|
||||
$php = new PhpInterface($domain);
|
||||
$phpconfig = $php->getPhpConfig((int)$domain['phpsettingid']);
|
||||
|
||||
if((int)Settings::Get('phpfpm.enabled') == 1)
|
||||
@@ -56,12 +61,12 @@ class apache_fcgid extends apache
|
||||
$php_options_text.= ' SetHandler proxy:unix:' . $php->getInterface()->getSocketFile() . '|fcgi://localhost'. "\n";
|
||||
$php_options_text.= ' </FilesMatch>' . "\n";
|
||||
|
||||
$mypath_dir = new frxDirectory($domain['documentroot']);
|
||||
$mypath_dir = new \Froxlor\Http\Directory($domain['documentroot']);
|
||||
|
||||
// only create the require all granted if there is not active directory-protection
|
||||
// for this path, as this would be the first require and therefore grant all access
|
||||
if ($mypath_dir->isUserProtected() == false) {
|
||||
$php_options_text.= ' <Directory "' . makeCorrectDir($domain['documentroot']) . '">' . "\n";
|
||||
$php_options_text.= ' <Directory "' . \Froxlor\FileDir::makeCorrectDir($domain['documentroot']) . '">' . "\n";
|
||||
if ($phpconfig['pass_authorizationheader'] == '1') {
|
||||
$php_options_text.= ' CGIPassAuth On' . "\n";
|
||||
}
|
||||
@@ -70,7 +75,7 @@ class apache_fcgid extends apache
|
||||
$php_options_text.= ' </Directory>' . "\n";
|
||||
} elseif ($phpconfig['pass_authorizationheader'] == '1') {
|
||||
// allow Pass of Authorization header
|
||||
$php_options_text.= ' <Directory "' . makeCorrectDir($domain['documentroot']) . '">' . "\n";
|
||||
$php_options_text.= ' <Directory "' . \Froxlor\FileDir::makeCorrectDir($domain['documentroot']) . '">' . "\n";
|
||||
$php_options_text.= ' CGIPassAuth On' . "\n";
|
||||
$php_options_text.= ' </Directory>' . "\n";
|
||||
}
|
||||
@@ -81,7 +86,7 @@ class apache_fcgid extends apache
|
||||
$addheader = " -pass-header Authorization";
|
||||
}
|
||||
$php_options_text.= ' FastCgiExternalServer ' . $php->getInterface()->getAliasConfigDir() . $srvName . ' -socket ' . $php->getInterface()->getSocketFile() . ' -idle-timeout ' . $phpconfig['fpm_settings']['idle_timeout'] . $addheader . "\n";
|
||||
$php_options_text.= ' <Directory "' . makeCorrectDir($domain['documentroot']) . '">' . "\n";
|
||||
$php_options_text.= ' <Directory "' . \Froxlor\FileDir::makeCorrectDir($domain['documentroot']) . '">' . "\n";
|
||||
$filesmatch = $phpconfig['fpm_settings']['limit_extensions'];
|
||||
$extensions = explode(" ", $filesmatch);
|
||||
$filesmatch = "";
|
||||
@@ -97,7 +102,7 @@ class apache_fcgid extends apache
|
||||
$php_options_text.= ' </FilesMatch>' . "\n";
|
||||
// >=apache-2.4 enabled?
|
||||
if (Settings::Get('system.apache24') == '1') {
|
||||
$mypath_dir = new frxDirectory($domain['documentroot']);
|
||||
$mypath_dir = new \Froxlor\Http\Directory($domain['documentroot']);
|
||||
// only create the require all granted if there is not active directory-protection
|
||||
// for this path, as this would be the first require and therefore grant all access
|
||||
if ($mypath_dir->isUserProtected() == false) {
|
||||
@@ -123,7 +128,7 @@ class apache_fcgid extends apache
|
||||
else
|
||||
{
|
||||
$php_options_text.= ' SuexecUserGroup "' . $domain['loginname'] . '" "' . $domain['loginname'] . '"' . "\n";
|
||||
$php_options_text.= ' <Directory "' . makeCorrectDir($domain['documentroot']) . '">' . "\n";
|
||||
$php_options_text.= ' <Directory "' . \Froxlor\FileDir::makeCorrectDir($domain['documentroot']) . '">' . "\n";
|
||||
$file_extensions = explode(' ', $phpconfig['file_extensions']);
|
||||
$php_options_text.= ' <FilesMatch "\.(' . implode('|', $file_extensions) . ')$">' . "\n";
|
||||
$php_options_text.= ' SetHandler fcgid-script' . "\n";
|
||||
@@ -135,7 +140,7 @@ class apache_fcgid extends apache
|
||||
$php_options_text.= ' </FilesMatch>' . "\n";
|
||||
// >=apache-2.4 enabled?
|
||||
if (Settings::Get('system.apache24') == '1') {
|
||||
$mypath_dir = new frxDirectory($domain['documentroot']);
|
||||
$mypath_dir = new \Froxlor\Http\Directory($domain['documentroot']);
|
||||
// only create the require all granted if there is not active directory-protection
|
||||
// for this path, as this would be the first require and therefore grant all access
|
||||
if ($mypath_dir->isUserProtected() == false) {
|
||||
@@ -171,7 +176,7 @@ class apache_fcgid extends apache
|
||||
|| (Settings::Get('phpfpm.enabled') == '1'
|
||||
&& Settings::Get('phpfpm.enabled_ownvhost') == '1')
|
||||
) {
|
||||
$mypath = makeCorrectDir(dirname(dirname(dirname(__FILE__)))); // /var/www/froxlor, needed for chown
|
||||
$mypath = \Froxlor\Froxlor::getInstallDir();
|
||||
|
||||
if (Settings::Get('system.mod_fcgid_ownvhost') == '1')
|
||||
{
|
||||
@@ -212,10 +217,10 @@ class apache_fcgid extends apache
|
||||
|
||||
// all the files and folders have to belong to the local user
|
||||
// now because we also use fcgid for our own vhost
|
||||
safe_exec('chown -R ' . $user . ':' . $group . ' ' . escapeshellarg($mypath));
|
||||
\Froxlor\FileDir::safe_exec('chown -R ' . $user . ':' . $group . ' ' . escapeshellarg($mypath));
|
||||
|
||||
// get php.ini for our own vhost
|
||||
$php = new phpinterface($domain);
|
||||
$php = new PhpInterface($domain);
|
||||
|
||||
// get php-config
|
||||
if (Settings::Get('phpfpm.enabled') == '1') {
|
||||
319
lib/Froxlor/Cron/Http/ConfigIO.php
Normal file
319
lib/Froxlor/Cron/Http/ConfigIO.php
Normal file
@@ -0,0 +1,319 @@
|
||||
<?php
|
||||
namespace Froxlor\Cron\Http;
|
||||
|
||||
use Froxlor\Settings;
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||
*
|
||||
* For the full copyright and license information, please view the COPYING
|
||||
* file that was distributed with this source code. You can also view the
|
||||
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
|
||||
*
|
||||
* @copyright (c) the authors
|
||||
* @author Michael Kaufmann <mkaufmann@nutime.de>
|
||||
* @author Froxlor team <team@froxlor.org> (2010-)
|
||||
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
|
||||
* @package Cron
|
||||
*
|
||||
* @since 0.9.29
|
||||
*
|
||||
*/
|
||||
class ConfigIO
|
||||
{
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{}
|
||||
|
||||
/**
|
||||
* clean up former created configs, including (if enabled)
|
||||
* awstats, fcgid, php-fpm and of course automatically created
|
||||
* webserver vhost and diroption files
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function cleanUp()
|
||||
{
|
||||
|
||||
// old error logs
|
||||
$this->_cleanErrLogs();
|
||||
|
||||
// awstats files
|
||||
$this->_cleanAwstatsFiles();
|
||||
|
||||
// fcgid files
|
||||
$this->_cleanFcgidFiles();
|
||||
|
||||
// php-fpm files
|
||||
$this->_cleanFpmFiles();
|
||||
|
||||
// clean webserver-configs
|
||||
$this->_cleanWebserverConfigs();
|
||||
|
||||
// old htpasswd files
|
||||
$this->_cleanHtpasswdFiles();
|
||||
|
||||
// customer-specified ssl-certificates
|
||||
$this->_cleanCustomerSslCerts();
|
||||
}
|
||||
|
||||
private function _cleanErrLogs()
|
||||
{
|
||||
$err_dir = \Froxlor\FileDir::makeCorrectDir(\Froxlor\Froxlor::getInstallDir() . "/logs/");
|
||||
if (@is_dir($err_dir)) {
|
||||
// now get rid of old stuff
|
||||
// (but append /*.log so we don't delete the directory)
|
||||
$err_dir .= '/*.log';
|
||||
\Froxlor\FileDir::safe_exec('rm -f ' . \Froxlor\FileDir::makeCorrectFile($err_dir));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* remove customer-specified auto-generated ssl-certificates
|
||||
* (they are being regenerated)
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
private function _cleanCustomerSslCerts()
|
||||
{
|
||||
|
||||
/*
|
||||
* only clean up if we're actually using SSL
|
||||
*/
|
||||
if (Settings::Get('system.use_ssl') == '1') {
|
||||
// get correct directory
|
||||
$configdir = $this->_getFile('system', 'customer_ssl_path');
|
||||
if ($configdir !== false) {
|
||||
|
||||
$configdir = \Froxlor\FileDir::makeCorrectDir($configdir);
|
||||
|
||||
if (@is_dir($configdir)) {
|
||||
// now get rid of old stuff
|
||||
// (but append /* so we don't delete the directory)
|
||||
$configdir .= '/*';
|
||||
\Froxlor\FileDir::safe_exec('rm -f ' . \Froxlor\FileDir::makeCorrectFile($configdir));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* remove webserver related configuration files before regeneration
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
private function _cleanWebserverConfigs()
|
||||
{
|
||||
|
||||
// get directories
|
||||
$configdirs = array();
|
||||
$dir = $this->_getFile('system', 'apacheconf_vhost');
|
||||
if ($dir !== false)
|
||||
$configdirs[] = \Froxlor\FileDir::makeCorrectDir($dir);
|
||||
|
||||
$dir = $this->_getFile('system', 'apacheconf_diroptions');
|
||||
if ($dir !== false)
|
||||
$configdirs[] = \Froxlor\FileDir::makeCorrectDir($dir);
|
||||
|
||||
// file pattern
|
||||
$pattern = "/^([0-9]){2}_(froxlor|syscp)_(.+)\.conf$/";
|
||||
|
||||
// check ALL the folders
|
||||
foreach ($configdirs as $config_dir) {
|
||||
|
||||
// check directory
|
||||
if (@is_dir($config_dir)) {
|
||||
|
||||
// create directory iterator
|
||||
$its = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($config_dir));
|
||||
|
||||
// iterate through all subdirs,
|
||||
// look for vhost/diroption files
|
||||
// and delete them
|
||||
foreach ($its as $fullFileName => $it) {
|
||||
if ($it->isFile() && preg_match($pattern, $it->getFilename())) {
|
||||
// remove file
|
||||
\Froxlor\FileDir::safe_exec('rm -f ' . escapeshellarg(\Froxlor\FileDir::makeCorrectFile($its->getPathname())));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* remove htpasswd files before regeneration
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
private function _cleanHtpasswdFiles()
|
||||
{
|
||||
|
||||
// get correct directory
|
||||
$configdir = $this->_getFile('system', 'apacheconf_htpasswddir');
|
||||
|
||||
if ($configdir !== false) {
|
||||
$configdir = \Froxlor\FileDir::makeCorrectDir($configdir);
|
||||
|
||||
if (@is_dir($configdir)) {
|
||||
// now get rid of old stuff
|
||||
// (but append /* so we don't delete the directory)
|
||||
$configdir .= '/*';
|
||||
\Froxlor\FileDir::safe_exec('rm -f ' . \Froxlor\FileDir::makeCorrectFile($configdir));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* remove awstats related configuration files before regeneration
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
private function _cleanAwstatsFiles()
|
||||
{
|
||||
if (Settings::Get('system.awstats_enabled') == '0') {
|
||||
return;
|
||||
}
|
||||
|
||||
// dhr: cleanout froxlor-generated awstats configs prior to re-creation
|
||||
$awstatsclean = array();
|
||||
$awstatsclean['header'] = "## GENERATED BY FROXLOR\n";
|
||||
$awstatsclean['headerold'] = "## GENERATED BY SYSCP\n";
|
||||
$awstatsclean['path'] = $this->_getFile('system', 'awstats_conf');
|
||||
|
||||
/**
|
||||
* don't do anything if the directory does not exist
|
||||
* (e.g.
|
||||
* awstats not installed yet or whatever)
|
||||
* fixes #45
|
||||
*/
|
||||
if ($awstatsclean['path'] !== false && is_dir($awstatsclean['path'])) {
|
||||
$awstatsclean['dir'] = dir($awstatsclean['path']);
|
||||
while ($awstatsclean['entry'] = $awstatsclean['dir']->read()) {
|
||||
$awstatsclean['fullentry'] = \Froxlor\FileDir::makeCorrectFile($awstatsclean['path'] . '/' . $awstatsclean['entry']);
|
||||
/**
|
||||
* don't do anything if the file does not exist
|
||||
*/
|
||||
if (@file_exists($awstatsclean['fullentry'])) {
|
||||
$awstatsclean['fh'] = fopen($awstatsclean['fullentry'], 'r');
|
||||
$awstatsclean['headerRead'] = fgets($awstatsclean['fh'], strlen($awstatsclean['header']) + 1);
|
||||
fclose($awstatsclean['fh']);
|
||||
|
||||
if ($awstatsclean['headerRead'] == $awstatsclean['header'] || $awstatsclean['headerRead'] == $awstatsclean['headerold']) {
|
||||
$awstats_conf_file = \Froxlor\FileDir::makeCorrectFile($awstatsclean['fullentry']);
|
||||
@unlink($awstats_conf_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($awstatsclean);
|
||||
// end dhr
|
||||
}
|
||||
|
||||
/**
|
||||
* remove fcgid related configuration files before regeneration
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
private function _cleanFcgidFiles()
|
||||
{
|
||||
if (Settings::Get('system.mod_fcgid') == '0') {
|
||||
return;
|
||||
}
|
||||
|
||||
// get correct directory
|
||||
$configdir = $this->_getFile('system', 'mod_fcgid_configdir');
|
||||
if ($configdir !== false) {
|
||||
|
||||
$configdir = \Froxlor\FileDir::makeCorrectDir($configdir);
|
||||
|
||||
if (@is_dir($configdir)) {
|
||||
// create directory iterator
|
||||
$its = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($configdir));
|
||||
|
||||
// iterate through all subdirs,
|
||||
// look for php-fcgi-starter files
|
||||
// and take immutable-flag away from them
|
||||
// so we can delete them :)
|
||||
foreach ($its as $fullFileName => $it) {
|
||||
if ($it->isFile() && $it->getFilename() == 'php-fcgi-starter') {
|
||||
// set chattr -i
|
||||
\Froxlor\FileDir::removeImmutable($its->getPathname());
|
||||
}
|
||||
}
|
||||
|
||||
// now get rid of old stuff
|
||||
// (but append /* so we don't delete the directory)
|
||||
$configdir .= '/*';
|
||||
\Froxlor\FileDir::safe_exec('rm -rf ' . \Froxlor\FileDir::makeCorrectFile($configdir));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* remove php-fpm related configuration files before regeneration
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
private function _cleanFpmFiles()
|
||||
{
|
||||
if (Settings::Get('phpfpm.enabled') == '0') {
|
||||
return;
|
||||
}
|
||||
|
||||
// get all fpm config paths
|
||||
$fpmconf_sel = \Froxlor\Database\Database::prepare("SELECT config_dir FROM `" . TABLE_PANEL_FPMDAEMONS . "`");
|
||||
\Froxlor\Database\Database::pexecute($fpmconf_sel);
|
||||
$fpmconf_paths = $fpmconf_sel->fetchAll(\PDO::FETCH_ASSOC);
|
||||
// clean all php-fpm config-dirs
|
||||
foreach ($fpmconf_paths as $configdir) {
|
||||
$configdir = \Froxlor\FileDir::makeCorrectDir($configdir['config_dir']);
|
||||
if (@is_dir($configdir)) {
|
||||
// now get rid of old stuff
|
||||
// (but append /*.conf so we don't delete the directory)
|
||||
$configdir .= '/*.conf';
|
||||
\Froxlor\FileDir::safe_exec('rm -f ' . makeCorrectFile($configdir));
|
||||
} else {
|
||||
\Froxlor\FileDir::safe_exec('mkdir -p ' . $configdir);
|
||||
}
|
||||
}
|
||||
|
||||
// also remove aliasconfigdir #1273
|
||||
$aliasconfigdir = $this->_getFile('phpfpm', 'aliasconfigdir');
|
||||
if ($aliasconfigdir !== false) {
|
||||
$aliasconfigdir = \Froxlor\FileDir::makeCorrectDir($aliasconfigdir);
|
||||
if (@is_dir($aliasconfigdir)) {
|
||||
$aliasconfigdir .= '/*';
|
||||
\Froxlor\FileDir::safe_exec('rm -rf ' . \Froxlor\FileDir::makeCorrectFile($aliasconfigdir));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a file/direcotry from the settings and checks whether it exists
|
||||
*
|
||||
* @param string $group
|
||||
* settings-group
|
||||
* @param string $varname
|
||||
* var-name
|
||||
* @param boolean $check_exists
|
||||
* check if the file exists
|
||||
*
|
||||
* @return string|boolean complete path including filename if any or false on error
|
||||
*/
|
||||
private function _getFile($group, $varname, $check_exists = true)
|
||||
{
|
||||
|
||||
// read from settings
|
||||
$file = Settings::Get($group . '.' . $varname);
|
||||
|
||||
// check whether it exists
|
||||
if ($check_exists && @file_exists($file) == false) {
|
||||
return false;
|
||||
}
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
121
lib/Froxlor/Cron/Http/DomainSSL.php
Normal file
121
lib/Froxlor/Cron/Http/DomainSSL.php
Normal file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
namespace Froxlor\Cron\Http;
|
||||
|
||||
use Froxlor\Database;
|
||||
use Froxlor\Settings;
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||
*
|
||||
* For the full copyright and license information, please view the COPYING
|
||||
* file that was distributed with this source code. You can also view the
|
||||
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
|
||||
*
|
||||
* @copyright (c) the authors
|
||||
* @author Michael Kaufmann <mkaufmann@nutime.de>
|
||||
* @author Froxlor team <team@froxlor.org> (2010-)
|
||||
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
|
||||
* @package Cron
|
||||
*
|
||||
* @since 0.9.29
|
||||
*
|
||||
*/
|
||||
class DomainSSL
|
||||
{
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{}
|
||||
|
||||
/**
|
||||
* read domain-related (or if empty, parentdomain-related) ssl-certificates from the database
|
||||
* and (if not empty) set the corresponding array-indices (ssl_cert_file, ssl_key_file,
|
||||
* ssl_ca_file and ssl_cert_chainfile).
|
||||
* Hence the parameter as reference.
|
||||
*
|
||||
* @param array $domain
|
||||
* domain-array as reference so we can set the corresponding array-indices
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function setDomainSSLFilesArray(array &$domain = null)
|
||||
{
|
||||
// check if the domain itself has a certificate defined
|
||||
$dom_certs_stmt = Database::prepare("
|
||||
SELECT * FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` WHERE `domainid` = :domid
|
||||
");
|
||||
$dom_certs = Database::pexecute_first($dom_certs_stmt, array(
|
||||
'domid' => $domain['id']
|
||||
));
|
||||
|
||||
if (! is_array($dom_certs) || ! isset($dom_certs['ssl_cert_file']) || $dom_certs['ssl_cert_file'] == '') {
|
||||
// maybe its parent?
|
||||
if (isset($domain['parentdomainid']) && $domain['parentdomainid'] != 0) {
|
||||
$dom_certs = Database::pexecute_first($dom_certs_stmt, array(
|
||||
'domid' => $domain['parentdomainid']
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// check if it's an array and if the most important field is set
|
||||
if (is_array($dom_certs) && isset($dom_certs['ssl_cert_file']) && $dom_certs['ssl_cert_file'] != '') {
|
||||
// get destination path
|
||||
$sslcertpath = makeCorrectDir(Settings::Get('system.customer_ssl_path'));
|
||||
// create path if it does not exist
|
||||
if (! file_exists($sslcertpath)) {
|
||||
safe_exec('mkdir -p ' . escapeshellarg($sslcertpath));
|
||||
}
|
||||
// make correct files for the certificates
|
||||
$ssl_files = array(
|
||||
'ssl_cert_file' => makeCorrectFile($sslcertpath . '/' . $domain['domain'] . '.crt'),
|
||||
'ssl_key_file' => makeCorrectFile($sslcertpath . '/' . $domain['domain'] . '.key')
|
||||
);
|
||||
|
||||
if (Settings::Get('system.webserver') == 'lighttpd') {
|
||||
// put my.crt and my.key together for lighty.
|
||||
$dom_certs['ssl_cert_file'] = trim($dom_certs['ssl_cert_file']) . "\n" . trim($dom_certs['ssl_key_file']) . "\n";
|
||||
$ssl_files['ssl_key_file'] = '';
|
||||
}
|
||||
|
||||
// initialize optional files
|
||||
$ssl_files['ssl_ca_file'] = '';
|
||||
$ssl_files['ssl_cert_chainfile'] = '';
|
||||
// set them if they are != empty
|
||||
if ($dom_certs['ssl_ca_file'] != '') {
|
||||
$ssl_files['ssl_ca_file'] = makeCorrectFile($sslcertpath . '/' . $domain['domain'] . '_CA.pem');
|
||||
}
|
||||
if ($dom_certs['ssl_cert_chainfile'] != '') {
|
||||
if (Settings::Get('system.webserver') == 'nginx') {
|
||||
// put ca.crt in my.crt, as nginx does not support a separate chain file.
|
||||
$dom_certs['ssl_cert_file'] = trim($dom_certs['ssl_cert_file']) . "\n" . trim($dom_certs['ssl_cert_chainfile']) . "\n";
|
||||
} else {
|
||||
$ssl_files['ssl_cert_chainfile'] = makeCorrectFile($sslcertpath . '/' . $domain['domain'] . '_chain.pem');
|
||||
}
|
||||
}
|
||||
// will only be generated to be used externally, froxlor does not need this
|
||||
if ($dom_certs['ssl_fullchain_file'] != '') {
|
||||
$ssl_files['ssl_fullchain_file'] = makeCorrectFile($sslcertpath . '/' . $domain['domain'] . '_fullchain.pem');
|
||||
}
|
||||
// create them on the filesystem
|
||||
foreach ($ssl_files as $type => $filename) {
|
||||
if ($filename != '') {
|
||||
touch($filename);
|
||||
$_fh = fopen($filename, 'w');
|
||||
fwrite($_fh, $dom_certs[$type]);
|
||||
fclose($_fh);
|
||||
chmod($filename, 0600);
|
||||
}
|
||||
}
|
||||
// override corresponding array values
|
||||
$domain['ssl_cert_file'] = $ssl_files['ssl_cert_file'];
|
||||
$domain['ssl_key_file'] = $ssl_files['ssl_key_file'];
|
||||
$domain['ssl_ca_file'] = $ssl_files['ssl_ca_file'];
|
||||
$domain['ssl_cert_chainfile'] = $ssl_files['ssl_cert_chainfile'];
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,8 @@
|
||||
<?php
|
||||
namespace Froxlor\Cron\Http;
|
||||
|
||||
use Froxlor\Database;
|
||||
use Froxlor\Settings;
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
@@ -8,18 +12,17 @@
|
||||
* file that was distributed with this source code. You can also view the
|
||||
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
|
||||
*
|
||||
* @copyright (c) the authors
|
||||
* @author Froxlor team <team@froxlor.org> (2016-)
|
||||
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
|
||||
* @package Cron
|
||||
*
|
||||
* @copyright (c) the authors
|
||||
* @author Froxlor team <team@froxlor.org> (2016-)
|
||||
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
|
||||
* @package Cron
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class HttpConfigBase
|
||||
*
|
||||
* Base class for all HTTP server configs
|
||||
*
|
||||
*/
|
||||
class HttpConfigBase
|
||||
{
|
||||
@@ -1,7 +1,10 @@
|
||||
<?php
|
||||
namespace Froxlor\Cron\Http;
|
||||
|
||||
if (! defined('MASTER_CRONJOB'))
|
||||
die('You cannot access this file directly!');
|
||||
use Froxlor\Database;
|
||||
use Froxlor\Settings;
|
||||
use Froxlor\Cron\Http\Php\Fpm;
|
||||
use Froxlor\Cron\Http\Php\PhpInterface;
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
@@ -21,15 +24,9 @@ if (! defined('MASTER_CRONJOB'))
|
||||
* @todo ssl-redirect to non-standard port
|
||||
*/
|
||||
|
||||
require_once (dirname(__FILE__) . '/../classes/class.HttpConfigBase.php');
|
||||
|
||||
class lighttpd extends HttpConfigBase
|
||||
class Lighttpd extends HttpConfigBase
|
||||
{
|
||||
|
||||
private $logger = false;
|
||||
|
||||
private $idnaConvert = false;
|
||||
|
||||
// protected
|
||||
protected $lighttpd_data = array();
|
||||
|
||||
@@ -49,19 +46,13 @@ class lighttpd extends HttpConfigBase
|
||||
*/
|
||||
private $_deactivated = false;
|
||||
|
||||
public function __construct($logger, $idnaConvert)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
$this->idnaConvert = $idnaConvert;
|
||||
}
|
||||
|
||||
public function reload()
|
||||
{
|
||||
if ((int) Settings::Get('phpfpm.enabled') == 1) {
|
||||
// get all start/stop commands
|
||||
$startstop_sel = Database::prepare("SELECT reload_cmd, config_dir FROM `" . TABLE_PANEL_FPMDAEMONS . "`");
|
||||
Database::pexecute($startstop_sel);
|
||||
$restart_cmds = $startstop_sel->fetchAll(PDO::FETCH_ASSOC);
|
||||
$restart_cmds = $startstop_sel->fetchAll(\PDO::FETCH_ASSOC);
|
||||
// restart all php-fpm instances
|
||||
foreach ($restart_cmds as $restart_cmd) {
|
||||
// check whether the config dir is empty (no domains uses this daemon)
|
||||
@@ -69,7 +60,7 @@ class lighttpd extends HttpConfigBase
|
||||
$_conffiles = glob(makeCorrectFile($restart_cmd['config_dir'] . "/*.conf"));
|
||||
if ($_conffiles === false || empty($_conffiles)) {
|
||||
$this->logger->logAction(CRON_ACTION, LOG_INFO, 'lighttpd::reload: fpm config directory "' . $restart_cmd['config_dir'] . '" is empty. Creating dummy.');
|
||||
phpinterface_fpm::createDummyPool($restart_cmd['config_dir']);
|
||||
Fpm::createDummyPool($restart_cmd['config_dir']);
|
||||
}
|
||||
$this->logger->logAction(CRON_ACTION, LOG_INFO, 'lighttpd::reload: running ' . $restart_cmd['reload_cmd']);
|
||||
safe_exec(escapeshellcmd($restart_cmd['reload_cmd']));
|
||||
@@ -83,7 +74,7 @@ class lighttpd extends HttpConfigBase
|
||||
{
|
||||
$result_ipsandports_stmt = Database::query("SELECT * FROM `" . TABLE_PANEL_IPSANDPORTS . "` ORDER BY `ip` ASC, `port` ASC");
|
||||
|
||||
while ($row_ipsandports = $result_ipsandports_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
while ($row_ipsandports = $result_ipsandports_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
if (filter_var($row_ipsandports['ip'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
|
||||
$ip = '[' . $row_ipsandports['ip'] . ']';
|
||||
$port = $row_ipsandports['port'];
|
||||
@@ -176,7 +167,7 @@ class lighttpd extends HttpConfigBase
|
||||
'fpm_config_id' => isset($fpm_config['id']) ? $fpm_config['id'] : 1
|
||||
);
|
||||
|
||||
$php = new phpinterface($domain);
|
||||
$php = new PhpInterface($domain);
|
||||
|
||||
$this->lighttpd_data[$vhost_filename] .= ' fastcgi.server = ( ' . "\n";
|
||||
$this->lighttpd_data[$vhost_filename] .= "\t" . '".php" => (' . "\n";
|
||||
@@ -345,7 +336,7 @@ class lighttpd extends HttpConfigBase
|
||||
));
|
||||
|
||||
$htaccess_text = '';
|
||||
while ($row_htpasswds = $result_htpasswds_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
while ($row_htpasswds = $result_htpasswds_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
$row_htpasswds['path'] = makeCorrectDir($row_htpasswds['path']);
|
||||
mkDirWithCorrectOwnership($domain['documentroot'], $row_htpasswds['path'], $domain['guid'], $domain['guid']);
|
||||
|
||||
@@ -658,7 +649,7 @@ class lighttpd extends HttpConfigBase
|
||||
'domainid' => $domain['id']
|
||||
));
|
||||
|
||||
while (($alias_domain = $alias_domains_stmt->fetch(PDO::FETCH_ASSOC)) !== false) {
|
||||
while (($alias_domain = $alias_domains_stmt->fetch(\PDO::FETCH_ASSOC)) !== false) {
|
||||
|
||||
$server_alias .= ' ' . $alias_domain['domain'] . ' ';
|
||||
|
||||
@@ -707,7 +698,7 @@ class lighttpd extends HttpConfigBase
|
||||
$path_options = '';
|
||||
$error_string = '';
|
||||
|
||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
while ($row = $result_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
|
||||
if (! empty($row['error404path'])) {
|
||||
$defhandler = $row['error404path'];
|
||||
@@ -768,7 +759,7 @@ class lighttpd extends HttpConfigBase
|
||||
'customerid' => $domain['customerid']
|
||||
));
|
||||
|
||||
while ($row_htpasswds = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
while ($row_htpasswds = $result_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
if ($auth_backend_loaded[$domain['ipandport']] != 'yes' && $auth_backend_loaded[$domain['ssl_ipandport']] != 'yes') {
|
||||
$filename = $domain['customerid'] . '.htpasswd';
|
||||
|
||||
@@ -832,7 +823,7 @@ class lighttpd extends HttpConfigBase
|
||||
'domainid' => $domain['id']
|
||||
));
|
||||
|
||||
while (($alias_domain = $alias_domains_stmt->fetch(PDO::FETCH_ASSOC)) !== false) {
|
||||
while (($alias_domain = $alias_domains_stmt->fetch(\PDO::FETCH_ASSOC)) !== false) {
|
||||
$alias_domain_name = str_replace('.', '\.', $alias_domain['domain']);
|
||||
|
||||
if ($alias_domain['iswildcarddomain'] == '1') {
|
||||
@@ -953,7 +944,7 @@ class lighttpd extends HttpConfigBase
|
||||
{
|
||||
$this->logger->logAction(CRON_ACTION, LOG_INFO, "lighttpd::writeConfigs: rebuilding " . Settings::Get('system.apacheconf_vhost'));
|
||||
|
||||
$vhostDir = new frxDirectory(Settings::Get('system.apacheconf_vhost'));
|
||||
$vhostDir = new \Froxlor\Http\Directory(Settings::Get('system.apacheconf_vhost'));
|
||||
if (! $vhostDir->isConfigDir()) {
|
||||
// Save one big file
|
||||
$vhosts_file = '';
|
||||
@@ -998,7 +989,7 @@ class lighttpd extends HttpConfigBase
|
||||
}
|
||||
|
||||
// Write the diroptions
|
||||
$htpasswdDir = new frxDirectory(Settings::Get('system.apacheconf_htpasswddir'));
|
||||
$htpasswdDir = new \Froxlor\Http\Directory(Settings::Get('system.apacheconf_htpasswddir'));
|
||||
if ($htpasswdDir->isConfigDir()) {
|
||||
foreach ($this->needed_htpasswds as $key => $data) {
|
||||
if (! is_dir(Settings::Get('system.apacheconf_htpasswddir'))) {
|
||||
151
lib/Froxlor/Cron/Http/LighttpdFcgi.php
Normal file
151
lib/Froxlor/Cron/Http/LighttpdFcgi.php
Normal file
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
namespace Froxlor\Cron\Http;
|
||||
|
||||
use Froxlor\Database;
|
||||
use Froxlor\Settings;
|
||||
use Froxlor\Cron\Http\Php\PhpInterface;
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||
*
|
||||
* For the full copyright and license information, please view the COPYING
|
||||
* file that was distributed with this source code. You can also view the
|
||||
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
|
||||
*
|
||||
* @copyright (c) the authors
|
||||
* @author Froxlor team <team@froxlor.org> (2010-)
|
||||
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
|
||||
* @package Cron
|
||||
*
|
||||
*/
|
||||
class LighttpdFcgi extends Lighttpd
|
||||
{
|
||||
|
||||
protected function composePhpOptions($domain)
|
||||
{
|
||||
$php_options_text = '';
|
||||
|
||||
if ($domain['phpenabled_customer'] == 1 && $domain['phpenabled_vhost'] == '1') {
|
||||
$php = new PhpInterface($domain);
|
||||
$phpconfig = $php->getPhpConfig((int) $domain['phpsettingid']);
|
||||
|
||||
// vhost data for php-fpm
|
||||
if ((int) Settings::Get('phpfpm.enabled') == 1) {
|
||||
$php_options_text = ' fastcgi.server = ( ' . "\n";
|
||||
$php_options_text .= "\t" . '".php" => (' . "\n";
|
||||
$php_options_text .= "\t\t" . '"localhost" => (' . "\n";
|
||||
$php_options_text .= "\t\t" . '"socket" => "' . $php->getInterface()->getSocketFile() . '",' . "\n";
|
||||
$php_options_text .= "\t\t" . '"check-local" => "enable",' . "\n";
|
||||
$php_options_text .= "\t\t" . '"disable-time" => 1' . "\n";
|
||||
$php_options_text .= "\t" . ')' . "\n";
|
||||
$php_options_text .= "\t" . ')' . "\n";
|
||||
$php_options_text .= ' )' . "\n";
|
||||
} // vhost data for fcgid
|
||||
elseif ((int) Settings::Get('system.mod_fcgid') == 1) {
|
||||
$php_options_text = ' fastcgi.server = ( ' . "\n";
|
||||
$file_extensions = explode(' ', $phpconfig['file_extensions']);
|
||||
foreach ($file_extensions as $f_extension) {
|
||||
$php_options_text .= "\t" . '".' . $f_extension . '" => (' . "\n";
|
||||
$php_options_text .= "\t\t" . '"localhost" => (' . "\n";
|
||||
$php_options_text .= "\t\t" . '"socket" => "/var/run/lighttpd/' . $domain['loginname'] . '-' . $domain['domain'] . '-php.socket",' . "\n";
|
||||
$php_options_text .= "\t\t" . '"bin-path" => "' . $phpconfig['binary'] . ' -c ' . $php->getInterface()->getIniFile() . '",' . "\n";
|
||||
$php_options_text .= "\t\t" . '"bin-environment" => (' . "\n";
|
||||
if ((int) $domain['mod_fcgid_starter'] != - 1) {
|
||||
$php_options_text .= "\t\t\t" . '"PHP_FCGI_CHILDREN" => "' . (int) $domain['mod_fcgid_starter'] . '",' . "\n";
|
||||
} else {
|
||||
if ((int) $phpconfig['mod_fcgid_starter'] != - 1) {
|
||||
$php_options_text .= "\t\t\t" . '"PHP_FCGI_CHILDREN" => "' . (int) $phpconfig['mod_fcgid_starter'] . '",' . "\n";
|
||||
} else {
|
||||
$php_options_text .= "\t\t\t" . '"PHP_FCGI_CHILDREN" => "' . (int) Settings::Get('system.mod_fcgid_starter') . '",' . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ((int) $domain['mod_fcgid_maxrequests'] != - 1) {
|
||||
$php_options_text .= "\t\t\t" . '"PHP_FCGI_MAX_REQUESTS" => "' . (int) $domain['mod_fcgid_maxrequests'] . '"' . "\n";
|
||||
} else {
|
||||
if ((int) $phpconfig['mod_fcgid_maxrequests'] != - 1) {
|
||||
$php_options_text .= "\t\t\t" . '"PHP_FCGI_MAX_REQUESTS" => "' . (int) $phpconfig['mod_fcgid_maxrequests'] . '"' . "\n";
|
||||
} else {
|
||||
$php_options_text .= "\t\t\t" . '"PHP_FCGI_MAX_REQUESTS" => "' . (int) Settings::Get('system.mod_fcgid_maxrequests') . '"' . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
$php_options_text .= "\t\t" . ')' . "\n";
|
||||
$php_options_text .= "\t" . ')' . "\n";
|
||||
$php_options_text .= "\t" . ')' . "\n";
|
||||
} // foreach extension
|
||||
$php_options_text .= ' )' . "\n";
|
||||
}
|
||||
|
||||
// create starter-file | config-file
|
||||
$php->getInterface()->createConfig($phpconfig);
|
||||
|
||||
// create php.ini (fpm does nothing here, as it
|
||||
// defines ini-settings in its pool config)
|
||||
$php->getInterface()->createIniFile($phpconfig);
|
||||
} else {
|
||||
$php_options_text .= ' # PHP is disabled for this vHost' . "\n";
|
||||
}
|
||||
|
||||
return $php_options_text;
|
||||
}
|
||||
|
||||
public function createOwnVhostStarter()
|
||||
{
|
||||
if (Settings::Get('phpfpm.enabled') == '1' && Settings::Get('phpfpm.enabled_ownvhost') == '1') {
|
||||
$mypath = makeCorrectDir(dirname(dirname(dirname(__FILE__)))); // /var/www/froxlor, needed for chown
|
||||
|
||||
$user = Settings::Get('phpfpm.vhost_httpuser');
|
||||
$group = Settings::Get('phpfpm.vhost_httpgroup');
|
||||
|
||||
// get fpm config
|
||||
$fpm_sel_stmt = Database::prepare("
|
||||
SELECT f.id FROM `" . TABLE_PANEL_FPMDAEMONS . "` f
|
||||
LEFT JOIN `" . TABLE_PANEL_PHPCONFIGS . "` p ON p.fpmsettingid = f.id
|
||||
WHERE p.id = :phpconfigid
|
||||
");
|
||||
$fpm_config = Database::pexecute_first($fpm_sel_stmt, array(
|
||||
'phpconfigid' => Settings::Get('phpfpm.vhost_defaultini')
|
||||
));
|
||||
|
||||
$domain = array(
|
||||
'id' => 'none',
|
||||
'domain' => Settings::Get('system.hostname'),
|
||||
'adminid' => 1, /* first admin-user (superadmin) */
|
||||
'mod_fcgid_starter' => - 1,
|
||||
'mod_fcgid_maxrequests' => - 1,
|
||||
'guid' => $user,
|
||||
'openbasedir' => 0,
|
||||
'email' => Settings::Get('panel.adminmail'),
|
||||
'loginname' => 'froxlor.panel',
|
||||
'documentroot' => $mypath,
|
||||
'customerroot' => $mypath,
|
||||
'fpm_config_id' => isset($fpm_config['id']) ? $fpm_config['id'] : 1
|
||||
);
|
||||
|
||||
// all the files and folders have to belong to the local user
|
||||
// now because we also use fcgid for our own vhost
|
||||
safe_exec('chown -R ' . $user . ':' . $group . ' ' . escapeshellarg($mypath));
|
||||
|
||||
// get php.ini for our own vhost
|
||||
$php = new PhpInterface($domain);
|
||||
|
||||
// get php-config
|
||||
if (Settings::Get('phpfpm.enabled') == '1') {
|
||||
// fpm
|
||||
$phpconfig = $php->getPhpConfig(Settings::Get('phpfpm.vhost_defaultini'));
|
||||
} else {
|
||||
// fcgid
|
||||
$phpconfig = $php->getPhpConfig(Settings::Get('system.mod_fcgid_defaultini_ownvhost'));
|
||||
}
|
||||
|
||||
// create starter-file | config-file
|
||||
$php->getInterface()->createConfig($phpconfig);
|
||||
|
||||
// create php.ini (fpm does nothing here, as it
|
||||
// defines ini-settings in its pool config)
|
||||
$php->getInterface()->createIniFile($phpconfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
<?php
|
||||
namespace Froxlor\Cron\Http;
|
||||
|
||||
if (! defined('MASTER_CRONJOB'))
|
||||
die('You cannot access this file directly!');
|
||||
use Froxlor\Database;
|
||||
use Froxlor\Settings;
|
||||
use Froxlor\Cron\Http\Php\Fpm;
|
||||
use Froxlor\Cron\Http\Php\PhpInterface;
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
@@ -15,18 +18,11 @@ if (! defined('MASTER_CRONJOB'))
|
||||
* @author Froxlor team <team@froxlor.org> (2010-)
|
||||
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
|
||||
* @package Cron
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
require_once (dirname(__FILE__) . '/../classes/class.HttpConfigBase.php');
|
||||
|
||||
class nginx extends HttpConfigBase
|
||||
class Nginx extends HttpConfigBase
|
||||
{
|
||||
|
||||
private $logger = false;
|
||||
|
||||
private $idnaConvert = false;
|
||||
|
||||
private $nginx_server = array();
|
||||
|
||||
// protected
|
||||
@@ -54,10 +50,8 @@ class nginx extends HttpConfigBase
|
||||
*/
|
||||
private $_deactivated = false;
|
||||
|
||||
public function __construct($logger, $idnaConvert, $nginx_server = array())
|
||||
public function __construct($nginx_server = array())
|
||||
{
|
||||
$this->logger = $logger;
|
||||
$this->idnaConvert = $idnaConvert;
|
||||
$this->nginx_server = $nginx_server;
|
||||
}
|
||||
|
||||
@@ -67,7 +61,7 @@ class nginx extends HttpConfigBase
|
||||
// get all start/stop commands
|
||||
$startstop_sel = Database::prepare("SELECT reload_cmd, config_dir FROM `" . TABLE_PANEL_FPMDAEMONS . "`");
|
||||
Database::pexecute($startstop_sel);
|
||||
$restart_cmds = $startstop_sel->fetchAll(PDO::FETCH_ASSOC);
|
||||
$restart_cmds = $startstop_sel->fetchAll(\PDO::FETCH_ASSOC);
|
||||
// restart all php-fpm instances
|
||||
foreach ($restart_cmds as $restart_cmd) {
|
||||
// check whether the config dir is empty (no domains uses this daemon)
|
||||
@@ -75,7 +69,7 @@ class nginx extends HttpConfigBase
|
||||
$_conffiles = glob(makeCorrectFile($restart_cmd['config_dir'] . "/*.conf"));
|
||||
if ($_conffiles === false || empty($_conffiles)) {
|
||||
$this->logger->logAction(CRON_ACTION, LOG_INFO, 'nginx::reload: fpm config directory "' . $restart_cmd['config_dir'] . '" is empty. Creating dummy.');
|
||||
phpinterface_fpm::createDummyPool($restart_cmd['config_dir']);
|
||||
Fpm::createDummyPool($restart_cmd['config_dir']);
|
||||
}
|
||||
$this->logger->logAction(CRON_ACTION, LOG_INFO, 'nginx::reload: running ' . $restart_cmd['reload_cmd']);
|
||||
safe_exec(escapeshellcmd($restart_cmd['reload_cmd']));
|
||||
@@ -143,7 +137,7 @@ class nginx extends HttpConfigBase
|
||||
SELECT * FROM `" . TABLE_PANEL_IPSANDPORTS . "` ORDER BY `ip` ASC, `port` ASC
|
||||
");
|
||||
|
||||
while ($row_ipsandports = $result_ipsandports_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
while ($row_ipsandports = $result_ipsandports_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
if (filter_var($row_ipsandports['ip'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
|
||||
$ip = '[' . $row_ipsandports['ip'] . ']';
|
||||
} else {
|
||||
@@ -170,10 +164,10 @@ class nginx extends HttpConfigBase
|
||||
if ($row_ipsandports['ssl'] == '1') {
|
||||
if ($row_ipsandports['ssl_cert_file'] == '') {
|
||||
$row_ipsandports['ssl_cert_file'] = Settings::Get('system.ssl_cert_file');
|
||||
if (!file_exists($row_ipsandports['ssl_cert_file'])) {
|
||||
if (! file_exists($row_ipsandports['ssl_cert_file'])) {
|
||||
// explicitly disable ssl for this vhost
|
||||
$row_ipsandports['ssl_cert_file'] = "";
|
||||
$this->logger->logAction(CRON_ACTION, LOG_DEBUG, 'System certificate file "'.Settings::Get('system.ssl_cert_file').'" does not seem to exist. Disabling SSL-vhost for "'.Settings::Get('system.hostname').'"');
|
||||
$this->logger->logAction(CRON_ACTION, LOG_DEBUG, 'System certificate file "' . Settings::Get('system.ssl_cert_file') . '" does not seem to exist. Disabling SSL-vhost for "' . Settings::Get('system.hostname') . '"');
|
||||
}
|
||||
}
|
||||
if ($row_ipsandports['ssl_key_file'] == '') {
|
||||
@@ -313,7 +307,7 @@ class nginx extends HttpConfigBase
|
||||
'fpm_config_id' => isset($fpm_config['id']) ? $fpm_config['id'] : 1
|
||||
);
|
||||
|
||||
$php = new phpinterface($domain);
|
||||
$php = new PhpInterface($domain);
|
||||
$this->nginx_data[$vhost_filename] .= "\t\tfastcgi_pass unix:" . $php->getInterface()->getSocketFile() . ";\n";
|
||||
} else {
|
||||
$this->nginx_data[$vhost_filename] .= "\t\tfastcgi_pass " . Settings::Get('system.nginx_php_backend') . ";\n";
|
||||
@@ -425,7 +419,7 @@ class nginx extends HttpConfigBase
|
||||
'domainid' => $domain['id']
|
||||
));
|
||||
|
||||
while ($ipandport = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
while ($ipandport = $result_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
|
||||
$domain['ip'] = $ipandport['ip'];
|
||||
$domain['port'] = $ipandport['port'];
|
||||
@@ -454,7 +448,7 @@ class nginx extends HttpConfigBase
|
||||
|
||||
$http2 = $ssl_vhost == true && (isset($domain['http2']) && $domain['http2'] == '1' && Settings::Get('system.http2_support') == '1');
|
||||
|
||||
$vhost_content .= "\t" . 'listen ' . $ipport . ($ssl_vhost == true ? ' ssl' : '') . ($http2 == true ? ' http2' : '') . ';' . "\n";
|
||||
$vhost_content .= "\t" . 'listen ' . $ipport . ($ssl_vhost == true ? ' ssl' : '') . ($http2 == true ? ' http2' : '') . ';' . "\n";
|
||||
}
|
||||
|
||||
// get all server-names
|
||||
@@ -508,7 +502,7 @@ class nginx extends HttpConfigBase
|
||||
$code = getDomainRedirectCode($domain['id']);
|
||||
|
||||
$vhost_content .= "\t" . 'if ($request_uri !~ ^/.well-known/acme-challenge/[-\w]+$) {' . "\n";
|
||||
$vhost_content .= "\t\t" . 'return ' . $code .' ' . $uri . '$request_uri;' . "\n";
|
||||
$vhost_content .= "\t\t" . 'return ' . $code . ' ' . $uri . '$request_uri;' . "\n";
|
||||
$vhost_content .= "\t" . '}' . "\n";
|
||||
} else {
|
||||
mkDirWithCorrectOwnership($domain['customerroot'], $domain['documentroot'], $domain['guid'], $domain['guid'], true);
|
||||
@@ -620,10 +614,10 @@ class nginx extends HttpConfigBase
|
||||
|
||||
if ($domain_or_ip['ssl_cert_file'] == '') {
|
||||
$domain_or_ip['ssl_cert_file'] = Settings::Get('system.ssl_cert_file');
|
||||
if (!file_exists($domain_or_ip['ssl_cert_file'])) {
|
||||
if (! file_exists($domain_or_ip['ssl_cert_file'])) {
|
||||
// explicitly disable ssl for this vhost
|
||||
$domain_or_ip['ssl_cert_file'] = "";
|
||||
$this->logger->logAction(CRON_ACTION, LOG_DEBUG, 'System certificate file "'.Settings::Get('system.ssl_cert_file').'" does not seem to exist. Disabling SSL-vhost for "'.$domain_or_ip['domain'].'"');
|
||||
$this->logger->logAction(CRON_ACTION, LOG_DEBUG, 'System certificate file "' . Settings::Get('system.ssl_cert_file') . '" does not seem to exist. Disabling SSL-vhost for "' . $domain_or_ip['domain'] . '"');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -650,10 +644,10 @@ class nginx extends HttpConfigBase
|
||||
// $sslsettings .= "\t" . 'ssl on;' . "\n";
|
||||
$sslsettings .= "\t" . 'ssl_protocols ' . str_replace(",", " ", Settings::Get('system.ssl_protocols')) . ';' . "\n";
|
||||
$sslsettings .= "\t" . 'ssl_ciphers ' . Settings::Get('system.ssl_cipher_list') . ';' . "\n";
|
||||
if (!empty(Settings::Get('system.dhparams_file'))) {
|
||||
if (! empty(Settings::Get('system.dhparams_file'))) {
|
||||
$dhparams = makeCorrectFile(Settings::Get('system.dhparams_file'));
|
||||
if (!file_exists($dhparams)) {
|
||||
safe_exec('openssl dhparam -out '.escapeshellarg($dhparams).' 4096');
|
||||
if (! file_exists($dhparams)) {
|
||||
safe_exec('openssl dhparam -out ' . escapeshellarg($dhparams) . ' 4096');
|
||||
}
|
||||
$sslsettings .= 'ssl_dhparam ' . $dhparams . ';' . "\n";
|
||||
}
|
||||
@@ -681,12 +675,10 @@ class nginx extends HttpConfigBase
|
||||
$sslsettings .= '";' . "\n";
|
||||
}
|
||||
|
||||
if ((isset($domain_or_ip['ocsp_stapling']) && $domain_or_ip['ocsp_stapling'] == "1") ||
|
||||
(isset($domain_or_ip['letsencrypt']) && $domain_or_ip['letsencrypt'] == "1") ) {
|
||||
if ((isset($domain_or_ip['ocsp_stapling']) && $domain_or_ip['ocsp_stapling'] == "1") || (isset($domain_or_ip['letsencrypt']) && $domain_or_ip['letsencrypt'] == "1")) {
|
||||
$sslsettings .= "\t" . 'ssl_stapling on;' . "\n";
|
||||
$sslsettings .= "\t" . 'ssl_stapling_verify on;' . "\n";
|
||||
$sslsettings .= "\t" . 'ssl_trusted_certificate ' .
|
||||
makeCorrectFile($domain_or_ip['ssl_cert_file']) . ';' . "\n";
|
||||
$sslsettings .= "\t" . 'ssl_trusted_certificate ' . makeCorrectFile($domain_or_ip['ssl_cert_file']) . ';' . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -696,8 +688,6 @@ class nginx extends HttpConfigBase
|
||||
|
||||
protected function create_pathOptions($domain)
|
||||
{
|
||||
$has_location = false;
|
||||
|
||||
$result_stmt = Database::prepare("
|
||||
SELECT * FROM " . TABLE_PANEL_HTACCESS . "
|
||||
WHERE `path` LIKE :docroot
|
||||
@@ -710,7 +700,7 @@ class nginx extends HttpConfigBase
|
||||
$htpasswds = $this->getHtpasswds($domain);
|
||||
|
||||
// for each entry in the htaccess table
|
||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
while ($row = $result_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
if (! empty($row['error404path'])) {
|
||||
$defhandler = $row['error404path'];
|
||||
if (! validateUrl($defhandler)) {
|
||||
@@ -860,7 +850,7 @@ class nginx extends HttpConfigBase
|
||||
|
||||
$returnval = array();
|
||||
$x = 0;
|
||||
while ($row_htpasswds = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
while ($row_htpasswds = $result_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
if (count($row_htpasswds) > 0) {
|
||||
$htpasswd_filename = makeCorrectFile(Settings::Get('system.apacheconf_htpasswddir') . '/' . $row_htpasswds['customerid'] . '-' . md5($row_htpasswds['path']) . '.htpasswd');
|
||||
|
||||
@@ -1067,7 +1057,7 @@ class nginx extends HttpConfigBase
|
||||
'domainid' => $domain['id']
|
||||
));
|
||||
|
||||
while (($alias_domain = $alias_domains_stmt->fetch(PDO::FETCH_ASSOC)) !== false) {
|
||||
while (($alias_domain = $alias_domains_stmt->fetch(\PDO::FETCH_ASSOC)) !== false) {
|
||||
$server_alias .= ' ' . $alias_domain['domain'] . ' ';
|
||||
|
||||
if ($alias_domain['iswildcarddomain'] == '1') {
|
||||
@@ -1121,7 +1111,7 @@ class nginx extends HttpConfigBase
|
||||
'domainid' => $domain['id']
|
||||
));
|
||||
|
||||
while (($alias_domain = $alias_domains_stmt->fetch(PDO::FETCH_ASSOC)) !== false) {
|
||||
while (($alias_domain = $alias_domains_stmt->fetch(\PDO::FETCH_ASSOC)) !== false) {
|
||||
$server_alias .= ' ' . $alias_domain['domain'];
|
||||
|
||||
if ($alias_domain['iswildcarddomain'] == '1') {
|
||||
@@ -1144,7 +1134,7 @@ class nginx extends HttpConfigBase
|
||||
{
|
||||
$this->logger->logAction(CRON_ACTION, LOG_INFO, "nginx::writeConfigs: rebuilding " . Settings::Get('system.apacheconf_vhost'));
|
||||
|
||||
$vhostDir = new frxDirectory(Settings::Get('system.apacheconf_vhost'));
|
||||
$vhostDir = new \Froxlor\Http\Directory(Settings::Get('system.apacheconf_vhost'));
|
||||
if (! $vhostDir->isConfigDir()) {
|
||||
// Save one big file
|
||||
$vhosts_file = '';
|
||||
@@ -1,4 +1,9 @@
|
||||
<?php if (!defined('MASTER_CRONJOB')) die('You cannot access this file directly!');
|
||||
<?php
|
||||
namespace Froxlor\Cron\Http;
|
||||
|
||||
use Froxlor\Database;
|
||||
use Froxlor\Settings;
|
||||
use Froxlor\Cron\Http\Php\PhpInterface;
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
@@ -8,22 +13,23 @@
|
||||
* file that was distributed with this source code. You can also view the
|
||||
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
|
||||
*
|
||||
* @copyright (c) the authors
|
||||
* @author Froxlor team <team@froxlor.org> (2010-)
|
||||
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
|
||||
* @package Cron
|
||||
*
|
||||
* @copyright (c) the authors
|
||||
* @author Froxlor team <team@froxlor.org> (2010-)
|
||||
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
|
||||
* @package Cron
|
||||
*
|
||||
*/
|
||||
|
||||
class nginx_phpfpm extends nginx
|
||||
class NginxFcgi extends Nginx
|
||||
{
|
||||
protected function composePhpOptions($domain, $ssl_vhost = false) {
|
||||
|
||||
protected function composePhpOptions($domain, $ssl_vhost = false)
|
||||
{
|
||||
$php_options_text = '';
|
||||
|
||||
if ($domain['phpenabled_customer'] == 1 && $domain['phpenabled_vhost'] == '1') {
|
||||
$php = new phpinterface($domain);
|
||||
$phpconfig = $php->getPhpConfig((int)$domain['phpsettingid']);
|
||||
|
||||
$php = new PhpInterface($domain);
|
||||
$phpconfig = $php->getPhpConfig((int) $domain['phpsettingid']);
|
||||
|
||||
$php_options_text = "\t" . 'location ~ ^(.+?\.php)(/.*)?$ {' . "\n";
|
||||
$php_options_text .= "\t\t" . 'try_files ' . $domain['nonexistinguri'] . ' @php;' . "\n";
|
||||
$php_options_text .= "\t" . '}' . "\n\n";
|
||||
@@ -40,26 +46,23 @@ class nginx_phpfpm extends nginx
|
||||
$php_options_text .= "\t\t" . 'fastcgi_pass unix:' . $php->getInterface()->getSocketFile() . ";\n";
|
||||
$php_options_text .= "\t\t" . 'fastcgi_index index.php;' . "\n";
|
||||
$php_options_text .= "\t}\n\n";
|
||||
|
||||
|
||||
// create starter-file | config-file
|
||||
$php->getInterface()->createConfig($phpconfig);
|
||||
|
||||
// create php.ini (fpm does nothing here, as it
|
||||
// defines ini-settings in its pool config)
|
||||
$php->getInterface()->createIniFile($phpconfig);
|
||||
}
|
||||
else {
|
||||
$php_options_text.= ' # PHP is disabled for this vHost' . "\n";
|
||||
} else {
|
||||
$php_options_text .= ' # PHP is disabled for this vHost' . "\n";
|
||||
}
|
||||
|
||||
return $php_options_text;
|
||||
}
|
||||
|
||||
|
||||
public function createOwnVhostStarter() {
|
||||
if (Settings::Get('phpfpm.enabled') == '1'
|
||||
&& Settings::Get('phpfpm.enabled_ownvhost') == '1'
|
||||
) {
|
||||
public function createOwnVhostStarter()
|
||||
{
|
||||
if (Settings::Get('phpfpm.enabled') == '1' && Settings::Get('phpfpm.enabled_ownvhost') == '1') {
|
||||
$mypath = makeCorrectDir(dirname(dirname(dirname(__FILE__)))); // /var/www/froxlor, needed for chown
|
||||
|
||||
$user = Settings::Get('phpfpm.vhost_httpuser');
|
||||
@@ -79,8 +82,8 @@ class nginx_phpfpm extends nginx
|
||||
'id' => 'none',
|
||||
'domain' => Settings::Get('system.hostname'),
|
||||
'adminid' => 1, /* first admin-user (superadmin) */
|
||||
'mod_fcgid_starter' => -1,
|
||||
'mod_fcgid_maxrequests' => -1,
|
||||
'mod_fcgid_starter' => - 1,
|
||||
'mod_fcgid_maxrequests' => - 1,
|
||||
'guid' => $user,
|
||||
'openbasedir' => 0,
|
||||
'email' => Settings::Get('panel.adminmail'),
|
||||
@@ -95,7 +98,7 @@ class nginx_phpfpm extends nginx
|
||||
safe_exec('chown -R ' . $user . ':' . $group . ' ' . escapeshellarg($mypath));
|
||||
|
||||
// get php.ini for our own vhost
|
||||
$php = new phpinterface($domain);
|
||||
$php = new PhpInterface($domain);
|
||||
|
||||
// get php-config
|
||||
if (Settings::Get('phpfpm.enabled') == '1') {
|
||||
@@ -114,6 +117,4 @@ class nginx_phpfpm extends nginx
|
||||
$php->getInterface()->createIniFile($phpconfig);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
264
lib/Froxlor/Cron/Http/Php/Fcgid.php
Normal file
264
lib/Froxlor/Cron/Http/Php/Fcgid.php
Normal file
@@ -0,0 +1,264 @@
|
||||
<?php
|
||||
namespace Froxlor\Cron\Http\Php;
|
||||
|
||||
use Froxlor\Database;
|
||||
use Froxlor\Settings;
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||
*
|
||||
* For the full copyright and license information, please view the COPYING
|
||||
* file that was distributed with this source code. You can also view the
|
||||
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
|
||||
*
|
||||
* @copyright (c) the authors
|
||||
* @author Michael Kaufmann <mkaufmann@nutime.de>
|
||||
* @author Froxlor team <team@froxlor.org> (2010-)
|
||||
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
|
||||
* @package Cron
|
||||
*
|
||||
* @link http://www.nutime.de/
|
||||
* @since 0.9.16
|
||||
*
|
||||
*/
|
||||
class Fcgid
|
||||
{
|
||||
|
||||
/**
|
||||
* Domain-Data array
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_domain = array();
|
||||
|
||||
/**
|
||||
* Admin-Date cache array
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_admin_cache = array();
|
||||
|
||||
/**
|
||||
* main constructor
|
||||
*/
|
||||
public function __construct($domain)
|
||||
{
|
||||
$this->_domain = $domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* create fcgid-starter-file
|
||||
*
|
||||
* @param array $phpconfig
|
||||
*/
|
||||
public function createConfig($phpconfig)
|
||||
{
|
||||
|
||||
// create starter
|
||||
$starter_file = "#!/bin/sh\n\n";
|
||||
$starter_file .= "#\n";
|
||||
$starter_file .= "# starter created/changed on " . date("Y.m.d H:i:s") . " for domain '" . $this->_domain['domain'] . "' with id #" . $this->_domain['id'] . " from php template '" . $phpconfig['description'] . "' with id #" . $phpconfig['id'] . "\n";
|
||||
$starter_file .= "# Do not change anything in this file, it will be overwritten by the Froxlor Cronjob!\n";
|
||||
$starter_file .= "#\n\n";
|
||||
$starter_file .= "umask " . $phpconfig['mod_fcgid_umask'] . "\n";
|
||||
$starter_file .= "PHPRC=" . escapeshellarg($this->getConfigDir()) . "\n";
|
||||
$starter_file .= "export PHPRC\n";
|
||||
|
||||
// set number of processes for one domain
|
||||
if ((int) $this->_domain['mod_fcgid_starter'] != - 1) {
|
||||
$starter_file .= "PHP_FCGI_CHILDREN=" . (int) $this->_domain['mod_fcgid_starter'] . "\n";
|
||||
} else {
|
||||
if ((int) $phpconfig['mod_fcgid_starter'] != - 1) {
|
||||
$starter_file .= "PHP_FCGI_CHILDREN=" . (int) $phpconfig['mod_fcgid_starter'] . "\n";
|
||||
} else {
|
||||
$starter_file .= "PHP_FCGI_CHILDREN=" . (int) Settings::Get('system.mod_fcgid_starter') . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
$starter_file .= "export PHP_FCGI_CHILDREN\n";
|
||||
|
||||
// set number of maximum requests for one domain
|
||||
if ((int) $this->_domain['mod_fcgid_maxrequests'] != - 1) {
|
||||
$starter_file .= "PHP_FCGI_MAX_REQUESTS=" . (int) $this->_domain['mod_fcgid_maxrequests'] . "\n";
|
||||
} else {
|
||||
if ((int) $phpconfig['mod_fcgid_maxrequests'] != - 1) {
|
||||
$starter_file .= "PHP_FCGI_MAX_REQUESTS=" . (int) $phpconfig['mod_fcgid_maxrequests'] . "\n";
|
||||
} else {
|
||||
$starter_file .= "PHP_FCGI_MAX_REQUESTS=" . (int) Settings::Get('system.mod_fcgid_maxrequests') . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
$starter_file .= "export PHP_FCGI_MAX_REQUESTS\n";
|
||||
|
||||
// Set Binary
|
||||
$starter_file .= "exec " . $phpconfig['binary'] . " -c " . escapeshellarg($this->getConfigDir()) . "\n";
|
||||
|
||||
// remove +i attibute, so starter can be overwritten
|
||||
if (file_exists($this->getStarterFile())) {
|
||||
removeImmutable($this->getStarterFile());
|
||||
}
|
||||
|
||||
$starter_file_handler = fopen($this->getStarterFile(), 'w');
|
||||
fwrite($starter_file_handler, $starter_file);
|
||||
fclose($starter_file_handler);
|
||||
safe_exec('chmod 750 ' . escapeshellarg($this->getStarterFile()));
|
||||
safe_exec('chown ' . $this->_domain['guid'] . ':' . $this->_domain['guid'] . ' ' . escapeshellarg($this->getStarterFile()));
|
||||
setImmutable($this->getStarterFile());
|
||||
}
|
||||
|
||||
/**
|
||||
* create customized php.ini
|
||||
*
|
||||
* @param array $phpconfig
|
||||
*/
|
||||
public function createIniFile($phpconfig)
|
||||
{
|
||||
$openbasedir = '';
|
||||
$openbasedirc = ';';
|
||||
|
||||
if ($this->_domain['openbasedir'] == '1') {
|
||||
|
||||
$openbasedirc = '';
|
||||
$_phpappendopenbasedir = '';
|
||||
|
||||
$_custom_openbasedir = explode(':', Settings::Get('system.mod_fcgid_peardir'));
|
||||
foreach ($_custom_openbasedir as $cobd) {
|
||||
$_phpappendopenbasedir .= appendOpenBasedirPath($cobd);
|
||||
}
|
||||
|
||||
$_custom_openbasedir = explode(':', Settings::Get('system.phpappendopenbasedir'));
|
||||
foreach ($_custom_openbasedir as $cobd) {
|
||||
$_phpappendopenbasedir .= appendOpenBasedirPath($cobd);
|
||||
}
|
||||
|
||||
if ($this->_domain['openbasedir_path'] == '0' && strstr($this->_domain['documentroot'], ":") === false) {
|
||||
$openbasedir = appendOpenBasedirPath($this->_domain['documentroot'], true);
|
||||
} else {
|
||||
$openbasedir = appendOpenBasedirPath($this->_domain['customerroot'], true);
|
||||
}
|
||||
|
||||
$openbasedir .= appendOpenBasedirPath($this->getTempDir());
|
||||
$openbasedir .= $_phpappendopenbasedir;
|
||||
} else {
|
||||
$openbasedir = 'none';
|
||||
$openbasedirc = ';';
|
||||
}
|
||||
|
||||
$admin = $this->_getAdminData($this->_domain['adminid']);
|
||||
$php_ini_variables = array(
|
||||
'SAFE_MODE' => 'Off', // keep this for compatibility, just in case
|
||||
'PEAR_DIR' => Settings::Get('system.mod_fcgid_peardir'),
|
||||
'TMP_DIR' => $this->getTempDir(),
|
||||
'CUSTOMER_EMAIL' => $this->_domain['email'],
|
||||
'ADMIN_EMAIL' => $admin['email'],
|
||||
'DOMAIN' => $this->_domain['domain'],
|
||||
'CUSTOMER' => $this->_domain['loginname'],
|
||||
'ADMIN' => $admin['loginname'],
|
||||
'OPEN_BASEDIR' => $openbasedir,
|
||||
'OPEN_BASEDIR_C' => $openbasedirc,
|
||||
'OPEN_BASEDIR_GLOBAL' => Settings::Get('system.phpappendopenbasedir'),
|
||||
'DOCUMENT_ROOT' => makeCorrectDir($this->_domain['documentroot']),
|
||||
'CUSTOMER_HOMEDIR' => makeCorrectDir($this->_domain['customerroot'])
|
||||
);
|
||||
|
||||
// insert a small header for the file
|
||||
$phpini_file = ";\n";
|
||||
$phpini_file .= "; php.ini created/changed on " . date("Y.m.d H:i:s") . " for domain '" . $this->_domain['domain'] . "' with id #" . $this->_domain['id'] . " from php template '" . $phpconfig['description'] . "' with id #" . $phpconfig['id'] . "\n";
|
||||
$phpini_file .= "; Do not change anything in this file, it will be overwritten by the Froxlor Cronjob!\n";
|
||||
$phpini_file .= ";\n\n";
|
||||
$phpini_file .= replace_variables($phpconfig['phpsettings'], $php_ini_variables);
|
||||
$phpini_file = str_replace('"none"', 'none', $phpini_file);
|
||||
// $phpini_file = preg_replace('/\"+/', '"', $phpini_file);
|
||||
$phpini_file_handler = fopen($this->getIniFile(), 'w');
|
||||
fwrite($phpini_file_handler, $phpini_file);
|
||||
fclose($phpini_file_handler);
|
||||
safe_exec('chown root:0 ' . escapeshellarg($this->getIniFile()));
|
||||
safe_exec('chmod 0644 ' . escapeshellarg($this->getIniFile()));
|
||||
}
|
||||
|
||||
/**
|
||||
* fcgid-config directory
|
||||
*
|
||||
* @param boolean $createifnotexists
|
||||
* create the directory if it does not exist
|
||||
*
|
||||
* @return string the directory
|
||||
*/
|
||||
public function getConfigDir($createifnotexists = true)
|
||||
{
|
||||
$configdir = makeCorrectDir(Settings::Get('system.mod_fcgid_configdir') . '/' . $this->_domain['loginname'] . '/' . $this->_domain['domain'] . '/');
|
||||
|
||||
if (! is_dir($configdir) && $createifnotexists) {
|
||||
safe_exec('mkdir -p ' . escapeshellarg($configdir));
|
||||
safe_exec('chown ' . $this->_domain['guid'] . ':' . $this->_domain['guid'] . ' ' . escapeshellarg($configdir));
|
||||
}
|
||||
|
||||
return $configdir;
|
||||
}
|
||||
|
||||
/**
|
||||
* fcgid-temp directory
|
||||
*
|
||||
* @param boolean $createifnotexists
|
||||
* create the directory if it does not exist
|
||||
*
|
||||
* @return string the directory
|
||||
*/
|
||||
public function getTempDir($createifnotexists = true)
|
||||
{
|
||||
$tmpdir = makeCorrectDir(Settings::Get('system.mod_fcgid_tmpdir') . '/' . $this->_domain['loginname'] . '/');
|
||||
|
||||
if (! is_dir($tmpdir) && $createifnotexists) {
|
||||
safe_exec('mkdir -p ' . escapeshellarg($tmpdir));
|
||||
safe_exec('chown -R ' . $this->_domain['guid'] . ':' . $this->_domain['guid'] . ' ' . escapeshellarg($tmpdir));
|
||||
safe_exec('chmod 0750 ' . escapeshellarg($tmpdir));
|
||||
}
|
||||
|
||||
return $tmpdir;
|
||||
}
|
||||
|
||||
/**
|
||||
* return path of php-starter file
|
||||
*
|
||||
* @return string the directory
|
||||
*/
|
||||
public function getStarterFile()
|
||||
{
|
||||
$starter_filename = makeCorrectFile($this->getConfigDir() . '/php-fcgi-starter');
|
||||
return $starter_filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* return path of php.ini file
|
||||
*
|
||||
* @return string full with path file-name
|
||||
*/
|
||||
public function getIniFile()
|
||||
{
|
||||
$phpini_filename = makeCorrectFile($this->getConfigDir() . '/php.ini');
|
||||
return $phpini_filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the admin-data of a specific admin
|
||||
*
|
||||
* @param int $adminid
|
||||
* id of the admin-user
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function _getAdminData($adminid)
|
||||
{
|
||||
$adminid = intval($adminid);
|
||||
|
||||
if (! isset($this->_admin_cache[$adminid])) {
|
||||
$stmt = Database::prepare("
|
||||
SELECT `email`, `loginname` FROM `" . TABLE_PANEL_ADMINS . "` WHERE `adminid` = :id");
|
||||
$this->_admin_cache[$adminid] = Database::pexecute_first($stmt, array(
|
||||
'id' => $adminid
|
||||
));
|
||||
}
|
||||
return $this->_admin_cache[$adminid];
|
||||
}
|
||||
}
|
||||
409
lib/Froxlor/Cron/Http/Php/Fpm.php
Normal file
409
lib/Froxlor/Cron/Http/Php/Fpm.php
Normal file
@@ -0,0 +1,409 @@
|
||||
<?php
|
||||
namespace Froxlor\Cron\Http\Php;
|
||||
|
||||
use Froxlor\Database;
|
||||
use Froxlor\Settings;
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||
*
|
||||
* For the full copyright and license information, please view the COPYING
|
||||
* file that was distributed with this source code. You can also view the
|
||||
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
|
||||
*
|
||||
* @copyright (c) the authors
|
||||
* @author Michael Kaufmann <mkaufmann@nutime.de>
|
||||
* @author Froxlor team <team@froxlor.org> (2010-)
|
||||
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
|
||||
* @package Cron
|
||||
*
|
||||
* @link http://www.nutime.de/
|
||||
* @since 0.9.16
|
||||
*
|
||||
*/
|
||||
class Fpm
|
||||
{
|
||||
|
||||
/**
|
||||
* Domain-Data array
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_domain = array();
|
||||
|
||||
/**
|
||||
* fpm config
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_fpm_cfg = array();
|
||||
|
||||
/**
|
||||
* Admin-Date cache array
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_admin_cache = array();
|
||||
|
||||
/**
|
||||
* defines what can be used for pool-config from php.ini
|
||||
* Mostly taken from http://php.net/manual/en/ini.list.php
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_ini = array();
|
||||
|
||||
/**
|
||||
* main constructor
|
||||
*/
|
||||
public function __construct($domain)
|
||||
{
|
||||
if (! isset($domain['fpm_config_id']) || empty($domain['fpm_config_id'])) {
|
||||
$domain['fpm_config_id'] = 1;
|
||||
}
|
||||
$this->_domain = $domain;
|
||||
$this->_readFpmConfig($domain['fpm_config_id']);
|
||||
$this->_buildIniMapping();
|
||||
}
|
||||
|
||||
private function _buildIniMapping()
|
||||
{
|
||||
$this->_ini = array(
|
||||
'php_flag' => explode("\n", Settings::Get('phpfpm.ini_flags')),
|
||||
'php_value' => explode("\n", Settings::Get('phpfpm.ini_values')),
|
||||
'php_admin_flag' => explode("\n", Settings::Get('phpfpm.ini_admin_flags')),
|
||||
'php_admin_value' => explode("\n", Settings::Get('phpfpm.ini_admin_values'))
|
||||
);
|
||||
}
|
||||
|
||||
private function _readFpmConfig($fpm_config_id)
|
||||
{
|
||||
$stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_FPMDAEMONS . "` WHERE `id` = :id");
|
||||
$this->_fpm_cfg = Database::pexecute_first($stmt, array(
|
||||
'id' => $fpm_config_id
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* create fpm-pool config
|
||||
*
|
||||
* @param array $phpconfig
|
||||
*/
|
||||
public function createConfig($phpconfig)
|
||||
{
|
||||
$fh = @fopen($this->getConfigFile(), 'w');
|
||||
|
||||
if ($fh) {
|
||||
|
||||
if ($phpconfig['override_fpmconfig'] == 1) {
|
||||
$this->_fpm_cfg['pm'] = $phpconfig['pm'];
|
||||
$this->_fpm_cfg['max_children'] = $phpconfig['max_children'];
|
||||
$this->_fpm_cfg['start_servers'] = $phpconfig['start_servers'];
|
||||
$this->_fpm_cfg['min_spare_servers'] = $phpconfig['min_spare_servers'];
|
||||
$this->_fpm_cfg['max_spare_servers'] = $phpconfig['max_spare_servers'];
|
||||
$this->_fpm_cfg['max_requests'] = $phpconfig['max_requests'];
|
||||
$this->_fpm_cfg['idle_timeout'] = $phpconfig['idle_timeout'];
|
||||
$this->_fpm_cfg['limit_extensions'] = $phpconfig['limit_extensions'];
|
||||
}
|
||||
|
||||
$fpm_pm = $this->_fpm_cfg['pm'];
|
||||
$fpm_children = (int) $this->_fpm_cfg['max_children'];
|
||||
$fpm_start_servers = (int) $this->_fpm_cfg['start_servers'];
|
||||
$fpm_min_spare_servers = (int) $this->_fpm_cfg['min_spare_servers'];
|
||||
$fpm_max_spare_servers = (int) $this->_fpm_cfg['max_spare_servers'];
|
||||
$fpm_requests = (int) $this->_fpm_cfg['max_requests'];
|
||||
$fpm_process_idle_timeout = (int) $this->_fpm_cfg['idle_timeout'];
|
||||
$fpm_limit_extensions = $this->_fpm_cfg['limit_extensions'];
|
||||
|
||||
if ($fpm_children == 0) {
|
||||
$fpm_children = 1;
|
||||
}
|
||||
|
||||
$fpm_config = ';PHP-FPM configuration for "' . $this->_domain['domain'] . '" created on ' . date("Y.m.d H:i:s") . "\n";
|
||||
$fpm_config .= '[' . $this->_domain['domain'] . ']' . "\n";
|
||||
$fpm_config .= 'listen = ' . $this->getSocketFile() . "\n";
|
||||
if ($this->_domain['loginname'] == 'froxlor.panel') {
|
||||
$fpm_config .= 'listen.owner = ' . $this->_domain['guid'] . "\n";
|
||||
$fpm_config .= 'listen.group = ' . $this->_domain['guid'] . "\n";
|
||||
} else {
|
||||
$fpm_config .= 'listen.owner = ' . $this->_domain['loginname'] . "\n";
|
||||
$fpm_config .= 'listen.group = ' . $this->_domain['loginname'] . "\n";
|
||||
}
|
||||
// see #1418 why this is 0660
|
||||
$fpm_config .= 'listen.mode = 0660' . "\n";
|
||||
|
||||
if ($this->_domain['loginname'] == 'froxlor.panel') {
|
||||
$fpm_config .= 'user = ' . $this->_domain['guid'] . "\n";
|
||||
$fpm_config .= 'group = ' . $this->_domain['guid'] . "\n";
|
||||
} else {
|
||||
$fpm_config .= 'user = ' . $this->_domain['loginname'] . "\n";
|
||||
$fpm_config .= 'group = ' . $this->_domain['loginname'] . "\n";
|
||||
}
|
||||
|
||||
$fpm_config .= 'pm = ' . $fpm_pm . "\n";
|
||||
$fpm_config .= 'pm.max_children = ' . $fpm_children . "\n";
|
||||
|
||||
if ($fpm_pm == 'dynamic') {
|
||||
// honor max_children
|
||||
if ($fpm_children < $fpm_min_spare_servers) {
|
||||
$fpm_min_spare_servers = $fpm_children;
|
||||
}
|
||||
if ($fpm_children < $fpm_max_spare_servers) {
|
||||
$fpm_max_spare_servers = $fpm_children;
|
||||
}
|
||||
// failsafe, refs #955
|
||||
if ($fpm_start_servers < $fpm_min_spare_servers) {
|
||||
$fpm_start_servers = $fpm_min_spare_servers;
|
||||
}
|
||||
if ($fpm_start_servers > $fpm_max_spare_servers) {
|
||||
$fpm_start_servers = $fpm_max_spare_servers;
|
||||
}
|
||||
$fpm_config .= 'pm.start_servers = ' . $fpm_start_servers . "\n";
|
||||
$fpm_config .= 'pm.min_spare_servers = ' . $fpm_min_spare_servers . "\n";
|
||||
$fpm_config .= 'pm.max_spare_servers = ' . $fpm_max_spare_servers . "\n";
|
||||
} elseif ($fpm_pm == 'ondemand') {
|
||||
$fpm_config .= 'pm.process_idle_timeout = ' . $fpm_process_idle_timeout . "\n";
|
||||
}
|
||||
|
||||
$fpm_config .= 'pm.max_requests = ' . $fpm_requests . "\n";
|
||||
|
||||
// possible slowlog configs
|
||||
if ($phpconfig['fpm_slowlog'] == '1') {
|
||||
$fpm_config .= 'request_terminate_timeout = ' . $phpconfig['fpm_reqterm'] . "\n";
|
||||
$fpm_config .= 'request_slowlog_timeout = ' . $phpconfig['fpm_reqslow'] . "\n";
|
||||
$slowlog = makeCorrectFile(Settings::Get('system.logfiles_directory') . '/' . $this->_domain['loginname'] . '-php-slow.log');
|
||||
$fpm_config .= 'slowlog = ' . $slowlog . "\n";
|
||||
$fpm_config .= 'catch_workers_output = yes' . "\n";
|
||||
}
|
||||
|
||||
$fpm_config .= ';chroot = ' . makeCorrectDir($this->_domain['documentroot']) . "\n";
|
||||
$fpm_config .= 'security.limit_extensions = ' . $fpm_limit_extensions . "\n";
|
||||
|
||||
$tmpdir = makeCorrectDir(Settings::Get('phpfpm.tmpdir') . '/' . $this->_domain['loginname'] . '/');
|
||||
if (! is_dir($tmpdir)) {
|
||||
$this->getTempDir();
|
||||
}
|
||||
|
||||
$env_path = Settings::Get('phpfpm.envpath');
|
||||
if (! empty($env_path)) {
|
||||
$fpm_config .= 'env[PATH] = ' . $env_path . "\n";
|
||||
}
|
||||
$fpm_config .= 'env[TMP] = ' . $tmpdir . "\n";
|
||||
$fpm_config .= 'env[TMPDIR] = ' . $tmpdir . "\n";
|
||||
$fpm_config .= 'env[TEMP] = ' . $tmpdir . "\n";
|
||||
|
||||
$openbasedir = '';
|
||||
if ($this->_domain['loginname'] != 'froxlor.panel') {
|
||||
if ($this->_domain['openbasedir'] == '1') {
|
||||
$_phpappendopenbasedir = '';
|
||||
$_custom_openbasedir = explode(':', Settings::Get('phpfpm.peardir'));
|
||||
foreach ($_custom_openbasedir as $cobd) {
|
||||
$_phpappendopenbasedir .= appendOpenBasedirPath($cobd);
|
||||
}
|
||||
|
||||
$_custom_openbasedir = explode(':', Settings::Get('system.phpappendopenbasedir'));
|
||||
foreach ($_custom_openbasedir as $cobd) {
|
||||
$_phpappendopenbasedir .= appendOpenBasedirPath($cobd);
|
||||
}
|
||||
|
||||
if ($this->_domain['openbasedir_path'] == '0' && strstr($this->_domain['documentroot'], ":") === false) {
|
||||
$openbasedir = appendOpenBasedirPath($this->_domain['documentroot'], true);
|
||||
} else {
|
||||
$openbasedir = appendOpenBasedirPath($this->_domain['customerroot'], true);
|
||||
}
|
||||
|
||||
$openbasedir .= appendOpenBasedirPath($this->getTempDir());
|
||||
$openbasedir .= $_phpappendopenbasedir;
|
||||
}
|
||||
}
|
||||
$fpm_config .= 'php_admin_value[session.save_path] = ' . makeCorrectDir(Settings::Get('phpfpm.tmpdir') . '/' . $this->_domain['loginname'] . '/') . "\n";
|
||||
$fpm_config .= 'php_admin_value[upload_tmp_dir] = ' . makeCorrectDir(Settings::Get('phpfpm.tmpdir') . '/' . $this->_domain['loginname'] . '/') . "\n";
|
||||
|
||||
$admin = $this->_getAdminData($this->_domain['adminid']);
|
||||
$php_ini_variables = array(
|
||||
'SAFE_MODE' => 'Off', // keep this for compatibility, just in case
|
||||
'PEAR_DIR' => Settings::Get('phpfpm.peardir'),
|
||||
'TMP_DIR' => $this->getTempDir(),
|
||||
'CUSTOMER_EMAIL' => $this->_domain['email'],
|
||||
'ADMIN_EMAIL' => $admin['email'],
|
||||
'DOMAIN' => $this->_domain['domain'],
|
||||
'CUSTOMER' => $this->_domain['loginname'],
|
||||
'ADMIN' => $admin['loginname'],
|
||||
'OPEN_BASEDIR' => $openbasedir,
|
||||
'OPEN_BASEDIR_C' => '',
|
||||
'OPEN_BASEDIR_GLOBAL' => Settings::Get('system.phpappendopenbasedir'),
|
||||
'DOCUMENT_ROOT' => makeCorrectDir($this->_domain['documentroot']),
|
||||
'CUSTOMER_HOMEDIR' => makeCorrectDir($this->_domain['customerroot'])
|
||||
);
|
||||
|
||||
$phpini = replace_variables($phpconfig['phpsettings'], $php_ini_variables);
|
||||
$phpini_array = explode("\n", $phpini);
|
||||
|
||||
$fpm_config .= "\n\n";
|
||||
foreach ($phpini_array as $inisection) {
|
||||
$is = explode("=", $inisection);
|
||||
foreach ($this->_ini as $sec => $possibles) {
|
||||
if (in_array(trim($is[0]), $possibles)) {
|
||||
// check explicitly for open_basedir
|
||||
if (trim($is[0]) == 'open_basedir' && $openbasedir == '') {
|
||||
continue;
|
||||
}
|
||||
$fpm_config .= $sec . '[' . trim($is[0]) . '] = ' . trim($is[1]) . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now check if 'sendmail_path' has not beed set in the custom-php.ini
|
||||
// if not we use our fallback-default as usual
|
||||
if (strpos($fpm_config, 'php_admin_value[sendmail_path]') === false) {
|
||||
$fpm_config .= 'php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f ' . $this->_domain['email'] . "\n";
|
||||
}
|
||||
|
||||
fwrite($fh, $fpm_config, strlen($fpm_config));
|
||||
fclose($fh);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* this is done via createConfig as php-fpm defines
|
||||
* the ini-values/flags in its pool-config
|
||||
*
|
||||
* @param string $phpconfig
|
||||
*/
|
||||
public function createIniFile($phpconfig)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpm-config file
|
||||
*
|
||||
* @param boolean $createifnotexists
|
||||
* create the directory if it does not exist
|
||||
*
|
||||
* @return string the full path to the file
|
||||
*/
|
||||
public function getConfigFile($createifnotexists = true)
|
||||
{
|
||||
$configdir = $this->_fpm_cfg['config_dir'];
|
||||
$config = makeCorrectFile($configdir . '/' . $this->_domain['domain'] . '.conf');
|
||||
|
||||
if (! is_dir($configdir) && $createifnotexists) {
|
||||
safe_exec('mkdir -p ' . escapeshellarg($configdir));
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* return path of fpm-socket file
|
||||
*
|
||||
* @param boolean $createifnotexists
|
||||
* create the directory if it does not exist
|
||||
*
|
||||
* @return string the full path to the socket
|
||||
*/
|
||||
public function getSocketFile($createifnotexists = true)
|
||||
{
|
||||
$socketdir = makeCorrectDir(Settings::Get('phpfpm.fastcgi_ipcdir'));
|
||||
// add fpm-config-id to filename so it's unique for the fpm-daemon and doesn't interfere with running configs when reuilding
|
||||
$socket = strtolower(makeCorrectFile($socketdir . '/' . $this->_domain['fpm_config_id'] . '-' . $this->_domain['loginname'] . '-' . $this->_domain['domain'] . '-php-fpm.socket'));
|
||||
|
||||
if (! is_dir($socketdir) && $createifnotexists) {
|
||||
safe_exec('mkdir -p ' . escapeshellarg($socketdir));
|
||||
safe_exec('chown -R ' . Settings::Get('system.httpuser') . ':' . Settings::Get('system.httpgroup') . ' ' . escapeshellarg($socketdir));
|
||||
}
|
||||
|
||||
return $socket;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpm-temp directory
|
||||
*
|
||||
* @param boolean $createifnotexists
|
||||
* create the directory if it does not exist
|
||||
*
|
||||
* @return string the directory
|
||||
*/
|
||||
public function getTempDir($createifnotexists = true)
|
||||
{
|
||||
$tmpdir = makeCorrectDir(Settings::Get('phpfpm.tmpdir') . '/' . $this->_domain['loginname'] . '/');
|
||||
|
||||
if (! is_dir($tmpdir) && $createifnotexists) {
|
||||
safe_exec('mkdir -p ' . escapeshellarg($tmpdir));
|
||||
safe_exec('chown -R ' . $this->_domain['guid'] . ':' . $this->_domain['guid'] . ' ' . escapeshellarg($tmpdir));
|
||||
safe_exec('chmod 0750 ' . escapeshellarg($tmpdir));
|
||||
}
|
||||
|
||||
return $tmpdir;
|
||||
}
|
||||
|
||||
/**
|
||||
* fastcgi-fakedirectory directory
|
||||
*
|
||||
* @param boolean $createifnotexists
|
||||
* create the directory if it does not exist
|
||||
*
|
||||
* @return string the directory
|
||||
*/
|
||||
public function getAliasConfigDir($createifnotexists = true)
|
||||
{
|
||||
|
||||
// ensure default...
|
||||
if (Settings::Get('phpfpm.aliasconfigdir') == null) {
|
||||
Settings::Set('phpfpm.aliasconfigdir', '/var/www/php-fpm');
|
||||
}
|
||||
|
||||
$configdir = makeCorrectDir(Settings::Get('phpfpm.aliasconfigdir') . '/' . $this->_domain['loginname'] . '/' . $this->_domain['domain'] . '/');
|
||||
if (! is_dir($configdir) && $createifnotexists) {
|
||||
safe_exec('mkdir -p ' . escapeshellarg($configdir));
|
||||
safe_exec('chown ' . $this->_domain['guid'] . ':' . $this->_domain['guid'] . ' ' . escapeshellarg($configdir));
|
||||
}
|
||||
|
||||
return $configdir;
|
||||
}
|
||||
|
||||
/**
|
||||
* create a dummy fpm pool config with minimal configuration
|
||||
* (this is used whenever a config directory is empty but needs at least one pool to startup/restart)
|
||||
*
|
||||
* @param string $configdir
|
||||
*/
|
||||
public static function createDummyPool($configdir)
|
||||
{
|
||||
if (! is_dir($configdir)) {
|
||||
safe_exec('mkdir -p ' . escapeshellarg($configdir));
|
||||
}
|
||||
$config = makeCorrectFile($configdir . '/dummy.conf');
|
||||
$dummy = "[dummy]
|
||||
user = " . Settings::Get('system.httpuser') . "
|
||||
listen = /run/" . md5($configdir) . "-fpm.sock
|
||||
pm = static
|
||||
pm.max_children = 1
|
||||
";
|
||||
file_put_contents($config, $dummy);
|
||||
}
|
||||
|
||||
/**
|
||||
* return the admin-data of a specific admin
|
||||
*
|
||||
* @param int $adminid
|
||||
* id of the admin-user
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function _getAdminData($adminid)
|
||||
{
|
||||
$adminid = intval($adminid);
|
||||
|
||||
if (! isset($this->_admin_cache[$adminid])) {
|
||||
$stmt = Database::prepare("
|
||||
SELECT `email`, `loginname` FROM `" . TABLE_PANEL_ADMINS . "` WHERE `adminid` = :id");
|
||||
$this->_admin_cache[$adminid] = Database::pexecute_first($stmt, array(
|
||||
'id' => $adminid
|
||||
));
|
||||
}
|
||||
return $this->_admin_cache[$adminid];
|
||||
}
|
||||
}
|
||||
116
lib/Froxlor/Cron/Http/Php/PhpInterface.php
Normal file
116
lib/Froxlor/Cron/Http/Php/PhpInterface.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
namespace Froxlor\Cron\Http\Php;
|
||||
|
||||
use Froxlor\Database;
|
||||
use Froxlor\Settings;
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||
*
|
||||
* For the full copyright and license information, please view the COPYING
|
||||
* file that was distributed with this source code. You can also view the
|
||||
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
|
||||
*
|
||||
* @copyright (c) the authors
|
||||
* @author Michael Kaufmann <mkaufmann@nutime.de>
|
||||
* @author Froxlor team <team@froxlor.org> (2010-)
|
||||
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
|
||||
* @package Cron
|
||||
*
|
||||
* @link http://www.nutime.de/
|
||||
* @since 0.9.16
|
||||
*
|
||||
*/
|
||||
class PhpInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Domain-Data array
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_domain = array();
|
||||
|
||||
/**
|
||||
* Interface object
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
private $_interface = null;
|
||||
|
||||
/**
|
||||
* Admin-User data array
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_admin_cache = array();
|
||||
|
||||
/**
|
||||
* main constructor
|
||||
*/
|
||||
public function __construct($domain)
|
||||
{
|
||||
$this->_domain = $domain;
|
||||
$this->_setInterface();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the interface-object
|
||||
* from where we can control it
|
||||
*/
|
||||
public function getInterface()
|
||||
{
|
||||
return $this->_interface;
|
||||
}
|
||||
|
||||
/**
|
||||
* set interface-object by type of
|
||||
* php-interface: fcgid or php-fpm
|
||||
* sets private $_interface variable
|
||||
*/
|
||||
private function _setInterface()
|
||||
{
|
||||
// php-fpm
|
||||
if ((int) Settings::Get('phpfpm.enabled') == 1) {
|
||||
$this->_interface = new Fpm($this->_domain);
|
||||
} elseif ((int) Settings::Get('system.mod_fcgid') == 1) {
|
||||
$this->_interface = new Fcgid($this->_domain);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return the php-configuration from the database
|
||||
*
|
||||
* @param int $php_config_id
|
||||
* id of the php-configuration
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getPhpConfig($php_config_id)
|
||||
{
|
||||
$php_config_id = intval($php_config_id);
|
||||
|
||||
// If domain has no config, we will use the default one.
|
||||
if ($php_config_id == 0) {
|
||||
$php_config_id = 1;
|
||||
}
|
||||
|
||||
if (! isset($this->php_configs_cache[$php_config_id])) {
|
||||
$stmt = Database::prepare("
|
||||
SELECT * FROM `" . TABLE_PANEL_PHPCONFIGS . "` WHERE `id` = :id");
|
||||
$this->_php_configs_cache[$php_config_id] = Database::pexecute_first($stmt, array(
|
||||
'id' => $php_config_id
|
||||
));
|
||||
if ((int) Settings::Get('phpfpm.enabled') == 1) {
|
||||
$stmt = Database::prepare("
|
||||
SELECT * FROM `" . TABLE_PANEL_FPMDAEMONS . "` WHERE `id` = :id");
|
||||
$this->_php_configs_cache[$php_config_id]['fpm_settings'] = Database::pexecute_first($stmt, array(
|
||||
'id' => $this->_php_configs_cache[$php_config_id]['fpmsettingid']
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_php_configs_cache[$php_config_id];
|
||||
}
|
||||
}
|
||||
114
lib/Froxlor/Cron/Http/WebserverBase.php
Normal file
114
lib/Froxlor/Cron/Http/WebserverBase.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
namespace Froxlor\Cron\Http;
|
||||
|
||||
use Froxlor\Database;
|
||||
use Froxlor\Settings;
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||
*
|
||||
* For the full copyright and license information, please view the COPYING
|
||||
* file that was distributed with this source code. You can also view the
|
||||
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
|
||||
*
|
||||
* @copyright (c) the authors
|
||||
* @author Michael Kaufmann <mkaufmann@nutime.de>
|
||||
* @author Froxlor team <team@froxlor.org> (2010-)
|
||||
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
|
||||
* @package Cron
|
||||
*
|
||||
* @since 0.9.31
|
||||
*
|
||||
*/
|
||||
class WebserverBase
|
||||
{
|
||||
|
||||
/**
|
||||
* returns an array with all entries required for all
|
||||
* webserver-vhost-configs
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getVhostsToCreate()
|
||||
{
|
||||
$query = "SELECT `d`.*, `pd`.`domain` AS `parentdomain`, `c`.`loginname`,
|
||||
`d`.`phpsettingid`, `c`.`adminid`, `c`.`guid`, `c`.`email`,
|
||||
`c`.`documentroot` AS `customerroot`, `c`.`deactivated`,
|
||||
`c`.`phpenabled` AS `phpenabled_customer`,
|
||||
`d`.`phpenabled` AS `phpenabled_vhost`,
|
||||
`d`.`mod_fcgid_starter`,`d`.`mod_fcgid_maxrequests`,
|
||||
`d`.`ocsp_stapling`
|
||||
FROM `" . TABLE_PANEL_DOMAINS . "` `d`
|
||||
|
||||
LEFT JOIN `" . TABLE_PANEL_CUSTOMERS . "` `c` USING(`customerid`)
|
||||
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` `pd` ON (`pd`.`id` = `d`.`parentdomainid`)
|
||||
|
||||
WHERE `d`.`aliasdomain` IS NULL AND `d`.`email_only` <> '1'
|
||||
ORDER BY `d`.`parentdomainid` DESC, `d`.`iswildcarddomain`, `d`.`domain` ASC;
|
||||
";
|
||||
|
||||
$result_domains_stmt = Database::query($query);
|
||||
|
||||
// prepare IP statement
|
||||
$ip_stmt = Database::prepare("
|
||||
SELECT `di`.`id_domain` , `p`.`ssl`, `p`.`ssl_cert_file`, `p`.`ssl_key_file`, `p`.`ssl_ca_file`, `p`.`ssl_cert_chainfile`
|
||||
FROM `" . TABLE_DOMAINTOIP . "` `di`, `" . TABLE_PANEL_IPSANDPORTS . "` `p`
|
||||
WHERE `p`.`id` = `di`.`id_ipandports`
|
||||
AND `di`.`id_domain` = :domainid
|
||||
AND `p`.`ssl` = '1'
|
||||
");
|
||||
|
||||
// prepare fpm-config select query
|
||||
$fpm_sel_stmt = Database::prepare("
|
||||
SELECT f.id FROM `" . TABLE_PANEL_FPMDAEMONS . "` f
|
||||
LEFT JOIN `" . TABLE_PANEL_PHPCONFIGS . "` p ON p.fpmsettingid = f.id
|
||||
WHERE p.id = :phpconfigid
|
||||
");
|
||||
|
||||
$domains = array();
|
||||
while ($domain = $result_domains_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
|
||||
// set whole domain
|
||||
$domains[$domain['domain']] = $domain;
|
||||
// set empty-defaults for non-ssl
|
||||
$domains[$domain['domain']]['ssl'] = '';
|
||||
$domains[$domain['domain']]['ssl_cert_file'] = '';
|
||||
$domains[$domain['domain']]['ssl_key_file'] = '';
|
||||
$domains[$domain['domain']]['ssl_ca_file'] = '';
|
||||
$domains[$domain['domain']]['ssl_cert_chainfile'] = '';
|
||||
|
||||
// now, if the domain has an ssl ip/port assigned, get
|
||||
// the corresponding information from the db
|
||||
if (domainHasSslIpPort($domain['id'])) {
|
||||
|
||||
$ssl_ip = Database::pexecute_first($ip_stmt, array(
|
||||
'domainid' => $domain['id']
|
||||
));
|
||||
|
||||
// set ssl info for domain
|
||||
$domains[$domain['domain']]['ssl'] = '1';
|
||||
$domains[$domain['domain']]['ssl_cert_file'] = $ssl_ip['ssl_cert_file'];
|
||||
$domains[$domain['domain']]['ssl_key_file'] = $ssl_ip['ssl_key_file'];
|
||||
$domains[$domain['domain']]['ssl_ca_file'] = $ssl_ip['ssl_ca_file'];
|
||||
$domains[$domain['domain']]['ssl_cert_chainfile'] = $ssl_ip['ssl_cert_chainfile'];
|
||||
}
|
||||
|
||||
// read fpm-config-id if using fpm
|
||||
if ((int) Settings::Get('phpfpm.enabled') == 1) {
|
||||
|
||||
$fpm_config = Database::pexecute_first($fpm_sel_stmt, array(
|
||||
'phpconfigid' => $domain['phpsettingid']
|
||||
));
|
||||
if ($fpm_config) {
|
||||
$domains[$domain['domain']]['fpm_config_id'] = $fpm_config['id'];
|
||||
} else {
|
||||
// fallback
|
||||
$domains[$domain['domain']]['fpm_config_id'] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $domains;
|
||||
}
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
<?php if (!defined('MASTER_CRONJOB')) die('You cannot access this file directly!');
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||
*
|
||||
* For the full copyright and license information, please view the COPYING
|
||||
* file that was distributed with this source code. You can also view the
|
||||
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
|
||||
*
|
||||
* @copyright (c) the authors
|
||||
* @author Froxlor team <team@froxlor.org> (2010-)
|
||||
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
|
||||
* @package Cron
|
||||
*
|
||||
*/
|
||||
|
||||
class lighttpd_fcgid extends lighttpd
|
||||
{
|
||||
protected function composePhpOptions($domain)
|
||||
{
|
||||
$php_options_text = '';
|
||||
|
||||
if($domain['phpenabled_customer'] == 1 && $domain['phpenabled_vhost'] == '1')
|
||||
{
|
||||
$php = new phpinterface($domain);
|
||||
$phpconfig = $php->getPhpConfig((int)$domain['phpsettingid']);
|
||||
|
||||
// vhost data for php-fpm
|
||||
if((int)Settings::Get('phpfpm.enabled') == 1)
|
||||
{
|
||||
$php_options_text = ' fastcgi.server = ( '."\n";
|
||||
$php_options_text.= "\t".'".php" => ('."\n";
|
||||
$php_options_text.= "\t\t".'"localhost" => ('."\n";
|
||||
$php_options_text.= "\t\t".'"socket" => "'.$php->getInterface()->getSocketFile().'",'."\n";
|
||||
$php_options_text.= "\t\t".'"check-local" => "enable",'."\n";
|
||||
$php_options_text.= "\t\t".'"disable-time" => 1'."\n";
|
||||
$php_options_text.= "\t".')'."\n";
|
||||
$php_options_text.= "\t".')'."\n";
|
||||
$php_options_text.= ' )'."\n";
|
||||
}
|
||||
// vhost data for fcgid
|
||||
elseif((int)Settings::Get('system.mod_fcgid') == 1)
|
||||
{
|
||||
$php_options_text = ' fastcgi.server = ( '."\n";
|
||||
$file_extensions = explode(' ', $phpconfig['file_extensions']);
|
||||
foreach($file_extensions as $f_extension)
|
||||
{
|
||||
$php_options_text.= "\t".'".'.$f_extension.'" => ('."\n";
|
||||
$php_options_text.= "\t\t".'"localhost" => ('."\n";
|
||||
$php_options_text.= "\t\t".'"socket" => "/var/run/lighttpd/'.$domain['loginname'].'-'.$domain['domain'].'-php.socket",'."\n";
|
||||
$php_options_text.= "\t\t".'"bin-path" => "'.$phpconfig['binary'].' -c '.$php->getInterface()->getIniFile().'",'."\n";
|
||||
$php_options_text.= "\t\t".'"bin-environment" => ('."\n";
|
||||
if((int)$domain['mod_fcgid_starter'] != - 1)
|
||||
{
|
||||
$php_options_text.= "\t\t\t".'"PHP_FCGI_CHILDREN" => "' . (int)$domain['mod_fcgid_starter'] . '",'."\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
if((int)$phpconfig['mod_fcgid_starter'] != - 1)
|
||||
{
|
||||
$php_options_text.= "\t\t\t".'"PHP_FCGI_CHILDREN" => "' . (int)$phpconfig['mod_fcgid_starter'] . '",'."\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$php_options_text.= "\t\t\t".'"PHP_FCGI_CHILDREN" => "' . (int)Settings::Get('system.mod_fcgid_starter') . '",'."\n";
|
||||
}
|
||||
}
|
||||
|
||||
if((int)$domain['mod_fcgid_maxrequests'] != - 1)
|
||||
{
|
||||
$php_options_text.= "\t\t\t".'"PHP_FCGI_MAX_REQUESTS" => "' . (int)$domain['mod_fcgid_maxrequests'] . '"'."\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
if((int)$phpconfig['mod_fcgid_maxrequests'] != - 1)
|
||||
{
|
||||
$php_options_text.= "\t\t\t".'"PHP_FCGI_MAX_REQUESTS" => "' . (int)$phpconfig['mod_fcgid_maxrequests'] . '"'."\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$php_options_text.= "\t\t\t".'"PHP_FCGI_MAX_REQUESTS" => "' . (int)Settings::Get('system.mod_fcgid_maxrequests') . '"'."\n";
|
||||
}
|
||||
}
|
||||
|
||||
$php_options_text.= "\t\t".')'."\n";
|
||||
$php_options_text.= "\t".')'."\n";
|
||||
$php_options_text.= "\t".')'."\n";
|
||||
|
||||
} // foreach extension
|
||||
$php_options_text.= ' )'."\n";
|
||||
}
|
||||
|
||||
// create starter-file | config-file
|
||||
$php->getInterface()->createConfig($phpconfig);
|
||||
|
||||
// create php.ini (fpm does nothing here, as it
|
||||
// defines ini-settings in its pool config)
|
||||
$php->getInterface()->createIniFile($phpconfig);
|
||||
}
|
||||
else
|
||||
{
|
||||
$php_options_text.= ' # PHP is disabled for this vHost' . "\n";
|
||||
}
|
||||
|
||||
return $php_options_text;
|
||||
}
|
||||
|
||||
public function createOwnVhostStarter()
|
||||
{
|
||||
if (Settings::Get('phpfpm.enabled') == '1'
|
||||
&& Settings::Get('phpfpm.enabled_ownvhost') == '1'
|
||||
) {
|
||||
$mypath = makeCorrectDir(dirname(dirname(dirname(__FILE__)))); // /var/www/froxlor, needed for chown
|
||||
|
||||
$user = Settings::Get('phpfpm.vhost_httpuser');
|
||||
$group = Settings::Get('phpfpm.vhost_httpgroup');
|
||||
|
||||
// get fpm config
|
||||
$fpm_sel_stmt = Database::prepare("
|
||||
SELECT f.id FROM `" . TABLE_PANEL_FPMDAEMONS . "` f
|
||||
LEFT JOIN `" . TABLE_PANEL_PHPCONFIGS . "` p ON p.fpmsettingid = f.id
|
||||
WHERE p.id = :phpconfigid
|
||||
");
|
||||
$fpm_config = Database::pexecute_first($fpm_sel_stmt, array(
|
||||
'phpconfigid' => Settings::Get('phpfpm.vhost_defaultini')
|
||||
));
|
||||
|
||||
$domain = array(
|
||||
'id' => 'none',
|
||||
'domain' => Settings::Get('system.hostname'),
|
||||
'adminid' => 1, /* first admin-user (superadmin) */
|
||||
'mod_fcgid_starter' => -1,
|
||||
'mod_fcgid_maxrequests' => -1,
|
||||
'guid' => $user,
|
||||
'openbasedir' => 0,
|
||||
'email' => Settings::Get('panel.adminmail'),
|
||||
'loginname' => 'froxlor.panel',
|
||||
'documentroot' => $mypath,
|
||||
'customerroot' => $mypath,
|
||||
'fpm_config_id' => isset($fpm_config['id']) ? $fpm_config['id'] : 1
|
||||
);
|
||||
|
||||
// all the files and folders have to belong to the local user
|
||||
// now because we also use fcgid for our own vhost
|
||||
safe_exec('chown -R ' . $user . ':' . $group . ' ' . escapeshellarg($mypath));
|
||||
|
||||
// get php.ini for our own vhost
|
||||
$php = new phpinterface($domain);
|
||||
|
||||
// get php-config
|
||||
if (Settings::Get('phpfpm.enabled') == '1') {
|
||||
// fpm
|
||||
$phpconfig = $php->getPhpConfig(Settings::Get('phpfpm.vhost_defaultini'));
|
||||
} else {
|
||||
// fcgid
|
||||
$phpconfig = $php->getPhpConfig(Settings::Get('system.mod_fcgid_defaultini_ownvhost'));
|
||||
}
|
||||
|
||||
// create starter-file | config-file
|
||||
$php->getInterface()->createConfig($phpconfig);
|
||||
|
||||
// create php.ini (fpm does nothing here, as it
|
||||
// defines ini-settings in its pool config)
|
||||
$php->getInterface()->createIniFile($phpconfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
151
lib/Froxlor/Cron/MasterCron.php
Normal file
151
lib/Froxlor/Cron/MasterCron.php
Normal file
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
namespace Froxlor\Cron;
|
||||
|
||||
use Froxlor\Database;
|
||||
use Froxlor\Settings;
|
||||
use Froxlor\FroxlorLogger;
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||
*
|
||||
* For the full copyright and license information, please view the COPYING
|
||||
* file that was distributed with this source code. You can also view the
|
||||
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
|
||||
*
|
||||
* @copyright (c) the authors
|
||||
* @author Froxlor team <team@froxlor.org> (2010-)
|
||||
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
|
||||
* @package Cron
|
||||
*
|
||||
*/
|
||||
class MasterCron extends \Froxlor\Cron\FroxlorCron
|
||||
{
|
||||
|
||||
public static function run()
|
||||
{
|
||||
define('MASTER_CRONJOB', 1);
|
||||
|
||||
include_once \Froxlor\Froxlor::getInstallDir() . '/lib/cron_init.php';
|
||||
|
||||
$jobs_to_run = array();
|
||||
|
||||
/**
|
||||
* check for --help
|
||||
*/
|
||||
if (count($argv) < 2 || (isset($argv[1]) && strtolower($argv[1]) == '--help')) {
|
||||
echo "\n*** Froxlor Master Cronjob ***\n\n";
|
||||
echo "Below are possible parameters for this file\n\n";
|
||||
echo "--[cronname]\t\tincludes the given cron-file\n";
|
||||
echo "--force\t\t\tforces re-generating of config-files (webserver, nameserver, etc.)\n";
|
||||
echo "--debug\t\t\toutput debug information about what is going on to STDOUT.\n";
|
||||
echo "--no-fork\t\t\tdo not fork to backkground (traffic cron only).\n\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* check for parameters
|
||||
*
|
||||
* --[cronname] include [cronname]
|
||||
* --force to include cron_tasks even if it's not its turn
|
||||
* --debug to output debug information
|
||||
*/
|
||||
for ($x = 1; $x < count($argv); $x ++) {
|
||||
// check argument
|
||||
if (isset($argv[$x])) {
|
||||
// --force
|
||||
if (strtolower($argv[$x]) == '--force') {
|
||||
// really force re-generating of config-files by
|
||||
// inserting task 1
|
||||
inserttask('1');
|
||||
// bind (if enabled, inserttask() checks this)
|
||||
inserttask('4');
|
||||
// set quotas (if enabled)
|
||||
inserttask('10');
|
||||
// also regenerate cron.d-file
|
||||
inserttask('99');
|
||||
addToQueue($jobs_to_run, 'tasks');
|
||||
} elseif (strtolower($argv[$x]) == '--debug') {
|
||||
define('CRON_DEBUG_FLAG', 1);
|
||||
} elseif (strtolower($argv[$x]) == '--no-fork') {
|
||||
define('CRON_NOFORK_FLAG', 1);
|
||||
} // --[cronname]
|
||||
elseif (substr(strtolower($argv[$x]), 0, 2) == '--') {
|
||||
if (strlen($argv[$x]) > 3) {
|
||||
$cronname = substr(strtolower($argv[$x]), 2);
|
||||
addToQueue($jobs_to_run, $cronname);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$cronlog->setCronDebugFlag(defined('CRON_DEBUG_FLAG'));
|
||||
|
||||
$tasks_cnt_stmt = \Froxlor\Database\Database::query("SELECT COUNT(*) as jobcnt FROM `panel_tasks`");
|
||||
$tasks_cnt = $tasks_cnt_stmt->fetch(\PDO::FETCH_ASSOC);
|
||||
|
||||
// do we have anything to include?
|
||||
if (count($jobs_to_run) > 0) {
|
||||
// include all jobs we want to execute
|
||||
foreach ($jobs_to_run as $cron) {
|
||||
self::updateLastRunOfCron($cron);
|
||||
$cronfile = self::getCronModule($cron);
|
||||
if ($cronfile && class_exists($cronfile)) {
|
||||
$cronfile::run();
|
||||
}
|
||||
}
|
||||
|
||||
if ($tasks_cnt['jobcnt'] > 0) {
|
||||
if (\Froxlor\Settings::Get('system.nssextrausers') == 1) {
|
||||
\Froxlor\Cron\System\Extrausers::generateFiles($cronlog);
|
||||
}
|
||||
|
||||
// clear NSCD cache if using fcgid or fpm, #1570
|
||||
if (\Froxlor\Settings::Get('system.mod_fcgid') == 1 || (int) \Froxlor\Settings::Get('phpfpm.enabled') == 1) {
|
||||
$false_val = false;
|
||||
\Froxlor\FileDir::safe_exec('nscd -i passwd 1> /dev/null', $false_val, array(
|
||||
'>'
|
||||
));
|
||||
\Froxlor\FileDir::safe_exec('nscd -i group 1> /dev/null', $false_val, array(
|
||||
'>'
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* we have to check the system's last guid with every cron run
|
||||
* in case the admin installed new software which added a new user
|
||||
* so users in the database don't conflict with system users
|
||||
*/
|
||||
$cronlog->logAction(CRON_ACTION, LOG_NOTICE, 'Checking system\'s last guid');
|
||||
checkLastGuid();
|
||||
|
||||
// shutdown cron
|
||||
include_once \Froxlor\Froxlor::getInstallDir() . '/lib/cron_shutdown.php';
|
||||
}
|
||||
|
||||
private static function updateLastRunOfCron($cronname)
|
||||
{
|
||||
$upd_stmt = Database::prepare("
|
||||
UPDATE `" . TABLE_PANEL_CRONRUNS . "` SET `lastrun` = UNIX_TIMESTAMP() WHERE `cronfile` = :cron;
|
||||
");
|
||||
Database::pexecute($upd_stmt, array(
|
||||
'cron' => $cronname
|
||||
));
|
||||
}
|
||||
|
||||
private static function getCronModule($cronname)
|
||||
{
|
||||
$upd_stmt = Database::prepare("
|
||||
SELECT `cronclass` FROM `" . TABLE_PANEL_CRONRUNS . "` WHERE `cronfile` = :cron;
|
||||
");
|
||||
$cron = Database::pexecute_first($upd_stmt, array(
|
||||
'cron' => $cronname
|
||||
));
|
||||
if ($cron) {
|
||||
return $cron['cronclass'];
|
||||
}
|
||||
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(CRON_ACTION, LOG_ERROR, "Requested cronjob '" . $cronname . "' could not be found.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
<?php
|
||||
namespace Froxlor\Cron\System;
|
||||
|
||||
use \Froxlor\Database;
|
||||
use \Froxlor\Settings;
|
||||
use \Froxlor\FroxlorLogger;
|
||||
use Froxlor\Database;
|
||||
use Froxlor\Settings;
|
||||
use Froxlor\FroxlorLogger;
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
@@ -96,7 +96,7 @@ class BackupCron extends \Froxlor\Cron\FroxlorCron
|
||||
\Froxlor\FileDir::safe_exec('mkdir -p ' . escapeshellarg($row['data']['destdir']));
|
||||
}
|
||||
|
||||
createCustomerBackup($row['data'], $customerdocroot, FroxlorLogger::getInstanceOf());
|
||||
self::createCustomerBackup($row['data'], $customerdocroot, FroxlorLogger::getInstanceOf());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,4 +111,112 @@ class BackupCron extends \Froxlor\Cron\FroxlorCron
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* depending on the give choice, the customers web-data, email-data and databases are being backup'ed
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
*/
|
||||
private static function createCustomerBackup($data = null, $customerdocroot = null, &$cronlog)
|
||||
{
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'Creating Backup for user "' . $data['loginname'] . '"');
|
||||
|
||||
// create tmp folder
|
||||
$tmpdir = makeCorrectDir($data['destdir'] . '/.tmp/');
|
||||
$cronlog->logAction(CRON_ACTION, LOG_DEBUG, 'Creating tmp-folder "' . $tmpdir . '"');
|
||||
$cronlog->logAction(CRON_ACTION, LOG_DEBUG, 'shell> mkdir -p ' . escapeshellarg($tmpdir));
|
||||
\Froxlor\FileDir::safe_exec('mkdir -p ' . escapeshellarg($tmpdir));
|
||||
$create_backup_tar_data = "";
|
||||
|
||||
// MySQL databases
|
||||
if ($data['backup_dbs'] == 1) {
|
||||
|
||||
$cronlog->logAction(CRON_ACTION, LOG_DEBUG, 'Creating mysql-folder "' . \Froxlor\FileDir::makeCorrectDir($tmpdir . '/mysql') . '"');
|
||||
$cronlog->logAction(CRON_ACTION, LOG_DEBUG, 'shell> mkdir -p ' . escapeshellarg(makeCorrectDir($tmpdir . '/mysql')));
|
||||
\Froxlor\FileDir::safe_exec('mkdir -p ' . escapeshellarg(makeCorrectDir($tmpdir . '/mysql')));
|
||||
|
||||
// get all customer database-names
|
||||
$sel_stmt = Database::prepare("SELECT `databasename` FROM `" . TABLE_PANEL_DATABASES . "` WHERE `customerid` = :cid");
|
||||
Database::pexecute($sel_stmt, array(
|
||||
'cid' => $data['customerid']
|
||||
));
|
||||
|
||||
Database::needRoot(true);
|
||||
Database::needSqlData();
|
||||
$sql_root = Database::getSqlData();
|
||||
Database::needRoot(false);
|
||||
|
||||
$has_dbs = false;
|
||||
while ($row = $sel_stmt->fetch()) {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_DEBUG, 'shell> mysqldump -u ' . escapeshellarg($sql_root['user']) . ' -pXXXXX ' . $row['databasename'] . ' > ' . \Froxlor\FileDir::makeCorrectFile($tmpdir . '/mysql/' . $row['databasename'] . '_' . date('YmdHi', time()) . '.sql'));
|
||||
$bool_false = false;
|
||||
\Froxlor\FileDir::safe_exec('mysqldump -u ' . escapeshellarg($sql_root['user']) . ' -p' . $sql_root['passwd'] . ' ' . $row['databasename'] . ' > ' . \Froxlor\FileDir::makeCorrectFile($tmpdir . '/mysql/' . $row['databasename'] . '_' . date('YmdHi', time()) . '.sql'), $bool_false, array(
|
||||
'>'
|
||||
));
|
||||
$has_dbs = true;
|
||||
}
|
||||
|
||||
if ($has_dbs) {
|
||||
$create_backup_tar_data .= './mysql ';
|
||||
}
|
||||
|
||||
unset($sql_root);
|
||||
}
|
||||
|
||||
// E-mail data
|
||||
if ($data['backup_mail'] == 1) {
|
||||
|
||||
$cronlog->logAction(CRON_ACTION, LOG_DEBUG, 'Creating mail-folder "' . \Froxlor\FileDir::makeCorrectDir($tmpdir . '/mail') . '"');
|
||||
\Froxlor\FileDir::safe_exec('mkdir -p ' . escapeshellarg(\Froxlor\FileDir::makeCorrectDir($tmpdir . '/mail')));
|
||||
|
||||
// get all customer mail-accounts
|
||||
$sel_stmt = Database::prepare("SELECT `homedir`, `maildir` FROM `" . TABLE_MAIL_USERS . "` WHERE `customerid` = :cid");
|
||||
Database::pexecute($sel_stmt, array(
|
||||
'cid' => $data['customerid']
|
||||
));
|
||||
|
||||
$tar_file_list = "";
|
||||
$mail_homedir = "";
|
||||
while ($row = $sel_stmt->fetch()) {
|
||||
$tar_file_list .= escapeshellarg("./" . $row['maildir']) . " ";
|
||||
$mail_homedir = $row['homedir'];
|
||||
}
|
||||
|
||||
if (! empty($tar_file_list)) {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_DEBUG, 'shell> tar cfvz ' . escapeshellarg(\Froxlor\FileDir::makeCorrectFile($tmpdir . '/mail/' . $data['loginname'] . '-mail.tar.gz')) . ' -C ' . escapeshellarg($mail_homedir) . ' ' . trim($tar_file_list));
|
||||
\Froxlor\FileDir::safe_exec('tar cfz ' . escapeshellarg(\Froxlor\FileDir::makeCorrectFile($tmpdir . '/mail/' . $data['loginname'] . '-mail.tar.gz')) . ' -C ' . escapeshellarg($mail_homedir) . ' ' . trim($tar_file_list));
|
||||
$create_backup_tar_data .= './mail ';
|
||||
}
|
||||
}
|
||||
|
||||
// Web data
|
||||
if ($data['backup_web'] == 1) {
|
||||
|
||||
$cronlog->logAction(CRON_ACTION, LOG_DEBUG, 'Creating web-folder "' . \Froxlor\FileDir::makeCorrectDir($tmpdir . '/web') . '"');
|
||||
\Froxlor\FileDir::safe_exec('mkdir -p ' . escapeshellarg(\Froxlor\FileDir::makeCorrectDir($tmpdir . '/web')));
|
||||
$cronlog->logAction(CRON_ACTION, LOG_DEBUG, 'shell> tar cfz ' . escapeshellarg(\Froxlor\FileDir::makeCorrectFile($tmpdir . '/web/' . $data['loginname'] . '-web.tar.gz')) . ' --exclude=' . escapeshellarg(str_replace($customerdocroot, "./", \Froxlor\FileDir::makeCorrectFile($tmpdir . '/*'))) . ' --exclude=' . escapeshellarg(str_replace($customerdocroot, "./", substr(\Froxlor\FileDir::makeCorrectDir($tmpdir), 0, - 1))) . ' -C ' . escapeshellarg($customerdocroot) . ' .');
|
||||
\Froxlor\FileDir::safe_exec('tar cfz ' . escapeshellarg(\Froxlor\FileDir::makeCorrectFile($tmpdir . '/web/' . $data['loginname'] . '-web.tar.gz')) . ' --exclude=' . escapeshellarg(str_replace($customerdocroot, "./", \Froxlor\FileDir::makeCorrectFile($tmpdir . '/*'))) . ' --exclude=' . escapeshellarg(str_replace($customerdocroot, "./", substr(\Froxlor\FileDir::makeCorrectFile($tmpdir), 0, - 1))) . ' -C ' . escapeshellarg($customerdocroot) . ' .');
|
||||
$create_backup_tar_data .= './web ';
|
||||
}
|
||||
|
||||
if (! empty($create_backup_tar_data)) {
|
||||
$backup_file = \Froxlor\FileDir::makeCorrectFile($tmpdir . '/' . $data['loginname'] . '-backup_' . date('YmdHi', time()) . '.tar.gz');
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'Creating backup-file "' . $backup_file . '"');
|
||||
// pack all archives in tmp-dir to one
|
||||
$cronlog->logAction(CRON_ACTION, LOG_DEBUG, 'shell> tar cfz ' . escapeshellarg($backup_file) . ' -C ' . escapeshellarg($tmpdir) . ' ' . trim($create_backup_tar_data));
|
||||
\Froxlor\FileDir::safe_exec('tar cfz ' . escapeshellarg($backup_file) . ' -C ' . escapeshellarg($tmpdir) . ' ' . trim($create_backup_tar_data));
|
||||
// move to destination directory
|
||||
$cronlog->logAction(CRON_ACTION, LOG_DEBUG, 'shell> mv ' . escapeshellarg($backup_file) . ' ' . escapeshellarg($data['destdir']));
|
||||
\Froxlor\FileDir::safe_exec('mv ' . escapeshellarg($backup_file) . ' ' . escapeshellarg($data['destdir']));
|
||||
// remove tmp-files
|
||||
$cronlog->logAction(CRON_ACTION, LOG_DEBUG, 'shell> rm -rf ' . escapeshellarg($tmpdir));
|
||||
\Froxlor\FileDir::safe_exec('rm -rf ' . escapeshellarg($tmpdir));
|
||||
// set owner to customer
|
||||
$cronlog->logAction(CRON_ACTION, LOG_DEBUG, 'shell> chown -R ' . (int) $data['uid'] . ':' . (int) $data['gid'] . ' ' . escapeshellarg($data['destdir']));
|
||||
\Froxlor\FileDir::safe_exec('chown -R ' . (int) $data['uid'] . ':' . (int) $data['gid'] . ' ' . escapeshellarg($data['destdir']));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Froxlor\Cron\System;
|
||||
* @since 0.9.29.1
|
||||
*
|
||||
*/
|
||||
class MailboxSizeCron extends \Froxlor\Cron\FroxlorCron
|
||||
class MailboxsizeCron extends \Froxlor\Cron\FroxlorCron
|
||||
{
|
||||
|
||||
public static function run()
|
||||
433
lib/Froxlor/Cron/System/TasksCron.php
Normal file
433
lib/Froxlor/Cron/System/TasksCron.php
Normal file
@@ -0,0 +1,433 @@
|
||||
<?php
|
||||
namespace Froxlor\Cron\System;
|
||||
|
||||
use Froxlor\Database;
|
||||
use Froxlor\Settings;
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
* Copyright (c) 2003-2009 the SysCP Team (see authors).
|
||||
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||
*
|
||||
* For the full copyright and license information, please view the COPYING
|
||||
* file that was distributed with this source code. You can also view the
|
||||
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
|
||||
*
|
||||
* @copyright (c) the authors
|
||||
* @author Florian Lippert <flo@syscp.org> (2003-2009)
|
||||
* @author Froxlor team <team@froxlor.org> (2010-)
|
||||
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
|
||||
* @package Cron
|
||||
*
|
||||
*/
|
||||
class TasksCron extends \Froxlor\Cron\FroxlorCron
|
||||
{
|
||||
|
||||
public static function run()
|
||||
{
|
||||
/**
|
||||
* LOOK INTO TASKS TABLE TO SEE IF THERE ARE ANY UNDONE JOBS
|
||||
*/
|
||||
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(CRON_ACTION, LOG_INFO, "TasksCron: Searching for tasks to do");
|
||||
// no type 99 (regenerate cron.d-file) and no type 20 (customer backup)
|
||||
$result_tasks_stmt = Database::query("
|
||||
SELECT `id`, `type`, `data` FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` <> '99' AND `type` <> '20' ORDER BY `id` ASC
|
||||
");
|
||||
$num_results = Database::num_rows();
|
||||
$resultIDs = array();
|
||||
|
||||
while ($row = $result_tasks_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
|
||||
$resultIDs[] = $row['id'];
|
||||
|
||||
if ($row['data'] != '') {
|
||||
$row['data'] = json_decode($row['data'], true);
|
||||
}
|
||||
|
||||
if ($row['type'] == '1') {
|
||||
/**
|
||||
* TYPE=1 MEANS TO REBUILD APACHE VHOSTS.CONF
|
||||
*/
|
||||
self::rebuildWebserverConfigs();
|
||||
} elseif ($row['type'] == '2') {
|
||||
/**
|
||||
* TYPE=2 MEANS TO CREATE A NEW HOME AND CHOWN
|
||||
*/
|
||||
self::createNewHome($row);
|
||||
} elseif ($row['type'] == '4' && (int) Settings::Get('system.bind_enable') != 0) {
|
||||
/**
|
||||
* TYPE=4 MEANS THAT SOMETHING IN THE BIND CONFIG HAS CHANGED.
|
||||
* REBUILD froxlor_bind.conf IF BIND IS ENABLED
|
||||
*/
|
||||
self::rebuildDnsConfigs();
|
||||
} elseif ($row['type'] == '5') {
|
||||
/**
|
||||
* TYPE=5 MEANS THAT A NEW FTP-ACCOUNT HAS BEEN CREATED, CREATE THE DIRECTORY
|
||||
*/
|
||||
self::createNewFtpHome($row);
|
||||
} elseif ($row['type'] == '6') {
|
||||
/**
|
||||
* TYPE=6 MEANS THAT A CUSTOMER HAS BEEN DELETED AND THAT WE HAVE TO REMOVE ITS FILES
|
||||
*/
|
||||
self::deleteCustomerData($row);
|
||||
} elseif ($row['type'] == '7') {
|
||||
/**
|
||||
* TYPE=7 Customer deleted an email account and wants the data to be deleted on the filesystem
|
||||
*/
|
||||
self::deleteEmailData($row);
|
||||
} elseif ($row['type'] == '8') {
|
||||
/**
|
||||
* TYPE=8 Customer deleted a ftp account and wants the homedir to be deleted on the filesystem
|
||||
* refs #293
|
||||
*/
|
||||
self::deleteFtpData($row);
|
||||
} elseif ($row['type'] == '10' && (int) Settings::Get('system.diskquota_enabled') != 0) {
|
||||
/**
|
||||
* TYPE=10 Set the filesystem - quota
|
||||
*/
|
||||
self::setFilesystemQuota();
|
||||
} elseif ($row['type'] == '11' && Settings::Get('system.dns_server') == 'PowerDNS') {
|
||||
/**
|
||||
* TYPE=11 domain has been deleted, remove from pdns database if used
|
||||
*/
|
||||
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(CRON_ACTION, LOG_NOTICE, "Removing PowerDNS entries for domain " . $row['data']['domain']);
|
||||
\Froxlor\Dns\PowerDNS::cleanDomainZone($row['data']['domain']);
|
||||
}
|
||||
}
|
||||
|
||||
if ($num_results != 0) {
|
||||
$where = array();
|
||||
$where_data = array();
|
||||
foreach ($resultIDs as $id) {
|
||||
$where[] = "`id` = :id_" . (int) $id;
|
||||
$where_data['id_' . $id] = $id;
|
||||
}
|
||||
$where = implode($where, ' OR ');
|
||||
$del_stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_TASKS . "` WHERE " . $where);
|
||||
Database::pexecute($del_stmt, $where_data);
|
||||
unset($resultIDs);
|
||||
unset($where);
|
||||
}
|
||||
|
||||
Database::query("UPDATE `" . TABLE_PANEL_SETTINGS . "` SET `value` = UNIX_TIMESTAMP() WHERE `settinggroup` = 'system' AND `varname` = 'last_tasks_run';");
|
||||
}
|
||||
|
||||
private static function rebuildWebserverConfigs()
|
||||
{
|
||||
// get configuration-I/O object
|
||||
$configio = new \Froxlor\Cron\Http\ConfigIO();
|
||||
// clean up old configs
|
||||
$configio->cleanUp();
|
||||
|
||||
if (Settings::Get('system.webserver') == "apache2") {
|
||||
$websrv = '\\Froxlor\\Cron\\Http\\Apache';
|
||||
if (Settings::Get('system.mod_fcgid') == 1 || Settings::Get('phpfpm.enabled') == 1) {
|
||||
$websrv .= 'Fcgi';
|
||||
}
|
||||
} elseif (Settings::Get('system.webserver') == "lighttpd") {
|
||||
$websrv = '\\Froxlor\\Cron\\Http\\Lighttpd';
|
||||
if (Settings::Get('system.mod_fcgid') == 1 || Settings::Get('phpfpm.enabled') == 1) {
|
||||
$websrv .= 'Fcgi';
|
||||
}
|
||||
} elseif (Settings::Get('system.webserver') == "nginx") {
|
||||
$websrv = '\\Froxlor\\Cron\\Http\\Nginx';
|
||||
if (Settings::Get('phpfpm.enabled') == 1) {
|
||||
$websrv .= 'Fcgi';
|
||||
}
|
||||
}
|
||||
|
||||
$webserver = new $websrv();
|
||||
|
||||
if (isset($webserver)) {
|
||||
$webserver->createIpPort();
|
||||
$webserver->createVirtualHosts();
|
||||
$webserver->createFileDirOptions();
|
||||
$webserver->writeConfigs();
|
||||
$webserver->createOwnVhostStarter();
|
||||
$webserver->reload();
|
||||
} else {
|
||||
echo "Please check you Webserver settings\n";
|
||||
}
|
||||
|
||||
// if we use php-fpm and have a local user for froxlor, we need to
|
||||
// add the webserver-user to the local-group in order to allow the webserver
|
||||
// to access the fpm-socket
|
||||
if (Settings::Get('phpfpm.enabled') == 1 && function_exists("posix_getgrnam")) {
|
||||
// get group info about the local-user's group (e.g. froxlorlocal)
|
||||
$groupinfo = posix_getgrnam(Settings::Get('phpfpm.vhost_httpgroup'));
|
||||
// check group members
|
||||
if (isset($groupinfo['members']) && ! in_array(Settings::Get('system.httpuser'), $groupinfo['members'])) {
|
||||
// webserver has no access, add it
|
||||
if (isFreeBSD()) {
|
||||
\Froxlor\FileDir::safe_exec('pw usermod ' . escapeshellarg(Settings::Get('system.httpuser')) . ' -G ' . escapeshellarg(Settings::Get('phpfpm.vhost_httpgroup')));
|
||||
} else {
|
||||
\Froxlor\FileDir::safe_exec('usermod -a -G ' . escapeshellarg(Settings::Get('phpfpm.vhost_httpgroup')) . ' ' . escapeshellarg(Settings::Get('system.httpuser')));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tell the Let's Encrypt cron it's okay to generate the certificate and enable the redirect afterwards
|
||||
$upd_stmt = Database::prepare("UPDATE `" . TABLE_PANEL_DOMAINS . "` SET `ssl_redirect` = '3' WHERE `ssl_redirect` = '2'");
|
||||
Database::pexecute($upd_stmt);
|
||||
}
|
||||
|
||||
private static function createNewHome($row = null)
|
||||
{
|
||||
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(CRON_ACTION, LOG_INFO, 'TasksCron: Task2 started - create new home');
|
||||
|
||||
if (is_array($row['data'])) {
|
||||
// define paths
|
||||
$userhomedir = \Froxlor\FileDir::makeCorrectDir(Settings::Get('system.documentroot_prefix') . '/' . $row['data']['loginname'] . '/');
|
||||
$usermaildir = \Froxlor\FileDir::makeCorrectDir(Settings::Get('system.vmail_homedir') . '/' . $row['data']['loginname'] . '/');
|
||||
|
||||
// stats directory
|
||||
if (Settings::Get('system.awstats_enabled') == '1') {
|
||||
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(CRON_ACTION, LOG_NOTICE, 'Running: mkdir -p ' . escapeshellarg($userhomedir . 'awstats'));
|
||||
\Froxlor\FileDir::safe_exec('mkdir -p ' . escapeshellarg($userhomedir . 'awstats'));
|
||||
// in case we changed from the other stats -> remove old
|
||||
// (yes i know, the stats are lost - that's why you should not change all the time!)
|
||||
if (file_exists($userhomedir . 'webalizer')) {
|
||||
\Froxlor\FileDir::safe_exec('rm -rf ' . escapeshellarg($userhomedir . 'webalizer'));
|
||||
}
|
||||
} else {
|
||||
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(CRON_ACTION, LOG_NOTICE, 'Running: mkdir -p ' . escapeshellarg($userhomedir . 'webalizer'));
|
||||
\Froxlor\FileDir::safe_exec('mkdir -p ' . escapeshellarg($userhomedir . 'webalizer'));
|
||||
// in case we changed from the other stats -> remove old
|
||||
// (yes i know, the stats are lost - that's why you should not change all the time!)
|
||||
if (file_exists($userhomedir . 'awstats')) {
|
||||
\Froxlor\FileDir::safe_exec('rm -rf ' . escapeshellarg($userhomedir . 'awstats'));
|
||||
}
|
||||
}
|
||||
|
||||
// maildir
|
||||
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(CRON_ACTION, LOG_NOTICE, 'Running: mkdir -p ' . escapeshellarg($usermaildir));
|
||||
\Froxlor\FileDir::safe_exec('mkdir -p ' . escapeshellarg($usermaildir));
|
||||
|
||||
// check if admin of customer has added template for new customer directories
|
||||
if ((int) $row['data']['store_defaultindex'] == 1) {
|
||||
storeDefaultIndex($row['data']['loginname'], $userhomedir, \Froxlor\FroxlorLogger::getInstanceOf(), true);
|
||||
}
|
||||
|
||||
// strip of last slash of paths to have correct chown results
|
||||
$userhomedir = (substr($userhomedir, 0, - 1) == '/') ? substr($userhomedir, 0, - 1) : $userhomedir;
|
||||
$usermaildir = (substr($usermaildir, 0, - 1) == '/') ? substr($usermaildir, 0, - 1) : $usermaildir;
|
||||
|
||||
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(CRON_ACTION, LOG_NOTICE, 'Running: chown -R ' . (int) $row['data']['uid'] . ':' . (int) $row['data']['gid'] . ' ' . escapeshellarg($userhomedir));
|
||||
\Froxlor\FileDir::safe_exec('chown -R ' . (int) $row['data']['uid'] . ':' . (int) $row['data']['gid'] . ' ' . escapeshellarg($userhomedir));
|
||||
// don't allow others to access the directory (webserver will be the group via libnss-mysql)
|
||||
if (Settings::Get('system.mod_fcgid') == 1 || Settings::Get('phpfpm.enabled') == 1) {
|
||||
// fcgid or fpm
|
||||
\Froxlor\FileDir::safe_exec('chmod 0750 ' . escapeshellarg($userhomedir));
|
||||
} else {
|
||||
// mod_php -> no libnss-mysql -> no webserver-user in group
|
||||
\Froxlor\FileDir::safe_exec('chmod 0755 ' . escapeshellarg($userhomedir));
|
||||
}
|
||||
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(CRON_ACTION, LOG_NOTICE, 'Running: chown -R ' . (int) Settings::Get('system.vmail_uid') . ':' . (int) Settings::Get('system.vmail_gid') . ' ' . escapeshellarg($usermaildir));
|
||||
\Froxlor\FileDir::safe_exec('chown -R ' . (int) Settings::Get('system.vmail_uid') . ':' . (int) Settings::Get('system.vmail_gid') . ' ' . escapeshellarg($usermaildir));
|
||||
|
||||
if (Settings::Get('system.nssextrausers') == 1) {
|
||||
// explicitly create files after user has been created to avoid unknown user issues for apache/php-fpm when task#1 runs after this
|
||||
Extrausers::generateFiles(\Froxlor\FroxlorLogger::getInstanceOf());
|
||||
}
|
||||
|
||||
// clear NSCD cache if using fcgid or fpm, #1570
|
||||
if (Settings::Get('system.mod_fcgid') == 1 || (int) Settings::Get('phpfpm.enabled') == 1) {
|
||||
$false_val = false;
|
||||
\Froxlor\FileDir::safe_exec('nscd -i passwd 1> /dev/null', $false_val, array(
|
||||
'>'
|
||||
));
|
||||
\Froxlor\FileDir::safe_exec('nscd -i group 1> /dev/null', $false_val, array(
|
||||
'>'
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static function rebuildDnsConfigs()
|
||||
{
|
||||
$dnssrv = '\\Froxlor\\Cron\\Dns\\' . Settings::Get('system.dns_server');
|
||||
|
||||
$nameserver = new $dnssrv(\Froxlor\FroxlorLogger::getInstanceOf());
|
||||
|
||||
if (Settings::Get('dkim.use_dkim') == '1') {
|
||||
$nameserver->writeDKIMconfigs();
|
||||
}
|
||||
|
||||
$nameserver->writeConfigs();
|
||||
}
|
||||
|
||||
private static function createNewFtpHome($row = null)
|
||||
{
|
||||
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(CRON_ACTION, LOG_INFO, 'Creating new FTP-home');
|
||||
$result_directories_stmt = Database::query("
|
||||
SELECT `f`.`homedir`, `f`.`uid`, `f`.`gid`, `c`.`documentroot` AS `customerroot`
|
||||
FROM `" . TABLE_FTP_USERS . "` `f` LEFT JOIN `" . TABLE_PANEL_CUSTOMERS . "` `c` USING (`customerid`)
|
||||
");
|
||||
|
||||
while ($directory = $result_directories_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
\Froxlor\FileDir::mkDirWithCorrectOwnership($directory['customerroot'], $directory['homedir'], $directory['uid'], $directory['gid']);
|
||||
}
|
||||
}
|
||||
|
||||
private static function deleteCustomerData($row = null)
|
||||
{
|
||||
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(CRON_ACTION, LOG_INFO, 'TasksCron: Task6 started - deleting customer data');
|
||||
|
||||
if (is_array($row['data'])) {
|
||||
if (isset($row['data']['loginname'])) {
|
||||
// remove homedir
|
||||
$homedir = \Froxlor\FileDir::makeCorrectDir(Settings::Get('system.documentroot_prefix') . '/' . $row['data']['loginname']);
|
||||
|
||||
if (file_exists($homedir) && $homedir != '/' && $homedir != Settings::Get('system.documentroot_prefix') && substr($homedir, 0, strlen(Settings::Get('system.documentroot_prefix'))) == Settings::Get('system.documentroot_prefix')) {
|
||||
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(CRON_ACTION, LOG_NOTICE, 'Running: rm -rf ' . escapeshellarg($homedir));
|
||||
\Froxlor\FileDir::safe_exec('rm -rf ' . escapeshellarg($homedir));
|
||||
}
|
||||
|
||||
// remove maildir
|
||||
$maildir = \Froxlor\FileDir::makeCorrectDir(Settings::Get('system.vmail_homedir') . '/' . $row['data']['loginname']);
|
||||
|
||||
if (file_exists($maildir) && $maildir != '/' && $maildir != Settings::Get('system.vmail_homedir') && substr($maildir, 0, strlen(Settings::Get('system.vmail_homedir'))) == Settings::Get('system.vmail_homedir') && is_dir($maildir) && fileowner($maildir) == Settings::Get('system.vmail_uid') && filegroup($maildir) == Settings::Get('system.vmail_gid')) {
|
||||
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(CRON_ACTION, LOG_NOTICE, 'Running: rm -rf ' . escapeshellarg($maildir));
|
||||
// mail-address allows many special characters, see http://en.wikipedia.org/wiki/Email_address#Local_part
|
||||
$return = false;
|
||||
\Froxlor\FileDir::safe_exec('rm -rf ' . escapeshellarg($maildir), $return, array(
|
||||
'|',
|
||||
'&',
|
||||
'`',
|
||||
'$',
|
||||
'?'
|
||||
));
|
||||
}
|
||||
|
||||
// remove tmpdir if it exists
|
||||
$tmpdir = \Froxlor\FileDir::makeCorrectDir(Settings::Get('system.mod_fcgid_tmpdir') . '/' . $row['data']['loginname'] . '/');
|
||||
|
||||
if (file_exists($tmpdir) && is_dir($tmpdir) && $tmpdir != "/" && $tmpdir != Settings::Get('system.mod_fcgid_tmpdir') && substr($tmpdir, 0, strlen(Settings::Get('system.mod_fcgid_tmpdir'))) == Settings::Get('system.mod_fcgid_tmpdir')) {
|
||||
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(CRON_ACTION, LOG_NOTICE, 'Running: rm -rf ' . escapeshellarg($tmpdir));
|
||||
\Froxlor\FileDir::safe_exec('rm -rf ' . escapeshellarg($tmpdir));
|
||||
}
|
||||
|
||||
// webserver logs
|
||||
$logsdir = \Froxlor\FileDir::makeCorrectFile(Settings::Get('system.logfiles_directory') . '/' . $row['data']['loginname']);
|
||||
|
||||
if (file_exists($logsdir) && $logsdir != '/' && $logsdir != \Froxlor\FileDir::makeCorrectDir(Settings::Get('system.logfiles_directory')) && substr($logsdir, 0, strlen(Settings::Get('system.logfiles_directory'))) == Settings::Get('system.logfiles_directory')) {
|
||||
// build up wildcard for webX-{access,error}.log{*}
|
||||
$logfiles .= '-*';
|
||||
\Froxlor\FileDir::safe_exec('rm -f ' . escapeshellarg($logfiles));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static function deleteEmailData($row = null)
|
||||
{
|
||||
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(CRON_ACTION, LOG_INFO, 'TasksCron: Task7 started - deleting customer e-mail data');
|
||||
|
||||
if (is_array($row['data'])) {
|
||||
|
||||
if (isset($row['data']['loginname']) && isset($row['data']['email'])) {
|
||||
// remove specific maildir
|
||||
$email_full = $row['data']['email'];
|
||||
if (empty($email_full)) {
|
||||
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(CRON_ACTION, LOG_ERROR, 'FATAL: Task7 asks to delete a email account but email field is empty!');
|
||||
}
|
||||
$email_user = substr($email_full, 0, strrpos($email_full, "@"));
|
||||
$email_domain = substr($email_full, strrpos($email_full, "@") + 1);
|
||||
$maildirname = trim(Settings::Get('system.vmail_maildirname'));
|
||||
// Add trailing slash to Maildir if needed
|
||||
$maildirpath = $maildirname;
|
||||
if (! empty($maildirname) and substr($maildirname, - 1) != "/") {
|
||||
$maildirpath .= "/";
|
||||
}
|
||||
|
||||
$maildir = \Froxlor\FileDir::makeCorrectDir(Settings::Get('system.vmail_homedir') . '/' . $row['data']['loginname'] . '/' . $email_domain . '/' . $email_user);
|
||||
|
||||
if ($maildir != '/' && ! empty($maildir) && ! empty($email_full) && $maildir != Settings::Get('system.vmail_homedir') && substr($maildir, 0, strlen(Settings::Get('system.vmail_homedir'))) == Settings::Get('system.vmail_homedir') && is_dir($maildir) && is_dir(\Froxlor\FileDir::makeCorrectDir($maildir . '/' . $maildirpath)) && fileowner($maildir) == Settings::Get('system.vmail_uid') && filegroup($maildir) == Settings::Get('system.vmail_gid')) {
|
||||
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(CRON_ACTION, LOG_NOTICE, 'Running: rm -rf ' . escapeshellarg($maildir));
|
||||
// mail-address allows many special characters, see http://en.wikipedia.org/wiki/Email_address#Local_part
|
||||
$return = false;
|
||||
\Froxlor\FileDir::safe_exec('rm -rf ' . escapeshellarg($maildir), $return, array(
|
||||
'|',
|
||||
'&',
|
||||
'`',
|
||||
'$',
|
||||
'~',
|
||||
'?'
|
||||
));
|
||||
} else {
|
||||
// backward-compatibility for old folder-structure
|
||||
$maildir_old = \Froxlor\FileDir::makeCorrectDir(Settings::Get('system.vmail_homedir') . '/' . $row['data']['loginname'] . '/' . $row['data']['email']);
|
||||
|
||||
if ($maildir_old != '/' && ! empty($maildir_old) && $maildir_old != Settings::Get('system.vmail_homedir') && substr($maildir_old, 0, strlen(Settings::Get('system.vmail_homedir'))) == Settings::Get('system.vmail_homedir') && is_dir($maildir_old) && fileowner($maildir_old) == Settings::Get('system.vmail_uid') && filegroup($maildir_old) == Settings::Get('system.vmail_gid')) {
|
||||
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(CRON_ACTION, LOG_NOTICE, 'Running: rm -rf ' . escapeshellarg($maildir_old));
|
||||
// mail-address allows many special characters, see http://en.wikipedia.org/wiki/Email_address#Local_part
|
||||
$return = false;
|
||||
\Froxlor\FileDir::safe_exec('rm -rf ' . escapeshellarg($maildir_old), $return, array(
|
||||
'|',
|
||||
'&',
|
||||
'`',
|
||||
'$',
|
||||
'~',
|
||||
'?'
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static function deleteFtpData($row = null)
|
||||
{
|
||||
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(CRON_ACTION, LOG_INFO, 'TasksCron: Task8 started - deleting customer ftp homedir');
|
||||
|
||||
if (is_array($row['data'])) {
|
||||
|
||||
if (isset($row['data']['loginname']) && isset($row['data']['homedir'])) {
|
||||
// remove specific homedir
|
||||
$ftphomedir = \Froxlor\FileDir::makeCorrectDir($row['data']['homedir']);
|
||||
$customerdocroot = \Froxlor\FileDir::makeCorrectDir(Settings::Get('system.documentroot_prefix') . '/' . $row['data']['loginname'] . '/');
|
||||
|
||||
if (file_exists($ftphomedir) && $ftphomedir != '/' && $ftphomedir != Settings::Get('system.documentroot_prefix') && $ftphomedir != $customerdocroot) {
|
||||
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(CRON_ACTION, LOG_NOTICE, 'Running: rm -rf ' . escapeshellarg($ftphomedir));
|
||||
\Froxlor\FileDir::safe_exec('rm -rf ' . escapeshellarg($ftphomedir));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static function setFilesystemQuota()
|
||||
{
|
||||
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(CRON_ACTION, LOG_INFO, 'TasksCron: Task10 started - setting filesystem quota');
|
||||
|
||||
// @fixme
|
||||
$usedquota = getFilesystemQuota();
|
||||
|
||||
// Check whether we really have entries to check
|
||||
if (is_array($usedquota) && count($usedquota) > 0) {
|
||||
// Select all customers Froxlor knows about
|
||||
$result_stmt = Database::query("SELECT `guid`, `loginname`, `diskspace` FROM `" . TABLE_PANEL_CUSTOMERS . "`;");
|
||||
while ($row = $result_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
// We do not want to set a quota for root by accident
|
||||
if ($row['guid'] != 0) {
|
||||
// The user has no quota in Froxlor, but on the filesystem
|
||||
if (($row['diskspace'] == 0 || $row['diskspace'] == - 1024) && $usedquota[$row['guid']]['block']['hard'] != 0) {
|
||||
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(CRON_ACTION, LOG_NOTICE, "Disabling quota for " . $row['loginname']);
|
||||
if (\Froxlor\FileDir::isFreeBSD()) {
|
||||
\Froxlor\FileDir::safe_exec(Settings::Get('system.diskquota_quotatool_path') . " -e " . escapeshellarg(Settings::Get('system.diskquota_customer_partition')) . ":0:0 " . $row['guid']);
|
||||
} else {
|
||||
\Froxlor\FileDir::safe_exec(Settings::Get('system.diskquota_quotatool_path') . " -u " . $row['guid'] . " -bl 0 -q 0 " . escapeshellarg(Settings::Get('system.diskquota_customer_partition')));
|
||||
}
|
||||
} // The user quota in Froxlor is different than on the filesystem
|
||||
elseif ($row['diskspace'] != $usedquota[$row['guid']]['block']['hard'] && $row['diskspace'] != - 1024) {
|
||||
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(CRON_ACTION, LOG_NOTICE, "Setting quota for " . $row['loginname'] . " from " . $usedquota[$row['guid']]['block']['hard'] . " to " . $row['diskspace']);
|
||||
if (\Froxlor\FileDir::isFreeBSD()) {
|
||||
\Froxlor\FileDir::safe_exec(Settings::Get('system.diskquota_quotatool_path') . " -e " . escapeshellarg(Settings::Get('system.diskquota_customer_partition')) . ":" . $row['diskspace'] . ":" . $row['diskspace'] . " " . $row['guid']);
|
||||
} else {
|
||||
\Froxlor\FileDir::safe_exec(Settings::Get('system.diskquota_quotatool_path') . " -u " . $row['guid'] . " -bl " . $row['diskspace'] . " -q " . $row['diskspace'] . " " . escapeshellarg(Settings::Get('system.diskquota_customer_partition')));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,445 +0,0 @@
|
||||
<?php if (!defined('MASTER_CRONJOB')) die('You cannot access this file directly!');
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
* Copyright (c) 2003-2009 the SysCP Team (see authors).
|
||||
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||
*
|
||||
* For the full copyright and license information, please view the COPYING
|
||||
* file that was distributed with this source code. You can also view the
|
||||
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
|
||||
*
|
||||
* @copyright (c) the authors
|
||||
* @author Florian Lippert <flo@syscp.org> (2003-2009)
|
||||
* @author Froxlor team <team@froxlor.org> (2010-)
|
||||
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
|
||||
* @package Cron
|
||||
*
|
||||
*/
|
||||
|
||||
// necessary includes
|
||||
require_once makeCorrectFile(dirname(__FILE__) . '/cron_tasks.inc.dns.10.bind.php');
|
||||
require_once makeCorrectFile(dirname(__FILE__) . '/cron_tasks.inc.dns.20.pdns.php');
|
||||
require_once makeCorrectFile(dirname(__FILE__) . '/cron_tasks.inc.http.10.apache.php');
|
||||
require_once makeCorrectFile(dirname(__FILE__) . '/cron_tasks.inc.http.15.apache_fcgid.php');
|
||||
require_once makeCorrectFile(dirname(__FILE__) . '/cron_tasks.inc.http.20.lighttpd.php');
|
||||
require_once makeCorrectFile(dirname(__FILE__) . '/cron_tasks.inc.http.25.lighttpd_fcgid.php');
|
||||
require_once makeCorrectFile(dirname(__FILE__) . '/cron_tasks.inc.http.30.nginx.php');
|
||||
require_once makeCorrectFile(dirname(__FILE__) . '/cron_tasks.inc.http.35.nginx_phpfpm.php');
|
||||
|
||||
/**
|
||||
* LOOK INTO TASKS TABLE TO SEE IF THERE ARE ANY UNDONE JOBS
|
||||
*/
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, "cron_tasks: Searching for tasks to do");
|
||||
// no type 99 (regenerate cron.d-file) and no type 20 (customer backup)
|
||||
$result_tasks_stmt = Database::query("
|
||||
SELECT `id`, `type`, `data` FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` <> '99' AND `type` <> '20' ORDER BY `id` ASC
|
||||
");
|
||||
$num_results = Database::num_rows();
|
||||
$resultIDs = array();
|
||||
|
||||
while ($row = $result_tasks_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
|
||||
$resultIDs[] = $row['id'];
|
||||
|
||||
if ($row['data'] != '') {
|
||||
$row['data'] = json_decode($row['data'], true);
|
||||
}
|
||||
|
||||
/**
|
||||
* TYPE=1 MEANS TO REBUILD APACHE VHOSTS.CONF
|
||||
*/
|
||||
if ($row['type'] == '1') {
|
||||
|
||||
// get configuration-I/O object
|
||||
$configio = new ConfigIO();
|
||||
// clean up old configs
|
||||
$configio->cleanUp();
|
||||
|
||||
if (!isset($webserver)) {
|
||||
if (Settings::Get('system.webserver') == "apache2") {
|
||||
$websrv = 'apache';
|
||||
if (Settings::Get('system.mod_fcgid') == 1 || Settings::Get('phpfpm.enabled') == 1) {
|
||||
$websrv .= '_fcgid';
|
||||
}
|
||||
} elseif (Settings::Get('system.webserver') == "lighttpd") {
|
||||
$websrv = 'lighttpd';
|
||||
if (Settings::Get('system.mod_fcgid') == 1 || Settings::Get('phpfpm.enabled') == 1) {
|
||||
$websrv .= '_fcgid';
|
||||
}
|
||||
} elseif (Settings::Get('system.webserver') == "nginx") {
|
||||
$websrv = 'nginx';
|
||||
if (Settings::Get('phpfpm.enabled') == 1) {
|
||||
$websrv .= '_phpfpm';
|
||||
}
|
||||
}
|
||||
|
||||
$webserver = new $websrv($cronlog, $idna_convert);
|
||||
}
|
||||
|
||||
if (isset($webserver)) {
|
||||
$webserver->createIpPort();
|
||||
$webserver->createVirtualHosts();
|
||||
$webserver->createFileDirOptions();
|
||||
$webserver->writeConfigs();
|
||||
$webserver->createOwnVhostStarter();
|
||||
$webserver->reload();
|
||||
} else {
|
||||
echo "Please check you Webserver settings\n";
|
||||
}
|
||||
|
||||
// if we use php-fpm and have a local user for froxlor, we need to
|
||||
// add the webserver-user to the local-group in order to allow the webserver
|
||||
// to access the fpm-socket
|
||||
if (Settings::Get('phpfpm.enabled') == 1 && function_exists("posix_getgrnam")) {
|
||||
// get group info about the local-user's group (e.g. froxlorlocal)
|
||||
$groupinfo = posix_getgrnam(Settings::Get('phpfpm.vhost_httpgroup'));
|
||||
// check group members
|
||||
if (isset($groupinfo['members'])
|
||||
&& !in_array(Settings::Get('system.httpuser'), $groupinfo['members'])
|
||||
) {
|
||||
// webserver has no access, add it
|
||||
if (isFreeBSD()) {
|
||||
safe_exec('pw usermod '.escapeshellarg(Settings::Get('system.httpuser')).' -G '.escapeshellarg(Settings::Get('phpfpm.vhost_httpgroup')));
|
||||
} else {
|
||||
safe_exec('usermod -a -G ' . escapeshellarg(Settings::Get('phpfpm.vhost_httpgroup')).' '.escapeshellarg(Settings::Get('system.httpuser')));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tell the Let's Encrypt cron it's okay to generate the certificate and enable the redirect afterwards
|
||||
$upd_stmt = Database::prepare("UPDATE `" . TABLE_PANEL_DOMAINS . "` SET `ssl_redirect` = '3' WHERE `ssl_redirect` = '2'");
|
||||
Database::pexecute($upd_stmt);
|
||||
}
|
||||
|
||||
/**
|
||||
* TYPE=2 MEANS TO CREATE A NEW HOME AND CHOWN
|
||||
*/
|
||||
elseif ($row['type'] == '2') {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'cron_tasks: Task2 started - create new home');
|
||||
|
||||
if (is_array($row['data'])) {
|
||||
// define paths
|
||||
$userhomedir = makeCorrectDir(Settings::Get('system.documentroot_prefix') . '/' . $row['data']['loginname'] . '/');
|
||||
$usermaildir = makeCorrectDir(Settings::Get('system.vmail_homedir') . '/' . $row['data']['loginname'] . '/');
|
||||
|
||||
// stats directory
|
||||
if (Settings::Get('system.awstats_enabled') == '1') {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_NOTICE, 'Running: mkdir -p ' . escapeshellarg($userhomedir . 'awstats'));
|
||||
safe_exec('mkdir -p ' . escapeshellarg($userhomedir . 'awstats'));
|
||||
// in case we changed from the other stats -> remove old
|
||||
// (yes i know, the stats are lost - that's why you should not change all the time!)
|
||||
if (file_exists($userhomedir . 'webalizer')) {
|
||||
safe_exec('rm -rf ' . escapeshellarg($userhomedir . 'webalizer'));
|
||||
}
|
||||
} else {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_NOTICE, 'Running: mkdir -p ' . escapeshellarg($userhomedir . 'webalizer'));
|
||||
safe_exec('mkdir -p ' . escapeshellarg($userhomedir . 'webalizer'));
|
||||
// in case we changed from the other stats -> remove old
|
||||
// (yes i know, the stats are lost - that's why you should not change all the time!)
|
||||
if (file_exists($userhomedir . 'awstats')) {
|
||||
safe_exec('rm -rf ' . escapeshellarg($userhomedir . 'awstats'));
|
||||
}
|
||||
}
|
||||
|
||||
// maildir
|
||||
$cronlog->logAction(CRON_ACTION, LOG_NOTICE, 'Running: mkdir -p ' . escapeshellarg($usermaildir));
|
||||
safe_exec('mkdir -p ' . escapeshellarg($usermaildir));
|
||||
|
||||
//check if admin of customer has added template for new customer directories
|
||||
if ((int)$row['data']['store_defaultindex'] == 1) {
|
||||
storeDefaultIndex($row['data']['loginname'], $userhomedir, $cronlog, true);
|
||||
}
|
||||
|
||||
// strip of last slash of paths to have correct chown results
|
||||
$userhomedir = (substr($userhomedir, 0, -1) == '/') ? substr($userhomedir, 0, -1) : $userhomedir;
|
||||
$usermaildir = (substr($usermaildir, 0, -1) == '/') ? substr($usermaildir, 0, -1) : $usermaildir;
|
||||
|
||||
$cronlog->logAction(CRON_ACTION, LOG_NOTICE, 'Running: chown -R ' . (int)$row['data']['uid'] . ':' . (int)$row['data']['gid'] . ' ' . escapeshellarg($userhomedir));
|
||||
safe_exec('chown -R ' . (int)$row['data']['uid'] . ':' . (int)$row['data']['gid'] . ' ' . escapeshellarg($userhomedir));
|
||||
// don't allow others to access the directory (webserver will be the group via libnss-mysql)
|
||||
if (Settings::Get('system.mod_fcgid') == 1 || Settings::Get('phpfpm.enabled') == 1) {
|
||||
// fcgid or fpm
|
||||
safe_exec('chmod 0750 ' . escapeshellarg($userhomedir));
|
||||
} else {
|
||||
// mod_php -> no libnss-mysql -> no webserver-user in group
|
||||
safe_exec('chmod 0755 ' . escapeshellarg($userhomedir));
|
||||
}
|
||||
$cronlog->logAction(CRON_ACTION, LOG_NOTICE, 'Running: chown -R ' . (int)Settings::Get('system.vmail_uid') . ':' . (int)Settings::Get('system.vmail_gid') . ' ' . escapeshellarg($usermaildir));
|
||||
safe_exec('chown -R ' . (int)Settings::Get('system.vmail_uid') . ':' . (int)Settings::Get('system.vmail_gid') . ' ' . escapeshellarg($usermaildir));
|
||||
|
||||
if (Settings::Get('system.nssextrausers') == 1)
|
||||
{
|
||||
// explicitly create files after user has been created to avoid unknown user issues for apache/php-fpm when task#1 runs after this
|
||||
include_once makeCorrectFile(\Froxlor\Froxlor::getInstallDir().'/scripts/classes/class.Extrausers.php');
|
||||
Extrausers::generateFiles($cronlog);
|
||||
}
|
||||
|
||||
// clear NSCD cache if using fcgid or fpm, #1570
|
||||
if (Settings::Get('system.mod_fcgid') == 1 || (int)Settings::Get('phpfpm.enabled') == 1) {
|
||||
$false_val = false;
|
||||
safe_exec('nscd -i passwd 1> /dev/null', $false_val, array('>'));
|
||||
safe_exec('nscd -i group 1> /dev/null', $false_val, array('>'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TYPE=4 MEANS THAT SOMETHING IN THE BIND CONFIG HAS CHANGED. REBUILD froxlor_bind.conf IF BIND IS ENABLED
|
||||
*/
|
||||
elseif ($row['type'] == '4' && (int)Settings::Get('system.bind_enable') != 0) {
|
||||
|
||||
$dnssrv = Settings::Get('system.dns_server');
|
||||
|
||||
if (!isset($nameserver)) {
|
||||
$nameserver = new $dnssrv($cronlog);
|
||||
}
|
||||
|
||||
if (Settings::Get('dkim.use_dkim') == '1') {
|
||||
$nameserver->writeDKIMconfigs();
|
||||
}
|
||||
|
||||
$nameserver->writeConfigs();
|
||||
}
|
||||
|
||||
/**
|
||||
* TYPE=5 MEANS THAT A NEW FTP-ACCOUNT HAS BEEN CREATED, CREATE THE DIRECTORY
|
||||
*/
|
||||
elseif ($row['type'] == '5') {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'Creating new FTP-home');
|
||||
$result_directories_stmt = Database::query("
|
||||
SELECT `f`.`homedir`, `f`.`uid`, `f`.`gid`, `c`.`documentroot` AS `customerroot`
|
||||
FROM `" . TABLE_FTP_USERS . "` `f` LEFT JOIN `" . TABLE_PANEL_CUSTOMERS . "` `c` USING (`customerid`)
|
||||
");
|
||||
|
||||
while ($directory = $result_directories_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
mkDirWithCorrectOwnership($directory['customerroot'], $directory['homedir'], $directory['uid'], $directory['gid']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TYPE=6 MEANS THAT A CUSTOMER HAS BEEN DELETED AND THAT WE HAVE TO REMOVE ITS FILES
|
||||
*/
|
||||
elseif ($row['type'] == '6') {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'cron_tasks: Task6 started - deleting customer data');
|
||||
|
||||
if (is_array($row['data'])) {
|
||||
if (isset($row['data']['loginname'])) {
|
||||
// remove homedir
|
||||
$homedir = makeCorrectDir(Settings::Get('system.documentroot_prefix') . '/' . $row['data']['loginname']);
|
||||
|
||||
if (file_exists($homedir)
|
||||
&& $homedir != '/'
|
||||
&& $homedir != Settings::Get('system.documentroot_prefix')
|
||||
&& substr($homedir, 0, strlen(Settings::Get('system.documentroot_prefix'))) == Settings::Get('system.documentroot_prefix')
|
||||
) {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_NOTICE, 'Running: rm -rf ' . escapeshellarg($homedir));
|
||||
safe_exec('rm -rf '.escapeshellarg($homedir));
|
||||
}
|
||||
|
||||
// remove maildir
|
||||
$maildir = makeCorrectDir(Settings::Get('system.vmail_homedir') . '/' . $row['data']['loginname']);
|
||||
|
||||
if (file_exists($maildir)
|
||||
&& $maildir != '/'
|
||||
&& $maildir != Settings::Get('system.vmail_homedir')
|
||||
&& substr($maildir, 0, strlen(Settings::Get('system.vmail_homedir'))) == Settings::Get('system.vmail_homedir')
|
||||
&& is_dir($maildir)
|
||||
&& fileowner($maildir) == Settings::Get('system.vmail_uid')
|
||||
&& filegroup($maildir) == Settings::Get('system.vmail_gid')
|
||||
) {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_NOTICE, 'Running: rm -rf ' . escapeshellarg($maildir));
|
||||
// mail-address allows many special characters, see http://en.wikipedia.org/wiki/Email_address#Local_part
|
||||
$return = false;
|
||||
safe_exec('rm -rf '.escapeshellarg($maildir), $return, array('|', '&', '`', '$', '~', '?'));
|
||||
}
|
||||
|
||||
// remove tmpdir if it exists
|
||||
$tmpdir = makeCorrectDir(Settings::Get('system.mod_fcgid_tmpdir') . '/' . $row['data']['loginname'] . '/');
|
||||
|
||||
if (file_exists($tmpdir)
|
||||
&& is_dir($tmpdir)
|
||||
&& $tmpdir != "/"
|
||||
&& $tmpdir != Settings::Get('system.mod_fcgid_tmpdir')
|
||||
&& substr($tmpdir, 0, strlen(Settings::Get('system.mod_fcgid_tmpdir'))) == Settings::Get('system.mod_fcgid_tmpdir')
|
||||
) {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_NOTICE, 'Running: rm -rf ' . escapeshellarg($tmpdir));
|
||||
safe_exec('rm -rf '.escapeshellarg($tmpdir));
|
||||
}
|
||||
|
||||
// webserver logs
|
||||
$logsdir = makeCorrectFile(Settings::Get('system.logfiles_directory').'/'.$row['data']['loginname']);
|
||||
|
||||
if (file_exists($logsdir)
|
||||
&& $logsdir != '/'
|
||||
&& $logsdir != makeCorrectDir(Settings::Get('system.logfiles_directory'))
|
||||
&& substr($logsdir, 0, strlen(Settings::Get('system.logfiles_directory'))) == Settings::Get('system.logfiles_directory')
|
||||
) {
|
||||
// build up wildcard for webX-{access,error}.log{*}
|
||||
$logfiles .= '-*';
|
||||
safe_exec('rm -f '.escapeshellarg($logfiles));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TYPE=7 Customer deleted an email account and wants the data to be deleted on the filesystem
|
||||
*/
|
||||
elseif ($row['type'] == '7') {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'cron_tasks: Task7 started - deleting customer e-mail data');
|
||||
|
||||
if (is_array($row['data'])) {
|
||||
|
||||
if (isset($row['data']['loginname'])
|
||||
&& isset($row['data']['email'])
|
||||
) {
|
||||
// remove specific maildir
|
||||
$email_full = $row['data']['email'];
|
||||
if (empty($email_full)) {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_ERROR, 'FATAL: Task7 asks to delete a email account but email field is empty!');
|
||||
}
|
||||
$email_user = substr($email_full,0,strrpos($email_full,"@"));
|
||||
$email_domain = substr($email_full,strrpos($email_full,"@")+1);
|
||||
$maildirname = trim(Settings::Get('system.vmail_maildirname'));
|
||||
// Add trailing slash to Maildir if needed
|
||||
$maildirpath = $maildirname;
|
||||
if (!empty($maildirname) and substr($maildirname,-1) != "/") {
|
||||
$maildirpath .= "/";
|
||||
}
|
||||
|
||||
$maildir = makeCorrectDir(Settings::Get('system.vmail_homedir') .'/'. $row['data']['loginname'] .'/'. $email_domain .'/'. $email_user);
|
||||
|
||||
if ($maildir != '/'
|
||||
&& !empty($maildir)
|
||||
&& !empty($email_full)
|
||||
&& $maildir != Settings::Get('system.vmail_homedir')
|
||||
&& substr($maildir, 0, strlen(Settings::Get('system.vmail_homedir'))) == Settings::Get('system.vmail_homedir')
|
||||
&& is_dir($maildir)
|
||||
&& is_dir(makeCorrectDir($maildir.'/'.$maildirpath))
|
||||
&& fileowner($maildir) == Settings::Get('system.vmail_uid')
|
||||
&& filegroup($maildir) == Settings::Get('system.vmail_gid')
|
||||
) {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_NOTICE, 'Running: rm -rf ' . escapeshellarg($maildir));
|
||||
// mail-address allows many special characters, see http://en.wikipedia.org/wiki/Email_address#Local_part
|
||||
$return = false;
|
||||
safe_exec('rm -rf '.escapeshellarg($maildir), $return, array('|', '&', '`', '$', '~', '?'));
|
||||
|
||||
} else {
|
||||
// backward-compatibility for old folder-structure
|
||||
$maildir_old = makeCorrectDir(Settings::Get('system.vmail_homedir') .'/'. $row['data']['loginname'] .'/'. $row['data']['email']);
|
||||
|
||||
if ($maildir_old != '/'
|
||||
&& !empty($maildir_old)
|
||||
&& $maildir_old != Settings::Get('system.vmail_homedir')
|
||||
&& substr($maildir_old, 0, strlen(Settings::Get('system.vmail_homedir'))) == Settings::Get('system.vmail_homedir')
|
||||
&& is_dir($maildir_old)
|
||||
&& fileowner($maildir_old) == Settings::Get('system.vmail_uid')
|
||||
&& filegroup($maildir_old) == Settings::Get('system.vmail_gid')
|
||||
) {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_NOTICE, 'Running: rm -rf ' . escapeshellarg($maildir_old));
|
||||
// mail-address allows many special characters, see http://en.wikipedia.org/wiki/Email_address#Local_part
|
||||
$return = false;
|
||||
safe_exec('rm -rf '.escapeshellarg($maildir_old), $return, array('|', '&', '`', '$', '~', '?'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TYPE=8 Customer deleted a ftp account and wants the homedir to be deleted on the filesystem
|
||||
* refs #293
|
||||
*/
|
||||
elseif ($row['type'] == '8') {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'cron_tasks: Task8 started - deleting customer ftp homedir');
|
||||
|
||||
if (is_array($row['data'])) {
|
||||
|
||||
if (isset($row['data']['loginname'])
|
||||
&& isset($row['data']['homedir'])
|
||||
) {
|
||||
// remove specific homedir
|
||||
$ftphomedir = makeCorrectDir($row['data']['homedir']);
|
||||
$customerdocroot = makeCorrectDir(Settings::Get('system.documentroot_prefix').'/'.$row['data']['loginname'].'/');
|
||||
|
||||
if (file_exists($ftphomedir)
|
||||
&& $ftphomedir != '/'
|
||||
&& $ftphomedir != Settings::Get('system.documentroot_prefix')
|
||||
&& $ftphomedir != $customerdocroot
|
||||
) {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_NOTICE, 'Running: rm -rf ' . escapeshellarg($ftphomedir));
|
||||
safe_exec('rm -rf '.escapeshellarg($ftphomedir));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TYPE=10 Set the filesystem - quota
|
||||
*/
|
||||
elseif ($row['type'] == '10' && (int)Settings::Get('system.diskquota_enabled') != 0) {
|
||||
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'cron_tasks: Task10 started - setting filesystem quota');
|
||||
|
||||
$usedquota = getFilesystemQuota();
|
||||
|
||||
// Check whether we really have entries to check
|
||||
if (is_array($usedquota) && count($usedquota) > 0) {
|
||||
// Select all customers Froxlor knows about
|
||||
$result_stmt = Database::query("SELECT `guid`, `loginname`, `diskspace` FROM `" . TABLE_PANEL_CUSTOMERS . "`;");
|
||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
// We do not want to set a quota for root by accident
|
||||
if ($row['guid'] != 0) {
|
||||
// The user has no quota in Froxlor, but on the filesystem
|
||||
if (($row['diskspace'] == 0 || $row['diskspace'] == -1024)
|
||||
&& $usedquota[$row['guid']]['block']['hard'] != 0
|
||||
) {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_NOTICE, "Disabling quota for " . $row['loginname']);
|
||||
if (isFreeBSD()) {
|
||||
safe_exec(Settings::Get('system.diskquota_quotatool_path') . " -e " . escapeshellarg(Settings::Get('system.diskquota_customer_partition')) . ":0:0 " . $row['guid']);
|
||||
} else {
|
||||
safe_exec(Settings::Get('system.diskquota_quotatool_path') . " -u " . $row['guid'] . " -bl 0 -q 0 " . escapeshellarg(Settings::Get('system.diskquota_customer_partition')));
|
||||
}
|
||||
}
|
||||
// The user quota in Froxlor is different than on the filesystem
|
||||
elseif ($row['diskspace'] != $usedquota[$row['guid']]['block']['hard']
|
||||
&& $row['diskspace'] != -1024
|
||||
) {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_NOTICE, "Setting quota for " . $row['loginname'] . " from " . $usedquota[$row['guid']]['block']['hard'] . " to " . $row['diskspace']);
|
||||
if (isFreeBSD()) {
|
||||
safe_exec(Settings::Get('system.diskquota_quotatool_path') . " -e " . escapeshellarg(Settings::Get('system.diskquota_customer_partition')) . ":" . $row['diskspace'] . ":" . $row['diskspace'] . " " . $row['guid']);
|
||||
} else {
|
||||
safe_exec(Settings::Get('system.diskquota_quotatool_path') . " -u " . $row['guid'] . " -bl " . $row['diskspace'] . " -q " . $row['diskspace'] . " " . escapeshellarg(Settings::Get('system.diskquota_customer_partition')));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TYPE=11 domain has been deleted, remove from pdns database if used
|
||||
*/
|
||||
if ($row['type'] == '11' && Settings::Get('system.dns_server') == 'pdns')
|
||||
{
|
||||
$cronlog->logAction(CRON_ACTION, LOG_NOTICE, "Removing PowerDNS entries for domain " . $row['data']['domain']);
|
||||
PowerDNS::cleanDomainZone($row['data']['domain']);
|
||||
}
|
||||
}
|
||||
|
||||
if ($num_results != 0) {
|
||||
$where = array();
|
||||
$where_data = array();
|
||||
foreach ($resultIDs as $id) {
|
||||
$where[] = "`id` = :id_" . (int)$id;
|
||||
$where_data['id_'.$id] = $id;
|
||||
}
|
||||
$where = implode($where, ' OR ');
|
||||
$del_stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_TASKS . "` WHERE " . $where);
|
||||
Database::pexecute($del_stmt, $where_data);
|
||||
unset($resultIDs);
|
||||
unset($where);
|
||||
}
|
||||
|
||||
Database::query("UPDATE `" . TABLE_PANEL_SETTINGS . "` SET `value` = UNIX_TIMESTAMP() WHERE `settinggroup` = 'system' AND `varname` = 'last_tasks_run';");
|
||||
@@ -1,53 +0,0 @@
|
||||
<?php if (!defined('MASTER_CRONJOB')) die('You cannot access this file directly!');
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
* Copyright (c) 2003-2009 the SysCP Team (see authors).
|
||||
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||
*
|
||||
* For the full copyright and license information, please view the COPYING
|
||||
* file that was distributed with this source code. You can also view the
|
||||
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
|
||||
*
|
||||
* @copyright (c) the authors
|
||||
* @author Florian Lippert <flo@syscp.org> (2003-2009)
|
||||
* @author Froxlor team <team@froxlor.org> (2010-)
|
||||
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
|
||||
* @package Cron
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* ARCHIVING CLOSED TICKETS
|
||||
*/
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'Ticket-archiving run started...');
|
||||
$result_tickets_stmt = Database::query("
|
||||
SELECT `id`, `lastchange`, `subject` FROM `" . TABLE_PANEL_TICKETS . "`
|
||||
WHERE `status` = '3' AND `answerto` = '0';"
|
||||
);
|
||||
$archiving_count = 0;
|
||||
|
||||
while ($row_ticket = $result_tickets_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
|
||||
$lastchange = $row_ticket['lastchange'];
|
||||
$now = time();
|
||||
$days = (int)(($now - $lastchange) / 86400);
|
||||
|
||||
if ($days >= Settings::Get('ticket.archiving_days')) {
|
||||
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'archiving ticket "' . $row_ticket['subject'] . '" (ID #' . $row_ticket['id'] . ')');
|
||||
$mainticket = ticket::getInstanceOf(null, (int)$row_ticket['id']);
|
||||
$mainticket->Set('lastchange', $now, true, true);
|
||||
$mainticket->Set('lastreplier', '1', true, true);
|
||||
$mainticket->Set('status', '3', true, true);
|
||||
$mainticket->Update();
|
||||
$mainticket->Archive();
|
||||
$archiving_count++;
|
||||
}
|
||||
}
|
||||
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'Archived ' . $archiving_count . ' tickets');
|
||||
Database::query("
|
||||
UPDATE `" . TABLE_PANEL_SETTINGS . "` SET `value` = UNIX_TIMESTAMP()
|
||||
WHERE `settinggroup` = 'system' AND `varname` = 'last_archive_run'"
|
||||
);
|
||||
@@ -1,24 +0,0 @@
|
||||
<?php if (!defined('MASTER_CRONJOB')) die('You cannot access this file directly!');
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
* Copyright (c) 2003-2009 the SysCP Team (see authors).
|
||||
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||
*
|
||||
* For the full copyright and license information, please view the COPYING
|
||||
* file that was distributed with this source code. You can also view the
|
||||
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
|
||||
*
|
||||
* @copyright (c) the authors
|
||||
* @author Florian Lippert <flo@syscp.org> (2003-2009)
|
||||
* @author Froxlor team <team@froxlor.org> (2010-)
|
||||
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
|
||||
* @package Cron
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* RESET USED TICKETS COUNTER
|
||||
*/
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, "Resetting customers used ticket counter");
|
||||
Database::query("UPDATE `" . TABLE_PANEL_CUSTOMERS . "` SET `tickets_used` = '0'");
|
||||
361
lib/Froxlor/Cron/Traffic/ReportsCron.php
Normal file
361
lib/Froxlor/Cron/Traffic/ReportsCron.php
Normal file
@@ -0,0 +1,361 @@
|
||||
<?php
|
||||
namespace Froxlor\Cron\Traffic;
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
* Copyright (c) 2003-2009 the SysCP Team (see authors).
|
||||
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||
*
|
||||
* For the full copyright and license information, please view the COPYING
|
||||
* file that was distributed with this source code. You can also view the
|
||||
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
|
||||
*
|
||||
* @copyright (c) the authors
|
||||
* @author Florian Lippert <flo@syscp.org> (2003-2009)
|
||||
* @author Froxlor team <team@froxlor.org> (2010-)
|
||||
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
|
||||
* @package Cron
|
||||
*
|
||||
*/
|
||||
use Froxlor\Database;
|
||||
use Froxlor\Settings;
|
||||
|
||||
class ReportsCron extends \Froxlor\Cron\FroxlorCron
|
||||
{
|
||||
|
||||
public static function run()
|
||||
{
|
||||
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(CRON_ACTION, LOG_INFO, 'Web- and Traffic-usage reporting started...');
|
||||
$yesterday = time() - (60 * 60 * 24);
|
||||
|
||||
/**
|
||||
* Initialize the mailingsystem
|
||||
*/
|
||||
$mail = new \PHPMailer\PHPMailer\PHPMailer(true);
|
||||
$mail->CharSet = "UTF-8";
|
||||
|
||||
if (Settings::Get('system.mail_use_smtp')) {
|
||||
$mail->isSMTP();
|
||||
$mail->Host = Settings::Get('system.mail_smtp_host');
|
||||
$mail->SMTPAuth = Settings::Get('system.mail_smtp_auth') == '1' ? true : false;
|
||||
$mail->Username = Settings::Get('system.mail_smtp_user');
|
||||
$mail->Password = Settings::Get('system.mail_smtp_passwd');
|
||||
if (Settings::Get('system.mail_smtp_usetls')) {
|
||||
$mail->SMTPSecure = 'tls';
|
||||
} else {
|
||||
$mail->SMTPAutoTLS = false;
|
||||
}
|
||||
$mail->Port = Settings::Get('system.mail_smtp_port');
|
||||
}
|
||||
|
||||
if (\PHPMailer\PHPMailer\PHPMailer::ValidateAddress(Settings::Get('panel.adminmail')) !== false) {
|
||||
// set return-to address and custom sender-name, see #76
|
||||
$mail->SetFrom(Settings::Get('panel.adminmail'), Settings::Get('panel.adminmail_defname'));
|
||||
if (Settings::Get('panel.adminmail_return') != '') {
|
||||
$mail->AddReplyTo(Settings::Get('panel.adminmail_return'), Settings::Get('panel.adminmail_defname'));
|
||||
}
|
||||
}
|
||||
|
||||
if ((int) Settings::Get('system.report_trafficmax') > 0) {
|
||||
// Warn the customers at xx% traffic-usage
|
||||
$result_stmt = Database::prepare("
|
||||
SELECT `c`.`customerid`, `c`.`adminid`, `c`.`name`, `c`.`firstname`,
|
||||
`c`.`company`, `c`.`traffic`, `c`.`email`, `c`.`def_language`,
|
||||
`a`.`name` AS `adminname`, `a`.`email` AS `adminmail`,
|
||||
(SELECT SUM(`t`.`http` + `t`.`ftp_up` + `t`.`ftp_down` + `t`.`mail`)
|
||||
FROM `" . TABLE_PANEL_TRAFFIC . "` `t`
|
||||
WHERE `t`.`customerid` = `c`.`customerid` AND `t`.`year` = :year AND `t`.`month` = :month
|
||||
) as `traffic_used`
|
||||
FROM `" . TABLE_PANEL_CUSTOMERS . "` AS `c`
|
||||
LEFT JOIN `" . TABLE_PANEL_ADMINS . "` AS `a`
|
||||
ON `a`.`adminid` = `c`.`adminid` WHERE `c`.`reportsent` <> '1'
|
||||
");
|
||||
|
||||
$result_data = array(
|
||||
'year' => date("Y", $yesterday),
|
||||
'month' => date("m", $yesterday)
|
||||
);
|
||||
Database::pexecute($result_stmt, $result_data);
|
||||
|
||||
while ($row = $result_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
|
||||
if (isset($row['traffic']) && $row['traffic'] > 0 && $row['traffic_used'] != null && (($row['traffic_used'] * 100) / $row['traffic']) >= (int) Settings::Get('system.report_trafficmax')) {
|
||||
$rep_userinfo = array(
|
||||
'name' => $row['name'],
|
||||
'firstname' => $row['firstname'],
|
||||
'company' => $row['company']
|
||||
);
|
||||
$replace_arr = array(
|
||||
'SALUTATION' => getCorrectUserSalutation($rep_userinfo),
|
||||
'NAME' => $row['name'], // < keep this for compatibility
|
||||
'TRAFFIC' => round(($row['traffic'] / 1024), 2), /* traffic is stored in KB, template uses MB */
|
||||
'TRAFFICUSED' => round(($row['traffic_used'] / 1024), 2), /* traffic is stored in KB, template uses MB */
|
||||
'USAGE_PERCENT' => round(($row['traffic_used'] * 100) / $row['traffic'], 2),
|
||||
'MAX_PERCENT' => Settings::Get('system.report_trafficmax')
|
||||
);
|
||||
|
||||
$lngfile_stmt = Database::prepare("
|
||||
SELECT `file` FROM `" . TABLE_PANEL_LANGUAGE . "`
|
||||
WHERE `language` = :deflang
|
||||
");
|
||||
$lngfile = Database::pexecute_first($lngfile_stmt, array(
|
||||
'deflang' => $row['def_language']
|
||||
));
|
||||
|
||||
if ($lngfile !== null) {
|
||||
$langfile = $lngfile['file'];
|
||||
} else {
|
||||
$lngfile = Database::pexecute_first($lngfile_stmt, array(
|
||||
'deflang' => Settings::Get('panel.standardlanguage')
|
||||
));
|
||||
$langfile = $lngfile['file'];
|
||||
}
|
||||
|
||||
// include english language file (fallback)
|
||||
include_once makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . '/lng/english.lng.php');
|
||||
// include admin/customer language file
|
||||
include_once makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . '/' . $langfile);
|
||||
|
||||
// Get mail templates from database; the ones from 'admin' are fetched for fallback
|
||||
$result2_stmt = Database::prepare("
|
||||
SELECT `value` FROM `" . TABLE_PANEL_TEMPLATES . "`
|
||||
WHERE `adminid` = :adminid
|
||||
AND `language` = :lang
|
||||
AND `templategroup` = 'mails' AND `varname` = :varname
|
||||
");
|
||||
$result2_data = array(
|
||||
'adminid' => $row['adminid'],
|
||||
'lang' => $row['def_language'],
|
||||
'varname' => 'trafficmaxpercent_subject'
|
||||
);
|
||||
$result2 = Database::pexecute_first($result2_stmt, $result2_data);
|
||||
$mail_subject = html_entity_decode(replace_variables((($result2['value'] != '') ? $result2['value'] : $lng['mails']['trafficmaxpercent']['subject']), $replace_arr));
|
||||
|
||||
$result2_data['varname'] = 'trafficmaxpercent_mailbody';
|
||||
$result2 = Database::pexecute_first($result2_stmt, $result2_data);
|
||||
$mail_body = html_entity_decode(replace_variables((($result2['value'] != '') ? $result2['value'] : $lng['mails']['trafficmaxpercent']['mailbody']), $replace_arr));
|
||||
|
||||
$_mailerror = false;
|
||||
$mailerr_msg = "";
|
||||
try {
|
||||
$mail->SetFrom($row['adminmail'], $row['adminname']);
|
||||
$mail->Subject = $mail_subject;
|
||||
$mail->AltBody = $mail_body;
|
||||
$mail->MsgHTML(nl2br($mail_body));
|
||||
$mail->AddAddress($row['email'], $row['firstname'] . ' ' . $row['name']);
|
||||
$mail->Send();
|
||||
} catch (\PHPMailer\PHPMailer\Exception $e) {
|
||||
$mailerr_msg = $e->errorMessage();
|
||||
$_mailerror = true;
|
||||
} catch (\Exception $e) {
|
||||
$mailerr_msg = $e->getMessage();
|
||||
$_mailerror = true;
|
||||
}
|
||||
|
||||
if ($_mailerror) {
|
||||
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(CRON_ACTION, LOG_ERR, 'Error sending mail: ' . $mailerr_msg);
|
||||
echo 'Error sending mail: ' . $mailerr_msg . "\n";
|
||||
}
|
||||
|
||||
$mail->ClearAddresses();
|
||||
$upd_stmt = Database::prepare("
|
||||
UPDATE `" . TABLE_PANEL_CUSTOMERS . "` SET `reportsent` = '1'
|
||||
WHERE `customerid` = :customerid
|
||||
");
|
||||
Database::pexecute($upd_stmt, array(
|
||||
'customerid' => $row['customerid']
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Warn the admins at xx% traffic-usage
|
||||
$result_stmt = Database::prepare("
|
||||
SELECT `a`.*,
|
||||
(SELECT SUM(`t`.`http` + `t`.`ftp_up` + `t`.`ftp_down` + `t`.`mail`)
|
||||
FROM `" . TABLE_PANEL_TRAFFIC_ADMINS . "` `t`
|
||||
WHERE `t`.`adminid` = `a`.`adminid` AND `t`.`year` = :year AND `t`.`month` = :month
|
||||
) as `traffic_used_total`
|
||||
FROM `" . TABLE_PANEL_ADMINS . "` `a` WHERE `a`.`reportsent` = '0'
|
||||
");
|
||||
|
||||
$result_data = array(
|
||||
'year' => date("Y", $yesterday),
|
||||
'month' => date("m", $yesterday)
|
||||
);
|
||||
Database::pexecute($result_stmt, $result_data);
|
||||
|
||||
while ($row = $result_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
|
||||
if (isset($row['traffic']) && $row['traffic'] > 0 && (($row['traffic_used_total'] * 100) / $row['traffic']) >= (int) Settings::Get('system.report_trafficmax')) {
|
||||
|
||||
$replace_arr = array(
|
||||
'NAME' => $row['name'],
|
||||
'TRAFFIC' => round(($row['traffic'] / 1024), 2), /* traffic is stored in KB, template uses MB */
|
||||
'TRAFFICUSED' => round(($row['traffic_used_total'] / 1024), 2), /* traffic is stored in KB, template uses MB */
|
||||
'USAGE_PERCENT' => round(($row['traffic_used_total'] * 100) / $row['traffic'], 2),
|
||||
'MAX_PERCENT' => Settings::Get('system.report_trafficmax')
|
||||
);
|
||||
|
||||
$lngfile_stmt = Database::prepare("
|
||||
SELECT `file` FROM `" . TABLE_PANEL_LANGUAGE . "`
|
||||
WHERE `language` = :deflang
|
||||
");
|
||||
$lngfile = Database::pexecute_first($lngfile_stmt, array(
|
||||
'deflang' => $row['def_language']
|
||||
));
|
||||
|
||||
if ($lngfile !== null) {
|
||||
$langfile = $lngfile['file'];
|
||||
} else {
|
||||
$lngfile = Database::pexecute_first($lngfile_stmt, array(
|
||||
'deflang' => Settings::Get('panel.standardlanguage')
|
||||
));
|
||||
$langfile = $lngfile['file'];
|
||||
}
|
||||
|
||||
// include english language file (fallback)
|
||||
include_once makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . '/lng/english.lng.php');
|
||||
// include admin/customer language file
|
||||
include_once makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . '/' . $langfile);
|
||||
|
||||
// Get mail templates from database; the ones from 'admin' are fetched for fallback
|
||||
$result2_stmt = Database::prepare("
|
||||
SELECT `value` FROM `" . TABLE_PANEL_TEMPLATES . "`
|
||||
WHERE `adminid` = :adminid
|
||||
AND `language` = :lang
|
||||
AND `templategroup` = 'mails' AND `varname` = :varname
|
||||
");
|
||||
$resul2_data = array(
|
||||
'adminid' => $row['adminid'],
|
||||
'lang' => $row['def_language'],
|
||||
'varname' => 'trafficmaxpercent_subject'
|
||||
);
|
||||
$result2 = Database::pexecute_first($result2_stmt, $result2_data);
|
||||
$mail_subject = html_entity_decode(replace_variables((($result2['value'] != '') ? $result2['value'] : $lng['mails']['trafficmaxpercent']['subject']), $replace_arr));
|
||||
|
||||
$resul2_data['varname'] = 'trafficmaxpercent_mailbody';
|
||||
$result2 = Database::pexecute_first($result2_stmt, $result2_data);
|
||||
$mail_body = html_entity_decode(replace_variables((($result2['value'] != '') ? $result2['value'] : $lng['mails']['trafficmaxpercent']['mailbody']), $replace_arr));
|
||||
|
||||
$_mailerror = false;
|
||||
$mailerr_msg = "";
|
||||
try {
|
||||
$mail->SetFrom($row['email'], $row['name']);
|
||||
$mail->Subject = $mail_subject;
|
||||
$mail->AltBody = $mail_body;
|
||||
$mail->MsgHTML(nl2br($mail_body));
|
||||
$mail->AddAddress($row['email'], $row['name']);
|
||||
$mail->Send();
|
||||
} catch (\PHPMailer\PHPMailer\Exception $e) {
|
||||
$mailerr_msg = $e->errorMessage();
|
||||
$_mailerror = true;
|
||||
} catch (\Exception $e) {
|
||||
$mailerr_msg = $e->getMessage();
|
||||
$_mailerror = true;
|
||||
}
|
||||
|
||||
if ($_mailerror) {
|
||||
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(CRON_ACTION, LOG_ERR, "Error sending mail: " . $mailerr_msg);
|
||||
echo "Error sending mail: " . $mailerr_msg . "\n";
|
||||
}
|
||||
|
||||
$mail->ClearAddresses();
|
||||
$upd_stmt = Database::prepare("
|
||||
UPDATE `" . TABLE_PANEL_ADMINS . "` SET `reportsent` = '1'
|
||||
WHERE `adminid` = :adminid
|
||||
");
|
||||
Database::pexecute($upd_stmt, array(
|
||||
'adminid' => $row['adminid']
|
||||
));
|
||||
}
|
||||
|
||||
// Another month, let's build our report
|
||||
if (date('d') == '01') {
|
||||
|
||||
$mail_subject = 'Trafficreport ' . date("m/y", $yesterday) . ' for ' . $row['name'];
|
||||
$mail_body = 'Trafficreport ' . date("m/y", $yesterday) . ' for ' . $row['name'] . "\n";
|
||||
$mail_body .= '---------------------------------------------------------------' . "\n";
|
||||
$mail_body .= 'Loginname Traffic used (Percent) | Traffic available' . "\n";
|
||||
$customers_stmt = Database::prepare("
|
||||
SELECT `c`.*,
|
||||
(SELECT SUM(`t`.`http` + `t`.`ftp_up` + `t`.`ftp_down` + `t`.`mail`)
|
||||
FROM `" . TABLE_PANEL_TRAFFIC . "` `t`
|
||||
WHERE `t`.`customerid` = `c`.`customerid` AND `t`.`year` = :year AND `t`.`month` = :month
|
||||
) as `traffic_used_total`
|
||||
FROM `" . TABLE_PANEL_CUSTOMERS . "` `c` WHERE `c`.`adminid` = :adminid
|
||||
");
|
||||
$customers_data = array(
|
||||
'year' => date("Y", $yesterday),
|
||||
'month' => date("m", $yesterday),
|
||||
'adminid' => $row['adminid']
|
||||
);
|
||||
Database::pexecute($customers_stmt, $customers_data);
|
||||
|
||||
while ($customer = $customers_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
$t = $customer['traffic_used_total'] / 1048576;
|
||||
if ($customer['traffic'] > 0) {
|
||||
$p = (($customer['traffic_used_total'] * 100) / $customer['traffic']);
|
||||
$tg = $customer['traffic'] / 1048576;
|
||||
$str = sprintf('%00.1f GB ( %00.1f %% )', $t, $p);
|
||||
$mail_body .= sprintf('%-15s', $customer['loginname']) . ' ' . sprintf('%-25s', $str) . ' ' . sprintf('%00.1f GB', $tg) . "\n";
|
||||
} else if ($customer['traffic'] == 0) {
|
||||
$str = sprintf('%00.1f GB ( - )', $t);
|
||||
$mail_body .= sprintf('%-15s', $customer['loginname']) . ' ' . sprintf('%-25s', $str) . ' ' . '0' . "\n";
|
||||
} else {
|
||||
$str = sprintf('%00.1f GB ( - )', $t);
|
||||
$mail_body .= sprintf('%-15s', $customer['loginname']) . ' ' . sprintf('%-25s', $str) . ' ' . 'unlimited' . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
$mail_body .= '---------------------------------------------------------------' . "\n";
|
||||
|
||||
$t = $row['traffic_used_total'] / 1048576;
|
||||
if ($row['traffic'] > 0) {
|
||||
$p = (($row['traffic_used_total'] * 100) / $row['traffic']);
|
||||
$tg = $row['traffic'] / 1048576;
|
||||
$str = sprintf('%00.1f GB ( %00.1f %% )', $t, $p);
|
||||
$mail_body .= sprintf('%-15s', $row['loginname']) . ' ' . sprintf('%-25s', $str) . ' ' . sprintf('%00.1f GB', $tg) . "\n";
|
||||
} else if ($row['traffic'] == 0) {
|
||||
$str = sprintf('%00.1f GB ( - )', $t);
|
||||
$mail_body .= sprintf('%-15s', $row['loginname']) . ' ' . sprintf('%-25s', $str) . ' ' . '0' . "\n";
|
||||
} else {
|
||||
$str = sprintf('%00.1f GB ( - )', $t);
|
||||
$mail_body .= sprintf('%-15s', $row['loginname']) . ' ' . sprintf('%-25s', $str) . ' ' . 'unlimited' . "\n";
|
||||
}
|
||||
|
||||
$_mailerror = false;
|
||||
$mailerr_msg = "";
|
||||
try {
|
||||
$mail->SetFrom($row['email'], $row['name']);
|
||||
$mail->Subject = $mail_subject;
|
||||
$mail->Body = $mail_body;
|
||||
$mail->AddAddress($row['email'], $row['name']);
|
||||
$mail->Send();
|
||||
} catch (\PHPMailer\PHPMailer\Exception $e) {
|
||||
$mailerr_msg = $e->errorMessage();
|
||||
$_mailerror = true;
|
||||
} catch (\Exception $e) {
|
||||
$mailerr_msg = $e->getMessage();
|
||||
$_mailerror = true;
|
||||
}
|
||||
|
||||
if ($_mailerror) {
|
||||
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(CRON_ACTION, LOG_ERR, 'Error sending mail: ' . $mailerr_msg);
|
||||
echo 'Error sending mail: ' . $mailerr_msg . "\n";
|
||||
}
|
||||
|
||||
$mail->ClearAddresses();
|
||||
}
|
||||
}
|
||||
} // trafficmax > 0
|
||||
|
||||
// include diskspace-usage report, #466
|
||||
include dirname(__FILE__) . '/cron_usage.inc.diskspace.php';
|
||||
|
||||
// Another month, reset the reportstatus
|
||||
if (date('d') == '01') {
|
||||
Database::query("UPDATE `" . TABLE_PANEL_CUSTOMERS . "` SET `reportsent` = '0';");
|
||||
Database::query("UPDATE `" . TABLE_PANEL_ADMINS . "` SET `reportsent` = '0';");
|
||||
}
|
||||
}
|
||||
}
|
||||
933
lib/Froxlor/Cron/Traffic/TrafficCron.php
Normal file
933
lib/Froxlor/Cron/Traffic/TrafficCron.php
Normal file
@@ -0,0 +1,933 @@
|
||||
<?php
|
||||
namespace Froxlor\Cron\Traffic;
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
* Copyright (c) 2003-2009 the SysCP Team (see authors).
|
||||
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||
*
|
||||
* For the full copyright and license information, please view the COPYING
|
||||
* file that was distributed with this source code. You can also view the
|
||||
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
|
||||
*
|
||||
* @copyright (c) the authors
|
||||
* @author Florian Lippert <flo@syscp.org> (2003-2009)
|
||||
* @author Froxlor team <team@froxlor.org> (2010-)
|
||||
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
|
||||
* @package Cron
|
||||
*
|
||||
*/
|
||||
use Froxlor\Database;
|
||||
use Froxlor\Settings;
|
||||
|
||||
class TrafficCron extends \Froxlor\Cron\FroxlorCron
|
||||
{
|
||||
|
||||
public static function run()
|
||||
{
|
||||
|
||||
// Check Traffic-Lock
|
||||
if (function_exists('pcntl_fork') && ! defined('CRON_NOFORK_FLAG')) {
|
||||
$TrafficLock = makeCorrectFile(dirname($lockfile) . "/froxlor_cron_traffic.lock");
|
||||
if (file_exists($TrafficLock) && is_numeric($TrafficPid = file_get_contents($TrafficLock))) {
|
||||
if (function_exists('posix_kill')) {
|
||||
$TrafficPidStatus = @posix_kill($TrafficPid, 0);
|
||||
} else {
|
||||
system("kill -CHLD " . $TrafficPid . " 1> /dev/null 2> /dev/null", $TrafficPidStatus);
|
||||
$TrafficPidStatus = $TrafficPidStatus ? false : true;
|
||||
}
|
||||
if ($TrafficPidStatus) {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'Traffic Run already in progress');
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
// Create Traffic Log and Fork
|
||||
// We close the database - connection before we fork, so we don't share resources with the child
|
||||
Database::needRoot(false); // this forces the connection to be set to null
|
||||
$TrafficPid = pcntl_fork();
|
||||
// Parent
|
||||
if ($TrafficPid) {
|
||||
file_put_contents($TrafficLock, $TrafficPid);
|
||||
// unnecessary to recreate database connection here
|
||||
return 0;
|
||||
} // Child
|
||||
elseif ($TrafficPid == 0) {
|
||||
posix_setsid();
|
||||
fclose($debugHandler);
|
||||
// re-create db
|
||||
Database::needRoot(false);
|
||||
} // Fork failed
|
||||
else {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (extension_loaded('pcntl')) {
|
||||
$msg = "PHP compiled with pcntl but pcntl_fork function is not available.";
|
||||
} else {
|
||||
$msg = "PHP compiled without pcntl.";
|
||||
}
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, $msg . " Not forking traffic-cron, this may take a long time!");
|
||||
}
|
||||
|
||||
require_once makeCorrectFile(dirname(__FILE__) . '/TrafficCron.inc.functions.php');
|
||||
|
||||
/**
|
||||
* TRAFFIC AND DISKUSAGE MESSURE
|
||||
*/
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'Traffic run started...');
|
||||
$admin_traffic = array();
|
||||
$domainlist = array();
|
||||
$speciallogfile_domainlist = array();
|
||||
$result_domainlist_stmt = Database::query("
|
||||
SELECT `id`, `domain`, `customerid`, `parentdomainid`, `speciallogfile`
|
||||
FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `aliasdomain` IS NULL AND `email_only` <> '1';
|
||||
");
|
||||
|
||||
while ($row_domainlist = $result_domainlist_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
|
||||
if (! isset($domainlist[$row_domainlist['customerid']])) {
|
||||
$domainlist[$row_domainlist['customerid']] = array();
|
||||
}
|
||||
|
||||
$domainlist[$row_domainlist['customerid']][$row_domainlist['id']] = $row_domainlist['domain'];
|
||||
|
||||
if ($row_domainlist['parentdomainid'] == '0' && $row_domainlist['speciallogfile'] == '1') {
|
||||
if (! isset($speciallogfile_domainlist[$row_domainlist['customerid']])) {
|
||||
$speciallogfile_domainlist[$row_domainlist['customerid']] = array();
|
||||
}
|
||||
$speciallogfile_domainlist[$row_domainlist['customerid']][$row_domainlist['id']] = $row_domainlist['domain'];
|
||||
}
|
||||
}
|
||||
|
||||
$mysqlusage_all = array();
|
||||
$databases_stmt = Database::query("SELECT * FROM " . TABLE_PANEL_DATABASES . " ORDER BY `dbserver`");
|
||||
$last_dbserver = 0;
|
||||
|
||||
$databases_list = array();
|
||||
Database::needRoot(true);
|
||||
$databases_list_result_stmt = Database::query("SHOW DATABASES");
|
||||
while ($databases_list_row = $databases_list_result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$databases_list[] = strtolower($databases_list_row['Database']);
|
||||
}
|
||||
|
||||
while ($row_database = $databases_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
|
||||
if ($last_dbserver != $row_database['dbserver']) {
|
||||
Database::needRoot(true, $row_database['dbserver']);
|
||||
$last_dbserver = $row_database['dbserver'];
|
||||
|
||||
$databases_list = array();
|
||||
$databases_list_result_stmt = Database::query("SHOW DATABASES");
|
||||
while ($databases_list_row = $databases_list_result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$databases_list[] = strtolower($databases_list_row['Database']);
|
||||
}
|
||||
}
|
||||
|
||||
if (in_array(strtolower($row_database['databasename']), $databases_list)) {
|
||||
// sum up data_length and index_length
|
||||
$mysql_usage_result_stmt = Database::prepare("
|
||||
SELECT SUM(data_length + index_length) AS customerusage
|
||||
FROM information_schema.TABLES
|
||||
WHERE table_schema = :database
|
||||
GROUP BY table_schema;
|
||||
");
|
||||
// get the result
|
||||
$mysql_usage_row = Database::pexecute_first($mysql_usage_result_stmt, array(
|
||||
'database' => $row_database['databasename']
|
||||
));
|
||||
// initialize counter for customer
|
||||
if (! isset($mysqlusage_all[$row_database['customerid']])) {
|
||||
$mysqlusage_all[$row_database['customerid']] = 0;
|
||||
}
|
||||
// sum up result
|
||||
$mysqlusage_all[$row_database['customerid']] += floatval($mysql_usage_row['customerusage']);
|
||||
} else {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_WARNING, "Seems like the database " . $row_database['databasename'] . " had been removed manually.");
|
||||
}
|
||||
}
|
||||
|
||||
Database::needRoot(false);
|
||||
|
||||
// We are using the file-system quota, this will speed up the diskusage - collection
|
||||
if (Settings::Get('system.diskquota_enabled')) {
|
||||
$usedquota = getFilesystemQuota();
|
||||
}
|
||||
|
||||
/**
|
||||
* MAIL-Traffic
|
||||
*/
|
||||
if (Settings::Get("system.mailtraffic_enabled")) {
|
||||
$mailTrafficCalc = new \Froxlor\MailLogParser(Settings::Get("system.last_traffic_run"));
|
||||
}
|
||||
|
||||
$result_stmt = Database::query("SELECT * FROM `" . TABLE_PANEL_CUSTOMERS . "` ORDER BY `customerid` ASC");
|
||||
|
||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
/**
|
||||
* HTTP-Traffic
|
||||
*/
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'http traffic for ' . $row['loginname'] . ' started...');
|
||||
$httptraffic = 0;
|
||||
|
||||
if (isset($domainlist[$row['customerid']]) && is_array($domainlist[$row['customerid']]) && count($domainlist[$row['customerid']]) != 0) {
|
||||
// Examining which caption to use for default webalizer stats...
|
||||
if ($row['standardsubdomain'] != '0') {
|
||||
// ... of course we'd prefer to use the standardsubdomain ...
|
||||
$caption = $domainlist[$row['customerid']][$row['standardsubdomain']];
|
||||
} else {
|
||||
// ... but if there is no standardsubdomain, we have to use the loginname ...
|
||||
$caption = $row['loginname'];
|
||||
|
||||
// ... which results in non-usable links to files in the stats, so lets have a look if we find a domain which is not speciallogfiledomain
|
||||
foreach ($domainlist[$row['customerid']] as $domainid => $domain) {
|
||||
|
||||
if (! isset($speciallogfile_domainlist[$row['customerid']]) || ! isset($speciallogfile_domainlist[$row['customerid']][$domainid])) {
|
||||
$caption = $domain;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$httptraffic = 0;
|
||||
reset($domainlist[$row['customerid']]);
|
||||
|
||||
if (isset($speciallogfile_domainlist[$row['customerid']]) && is_array($speciallogfile_domainlist[$row['customerid']]) && count($speciallogfile_domainlist[$row['customerid']]) != 0) {
|
||||
reset($speciallogfile_domainlist[$row['customerid']]);
|
||||
if (Settings::Get('system.awstats_enabled') == '0') {
|
||||
foreach ($speciallogfile_domainlist[$row['customerid']] as $domainid => $domain) {
|
||||
$httptraffic += floatval(callWebalizerGetTraffic($row['loginname'] . '-' . $domain, $row['documentroot'] . '/webalizer/' . $domain . '/', $domain, $domainlist[$row['customerid']]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reset($domainlist[$row['customerid']]);
|
||||
|
||||
// callAwstatsGetTraffic is called ONLY HERE and
|
||||
// *not* also in the special-logfiles-loop, because the function
|
||||
// will iterate through all customer-domains and the awstats-configs
|
||||
// know the logfile-name, #246
|
||||
if (Settings::Get('system.awstats_enabled') == '1') {
|
||||
$httptraffic += floatval(callAwstatsGetTraffic($row['customerid'], $row['documentroot'] . '/awstats/', $domainlist[$row['customerid']]));
|
||||
} else {
|
||||
$httptraffic += floatval(callWebalizerGetTraffic($row['loginname'], $row['documentroot'] . '/webalizer/', $caption, $domainlist[$row['customerid']]));
|
||||
}
|
||||
|
||||
// make the stuff readable for the customer, #258
|
||||
makeChownWithNewStats($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* FTP-Traffic
|
||||
*/
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'ftp traffic for ' . $row['loginname'] . ' started...');
|
||||
$ftptraffic_stmt = Database::prepare("
|
||||
SELECT SUM(`up_bytes`) AS `up_bytes_sum`, SUM(`down_bytes`) AS `down_bytes_sum`
|
||||
FROM `" . TABLE_FTP_USERS . "` WHERE `customerid` = :customerid
|
||||
");
|
||||
$ftptraffic = Database::pexecute_first($ftptraffic_stmt, array(
|
||||
'customerid' => $row['customerid']
|
||||
));
|
||||
|
||||
if (! is_array($ftptraffic)) {
|
||||
$ftptraffic = array(
|
||||
'up_bytes_sum' => 0,
|
||||
'down_bytes_sum' => 0
|
||||
);
|
||||
}
|
||||
|
||||
$upd_stmt = Database::prepare("
|
||||
UPDATE `" . TABLE_FTP_USERS . "` SET `up_bytes` = '0', `down_bytes` = '0' WHERE `customerid` = :customerid
|
||||
");
|
||||
Database::pexecute($upd_stmt, array(
|
||||
'customerid' => $row['customerid']
|
||||
));
|
||||
|
||||
/**
|
||||
* Mail-Traffic
|
||||
*/
|
||||
$mailtraffic = 0;
|
||||
if (Settings::Get("system.mailtraffic_enabled")) {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'mail traffic usage for ' . $row['loginname'] . " started...");
|
||||
|
||||
$currentDate = date("Y-m-d");
|
||||
|
||||
$domains_stmt = Database::prepare("SELECT domain FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `customerid` = :cid");
|
||||
Database::pexecute($domains_stmt, array(
|
||||
"cid" => $row['customerid']
|
||||
));
|
||||
while ($domainRow = $domains_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$domainMailTraffic = $mailTrafficCalc->getDomainTraffic($domainRow["domain"]);
|
||||
if (! is_array($domainMailTraffic)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($domainMailTraffic as $dateTraffic => $dayTraffic) {
|
||||
$dayTraffic = floatval($dayTraffic / 1024);
|
||||
|
||||
list ($year, $month, $day) = explode("-", $dateTraffic);
|
||||
if ($dateTraffic == $currentDate) {
|
||||
$mailtraffic = $dayTraffic;
|
||||
} else {
|
||||
// Check if an entry for the given day exists
|
||||
$stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_TRAFFIC . "`
|
||||
WHERE `customerid` = :cid
|
||||
AND `year` = :year
|
||||
AND `month` = :month
|
||||
AND `day` = :day");
|
||||
$params = array(
|
||||
"cid" => $row['customerid'],
|
||||
"year" => $year,
|
||||
"month" => $month,
|
||||
"day" => $day
|
||||
);
|
||||
Database::pexecute($stmt, $params);
|
||||
if ($stmt->rowCount() > 0) {
|
||||
$updRow = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$upd_stmt = Database::prepare("UPDATE `" . TABLE_PANEL_TRAFFIC . "` SET
|
||||
`mail` = :mail
|
||||
WHERE `id` = :id");
|
||||
Database::pexecute($upd_stmt, array(
|
||||
"mail" => $updRow['mail'] + $dayTraffic,
|
||||
"id" => $updRow['id']
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Total Traffic
|
||||
*/
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'total traffic for ' . $row['loginname'] . ' started');
|
||||
$current_traffic = array();
|
||||
$current_traffic['http'] = floatval($httptraffic);
|
||||
$current_traffic['ftp_up'] = floatval(($ftptraffic['up_bytes_sum'] / 1024));
|
||||
$current_traffic['ftp_down'] = floatval(($ftptraffic['down_bytes_sum'] / 1024));
|
||||
$current_traffic['mail'] = floatval($mailtraffic);
|
||||
$current_traffic['all'] = $current_traffic['http'] + $current_traffic['ftp_up'] + $current_traffic['ftp_down'] + $current_traffic['mail'];
|
||||
|
||||
$ins_data = array(
|
||||
'customerid' => $row['customerid'],
|
||||
'year' => date('Y', time()),
|
||||
'month' => date('m', time()),
|
||||
'day' => date('d', time()),
|
||||
'stamp' => time(),
|
||||
'http' => $current_traffic['http'],
|
||||
'ftp_up' => $current_traffic['ftp_up'],
|
||||
'ftp_down' => $current_traffic['ftp_down'],
|
||||
'mail' => $current_traffic['mail']
|
||||
);
|
||||
$ins_stmt = Database::prepare("
|
||||
INSERT INTO `" . TABLE_PANEL_TRAFFIC . "` SET
|
||||
`customerid` = :customerid,
|
||||
`year` = :year,
|
||||
`month` = :month,
|
||||
`day` = :day,
|
||||
`stamp` = :stamp,
|
||||
`http` = :http,
|
||||
`ftp_up` = :ftp_up,
|
||||
`ftp_down` = :ftp_down,
|
||||
`mail` = :mail
|
||||
");
|
||||
Database::pexecute($ins_stmt, $ins_data);
|
||||
|
||||
$sum_month_traffic_stmt = Database::prepare("
|
||||
SELECT SUM(`http`) AS `http`, SUM(`ftp_up`) AS `ftp_up`, SUM(`ftp_down`) AS `ftp_down`, SUM(`mail`) AS `mail`
|
||||
FROM `" . TABLE_PANEL_TRAFFIC . "` WHERE `year` = :year AND `month` = :month AND `customerid` = :customerid
|
||||
");
|
||||
$sum_month_traffic = Database::pexecute_first($sum_month_traffic_stmt, array(
|
||||
'year' => date('Y', time()),
|
||||
'month' => date('m', time()),
|
||||
'customerid' => $row['customerid']
|
||||
));
|
||||
$sum_month_traffic['all'] = $sum_month_traffic['http'] + $sum_month_traffic['ftp_up'] + $sum_month_traffic['ftp_down'] + $sum_month_traffic['mail'];
|
||||
|
||||
if (! isset($admin_traffic[$row['adminid']]) || ! is_array($admin_traffic[$row['adminid']])) {
|
||||
$admin_traffic[$row['adminid']]['http'] = 0;
|
||||
$admin_traffic[$row['adminid']]['ftp_up'] = 0;
|
||||
$admin_traffic[$row['adminid']]['ftp_down'] = 0;
|
||||
$admin_traffic[$row['adminid']]['mail'] = 0;
|
||||
$admin_traffic[$row['adminid']]['all'] = 0;
|
||||
$admin_traffic[$row['adminid']]['sum_month'] = 0;
|
||||
}
|
||||
|
||||
$admin_traffic[$row['adminid']]['http'] += $current_traffic['http'];
|
||||
$admin_traffic[$row['adminid']]['ftp_up'] += $current_traffic['ftp_up'];
|
||||
$admin_traffic[$row['adminid']]['ftp_down'] += $current_traffic['ftp_down'];
|
||||
$admin_traffic[$row['adminid']]['mail'] += $current_traffic['mail'];
|
||||
$admin_traffic[$row['adminid']]['all'] += $current_traffic['all'];
|
||||
$admin_traffic[$row['adminid']]['sum_month'] += $sum_month_traffic['all'];
|
||||
|
||||
/**
|
||||
* WebSpace-Usage
|
||||
*/
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'calculating webspace usage for ' . $row['loginname']);
|
||||
$webspaceusage = 0;
|
||||
|
||||
// Using repquota, it's faster using this tool than using du traversing the complete directory
|
||||
if (Settings::Get('system.diskquota_enabled') && isset($usedquota[$row['guid']]['block']['used']) && $usedquota[$row['guid']]['block']['used'] >= 1) {
|
||||
// We may use the array we created earlier, the used diskspace is stored in [<guid>][block][used]
|
||||
$webspaceusage = floatval($usedquota[$row['guid']]['block']['used']);
|
||||
} else {
|
||||
|
||||
// Use the old fashioned way with "du"
|
||||
if (file_exists($row['documentroot']) && is_dir($row['documentroot'])) {
|
||||
$back = safe_exec('du -sk ' . escapeshellarg($row['documentroot']) . '');
|
||||
foreach ($back as $backrow) {
|
||||
$webspaceusage = explode(' ', $backrow);
|
||||
}
|
||||
|
||||
$webspaceusage = floatval($webspaceusage['0']);
|
||||
unset($back);
|
||||
} else {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_WARNING, 'documentroot ' . $row['documentroot'] . ' does not exist');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MailSpace-Usage
|
||||
*/
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'calculating mailspace usage for ' . $row['loginname']);
|
||||
$emailusage = 0;
|
||||
|
||||
$maildir = makeCorrectDir(Settings::Get('system.vmail_homedir') . $row['loginname']);
|
||||
if (file_exists($maildir) && is_dir($maildir)) {
|
||||
$back = safe_exec('du -sk ' . escapeshellarg($maildir) . '');
|
||||
foreach ($back as $backrow) {
|
||||
$emailusage = explode(' ', $backrow);
|
||||
}
|
||||
|
||||
$emailusage = floatval($emailusage['0']);
|
||||
unset($back);
|
||||
} else {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_WARNING, 'maildir ' . $maildir . ' does not exist');
|
||||
}
|
||||
|
||||
/**
|
||||
* MySQLSpace-Usage
|
||||
*/
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'calculating mysqlspace usage for ' . $row['loginname']);
|
||||
$mysqlusage = 0;
|
||||
|
||||
if (isset($mysqlusage_all[$row['customerid']])) {
|
||||
$mysqlusage = floatval($mysqlusage_all[$row['customerid']] / 1024);
|
||||
}
|
||||
|
||||
$current_diskspace = array();
|
||||
$current_diskspace['webspace'] = floatval($webspaceusage);
|
||||
$current_diskspace['mail'] = floatval($emailusage);
|
||||
$current_diskspace['mysql'] = floatval($mysqlusage);
|
||||
$current_diskspace['all'] = $current_diskspace['webspace'] + $current_diskspace['mail'] + $current_diskspace['mysql'];
|
||||
|
||||
$ins_data = array(
|
||||
'customerid' => $row['customerid'],
|
||||
'year' => date('Y', time()),
|
||||
'month' => date('m', time()),
|
||||
'day' => date('d', time()),
|
||||
'stamp' => time(),
|
||||
'webspace' => $current_diskspace['webspace'],
|
||||
'mail' => $current_diskspace['mail'],
|
||||
'mysql' => $current_diskspace['mysql']
|
||||
);
|
||||
$ins_stmt = Database::prepare("
|
||||
INSERT INTO `" . TABLE_PANEL_DISKSPACE . "` SET
|
||||
`customerid` = :customerid,
|
||||
`year` = :year,
|
||||
`month` = :month,
|
||||
`day` = :day,
|
||||
`stamp` = :stamp,
|
||||
`webspace` = :webspace,
|
||||
`mail` = :mail,
|
||||
`mysql` = :mysql
|
||||
");
|
||||
Database::pexecute($ins_stmt, $ins_data);
|
||||
|
||||
if (! isset($admin_diskspace[$row['adminid']]) || ! is_array($admin_diskspace[$row['adminid']])) {
|
||||
$admin_diskspace[$row['adminid']] = array();
|
||||
$admin_diskspace[$row['adminid']]['webspace'] = 0;
|
||||
$admin_diskspace[$row['adminid']]['mail'] = 0;
|
||||
$admin_diskspace[$row['adminid']]['mysql'] = 0;
|
||||
$admin_diskspace[$row['adminid']]['all'] = 0;
|
||||
}
|
||||
|
||||
$admin_diskspace[$row['adminid']]['webspace'] += $current_diskspace['webspace'];
|
||||
$admin_diskspace[$row['adminid']]['mail'] += $current_diskspace['mail'];
|
||||
$admin_diskspace[$row['adminid']]['mysql'] += $current_diskspace['mysql'];
|
||||
$admin_diskspace[$row['adminid']]['all'] += $current_diskspace['all'];
|
||||
|
||||
/**
|
||||
* Total Usage
|
||||
*/
|
||||
$diskusage = floatval($webspaceusage + $emailusage + $mysqlusage);
|
||||
|
||||
$upd_data = array(
|
||||
'diskspace' => $current_diskspace['all'],
|
||||
'traffic' => $sum_month_traffic['all'],
|
||||
'customerid' => $row['customerid']
|
||||
);
|
||||
$upd_stmt = Database::prepare("
|
||||
UPDATE `" . TABLE_PANEL_CUSTOMERS . "` SET
|
||||
`diskspace_used` = :diskspace,
|
||||
`traffic_used` = :traffic
|
||||
WHERE `customerid` = :customerid
|
||||
");
|
||||
Database::pexecute($upd_stmt, $upd_data);
|
||||
|
||||
/**
|
||||
* Proftpd Quota
|
||||
*/
|
||||
$upd_data = array(
|
||||
'biu' => ($current_diskspace['all'] * 1024),
|
||||
'loginname' => $row['loginname'],
|
||||
'loginnamelike' => $row['loginname'] . Settings::Get('customer.ftpprefix') . "%"
|
||||
);
|
||||
$upd_stmt = Database::prepare("
|
||||
UPDATE `" . TABLE_FTP_QUOTATALLIES . "` SET
|
||||
`bytes_in_used` = :biu WHERE `name` = :loginname OR `name` LIKE :loginnamelike
|
||||
");
|
||||
Database::pexecute($upd_stmt, $upd_data);
|
||||
|
||||
/**
|
||||
* Pureftpd Quota
|
||||
*/
|
||||
if (Settings::Get('system.ftpserver') == "pureftpd") {
|
||||
|
||||
$result_quota_stmt = Database::prepare("
|
||||
SELECT homedir FROM `" . TABLE_FTP_USERS . "` WHERE customerid = :customerid
|
||||
");
|
||||
Database::pexecute($result_quota_stmt, array(
|
||||
'customerid' => $row['customerid']
|
||||
));
|
||||
|
||||
// get correct user
|
||||
if ((Settings::Get('system.mod_fcgid') == 1 || Settings::Get('phpfpm.enabled') == 1) && $row['deactivated'] == '0') {
|
||||
$user = $row['loginname'];
|
||||
$group = $row['loginname'];
|
||||
} else {
|
||||
$user = $row['guid'];
|
||||
$group = $row['guid'];
|
||||
}
|
||||
|
||||
while ($row_quota = $result_quota_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$quotafile = "" . $row_quota['homedir'] . ".ftpquota";
|
||||
$fh = fopen($quotafile, 'w');
|
||||
$stringdata = "0 " . $current_diskspace['all'] * 1024 . "";
|
||||
fwrite($fh, $stringdata);
|
||||
fclose($fh);
|
||||
safe_exec('chown ' . $user . ':' . $group . ' ' . escapeshellarg($quotafile) . '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin Usage
|
||||
*/
|
||||
$result_stmt = Database::query("SELECT `adminid` FROM `" . TABLE_PANEL_ADMINS . "` ORDER BY `adminid` ASC");
|
||||
|
||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
|
||||
if (isset($admin_traffic[$row['adminid']])) {
|
||||
|
||||
$ins_data = array(
|
||||
'adminid' => $row['adminid'],
|
||||
'year' => date('Y', time()),
|
||||
'month' => date('m', time()),
|
||||
'day' => date('d', time()),
|
||||
'stamp' => time(),
|
||||
'http' => $admin_traffic[$row['adminid']]['http'],
|
||||
'ftp_up' => $admin_traffic[$row['adminid']]['ftp_up'],
|
||||
'ftp_down' => $admin_traffic[$row['adminid']]['ftp_down'],
|
||||
'mail' => $admin_traffic[$row['adminid']]['mail']
|
||||
);
|
||||
$ins_stmt = Database::prepare("
|
||||
INSERT INTO `" . TABLE_PANEL_TRAFFIC_ADMINS . "` SET
|
||||
`adminid` = :adminid,
|
||||
`year` = :year,
|
||||
`month` = :month,
|
||||
`day` = :day,
|
||||
`stamp` = :stamp,
|
||||
`http` = :http,
|
||||
`ftp_up` = :ftp_up,
|
||||
`ftp_down` = :ftp_down,
|
||||
`mail` = :mail
|
||||
");
|
||||
Database::pexecute($ins_stmt, $ins_data);
|
||||
|
||||
$upd_data = array(
|
||||
'traffic' => $admin_traffic[$row['adminid']]['sum_month'],
|
||||
'adminid' => $row['adminid']
|
||||
);
|
||||
$upd_stmt = Database::prepare("
|
||||
UPDATE `" . TABLE_PANEL_ADMINS . "` SET
|
||||
`traffic_used` = :traffic
|
||||
WHERE `adminid` = :adminid
|
||||
");
|
||||
Database::pexecute($upd_stmt, $upd_data);
|
||||
}
|
||||
|
||||
if (isset($admin_diskspace[$row['adminid']])) {
|
||||
|
||||
$ins_data = array(
|
||||
'adminid' => $row['adminid'],
|
||||
'year' => date('Y', time()),
|
||||
'month' => date('m', time()),
|
||||
'day' => date('d', time()),
|
||||
'stamp' => time(),
|
||||
'webspace' => $admin_diskspace[$row['adminid']]['webspace'],
|
||||
'mail' => $admin_diskspace[$row['adminid']]['mail'],
|
||||
'mysql' => $admin_diskspace[$row['adminid']]['mysql']
|
||||
);
|
||||
$ins_stmt = Database::prepare("
|
||||
INSERT INTO `" . TABLE_PANEL_DISKSPACE_ADMINS . "` SET
|
||||
`adminid` = :adminid,
|
||||
`year` = :year,
|
||||
`month` = :month,
|
||||
`day` = :day,
|
||||
`stamp` = :stamp,
|
||||
`webspace` = :webspace,
|
||||
`mail` = :mail,
|
||||
`mysql` = :mysql
|
||||
");
|
||||
|
||||
$upd_data = array(
|
||||
'diskspace' => $admin_diskspace[$row['adminid']]['all'],
|
||||
'adminid' => $row['adminid']
|
||||
);
|
||||
$upd_stmt = Database::prepare("
|
||||
UPDATE `" . TABLE_PANEL_ADMINS . "` SET
|
||||
`diskspace_used` = :diskspace
|
||||
WHERE `adminid` = :adminid
|
||||
");
|
||||
Database::pexecute($upd_stmt, $upd_data);
|
||||
}
|
||||
}
|
||||
|
||||
Database::query("UPDATE `" . TABLE_PANEL_SETTINGS . "` SET `value` = UNIX_TIMESTAMP() WHERE `settinggroup` = 'system' AND `varname` = 'last_traffic_run'");
|
||||
|
||||
if (function_exists('pcntl_fork') && ! defined('CRON_NOFORK_FLAG')) {
|
||||
@unlink($TrafficLock);
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
||||
public static function awstatsDoSingleDomain($domain, $outputdir)
|
||||
{
|
||||
$returnval = 0;
|
||||
|
||||
$domainconfig = makeCorrectFile(Settings::Get('system.awstats_conf') . '/awstats.' . $domain . '.conf');
|
||||
|
||||
if (file_exists($domainconfig)) {
|
||||
|
||||
$outputdir = makeCorrectDir($outputdir . '/' . $domain);
|
||||
$staticOutputdir = makeCorrectDir($outputdir . '/' . date('Y') . '-' . date('m'));
|
||||
|
||||
if (! is_dir($staticOutputdir)) {
|
||||
safe_exec('mkdir -p ' . escapeshellarg($staticOutputdir));
|
||||
}
|
||||
|
||||
// check for correct path of awstats_buildstaticpages.pl
|
||||
$awbsp = makeCorrectFile(Settings::Get('system.awstats_path') . '/awstats_buildstaticpages.pl');
|
||||
$awprog = makeCorrectFile(Settings::Get('system.awstats_awstatspath') . '/awstats.pl');
|
||||
|
||||
if (! file_exists($awbsp)) {
|
||||
echo "WANRING: Necessary awstats_buildstaticpages.pl script could not be found, no traffic is being calculated and no stats are generated. Please check your AWStats-Path setting";
|
||||
$cronlog->logAction(CRON_ACTION, LOG_WARNING, "Necessary awstats_buildstaticpages.pl script could not be found, no traffic is being calculated and no stats are generated. Please check your AWStats-Path setting");
|
||||
exit();
|
||||
}
|
||||
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, "Running awstats_buildstaticpages.pl for domain '" . $domain . "' (Output: '" . $staticOutputdir . "')");
|
||||
safe_exec($awbsp . ' -awstatsprog=' . escapeshellarg($awprog) . ' -update -month=' . date('m') . ' -year=' . date('Y') . ' -config=' . $domain . ' -dir=' . escapeshellarg($staticOutputdir));
|
||||
|
||||
// update our awstats index files
|
||||
awstatsGenerateIndex($domain, $outputdir);
|
||||
|
||||
// the default selection is 'current',
|
||||
// so link the latest dir to it
|
||||
$new_current = makeCorrectFile($outputdir . '/current');
|
||||
safe_exec('ln -fTs ' . escapeshellarg($staticOutputdir) . ' ' . escapeshellarg($new_current));
|
||||
|
||||
// statistics file looks like: 'awstats[month][year].[domain].txt'
|
||||
$file = makeCorrectFile($outputdir . '/awstats' . date('mY', time()) . '.' . $domain . '.txt');
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, "Gathering traffic information from '" . $file . "'");
|
||||
|
||||
if (file_exists($file)) {
|
||||
|
||||
$content = @file_get_contents($file);
|
||||
if ($content !== false) {
|
||||
$content_array = explode("\n", $content);
|
||||
|
||||
$count_bdw = false;
|
||||
foreach ($content_array as $line) {
|
||||
// skip empty lines and comments
|
||||
if (trim($line) == '' || substr(trim($line), 0, 1) == '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$parts = explode(' ', $line);
|
||||
|
||||
if (isset($parts[0]) && strtoupper($parts[0]) == 'BEGIN_DOMAIN') {
|
||||
$count_bdw = true;
|
||||
}
|
||||
|
||||
if ($count_bdw) {
|
||||
if (isset($parts[0]) && strtoupper($parts[0]) == 'END_DOMAIN') {
|
||||
$count_bdw = false;
|
||||
break;
|
||||
} elseif (isset($parts[3])) {
|
||||
$returnval += floatval($parts[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $returnval;
|
||||
}
|
||||
|
||||
public static function awstatsGenerateIndex($domain, $outputdir)
|
||||
{
|
||||
|
||||
// Generation header
|
||||
$header = "<!-- GENERATED BY FROXLOR -->\n";
|
||||
|
||||
// Looking for {year}-{month} directories
|
||||
$entries = array();
|
||||
foreach (scandir($outputdir) as $a) {
|
||||
if (is_dir(makeCorrectDir($outputdir . '/' . $a)) && preg_match('/^[0-9]{4}-[0-9]{2}$/', $a)) {
|
||||
array_push($entries, '<option value="' . $a . '">' . $a . '</option>');
|
||||
}
|
||||
}
|
||||
|
||||
// These are the variables we will replace
|
||||
$regex = array(
|
||||
'/\{SITE_DOMAIN\}/',
|
||||
'/\{SELECT_ENTRIES\}/'
|
||||
);
|
||||
|
||||
$replace = array(
|
||||
$domain,
|
||||
implode($entries)
|
||||
);
|
||||
|
||||
// File names
|
||||
$index_file = \Froxlor\Froxlor::getInstallDir() . '/templates/misc/awstats/index.html';
|
||||
$index_file = makeCorrectFile($index_file);
|
||||
$nav_file = \Froxlor\Froxlor::getInstallDir() . '/templates/misc/awstats/nav.html';
|
||||
$nav_file = makeCorrectFile($nav_file);
|
||||
|
||||
// Write the index file
|
||||
{
|
||||
// 'index.html' used to be a symlink (ignore errors in case this is the first run and no index.html exists yet)
|
||||
@unlink(makeCorrectFile($outputdir . '/' . 'index.html'));
|
||||
|
||||
$awstats_index_file = fopen(makeCorrectFile($outputdir . '/' . 'index.html'), 'w');
|
||||
$awstats_index_tpl = fopen($index_file, 'r');
|
||||
|
||||
// Write the header
|
||||
fwrite($awstats_index_file, $header);
|
||||
|
||||
// Write the configuration file
|
||||
while (($line = fgets($awstats_index_tpl, 4096)) !== false) {
|
||||
if (! preg_match('/^#/', $line) && trim($line) != '') {
|
||||
fwrite($awstats_index_file, preg_replace($regex, $replace, $line));
|
||||
}
|
||||
}
|
||||
fclose($awstats_index_file);
|
||||
fclose($awstats_index_tpl);
|
||||
}
|
||||
|
||||
// Write the nav file
|
||||
{
|
||||
$awstats_nav_file = fopen(makeCorrectFile($outputdir . '/' . 'nav.html'), 'w');
|
||||
$awstats_nav_tpl = fopen($nav_file, 'r');
|
||||
|
||||
// Write the header
|
||||
fwrite($awstats_nav_file, $header);
|
||||
|
||||
// Write the configuration file
|
||||
while (($line = fgets($awstats_nav_tpl, 4096)) !== false) {
|
||||
if (! preg_match('/^#/', $line) && trim($line) != '') {
|
||||
fwrite($awstats_nav_file, preg_replace($regex, $replace, $line));
|
||||
}
|
||||
}
|
||||
fclose($awstats_nav_file);
|
||||
fclose($awstats_nav_tpl);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public static function callAwstatsGetTraffic($customerid, $outputdir, $usersdomainlist)
|
||||
{
|
||||
global $cronlog;
|
||||
|
||||
$returnval = 0;
|
||||
|
||||
foreach ($usersdomainlist as $domainid => $singledomain) {
|
||||
// as we check for the config-model awstats will only parse
|
||||
// 'real' domains and no subdomains which are aliases in the
|
||||
// model-config-file.
|
||||
$returnval += awstatsDoSingleDomain($singledomain, $outputdir);
|
||||
}
|
||||
|
||||
/**
|
||||
* as of #124, awstats traffic is saved in bytes instead
|
||||
* of kilobytes (like webalizer does)
|
||||
*/
|
||||
$returnval = floatval($returnval / 1024);
|
||||
|
||||
/**
|
||||
* now, because this traffic is being saved daily, we have to
|
||||
* subtract the values from all the month's values to return
|
||||
* a sane value for our panel_traffic and to remain the whole stats
|
||||
* (awstats overwrites the customers .html stats-files)
|
||||
*/
|
||||
if ($customerid !== false) {
|
||||
|
||||
$result_stmt = Database::prepare("
|
||||
SELECT SUM(`http`) as `trafficmonth` FROM `" . TABLE_PANEL_TRAFFIC . "`
|
||||
WHERE `customerid` = :customerid
|
||||
AND `year` = :year AND `month` = :month
|
||||
");
|
||||
$result_data = array(
|
||||
'customerid' => $customerid,
|
||||
'year' => date('Y', time()),
|
||||
'month' => date('m', time())
|
||||
);
|
||||
$result = Database::pexecute_first($result_stmt, $result_data);
|
||||
|
||||
if (is_array($result) && isset($result['trafficmonth'])) {
|
||||
$returnval = ($returnval - floatval($result['trafficmonth']));
|
||||
}
|
||||
}
|
||||
|
||||
return floatval($returnval);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function which make webalizer statistics and returns used traffic since last run
|
||||
*
|
||||
* @param
|
||||
* string Name of logfile
|
||||
* @param
|
||||
* string Place where stats should be build
|
||||
* @param
|
||||
* string Caption for webalizer output
|
||||
* @return int Used traffic
|
||||
* @author Florian Lippert <flo@syscp.org>
|
||||
*/
|
||||
public static function callWebalizerGetTraffic($logfile, $outputdir, $caption, $usersdomainlist)
|
||||
{
|
||||
global $cronlog;
|
||||
|
||||
$returnval = 0;
|
||||
|
||||
$logfile = makeCorrectFile(Settings::Get('system.logfiles_directory') . $logfile . '-access.log');
|
||||
if (file_exists($logfile)) {
|
||||
$domainargs = '';
|
||||
foreach ($usersdomainlist as $domainid => $domain) {
|
||||
// hide referer
|
||||
$domainargs .= ' -r ' . escapeshellarg($domain);
|
||||
}
|
||||
|
||||
$outputdir = makeCorrectDir($outputdir);
|
||||
if (! file_exists($outputdir)) {
|
||||
safe_exec('mkdir -p ' . escapeshellarg($outputdir));
|
||||
}
|
||||
|
||||
if (file_exists($outputdir . 'webalizer.hist.1')) {
|
||||
@unlink($outputdir . 'webalizer.hist.1');
|
||||
}
|
||||
|
||||
if (file_exists($outputdir . 'webalizer.hist') && ! file_exists($outputdir . 'webalizer.hist.1')) {
|
||||
safe_exec('cp ' . escapeshellarg($outputdir . 'webalizer.hist') . ' ' . escapeshellarg($outputdir . 'webalizer.hist.1'));
|
||||
}
|
||||
|
||||
$verbosity = '';
|
||||
if (Settings::Get('system.webalizer_quiet') == '1') {
|
||||
$verbosity = '-q';
|
||||
} elseif (Settings::Get('system.webalizer_quiet') == '2') {
|
||||
$verbosity = '-Q';
|
||||
}
|
||||
|
||||
$we = '/usr/bin/webalizer';
|
||||
|
||||
// FreeBSD uses other paths, #140
|
||||
if (! file_exists($we)) {
|
||||
$we = '/usr/local/bin/webalizer';
|
||||
}
|
||||
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, "Running webalizer for domain '" . $caption . "'");
|
||||
safe_exec($we . ' ' . $verbosity . ' -p -o ' . escapeshellarg($outputdir) . ' -n ' . escapeshellarg($caption) . $domainargs . ' ' . escapeshellarg($logfile));
|
||||
|
||||
/**
|
||||
* Format of webalizer.hist-files:
|
||||
* Month: $webalizer_hist_row['0']
|
||||
* Year: $webalizer_hist_row['1']
|
||||
* KB: $webalizer_hist_row['5']
|
||||
*/
|
||||
$httptraffic = array();
|
||||
$webalizer_hist = @file_get_contents($outputdir . 'webalizer.hist');
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, "Gathering traffic information from '" . $webalizer_hist . "'");
|
||||
|
||||
$webalizer_hist_rows = explode("\n", $webalizer_hist);
|
||||
foreach ($webalizer_hist_rows as $webalizer_hist_row) {
|
||||
if ($webalizer_hist_row != '') {
|
||||
|
||||
$webalizer_hist_row = explode(' ', $webalizer_hist_row);
|
||||
|
||||
if (isset($webalizer_hist_row['0']) && isset($webalizer_hist_row['1']) && isset($webalizer_hist_row['5'])) {
|
||||
$month = intval($webalizer_hist_row['0']);
|
||||
$year = intval($webalizer_hist_row['1']);
|
||||
$traffic = floatval($webalizer_hist_row['5']);
|
||||
|
||||
if (! isset($httptraffic[$year])) {
|
||||
$httptraffic[$year] = array();
|
||||
}
|
||||
|
||||
$httptraffic[$year][$month] = $traffic;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reset($httptraffic);
|
||||
$httptrafficlast = array();
|
||||
$webalizer_lasthist = @file_get_contents($outputdir . 'webalizer.hist.1');
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, "Gathering traffic information from '" . $webalizer_lasthist . "'");
|
||||
|
||||
$webalizer_lasthist_rows = explode("\n", $webalizer_lasthist);
|
||||
foreach ($webalizer_lasthist_rows as $webalizer_lasthist_row) {
|
||||
if ($webalizer_lasthist_row != '') {
|
||||
|
||||
$webalizer_lasthist_row = explode(' ', $webalizer_lasthist_row);
|
||||
|
||||
if (isset($webalizer_lasthist_row['0']) && isset($webalizer_lasthist_row['1']) && isset($webalizer_lasthist_row['5'])) {
|
||||
$month = intval($webalizer_lasthist_row['0']);
|
||||
$year = intval($webalizer_lasthist_row['1']);
|
||||
$traffic = floatval($webalizer_lasthist_row['5']);
|
||||
|
||||
if (! isset($httptrafficlast[$year])) {
|
||||
$httptrafficlast[$year] = array();
|
||||
}
|
||||
|
||||
$httptrafficlast[$year][$month] = $traffic;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reset($httptrafficlast);
|
||||
foreach ($httptraffic as $year => $months) {
|
||||
foreach ($months as $month => $traffic) {
|
||||
if (! isset($httptrafficlast[$year][$month])) {
|
||||
$returnval += $traffic;
|
||||
} elseif ($httptrafficlast[$year][$month] < $httptraffic[$year][$month]) {
|
||||
$returnval += ($httptraffic[$year][$month] - $httptrafficlast[$year][$month]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return floatval($returnval);
|
||||
}
|
||||
}
|
||||
@@ -17,342 +17,4 @@
|
||||
*
|
||||
*/
|
||||
|
||||
function awstatsDoSingleDomain($domain, $outputdir) {
|
||||
|
||||
global $cronlog, $theme;
|
||||
$returnval = 0;
|
||||
|
||||
$domainconfig = makeCorrectFile(Settings::Get('system.awstats_conf').'/awstats.' . $domain . '.conf');
|
||||
|
||||
if (file_exists($domainconfig)) {
|
||||
|
||||
$outputdir = makeCorrectDir($outputdir . '/' . $domain);
|
||||
$staticOutputdir = makeCorrectDir($outputdir . '/' . date('Y') . '-' . date('m'));
|
||||
|
||||
if (!is_dir($staticOutputdir)) {
|
||||
safe_exec('mkdir -p ' . escapeshellarg($staticOutputdir));
|
||||
}
|
||||
|
||||
//check for correct path of awstats_buildstaticpages.pl
|
||||
$awbsp = makeCorrectFile(Settings::Get('system.awstats_path').'/awstats_buildstaticpages.pl');
|
||||
$awprog = makeCorrectFile(Settings::Get('system.awstats_awstatspath').'/awstats.pl');
|
||||
|
||||
if (!file_exists($awbsp)) {
|
||||
echo "WANRING: Necessary awstats_buildstaticpages.pl script could not be found, no traffic is being calculated and no stats are generated. Please check your AWStats-Path setting";
|
||||
$cronlog->logAction(CRON_ACTION, LOG_WARNING, "Necessary awstats_buildstaticpages.pl script could not be found, no traffic is being calculated and no stats are generated. Please check your AWStats-Path setting");
|
||||
exit;
|
||||
}
|
||||
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, "Running awstats_buildstaticpages.pl for domain '".$domain."' (Output: '".$staticOutputdir."')");
|
||||
safe_exec($awbsp.' -awstatsprog='.escapeshellarg($awprog).' -update -month=' . date('m') . ' -year=' . date('Y') . ' -config=' . $domain . ' -dir='.escapeshellarg($staticOutputdir));
|
||||
|
||||
// update our awstats index files
|
||||
awstatsGenerateIndex($domain, $outputdir);
|
||||
|
||||
// the default selection is 'current',
|
||||
// so link the latest dir to it
|
||||
$new_current = makeCorrectFile($outputdir . '/current');
|
||||
safe_exec('ln -fTs ' . escapeshellarg($staticOutputdir) . ' ' . escapeshellarg($new_current));
|
||||
|
||||
//statistics file looks like: 'awstats[month][year].[domain].txt'
|
||||
$file = makeCorrectFile($outputdir.'/awstats'.date('mY', time()).'.'.$domain.'.txt');
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, "Gathering traffic information from '".$file."'");
|
||||
|
||||
if (file_exists($file)) {
|
||||
|
||||
$content = @file_get_contents($file);
|
||||
if ($content !== false) {
|
||||
$content_array = explode("\n", $content);
|
||||
|
||||
$count_bdw = false;
|
||||
foreach ($content_array as $line) {
|
||||
// skip empty lines and comments
|
||||
if (trim($line) == ''
|
||||
|| substr(trim($line), 0, 1) == '#'
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$parts = explode(' ', $line);
|
||||
|
||||
if (isset($parts[0])
|
||||
&& strtoupper($parts[0]) == 'BEGIN_DOMAIN'
|
||||
) {
|
||||
$count_bdw = true;
|
||||
}
|
||||
|
||||
if ($count_bdw) {
|
||||
if (isset($parts[0])
|
||||
&& strtoupper($parts[0]) == 'END_DOMAIN'
|
||||
) {
|
||||
$count_bdw = false;
|
||||
break;
|
||||
} elseif (isset($parts[3])) {
|
||||
$returnval += floatval($parts[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $returnval;
|
||||
}
|
||||
|
||||
|
||||
function awstatsGenerateIndex($domain, $outputdir) {
|
||||
|
||||
// Generation header
|
||||
$header = "<!-- GENERATED BY FROXLOR -->\n";
|
||||
|
||||
// Looking for {year}-{month} directories
|
||||
$entries = array();
|
||||
foreach (scandir($outputdir) as $a) {
|
||||
if (is_dir(makeCorrectDir($outputdir . '/' . $a)) && preg_match('/^[0-9]{4}-[0-9]{2}$/', $a)) {
|
||||
array_push($entries, '<option value="' . $a . '">' . $a . '</option>');
|
||||
}
|
||||
}
|
||||
|
||||
// These are the variables we will replace
|
||||
$regex = array(
|
||||
'/\{SITE_DOMAIN\}/',
|
||||
'/\{SELECT_ENTRIES\}/'
|
||||
);
|
||||
|
||||
$replace = array(
|
||||
$domain,
|
||||
implode($entries)
|
||||
);
|
||||
|
||||
// File names
|
||||
$index_file = \Froxlor\Froxlor::getInstallDir().'/templates/misc/awstats/index.html';
|
||||
$index_file = makeCorrectFile($index_file);
|
||||
$nav_file = \Froxlor\Froxlor::getInstallDir().'/templates/misc/awstats/nav.html';
|
||||
$nav_file = makeCorrectFile($nav_file);
|
||||
|
||||
// Write the index file
|
||||
{
|
||||
// 'index.html' used to be a symlink (ignore errors in case this is the first run and no index.html exists yet)
|
||||
@unlink(makeCorrectFile($outputdir . '/' . 'index.html'));
|
||||
|
||||
$awstats_index_file = fopen(makeCorrectFile($outputdir . '/' . 'index.html'), 'w');
|
||||
$awstats_index_tpl = fopen($index_file, 'r');
|
||||
|
||||
// Write the header
|
||||
fwrite($awstats_index_file, $header);
|
||||
|
||||
// Write the configuration file
|
||||
while (($line = fgets($awstats_index_tpl, 4096)) !== false) {
|
||||
if (!preg_match('/^#/', $line)
|
||||
&& trim($line) != ''
|
||||
) {
|
||||
fwrite($awstats_index_file, preg_replace($regex, $replace, $line));
|
||||
}
|
||||
}
|
||||
fclose($awstats_index_file);
|
||||
fclose($awstats_index_tpl);
|
||||
}
|
||||
|
||||
// Write the nav file
|
||||
{
|
||||
$awstats_nav_file = fopen(makeCorrectFile($outputdir . '/' . 'nav.html'), 'w');
|
||||
$awstats_nav_tpl = fopen($nav_file, 'r');
|
||||
|
||||
// Write the header
|
||||
fwrite($awstats_nav_file, $header);
|
||||
|
||||
// Write the configuration file
|
||||
while (($line = fgets($awstats_nav_tpl, 4096)) !== false) {
|
||||
if (!preg_match('/^#/', $line)
|
||||
&& trim($line) != ''
|
||||
) {
|
||||
fwrite($awstats_nav_file, preg_replace($regex, $replace, $line));
|
||||
}
|
||||
}
|
||||
fclose($awstats_nav_file);
|
||||
fclose($awstats_nav_tpl);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
function callAwstatsGetTraffic($customerid, $outputdir, $usersdomainlist) {
|
||||
|
||||
global $cronlog;
|
||||
|
||||
$returnval = 0;
|
||||
|
||||
foreach ($usersdomainlist as $domainid => $singledomain) {
|
||||
// as we check for the config-model awstats will only parse
|
||||
// 'real' domains and no subdomains which are aliases in the
|
||||
// model-config-file.
|
||||
$returnval += awstatsDoSingleDomain($singledomain, $outputdir);
|
||||
}
|
||||
|
||||
/**
|
||||
* as of #124, awstats traffic is saved in bytes instead
|
||||
* of kilobytes (like webalizer does)
|
||||
*/
|
||||
$returnval = floatval($returnval / 1024);
|
||||
|
||||
/**
|
||||
* now, because this traffic is being saved daily, we have to
|
||||
* subtract the values from all the month's values to return
|
||||
* a sane value for our panel_traffic and to remain the whole stats
|
||||
* (awstats overwrites the customers .html stats-files)
|
||||
*/
|
||||
if ($customerid !== false) {
|
||||
|
||||
$result_stmt = Database::prepare("
|
||||
SELECT SUM(`http`) as `trafficmonth` FROM `" . TABLE_PANEL_TRAFFIC . "`
|
||||
WHERE `customerid` = :customerid
|
||||
AND `year` = :year AND `month` = :month
|
||||
");
|
||||
$result_data = array(
|
||||
'customerid' => $customerid,
|
||||
'year' => date('Y', time()),
|
||||
'month' => date('m', time())
|
||||
);
|
||||
$result = Database::pexecute_first($result_stmt, $result_data);
|
||||
|
||||
if (is_array($result)
|
||||
&& isset($result['trafficmonth'])
|
||||
) {
|
||||
$returnval = ($returnval - floatval($result['trafficmonth']));
|
||||
}
|
||||
}
|
||||
|
||||
return floatval($returnval);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function which make webalizer statistics and returns used traffic since last run
|
||||
*
|
||||
* @param string Name of logfile
|
||||
* @param string Place where stats should be build
|
||||
* @param string Caption for webalizer output
|
||||
* @return int Used traffic
|
||||
* @author Florian Lippert <flo@syscp.org>
|
||||
*/
|
||||
function callWebalizerGetTraffic($logfile, $outputdir, $caption, $usersdomainlist) {
|
||||
|
||||
global $cronlog;
|
||||
|
||||
$returnval = 0;
|
||||
|
||||
$logfile = makeCorrectFile(Settings::Get('system.logfiles_directory') . $logfile . '-access.log');
|
||||
if (file_exists($logfile)) {
|
||||
$domainargs = '';
|
||||
foreach ($usersdomainlist as $domainid => $domain) {
|
||||
// hide referer
|
||||
$domainargs.= ' -r ' . escapeshellarg($domain);
|
||||
}
|
||||
|
||||
$outputdir = makeCorrectDir($outputdir);
|
||||
if (!file_exists($outputdir)) {
|
||||
safe_exec('mkdir -p ' . escapeshellarg($outputdir));
|
||||
}
|
||||
|
||||
if (file_exists($outputdir . 'webalizer.hist.1')) {
|
||||
@unlink($outputdir . 'webalizer.hist.1');
|
||||
}
|
||||
|
||||
if (file_exists($outputdir . 'webalizer.hist')
|
||||
&& !file_exists($outputdir . 'webalizer.hist.1')
|
||||
) {
|
||||
safe_exec('cp ' . escapeshellarg($outputdir . 'webalizer.hist') . ' ' . escapeshellarg($outputdir . 'webalizer.hist.1'));
|
||||
}
|
||||
|
||||
$verbosity = '';
|
||||
if (Settings::Get('system.webalizer_quiet') == '1') {
|
||||
$verbosity = '-q';
|
||||
} elseif (Settings::Get('system.webalizer_quiet') == '2') {
|
||||
$verbosity = '-Q';
|
||||
}
|
||||
|
||||
$we = '/usr/bin/webalizer';
|
||||
|
||||
// FreeBSD uses other paths, #140
|
||||
if (!file_exists($we)) {
|
||||
$we = '/usr/local/bin/webalizer';
|
||||
}
|
||||
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, "Running webalizer for domain '".$caption."'");
|
||||
safe_exec($we . ' ' . $verbosity . ' -p -o ' . escapeshellarg($outputdir) . ' -n ' . escapeshellarg($caption) . $domainargs . ' ' . escapeshellarg($logfile));
|
||||
|
||||
/**
|
||||
* Format of webalizer.hist-files:
|
||||
* Month: $webalizer_hist_row['0']
|
||||
* Year: $webalizer_hist_row['1']
|
||||
* KB: $webalizer_hist_row['5']
|
||||
*/
|
||||
$httptraffic = array();
|
||||
$webalizer_hist = @file_get_contents($outputdir . 'webalizer.hist');
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, "Gathering traffic information from '".$webalizer_hist."'");
|
||||
|
||||
$webalizer_hist_rows = explode("\n", $webalizer_hist);
|
||||
foreach ($webalizer_hist_rows as $webalizer_hist_row) {
|
||||
if ($webalizer_hist_row != '') {
|
||||
|
||||
$webalizer_hist_row = explode(' ', $webalizer_hist_row);
|
||||
|
||||
if (isset($webalizer_hist_row['0'])
|
||||
&& isset($webalizer_hist_row['1'])
|
||||
&& isset($webalizer_hist_row['5'])
|
||||
) {
|
||||
$month = intval($webalizer_hist_row['0']);
|
||||
$year = intval($webalizer_hist_row['1']);
|
||||
$traffic = floatval($webalizer_hist_row['5']);
|
||||
|
||||
if (!isset($httptraffic[$year])) {
|
||||
$httptraffic[$year] = array();
|
||||
}
|
||||
|
||||
$httptraffic[$year][$month] = $traffic;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reset($httptraffic);
|
||||
$httptrafficlast = array();
|
||||
$webalizer_lasthist = @file_get_contents($outputdir . 'webalizer.hist.1');
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, "Gathering traffic information from '".$webalizer_lasthist."'");
|
||||
|
||||
$webalizer_lasthist_rows = explode("\n", $webalizer_lasthist);
|
||||
foreach ($webalizer_lasthist_rows as $webalizer_lasthist_row) {
|
||||
if ($webalizer_lasthist_row != '') {
|
||||
|
||||
$webalizer_lasthist_row = explode(' ', $webalizer_lasthist_row);
|
||||
|
||||
if (isset($webalizer_lasthist_row['0'])
|
||||
&& isset($webalizer_lasthist_row['1'])
|
||||
&& isset($webalizer_lasthist_row['5'])
|
||||
) {
|
||||
$month = intval($webalizer_lasthist_row['0']);
|
||||
$year = intval($webalizer_lasthist_row['1']);
|
||||
$traffic = floatval($webalizer_lasthist_row['5']);
|
||||
|
||||
if (!isset($httptrafficlast[$year])) {
|
||||
$httptrafficlast[$year] = array();
|
||||
}
|
||||
|
||||
$httptrafficlast[$year][$month] = $traffic;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reset($httptrafficlast);
|
||||
foreach ($httptraffic as $year => $months) {
|
||||
foreach ($months as $month => $traffic) {
|
||||
if (!isset($httptrafficlast[$year][$month])) {
|
||||
$returnval+= $traffic;
|
||||
} elseif ($httptrafficlast[$year][$month] < $httptraffic[$year][$month]) {
|
||||
$returnval+= ($httptraffic[$year][$month] - $httptrafficlast[$year][$month]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return floatval($returnval);
|
||||
}
|
||||
|
||||
@@ -1,615 +0,0 @@
|
||||
<?php if (!defined('MASTER_CRONJOB')) die('You cannot access this file directly!');
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
* Copyright (c) 2003-2009 the SysCP Team (see authors).
|
||||
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||
*
|
||||
* For the full copyright and license information, please view the COPYING
|
||||
* file that was distributed with this source code. You can also view the
|
||||
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
|
||||
*
|
||||
* @copyright (c) the authors
|
||||
* @author Florian Lippert <flo@syscp.org> (2003-2009)
|
||||
* @author Froxlor team <team@froxlor.org> (2010-)
|
||||
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
|
||||
* @package Cron
|
||||
*
|
||||
*/
|
||||
|
||||
use \Froxlor\Database;
|
||||
use \Froxlor\Settings;
|
||||
|
||||
// Check Traffic-Lock
|
||||
if (function_exists('pcntl_fork') && !defined('CRON_NOFORK_FLAG')) {
|
||||
$TrafficLock = makeCorrectFile(dirname($lockfile)."/froxlor_cron_traffic.lock");
|
||||
if (file_exists($TrafficLock)
|
||||
&& is_numeric($TrafficPid=file_get_contents($TrafficLock))
|
||||
) {
|
||||
if (function_exists('posix_kill')) {
|
||||
$TrafficPidStatus = @posix_kill($TrafficPid,0);
|
||||
} else {
|
||||
system("kill -CHLD " . $TrafficPid . " 1> /dev/null 2> /dev/null", $TrafficPidStatus);
|
||||
$TrafficPidStatus = $TrafficPidStatus ? false : true;
|
||||
}
|
||||
if ($TrafficPidStatus) {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'Traffic Run already in progress');
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
// Create Traffic Log and Fork
|
||||
// We close the database - connection before we fork, so we don't share resources with the child
|
||||
Database::needRoot(false); // this forces the connection to be set to null
|
||||
$TrafficPid = pcntl_fork();
|
||||
// Parent
|
||||
if ($TrafficPid) {
|
||||
file_put_contents($TrafficLock, $TrafficPid);
|
||||
// unnecessary to recreate database connection here
|
||||
return 0;
|
||||
|
||||
}
|
||||
//Child
|
||||
elseif ($TrafficPid == 0) {
|
||||
posix_setsid();
|
||||
fclose($debugHandler);
|
||||
// re-create db
|
||||
Database::needRoot(false);
|
||||
}
|
||||
//Fork failed
|
||||
else {
|
||||
return 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (extension_loaded('pcntl')) {
|
||||
$msg = "PHP compiled with pcntl but pcntl_fork function is not available.";
|
||||
} else {
|
||||
$msg = "PHP compiled without pcntl.";
|
||||
}
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, $msg." Not forking traffic-cron, this may take a long time!");
|
||||
}
|
||||
|
||||
require_once makeCorrectFile(dirname(__FILE__) . '/cron_traffic.inc.functions.php');
|
||||
|
||||
/**
|
||||
* TRAFFIC AND DISKUSAGE MESSURE
|
||||
*/
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'Traffic run started...');
|
||||
$admin_traffic = array();
|
||||
$domainlist = array();
|
||||
$speciallogfile_domainlist = array();
|
||||
$result_domainlist_stmt = Database::query("
|
||||
SELECT `id`, `domain`, `customerid`, `parentdomainid`, `speciallogfile`
|
||||
FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `aliasdomain` IS NULL AND `email_only` <> '1';
|
||||
");
|
||||
|
||||
while ($row_domainlist = $result_domainlist_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
|
||||
if (!isset($domainlist[$row_domainlist['customerid']])) {
|
||||
$domainlist[$row_domainlist['customerid']] = array();
|
||||
}
|
||||
|
||||
$domainlist[$row_domainlist['customerid']][$row_domainlist['id']] = $row_domainlist['domain'];
|
||||
|
||||
if ($row_domainlist['parentdomainid'] == '0'
|
||||
&& $row_domainlist['speciallogfile'] == '1'
|
||||
) {
|
||||
if (!isset($speciallogfile_domainlist[$row_domainlist['customerid']])) {
|
||||
$speciallogfile_domainlist[$row_domainlist['customerid']] = array();
|
||||
}
|
||||
$speciallogfile_domainlist[$row_domainlist['customerid']][$row_domainlist['id']] = $row_domainlist['domain'];
|
||||
}
|
||||
}
|
||||
|
||||
$mysqlusage_all = array();
|
||||
$databases_stmt = Database::query("SELECT * FROM " . TABLE_PANEL_DATABASES . " ORDER BY `dbserver`");
|
||||
$last_dbserver = 0;
|
||||
|
||||
$databases_list = array();
|
||||
Database::needRoot(true);
|
||||
$databases_list_result_stmt = Database::query("SHOW DATABASES");
|
||||
while ($databases_list_row = $databases_list_result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$databases_list[] = strtolower($databases_list_row['Database']);
|
||||
}
|
||||
|
||||
while ($row_database = $databases_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
|
||||
if ($last_dbserver != $row_database['dbserver']) {
|
||||
Database::needRoot(true, $row_database['dbserver']);
|
||||
$last_dbserver = $row_database['dbserver'];
|
||||
|
||||
$databases_list = array();
|
||||
$databases_list_result_stmt = Database::query("SHOW DATABASES");
|
||||
while ($databases_list_row = $databases_list_result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$databases_list[] = strtolower($databases_list_row['Database']);
|
||||
}
|
||||
}
|
||||
|
||||
if (in_array(strtolower($row_database['databasename']), $databases_list)) {
|
||||
// sum up data_length and index_length
|
||||
$mysql_usage_result_stmt = Database::prepare("
|
||||
SELECT SUM(data_length + index_length) AS customerusage
|
||||
FROM information_schema.TABLES
|
||||
WHERE table_schema = :database
|
||||
GROUP BY table_schema;
|
||||
");
|
||||
// get the result
|
||||
$mysql_usage_row = Database::pexecute_first($mysql_usage_result_stmt, array('database' => $row_database['databasename']));
|
||||
// initialize counter for customer
|
||||
if (!isset($mysqlusage_all[$row_database['customerid']])) {
|
||||
$mysqlusage_all[$row_database['customerid']] = 0;
|
||||
}
|
||||
// sum up result
|
||||
$mysqlusage_all[$row_database['customerid']] += floatval($mysql_usage_row['customerusage']);
|
||||
} else {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_WARNING, "Seems like the database " . $row_database['databasename'] . " had been removed manually.");
|
||||
}
|
||||
}
|
||||
|
||||
Database::needRoot(false);
|
||||
|
||||
// We are using the file-system quota, this will speed up the diskusage - collection
|
||||
if (Settings::Get('system.diskquota_enabled')) {
|
||||
$usedquota = getFilesystemQuota();
|
||||
}
|
||||
|
||||
/**
|
||||
* MAIL-Traffic
|
||||
*/
|
||||
if (Settings::Get("system.mailtraffic_enabled")) {
|
||||
$mailTrafficCalc = new \Froxlor\MailLogParser(Settings::Get("system.last_traffic_run"));
|
||||
}
|
||||
|
||||
$result_stmt = Database::query("SELECT * FROM `" . TABLE_PANEL_CUSTOMERS . "` ORDER BY `customerid` ASC");
|
||||
|
||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
/**
|
||||
* HTTP-Traffic
|
||||
*/
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'http traffic for ' . $row['loginname'] . ' started...');
|
||||
$httptraffic = 0;
|
||||
|
||||
if (isset($domainlist[$row['customerid']])
|
||||
&& is_array($domainlist[$row['customerid']])
|
||||
&& count($domainlist[$row['customerid']]) != 0
|
||||
) {
|
||||
// Examining which caption to use for default webalizer stats...
|
||||
if ($row['standardsubdomain'] != '0') {
|
||||
// ... of course we'd prefer to use the standardsubdomain ...
|
||||
$caption = $domainlist[$row['customerid']][$row['standardsubdomain']];
|
||||
} else {
|
||||
// ... but if there is no standardsubdomain, we have to use the loginname ...
|
||||
$caption = $row['loginname'];
|
||||
|
||||
// ... which results in non-usable links to files in the stats, so lets have a look if we find a domain which is not speciallogfiledomain
|
||||
foreach ($domainlist[$row['customerid']] as $domainid => $domain) {
|
||||
|
||||
if (!isset($speciallogfile_domainlist[$row['customerid']])
|
||||
|| !isset($speciallogfile_domainlist[$row['customerid']][$domainid])
|
||||
) {
|
||||
$caption = $domain;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$httptraffic = 0;
|
||||
reset($domainlist[$row['customerid']]);
|
||||
|
||||
if (isset($speciallogfile_domainlist[$row['customerid']])
|
||||
&& is_array($speciallogfile_domainlist[$row['customerid']])
|
||||
&& count($speciallogfile_domainlist[$row['customerid']]) != 0
|
||||
) {
|
||||
reset($speciallogfile_domainlist[$row['customerid']]);
|
||||
if (Settings::Get('system.awstats_enabled') == '0') {
|
||||
foreach ($speciallogfile_domainlist[$row['customerid']] as $domainid => $domain) {
|
||||
$httptraffic+= floatval(callWebalizerGetTraffic($row['loginname'] . '-' . $domain, $row['documentroot'] . '/webalizer/' . $domain . '/', $domain, $domainlist[$row['customerid']]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reset($domainlist[$row['customerid']]);
|
||||
|
||||
// callAwstatsGetTraffic is called ONLY HERE and
|
||||
// *not* also in the special-logfiles-loop, because the function
|
||||
// will iterate through all customer-domains and the awstats-configs
|
||||
// know the logfile-name, #246
|
||||
if (Settings::Get('system.awstats_enabled') == '1') {
|
||||
$httptraffic+= floatval(callAwstatsGetTraffic($row['customerid'], $row['documentroot'] . '/awstats/', $domainlist[$row['customerid']]));
|
||||
} else {
|
||||
$httptraffic+= floatval(callWebalizerGetTraffic($row['loginname'], $row['documentroot'] . '/webalizer/', $caption, $domainlist[$row['customerid']]));
|
||||
}
|
||||
|
||||
// make the stuff readable for the customer, #258
|
||||
makeChownWithNewStats($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* FTP-Traffic
|
||||
*/
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'ftp traffic for ' . $row['loginname'] . ' started...');
|
||||
$ftptraffic_stmt = Database::prepare("
|
||||
SELECT SUM(`up_bytes`) AS `up_bytes_sum`, SUM(`down_bytes`) AS `down_bytes_sum`
|
||||
FROM `" . TABLE_FTP_USERS . "` WHERE `customerid` = :customerid
|
||||
");
|
||||
$ftptraffic = Database::pexecute_first($ftptraffic_stmt, array('customerid' => $row['customerid']));
|
||||
|
||||
if (!is_array($ftptraffic)) {
|
||||
$ftptraffic = array(
|
||||
'up_bytes_sum' => 0,
|
||||
'down_bytes_sum' => 0
|
||||
);
|
||||
}
|
||||
|
||||
$upd_stmt = Database::prepare("
|
||||
UPDATE `" . TABLE_FTP_USERS . "` SET `up_bytes` = '0', `down_bytes` = '0' WHERE `customerid` = :customerid
|
||||
");
|
||||
Database::pexecute($upd_stmt, array('customerid' => $row['customerid']));
|
||||
|
||||
/**
|
||||
* Mail-Traffic
|
||||
*/
|
||||
$mailtraffic = 0;
|
||||
if (Settings::Get("system.mailtraffic_enabled")) {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'mail traffic usage for ' . $row['loginname'] . " started...");
|
||||
|
||||
$currentDate = date("Y-m-d");
|
||||
|
||||
$domains_stmt = Database::prepare("SELECT domain FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `customerid` = :cid");
|
||||
Database::pexecute($domains_stmt, array("cid" => $row['customerid']));
|
||||
while ($domainRow = $domains_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$domainMailTraffic = $mailTrafficCalc->getDomainTraffic($domainRow["domain"]);
|
||||
if (!is_array($domainMailTraffic)) { continue; }
|
||||
|
||||
foreach ($domainMailTraffic as $dateTraffic => $dayTraffic) {
|
||||
$dayTraffic = floatval($dayTraffic / 1024);
|
||||
|
||||
list($year, $month, $day) = explode("-", $dateTraffic);
|
||||
if ($dateTraffic == $currentDate) {
|
||||
$mailtraffic = $dayTraffic;
|
||||
} else {
|
||||
// Check if an entry for the given day exists
|
||||
$stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_TRAFFIC . "`
|
||||
WHERE `customerid` = :cid
|
||||
AND `year` = :year
|
||||
AND `month` = :month
|
||||
AND `day` = :day");
|
||||
$params = array(
|
||||
"cid" => $row['customerid'],
|
||||
"year" => $year,
|
||||
"month" => $month,
|
||||
"day" => $day
|
||||
);
|
||||
Database::pexecute($stmt, $params);
|
||||
if ($stmt->rowCount() > 0) {
|
||||
$updRow = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$upd_stmt = Database::prepare("UPDATE `" . TABLE_PANEL_TRAFFIC . "` SET
|
||||
`mail` = :mail
|
||||
WHERE `id` = :id");
|
||||
Database::pexecute($upd_stmt, array("mail" => $updRow['mail'] + $dayTraffic, "id" => $updRow['id']));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Total Traffic
|
||||
*/
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'total traffic for ' . $row['loginname'] . ' started');
|
||||
$current_traffic = array();
|
||||
$current_traffic['http'] = floatval($httptraffic);
|
||||
$current_traffic['ftp_up'] = floatval(($ftptraffic['up_bytes_sum'] / 1024));
|
||||
$current_traffic['ftp_down'] = floatval(($ftptraffic['down_bytes_sum'] / 1024));
|
||||
$current_traffic['mail'] = floatval($mailtraffic);
|
||||
$current_traffic['all'] = $current_traffic['http'] + $current_traffic['ftp_up'] + $current_traffic['ftp_down'] + $current_traffic['mail'];
|
||||
|
||||
$ins_data = array(
|
||||
'customerid' => $row['customerid'],
|
||||
'year' => date('Y', time()),
|
||||
'month' => date('m', time()),
|
||||
'day' => date('d', time()),
|
||||
'stamp' => time(),
|
||||
'http' => $current_traffic['http'],
|
||||
'ftp_up' => $current_traffic['ftp_up'],
|
||||
'ftp_down' => $current_traffic['ftp_down'],
|
||||
'mail' => $current_traffic['mail']
|
||||
);
|
||||
$ins_stmt = Database::prepare("
|
||||
INSERT INTO `" . TABLE_PANEL_TRAFFIC . "` SET
|
||||
`customerid` = :customerid,
|
||||
`year` = :year,
|
||||
`month` = :month,
|
||||
`day` = :day,
|
||||
`stamp` = :stamp,
|
||||
`http` = :http,
|
||||
`ftp_up` = :ftp_up,
|
||||
`ftp_down` = :ftp_down,
|
||||
`mail` = :mail
|
||||
");
|
||||
Database::pexecute($ins_stmt, $ins_data);
|
||||
|
||||
$sum_month_traffic_stmt = Database::prepare("
|
||||
SELECT SUM(`http`) AS `http`, SUM(`ftp_up`) AS `ftp_up`, SUM(`ftp_down`) AS `ftp_down`, SUM(`mail`) AS `mail`
|
||||
FROM `" . TABLE_PANEL_TRAFFIC . "` WHERE `year` = :year AND `month` = :month AND `customerid` = :customerid
|
||||
");
|
||||
$sum_month_traffic = Database::pexecute_first($sum_month_traffic_stmt, array('year' => date('Y', time()), 'month' => date('m', time()), 'customerid' => $row['customerid']));
|
||||
$sum_month_traffic['all'] = $sum_month_traffic['http'] + $sum_month_traffic['ftp_up'] + $sum_month_traffic['ftp_down'] + $sum_month_traffic['mail'];
|
||||
|
||||
if (!isset($admin_traffic[$row['adminid']])
|
||||
|| !is_array($admin_traffic[$row['adminid']])
|
||||
) {
|
||||
$admin_traffic[$row['adminid']]['http'] = 0;
|
||||
$admin_traffic[$row['adminid']]['ftp_up'] = 0;
|
||||
$admin_traffic[$row['adminid']]['ftp_down'] = 0;
|
||||
$admin_traffic[$row['adminid']]['mail'] = 0;
|
||||
$admin_traffic[$row['adminid']]['all'] = 0;
|
||||
$admin_traffic[$row['adminid']]['sum_month'] = 0;
|
||||
}
|
||||
|
||||
$admin_traffic[$row['adminid']]['http']+= $current_traffic['http'];
|
||||
$admin_traffic[$row['adminid']]['ftp_up']+= $current_traffic['ftp_up'];
|
||||
$admin_traffic[$row['adminid']]['ftp_down']+= $current_traffic['ftp_down'];
|
||||
$admin_traffic[$row['adminid']]['mail']+= $current_traffic['mail'];
|
||||
$admin_traffic[$row['adminid']]['all']+= $current_traffic['all'];
|
||||
$admin_traffic[$row['adminid']]['sum_month']+= $sum_month_traffic['all'];
|
||||
|
||||
/**
|
||||
* WebSpace-Usage
|
||||
*/
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'calculating webspace usage for ' . $row['loginname']);
|
||||
$webspaceusage = 0;
|
||||
|
||||
// Using repquota, it's faster using this tool than using du traversing the complete directory
|
||||
if (Settings::Get('system.diskquota_enabled')
|
||||
&& isset($usedquota[$row['guid']]['block']['used'])
|
||||
&& $usedquota[$row['guid']]['block']['used'] >= 1
|
||||
) {
|
||||
// We may use the array we created earlier, the used diskspace is stored in [<guid>][block][used]
|
||||
$webspaceusage = floatval($usedquota[$row['guid']]['block']['used']);
|
||||
|
||||
} else {
|
||||
|
||||
// Use the old fashioned way with "du"
|
||||
if (file_exists($row['documentroot'])
|
||||
&& is_dir($row['documentroot'])
|
||||
) {
|
||||
$back = safe_exec('du -sk ' . escapeshellarg($row['documentroot']) . '');
|
||||
foreach ($back as $backrow) {
|
||||
$webspaceusage = explode(' ', $backrow);
|
||||
}
|
||||
|
||||
$webspaceusage = floatval($webspaceusage['0']);
|
||||
unset($back);
|
||||
|
||||
} else {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_WARNING, 'documentroot ' . $row['documentroot'] . ' does not exist');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MailSpace-Usage
|
||||
*/
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'calculating mailspace usage for ' . $row['loginname']);
|
||||
$emailusage = 0;
|
||||
|
||||
$maildir = makeCorrectDir(Settings::Get('system.vmail_homedir') . $row['loginname']);
|
||||
if (file_exists($maildir) && is_dir($maildir)) {
|
||||
$back = safe_exec('du -sk ' . escapeshellarg($maildir) . '');
|
||||
foreach ($back as $backrow) {
|
||||
$emailusage = explode(' ', $backrow);
|
||||
}
|
||||
|
||||
$emailusage = floatval($emailusage['0']);
|
||||
unset($back);
|
||||
|
||||
} else {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_WARNING, 'maildir ' . $maildir . ' does not exist');
|
||||
}
|
||||
|
||||
/**
|
||||
* MySQLSpace-Usage
|
||||
*/
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'calculating mysqlspace usage for ' . $row['loginname']);
|
||||
$mysqlusage = 0;
|
||||
|
||||
if (isset($mysqlusage_all[$row['customerid']])) {
|
||||
$mysqlusage = floatval($mysqlusage_all[$row['customerid']] / 1024);
|
||||
}
|
||||
|
||||
$current_diskspace = array();
|
||||
$current_diskspace['webspace'] = floatval($webspaceusage);
|
||||
$current_diskspace['mail'] = floatval($emailusage);
|
||||
$current_diskspace['mysql'] = floatval($mysqlusage);
|
||||
$current_diskspace['all'] = $current_diskspace['webspace'] + $current_diskspace['mail'] + $current_diskspace['mysql'];
|
||||
|
||||
$ins_data = array(
|
||||
'customerid' => $row['customerid'],
|
||||
'year' => date('Y', time()),
|
||||
'month' => date('m', time()),
|
||||
'day' => date('d', time()),
|
||||
'stamp' => time(),
|
||||
'webspace' => $current_diskspace['webspace'],
|
||||
'mail' => $current_diskspace['mail'],
|
||||
'mysql' => $current_diskspace['mysql']
|
||||
);
|
||||
$ins_stmt = Database::prepare("
|
||||
INSERT INTO `" . TABLE_PANEL_DISKSPACE . "` SET
|
||||
`customerid` = :customerid,
|
||||
`year` = :year,
|
||||
`month` = :month,
|
||||
`day` = :day,
|
||||
`stamp` = :stamp,
|
||||
`webspace` = :webspace,
|
||||
`mail` = :mail,
|
||||
`mysql` = :mysql
|
||||
");
|
||||
Database::pexecute($ins_stmt, $ins_data);
|
||||
|
||||
if (!isset($admin_diskspace[$row['adminid']])
|
||||
|| !is_array($admin_diskspace[$row['adminid']])
|
||||
) {
|
||||
$admin_diskspace[$row['adminid']] = array();
|
||||
$admin_diskspace[$row['adminid']]['webspace'] = 0;
|
||||
$admin_diskspace[$row['adminid']]['mail'] = 0;
|
||||
$admin_diskspace[$row['adminid']]['mysql'] = 0;
|
||||
$admin_diskspace[$row['adminid']]['all'] = 0;
|
||||
}
|
||||
|
||||
$admin_diskspace[$row['adminid']]['webspace']+= $current_diskspace['webspace'];
|
||||
$admin_diskspace[$row['adminid']]['mail']+= $current_diskspace['mail'];
|
||||
$admin_diskspace[$row['adminid']]['mysql']+= $current_diskspace['mysql'];
|
||||
$admin_diskspace[$row['adminid']]['all']+= $current_diskspace['all'];
|
||||
|
||||
/**
|
||||
* Total Usage
|
||||
*/
|
||||
$diskusage = floatval($webspaceusage + $emailusage + $mysqlusage);
|
||||
|
||||
$upd_data = array(
|
||||
'diskspace' => $current_diskspace['all'],
|
||||
'traffic' => $sum_month_traffic['all'],
|
||||
'customerid' => $row['customerid']
|
||||
);
|
||||
$upd_stmt = Database::prepare("
|
||||
UPDATE `" . TABLE_PANEL_CUSTOMERS . "` SET
|
||||
`diskspace_used` = :diskspace,
|
||||
`traffic_used` = :traffic
|
||||
WHERE `customerid` = :customerid
|
||||
");
|
||||
Database::pexecute($upd_stmt, $upd_data);
|
||||
|
||||
/**
|
||||
* Proftpd Quota
|
||||
*/
|
||||
$upd_data = array(
|
||||
'biu' => ($current_diskspace['all'] * 1024),
|
||||
'loginname' => $row['loginname'],
|
||||
'loginnamelike' => $row['loginname'] . Settings::Get('customer.ftpprefix') . "%"
|
||||
);
|
||||
$upd_stmt = Database::prepare("
|
||||
UPDATE `" . TABLE_FTP_QUOTATALLIES . "` SET
|
||||
`bytes_in_used` = :biu WHERE `name` = :loginname OR `name` LIKE :loginnamelike
|
||||
");
|
||||
Database::pexecute($upd_stmt, $upd_data);
|
||||
|
||||
/**
|
||||
* Pureftpd Quota
|
||||
*/
|
||||
if (Settings::Get('system.ftpserver') == "pureftpd") {
|
||||
|
||||
$result_quota_stmt = Database::prepare("
|
||||
SELECT homedir FROM `" . TABLE_FTP_USERS . "` WHERE customerid = :customerid
|
||||
");
|
||||
Database::pexecute($result_quota_stmt, array('customerid' => $row['customerid']));
|
||||
|
||||
// get correct user
|
||||
if ((Settings::Get('system.mod_fcgid') == 1 || Settings::Get('phpfpm.enabled') == 1) && $row['deactivated'] == '0') {
|
||||
$user = $row['loginname'];
|
||||
$group = $row['loginname'];
|
||||
} else {
|
||||
$user = $row['guid'];
|
||||
$group = $row['guid'];
|
||||
}
|
||||
|
||||
while ($row_quota = $result_quota_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$quotafile = "" . $row_quota['homedir'] . ".ftpquota";
|
||||
$fh = fopen($quotafile, 'w');
|
||||
$stringdata = "0 " . $current_diskspace['all']*1024 . "";
|
||||
fwrite($fh, $stringdata);
|
||||
fclose($fh);
|
||||
safe_exec('chown ' . $user . ':' . $group . ' ' . escapeshellarg($quotafile) . '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin Usage
|
||||
*/
|
||||
$result_stmt = Database::query("SELECT `adminid` FROM `" . TABLE_PANEL_ADMINS . "` ORDER BY `adminid` ASC");
|
||||
|
||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
|
||||
if (isset($admin_traffic[$row['adminid']])) {
|
||||
|
||||
$ins_data = array(
|
||||
'adminid' => $row['adminid'],
|
||||
'year' => date('Y', time()),
|
||||
'month' => date('m', time()),
|
||||
'day' => date('d', time()),
|
||||
'stamp' => time(),
|
||||
'http' => $admin_traffic[$row['adminid']]['http'],
|
||||
'ftp_up' => $admin_traffic[$row['adminid']]['ftp_up'],
|
||||
'ftp_down' => $admin_traffic[$row['adminid']]['ftp_down'],
|
||||
'mail' => $admin_traffic[$row['adminid']]['mail']
|
||||
);
|
||||
$ins_stmt = Database::prepare("
|
||||
INSERT INTO `" . TABLE_PANEL_TRAFFIC_ADMINS . "` SET
|
||||
`adminid` = :adminid,
|
||||
`year` = :year,
|
||||
`month` = :month,
|
||||
`day` = :day,
|
||||
`stamp` = :stamp,
|
||||
`http` = :http,
|
||||
`ftp_up` = :ftp_up,
|
||||
`ftp_down` = :ftp_down,
|
||||
`mail` = :mail
|
||||
");
|
||||
Database::pexecute($ins_stmt, $ins_data);
|
||||
|
||||
$upd_data = array(
|
||||
'traffic' => $admin_traffic[$row['adminid']]['sum_month'],
|
||||
'adminid' => $row['adminid']
|
||||
);
|
||||
$upd_stmt = Database::prepare("
|
||||
UPDATE `" . TABLE_PANEL_ADMINS . "` SET
|
||||
`traffic_used` = :traffic
|
||||
WHERE `adminid` = :adminid
|
||||
");
|
||||
Database::pexecute($upd_stmt, $upd_data);
|
||||
}
|
||||
|
||||
if (isset($admin_diskspace[$row['adminid']])) {
|
||||
|
||||
$ins_data = array(
|
||||
'adminid' => $row['adminid'],
|
||||
'year' => date('Y', time()),
|
||||
'month' => date('m', time()),
|
||||
'day' => date('d', time()),
|
||||
'stamp' => time(),
|
||||
'webspace' => $admin_diskspace[$row['adminid']]['webspace'],
|
||||
'mail' => $admin_diskspace[$row['adminid']]['mail'],
|
||||
'mysql' => $admin_diskspace[$row['adminid']]['mysql']
|
||||
);
|
||||
$ins_stmt = Database::prepare("
|
||||
INSERT INTO `" . TABLE_PANEL_DISKSPACE_ADMINS . "` SET
|
||||
`adminid` = :adminid,
|
||||
`year` = :year,
|
||||
`month` = :month,
|
||||
`day` = :day,
|
||||
`stamp` = :stamp,
|
||||
`webspace` = :webspace,
|
||||
`mail` = :mail,
|
||||
`mysql` = :mysql
|
||||
");
|
||||
|
||||
$upd_data = array(
|
||||
'diskspace' => $admin_diskspace[$row['adminid']]['all'],
|
||||
'adminid' => $row['adminid']
|
||||
);
|
||||
$upd_stmt = Database::prepare("
|
||||
UPDATE `" . TABLE_PANEL_ADMINS . "` SET
|
||||
`diskspace_used` = :diskspace
|
||||
WHERE `adminid` = :adminid
|
||||
");
|
||||
Database::pexecute($upd_stmt, $upd_data);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Database::query("UPDATE `" . TABLE_PANEL_SETTINGS . "` SET `value` = UNIX_TIMESTAMP() WHERE `settinggroup` = 'system' AND `varname` = 'last_traffic_run'");
|
||||
|
||||
if (function_exists('pcntl_fork') && !defined('CRON_NOFORK_FLAG')) {
|
||||
@unlink($TrafficLock);
|
||||
die();
|
||||
}
|
||||
@@ -1,347 +0,0 @@
|
||||
<?php if (!defined('MASTER_CRONJOB')) die('You cannot access this file directly!');
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
* Copyright (c) 2003-2009 the SysCP Team (see authors).
|
||||
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||
*
|
||||
* For the full copyright and license information, please view the COPYING
|
||||
* file that was distributed with this source code. You can also view the
|
||||
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
|
||||
*
|
||||
* @copyright (c) the authors
|
||||
* @author Florian Lippert <flo@syscp.org> (2003-2009)
|
||||
* @author Froxlor team <team@froxlor.org> (2010-)
|
||||
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
|
||||
* @package Cron
|
||||
*
|
||||
*/
|
||||
|
||||
use \Froxlor\Database;
|
||||
use \Froxlor\Settings;
|
||||
|
||||
$cronlog->logAction(CRON_ACTION, LOG_INFO, 'Web- and Traffic-usage reporting started...');
|
||||
$yesterday = time() - (60 * 60 * 24);
|
||||
|
||||
/**
|
||||
* Initialize the mailingsystem
|
||||
*/
|
||||
$mail = new \PHPMailer\PHPMailer\PHPMailer(true);
|
||||
$mail->CharSet = "UTF-8";
|
||||
|
||||
if (Settings::Get('system.mail_use_smtp')) {
|
||||
$mail->isSMTP();
|
||||
$mail->Host = Settings::Get('system.mail_smtp_host');
|
||||
$mail->SMTPAuth = Settings::Get('system.mail_smtp_auth') == '1' ? true : false;
|
||||
$mail->Username = Settings::Get('system.mail_smtp_user');
|
||||
$mail->Password = Settings::Get('system.mail_smtp_passwd');
|
||||
if (Settings::Get('system.mail_smtp_usetls')) {
|
||||
$mail->SMTPSecure = 'tls';
|
||||
} else {
|
||||
$mail->SMTPAutoTLS = false;
|
||||
}
|
||||
$mail->Port = Settings::Get('system.mail_smtp_port');
|
||||
}
|
||||
|
||||
if (\PHPMailer\PHPMailer\PHPMailer::ValidateAddress(Settings::Get('panel.adminmail')) !== false) {
|
||||
// set return-to address and custom sender-name, see #76
|
||||
$mail->SetFrom(Settings::Get('panel.adminmail'), Settings::Get('panel.adminmail_defname'));
|
||||
if (Settings::Get('panel.adminmail_return') != '') {
|
||||
$mail->AddReplyTo(Settings::Get('panel.adminmail_return'), Settings::Get('panel.adminmail_defname'));
|
||||
}
|
||||
}
|
||||
|
||||
if ((int)Settings::Get('system.report_trafficmax') > 0)
|
||||
{
|
||||
// Warn the customers at xx% traffic-usage
|
||||
$result_stmt = Database::prepare("
|
||||
SELECT `c`.`customerid`, `c`.`adminid`, `c`.`name`, `c`.`firstname`,
|
||||
`c`.`company`, `c`.`traffic`, `c`.`email`, `c`.`def_language`,
|
||||
`a`.`name` AS `adminname`, `a`.`email` AS `adminmail`,
|
||||
(SELECT SUM(`t`.`http` + `t`.`ftp_up` + `t`.`ftp_down` + `t`.`mail`)
|
||||
FROM `" . TABLE_PANEL_TRAFFIC . "` `t`
|
||||
WHERE `t`.`customerid` = `c`.`customerid` AND `t`.`year` = :year AND `t`.`month` = :month
|
||||
) as `traffic_used`
|
||||
FROM `" . TABLE_PANEL_CUSTOMERS . "` AS `c`
|
||||
LEFT JOIN `" . TABLE_PANEL_ADMINS . "` AS `a`
|
||||
ON `a`.`adminid` = `c`.`adminid` WHERE `c`.`reportsent` <> '1'
|
||||
");
|
||||
|
||||
$result_data = array(
|
||||
'year' => date("Y", $yesterday),
|
||||
'month' => date("m", $yesterday)
|
||||
);
|
||||
Database::pexecute($result_stmt, $result_data);
|
||||
|
||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
|
||||
if (isset($row['traffic'])
|
||||
&& $row['traffic'] > 0
|
||||
&& $row['traffic_used'] != null
|
||||
&& (($row['traffic_used'] * 100) / $row['traffic']) >= (int)Settings::Get('system.report_trafficmax')
|
||||
) {
|
||||
$rep_userinfo = array(
|
||||
'name' => $row['name'],
|
||||
'firstname' => $row['firstname'],
|
||||
'company' => $row['company']
|
||||
);
|
||||
$replace_arr = array(
|
||||
'SALUTATION' => getCorrectUserSalutation($rep_userinfo),
|
||||
'NAME' => $row['name'], // < keep this for compatibility
|
||||
'TRAFFIC' => round(($row['traffic'] / 1024), 2), /* traffic is stored in KB, template uses MB */
|
||||
'TRAFFICUSED' => round(($row['traffic_used'] / 1024), 2), /* traffic is stored in KB, template uses MB */
|
||||
'USAGE_PERCENT' => round(($row['traffic_used'] * 100) / $row['traffic'], 2),
|
||||
'MAX_PERCENT' => Settings::Get('system.report_trafficmax')
|
||||
);
|
||||
|
||||
$lngfile_stmt = Database::prepare("
|
||||
SELECT `file` FROM `" . TABLE_PANEL_LANGUAGE . "`
|
||||
WHERE `language` = :deflang
|
||||
");
|
||||
$lngfile = Database::pexecute_first($lngfile_stmt, array('deflang' => $row['def_language']));
|
||||
|
||||
if ($lngfile !== null) {
|
||||
$langfile = $lngfile['file'];
|
||||
} else {
|
||||
$lngfile = Database::pexecute_first($lngfile_stmt, array('deflang' => Settings::Get('panel.standardlanguage')));
|
||||
$langfile = $lngfile['file'];
|
||||
}
|
||||
|
||||
// include english language file (fallback)
|
||||
include_once makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . '/lng/english.lng.php');
|
||||
// include admin/customer language file
|
||||
include_once makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . '/' . $langfile);
|
||||
|
||||
// Get mail templates from database; the ones from 'admin' are fetched for fallback
|
||||
$result2_stmt = Database::prepare("
|
||||
SELECT `value` FROM `" . TABLE_PANEL_TEMPLATES . "`
|
||||
WHERE `adminid` = :adminid
|
||||
AND `language` = :lang
|
||||
AND `templategroup` = 'mails' AND `varname` = :varname
|
||||
");
|
||||
$result2_data = array(
|
||||
'adminid' => $row['adminid'],
|
||||
'lang' => $row['def_language'],
|
||||
'varname' => 'trafficmaxpercent_subject'
|
||||
);
|
||||
$result2 = Database::pexecute_first($result2_stmt, $result2_data);
|
||||
$mail_subject = html_entity_decode(replace_variables((($result2['value'] != '') ? $result2['value'] : $lng['mails']['trafficmaxpercent']['subject']), $replace_arr));
|
||||
|
||||
$result2_data['varname'] = 'trafficmaxpercent_mailbody';
|
||||
$result2 = Database::pexecute_first($result2_stmt, $result2_data);
|
||||
$mail_body = html_entity_decode(replace_variables((($result2['value'] != '') ? $result2['value'] : $lng['mails']['trafficmaxpercent']['mailbody']), $replace_arr));
|
||||
|
||||
$_mailerror = false;
|
||||
try {
|
||||
$mail->SetFrom($row['adminmail'], $row['adminname']);
|
||||
$mail->Subject = $mail_subject;
|
||||
$mail->AltBody = $mail_body;
|
||||
$mail->MsgHTML(nl2br($mail_body));
|
||||
$mail->AddAddress($row['email'], $row['firstname'] . ' ' . $row['name']);
|
||||
$mail->Send();
|
||||
} catch(\PHPMailer\PHPMailer\Exception $e) {
|
||||
$mailerr_msg = $e->errorMessage();
|
||||
$_mailerror = true;
|
||||
} catch (Exception $e) {
|
||||
$mailerr_msg = $e->getMessage();
|
||||
$_mailerror = true;
|
||||
}
|
||||
|
||||
if ($_mailerror) {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_ERR, 'Error sending mail: ' . $mailerr_msg);
|
||||
echo 'Error sending mail: ' . $mailerr_msg . "\n";
|
||||
}
|
||||
|
||||
$mail->ClearAddresses();
|
||||
$upd_stmt = Database::prepare("
|
||||
UPDATE `" . TABLE_PANEL_CUSTOMERS . "` SET `reportsent` = '1'
|
||||
WHERE `customerid` = :customerid
|
||||
");
|
||||
Database::pexecute($upd_stmt, array('customerid' => $row['customerid']));
|
||||
}
|
||||
}
|
||||
|
||||
// Warn the admins at xx% traffic-usage
|
||||
$result_stmt = Database::prepare("
|
||||
SELECT `a`.*,
|
||||
(SELECT SUM(`t`.`http` + `t`.`ftp_up` + `t`.`ftp_down` + `t`.`mail`)
|
||||
FROM `" . TABLE_PANEL_TRAFFIC_ADMINS . "` `t`
|
||||
WHERE `t`.`adminid` = `a`.`adminid` AND `t`.`year` = :year AND `t`.`month` = :month
|
||||
) as `traffic_used_total`
|
||||
FROM `" . TABLE_PANEL_ADMINS . "` `a` WHERE `a`.`reportsent` = '0'
|
||||
");
|
||||
|
||||
$result_data = array(
|
||||
'year' => date("Y", $yesterday),
|
||||
'month' => date("m", $yesterday)
|
||||
);
|
||||
Database::pexecute($result_stmt, $result_data);
|
||||
|
||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
|
||||
if (isset($row['traffic'])
|
||||
&& $row['traffic'] > 0
|
||||
&& (($row['traffic_used_total'] * 100) / $row['traffic']) >= (int)Settings::Get('system.report_trafficmax')
|
||||
) {
|
||||
|
||||
$replace_arr = array(
|
||||
'NAME' => $row['name'],
|
||||
'TRAFFIC' => round(($row['traffic'] / 1024), 2), /* traffic is stored in KB, template uses MB */
|
||||
'TRAFFICUSED' => round(($row['traffic_used_total'] / 1024), 2), /* traffic is stored in KB, template uses MB */
|
||||
'USAGE_PERCENT' => round(($row['traffic_used_total'] * 100) / $row['traffic'], 2),
|
||||
'MAX_PERCENT' => Settings::Get('system.report_trafficmax')
|
||||
);
|
||||
|
||||
$lngfile_stmt = Database::prepare("
|
||||
SELECT `file` FROM `" . TABLE_PANEL_LANGUAGE . "`
|
||||
WHERE `language` = :deflang
|
||||
");
|
||||
$lngfile = Database::pexecute_first($lngfile_stmt, array('deflang' => $row['def_language']));
|
||||
|
||||
if ($lngfile !== null) {
|
||||
$langfile = $lngfile['file'];
|
||||
} else {
|
||||
$lngfile = Database::pexecute_first($lngfile_stmt, array('deflang' => Settings::Get('panel.standardlanguage')));
|
||||
$langfile = $lngfile['file'];
|
||||
}
|
||||
|
||||
// include english language file (fallback)
|
||||
include_once makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . '/lng/english.lng.php');
|
||||
// include admin/customer language file
|
||||
include_once makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . '/' . $langfile);
|
||||
|
||||
// Get mail templates from database; the ones from 'admin' are fetched for fallback
|
||||
$result2_stmt = Database::prepare("
|
||||
SELECT `value` FROM `" . TABLE_PANEL_TEMPLATES . "`
|
||||
WHERE `adminid` = :adminid
|
||||
AND `language` = :lang
|
||||
AND `templategroup` = 'mails' AND `varname` = :varname
|
||||
");
|
||||
$resul2_data = array(
|
||||
'adminid' => $row['adminid'],
|
||||
'lang' => $row['def_language'],
|
||||
'varname' => 'trafficmaxpercent_subject'
|
||||
);
|
||||
$result2 = Database::pexecute_first($result2_stmt, $result2_data);
|
||||
$mail_subject = html_entity_decode(replace_variables((($result2['value'] != '') ? $result2['value'] : $lng['mails']['trafficmaxpercent']['subject']), $replace_arr));
|
||||
|
||||
$resul2_data['varname'] = 'trafficmaxpercent_mailbody';
|
||||
$result2 = Database::pexecute_first($result2_stmt, $result2_data);
|
||||
$mail_body = html_entity_decode(replace_variables((($result2['value'] != '') ? $result2['value'] : $lng['mails']['trafficmaxpercent']['mailbody']), $replace_arr));
|
||||
|
||||
$_mailerror = false;
|
||||
try {
|
||||
$mail->SetFrom($row['email'], $row['name']);
|
||||
$mail->Subject = $mail_subject;
|
||||
$mail->AltBody = $mail_body;
|
||||
$mail->MsgHTML(nl2br($mail_body));
|
||||
$mail->AddAddress($row['email'], $row['name']);
|
||||
$mail->Send();
|
||||
} catch(\PHPMailer\PHPMailer\Exception $e) {
|
||||
$mailerr_msg = $e->errorMessage();
|
||||
$_mailerror = true;
|
||||
} catch (Exception $e) {
|
||||
$mailerr_msg = $e->getMessage();
|
||||
$_mailerror = true;
|
||||
}
|
||||
|
||||
if ($_mailerror) {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_ERR, "Error sending mail: " . $mailerr_msg);
|
||||
echo "Error sending mail: " . $mailerr_msg . "\n";
|
||||
}
|
||||
|
||||
$mail->ClearAddresses();
|
||||
$upd_stmt = Database::prepare("
|
||||
UPDATE `" . TABLE_PANEL_ADMINS . "` SET `reportsent` = '1'
|
||||
WHERE `adminid` = :adminid
|
||||
");
|
||||
Database::pexecute($upd_stmt, array('adminid' => $row['adminid']));
|
||||
}
|
||||
|
||||
// Another month, let's build our report
|
||||
if (date('d') == '01') {
|
||||
|
||||
$mail_subject = 'Trafficreport ' . date("m/y", $yesterday) . ' for ' . $row['name'];
|
||||
$mail_body = 'Trafficreport ' . date("m/y", $yesterday) . ' for ' . $row['name'] . "\n";
|
||||
$mail_body.= '---------------------------------------------------------------' . "\n";
|
||||
$mail_body.= 'Loginname Traffic used (Percent) | Traffic available' . "\n";
|
||||
$customers_stmt = Database::prepare("
|
||||
SELECT `c`.*,
|
||||
(SELECT SUM(`t`.`http` + `t`.`ftp_up` + `t`.`ftp_down` + `t`.`mail`)
|
||||
FROM `" . TABLE_PANEL_TRAFFIC . "` `t`
|
||||
WHERE `t`.`customerid` = `c`.`customerid` AND `t`.`year` = :year AND `t`.`month` = :month
|
||||
) as `traffic_used_total`
|
||||
FROM `" . TABLE_PANEL_CUSTOMERS . "` `c` WHERE `c`.`adminid` = :adminid
|
||||
");
|
||||
$customers_data = array(
|
||||
'year' => date("Y", $yesterday),
|
||||
'month' => date("m", $yesterday),
|
||||
'adminid' => $row['adminid']
|
||||
);
|
||||
Database::pexecute($customers_stmt, $customers_data);
|
||||
|
||||
while ($customer = $customers_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$t = $customer['traffic_used_total']/1048576;
|
||||
if ($customer['traffic'] > 0) {
|
||||
$p = (($customer['traffic_used_total'] * 100) / $customer['traffic'] );
|
||||
$tg = $customer['traffic']/1048576;
|
||||
$str = sprintf('%00.1f GB ( %00.1f %% )', $t, $p);
|
||||
$mail_body.= sprintf('%-15s', $customer['loginname']) . ' ' . sprintf('%-25s', $str) . ' ' . sprintf('%00.1f GB', $tg) . "\n";
|
||||
} else if ($customer['traffic'] == 0) {
|
||||
$str = sprintf('%00.1f GB ( - )', $t);
|
||||
$mail_body.= sprintf('%-15s', $customer['loginname']) . ' ' . sprintf('%-25s', $str) . ' ' . '0' . "\n";
|
||||
} else {
|
||||
$str = sprintf('%00.1f GB ( - )', $t);
|
||||
$mail_body.= sprintf('%-15s', $customer['loginname']) . ' ' . sprintf('%-25s', $str) . ' ' . 'unlimited' . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
$mail_body.= '---------------------------------------------------------------' . "\n";
|
||||
|
||||
$t = $row['traffic_used_total']/1048576;
|
||||
if ($row['traffic'] > 0) {
|
||||
$p = (($row['traffic_used_total'] * 100) / $row['traffic']);
|
||||
$tg = $row['traffic']/1048576;
|
||||
$str = sprintf('%00.1f GB ( %00.1f %% )', $t, $p);
|
||||
$mail_body.= sprintf('%-15s', $row['loginname']) . ' ' . sprintf('%-25s', $str) . ' ' . sprintf('%00.1f GB', $tg) . "\n";
|
||||
} else if ($row['traffic'] == 0) {
|
||||
$str = sprintf('%00.1f GB ( - )', $t);
|
||||
$mail_body.= sprintf('%-15s', $row['loginname']) . ' ' . sprintf('%-25s', $str) . ' ' . '0' . "\n";
|
||||
} else {
|
||||
$str = sprintf('%00.1f GB ( - )', $t);
|
||||
$mail_body.= sprintf('%-15s', $row['loginname']) . ' ' . sprintf('%-25s', $str) . ' ' . 'unlimited' . "\n";
|
||||
}
|
||||
|
||||
$_mailerror = false;
|
||||
try {
|
||||
$mail->SetFrom($row['email'], $row['name']);
|
||||
$mail->Subject = $mail_subject;
|
||||
$mail->Body = $mail_body;
|
||||
$mail->AddAddress($row['email'], $row['name']);
|
||||
$mail->Send();
|
||||
} catch(\PHPMailer\PHPMailer\Exception $e) {
|
||||
$mailerr_msg = $e->errorMessage();
|
||||
$_mailerror = true;
|
||||
} catch (Exception $e) {
|
||||
$mailerr_msg = $e->getMessage();
|
||||
$_mailerror = true;
|
||||
}
|
||||
|
||||
if ($_mailerror) {
|
||||
$cronlog->logAction(CRON_ACTION, LOG_ERR, 'Error sending mail: ' . $mailerr_msg);
|
||||
echo 'Error sending mail: ' . $mailerr_msg . "\n";
|
||||
}
|
||||
|
||||
$mail->ClearAddresses();
|
||||
}
|
||||
}
|
||||
} // trafficmax > 0
|
||||
|
||||
// include diskspace-usage report, #466
|
||||
include dirname(__FILE__).'/cron_usage.inc.diskspace.php';
|
||||
|
||||
// Another month, reset the reportstatus
|
||||
if (date('d') == '01') {
|
||||
Database::query("UPDATE `" . TABLE_PANEL_CUSTOMERS . "` SET `reportsent` = '0';");
|
||||
Database::query("UPDATE `" . TABLE_PANEL_ADMINS . "` SET `reportsent` = '0';");
|
||||
}
|
||||
Reference in New Issue
Block a user