Marius Burkard
2016-04-20 4569cae57f127afd093794310ccd290d2d9fdf36
commit | author | age
196622 1 <?php
T 2
3 /*
4 Copyright (c) 2007 - 2009, Till Brehm, projektfarm Gmbh
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without modification,
8 are permitted provided that the following conditions are met:
9
10     * Redistributions of source code must retain the above copyright notice,
11       this list of conditions and the following disclaimer.
12     * Redistributions in binary form must reproduce the above copyright notice,
13       this list of conditions and the following disclaimer in the documentation
14       and/or other materials provided with the distribution.
15     * Neither the name of ISPConfig nor the names of its contributors
16       may be used to endorse or promote products derived from this software without
17       specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26 OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 class modules {
b1a6a5 32
196622 33     var $notification_hooks = array();
T 34     var $current_datalog_id = 0;
35     var $debug = false;
b1a6a5 36
196622 37     /*
T 38      This function is called to load the modules from the mods-enabled or the mods-core folder
39     */
40     function loadModules($type) {
41         global $app, $conf;
b1a6a5 42
196622 43         $subPath = 'mods-enabled';
T 44         if ($type == 'core') $subPath = 'mods-core';
45
458767 46         $modules_dir = $conf['rootpath'].$conf['fs_div'].$subPath.$conf['fs_div'];
196622 47         if (is_dir($modules_dir)) {
T 48             if ($dh = opendir($modules_dir)) {
49                 while (($file = readdir($dh)) !== false) {
b1a6a5 50                     if($file != '.' && $file != '..' && substr($file, -8, 8) == '.inc.php') {
MC 51                         $module_name = substr($file, 0, -8);
52                         include_once $modules_dir.$file;
53                         if($this->debug) $app->log('Loading Module: '.$module_name, LOGLEVEL_DEBUG);
196622 54                         $app->loaded_modules[$module_name] = new $module_name;
T 55                         $app->loaded_modules[$module_name]->onLoad();
56                     }
57                 }
58             }
59         } else {
b1a6a5 60             $app->log('Modules directory missing: '.$modules_dir, LOGLEVEL_ERROR);
196622 61         }
b1a6a5 62
196622 63     }
b1a6a5 64
196622 65     /*
T 66      This function is called by the modules to register for a specific
67      table change notification
68     */
b1a6a5 69
MC 70     function registerTableHook($table_name, $module_name, $function_name) {
196622 71         global $app;
T 72         $this->notification_hooks[$table_name][] = array('module' => $module_name, 'function' => $function_name);
b1a6a5 73         if($this->debug) $app->log("Registered TableHook '$table_name' in module '$module_name' for processing function '$function_name'", LOGLEVEL_DEBUG);
196622 74     }
b1a6a5 75
196622 76     /*
T 77      This function goes through all new records in the
78      sys_datalog table and and calls the function in the
79      modules that hooked on to the table change.
80     */
b1a6a5 81
196622 82     function processDatalog() {
b1a6a5 83         global $app, $conf;
MC 84
196622 85         //* If its a multiserver setup
dec0df 86         if($app->db->dbHost != $app->dbmaster->dbHost || ($app->db->dbHost == $app->dbmaster->dbHost && $app->db->dbName != $app->dbmaster->dbName)) {
458767 87             if($conf['mirror_server_id'] > 0) {
cc7a82 88                 $sql = "SELECT * FROM sys_datalog WHERE datalog_id > ? AND (server_id = ? OR server_id = ? OR server_id = 0) ORDER BY datalog_id LIMIT 0,1000";
9adcf5 89             } else {
cc7a82 90                 $sql = "SELECT * FROM sys_datalog WHERE datalog_id > ? AND (server_id = ? OR server_id = 0) ORDER BY datalog_id LIMIT 0,1000";
9adcf5 91             }
b1a6a5 92
cc7a82 93             $records = $app->dbmaster->queryAllRecords($sql, $conf['last_datalog_id'], $conf['server_id'], $conf['mirror_server_id']);
196622 94             foreach($records as $d) {
b1a6a5 95
196622 96                 //** encode data to utf-8 and unserialize it
458767 97                 if(!$data = unserialize(stripslashes($d['data']))) {
J 98                     $data = unserialize($d['data']);
196622 99                 }
T 100                 //** Decode data back to locale
1ca823 101                 /*
196622 102                 foreach($data['old'] as $key => $val) {
T 103                     $data['old'][$key] = utf8_decode($val);
104                 }
105                 foreach($data['new'] as $key => $val) {
106                     $data['new'][$key] = utf8_decode($val);
107                 }
1ca823 108                 */
b1a6a5 109
196622 110                 $replication_error = false;
1bf462 111                 $data['mirrored'] = false;
b1a6a5 112
458767 113                 $this->current_datalog_id = $d['datalog_id'];
b1a6a5 114
5619c7 115                 /*
b1a6a5 116                 * If we are in a mirror setup, rewrite the server_id of records that originally
5619c7 117                 * belonged to the mirrored server to the local server_id
T 118                 */
b1a6a5 119
458767 120                 if($conf['mirror_server_id'] > 0 && $d['dbtable'] != 'server') {
1bf462 121                     if(isset($data['new']['server_id']) && $data['new']['server_id'] == $conf['mirror_server_id']) {
T 122                         $data['new']['server_id'] = $conf['server_id'];
123                         $data['mirrored'] = true;
124                     }
125                     if(isset($data['old']['server_id']) && $data['old']['server_id'] == $conf['mirror_server_id']) {
126                         $data['old']['server_id'] = $conf['server_id'];
127                         $data['mirrored'] = true;
128                     }
5619c7 129                 }
b1a6a5 130
196622 131                 if(count($data['new']) > 0) {
458767 132                     if($d['action'] == 'i' || $d['action'] == 'u') {
b1a6a5 133                         $idx = explode(':', $d['dbidx']);
196622 134                         $tmp_sql1 = '';
T 135                         $tmp_sql2 = '';
cc7a82 136                         $f_params = array($d['dbtable']);
MC 137                         $params = array();
196622 138                         foreach($data['new'] as $fieldname => $val) {
cc7a82 139                             $tmp_sql1 .= "??,";
MC 140                             $tmp_sql2 .= "?,";
141                             $f_params[] = $fieldname;
142                             $params[] = $val;
196622 143                         }
e559f3 144                         $params = array_merge($f_params, $params);
cc7a82 145                         unset($f_params);
MC 146                         
b1a6a5 147                         $tmp_sql1 = substr($tmp_sql1, 0, -1);
MC 148                         $tmp_sql2 = substr($tmp_sql2, 0, -1);
196622 149                         //$tmp_sql1 .= "$idx[0]";
T 150                         //$tmp_sql2 .= "$idx[1]";
cc7a82 151                         $sql = "REPLACE INTO ?? ($tmp_sql1) VALUES ($tmp_sql2)";
61377e 152                         $app->db->errorNumber = 0;
T 153                         $app->db->errorMessage = '';
cc7a82 154                         $app->db->query($sql, true, $params);
196622 155                         if($app->db->errorNumber > 0) {
T 156                             $replication_error = true;
b1a6a5 157                             $app->log("Replication failed. Error: (" . $d['dbtable'] . ") in MySQL server: (".$app->db->dbHost.") " . $app->db->errorMessage . " # SQL: " . $sql, LOGLEVEL_ERROR);
196622 158                         }
931773 159                         $log = $app->db->_build_query_string($sql, true, $params);
FS 160                         $app->log('Replicated from master: '.$log, LOGLEVEL_DEBUG);
161                         unset($params);
162                         unset($log);
196622 163                     }
cc7a82 164                     
458767 165                     if($d['action'] == 'd') {
b1a6a5 166                         $idx = explode(':', $d['dbidx']);
cc7a82 167                         $sql = "DELETE FROM ?? ";
MC 168                         $sql .= " WHERE ?? = ?";
169                         $app->db->query($sql, $d['dbtable'], $idx[0], $idx[1]);
196622 170                         if($app->db->errorNumber > 0) {
T 171                             $replication_error = true;
b1a6a5 172                             $app->log("Replication failed. Error: (" . $d[dbtable] . ") " . $app->db->errorMessage . " # SQL: " . $sql, LOGLEVEL_ERROR);
196622 173                         }
931773 174                         $log = $app->db->_build_query_string($sql, $d['dbtable'], $idx[0], $idx[1]);
FS 175                         $app->log('Replicated from master: '.$log, LOGLEVEL_DEBUG);
176                         unset($log);
196622 177                     }
b1a6a5 178
MC 179
196622 180                     if($replication_error == false) {
bc5697 181                         if(is_array($data['old']) || is_array($data['new'])) {
cc7a82 182                             $app->db->query("UPDATE server SET updated = ? WHERE server_id = ?", $d["datalog_id"], $conf['server_id']);
b1a6a5 183                             $this->raiseTableHook($d['dbtable'], $d['action'], $data);
bc5697 184                         } else {
b1a6a5 185                             $app->log('Data array was empty for datalog_id '.$d['datalog_id'], LOGLEVEL_WARN);
bc5697 186                         }
cc7a82 187                         $app->dbmaster->query("UPDATE server SET updated = ? WHERE server_id = ?", $d["datalog_id"], $conf['server_id']);
b1a6a5 188                         $app->log('Processed datalog_id '.$d['datalog_id'], LOGLEVEL_DEBUG);
196622 189                     } else {
b1a6a5 190                         $app->log('Error in Replication, changes were not processed.', LOGLEVEL_ERROR);
196622 191                         /*
T 192                          * If there is any error in processing the datalog we can't continue, because
193                          * we do not know if the newer actions require this (old) one.
194                          */
195                         return;
196                     }
197                 } else {
b1a6a5 198                     $app->log('Datalog does not contain any changes for this record '.$d['datalog_id'], LOGLEVEL_DEBUG);
196622 199                 }
T 200             }
b1a6a5 201
MC 202             //* if we have a single server setup
196622 203         } else {
cc7a82 204             $sql = "SELECT * FROM sys_datalog WHERE datalog_id > ? AND (server_id = ? OR server_id = 0) ORDER BY datalog_id LIMIT 0,1000";
MC 205             $records = $app->db->queryAllRecords($sql, $conf['last_datalog_id'], $conf['server_id']);
196622 206             foreach($records as $d) {
b1a6a5 207
196622 208                 //** encode data to utf-8 to be able to unserialize it and then unserialize it
458767 209                 if(!$data = unserialize(stripslashes($d['data']))) {
J 210                     $data = unserialize($d['data']);
196622 211                 }
b1a6a5 212
1bf462 213                 //* Data on a single server is never mirrored
T 214                 $data['mirrored'] = false;
b1a6a5 215
458767 216                 $this->current_datalog_id = $d['datalog_id'];
bc5697 217                 if(is_array($data['old']) || is_array($data['new'])) {
b1a6a5 218                     $this->raiseTableHook($d['dbtable'], $d['action'], $data);
bc5697 219                 } else {
b1a6a5 220                     $app->log('Data array was empty for datalog_id '.$d['datalog_id'], LOGLEVEL_WARN);
bc5697 221                 }
cc7a82 222                 $app->db->query("UPDATE server SET updated = ? WHERE server_id = ?", $d['datalog_id'], $conf['server_id']);
b1a6a5 223                 $app->log('Processed datalog_id '.$d['datalog_id'], LOGLEVEL_DEBUG);
196622 224             }
T 225         }
5a43e7 226     }
b1a6a5 227
5a43e7 228     function processActions() {
b1a6a5 229         global $app, $conf;
MC 230
5a43e7 231         //* get the server_id of the local server
T 232         $server_id = intval($conf["server_id"]);
b1a6a5 233
MC 234         include_once SCRIPT_PATH."/lib/remote_action.inc.php";
235
5a43e7 236         //* SQL query to get all pending actions
T 237         $sql = "SELECT action_id, action_type, action_param " .
b1a6a5 238             "FROM sys_remoteaction " .
cc7a82 239             "WHERE server_id = ? ".
MC 240             " AND  action_id > ? ".
b1a6a5 241             "ORDER BY action_id";
MC 242
cc7a82 243         $actions = $app->dbmaster->queryAllRecords($sql, $server_id, $maxid_remote_action);
b1a6a5 244
5a43e7 245         if(is_array($actions)) {
T 246             foreach($actions as $action) {
b1a6a5 247
5a43e7 248                 //* Raise the action
b1a6a5 249                 $state = $app->plugins->raiseAction($action['action_type'], $action['action_param']);
MC 250
5a43e7 251                 //* Update the action state
T 252                 $sql = "UPDATE sys_remoteaction " .
cc7a82 253                     "SET action_state = ? " .
MC 254                     "WHERE action_id = ?";
255                 $app->dbmaster->query($sql, $state, $action['action_id']);
5a43e7 256
T 257                 /*
258                 * Then save the maxid for the next time...
259                 */
260                 $fp = fopen(ISPC_LIB_PATH."/remote_action.inc.php", 'wb');
261                 $content = '<?php' . "\n" . '$maxid_remote_action = ' . $action['action_id'] . ';' . "\n?>";
262                 fwrite($fp, $content);
263                 fclose($fp);
264             }
265         }
b1a6a5 266
MC 267
268
196622 269     }
b1a6a5 270
MC 271     function raiseTableHook($table_name, $action, $data) {
196622 272         global $app;
b1a6a5 273
196622 274         // Get the hooks for this table
T 275         $hooks = (isset($this->notification_hooks[$table_name]))?$this->notification_hooks[$table_name]:'';
b1a6a5 276         if($this->debug) $app->log("Raised TableHook for table: '$table_name'", LOGLEVEL_DEBUG);
MC 277
196622 278         if(is_array($hooks)) {
T 279             foreach($hooks as $hook) {
458767 280                 $module_name = $hook['module'];
J 281                 $function_name = $hook['function'];
04620b 282                 // Call the processing function of the module
b1a6a5 283                 if($this->debug) $app->log("Call function '$function_name' in module '$module_name' raised by TableHook '$table_name'.", LOGLEVEL_DEBUG);
04620b 284                 // call_user_method($function_name,$app->loaded_modules[$module_name],$table_name,$action,$data);
b1a6a5 285                 call_user_func(array($app->loaded_modules[$module_name], $function_name), $table_name, $action, $data);
196622 286                 unset($module_name);
T 287                 unset($function_name);
288             }
289         }
290         unset($hook);
291         unset($hooks);
292     }
b1a6a5 293
196622 294 }
T 295
458767 296 ?>