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;
29 function __construct()
33 include $path_to_root."/config_db.php";
35 $this->companies = $db_connections;
37 return $this->companies;
41 Collect/log messages generated during upgrade process.
43 function log_error($msg, $type='Error')
46 $this->errors[] = $msg;
47 error_log(sprintf('[%s] %s', $type, $msg));
52 Selectively extends access to selected security areas/sections.
54 function update_security_roles($sec_updates)
56 global $security_areas, $security_sections;
58 $roles = db_query("SELECT * FROM ".TB_PREF."security_roles");
60 while($role = db_fetch($roles))
62 $role['areas'] = explode(';', $role['areas']);
63 $role['sections'] = explode(';', $role['sections']);
64 foreach($sec_updates as $has => $add)
66 if (in_array($security_areas[$has][0], $role['areas']))
69 foreach($add as $area)
71 $role['areas'][] = $security_areas[$area][0];
72 $role['sections'][] = $security_areas[$area][0]&~0xff;
75 update_security_role($role['id'], $role['role'], $role['description'],
76 array_values($role['sections']), array_values($role['areas']));
84 Check and disable incompatible extensions.
86 function update_extensions()
90 $mods = get_company_extensions();
91 $exts = get_company_extensions($this->cur_company);
94 foreach($mods as $key => $ins) {
95 foreach($exts as $ext)
96 if ($ext['name'] == $ins['name'] && (!check_src_ext_version($ins['version']))) {
97 $mods[$key]['active'] = false;
98 $this->log_error(sprintf(_("Uncompatible extension '%s' disabled for company %d."), $ins['name'], $this->cur_company), 'Notice');
104 write_extensions($mods, $this->cur_company);
108 Pre-install maintenance: login to company, open upgrade log, make a backup
110 function pre_install($company)
114 $this->cur_company = $company;
115 $this->errors = array();
116 $this->backup = null;
118 $this->save_log = ini_set('error_log', VARLOG_PATH.'/upgrade.'.$this->cur_company.'.log');
119 $this->log_error(sprintf(_("Upgrade started for company %s."), $this->cur_company), 'Info');
121 if (!set_global_connection($this->cur_company))
122 return $this->log_error(_("Cannot connect to company database."));
124 $cur_ver = get_company_pref('version_id', true);
125 if ($cur_ver != $this->previous)
126 return $this->log_error(sprintf(_("Cannot upgrade company %s: database version is incompatible ('%s' instead of '%s')."),
127 $this->cur_company, $cur_ver, $this->previous));
129 $this->update_extensions(); // disable uncompatible extensions
131 if (!$this->prepare()) // fetch params, perform additional checks (if any)
135 return true; // skip security backup if database content is not changed
137 $this->backup = db_backup($this->companies[$this->cur_company], 'no', 'Security backup before upgrade',
138 $SysPrefs->backup_dir($this->cur_company));
141 return $this->log_error(_("Security backup failed."));
143 $this->log_error(sprintf(_("Security backup in file %s done."), $this->backup), 'Info');
148 Basic install procedure using sql file.
150 function sql_install($company, $force=false)
152 global $path_to_root;
154 if ($this->sql != '') // perform basic upgrade operations defined in sql file
158 if ($result === true)
159 $result = db_import($path_to_root. '/sql/'.$this->sql, $this->companies[$company],
160 $force, true, false, true);
162 if ($result !== true)
164 if (is_array($result))
166 foreach($result as $err)
167 $this->log_error($err[1] . ':'. $err[0]);
169 $this->log_error($result);
170 unset($this->backup); // prevent restore (database was not touched due to other errors)
179 Post install procedures: update database version, or restore databse from backup file in case of errors
181 function post_install($result=true)
185 if ($result !== true)
189 if (!set_global_connection($this->cur_company)) // reset connection to clear encoding
190 return $this->log_error(_("Cannot connect to company database for database restore."));
192 set_time_limit($this->max_upgrade_time);
193 $result = db_import($this->backup, $this->companies[$this->cur_company], true, false);
195 $this->log_error(_("Upgrade failed. Original database content restored successfully."), 'Info');
197 $this->log_error(sprintf(_("Database restore operation failed. Original database content is in %s file."), $this->backup));
198 $this->post_fail($this->cur_company);
201 update_company_prefs(array('version_id' => $this->version));
204 $this->log_error(sprintf(_("Upgrade for company %s finished."), $this->cur_company), 'Info');
206 set_global_connection();
207 ini_set('error_log', $this->save_log);
216 Main routine for single company upgrade.
218 function upgrade_company($comp, $force=false)
220 $result = $this->pre_install($comp) && $this->sql_install($comp, $force) && $this->install($comp, $force);
222 $this->post_install($result);
224 return count($this->errors) == 0;
228 Additional version specific php/sql upgrade procedures.
229 This procedure is performed after basic sql upgrade script is run.
231 function install($company, $force=false)
236 Optional cleanup procedure.
237 This procedure is run in case of upgrade failure, before the backup is restored.
239 function post_fail($company)
244 Present upgrade parameters to administrator.
245 This function is run after successfull switching to target database connection
246 and presents upgrade choices, later fetched in prepare() method.
248 function show_params($comp)
253 Fetch & check upgrade parameters, check additional upgrade pre-conditions.
254 This function is run after successfull switching to target database connection, before sql upgrade script is run.
264 Return databases status info.
266 function get_site_status($connections)
272 foreach($connections as $i => $conn)
274 $info[$i]['status'] = set_global_connection($i) !== false;
276 $info[$i]['name'] = $conn['name'];
277 $info[$i]['table_set'] = $conn['host'].'/'.$conn['dbname'].':'.$conn['tbpref'].'*';
278 if ($info[$i]['status'])
280 $info[$i]['version'] = get_company_pref('version_id');
283 set_global_connection();
284 $SysPrefs->refresh();
290 Creates table of installer objects sorted by applicable db scheme version.
292 function get_installers()
294 global $path_to_root;
296 $patchdir = $path_to_root."/sql/";
298 $datadir = @opendir($patchdir);
302 while(false !== ($fname = readdir($datadir)))
303 { // check all php files but index.php
304 if (!is_dir($patchdir . $fname) && ($fname != 'index.php')
305 && stristr($fname, '.php') != false && $fname[0] != '.')
308 include_once($patchdir . $fname);
309 if (isset($install)) // add installer if found
310 $upgrades[$install->previous] = $install;
313 ksort($upgrades); // sort by file name