Marius Cramer
2015-08-06 37b29231e47a0c4458dc1c15d98588f16f07e1e2
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                         }
cc7a82 144                         $params = $f_params + $params;
MC 145                         unset($f_params);
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);
MC 155                         unset($params);
196622 156                         if($app->db->errorNumber > 0) {
T 157                             $replication_error = true;
b1a6a5 158                             $app->log("Replication failed. Error: (" . $d['dbtable'] . ") in MySQL server: (".$app->db->dbHost.") " . $app->db->errorMessage . " # SQL: " . $sql, LOGLEVEL_ERROR);
196622 159                         }
b1a6a5 160                         $app->log('Replicated from master: '.$sql, LOGLEVEL_DEBUG);
196622 161                     }
cc7a82 162                     
458767 163                     if($d['action'] == 'd') {
b1a6a5 164                         $idx = explode(':', $d['dbidx']);
cc7a82 165                         $sql = "DELETE FROM ?? ";
MC 166                         $sql .= " WHERE ?? = ?";
167                         $app->db->query($sql, $d['dbtable'], $idx[0], $idx[1]);
196622 168                         if($app->db->errorNumber > 0) {
T 169                             $replication_error = true;
b1a6a5 170                             $app->log("Replication failed. Error: (" . $d[dbtable] . ") " . $app->db->errorMessage . " # SQL: " . $sql, LOGLEVEL_ERROR);
196622 171                         }
b1a6a5 172                         $app->log('Replicated from master: '.$sql, LOGLEVEL_DEBUG);
196622 173                     }
b1a6a5 174
MC 175
196622 176                     if($replication_error == false) {
bc5697 177                         if(is_array($data['old']) || is_array($data['new'])) {
cc7a82 178                             $app->db->query("UPDATE server SET updated = ? WHERE server_id = ?", $d["datalog_id"], $conf['server_id']);
b1a6a5 179                             $this->raiseTableHook($d['dbtable'], $d['action'], $data);
bc5697 180                         } else {
b1a6a5 181                             $app->log('Data array was empty for datalog_id '.$d['datalog_id'], LOGLEVEL_WARN);
bc5697 182                         }
cc7a82 183                         $app->dbmaster->query("UPDATE server SET updated = ? WHERE server_id = ?", $d["datalog_id"], $conf['server_id']);
b1a6a5 184                         $app->log('Processed datalog_id '.$d['datalog_id'], LOGLEVEL_DEBUG);
196622 185                     } else {
b1a6a5 186                         $app->log('Error in Replication, changes were not processed.', LOGLEVEL_ERROR);
196622 187                         /*
T 188                          * If there is any error in processing the datalog we can't continue, because
189                          * we do not know if the newer actions require this (old) one.
190                          */
191                         return;
192                     }
193                 } else {
b1a6a5 194                     $app->log('Datalog does not contain any changes for this record '.$d['datalog_id'], LOGLEVEL_DEBUG);
196622 195                 }
T 196             }
b1a6a5 197
MC 198             //* if we have a single server setup
196622 199         } else {
cc7a82 200             $sql = "SELECT * FROM sys_datalog WHERE datalog_id > ? AND (server_id = ? OR server_id = 0) ORDER BY datalog_id LIMIT 0,1000";
MC 201             $records = $app->db->queryAllRecords($sql, $conf['last_datalog_id'], $conf['server_id']);
196622 202             foreach($records as $d) {
b1a6a5 203
196622 204                 //** encode data to utf-8 to be able to unserialize it and then unserialize it
458767 205                 if(!$data = unserialize(stripslashes($d['data']))) {
J 206                     $data = unserialize($d['data']);
196622 207                 }
b1a6a5 208
1bf462 209                 //* Data on a single server is never mirrored
T 210                 $data['mirrored'] = false;
b1a6a5 211
458767 212                 $this->current_datalog_id = $d['datalog_id'];
bc5697 213                 if(is_array($data['old']) || is_array($data['new'])) {
b1a6a5 214                     $this->raiseTableHook($d['dbtable'], $d['action'], $data);
bc5697 215                 } else {
b1a6a5 216                     $app->log('Data array was empty for datalog_id '.$d['datalog_id'], LOGLEVEL_WARN);
bc5697 217                 }
cc7a82 218                 $app->db->query("UPDATE server SET updated = ? WHERE server_id = ?", $d['datalog_id'], $conf['server_id']);
b1a6a5 219                 $app->log('Processed datalog_id '.$d['datalog_id'], LOGLEVEL_DEBUG);
196622 220             }
T 221         }
5a43e7 222     }
b1a6a5 223
5a43e7 224     function processActions() {
b1a6a5 225         global $app, $conf;
MC 226
5a43e7 227         //* get the server_id of the local server
T 228         $server_id = intval($conf["server_id"]);
b1a6a5 229
MC 230         include_once SCRIPT_PATH."/lib/remote_action.inc.php";
231
5a43e7 232         //* SQL query to get all pending actions
T 233         $sql = "SELECT action_id, action_type, action_param " .
b1a6a5 234             "FROM sys_remoteaction " .
cc7a82 235             "WHERE server_id = ? ".
MC 236             " AND  action_id > ? ".
b1a6a5 237             "ORDER BY action_id";
MC 238
cc7a82 239         $actions = $app->dbmaster->queryAllRecords($sql, $server_id, $maxid_remote_action);
b1a6a5 240
5a43e7 241         if(is_array($actions)) {
T 242             foreach($actions as $action) {
b1a6a5 243
5a43e7 244                 //* Raise the action
b1a6a5 245                 $state = $app->plugins->raiseAction($action['action_type'], $action['action_param']);
MC 246
5a43e7 247                 //* Update the action state
T 248                 $sql = "UPDATE sys_remoteaction " .
cc7a82 249                     "SET action_state = ? " .
MC 250                     "WHERE action_id = ?";
251                 $app->dbmaster->query($sql, $state, $action['action_id']);
5a43e7 252
T 253                 /*
254                 * Then save the maxid for the next time...
255                 */
256                 $fp = fopen(ISPC_LIB_PATH."/remote_action.inc.php", 'wb');
257                 $content = '<?php' . "\n" . '$maxid_remote_action = ' . $action['action_id'] . ';' . "\n?>";
258                 fwrite($fp, $content);
259                 fclose($fp);
260             }
261         }
b1a6a5 262
MC 263
264
196622 265     }
b1a6a5 266
MC 267     function raiseTableHook($table_name, $action, $data) {
196622 268         global $app;
b1a6a5 269
196622 270         // Get the hooks for this table
T 271         $hooks = (isset($this->notification_hooks[$table_name]))?$this->notification_hooks[$table_name]:'';
b1a6a5 272         if($this->debug) $app->log("Raised TableHook for table: '$table_name'", LOGLEVEL_DEBUG);
MC 273
196622 274         if(is_array($hooks)) {
T 275             foreach($hooks as $hook) {
458767 276                 $module_name = $hook['module'];
J 277                 $function_name = $hook['function'];
04620b 278                 // Call the processing function of the module
b1a6a5 279                 if($this->debug) $app->log("Call function '$function_name' in module '$module_name' raised by TableHook '$table_name'.", LOGLEVEL_DEBUG);
04620b 280                 // call_user_method($function_name,$app->loaded_modules[$module_name],$table_name,$action,$data);
b1a6a5 281                 call_user_func(array($app->loaded_modules[$module_name], $function_name), $table_name, $action, $data);
196622 282                 unset($module_name);
T 283                 unset($function_name);
284             }
285         }
286         unset($hook);
287         unset($hooks);
288     }
b1a6a5 289
196622 290 }
T 291
458767 292 ?>