diff --git a/setup/inc/class.migrater.php b/setup/inc/class.migrater.php new file mode 100644 index 0000000000000000000000000000000000000000..6475ac03cf1ca6247e9e0402e447635d886f188b --- /dev/null +++ b/setup/inc/class.migrater.php @@ -0,0 +1,55 @@ +<?php +/********************************************************************* + class.migrater.php + + SQL database migrater. This provides the engine capable of rolling the + database for an osTicket installation forward (and perhaps even + backward) in time using a set of included migration scripts. Each script + will roll the database between two database checkpoints. Where possible, + the migrater will roll several checkpoint scripts into one to be applied + together. + + Jared Hancock <jared@osticket.com> + Copyright (c) 2006-2012 osTicket + http://www.osticket.com + + Released under the GNU General Public License WITHOUT ANY WARRANTY. + See LICENSE.TXT for details. + + vim: expandtab sw=4 ts=4 sts=4: +**********************************************************************/ + +class DatabaseMigrater { + + function DatabaseMigrater($sqldir) { + $this->sqldir = $sqldir; + } + + function getRollup($stops) { + $cfg->reload(); + $start = $cfg->getSchemaSignature(); + + $patches = array(); + while (true) { + $next = glob($this->sqldir . $substr($start,0,8) + . '-*.patch.sql'); + if (count($next) == 1) { + $patches[] = $next[0]; + $start = substr($next[0], 0, 8); + } elseif ($count($next) == 0) { + # There are no patches leaving the current signature. We + # have to assume that we've applied all the available + # patches. + break; + } else { + # Problem -- more than one patch exists from this snapshot. + # We probably need a graph approach to solve this. + break; + } + + if (array_key_exists($next[0], $stops)) + break; + } + return $patches; + } +} diff --git a/setup/inc/class.setup.php b/setup/inc/class.setup.php index 5108cd4306bc840bc38177088cd6b11c938c391b..34bc57486942bca10d9540459dfd8daf37a4f232 100644 --- a/setup/inc/class.setup.php +++ b/setup/inc/class.setup.php @@ -120,452 +120,4 @@ Class SetupWizard { return $this->setError($error); } } - -class Upgrader extends SetupWizard { - - var $prefix; - var $sqldir; - var $signature; - - function Upgrader($signature, $prefix, $sqldir) { - - $this->signature = $signature; - $this->shash = substr($signature, 0, 8); - $this->prefix = $prefix; - $this->sqldir = $sqldir; - $this->errors = array(); - - //Init persistent state of upgrade. - $this->state = &$_SESSION['ost_upgrader'][$this->getShash()]['state']; - - //Init the task Manager. - if(!isset($_SESSION['ost_upgrader'][$this->getShash()])) - $_SESSION['ost_upgrader'][$this->getShash()]['tasks']=array(); - - //Tasks to perform - saved on the session. - $this->tasks = &$_SESSION['ost_upgrader'][$this->getShash()]['tasks']; - } - - function onError($error) { - $this->setError($error); - $this->setState('aborted'); - } - - function isUpgradable() { - return (!$this->isAborted() && $this->getNextPatch()); - } - - function isAborted() { - return !strcasecmp($this->getState(), 'aborted'); - } - - function getSchemaSignature() { - return $this->signature; - } - - function getShash() { - return $this->shash; - } - - function getTablePrefix() { - return $this->prefix; - } - - function getSQLDir() { - return $this->sqldir; - } - - function getState() { - return $this->state; - } - - function setState($state) { - $this->state = $state; - } - - function getNextPatch() { - - if(!($patch=glob($this->getSQLDir().$this->getShash().'-*.patch.sql'))) - return null; - - return $patch[0]; - } - - function getThisPatch() { - - if(!($patch=glob($this->getSQLDir().'*-'.$this->getShash().'.patch.sql'))) - return null; - - return $patch[0]; - - } - - function getNextVersion() { - if(!$patch=$this->getNextPatch()) - return '(Latest)'; - - if(preg_match('/\*(.*)\*/', file_get_contents($patch), $matches)) - $info=$matches[0]; - else - $info=substr(basename($patch), 9, 8); - - return $info; - } - - function getNextAction() { - - $action='Upgrade osTicket to '.$this->getVersion(); - if($this->getNumPendingTasks() && ($task=$this->getNextTask())) { - $action = $task['desc']; - if($task['status']) //Progress report... - $action.=' ('.$task['status'].')'; - } elseif($this->isUpgradable() && ($nextversion = $this->getNextVersion())) { - $action = "Upgrade to $nextversion"; - } - - return $action; - } - - function getNextStepInfo() { - - if(($patches=$this->getPatches())) - return $patches[0]; - - if(($hooks=$this->getScriptedHooks())) - return $hooks[0]['desc']; - - return null; - } - - function getPatches($ToSignature) { - - $signature = $this->getSignature(); - $patches = array(); - while(($patch=glob($this->getSQLDir().substr($signature,0,8).'-*.patch.sql')) && $i++) { - $patches = array_merge($patches, $patch); - if(!($signature=substr(basename($patch[0]), 10, 8)) || !strncasecmp($signature, $ToSignature, 8)) - break; - } - - return $patches; - } - - function getNumPendingTasks() { - - return count($this->getPendingTasks()); - } - - function getPendingTasks() { - - $pending=array(); - if(($tasks=$this->getTasks())) { - foreach($tasks as $k => $task) { - if(!$task['done']) - $pending[$k] = $task; - } - } - - return $pending; - } - - function getTasks() { - return $this->tasks; - } - - function getNextTask() { - - if(!($tasks=$this->getPendingTasks())) - return null; - - return current($tasks); - } - - function removeTask($tId) { - - if(isset($this->tasks[$tId])) - unset($this->tasks[$tId]); - - return (!$this->tasks[$tId]); - } - - function setTaskStatus($tId, $status) { - if(isset($this->tasks[$tId])) - $this->tasks[$tId]['status'] = $status; - } - - function doTasks() { - - if(!($tasks=$this->getPendingTasks())) - return true; //Nothing to do. - - foreach($tasks as $k => $task) { - if(call_user_func(array($this, $task['func']), $k)===0) { - $this->tasks[$k]['done'] = true; - } else { //Task has pending items to process. - break; - } - } - - return (!$this->getPendingTasks()); - } - - function upgrade() { - - if($this->getPendingTasks() || !($patch=$this->getNextPatch())) - return false; - - if(!$this->load_sql_file($patch, $this->getTablePrefix(), true, true)) - return false; - - //TODO: Log the upgrade - - //Load up post install tasks. - $shash = substr(basename($patch), 9, 8); - $phash = substr(basename($patch), 0, 17); - - $tasks=array(); - $tasks[] = array('func' => 'sometask', - 'desc' => 'Some Task.... blah'); - switch($phash) { //Add patch specific scripted tasks. - case 'xxxx': //V1.6 ST- 1.7 * - $tasks[] = array('func' => 'migrateAttachments2DB', - 'desc' => 'Migrating attachments to database, it might take a while depending on the number of files.'); - break; - } - - $tasks[] = array('func' => 'cleanup', - 'desc' => 'Post-upgrade cleanup!'); - - - - //Load up tasks - NOTE: writing directly to the session - back to the future majic. - $_SESSION['ost_upgrader'][$shash]['tasks'] = $tasks; - $_SESSION['ost_upgrader'][$shash]['state'] = 'upgrade'; - - //clear previous patch info - - unset($_SESSION['ost_upgrader'][$this->getSHash()]); - - return true; - } - - /************* TASKS **********************/ - function sometask($tId) { - - $this->setTaskStatus($tId, 'Doing... '.time(). ' #'.$_SESSION['sometask']); - - sleep(2); - $_SESSION['sometask']+=1; - if($_SESSION['sometask']<4) - return 22; - - $_SESSION['sometask']=0; - - return 0; //Change to 1 for testing... - } - - function cleanup($tId=0) { - - $file=$this->getSQLDir().$this->getSchemaSignature().'-cleanup.sql'; - if(!file_exists($file)) //No cleanup script. - return 0; - - //We have a cleanup script ::XXX: Don't abort on error? - if($this->load_sql_file($file, $this->getTablePrefix(), false, true)) - return 0; - - //XXX: ??? - return false; - } - - - function migrateAttachments2DB($tId=0) { - echo "Process attachments here - $tId"; - return 0; - } -} - -/* - Installer class - latest version. - */ -class Installer extends SetupWizard { - - var $config; - - function Installer($configfile) { - $this->config =$configfile; - $this->errors=array(); - } - - function getConfigFile() { - return $this->config; - } - - function config_exists() { - return ($this->getConfigFile() && file_exists($this->getConfigFile())); - } - - function config_writable() { - return ($this->getConfigFile() && is_writable($this->getConfigFile())); - } - - function check_config() { - return ($this->config_exists() && $this->config_writable()); - } - - //XXX: Latest version insall logic...no carry over. - function install($vars) { - - $this->errors=$f=array(); - - $f['name'] = array('type'=>'string', 'required'=>1, 'error'=>'Name required'); - $f['email'] = array('type'=>'email', 'required'=>1, 'error'=>'Valid email required'); - $f['fname'] = array('type'=>'string', 'required'=>1, 'error'=>'First name required'); - $f['lname'] = array('type'=>'string', 'required'=>1, 'error'=>'Last name required'); - $f['admin_email'] = array('type'=>'email', 'required'=>1, 'error'=>'Valid email required'); - $f['username'] = array('type'=>'username', 'required'=>1, 'error'=>'Username required'); - $f['passwd'] = array('type'=>'password', 'required'=>1, 'error'=>'Password required'); - $f['passwd2'] = array('type'=>'string', 'required'=>1, 'error'=>'Confirm password'); - $f['prefix'] = array('type'=>'string', 'required'=>1, 'error'=>'Table prefix required'); - $f['dbhost'] = array('type'=>'string', 'required'=>1, 'error'=>'Hostname required'); - $f['dbname'] = array('type'=>'string', 'required'=>1, 'error'=>'Database name required'); - $f['dbuser'] = array('type'=>'string', 'required'=>1, 'error'=>'Username required'); - $f['dbpass'] = array('type'=>'string', 'required'=>1, 'error'=>'password required'); - - - if(!Validator::process($f,$vars,$this->errors) && !$this->errors['err']) - $this->errors['err']='Missing or invalid data - correct the errors and try again.'; - - - //Staff's email can't be same as system emails. - if($vars['admin_email'] && $vars['email'] && !strcasecmp($vars['admin_email'],$vars['email'])) - $this->errors['admin_email']='Conflicts with system email above'; - //Admin's pass confirmation. - if(!$this->errors && strcasecmp($vars['passwd'],$vars['passwd2'])) - $this->errors['passwd2']='passwords to not match!'; - //Check table prefix underscore required at the end! - if($vars['prefix'] && substr($vars['prefix'], -1)!='_') - $this->errors['prefix']='Bad prefix. Must have underscore (_) at the end. e.g \'ost_\''; - - //Make sure admin username is not very predictable. XXX: feels dirty but necessary - if(!$this->errors['username'] && in_array(strtolower($vars['username']),array('admin','admins','username','osticket'))) - $this->errors['username']='Bad username'; - - //MYSQL: Connect to the DB and check the version & database (create database if it doesn't exist!) - if(!$this->errors) { - if(!db_connect($vars['dbhost'],$vars['dbuser'],$vars['dbpass'])) - $this->errors['db']='Unable to connect to MySQL server. Possibly invalid login info.'; - elseif(db_version()< $this->getMySQLVersion()) - $this->errors['db']=sprintf('osTicket requires MySQL %s or better!',$this->getMySQLVersion()); - elseif(!db_select_database($vars['dbname']) && !db_create_database($vars['dbname'])) { - $this->errors['dbname']='Database doesn\'t exist'; - $this->errors['db']='Unable to create the database.'; - } elseif(!db_select_database($vars['dbname'])) { - $this->errors['dbname']='Unable to select the database'; - } - } - - //bailout on errors. - if($this->errors) return false; - - /*************** We're ready to install ************************/ - define('ADMIN_EMAIL',$vars['admin_email']); //Needed to report SQL errors during install. - define('PREFIX',$vars['prefix']); //Table prefix - - $schemaFile =INC_DIR.'sql/osticket-v1.7-mysql.sql'; //DB dump. - $debug = true; //XXX:Change it to true to show SQL errors. - - //Last minute checks. - if(!file_exists($schemaFile)) - $this->errors['err']='Internal Error - please make sure your download is the latest (#1)'; - elseif(!file_exists($this->getConfigFile()) || !($configFile=file_get_contents($this->getConfigFile()))) - $this->errors['err']='Unable to read config file. Permission denied! (#2)'; - elseif(!($fp = @fopen($this->getConfigFile(),'r+'))) - $this->errors['err']='Unable to open config file for writing. Permission denied! (#3)'; - elseif(!$this->load_sql_file($schemaFile,$vars['prefix'], true, $debug)) - $this->errors['err']='Error parsing SQL schema! Get help from developers (#4)'; - - if(!$this->errors) { - //Create admin user. - $sql='INSERT INTO '.PREFIX.'staff SET created=NOW() ' - .', isactive=1, isadmin=1, group_id=1, dept_id=1, timezone_id=8, max_page_size=25 ' - .', email='.db_input($_POST['admin_email']) - .', firstname='.db_input($vars['fname']) - .', lastname='.db_input($vars['lname']) - .', username='.db_input($vars['username']) - .', passwd='.db_input(Passwd::hash($vars['passwd'])); - if(!mysql_query($sql) || !($uid=mysql_insert_id())) - $this->errors['err']='Unable to create admin user (#6)'; - } - - if(!$this->errors) { - //Create config settings---default settings! - //XXX: rename ostversion helpdesk_* ?? - $sql='INSERT INTO '.PREFIX.'config SET updated=NOW(), isonline=0 ' - .', default_email_id=1, alert_email_id=2, default_dept_id=1 ' - .', default_sla_id=1, default_timezone_id=8, default_template_id=1 ' - .', admin_email='.db_input($vars['admin_email']) - .', schema_signature='.db_input(md5_file($schemaFile)) - .', helpdesk_url='.db_input(URL) - .', helpdesk_title='.db_input($vars['name']); - if(!mysql_query($sql) || !($cid=mysql_insert_id())) - $this->errors['err']='Unable to create config settings (#7)'; - } - - if($this->errors) return false; //Abort on internal errors. - - - //Rewrite the config file - MUST be done last to allow for installer recovery. - $configFile= str_replace("define('OSTINSTALLED',FALSE);","define('OSTINSTALLED',TRUE);",$configFile); - $configFile= str_replace('%ADMIN-EMAIL',$vars['admin_email'],$configFile); - $configFile= str_replace('%CONFIG-DBHOST',$vars['dbhost'],$configFile); - $configFile= str_replace('%CONFIG-DBNAME',$vars['dbname'],$configFile); - $configFile= str_replace('%CONFIG-DBUSER',$vars['dbuser'],$configFile); - $configFile= str_replace('%CONFIG-DBPASS',$vars['dbpass'],$configFile); - $configFile= str_replace('%CONFIG-PREFIX',$vars['prefix'],$configFile); - $configFile= str_replace('%CONFIG-SIRI',Misc::randcode(32),$configFile); - if(!$fp || !ftruncate($fp,0) || !fwrite($fp,$configFile)) { - $this->errors['err']='Unable to write to config file. Permission denied! (#5)'; - return false; - } - @fclose($fp); - - /************* Make the system happy ***********************/ - //Create default emails! - $email = $vars['email']; - list(,$domain)=explode('@',$vars['email']); - $sql='INSERT INTO '.PREFIX.'email (`email_id`, `dept_id`, `name`,`email`,`created`,`updated`) VALUES ' - ." (1,1,'Support','$email',NOW(),NOW())" - .",(2,1,'osTicket Alerts','alerts@$domain',NOW(),NOW())" - .",(3,1,'','noreply@$domain',NOW(),NOW())"; - @mysql_query($sql); - - //Create a ticket to make the system warm and happy. - $sql='INSERT INTO '.PREFIX.'ticket SET created=NOW(), status="open", source="Web" ' - .' ,priority_id=2, dept_id=1, topic_id=1 ' - .' ,ticketID='.db_input(Misc::randNumber(6)) - .' ,email="support@osticket.com" ' - .' ,name="osTicket Support" ' - .' ,subject="osTicket Installed!"'; - if(mysql_query($sql) && ($tid=mysql_insert_id())) { - if(!($msg=file_get_contents(INC_DIR.'msg/installed.txt'))) - $msg='Congratulations and Thank you for choosing osTicket!'; - - $sql='INSERT INTO '.PREFIX.'ticket_message SET created=NOW(),source="Web" ' - .', ticket_id='.db_input($tid) - .', message='.db_input($msg); - @mysql_query($sql); - } - //TODO: create another personalized ticket and assign to admin?? - - //Log a message. - $msg="Congratulations osTicket basic installation completed!\n\nThank you for choosing osTicket!"; - $sql='INSERT INTO '.PREFIX.'syslog SET created=NOW(),updated=NOW(),log_type="Debug" ' - .', title="osTicket installed!"' - .', log='.db_input($msg) - .', ip_address='.db_input($_SERVER['REMOTE_ADDR']); - @mysql_query($sql); - - return true; - } -} ?> diff --git a/setup/inc/sql/522e5b78-02decaa2.patch.sql b/setup/inc/sql/522e5b78-02decaa2.patch.sql index a6d9a6e09cc1c16aac70dc6a9b4a0f03987a6c9b..78c951d69cc10f255ffb3e4ba85fcf93dae6db58 100644 --- a/setup/inc/sql/522e5b78-02decaa2.patch.sql +++ b/setup/inc/sql/522e5b78-02decaa2.patch.sql @@ -1,4 +1,6 @@ -/* v1.7-DPR2-P2 */ +/** + * @version v1.7-DPR2-P2 + */ UPDATE `%TABLE_PREFIX%sla` SET `created` = NOW(), `updated` = NOW() diff --git a/setup/inc/sql/7be60a84-522e5b78.patch.sql b/setup/inc/sql/7be60a84-522e5b78.patch.sql index 35e744566d50f8a5e8d37d56c3fe3b795db2e1e5..acdaf7d0d3c1f8baaedd40bd68e33b01b97e72c9 100644 --- a/setup/inc/sql/7be60a84-522e5b78.patch.sql +++ b/setup/inc/sql/7be60a84-522e5b78.patch.sql @@ -1,4 +1,6 @@ -/* v1.7-DPR1 (P1) */ +/** + * @version v1.7-DPR1 (P1) + */ UPDATE `%TABLE_PREFIX%email_template` SET `ticket_overlimit_subj` = 'Open Tickets Limit Reached' WHERE `tpl_id` = 1 AND `cfg_id` = 1;