diff --git a/install/sql/ispconfig3.sql b/install/sql/ispconfig3.sql
index d2df925babe0c6b8de7a0d30b68520387bb90bb4..b4c5793612b6f48320d5133a986c0ee33a6ec55c 100644
--- a/install/sql/ispconfig3.sql
+++ b/install/sql/ispconfig3.sql
@@ -97,6 +97,7 @@ CREATE TABLE `client` (
`limit_cron` int(11) NOT NULL default '0',
`limit_cron_type` enum('url','chrooted','full') NOT NULL default 'url',
`limit_cron_frequency` int(11) NOT NULL default '5',
+ `limit_traffic_quota` int(11) NOT NULL default '-1',
`limit_client` int(11) NOT NULL default '0',
`parent_client_id` int(11) unsigned NOT NULL default '0',
`username` varchar(64) default NULL,
@@ -150,6 +151,7 @@ CREATE TABLE `client_template` (
`limit_cron` int(11) NOT NULL default '0',
`limit_cron_type` enum('url','chrooted','full') NOT NULL default 'url',
`limit_cron_frequency` int(11) NOT NULL default '5',
+ `limit_traffic_quota` int(11) NOT NULL default '-1',
`limit_client` int(11) NOT NULL default '0',
PRIMARY KEY (`template_id`)
) ENGINE=MyISAM AUTO_INCREMENT=1;
@@ -1035,7 +1037,7 @@ CREATE TABLE `web_domain` (
`system_user` varchar(255) default NULL,
`system_group` varchar(255) default NULL,
`hd_quota` bigint(20) NOT NULL default '0',
- `traffic_quota` bigint(20) NOT NULL default '0',
+ `traffic_quota` bigint(20) NOT NULL default '-1',
`cgi` enum('n','y') NOT NULL default 'y',
`ssi` enum('n','y') NOT NULL default 'y',
`suexec` enum('n','y') NOT NULL default 'y',
@@ -1061,6 +1063,7 @@ CREATE TABLE `web_domain` (
`apache_directives` text,
`php_open_basedir` text,
`active` enum('n','y') NOT NULL default 'y',
+ `traffic_quota_lock` enum('n','y') NOT NULL default 'n',
PRIMARY KEY (`domain_id`)
) ENGINE=MyISAM AUTO_INCREMENT=1;
diff --git a/interface/lib/classes/tform.inc.php b/interface/lib/classes/tform.inc.php
index 31916acee4ac83ddf77978769f264b7993dc1a1e..4e047da76b081f7ee90fe67cf84dc8a0943966ac 100644
--- a/interface/lib/classes/tform.inc.php
+++ b/interface/lib/classes/tform.inc.php
@@ -1199,7 +1199,7 @@ class tform {
// translation function for forms, tries the form wordbook first and if this fails, it tries the global wordbook
function lng($msg) {
- global $app;
+ global $app,$conf;
if(isset($this->wordbook[$msg])) {
return $this->wordbook[$msg];
diff --git a/interface/web/client/form/client.tform.php b/interface/web/client/form/client.tform.php
index cd599dfa1e61dcdcb47414959675ee45e8369c06..99b1cab2d04632b225c7ded4b5a56cf19115facf 100644
--- a/interface/web/client/form/client.tform.php
+++ b/interface/web/client/form/client.tform.php
@@ -727,6 +727,20 @@ $form["tabs"]['limits'] = array (
'rows' => '',
'cols' => ''
),
+ 'limit_traffic_quota' => array (
+ 'datatype' => 'INTEGER',
+ 'formtype' => 'TEXT',
+ 'validators' => array ( 0 => array ( 'type' => 'ISINT',
+ 'errmsg'=> 'limit_traffic_quota_error_notint'),
+ ),
+ 'default' => '-1',
+ 'value' => '',
+ 'separator' => '',
+ 'width' => '10',
+ 'maxlength' => '10',
+ 'rows' => '',
+ 'cols' => ''
+ ),
##################################
# END Datatable fields
##################################
diff --git a/interface/web/client/form/client_template.tform.php b/interface/web/client/form/client_template.tform.php
index 6f924501f32c5d538cde84202eca861b56c7a179..1b7ed25a9560f9714dd0d945fb55712d40769a5e 100644
--- a/interface/web/client/form/client_template.tform.php
+++ b/interface/web/client/form/client_template.tform.php
@@ -459,6 +459,20 @@ $form["tabs"]['limits'] = array (
'rows' => '',
'cols' => ''
),
+ 'limit_traffic_quota' => array (
+ 'datatype' => 'INTEGER',
+ 'formtype' => 'TEXT',
+ 'validators' => array ( 0 => array ( 'type' => 'ISINT',
+ 'errmsg'=> 'limit_traffic_quota_error_notint'),
+ ),
+ 'default' => '-1',
+ 'value' => '',
+ 'separator' => '',
+ 'width' => '10',
+ 'maxlength' => '10',
+ 'rows' => '',
+ 'cols' => ''
+ ),
##################################
# END Datatable fields
##################################
diff --git a/interface/web/client/form/reseller.tform.php b/interface/web/client/form/reseller.tform.php
index a7c5ea6b080476fa8e1a7f1139e5d86b2251de5f..4cfb52d631d00496c0fa5ec78a416c6ea9b08681 100644
--- a/interface/web/client/form/reseller.tform.php
+++ b/interface/web/client/form/reseller.tform.php
@@ -714,6 +714,20 @@ $form["tabs"]['limits'] = array (
'rows' => '',
'cols' => ''
),
+ 'limit_traffic_quota' => array (
+ 'datatype' => 'INTEGER',
+ 'formtype' => 'TEXT',
+ 'validators' => array ( 0 => array ( 'type' => 'ISINT',
+ 'errmsg'=> 'limit_traffic_quota_error_notint'),
+ ),
+ 'default' => '-1',
+ 'value' => '',
+ 'separator' => '',
+ 'width' => '10',
+ 'maxlength' => '10',
+ 'rows' => '',
+ 'cols' => ''
+ ),
##################################
# END Datatable fields
##################################
diff --git a/interface/web/client/lib/lang/en_client.lng b/interface/web/client/lib/lang/en_client.lng
index 4c0332cc6c0db73a813c3fa3b698a78e75715658..e87ba45e073c66489d2e0bdcb5adf9e307bf44f8 100644
--- a/interface/web/client/lib/lang/en_client.lng
+++ b/interface/web/client/lib/lang/en_client.lng
@@ -92,4 +92,6 @@ $wb["ssh_chroot_txt"] = 'SSH-Chroot Options';
$wb["web_php_options_txt"] = 'PHP Options';
$wb["limit_client_error"] = 'The max. number of clients is reached.';
$wb["limit_web_quota_txt"] = 'Web Quota';
+$wb["limit_traffic_quota_txt"] = 'Traffic Quota';
+$wb["limit_trafficquota_error_notint"] = 'Traffic Quota must be a number.';
?>
diff --git a/interface/web/client/lib/lang/en_client_template.lng b/interface/web/client/lib/lang/en_client_template.lng
index f7299744a84b0022e6506824c697bcf28773d9a8..53878e97d6f29cf1fa383bc492d7fc3a97490dcf 100644
--- a/interface/web/client/lib/lang/en_client_template.lng
+++ b/interface/web/client/lib/lang/en_client_template.lng
@@ -55,4 +55,6 @@ $wb["limit_cron_error_notint"] = 'The cron limit must be a number.';
$wb["limit_cron_error_frequency"] = 'The cron frequency limit must be a number.';
$wb["error_template_name_empty"] = 'Please enter a Template name';
$wb["limit_web_quota_txt"] = 'Web Quota';
+$wb["limit_traffic_quota_txt"] = 'Traffic Quota';
+$wb["limit_trafficquota_error_notint"] = 'Traffic Quota must be a number.';
?>
\ No newline at end of file
diff --git a/interface/web/client/lib/lang/en_reseller.lng b/interface/web/client/lib/lang/en_reseller.lng
index e3e7e30704ac3e7526035e17c97fd9760ef2fb93..2b06c33d30a6d778219b54f0a0ccb8f6c043bfe5 100644
--- a/interface/web/client/lib/lang/en_reseller.lng
+++ b/interface/web/client/lib/lang/en_reseller.lng
@@ -91,4 +91,6 @@ $wb["web_php_options_txt"] = 'PHP Options';
$wb["limit_client_error"] = 'The max. number of clients is reached.';
$wb["limit_client_error_positive"] = 'The number of clients must be > 0';
$wb["limit_web_quota_txt"] = 'Web Quota';
+$wb["limit_traffic_quota_txt"] = 'Traffic Quota';
+$wb["limit_trafficquota_error_notint"] = 'Traffic Quota must be a number.';
?>
diff --git a/interface/web/client/templates/client_edit_limits.htm b/interface/web/client/templates/client_edit_limits.htm
index 3bdca109747665efb313c1c4255851213c55ab6f..ba1850870918be03975d0ed442a013cf8ccfd203 100644
--- a/interface/web/client/templates/client_edit_limits.htm
+++ b/interface/web/client/templates/client_edit_limits.htm
@@ -173,6 +173,10 @@
+
+
+ MB
+
diff --git a/interface/web/client/templates/client_template_edit_limits.htm b/interface/web/client/templates/client_template_edit_limits.htm
index 8f5d3d2655e7432968225556f8a0c1dc49416c82..6509329eed8d2bd7c9626b24839a6a33d8722609 100644
--- a/interface/web/client/templates/client_template_edit_limits.htm
+++ b/interface/web/client/templates/client_template_edit_limits.htm
@@ -107,6 +107,10 @@
+
+
+ MB
+
diff --git a/interface/web/client/templates/reseller_edit_limits.htm b/interface/web/client/templates/reseller_edit_limits.htm
index d413eb5dc7341cc248b35189496a2064ea1a50ff..dfed34f65b80c7ac04af42378bb152985b4d0fc9 100644
--- a/interface/web/client/templates/reseller_edit_limits.htm
+++ b/interface/web/client/templates/reseller_edit_limits.htm
@@ -162,6 +162,10 @@
+
+
+ MB
+
diff --git a/interface/web/sites/form/web_domain.tform.php b/interface/web/sites/form/web_domain.tform.php
index d0a31d8ae78bf0d86320bd83e3e57aeafa1de993..1e5afad80d6f8b7c1d5f26d11e1b8773ce179817 100644
--- a/interface/web/sites/form/web_domain.tform.php
+++ b/interface/web/sites/form/web_domain.tform.php
@@ -139,7 +139,6 @@ $form["tabs"]['domain'] = array (
'width' => '7',
'maxlength' => '7'
),
- /*
'traffic_quota' => array (
'datatype' => 'INTEGER',
'formtype' => 'TEXT',
@@ -151,7 +150,6 @@ $form["tabs"]['domain'] = array (
'width' => '7',
'maxlength' => '7'
),
- */
'cgi' => array (
'datatype' => 'VARCHAR',
'formtype' => 'CHECKBOX',
diff --git a/interface/web/sites/lib/lang/en_web_domain.lng b/interface/web/sites/lib/lang/en_web_domain.lng
index 2ad101375fe4318557cd03606f333faeea977de7..474240b73a0c6ba11cfcb3e5c922ab59f6bcb199 100644
--- a/interface/web/sites/lib/lang/en_web_domain.lng
+++ b/interface/web/sites/lib/lang/en_web_domain.lng
@@ -54,5 +54,5 @@ $wb["ssl_locality_error_regex"] = 'Invalid SSL Locality. Valid characters are: a
$wb["ssl_organisation_error_regex"] = 'Invalid SSL Organisation. Valid characters are: a-z, 0-9 and .,-_';
$wb["ssl_organistaion_unit_error_regex"] = 'Invalid SSL Organisation Unit. Valid characters are: a-z, 0-9 and .,-_';
$wb["ssl_country_error_regex"] = 'Invalid SSL Country. Valid characters are: A-Z';
-
+$wb["limit_web_quota_free_txt"] = 'Max. available Traffic Quota';
?>
diff --git a/interface/web/sites/templates/web_domain_edit.htm b/interface/web/sites/templates/web_domain_edit.htm
index d19550fc7ff990062ab97ac0bb3bfb6da9924690..3ea0603f2185e0ad9a05ed98579c2de59cfc44c4 100644
--- a/interface/web/sites/templates/web_domain_edit.htm
+++ b/interface/web/sites/templates/web_domain_edit.htm
@@ -49,12 +49,10 @@
MB
-
{tmpl_var name='cgi_txt'}
diff --git a/interface/web/sites/web_domain_edit.php b/interface/web/sites/web_domain_edit.php
index 6ad9f4b2d184b58d462be41f6a5c3c158fb8f880..77367000e7bfa4a6d557bead13c75608c8c24ec5 100644
--- a/interface/web/sites/web_domain_edit.php
+++ b/interface/web/sites/web_domain_edit.php
@@ -217,7 +217,7 @@ class page_action extends tform_actions {
if($_SESSION["s"]["user"]["typ"] != 'admin') {
// Get the limits of the client
$client_group_id = $_SESSION["s"]["user"]["default_group"];
- $client = $app->db->queryOneRecord("SELECT limit_web_domain, default_webserver, parent_client_id, limit_web_quota FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
+ $client = $app->db->queryOneRecord("SELECT limit_traffic_quota, limit_web_domain, default_webserver, parent_client_id, limit_web_quota FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
//* Check the website quota
if(isset($_POST["hd_quota"]) && $client["limit_web_quota"] >= 0) {
@@ -235,6 +235,22 @@ class page_action extends tform_actions {
unset($tmp_quota);
}
+ //* Check the traffic quota
+ if(isset($_POST["traffic_quota"]) && $client["limit_traffic_quota"] > 0) {
+ $tmp = $app->db->queryOneRecord("SELECT sum(traffic_quota) as trafficquota FROM web_domain WHERE domain_id != ".intval($this->id)." AND ".$app->tform->getAuthSQL('u'));
+ $trafficquota = $tmp["trafficquota"];
+ $new_traffic_quota = intval($this->dataRecord["traffic_quota"]);
+ if(($trafficquota + $new_traffic_quota > $client["limit_traffic_quota"]) || ($new_traffic_quota == -1 && $client["limit_traffic_quota"] != -1)) {
+ $max_free_quota = floor($client["limit_traffic_quota"] - $trafficquota);
+ if($max_free_quota < 0) $max_free_quota = 0;
+ $app->tform->errorMessage .= $app->tform->lng("limit_traffic_quota_free_txt").": ".$max_free_quota." MB
";
+ // Set the quota field to the max free space
+ $this->dataRecord["traffic_quota"] = $max_free_quota;
+ }
+ unset($tmp);
+ unset($tmp_quota);
+ }
+
// When the record is updated
if($this->id > 0) {
// restore the server ID if the user is not admin and record is edited
diff --git a/server/cron_daily.php b/server/cron_daily.php
index 0d949367cccec78ea6a3c81766c30c1db95931d4..c68f8ab893b48a5917cabb5f67003056f5a75060 100644
--- a/server/cron_daily.php
+++ b/server/cron_daily.php
@@ -233,5 +233,57 @@ if ($app->dbmaster == $app->db) {
}
}
+#######################################################################################################
+// enforce traffic quota (only the "master-server")
+#######################################################################################################
+
+if ($app->dbmaster == $app->db) {
+
+ $current_month = date('Y-m');
+
+ //* Check website traffic quota
+ $sql = "SELECT sys_groupid,domain_id,domain,traffic_quota,traffic_quota_lock FROM web_domain WHERE traffic_quota > 0 and type = 'vhost'";
+ $records = $app->db->queryAllRecords($sql);
+ if(is_array($records)) {
+ foreach($records as $rec) {
+
+ $web_traffic_quota = $rec['traffic_quota'];
+ $domain = $rec['web_domain'];
+
+ // get the client
+ /*
+ $client_group_id = $rec["sys_groupid"];
+ $client = $app->db->queryOneRecord("SELECT limit_traffic_quota,parent_client_id FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
+ $reseller = $app->db->queryOneRecord("SELECT limit_traffic_quota FROM client WHERE client_id = ".intval($client['parent_client_id']));
+
+ $client_traffic_quota = intval($client['limit_traffic_quota']);
+ $reseller_traffic_quota = intval($reseller['limit_traffic_quota']);
+ */
+
+ //* get the traffic
+ $tmp = $app->db->query("SELECT traffic_bytes FROM web_traffic WHERE traffic_date like '$current_month%' AND hostname = '$domain'");
+ $web_traffic = $tmp['traffic_bytes']/1024/1024;
+
+ //* Website is over quota, we will disable it
+ /*if( ($web_traffic_quota > 0 && $web_traffic > $web_traffic_quota) ||
+ ($client_traffic_quota > 0 && $web_traffic > $client_traffic_quota) ||
+ ($reseller_traffic_quota > 0 && $web_traffic > $reseller_traffic_quota)) {*/
+ if($web_traffic_quota > 0 && $web_traffic > $web_traffic_quota) {
+ $app->db->datalogUpdate('web_domain', "traffic_quota_lock = 'y',active = 'n'", 'domain_id', $rec['domain_id']);
+ $app->log("Traffic quota for ".$rec['domain_id']." Exceeded. Disabling website.",LOGLEVEL_DEBUG);
+ } else {
+ //* unlock the website, if traffic is lower then quota
+ if($rec['traffic_quota_lock'] == 'y') {
+ $app->db->datalogUpdate('web_domain', "traffic_quota_lock = 'n',active = 'y'", 'domain_id', $rec['domain_id']);
+ $app->log("Traffic quota for ".$rec['domain_id']." ok again. Enabling website.",LOGLEVEL_DEBUG);
+ }
+ }
+ }
+ }
+
+
+}
+
+
die("finished.\n");
?>
\ No newline at end of file
diff --git a/server/lib/classes/db_mysql.inc.php b/server/lib/classes/db_mysql.inc.php
index 364fd7e7ea3915d6514b1739aae1d36cce72b81a..229b11e49eb69cfe26a502d00478957db369fcdc 100644
--- a/server/lib/classes/db_mysql.inc.php
+++ b/server/lib/classes/db_mysql.inc.php
@@ -229,6 +229,116 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
}
*/
+
+ public function diffrec($record_old, $record_new) {
+ $diffrec_full = array();
+ $diff_num = 0;
+
+ if(is_array($record_old) && count($record_old) > 0) {
+ foreach($record_old as $key => $val) {
+ // if(!isset($record_new[$key]) || $record_new[$key] != $val) {
+ if($record_new[$key] != $val) {
+ // Record has changed
+ $diffrec_full['old'][$key] = $val;
+ $diffrec_full['new'][$key] = $record_new[$key];
+ $diff_num++;
+ } else {
+ $diffrec_full['old'][$key] = $val;
+ $diffrec_full['new'][$key] = $val;
+ }
+ }
+ } elseif(is_array($record_new)) {
+ foreach($record_new as $key => $val) {
+ if(isset($record_new[$key]) && @$record_old[$key] != $val) {
+ // Record has changed
+ $diffrec_full['new'][$key] = $val;
+ $diffrec_full['old'][$key] = @$record_old[$key];
+ $diff_num++;
+ } else {
+ $diffrec_full['new'][$key] = $val;
+ $diffrec_full['old'][$key] = $val;
+ }
+ }
+ }
+
+ return array('diff_num' => $diff_num, 'diff_rec' => $diffrec_full);
+
+ }
+
+ //** Function to fill the datalog with a full differential record.
+ public function datalogSave($db_table, $action, $primary_field, $primary_id, $record_old, $record_new) {
+ global $app,$conf;
+
+ // Insert backticks only for incomplete table names.
+ if(stristr($db_table,'.')) {
+ $escape = '';
+ } else {
+ $escape = '`';
+ }
+
+ $tmp = $this->diffrec($record_old, $record_new);
+ $diffrec_full = $tmp['diff_rec'];
+ $diff_num = $tmp['diff_num'];
+ unset($tmp);
+
+ // Insert the server_id, if the record has a server_id
+ $server_id = (isset($record_old["server_id"]) && $record_old["server_id"] > 0)?$record_old["server_id"]:0;
+ if(isset($record_new["server_id"])) $server_id = $record_new["server_id"];
+
+
+ if($diff_num > 0) {
+ //print_r($diff_num);
+ //print_r($diffrec_full);
+ $diffstr = $app->db->quote(serialize($diffrec_full));
+ $username = $app->db->quote($_SESSION["s"]["user"]["username"]);
+ $dbidx = $primary_field.":".$primary_id;
+
+ if($action == 'INSERT') $action = 'i';
+ if($action == 'UPDATE') $action = 'u';
+ if($action == 'DELETE') $action = 'd';
+ $sql = "INSERT INTO sys_datalog (dbtable,dbidx,server_id,action,tstamp,user,data) VALUES ('".$db_table."','$dbidx','$server_id','$action','".time()."','$username','$diffstr')";
+ $app->db->query($sql);
+ }
+
+ return true;
+ }
+
+ //** Inserts a record and saves the changes into the datalog
+ public function datalogInsert($tablename, $insert_data, $index_field) {
+ global $app;
+
+ $old_rec = array();
+ $this->query("INSERT INTO $tablename $insert_data");
+ $index_value = $this->insertID();
+ $new_rec = $this->queryOneRecord("SELECT * FROM $tablename WHERE $index_field = '$index_value'");
+ $this->datalogSave($tablename, 'INSERT', $index_field, $index_value, $old_rec, $new_rec);
+
+ return $index_value;
+ }
+
+ //** Updates a record and saves the changes into the datalog
+ public function datalogUpdate($tablename, $update_data, $index_field, $index_value) {
+ global $app;
+
+ $old_rec = $this->queryOneRecord("SELECT * FROM $tablename WHERE $index_field = '$index_value'");
+ $this->query("UPDATE $tablename SET $update_data WHERE $index_field = '$index_value'");
+ $new_rec = $this->queryOneRecord("SELECT * FROM $tablename WHERE $index_field = '$index_value'");
+ $this->datalogSave($tablename, 'UPDATE', $index_field, $index_value, $old_rec, $new_rec);
+
+ return true;
+ }
+
+ //** Deletes a record and saves the changes into the datalog
+ public function datalogDelete($tablename, $index_field, $index_value) {
+ global $app;
+
+ $old_rec = $this->queryOneRecord("SELECT * FROM $tablename WHERE $index_field = '$index_value'");
+ $this->query("DELETE FROM $tablename WHERE $index_field = '$index_value'");
+ $new_rec = array();
+ $this->datalogSave($tablename, 'DELETE', $index_field, $index_value, $old_rec, $new_rec);
+
+ return true;
+ }
public function closeConn()
{