diff --git a/include/ajax.upgrader.php b/include/ajax.upgrader.php index 331d23d26bef97b89eddbf2e80170947a794b72f..d021086ef1a55c84745b741dcebc70df160613d7 100644 --- a/include/ajax.upgrader.php +++ b/include/ajax.upgrader.php @@ -32,7 +32,7 @@ class UpgraderAjaxAPI extends AjaxController { exit; } - if($upgrader->getNumPendingTasks() && $upgrader->doTasks()) { + if($upgrader->getTask() && $upgrader->doTask()) { //More pending tasks - doTasks returns the number of pending tasks Http::response(200, $upgrader->getNextAction()); exit; diff --git a/include/class.migrater.php b/include/class.migrater.php index f3d6c775dc50240deaf460b7586d961770422aed..b9dbdca2e663c01b9e7f506319367b4a16548175 100644 --- a/include/class.migrater.php +++ b/include/class.migrater.php @@ -102,216 +102,67 @@ class DatabaseMigrater { } } - -/* - AttachmentMigrater - - Attachment migration from file-based attachments in pre-1.7 to - database-backed attachments in osTicket v1.7. This class provides the - hardware to find and retrieve old attachments and move them into the new - database scheme with the data in the actual database. - - Copyright (c) 2006-2013 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: -*/ - -include_once(INCLUDE_DIR.'class.file.php'); - -class AttachmentMigrater { - - - function AttachmentMigrater() { - $this->queue = &$_SESSION['ost_upgrader']['AttachmentMigrater']['queue']; - $this->skipList = &$_SESSION['ost_upgrader']['AttachmentMigrater']['skip']; - $this->errorList = array(); - } - +class MigrationTask { + var $description = "[Unnamed task]"; + var $status = "finished"; /** - * Process the migration for a unit of time. This will be used to - * overcome the execution time restriction of PHP. This instance can be - * stashed in a session and have this method called periodically to - * process another batch of attachments + * Function: run + * + * (Abstract) method which will perform the migration task. The task + * does not have to be completed in one invocation; however, if the + * run() method is called again, the task should not be restarted from the + * beginning. The ::isFinished() method will be used to determine if the + * migration task has more work to be done. * - * Returns: - * Number of pending attachments to migrate. + * If ::isFinished() returns boolean false, then the run method will be + * called again. Note that the next invocation may be in a separate + * request. Ensure that you properly capture the state of the task before + * exiting the ::run() method. The entire MigrationTask instance is stored + * in the migration session, so all instance variables will be preserved + * between calls. + * + * Parameters: + * max_time - (int) number of seconds the task should be allowed to run */ - function do_batch($time=30, $max=0) { - - if(!$this->queueAttachments($max) || !$this->getQueueLength()) - return 0; - - $count = 0; - $start = Misc::micro_time(); - while ($this->getQueueLength() && (Misc::micro_time()-$start) < $time) - if($this->next() && $max && ++$count>=$max) - break; - - return $this->queueAttachments($max); - - } + /* abstract */ + function run($max_time) { } - function getSkipList() { - return $this->skipList; - } - - function enqueue($fileinfo) { - $this->queue[] = $fileinfo; - } - - function getQueue() { - return $this->queue; - } - - function getQueueLength() { return count($this->queue); } /** - * Processes the next item on the work queue. Emits a JSON messages to - * indicate current progress. + * Function: isFinished * - * Returns: - * TRUE/NULL if the migration was successful + * Returns boolean TRUE if another call to ::run() is required, and + * false otherwise */ - function next() { - # Fetch next item -- use the last item so the array indices don't - # need to be recalculated for every shift() operation. - $info = array_pop($this->queue); - # Attach file to the ticket - if (!($info['data'] = @file_get_contents($info['path']))) { - # Continue with next file - return $this->skip($info['attachId'], - sprintf('%s: Cannot read file contents', $info['path'])); - } - # Get the mime/type of each file - # XXX: Use finfo_buffer for PHP 5.3+ - if(function_exists('mime_content_type')) { - //XXX: function depreciated in newer versions of PHP!!!!! - $info['type'] = mime_content_type($info['path']); - } elseif (function_exists('finfo_file')) { // PHP 5.3.0+ - $finfo = finfo_open(FILEINFO_MIME_TYPE); - $info['type'] = finfo_file($finfo, $info['path']); - } - # TODO: Add extension-based mime-type lookup + /* abstract */ + function isFinished() { return true; } - if (!($fileId = AttachmentFile::save($info))) { - return $this->skip($info['attachId'], - sprintf('%s: Unable to migrate attachment', $info['path'])); - } - # Update the ATTACHMENT_TABLE record to set file_id - db_query('update '.TICKET_ATTACHMENT_TABLE - .' set file_id='.db_input($fileId) - .' where attach_id='.db_input($info['attachId'])); - # Remove disk image of the file. If this fails, the migration for - # this file would not be retried, because the file_id in the - # TICKET_ATTACHMENT_TABLE has a nonzero value now - if (!@unlink($info['path'])) //XXX: what should we do on failure? - $this->error( - sprintf('%s: Unable to remove file from disk', - $info['path'])); - # TODO: Log an internal note to the ticket? - return true; - } /** - * From (class Ticket::fixAttachments), used to detect the locations of - * attachment files + * Funciton: sleep + * + * Called if isFinished() returns false. The data returned is passed to + * the ::wakeup() method before the ::run() method is called again */ - /* static */ function queueAttachments($limit=0){ - global $cfg, $ost; - - # Since the queue is persistent - we want to make sure we get to empty - # before we find more attachments. - if(($qc=$this->getQueueLength())) - return $qc; - - $sql='SELECT attach_id, file_name, file_key, Ti.created' - .' FROM '.TICKET_ATTACHMENT_TABLE.' TA' - .' INNER JOIN '.TICKET_TABLE.' Ti ON (Ti.ticket_id=TA.ticket_id)' - .' WHERE NOT file_id '; - - if(($skipList=$this->getSkipList())) - $sql.= ' AND attach_id NOT IN('.implode(',', db_input($skipList)).')'; - - if($limit && is_numeric($limit)) - $sql.=' LIMIT '.$limit; - - //XXX: Do a hard fail or error querying the database? - if(!($res=db_query($sql))) - return $this->error('Unable to query DB for attached files to migrate!'); - - $ost->logDebug("Attachment migration", 'Found '.db_num_rows($res).' attachments to migrate'); - if(!db_num_rows($res)) - return 0; //Nothing else to do!! + function sleep() { return null; } - $dir=$cfg->getUploadDir(); - if(!$dir || !is_dir($dir)) //XXX: Abort the upgrade??? Attachments are obviously critical! - return $this->error("Attachment directory [$dir] is invalid - aborting attachment migration"); - - //Clear queue - $this->queue = array(); - while (list($id,$name,$key,$created)=db_fetch_row($res)) { - $month=date('my',strtotime($created)); - $info=array( - 'name'=> $name, - 'attachId'=> $id, - ); - $filename15=sprintf("%s/%s_%s",rtrim($dir,'/'),$key,$name); - $filename16=sprintf("%s/%s/%s_%s",rtrim($dir,'/'),$month,$key,$name); //new destination. - if (file_exists($filename15)) { - $info['path'] = $filename15; - } elseif (file_exists($filename16)) { - $info['path'] = $filename16; - } else { - # XXX Cannot find file for attachment - $this->skip($id, - sprintf('%s: Unable to locate attachment file', - $name)); - # No need to further process this file - continue; - } - # TODO: Get the size and mime/type of each file. - # - # NOTE: If filesize() fails and file_get_contents() doesn't, - # then the AttachmentFile::save() method will automatically - # estimate the filesize based on the length of the string data - # received in $info['data'] -- ie. no need to do that here. - # - # NOTE: The size is done here because it should be quick to - # lookup out of file inode already loaded. The mime/type may - # take a while because it will require a second IO to read the - # file data. To ensure this will finish before the - # max_execution_time, perform the type match in the ::next() - # method since the entire file content will be read there - # anyway. - $info['size'] = @filesize($info['path']); - # Coroutines would be nice .. - $this->enqueue($info); - } - - return $this->queueAttachments($limit); - } - - function skip($attachId, $error) { - - $this->skipList[] = $attachId; + /** + * Function: wakeup + * + * Called before the ::run() method if the migration task was saved in + * the session and run in multiple requests + */ + function wakeup($data) { } - return $this->error($error." (ID #$attachId)"); + function getDescription() { + return $this->description; } - function error($what) { - global $ost; - - $this->errors++; - $this->errorList[] = $what; - $ost->logDebug('Upgrader: Attachment Migrater', $what); - # Assist in returning FALSE for inline returns with this method - return false; + function getStatus() { + return $this->status; } - function getErrors() { - return $this->errorList; + function setStatus($message) { + $this->status = $message; } } + ?> diff --git a/include/class.upgrader.php b/include/class.upgrader.php index b09aabe48d43ba70545556ac10b0c4c5c2199d28..e76f9cb1ecb1b42ae1152851d7668dc6b8981d42 100644 --- a/include/class.upgrader.php +++ b/include/class.upgrader.php @@ -102,14 +102,8 @@ class Upgrader { return $this->getCurrentStream()->check_mysql(); } - function getNumPendingTasks() { - if ($this->getCurrentStream()) - return $this->getCurrentStream()->getNumPendingTasks(); - } - - function doTasks() { - if ($this->getNumPendingTasks()) - return $this->getCurrentStream()->doTasks(); + function doTask() { + return $this->getCurrentStream()->doTask(); } function getErrors() { @@ -155,6 +149,8 @@ class StreamUpgrader extends SetupWizard { var $state; var $mode; + var $phash; + /** * Parameters: * schema_signature - (string<hash-hex>) Current database-reflected (via @@ -181,13 +177,12 @@ class StreamUpgrader extends SetupWizard { if(!ini_get('safe_mode')) set_time_limit(0); - //Init the task Manager. if(!isset($_SESSION['ost_upgrader'][$this->getShash()])) - $_SESSION['ost_upgrader'][$this->getShash()]['tasks']=array(); + $_SESSION['ost_upgrader']['task'] = array(); //Tasks to perform - saved on the session. - $this->tasks = &$_SESSION['ost_upgrader'][$this->getShash()]['tasks']; + $this->phash = &$_SESSION['ost_upgrader']['phash']; //Database migrater $this->migrater = null; @@ -287,10 +282,8 @@ class StreamUpgrader extends SetupWizard { 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'].')'; + if($task=$this->getTask()) { + $action = $task->getDescription() .' ('.$task->getStatus().')'; } elseif($this->isUpgradable() && ($nextversion = $this->getNextVersion())) { $action = "Upgrade to $nextversion"; } @@ -298,77 +291,62 @@ class StreamUpgrader extends SetupWizard { return '['.$this->name.'] '.$action; } - function getNumPendingTasks() { - - return count($this->getPendingTasks()); - } - - function getPendingTasks() { + function getPendingTask() { $pending=array(); - if(($tasks=$this->getTasks())) { - foreach($tasks as $k => $task) { - if(!$task['done']) - $pending[$k] = $task; - } - } - - return $pending; - } + if ($task=$this->getTask()) + return ($task->isFinished()) ? 1 : 0; - function getTasks() { - return $this->tasks; + return false; } - function getNextTask() { - - if(!($tasks=$this->getPendingTasks())) + function getTask() { + $task_file = $this->getSQLDir() . "{$this->phash}.task.php"; + if (!file_exists($task_file)) 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; + if (!isset($this->task)) { + $class = (include $task_file); + if (!is_string($class) || !class_exists($class)) + return $ost->logError("{$phash}:{$class}: Bogus migration task"); + $this->task = new $class(); + if (isset($_SESSION['ost_upgrader']['task'][$this->phash])) + $this->task->wakeup($_SESSION['ost_upgrader']['task'][$this->phash]); + } + return $this->task; } - function doTasks() { + function doTask() { global $ost; - if(!($tasks=$this->getPendingTasks())) - return true; //Nothing to do. + if(!($task = $this->getTask())) + return false; //Nothing to do. - $c = count($tasks); $ost->logDebug( - sprintf('Upgrader - %s (%d pending tasks).', $this->getShash(), $c), - sprintf('There are %d pending upgrade tasks for %s patch', $c, $this->getShash()) + sprintf('Upgrader - %s (task pending).', $this->getShash()), + sprintf('The %s task reports there is work to do', + get_class($task)) ); - $start_time = Misc::micro_time(); - foreach($tasks as $k => $task) { - //TODO: check time used vs. max execution - break if need be - if(call_user_func(array($this, $task['func']), $k)===0) { - $this->tasks[$k]['done'] = true; - } else { //Task has pending items to process. - break; - } - } + if(!($max_time = ini_get('max_execution_time'))) + $max_time = 30; //Default to 30 sec batches. - return $this->getPendingTasks(); + $task->run($max_time); + if (!$task->isFinished()) { + $_SESSION['ost_upgrader']['task'][$this->phash] = $task->sleep(); + return true; + } + // Run the cleanup script, if any, and destroy the task's session + // data + $this->cleanup(); + unset($_SESSION['ost_upgrader']['task'][$this->phash]); + unset($this->phash); + return false; } function upgrade() { global $ost; - if($this->getPendingTasks() || !($patches=$this->getPatches())) + if($this->getPendingTask() || !($patches=$this->getPatches())) return false; $start_time = Misc::micro_time(); @@ -394,19 +372,20 @@ class StreamUpgrader extends SetupWizard { $ost->logDebug("Upgrader - $shash applied", $logMsg); $this->signature = $shash; //Update signature to the *new* HEAD + $this->phash = $phash; - //Check if the said patch has scripted tasks - if(!($tasks=$this->getTasksForPatch($phash))) { - //Break IF elapsed time is greater than 80% max time allowed. - if(($elapsedtime=(Misc::micro_time()-$start_time)) && $max_time && $elapsedtime>($max_time*0.80)) + //Break IF elapsed time is greater than 80% max time allowed. + if (!($task=$this->getTask())) { + $this->cleanup(); + if (($elapsedtime=(Misc::micro_time()-$start_time)) + && $max_time && $elapsedtime>($max_time*0.80)) break; - - continue; - + else + // Apply the next patch + continue; } //We have work to do... set the tasks and break. - $_SESSION['ost_upgrader'][$shash]['tasks'] = $tasks; $_SESSION['ost_upgrader'][$shash]['state'] = 'upgrade'; break; } @@ -415,47 +394,13 @@ class StreamUpgrader extends SetupWizard { $this->migrater = null; return true; - - } - - function getTasksForPatch($phash) { - - $tasks=array(); - switch($phash) { //Add patch specific scripted tasks. - case 'c00511c7-7be60a84': //V1.6 ST- 1.7 * {{MD5('1.6 ST') -> c00511c7c1db65c0cfad04b4842afc57}} - $tasks[] = array('func' => 'migrateSessionFile2DB', - 'desc' => 'Transitioning to db-backed sessions'); - break; - case '98ae1ed2-e342f869': //v1.6 RC1-4 -> v1.6 RC5 - $tasks[] = array('func' => 'migrateAPIKeys', - 'desc' => 'Migrating API keys to a new table'); - break; - case '435c62c3-2e7531a2': - $tasks[] = array('func' => 'migrateGroupDeptAccess', - 'desc' => 'Migrating group\'s department access to a new table'); - break; - case '15b30765-dd0022fb': - $tasks[] = array('func' => 'migrateAttachments2DB', - 'desc' => 'Migrating attachments to database, it might take a while depending on the number of files.'); - break; - } - - //Check IF SQL cleanup exists. - $file=$this->getSQLDir().$phash.'.cleanup.sql'; - if(file_exists($file)) - $tasks[] = array('func' => 'cleanup', - 'desc' => 'Post-upgrade cleanup!', - 'phash' => $phash); - - return $tasks; } /************* TASKS **********************/ - function cleanup($taskId) { + function cleanup() { global $ost; - $phash = $this->tasks[$taskId]['phash']; - $file=$this->getSQLDir().$phash.'.cleanup.sql'; + $file = $this->getSQLDir().$this->phash.'.cleanup.sql'; if(!file_exists($file)) //No cleanup script. return 0; @@ -468,64 +413,5 @@ class StreamUpgrader extends SetupWizard { $phash)); return 0; } - - function migrateAttachments2DB($taskId) { - global $ost; - - if(!($max_time = ini_get('max_execution_time'))) - $max_time = 30; //Default to 30 sec batches. - - $att_migrater = new AttachmentMigrater(); - if($att_migrater->do_batch(($max_time*0.9), 100)===0) - return 0; - - return $att_migrater->getQueueLength(); - } - - function migrateSessionFile2DB($taskId) { - # How about 'dis for a hack? - osTicketSession::write(session_id(), session_encode()); - return 0; - } - - function migrateAPIKeys($taskId) { - - $res = db_query('SELECT api_whitelist, api_key FROM '.CONFIG_TABLE.' WHERE id=1'); - if(!$res || !db_num_rows($res)) - return 0; //Reporting success. - - list($whitelist, $key) = db_fetch_row($res); - - $ips=array_filter(array_map('trim', explode(',', $whitelist))); - foreach($ips as $ip) { - $sql='INSERT INTO '.API_KEY_TABLE.' SET created=NOW(), updated=NOW(), isactive=1 ' - .',ipaddr='.db_input($ip) - .',apikey='.db_input(strtoupper(md5($ip.md5($key)))); - db_query($sql); - } - - return 0; - } - - function migrateGroupDeptAccess($taskId) { - - $res = db_query('SELECT group_id, dept_access FROM '.GROUP_TABLE); - if(!$res || !db_num_rows($res)) - return 0; //No groups?? - - while(list($groupId, $access) = db_fetch_row($res)) { - $depts=array_filter(array_map('trim', explode(',', $access))); - foreach($depts as $deptId) { - $sql='INSERT INTO '.GROUP_DEPT_TABLE - .' SET dept_id='.db_input($deptId).', group_id='.db_input($groupId); - db_query($sql); - } - } - - return 0; - - - - } } ?> diff --git a/include/upgrader/streams/core/15b30765-dd0022fb.task.php b/include/upgrader/streams/core/15b30765-dd0022fb.task.php new file mode 100644 index 0000000000000000000000000000000000000000..6e2739218ad0e9499fafc14294df6fefd5c4b1e9 --- /dev/null +++ b/include/upgrader/streams/core/15b30765-dd0022fb.task.php @@ -0,0 +1,230 @@ +<?php +/********************************************************************* + AttachmentMigrater + + Attachment migration from file-based attachments in pre-1.7 to + database-backed attachments in osTicket v1.7. This class provides the + hardware to find and retrieve old attachments and move them into the new + database scheme with the data in the actual database. + + Copyright (c) 2006-2013 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: +**********************************************************************/ +require_once INCLUDE_DIR.'class.migrater.php'; +require_once(INCLUDE_DIR.'class.file.php'); + +class AttachmentMigrater extends MigrationTask { + var $description = "Attachment migration from disk to database"; + + var $queue; + var $skipList; + var $errorList = array(); + + function sleep() { + return array('queue'=>$this->queue, 'skipList'=>$this->skipList); + } + function wakeup($stuff) { + $this->queue = $stuff['queue']; + $this->skipList = $stuff['skipList']; + } + + function run($max_time) { + $this->do_batch($max_time * 0.9, 100); + } + + function isFinished() { + return $this->getQueueLength() == 0; + } + + /** + * Process the migration for a unit of time. This will be used to + * overcome the execution time restriction of PHP. This instance can be + * stashed in a session and have this method called periodically to + * process another batch of attachments + * + * Returns: + * Number of pending attachments to migrate. + */ + function do_batch($time=30, $max=0) { + + if(!$this->queueAttachments($max) || !$this->getQueueLength()) + return 0; + + $this->setStatus("{$this->getQueueLength()} attachments remaining"); + + $count = 0; + $start = Misc::micro_time(); + while ($this->getQueueLength() && (Misc::micro_time()-$start) < $time) + if($this->next() && $max && ++$count>=$max) + break; + + return $this->queueAttachments($max); + + } + + function getSkipList() { + return $this->skipList; + } + + function enqueue($fileinfo) { + $this->queue[] = $fileinfo; + } + + function getQueue() { + return $this->queue; + } + + function getQueueLength() { return count($this->queue); } + /** + * Processes the next item on the work queue. Emits a JSON messages to + * indicate current progress. + * + * Returns: + * TRUE/NULL if the migration was successful + */ + function next() { + # Fetch next item -- use the last item so the array indices don't + # need to be recalculated for every shift() operation. + $info = array_pop($this->queue); + # Attach file to the ticket + if (!($info['data'] = @file_get_contents($info['path']))) { + # Continue with next file + return $this->skip($info['attachId'], + sprintf('%s: Cannot read file contents', $info['path'])); + } + # Get the mime/type of each file + # XXX: Use finfo_buffer for PHP 5.3+ + if(function_exists('mime_content_type')) { + //XXX: function depreciated in newer versions of PHP!!!!! + $info['type'] = mime_content_type($info['path']); + } elseif (function_exists('finfo_file')) { // PHP 5.3.0+ + $finfo = finfo_open(FILEINFO_MIME_TYPE); + $info['type'] = finfo_file($finfo, $info['path']); + } + # TODO: Add extension-based mime-type lookup + + if (!($fileId = AttachmentFile::save($info))) { + return $this->skip($info['attachId'], + sprintf('%s: Unable to migrate attachment', $info['path'])); + } + # Update the ATTACHMENT_TABLE record to set file_id + db_query('update '.TICKET_ATTACHMENT_TABLE + .' set file_id='.db_input($fileId) + .' where attach_id='.db_input($info['attachId'])); + # Remove disk image of the file. If this fails, the migration for + # this file would not be retried, because the file_id in the + # TICKET_ATTACHMENT_TABLE has a nonzero value now + if (!@unlink($info['path'])) //XXX: what should we do on failure? + $this->error( + sprintf('%s: Unable to remove file from disk', + $info['path'])); + # TODO: Log an internal note to the ticket? + return true; + } + /** + * From (class Ticket::fixAttachments), used to detect the locations of + * attachment files + */ + /* static */ function queueAttachments($limit=0){ + global $cfg, $ost; + + # Since the queue is persistent - we want to make sure we get to empty + # before we find more attachments. + if(($qc=$this->getQueueLength())) + return $qc; + + $sql='SELECT attach_id, file_name, file_key, Ti.created' + .' FROM '.TICKET_ATTACHMENT_TABLE.' TA' + .' INNER JOIN '.TICKET_TABLE.' Ti ON (Ti.ticket_id=TA.ticket_id)' + .' WHERE NOT file_id '; + + if(($skipList=$this->getSkipList())) + $sql.= ' AND attach_id NOT IN('.implode(',', db_input($skipList)).')'; + + if($limit && is_numeric($limit)) + $sql.=' LIMIT '.$limit; + + //XXX: Do a hard fail or error querying the database? + if(!($res=db_query($sql))) + return $this->error('Unable to query DB for attached files to migrate!'); + + $ost->logDebug("Attachment migration", 'Found '.db_num_rows($res).' attachments to migrate'); + if(!db_num_rows($res)) + return 0; //Nothing else to do!! + + $dir=$cfg->getUploadDir(); + if(!$dir || !is_dir($dir)) //XXX: Abort the upgrade??? Attachments are obviously critical! + return $this->error("Attachment directory [$dir] is invalid - aborting attachment migration"); + + //Clear queue + $this->queue = array(); + while (list($id,$name,$key,$created)=db_fetch_row($res)) { + $month=date('my',strtotime($created)); + $info=array( + 'name'=> $name, + 'attachId'=> $id, + ); + $filename15=sprintf("%s/%s_%s",rtrim($dir,'/'),$key,$name); + $filename16=sprintf("%s/%s/%s_%s",rtrim($dir,'/'),$month,$key,$name); //new destination. + if (file_exists($filename15)) { + $info['path'] = $filename15; + } elseif (file_exists($filename16)) { + $info['path'] = $filename16; + } else { + # XXX Cannot find file for attachment + $this->skip($id, + sprintf('%s: Unable to locate attachment file', + $name)); + # No need to further process this file + continue; + } + # TODO: Get the size and mime/type of each file. + # + # NOTE: If filesize() fails and file_get_contents() doesn't, + # then the AttachmentFile::save() method will automatically + # estimate the filesize based on the length of the string data + # received in $info['data'] -- ie. no need to do that here. + # + # NOTE: The size is done here because it should be quick to + # lookup out of file inode already loaded. The mime/type may + # take a while because it will require a second IO to read the + # file data. To ensure this will finish before the + # max_execution_time, perform the type match in the ::next() + # method since the entire file content will be read there + # anyway. + $info['size'] = @filesize($info['path']); + # Coroutines would be nice .. + $this->enqueue($info); + } + + return $this->queueAttachments($limit); + } + + function skip($attachId, $error) { + + $this->skipList[] = $attachId; + + return $this->error($error." (ID #$attachId)"); + } + + function error($what) { + global $ost; + + $this->errors++; + $this->errorList[] = $what; + $ost->logDebug('Upgrader: Attachment Migrater', $what); + # Assist in returning FALSE for inline returns with this method + return false; + } + function getErrors() { + return $this->errorList; + } +} + +return 'AttachmentMigrater'; +?> diff --git a/include/upgrader/streams/core/435c62c3-2e7531a2.task.php b/include/upgrader/streams/core/435c62c3-2e7531a2.task.php new file mode 100644 index 0000000000000000000000000000000000000000..d80bc23a2e616248409c3c3780e3eedfca975799 --- /dev/null +++ b/include/upgrader/streams/core/435c62c3-2e7531a2.task.php @@ -0,0 +1,26 @@ +<?php +require_once INCLUDE_DIR.'class.migrater.php'; + +class MigrateGroupDeptAccess extends MigrationTask { + var $description = "Migrate department access for groups from v1.6"; + + function run($max_time) { + $this->setStatus("Migrating department access"); + + $res = db_query('SELECT group_id, dept_access FROM '.GROUP_TABLE); + if(!$res || !db_num_rows($res)) + return false; //No groups?? + + while(list($groupId, $access) = db_fetch_row($res)) { + $depts=array_filter(array_map('trim', explode(',', $access))); + foreach($depts as $deptId) { + $sql='INSERT INTO '.GROUP_DEPT_TABLE + .' SET dept_id='.db_input($deptId).', group_id='.db_input($groupId); + db_query($sql); + } + } + } +} + +return 'MigrateGroupDeptAccess'; +?> diff --git a/include/upgrader/streams/core/98ae1ed2-e342f869.task.php b/include/upgrader/streams/core/98ae1ed2-e342f869.task.php new file mode 100644 index 0000000000000000000000000000000000000000..e479410b55fcbc2662ecab48a95556dc7a1a9cbf --- /dev/null +++ b/include/upgrader/streams/core/98ae1ed2-e342f869.task.php @@ -0,0 +1,25 @@ +<?php +require_once INCLUDE_DIR.'class.migrater.php'; + +class APIKeyMigrater extends MigrationTask { + var $description = "Migrating v1.6 API keys"; + + function run() { + $res = db_query('SELECT api_whitelist, api_key FROM '.CONFIG_TABLE.' WHERE id=1'); + if(!$res || !db_num_rows($res)) + return 0; //Reporting success. + + list($whitelist, $key) = db_fetch_row($res); + + $ips=array_filter(array_map('trim', explode(',', $whitelist))); + foreach($ips as $ip) { + $sql='INSERT INTO '.API_KEY_TABLE.' SET created=NOW(), updated=NOW(), isactive=1 ' + .',ipaddr='.db_input($ip) + .',apikey='.db_input(strtoupper(md5($ip.md5($key)))); + db_query($sql); + } + } +} + +return 'APIKeyMigrater'; +?> diff --git a/include/upgrader/streams/core/c00511c7-7be60a84.task.php b/include/upgrader/streams/core/c00511c7-7be60a84.task.php new file mode 100644 index 0000000000000000000000000000000000000000..eca25aee2c623a13a956d2d7df13843ba4b7bee0 --- /dev/null +++ b/include/upgrader/streams/core/c00511c7-7be60a84.task.php @@ -0,0 +1,14 @@ +<?php +require_once INCLUDE_DIR.'class.migrater.php'; + +class MigrateDbSession extends MigrationTask { + var $description = "Migrate to database-backed sessions"; + + function run() { + # How about 'dis for a hack? + osTicketSession::write(session_id(), session_encode()); + } +} + +return 'MigrateDbSession'; +?>