2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4 * SugarCRM Community Edition is a customer relationship management program developed by
5 * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
7 * This program is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Affero General Public License version 3 as published by the
9 * Free Software Foundation with the addition of the following permission added
10 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
19 * You should have received a copy of the GNU Affero General Public License along with
20 * this program; if not, see http://www.gnu.org/licenses or write to the Free
21 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
27 * The interactive user interfaces in modified source and object code versions
28 * of this program must display Appropriate Legal Notices, as required under
29 * Section 5 of the GNU Affero General Public License version 3.
31 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32 * these Appropriate Legal Notices must retain the display of the "Powered by
33 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34 * technical reasons, the Appropriate Legal Notices must display the words
35 * "Powered by SugarCRM".
36 ********************************************************************************/
42 * Helper function for upgrade - get path from upload:// name
46 function getUploadRelativeName($path)
48 if(class_exists('UploadFile')) {
49 return UploadFile::realpath($path);
51 if(substr($path, 0, 9) == "upload://") {
52 $path = rtrim($GLOBALS['sugar_config']['upload_dir'], "/\\")."/".substr($path, 9);
58 * Backs-up files that are targeted for patch/upgrade to a restore directory
59 * @param string rest_dir Full path to the directory containing the original, replaced files.
60 * @param string install_file Full path to the uploaded patch/upgrade zip file
61 * @param string unzip_dir Full path to the unzipped files in a temporary directory
62 * @param string zip_from_dir Name of directory that the unzipped files containing the actuall replacement files
63 * @param array errors Collection of errors to be displayed at end of process
64 * @param string path Optional full path to the log file.
65 * @return array errors
67 function commitMakeBackupFiles($rest_dir, $install_file, $unzip_dir, $zip_from_dir, $errors, $path='') {
69 // create restore file directory
70 sugar_mkdir($rest_dir, 0775, true);
72 if(file_exists($rest_dir) && is_dir($rest_dir)){
73 logThis('backing up files to be overwritten...', $path);
74 $newFiles = findAllFiles(clean_path($unzip_dir . '/' . $zip_from_dir), array());
76 // keep this around for canceling
77 $_SESSION['uw_restore_dir'] = getUploadRelativeName($rest_dir);
79 foreach ($newFiles as $file) {
80 if (strpos($file, 'md5'))
83 // get name of current file to place in restore directory
84 $cleanFile = str_replace(clean_path($unzip_dir . '/' . $zip_from_dir), '', $file);
86 // make sure the directory exists
87 $cleanDir = $rest_dir . '/' . dirname($cleanFile);
88 sugar_mkdir($cleanDir, 0775, true);
89 $oldFile = clean_path(getcwd() . '/' . $cleanFile);
91 // only copy restore files for replacements - ignore new files from patch
92 if (is_file($oldFile)) {
93 if (is_writable($rest_dir)) {
94 logThis('Backing up file: ' . $oldFile, $path);
95 if (!copy($oldFile, $rest_dir . '/' . $cleanFile)) {
96 logThis('*** ERROR: could not backup file: ' . $oldFile, $path);
97 $errors[] = "{$mod_strings['LBL_UW_BACKUP']}::{$mod_strings['ERR_UW_FILE_NOT_COPIED']}: {$oldFile}";
99 $backupFilesExist = true;
103 logThis('*** ERROR: directory not writable: ' . $rest_dir, $path);
104 $errors[] = "{$mod_strings['LBL_UW_BACKUP']}::{$mod_strings['ERR_UW_DIR_NOT_WRITABLE']}: {$oldFile}";
109 logThis('file backup done.', $path);
114 * Copies files from the unzipped patch to the destination.
115 * @param string unzip_dir Full path to the temporary directory created during unzip operation.
116 * @param string zip_from_dir Name of folder containing the unzipped files; usually the name of the Patch without the
118 * @param string path Optional full path to alternate upgradeWizard log file.
119 * @return array Two element array containing to $copiedFiles and $skippedFiles.
124 function commitCopyNewFiles($unzip_dir, $zip_from_dir, $path='') {
125 logThis('Starting file copy process...', $path);
126 global $sugar_version;
128 if(substr($sugar_version,0,1) >= 5){
129 $modules = getAllModules();
130 $backwardModules = array();
131 foreach($modules as $mod){
132 if(is_dir(clean_path(getcwd().'/modules/'.$mod.'/.500'))){
134 $files= findAllFiles(clean_path(getcwd().'/modules/'.$mod.'/.500'),$files);
135 if(sizeof($files) >0){
136 //backward compatibility is on
137 $backwardModules[] = $mod;
143 $newFiles = findAllFiles(clean_path($unzip_dir . '/' . $zip_from_dir), array());
144 $zipPath = clean_path($unzip_dir . '/' . $zip_from_dir);
146 // handle special do-not-overwrite conditions
147 $doNotOverwrite = array();
148 $doNotOverwrite[] = '__stub';
149 if(isset($_REQUEST['overwrite_files_serial'])) {
150 $doNotOverwrite = explode('::', $_REQUEST['overwrite_files_serial']);
153 $copiedFiles = array();
154 $skippedFiles = array();
156 foreach($newFiles as $file) {
157 $cleanFile = str_replace($zipPath, '', $file);
158 $srcFile = $zipPath . $cleanFile;
159 $targetFile = clean_path(getcwd() . '/' . $cleanFile);
160 if($backwardModules != null && sizeof($backwardModules) >0){
161 foreach($backwardModules as $mod){
162 $splitPath = explode('/',trim($cleanFile));
163 if('modules' == trim($splitPath[1]) && $mod == trim($splitPath[2])){
164 $cleanFile = str_replace('/modules/'.$mod, '/modules/'.$mod.'/.500', $cleanFile);
165 $targetFile = clean_path(getcwd() . '/' . $cleanFile);
169 if(!is_dir(dirname($targetFile))) {
170 mkdir_recursive(dirname($targetFile)); // make sure the directory exists
173 if((!file_exists($targetFile)) || /* brand new file */
174 (!in_array($targetFile, $doNotOverwrite)) /* manual diff file */
176 // handle sugar_version.php
177 if(strpos($targetFile, 'sugar_version.php') !== false && !preg_match('/\/portal\/sugar_version\.php$/i', $targetFile)) {
178 logThis('Skipping "sugar_version.php" - file copy will occur at end of successful upgrade', $path);
179 $_SESSION['sugar_version_file'] = $srcFile;
183 //logThis('Copying file to destination: ' . $targetFile, $path);
185 if(!copy($srcFile, $targetFile)) {
186 logThis('*** ERROR: could not copy file: ' . $targetFile, $path);
188 $copiedFiles[] = $targetFile;
191 //logThis('Skipping file: ' . $targetFile, $path);
192 $skippedFiles[] = $targetFile;
195 logThis('File copy done.', $path);
198 $ret['copiedFiles'] = $copiedFiles;
199 $ret['skippedFiles'] = $skippedFiles;
205 //On cancel put back the copied files from 500 to 451 state
206 function copyFilesOnCancel($step){
207 //place hoder for cancel action
212 function removeFileFromPath($file,$path, $deleteNot=array()){
214 $cur = $path . '/' . $file;
215 if(file_exists($cur)){
217 foreach($deleteNot as $dn){
227 if(!file_exists($path))return $removed;
229 while(false !== ($e = $d->read())){ // Fixed bug. !== is required to literally match the type and value of false, so that a filename that could evaluate and cast to false, ie "false" or "0", still allows the while loop to continue. From example at http://www.php.net/manual/en/function.dir.php
230 $next = $path . '/'. $e;
231 if(substr($e, 0, 1) != '.' && is_dir($next)){
232 $removed += removeFileFromPath($file, $next, $deleteNot);
235 $d->close(); // from example at http://www.php.net/manual/en/function.dir.php
240 * This function copies/overwrites between directories
242 * @param string the directory name to remove
243 * @param boolean whether to just empty the given directory, without deleting the given directory.
244 * @return boolean True/False whether the directory was deleted.
247 function copyRecursiveBetweenDirectories($from,$to){
248 if(file_exists($from)){
249 $modifiedFiles = array();
250 $modifiedFiles = findAllFiles(clean_path($from), $modifiedFiles);
251 $cwd = clean_path(getcwd());
252 foreach($modifiedFiles as $file) {
253 $srcFile = clean_path($file);
254 if (strpos($srcFile,".svn") === false) {
255 $targetFile = str_replace($from, $to, $srcFile);
257 if(!is_dir(dirname($targetFile))) {
258 mkdir_recursive(dirname($targetFile)); // make sure the directory exists
261 // handle sugar_version.php
262 if(strpos($targetFile, 'sugar_version.php') !== false && !preg_match('/\/portal\/sugar_version\.php$/i', $targetFile)) {
263 logThis('Skipping "sugar_version.php" - file copy will occur at end of successful upgrade', $targetFile);
264 $_SESSION['sugar_version_file'] = $srcFile;
268 if(!copy($srcFile, $targetFile)) {
269 logThis("*** ERROR: could not copy file $srcFile to $targetFile");
276 function deleteDirectory($dirname,$only_empty=false) {
277 if (!is_dir($dirname))
279 $dscan = array(realpath($dirname));
281 while (!empty($dscan)) {
282 $dcur = array_pop($dscan);
284 if ($d=opendir($dcur)) {
285 while ($f=readdir($d)) {
286 if ($f=='.' || $f=='..')
297 $i_until = ($only_empty)? 1 : 0;
298 for ($i=count($darr)-1; $i>=$i_until; $i--) {
299 if (rmdir($darr[$i]))
300 logThis('Success :Copying file to destination: ' . $darr[$i]);
302 logThis('Copy problem:Copying file to destination: ' . $darr[$i]);
304 return (($only_empty)? (count(scandir)<=2) : (!is_dir($dirname)));
307 * Get all the customized modules. Compare the file md5s with the base md5s
308 * If a file has been modified then put the module in the list of customized
309 * modules. Show the list in the preflight check UI.
312 function deleteAndOverWriteSelectedFiles($unzip_dir, $zip_from_dir,$delete_dirs){
313 if($delete_dirs != null){
314 foreach($delete_dirs as $del_dir){
315 deleteDirectory($del_dir);
316 $newFiles = findAllFiles(clean_path($unzip_dir . '/' . $zip_from_dir.'/'.$del_dir), array());
317 $zipPath = clean_path($unzip_dir . '/' . $zip_from_dir.'/'.$del_dir);
318 $copiedFiles = array();
319 $skippedFiles = array();
321 foreach($newFiles as $file) {
322 $cleanFile = str_replace($zipPath, '', $file);
323 $srcFile = $zipPath . $cleanFile;
324 $targetFile = clean_path(getcwd() . '/' . $cleanFile);
326 if(!is_dir(dirname($targetFile))) {
327 mkdir_recursive(dirname($targetFile)); // make sure the directory exists
330 if(!file_exists($targetFile)){
331 // handle sugar_version.php
332 if(strpos($targetFile, 'sugar_version.php') !== false) {
333 logThis('Skipping sugar_version.php - file copy will occur at end of successful upgrade');
334 $_SESSION['sugar_version_file'] = $srcFile;
338 //logThis('Copying file to destination: ' . $targetFile);
340 if(!copy($srcFile, $targetFile)) {
341 logThis('*** ERROR: could not copy file: ' . $targetFile);
343 $copiedFiles[] = $targetFile;
346 //logThis('Skipping file: ' . $targetFile);
347 $skippedFiles[] = $targetFile;
353 $ret['copiedFiles'] = $copiedFiles;
354 $ret['skippedFiles'] = $skippedFiles;
359 //Default is empty the directory. For removing set it to false
360 // to use this function to totally remove a directory, write:
361 // recursive_remove_directory('path/to/directory/to/delete',FALSE);
363 // to use this function to empty a directory, write:
364 // recursive_remove_directory('path/to/full_directory');
366 function recursive_empty_or_remove_directory($directory, $exclude_dirs=null,$exclude_files=null,$empty=TRUE)
368 // if the path has a slash at the end we remove it here
369 if(substr($directory,-1) == '/')
371 $directory = substr($directory,0,-1);
374 // if the path is not valid or is not a directory ...
375 if(!file_exists($directory) || !is_dir($directory))
377 // ... we return false and exit the function
380 // ... if the path is not readable
381 }elseif(!is_readable($directory))
383 // ... we return false and exit the function
386 // ... else if the path is readable
389 // we open the directory
390 $handle = opendir($directory);
392 // and scan through the items inside
393 while (FALSE !== ($item = readdir($handle)))
395 // if the filepointer is not the current directory
396 // or the parent directory
397 if($item != '.' && $item != '..')
399 // we build the new path to delete
400 $path = $directory.'/'.$item;
402 // if the new path is a directory
403 //add another check if the dir is in the list to exclude delete
404 if(is_dir($path) && $exclude_dirs != null && in_array($path,$exclude_dirs)){
407 else if(is_dir($path))
409 // we call this function with the new path
410 recursive_empty_or_remove_directory($path);
412 // if the new path is a file
414 // we remove the file
415 if($exclude_files != null && in_array($path,$exclude_files)){
424 // close the directory
427 // if the option to empty is not set to true
430 // try to delete the now empty directory
431 if(!rmdir($directory))
433 // return false if not possible
441 // ------------------------------------------------------------
446 function getAllCustomizedModules() {
448 require_once('files.md5');
450 $return_array = array();
451 $modules = getAllModules();
452 foreach($modules as $mod) {
453 //find all files in each module if the files have been modified
454 //as compared to the base version then add the module to the
455 //customized modules array
456 $modFiles = findAllFiles(clean_path(getcwd())."/modules/$mod", array());
457 foreach($modFiles as $file){
458 $fileContents = file_get_contents($file);
459 $file = str_replace(clean_path(getcwd()),'',$file);
460 if($md5_string['./' . $file]){
461 if(md5($fileContents) != $md5_string['./' . $file]) {
462 //A file has been customized in the module. Put the module into the
463 // customized modules array.
464 echo 'Changed File'.$file;
470 // This is a new file in user's version and indicates that module has been
471 //customized. Put the module in the customized array.
472 echo 'New File'.$file;
479 return $return_array;
483 * Array of all Modules in the version bein upgraded
484 * This method returns an Array of all modules
485 * @return $modules Array of modules.
487 function getAllModules() {
490 while($e = $d->read()){
491 if(substr($e, 0, 1) == '.' || !is_dir('modules/' . $e))continue;
497 //Remove files with the smae md5
499 function removeMd5MatchingFiles($deleteNot=array()){
501 $md5_string = array();
502 if(file_exists(clean_path(getcwd().'/files.md5'))){
503 require(clean_path(getcwd().'/files.md5'));
505 $modulesAll = getAllModules();
506 foreach($modulesAll as $mod){
507 $allModFiles = array();
508 if(is_dir('modules/'.$mod)){
509 $allModFiles = findAllFiles('modules/'.$mod,$allModFiles);
510 foreach($allModFiles as $file){
511 if(file_exists($file) && !in_array(basename($file),$deleteNot)){
512 if(isset($md5_string['./'.$file])) {
513 $fileContents = file_get_contents($file);
514 if(md5($fileContents) == $md5_string['./'.$file]) {
525 * Handles requirements for creating reminder Tasks and Emails
526 * @param array skippedFiles Array of files that were not overwriten and must be manually mereged.
527 * @param string path Optional full path to alternate upgradeWizard log.
529 function commitHandleReminders($skippedFiles, $path='') {
531 global $current_user;
533 if(empty($mod_strings))
534 $mod_strings = return_module_language('en_us', 'UpgradeWizard');
536 if(empty($current_user->id)) {
537 $current_user->getSystemUser();
540 if(count($skippedFiles) > 0) {
541 $desc = $mod_strings['LBL_UW_COMMIT_ADD_TASK_OVERVIEW'] . "\n\n";
542 $desc .= $mod_strings['LBL_UW_COMMIT_ADD_TASK_DESC_1'];
543 $desc .= $_SESSION['uw_restore_dir'] . "\n\n";
544 $desc .= $mod_strings['LBL_UW_COMMIT_ADD_TASK_DESC_2'] . "\n\n";
546 foreach($skippedFiles as $file) {
547 $desc .= $file . "\n";
551 /// Not using new TimeDate stuff here because it needs to be compatible with 6.0
552 $nowDate = gmdate('Y-m-d');
553 $nowTime = gmdate('H:i:s');
554 $nowDateTime = $nowDate . ' ' . $nowTime;
556 if($_REQUEST['addTaskReminder'] == 'remind') {
557 logThis('Adding Task for admin for manual merge.', $path);
560 $task->name = $mod_strings['LBL_UW_COMMIT_ADD_TASK_NAME'];
561 $task->description = $desc;
562 $task->date_due = $nowDate;
563 $task->time_due = $nowTime;
564 $task->priority = 'High';
565 $task->status = 'Not Started';
566 $task->assigned_user_id = $current_user->id;
567 $task->created_by = $current_user->id;
568 $task->date_entered = $nowDateTime;
569 $task->date_modified = $nowDateTime;
573 if($_REQUEST['addEmailReminder'] == 'remind') {
574 logThis('Sending Reminder for admin for manual merge.', $path);
576 $email = new Email();
577 $email->assigned_user_id = $current_user->id;
578 $email->name = $mod_strings['LBL_UW_COMMIT_ADD_TASK_NAME'];
579 $email->description = $desc;
580 $email->description_html = nl2br($desc);
581 $email->from_name = $current_user->full_name;
582 $email->from_addr = $current_user->email1;
583 $email->to_addrs_arr = $email->parse_addrs($current_user->email1, '', '', '');
584 $email->cc_addrs_arr = array();
585 $email->bcc_addrs_arr = array();
586 $email->date_entered = $nowDateTime;
587 $email->date_modified = $nowDateTime;
594 function deleteCache(){
595 //Clean modules from cache
596 $cachedir = sugar_cached('modules');
597 if(is_dir($cachedir)){
598 $allModFiles = array();
599 $allModFiles = findAllFiles($cachedir,$allModFiles, true);
600 foreach($allModFiles as $file) {
601 if(file_exists($file)) {
603 rmdir_recursive($file);
612 //Clean jsLanguage from cache
613 $cachedir = sugar_cached('jsLanguage');
614 if(is_dir($cachedir)){
615 $allModFiles = array();
616 $allModFiles = findAllFiles($cachedir,$allModFiles);
617 foreach($allModFiles as $file){
618 if(file_exists($file)){
623 //Clean smarty from cache
624 $cachedir = sugar_cached('smarty');
625 if(is_dir($cachedir)){
626 $allModFiles = array();
627 $allModFiles = findAllFiles($cachedir,$allModFiles);
628 foreach($allModFiles as $file){
629 if(file_exists($file)){
634 //Rebuild dashlets cache
635 require_once('include/Dashlets/DashletCacheBuilder.php');
636 $dc = new DashletCacheBuilder();
640 function deleteChance(){
641 //Clean folder from cache
642 if(is_dir('include/SugarObjects/templates/chance')){
643 rmdir_recursive('include/SugarObjects/templates/chance');
645 if(is_dir('include/SugarObjects/templates/chance')){
646 if(!isset($_SESSION['chance'])){
647 $_SESSION['chance'] = '';
649 $_SESSION['chance'] = 'include/SugarObjects/templates/chance';
650 //rename('include/SugarObjects/templates/chance','include/SugarObjects/templates/chance_removeit');
658 * This function copies upgrade wizard files from new patch if that dir exists
660 * @param $file String path to uploaded zip file
662 function upgradeUWFiles($file) {
663 $cacheUploadUpgradesTemp = mk_temp_dir(sugar_cached("upgrades/temp"));
665 unzip($file, $cacheUploadUpgradesTemp);
667 if(!file_exists("$cacheUploadUpgradesTemp/manifest.php")) {
668 logThis("*** ERROR: no manifest file detected while bootstraping upgrade wizard files!");
671 include("$cacheUploadUpgradesTemp/manifest.php");
675 $from_dir = "{$cacheUploadUpgradesTemp}/{$manifest['copy_files']['from_dir']}";
678 if(file_exists("$from_dir/include/Localization/Localization.php")) {
679 $allFiles[] = "$from_dir/include/Localization/Localization.php";
682 if(file_exists("$from_dir/modules/UpgradeWizard")) {
683 $allFiles[] = findAllFiles("$from_dir/modules/UpgradeWizard", $allFiles);
686 if(file_exists("$from_dir/ModuleInstall")) {
687 $allFiles[] = findAllFiles("$from_dir/ModuleInstall", $allFiles);
689 if(file_exists("$from_dir/include/javascript/yui")) {
690 $allFiles[] = findAllFiles("$from_dir/include/javascript/yui", $allFiles);
692 if(file_exists("$from_dir/HandleAjaxCall.php")) {
693 $allFiles[] = "$from_dir/HandleAjaxCall.php";
695 if(file_exists("$from_dir/include/SugarTheme")) {
696 $allFiles[] = findAllFiles("$from_dir/include/SugarTheme", $allFiles);
698 if(file_exists("$from_dir/include/SugarCache")) {
699 $allFiles[] = findAllFiles("$from_dir/include/SugarCache", $allFiles);
701 if(file_exists("$from_dir/include/utils/external_cache.php")) {
702 $allFiles[] = "$from_dir/include/utils/external_cache.php";
704 if(file_exists("$from_dir/include/upload_file.php")) {
705 $allFiles[] = "$from_dir/include/upload_file.php";
707 if(file_exists("$from_dir/include/file_utils.php")) {
708 $allFiles[] = "$from_dir/include/file_utils.php";
710 if(file_exists("$from_dir/include/upload_file.php")) {
711 $allFiles[] = "$from_dir/include/upload_file.php";
713 if(file_exists("$from_dir/include/utils/sugar_file_utils.php")) {
714 $allFiles[] = "$from_dir/include/utils/sugar_file_utils.php";
717 if(file_exists("$from_dir/modules/Users")) {
718 $allFiles[] = findAllFiles("$from_dir/modules/Users", $allFiles);
721 upgradeUWFilesCopy($allFiles, $from_dir);
727 * This function recursively copies files from the upgradeUWFiles Array
728 * @see upgradeUWFiles
730 * @param array $allFiles Array of files to copy over after zip file has been uploaded
731 * @param string $from_dir Source directory
733 function upgradeUWFilesCopy($allFiles, $from_dir)
735 foreach($allFiles as $file)
739 upgradeUWFilesCopy($file, $from_dir);
741 $destFile = str_replace($from_dir."/", "", $file);
742 if(!is_dir(dirname($destFile))) {
743 mkdir_recursive(dirname($destFile)); // make sure the directory exists
746 if(stristr($file,'uw_main.tpl'))
747 logThis('Skipping "'.$file.'" - file copy will during commit step.');
749 logThis('updating UpgradeWizard code: '.$destFile);
750 copy_recursive($file, $destFile);
759 * gets valid patch file names that exist in upload/upgrade/patch/
761 function getValidPatchName($returnFull = true) {
762 global $base_upgrade_dir;
765 global $sugar_version;
766 global $sugar_config;
767 $uh = new UpgradeHistory();
768 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
771 // scan for new files (that are not installed)
772 logThis('finding new files for upgrade');
773 $upgrade_content = '';
774 $upgrade_contents = findAllFiles($base_upgrade_dir, array(), false, 'zip');
775 //other variations of zip file i.e. ZIP, zIp,zIP,Zip,ZIp,ZiP
782 <b>{$mod_strings['LBL_ML_NAME']}</b>
785 <b>{$mod_strings['LBL_ML_TYPE']}</b>
788 <b>{$mod_strings['LBL_ML_VERSION']}</b>
791 <b>{$mod_strings['LBL_ML_PUBLISHED']}</b>
794 <b>{$mod_strings['LBL_ML_UNINSTALLABLE']}</b>
797 <b>{$mod_strings['LBL_ML_DESCRIPTION']}</b>
802 // assume old patches are there.
803 $upgradeToVersion = array(); // fill with valid patches - we will only use the latest qualified found patch
805 // cn: bug 10609 - notices for uninitialized variables
810 $published_date = '';
815 foreach($upgrade_contents as $upgrade_content) {
816 if(!preg_match("#.*\.zip\$#i", $upgrade_content)) {
820 $the_base = basename($upgrade_content);
821 $the_md5 = md5_file($upgrade_content);
823 $md5_matches = $uh->findByMd5($the_md5);
825 /* If a patch is in the /patch dir AND has no record in the upgrade_history table we assume that it's the one we want.
826 * Edge-case: manual upgrade with a FTP of a patch; UH table has no entry for it. Assume nothing. :( */
827 if(0 == sizeof($md5_matches)) {
828 $target_manifest = remove_file_extension( $upgrade_content ) . '-manifest.php';
829 require_once($target_manifest);
831 if(empty($manifest['version'])) {
832 logThis("*** Potential error: patch found with no version [ {$upgrade_content} ]");
835 if(!isset($manifest['type']) || $manifest['type'] != 'patch') {
836 logThis("*** Potential error: patch found with either no 'type' or non-patch type [ {$upgrade_content} ]");
840 $upgradeToVersion[$manifest['version']] = urlencode($upgrade_content);
842 $name = empty($manifest['name']) ? $upgrade_content : $manifest['name'];
843 $version = empty($manifest['version']) ? '' : $manifest['version'];
844 $published_date = empty($manifest['published_date']) ? '' : $manifest['published_date'];
846 $description = empty($manifest['description']) ? 'None' : $manifest['description'];
847 $uninstallable = empty($manifest['is_uninstallable']) ? 'No' : 'Yes';
848 $type = getUITextForType( $manifest['type'] );
849 $manifest_type = $manifest['type'];
851 if(empty($manifest['icon'])) {
852 $icon = getImageForType( $manifest['type'] );
854 $path_parts = pathinfo( $manifest['icon'] );
855 $icon = "<!--not_in_theme!--><img src=\"" . remove_file_extension( $upgrade_content ) . "-icon." . $path_parts['extension'] . "\">";
860 // cn: bug 10488 use the NEWEST upgrade/patch available when running upgrade wizard.
861 ksort($upgradeToVersion);
862 $upgradeToVersion = array_values($upgradeToVersion);
863 $newest = array_pop($upgradeToVersion);
864 $_SESSION['install_file'] = urldecode($newest); // in-case it was there from a prior.
865 logThis("*** UW using [ {$_SESSION['install_file']} ] as source for patch files.");
867 $cleanUpgradeContent = urlencode($_SESSION['install_file']);
869 // cn: 10606 - cannot upload a patch file since this returned always.
870 if(!empty($cleanUpgradeContent)) {
871 $ready .= "<tr><td>$icon</td><td>$name</td><td>$type</td><td>$version</td><td>$published_date</td><td>$uninstallable</td><td>$description</td>\n";
874 <form action="index.php" method="post">
875 <input type="hidden" name="module" value="UpgradeWizard">
876 <input type="hidden" name="action" value="index">
877 <input type="hidden" name="step" value="{$_REQUEST['step']}">
878 <input type="hidden" name="run" value="delete">
879 <input type=hidden name="install_file" value="{$cleanUpgradeContent}" />
880 <input type=submit value="{$mod_strings['LBL_BUTTON_DELETE']}" />
884 $disabled = "DISABLED";
889 if(empty($cleanUpgradeContent)){
890 $ready .= "<tr><td colspan='7'><i>None</i></td>\n";
891 $ready .= "</table>\n";
893 $ready .= "<br></ul>\n";
895 $return['ready'] = $ready;
896 $return['disabled'] = $disabled;
905 * finalizes upgrade by setting upgrade versions in DB (config table) and sugar_version.php
906 * @return bool true on success
908 function updateVersions($version) {
910 global $sugar_config;
913 logThis('At updateVersions()... updating config table and sugar_version.php.', $path);
916 if(isset($_SESSION['sugar_version_file']) && !empty($_SESSION['sugar_version_file'])) {
917 if(!copy($_SESSION['sugar_version_file'], clean_path(getcwd().'/sugar_version.php'))) {
918 logThis('*** ERROR: sugar_version.php could not be copied to destination! Cannot complete upgrade', $path);
921 logThis('sugar_version.php successfully updated!', $path);
924 logThis('*** ERROR: no sugar_version.php file location found! - cannot complete upgrade...', $path);
928 $q1 = "DELETE FROM config WHERE category = 'info' AND name = 'sugar_version'";
929 $q2 = "INSERT INTO config (category, name, value) VALUES ('info', 'sugar_version', '{$version}')";
931 logThis('Deleting old DB version info from config table.', $path);
934 logThis('Inserting updated version info into config table.', $path);
937 logThis('updateVersions() complete.', $path);
944 * gets a module's lang pack - does not need to be a SugarModule
945 * @param lang string Language
946 * @param module string Path to language folder
947 * @return array mod_strings
949 function getModuleLanguagePack($lang, $module) {
950 $mod_strings = array();
952 if(!empty($lang) && !empty($module)) {
953 $langPack = clean_path(getcwd().'/'.$module.'/language/'.$lang.'.lang.php');
954 $langPackEn = clean_path(getcwd().'/'.$module.'/language/en_us.lang.php');
956 if (file_exists($langPack))
960 elseif (file_exists($langPackEn))
962 include($langPackEn);
969 * checks system compliance for 4.5+ codebase
970 * @return array Mixed values
972 function checkSystemCompliance() {
973 global $sugar_config;
974 global $current_language;
979 if(!defined('SUGARCRM_MIN_MEM')) {
980 define('SUGARCRM_MIN_MEM', 40);
983 $installer_mod_strings = getModuleLanguagePack($current_language, './install');
985 $ret['error_found'] = false;
988 $php_version = constant('PHP_VERSION');
989 $check_php_version_result = check_php_version($php_version);
991 switch($check_php_version_result) {
993 $ret['phpVersion'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_PHP_INVALID_VER']} {$php_version} )</span></b>";
994 $ret['error_found'] = true;
997 $ret['phpVersion'] = "<b><span class=go>{$installer_mod_strings['ERR_CHECKSYS_PHP_UNSUPPORTED']} {$php_version} )</span></b>";
1000 $ret['phpVersion'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_PHP_OK']} {$php_version} )</span></b>";
1004 // database and connect
1005 $canInstall = $db->canInstall();
1006 if ($canInstall !== true)
1008 $ret['error_found'] = true;
1009 if (count($canInstall) == 1)
1011 $ret['dbVersion'] = "<b><span class=stop>" . $installer_mod_strings[$canInstall[0]] . "</span></b>";
1015 $ret['dbVersion'] = "<b><span class=stop>" . sprintf($installer_mod_strings[$canInstall[0]], $canInstall[1]) . "</span></b>";
1020 if(function_exists('xml_parser_create')) {
1021 $ret['xmlStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1023 $ret['xmlStatus'] = "<b><span class=stop>{$installer_mod_strings['LBL_CHECKSYS_NOT_AVAILABLE']}</span></b>";
1024 $ret['error_found'] = true;
1028 if(function_exists('curl_init')) {
1029 $ret['curlStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1031 $ret['curlStatus'] = "<b><span class=go>{$installer_mod_strings['ERR_CHECKSYS_CURL']}</span></b>";
1032 $ret['error_found'] = false;
1036 if(function_exists('mb_strlen')) {
1037 $ret['mbstringStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1039 $ret['mbstringStatus'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_MBSTRING']}</span></b>";
1040 $ret['error_found'] = true;
1044 if(function_exists('imap_open')) {
1045 $ret['imapStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1047 $ret['imapStatus'] = "<b><span class=go>{$installer_mod_strings['ERR_CHECKSYS_IMAP']}</span></b>";
1048 $ret['error_found'] = false;
1053 if('1' == ini_get('safe_mode')) {
1054 $ret['safeModeStatus'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_SAFE_MODE']}</span></b>";
1055 $ret['error_found'] = true;
1057 $ret['safeModeStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1061 // call time pass by ref
1062 if('1' == ini_get('allow_call_time_pass_reference')) {
1063 $ret['callTimeStatus'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_CALL_TIME']}</span></b>";
1064 //continue upgrading
1066 $ret['callTimeStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1070 $ret['memory_msg'] = "";
1071 $memory_limit = "-1";//ini_get('memory_limit');
1072 $sugarMinMem = constant('SUGARCRM_MIN_MEM');
1073 // logic based on: http://us2.php.net/manual/en/ini.core.php#ini.memory-limit
1074 if( $memory_limit == "" ){ // memory_limit disabled at compile time, no memory limit
1075 $ret['memory_msg'] = "<b><span class=\"go\">{$installer_mod_strings['LBL_CHECKSYS_MEM_OK']}</span></b>";
1076 } elseif( $memory_limit == "-1" ){ // memory_limit enabled, but set to unlimited
1077 $ret['memory_msg'] = "<b><span class=\"go\">{$installer_mod_strings['LBL_CHECKSYS_MEM_UNLIMITED']}</span></b>";
1079 rtrim($memory_limit, 'M');
1080 $memory_limit_int = (int) $memory_limit;
1081 if( $memory_limit_int < constant('SUGARCRM_MIN_MEM') ){
1082 $ret['memory_msg'] = "<b><span class=\"stop\">{$installer_mod_strings['ERR_CHECKSYS_MEM_LIMIT_1']}" . constant('SUGARCRM_MIN_MEM') . "{$installer_mod_strings['ERR_CHECKSYS_MEM_LIMIT_2']}</span></b>";
1083 $ret['error_found'] = true;
1085 $ret['memory_msg'] = "<b><span class=\"go\">{$installer_mod_strings['LBL_CHECKSYS_OK']} ({$memory_limit})</span></b>";
1089 if (!class_exists("ZipArchive"))
1091 $ret['ZipStatus'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_ZIP']}</span></b>";
1092 $ret['error_found'] = true;
1094 $ret['ZipStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1099 // Suhosin allow to use upload://
1100 $ret['stream_msg'] = '';
1101 if (UploadStream::getSuhosinStatus() == true)
1103 $ret['stream_msg'] = "<b><span class=\"go\">{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1107 $ret['stream_msg'] = "<b><span class=\"stop\">{$app_strings['ERR_SUHOSIN']}</span></b>";
1108 $ret['error_found'] = true;
1111 /* mbstring.func_overload
1112 $ret['mbstring.func_overload'] = '';
1113 $mb = ini_get('mbstring.func_overload');
1116 $ret['mbstring.func_overload'] = "<b><span class=\"stop\">{$mod_strings['ERR_UW_MBSTRING_FUNC_OVERLOAD']}</b>";
1117 $ret['error_found'] = true;
1125 * is a file that we blow away automagically
1127 function isAutoOverwriteFile($file) {
1128 $overwriteDirs = array(
1129 './sugar_version.php',
1130 './modules/UpgradeWizard/uw_main.tpl',
1132 $file = trim('.'.str_replace(clean_path(getcwd()), '', $file));
1134 if(in_array($file, $overwriteDirs)) {
1138 $fileExtension = substr(strrchr($file, "."), 1);
1139 if($fileExtension == 'tpl' || $fileExtension == 'html') {
1149 function logThis($entry, $path='') {
1150 global $mod_strings;
1151 if(file_exists('include/utils/sugar_file_utils.php')){
1152 require_once('include/utils/sugar_file_utils.php');
1154 $log = empty($path) ? clean_path(getcwd().'/upgradeWizard.log') : clean_path($path);
1156 // create if not exists
1157 if(!file_exists($log)) {
1158 if(function_exists('sugar_fopen')){
1159 $fp = @sugar_fopen($log, 'w+'); // attempts to create file
1162 $fp = fopen($log, 'w+'); // attempts to create file
1164 if(!is_resource($fp)) {
1165 $GLOBALS['log']->fatal('UpgradeWizard could not create the upgradeWizard.log file');
1166 die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
1169 if(function_exists('sugar_fopen')){
1170 $fp = @sugar_fopen($log, 'a+'); // write pointer at end of file
1173 $fp = @fopen($log, 'a+'); // write pointer at end of file
1176 if(!is_resource($fp)) {
1177 $GLOBALS['log']->fatal('UpgradeWizard could not open/lock upgradeWizard.log file');
1178 die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
1182 $line = date('r').' [UpgradeWizard] - '.$entry."\n";
1184 if(@fwrite($fp, $line) === false) {
1185 $GLOBALS['log']->fatal('UpgradeWizard could not write to upgradeWizard.log: '.$entry);
1186 die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
1189 if(is_resource($fp)) {
1197 * @desc This function is to be used in the upgrade process to preserve changes/customaizations made to pre 5.1 quickcreate layout.
1198 * Prior to 5.1 we have been using editviewdefs as the base for quickcreatedefs. If a custom field was added to edit view layout, it
1199 * was automatically picked up by the quick create. [Addresses Bug 21469]
1200 * This function will check if customizations were made, and will create quickcreatedefs.php in the /cutom/working/$module_name directory.
1202 function updateQuickCreateDefs(){
1203 $d = dir('modules');
1204 $studio_modules = array();
1206 while($e = $d->read()){ //collect all studio modules.
1207 if(substr($e, 0, 1) == '.' || !is_dir('modules/' . $e))continue;
1208 if(file_exists('modules/' . $e . '/metadata/studio.php'))
1210 array_push($studio_modules, $e);
1214 foreach( $studio_modules as $modname ){ //for each studio enabled module
1215 //Check !exists modules/$modname/metadata/quickcreatedefs.php &&
1216 //exists custom/$modname/editviewdefs.php (module was customized) &&
1217 //!exists custom/$modname/quickcreateviewdefs.php
1219 $editviewdefs = "custom/working/modules/".$modname."/metadata/editviewdefs.php";
1220 $quickcreatedefs = "custom/working/modules/".$modname."/metadata/quickcreatedefs.php";
1222 if ( !file_exists("modules/".$modname."/metadata/quickcreatedefs.php") &&
1223 file_exists($editviewdefs) &&
1224 !file_exists($quickcreatedefs) ){
1225 //clone editviewdef and save it in custom/working/modules/metadata
1226 $GLOBALS['log']->debug("Copying editviewdefs.php as quickcreatedefs.php for the $modname module in custom/working/modules/$modname/metadata!");
1227 if(copy( $editviewdefs, $quickcreatedefs)){
1228 if(file_exists($quickcreatedefs) && is_readable($quickcreatedefs)){
1229 $file = file($quickcreatedefs);
1230 //replace 'EditView' with 'QuickCreate'
1231 $fp = fopen($quickcreatedefs,'w');
1232 foreach($file as &$line){
1233 if(preg_match('/^\s*\'EditView\'\s*=>\s*$/', $line) > 0){
1234 $line = "'QuickCreate' =>\n";
1242 $GLOBALS['log']->debug("Failed to replace 'EditView' with QuickCreate because $quickcreatedefs is either not readable or does not exist.");
1245 $GLOBALS['log']->debug("Failed to copy $editviewdefs to $quickcreatedefs!");
1252 * test perms for CREATE queries
1254 function testPermsCreate($db, $out) {
1255 logThis('Checking CREATE TABLE permissions...');
1256 global $mod_strings;
1258 if(!$db->checkPrivilege("CREATE TABLE")) {
1259 logThis('cannot CREATE TABLE!');
1260 $out['db']['dbNoCreate'] = true;
1261 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_CREATE']}</span></td></tr>";
1267 * test perms for INSERT
1269 function testPermsInsert($db, $out, $skip=false) {
1270 logThis('Checking INSERT INTO permissions...');
1271 global $mod_strings;
1273 if(!$db->checkPrivilege("INSERT")) {
1274 logThis('cannot INSERT INTO!');
1275 $out['db']['dbNoInsert'] = true;
1276 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_INSERT']}</span></td></tr>";
1283 * test perms for UPDATE TABLE
1285 function testPermsUpdate($db, $out, $skip=false) {
1286 logThis('Checking UPDATE TABLE permissions...');
1287 global $mod_strings;
1288 if(!$db->checkPrivilege("UPDATE")) {
1289 logThis('cannot UPDATE TABLE!');
1290 $out['db']['dbNoUpdate'] = true;
1291 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_UPDATE']}</span></td></tr>";
1298 * test perms for SELECT
1300 function testPermsSelect($db, $out, $skip=false) {
1301 logThis('Checking SELECT permissions...');
1302 global $mod_strings;
1303 if(!$db->checkPrivilege("SELECT")) {
1304 logThis('cannot SELECT!');
1305 $out['db']['dbNoSelect'] = true;
1306 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_SELECT']}</span></td></tr>";
1312 * test perms for DELETE
1314 function testPermsDelete($db, $out, $skip=false) {
1315 logThis('Checking DELETE FROM permissions...');
1316 global $mod_strings;
1317 if(!$db->checkPrivilege("DELETE")) {
1318 logThis('cannot DELETE FROM!');
1319 $out['db']['dbNoDelete'] = true;
1320 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_DELETE']}</span></td></tr>";
1327 * test perms for ALTER TABLE ADD COLUMN
1329 function testPermsAlterTableAdd($db, $out, $skip=false) {
1330 logThis('Checking ALTER TABLE ADD COLUMN permissions...');
1331 global $mod_strings;
1332 if(!$db->checkPrivilege("ADD COLUMN")) {
1333 logThis('cannot ADD COLUMN!');
1334 $out['db']['dbNoAddColumn'] = true;
1335 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_ADD_COLUMN']}</span></td></tr>";
1341 * test perms for ALTER TABLE ADD COLUMN
1343 function testPermsAlterTableChange($db, $out, $skip=false) {
1344 logThis('Checking ALTER TABLE CHANGE COLUMN permissions...');
1345 global $mod_strings;
1346 if(!$db->checkPrivilege("CHANGE COLUMN")) {
1347 logThis('cannot CHANGE COLUMN!');
1348 $out['db']['dbNoChangeColumn'] = true;
1349 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_CHANGE_COLUMN']}</span></td></tr>";
1355 * test perms for ALTER TABLE DROP COLUMN
1357 function testPermsAlterTableDrop($db, $out, $skip=false) {
1358 logThis('Checking ALTER TABLE DROP COLUMN permissions...');
1359 global $mod_strings;
1360 if(!$db->checkPrivilege("DROP COLUMN")) {
1361 logThis('cannot DROP COLUMN!');
1362 $out['db']['dbNoDropColumn'] = true;
1363 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_DROP_COLUMN']}</span></td></tr>";
1370 * test perms for DROP TABLE
1372 function testPermsDropTable($db, $out, $skip=false) {
1373 logThis('Checking DROP TABLE permissions...');
1374 global $mod_strings;
1375 if(!$db->checkPrivilege("DROP TABLE")) {
1376 logThis('cannot DROP TABLE!');
1377 $out['db']['dbNoDropTable'] = true;
1378 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_DROP_TABLE']}</span></td></tr>";
1383 function getFormattedError($error, $query) {
1384 $error = "<div><b>".$error;
1385 $error .= "</b>::{$query}</div>";
1391 * parses a query finding the table name
1392 * @param string query The query
1393 * @return string table The table
1395 function getTableFromQuery($query) {
1396 $standardQueries = array('ALTER TABLE', 'DROP TABLE', 'CREATE TABLE', 'INSERT INTO', 'UPDATE', 'DELETE FROM');
1397 $query = preg_replace("/[^A-Za-z0-9\_\s]/", "", $query);
1398 $query = trim(str_replace($standardQueries, '', $query));
1400 $firstSpc = strpos($query, " ");
1401 $end = ($firstSpc > 0) ? $firstSpc : strlen($query);
1402 $table = substr($query, 0, $end);
1409 function preLicenseCheck() {
1410 require_once('modules/UpgradeWizard/uw_files.php');
1412 global $sugar_config;
1413 global $mod_strings;
1414 global $sugar_version;
1416 if(!isset($sugar_version) || empty($sugar_version)) {
1417 require_once('./sugar_version.php');
1420 if(!isset($_SESSION['unzip_dir']) || empty($_SESSION['unzip_dir'])) {
1421 logThis('unzipping files in upgrade archive...');
1423 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
1425 //also come up with mechanism to read from upgrade-progress file
1426 if(!isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !is_file($_SESSION['install_file'])) {
1427 if (file_exists(clean_path($base_tmp_upgrade_dir)) && $handle = opendir(clean_path($base_tmp_upgrade_dir))) {
1428 while (false !== ($file = readdir($handle))) {
1429 if($file !="." && $file !="..") {
1430 if(is_file($base_tmp_upgrade_dir."/".$file."/manifest.php")){
1431 require_once($base_tmp_upgrade_dir."/".$file."/manifest.php");
1432 $package_name= $manifest['copy_files']['from_dir'];
1433 if(file_exists($base_tmp_upgrade_dir."/".$file."/".$package_name) && file_exists($base_tmp_upgrade_dir."/".$file."/scripts") && file_exists($base_tmp_upgrade_dir."/".$file."/manifest.php")){
1434 $unzip_dir = $base_tmp_upgrade_dir."/".$file;
1435 if(file_exists("$base_upgrade_dir/patch/".$package_name.'.zip')){
1436 $_SESSION['install_file'] = $package_name.".zip";
1445 if(empty($_SESSION['install_file'])){
1446 unlinkUWTempFiles();
1448 echo 'Upload File not found so redirecting to Upgrade Start ';
1449 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1450 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1451 $upgrade_directories_not_found =<<<eoq
1452 <table cellpadding="3" cellspacing="0" border="0">
1454 <th colspan="2" align="left">
1455 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1460 $uwMain = $upgrade_directories_not_found;
1463 $install_file = "$base_upgrade_dir/patch/".basename(urldecode( $_SESSION['install_file'] ));
1465 if(empty($unzip_dir)){
1466 $unzip_dir = mk_temp_dir( $base_tmp_upgrade_dir );
1468 $zip_from_dir = ".";
1470 $zip_force_copy = array();
1473 logThis('Could not create a temporary directory using mk_temp_dir( $base_tmp_upgrade_dir )');
1474 die($mod_strings['ERR_UW_NO_CREATE_TMP_DIR']);
1477 //double check whether unzipped .
1478 if(file_exists($unzip_dir ."/scripts") && file_exists($unzip_dir."/manifest.php")){
1482 unzip( $install_file, $unzip_dir );
1485 // assumption -- already validated manifest.php at time of upload
1486 require_once( "$unzip_dir/manifest.php" );
1488 if( isset( $manifest['copy_files']['from_dir'] ) && $manifest['copy_files']['from_dir'] != "" ){
1489 $zip_from_dir = $manifest['copy_files']['from_dir'];
1491 if( isset( $manifest['copy_files']['to_dir'] ) && $manifest['copy_files']['to_dir'] != "" ){
1492 $zip_to_dir = $manifest['copy_files']['to_dir'];
1494 if( isset( $manifest['copy_files']['force_copy'] ) && $manifest['copy_files']['force_copy'] != "" ){
1495 $zip_force_copy = $manifest['copy_files']['force_copy'];
1497 if( isset( $manifest['version'] ) ){
1498 $version = $manifest['version'];
1500 if( !is_writable( "config.php" ) ){
1501 return $mod_strings['ERR_UW_CONFIG'];
1504 $_SESSION['unzip_dir'] = clean_path($unzip_dir);
1505 $_SESSION['zip_from_dir'] = clean_path($zip_from_dir);
1506 logThis('unzip done.');
1508 $unzip_dir = $_SESSION['unzip_dir'];
1509 $zip_from_dir = $_SESSION['zip_from_dir'];
1512 //check if $_SESSION['unzip_dir'] and $_SESSION['zip_from_dir'] exist
1513 if(!isset($_SESSION['unzip_dir']) || !file_exists($_SESSION['unzip_dir'])
1514 || !isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !file_exists($_SESSION['install_file'])){
1516 unlinkUWTempFiles();
1518 echo 'Upload File not found so redirecting to Upgrade Start ';
1519 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1520 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1521 $upgrade_directories_not_found =<<<eoq
1522 <table cellpadding="3" cellspacing="0" border="0">
1524 <th colspan="2" align="left">
1525 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1530 $uwMain = $upgrade_directories_not_found;
1534 logThis ('is SugarConfig there '.file_exists(clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarObjects/SugarConfig.php")));
1535 if(file_exists(clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarObjects/SugarConfig.php"))) {
1536 $file = clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarObjects/SugarConfig.php");
1537 $destFile = str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), $cwd, $file);
1538 if(!is_dir(dirname($destFile))) {
1539 mkdir_recursive(dirname($destFile)); // make sure the directory exists
1541 copy($file,$destFile);
1542 //also copy include utils array utils
1543 $file = clean_path($unzip_dir.'/'.$zip_from_dir."/include/utils/array_utils.php");
1544 $destFile = str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), $cwd, $file);
1545 if(!is_dir(dirname($destFile))) {
1546 mkdir_recursive(dirname($destFile)); // make sure the directory exists
1548 copy($file,$destFile);
1553 function preflightCheck() {
1554 require_once('modules/UpgradeWizard/uw_files.php');
1556 global $sugar_config;
1557 global $mod_strings;
1558 global $sugar_version;
1560 if(!isset($sugar_version) || empty($sugar_version)) {
1561 require_once('./sugar_version.php');
1564 unset($_SESSION['rebuild_relationships']);
1565 unset($_SESSION['rebuild_extensions']);
1567 // don't bother if are rechecking
1568 $manualDiff = array();
1569 if(!isset($_SESSION['unzip_dir']) || empty($_SESSION['unzip_dir'])) {
1570 logThis('unzipping files in upgrade archive...');
1572 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
1574 //Following is if User logged out unexpectedly and then logged into UpgradeWizard again.
1575 //also come up with mechanism to read from upgrade-progress file.
1576 if(!isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !is_file($_SESSION['install_file'])) {
1577 if (file_exists($base_tmp_upgrade_dir) && $handle = opendir($base_tmp_upgrade_dir)) {
1578 while (false !== ($file = readdir($handle))) {
1579 if($file !="." && $file !="..") {
1580 if(is_file($base_tmp_upgrade_dir."/".$file."/manifest.php")){
1581 require_once($base_tmp_upgrade_dir."/".$file."/manifest.php");
1582 $package_name= $manifest['copy_files']['from_dir'];
1583 if(file_exists($base_tmp_upgrade_dir."/".$file."/".$package_name) && file_exists($base_tmp_upgrade_dir."/".$file."/scripts") && file_exists($base_tmp_upgrade_dir."/".$file."/manifest.php")){
1584 $unzip_dir = $base_tmp_upgrade_dir."/".$file;
1585 if(file_exists("$base_upgrade_dir/patch/".$package_name.'.zip')){
1586 $_SESSION['install_file'] = $package_name.".zip";
1595 if(empty($_SESSION['install_file'])){
1596 unlinkUWTempFiles();
1598 echo 'Upload File not found so redirecting to Upgrade Start ';
1599 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1600 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1601 $upgrade_directories_not_found =<<<eoq
1602 <table cellpadding="3" cellspacing="0" border="0">
1604 <th colspan="2" align="left">
1605 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1610 $uwMain = $upgrade_directories_not_found;
1614 $install_file = "$base_upgrade_dir/patch/".basename(urldecode( $_SESSION['install_file'] ));
1616 if(empty($unzip_dir)){
1617 $unzip_dir = mk_temp_dir( $base_tmp_upgrade_dir );
1619 $zip_from_dir = ".";
1621 $zip_force_copy = array();
1624 logThis('Could not create a temporary directory using mk_temp_dir( $base_tmp_upgrade_dir )');
1625 die($mod_strings['ERR_UW_NO_CREATE_TMP_DIR']);
1628 //double check whether unzipped .
1629 if(file_exists($unzip_dir ."/scripts") && file_exists($unzip_dir."/manifest.php")){
1633 unzip( $install_file, $unzip_dir );
1636 // assumption -- already validated manifest.php at time of upload
1637 require_once( "$unzip_dir/manifest.php" );
1639 if( isset( $manifest['copy_files']['from_dir'] ) && $manifest['copy_files']['from_dir'] != "" ){
1640 $zip_from_dir = $manifest['copy_files']['from_dir'];
1642 if( isset( $manifest['copy_files']['to_dir'] ) && $manifest['copy_files']['to_dir'] != "" ){
1643 $zip_to_dir = $manifest['copy_files']['to_dir'];
1645 if( isset( $manifest['copy_files']['force_copy'] ) && $manifest['copy_files']['force_copy'] != "" ){
1646 $zip_force_copy = $manifest['copy_files']['force_copy'];
1648 if( isset( $manifest['version'] ) ){
1649 $version = $manifest['version'];
1651 if( !is_writable( "config.php" ) ){
1652 return $mod_strings['ERR_UW_CONFIG'];
1655 $_SESSION['unzip_dir'] = clean_path($unzip_dir);
1656 $_SESSION['zip_from_dir'] = clean_path($zip_from_dir);
1658 //logThis('unzip done.');
1660 $unzip_dir = $_SESSION['unzip_dir'];
1661 $zip_from_dir = $_SESSION['zip_from_dir'];
1663 //check if $_SESSION['unzip_dir'] and $_SESSION['zip_from_dir'] exist
1664 if(!isset($_SESSION['unzip_dir']) || !file_exists($_SESSION['unzip_dir'])
1665 || !isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !file_exists($_SESSION['install_file'])){
1667 unlinkUWTempFiles();
1669 echo 'Upload File not found so redirecting to Upgrade Start ';
1670 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1671 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1672 $upgrade_directories_not_found =<<<eoq
1673 <table cellpadding="3" cellspacing="0" border="0">
1675 <th colspan="2" align="left">
1676 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1681 $uwMain = $upgrade_directories_not_found;
1684 //copy minimum required files
1685 fileCopy('include/utils/sugar_file_utils.php');
1687 $upgradeFiles = findAllFiles(clean_path("$unzip_dir/$zip_from_dir"), array());
1688 $cache_html_files= array();
1691 $md5_string = array();
1692 if(file_exists(clean_path(getcwd().'/files.md5'))){
1693 require(clean_path(getcwd().'/files.md5'));
1696 // file preflight checks
1697 logThis('verifying md5 checksums for files...');
1698 foreach($upgradeFiles as $file) {
1699 if(in_array(str_replace(clean_path("$unzip_dir/$zip_from_dir") . "/", '', $file), $uw_files))
1700 continue; // skip already loaded files
1702 if(strpos($file, '.md5'))
1703 continue; // skip md5 file
1705 // normalize file paths
1706 $file = clean_path($file);
1708 // check that we can move/delete the upgraded file
1709 if(!is_writable($file)) {
1710 $errors[] = $mod_strings['ERR_UW_FILE_NOT_WRITABLE'].": ".$file;
1712 // check that destination files are writable
1713 $destFile = getcwd().str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), '', $file);
1715 if(is_file($destFile)) { // of course it needs to exist first...
1716 if(!is_writable($destFile)) {
1717 $errors[] = $mod_strings['ERR_UW_FILE_NOT_WRITABLE'].": ".$destFile;
1721 ///////////////////////////////////////////////////////////////////////
1723 // compare md5s and build up a manual merge list
1724 $targetFile = clean_path(".".str_replace(getcwd(),'',$destFile));
1726 if(is_file($destFile)) {
1727 if(strpos($targetFile, '.php')) {
1728 // handle PHP files that were hit with the security regex
1730 if(function_exists('sugar_fopen')){
1731 $fp = sugar_fopen($destFile, 'r');
1734 $fp = fopen($destFile, 'r');
1736 $filesize = filesize($destFile);
1738 $fileContents = stream_get_contents($fp);
1739 $targetMd5 = md5($fileContents);
1742 $targetMd5 = md5_file($destFile);
1746 if(isset($md5_string[$targetFile]) && $md5_string[$targetFile] != $targetMd5) {
1747 logThis('found a file with a differing md5: ['.$targetFile.']');
1748 $manualDiff[] = $destFile;
1751 ///////////////////////////////////////////////////////////////////////
1753 logThis('md5 verification done.');
1754 $errors['manual'] = $manualDiff;
1759 function fileCopy($file_path){
1760 if(file_exists(clean_path($_SESSION['unzip_dir'].'/'.$_SESSION['zip_from_dir'].'/'.$file_path))) {
1761 $file = clean_path($_SESSION['unzip_dir'].'/'.$_SESSION['zip_from_dir'].'/'.$file_path);
1762 $destFile = str_replace(clean_path($_SESSION['unzip_dir'].'/'.$_SESSION['zip_from_dir']), clean_path(getcwd()), $file);
1763 if(!is_dir(dirname($destFile))) {
1764 mkdir_recursive(dirname($destFile)); // make sure the directory exists
1766 copy_recursive($file,$destFile);
1769 function getChecklist($steps, $step) {
1770 global $mod_strings;
1772 $skip = array('start', 'cancel', 'uninstall','end');
1775 $ret = '<table cellpadding="3" cellspacing="4" border="0">';
1776 $ret .= '<tr><th colspan="3" align="left">'.$mod_strings['LBL_UW_CHECKLIST'].':</th></tr>';
1777 foreach($steps['desc'] as $k => $desc) {
1778 if(in_array($steps['files'][$j], $skip)) {
1783 //$status = "<span class='error'>{$mod_strings['LBL_UW_INCOMPLETE']}</span>";
1785 $desc_mod_post = '';
1787 if(isset($_SESSION['step'][$steps['files'][$k]]) && $_SESSION['step'][$steps['files'][$k]] == 'success') {
1788 //$status = $mod_strings['LBL_UW_COMPLETE'];
1792 if($k == $_REQUEST['step']) {
1793 //$status = $mod_strings['LBL_UW_IN_PROGRESS'];
1794 $desc_mod_pre = "<font color=blue><i>";
1795 $desc_mod_post = "</i></font>";
1798 $ret .= "<tr><td> </td><td><b>{$i}: {$desc_mod_pre}{$desc}{$desc_mod_post}</b></td>";
1799 $ret .= "<td id={$steps['files'][$j]}><i></i></td></tr>";
1807 function prepSystemForUpgrade() {
1808 global $sugar_config;
1809 global $sugar_flavor;
1810 global $mod_strings;
1811 global $current_language;
1813 global $base_upgrade_dir;
1814 global $base_tmp_upgrade_dir;
1815 list($p_base_upgrade_dir, $p_base_tmp_upgrade_dir) = getUWDirs();
1816 ///////////////////////////////////////////////////////////////////////////////
1817 //// Make sure variables exist
1818 if(empty($base_upgrade_dir)){
1819 $base_upgrade_dir = $p_base_upgrade_dir;
1821 if(empty($base_tmp_upgrade_dir)){
1822 $base_tmp_upgrade_dir = $p_base_tmp_upgrade_dir;
1824 sugar_mkdir($base_tmp_upgrade_dir, 0775, true);
1825 if(!isset($subdirs) || empty($subdirs)){
1826 $subdirs = array('full', 'langpack', 'module', 'patch', 'theme');
1829 $upgrade_progress_dir = $base_tmp_upgrade_dir;
1830 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
1831 if(file_exists($upgrade_progress_file)){
1832 if(function_exists('get_upgrade_progress') && function_exists('didThisStepRunBefore')){
1833 if(didThisStepRunBefore('end')){
1834 include($upgrade_progress_file);
1835 unset($upgrade_config);
1836 unlink($upgrade_progress_file);
1841 // increase the cuttoff time to 1 hour
1842 ini_set("max_execution_time", "3600");
1844 // make sure dirs exist
1845 if($subdirs != null){
1846 foreach($subdirs as $subdir) {
1847 sugar_mkdir("$base_upgrade_dir/$subdir", 0775, true);
1850 // array of special scripts that are executed during (un)installation-- key is type of script, value is filename
1851 if(!defined('SUGARCRM_PRE_INSTALL_FILE')) {
1852 define('SUGARCRM_PRE_INSTALL_FILE', 'scripts/pre_install.php');
1853 define('SUGARCRM_POST_INSTALL_FILE', 'scripts/post_install.php');
1854 define('SUGARCRM_PRE_UNINSTALL_FILE', 'scripts/pre_uninstall.php');
1855 define('SUGARCRM_POST_UNINSTALL_FILE', 'scripts/post_uninstall.php');
1858 $script_files = array(
1859 "pre-install" => constant('SUGARCRM_PRE_INSTALL_FILE'),
1860 "post-install" => constant('SUGARCRM_POST_INSTALL_FILE'),
1861 "pre-uninstall" => constant('SUGARCRM_PRE_UNINSTALL_FILE'),
1862 "post-uninstall" => constant('SUGARCRM_POST_UNINSTALL_FILE'),
1865 // check that the upload limit is set to 6M or greater
1866 define('SUGARCRM_MIN_UPLOAD_MAX_FILESIZE_BYTES', 6 * 1024 * 1024); // 6 Megabytes
1867 $upload_max_filesize = ini_get('upload_max_filesize');
1868 $upload_max_filesize_bytes = return_bytes($upload_max_filesize);
1870 if($upload_max_filesize_bytes < constant('SUGARCRM_MIN_UPLOAD_MAX_FILESIZE_BYTES')) {
1871 $GLOBALS['log']->debug("detected upload_max_filesize: $upload_max_filesize");
1872 $admin_strings = return_module_language($current_language, 'Administration');
1873 echo '<p class="error">'.$admin_strings['MSG_INCREASE_UPLOAD_MAX_FILESIZE'].' '.get_cfg_var('cfg_file_path')."</p>\n";
1877 if ( !function_exists('extractFile') ) {
1878 function extractFile($zip_file, $file_in_zip) {
1879 global $base_tmp_upgrade_dir;
1882 $absolute_base_tmp_upgrade_dir = clean_path($base_tmp_upgrade_dir);
1883 $relative_base_tmp_upgrade_dir = clean_path(str_replace(clean_path(getcwd()), '', $absolute_base_tmp_upgrade_dir));
1885 // mk_temp_dir expects relative pathing
1886 $my_zip_dir = mk_temp_dir($relative_base_tmp_upgrade_dir);
1888 unzip_file($zip_file, $file_in_zip, $my_zip_dir);
1890 return("$my_zip_dir/$file_in_zip");
1894 if ( !function_exists('extractManifest') ) {
1895 function extractManifest($zip_file) {
1896 logThis('extracting manifest.');
1897 return(extractFile($zip_file, "manifest.php"));
1901 if ( !function_exists('getInstallType') ) {
1902 function getInstallType($type_string) {
1905 $subdirs = array('full', 'langpack', 'module', 'patch', 'theme', 'temp');
1906 foreach($subdirs as $subdir) {
1907 if(preg_match("#/$subdir/#", $type_string)) {
1911 // return empty if no match
1916 function getImageForType($type) {
1918 global $mod_strings;
1923 $icon = SugarThemeRegistry::current()->getImage("Upgrade", "",null,null,'.gif',$mod_strings['LBL_UPGRADE']);
1926 $icon = SugarThemeRegistry::current()->getImage("LanguagePacks", "",null,null,'.gif',$mod_strings['LBL_LANGPACKS']);
1929 $icon = SugarThemeRegistry::current()->getImage("ModuleLoader", "",null,null,'.gif',$mod_strings['LBL_MODULELOADER']);
1932 $icon = SugarThemeRegistry::current()->getImage("PatchUpgrades", "",null,null,'.gif',$mod_strings['LBL_PATCHUPGRADES']);
1935 $icon = SugarThemeRegistry::current()->getImage("Themes", "",null,null,'.gif',$mod_strings['LBL_THEMES']);
1943 if ( !function_exists('getLanguagePackName') ) {
1944 function getLanguagePackName($the_file) {
1945 require_once("$the_file");
1946 if(isset($app_list_strings["language_pack_name"])) {
1947 return($app_list_strings["language_pack_name"]);
1953 function getUITextForType($type) {
1954 if($type == "full") {
1955 return("Full Upgrade");
1957 if($type == "langpack") {
1958 return("Language Pack");
1960 if($type == "module") {
1963 if($type == "patch") {
1966 if($type == "theme") {
1971 if ( !function_exists('validate_manifest') ) {
1973 * Verifies a manifest from a patch or module to be compatible with the current Sugar version and flavor
1974 * @param array manifest Standard manifest array
1975 * @return string Error message, blank on success
1977 function validate_manifest($manifest) {
1978 logThis('validating manifest.php file');
1979 // takes a manifest.php manifest array and validates contents
1981 global $sugar_version;
1982 global $sugar_flavor;
1983 global $mod_strings;
1985 if(!isset($manifest['type'])) {
1986 return $mod_strings['ERROR_MANIFEST_TYPE'];
1989 $type = $manifest['type'];
1991 if(getInstallType("/$type/") == "") {
1992 return $mod_strings['ERROR_PACKAGE_TYPE']. ": '" . $type . "'.";
1995 if(isset($manifest['acceptable_sugar_versions'])) {
1996 $version_ok = false;
1997 $matches_empty = true;
1998 if(isset($manifest['acceptable_sugar_versions']['exact_matches'])) {
1999 $matches_empty = false;
2000 foreach($manifest['acceptable_sugar_versions']['exact_matches'] as $match) {
2001 if($match == $sugar_version) {
2006 if(!$version_ok && isset($manifest['acceptable_sugar_versions']['regex_matches'])) {
2007 $matches_empty = false;
2008 foreach($manifest['acceptable_sugar_versions']['regex_matches'] as $match) {
2009 if(preg_match("/$match/", $sugar_version)) {
2015 if(!$matches_empty && !$version_ok) {
2016 return $mod_strings['ERROR_VERSION_INCOMPATIBLE']."<br />".
2017 $mod_strings['ERR_UW_VERSION'].$sugar_version;
2021 if(isset($manifest['acceptable_sugar_flavors']) && sizeof($manifest['acceptable_sugar_flavors']) > 0) {
2023 foreach($manifest['acceptable_sugar_flavors'] as $match) {
2024 if($match == $sugar_flavor) {
2029 return $mod_strings['ERROR_FLAVOR_INCOMPATIBLE']."<br />".
2030 $mod_strings['ERR_UW_FLAVOR'].$sugar_flavor."<br />".
2031 $mod_strings['ERR_UW_FLAVOR_2'].$manifest['acceptable_sugar_flavors'][0];
2039 function unlinkUploadFiles() {
2041 // logThis('at unlinkUploadFiles()');
2043 // if(isset($_SESSION['install_file']) && !empty($_SESSION['install_file'])) {
2044 // $upload = $_SESSION['install_file'];
2046 // if(is_file($upload)) {
2047 // logThis('unlinking ['.$upload.']');
2048 // @unlink($upload);
2054 * deletes files created by unzipping a package
2056 function unlinkUWTempFiles() {
2057 global $sugar_config;
2060 logThis('at unlinkUWTempFiles()');
2062 list($upgDir, $tempDir) = getUWDirs();
2064 if(file_exists($tempDir) && is_dir($tempDir)){
2065 $files = findAllFiles($tempDir, array(), false);
2067 foreach($files as $file) {
2068 if(!is_dir($file)) {
2069 //logThis('unlinking ['.$file.']', $path);
2074 $files = findAllFiles($tempDir, array(), true);
2075 foreach($files as $dir) {
2077 //logThis('removing dir ['.$dir.']', $path);
2081 $cacheFile = sugar_cached("modules/UpgradeWizard/_persistence.php");
2082 if(is_file($cacheFile)) {
2083 logThis("Unlinking Upgrade cache file: '_persistence.php'", $path);
2084 @unlink($cacheFile);
2087 logThis("finished!");
2091 * finds all files in the passed path, but skips select directories
2092 * @param string dir Relative path
2093 * @param array the_array Collections of found files/dirs
2094 * @param bool include_dir True if we want to include directories in the
2095 * returned collection
2097 function uwFindAllFiles($dir, $theArray, $includeDirs=false, $skipDirs=array(), $echo=false) {
2099 if (whetherNeedToSkipDir($dir, $skipDirs))
2104 if (!is_dir($dir)) { return $theArray; } // Bug # 46035, just checking for valid dir
2106 if ($d === false) { return $theArray; } // Bug # 46035, more checking
2108 while($f = $d->read()) {
2109 // bug 40793 Skip Directories array in upgradeWizard does not function correctly
2110 if($f == "." || $f == ".." || whetherNeedToSkipDir("$dir/$f", $skipDirs)) { // skip *nix self/parent
2114 // for AJAX length count
2120 if(is_dir("$dir/$f")) {
2121 if($includeDirs) { // add the directory if flagged
2122 $theArray[] = clean_path("$dir/$f");
2126 $theArray = uwFindAllFiles("$dir/$f/", $theArray, $includeDirs, $skipDirs, $echo);
2128 $theArray[] = clean_path("$dir/$f");
2141 * unset's UW's Session Vars
2143 function resetUwSession() {
2144 logThis('resetting $_SESSION');
2146 if(isset($_SESSION['committed']))
2147 unset($_SESSION['committed']);
2148 if(isset($_SESSION['sugar_version_file']))
2149 unset($_SESSION['sugar_version_file']);
2150 if(isset($_SESSION['upgrade_complete']))
2151 unset($_SESSION['upgrade_complete']);
2152 if(isset($_SESSION['allTables']))
2153 unset($_SESSION['allTables']);
2154 if(isset($_SESSION['alterCustomTableQueries']))
2155 unset($_SESSION['alterCustomTableQueries']);
2156 if(isset($_SESSION['skip_zip_upload']))
2157 unset($_SESSION['skip_zip_upload']);
2158 if(isset($_SESSION['sugar_version_file']))
2159 unset($_SESSION['sugar_version_file']);
2160 if(isset($_SESSION['install_file']))
2161 unset($_SESSION['install_file']);
2162 if(isset($_SESSION['unzip_dir']))
2163 unset($_SESSION['unzip_dir']);
2164 if(isset($_SESSION['zip_from_dir']))
2165 unset($_SESSION['zip_from_dir']);
2166 if(isset($_SESSION['overwrite_files']))
2167 unset($_SESSION['overwrite_files']);
2168 if(isset($_SESSION['schema_change']))
2169 unset($_SESSION['schema_change']);
2170 if(isset($_SESSION['uw_restore_dir']))
2171 unset($_SESSION['uw_restore_dir']);
2172 if(isset($_SESSION['step']))
2173 unset($_SESSION['step']);
2174 if(isset($_SESSION['files']))
2175 unset($_SESSION['files']);
2176 if(isset($_SESSION['Upgraded451Wizard'])){
2177 unset($_SESSION['Upgraded451Wizard']);
2179 if(isset($_SESSION['Initial_451to500_Step'])){
2180 unset($_SESSION['Initial_451to500_Step']);
2182 if(isset($_SESSION['license_shown']))
2183 unset($_SESSION['license_shown']);
2184 if(isset($_SESSION['sugarMergeRunResults']))
2185 unset($_SESSION['sugarMergeRunResults']);
2189 * runs rebuild scripts
2191 function UWrebuild() {
2195 //CCL - Comment this block out, it is called in end.php
2196 logThis('Rebuilding everything...', $path);
2197 require_once('modules/Administration/QuickRepairAndRebuild.php');
2198 $randc = new RepairAndClear();
2199 $randc->repairAndClearAll(array('clearAll'),array(translate('LBL_ALL_MODULES')), false, false);
2201 $query = "DELETE FROM versions WHERE name='Rebuild Extensions'";
2203 logThis('Registering rebuild record: '.$query, $path);
2204 logThis('Rebuild done.', $path);
2206 // insert a new database row to show the rebuild extensions is done
2207 $id = create_guid();
2208 $gmdate = gmdate('Y-m-d H:i:s');
2209 $date_entered = db_convert("'$gmdate'", 'datetime');
2210 $query = 'INSERT INTO versions (id, deleted, date_entered, date_modified, modified_user_id, created_by, name, file_version, db_version) '
2211 . "VALUES ('$id', '0', $date_entered, $date_entered, '1', '1', 'Rebuild Extensions', '4.0.0', '4.0.0')";
2213 logThis('Registering rebuild record in versions table: '.$query, $path);
2216 function getCustomTables() {
2219 return $db->tablesLike('%_cstm');
2222 function alterCustomTables($customTables)
2227 function getAllTables() {
2229 return $db->getTablesArray();
2232 function printAlterTableSql($tables)
2234 $alterTableSql = '';
2236 foreach($tables as $table)
2237 $alterTableSql .= "ALTER TABLE " . $table . " CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;" . "\n";
2239 return $alterTableSql;
2242 function executeConvertTablesSql($tables)
2246 foreach($tables as $table){
2247 $query = "ALTER TABLE " . $table . " CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci";
2249 logThis("Sending query: ".$query);
2250 $db->query($query);//, true, "An error has occured while performing db query. See log file for details.<br>");
2256 function testThis() {
2257 $files = uwFindAllFiles(getcwd().'/test', array());
2259 $out = "<table cellpadding='1' cellspacing='0' border='0'>\n";
2262 foreach($files as $file) {
2263 $relativeFile = clean_path(str_replace(getcwd().'/test', '', $file));
2264 $relativeFile = ($relativeFile{0} == '/') ? substr($relativeFile, 1, strlen($relativeFile)) : $relativeFile;
2266 $relativePath = dirname($relativeFile);
2268 if($relativePath == $priorPath) { // same dir, new file
2269 $out .= "<tr><td>".basename($relativeFile)."</td></tr>";
2270 $priorPath = $relativePath;
2284 function testThis2($dir, $id=0, $hide=false) {
2285 global $mod_strings;
2287 $dh = opendir($dir);
2290 $doHide = ($hide) ? 'none' : '';
2291 $out = "<div id='{$id}' style='display:{$doHide};'>";
2292 $out .= "<table cellpadding='1' cellspacing='0' style='border:0px solid #ccc'>\n";
2294 while($file = readdir($dh)) {
2295 if($file == '.' || $file == '..' || $file == 'CVS' || $file == '.cvsignore')
2298 if(is_dir($path.'/'.$file)) {
2299 $file = $path.'/'.$file;
2300 $newI = create_guid();
2301 $out .= "<tr><td valign='top'><a href='javascript:toggleNwFiles(\"{$newI}\");'>".SugarThemeRegistry::current()->getImage("Workflow", "", null, null, ".gif", $mod_strings['LBL_WORKFLOW'])."</a></td>\n";
2302 $out .= "<td valign='top'><b><a href='javascript:toggleNwFiles(\"{$newI}\");'>".basename($file)."</a></b></td></tr>";
2303 $out .= "<tr><td></td><td valign='top'>".testThis2($file, $newI, true)."</td></tr>";
2305 $out .= "<tr><td valign='top'> </td>\n";
2306 $out .= "<td valign='top'>".basename($file)."</td></tr>";
2310 $out .= "</tr></table>";
2321 function testThis3(&$files, $id, $hide, $previousPath = '') {
2322 if(!is_array($files) || empty($files))
2327 global $mod_strings;
2328 // expecting full path here
2329 foreach($files as $k => $file) {
2330 $file = str_replace(getcwd(), '', $file);
2331 $path = dirname($file);
2332 $fileName = basename($file);
2334 if($fileName == 'CVS' || $fileName == '.cvsignore')
2337 if($path == $previousPath) { // same directory
2338 // new row for each file
2339 $out .= "<tr><td valign='top' align='left'> </td>";
2340 $out .= "<td valign='top' align='left'>{$fileName}</td></tr>";
2341 } else { // new directory
2343 $out .= "<tr><td valign='top'><a href='javascript:toggleNwFiles(\"{$newI}\");'>".SugarThemeRegistry::current()->getImage("Workflow", "", null, null, ".gif", $mod_strings['LBL_WORKFLOW'])."</a></td>\n";
2344 $out .= "<td valign='top'><b><a href='javascript:toggleNwFiles(\"{$newI}\");'>".$fileName."</a></b></td></tr>";
2345 $recurse = testThis3($files, $newI, true, $previousPath);
2346 $out .= "<tr><td></td><td valign='top'>".$recurse."</td></tr>";
2349 $previousPath = $path;
2351 $display = ($hide) ? 'none' : '';
2353 <div id="{$id}" style="display:{$display}">
2354 <table cellpadding='1' cellspacing='0' border='0' style='border:1px solid #ccc'>
2363 function testThis4($filePath, $fileNodes=array(), $fileName='') {
2364 $path = dirname($filePath);
2365 $file = basename($filePath);
2367 $exFile = explode('/', $path);
2369 foreach($exFile as $pathSegment) {
2370 if(is_array($fileNodes[$pathSegment])) { // path already processed
2372 } else { // newly found path
2373 $fileNodes[$pathSegment] = array();
2376 if($fileName != '') {
2377 $fileNodes[$pathSegment][] = $fileName;
2386 ///////////////////////////////////////////////////////////////////////////////
2387 //// SYSTEM CHECK FUNCTIONS
2389 * generates an array with all files in the SugarCRM root directory, skipping
2391 * @return array files Array of files with absolute paths
2393 function getFilesForPermsCheck() {
2394 global $sugar_config;
2396 logThis('Got JSON call to find all files...');
2397 $filesNotWritable = array();
2398 $filesNWPerms = array();
2400 // add directories here that should be skipped when doing file permissions checks (cache/upload is the nasty one)
2402 $sugar_config['upload_dir'],
2404 $files = uwFindAllFiles(".", array(), true, $skipDirs, true);
2409 * checks files for permissions
2410 * @param array files Array of files with absolute paths
2411 * @return string result of check
2413 function checkFiles($files, $echo=false) {
2414 global $mod_strings;
2415 $filesNotWritable = array();
2418 <a href='javascript:void(0); toggleNwFiles(\"filesNw\");'>{$mod_strings['LBL_UW_SHOW_NW_FILES']}</a>
2419 <div id='filesNw' style='display:none;'>
2420 <table cellpadding='3' cellspacing='0' border='0'>
2422 <th align='left'>{$mod_strings['LBL_UW_FILE']}</th>
2423 <th align='left'>{$mod_strings['LBL_UW_FILE_PERMS']}</th>
2424 <th align='left'>{$mod_strings['LBL_UW_FILE_OWNER']}</th>
2425 <th align='left'>{$mod_strings['LBL_UW_FILE_GROUP']}</th>
2428 $isWindows = is_windows();
2429 foreach($files as $file) {
2432 if(!is_writable_windows($file)) {
2433 logThis('WINDOWS: File ['.$file.'] not readable - saving for display');
2434 // don't warn yet - we're going to use this to check against replacement files
2435 // aw: commented out; it's a hack to allow upgrade wizard to continue on windows... will fix later
2436 /*$filesNotWritable[$i] = $file;
2437 $filesNWPerms[$i] = substr(sprintf('%o',fileperms($file)), -4);
2438 $filesOut .= "<tr>".
2439 "<td><span class='error'>{$file}</span></td>".
2440 "<td>{$filesNWPerms[$i]}</td>".
2441 "<td>".$mod_strings['ERR_UW_CANNOT_DETERMINE_USER']."</td>".
2442 "<td>".$mod_strings['ERR_UW_CANNOT_DETERMINE_GROUP']."</td>".
2446 if(!is_writable($file)) {
2447 logThis('File ['.$file.'] not writable - saving for display');
2448 // don't warn yet - we're going to use this to check against replacement files
2449 $filesNotWritable[$i] = $file;
2450 $filesNWPerms[$i] = substr(sprintf('%o',fileperms($file)), -4);
2451 $owner = posix_getpwuid(fileowner($file));
2452 $group = posix_getgrgid(filegroup($file));
2453 $filesOut .= "<tr>".
2454 "<td><span class='error'>{$file}</span></td>".
2455 "<td>{$filesNWPerms[$i]}</td>".
2456 "<td>".$owner['name']."</td>".
2457 "<td>".$group['name']."</td>".
2464 $filesOut .= '</table></div>';
2466 $errors['files']['filesNotWritable'] = (count($filesNotWritable) > 0) ? true : false;
2467 if(count($filesNotWritable) < 1) {
2468 $filesOut = "{$mod_strings['LBL_UW_FILE_NO_ERRORS']}";
2474 function deletePackageOnCancel(){
2475 global $mod_strings;
2476 global $sugar_config;
2477 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
2478 logThis('running delete');
2479 if(!isset($_SESSION['install_file']) || ($_SESSION['install_file'] == "")) {
2480 logThis('ERROR: trying to delete non-existent file: ['.$_REQUEST['install_file'].']');
2481 $error = $mod_strings['ERR_UW_NO_FILE_UPLOADED'];
2483 // delete file in upgrades/patch
2484 $delete_me = "$base_upgrade_dir/patch/".basename(urldecode( $_REQUEST['install_file'] ));
2485 if(@unlink($delete_me)) {
2486 //logThis('unlinking: '.$delete_me);
2487 $out = basename($delete_me).$mod_strings['LBL_UW_FILE_DELETED'];
2489 logThis('ERROR: could not delete ['.$delete_me.']');
2490 $error = $mod_strings['ERR_UW_FILE_NOT_DELETED'].$delete_me;
2493 if(!empty($error)) {
2494 $out = "<b><span class='error'>{$error}</span></b><br />";
2498 function handleExecuteSqlKeys($db, $tableName, $disable)
2500 if(empty($tableName)) return true;
2501 if(is_callable(array($db, "supports"))) {
2503 return $disable?$db->disableKeys($tableName):$db->enableKeys($tableName);
2506 $op = $disable?"DISABLE":"ENABLE";
2507 return $db->query("ALTER TABLE $tableName $op KEYS");
2511 function parseAndExecuteSqlFile($sqlScript,$forStepQuery='',$resumeFromQuery='')
2513 global $sugar_config;
2514 $alterTableSchema = '';
2515 $sqlErrors = array();
2516 if(!isset($_SESSION['sqlSkippedQueries'])){
2517 $_SESSION['sqlSkippedQueries'] = array();
2519 $db = DBManagerFactory::getInstance();
2520 $disable_keys = ($db->dbType == "mysql"); // have to use old way for now for upgrades
2521 if(strpos($resumeFromQuery,",") != false){
2522 $resumeFromQuery = explode(",",$resumeFromQuery);
2524 if(file_exists($sqlScript)) {
2525 $fp = fopen($sqlScript, 'r');
2526 $contents = stream_get_contents($fp);
2527 $anyScriptChanges =$contents;
2528 $resumeAfterFound = false;
2532 while($line = fgets($fp)) {
2533 if(strpos($line, '--') === false) {
2534 $completeLine .= " ".trim($line);
2535 if(strpos($line, ';') !== false) {
2537 $query = str_replace(';','',$completeLine);
2538 //if resume from query is not null then find out from where
2539 //it should start executing the query.
2541 if($query != null && $resumeFromQuery != null){
2542 if(!$resumeAfterFound){
2543 if(strpos($query,",") != false){
2544 $queArray = explode(",",$query);
2545 for($i=0;$i<sizeof($resumeFromQuery);$i++){
2546 if(strcasecmp(trim($resumeFromQuery[$i]),trim($queArray[$i]))==0){
2547 $resumeAfterFound = true;
2549 $resumeAfterFound = false;
2555 elseif(strcasecmp(trim($resumeFromQuery),trim($query))==0){
2556 $resumeAfterFound = true;
2559 if($resumeAfterFound){
2562 // if $count=1 means it is just found so skip the query. Run the next one
2563 if($query != null && $resumeAfterFound && $count >1){
2564 $tableName = getAlterTable($query);
2567 handleExecuteSqlKeys($db, $tableName, true);
2570 if($db->checkError()){
2571 //put in the array to use later on
2572 $_SESSION['sqlSkippedQueries'][] = $query;
2576 handleExecuteSqlKeys($db, $tableName, false);
2578 $progQuery[$forStepQuery]=$query;
2579 post_install_progress($progQuery,$action='set');
2582 elseif($query != null){
2583 $tableName = getAlterTable($query);
2586 handleExecuteSqlKeys($db, $tableName, true);
2591 handleExecuteSqlKeys($db, $tableName, false);
2593 $progQuery[$forStepQuery]=$query;
2594 post_install_progress($progQuery,$action='set');
2595 if($db->checkError()){
2596 //put in the array to use later on
2597 $_SESSION['sqlSkippedQueries'][] = $query;
2609 function getAlterTable($query){
2610 $query = strtolower($query);
2611 if (preg_match('/^\s*alter\s+table\s+/', $query)) {
2612 $sqlArray = explode(" ", $query);
2613 $key = array_search('table', $sqlArray);
2614 return $sqlArray[($key+1)];
2620 function set_upgrade_vars(){
2621 logThis('setting session variables...');
2622 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2623 if(!is_dir($upgrade_progress_dir)){
2624 mkdir_recursive($upgrade_progress_dir);
2626 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2627 if(file_exists($upgrade_progress_file)){
2628 include($upgrade_progress_file);
2631 fopen($upgrade_progress_file, 'w+');
2633 if(!isset($upgrade_config) || $upgrade_config == null){
2634 $upgrade_config = array();
2635 $upgrade_config[1]['upgrade_vars']=array();
2637 if(isset($upgrade_config[1]) && isset($upgrade_config[1]['upgrade_vars']) && !is_array($upgrade_config[1]['upgrade_vars'])){
2638 $upgrade_config[1]['upgrade_vars'] = array();
2641 if(!isset($upgrade_vars) || $upgrade_vars == NULL){
2642 $upgrade_vars = array();
2644 if(isset($_SESSION['unzip_dir']) && !empty($_SESSION['unzip_dir']) && file_exists($_SESSION['unzip_dir'])){
2645 $upgrade_vars['unzip_dir']=$_SESSION['unzip_dir'];
2647 if(isset($_SESSION['install_file']) && !empty($_SESSION['install_file']) && file_exists($_SESSION['install_file'])){
2648 $upgrade_vars['install_file']=$_SESSION['install_file'];
2650 if(isset($_SESSION['Upgraded451Wizard']) && !empty($_SESSION['Upgraded451Wizard'])){
2651 $upgrade_vars['Upgraded451Wizard']=$_SESSION['Upgraded451Wizard'];
2653 if(isset($_SESSION['license_shown']) && !empty($_SESSION['license_shown'])){
2654 $upgrade_vars['license_shown']=$_SESSION['license_shown'];
2656 if(isset($_SESSION['Initial_451to500_Step']) && !empty($_SESSION['Initial_451to500_Step'])){
2657 $upgrade_vars['Initial_451to500_Step']=$_SESSION['Initial_451to500_Step'];
2659 if(isset($_SESSION['zip_from_dir']) && !empty($_SESSION['zip_from_dir'])){
2660 $upgrade_vars['zip_from_dir']=$_SESSION['zip_from_dir'];
2662 //place into the upgrade_config array and rewrite config array only if new values are being inserted
2663 if(isset($upgrade_vars) && $upgrade_vars != null && sizeof($upgrade_vars) > 0){
2664 foreach($upgrade_vars as $key=>$val){
2665 if($key != null && $val != null){
2666 $upgrade_config[1]['upgrade_vars'][$key]=$upgrade_vars[$key];
2669 ksort($upgrade_config);
2670 if(is_writable($upgrade_progress_file) && write_array_to_file( "upgrade_config", $upgrade_config,
2671 $upgrade_progress_file)) {
2672 //writing to the file
2677 function initialize_session_vars(){
2678 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2679 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2680 if(file_exists($upgrade_progress_file)){
2681 include($upgrade_progress_file);
2682 if(isset($upgrade_config) && $upgrade_config != null && is_array($upgrade_config) && sizeof($upgrade_config) >0){
2683 $currVarsArray=$upgrade_config[1]['upgrade_vars'];
2684 //print_r($currVarsArray);
2685 if(isset($currVarsArray) && $currVarsArray != null && is_array($currVarsArray) && sizeof($currVarsArray)>0){
2686 foreach($currVarsArray as $key=>$val){
2687 if($key != null && $val !=null){
2688 //set session variables
2689 $_SESSION[$key]=$val;
2698 //track the upgrade progress on each step
2699 //track the upgrade progress on each step
2700 function set_upgrade_progress($currStep,$currState,$currStepSub='',$currStepSubState=''){
2702 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2703 if(!is_dir($upgrade_progress_dir)){
2704 mkdir_recursive($upgrade_progress_dir);
2706 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2707 if(file_exists($upgrade_progress_file)){
2708 include($upgrade_progress_file);
2711 if(function_exists('sugar_fopen')){
2712 sugar_fopen($upgrade_progress_file, 'w+');
2715 fopen($upgrade_progress_file, 'w+');
2718 if(!isset($upgrade_config) || $upgrade_config == null){
2719 $upgrade_config = array();
2720 $upgrade_config[1]['upgrade_vars']=array();
2722 if(!is_array($upgrade_config[1]['upgrade_vars'])){
2723 $upgrade_config[1]['upgrade_vars'] = array();
2725 if($currStep != null && $currState != null){
2726 if(sizeof($upgrade_config) > 0){
2727 if($currStepSub != null && $currStepSubState !=null){
2728 //check if new status to be set or update
2729 //get the latest in array. since it has sub components prepare an array
2730 if(!empty($upgrade_config[sizeof($upgrade_config)][$currStep]) && is_array($upgrade_config[sizeof($upgrade_config)][$currStep])){
2731 $latestStepSub = currSubStep($upgrade_config[sizeof($upgrade_config)][$currStep]);
2732 if($latestStepSub == $currStepSub){
2733 $upgrade_config[sizeof($upgrade_config)][$currStep][$latestStepSub]=$currStepSubState;
2734 $upgrade_config[sizeof($upgrade_config)][$currStep][$currStep] = $currState;
2737 $upgrade_config[sizeof($upgrade_config)][$currStep][$currStepSub]=$currStepSubState;
2738 $upgrade_config[sizeof($upgrade_config)][$currStep][$currStep] = $currState;
2742 $currArray = array();
2743 $currArray[$currStep] = $currState;
2744 $currArray[$currStepSub] = $currStepSubState;
2745 $upgrade_config[sizeof($upgrade_config)+1][$currStep] = $currArray;
2749 //get the current upgrade progress
2750 $latestStep = get_upgrade_progress();
2751 //set the upgrade progress
2752 if($latestStep == $currStep){
2753 //update the current step with new progress status
2754 $upgrade_config[sizeof($upgrade_config)][$latestStep]=$currState;
2758 $upgrade_config[sizeof($upgrade_config)+1][$currStep]=$currState;
2760 // now check if there elements within array substeps
2764 //set the upgrade progress (just starting)
2765 $upgrade_config[sizeof($upgrade_config)+1][$currStep]= $currState;
2768 if(is_writable($upgrade_progress_file) && write_array_to_file( "upgrade_config", $upgrade_config,
2769 $upgrade_progress_file)) {
2770 //writing to the file
2776 function get_upgrade_progress(){
2777 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2778 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2781 if(file_exists($upgrade_progress_file)){
2782 include($upgrade_progress_file);
2783 if(!isset($upgrade_config) || $upgrade_config == null){
2784 $upgrade_config = array();
2786 if($upgrade_config != null && sizeof($upgrade_config) >1){
2787 $currArr = $upgrade_config[sizeof($upgrade_config)];
2788 if(is_array($currArr)){
2789 foreach($currArr as $key=>$val){
2797 function currSubStep($currStep){
2799 if(is_array($currStep)){
2800 foreach($currStep as $key=>$val){
2808 function currUpgradeState($currState){
2810 if(is_array($currState)){
2811 foreach($currState as $key=>$val){
2813 foreach($val as $k=>$v){
2827 function didThisStepRunBefore($step,$SubStep=''){
2828 if($step == null) return;
2829 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2830 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2833 if(file_exists($upgrade_progress_file)){
2834 include($upgrade_progress_file);
2835 if(isset($upgrade_config) && $upgrade_config != null && is_array($upgrade_config) && sizeof($upgrade_config) >0){
2836 for($i=1;$i<=sizeof($upgrade_config);$i++){
2837 if(is_array($upgrade_config[$i])){
2838 foreach($upgrade_config[$i] as $key=>$val){
2840 if(is_array($upgrade_config[$i][$step])){
2842 foreach ($upgrade_config[$i][$step] as $k=>$v){
2844 foreach($v as $k1=>$v1){
2845 if($SubStep != null){
2846 if($SubStep ==$k1 && $v1=='done'){
2853 elseif($SubStep !=null){
2854 if($SubStep==$k && $v=='done'){
2859 elseif($step==$k && $v=='done'){
2865 elseif($val=='done'){
2879 //get and set post install status
2880 function post_install_progress($progArray='',$action=''){
2881 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2882 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2883 if($action=='' || $action=='get'){
2884 //get the state of post install
2885 $currProg = array();
2886 if(file_exists($upgrade_progress_file)){
2887 include($upgrade_progress_file);
2888 if(is_array($upgrade_config[sizeof($upgrade_config)]['commit']['post_install']) && sizeof($upgrade_config[sizeof($upgrade_config)]['commit']['post_install'])>0){
2889 foreach($upgrade_config[sizeof($upgrade_config)]['commit']['post_install'] as $k=>$v){
2896 elseif($action=='set'){
2897 if(!is_dir($upgrade_progress_dir)){
2898 mkdir($upgrade_progress_dir);
2900 if(file_exists($upgrade_progress_file)){
2901 include($upgrade_progress_file);
2904 fopen($upgrade_progress_file, 'w+');
2906 if(!is_array($upgrade_config[sizeof($upgrade_config)]['commit']['post_install'])){
2907 $upgrade_config[sizeof($upgrade_config)]['commit']['post_install']=array();
2908 $upgrade_config[sizeof($upgrade_config)]['commit']['post_install']['post_install'] = 'in_progress';
2910 if($progArray != null && is_array($progArray)){
2911 foreach($progArray as $key=>$val){
2912 $upgrade_config[sizeof($upgrade_config)]['commit']['post_install'][$key]=$val;
2915 if(is_writable($upgrade_progress_file) && write_array_to_file( "upgrade_config", $upgrade_config,
2916 $upgrade_progress_file)) {
2917 //writing to the file
2922 function repairDBForUpgrade($execute=false,$path=''){
2924 global $current_user, $beanFiles;
2926 set_time_limit(3600);
2928 $db = &DBManagerFactory::getInstance();
2930 VardefManager::clearVardef();
2931 require_once('include/ListView/ListView.php');
2932 foreach ($beanFiles as $bean => $file) {
2933 require_once ($file);
2934 $focus = new $bean ();
2935 $sql .= $db->repairTable($focus, $execute);
2939 $olddictionary = $dictionary;
2940 unset ($dictionary);
2941 include ('modules/TableDictionary.php');
2942 foreach ($dictionary as $meta) {
2943 $tablename = $meta['table'];
2944 $fielddefs = $meta['fields'];
2945 $indices = $meta['indices'];
2946 $sql .= $db->repairTableParams($tablename, $fielddefs, $indices, $execute);
2949 foreach (explode("\n", $sql) as $line) {
2950 if (!empty ($line) && substr($line, -2) != "*/") {
2953 $qry_str .= $line . "\n";
2964 preg_replace('#(/\*.+?\*/\n*)#', '', $qry_str)
2966 logThis("*******START EXECUTING DB UPGRADE QUERIES***************",$path);
2967 logThis($sql,$path);
2968 logThis("*******END EXECUTING DB UPGRADE QUERIES****************",$path);
2977 * upgradeUserPreferences
2978 * This method updates the user_preferences table and sets the pages/dashlets for users
2979 * which have ACL access to Trackers so that the Tracker dashlets are set in their user perferences
2982 function upgradeUserPreferences() {
2983 global $sugar_config, $sugar_version;
2984 $uw_strings = return_module_language($GLOBALS['current_language'], 'UpgradeWizard');
2986 $localization = new Localization();
2987 $localeCoreDefaults = $localization->getLocaleConfigDefaults();
2989 // check the current system wide default_locale_name_format and add it to the list if it's not there
2990 if(empty($sugar_config['name_formats'])) {
2991 $sugar_config['name_formats'] = $localeCoreDefaults['name_formats'];
2992 if(!rebuildConfigFile($sugar_config, $sugar_version)) {
2993 $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
2997 $currentDefaultLocaleNameFormat = $sugar_config['default_locale_name_format'];
2999 if ($localization->isAllowedNameFormat($currentDefaultLocaleNameFormat)) {
3000 upgradeLocaleNameFormat($currentDefaultLocaleNameFormat);
3002 $sugar_config['default_locale_name_format'] = $localeCoreDefaults['default_locale_name_format'];
3003 if(!rebuildConfigFile($sugar_config, $sugar_version)) {
3004 $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
3006 $localization->createInvalidLocaleNameFormatUpgradeNotice();
3009 $db = &DBManagerFactory::getInstance();
3010 $result = $db->query("SELECT id FROM users where deleted = '0'");
3011 while($row = $db->fetchByAssoc($result))
3013 $current_user = new User();
3014 $current_user->retrieve($row['id']);
3016 // get the user's name locale format, check if it's in our list, add it if it's not, keep it as user's default
3017 $currentUserNameFormat = $current_user->getPreference('default_locale_name_format');
3018 if ($localization->isAllowedNameFormat($currentUserNameFormat)) {
3019 upgradeLocaleNameFormat($currentUserNameFormat);
3021 $current_user->setPreference('default_locale_name_format', 's f l', 0, 'global');
3022 $current_user->savePreferencesToDB();
3026 if(!$current_user->getPreference('calendar_publish_key')) {
3027 // set publish key if not set already
3028 $current_user->setPreference('calendar_publish_key', create_guid());
3033 // we need to force save the changes to disk, otherwise we lose them.
3036 $current_user->savePreferencesToDB();
3044 * Checks if a locale name format is part of the default list, if not adds it to the config
3045 * @param $name_format string a local name format string such as 's f l'
3046 * @return bool true on successful write to config file, false on failure;
3048 function upgradeLocaleNameFormat($name_format) {
3049 global $sugar_config, $sugar_version;
3051 $localization = new Localization();
3052 $localeConfigDefaults = $localization->getLocaleConfigDefaults();
3054 $uw_strings = return_module_language($GLOBALS['current_language'], 'UpgradeWizard');
3055 if(empty($sugar_config['name_formats'])) {
3056 $sugar_config['name_formats'] = $localeConfigDefaults['name_formats'];
3057 if(!rebuildConfigFile($sugar_config, $sugar_version)) {
3058 $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
3061 if (!in_array($name_format, $sugar_config['name_formats'])) {
3062 $new_config = sugarArrayMerge($sugar_config['name_formats'], array($name_format=>$name_format));
3063 $sugar_config['name_formats'] = $new_config;
3064 if(!rebuildConfigFile($sugar_config, $sugar_version)) {
3065 $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
3074 function add_custom_modules_favorites_search(){
3075 $module_directories = scandir('modules');
3077 foreach($module_directories as $module_dir){
3078 if($module_dir == '.' || $module_dir == '..' || !is_dir("modules/{$module_dir}")){
3083 preg_match('/^[a-z0-9]{1,5}_[a-z0-9_]+$/i' , $module_dir, $matches);
3085 // Make sure the module was created by module builder
3086 if(empty($matches)){
3090 $full_module_dir = "modules/{$module_dir}/";
3091 $read_searchdefs_from = "{$full_module_dir}/metadata/searchdefs.php";
3092 $read_SearchFields_from = "{$full_module_dir}/metadata/SearchFields.php";
3093 $read_custom_SearchFields_from = "custom/{$full_module_dir}/metadata/SearchFields.php";
3095 // Studio can possibly override this file, so we check for a custom version of it
3096 if(file_exists("custom/{$full_module_dir}/metadata/searchdefs.php")){
3097 $read_searchdefs_from = "custom/{$full_module_dir}/metadata/searchdefs.php";
3100 if(file_exists($read_searchdefs_from) && file_exists($read_SearchFields_from)){
3103 require($read_searchdefs_from);
3104 foreach($searchdefs[$module_dir]['layout']['basic_search'] as $sf_array){
3105 if(isset($sf_array['name']) && $sf_array['name'] == 'favorites_only'){
3110 require($read_SearchFields_from);
3111 if(isset($searchFields[$module_dir]['favorites_only'])){
3115 if(!$found_sf1 && !$found_sf2){
3116 $searchdefs[$module_dir]['layout']['basic_search']['favorites_only'] = array('name' => 'favorites_only','label' => 'LBL_FAVORITES_FILTER','type' => 'bool',);
3117 $searchdefs[$module_dir]['layout']['advanced_search']['favorites_only'] = array('name' => 'favorites_only','label' => 'LBL_FAVORITES_FILTER','type' => 'bool',);
3118 $searchFields[$module_dir]['favorites_only'] = array(
3119 'query_type'=>'format',
3120 'operator' => 'subquery',
3121 'subquery' => 'SELECT sugarfavorites.record_id FROM sugarfavorites
3122 WHERE sugarfavorites.deleted=0
3123 and sugarfavorites.module = \''.$module_dir.'\'
3124 and sugarfavorites.assigned_user_id = \'{0}\'',
3125 'db_field'=>array('id')
3128 if(!is_dir("custom/{$full_module_dir}/metadata")){
3129 mkdir_recursive("custom/{$full_module_dir}/metadata");
3131 $success_sf1 = write_array_to_file('searchdefs', $searchdefs, "custom/{$full_module_dir}/metadata/searchdefs.php");
3132 $success_sf2 = write_array_to_file('searchFields', $searchFields, "{$full_module_dir}/metadata/SearchFields.php");
3135 logThis("add_custom_modules_favorites_search failed for searchdefs.php for {$module_dir}");
3138 logThis("add_custom_modules_favorites_search failed for SearchFields.php for {$module_dir}");
3140 if($success_sf1 && $success_sf2){
3141 logThis("add_custom_modules_favorites_search successfully updated searchdefs and searchFields for {$module_dir}");
3150 * upgradeModulesForTeamsets
3152 * This method adds the team_set_id values to the module tables that have the new team_set_id column
3153 * added through the SugarCRM 5.5.x upgrade process. It also adds the values into the team_sets and
3154 * team_sets_teams tables.
3156 * @param filter Array of modules to process; empty by default
3158 function upgradeModulesForTeamsets($filter=array()) {
3159 require('include/modules.php');
3160 foreach($beanList as $moduleName=>$beanName) {
3161 if(!empty($filter) && array_search($moduleName, $filter) === false) {
3164 if($moduleName == 'TeamMemberships' || $moduleName == 'ForecastOpportunities'){
3167 $bean = loadBean($moduleName);
3169 empty($bean->table_name)) {
3173 $FieldArray = $GLOBALS['db']->helper->get_columns($bean->table_name);
3174 if(!isset($FieldArray['team_id'])) {
3178 upgradeTeamColumn($bean, 'team_id');
3182 //Upgrade users table
3183 $bean = loadBean('Users');
3184 upgradeTeamColumn($bean, 'default_team');
3185 $result = $GLOBALS['db']->query("SELECT id FROM teams where deleted=0");
3186 while($row = $GLOBALS['db']->fetchByAssoc($result)) {
3187 $teamset = new TeamSet();
3188 $teamset->addTeams($row['id']);
3195 * Helper function to create a team_set_id column and also set team_set_id column
3196 * to have the value of the $column_name parameter
3198 * @param $bean SugarBean which we are adding team_set_id column to
3199 * @param $column_name The name of the column containing the default team_set_id value
3201 function upgradeTeamColumn($bean, $column_name) {
3202 //first let's check to ensure that the team_set_id field is defined, if not it could be the case that this is an older
3203 //module that does not use the SugarObjects
3204 if(empty($bean->field_defs['team_set_id']) && $bean->module_dir != 'Trackers'){
3206 //at this point we could assume that since we have a team_id defined and not a team_set_id that we need to
3207 //add that field and the corresponding relationships
3208 $object = $bean->object_name;
3209 $module = $bean->module_dir;
3210 $object_name = $object;
3211 $_object_name = strtolower($object_name);
3213 if(!empty($GLOBALS['dictionary'][$object]['table'])){
3214 $table_name = $GLOBALS['dictionary'][$object]['table'];
3216 $table_name = strtolower($module);
3219 $path = 'include/SugarObjects/implements/team_security/vardefs.php';
3221 //go through each entry in the vardefs from team_security and unset anything that is already set in the core module
3222 //this will ensure we have the proper ordering.
3223 $fieldDiff = array_diff_assoc($vardefs['fields'], $GLOBALS['dictionary'][$bean->object_name]['fields']);
3225 $file = 'custom/Extension/modules/' . $bean->module_dir. '/Ext/Vardefs/teams.php';
3226 $contents = "<?php\n";
3227 if(!empty($fieldDiff)){
3228 foreach($fieldDiff as $key => $val){
3229 $contents .= "\n\$GLOBALS['dictionary']['". $object . "']['fields']['". $key . "']=" . var_export_helper($val) . ";";
3232 $relationshipDiff = array_diff_assoc($vardefs['relationships'], $GLOBALS['dictionary'][$bean->object_name]['relationships']);
3233 if(!empty($relationshipDiff)){
3234 foreach($relationshipDiff as $key => $val){
3235 $contents .= "\n\$GLOBALS['dictionary']['". $object . "']['relationships']['". $key . "']=" . var_export_helper($val) . ";";
3238 $indexDiff = array_diff_assoc($vardefs['indices'], $GLOBALS['dictionary'][$bean->object_name]['indices']);
3239 if(!empty($indexDiff)){
3240 foreach($indexDiff as $key => $val){
3241 $contents .= "\n\$GLOBALS['dictionary']['". $object . "']['indices']['". $key . "']=" . var_export_helper($val) . ";";
3244 if( $fh = @sugar_fopen( $file, 'wt' ) )
3246 fputs( $fh, $contents);
3251 //we have written out the teams.php into custom/Extension/modules/{$module_dir}/Ext/Vardefs/teams.php'
3252 //now let's merge back into vardefs.ext.php
3253 require_once('ModuleInstall/ModuleInstaller.php');
3254 $mi = new ModuleInstaller();
3255 $mi->merge_files('Ext/Vardefs/', 'vardefs.ext.php');
3256 VardefManager::loadVardef($bean->module_dir, $bean->object_name, true);
3257 $bean->field_defs = $GLOBALS['dictionary'][$bean->object_name]['fields'];
3260 if(isset($bean->field_defs['team_set_id'])) {
3261 //Create the team_set_id column
3262 $FieldArray = $GLOBALS['db']->helper->get_columns($bean->table_name);
3263 if(!isset($FieldArray['team_set_id'])) {
3264 $GLOBALS['db']->addColumn($bean->table_name, $bean->field_defs['team_set_id']);
3266 $indexArray = $GLOBALS['db']->helper->get_indices($bean->table_name);
3268 $indexName = getValidDBName('idx_'.strtolower($bean->table_name).'_tmst_id', true, 34);
3271 'name' => $indexName,
3273 'fields' => array('team_set_id')
3276 if(!isset($indexArray[$indexName])) {
3277 $GLOBALS['db']->addIndexes($bean->table_name, $indexDef);
3280 //Update the table's team_set_id column to have the same values as team_id
3281 $GLOBALS['db']->query("UPDATE {$bean->table_name} SET team_set_id = {$column_name}");
3286 * Update the folder subscription table which confirms to the team security mechanism but
3287 * the class SugarFolders does not extend SugarBean and is therefore never picked up by the
3288 * upgradeModulesForTeamsets function.
3290 function upgradeFolderSubscriptionsTeamSetId()
3292 logThis("In upgradeFolderSubscriptionsTeamSetId()");
3293 $query = "UPDATE folders SET team_set_id = team_id";
3294 $result = $GLOBALS['db']->query($query);
3295 logThis("Finished upgradeFolderSubscriptionsTeamSetId()");
3299 * upgradeModulesForTeam
3301 * This method update the associated_user_id, name, name_2 to the private team records on teams table
3302 * This function is used for upgrade process from 5.1.x and 5.2.x.
3305 function upgradeModulesForTeam() {
3306 logThis("In upgradeModulesForTeam()");
3307 $result = $GLOBALS['db']->query("SELECT id, user_name, first_name, last_name FROM users where deleted=0");
3309 while($row = $GLOBALS['db']->fetchByAssoc($result)) {
3310 $results2 = $GLOBALS['db']->query("SELECT id FROM teams WHERE name = '({$row['user_name']})'");
3312 if(!$assoc = $GLOBALS['db']->fetchByAssoc($results2)) {
3313 //if team does not exist, then lets create the team for this user
3316 $user->retrieve($row['id']);
3317 $team->new_user_created($user);
3318 $team_id = $team->id;
3320 $team_id =$assoc['id'];
3324 $name = is_null($row['first_name'])?'':$row['first_name'];
3325 $name_2 = is_null($row['last_name'])?'':$row['last_name'];
3326 $associated_user_id = $row['id'];
3329 //Ensure team->name is not empty by using team->name_2 if available
3330 if(empty($name) && !empty($name_2)) {
3335 $query = "UPDATE teams SET name = '{$name}', name_2 = '{$name_2}', associated_user_id = '{$associated_user_id}' WHERE id = '{$team_id}'";
3336 $GLOBALS['db']->query($query);
3339 //Update the team_set_id and default_team columns
3340 $ce_to_pro_or_ent = (isset($_SESSION['upgrade_from_flavor']) && ($_SESSION['upgrade_from_flavor'] == 'SugarCE to SugarPro' || $_SESSION['upgrade_from_flavor'] == 'SugarCE to SugarEnt' || $_SESSION['upgrade_from_flavor'] == 'SugarCE to SugarCorp' || $_SESSION['upgrade_from_flavor'] == 'SugarCE to SugarUlt'));
3342 //Update team_set_id
3343 if($ce_to_pro_or_ent) {
3344 $GLOBALS['db']->query("update users set team_set_id = (select teams.id from teams where teams.associated_user_id = users.id)");
3345 $GLOBALS['db']->query("update users set default_team = (select teams.id from teams where teams.associated_user_id = users.id)");
3351 function addNewSystemTabsFromUpgrade($from_dir){
3353 if(isset($_SESSION['upgrade_from_flavor'])){
3355 //check to see if there are any new files that need to be added to systems tab
3356 //retrieve old modules list
3357 logThis('check to see if new modules exist',$path);
3358 $oldModuleList = array();
3359 $newModuleList = array();
3360 include($from_dir.'/include/modules.php');
3361 $oldModuleList = $moduleList;
3362 include('include/modules.php');
3363 $newModuleList = $moduleList;
3365 //include tab controller
3366 require_once('modules/MySettings/TabController.php');
3367 $newTB = new TabController();
3369 //make sure new modules list has a key we can reference directly
3370 $newModuleList = $newTB->get_key_array($newModuleList);
3371 $oldModuleList = $newTB->get_key_array($oldModuleList);
3373 //iterate through list and remove commonalities to get new modules
3374 foreach ($newModuleList as $remove_mod){
3375 if(in_array($remove_mod, $oldModuleList)){
3376 unset($newModuleList[$remove_mod]);
3379 //new modules list now has left over modules which are new to this install, so lets add them to the system tabs
3380 logThis('new modules to add are '.var_export($newModuleList,true),$path);
3382 if(!empty($newModuleList))
3384 //grab the existing system tabs
3385 $tabs = $newTB->get_system_tabs();
3387 //add the new tabs to the array
3388 foreach($newModuleList as $nm ){
3392 $newTB->set_system_tabs($tabs);
3394 logThis('module tabs updated',$path);
3400 * This method attempts to fix dropdown lists that were incorrectly named.
3401 * There were versions of SugarCRM that did not enforce naming convention rules
3402 * for the dropdown list field name. This method attempts to resolve that by
3403 * fixing the language files that may have been affected and then updating the
3404 * fields_meta_data table accordingly. It also refreshes any vardefs that may
3405 * have been affected.
3408 function fix_dropdown_list() {
3409 if(file_exists('custom/include/language')) {
3411 $affected_modules = array();
3412 $affected_keys = array();
3414 getFiles($files, 'custom/include/language', '/\.php$/i');
3415 foreach($files as $file) {
3417 if(file_exists($file . '.bak')) {
3418 $bak_mod_time = filemtime($file . '.bak');
3419 $php_mod_time = filemtime($file);
3420 //We're saying if the .php file was modified 30 seconds no more than php.bak file then we
3421 //run these additional cleanup checks
3422 if($php_mod_time - $bak_mod_time < 30) {
3424 $app_list_strings = array();
3425 $GLOBALS['app_list_strings'] = array();
3426 require($file . '.bak');
3427 $bak_app_list_strings = array_merge($app_list_strings, $GLOBALS['app_list_strings']);
3429 $app_list_strings = array();
3430 $GLOBALS['app_list_strings'] = array();
3432 $php_app_list_strings = array_merge($app_list_strings, $GLOBALS['app_list_strings']);
3434 //Get the file contents
3435 $contents = file_get_contents($file);
3437 //Now simulate a fix for the file before we compare w/ the .php file
3438 //we also append to the $contents
3439 foreach($bak_app_list_strings as $key=>$entry) {
3440 if(preg_match('/([^A-Za-z_])/', $key, $matches) && is_array($entry)) {
3441 $new_key = preg_replace('/[^A-Za-z_]/', '_', $key);
3442 $bak_app_list_strings[$new_key] = $bak_app_list_strings[$key];
3443 unset($bak_app_list_strings[$key]);
3444 //Now if the entry doesn't exists in the .php file, then add to contents
3445 if(!isset($php_app_list_strings[$new_key])) {
3446 $contents .= "\n\$GLOBALS['app_list_strings']['{$new_key}'] = " . var_export_helper($bak_app_list_strings[$new_key]) . ";";
3451 //Now load the .php file to do the comparison
3452 foreach($php_app_list_strings as $key=>$entry) {
3453 if(isset($bak_app_list_strings[$key])) {
3454 $diff = array_diff($bak_app_list_strings[$key], $entry);
3456 //There is a difference, so copy the $bak_app_list_strings version into the .php file
3457 $contents .= "\n\$GLOBALS['app_list_strings']['{$key}'] = " . var_export_helper($bak_app_list_strings[$key]) . ";";
3462 //Now write out the file contents
3463 //Create backup just in case
3464 copy($file, $file . '.php_bak');
3465 $fp = @sugar_fopen($file, 'w');
3467 fwrite($fp, $contents);
3470 $GLOBALS['log']->error("Unable to update file contents in fix_dropdown_list for {$file}");
3475 unset($GLOBALS['app_strings']);
3476 unset($GLOBALS['app_list_strings']);
3477 $app_list_strings = array();
3480 $contents = file_get_contents($file);
3481 if ( !isset($GLOBALS['app_list_strings']) ) {
3482 $GLOBALS['app_list_strings'] = $app_list_strings;
3485 $GLOBALS['app_list_strings'] = array_merge($app_list_strings, $GLOBALS['app_list_strings']);
3488 if(isset($GLOBALS['app_list_strings']) && is_array($GLOBALS['app_list_strings'])) {
3489 foreach($GLOBALS['app_list_strings'] as $key=>$entry) {
3490 if(preg_match('/([^A-Za-z_])/', $key, $matches) && is_array($entry)) {
3491 $result = $GLOBALS['db']->query("SELECT custom_module FROM fields_meta_data WHERE ext1 = '{$key}'");
3492 if(!empty($result)) {
3493 while($row = $GLOBALS['db']->fetchByAssoc($result)) {
3494 $custom_module = $row['custom_module'];
3495 if(!empty($GLOBALS['beanList'][$custom_module])) {
3496 $affected_modules[$custom_module] = $GLOBALS['beanList'][$custom_module];
3501 //Replace all invalid characters with '_' character
3502 $new_key = preg_replace('/[^A-Za-z_]/', '_', $key);
3503 $affected_keys[$key] = $new_key;
3505 $GLOBALS['app_list_strings'][$new_key] = $GLOBALS['app_list_strings'][$key];
3506 unset($GLOBALS['app_list_strings'][$key]);
3508 $pattern_match = "/(\[\s*\'{$key}\'\s*\])/";
3509 $new_key = "['{$new_key}']";
3510 $out = preg_replace($pattern_match, $new_key, $contents);
3516 //This is a check for g => h instances where the file contents were incorrectly written
3517 //and also fixes the scenario where via a UI upgrade, the app_list_strings were incorrectly
3518 //merged with app_list_strings variables declared elsewhere
3520 if(preg_match('/\$GLOBALS\s*\[\s*[\"|\']app_list_strings[\"|\']\s*\]\s*=\s*array\s*\(/', $contents)) {
3521 //Now also remove all the non-custom labels that were added
3522 if(preg_match('/language\/([^\.]+)\.lang\.php$/', $file, $matches)) {
3523 $language = $matches[1];
3525 $app_list_strings = array();
3527 if(file_exists("include/language/$language.lang.php")) {
3528 include("include/language/$language.lang.php");
3530 if(file_exists("include/language/$language.lang.override.php")) {
3531 $app_list_strings = _mergeCustomAppListStrings("include/language/$language.lang.override.php" , $app_list_strings) ;
3533 if(file_exists("custom/application/Ext/Language/$language.ext.lang.php")) {
3534 $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$language.ext.lang.php" , $app_list_strings) ;
3536 if(file_exists("custom/application/Ext/Language/$language.lang.ext.php")) {
3537 $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$language.lang.ext.php" , $app_list_strings) ;
3540 $all_non_custom_include_language_strings = $app_strings;
3541 $all_non_custom_include_language_list_strings = $app_list_strings;
3543 $unset_keys = array();
3544 if(!empty($GLOBALS['app_list_strings'])) {
3545 foreach($GLOBALS['app_list_strings'] as $key=>$value) {
3547 if(isset($all_non_custom_include_language_list_strings[$key])) {
3548 $diff = array_diff($all_non_custom_include_language_list_strings[$key], $GLOBALS['app_list_strings'][$key]);
3551 if(!empty($all_non_custom_include_language_list_strings[$key]) && empty($diff)) {
3552 $unset_keys[] = $key;
3557 foreach($unset_keys as $key) {
3558 unset($GLOBALS['app_list_strings'][$key]);
3561 if(!empty($GLOBALS['app_strings'])) {
3562 foreach($GLOBALS['app_strings'] as $key=>$value) {
3563 if(!empty($all_non_custom_include_language_strings[$key])) {
3564 unset($GLOBALS['app_strings'][$key]);
3568 } //if(preg_match...)
3571 if(!empty($GLOBALS['app_strings'])) {
3572 foreach($GLOBALS['app_strings'] as $key=>$entry) {
3573 $out .= "\n\$GLOBALS['app_strings']['$key']=" . var_export_helper($entry) . ";";
3577 foreach($GLOBALS['app_list_strings'] as $key=>$entry) {
3578 $out .= "\n\$GLOBALS['app_list_strings']['$key']=" . var_export_helper($entry) . ";";
3582 } //if(preg_match...)
3586 //Create a backup just in case
3587 copy($file, $file . '.bak');
3588 $fp = @sugar_fopen($file, 'w');
3593 //If we can't update the file, just return
3594 $GLOBALS['log']->error("Unable to update file contents in fix_dropdown_list.");
3602 //Update db entries (the order matters here... need to process database changes first)
3603 if(!empty($affected_keys)) {
3604 foreach($affected_keys as $old_key=>$new_key) {
3605 $GLOBALS['db']->query("UPDATE fields_meta_data SET ext1 = '{$new_key}' WHERE ext1 = '{$old_key}'");
3609 //Update vardef files for affected modules
3610 if(!empty($affected_modules)) {
3611 foreach($affected_modules as $module=>$object) {
3612 VardefManager::refreshVardefs($module, $object);
3619 function update_iframe_dashlets(){
3620 require_once(sugar_cached('dashlets/dashlets.php'));
3622 $db = DBManagerFactory::getInstance();
3623 $query = "SELECT id, contents, assigned_user_id FROM user_preferences WHERE deleted = 0 AND category = 'Home'";
3624 $result = $db->query($query, true, "Unable to update new default dashlets! ");
3625 while ($row = $db->fetchByAssoc($result)) {
3626 $content = unserialize(base64_decode($row['contents']));
3627 $assigned_user_id = $row['assigned_user_id'];
3628 $record_id = $row['id'];
3630 $current_user = new User();
3631 $current_user->retrieve($row['assigned_user_id']);
3633 if(!empty($content['dashlets']) && !empty($content['pages'])){
3634 $originalDashlets = $content['dashlets'];
3635 foreach($originalDashlets as $key => $ds){
3636 if(!empty($ds['options']['url']) && stristr($ds['options']['url'],'http://www.sugarcrm.com/crm/product/gopro')){
3637 unset($originalDashlets[$key]);
3640 $current_user->setPreference('dashlets', $originalDashlets, 0, 'Home');
3647 * convertImageToText
3649 * This method attempts to convert date type image to text on Microsoft SQL Server.
3650 * This method could NOT be used in any other type of datebases.
3652 function convertImageToText($table_name,$column_name){
3653 $set_lang = "SET LANGUAGE us_english";
3654 $GLOBALS['db']->query($set_lang);
3655 if($GLOBALS['db']->lastError()){
3656 logThis('An error occurred when performing this query-->'.$set_lang);
3658 $q="SELECT data_type
3659 FROM INFORMATION_SCHEMA.Tables T JOIN INFORMATION_SCHEMA.Columns C
3660 ON T.TABLE_NAME = C.TABLE_NAME where T.TABLE_NAME = '$table_name' and C.COLUMN_NAME = '$column_name'";
3661 $res= $GLOBALS['db']->query($q);
3662 if($GLOBALS['db']->lastError()){
3663 logThis('An error occurred when performing this query-->'.$q);
3665 $row= $GLOBALS['db']->fetchByAssoc($res);
3667 if(trim(strtolower($row['data_type'])) == 'image'){
3668 $addContent_temp = "alter table {$table_name} add {$column_name}_temp text null";
3669 $GLOBALS['db']->query($addContent_temp);
3670 if($GLOBALS['db']->lastError()){
3671 logThis('An error occurred when performing this query-->'.$addContent_temp);
3673 $qN = "select count=datalength({$column_name}), id, {$column_name} from {$table_name}";
3674 $result = $GLOBALS['db']->query($qN);
3675 while($row = $GLOBALS['db']->fetchByAssoc($result)){
3676 if($row['count'] >8000){
3677 $contentLength = $row['count'];
3680 $convertedContent = '';
3681 while($contentLength >0){
3682 $stepsQuery = "select cont=convert(varchar(max), convert(varbinary(8000), substring({$column_name},{$start},{$next}))) from {$table_name} where id= '{$row['id']}'";
3683 $steContQ = $GLOBALS['db']->query($stepsQuery);
3684 if($GLOBALS['db']->lastError()){
3685 logThis('An error occurred when performing this query-->'.$stepsQuery);
3687 $stepCont = $GLOBALS['db']->fetchByAssoc($steContQ);
3688 if(isset($stepCont['cont'])){
3689 $convertedContent = $convertedContent.$stepCont['cont'];
3691 $start = $start+$next;
3692 $contentLength = $contentLength - $next;
3694 $addContentDataText="update {$table_name} set {$column_name}_temp = '{$convertedContent}' where id= '{$row['id']}'";
3695 $GLOBALS['db']->query($addContentDataText);
3696 if($GLOBALS['db']->lastError()){
3697 logThis('An error occurred when performing this query-->'.$addContentDataText);
3701 $addContentDataText="update {$table_name} set {$column_name}_temp =
3702 convert(varchar(max), convert(varbinary(8000), {$column_name})) where id= '{$row['id']}'";
3703 $GLOBALS['db']->query($addContentDataText);
3704 if($GLOBALS['db']->lastError()){
3705 logThis('An error occurred when performing this query-->'.$addContentDataText);
3709 //drop the contents now and change contents_temp to contents
3710 $dropColumn = "alter table {$table_name} drop column {$column_name}";
3711 $GLOBALS['db']->query($dropColumn);
3712 if($GLOBALS['db']->lastError()){
3713 logThis('An error occurred when performing this query-->'.$dropColumn);
3715 $changeColumnName = "EXEC sp_rename '{$table_name}.[{$column_name}_temp]','{$column_name}','COLUMN'";
3716 $GLOBALS['db']->query($changeColumnName);
3717 if($GLOBALS['db']->lastError()){
3718 logThis('An error occurred when performing this query-->'.$changeColumnName);
3725 * This method attempts to delete all English inline help files.
3726 * This method was introduced by 5.5.0RC2.
3728 function clearHelpFiles(){
3729 $modulePath = clean_path(getcwd() . '/modules');
3730 $allHelpFiles = array();
3731 getFiles($allHelpFiles, $modulePath, "/en_us.help.*/");
3733 foreach( $allHelpFiles as $the_file ){
3734 if( is_file( $the_file ) ){
3735 unlink( $the_file );
3736 logThis("Deleted file: $the_file");
3744 * upgradeDateTimeFields
3746 * This method came from bug: 39757 where the date_end field is a date field and not a datetime field
3747 * which prevents you from performing timezone offset calculations once the data has been saved.
3749 * @param path String location to log file, empty by default
3751 function upgradeDateTimeFields($path)
3755 $meetingsSql = "UPDATE meetings SET date_end = ".$db->convert("date_start", 'add_time', array('duration_hours', 'duration_minutes'));
3756 $callsSql = "UPDATE calls SET date_end = ".$db->convert("date_start", 'add_time', array('duration_hours', 'duration_minutes'));
3757 logThis('upgradeDateTimeFields Meetings SQL:' . $meetingsSql, $path);
3758 $db->query($meetingsSql);
3760 logThis('upgradeDateTimeFields Calls SQL:' . $callsSql, $path);
3761 $db->query($callsSql);
3765 * upgradeDocumentTypeFields
3768 function upgradeDocumentTypeFields($path){
3772 $documentsSql = "UPDATE documents SET doc_type = 'Sugar' WHERE doc_type IS NULL";
3773 $meetingsSql = "UPDATE meetings SET type = 'Sugar' WHERE type IS NULL";
3775 logThis('upgradeDocumentTypeFields Documents SQL:' . $documentsSql, $path);
3776 $db->query($documentsSql);
3777 logThis('upgradeDocumentTypeFields Meetings SQL:' . $meetingsSql, $path);
3778 $db->query($meetingsSql);
3783 * merge_config_si_settings
3784 * This method checks for the presence of a config_si.php file and, if found, merges the configuration
3785 * settings from the config_si.php file into config.php. If a config_si_location parameter value is not
3786 * supplied it will attempt to discover the config_si.php file location from where the executing script
3789 * @param write_to_upgrade_log boolean optional value to write to the upgradeWizard.log file
3790 * @param config_location String optional value to config.php file location
3791 * @param config_si_location String optional value to config_si.php file location
3792 * @param path String file of the location of log file to write to
3793 * @return boolean value indicating whether or not a merge was attempted with config_si.php file
3795 function merge_config_si_settings($write_to_upgrade_log=false, $config_location='', $config_si_location='', $path='')
3797 if(!empty($config_location) && !file_exists($config_location))
3799 if($write_to_upgrade_log)
3801 logThis('config.php file specified in ' . $config_si_location . ' could not be found. Skip merging', $path);
3804 } else if(empty($config_location)) {
3806 //We are assuming this is from the silentUpgrade scripts so argv[3] will point to SugarCRM install location
3807 if(isset($argv[3]) && is_dir($argv[3]))
3809 $config_location = $argv[3] . DIRECTORY_SEPARATOR . 'config.php';
3813 //If config_location is still empty or if the file cannot be found, skip merging
3814 if(empty($config_location) || !file_exists($config_location))
3816 if($write_to_upgrade_log)
3818 logThis('config.php file at (' . $config_location . ') could not be found. Skip merging.', $path);
3822 if($write_to_upgrade_log)
3824 logThis('Loading config.php file at (' . $config_location . ') for merging.', $path);
3827 include($config_location);
3828 if(empty($sugar_config))
3830 if($write_to_upgrade_log)
3832 logThis('config.php contents are empty. Skip merging.', $path);
3838 if(!empty($config_si_location) && !file_exists($config_si_location))
3840 if($write_to_upgrade_log)
3842 logThis('config_si.php file specified in ' . $config_si_location . ' could not be found. Skip merging', $path);
3845 } else if(empty($config_si_location)) {
3846 if(isset($argv[0]) && is_file($argv[0]))
3848 $php_file = $argv[0];
3849 $p_info = pathinfo($php_file);
3850 $php_dir = (isset($p_info['dirname']) && $p_info['dirname'] != '.') ? $p_info['dirname'] . DIRECTORY_SEPARATOR : '';
3851 $config_si_location = $php_dir . 'config_si.php';
3855 //If config_si_location is still empty or if the file cannot be found, skip merging
3856 if(empty($config_si_location) || !file_exists($config_si_location))
3858 if($write_to_upgrade_log)
3860 logThis('config_si.php file at (' . $config_si_location . ') could not be found. Skip merging.', $path);
3864 if($write_to_upgrade_log)
3866 logThis('Loading config_si.php file at (' . $config_si_location . ') for merging.', $path);
3869 include($config_si_location);
3870 if(empty($sugar_config_si))
3872 if($write_to_upgrade_log)
3874 logThis('config_si.php contents are empty. Skip merging.', $path);
3880 //Now perform the merge operation
3882 foreach($sugar_config_si as $key=>$value)
3884 if(!preg_match('/^setup_/', $key) && !isset($sugar_config[$key]))
3886 if($write_to_upgrade_log)
3888 logThis('Merge key (' . $key . ') with value (' . $value . ')', $path);
3890 $sugar_config[$key] = $value;
3897 if($write_to_upgrade_log)
3899 logThis('Update config.php file with new values', $path);
3902 if(!write_array_to_file("sugar_config", $sugar_config, $config_location)) {
3903 if($write_to_upgrade_log)
3905 logThis('*** ERROR: could not write to config.php', $path);
3910 if($write_to_upgrade_log)
3912 logThis('config.php values are in sync with config_si.php values. Skipped merging.');
3917 if($write_to_upgrade_log)
3919 logThis('End merge_config_si_settings', $path);
3926 * upgrade_connectors
3928 * This function handles support for upgrading connectors it is invoked from both end.php and silentUpgrade_step2.php
3931 function upgrade_connectors() {
3932 require_once('include/connectors/utils/ConnectorUtils.php');
3933 if(!ConnectorUtils::updateMetaDataFiles()) {
3934 $GLOBALS['log']->fatal('Cannot update metadata files for connectors');
3937 //Delete the custom connectors.php file if it exists so that it may be properly rebuilt
3938 if(file_exists('custom/modules/Connectors/metadata/connectors.php'))
3940 unlink('custom/modules/Connectors/metadata/connectors.php');
3945 * Enable the InsideView connector for the four default modules.
3947 function upgradeEnableInsideViewConnector($path='')
3949 logThis('Begin upgradeEnableInsideViewConnector', $path);
3951 // Load up the existing mapping and hand it to the InsideView connector to have it setup the correct logic hooks
3952 $mapFile = 'modules/Connectors/connectors/sources/ext/rest/insideview/mapping.php';
3953 if ( file_exists('custom/'.$mapFile) ) {
3954 logThis('Found CUSTOM mappings', $path);
3955 require('custom/'.$mapFile);
3957 logThis('Used default mapping', $path);
3961 require_once('include/connectors/sources/SourceFactory.php');
3962 $source = SourceFactory::getSource('ext_rest_insideview');
3964 // $mapping is brought in from the mapping.php file above
3965 $source->saveMappingHook($mapping);
3967 require_once('include/connectors/utils/ConnectorUtils.php');
3968 ConnectorUtils::installSource('ext_rest_insideview');
3970 // Now time to set the various modules to active, because this part ignores the default config
3971 require(CONNECTOR_DISPLAY_CONFIG_FILE);
3972 // $modules_sources come from that config file
3973 foreach ( $source->allowedModuleList as $module ) {
3974 $modules_sources[$module]['ext_rest_insideview'] = 'ext_rest_insideview';
3976 if(!write_array_to_file('modules_sources', $modules_sources, CONNECTOR_DISPLAY_CONFIG_FILE)) {
3977 //Log error and return empty array
3978 logThis("Cannot write \$modules_sources to " . CONNECTOR_DISPLAY_CONFIG_FILE,$path);
3981 logThis('End upgradeEnableInsideViewConnector', $path);
3985 function repair_long_relationship_names($path='')
3987 logThis("Begin repair_long_relationship_names", $path);
3988 require_once 'modules/ModuleBuilder/parsers/relationships/DeployedRelationships.php' ;
3989 $GLOBALS['mi_remove_tables'] = false;
3991 foreach($GLOBALS['moduleList'] as $module)
3993 $relationships = new DeployedRelationships ($module) ;
3994 foreach($relationships->getRelationshipList() as $rel_name)
3996 if (strlen($rel_name) > 27 && empty($touched[$rel_name]))
3998 logThis("Rebuilding relationship fields for $rel_name", $path);
3999 $touched[$rel_name] = true;
4000 $rel_obj = $relationships->get($rel_name);
4001 $rel_obj->setReadonly(false);
4002 $relationships->delete($rel_name);
4003 $relationships->save();
4004 $relationships->add($rel_obj);
4005 $relationships->save();
4006 $relationships->build () ;
4010 logThis("End repair_long_relationship_names", $path);
4013 function removeSilentUpgradeVarsCache(){
4014 global $silent_upgrade_vars_loaded;
4016 $cacheFileDir = "{$GLOBALS['sugar_config']['cache_dir']}/silentUpgrader";
4017 $cacheFile = "{$cacheFileDir}/silentUpgradeCache.php";
4019 if(file_exists($cacheFile)){
4023 $silent_upgrade_vars_loaded = array(); // Set to empty to reset it
4028 function loadSilentUpgradeVars(){
4029 global $silent_upgrade_vars_loaded;
4031 if(empty($silent_upgrade_vars_loaded)){
4032 $cacheFile = "{$GLOBALS['sugar_config']['cache_dir']}/silentUpgrader/silentUpgradeCache.php";
4033 // We have no pre existing vars
4034 if(!file_exists($cacheFile)){
4035 // Set the vars array so it's loaded
4036 $silent_upgrade_vars_loaded = array('vars' => array());
4039 require_once($cacheFile);
4040 $silent_upgrade_vars_loaded = $silent_upgrade_vars_cache;
4047 function writeSilentUpgradeVars(){
4048 global $silent_upgrade_vars_loaded;
4050 if(empty($silent_upgrade_vars_loaded)){
4051 return false; // You should have set some values before trying to write the silent upgrade vars
4054 $cacheFileDir = "{$GLOBALS['sugar_config']['cache_dir']}/silentUpgrader";
4055 $cacheFile = "{$cacheFileDir}/silentUpgradeCache.php";
4057 require_once('include/dir_inc.php');
4058 if(!mkdir_recursive($cacheFileDir)){
4061 require_once('include/utils/file_utils.php');
4062 if(!write_array_to_file('silent_upgrade_vars_cache', $silent_upgrade_vars_loaded, $cacheFile, 'w')){
4064 logThis("WARNING: writeSilentUpgradeVars could not write to {$cacheFile}", $path);
4071 function setSilentUpgradeVar($var, $value){
4072 if(!loadSilentUpgradeVars()){
4076 global $silent_upgrade_vars_loaded;
4078 $silent_upgrade_vars_loaded['vars'][$var] = $value;
4083 function getSilentUpgradeVar($var){
4084 if(!loadSilentUpgradeVars()){
4088 global $silent_upgrade_vars_loaded;
4090 if(!isset($silent_upgrade_vars_loaded['vars'][$var])){
4094 return $silent_upgrade_vars_loaded['vars'][$var];
4100 * add_unified_search_to_custom_modules_vardefs
4102 * This method calls the repair code to remove the unified_search_modules.php fiel
4105 function add_unified_search_to_custom_modules_vardefs()
4107 if(file_exists($cachefile = sugar_cached('modules/unified_search_modules.php')))
4115 * change from using the older SugarCache in 6.1 and below to the new one in 6.2
4117 function upgradeSugarCache($file)
4119 global $sugar_config;
4120 $cacheUploadUpgradesTemp = mk_temp_dir(sugar_cached('upgrades/temp'));
4122 unzip($file, $cacheUploadUpgradesTemp);
4124 if(!file_exists(clean_path("{$cacheUploadUpgradesTemp}/manifest.php"))) {
4125 logThis("*** ERROR: no manifest file detected while bootstraping upgrade wizard files!");
4128 include(clean_path("{$cacheUploadUpgradesTemp}/manifest.php"));
4131 $from_dir = "{$cacheUploadUpgradesTemp}/{$manifest['copy_files']['from_dir']}";
4132 $allFiles = array();
4133 if(file_exists("$from_dir/include/SugarCache")) {
4134 $allFiles = findAllFiles("$from_dir/include/SugarCache", $allFiles);
4136 if(file_exists("$from_dir/include/database")) {
4137 $allFiles = findAllFiles("$from_dir/include/database", $allFiles);
4139 if(file_exists("$from_dir/include/utils/external_cache.php")) {
4140 $allFiles[] = "$from_dir/include/utils/external_cache.php";
4142 if(file_exists("$from_dir/include/utils/sugar_file_utils.php")) {
4143 $allFiles[] = "$from_dir/include/utils/sugar_file_utils.php";
4145 if(file_exists("$from_dir/include/utils/sugar_file_utils.php")) {
4146 $allFiles[] = "$from_dir/include/utils/sugar_file_utils.php";
4149 foreach($allFiles as $k => $file) {
4150 $destFile = str_replace($from_dir."/", "", $file);
4151 if(!is_dir(dirname($destFile))) {
4152 mkdir_recursive(dirname($destFile)); // make sure the directory exists
4154 if ( stristr($file,'uw_main.tpl') )
4155 logThis('Skipping "'.$file.'" - file copy will during commit step.');
4157 logThis('updating UpgradeWizard code: '.$destFile);
4158 copy_recursive($file, $destFile);
4165 * upgradeDisplayedTabsAndSubpanels
4167 * @param $version String value of current system version (pre upgrade)
4169 function upgradeDisplayedTabsAndSubpanels($version)
4171 if($version < '620')
4173 logThis('start upgrading system displayed tabs and subpanels');
4174 require_once('modules/MySettings/TabController.php');
4175 $tc = new TabController();
4177 //grab the existing system tabs
4178 $tabs = $tc->get_tabs_system();
4180 //add Calls, Meetings, Tasks, Notes, Prospects (Targets) and ProspectLists (Target Lists)
4181 //to displayed tabs unless explicitly set to hidden
4182 $modules_to_add = array('Calls', 'Meetings', 'Tasks', 'Notes', 'Prospects', 'ProspectLists');
4183 $added_tabs = array();
4185 foreach($modules_to_add as $module)
4187 $tabs[0][$module] = $module;
4188 $added_tabs[] = $module;
4191 logThis('calling set_system_tabs on TabController to add tabs: ' . var_export($added_tabs, true));
4192 $tc->set_system_tabs($tabs[0]);
4193 logThis('finish upgrading system displayed tabs and subpanels');
4199 * unlinkUpgradeFiles
4200 * This is a helper function to clean up
4202 * @param $version String value of current system version (pre upgrade)
4204 function unlinkUpgradeFiles($version)
4206 if(!isset($version))
4211 //First check if we even have the scripts_for_patch/files_to_remove directory
4212 require_once('modules/UpgradeWizard/UpgradeRemoval.php');
4215 if(empty($_SESSION['unzip_dir']))
4217 global $sugar_config;
4218 $base_upgrade_dir = $sugar_config['upload_dir'] . "/upgrades";
4219 $base_tmp_upgrade_dir = "$base_upgrade_dir/temp";
4220 $_SESSION['unzip_dir'] = mk_temp_dir( $base_tmp_upgrade_dir );
4224 if(isset($_SESSION['unzip_dir']) && file_exists($_SESSION['unzip_dir'].'/scripts/files_to_remove'))
4226 $files_to_remove = glob($_SESSION['unzip_dir'].'/scripts/files_to_remove/*.php');
4228 foreach($files_to_remove as $script)
4230 if(preg_match('/UpgradeRemoval(\d+)x\.php/', $script, $matches))
4232 $checkVersion = $matches[1] + 1; //Increment by one to check everything equal or below the target version
4233 $upgradeClass = 'UpgradeRemoval' . $matches[1] . 'x';
4234 require_once($_SESSION['unzip_dir'].'/scripts/files_to_remove/' . $upgradeClass . '.php');
4236 //Check to make sure we should load and run this UpgradeRemoval instance
4237 if($checkVersion <= $version && class_exists($upgradeClass))
4239 $upgradeInstance = new $upgradeClass();
4240 if($upgradeInstance instanceof UpgradeRemoval)
4242 logThis('Running UpgradeRemoval instance ' . $upgradeClass);
4243 logThis('Files will be backed up to custom/backup');
4244 $files = $upgradeInstance->getFilesToRemove($version);
4245 foreach($files as $file)
4249 $upgradeInstance->processFilesToRemove($files);
4256 //Check if we have a custom directory
4257 if(file_exists('custom/scripts/files_to_remove'))
4260 $files_to_remove = glob('custom/scripts/files_to_remove/*.php');
4262 foreach($files_to_remove as $script)
4264 if(preg_match('/\/files_to_remove\/(.*?)\.php$/', $script, $matches))
4266 require_once($script);
4267 $upgradeClass = $matches[1];
4269 if(!class_exists($upgradeClass))
4274 $upgradeInstance = new $upgradeClass();
4275 if($upgradeInstance instanceof UpgradeRemoval)
4277 logThis('Running Custom UpgradeRemoval instance ' . $upgradeClass);
4278 $files = $upgradeInstance->getFilesToRemove($version);
4279 foreach($files as $file)
4283 $upgradeInstance->processFilesToRemove($files);
4291 if (!function_exists("getValidDBName"))
4294 * Return a version of $proposed that can be used as a column name in any of our supported databases
4295 * Practically this means no longer than 25 characters as the smallest identifier length for our supported DBs is 30 chars for Oracle plus we add on at least four characters in some places (for indicies for example)
4296 * @param string $name Proposed name for the column
4297 * @param string $ensureUnique
4298 * @return string Valid column name trimmed to right length and with invalid characters removed
4300 function getValidDBName ($name, $ensureUnique = false, $maxLen = 30)
4302 // first strip any invalid characters - all but alphanumerics and -
4303 $name = preg_replace ( '/[^\w-]+/i', '', $name ) ;
4304 $len = strlen ( $name ) ;
4308 $md5str = md5($name);
4309 $tail = substr ( $name, -11) ;
4310 $temp = substr($md5str , strlen($md5str)-4 );
4311 $result = substr ( $name, 0, 10) . $temp . $tail ;
4312 }else if ($len > ($maxLen - 5))
4314 $result = substr ( $name, 0, 11) . substr ( $name, 11 - $maxLen + 5);
4316 return strtolower ( $result ) ;
4323 * Get UW directories
4324 * Provides compatibility with both 6.3 and pre-6.3 setup
4326 function getUWDirs()
4328 if(!class_exists('UploadStream')) {
4329 // we're still running the old code
4330 global $sugar_config;
4331 return array($sugar_config['upload_dir'] . "/upgrades", $sugar_config['cache_dir'] . "upload/upgrades/temp");
4333 if(!in_array("upload", stream_get_wrappers())) {
4334 UploadStream::register(); // just in case file was copied, but not run
4336 return array("upload://upgrades", sugar_cached("upgrades/temp"));
4341 * Whether directory exists within list of directories to skip
4342 * @param string $dir dir to be checked
4343 * @param array $skipDirs list with skipped dirs
4346 function whetherNeedToSkipDir($dir, $skipDirs)
4348 foreach($skipDirs as $skipMe) {
4349 if(strpos( clean_path($dir), $skipMe ) !== false) {
4359 * @param silentUpgrade boolean flag indicating whether or not we should treat running the SugarSpriteBuilder as an upgrade operation
4362 function rebuildSprites($fromUpgrade=true)
4364 require_once('modules/Administration/SugarSpriteBuilder.php');
4365 $sb = new SugarSpriteBuilder();
4366 $sb->cssMinify = true;
4367 $sb->fromSilentUpgrade = $fromUpgrade;
4368 $sb->silentRun = $fromUpgrade;
4370 // add common image directories
4371 $sb->addDirectory('default', 'include/images');
4372 $sb->addDirectory('default', 'themes/default/images');
4373 $sb->addDirectory('default', 'themes/default/images/SugarLogic');
4375 // add all theme image directories
4376 if($dh = opendir('themes'))
4378 while (($dir = readdir($dh)) !== false)
4380 if ($dir != "." && $dir != ".." && $dir != 'default' && is_dir('themes/'.$dir)) {
4381 $sb->addDirectory($dir, "themes/{$dir}/images");
4387 // add all theme custom image directories
4388 $custom_themes_dir = "custom/themes";
4389 if (is_dir($custom_themes_dir)) {
4390 if($dh = opendir($custom_themes_dir))
4392 while (($dir = readdir($dh)) !== false)
4394 //Since the custom theme directories don't require an images directory
4395 // we check for it implicitly
4396 if ($dir != "." && $dir != ".." && is_dir('custom/themes/'.$dir."/images")) {
4397 $sb->addDirectory($dir, "custom/themes/{$dir}/images");
4404 // generate the sprite goodies
4405 // everything is saved into cache/sprites
4406 $sb->createSprites();
4411 * repairSearchFields
4413 * This method goes through the list of SearchFields files based and calls TemplateRange::repairCustomSearchFields
4414 * method on the files in an attempt to ensure the range search attributes are properly set in SearchFields.php.
4416 * @param $globString String value used for glob search defaults to searching for all SearchFields.php files in modules directory
4417 * @param $path String value used to point to log file should logging be required. Defaults to empty.
4420 function repairSearchFields($globString='modules/*/metadata/SearchFields.php', $path='')
4424 logThis('Begin repairSearchFields', $path);
4427 require_once('include/dir_inc.php');
4428 require_once('modules/DynamicFields/templates/Fields/TemplateRange.php');
4429 require('include/modules.php');
4432 $searchFieldsFiles = glob($globString);
4434 foreach($searchFieldsFiles as $file)
4436 if(preg_match('/modules\/(.*?)\/metadata\/SearchFields\.php/', $file, $matches) && isset($beanList[$matches[1]]))
4438 $module = $matches[1];
4439 $beanName = $beanList[$module];
4440 VardefManager::loadVardef($module, $beanName);
4441 if(isset($GLOBALS['dictionary'][$beanName]['fields']))
4445 logThis('Calling TemplateRange::repairCustomSearchFields for module ' . $module, $path);
4447 TemplateRange::repairCustomSearchFields($GLOBALS['dictionary'][$beanName]['fields'], $module);
4454 logThis('End repairSearchFields', $path);
4459 * repairUpgradeHistoryTable
4461 * This is a helper function used in the upgrade process to fix upgrade_history entries so that the filename column points
4462 * to the new upload directory location introduced in 6.4 versions
4464 function repairUpgradeHistoryTable()
4466 require_once('modules/Configurator/Configurator.php');
4468 global $sugar_config;
4470 //Now upgrade the upgrade_history table entries
4471 $results = $GLOBALS['db']->query('SELECT id, filename FROM upgrade_history');
4472 $upload_dir = $sugar_config['cache_dir'].'upload/';
4474 //Create regular expression string to
4475 $match = '/^' . str_replace('/', '\/', $upload_dir) . '(.*?)$/';
4477 while(($row = $GLOBALS['db']->fetchByAssoc($results)))
4479 $file = str_replace('//', '/', $row['filename']); //Strip out double-paths that may exist
4481 if(!empty($file) && preg_match($match, $file, $matches))
4483 //Update new file location to use the new $sugar_config['upload_dir'] value
4484 $new_file_location = $sugar_config['upload_dir'] . $matches[1];
4485 $GLOBALS['db']->query("UPDATE upgrade_history SET filename = '{$new_file_location}' WHERE id = '{$row['id']}'");