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 |
?> |