diff --git a/install/dist/lib/fedora.lib.php b/install/dist/lib/fedora.lib.php index 9ffc7d0ef4fea39a70ff8fde2a893f070c23044a..0cf2141f72ad6c4c478ab8c1fc4982386591ce75 100644 --- a/install/dist/lib/fedora.lib.php +++ b/install/dist/lib/fedora.lib.php @@ -121,12 +121,6 @@ class installer_dist extends installer_base { $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/postfix-'.$filename.'.master', 'tpl/postfix-'.$filename.'.master'); wf($full_file_name, $content); - //* Changing mode and group of the new created config files. - caselog('chmod o= '.$config_dir.'/mysql-virtual_*.cf* &> /dev/null', - __FILE__, __LINE__, 'chmod on mysql-virtual_*.cf*', 'chmod on mysql-virtual_*.cf* failed'); - caselog('chgrp '.$cf['group'].' '.$config_dir.'/mysql-virtual_*.cf* &> /dev/null', - __FILE__, __LINE__, 'chgrp on mysql-virtual_*.cf*', 'chgrp on mysql-virtual_*.cf* failed'); - //* Creating virtual mail user and group $command = 'groupadd -g '.$cf['vmail_groupid'].' '.$cf['vmail_groupname']; if(!is_group($cf['vmail_groupname'])) caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command"); diff --git a/install/dist/lib/opensuse.lib.php b/install/dist/lib/opensuse.lib.php index 15ab5b6e91c7dded34c8a5285d5a87424a4b474e..1401614c3fd2b4c1dc3a8b6ddf687c50638fc342 100644 --- a/install/dist/lib/opensuse.lib.php +++ b/install/dist/lib/opensuse.lib.php @@ -118,12 +118,6 @@ class installer_dist extends installer_base { $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/postfix-'.$filename.'.master', 'tpl/postfix-'.$filename.'.master'); wf($full_file_name, $content); - //* Changing mode and group of the new created config files. - caselog('chmod o= '.$config_dir.'/mysql-virtual_*.cf* &> /dev/null', - __FILE__, __LINE__, 'chmod on mysql-virtual_*.cf*', 'chmod on mysql-virtual_*.cf* failed'); - caselog('chgrp '.$cf['group'].' '.$config_dir.'/mysql-virtual_*.cf* &> /dev/null', - __FILE__, __LINE__, 'chgrp on mysql-virtual_*.cf*', 'chgrp on mysql-virtual_*.cf* failed'); - if(!is_dir($cf['vmail_mailbox_base'])) mkdir($cf['vmail_mailbox_base']); //* Creating virtual mail user and group diff --git a/install/lib/installer_base.lib.php b/install/lib/installer_base.lib.php index 2121eadeb13e6736d857acd6508a4b92fcb81286..10533dd66f9bed87df51632425cf988649aaa8d5 100644 --- a/install/lib/installer_base.lib.php +++ b/install/lib/installer_base.lib.php @@ -737,11 +737,16 @@ class installer_base { global $conf; $config_dir = $conf['postfix']['config_dir'].'/'; + $postfix_group = $conf['postfix']['group']; $full_file_name = $config_dir.$configfile; + //* Backup exiting file if(is_file($full_file_name)) { copy($full_file_name, $config_dir.$configfile.'~'); + chmod($config_dir.$configfile.'~',0600); } + + //* Replace variables in config file template $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/'.$configfile.'.master', 'tpl/'.$configfile.'.master'); $content = str_replace('{mysql_server_ispconfig_user}', $conf['mysql']['ispconfig_user'], $content); $content = str_replace('{mysql_server_ispconfig_password}', $conf['mysql']['ispconfig_password'], $content); @@ -749,6 +754,13 @@ class installer_base { $content = str_replace('{mysql_server_ip}', $conf['mysql']['ip'], $content); $content = str_replace('{server_id}', $conf['server_id'], $content); wf($full_file_name, $content); + + //* Changing mode and group of the new created config file + caselog('chmod u=rw,g=r,o= '.escapeshellarg($full_file_name).' &> /dev/null', + __FILE__, __LINE__, 'chmod on '.$full_file_name, 'chmod on '.$full_file_name.' failed'); + caselog('chgrp '.escapeshellarg($postfix_group).' '.escapeshellarg($full_file_name).' &> /dev/null', + __FILE__, __LINE__, 'chgrp on '.$full_file_name, 'chgrp on '.$full_file_name.' failed'); + } public function configure_jailkit() { @@ -1028,12 +1040,6 @@ class installer_base { } wf($full_file_name, $content); - //* Changing mode and group of the new created config files. - caselog('chmod u=rw,g=r,o= '.$config_dir.'/mysql-virtual_*.cf* &> /dev/null', - __FILE__, __LINE__, 'chmod on mysql-virtual_*.cf*', 'chmod on mysql-virtual_*.cf* failed'); - caselog('chgrp '.$cf['group'].' '.$config_dir.'/mysql-virtual_*.cf* &> /dev/null', - __FILE__, __LINE__, 'chgrp on mysql-virtual_*.cf*', 'chgrp on mysql-virtual_*.cf* failed'); - //* Creating virtual mail user and group $command = 'groupadd -g '.$cf['vmail_groupid'].' '.$cf['vmail_groupname']; if(!is_group($cf['vmail_groupname'])) caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command"); diff --git a/interface/web/admin/directive_snippets_edit.php b/interface/web/admin/directive_snippets_edit.php index af700213a47dfca1cce592c4f7d898a0a98c572a..e22a7cf42a2d7903121f6c87873c19a06f93a71f 100644 --- a/interface/web/admin/directive_snippets_edit.php +++ b/interface/web/admin/directive_snippets_edit.php @@ -77,9 +77,6 @@ class page_action extends tform_actions { } $app->tpl->setVar("is_master", $is_master); - - if($this->dataRecord['managed_snippet_id'] > 0) { - } parent::onShowEnd(); } diff --git a/interface/web/dashboard/dashlets/mailquota.php b/interface/web/dashboard/dashlets/mailquota.php index 4629d6a4630c23bea7fe6d71a3846ca76667da6d..a9434e58eaac846087c77738d9d131ebe4d51abe 100644 --- a/interface/web/dashboard/dashlets/mailquota.php +++ b/interface/web/dashboard/dashlets/mailquota.php @@ -21,13 +21,17 @@ class dashlet_mailquota { $has_mailquota = false; if(is_array($emails) && !empty($emails)){ + foreach($emails as &$email) { + $email['email'] = $app->functions->idn_decode($email['email']); + } + unset($email); // email username is quoted in quota.lib already, so no htmlentities here to prevent double encoding //$emails = $app->functions->htmlentities($emails); $tpl->setloop('mailquota', $emails); $has_mailquota = isset($emails[0]['used']); } $tpl->setVar('has_mailquota', $has_mailquota); - + return $tpl->grab(); } diff --git a/interface/web/dashboard/dashlets/quota.php b/interface/web/dashboard/dashlets/quota.php index dfb82d5c242bbe6ad8699e97db26855e1d378829..3fd5adbb85c5843bd51646304cb071f54f1eda33 100644 --- a/interface/web/dashboard/dashlets/quota.php +++ b/interface/web/dashboard/dashlets/quota.php @@ -7,9 +7,9 @@ class dashlet_quota { //* Loading Template $app->uses('tpl,quota_lib'); - if (!$app->auth->verify_module_permissions('sites')) { - return; - } + if (!$app->auth->verify_module_permissions('sites')) { + return; + } $tpl = new tpl; $tpl->newTemplate("dashlets/templates/quota.htm"); @@ -24,6 +24,11 @@ class dashlet_quota { $has_quota = false; if(is_array($sites) && !empty($sites)){ + foreach($sites as &$site) { + $site['domain'] = $app->functions->idn_decode($site['domain']); + } + unset($site); + $sites = $app->functions->htmlentities($sites); $tpl->setloop('quota', $sites); $has_quota = isset($sites[0]['used']); diff --git a/interface/web/sites/form/web_vhost_domain.tform.php b/interface/web/sites/form/web_vhost_domain.tform.php index 6031b7ea943a91a7a951f824defcaf067e87aa21..eecb634c989be6e610e56784a9cb0b1afa4b7178 100644 --- a/interface/web/sites/form/web_vhost_domain.tform.php +++ b/interface/web/sites/form/web_vhost_domain.tform.php @@ -629,7 +629,7 @@ $form["tabs"]['stats'] = array ( 'datatype' => 'VARCHAR', 'formtype' => 'SELECT', 'default' => 'awstats', - 'value' => array('webalizer' => 'Webalizer', 'awstats' => 'AWStats', '' => 'None') + 'value' => array('awstats' => 'AWStats', 'goaccess' => 'GoAccess', 'webalizer' => 'Webalizer','' => 'None') ), //################################# // END Datatable fields diff --git a/interface/web/tools/form/user_settings.tform.php b/interface/web/tools/form/user_settings.tform.php index a696d7533944348113cf550ab9265b7fb31a8eda..f063634b0ccf96ed6222acb33274c81b7dbd9ea2 100644 --- a/interface/web/tools/form/user_settings.tform.php +++ b/interface/web/tools/form/user_settings.tform.php @@ -68,7 +68,7 @@ $form['db_table'] = 'sys_user'; $form['db_table_idx'] = 'userid'; $form["db_history"] = "no"; $form['tab_default'] = 'users'; -$form['list_default'] = 'index.php'; +$form['list_default'] = 'user_settings.php'; $form['auth'] = 'no'; //* 0 = id of the user, > 0 id must match with id of current user diff --git a/server/conf/awstats_index.php.master b/server/conf/awstats_index.php.master index f7222c968721c87da286dc0ec937e25346bd58cc..b3e694ebbf3441038b45508f8e1e1624c3a0f481 100644 --- a/server/conf/awstats_index.php.master +++ b/server/conf/awstats_index.php.master @@ -45,10 +45,21 @@ arsort($awprev); $options = ""; foreach ($awprev as $key => $value) { + + if(file_exists($value.'/awsindex.html') && file_exists($value.'/goaindex.html')) { + $awstatsindex = 'awsindex.html'; + } elseif(file_exists($value.'/awsindex.html') && !file_exists($value.'/goaindex.html')) { + $awstatsindex = 'awsindex.html'; + } else { + $awstatsindex = 'goaindex.html'; + } + if($key == $current) $options .= "<option selected=\"selected\" value=\"{$awstatsindex}\">{$value}</option>\n"; else $options .= "<option value=\"{$value}/{$awstatsindex}\">{$value}</option>\n"; } +$awstatsindex = 'awsindex.html'; + $html = "<!DOCTYPE html>\n<html>\n<head>\n<title>Stats</title>\n"; $html .= "<style>\nhtml,body {margin:0px;padding:0px;width:100%;height:100%;background-color: #ccc;}\n"; $html .= "#header\n{\nwidth:100%;margin:0px auto;\nheight:20px;\nposition:fixed;\npadding:4px;\ntext-align:center;\n}\n"; @@ -60,4 +71,4 @@ $html .= $options; $html .= "</select>\n</div>\n<iframe src=\"{$awstatsindex}\" id=\"content\"></iframe>\n"; $html .= "</body></html>"; echo $html; -?> \ No newline at end of file +?> diff --git a/server/conf/goaccess_index.php.master b/server/conf/goaccess_index.php.master new file mode 100644 index 0000000000000000000000000000000000000000..d0a8bf3c84a39a3e1cab901fef8f64f674a37315 --- /dev/null +++ b/server/conf/goaccess_index.php.master @@ -0,0 +1,73 @@ +<?php +$yearmonth_text = "Jump to previous stats: "; +$script = "<script>function load_content(url){var iframe = document.getElementById(\"content\");iframe.src = url;}</script>\n"; + +if ($handle = opendir('.')) +{ + while(false !== ($file = readdir($handle))) + { + if (substr($file,0,1) != "." && is_dir($file)) + { + $orderkey = substr($file,0,4).substr($file,5,2); + if (substr($file,5,2) < 10 ) + { + $orderkey = substr($file,0,4)."0".substr($file,5,2); + } + $goaprev[$orderkey] = $file; + } + } + + $month = date("n"); + $year = date("Y"); + + if (date("d") == 1) + { + $month = date("m")-1; + if (date("m") == 1) + { + $year = date("Y")-1; + $month = "12"; + } + } + + $current = $year.$month; + if ( $month < 10 ) { + $current = $year."0".$month; + } + $goaprev[$current] = $year."-".$month; + + closedir($handle); +} + +arsort($goaprev); + +$options = ""; +foreach ($goaprev as $key => $value) +{ + + if(file_exists($value.'/awsindex.html') && file_exists($value.'/goaindex.html')) { + $goaccessindex = 'goaindex.html'; + } elseif(file_exists($value.'/awsindex.html') && !file_exists($value.'/goaindex.html')) { + $goaccessindex = 'awsindex.html'; + } else { + $goaccessindex = 'goaindex.html'; + } + + if($key == $current) $options .= "<option selected=\"selected\" value=\"{$goaccessindex}\">{$value}</option>\n"; + else $options .= "<option value=\"{$value}/{$goaccessindex}\">{$value}</option>\n"; + +} +$goaccessindex = 'goaindex.html'; + +$html = "<!DOCTYPE html>\n<html>\n<head>\n<title>Stats</title>\n"; +$html .= "<style>\nhtml,body {margin:0px;padding:0px;width:100%;height:100%;background-color: #ccc;}\n"; +$html .= "#header\n{\nwidth:100%;margin:0px auto;\nheight:20px;\nposition:fixed;\npadding:4px;\ntext-align:center;\n}\n"; +$html .= "iframe {width:100%;height:95%;margin:0px;margin-top:40px;border:0px;padding:0px;}\n</style>\n</head>\n<body>\n"; +$html .= $script; +$html .= "<div id=\"header\">{$yearmonth_text}\n"; +$html .= "<select name=\"goadate\" onchange=\"load_content(this.value)\">\n"; +$html .= $options; +$html .= "</select>\n</div>\n<iframe src=\"{$goaccessindex}\" id=\"content\"></iframe>\n"; +$html .= "</body></html>"; +echo $html; +?> diff --git a/server/lib/classes/cron.d/150-goaccess.inc.php b/server/lib/classes/cron.d/150-goaccess.inc.php new file mode 100644 index 0000000000000000000000000000000000000000..8c9d7644420490272e36578cc933f8f883073fa2 --- /dev/null +++ b/server/lib/classes/cron.d/150-goaccess.inc.php @@ -0,0 +1,254 @@ +<?php + +/* +Copyright (c) 2013, Marius Cramer, pixcept KG +Copyright (c) 2020, Michael Seevogel +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of ISPConfig nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +class cronjob_goaccess extends cronjob { + + // job schedule + protected $_schedule = '0 0 * * *'; + + /* this function is optional if it contains no custom code */ + public function onPrepare() { + global $app; + + parent::onPrepare(); + } + + /* this function is optional if it contains no custom code */ + public function onBeforeRun() { + global $app; + + return parent::onBeforeRun(); + } + + public function onRunJob() { + global $app, $conf; + + + //###################################################################################################### + // Create goaccess statistics + //###################################################################################################### + + $sql = "SELECT domain_id, domain, document_root, web_folder, type, system_user, system_group, parent_domain_id FROM web_domain WHERE (type = 'vhost' or type = 'vhostsubdomain' or type = 'vhostalias') and stats_type = 'goaccess' AND server_id = ?"; + $records = $app->db->queryAllRecords($sql, $conf['server_id']); + + $web_config = $app->getconf->get_server_config($conf['server_id'], 'web'); + + $goaccess_conf_locs = array('/etc/goaccess.conf', '/etc/goaccess/goaccess.conf'); + $count = 0; + + foreach($goaccess_conf_locs as $goa_loc) { + if(is_file($goa_loc) && (filesize($goa_loc) > 0)) { + $goaccess_conf_main = $goa_loc; + break; + } else { + $count++; + if($count == 2) { + $app->log("No GoAccess base config found. Make sure that GoAccess is installed and that the goaccess.conf does exist in /etc or /etc/goaccess", LOGLEVEL_ERROR); + } + } + } + + + /* Check if goaccess binary is in path */ + system("type goaccess 2>&1>/dev/null", $retval); + if ($retval === 0) { + + foreach($records as $rec) { + $yesterday = date('Ymd', strtotime("-1 day", time())); + + $log_folder = 'log'; + + if($rec['type'] == 'vhostsubdomain' || $rec['type'] == 'vhostalias') { + $tmp = $app->db->queryOneRecord('SELECT `domain` FROM web_domain WHERE domain_id = ?', $rec['parent_domain_id']); + $subdomain_host = preg_replace('/^(.*)\.' . preg_quote($tmp['domain'], '/') . '$/', '$1', $rec['domain']); + if($subdomain_host == '') $subdomain_host = 'web'.$rec['domain_id']; + $log_folder .= '/' . $subdomain_host; + unset($tmp); + } + + $logfile = $rec['document_root'].'/' . $log_folder . '/'.$yesterday.'-access.log'; + + if(!@is_file($logfile)) { + $logfile = $rec['document_root'].'/' . $log_folder . '/'.$yesterday.'-access.log.gz'; + if(!@is_file($logfile)) { + continue; + } + } + + $web_folder = (($rec['type'] == 'vhostsubdomain' || $rec['type'] == 'vhostalias') ? $rec['web_folder'] : 'web'); + $domain = $rec['domain']; + $statsdir = $rec['document_root'].'/'.$web_folder.'/stats'; + $goaccess_conf = $rec['document_root'].'/log/goaccess.conf'; + + /* + In case that you use a different log format, you should use a custom goaccess.conf which you'll have to put into /usr/local/ispconfig/server/conf-custom/. + By default the originally, with GoAccess shipped goaccess.conf from /etc/ or /etc/goaccess will be used along with the log-format value COMBINED. + */ + + if(file_exists("/usr/local/ispconfig/server/conf-custom/goaccess.conf.master") && (!file_exists($goaccess_conf))) { + $app->system->copy("/usr/local/ispconfig/server/conf-custom/goaccess.conf.master", $goaccess_conf); + } elseif(!file_exists($goaccess_conf)) { + /* + By default the goaccess.conf should get copied by the webserver plugin but in case it wasn't, or it got deleted by accident we gonna copy it again to the destination dir. + Also there was no /usr/local/ispconfig/server/conf-custom/goaccess.conf.master, so we gonna use /etc/goaccess.conf as the base conf. + */ + + $app->system->copy($goaccess_conf_main, $goaccess_conf); + $content = $app->system->file_get_contents($goaccess_conf, true); + $content = preg_replace('/^(#)?log-format COMBINED/m', "log-format COMBINED", $content); + $app->system->file_put_contents($goaccess_conf, $content, true); + unset($content); + } + + /* Update the primary domain name in the title, it could occasionally change */ + if(is_file($goaccess_conf) && (filesize($goaccess_conf) > 0)) { + $content = $app->system->file_get_contents($goaccess_conf, true); + $content = preg_replace('/^(#)?html-report-title(.*)/m', "html-report-title $domain", $content); + $app->system->file_put_contents($goaccess_conf, $content, true); + unset($content); + } + + $username = $rec['system_user']; + $groupname = $rec['system_group']; + $docroot = $rec['document_root']; + + if(!@is_dir($statsdir)) $app->system->mkdirpath($statsdir, 0755, $username, $groupname); + + $goa_db_dir = $docroot.'/'.$web_folder.'/stats/.db/'; + $output_html = $docroot.'/'.$web_folder.'/stats/goaindex.html'; + if(!@is_dir($goa_db_dir)) $app->system->mkdirpath($goa_db_dir); + + if(is_link('/var/log/ispconfig/httpd/'.$domain.'/yesterday-access.log')) $app->system->unlink('/var/log/ispconfig/httpd/'.$domain.'/yesterday-access.log'); + symlink($logfile, '/var/log/ispconfig/httpd/'.$domain.'/yesterday-access.log'); + + + $app->system->exec_safe('chown -R ?:? ?', $username, $groupname, $statsdir); + + $goamonth = date("n"); + $goayear = date("Y"); + + if (date("d") == 1) { + $goamonth = date("m")-1; + if (date("m") == 1) { + $goayear = date("Y")-1; + $goamonth = "12"; + } + } + + if (date("d") == 2) { + $goamonth = date("m")-1; + if (date("m") == 1) { + $goayear = date("Y")-1; + $goamonth = "12"; + } + + $statsdirold = $statsdir."/".$goayear."-".$goamonth."/"; + + if(!is_dir($statsdirold)) { + $app->system->mkdirpath($statsdirold, 0755, $username, $groupname); + } + + // don't rotate db files per month + //rename($goa_db_dir, $statsdirold.'db'); + //mkdir($goa_db_dir); + + $files = scandir($statsdir); + + foreach ($files as $file) { + if (substr($file, 0, 1) != "." && !is_dir("$statsdir"."/"."$file") && substr($file, 0, 1) != "w" && substr($file, 0, 1) != "i") $app->system->copy("$statsdir"."/"."$file", "$statsdirold"."$file"); + } + } + + // Get the GoAccess version + $match = array(); + + $goaccess_version = $app->system->system_safe('goaccess --version 2>&1'); + + if(preg_match('/[0-9]\.[0-9]{1,2}/', $goaccess_version, $match)) { + $goaccess_version = $match[0]; + } + + + /* + * GoAccess removed with 1.4 btree support and supports from this version on only "In-Memory with On-Disk Persitance Storage". + * For versions prior 1.4 you need GoAccess with btree support compiled! + */ + + $cust_lang = $conf['language']."_".strtoupper($conf['language']); + + if(version_compare($goaccess_version,1.4) >= 0) { + $app->system->exec_safe("LANG=? goaccess -f ? --config-file ? --restore --persist --db-path=? --output=?", $cust_lang, $logfile, $goaccess_conf, $goa_db_dir, $output_html); + } else { + $output = $app->system->system_safe('goaccess --help 2>&1'); + preg_match('/keep-db-files/', $output, $match); + if($match[0] == "keep-db-files") { + $app->system->exec_safe("LANG=? goaccess -f ? --config-file ? --load-from-disk --keep-db-files --db-path=? --output=?", $cust_lang, $logfile, $goaccess_conf, $goa_db_dir, $output_html); + } else { + $app->log("Stats not generated. The GoAccess binary was not compiled with btree support. Please recompile/reinstall GoAccess with btree support, or install GoAccess version >= 1.4!", LOGLEVEL_ERROR); + } + unset($output); + } + unset($cust_lang); + + if(!is_file($rec['document_root']."/".$web_folder."/stats/index.php")) { + if(file_exists("/usr/local/ispconfig/server/conf-custom/goaccess_index.php.master")) { + $app->system->copy("/usr/local/ispconfig/server/conf-custom/goaccess_index.php.master", $rec['document_root']."/".$web_folder."/stats/index.php"); + } else { + $app->system->copy("/usr/local/ispconfig/server/conf/goaccess_index.php.master", $rec['document_root']."/".$web_folder."/stats/index.php"); + } + } + + $app->log('Created GoAccess statistics for ' . $domain, LOGLEVEL_DEBUG); + if(is_file($rec['document_root']."/".$web_folder."/stats/index.php")) { + chown($rec['document_root']."/".$web_folder."/stats/index.php", $rec['system_user']); + chgrp($rec['document_root']."/".$web_folder."/stats/index.php", $rec['system_group']); + } + + $app->system->exec_safe('chown -R ?:? ?', $username, $groupname, $statsdir); + } + + } else { + $app->log("Stats not generated. The GoAccess binary couldn't be found. Make sure that GoAccess is installed and that it is in \$PATH", LOGLEVEL_ERROR); + } + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/150-webalizer.inc.php b/server/lib/classes/cron.d/150-webalizer.inc.php index 42aa125e0f9b427883196bf2d511e25a3ad6d182..6c68cef183a6bcad8532bc5cbb13edcf01201800 100644 --- a/server/lib/classes/cron.d/150-webalizer.inc.php +++ b/server/lib/classes/cron.d/150-webalizer.inc.php @@ -127,8 +127,8 @@ class cronjob_webalizer extends cronjob { chown($statsdir, $username); chgrp($statsdir, $groupname); $app->system->exec_safe("$webalizer -c ? -n ? -s ? -r ? -q -T -p -o ? ?", $webalizer_conf, $domain, $domain, $domain, $statsdir, $logfile); - - exec('chown -R ?:? ?', $username, $groupname, $statsdir); + + $app->system->exec_safe('chown -R ?:? ?', $username, $groupname, $statsdir); } diff --git a/server/plugins-available/apache2_plugin.inc.php b/server/plugins-available/apache2_plugin.inc.php index 3ef5e21467f5c98c2ab901e1f0a3bc14f3cb037d..82340587140d9b8c8cc550c9157677adf1cd4889 100644 --- a/server/plugins-available/apache2_plugin.inc.php +++ b/server/plugins-available/apache2_plugin.inc.php @@ -107,7 +107,7 @@ class apache2_plugin { $affected_snippets = $app->db->queryAllRecords('SELECT directive_snippets_id FROM directive_snippets WHERE required_php_snippets RLIKE(?) AND type = ?', $rlike, 'apache'); if(is_array($affected_snippets) && !empty($affected_snippets)) { foreach($affected_snippets as $snippet) $sql_in[] = $snippet['directive_snippets_id']; - $affected_sites = $app->db->queryAllRecords('SELECT domain_id FROM web_domain WHERE server_id = ? AND directive_snippets_id IN('.implode(',', $sql_in).')', $conf['server_id']); + $affected_sites = $app->db->queryAllRecords('SELECT domain_id FROM web_domain WHERE server_id = ? AND directive_snippets_id IN ?', $conf['server_id'], $sql_in); } } if($snippet['type'] == 'apache') $affected_sites = $app->db->queryAllRecords('SELECT domain_id FROM web_domain WHERE server_id = ? AND directive_snippets_id = ?', $conf['server_id'], $snippet['directive_snippets_id']); @@ -1915,6 +1915,11 @@ class apache2_plugin { $this->awstats_update($data, $web_config); } + //* Create GoAccess configuration + if($data['new']['stats_type'] == 'goaccess' && ($data['new']['type'] == 'vhost' || $data['new']['type'] == 'vhostsubdomain' || $data['new']['type'] == 'vhostalias')) { + $this->goaccess_update($data, $web_config); + } + //* Remove Stats-Folder when Statistics set to none if($data['new']['stats_type'] == '' && ($data['new']['type'] == 'vhost' || $data['new']['type'] == 'vhostsubdomain' || $data['new']['type'] == 'vhostalias')) { $app->file->removeDirectory($data['new']['document_root'].'/web/stats'); @@ -2328,6 +2333,11 @@ class apache2_plugin { $this->awstats_delete($data, $web_config); } + //* Remove the GoAccess configuration file + if($data['old']['stats_type'] == 'goaccess') { + $this->goaccess_delete($data, $web_config); + } + if($data['old']['type'] == 'vhostsubdomain' || $data['old']['type'] == 'vhostalias') { $app->system->web_folder_protection($parent_web_document_root, true); } @@ -3025,15 +3035,96 @@ class apache2_plugin { } } - //* Delete the awstats configuration file - private function awstats_delete ($data, $web_config) { + //* Delete the awstats configuration file + private function awstats_delete ($data, $web_config) { + global $app; + + $awstats_conf_dir = $web_config['awstats_conf_dir']; + + if ( @is_file($awstats_conf_dir.'/awstats.'.$data['old']['domain'].'.conf') ) { + $app->system->unlink($awstats_conf_dir.'/awstats.'.$data['old']['domain'].'.conf'); + $app->log('Removed AWStats config file: '.$awstats_conf_dir.'/awstats.'.$data['old']['domain'].'.conf', LOGLEVEL_DEBUG); + } + } + + //* Update the GoAccess configuration file + private function goaccess_update ($data, $web_config) { + global $app; + + $web_folder = $data['new']['web_folder']; + if($data['new']['type'] == 'vhost') $web_folder = 'web'; + + $goaccess_conf_locs = array('/etc/goaccess.conf', '/etc/goaccess/goaccess.conf'); + $count = 0; + + foreach($goaccess_conf_locs as $goa_loc) { + if(is_file($goa_loc) && (filesize($goa_loc) > 0)) { + $goaccess_conf_main = $goa_loc; + break; + } else { + $count++; + if($count == 2) { + $app->log("No GoAccess base config found. Make sure that GoAccess is installed and that the goaccess.conf does exist in /etc or /etc/goaccess", LOGLEVEL_WARN); + } + } + } + + if(!is_dir($data['new']['document_root']."/" . $web_folder . "/stats/.db")) $app->system->mkdirpath($data['new']['document_root'] . "/" . $web_folder . "/stats/.db"); + $goaccess_conf = $data['new']['document_root'].'/log/goaccess.conf'; + + /* + In case that you use a different log format, you should use a custom goaccess.conf which you'll have to put into /usr/local/ispconfig/server/conf-custom/. + By default the originaly with GoAccess shipped goaccess.conf from /etc/ will be used along with the log-format value COMBINED. + */ + + if(file_exists("/usr/local/ispconfig/server/conf-custom/goaccess.conf.master")) { + $app->system->copy("/usr/local/ispconfig/server/conf-custom/goaccess_index.php.master", $goaccess_conf); + + } elseif(!file_exists($goaccess_conf)) { + + /* + By default the goaccess.conf should get copied by the webserver plugin but in case it wasn't, or it got deleted by accident we gonna copy it again to the destination dir. + Also there was no /usr/local/ispconfig/server/conf-custom/goaccess.conf.master, so we gonna use /etc/goaccess.conf as the base conf. + */ + + $app->system->copy($goaccess_conf_main, $goaccess_conf); + $content = $app->system->file_get_contents($goaccess_conf, true); + $content = preg_replace('/^(#)?log-format COMBINED/m', "log-format COMBINED", $content); + $app->system->file_put_contents($goaccess_conf, $content, true); + unset($content); + + } + + if(file_exists($goaccess_conf)) { + $domain = $data['new']['domain']; + $content = $app->system->file_get_contents($goaccess_conf, true); + $content = preg_replace('/^(#)?html-report-title(.*)/m', "html-report-title $domain", $content); + $app->system->file_put_contents($goaccess_conf, $content, true); + unset($content); + + } + + if(is_file($goaccess_conf) && (filesize($goaccess_conf) > 0)) { + $app->log('Created GoAccess config file: '.$goaccess_conf, LOGLEVEL_DEBUG); + } + + if(is_file($data['new']['document_root']."/" . $web_folder . "/stats/index.html")) $app->system->unlink($data['new']['document_root']."/" . $web_folder . "/stats/index.html"); + if(file_exists("/usr/local/ispconfig/server/conf-custom/goaccess_index.php.master")) { + $app->system->copy("/usr/local/ispconfig/server/conf-custom/goaccess_index.php.master", $data['new']['document_root']."/" . $web_folder . "/stats/index.php"); + } else { + $app->system->copy("/usr/local/ispconfig/server/conf/goaccess_index.php.master", $data['new']['document_root']."/" . $web_folder . "/stats/index.php"); + } + } + + //* Delete the GoAccess configuration file + private function goaccess_delete ($data, $web_config) { global $app; - $awstats_conf_dir = $web_config['awstats_conf_dir']; + $goaccess_conf = $data['old']['document_root'] . "/log/goaccess.conf"; - if ( @is_file($awstats_conf_dir.'/awstats.'.$data['old']['domain'].'.conf') ) { - $app->system->unlink($awstats_conf_dir.'/awstats.'.$data['old']['domain'].'.conf'); - $app->log('Removed AWStats config file: '.$awstats_conf_dir.'/awstats.'.$data['old']['domain'].'.conf', LOGLEVEL_DEBUG); + if ( @is_file($goaccess_conf) ) { + $app->system->unlink($goaccess_conf); + $app->log('Removed GoAccess config file: '.$goaccess_conf, LOGLEVEL_DEBUG); } } diff --git a/server/plugins-available/nginx_plugin.inc.php b/server/plugins-available/nginx_plugin.inc.php index 85661b97ce2a7aac4ff911b1d4fffc86077a9ded..6483df4eb99555599963ae66254c8b946fa500ea 100644 --- a/server/plugins-available/nginx_plugin.inc.php +++ b/server/plugins-available/nginx_plugin.inc.php @@ -103,7 +103,7 @@ class nginx_plugin { $affected_snippets = $app->db->queryAllRecords('SELECT directive_snippets_id FROM directive_snippets WHERE required_php_snippets RLIKE(?) AND type = ?', $rlike, 'nginx'); if(is_array($affected_snippets) && !empty($affected_snippets)) { foreach($affected_snippets as $snippet) $sql_in[] = $snippet['directive_snippets_id']; - $affected_sites = $app->db->queryAllRecords('SELECT domain_id FROM web_domain WHERE server_id = ? AND directive_snippets_id IN('.implode(',', $sql_in).')', $conf['server_id']); + $affected_sites = $app->db->queryAllRecords('SELECT domain_id FROM web_domain WHERE server_id = ? AND directive_snippets_id IN ?', $conf['server_id'], $sql_in); } } if($snippet['type'] == 'nginx') $affected_sites = $app->db->queryAllRecords('SELECT domain_id FROM web_domain WHERE server_id = ? AND directive_snippets_id = ?', $conf['server_id'], $snippet['directive_snippets_id']); @@ -1934,6 +1934,11 @@ class nginx_plugin { $this->awstats_update($data, $web_config); } + //* Create GoAccess configuration + if($data['new']['stats_type'] == 'goaccess' && ($data['new']['type'] == 'vhost' || $data['new']['type'] == 'vhostsubdomain' || $data['new']['type'] == 'vhostalias')) { + $this->goaccess_update($data, $web_config); + } + //* Remove Stats-Folder when Statistics set to none if($data['new']['stats_type'] == '' && ($data['new']['type'] == 'vhost' || $data['new']['type'] == 'vhostsubdomain' || $data['new']['type'] == 'vhostalias')) { $app->file->removeDirectory($data['new']['document_root'].'/web/stats'); @@ -2320,6 +2325,11 @@ class nginx_plugin { $this->awstats_delete($data, $web_config); } + //* Remove the GoAccess configuration file + if($data['old']['stats_type'] == 'goaccess') { + $this->goaccess_delete($data, $web_config); + } + //* Delete the web-backups if($data['old']['type'] == 'vhost') { $server_config = $app->getconf->get_server_config($conf['server_id'], 'server'); @@ -2560,6 +2570,89 @@ class nginx_plugin { //$app->services->restartServiceDelayed('httpd','reload'); } + + + //* Update the GoAccess configuration file + private function goaccess_update ($data, $web_config) { + global $app; + + $web_folder = $data['new']['web_folder']; + if($data['new']['type'] == 'vhost') $web_folder = 'web'; + + $goaccess_conf_locs = array('/etc/goaccess.conf', '/etc/goaccess/goaccess.conf'); + $count = 0; + + foreach($goaccess_conf_locs as $goa_loc) { + if(is_file($goa_loc) && (filesize($goa_loc) > 0)) { + $goaccess_conf_main = $goa_loc; + break; + } else { + $count++; + if($count == 2) { + $app->log("No GoAccess base config found. Make sure that GoAccess is installed and that the goaccess.conf does exist in /etc or /etc/goaccess", LOGLEVEL_WARN); + } + } + } + + if(!is_dir($data['new']['document_root']."/" . $web_folder . "/stats/.db")) $app->system->mkdirpath($data['new']['document_root'] . "/" . $web_folder . "/stats/.db"); + $goaccess_conf = $data['new']['document_root'].'/log/goaccess.conf'; + + /* + In case that you use a different log format, you should use a custom goaccess.conf which you'll have to put into /usr/local/ispconfig/server/conf-custom/. + By default the originaly with GoAccess shipped goaccess.conf from /etc/ will be used along with the log-format value COMBINED. + */ + + if(file_exists("/usr/local/ispconfig/server/conf-custom/goaccess.conf.master")) { + $app->system->copy("/usr/local/ispconfig/server/conf-custom/goaccess_index.php.master", $goaccess_conf); + + } elseif(!file_exists($goaccess_conf)) { + + /* + By default the goaccess.conf should get copied by the webserver plugin but in case it wasn't, or it got deleted by accident we gonna copy it again to the destination dir. + Also there was no /usr/local/ispconfig/server/conf-custom/goaccess.conf.master, so we gonna use /etc/goaccess.conf as the base conf. + */ + + $app->system->copy($goaccess_conf_main, $goaccess_conf); + $content = $app->system->file_get_contents($goaccess_conf, true); + $content = preg_replace('/^(#)?log-format COMBINED/m', "log-format COMBINED", $content); + $app->system->file_put_contents($goaccess_conf, $content, true); + unset($content); + + } + + if(file_exists($goaccess_conf)) { + $domain = $data['new']['domain']; + $content = $app->system->file_get_contents($goaccess_conf, true); + $content = preg_replace('/^(#)?html-report-title(.*)/m', "html-report-title $domain", $content); + $app->system->file_put_contents($goaccess_conf, $content, true); + unset($content); + + } + + if(is_file($goaccess_conf) && (filesize($goaccess_conf) > 0)) { + $app->log('Created GoAccess config file: '.$goaccess_conf, LOGLEVEL_DEBUG); + } + + if(is_file($data['new']['document_root']."/" . $web_folder . "/stats/index.html")) $app->system->unlink($data['new']['document_root']."/" . $web_folder . "/stats/index.html"); + if(file_exists("/usr/local/ispconfig/server/conf-custom/goaccess_index.php.master")) { + $app->system->copy("/usr/local/ispconfig/server/conf-custom/goaccess_index.php.master", $data['new']['document_root']."/" . $web_folder . "/stats/index.php"); + } else { + $app->system->copy("/usr/local/ispconfig/server/conf/goaccess_index.php.master", $data['new']['document_root']."/" . $web_folder . "/stats/index.php"); + } + } + + //* Delete the GoAccess configuration file + private function goaccess_delete ($data, $web_config) { + global $app; + + $goaccess_conf = $data['old']['document_root'] . "/log/goaccess.conf"; + + if ( @is_file($goaccess_conf) ) { + $app->system->unlink($goaccess_conf); + $app->log('Removed GoAccess config file: '.$goaccess_conf, LOGLEVEL_DEBUG); + } + } + //* Update the awstats configuration file private function awstats_update ($data, $web_config) { global $app;