2 /**********************************************************************
3 Copyright (C) FrontAccounting, LLC.
4 Released under the terms of the GNU General Public License, GPL,
5 as published by the Free Software Foundation, either version 3
6 of the License, or (at your option) any later version.
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
11 ***********************************************************************/
12 include_once($path_to_root."/includes/packages.inc");
14 // Utility class contains basic database upgrade routines.
17 var $previous; // previous database version
18 var $version; // version after upgrade
19 var $description; // short patch description
21 var $sql; // basic sql file
24 var $backup; // pre-upgrade backup filename
26 var $errors = array();
27 var $max_upgrade_time = 300;
28 var $companies = null;
30 function __construct()
34 include $path_to_root."/config_db.php";
36 $this->companies = $db_connections;
38 return $this->companies;
42 Collect/log messages generated during upgrade process.
44 function log_error($msg, $type='Error')
47 $this->errors[] = $msg;
48 error_log(sprintf('[%s] %s', $type, $msg));
53 Selectively extends access to selected security areas/sections.
55 function update_security_roles($sec_updates)
57 global $security_areas, $security_sections;
59 $roles = db_query("SELECT * FROM ".TB_PREF."security_roles");
61 while($role = db_fetch($roles))
63 $role['areas'] = explode(';', $role['areas']);
64 $role['sections'] = explode(';', $role['sections']);
65 foreach($sec_updates as $has => $add)
67 if (in_array($security_areas[$has][0], $role['areas']))
70 foreach($add as $area)
72 $role['areas'][] = $security_areas[$area][0];
73 $role['sections'][] = $security_areas[$area][0]&~0xff;
76 update_security_role($role['id'], $role['role'], $role['description'],
77 array_values($role['sections']), array_values($role['areas']));
85 Check and disable incompatible extensions.
87 function update_extensions()
91 $mods = get_company_extensions();
92 $exts = get_company_extensions($this->cur_company);
95 foreach($mods as $key => $ins) {
96 foreach($exts as $ext)
97 if ($ext['name'] == $ins['name'] && (!check_src_ext_version($ins['version']))) {
98 $mods[$key]['active'] = false;
99 $this->log_error(sprintf(_("Uncompatible extension '%s' disabled for company %d."), $ins['name'], $this->cur_company), 'Notice');
105 write_extensions($mods, $this->cur_company);
109 Pre-install maintenance: login to company, open upgrade log, make a backup
111 function pre_install($company)
115 $this->cur_company = $company;
116 $this->errors = array();
117 $this->backup = null;
119 $this->save_log = ini_set('error_log', VARLOG_PATH.'/upgrade.'.$this->cur_company.'.log');
120 $this->log_error(sprintf(_("Upgrade started for company %s."), $this->cur_company), 'Info');
122 if (!set_global_connection($this->cur_company))
123 return $this->log_error(_("Cannot connect to company database."));
125 $cur_ver = get_company_pref('version_id', true);
126 if ($cur_ver != $this->previous)
127 return $this->log_error(sprintf(_("Cannot upgrade company %s: database version is incompatible ('%s' instead of '%s')."),
128 $this->cur_company, $cur_ver, $this->previous));
130 $this->update_extensions(); // disable uncompatible extensions
132 if (!$this->prepare()) // fetch params, perform additional checks (if any)
136 return true; // skip security backup if database content is not changed
138 $this->backup = db_backup($this->companies[$this->cur_company], 'no', 'Security backup before upgrade',
139 $SysPrefs->backup_dir($this->cur_company));
142 return $this->log_error(_("Security backup failed."));
144 $this->log_error(sprintf(_("Security backup in file %s done."), $this->backup), 'Info');
149 Basic install procedure using sql file.
151 function sql_install($company, $force=false)
153 global $path_to_root;
155 if ($this->sql != '') // perform basic upgrade operations defined in sql file
159 if ($result === true)
160 $result = db_import($path_to_root. '/sql/'.$this->sql, $this->companies[$company],
161 $force, true, false, true);
163 if ($result !== true)
165 if (is_array($result))
167 foreach($result as $err)
168 $this->log_error($err[1] . ':'. $err[0]);
171 $this->log_error($result);
172 unset($this->backup); // prevent restore (database was not touched due to other errors)
181 Post install procedures: update database version, or restore databse from backup file in case of errors
183 function post_install($result=true)
187 if ($result !== true)
191 if (!set_global_connection($this->cur_company)) // reset connection to clear encoding
192 return $this->log_error(_("Cannot connect to company database for database restore."));
194 set_time_limit($this->max_upgrade_time);
195 $result = db_import($this->backup, $this->companies[$this->cur_company], true, false);
197 $this->log_error(_("Upgrade failed. Original database content restored successfully."), 'Info');
199 $this->log_error(sprintf(_("Database restore operation failed. Original database content is in %s file."), $this->backup));
200 $this->post_fail($this->cur_company);
203 update_company_prefs(array('version_id' => $this->version));
206 $this->log_error(sprintf(_("Upgrade for company %s finished."), $this->cur_company), 'Info');
208 set_global_connection();
209 ini_set('error_log', $this->save_log);
218 Main routine for single company upgrade.
220 function upgrade_company($comp, $force=false)
222 $result = $this->pre_install($comp) && $this->sql_install($comp, $force) && $this->install($comp, $force);
224 $this->post_install($result);
226 return count($this->errors) == 0;
230 Additional version specific php/sql upgrade procedures.
231 This procedure is performed after basic sql upgrade script is run.
233 function install($company, $force=false)
238 Optional cleanup procedure.
239 This procedure is run in case of upgrade failure, before the backup is restored.
241 function post_fail($company)
246 Present upgrade parameters to administrator
247 This function presents upgrade choices, after selection company to be upgraded.
249 function show_params($comp)
254 Fetch & check upgrade parameters, check additional upgrade pre-conditions.
255 This function is run after successfull switching to target database connection.
265 Return databases status info.
267 function get_site_status($connections)
273 foreach($connections as $i => $conn)
275 $info[$i]['status'] = set_global_connection($i) !== false;
277 $info[$i]['name'] = $conn['name'];
278 $info[$i]['table_set'] = $conn['host'].'/'.$conn['dbname'].':'.$conn['tbpref'].'*';
279 if ($info[$i]['status'])
281 $info[$i]['version'] = get_company_pref('version_id');
284 set_global_connection();
285 $SysPrefs->refresh();
291 Creates table of installer objects sorted by applicable db scheme version.
293 function get_installers()
295 global $path_to_root;
297 $patchdir = $path_to_root."/sql/";
299 $datadir = @opendir($patchdir);
303 while(false !== ($fname = readdir($datadir)))
304 { // check all php files but index.php
305 if (!is_dir($patchdir . $fname) && ($fname != 'index.php')
306 && stristr($fname, '.php') != false && $fname[0] != '.')
309 include_once($patchdir . $fname);
310 if (isset($install)) // add installer if found
311 $upgrades[$install->previous] = $install;
314 ksort($upgrades); // sort by file name