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($e = $d->read()){
230 $next = $path . '/'. $e;
231 if(substr($e, 0, 1) != '.' && is_dir($next)){
232 $removed += removeFileFromPath($file, $next, $deleteNot);
239 * This function copies/overwrites between directories
241 * @param string the directory name to remove
242 * @param boolean whether to just empty the given directory, without deleting the given directory.
243 * @return boolean True/False whether the directory was deleted.
246 function copyRecursiveBetweenDirectories($from,$to){
247 if(file_exists($from)){
248 $modifiedFiles = array();
249 $modifiedFiles = findAllFiles(clean_path($from), $modifiedFiles);
250 $cwd = clean_path(getcwd());
251 foreach($modifiedFiles as $file) {
252 $srcFile = clean_path($file);
253 if (strpos($srcFile,".svn") === false) {
254 $targetFile = str_replace($from, $to, $srcFile);
256 if(!is_dir(dirname($targetFile))) {
257 mkdir_recursive(dirname($targetFile)); // make sure the directory exists
260 // handle sugar_version.php
261 if(strpos($targetFile, 'sugar_version.php') !== false && !preg_match('/\/portal\/sugar_version\.php$/i', $targetFile)) {
262 logThis('Skipping "sugar_version.php" - file copy will occur at end of successful upgrade', $targetFile);
263 $_SESSION['sugar_version_file'] = $srcFile;
267 if(!copy($srcFile, $targetFile)) {
268 logThis("*** ERROR: could not copy file $srcFile to $targetFile");
275 function deleteDirectory($dirname,$only_empty=false) {
276 if (!is_dir($dirname))
278 $dscan = array(realpath($dirname));
280 while (!empty($dscan)) {
281 $dcur = array_pop($dscan);
283 if ($d=opendir($dcur)) {
284 while ($f=readdir($d)) {
285 if ($f=='.' || $f=='..')
296 $i_until = ($only_empty)? 1 : 0;
297 for ($i=count($darr)-1; $i>=$i_until; $i--) {
298 if (rmdir($darr[$i]))
299 logThis('Success :Copying file to destination: ' . $darr[$i]);
301 logThis('Copy problem:Copying file to destination: ' . $darr[$i]);
303 return (($only_empty)? (count(scandir)<=2) : (!is_dir($dirname)));
306 * Get all the customized modules. Compare the file md5s with the base md5s
307 * If a file has been modified then put the module in the list of customized
308 * modules. Show the list in the preflight check UI.
311 function deleteAndOverWriteSelectedFiles($unzip_dir, $zip_from_dir,$delete_dirs){
312 if($delete_dirs != null){
313 foreach($delete_dirs as $del_dir){
314 deleteDirectory($del_dir);
315 $newFiles = findAllFiles(clean_path($unzip_dir . '/' . $zip_from_dir.'/'.$del_dir), array());
316 $zipPath = clean_path($unzip_dir . '/' . $zip_from_dir.'/'.$del_dir);
317 $copiedFiles = array();
318 $skippedFiles = array();
320 foreach($newFiles as $file) {
321 $cleanFile = str_replace($zipPath, '', $file);
322 $srcFile = $zipPath . $cleanFile;
323 $targetFile = clean_path(getcwd() . '/' . $cleanFile);
325 if(!is_dir(dirname($targetFile))) {
326 mkdir_recursive(dirname($targetFile)); // make sure the directory exists
329 if(!file_exists($targetFile)){
330 // handle sugar_version.php
331 if(strpos($targetFile, 'sugar_version.php') !== false) {
332 logThis('Skipping sugar_version.php - file copy will occur at end of successful upgrade');
333 $_SESSION['sugar_version_file'] = $srcFile;
337 //logThis('Copying file to destination: ' . $targetFile);
339 if(!copy($srcFile, $targetFile)) {
340 logThis('*** ERROR: could not copy file: ' . $targetFile);
342 $copiedFiles[] = $targetFile;
345 //logThis('Skipping file: ' . $targetFile);
346 $skippedFiles[] = $targetFile;
352 $ret['copiedFiles'] = $copiedFiles;
353 $ret['skippedFiles'] = $skippedFiles;
358 //Default is empty the directory. For removing set it to false
359 // to use this function to totally remove a directory, write:
360 // recursive_remove_directory('path/to/directory/to/delete',FALSE);
362 // to use this function to empty a directory, write:
363 // recursive_remove_directory('path/to/full_directory');
365 function recursive_empty_or_remove_directory($directory, $exclude_dirs=null,$exclude_files=null,$empty=TRUE)
367 // if the path has a slash at the end we remove it here
368 if(substr($directory,-1) == '/')
370 $directory = substr($directory,0,-1);
373 // if the path is not valid or is not a directory ...
374 if(!file_exists($directory) || !is_dir($directory))
376 // ... we return false and exit the function
379 // ... if the path is not readable
380 }elseif(!is_readable($directory))
382 // ... we return false and exit the function
385 // ... else if the path is readable
388 // we open the directory
389 $handle = opendir($directory);
391 // and scan through the items inside
392 while (FALSE !== ($item = readdir($handle)))
394 // if the filepointer is not the current directory
395 // or the parent directory
396 if($item != '.' && $item != '..')
398 // we build the new path to delete
399 $path = $directory.'/'.$item;
401 // if the new path is a directory
402 //add another check if the dir is in the list to exclude delete
403 if(is_dir($path) && $exclude_dirs != null && in_array($path,$exclude_dirs)){
406 else if(is_dir($path))
408 // we call this function with the new path
409 recursive_empty_or_remove_directory($path);
411 // if the new path is a file
413 // we remove the file
414 if($exclude_files != null && in_array($path,$exclude_files)){
423 // close the directory
426 // if the option to empty is not set to true
429 // try to delete the now empty directory
430 if(!rmdir($directory))
432 // return false if not possible
440 // ------------------------------------------------------------
445 function getAllCustomizedModules() {
447 require_once('files.md5');
449 $return_array = array();
450 $modules = getAllModules();
451 foreach($modules as $mod) {
452 //find all files in each module if the files have been modified
453 //as compared to the base version then add the module to the
454 //customized modules array
455 $modFiles = findAllFiles(clean_path(getcwd())."/modules/$mod", array());
456 foreach($modFiles as $file){
457 $fileContents = file_get_contents($file);
458 $file = str_replace(clean_path(getcwd()),'',$file);
459 if($md5_string['./' . $file]){
460 if(md5($fileContents) != $md5_string['./' . $file]) {
461 //A file has been customized in the module. Put the module into the
462 // customized modules array.
463 echo 'Changed File'.$file;
469 // This is a new file in user's version and indicates that module has been
470 //customized. Put the module in the customized array.
471 echo 'New File'.$file;
478 return $return_array;
482 * Array of all Modules in the version bein upgraded
483 * This method returns an Array of all modules
484 * @return $modules Array of modules.
486 function getAllModules() {
489 while($e = $d->read()){
490 if(substr($e, 0, 1) == '.' || !is_dir('modules/' . $e))continue;
496 //Remove files with the smae md5
498 function removeMd5MatchingFiles($deleteNot=array()){
500 $md5_string = array();
501 if(file_exists(clean_path(getcwd().'/files.md5'))){
502 require(clean_path(getcwd().'/files.md5'));
504 $modulesAll = getAllModules();
505 foreach($modulesAll as $mod){
506 $allModFiles = array();
507 if(is_dir('modules/'.$mod)){
508 $allModFiles = findAllFiles('modules/'.$mod,$allModFiles);
509 foreach($allModFiles as $file){
510 if(file_exists($file) && !in_array(basename($file),$deleteNot)){
511 if(isset($md5_string['./'.$file])) {
512 $fileContents = file_get_contents($file);
513 if(md5($fileContents) == $md5_string['./'.$file]) {
524 * Handles requirements for creating reminder Tasks and Emails
525 * @param array skippedFiles Array of files that were not overwriten and must be manually mereged.
526 * @param string path Optional full path to alternate upgradeWizard log.
528 function commitHandleReminders($skippedFiles, $path='') {
530 global $current_user;
532 if(empty($mod_strings))
533 $mod_strings = return_module_language('en_us', 'UpgradeWizard');
535 if(empty($current_user->id)) {
536 $current_user->getSystemUser();
539 if(count($skippedFiles) > 0) {
540 $desc = $mod_strings['LBL_UW_COMMIT_ADD_TASK_OVERVIEW'] . "\n\n";
541 $desc .= $mod_strings['LBL_UW_COMMIT_ADD_TASK_DESC_1'];
542 $desc .= $_SESSION['uw_restore_dir'] . "\n\n";
543 $desc .= $mod_strings['LBL_UW_COMMIT_ADD_TASK_DESC_2'] . "\n\n";
545 foreach($skippedFiles as $file) {
546 $desc .= $file . "\n";
550 /// Not using new TimeDate stuff here because it needs to be compatible with 6.0
551 $nowDate = gmdate('Y-m-d');
552 $nowTime = gmdate('H:i:s');
553 $nowDateTime = $nowDate . ' ' . $nowTime;
555 if($_REQUEST['addTaskReminder'] == 'remind') {
556 logThis('Adding Task for admin for manual merge.', $path);
559 $task->name = $mod_strings['LBL_UW_COMMIT_ADD_TASK_NAME'];
560 $task->description = $desc;
561 $task->date_due = $nowDate;
562 $task->time_due = $nowTime;
563 $task->priority = 'High';
564 $task->status = 'Not Started';
565 $task->assigned_user_id = $current_user->id;
566 $task->created_by = $current_user->id;
567 $task->date_entered = $nowDateTime;
568 $task->date_modified = $nowDateTime;
572 if($_REQUEST['addEmailReminder'] == 'remind') {
573 logThis('Sending Reminder for admin for manual merge.', $path);
575 $email = new Email();
576 $email->assigned_user_id = $current_user->id;
577 $email->name = $mod_strings['LBL_UW_COMMIT_ADD_TASK_NAME'];
578 $email->description = $desc;
579 $email->description_html = nl2br($desc);
580 $email->from_name = $current_user->full_name;
581 $email->from_addr = $current_user->email1;
582 $email->to_addrs_arr = $email->parse_addrs($current_user->email1, '', '', '');
583 $email->cc_addrs_arr = array();
584 $email->bcc_addrs_arr = array();
585 $email->date_entered = $nowDateTime;
586 $email->date_modified = $nowDateTime;
593 function deleteCache(){
594 //Clean modules from cache
595 $cachedir = sugar_cached('modules');
596 if(is_dir($cachedir)){
597 $allModFiles = array();
598 $allModFiles = findAllFiles($cachedir,$allModFiles, true);
599 foreach($allModFiles as $file) {
600 if(file_exists($file)) {
602 rmdir_recursive($file);
611 //Clean jsLanguage from cache
612 $cachedir = sugar_cached('jsLanguage');
613 if(is_dir($cachedir)){
614 $allModFiles = array();
615 $allModFiles = findAllFiles($cachedir,$allModFiles);
616 foreach($allModFiles as $file){
617 if(file_exists($file)){
622 //Clean smarty from cache
623 $cachedir = sugar_cached('smarty');
624 if(is_dir($cachedir)){
625 $allModFiles = array();
626 $allModFiles = findAllFiles($cachedir,$allModFiles);
627 foreach($allModFiles as $file){
628 if(file_exists($file)){
633 //Rebuild dashlets cache
634 require_once('include/Dashlets/DashletCacheBuilder.php');
635 $dc = new DashletCacheBuilder();
639 function deleteChance(){
640 //Clean folder from cache
641 if(is_dir('include/SugarObjects/templates/chance')){
642 rmdir_recursive('include/SugarObjects/templates/chance');
644 if(is_dir('include/SugarObjects/templates/chance')){
645 if(!isset($_SESSION['chance'])){
646 $_SESSION['chance'] = '';
648 $_SESSION['chance'] = 'include/SugarObjects/templates/chance';
649 //rename('include/SugarObjects/templates/chance','include/SugarObjects/templates/chance_removeit');
657 * This function copies upgrade wizard files from new patch if that dir exists
659 * @param $file String path to uploaded zip file
661 function upgradeUWFiles($file) {
662 $cacheUploadUpgradesTemp = mk_temp_dir(sugar_cached("upgrades/temp"));
664 unzip($file, $cacheUploadUpgradesTemp);
666 if(!file_exists("$cacheUploadUpgradesTemp/manifest.php")) {
667 logThis("*** ERROR: no manifest file detected while bootstraping upgrade wizard files!");
670 include("$cacheUploadUpgradesTemp/manifest.php");
674 $from_dir = "{$cacheUploadUpgradesTemp}/{$manifest['copy_files']['from_dir']}";
677 if(file_exists("$from_dir/include/Localization/Localization.php")) {
678 $allFiles[] = "$from_dir/include/Localization/Localization.php";
681 if(file_exists("$from_dir/modules/UpgradeWizard")) {
682 $allFiles[] = findAllFiles("$from_dir/modules/UpgradeWizard", $allFiles);
685 if(file_exists("$from_dir/ModuleInstall")) {
686 $allFiles[] = findAllFiles("$from_dir/ModuleInstall", $allFiles);
688 if(file_exists("$from_dir/include/javascript/yui")) {
689 $allFiles[] = findAllFiles("$from_dir/include/javascript/yui", $allFiles);
691 if(file_exists("$from_dir/HandleAjaxCall.php")) {
692 $allFiles[] = "$from_dir/HandleAjaxCall.php";
694 if(file_exists("$from_dir/include/SugarTheme")) {
695 $allFiles[] = findAllFiles("$from_dir/include/SugarTheme", $allFiles);
697 if(file_exists("$from_dir/include/SugarCache")) {
698 $allFiles[] = findAllFiles("$from_dir/include/SugarCache", $allFiles);
700 if(file_exists("$from_dir/include/utils/external_cache.php")) {
701 $allFiles[] = "$from_dir/include/utils/external_cache.php";
703 if(file_exists("$from_dir/include/upload_file.php")) {
704 $allFiles[] = "$from_dir/include/upload_file.php";
706 if(file_exists("$from_dir/include/file_utils.php")) {
707 $allFiles[] = "$from_dir/include/file_utils.php";
709 if(file_exists("$from_dir/include/upload_file.php")) {
710 $allFiles[] = "$from_dir/include/upload_file.php";
712 if(file_exists("$from_dir/include/utils/sugar_file_utils.php")) {
713 $allFiles[] = "$from_dir/include/utils/sugar_file_utils.php";
716 if(file_exists("$from_dir/modules/Users")) {
717 $allFiles[] = findAllFiles("$from_dir/modules/Users", $allFiles);
720 upgradeUWFilesCopy($allFiles, $from_dir);
726 * This function recursively copies files from the upgradeUWFiles Array
727 * @see upgradeUWFiles
729 * @param array $allFiles Array of files to copy over after zip file has been uploaded
730 * @param string $from_dir Source directory
732 function upgradeUWFilesCopy($allFiles, $from_dir)
734 foreach($allFiles as $file)
738 upgradeUWFilesCopy($file, $from_dir);
740 $destFile = str_replace($from_dir."/", "", $file);
741 if(!is_dir(dirname($destFile))) {
742 mkdir_recursive(dirname($destFile)); // make sure the directory exists
745 if(stristr($file,'uw_main.tpl'))
746 logThis('Skipping "'.$file.'" - file copy will during commit step.');
748 logThis('updating UpgradeWizard code: '.$destFile);
749 copy_recursive($file, $destFile);
758 * gets valid patch file names that exist in upload/upgrade/patch/
760 function getValidPatchName($returnFull = true) {
761 global $base_upgrade_dir;
764 global $sugar_version;
765 global $sugar_config;
766 $uh = new UpgradeHistory();
767 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
770 // scan for new files (that are not installed)
771 logThis('finding new files for upgrade');
772 $upgrade_content = '';
773 $upgrade_contents = findAllFiles($base_upgrade_dir, array(), false, 'zip');
774 //other variations of zip file i.e. ZIP, zIp,zIP,Zip,ZIp,ZiP
781 <b>{$mod_strings['LBL_ML_NAME']}</b>
784 <b>{$mod_strings['LBL_ML_TYPE']}</b>
787 <b>{$mod_strings['LBL_ML_VERSION']}</b>
790 <b>{$mod_strings['LBL_ML_PUBLISHED']}</b>
793 <b>{$mod_strings['LBL_ML_UNINSTALLABLE']}</b>
796 <b>{$mod_strings['LBL_ML_DESCRIPTION']}</b>
801 // assume old patches are there.
802 $upgradeToVersion = array(); // fill with valid patches - we will only use the latest qualified found patch
804 // cn: bug 10609 - notices for uninitialized variables
809 $published_date = '';
814 foreach($upgrade_contents as $upgrade_content) {
815 if(!preg_match("#.*\.zip\$#i", $upgrade_content)) {
819 $the_base = basename($upgrade_content);
820 $the_md5 = md5_file($upgrade_content);
822 $md5_matches = $uh->findByMd5($the_md5);
824 /* 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.
825 * Edge-case: manual upgrade with a FTP of a patch; UH table has no entry for it. Assume nothing. :( */
826 if(0 == sizeof($md5_matches)) {
827 $target_manifest = remove_file_extension( $upgrade_content ) . '-manifest.php';
828 require_once($target_manifest);
830 if(empty($manifest['version'])) {
831 logThis("*** Potential error: patch found with no version [ {$upgrade_content} ]");
834 if(!isset($manifest['type']) || $manifest['type'] != 'patch') {
835 logThis("*** Potential error: patch found with either no 'type' or non-patch type [ {$upgrade_content} ]");
839 $upgradeToVersion[$manifest['version']] = urlencode($upgrade_content);
841 $name = empty($manifest['name']) ? $upgrade_content : $manifest['name'];
842 $version = empty($manifest['version']) ? '' : $manifest['version'];
843 $published_date = empty($manifest['published_date']) ? '' : $manifest['published_date'];
845 $description = empty($manifest['description']) ? 'None' : $manifest['description'];
846 $uninstallable = empty($manifest['is_uninstallable']) ? 'No' : 'Yes';
847 $type = getUITextForType( $manifest['type'] );
848 $manifest_type = $manifest['type'];
850 if(empty($manifest['icon'])) {
851 $icon = getImageForType( $manifest['type'] );
853 $path_parts = pathinfo( $manifest['icon'] );
854 $icon = "<!--not_in_theme!--><img src=\"" . remove_file_extension( $upgrade_content ) . "-icon." . $path_parts['extension'] . "\">";
859 // cn: bug 10488 use the NEWEST upgrade/patch available when running upgrade wizard.
860 ksort($upgradeToVersion);
861 $upgradeToVersion = array_values($upgradeToVersion);
862 $newest = array_pop($upgradeToVersion);
863 $_SESSION['install_file'] = urldecode($newest); // in-case it was there from a prior.
864 logThis("*** UW using [ {$_SESSION['install_file']} ] as source for patch files.");
866 $cleanUpgradeContent = urlencode($_SESSION['install_file']);
868 // cn: 10606 - cannot upload a patch file since this returned always.
869 if(!empty($cleanUpgradeContent)) {
870 $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";
873 <form action="index.php" method="post">
874 <input type="hidden" name="module" value="UpgradeWizard">
875 <input type="hidden" name="action" value="index">
876 <input type="hidden" name="step" value="{$_REQUEST['step']}">
877 <input type="hidden" name="run" value="delete">
878 <input type=hidden name="install_file" value="{$cleanUpgradeContent}" />
879 <input type=submit value="{$mod_strings['LBL_BUTTON_DELETE']}" />
883 $disabled = "DISABLED";
888 if(empty($cleanUpgradeContent)){
889 $ready .= "<tr><td colspan='7'><i>None</i></td>\n";
890 $ready .= "</table>\n";
892 $ready .= "<br></ul>\n";
894 $return['ready'] = $ready;
895 $return['disabled'] = $disabled;
904 * finalizes upgrade by setting upgrade versions in DB (config table) and sugar_version.php
905 * @return bool true on success
907 function updateVersions($version) {
909 global $sugar_config;
912 logThis('At updateVersions()... updating config table and sugar_version.php.', $path);
915 if(isset($_SESSION['sugar_version_file']) && !empty($_SESSION['sugar_version_file'])) {
916 if(!copy($_SESSION['sugar_version_file'], clean_path(getcwd().'/sugar_version.php'))) {
917 logThis('*** ERROR: sugar_version.php could not be copied to destination! Cannot complete upgrade', $path);
920 logThis('sugar_version.php successfully updated!', $path);
923 logThis('*** ERROR: no sugar_version.php file location found! - cannot complete upgrade...', $path);
927 $q1 = "DELETE FROM config WHERE category = 'info' AND name = 'sugar_version'";
928 $q2 = "INSERT INTO config (category, name, value) VALUES ('info', 'sugar_version', '{$version}')";
930 logThis('Deleting old DB version info from config table.', $path);
933 logThis('Inserting updated version info into config table.', $path);
936 logThis('updateVersions() complete.', $path);
943 * gets a module's lang pack - does not need to be a SugarModule
944 * @param lang string Language
945 * @param module string Path to language folder
946 * @return array mod_strings
948 function getModuleLanguagePack($lang, $module) {
949 $mod_strings = array();
951 if(!empty($lang) && !empty($module)) {
952 $langPack = clean_path(getcwd().'/'.$module.'/language/'.$lang.'.lang.php');
953 $langPackEn = clean_path(getcwd().'/'.$module.'/language/en_us.lang.php');
955 if (file_exists($langPack))
959 elseif (file_exists($langPackEn))
961 include($langPackEn);
968 * checks system compliance for 4.5+ codebase
969 * @return array Mixed values
971 function checkSystemCompliance() {
972 global $sugar_config;
973 global $current_language;
977 if(!defined('SUGARCRM_MIN_MEM')) {
978 define('SUGARCRM_MIN_MEM', 40);
981 $installer_mod_strings = getModuleLanguagePack($current_language, './install');
983 $ret['error_found'] = false;
986 $php_version = constant('PHP_VERSION');
987 $check_php_version_result = check_php_version($php_version);
989 switch($check_php_version_result) {
991 $ret['phpVersion'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_PHP_INVALID_VER']} {$php_version} )</span></b>";
992 $ret['error_found'] = true;
995 $ret['phpVersion'] = "<b><span class=go>{$installer_mod_strings['ERR_CHECKSYS_PHP_UNSUPPORTED']} {$php_version} )</span></b>";
998 $ret['phpVersion'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_PHP_OK']} {$php_version} )</span></b>";
1002 // database and connect
1003 $canInstall = $db->canInstall();
1004 if ($canInstall !== true)
1006 $ret['error_found'] = true;
1007 if (count($canInstall) == 1)
1009 $ret['dbVersion'] = "<b><span class=stop>" . $installer_mod_strings[$canInstall[0]] . "</span></b>";
1013 $ret['dbVersion'] = "<b><span class=stop>" . sprintf($installer_mod_strings[$canInstall[0]], $canInstall[1]) . "</span></b>";
1018 if(function_exists('xml_parser_create')) {
1019 $ret['xmlStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1021 $ret['xmlStatus'] = "<b><span class=stop>{$installer_mod_strings['LBL_CHECKSYS_NOT_AVAILABLE']}</span></b>";
1022 $ret['error_found'] = true;
1026 if(function_exists('curl_init')) {
1027 $ret['curlStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1029 $ret['curlStatus'] = "<b><span class=go>{$installer_mod_strings['ERR_CHECKSYS_CURL']}</span></b>";
1030 $ret['error_found'] = false;
1034 if(function_exists('mb_strlen')) {
1035 $ret['mbstringStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1037 $ret['mbstringStatus'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_MBSTRING']}</span></b>";
1038 $ret['error_found'] = true;
1042 if(function_exists('imap_open')) {
1043 $ret['imapStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1045 $ret['imapStatus'] = "<b><span class=go>{$installer_mod_strings['ERR_CHECKSYS_IMAP']}</span></b>";
1046 $ret['error_found'] = false;
1051 if('1' == ini_get('safe_mode')) {
1052 $ret['safeModeStatus'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_SAFE_MODE']}</span></b>";
1053 $ret['error_found'] = true;
1055 $ret['safeModeStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1059 // call time pass by ref
1060 if('1' == ini_get('allow_call_time_pass_reference')) {
1061 $ret['callTimeStatus'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_CALL_TIME']}</span></b>";
1062 //continue upgrading
1064 $ret['callTimeStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1068 $ret['memory_msg'] = "";
1069 $memory_limit = "-1";//ini_get('memory_limit');
1070 $sugarMinMem = constant('SUGARCRM_MIN_MEM');
1071 // logic based on: http://us2.php.net/manual/en/ini.core.php#ini.memory-limit
1072 if( $memory_limit == "" ){ // memory_limit disabled at compile time, no memory limit
1073 $ret['memory_msg'] = "<b><span class=\"go\">{$installer_mod_strings['LBL_CHECKSYS_MEM_OK']}</span></b>";
1074 } elseif( $memory_limit == "-1" ){ // memory_limit enabled, but set to unlimited
1075 $ret['memory_msg'] = "<b><span class=\"go\">{$installer_mod_strings['LBL_CHECKSYS_MEM_UNLIMITED']}</span></b>";
1077 rtrim($memory_limit, 'M');
1078 $memory_limit_int = (int) $memory_limit;
1079 if( $memory_limit_int < constant('SUGARCRM_MIN_MEM') ){
1080 $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>";
1081 $ret['error_found'] = true;
1083 $ret['memory_msg'] = "<b><span class=\"go\">{$installer_mod_strings['LBL_CHECKSYS_OK']} ({$memory_limit})</span></b>";
1087 if (!class_exists("ZipArchive"))
1089 $ret['ZipStatus'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_ZIP']}</span></b>";
1090 $ret['error_found'] = true;
1092 $ret['ZipStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1097 /* mbstring.func_overload
1098 $ret['mbstring.func_overload'] = '';
1099 $mb = ini_get('mbstring.func_overload');
1102 $ret['mbstring.func_overload'] = "<b><span class=\"stop\">{$mod_strings['ERR_UW_MBSTRING_FUNC_OVERLOAD']}</b>";
1103 $ret['error_found'] = true;
1111 * is a file that we blow away automagically
1113 function isAutoOverwriteFile($file) {
1114 $overwriteDirs = array(
1115 './sugar_version.php',
1116 './modules/UpgradeWizard/uw_main.tpl',
1118 $file = trim('.'.str_replace(clean_path(getcwd()), '', $file));
1120 if(in_array($file, $overwriteDirs)) {
1124 $fileExtension = substr(strrchr($file, "."), 1);
1125 if($fileExtension == 'tpl' || $fileExtension == 'html') {
1135 function logThis($entry, $path='') {
1136 global $mod_strings;
1137 if(file_exists('include/utils/sugar_file_utils.php')){
1138 require_once('include/utils/sugar_file_utils.php');
1140 $log = empty($path) ? clean_path(getcwd().'/upgradeWizard.log') : clean_path($path);
1142 // create if not exists
1143 if(!file_exists($log)) {
1144 if(function_exists('sugar_fopen')){
1145 $fp = @sugar_fopen($log, 'w+'); // attempts to create file
1148 $fp = fopen($log, 'w+'); // attempts to create file
1150 if(!is_resource($fp)) {
1151 $GLOBALS['log']->fatal('UpgradeWizard could not create the upgradeWizard.log file');
1152 die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
1155 if(function_exists('sugar_fopen')){
1156 $fp = @sugar_fopen($log, 'a+'); // write pointer at end of file
1159 $fp = @fopen($log, 'a+'); // write pointer at end of file
1162 if(!is_resource($fp)) {
1163 $GLOBALS['log']->fatal('UpgradeWizard could not open/lock upgradeWizard.log file');
1164 die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
1168 $line = date('r').' [UpgradeWizard] - '.$entry."\n";
1170 if(@fwrite($fp, $line) === false) {
1171 $GLOBALS['log']->fatal('UpgradeWizard could not write to upgradeWizard.log: '.$entry);
1172 die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
1175 if(is_resource($fp)) {
1183 * @desc This function is to be used in the upgrade process to preserve changes/customaizations made to pre 5.1 quickcreate layout.
1184 * 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
1185 * was automatically picked up by the quick create. [Addresses Bug 21469]
1186 * This function will check if customizations were made, and will create quickcreatedefs.php in the /cutom/working/$module_name directory.
1188 function updateQuickCreateDefs(){
1189 $d = dir('modules');
1190 $studio_modules = array();
1192 while($e = $d->read()){ //collect all studio modules.
1193 if(substr($e, 0, 1) == '.' || !is_dir('modules/' . $e))continue;
1194 if(file_exists('modules/' . $e . '/metadata/studio.php'))
1196 array_push($studio_modules, $e);
1200 foreach( $studio_modules as $modname ){ //for each studio enabled module
1201 //Check !exists modules/$modname/metadata/quickcreatedefs.php &&
1202 //exists custom/$modname/editviewdefs.php (module was customized) &&
1203 //!exists custom/$modname/quickcreateviewdefs.php
1205 $editviewdefs = "custom/working/modules/".$modname."/metadata/editviewdefs.php";
1206 $quickcreatedefs = "custom/working/modules/".$modname."/metadata/quickcreatedefs.php";
1208 if ( !file_exists("modules/".$modname."/metadata/quickcreatedefs.php") &&
1209 file_exists($editviewdefs) &&
1210 !file_exists($quickcreatedefs) ){
1211 //clone editviewdef and save it in custom/working/modules/metadata
1212 $GLOBALS['log']->debug("Copying editviewdefs.php as quickcreatedefs.php for the $modname module in custom/working/modules/$modname/metadata!");
1213 if(copy( $editviewdefs, $quickcreatedefs)){
1214 if(file_exists($quickcreatedefs) && is_readable($quickcreatedefs)){
1215 $file = file($quickcreatedefs);
1216 //replace 'EditView' with 'QuickCreate'
1217 $fp = fopen($quickcreatedefs,'w');
1218 foreach($file as &$line){
1219 if(preg_match('/^\s*\'EditView\'\s*=>\s*$/', $line) > 0){
1220 $line = "'QuickCreate' =>\n";
1228 $GLOBALS['log']->debug("Failed to replace 'EditView' with QuickCreate because $quickcreatedefs is either not readable or does not exist.");
1231 $GLOBALS['log']->debug("Failed to copy $editviewdefs to $quickcreatedefs!");
1238 * test perms for CREATE queries
1240 function testPermsCreate($db, $out) {
1241 logThis('Checking CREATE TABLE permissions...');
1242 global $mod_strings;
1244 if(!$db->checkPrivilege("CREATE TABLE")) {
1245 logThis('cannot CREATE TABLE!');
1246 $out['db']['dbNoCreate'] = true;
1247 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_CREATE']}</span></td></tr>";
1253 * test perms for INSERT
1255 function testPermsInsert($db, $out, $skip=false) {
1256 logThis('Checking INSERT INTO permissions...');
1257 global $mod_strings;
1259 if(!$db->checkPrivilege("INSERT")) {
1260 logThis('cannot INSERT INTO!');
1261 $out['db']['dbNoInsert'] = true;
1262 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_INSERT']}</span></td></tr>";
1269 * test perms for UPDATE TABLE
1271 function testPermsUpdate($db, $out, $skip=false) {
1272 logThis('Checking UPDATE TABLE permissions...');
1273 global $mod_strings;
1274 if(!$db->checkPrivilege("UPDATE")) {
1275 logThis('cannot UPDATE TABLE!');
1276 $out['db']['dbNoUpdate'] = true;
1277 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_UPDATE']}</span></td></tr>";
1284 * test perms for SELECT
1286 function testPermsSelect($db, $out, $skip=false) {
1287 logThis('Checking SELECT permissions...');
1288 global $mod_strings;
1289 if(!$db->checkPrivilege("SELECT")) {
1290 logThis('cannot SELECT!');
1291 $out['db']['dbNoSelect'] = true;
1292 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_SELECT']}</span></td></tr>";
1298 * test perms for DELETE
1300 function testPermsDelete($db, $out, $skip=false) {
1301 logThis('Checking DELETE FROM permissions...');
1302 global $mod_strings;
1303 if(!$db->checkPrivilege("DELETE")) {
1304 logThis('cannot DELETE FROM!');
1305 $out['db']['dbNoDelete'] = true;
1306 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_DELETE']}</span></td></tr>";
1313 * test perms for ALTER TABLE ADD COLUMN
1315 function testPermsAlterTableAdd($db, $out, $skip=false) {
1316 logThis('Checking ALTER TABLE ADD COLUMN permissions...');
1317 global $mod_strings;
1318 if(!$db->checkPrivilege("ADD COLUMN")) {
1319 logThis('cannot ADD COLUMN!');
1320 $out['db']['dbNoAddColumn'] = true;
1321 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_ADD_COLUMN']}</span></td></tr>";
1327 * test perms for ALTER TABLE ADD COLUMN
1329 function testPermsAlterTableChange($db, $out, $skip=false) {
1330 logThis('Checking ALTER TABLE CHANGE COLUMN permissions...');
1331 global $mod_strings;
1332 if(!$db->checkPrivilege("CHANGE COLUMN")) {
1333 logThis('cannot CHANGE COLUMN!');
1334 $out['db']['dbNoChangeColumn'] = true;
1335 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_CHANGE_COLUMN']}</span></td></tr>";
1341 * test perms for ALTER TABLE DROP COLUMN
1343 function testPermsAlterTableDrop($db, $out, $skip=false) {
1344 logThis('Checking ALTER TABLE DROP COLUMN permissions...');
1345 global $mod_strings;
1346 if(!$db->checkPrivilege("DROP COLUMN")) {
1347 logThis('cannot DROP COLUMN!');
1348 $out['db']['dbNoDropColumn'] = true;
1349 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_DROP_COLUMN']}</span></td></tr>";
1356 * test perms for DROP TABLE
1358 function testPermsDropTable($db, $out, $skip=false) {
1359 logThis('Checking DROP TABLE permissions...');
1360 global $mod_strings;
1361 if(!$db->checkPrivilege("DROP TABLE")) {
1362 logThis('cannot DROP TABLE!');
1363 $out['db']['dbNoDropTable'] = true;
1364 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_DROP_TABLE']}</span></td></tr>";
1369 function getFormattedError($error, $query) {
1370 $error = "<div><b>".$error;
1371 $error .= "</b>::{$query}</div>";
1377 * parses a query finding the table name
1378 * @param string query The query
1379 * @return string table The table
1381 function getTableFromQuery($query) {
1382 $standardQueries = array('ALTER TABLE', 'DROP TABLE', 'CREATE TABLE', 'INSERT INTO', 'UPDATE', 'DELETE FROM');
1383 $query = preg_replace("/[^A-Za-z0-9\_\s]/", "", $query);
1384 $query = trim(str_replace($standardQueries, '', $query));
1386 $firstSpc = strpos($query, " ");
1387 $end = ($firstSpc > 0) ? $firstSpc : strlen($query);
1388 $table = substr($query, 0, $end);
1395 function preLicenseCheck() {
1396 require_once('modules/UpgradeWizard/uw_files.php');
1398 global $sugar_config;
1399 global $mod_strings;
1400 global $sugar_version;
1402 if(!isset($sugar_version) || empty($sugar_version)) {
1403 require_once('./sugar_version.php');
1406 if(!isset($_SESSION['unzip_dir']) || empty($_SESSION['unzip_dir'])) {
1407 logThis('unzipping files in upgrade archive...');
1409 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
1411 //also come up with mechanism to read from upgrade-progress file
1412 if(!isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !is_file($_SESSION['install_file'])) {
1413 if (file_exists(clean_path($base_tmp_upgrade_dir)) && $handle = opendir(clean_path($base_tmp_upgrade_dir))) {
1414 while (false !== ($file = readdir($handle))) {
1415 if($file !="." && $file !="..") {
1416 if(is_file($base_tmp_upgrade_dir."/".$file."/manifest.php")){
1417 require_once($base_tmp_upgrade_dir."/".$file."/manifest.php");
1418 $package_name= $manifest['copy_files']['from_dir'];
1419 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")){
1420 $unzip_dir = $base_tmp_upgrade_dir."/".$file;
1421 if(file_exists("$base_upgrade_dir/patch/".$package_name.'.zip')){
1422 $_SESSION['install_file'] = $package_name.".zip";
1431 if(empty($_SESSION['install_file'])){
1432 unlinkUWTempFiles();
1434 echo 'Upload File not found so redirecting to Upgrade Start ';
1435 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1436 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1437 $upgrade_directories_not_found =<<<eoq
1438 <table cellpadding="3" cellspacing="0" border="0">
1440 <th colspan="2" align="left">
1441 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1446 $uwMain = $upgrade_directories_not_found;
1449 $install_file = "$base_upgrade_dir/patch/".basename(urldecode( $_SESSION['install_file'] ));
1451 if(empty($unzip_dir)){
1452 $unzip_dir = mk_temp_dir( $base_tmp_upgrade_dir );
1454 $zip_from_dir = ".";
1456 $zip_force_copy = array();
1459 logThis('Could not create a temporary directory using mk_temp_dir( $base_tmp_upgrade_dir )');
1460 die($mod_strings['ERR_UW_NO_CREATE_TMP_DIR']);
1463 //double check whether unzipped .
1464 if(file_exists($unzip_dir ."/scripts") && file_exists($unzip_dir."/manifest.php")){
1468 unzip( $install_file, $unzip_dir );
1471 // assumption -- already validated manifest.php at time of upload
1472 require_once( "$unzip_dir/manifest.php" );
1474 if( isset( $manifest['copy_files']['from_dir'] ) && $manifest['copy_files']['from_dir'] != "" ){
1475 $zip_from_dir = $manifest['copy_files']['from_dir'];
1477 if( isset( $manifest['copy_files']['to_dir'] ) && $manifest['copy_files']['to_dir'] != "" ){
1478 $zip_to_dir = $manifest['copy_files']['to_dir'];
1480 if( isset( $manifest['copy_files']['force_copy'] ) && $manifest['copy_files']['force_copy'] != "" ){
1481 $zip_force_copy = $manifest['copy_files']['force_copy'];
1483 if( isset( $manifest['version'] ) ){
1484 $version = $manifest['version'];
1486 if( !is_writable( "config.php" ) ){
1487 return $mod_strings['ERR_UW_CONFIG'];
1490 $_SESSION['unzip_dir'] = clean_path($unzip_dir);
1491 $_SESSION['zip_from_dir'] = clean_path($zip_from_dir);
1492 logThis('unzip done.');
1494 $unzip_dir = $_SESSION['unzip_dir'];
1495 $zip_from_dir = $_SESSION['zip_from_dir'];
1498 //check if $_SESSION['unzip_dir'] and $_SESSION['zip_from_dir'] exist
1499 if(!isset($_SESSION['unzip_dir']) || !file_exists($_SESSION['unzip_dir'])
1500 || !isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !file_exists($_SESSION['install_file'])){
1502 unlinkUWTempFiles();
1504 echo 'Upload File not found so redirecting to Upgrade Start ';
1505 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1506 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1507 $upgrade_directories_not_found =<<<eoq
1508 <table cellpadding="3" cellspacing="0" border="0">
1510 <th colspan="2" align="left">
1511 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1516 $uwMain = $upgrade_directories_not_found;
1520 logThis ('is SugarConfig there '.file_exists(clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarObjects/SugarConfig.php")));
1521 if(file_exists(clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarObjects/SugarConfig.php"))) {
1522 $file = clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarObjects/SugarConfig.php");
1523 $destFile = str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), $cwd, $file);
1524 if(!is_dir(dirname($destFile))) {
1525 mkdir_recursive(dirname($destFile)); // make sure the directory exists
1527 copy($file,$destFile);
1528 //also copy include utils array utils
1529 $file = clean_path($unzip_dir.'/'.$zip_from_dir."/include/utils/array_utils.php");
1530 $destFile = str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), $cwd, $file);
1531 if(!is_dir(dirname($destFile))) {
1532 mkdir_recursive(dirname($destFile)); // make sure the directory exists
1534 copy($file,$destFile);
1539 function preflightCheck() {
1540 require_once('modules/UpgradeWizard/uw_files.php');
1542 global $sugar_config;
1543 global $mod_strings;
1544 global $sugar_version;
1546 if(!isset($sugar_version) || empty($sugar_version)) {
1547 require_once('./sugar_version.php');
1550 unset($_SESSION['rebuild_relationships']);
1551 unset($_SESSION['rebuild_extensions']);
1553 // don't bother if are rechecking
1554 $manualDiff = array();
1555 if(!isset($_SESSION['unzip_dir']) || empty($_SESSION['unzip_dir'])) {
1556 logThis('unzipping files in upgrade archive...');
1558 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
1560 //Following is if User logged out unexpectedly and then logged into UpgradeWizard again.
1561 //also come up with mechanism to read from upgrade-progress file.
1562 if(!isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !is_file($_SESSION['install_file'])) {
1563 if (file_exists($base_tmp_upgrade_dir) && $handle = opendir($base_tmp_upgrade_dir)) {
1564 while (false !== ($file = readdir($handle))) {
1565 if($file !="." && $file !="..") {
1566 if(is_file($base_tmp_upgrade_dir."/".$file."/manifest.php")){
1567 require_once($base_tmp_upgrade_dir."/".$file."/manifest.php");
1568 $package_name= $manifest['copy_files']['from_dir'];
1569 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")){
1570 $unzip_dir = $base_tmp_upgrade_dir."/".$file;
1571 if(file_exists("$base_upgrade_dir/patch/".$package_name.'.zip')){
1572 $_SESSION['install_file'] = $package_name.".zip";
1581 if(empty($_SESSION['install_file'])){
1582 unlinkUWTempFiles();
1584 echo 'Upload File not found so redirecting to Upgrade Start ';
1585 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1586 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1587 $upgrade_directories_not_found =<<<eoq
1588 <table cellpadding="3" cellspacing="0" border="0">
1590 <th colspan="2" align="left">
1591 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1596 $uwMain = $upgrade_directories_not_found;
1600 $install_file = "$base_upgrade_dir/patch/".basename(urldecode( $_SESSION['install_file'] ));
1602 if(empty($unzip_dir)){
1603 $unzip_dir = mk_temp_dir( $base_tmp_upgrade_dir );
1605 $zip_from_dir = ".";
1607 $zip_force_copy = array();
1610 logThis('Could not create a temporary directory using mk_temp_dir( $base_tmp_upgrade_dir )');
1611 die($mod_strings['ERR_UW_NO_CREATE_TMP_DIR']);
1614 //double check whether unzipped .
1615 if(file_exists($unzip_dir ."/scripts") && file_exists($unzip_dir."/manifest.php")){
1619 unzip( $install_file, $unzip_dir );
1622 // assumption -- already validated manifest.php at time of upload
1623 require_once( "$unzip_dir/manifest.php" );
1625 if( isset( $manifest['copy_files']['from_dir'] ) && $manifest['copy_files']['from_dir'] != "" ){
1626 $zip_from_dir = $manifest['copy_files']['from_dir'];
1628 if( isset( $manifest['copy_files']['to_dir'] ) && $manifest['copy_files']['to_dir'] != "" ){
1629 $zip_to_dir = $manifest['copy_files']['to_dir'];
1631 if( isset( $manifest['copy_files']['force_copy'] ) && $manifest['copy_files']['force_copy'] != "" ){
1632 $zip_force_copy = $manifest['copy_files']['force_copy'];
1634 if( isset( $manifest['version'] ) ){
1635 $version = $manifest['version'];
1637 if( !is_writable( "config.php" ) ){
1638 return $mod_strings['ERR_UW_CONFIG'];
1641 $_SESSION['unzip_dir'] = clean_path($unzip_dir);
1642 $_SESSION['zip_from_dir'] = clean_path($zip_from_dir);
1644 //logThis('unzip done.');
1646 $unzip_dir = $_SESSION['unzip_dir'];
1647 $zip_from_dir = $_SESSION['zip_from_dir'];
1649 //check if $_SESSION['unzip_dir'] and $_SESSION['zip_from_dir'] exist
1650 if(!isset($_SESSION['unzip_dir']) || !file_exists($_SESSION['unzip_dir'])
1651 || !isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !file_exists($_SESSION['install_file'])){
1653 unlinkUWTempFiles();
1655 echo 'Upload File not found so redirecting to Upgrade Start ';
1656 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1657 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1658 $upgrade_directories_not_found =<<<eoq
1659 <table cellpadding="3" cellspacing="0" border="0">
1661 <th colspan="2" align="left">
1662 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1667 $uwMain = $upgrade_directories_not_found;
1670 //copy minimum required files
1671 fileCopy('include/utils/sugar_file_utils.php');
1673 $upgradeFiles = findAllFiles(clean_path("$unzip_dir/$zip_from_dir"), array());
1674 $cache_html_files= array();
1677 $md5_string = array();
1678 if(file_exists(clean_path(getcwd().'/files.md5'))){
1679 require(clean_path(getcwd().'/files.md5'));
1682 // file preflight checks
1683 logThis('verifying md5 checksums for files...');
1684 foreach($upgradeFiles as $file) {
1685 if(in_array(str_replace(clean_path("$unzip_dir/$zip_from_dir") . "/", '', $file), $uw_files))
1686 continue; // skip already loaded files
1688 if(strpos($file, '.md5'))
1689 continue; // skip md5 file
1691 // normalize file paths
1692 $file = clean_path($file);
1694 // check that we can move/delete the upgraded file
1695 if(!is_writable($file)) {
1696 $errors[] = $mod_strings['ERR_UW_FILE_NOT_WRITABLE'].": ".$file;
1698 // check that destination files are writable
1699 $destFile = getcwd().str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), '', $file);
1701 if(is_file($destFile)) { // of course it needs to exist first...
1702 if(!is_writable($destFile)) {
1703 $errors[] = $mod_strings['ERR_UW_FILE_NOT_WRITABLE'].": ".$destFile;
1707 ///////////////////////////////////////////////////////////////////////
1709 // compare md5s and build up a manual merge list
1710 $targetFile = clean_path(".".str_replace(getcwd(),'',$destFile));
1712 if(is_file($destFile)) {
1713 if(strpos($targetFile, '.php')) {
1714 // handle PHP files that were hit with the security regex
1716 if(function_exists('sugar_fopen')){
1717 $fp = sugar_fopen($destFile, 'r');
1720 $fp = fopen($destFile, 'r');
1722 $filesize = filesize($destFile);
1724 $fileContents = stream_get_contents($fp);
1725 $targetMd5 = md5($fileContents);
1728 $targetMd5 = md5_file($destFile);
1732 if(isset($md5_string[$targetFile]) && $md5_string[$targetFile] != $targetMd5) {
1733 logThis('found a file with a differing md5: ['.$targetFile.']');
1734 $manualDiff[] = $destFile;
1737 ///////////////////////////////////////////////////////////////////////
1739 logThis('md5 verification done.');
1740 $errors['manual'] = $manualDiff;
1745 function fileCopy($file_path){
1746 if(file_exists(clean_path($_SESSION['unzip_dir'].'/'.$_SESSION['zip_from_dir'].'/'.$file_path))) {
1747 $file = clean_path($_SESSION['unzip_dir'].'/'.$_SESSION['zip_from_dir'].'/'.$file_path);
1748 $destFile = str_replace(clean_path($_SESSION['unzip_dir'].'/'.$_SESSION['zip_from_dir']), clean_path(getcwd()), $file);
1749 if(!is_dir(dirname($destFile))) {
1750 mkdir_recursive(dirname($destFile)); // make sure the directory exists
1752 copy_recursive($file,$destFile);
1755 function getChecklist($steps, $step) {
1756 global $mod_strings;
1758 $skip = array('start', 'cancel', 'uninstall','end');
1761 $ret = '<table cellpadding="3" cellspacing="4" border="0">';
1762 $ret .= '<tr><th colspan="3" align="left">'.$mod_strings['LBL_UW_CHECKLIST'].':</th></tr>';
1763 foreach($steps['desc'] as $k => $desc) {
1764 if(in_array($steps['files'][$j], $skip)) {
1769 //$status = "<span class='error'>{$mod_strings['LBL_UW_INCOMPLETE']}</span>";
1771 $desc_mod_post = '';
1773 if(isset($_SESSION['step'][$steps['files'][$k]]) && $_SESSION['step'][$steps['files'][$k]] == 'success') {
1774 //$status = $mod_strings['LBL_UW_COMPLETE'];
1778 if($k == $_REQUEST['step']) {
1779 //$status = $mod_strings['LBL_UW_IN_PROGRESS'];
1780 $desc_mod_pre = "<font color=blue><i>";
1781 $desc_mod_post = "</i></font>";
1784 $ret .= "<tr><td> </td><td><b>{$i}: {$desc_mod_pre}{$desc}{$desc_mod_post}</b></td>";
1785 $ret .= "<td id={$steps['files'][$j]}><i></i></td></tr>";
1793 function prepSystemForUpgrade() {
1794 global $sugar_config;
1795 global $sugar_flavor;
1796 global $mod_strings;
1797 global $current_language;
1799 global $base_upgrade_dir;
1800 global $base_tmp_upgrade_dir;
1801 list($p_base_upgrade_dir, $p_base_tmp_upgrade_dir) = getUWDirs();
1802 ///////////////////////////////////////////////////////////////////////////////
1803 //// Make sure variables exist
1804 if(empty($base_upgrade_dir)){
1805 $base_upgrade_dir = $p_base_upgrade_dir;
1807 if(empty($base_tmp_upgrade_dir)){
1808 $base_tmp_upgrade_dir = $p_base_tmp_upgrade_dir;
1810 sugar_mkdir($base_tmp_upgrade_dir, 0775, true);
1811 if(!isset($subdirs) || empty($subdirs)){
1812 $subdirs = array('full', 'langpack', 'module', 'patch', 'theme');
1815 $upgrade_progress_dir = $base_tmp_upgrade_dir;
1816 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
1817 if(file_exists($upgrade_progress_file)){
1818 if(function_exists('get_upgrade_progress') && function_exists('didThisStepRunBefore')){
1819 if(didThisStepRunBefore('end')){
1820 include($upgrade_progress_file);
1821 unset($upgrade_config);
1822 unlink($upgrade_progress_file);
1827 // increase the cuttoff time to 1 hour
1828 ini_set("max_execution_time", "3600");
1830 // make sure dirs exist
1831 if($subdirs != null){
1832 foreach($subdirs as $subdir) {
1833 sugar_mkdir("$base_upgrade_dir/$subdir", 0775, true);
1836 // array of special scripts that are executed during (un)installation-- key is type of script, value is filename
1837 if(!defined('SUGARCRM_PRE_INSTALL_FILE')) {
1838 define('SUGARCRM_PRE_INSTALL_FILE', 'scripts/pre_install.php');
1839 define('SUGARCRM_POST_INSTALL_FILE', 'scripts/post_install.php');
1840 define('SUGARCRM_PRE_UNINSTALL_FILE', 'scripts/pre_uninstall.php');
1841 define('SUGARCRM_POST_UNINSTALL_FILE', 'scripts/post_uninstall.php');
1844 $script_files = array(
1845 "pre-install" => constant('SUGARCRM_PRE_INSTALL_FILE'),
1846 "post-install" => constant('SUGARCRM_POST_INSTALL_FILE'),
1847 "pre-uninstall" => constant('SUGARCRM_PRE_UNINSTALL_FILE'),
1848 "post-uninstall" => constant('SUGARCRM_POST_UNINSTALL_FILE'),
1851 // check that the upload limit is set to 6M or greater
1852 define('SUGARCRM_MIN_UPLOAD_MAX_FILESIZE_BYTES', 6 * 1024 * 1024); // 6 Megabytes
1853 $upload_max_filesize = ini_get('upload_max_filesize');
1854 $upload_max_filesize_bytes = return_bytes($upload_max_filesize);
1856 if($upload_max_filesize_bytes < constant('SUGARCRM_MIN_UPLOAD_MAX_FILESIZE_BYTES')) {
1857 $GLOBALS['log']->debug("detected upload_max_filesize: $upload_max_filesize");
1858 $admin_strings = return_module_language($current_language, 'Administration');
1859 echo '<p class="error">'.$admin_strings['MSG_INCREASE_UPLOAD_MAX_FILESIZE'].' '.get_cfg_var('cfg_file_path')."</p>\n";
1863 if ( !function_exists('extractFile') ) {
1864 function extractFile($zip_file, $file_in_zip) {
1865 global $base_tmp_upgrade_dir;
1868 $absolute_base_tmp_upgrade_dir = clean_path($base_tmp_upgrade_dir);
1869 $relative_base_tmp_upgrade_dir = clean_path(str_replace(clean_path(getcwd()), '', $absolute_base_tmp_upgrade_dir));
1871 // mk_temp_dir expects relative pathing
1872 $my_zip_dir = mk_temp_dir($relative_base_tmp_upgrade_dir);
1874 unzip_file($zip_file, $file_in_zip, $my_zip_dir);
1876 return("$my_zip_dir/$file_in_zip");
1880 if ( !function_exists('extractManifest') ) {
1881 function extractManifest($zip_file) {
1882 logThis('extracting manifest.');
1883 return(extractFile($zip_file, "manifest.php"));
1887 if ( !function_exists('getInstallType') ) {
1888 function getInstallType($type_string) {
1891 $subdirs = array('full', 'langpack', 'module', 'patch', 'theme', 'temp');
1892 foreach($subdirs as $subdir) {
1893 if(preg_match("#/$subdir/#", $type_string)) {
1897 // return empty if no match
1902 function getImageForType($type) {
1904 global $mod_strings;
1909 $icon = SugarThemeRegistry::current()->getImage("Upgrade", "",null,null,'.gif',$mod_strings['LBL_UPGRADE']);
1912 $icon = SugarThemeRegistry::current()->getImage("LanguagePacks", "",null,null,'.gif',$mod_strings['LBL_LANGPACKS']);
1915 $icon = SugarThemeRegistry::current()->getImage("ModuleLoader", "",null,null,'.gif',$mod_strings['LBL_MODULELOADER']);
1918 $icon = SugarThemeRegistry::current()->getImage("PatchUpgrades", "",null,null,'.gif',$mod_strings['LBL_PATCHUPGRADES']);
1921 $icon = SugarThemeRegistry::current()->getImage("Themes", "",null,null,'.gif',$mod_strings['LBL_THEMES']);
1929 if ( !function_exists('getLanguagePackName') ) {
1930 function getLanguagePackName($the_file) {
1931 require_once("$the_file");
1932 if(isset($app_list_strings["language_pack_name"])) {
1933 return($app_list_strings["language_pack_name"]);
1939 function getUITextForType($type) {
1940 if($type == "full") {
1941 return("Full Upgrade");
1943 if($type == "langpack") {
1944 return("Language Pack");
1946 if($type == "module") {
1949 if($type == "patch") {
1952 if($type == "theme") {
1957 if ( !function_exists('validate_manifest') ) {
1959 * Verifies a manifest from a patch or module to be compatible with the current Sugar version and flavor
1960 * @param array manifest Standard manifest array
1961 * @return string Error message, blank on success
1963 function validate_manifest($manifest) {
1964 logThis('validating manifest.php file');
1965 // takes a manifest.php manifest array and validates contents
1967 global $sugar_version;
1968 global $sugar_flavor;
1969 global $mod_strings;
1971 if(!isset($manifest['type'])) {
1972 return $mod_strings['ERROR_MANIFEST_TYPE'];
1975 $type = $manifest['type'];
1977 if(getInstallType("/$type/") == "") {
1978 return $mod_strings['ERROR_PACKAGE_TYPE']. ": '" . $type . "'.";
1981 if(isset($manifest['acceptable_sugar_versions'])) {
1982 $version_ok = false;
1983 $matches_empty = true;
1984 if(isset($manifest['acceptable_sugar_versions']['exact_matches'])) {
1985 $matches_empty = false;
1986 foreach($manifest['acceptable_sugar_versions']['exact_matches'] as $match) {
1987 if($match == $sugar_version) {
1992 if(!$version_ok && isset($manifest['acceptable_sugar_versions']['regex_matches'])) {
1993 $matches_empty = false;
1994 foreach($manifest['acceptable_sugar_versions']['regex_matches'] as $match) {
1995 if(preg_match("/$match/", $sugar_version)) {
2001 if(!$matches_empty && !$version_ok) {
2002 return $mod_strings['ERROR_VERSION_INCOMPATIBLE']."<br />".
2003 $mod_strings['ERR_UW_VERSION'].$sugar_version;
2007 if(isset($manifest['acceptable_sugar_flavors']) && sizeof($manifest['acceptable_sugar_flavors']) > 0) {
2009 foreach($manifest['acceptable_sugar_flavors'] as $match) {
2010 if($match == $sugar_flavor) {
2015 return $mod_strings['ERROR_FLAVOR_INCOMPATIBLE']."<br />".
2016 $mod_strings['ERR_UW_FLAVOR'].$sugar_flavor."<br />".
2017 $mod_strings['ERR_UW_FLAVOR_2'].$manifest['acceptable_sugar_flavors'][0];
2025 function unlinkUploadFiles() {
2027 // logThis('at unlinkUploadFiles()');
2029 // if(isset($_SESSION['install_file']) && !empty($_SESSION['install_file'])) {
2030 // $upload = $_SESSION['install_file'];
2032 // if(is_file($upload)) {
2033 // logThis('unlinking ['.$upload.']');
2034 // @unlink($upload);
2040 * deletes files created by unzipping a package
2042 function unlinkUWTempFiles() {
2043 global $sugar_config;
2046 logThis('at unlinkUWTempFiles()');
2048 list($upgDir, $tempDir) = getUWDirs();
2050 if(file_exists($tempDir) && is_dir($tempDir)){
2051 $files = findAllFiles($tempDir, array(), false);
2053 foreach($files as $file) {
2054 if(!is_dir($file)) {
2055 //logThis('unlinking ['.$file.']', $path);
2060 $files = findAllFiles($tempDir, array(), true);
2061 foreach($files as $dir) {
2063 //logThis('removing dir ['.$dir.']', $path);
2067 $cacheFile = sugar_cached("modules/UpgradeWizard/_persistence.php");
2068 if(is_file($cacheFile)) {
2069 logThis("Unlinking Upgrade cache file: '_persistence.php'", $path);
2070 @unlink($cacheFile);
2073 logThis("finished!");
2077 * finds all files in the passed path, but skips select directories
2078 * @param string dir Relative path
2079 * @param array the_array Collections of found files/dirs
2080 * @param bool include_dir True if we want to include directories in the
2081 * returned collection
2083 function uwFindAllFiles($dir, $theArray, $includeDirs=false, $skipDirs=array(), $echo=false) {
2085 if (whetherNeedToSkipDir($dir, $skipDirs))
2090 if (!is_dir($dir)) { return $theArray; } // Bug # 46035, just checking for valid dir
2092 if ($d === false) { return $theArray; } // Bug # 46035, more checking
2094 while($f = $d->read()) {
2095 // bug 40793 Skip Directories array in upgradeWizard does not function correctly
2096 if($f == "." || $f == ".." || whetherNeedToSkipDir("$dir/$f", $skipDirs)) { // skip *nix self/parent
2100 // for AJAX length count
2106 if(is_dir("$dir/$f")) {
2107 if($includeDirs) { // add the directory if flagged
2108 $theArray[] = clean_path("$dir/$f");
2112 $theArray = uwFindAllFiles("$dir/$f/", $theArray, $includeDirs, $skipDirs, $echo);
2114 $theArray[] = clean_path("$dir/$f");
2127 * unset's UW's Session Vars
2129 function resetUwSession() {
2130 logThis('resetting $_SESSION');
2132 if(isset($_SESSION['committed']))
2133 unset($_SESSION['committed']);
2134 if(isset($_SESSION['sugar_version_file']))
2135 unset($_SESSION['sugar_version_file']);
2136 if(isset($_SESSION['upgrade_complete']))
2137 unset($_SESSION['upgrade_complete']);
2138 if(isset($_SESSION['allTables']))
2139 unset($_SESSION['allTables']);
2140 if(isset($_SESSION['alterCustomTableQueries']))
2141 unset($_SESSION['alterCustomTableQueries']);
2142 if(isset($_SESSION['skip_zip_upload']))
2143 unset($_SESSION['skip_zip_upload']);
2144 if(isset($_SESSION['sugar_version_file']))
2145 unset($_SESSION['sugar_version_file']);
2146 if(isset($_SESSION['install_file']))
2147 unset($_SESSION['install_file']);
2148 if(isset($_SESSION['unzip_dir']))
2149 unset($_SESSION['unzip_dir']);
2150 if(isset($_SESSION['zip_from_dir']))
2151 unset($_SESSION['zip_from_dir']);
2152 if(isset($_SESSION['overwrite_files']))
2153 unset($_SESSION['overwrite_files']);
2154 if(isset($_SESSION['schema_change']))
2155 unset($_SESSION['schema_change']);
2156 if(isset($_SESSION['uw_restore_dir']))
2157 unset($_SESSION['uw_restore_dir']);
2158 if(isset($_SESSION['step']))
2159 unset($_SESSION['step']);
2160 if(isset($_SESSION['files']))
2161 unset($_SESSION['files']);
2162 if(isset($_SESSION['Upgraded451Wizard'])){
2163 unset($_SESSION['Upgraded451Wizard']);
2165 if(isset($_SESSION['Initial_451to500_Step'])){
2166 unset($_SESSION['Initial_451to500_Step']);
2168 if(isset($_SESSION['license_shown']))
2169 unset($_SESSION['license_shown']);
2170 if(isset($_SESSION['sugarMergeRunResults']))
2171 unset($_SESSION['sugarMergeRunResults']);
2175 * runs rebuild scripts
2177 function UWrebuild() {
2181 //CCL - Comment this block out, it is called in end.php
2182 logThis('Rebuilding everything...', $path);
2183 require_once('modules/Administration/QuickRepairAndRebuild.php');
2184 $randc = new RepairAndClear();
2185 $randc->repairAndClearAll(array('clearAll'),array(translate('LBL_ALL_MODULES')), false, false);
2187 $query = "DELETE FROM versions WHERE name='Rebuild Extensions'";
2189 logThis('Registering rebuild record: '.$query, $path);
2190 logThis('Rebuild done.', $path);
2192 // insert a new database row to show the rebuild extensions is done
2193 $id = create_guid();
2194 $gmdate = gmdate('Y-m-d H:i:s');
2195 $date_entered = db_convert("'$gmdate'", 'datetime');
2196 $query = 'INSERT INTO versions (id, deleted, date_entered, date_modified, modified_user_id, created_by, name, file_version, db_version) '
2197 . "VALUES ('$id', '0', $date_entered, $date_entered, '1', '1', 'Rebuild Extensions', '4.0.0', '4.0.0')";
2199 logThis('Registering rebuild record in versions table: '.$query, $path);
2202 function getCustomTables() {
2205 return $db->tablesLike('%_cstm');
2208 function alterCustomTables($customTables)
2213 function getAllTables() {
2215 return $db->getTablesArray();
2218 function printAlterTableSql($tables)
2220 $alterTableSql = '';
2222 foreach($tables as $table)
2223 $alterTableSql .= "ALTER TABLE " . $table . " CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;" . "\n";
2225 return $alterTableSql;
2228 function executeConvertTablesSql($tables)
2232 foreach($tables as $table){
2233 $query = "ALTER TABLE " . $table . " CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci";
2235 logThis("Sending query: ".$query);
2236 $db->query($query);//, true, "An error has occured while performing db query. See log file for details.<br>");
2242 function testThis() {
2243 $files = uwFindAllFiles(getcwd().'/test', array());
2245 $out = "<table cellpadding='1' cellspacing='0' border='0'>\n";
2248 foreach($files as $file) {
2249 $relativeFile = clean_path(str_replace(getcwd().'/test', '', $file));
2250 $relativeFile = ($relativeFile{0} == '/') ? substr($relativeFile, 1, strlen($relativeFile)) : $relativeFile;
2252 $relativePath = dirname($relativeFile);
2254 if($relativePath == $priorPath) { // same dir, new file
2255 $out .= "<tr><td>".basename($relativeFile)."</td></tr>";
2256 $priorPath = $relativePath;
2270 function testThis2($dir, $id=0, $hide=false) {
2271 global $mod_strings;
2273 $dh = opendir($dir);
2276 $doHide = ($hide) ? 'none' : '';
2277 $out = "<div id='{$id}' style='display:{$doHide};'>";
2278 $out .= "<table cellpadding='1' cellspacing='0' style='border:0px solid #ccc'>\n";
2280 while($file = readdir($dh)) {
2281 if($file == '.' || $file == '..' || $file == 'CVS' || $file == '.cvsignore')
2284 if(is_dir($path.'/'.$file)) {
2285 $file = $path.'/'.$file;
2286 $newI = create_guid();
2287 $out .= "<tr><td valign='top'><a href='javascript:toggleNwFiles(\"{$newI}\");'>".SugarThemeRegistry::current()->getImage("Workflow", "", null, null, ".gif", $mod_strings['LBL_WORKFLOW'])."</a></td>\n";
2288 $out .= "<td valign='top'><b><a href='javascript:toggleNwFiles(\"{$newI}\");'>".basename($file)."</a></b></td></tr>";
2289 $out .= "<tr><td></td><td valign='top'>".testThis2($file, $newI, true)."</td></tr>";
2291 $out .= "<tr><td valign='top'> </td>\n";
2292 $out .= "<td valign='top'>".basename($file)."</td></tr>";
2296 $out .= "</tr></table>";
2307 function testThis3(&$files, $id, $hide, $previousPath = '') {
2308 if(!is_array($files) || empty($files))
2313 global $mod_strings;
2314 // expecting full path here
2315 foreach($files as $k => $file) {
2316 $file = str_replace(getcwd(), '', $file);
2317 $path = dirname($file);
2318 $fileName = basename($file);
2320 if($fileName == 'CVS' || $fileName == '.cvsignore')
2323 if($path == $previousPath) { // same directory
2324 // new row for each file
2325 $out .= "<tr><td valign='top' align='left'> </td>";
2326 $out .= "<td valign='top' align='left'>{$fileName}</td></tr>";
2327 } else { // new directory
2329 $out .= "<tr><td valign='top'><a href='javascript:toggleNwFiles(\"{$newI}\");'>".SugarThemeRegistry::current()->getImage("Workflow", "", null, null, ".gif", $mod_strings['LBL_WORKFLOW'])."</a></td>\n";
2330 $out .= "<td valign='top'><b><a href='javascript:toggleNwFiles(\"{$newI}\");'>".$fileName."</a></b></td></tr>";
2331 $recurse = testThis3($files, $newI, true, $previousPath);
2332 $out .= "<tr><td></td><td valign='top'>".$recurse."</td></tr>";
2335 $previousPath = $path;
2337 $display = ($hide) ? 'none' : '';
2339 <div id="{$id}" style="display:{$display}">
2340 <table cellpadding='1' cellspacing='0' border='0' style='border:1px solid #ccc'>
2349 function testThis4($filePath, $fileNodes=array(), $fileName='') {
2350 $path = dirname($filePath);
2351 $file = basename($filePath);
2353 $exFile = explode('/', $path);
2355 foreach($exFile as $pathSegment) {
2356 if(is_array($fileNodes[$pathSegment])) { // path already processed
2358 } else { // newly found path
2359 $fileNodes[$pathSegment] = array();
2362 if($fileName != '') {
2363 $fileNodes[$pathSegment][] = $fileName;
2372 ///////////////////////////////////////////////////////////////////////////////
2373 //// SYSTEM CHECK FUNCTIONS
2375 * generates an array with all files in the SugarCRM root directory, skipping
2377 * @return array files Array of files with absolute paths
2379 function getFilesForPermsCheck() {
2380 global $sugar_config;
2382 logThis('Got JSON call to find all files...');
2383 $filesNotWritable = array();
2384 $filesNWPerms = array();
2386 // add directories here that should be skipped when doing file permissions checks (cache/upload is the nasty one)
2388 $sugar_config['upload_dir'],
2390 $files = uwFindAllFiles(".", array(), true, $skipDirs, true);
2395 * checks files for permissions
2396 * @param array files Array of files with absolute paths
2397 * @return string result of check
2399 function checkFiles($files, $echo=false) {
2400 global $mod_strings;
2401 $filesNotWritable = array();
2404 <a href='javascript:void(0); toggleNwFiles(\"filesNw\");'>{$mod_strings['LBL_UW_SHOW_NW_FILES']}</a>
2405 <div id='filesNw' style='display:none;'>
2406 <table cellpadding='3' cellspacing='0' border='0'>
2408 <th align='left'>{$mod_strings['LBL_UW_FILE']}</th>
2409 <th align='left'>{$mod_strings['LBL_UW_FILE_PERMS']}</th>
2410 <th align='left'>{$mod_strings['LBL_UW_FILE_OWNER']}</th>
2411 <th align='left'>{$mod_strings['LBL_UW_FILE_GROUP']}</th>
2414 $isWindows = is_windows();
2415 foreach($files as $file) {
2418 if(!is_writable_windows($file)) {
2419 logThis('WINDOWS: File ['.$file.'] not readable - saving for display');
2420 // don't warn yet - we're going to use this to check against replacement files
2421 // aw: commented out; it's a hack to allow upgrade wizard to continue on windows... will fix later
2422 /*$filesNotWritable[$i] = $file;
2423 $filesNWPerms[$i] = substr(sprintf('%o',fileperms($file)), -4);
2424 $filesOut .= "<tr>".
2425 "<td><span class='error'>{$file}</span></td>".
2426 "<td>{$filesNWPerms[$i]}</td>".
2427 "<td>".$mod_strings['ERR_UW_CANNOT_DETERMINE_USER']."</td>".
2428 "<td>".$mod_strings['ERR_UW_CANNOT_DETERMINE_GROUP']."</td>".
2432 if(!is_writable($file)) {
2433 logThis('File ['.$file.'] not writable - saving for display');
2434 // don't warn yet - we're going to use this to check against replacement files
2435 $filesNotWritable[$i] = $file;
2436 $filesNWPerms[$i] = substr(sprintf('%o',fileperms($file)), -4);
2437 $owner = posix_getpwuid(fileowner($file));
2438 $group = posix_getgrgid(filegroup($file));
2439 $filesOut .= "<tr>".
2440 "<td><span class='error'>{$file}</span></td>".
2441 "<td>{$filesNWPerms[$i]}</td>".
2442 "<td>".$owner['name']."</td>".
2443 "<td>".$group['name']."</td>".
2450 $filesOut .= '</table></div>';
2452 $errors['files']['filesNotWritable'] = (count($filesNotWritable) > 0) ? true : false;
2453 if(count($filesNotWritable) < 1) {
2454 $filesOut = "{$mod_strings['LBL_UW_FILE_NO_ERRORS']}";
2460 function deletePackageOnCancel(){
2461 global $mod_strings;
2462 global $sugar_config;
2463 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
2464 logThis('running delete');
2465 if(!isset($_SESSION['install_file']) || ($_SESSION['install_file'] == "")) {
2466 logThis('ERROR: trying to delete non-existent file: ['.$_REQUEST['install_file'].']');
2467 $error = $mod_strings['ERR_UW_NO_FILE_UPLOADED'];
2469 // delete file in upgrades/patch
2470 $delete_me = "$base_upgrade_dir/patch/".basename(urldecode( $_REQUEST['install_file'] ));
2471 if(@unlink($delete_me)) {
2472 //logThis('unlinking: '.$delete_me);
2473 $out = basename($delete_me).$mod_strings['LBL_UW_FILE_DELETED'];
2475 logThis('ERROR: could not delete ['.$delete_me.']');
2476 $error = $mod_strings['ERR_UW_FILE_NOT_DELETED'].$delete_me;
2479 if(!empty($error)) {
2480 $out = "<b><span class='error'>{$error}</span></b><br />";
2484 function handleExecuteSqlKeys($db, $tableName, $disable)
2486 if(empty($tableName)) return true;
2487 if(is_callable(array($db, "supports"))) {
2489 return $disable?$db->disableKeys($tableName):$db->enableKeys($tableName);
2492 $op = $disable?"DISABLE":"ENABLE";
2493 return $db->query("ALTER TABLE $tableName $op KEYS");
2497 function parseAndExecuteSqlFile($sqlScript,$forStepQuery='',$resumeFromQuery='')
2499 global $sugar_config;
2500 $alterTableSchema = '';
2501 $sqlErrors = array();
2502 if(!isset($_SESSION['sqlSkippedQueries'])){
2503 $_SESSION['sqlSkippedQueries'] = array();
2505 $db = DBManagerFactory::getInstance();
2506 $disable_keys = ($db->dbType == "mysql"); // have to use old way for now for upgrades
2507 if(strpos($resumeFromQuery,",") != false){
2508 $resumeFromQuery = explode(",",$resumeFromQuery);
2510 if(file_exists($sqlScript)) {
2511 $fp = fopen($sqlScript, 'r');
2512 $contents = stream_get_contents($fp);
2513 $anyScriptChanges =$contents;
2514 $resumeAfterFound = false;
2518 while($line = fgets($fp)) {
2519 if(strpos($line, '--') === false) {
2520 $completeLine .= " ".trim($line);
2521 if(strpos($line, ';') !== false) {
2523 $query = str_replace(';','',$completeLine);
2524 //if resume from query is not null then find out from where
2525 //it should start executing the query.
2527 if($query != null && $resumeFromQuery != null){
2528 if(!$resumeAfterFound){
2529 if(strpos($query,",") != false){
2530 $queArray = explode(",",$query);
2531 for($i=0;$i<sizeof($resumeFromQuery);$i++){
2532 if(strcasecmp(trim($resumeFromQuery[$i]),trim($queArray[$i]))==0){
2533 $resumeAfterFound = true;
2535 $resumeAfterFound = false;
2541 elseif(strcasecmp(trim($resumeFromQuery),trim($query))==0){
2542 $resumeAfterFound = true;
2545 if($resumeAfterFound){
2548 // if $count=1 means it is just found so skip the query. Run the next one
2549 if($query != null && $resumeAfterFound && $count >1){
2550 $tableName = getAlterTable($query);
2553 handleExecuteSqlKeys($db, $tableName, true);
2556 if($db->checkError()){
2557 //put in the array to use later on
2558 $_SESSION['sqlSkippedQueries'][] = $query;
2562 handleExecuteSqlKeys($db, $tableName, false);
2564 $progQuery[$forStepQuery]=$query;
2565 post_install_progress($progQuery,$action='set');
2568 elseif($query != null){
2569 $tableName = getAlterTable($query);
2572 handleExecuteSqlKeys($db, $tableName, true);
2577 handleExecuteSqlKeys($db, $tableName, false);
2579 $progQuery[$forStepQuery]=$query;
2580 post_install_progress($progQuery,$action='set');
2581 if($db->checkError()){
2582 //put in the array to use later on
2583 $_SESSION['sqlSkippedQueries'][] = $query;
2595 function getAlterTable($query){
2596 $query = strtolower($query);
2597 if (preg_match('/^\s*alter\s+table\s+/', $query)) {
2598 $sqlArray = explode(" ", $query);
2599 $key = array_search('table', $sqlArray);
2600 return $sqlArray[($key+1)];
2606 function set_upgrade_vars(){
2607 logThis('setting session variables...');
2608 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2609 if(!is_dir($upgrade_progress_dir)){
2610 mkdir_recursive($upgrade_progress_dir);
2612 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2613 if(file_exists($upgrade_progress_file)){
2614 include($upgrade_progress_file);
2617 fopen($upgrade_progress_file, 'w+');
2619 if(!isset($upgrade_config) || $upgrade_config == null){
2620 $upgrade_config = array();
2621 $upgrade_config[1]['upgrade_vars']=array();
2623 if(isset($upgrade_config[1]) && isset($upgrade_config[1]['upgrade_vars']) && !is_array($upgrade_config[1]['upgrade_vars'])){
2624 $upgrade_config[1]['upgrade_vars'] = array();
2627 if(!isset($upgrade_vars) || $upgrade_vars == NULL){
2628 $upgrade_vars = array();
2630 if(isset($_SESSION['unzip_dir']) && !empty($_SESSION['unzip_dir']) && file_exists($_SESSION['unzip_dir'])){
2631 $upgrade_vars['unzip_dir']=$_SESSION['unzip_dir'];
2633 if(isset($_SESSION['install_file']) && !empty($_SESSION['install_file']) && file_exists($_SESSION['install_file'])){
2634 $upgrade_vars['install_file']=$_SESSION['install_file'];
2636 if(isset($_SESSION['Upgraded451Wizard']) && !empty($_SESSION['Upgraded451Wizard'])){
2637 $upgrade_vars['Upgraded451Wizard']=$_SESSION['Upgraded451Wizard'];
2639 if(isset($_SESSION['license_shown']) && !empty($_SESSION['license_shown'])){
2640 $upgrade_vars['license_shown']=$_SESSION['license_shown'];
2642 if(isset($_SESSION['Initial_451to500_Step']) && !empty($_SESSION['Initial_451to500_Step'])){
2643 $upgrade_vars['Initial_451to500_Step']=$_SESSION['Initial_451to500_Step'];
2645 if(isset($_SESSION['zip_from_dir']) && !empty($_SESSION['zip_from_dir'])){
2646 $upgrade_vars['zip_from_dir']=$_SESSION['zip_from_dir'];
2648 //place into the upgrade_config array and rewrite config array only if new values are being inserted
2649 if(isset($upgrade_vars) && $upgrade_vars != null && sizeof($upgrade_vars) > 0){
2650 foreach($upgrade_vars as $key=>$val){
2651 if($key != null && $val != null){
2652 $upgrade_config[1]['upgrade_vars'][$key]=$upgrade_vars[$key];
2655 ksort($upgrade_config);
2656 if(is_writable($upgrade_progress_file) && write_array_to_file( "upgrade_config", $upgrade_config,
2657 $upgrade_progress_file)) {
2658 //writing to the file
2663 function initialize_session_vars(){
2664 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2665 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2666 if(file_exists($upgrade_progress_file)){
2667 include($upgrade_progress_file);
2668 if(isset($upgrade_config) && $upgrade_config != null && is_array($upgrade_config) && sizeof($upgrade_config) >0){
2669 $currVarsArray=$upgrade_config[1]['upgrade_vars'];
2670 //print_r($currVarsArray);
2671 if(isset($currVarsArray) && $currVarsArray != null && is_array($currVarsArray) && sizeof($currVarsArray)>0){
2672 foreach($currVarsArray as $key=>$val){
2673 if($key != null && $val !=null){
2674 //set session variables
2675 $_SESSION[$key]=$val;
2684 //track the upgrade progress on each step
2685 //track the upgrade progress on each step
2686 function set_upgrade_progress($currStep,$currState,$currStepSub='',$currStepSubState=''){
2688 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2689 if(!is_dir($upgrade_progress_dir)){
2690 mkdir_recursive($upgrade_progress_dir);
2692 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2693 if(file_exists($upgrade_progress_file)){
2694 include($upgrade_progress_file);
2697 if(function_exists('sugar_fopen')){
2698 sugar_fopen($upgrade_progress_file, 'w+');
2701 fopen($upgrade_progress_file, 'w+');
2704 if(!isset($upgrade_config) || $upgrade_config == null){
2705 $upgrade_config = array();
2706 $upgrade_config[1]['upgrade_vars']=array();
2708 if(!is_array($upgrade_config[1]['upgrade_vars'])){
2709 $upgrade_config[1]['upgrade_vars'] = array();
2711 if($currStep != null && $currState != null){
2712 if(sizeof($upgrade_config) > 0){
2713 if($currStepSub != null && $currStepSubState !=null){
2714 //check if new status to be set or update
2715 //get the latest in array. since it has sub components prepare an array
2716 if(!empty($upgrade_config[sizeof($upgrade_config)][$currStep]) && is_array($upgrade_config[sizeof($upgrade_config)][$currStep])){
2717 $latestStepSub = currSubStep($upgrade_config[sizeof($upgrade_config)][$currStep]);
2718 if($latestStepSub == $currStepSub){
2719 $upgrade_config[sizeof($upgrade_config)][$currStep][$latestStepSub]=$currStepSubState;
2720 $upgrade_config[sizeof($upgrade_config)][$currStep][$currStep] = $currState;
2723 $upgrade_config[sizeof($upgrade_config)][$currStep][$currStepSub]=$currStepSubState;
2724 $upgrade_config[sizeof($upgrade_config)][$currStep][$currStep] = $currState;
2728 $currArray = array();
2729 $currArray[$currStep] = $currState;
2730 $currArray[$currStepSub] = $currStepSubState;
2731 $upgrade_config[sizeof($upgrade_config)+1][$currStep] = $currArray;
2735 //get the current upgrade progress
2736 $latestStep = get_upgrade_progress();
2737 //set the upgrade progress
2738 if($latestStep == $currStep){
2739 //update the current step with new progress status
2740 $upgrade_config[sizeof($upgrade_config)][$latestStep]=$currState;
2744 $upgrade_config[sizeof($upgrade_config)+1][$currStep]=$currState;
2746 // now check if there elements within array substeps
2750 //set the upgrade progress (just starting)
2751 $upgrade_config[sizeof($upgrade_config)+1][$currStep]= $currState;
2754 if(is_writable($upgrade_progress_file) && write_array_to_file( "upgrade_config", $upgrade_config,
2755 $upgrade_progress_file)) {
2756 //writing to the file
2762 function get_upgrade_progress(){
2763 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2764 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2767 if(file_exists($upgrade_progress_file)){
2768 include($upgrade_progress_file);
2769 if(!isset($upgrade_config) || $upgrade_config == null){
2770 $upgrade_config = array();
2772 if($upgrade_config != null && sizeof($upgrade_config) >1){
2773 $currArr = $upgrade_config[sizeof($upgrade_config)];
2774 if(is_array($currArr)){
2775 foreach($currArr as $key=>$val){
2783 function currSubStep($currStep){
2785 if(is_array($currStep)){
2786 foreach($currStep as $key=>$val){
2794 function currUpgradeState($currState){
2796 if(is_array($currState)){
2797 foreach($currState as $key=>$val){
2799 foreach($val as $k=>$v){
2813 function didThisStepRunBefore($step,$SubStep=''){
2814 if($step == null) return;
2815 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2816 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2819 if(file_exists($upgrade_progress_file)){
2820 include($upgrade_progress_file);
2821 if(isset($upgrade_config) && $upgrade_config != null && is_array($upgrade_config) && sizeof($upgrade_config) >0){
2822 for($i=1;$i<=sizeof($upgrade_config);$i++){
2823 if(is_array($upgrade_config[$i])){
2824 foreach($upgrade_config[$i] as $key=>$val){
2826 if(is_array($upgrade_config[$i][$step])){
2828 foreach ($upgrade_config[$i][$step] as $k=>$v){
2830 foreach($v as $k1=>$v1){
2831 if($SubStep != null){
2832 if($SubStep ==$k1 && $v1=='done'){
2839 elseif($SubStep !=null){
2840 if($SubStep==$k && $v=='done'){
2845 elseif($step==$k && $v=='done'){
2851 elseif($val=='done'){
2865 //get and set post install status
2866 function post_install_progress($progArray='',$action=''){
2867 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2868 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2869 if($action=='' || $action=='get'){
2870 //get the state of post install
2871 $currProg = array();
2872 if(file_exists($upgrade_progress_file)){
2873 include($upgrade_progress_file);
2874 if(is_array($upgrade_config[sizeof($upgrade_config)]['commit']['post_install']) && sizeof($upgrade_config[sizeof($upgrade_config)]['commit']['post_install'])>0){
2875 foreach($upgrade_config[sizeof($upgrade_config)]['commit']['post_install'] as $k=>$v){
2882 elseif($action=='set'){
2883 if(!is_dir($upgrade_progress_dir)){
2884 mkdir($upgrade_progress_dir);
2886 if(file_exists($upgrade_progress_file)){
2887 include($upgrade_progress_file);
2890 fopen($upgrade_progress_file, 'w+');
2892 if(!is_array($upgrade_config[sizeof($upgrade_config)]['commit']['post_install'])){
2893 $upgrade_config[sizeof($upgrade_config)]['commit']['post_install']=array();
2894 $upgrade_config[sizeof($upgrade_config)]['commit']['post_install']['post_install'] = 'in_progress';
2896 if($progArray != null && is_array($progArray)){
2897 foreach($progArray as $key=>$val){
2898 $upgrade_config[sizeof($upgrade_config)]['commit']['post_install'][$key]=$val;
2901 if(is_writable($upgrade_progress_file) && write_array_to_file( "upgrade_config", $upgrade_config,
2902 $upgrade_progress_file)) {
2903 //writing to the file
2908 function repairDBForUpgrade($execute=false,$path=''){
2910 global $current_user, $beanFiles;
2912 set_time_limit(3600);
2914 $db = &DBManagerFactory::getInstance();
2916 VardefManager::clearVardef();
2917 require_once('include/ListView/ListView.php');
2918 foreach ($beanFiles as $bean => $file) {
2919 require_once ($file);
2920 $focus = new $bean ();
2921 $sql .= $db->repairTable($focus, $execute);
2925 $olddictionary = $dictionary;
2926 unset ($dictionary);
2927 include ('modules/TableDictionary.php');
2928 foreach ($dictionary as $meta) {
2929 $tablename = $meta['table'];
2930 $fielddefs = $meta['fields'];
2931 $indices = $meta['indices'];
2932 $sql .= $db->repairTableParams($tablename, $fielddefs, $indices, $execute);
2935 foreach (explode("\n", $sql) as $line) {
2936 if (!empty ($line) && substr($line, -2) != "*/") {
2939 $qry_str .= $line . "\n";
2950 preg_replace('#(/\*.+?\*/\n*)#', '', $qry_str)
2952 logThis("*******START EXECUTING DB UPGRADE QUERIES***************",$path);
2953 logThis($sql,$path);
2954 logThis("*******END EXECUTING DB UPGRADE QUERIES****************",$path);
2963 * upgradeUserPreferences
2964 * This method updates the user_preferences table and sets the pages/dashlets for users
2965 * which have ACL access to Trackers so that the Tracker dashlets are set in their user perferences
2968 function upgradeUserPreferences() {
2969 global $sugar_config, $sugar_version;
2970 $uw_strings = return_module_language($GLOBALS['current_language'], 'UpgradeWizard');
2972 $localization = new Localization();
2973 $localeCoreDefaults = $localization->getLocaleConfigDefaults();
2975 // check the current system wide default_locale_name_format and add it to the list if it's not there
2976 if(empty($sugar_config['name_formats'])) {
2977 $sugar_config['name_formats'] = $localeCoreDefaults['name_formats'];
2978 if(!rebuildConfigFile($sugar_config, $sugar_version)) {
2979 $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
2983 $currentDefaultLocaleNameFormat = $sugar_config['default_locale_name_format'];
2985 if ($localization->isAllowedNameFormat($currentDefaultLocaleNameFormat)) {
2986 upgradeLocaleNameFormat($currentDefaultLocaleNameFormat);
2988 $sugar_config['default_locale_name_format'] = $localeCoreDefaults['default_locale_name_format'];
2989 if(!rebuildConfigFile($sugar_config, $sugar_version)) {
2990 $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
2992 $localization->createInvalidLocaleNameFormatUpgradeNotice();
2995 $db = &DBManagerFactory::getInstance();
2996 $result = $db->query("SELECT id FROM users where deleted = '0'");
2997 while($row = $db->fetchByAssoc($result))
2999 $current_user = new User();
3000 $current_user->retrieve($row['id']);
3002 // 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
3003 $currentUserNameFormat = $current_user->getPreference('default_locale_name_format');
3004 if ($localization->isAllowedNameFormat($currentUserNameFormat)) {
3005 upgradeLocaleNameFormat($currentUserNameFormat);
3007 $current_user->setPreference('default_locale_name_format', 's f l', 0, 'global');
3008 $current_user->savePreferencesToDB();
3016 * Checks if a locale name format is part of the default list, if not adds it to the config
3017 * @param $name_format string a local name format string such as 's f l'
3018 * @return bool true on successful write to config file, false on failure;
3020 function upgradeLocaleNameFormat($name_format) {
3021 global $sugar_config, $sugar_version;
3023 $localization = new Localization();
3024 $localeConfigDefaults = $localization->getLocaleConfigDefaults();
3026 $uw_strings = return_module_language($GLOBALS['current_language'], 'UpgradeWizard');
3027 if(empty($sugar_config['name_formats'])) {
3028 $sugar_config['name_formats'] = $localeConfigDefaults['name_formats'];
3029 if(!rebuildConfigFile($sugar_config, $sugar_version)) {
3030 $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
3033 if (!in_array($name_format, $sugar_config['name_formats'])) {
3034 $new_config = sugarArrayMerge($sugar_config['name_formats'], array($name_format=>$name_format));
3035 $sugar_config['name_formats'] = $new_config;
3036 if(!rebuildConfigFile($sugar_config, $sugar_version)) {
3037 $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
3046 function add_custom_modules_favorites_search(){
3047 $module_directories = scandir('modules');
3049 foreach($module_directories as $module_dir){
3050 if($module_dir == '.' || $module_dir == '..' || !is_dir("modules/{$module_dir}")){
3055 preg_match('/^[a-z0-9]{1,5}_[a-z0-9_]+$/i' , $module_dir, $matches);
3057 // Make sure the module was created by module builder
3058 if(empty($matches)){
3062 $full_module_dir = "modules/{$module_dir}/";
3063 $read_searchdefs_from = "{$full_module_dir}/metadata/searchdefs.php";
3064 $read_SearchFields_from = "{$full_module_dir}/metadata/SearchFields.php";
3065 $read_custom_SearchFields_from = "custom/{$full_module_dir}/metadata/SearchFields.php";
3067 // Studio can possibly override this file, so we check for a custom version of it
3068 if(file_exists("custom/{$full_module_dir}/metadata/searchdefs.php")){
3069 $read_searchdefs_from = "custom/{$full_module_dir}/metadata/searchdefs.php";
3072 if(file_exists($read_searchdefs_from) && file_exists($read_SearchFields_from)){
3075 require($read_searchdefs_from);
3076 foreach($searchdefs[$module_dir]['layout']['basic_search'] as $sf_array){
3077 if(isset($sf_array['name']) && $sf_array['name'] == 'favorites_only'){
3082 require($read_SearchFields_from);
3083 if(isset($searchFields[$module_dir]['favorites_only'])){
3087 if(!$found_sf1 && !$found_sf2){
3088 $searchdefs[$module_dir]['layout']['basic_search']['favorites_only'] = array('name' => 'favorites_only','label' => 'LBL_FAVORITES_FILTER','type' => 'bool',);
3089 $searchdefs[$module_dir]['layout']['advanced_search']['favorites_only'] = array('name' => 'favorites_only','label' => 'LBL_FAVORITES_FILTER','type' => 'bool',);
3090 $searchFields[$module_dir]['favorites_only'] = array(
3091 'query_type'=>'format',
3092 'operator' => 'subquery',
3093 'subquery' => 'SELECT sugarfavorites.record_id FROM sugarfavorites
3094 WHERE sugarfavorites.deleted=0
3095 and sugarfavorites.module = \''.$module_dir.'\'
3096 and sugarfavorites.assigned_user_id = \'{0}\'',
3097 'db_field'=>array('id')
3100 if(!is_dir("custom/{$full_module_dir}/metadata")){
3101 mkdir_recursive("custom/{$full_module_dir}/metadata");
3103 $success_sf1 = write_array_to_file('searchdefs', $searchdefs, "custom/{$full_module_dir}/metadata/searchdefs.php");
3104 $success_sf2 = write_array_to_file('searchFields', $searchFields, "{$full_module_dir}/metadata/SearchFields.php");
3107 logThis("add_custom_modules_favorites_search failed for searchdefs.php for {$module_dir}");
3110 logThis("add_custom_modules_favorites_search failed for SearchFields.php for {$module_dir}");
3112 if($success_sf1 && $success_sf2){
3113 logThis("add_custom_modules_favorites_search successfully updated searchdefs and searchFields for {$module_dir}");
3122 * upgradeModulesForTeamsets
3124 * This method adds the team_set_id values to the module tables that have the new team_set_id column
3125 * added through the SugarCRM 5.5.x upgrade process. It also adds the values into the team_sets and
3126 * team_sets_teams tables.
3128 * @param filter Array of modules to process; empty by default
3130 function upgradeModulesForTeamsets($filter=array()) {
3131 require('include/modules.php');
3132 foreach($beanList as $moduleName=>$beanName) {
3133 if(!empty($filter) && array_search($moduleName, $filter) === false) {
3136 if($moduleName == 'TeamMemberships' || $moduleName == 'ForecastOpportunities'){
3139 $bean = loadBean($moduleName);
3141 empty($bean->table_name)) {
3145 $FieldArray = $GLOBALS['db']->helper->get_columns($bean->table_name);
3146 if(!isset($FieldArray['team_id'])) {
3150 upgradeTeamColumn($bean, 'team_id');
3154 //Upgrade users table
3155 $bean = loadBean('Users');
3156 upgradeTeamColumn($bean, 'default_team');
3157 $result = $GLOBALS['db']->query("SELECT id FROM teams where deleted=0");
3158 while($row = $GLOBALS['db']->fetchByAssoc($result)) {
3159 $teamset = new TeamSet();
3160 $teamset->addTeams($row['id']);
3167 * Helper function to create a team_set_id column and also set team_set_id column
3168 * to have the value of the $column_name parameter
3170 * @param $bean SugarBean which we are adding team_set_id column to
3171 * @param $column_name The name of the column containing the default team_set_id value
3173 function upgradeTeamColumn($bean, $column_name) {
3174 //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
3175 //module that does not use the SugarObjects
3176 if(empty($bean->field_defs['team_set_id']) && $bean->module_dir != 'Trackers'){
3178 //at this point we could assume that since we have a team_id defined and not a team_set_id that we need to
3179 //add that field and the corresponding relationships
3180 $object = $bean->object_name;
3181 $module = $bean->module_dir;
3182 $object_name = $object;
3183 $_object_name = strtolower($object_name);
3185 if(!empty($GLOBALS['dictionary'][$object]['table'])){
3186 $table_name = $GLOBALS['dictionary'][$object]['table'];
3188 $table_name = strtolower($module);
3191 $path = 'include/SugarObjects/implements/team_security/vardefs.php';
3193 //go through each entry in the vardefs from team_security and unset anything that is already set in the core module
3194 //this will ensure we have the proper ordering.
3195 $fieldDiff = array_diff_assoc($vardefs['fields'], $GLOBALS['dictionary'][$bean->object_name]['fields']);
3197 $file = 'custom/Extension/modules/' . $bean->module_dir. '/Ext/Vardefs/teams.php';
3198 $contents = "<?php\n";
3199 if(!empty($fieldDiff)){
3200 foreach($fieldDiff as $key => $val){
3201 $contents .= "\n\$GLOBALS['dictionary']['". $object . "']['fields']['". $key . "']=" . var_export_helper($val) . ";";
3204 $relationshipDiff = array_diff_assoc($vardefs['relationships'], $GLOBALS['dictionary'][$bean->object_name]['relationships']);
3205 if(!empty($relationshipDiff)){
3206 foreach($relationshipDiff as $key => $val){
3207 $contents .= "\n\$GLOBALS['dictionary']['". $object . "']['relationships']['". $key . "']=" . var_export_helper($val) . ";";
3210 $indexDiff = array_diff_assoc($vardefs['indices'], $GLOBALS['dictionary'][$bean->object_name]['indices']);
3211 if(!empty($indexDiff)){
3212 foreach($indexDiff as $key => $val){
3213 $contents .= "\n\$GLOBALS['dictionary']['". $object . "']['indices']['". $key . "']=" . var_export_helper($val) . ";";
3216 if( $fh = @sugar_fopen( $file, 'wt' ) )
3218 fputs( $fh, $contents);
3223 //we have written out the teams.php into custom/Extension/modules/{$module_dir}/Ext/Vardefs/teams.php'
3224 //now let's merge back into vardefs.ext.php
3225 require_once('ModuleInstall/ModuleInstaller.php');
3226 $mi = new ModuleInstaller();
3227 $mi->merge_files('Ext/Vardefs/', 'vardefs.ext.php');
3228 VardefManager::loadVardef($bean->module_dir, $bean->object_name, true);
3229 $bean->field_defs = $GLOBALS['dictionary'][$bean->object_name]['fields'];
3232 if(isset($bean->field_defs['team_set_id'])) {
3233 //Create the team_set_id column
3234 $FieldArray = $GLOBALS['db']->helper->get_columns($bean->table_name);
3235 if(!isset($FieldArray['team_set_id'])) {
3236 $GLOBALS['db']->addColumn($bean->table_name, $bean->field_defs['team_set_id']);
3238 $indexArray = $GLOBALS['db']->helper->get_indices($bean->table_name);
3240 $indexName = getValidDBName('idx_'.strtolower($bean->table_name).'_tmst_id', true, 34);
3243 'name' => $indexName,
3245 'fields' => array('team_set_id')
3248 if(!isset($indexArray[$indexName])) {
3249 $GLOBALS['db']->addIndexes($bean->table_name, $indexDef);
3252 //Update the table's team_set_id column to have the same values as team_id
3253 $GLOBALS['db']->query("UPDATE {$bean->table_name} SET team_set_id = {$column_name}");
3258 * Update the folder subscription table which confirms to the team security mechanism but
3259 * the class SugarFolders does not extend SugarBean and is therefore never picked up by the
3260 * upgradeModulesForTeamsets function.
3262 function upgradeFolderSubscriptionsTeamSetId()
3264 logThis("In upgradeFolderSubscriptionsTeamSetId()");
3265 $query = "UPDATE folders SET team_set_id = team_id";
3266 $result = $GLOBALS['db']->query($query);
3267 logThis("Finished upgradeFolderSubscriptionsTeamSetId()");
3271 * upgradeModulesForTeam
3273 * This method update the associated_user_id, name, name_2 to the private team records on teams table
3274 * This function is used for upgrade process from 5.1.x and 5.2.x.
3277 function upgradeModulesForTeam() {
3278 logThis("In upgradeModulesForTeam()");
3279 $result = $GLOBALS['db']->query("SELECT id, user_name, first_name, last_name FROM users where deleted=0");
3281 while($row = $GLOBALS['db']->fetchByAssoc($result)) {
3282 $results2 = $GLOBALS['db']->query("SELECT id FROM teams WHERE name = '({$row['user_name']})'");
3284 if(!$assoc = $GLOBALS['db']->fetchByAssoc($results2)) {
3285 //if team does not exist, then lets create the team for this user
3288 $user->retrieve($row['id']);
3289 $team->new_user_created($user);
3290 $team_id = $team->id;
3292 $team_id =$assoc['id'];
3296 $name = is_null($row['first_name'])?'':$row['first_name'];
3297 $name_2 = is_null($row['last_name'])?'':$row['last_name'];
3298 $associated_user_id = $row['id'];
3301 //Ensure team->name is not empty by using team->name_2 if available
3302 if(empty($name) && !empty($name_2)) {
3307 $query = "UPDATE teams SET name = '{$name}', name_2 = '{$name_2}', associated_user_id = '{$associated_user_id}' WHERE id = '{$team_id}'";
3308 $GLOBALS['db']->query($query);
3311 //Update the team_set_id and default_team columns
3312 $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'));
3314 //Update team_set_id
3315 if($ce_to_pro_or_ent) {
3316 $GLOBALS['db']->query("update users set team_set_id = (select teams.id from teams where teams.associated_user_id = users.id)");
3317 $GLOBALS['db']->query("update users set default_team = (select teams.id from teams where teams.associated_user_id = users.id)");
3323 function addNewSystemTabsFromUpgrade($from_dir){
3325 if(isset($_SESSION['upgrade_from_flavor'])){
3327 //check to see if there are any new files that need to be added to systems tab
3328 //retrieve old modules list
3329 logThis('check to see if new modules exist',$path);
3330 $oldModuleList = array();
3331 $newModuleList = array();
3332 include($from_dir.'/include/modules.php');
3333 $oldModuleList = $moduleList;
3334 include('include/modules.php');
3335 $newModuleList = $moduleList;
3337 //include tab controller
3338 require_once('modules/MySettings/TabController.php');
3339 $newTB = new TabController();
3341 //make sure new modules list has a key we can reference directly
3342 $newModuleList = $newTB->get_key_array($newModuleList);
3343 $oldModuleList = $newTB->get_key_array($oldModuleList);
3345 //iterate through list and remove commonalities to get new modules
3346 foreach ($newModuleList as $remove_mod){
3347 if(in_array($remove_mod, $oldModuleList)){
3348 unset($newModuleList[$remove_mod]);
3351 //new modules list now has left over modules which are new to this install, so lets add them to the system tabs
3352 logThis('new modules to add are '.var_export($newModuleList,true),$path);
3354 if(!empty($newModuleList))
3356 //grab the existing system tabs
3357 $tabs = $newTB->get_system_tabs();
3359 //add the new tabs to the array
3360 foreach($newModuleList as $nm ){
3364 $newTB->set_system_tabs($tabs);
3366 logThis('module tabs updated',$path);
3372 * This method attempts to fix dropdown lists that were incorrectly named.
3373 * There were versions of SugarCRM that did not enforce naming convention rules
3374 * for the dropdown list field name. This method attempts to resolve that by
3375 * fixing the language files that may have been affected and then updating the
3376 * fields_meta_data table accordingly. It also refreshes any vardefs that may
3377 * have been affected.
3380 function fix_dropdown_list() {
3381 if(file_exists('custom/include/language')) {
3383 $affected_modules = array();
3384 $affected_keys = array();
3386 getFiles($files, 'custom/include/language', '/\.php$/i');
3387 foreach($files as $file) {
3389 if(file_exists($file . '.bak')) {
3390 $bak_mod_time = filemtime($file . '.bak');
3391 $php_mod_time = filemtime($file);
3392 //We're saying if the .php file was modified 30 seconds no more than php.bak file then we
3393 //run these additional cleanup checks
3394 if($php_mod_time - $bak_mod_time < 30) {
3396 $app_list_strings = array();
3397 $GLOBALS['app_list_strings'] = array();
3398 require($file . '.bak');
3399 $bak_app_list_strings = array_merge($app_list_strings, $GLOBALS['app_list_strings']);
3401 $app_list_strings = array();
3402 $GLOBALS['app_list_strings'] = array();
3404 $php_app_list_strings = array_merge($app_list_strings, $GLOBALS['app_list_strings']);
3406 //Get the file contents
3407 $contents = file_get_contents($file);
3409 //Now simulate a fix for the file before we compare w/ the .php file
3410 //we also append to the $contents
3411 foreach($bak_app_list_strings as $key=>$entry) {
3412 if(preg_match('/([^A-Za-z_])/', $key, $matches) && is_array($entry)) {
3413 $new_key = preg_replace('/[^A-Za-z_]/', '_', $key);
3414 $bak_app_list_strings[$new_key] = $bak_app_list_strings[$key];
3415 unset($bak_app_list_strings[$key]);
3416 //Now if the entry doesn't exists in the .php file, then add to contents
3417 if(!isset($php_app_list_strings[$new_key])) {
3418 $contents .= "\n\$GLOBALS['app_list_strings']['{$new_key}'] = " . var_export_helper($bak_app_list_strings[$new_key]) . ";";
3423 //Now load the .php file to do the comparison
3424 foreach($php_app_list_strings as $key=>$entry) {
3425 if(isset($bak_app_list_strings[$key])) {
3426 $diff = array_diff($bak_app_list_strings[$key], $entry);
3428 //There is a difference, so copy the $bak_app_list_strings version into the .php file
3429 $contents .= "\n\$GLOBALS['app_list_strings']['{$key}'] = " . var_export_helper($bak_app_list_strings[$key]) . ";";
3434 //Now write out the file contents
3435 //Create backup just in case
3436 copy($file, $file . '.php_bak');
3437 $fp = @sugar_fopen($file, 'w');
3439 fwrite($fp, $contents);
3442 $GLOBALS['log']->error("Unable to update file contents in fix_dropdown_list for {$file}");
3447 unset($GLOBALS['app_strings']);
3448 unset($GLOBALS['app_list_strings']);
3449 $app_list_strings = array();
3452 $contents = file_get_contents($file);
3453 if ( !isset($GLOBALS['app_list_strings']) ) {
3454 $GLOBALS['app_list_strings'] = $app_list_strings;
3457 $GLOBALS['app_list_strings'] = array_merge($app_list_strings, $GLOBALS['app_list_strings']);
3460 if(isset($GLOBALS['app_list_strings']) && is_array($GLOBALS['app_list_strings'])) {
3461 foreach($GLOBALS['app_list_strings'] as $key=>$entry) {
3462 if(preg_match('/([^A-Za-z_])/', $key, $matches) && is_array($entry)) {
3463 $result = $GLOBALS['db']->query("SELECT custom_module FROM fields_meta_data WHERE ext1 = '{$key}'");
3464 if(!empty($result)) {
3465 while($row = $GLOBALS['db']->fetchByAssoc($result)) {
3466 $custom_module = $row['custom_module'];
3467 if(!empty($GLOBALS['beanList'][$custom_module])) {
3468 $affected_modules[$custom_module] = $GLOBALS['beanList'][$custom_module];
3473 //Replace all invalid characters with '_' character
3474 $new_key = preg_replace('/[^A-Za-z_]/', '_', $key);
3475 $affected_keys[$key] = $new_key;
3477 $GLOBALS['app_list_strings'][$new_key] = $GLOBALS['app_list_strings'][$key];
3478 unset($GLOBALS['app_list_strings'][$key]);
3480 $pattern_match = "/(\[\s*\'{$key}\'\s*\])/";
3481 $new_key = "['{$new_key}']";
3482 $out = preg_replace($pattern_match, $new_key, $contents);
3488 //This is a check for g => h instances where the file contents were incorrectly written
3489 //and also fixes the scenario where via a UI upgrade, the app_list_strings were incorrectly
3490 //merged with app_list_strings variables declared elsewhere
3492 if(preg_match('/\$GLOBALS\s*\[\s*[\"|\']app_list_strings[\"|\']\s*\]\s*=\s*array\s*\(/', $contents)) {
3493 //Now also remove all the non-custom labels that were added
3494 if(preg_match('/language\/([^\.]+)\.lang\.php$/', $file, $matches)) {
3495 $language = $matches[1];
3497 $app_list_strings = array();
3499 if(file_exists("include/language/$language.lang.php")) {
3500 include("include/language/$language.lang.php");
3502 if(file_exists("include/language/$language.lang.override.php")) {
3503 $app_list_strings = _mergeCustomAppListStrings("include/language/$language.lang.override.php" , $app_list_strings) ;
3505 if(file_exists("custom/application/Ext/Language/$language.ext.lang.php")) {
3506 $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$language.ext.lang.php" , $app_list_strings) ;
3508 if(file_exists("custom/application/Ext/Language/$language.lang.ext.php")) {
3509 $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$language.lang.ext.php" , $app_list_strings) ;
3512 $all_non_custom_include_language_strings = $app_strings;
3513 $all_non_custom_include_language_list_strings = $app_list_strings;
3515 $unset_keys = array();
3516 if(!empty($GLOBALS['app_list_strings'])) {
3517 foreach($GLOBALS['app_list_strings'] as $key=>$value) {
3519 if(isset($all_non_custom_include_language_list_strings[$key])) {
3520 $diff = array_diff($all_non_custom_include_language_list_strings[$key], $GLOBALS['app_list_strings'][$key]);
3523 if(!empty($all_non_custom_include_language_list_strings[$key]) && empty($diff)) {
3524 $unset_keys[] = $key;
3529 foreach($unset_keys as $key) {
3530 unset($GLOBALS['app_list_strings'][$key]);
3533 if(!empty($GLOBALS['app_strings'])) {
3534 foreach($GLOBALS['app_strings'] as $key=>$value) {
3535 if(!empty($all_non_custom_include_language_strings[$key])) {
3536 unset($GLOBALS['app_strings'][$key]);
3540 } //if(preg_match...)
3543 if(!empty($GLOBALS['app_strings'])) {
3544 foreach($GLOBALS['app_strings'] as $key=>$entry) {
3545 $out .= "\n\$GLOBALS['app_strings']['$key']=" . var_export_helper($entry) . ";";
3549 foreach($GLOBALS['app_list_strings'] as $key=>$entry) {
3550 $out .= "\n\$GLOBALS['app_list_strings']['$key']=" . var_export_helper($entry) . ";";
3554 } //if(preg_match...)
3558 //Create a backup just in case
3559 copy($file, $file . '.bak');
3560 $fp = @sugar_fopen($file, 'w');
3565 //If we can't update the file, just return
3566 $GLOBALS['log']->error("Unable to update file contents in fix_dropdown_list.");
3574 //Update db entries (the order matters here... need to process database changes first)
3575 if(!empty($affected_keys)) {
3576 foreach($affected_keys as $old_key=>$new_key) {
3577 $GLOBALS['db']->query("UPDATE fields_meta_data SET ext1 = '{$new_key}' WHERE ext1 = '{$old_key}'");
3581 //Update vardef files for affected modules
3582 if(!empty($affected_modules)) {
3583 foreach($affected_modules as $module=>$object) {
3584 VardefManager::refreshVardefs($module, $object);
3591 function update_iframe_dashlets(){
3592 require_once(sugar_cached('dashlets/dashlets.php'));
3594 $db = DBManagerFactory::getInstance();
3595 $query = "SELECT id, contents, assigned_user_id FROM user_preferences WHERE deleted = 0 AND category = 'Home'";
3596 $result = $db->query($query, true, "Unable to update new default dashlets! ");
3597 while ($row = $db->fetchByAssoc($result)) {
3598 $content = unserialize(base64_decode($row['contents']));
3599 $assigned_user_id = $row['assigned_user_id'];
3600 $record_id = $row['id'];
3602 $current_user = new User();
3603 $current_user->retrieve($row['assigned_user_id']);
3605 if(!empty($content['dashlets']) && !empty($content['pages'])){
3606 $originalDashlets = $content['dashlets'];
3607 foreach($originalDashlets as $key => $ds){
3608 if(!empty($ds['options']['url']) && stristr($ds['options']['url'],'http://www.sugarcrm.com/crm/product/gopro')){
3609 unset($originalDashlets[$key]);
3612 $current_user->setPreference('dashlets', $originalDashlets, 0, 'Home');
3619 * convertImageToText
3621 * This method attempts to convert date type image to text on Microsoft SQL Server.
3622 * This method could NOT be used in any other type of datebases.
3624 function convertImageToText($table_name,$column_name){
3625 $set_lang = "SET LANGUAGE us_english";
3626 $GLOBALS['db']->query($set_lang);
3627 if($GLOBALS['db']->lastError()){
3628 logThis('An error occurred when performing this query-->'.$set_lang);
3630 $q="SELECT data_type
3631 FROM INFORMATION_SCHEMA.Tables T JOIN INFORMATION_SCHEMA.Columns C
3632 ON T.TABLE_NAME = C.TABLE_NAME where T.TABLE_NAME = '$table_name' and C.COLUMN_NAME = '$column_name'";
3633 $res= $GLOBALS['db']->query($q);
3634 if($GLOBALS['db']->lastError()){
3635 logThis('An error occurred when performing this query-->'.$q);
3637 $row= $GLOBALS['db']->fetchByAssoc($res);
3639 if(trim(strtolower($row['data_type'])) == 'image'){
3640 $addContent_temp = "alter table {$table_name} add {$column_name}_temp text null";
3641 $GLOBALS['db']->query($addContent_temp);
3642 if($GLOBALS['db']->lastError()){
3643 logThis('An error occurred when performing this query-->'.$addContent_temp);
3645 $qN = "select count=datalength({$column_name}), id, {$column_name} from {$table_name}";
3646 $result = $GLOBALS['db']->query($qN);
3647 while($row = $GLOBALS['db']->fetchByAssoc($result)){
3648 if($row['count'] >8000){
3649 $contentLength = $row['count'];
3652 $convertedContent = '';
3653 while($contentLength >0){
3654 $stepsQuery = "select cont=convert(varchar(max), convert(varbinary(8000), substring({$column_name},{$start},{$next}))) from {$table_name} where id= '{$row['id']}'";
3655 $steContQ = $GLOBALS['db']->query($stepsQuery);
3656 if($GLOBALS['db']->lastError()){
3657 logThis('An error occurred when performing this query-->'.$stepsQuery);
3659 $stepCont = $GLOBALS['db']->fetchByAssoc($steContQ);
3660 if(isset($stepCont['cont'])){
3661 $convertedContent = $convertedContent.$stepCont['cont'];
3663 $start = $start+$next;
3664 $contentLength = $contentLength - $next;
3666 $addContentDataText="update {$table_name} set {$column_name}_temp = '{$convertedContent}' where id= '{$row['id']}'";
3667 $GLOBALS['db']->query($addContentDataText);
3668 if($GLOBALS['db']->lastError()){
3669 logThis('An error occurred when performing this query-->'.$addContentDataText);
3673 $addContentDataText="update {$table_name} set {$column_name}_temp =
3674 convert(varchar(max), convert(varbinary(8000), {$column_name})) where id= '{$row['id']}'";
3675 $GLOBALS['db']->query($addContentDataText);
3676 if($GLOBALS['db']->lastError()){
3677 logThis('An error occurred when performing this query-->'.$addContentDataText);
3681 //drop the contents now and change contents_temp to contents
3682 $dropColumn = "alter table {$table_name} drop column {$column_name}";
3683 $GLOBALS['db']->query($dropColumn);
3684 if($GLOBALS['db']->lastError()){
3685 logThis('An error occurred when performing this query-->'.$dropColumn);
3687 $changeColumnName = "EXEC sp_rename '{$table_name}.[{$column_name}_temp]','{$column_name}','COLUMN'";
3688 $GLOBALS['db']->query($changeColumnName);
3689 if($GLOBALS['db']->lastError()){
3690 logThis('An error occurred when performing this query-->'.$changeColumnName);
3697 * This method attempts to delete all English inline help files.
3698 * This method was introduced by 5.5.0RC2.
3700 function clearHelpFiles(){
3701 $modulePath = clean_path(getcwd() . '/modules');
3702 $allHelpFiles = array();
3703 getFiles($allHelpFiles, $modulePath, "/en_us.help.*/");
3705 foreach( $allHelpFiles as $the_file ){
3706 if( is_file( $the_file ) ){
3707 unlink( $the_file );
3708 logThis("Deleted file: $the_file");
3716 * upgradeDateTimeFields
3718 * This method came from bug: 39757 where the date_end field is a date field and not a datetime field
3719 * which prevents you from performing timezone offset calculations once the data has been saved.
3721 * @param path String location to log file, empty by default
3723 function upgradeDateTimeFields($path)
3727 $meetingsSql = "UPDATE meetings SET date_end = ".$db->convert("date_start", 'add_time', array('duration_hours', 'duration_minutes'));
3728 $callsSql = "UPDATE calls SET date_end = ".$db->convert("date_start", 'add_time', array('duration_hours', 'duration_minutes'));
3729 logThis('upgradeDateTimeFields Meetings SQL:' . $meetingsSql, $path);
3730 $db->query($meetingsSql);
3732 logThis('upgradeDateTimeFields Calls SQL:' . $callsSql, $path);
3733 $db->query($callsSql);
3737 * upgradeDocumentTypeFields
3740 function upgradeDocumentTypeFields($path){
3744 $documentsSql = "UPDATE documents SET doc_type = 'Sugar' WHERE doc_type IS NULL";
3745 $meetingsSql = "UPDATE meetings SET type = 'Sugar' WHERE type IS NULL";
3747 logThis('upgradeDocumentTypeFields Documents SQL:' . $documentsSql, $path);
3748 $db->query($documentsSql);
3749 logThis('upgradeDocumentTypeFields Meetings SQL:' . $meetingsSql, $path);
3750 $db->query($meetingsSql);
3755 * merge_config_si_settings
3756 * This method checks for the presence of a config_si.php file and, if found, merges the configuration
3757 * settings from the config_si.php file into config.php. If a config_si_location parameter value is not
3758 * supplied it will attempt to discover the config_si.php file location from where the executing script
3761 * @param write_to_upgrade_log boolean optional value to write to the upgradeWizard.log file
3762 * @param config_location String optional value to config.php file location
3763 * @param config_si_location String optional value to config_si.php file location
3764 * @param path String file of the location of log file to write to
3765 * @return boolean value indicating whether or not a merge was attempted with config_si.php file
3767 function merge_config_si_settings($write_to_upgrade_log=false, $config_location='', $config_si_location='', $path='')
3769 if(!empty($config_location) && !file_exists($config_location))
3771 if($write_to_upgrade_log)
3773 logThis('config.php file specified in ' . $config_si_location . ' could not be found. Skip merging', $path);
3776 } else if(empty($config_location)) {
3778 //We are assuming this is from the silentUpgrade scripts so argv[3] will point to SugarCRM install location
3779 if(isset($argv[3]) && is_dir($argv[3]))
3781 $config_location = $argv[3] . DIRECTORY_SEPARATOR . 'config.php';
3785 //If config_location is still empty or if the file cannot be found, skip merging
3786 if(empty($config_location) || !file_exists($config_location))
3788 if($write_to_upgrade_log)
3790 logThis('config.php file at (' . $config_location . ') could not be found. Skip merging.', $path);
3794 if($write_to_upgrade_log)
3796 logThis('Loading config.php file at (' . $config_location . ') for merging.', $path);
3799 include($config_location);
3800 if(empty($sugar_config))
3802 if($write_to_upgrade_log)
3804 logThis('config.php contents are empty. Skip merging.', $path);
3810 if(!empty($config_si_location) && !file_exists($config_si_location))
3812 if($write_to_upgrade_log)
3814 logThis('config_si.php file specified in ' . $config_si_location . ' could not be found. Skip merging', $path);
3817 } else if(empty($config_si_location)) {
3818 if(isset($argv[0]) && is_file($argv[0]))
3820 $php_file = $argv[0];
3821 $p_info = pathinfo($php_file);
3822 $php_dir = (isset($p_info['dirname']) && $p_info['dirname'] != '.') ? $p_info['dirname'] . DIRECTORY_SEPARATOR : '';
3823 $config_si_location = $php_dir . 'config_si.php';
3827 //If config_si_location is still empty or if the file cannot be found, skip merging
3828 if(empty($config_si_location) || !file_exists($config_si_location))
3830 if($write_to_upgrade_log)
3832 logThis('config_si.php file at (' . $config_si_location . ') could not be found. Skip merging.', $path);
3836 if($write_to_upgrade_log)
3838 logThis('Loading config_si.php file at (' . $config_si_location . ') for merging.', $path);
3841 include($config_si_location);
3842 if(empty($sugar_config_si))
3844 if($write_to_upgrade_log)
3846 logThis('config_si.php contents are empty. Skip merging.', $path);
3852 //Now perform the merge operation
3854 foreach($sugar_config_si as $key=>$value)
3856 if(!preg_match('/^setup_/', $key) && !isset($sugar_config[$key]))
3858 if($write_to_upgrade_log)
3860 logThis('Merge key (' . $key . ') with value (' . $value . ')', $path);
3862 $sugar_config[$key] = $value;
3869 if($write_to_upgrade_log)
3871 logThis('Update config.php file with new values', $path);
3874 if(!write_array_to_file("sugar_config", $sugar_config, $config_location)) {
3875 if($write_to_upgrade_log)
3877 logThis('*** ERROR: could not write to config.php', $path);
3882 if($write_to_upgrade_log)
3884 logThis('config.php values are in sync with config_si.php values. Skipped merging.');
3889 if($write_to_upgrade_log)
3891 logThis('End merge_config_si_settings', $path);
3898 * upgrade_connectors
3900 * This function handles support for upgrading connectors it is invoked from both end.php and silentUpgrade_step2.php
3903 function upgrade_connectors() {
3904 require_once('include/connectors/utils/ConnectorUtils.php');
3905 if(!ConnectorUtils::updateMetaDataFiles()) {
3906 $GLOBALS['log']->fatal('Cannot update metadata files for connectors');
3909 //Delete the custom connectors.php file if it exists so that it may be properly rebuilt
3910 if(file_exists('custom/modules/Connectors/metadata/connectors.php'))
3912 unlink('custom/modules/Connectors/metadata/connectors.php');
3917 * Enable the InsideView connector for the four default modules.
3919 function upgradeEnableInsideViewConnector($path='')
3921 logThis('Begin upgradeEnableInsideViewConnector', $path);
3923 // Load up the existing mapping and hand it to the InsideView connector to have it setup the correct logic hooks
3924 $mapFile = 'modules/Connectors/connectors/sources/ext/rest/insideview/mapping.php';
3925 if ( file_exists('custom/'.$mapFile) ) {
3926 logThis('Found CUSTOM mappings', $path);
3927 require('custom/'.$mapFile);
3929 logThis('Used default mapping', $path);
3933 require_once('include/connectors/sources/SourceFactory.php');
3934 $source = SourceFactory::getSource('ext_rest_insideview');
3936 // $mapping is brought in from the mapping.php file above
3937 $source->saveMappingHook($mapping);
3939 require_once('include/connectors/utils/ConnectorUtils.php');
3940 ConnectorUtils::installSource('ext_rest_insideview');
3942 // Now time to set the various modules to active, because this part ignores the default config
3943 require(CONNECTOR_DISPLAY_CONFIG_FILE);
3944 // $modules_sources come from that config file
3945 foreach ( $source->allowedModuleList as $module ) {
3946 $modules_sources[$module]['ext_rest_insideview'] = 'ext_rest_insideview';
3948 if(!write_array_to_file('modules_sources', $modules_sources, CONNECTOR_DISPLAY_CONFIG_FILE)) {
3949 //Log error and return empty array
3950 logThis("Cannot write \$modules_sources to " . CONNECTOR_DISPLAY_CONFIG_FILE,$path);
3953 logThis('End upgradeEnableInsideViewConnector', $path);
3957 function repair_long_relationship_names($path='')
3959 logThis("Begin repair_long_relationship_names", $path);
3960 require_once 'modules/ModuleBuilder/parsers/relationships/DeployedRelationships.php' ;
3961 $GLOBALS['mi_remove_tables'] = false;
3963 foreach($GLOBALS['moduleList'] as $module)
3965 $relationships = new DeployedRelationships ($module) ;
3966 foreach($relationships->getRelationshipList() as $rel_name)
3968 if (strlen($rel_name) > 27 && empty($touched[$rel_name]))
3970 logThis("Rebuilding relationship fields for $rel_name", $path);
3971 $touched[$rel_name] = true;
3972 $rel_obj = $relationships->get($rel_name);
3973 $rel_obj->setReadonly(false);
3974 $relationships->delete($rel_name);
3975 $relationships->save();
3976 $relationships->add($rel_obj);
3977 $relationships->save();
3978 $relationships->build () ;
3982 logThis("End repair_long_relationship_names", $path);
3985 function removeSilentUpgradeVarsCache(){
3986 global $silent_upgrade_vars_loaded;
3988 $cacheFileDir = "{$GLOBALS['sugar_config']['cache_dir']}/silentUpgrader";
3989 $cacheFile = "{$cacheFileDir}/silentUpgradeCache.php";
3991 if(file_exists($cacheFile)){
3995 $silent_upgrade_vars_loaded = array(); // Set to empty to reset it
4000 function loadSilentUpgradeVars(){
4001 global $silent_upgrade_vars_loaded;
4003 if(empty($silent_upgrade_vars_loaded)){
4004 $cacheFile = "{$GLOBALS['sugar_config']['cache_dir']}/silentUpgrader/silentUpgradeCache.php";
4005 // We have no pre existing vars
4006 if(!file_exists($cacheFile)){
4007 // Set the vars array so it's loaded
4008 $silent_upgrade_vars_loaded = array('vars' => array());
4011 require_once($cacheFile);
4012 $silent_upgrade_vars_loaded = $silent_upgrade_vars_cache;
4019 function writeSilentUpgradeVars(){
4020 global $silent_upgrade_vars_loaded;
4022 if(empty($silent_upgrade_vars_loaded)){
4023 return false; // You should have set some values before trying to write the silent upgrade vars
4026 $cacheFileDir = "{$GLOBALS['sugar_config']['cache_dir']}/silentUpgrader";
4027 $cacheFile = "{$cacheFileDir}/silentUpgradeCache.php";
4029 require_once('include/dir_inc.php');
4030 if(!mkdir_recursive($cacheFileDir)){
4033 require_once('include/utils/file_utils.php');
4034 if(!write_array_to_file('silent_upgrade_vars_cache', $silent_upgrade_vars_loaded, $cacheFile, 'w')){
4036 logThis("WARNING: writeSilentUpgradeVars could not write to {$cacheFile}", $path);
4043 function setSilentUpgradeVar($var, $value){
4044 if(!loadSilentUpgradeVars()){
4048 global $silent_upgrade_vars_loaded;
4050 $silent_upgrade_vars_loaded['vars'][$var] = $value;
4055 function getSilentUpgradeVar($var){
4056 if(!loadSilentUpgradeVars()){
4060 global $silent_upgrade_vars_loaded;
4062 if(!isset($silent_upgrade_vars_loaded['vars'][$var])){
4066 return $silent_upgrade_vars_loaded['vars'][$var];
4072 * add_unified_search_to_custom_modules_vardefs
4074 * This method calls the repair code to remove the unified_search_modules.php fiel
4077 function add_unified_search_to_custom_modules_vardefs()
4079 if(file_exists($cachefile = sugar_cached('modules/unified_search_modules.php')))
4087 * change from using the older SugarCache in 6.1 and below to the new one in 6.2
4089 function upgradeSugarCache($file)
4091 global $sugar_config;
4092 $cacheUploadUpgradesTemp = mk_temp_dir(sugar_cached('upgrades/temp'));
4094 unzip($file, $cacheUploadUpgradesTemp);
4096 if(!file_exists(clean_path("{$cacheUploadUpgradesTemp}/manifest.php"))) {
4097 logThis("*** ERROR: no manifest file detected while bootstraping upgrade wizard files!");
4100 include(clean_path("{$cacheUploadUpgradesTemp}/manifest.php"));
4103 $from_dir = "{$cacheUploadUpgradesTemp}/{$manifest['copy_files']['from_dir']}";
4104 $allFiles = array();
4105 if(file_exists("$from_dir/include/SugarCache")) {
4106 $allFiles = findAllFiles("$from_dir/include/SugarCache", $allFiles);
4108 if(file_exists("$from_dir/include/database")) {
4109 $allFiles = findAllFiles("$from_dir/include/database", $allFiles);
4111 if(file_exists("$from_dir/include/utils/external_cache.php")) {
4112 $allFiles[] = "$from_dir/include/utils/external_cache.php";
4114 if(file_exists("$from_dir/include/utils/sugar_file_utils.php")) {
4115 $allFiles[] = "$from_dir/include/utils/sugar_file_utils.php";
4117 if(file_exists("$from_dir/include/utils/sugar_file_utils.php")) {
4118 $allFiles[] = "$from_dir/include/utils/sugar_file_utils.php";
4121 foreach($allFiles as $k => $file) {
4122 $destFile = str_replace($from_dir."/", "", $file);
4123 if(!is_dir(dirname($destFile))) {
4124 mkdir_recursive(dirname($destFile)); // make sure the directory exists
4126 if ( stristr($file,'uw_main.tpl') )
4127 logThis('Skipping "'.$file.'" - file copy will during commit step.');
4129 logThis('updating UpgradeWizard code: '.$destFile);
4130 copy_recursive($file, $destFile);
4137 * upgradeDisplayedTabsAndSubpanels
4139 * @param $version String value of current system version (pre upgrade)
4141 function upgradeDisplayedTabsAndSubpanels($version)
4143 if($version < '620')
4145 logThis('start upgrading system displayed tabs and subpanels');
4146 require_once('modules/MySettings/TabController.php');
4147 $tc = new TabController();
4149 //grab the existing system tabs
4150 $tabs = $tc->get_tabs_system();
4152 //add Calls, Meetings, Tasks, Notes, Prospects (Targets) and ProspectLists (Target Lists)
4153 //to displayed tabs unless explicitly set to hidden
4154 $modules_to_add = array('Calls', 'Meetings', 'Tasks', 'Notes', 'Prospects', 'ProspectLists');
4155 $added_tabs = array();
4157 foreach($modules_to_add as $module)
4159 $tabs[0][$module] = $module;
4160 $added_tabs[] = $module;
4163 logThis('calling set_system_tabs on TabController to add tabs: ' . var_export($added_tabs, true));
4164 $tc->set_system_tabs($tabs[0]);
4165 logThis('finish upgrading system displayed tabs and subpanels');
4171 * unlinkUpgradeFiles
4172 * This is a helper function to clean up
4174 * @param $version String value of current system version (pre upgrade)
4176 function unlinkUpgradeFiles($version)
4178 if(!isset($version))
4183 //First check if we even have the scripts_for_patch/files_to_remove directory
4184 require_once('modules/UpgradeWizard/UpgradeRemoval.php');
4187 if(empty($_SESSION['unzip_dir']))
4189 global $sugar_config;
4190 $base_upgrade_dir = $sugar_config['upload_dir'] . "/upgrades";
4191 $base_tmp_upgrade_dir = "$base_upgrade_dir/temp";
4192 $_SESSION['unzip_dir'] = mk_temp_dir( $base_tmp_upgrade_dir );
4196 if(isset($_SESSION['unzip_dir']) && file_exists($_SESSION['unzip_dir'].'/scripts/files_to_remove'))
4198 $files_to_remove = glob($_SESSION['unzip_dir'].'/scripts/files_to_remove/*.php');
4200 foreach($files_to_remove as $script)
4202 if(preg_match('/UpgradeRemoval(\d+)x\.php/', $script, $matches))
4204 $checkVersion = $matches[1] + 1; //Increment by one to check everything equal or below the target version
4205 $upgradeClass = 'UpgradeRemoval' . $matches[1] . 'x';
4206 require_once($_SESSION['unzip_dir'].'/scripts/files_to_remove/' . $upgradeClass . '.php');
4208 //Check to make sure we should load and run this UpgradeRemoval instance
4209 if($checkVersion <= $version && class_exists($upgradeClass))
4211 $upgradeInstance = new $upgradeClass();
4212 if($upgradeInstance instanceof UpgradeRemoval)
4214 logThis('Running UpgradeRemoval instance ' . $upgradeClass);
4215 logThis('Files will be backed up to custom/backup');
4216 $files = $upgradeInstance->getFilesToRemove($version);
4217 foreach($files as $file)
4221 $upgradeInstance->processFilesToRemove($files);
4228 //Check if we have a custom directory
4229 if(file_exists('custom/scripts/files_to_remove'))
4232 $files_to_remove = glob('custom/scripts/files_to_remove/*.php');
4234 foreach($files_to_remove as $script)
4236 if(preg_match('/\/files_to_remove\/(.*?)\.php$/', $script, $matches))
4238 require_once($script);
4239 $upgradeClass = $matches[1];
4241 if(!class_exists($upgradeClass))
4246 $upgradeInstance = new $upgradeClass();
4247 if($upgradeInstance instanceof UpgradeRemoval)
4249 logThis('Running Custom UpgradeRemoval instance ' . $upgradeClass);
4250 $files = $upgradeInstance->getFilesToRemove($version);
4251 foreach($files as $file)
4255 $upgradeInstance->processFilesToRemove($files);
4263 if (!function_exists("getValidDBName"))
4266 * Return a version of $proposed that can be used as a column name in any of our supported databases
4267 * 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)
4268 * @param string $name Proposed name for the column
4269 * @param string $ensureUnique
4270 * @return string Valid column name trimmed to right length and with invalid characters removed
4272 function getValidDBName ($name, $ensureUnique = false, $maxLen = 30)
4274 // first strip any invalid characters - all but alphanumerics and -
4275 $name = preg_replace ( '/[^\w-]+/i', '', $name ) ;
4276 $len = strlen ( $name ) ;
4280 $md5str = md5($name);
4281 $tail = substr ( $name, -11) ;
4282 $temp = substr($md5str , strlen($md5str)-4 );
4283 $result = substr ( $name, 0, 10) . $temp . $tail ;
4284 }else if ($len > ($maxLen - 5))
4286 $result = substr ( $name, 0, 11) . substr ( $name, 11 - $maxLen + 5);
4288 return strtolower ( $result ) ;
4295 * Get UW directories
4296 * Provides compatibility with both 6.3 and pre-6.3 setup
4298 function getUWDirs()
4300 if(!class_exists('UploadStream')) {
4301 // we're still running the old code
4302 global $sugar_config;
4303 return array($sugar_config['upload_dir'] . "/upgrades", $sugar_config['cache_dir'] . "upload/upgrades/temp");
4305 if(!in_array("upload", stream_get_wrappers())) {
4306 UploadStream::register(); // just in case file was copied, but not run
4308 return array("upload://upgrades", sugar_cached("upgrades/temp"));
4313 * Whether directory exists within list of directories to skip
4314 * @param string $dir dir to be checked
4315 * @param array $skipDirs list with skipped dirs
4318 function whetherNeedToSkipDir($dir, $skipDirs)
4320 foreach($skipDirs as $skipMe) {
4321 if(strpos( clean_path($dir), $skipMe ) !== false) {
4331 * @param silentUpgrade boolean flag indicating whether or not we should treat running the SugarSpriteBuilder as an upgrade operation
4334 function rebuildSprites($fromUpgrade=true)
4336 require_once('modules/Administration/SugarSpriteBuilder.php');
4337 $sb = new SugarSpriteBuilder();
4338 $sb->cssMinify = true;
4339 $sb->fromSilentUpgrade = $fromUpgrade;
4340 $sb->silentRun = $fromUpgrade;
4342 // add common image directories
4343 $sb->addDirectory('default', 'include/images');
4344 $sb->addDirectory('default', 'themes/default/images');
4345 $sb->addDirectory('default', 'themes/default/images/SugarLogic');
4347 // add all theme image directories
4348 if($dh = opendir('themes'))
4350 while (($dir = readdir($dh)) !== false)
4352 if ($dir != "." && $dir != ".." && $dir != 'default' && is_dir('themes/'.$dir)) {
4353 $sb->addDirectory($dir, "themes/{$dir}/images");
4359 // generate the sprite goodies
4360 // everything is saved into cache/sprites
4361 $sb->createSprites();
4366 * repairSearchFields
4368 * This method goes through the list of SearchFields files based and calls TemplateRange::repairCustomSearchFields
4369 * method on the files in an attempt to ensure the range search attributes are properly set in SearchFields.php.
4371 * @param $globString String value used for glob search defaults to searching for all SearchFields.php files in modules directory
4372 * @param $path String value used to point to log file should logging be required. Defaults to empty.
4375 function repairSearchFields($globString='modules/*/metadata/SearchFields.php', $path='')
4379 logThis('Begin repairSearchFields', $path);
4382 require_once('include/dir_inc.php');
4383 require_once('modules/DynamicFields/templates/Fields/TemplateRange.php');
4384 require('include/modules.php');
4387 $searchFieldsFiles = glob($globString);
4389 foreach($searchFieldsFiles as $file)
4391 if(preg_match('/modules\/(.*?)\/metadata\/SearchFields\.php/', $file, $matches) && isset($beanList[$matches[1]]))
4393 $module = $matches[1];
4394 $beanName = $beanList[$module];
4395 VardefManager::loadVardef($module, $beanName);
4396 if(isset($GLOBALS['dictionary'][$beanName]['fields']))
4400 logThis('Calling TemplateRange::repairCustomSearchFields for module ' . $module, $path);
4402 TemplateRange::repairCustomSearchFields($GLOBALS['dictionary'][$beanName]['fields'], $module);
4409 logThis('End repairSearchFields', $path);
4414 * repairUpgradeHistoryTable
4416 * This is a helper function used in the upgrade process to fix upgrade_history entries so that the filename column points
4417 * to the new upload directory location introduced in 6.4 versions
4419 function repairUpgradeHistoryTable()
4421 require_once('modules/Configurator/Configurator.php');
4423 global $sugar_config;
4425 //Now upgrade the upgrade_history table entries
4426 $results = $GLOBALS['db']->query('SELECT id, filename FROM upgrade_history');
4427 $upload_dir = $sugar_config['cache_dir'].'upload/';
4429 //Create regular expression string to
4430 $match = '/^' . str_replace('/', '\/', $upload_dir) . '(.*?)$/';
4432 while(($row = $GLOBALS['db']->fetchByAssoc($results)))
4434 $file = str_replace('//', '/', $row['filename']); //Strip out double-paths that may exist
4436 if(!empty($file) && preg_match($match, $file, $matches))
4438 //Update new file location to use the new $sugar_config['upload_dir'] value
4439 $new_file_location = $sugar_config['upload_dir'] . $matches[1];
4440 $GLOBALS['db']->query("UPDATE upgrade_history SET filename = '{$new_file_location}' WHERE id = '{$row['id']}'");