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))
956 include_once($langPack);
957 elseif(file_exists($langPackEn))
958 include_once($langPackEn);
964 * checks system compliance for 4.5+ codebase
965 * @return array Mixed values
967 function checkSystemCompliance() {
968 global $sugar_config;
969 global $current_language;
973 if(!defined('SUGARCRM_MIN_MEM')) {
974 define('SUGARCRM_MIN_MEM', 40);
977 $installer_mod_strings = getModuleLanguagePack($current_language, './install');
979 $ret['error_found'] = false;
982 $php_version = constant('PHP_VERSION');
983 $check_php_version_result = check_php_version($php_version);
985 switch($check_php_version_result) {
987 $ret['phpVersion'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_PHP_INVALID_VER']} {$php_version} )</span></b>";
988 $ret['error_found'] = true;
991 $ret['phpVersion'] = "<b><span class=go>{$installer_mod_strings['ERR_CHECKSYS_PHP_UNSUPPORTED']} {$php_version} )</span></b>";
994 $ret['phpVersion'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_PHP_OK']} {$php_version} )</span></b>";
998 // database and connect
1000 if($db->dbType == 'mysql')
1002 if(version_compare($v, '4.1.2') < 0) {
1003 $ret['error_found'] = true;
1004 $ret['mysqlVersion'] = "<b><span class=stop>".$mod_strings['ERR_UW_MYSQL_VERSION'].$v."</span></b>";
1006 } elseif($db->dbType == 'oci8') {
1007 if(!preg_match("/Oracle9i|Oracle Database 10g|11|^10\./i", $v)) {
1008 $ret['error_found'] = true;
1009 $ret['ociVersion'] = "<b><span class=stop>".$mod_strings['ERR_UW_OCI8_VERSION'].$v."</span></b>";
1015 if(function_exists('xml_parser_create')) {
1016 $ret['xmlStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1018 $ret['xmlStatus'] = "<b><span class=stop>{$installer_mod_strings['LBL_CHECKSYS_NOT_AVAILABLE']}</span></b>";
1019 $ret['error_found'] = true;
1023 if(function_exists('curl_init')) {
1024 $ret['curlStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1026 $ret['curlStatus'] = "<b><span class=go>{$installer_mod_strings['ERR_CHECKSYS_CURL']}</span></b>";
1027 $ret['error_found'] = false;
1031 if(function_exists('mb_strlen')) {
1032 $ret['mbstringStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1034 $ret['mbstringStatus'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_MBSTRING']}</span></b>";
1035 $ret['error_found'] = true;
1039 if(function_exists('imap_open')) {
1040 $ret['imapStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1042 $ret['imapStatus'] = "<b><span class=go>{$installer_mod_strings['ERR_CHECKSYS_IMAP']}</span></b>";
1043 $ret['error_found'] = false;
1048 if('1' == ini_get('safe_mode')) {
1049 $ret['safeModeStatus'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_SAFE_MODE']}</span></b>";
1050 $ret['error_found'] = true;
1052 $ret['safeModeStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1056 // call time pass by ref
1057 if('1' == ini_get('allow_call_time_pass_reference')) {
1058 $ret['callTimeStatus'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_CALL_TIME']}</span></b>";
1059 //continue upgrading
1061 $ret['callTimeStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1065 $ret['memory_msg'] = "";
1066 $memory_limit = "-1";//ini_get('memory_limit');
1067 $sugarMinMem = constant('SUGARCRM_MIN_MEM');
1068 // logic based on: http://us2.php.net/manual/en/ini.core.php#ini.memory-limit
1069 if( $memory_limit == "" ){ // memory_limit disabled at compile time, no memory limit
1070 $ret['memory_msg'] = "<b><span class=\"go\">{$installer_mod_strings['LBL_CHECKSYS_MEM_OK']}</span></b>";
1071 } elseif( $memory_limit == "-1" ){ // memory_limit enabled, but set to unlimited
1072 $ret['memory_msg'] = "<b><span class=\"go\">{$installer_mod_strings['LBL_CHECKSYS_MEM_UNLIMITED']}</span></b>";
1074 rtrim($memory_limit, 'M');
1075 $memory_limit_int = (int) $memory_limit;
1076 if( $memory_limit_int < constant('SUGARCRM_MIN_MEM') ){
1077 $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>";
1078 $ret['error_found'] = true;
1080 $ret['memory_msg'] = "<b><span class=\"go\">{$installer_mod_strings['LBL_CHECKSYS_OK']} ({$memory_limit})</span></b>";
1084 if (!class_exists("ZipArchive"))
1086 $ret['ZipStatus'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_ZIP']}</span></b>";
1087 $ret['error_found'] = true;
1089 $ret['ZipStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1094 /* mbstring.func_overload
1095 $ret['mbstring.func_overload'] = '';
1096 $mb = ini_get('mbstring.func_overload');
1099 $ret['mbstring.func_overload'] = "<b><span class=\"stop\">{$mod_strings['ERR_UW_MBSTRING_FUNC_OVERLOAD']}</b>";
1100 $ret['error_found'] = true;
1108 * is a file that we blow away automagically
1110 function isAutoOverwriteFile($file) {
1111 $overwriteDirs = array(
1112 './sugar_version.php',
1113 './modules/UpgradeWizard/uw_main.tpl',
1115 $file = trim('.'.str_replace(clean_path(getcwd()), '', $file));
1117 if(in_array($file, $overwriteDirs)) {
1121 $fileExtension = substr(strrchr($file, "."), 1);
1122 if($fileExtension == 'tpl' || $fileExtension == 'html') {
1132 function logThis($entry, $path='') {
1133 global $mod_strings;
1134 if(file_exists('include/utils/sugar_file_utils.php')){
1135 require_once('include/utils/sugar_file_utils.php');
1137 $log = empty($path) ? clean_path(getcwd().'/upgradeWizard.log') : clean_path($path);
1139 // create if not exists
1140 if(!file_exists($log)) {
1141 if(function_exists('sugar_fopen')){
1142 $fp = @sugar_fopen($log, 'w+'); // attempts to create file
1145 $fp = fopen($log, 'w+'); // attempts to create file
1147 if(!is_resource($fp)) {
1148 $GLOBALS['log']->fatal('UpgradeWizard could not create the upgradeWizard.log file');
1149 die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
1152 if(function_exists('sugar_fopen')){
1153 $fp = @sugar_fopen($log, 'a+'); // write pointer at end of file
1156 $fp = @fopen($log, 'a+'); // write pointer at end of file
1159 if(!is_resource($fp)) {
1160 $GLOBALS['log']->fatal('UpgradeWizard could not open/lock upgradeWizard.log file');
1161 die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
1165 $line = date('r').' [UpgradeWizard] - '.$entry."\n";
1167 if(@fwrite($fp, $line) === false) {
1168 $GLOBALS['log']->fatal('UpgradeWizard could not write to upgradeWizard.log: '.$entry);
1169 die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
1172 if(is_resource($fp)) {
1180 * @desc This function is to be used in the upgrade process to preserve changes/customaizations made to pre 5.1 quickcreate layout.
1181 * 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
1182 * was automatically picked up by the quick create. [Addresses Bug 21469]
1183 * This function will check if customizations were made, and will create quickcreatedefs.php in the /cutom/working/$module_name directory.
1185 function updateQuickCreateDefs(){
1186 $d = dir('modules');
1187 $studio_modules = array();
1189 while($e = $d->read()){ //collect all studio modules.
1190 if(substr($e, 0, 1) == '.' || !is_dir('modules/' . $e))continue;
1191 if(file_exists('modules/' . $e . '/metadata/studio.php'))
1193 array_push($studio_modules, $e);
1197 foreach( $studio_modules as $modname ){ //for each studio enabled module
1198 //Check !exists modules/$modname/metadata/quickcreatedefs.php &&
1199 //exists custom/$modname/editviewdefs.php (module was customized) &&
1200 //!exists custom/$modname/quickcreateviewdefs.php
1202 $editviewdefs = "custom/working/modules/".$modname."/metadata/editviewdefs.php";
1203 $quickcreatedefs = "custom/working/modules/".$modname."/metadata/quickcreatedefs.php";
1205 if ( !file_exists("modules/".$modname."/metadata/quickcreatedefs.php") &&
1206 file_exists($editviewdefs) &&
1207 !file_exists($quickcreatedefs) ){
1208 //clone editviewdef and save it in custom/working/modules/metadata
1209 $GLOBALS['log']->debug("Copying editviewdefs.php as quickcreatedefs.php for the $modname module in custom/working/modules/$modname/metadata!");
1210 if(copy( $editviewdefs, $quickcreatedefs)){
1211 if(file_exists($quickcreatedefs) && is_readable($quickcreatedefs)){
1212 $file = file($quickcreatedefs);
1213 //replace 'EditView' with 'QuickCreate'
1214 $fp = fopen($quickcreatedefs,'w');
1215 foreach($file as &$line){
1216 if(preg_match('/^\s*\'EditView\'\s*=>\s*$/', $line) > 0){
1217 $line = "'QuickCreate' =>\n";
1225 $GLOBALS['log']->debug("Failed to replace 'EditView' with QuickCreate because $quickcreatedefs is either not readable or does not exist.");
1228 $GLOBALS['log']->debug("Failed to copy $editviewdefs to $quickcreatedefs!");
1235 * test perms for CREATE queries
1237 function testPermsCreate($db, $out) {
1238 logThis('Checking CREATE TABLE permissions...');
1239 global $mod_strings;
1241 if(!$db->checkPrivilege("CREATE TABLE")) {
1242 logThis('cannot CREATE TABLE!');
1243 $out['db']['dbNoCreate'] = true;
1244 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_CREATE']}</span></td></tr>";
1250 * test perms for INSERT
1252 function testPermsInsert($db, $out, $skip=false) {
1253 logThis('Checking INSERT INTO permissions...');
1254 global $mod_strings;
1256 if(!$db->checkPrivilege("INSERT")) {
1257 logThis('cannot INSERT INTO!');
1258 $out['db']['dbNoInsert'] = true;
1259 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_INSERT']}</span></td></tr>";
1266 * test perms for UPDATE TABLE
1268 function testPermsUpdate($db, $out, $skip=false) {
1269 logThis('Checking UPDATE TABLE permissions...');
1270 global $mod_strings;
1271 if(!$db->checkPrivilege("UPDATE")) {
1272 logThis('cannot UPDATE TABLE!');
1273 $out['db']['dbNoUpdate'] = true;
1274 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_UPDATE']}</span></td></tr>";
1281 * test perms for SELECT
1283 function testPermsSelect($db, $out, $skip=false) {
1284 logThis('Checking SELECT permissions...');
1285 global $mod_strings;
1286 if(!$db->checkPrivilege("SELECT")) {
1287 logThis('cannot SELECT!');
1288 $out['db']['dbNoSelect'] = true;
1289 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_SELECT']}</span></td></tr>";
1295 * test perms for DELETE
1297 function testPermsDelete($db, $out, $skip=false) {
1298 logThis('Checking DELETE FROM permissions...');
1299 global $mod_strings;
1300 if(!$db->checkPrivilege("DELETE")) {
1301 logThis('cannot DELETE FROM!');
1302 $out['db']['dbNoDelete'] = true;
1303 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_DELETE']}</span></td></tr>";
1310 * test perms for ALTER TABLE ADD COLUMN
1312 function testPermsAlterTableAdd($db, $out, $skip=false) {
1313 logThis('Checking ALTER TABLE ADD COLUMN permissions...');
1314 global $mod_strings;
1315 if(!$db->checkPrivilege("ADD COLUMN")) {
1316 logThis('cannot ADD COLUMN!');
1317 $out['db']['dbNoAddColumn'] = true;
1318 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_ADD_COLUMN']}</span></td></tr>";
1324 * test perms for ALTER TABLE ADD COLUMN
1326 function testPermsAlterTableChange($db, $out, $skip=false) {
1327 logThis('Checking ALTER TABLE CHANGE COLUMN permissions...');
1328 global $mod_strings;
1329 if(!$db->checkPrivilege("CHANGE COLUMN")) {
1330 logThis('cannot CHANGE COLUMN!');
1331 $out['db']['dbNoChangeColumn'] = true;
1332 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_CHANGE_COLUMN']}</span></td></tr>";
1338 * test perms for ALTER TABLE DROP COLUMN
1340 function testPermsAlterTableDrop($db, $out, $skip=false) {
1341 logThis('Checking ALTER TABLE DROP COLUMN permissions...');
1342 global $mod_strings;
1343 if(!$db->checkPrivilege("DROP COLUMN")) {
1344 logThis('cannot DROP COLUMN!');
1345 $out['db']['dbNoDropColumn'] = true;
1346 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_DROP_COLUMN']}</span></td></tr>";
1353 * test perms for DROP TABLE
1355 function testPermsDropTable($db, $out, $skip=false) {
1356 logThis('Checking DROP TABLE permissions...');
1357 global $mod_strings;
1358 if(!$db->checkPrivilege("DROP TABLE")) {
1359 logThis('cannot DROP TABLE!');
1360 $out['db']['dbNoDropTable'] = true;
1361 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_DROP_TABLE']}</span></td></tr>";
1366 function getFormattedError($error, $query) {
1367 $error = "<div><b>".$error;
1368 $error .= "</b>::{$query}</div>";
1374 * parses a query finding the table name
1375 * @param string query The query
1376 * @return string table The table
1378 function getTableFromQuery($query) {
1379 $standardQueries = array('ALTER TABLE', 'DROP TABLE', 'CREATE TABLE', 'INSERT INTO', 'UPDATE', 'DELETE FROM');
1380 $query = preg_replace("/[^A-Za-z0-9\_\s]/", "", $query);
1381 $query = trim(str_replace($standardQueries, '', $query));
1383 $firstSpc = strpos($query, " ");
1384 $end = ($firstSpc > 0) ? $firstSpc : strlen($query);
1385 $table = substr($query, 0, $end);
1392 function preLicenseCheck() {
1393 require_once('modules/UpgradeWizard/uw_files.php');
1395 global $sugar_config;
1396 global $mod_strings;
1397 global $sugar_version;
1399 if(!isset($sugar_version) || empty($sugar_version)) {
1400 require_once('./sugar_version.php');
1403 if(!isset($_SESSION['unzip_dir']) || empty($_SESSION['unzip_dir'])) {
1404 logThis('unzipping files in upgrade archive...');
1406 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
1408 //also come up with mechanism to read from upgrade-progress file
1409 if(!isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !is_file($_SESSION['install_file'])) {
1410 if (file_exists(clean_path($base_tmp_upgrade_dir)) && $handle = opendir(clean_path($base_tmp_upgrade_dir))) {
1411 while (false !== ($file = readdir($handle))) {
1412 if($file !="." && $file !="..") {
1413 if(is_file($base_tmp_upgrade_dir."/".$file."/manifest.php")){
1414 require_once($base_tmp_upgrade_dir."/".$file."/manifest.php");
1415 $package_name= $manifest['copy_files']['from_dir'];
1416 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")){
1417 $unzip_dir = $base_tmp_upgrade_dir."/".$file;
1418 if(file_exists("$base_upgrade_dir/patch/".$package_name.'.zip')){
1419 $_SESSION['install_file'] = $package_name.".zip";
1428 if(empty($_SESSION['install_file'])){
1429 unlinkUWTempFiles();
1431 echo 'Upload File not found so redirecting to Upgrade Start ';
1432 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1433 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1434 $upgrade_directories_not_found =<<<eoq
1435 <table cellpadding="3" cellspacing="0" border="0">
1437 <th colspan="2" align="left">
1438 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1443 $uwMain = $upgrade_directories_not_found;
1446 $install_file = "$base_upgrade_dir/patch/".basename(urldecode( $_SESSION['install_file'] ));
1448 if(empty($unzip_dir)){
1449 $unzip_dir = mk_temp_dir( $base_tmp_upgrade_dir );
1451 $zip_from_dir = ".";
1453 $zip_force_copy = array();
1456 logThis('Could not create a temporary directory using mk_temp_dir( $base_tmp_upgrade_dir )');
1457 die($mod_strings['ERR_UW_NO_CREATE_TMP_DIR']);
1460 //double check whether unzipped .
1461 if(file_exists($unzip_dir ."/scripts") && file_exists($unzip_dir."/manifest.php")){
1465 unzip( $install_file, $unzip_dir );
1468 // assumption -- already validated manifest.php at time of upload
1469 require_once( "$unzip_dir/manifest.php" );
1471 if( isset( $manifest['copy_files']['from_dir'] ) && $manifest['copy_files']['from_dir'] != "" ){
1472 $zip_from_dir = $manifest['copy_files']['from_dir'];
1474 if( isset( $manifest['copy_files']['to_dir'] ) && $manifest['copy_files']['to_dir'] != "" ){
1475 $zip_to_dir = $manifest['copy_files']['to_dir'];
1477 if( isset( $manifest['copy_files']['force_copy'] ) && $manifest['copy_files']['force_copy'] != "" ){
1478 $zip_force_copy = $manifest['copy_files']['force_copy'];
1480 if( isset( $manifest['version'] ) ){
1481 $version = $manifest['version'];
1483 if( !is_writable( "config.php" ) ){
1484 return $mod_strings['ERR_UW_CONFIG'];
1487 $_SESSION['unzip_dir'] = clean_path($unzip_dir);
1488 $_SESSION['zip_from_dir'] = clean_path($zip_from_dir);
1489 logThis('unzip done.');
1491 $unzip_dir = $_SESSION['unzip_dir'];
1492 $zip_from_dir = $_SESSION['zip_from_dir'];
1495 //check if $_SESSION['unzip_dir'] and $_SESSION['zip_from_dir'] exist
1496 if(!isset($_SESSION['unzip_dir']) || !file_exists($_SESSION['unzip_dir'])
1497 || !isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !file_exists($_SESSION['install_file'])){
1499 unlinkUWTempFiles();
1501 echo 'Upload File not found so redirecting to Upgrade Start ';
1502 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1503 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1504 $upgrade_directories_not_found =<<<eoq
1505 <table cellpadding="3" cellspacing="0" border="0">
1507 <th colspan="2" align="left">
1508 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1513 $uwMain = $upgrade_directories_not_found;
1517 logThis ('is SugarConfig there '.file_exists(clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarObjects/SugarConfig.php")));
1518 if(file_exists(clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarObjects/SugarConfig.php"))) {
1519 $file = clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarObjects/SugarConfig.php");
1520 $destFile = str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), $cwd, $file);
1521 if(!is_dir(dirname($destFile))) {
1522 mkdir_recursive(dirname($destFile)); // make sure the directory exists
1524 copy($file,$destFile);
1525 //also copy include utils array utils
1526 $file = clean_path($unzip_dir.'/'.$zip_from_dir."/include/utils/array_utils.php");
1527 $destFile = str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), $cwd, $file);
1528 if(!is_dir(dirname($destFile))) {
1529 mkdir_recursive(dirname($destFile)); // make sure the directory exists
1531 copy($file,$destFile);
1536 function preflightCheck() {
1537 require_once('modules/UpgradeWizard/uw_files.php');
1539 global $sugar_config;
1540 global $mod_strings;
1541 global $sugar_version;
1543 if(!isset($sugar_version) || empty($sugar_version)) {
1544 require_once('./sugar_version.php');
1547 unset($_SESSION['rebuild_relationships']);
1548 unset($_SESSION['rebuild_extensions']);
1550 // don't bother if are rechecking
1551 $manualDiff = array();
1552 if(!isset($_SESSION['unzip_dir']) || empty($_SESSION['unzip_dir'])) {
1553 logThis('unzipping files in upgrade archive...');
1555 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
1557 //Following is if User logged out unexpectedly and then logged into UpgradeWizard again.
1558 //also come up with mechanism to read from upgrade-progress file.
1559 if(!isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !is_file($_SESSION['install_file'])) {
1560 if (file_exists($base_tmp_upgrade_dir) && $handle = opendir($base_tmp_upgrade_dir)) {
1561 while (false !== ($file = readdir($handle))) {
1562 if($file !="." && $file !="..") {
1563 if(is_file($base_tmp_upgrade_dir."/".$file."/manifest.php")){
1564 require_once($base_tmp_upgrade_dir."/".$file."/manifest.php");
1565 $package_name= $manifest['copy_files']['from_dir'];
1566 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")){
1567 $unzip_dir = $base_tmp_upgrade_dir."/".$file;
1568 if(file_exists("$base_upgrade_dir/patch/".$package_name.'.zip')){
1569 $_SESSION['install_file'] = $package_name.".zip";
1578 if(empty($_SESSION['install_file'])){
1579 unlinkUWTempFiles();
1581 echo 'Upload File not found so redirecting to Upgrade Start ';
1582 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1583 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1584 $upgrade_directories_not_found =<<<eoq
1585 <table cellpadding="3" cellspacing="0" border="0">
1587 <th colspan="2" align="left">
1588 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1593 $uwMain = $upgrade_directories_not_found;
1597 $install_file = "$base_upgrade_dir/patch/".basename(urldecode( $_SESSION['install_file'] ));
1599 if(empty($unzip_dir)){
1600 $unzip_dir = mk_temp_dir( $base_tmp_upgrade_dir );
1602 $zip_from_dir = ".";
1604 $zip_force_copy = array();
1607 logThis('Could not create a temporary directory using mk_temp_dir( $base_tmp_upgrade_dir )');
1608 die($mod_strings['ERR_UW_NO_CREATE_TMP_DIR']);
1611 //double check whether unzipped .
1612 if(file_exists($unzip_dir ."/scripts") && file_exists($unzip_dir."/manifest.php")){
1616 unzip( $install_file, $unzip_dir );
1619 // assumption -- already validated manifest.php at time of upload
1620 require_once( "$unzip_dir/manifest.php" );
1622 if( isset( $manifest['copy_files']['from_dir'] ) && $manifest['copy_files']['from_dir'] != "" ){
1623 $zip_from_dir = $manifest['copy_files']['from_dir'];
1625 if( isset( $manifest['copy_files']['to_dir'] ) && $manifest['copy_files']['to_dir'] != "" ){
1626 $zip_to_dir = $manifest['copy_files']['to_dir'];
1628 if( isset( $manifest['copy_files']['force_copy'] ) && $manifest['copy_files']['force_copy'] != "" ){
1629 $zip_force_copy = $manifest['copy_files']['force_copy'];
1631 if( isset( $manifest['version'] ) ){
1632 $version = $manifest['version'];
1634 if( !is_writable( "config.php" ) ){
1635 return $mod_strings['ERR_UW_CONFIG'];
1638 $_SESSION['unzip_dir'] = clean_path($unzip_dir);
1639 $_SESSION['zip_from_dir'] = clean_path($zip_from_dir);
1641 //logThis('unzip done.');
1643 $unzip_dir = $_SESSION['unzip_dir'];
1644 $zip_from_dir = $_SESSION['zip_from_dir'];
1646 //check if $_SESSION['unzip_dir'] and $_SESSION['zip_from_dir'] exist
1647 if(!isset($_SESSION['unzip_dir']) || !file_exists($_SESSION['unzip_dir'])
1648 || !isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !file_exists($_SESSION['install_file'])){
1650 unlinkUWTempFiles();
1652 echo 'Upload File not found so redirecting to Upgrade Start ';
1653 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1654 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1655 $upgrade_directories_not_found =<<<eoq
1656 <table cellpadding="3" cellspacing="0" border="0">
1658 <th colspan="2" align="left">
1659 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1664 $uwMain = $upgrade_directories_not_found;
1667 //copy minimum required files
1668 fileCopy('include/utils/sugar_file_utils.php');
1670 $upgradeFiles = findAllFiles(clean_path("$unzip_dir/$zip_from_dir"), array());
1671 $cache_html_files= array();
1674 $md5_string = array();
1675 if(file_exists(clean_path(getcwd().'/files.md5'))){
1676 require(clean_path(getcwd().'/files.md5'));
1679 // file preflight checks
1680 logThis('verifying md5 checksums for files...');
1681 foreach($upgradeFiles as $file) {
1682 if(in_array(str_replace(clean_path("$unzip_dir/$zip_from_dir") . "/", '', $file), $uw_files))
1683 continue; // skip already loaded files
1685 if(strpos($file, '.md5'))
1686 continue; // skip md5 file
1688 // normalize file paths
1689 $file = clean_path($file);
1691 // check that we can move/delete the upgraded file
1692 if(!is_writable($file)) {
1693 $errors[] = $mod_strings['ERR_UW_FILE_NOT_WRITABLE'].": ".$file;
1695 // check that destination files are writable
1696 $destFile = getcwd().str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), '', $file);
1698 if(is_file($destFile)) { // of course it needs to exist first...
1699 if(!is_writable($destFile)) {
1700 $errors[] = $mod_strings['ERR_UW_FILE_NOT_WRITABLE'].": ".$destFile;
1704 ///////////////////////////////////////////////////////////////////////
1706 // compare md5s and build up a manual merge list
1707 $targetFile = clean_path(".".str_replace(getcwd(),'',$destFile));
1709 if(is_file($destFile)) {
1710 if(strpos($targetFile, '.php')) {
1711 // handle PHP files that were hit with the security regex
1713 if(function_exists('sugar_fopen')){
1714 $fp = sugar_fopen($destFile, 'r');
1717 $fp = fopen($destFile, 'r');
1719 $filesize = filesize($destFile);
1721 $fileContents = stream_get_contents($fp);
1722 $targetMd5 = md5($fileContents);
1725 $targetMd5 = md5_file($destFile);
1729 if(isset($md5_string[$targetFile]) && $md5_string[$targetFile] != $targetMd5) {
1730 logThis('found a file with a differing md5: ['.$targetFile.']');
1731 $manualDiff[] = $destFile;
1734 ///////////////////////////////////////////////////////////////////////
1736 logThis('md5 verification done.');
1737 $errors['manual'] = $manualDiff;
1742 function fileCopy($file_path){
1743 if(file_exists(clean_path($_SESSION['unzip_dir'].'/'.$_SESSION['zip_from_dir'].'/'.$file_path))) {
1744 $file = clean_path($_SESSION['unzip_dir'].'/'.$_SESSION['zip_from_dir'].'/'.$file_path);
1745 $destFile = str_replace(clean_path($_SESSION['unzip_dir'].'/'.$_SESSION['zip_from_dir']), clean_path(getcwd()), $file);
1746 if(!is_dir(dirname($destFile))) {
1747 mkdir_recursive(dirname($destFile)); // make sure the directory exists
1749 copy_recursive($file,$destFile);
1752 function getChecklist($steps, $step) {
1753 global $mod_strings;
1755 $skip = array('start', 'cancel', 'uninstall','end');
1758 $ret = '<table cellpadding="3" cellspacing="4" border="0">';
1759 $ret .= '<tr><th colspan="3" align="left">'.$mod_strings['LBL_UW_CHECKLIST'].':</th></tr>';
1760 foreach($steps['desc'] as $k => $desc) {
1761 if(in_array($steps['files'][$j], $skip)) {
1766 //$status = "<span class='error'>{$mod_strings['LBL_UW_INCOMPLETE']}</span>";
1768 $desc_mod_post = '';
1770 if(isset($_SESSION['step'][$steps['files'][$k]]) && $_SESSION['step'][$steps['files'][$k]] == 'success') {
1771 //$status = $mod_strings['LBL_UW_COMPLETE'];
1775 if($k == $_REQUEST['step']) {
1776 //$status = $mod_strings['LBL_UW_IN_PROGRESS'];
1777 $desc_mod_pre = "<font color=blue><i>";
1778 $desc_mod_post = "</i></font>";
1781 $ret .= "<tr><td> </td><td><b>{$i}: {$desc_mod_pre}{$desc}{$desc_mod_post}</b></td>";
1782 $ret .= "<td id={$steps['files'][$j]}><i></i></td></tr>";
1790 function prepSystemForUpgrade() {
1791 global $sugar_config;
1792 global $sugar_flavor;
1793 global $mod_strings;
1794 global $current_language;
1796 global $base_upgrade_dir;
1797 global $base_tmp_upgrade_dir;
1798 list($p_base_upgrade_dir, $p_base_tmp_upgrade_dir) = getUWDirs();
1799 ///////////////////////////////////////////////////////////////////////////////
1800 //// Make sure variables exist
1801 if(empty($base_upgrade_dir)){
1802 $base_upgrade_dir = $p_base_upgrade_dir;
1804 if(empty($base_tmp_upgrade_dir)){
1805 $base_tmp_upgrade_dir = $p_base_tmp_upgrade_dir;
1807 sugar_mkdir($base_tmp_upgrade_dir, 0775, true);
1808 if(!isset($subdirs) || empty($subdirs)){
1809 $subdirs = array('full', 'langpack', 'module', 'patch', 'theme');
1812 $upgrade_progress_dir = $base_tmp_upgrade_dir;
1813 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
1814 if(file_exists($upgrade_progress_file)){
1815 if(function_exists('get_upgrade_progress') && function_exists('didThisStepRunBefore')){
1816 if(didThisStepRunBefore('end')){
1817 include($upgrade_progress_file);
1818 unset($upgrade_config);
1819 unlink($upgrade_progress_file);
1824 // increase the cuttoff time to 1 hour
1825 ini_set("max_execution_time", "3600");
1827 // make sure dirs exist
1828 if($subdirs != null){
1829 foreach($subdirs as $subdir) {
1830 sugar_mkdir("$base_upgrade_dir/$subdir", 0775, true);
1833 // array of special scripts that are executed during (un)installation-- key is type of script, value is filename
1834 if(!defined('SUGARCRM_PRE_INSTALL_FILE')) {
1835 define('SUGARCRM_PRE_INSTALL_FILE', 'scripts/pre_install.php');
1836 define('SUGARCRM_POST_INSTALL_FILE', 'scripts/post_install.php');
1837 define('SUGARCRM_PRE_UNINSTALL_FILE', 'scripts/pre_uninstall.php');
1838 define('SUGARCRM_POST_UNINSTALL_FILE', 'scripts/post_uninstall.php');
1841 $script_files = array(
1842 "pre-install" => constant('SUGARCRM_PRE_INSTALL_FILE'),
1843 "post-install" => constant('SUGARCRM_POST_INSTALL_FILE'),
1844 "pre-uninstall" => constant('SUGARCRM_PRE_UNINSTALL_FILE'),
1845 "post-uninstall" => constant('SUGARCRM_POST_UNINSTALL_FILE'),
1848 // check that the upload limit is set to 6M or greater
1849 define('SUGARCRM_MIN_UPLOAD_MAX_FILESIZE_BYTES', 6 * 1024 * 1024); // 6 Megabytes
1850 $upload_max_filesize = ini_get('upload_max_filesize');
1851 $upload_max_filesize_bytes = return_bytes($upload_max_filesize);
1853 if($upload_max_filesize_bytes < constant('SUGARCRM_MIN_UPLOAD_MAX_FILESIZE_BYTES')) {
1854 $GLOBALS['log']->debug("detected upload_max_filesize: $upload_max_filesize");
1855 $admin_strings = return_module_language($current_language, 'Administration');
1856 echo '<p class="error">'.$admin_strings['MSG_INCREASE_UPLOAD_MAX_FILESIZE'].' '.get_cfg_var('cfg_file_path')."</p>\n";
1860 if ( !function_exists('extractFile') ) {
1861 function extractFile($zip_file, $file_in_zip) {
1862 global $base_tmp_upgrade_dir;
1865 $absolute_base_tmp_upgrade_dir = clean_path($base_tmp_upgrade_dir);
1866 $relative_base_tmp_upgrade_dir = clean_path(str_replace(clean_path(getcwd()), '', $absolute_base_tmp_upgrade_dir));
1868 // mk_temp_dir expects relative pathing
1869 $my_zip_dir = mk_temp_dir($relative_base_tmp_upgrade_dir);
1871 unzip_file($zip_file, $file_in_zip, $my_zip_dir);
1873 return("$my_zip_dir/$file_in_zip");
1877 if ( !function_exists('extractManifest') ) {
1878 function extractManifest($zip_file) {
1879 logThis('extracting manifest.');
1880 return(extractFile($zip_file, "manifest.php"));
1884 if ( !function_exists('getInstallType') ) {
1885 function getInstallType($type_string) {
1888 $subdirs = array('full', 'langpack', 'module', 'patch', 'theme', 'temp');
1889 foreach($subdirs as $subdir) {
1890 if(preg_match("#/$subdir/#", $type_string)) {
1894 // return empty if no match
1899 function getImageForType($type) {
1901 global $mod_strings;
1906 $icon = SugarThemeRegistry::current()->getImage("Upgrade", "",null,null,'.gif',$mod_strings['LBL_UPGRADE']);
1909 $icon = SugarThemeRegistry::current()->getImage("LanguagePacks", "",null,null,'.gif',$mod_strings['LBL_LANGPACKS']);
1912 $icon = SugarThemeRegistry::current()->getImage("ModuleLoader", "",null,null,'.gif',$mod_strings['LBL_MODULELOADER']);
1915 $icon = SugarThemeRegistry::current()->getImage("PatchUpgrades", "",null,null,'.gif',$mod_strings['LBL_PATCHUPGRADES']);
1918 $icon = SugarThemeRegistry::current()->getImage("Themes", "",null,null,'.gif',$mod_strings['LBL_THEMES']);
1926 if ( !function_exists('getLanguagePackName') ) {
1927 function getLanguagePackName($the_file) {
1928 require_once("$the_file");
1929 if(isset($app_list_strings["language_pack_name"])) {
1930 return($app_list_strings["language_pack_name"]);
1936 function getUITextForType($type) {
1937 if($type == "full") {
1938 return("Full Upgrade");
1940 if($type == "langpack") {
1941 return("Language Pack");
1943 if($type == "module") {
1946 if($type == "patch") {
1949 if($type == "theme") {
1954 if ( !function_exists('validate_manifest') ) {
1956 * Verifies a manifest from a patch or module to be compatible with the current Sugar version and flavor
1957 * @param array manifest Standard manifest array
1958 * @return string Error message, blank on success
1960 function validate_manifest($manifest) {
1961 logThis('validating manifest.php file');
1962 // takes a manifest.php manifest array and validates contents
1964 global $sugar_version;
1965 global $sugar_flavor;
1966 global $mod_strings;
1968 if(!isset($manifest['type'])) {
1969 return $mod_strings['ERROR_MANIFEST_TYPE'];
1972 $type = $manifest['type'];
1974 if(getInstallType("/$type/") == "") {
1975 return $mod_strings['ERROR_PACKAGE_TYPE']. ": '" . $type . "'.";
1978 if(isset($manifest['acceptable_sugar_versions'])) {
1979 $version_ok = false;
1980 $matches_empty = true;
1981 if(isset($manifest['acceptable_sugar_versions']['exact_matches'])) {
1982 $matches_empty = false;
1983 foreach($manifest['acceptable_sugar_versions']['exact_matches'] as $match) {
1984 if($match == $sugar_version) {
1989 if(!$version_ok && isset($manifest['acceptable_sugar_versions']['regex_matches'])) {
1990 $matches_empty = false;
1991 foreach($manifest['acceptable_sugar_versions']['regex_matches'] as $match) {
1992 if(preg_match("/$match/", $sugar_version)) {
1998 if(!$matches_empty && !$version_ok) {
1999 return $mod_strings['ERROR_VERSION_INCOMPATIBLE']."<br />".
2000 $mod_strings['ERR_UW_VERSION'].$sugar_version;
2004 if(isset($manifest['acceptable_sugar_flavors']) && sizeof($manifest['acceptable_sugar_flavors']) > 0) {
2006 foreach($manifest['acceptable_sugar_flavors'] as $match) {
2007 if($match == $sugar_flavor) {
2012 return $mod_strings['ERROR_FLAVOR_INCOMPATIBLE']."<br />".
2013 $mod_strings['ERR_UW_FLAVOR'].$sugar_flavor."<br />".
2014 $mod_strings['ERR_UW_FLAVOR_2'].$manifest['acceptable_sugar_flavors'][0];
2022 function unlinkUploadFiles() {
2024 // logThis('at unlinkUploadFiles()');
2026 // if(isset($_SESSION['install_file']) && !empty($_SESSION['install_file'])) {
2027 // $upload = $_SESSION['install_file'];
2029 // if(is_file($upload)) {
2030 // logThis('unlinking ['.$upload.']');
2031 // @unlink($upload);
2037 * deletes files created by unzipping a package
2039 function unlinkUWTempFiles() {
2040 global $sugar_config;
2043 logThis('at unlinkUWTempFiles()');
2045 list($upgDir, $tempDir) = getUWDirs();
2047 if(file_exists($tempDir) && is_dir($tempDir)){
2048 $files = findAllFiles($tempDir, array(), false);
2050 foreach($files as $file) {
2051 if(!is_dir($file)) {
2052 //logThis('unlinking ['.$file.']', $path);
2057 $files = findAllFiles($tempDir, array(), true);
2058 foreach($files as $dir) {
2060 //logThis('removing dir ['.$dir.']', $path);
2064 $cacheFile = sugar_cached("modules/UpgradeWizard/_persistence.php");
2065 if(is_file($cacheFile)) {
2066 logThis("Unlinking Upgrade cache file: '_persistence.php'", $path);
2067 @unlink($cacheFile);
2070 logThis("finished!");
2074 * finds all files in the passed path, but skips select directories
2075 * @param string dir Relative path
2076 * @param array the_array Collections of found files/dirs
2077 * @param bool include_dir True if we want to include directories in the
2078 * returned collection
2080 function uwFindAllFiles($dir, $theArray, $includeDirs=false, $skipDirs=array(), $echo=false) {
2082 if (whetherNeedToSkipDir($dir, $skipDirs))
2087 if (!is_dir($dir)) { return $theArray; } // Bug # 46035, just checking for valid dir
2089 if ($d === false) { return $theArray; } // Bug # 46035, more checking
2091 while($f = $d->read()) {
2092 // bug 40793 Skip Directories array in upgradeWizard does not function correctly
2093 if($f == "." || $f == ".." || whetherNeedToSkipDir("$dir/$f", $skipDirs)) { // skip *nix self/parent
2097 // for AJAX length count
2103 if(is_dir("$dir/$f")) {
2104 if($includeDirs) { // add the directory if flagged
2105 $theArray[] = clean_path("$dir/$f");
2109 $theArray = uwFindAllFiles("$dir/$f/", $theArray, $includeDirs, $skipDirs, $echo);
2111 $theArray[] = clean_path("$dir/$f");
2124 * unset's UW's Session Vars
2126 function resetUwSession() {
2127 logThis('resetting $_SESSION');
2129 if(isset($_SESSION['committed']))
2130 unset($_SESSION['committed']);
2131 if(isset($_SESSION['sugar_version_file']))
2132 unset($_SESSION['sugar_version_file']);
2133 if(isset($_SESSION['upgrade_complete']))
2134 unset($_SESSION['upgrade_complete']);
2135 if(isset($_SESSION['allTables']))
2136 unset($_SESSION['allTables']);
2137 if(isset($_SESSION['alterCustomTableQueries']))
2138 unset($_SESSION['alterCustomTableQueries']);
2139 if(isset($_SESSION['skip_zip_upload']))
2140 unset($_SESSION['skip_zip_upload']);
2141 if(isset($_SESSION['sugar_version_file']))
2142 unset($_SESSION['sugar_version_file']);
2143 if(isset($_SESSION['install_file']))
2144 unset($_SESSION['install_file']);
2145 if(isset($_SESSION['unzip_dir']))
2146 unset($_SESSION['unzip_dir']);
2147 if(isset($_SESSION['zip_from_dir']))
2148 unset($_SESSION['zip_from_dir']);
2149 if(isset($_SESSION['overwrite_files']))
2150 unset($_SESSION['overwrite_files']);
2151 if(isset($_SESSION['schema_change']))
2152 unset($_SESSION['schema_change']);
2153 if(isset($_SESSION['uw_restore_dir']))
2154 unset($_SESSION['uw_restore_dir']);
2155 if(isset($_SESSION['step']))
2156 unset($_SESSION['step']);
2157 if(isset($_SESSION['files']))
2158 unset($_SESSION['files']);
2159 if(isset($_SESSION['Upgraded451Wizard'])){
2160 unset($_SESSION['Upgraded451Wizard']);
2162 if(isset($_SESSION['Initial_451to500_Step'])){
2163 unset($_SESSION['Initial_451to500_Step']);
2165 if(isset($_SESSION['license_shown']))
2166 unset($_SESSION['license_shown']);
2167 if(isset($_SESSION['sugarMergeRunResults']))
2168 unset($_SESSION['sugarMergeRunResults']);
2172 * runs rebuild scripts
2174 function UWrebuild() {
2178 //CCL - Comment this block out, it is called in end.php
2179 logThis('Rebuilding everything...', $path);
2180 require_once('modules/Administration/QuickRepairAndRebuild.php');
2181 $randc = new RepairAndClear();
2182 $randc->repairAndClearAll(array('clearAll'),array(translate('LBL_ALL_MODULES')), false, false);
2184 $query = "DELETE FROM versions WHERE name='Rebuild Extensions'";
2186 logThis('Registering rebuild record: '.$query, $path);
2187 logThis('Rebuild done.', $path);
2189 // insert a new database row to show the rebuild extensions is done
2190 $id = create_guid();
2191 $gmdate = gmdate('Y-m-d H:i:s');
2192 $date_entered = db_convert("'$gmdate'", 'datetime');
2193 $query = 'INSERT INTO versions (id, deleted, date_entered, date_modified, modified_user_id, created_by, name, file_version, db_version) '
2194 . "VALUES ('$id', '0', $date_entered, $date_entered, '1', '1', 'Rebuild Extensions', '4.0.0', '4.0.0')";
2196 logThis('Registering rebuild record in versions table: '.$query, $path);
2199 function getCustomTables() {
2202 return $db->tablesLike('%_cstm');
2205 function alterCustomTables($customTables)
2210 function getAllTables() {
2212 return $db->getTablesArray();
2215 function printAlterTableSql($tables)
2217 $alterTableSql = '';
2219 foreach($tables as $table)
2220 $alterTableSql .= "ALTER TABLE " . $table . " CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;" . "\n";
2222 return $alterTableSql;
2225 function executeConvertTablesSql($tables)
2229 foreach($tables as $table){
2230 $query = "ALTER TABLE " . $table . " CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci";
2232 logThis("Sending query: ".$query);
2233 $db->query($query);//, true, "An error has occured while performing db query. See log file for details.<br>");
2239 function testThis() {
2240 $files = uwFindAllFiles(getcwd().'/test', array());
2242 $out = "<table cellpadding='1' cellspacing='0' border='0'>\n";
2245 foreach($files as $file) {
2246 $relativeFile = clean_path(str_replace(getcwd().'/test', '', $file));
2247 $relativeFile = ($relativeFile{0} == '/') ? substr($relativeFile, 1, strlen($relativeFile)) : $relativeFile;
2249 $relativePath = dirname($relativeFile);
2251 if($relativePath == $priorPath) { // same dir, new file
2252 $out .= "<tr><td>".basename($relativeFile)."</td></tr>";
2253 $priorPath = $relativePath;
2267 function testThis2($dir, $id=0, $hide=false) {
2268 global $mod_strings;
2270 $dh = opendir($dir);
2273 $doHide = ($hide) ? 'none' : '';
2274 $out = "<div id='{$id}' style='display:{$doHide};'>";
2275 $out .= "<table cellpadding='1' cellspacing='0' style='border:0px solid #ccc'>\n";
2277 while($file = readdir($dh)) {
2278 if($file == '.' || $file == '..' || $file == 'CVS' || $file == '.cvsignore')
2281 if(is_dir($path.'/'.$file)) {
2282 $file = $path.'/'.$file;
2283 $newI = create_guid();
2284 $out .= "<tr><td valign='top'><a href='javascript:toggleNwFiles(\"{$newI}\");'>".SugarThemeRegistry::current()->getImage("Workflow", "", null, null, ".gif", $mod_strings['LBL_WORKFLOW'])."</a></td>\n";
2285 $out .= "<td valign='top'><b><a href='javascript:toggleNwFiles(\"{$newI}\");'>".basename($file)."</a></b></td></tr>";
2286 $out .= "<tr><td></td><td valign='top'>".testThis2($file, $newI, true)."</td></tr>";
2288 $out .= "<tr><td valign='top'> </td>\n";
2289 $out .= "<td valign='top'>".basename($file)."</td></tr>";
2293 $out .= "</tr></table>";
2304 function testThis3(&$files, $id, $hide, $previousPath = '') {
2305 if(!is_array($files) || empty($files))
2310 global $mod_strings;
2311 // expecting full path here
2312 foreach($files as $k => $file) {
2313 $file = str_replace(getcwd(), '', $file);
2314 $path = dirname($file);
2315 $fileName = basename($file);
2317 if($fileName == 'CVS' || $fileName == '.cvsignore')
2320 if($path == $previousPath) { // same directory
2321 // new row for each file
2322 $out .= "<tr><td valign='top' align='left'> </td>";
2323 $out .= "<td valign='top' align='left'>{$fileName}</td></tr>";
2324 } else { // new directory
2326 $out .= "<tr><td valign='top'><a href='javascript:toggleNwFiles(\"{$newI}\");'>".SugarThemeRegistry::current()->getImage("Workflow", "", null, null, ".gif", $mod_strings['LBL_WORKFLOW'])."</a></td>\n";
2327 $out .= "<td valign='top'><b><a href='javascript:toggleNwFiles(\"{$newI}\");'>".$fileName."</a></b></td></tr>";
2328 $recurse = testThis3($files, $newI, true, $previousPath);
2329 $out .= "<tr><td></td><td valign='top'>".$recurse."</td></tr>";
2332 $previousPath = $path;
2334 $display = ($hide) ? 'none' : '';
2336 <div id="{$id}" style="display:{$display}">
2337 <table cellpadding='1' cellspacing='0' border='0' style='border:1px solid #ccc'>
2346 function testThis4($filePath, $fileNodes=array(), $fileName='') {
2347 $path = dirname($filePath);
2348 $file = basename($filePath);
2350 $exFile = explode('/', $path);
2352 foreach($exFile as $pathSegment) {
2353 if(is_array($fileNodes[$pathSegment])) { // path already processed
2355 } else { // newly found path
2356 $fileNodes[$pathSegment] = array();
2359 if($fileName != '') {
2360 $fileNodes[$pathSegment][] = $fileName;
2369 ///////////////////////////////////////////////////////////////////////////////
2370 //// SYSTEM CHECK FUNCTIONS
2372 * generates an array with all files in the SugarCRM root directory, skipping
2374 * @return array files Array of files with absolute paths
2376 function getFilesForPermsCheck() {
2377 global $sugar_config;
2379 logThis('Got JSON call to find all files...');
2380 $filesNotWritable = array();
2381 $filesNWPerms = array();
2383 // add directories here that should be skipped when doing file permissions checks (cache/upload is the nasty one)
2385 $sugar_config['upload_dir'],
2387 $files = uwFindAllFiles(".", array(), true, $skipDirs, true);
2392 * checks files for permissions
2393 * @param array files Array of files with absolute paths
2394 * @return string result of check
2396 function checkFiles($files, $echo=false) {
2397 global $mod_strings;
2398 $filesNotWritable = array();
2401 <a href='javascript:void(0); toggleNwFiles(\"filesNw\");'>{$mod_strings['LBL_UW_SHOW_NW_FILES']}</a>
2402 <div id='filesNw' style='display:none;'>
2403 <table cellpadding='3' cellspacing='0' border='0'>
2405 <th align='left'>{$mod_strings['LBL_UW_FILE']}</th>
2406 <th align='left'>{$mod_strings['LBL_UW_FILE_PERMS']}</th>
2407 <th align='left'>{$mod_strings['LBL_UW_FILE_OWNER']}</th>
2408 <th align='left'>{$mod_strings['LBL_UW_FILE_GROUP']}</th>
2411 $isWindows = is_windows();
2412 foreach($files as $file) {
2415 if(!is_writable_windows($file)) {
2416 logThis('WINDOWS: File ['.$file.'] not readable - saving for display');
2417 // don't warn yet - we're going to use this to check against replacement files
2418 // aw: commented out; it's a hack to allow upgrade wizard to continue on windows... will fix later
2419 /*$filesNotWritable[$i] = $file;
2420 $filesNWPerms[$i] = substr(sprintf('%o',fileperms($file)), -4);
2421 $filesOut .= "<tr>".
2422 "<td><span class='error'>{$file}</span></td>".
2423 "<td>{$filesNWPerms[$i]}</td>".
2424 "<td>".$mod_strings['ERR_UW_CANNOT_DETERMINE_USER']."</td>".
2425 "<td>".$mod_strings['ERR_UW_CANNOT_DETERMINE_GROUP']."</td>".
2429 if(!is_writable($file)) {
2430 logThis('File ['.$file.'] not writable - saving for display');
2431 // don't warn yet - we're going to use this to check against replacement files
2432 $filesNotWritable[$i] = $file;
2433 $filesNWPerms[$i] = substr(sprintf('%o',fileperms($file)), -4);
2434 $owner = posix_getpwuid(fileowner($file));
2435 $group = posix_getgrgid(filegroup($file));
2436 $filesOut .= "<tr>".
2437 "<td><span class='error'>{$file}</span></td>".
2438 "<td>{$filesNWPerms[$i]}</td>".
2439 "<td>".$owner['name']."</td>".
2440 "<td>".$group['name']."</td>".
2447 $filesOut .= '</table></div>';
2449 $errors['files']['filesNotWritable'] = (count($filesNotWritable) > 0) ? true : false;
2450 if(count($filesNotWritable) < 1) {
2451 $filesOut = "{$mod_strings['LBL_UW_FILE_NO_ERRORS']}";
2457 function deletePackageOnCancel(){
2458 global $mod_strings;
2459 global $sugar_config;
2460 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
2461 logThis('running delete');
2462 if(!isset($_SESSION['install_file']) || ($_SESSION['install_file'] == "")) {
2463 logThis('ERROR: trying to delete non-existent file: ['.$_REQUEST['install_file'].']');
2464 $error = $mod_strings['ERR_UW_NO_FILE_UPLOADED'];
2466 // delete file in upgrades/patch
2467 $delete_me = "$base_upgrade_dir/patch/".basename(urldecode( $_REQUEST['install_file'] ));
2468 if(@unlink($delete_me)) {
2469 //logThis('unlinking: '.$delete_me);
2470 $out = basename($delete_me).$mod_strings['LBL_UW_FILE_DELETED'];
2472 logThis('ERROR: could not delete ['.$delete_me.']');
2473 $error = $mod_strings['ERR_UW_FILE_NOT_DELETED'].$delete_me;
2476 if(!empty($error)) {
2477 $out = "<b><span class='error'>{$error}</span></b><br />";
2481 function handleExecuteSqlKeys($db, $tableName, $disable)
2483 if(empty($tableName)) return true;
2484 if(is_callable(array($db, "supports"))) {
2486 return $disable?$db->disableKeys($tableName):$db->enableKeys($tableName);
2489 $op = $disable?"DISABLE":"ENABLE";
2490 return $db->query("ALTER TABLE $tableName $op KEYS");
2494 function parseAndExecuteSqlFile($sqlScript,$forStepQuery='',$resumeFromQuery='')
2496 global $sugar_config;
2497 $alterTableSchema = '';
2498 $sqlErrors = array();
2499 if(!isset($_SESSION['sqlSkippedQueries'])){
2500 $_SESSION['sqlSkippedQueries'] = array();
2502 $db = DBManagerFactory::getInstance();
2503 $disable_keys = ($db->dbType == "mysql"); // have to use old way for now for upgrades
2504 if(strpos($resumeFromQuery,",") != false){
2505 $resumeFromQuery = explode(",",$resumeFromQuery);
2507 if(file_exists($sqlScript)) {
2508 $fp = fopen($sqlScript, 'r');
2509 $contents = stream_get_contents($fp);
2510 $anyScriptChanges =$contents;
2511 $resumeAfterFound = false;
2515 while($line = fgets($fp)) {
2516 if(strpos($line, '--') === false) {
2517 $completeLine .= " ".trim($line);
2518 if(strpos($line, ';') !== false) {
2520 $query = str_replace(';','',$completeLine);
2521 //if resume from query is not null then find out from where
2522 //it should start executing the query.
2524 if($query != null && $resumeFromQuery != null){
2525 if(!$resumeAfterFound){
2526 if(strpos($query,",") != false){
2527 $queArray = explode(",",$query);
2528 for($i=0;$i<sizeof($resumeFromQuery);$i++){
2529 if(strcasecmp(trim($resumeFromQuery[$i]),trim($queArray[$i]))==0){
2530 $resumeAfterFound = true;
2532 $resumeAfterFound = false;
2538 elseif(strcasecmp(trim($resumeFromQuery),trim($query))==0){
2539 $resumeAfterFound = true;
2542 if($resumeAfterFound){
2545 // if $count=1 means it is just found so skip the query. Run the next one
2546 if($query != null && $resumeAfterFound && $count >1){
2547 $tableName = getAlterTable($query);
2550 handleExecuteSqlKeys($db, $tableName, true);
2553 if($db->checkError()){
2554 //put in the array to use later on
2555 $_SESSION['sqlSkippedQueries'][] = $query;
2559 handleExecuteSqlKeys($db, $tableName, false);
2561 $progQuery[$forStepQuery]=$query;
2562 post_install_progress($progQuery,$action='set');
2565 elseif($query != null){
2566 $tableName = getAlterTable($query);
2569 handleExecuteSqlKeys($db, $tableName, true);
2574 handleExecuteSqlKeys($db, $tableName, false);
2576 $progQuery[$forStepQuery]=$query;
2577 post_install_progress($progQuery,$action='set');
2578 if($db->checkError()){
2579 //put in the array to use later on
2580 $_SESSION['sqlSkippedQueries'][] = $query;
2592 function getAlterTable($query){
2593 $query = strtolower($query);
2594 if (preg_match('/^\s*alter\s+table\s+/', $query)) {
2595 $sqlArray = explode(" ", $query);
2596 $key = array_search('table', $sqlArray);
2597 return $sqlArray[($key+1)];
2603 function set_upgrade_vars(){
2604 logThis('setting session variables...');
2605 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2606 if(!is_dir($upgrade_progress_dir)){
2607 mkdir_recursive($upgrade_progress_dir);
2609 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2610 if(file_exists($upgrade_progress_file)){
2611 include($upgrade_progress_file);
2614 fopen($upgrade_progress_file, 'w+');
2616 if(!isset($upgrade_config) || $upgrade_config == null){
2617 $upgrade_config = array();
2618 $upgrade_config[1]['upgrade_vars']=array();
2620 if(isset($upgrade_config[1]) && isset($upgrade_config[1]['upgrade_vars']) && !is_array($upgrade_config[1]['upgrade_vars'])){
2621 $upgrade_config[1]['upgrade_vars'] = array();
2624 if(!isset($upgrade_vars) || $upgrade_vars == NULL){
2625 $upgrade_vars = array();
2627 if(isset($_SESSION['unzip_dir']) && !empty($_SESSION['unzip_dir']) && file_exists($_SESSION['unzip_dir'])){
2628 $upgrade_vars['unzip_dir']=$_SESSION['unzip_dir'];
2630 if(isset($_SESSION['install_file']) && !empty($_SESSION['install_file']) && file_exists($_SESSION['install_file'])){
2631 $upgrade_vars['install_file']=$_SESSION['install_file'];
2633 if(isset($_SESSION['Upgraded451Wizard']) && !empty($_SESSION['Upgraded451Wizard'])){
2634 $upgrade_vars['Upgraded451Wizard']=$_SESSION['Upgraded451Wizard'];
2636 if(isset($_SESSION['license_shown']) && !empty($_SESSION['license_shown'])){
2637 $upgrade_vars['license_shown']=$_SESSION['license_shown'];
2639 if(isset($_SESSION['Initial_451to500_Step']) && !empty($_SESSION['Initial_451to500_Step'])){
2640 $upgrade_vars['Initial_451to500_Step']=$_SESSION['Initial_451to500_Step'];
2642 if(isset($_SESSION['zip_from_dir']) && !empty($_SESSION['zip_from_dir'])){
2643 $upgrade_vars['zip_from_dir']=$_SESSION['zip_from_dir'];
2645 //place into the upgrade_config array and rewrite config array only if new values are being inserted
2646 if(isset($upgrade_vars) && $upgrade_vars != null && sizeof($upgrade_vars) > 0){
2647 foreach($upgrade_vars as $key=>$val){
2648 if($key != null && $val != null){
2649 $upgrade_config[1]['upgrade_vars'][$key]=$upgrade_vars[$key];
2652 ksort($upgrade_config);
2653 if(is_writable($upgrade_progress_file) && write_array_to_file( "upgrade_config", $upgrade_config,
2654 $upgrade_progress_file)) {
2655 //writing to the file
2660 function initialize_session_vars(){
2661 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2662 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2663 if(file_exists($upgrade_progress_file)){
2664 include($upgrade_progress_file);
2665 if(isset($upgrade_config) && $upgrade_config != null && is_array($upgrade_config) && sizeof($upgrade_config) >0){
2666 $currVarsArray=$upgrade_config[1]['upgrade_vars'];
2667 //print_r($currVarsArray);
2668 if(isset($currVarsArray) && $currVarsArray != null && is_array($currVarsArray) && sizeof($currVarsArray)>0){
2669 foreach($currVarsArray as $key=>$val){
2670 if($key != null && $val !=null){
2671 //set session variables
2672 $_SESSION[$key]=$val;
2681 //track the upgrade progress on each step
2682 //track the upgrade progress on each step
2683 function set_upgrade_progress($currStep,$currState,$currStepSub='',$currStepSubState=''){
2685 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2686 if(!is_dir($upgrade_progress_dir)){
2687 mkdir_recursive($upgrade_progress_dir);
2689 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2690 if(file_exists($upgrade_progress_file)){
2691 include($upgrade_progress_file);
2694 if(function_exists('sugar_fopen')){
2695 sugar_fopen($upgrade_progress_file, 'w+');
2698 fopen($upgrade_progress_file, 'w+');
2701 if(!isset($upgrade_config) || $upgrade_config == null){
2702 $upgrade_config = array();
2703 $upgrade_config[1]['upgrade_vars']=array();
2705 if(!is_array($upgrade_config[1]['upgrade_vars'])){
2706 $upgrade_config[1]['upgrade_vars'] = array();
2708 if($currStep != null && $currState != null){
2709 if(sizeof($upgrade_config) > 0){
2710 if($currStepSub != null && $currStepSubState !=null){
2711 //check if new status to be set or update
2712 //get the latest in array. since it has sub components prepare an array
2713 if(!empty($upgrade_config[sizeof($upgrade_config)][$currStep]) && is_array($upgrade_config[sizeof($upgrade_config)][$currStep])){
2714 $latestStepSub = currSubStep($upgrade_config[sizeof($upgrade_config)][$currStep]);
2715 if($latestStepSub == $currStepSub){
2716 $upgrade_config[sizeof($upgrade_config)][$currStep][$latestStepSub]=$currStepSubState;
2717 $upgrade_config[sizeof($upgrade_config)][$currStep][$currStep] = $currState;
2720 $upgrade_config[sizeof($upgrade_config)][$currStep][$currStepSub]=$currStepSubState;
2721 $upgrade_config[sizeof($upgrade_config)][$currStep][$currStep] = $currState;
2725 $currArray = array();
2726 $currArray[$currStep] = $currState;
2727 $currArray[$currStepSub] = $currStepSubState;
2728 $upgrade_config[sizeof($upgrade_config)+1][$currStep] = $currArray;
2732 //get the current upgrade progress
2733 $latestStep = get_upgrade_progress();
2734 //set the upgrade progress
2735 if($latestStep == $currStep){
2736 //update the current step with new progress status
2737 $upgrade_config[sizeof($upgrade_config)][$latestStep]=$currState;
2741 $upgrade_config[sizeof($upgrade_config)+1][$currStep]=$currState;
2743 // now check if there elements within array substeps
2747 //set the upgrade progress (just starting)
2748 $upgrade_config[sizeof($upgrade_config)+1][$currStep]= $currState;
2751 if(is_writable($upgrade_progress_file) && write_array_to_file( "upgrade_config", $upgrade_config,
2752 $upgrade_progress_file)) {
2753 //writing to the file
2759 function get_upgrade_progress(){
2760 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2761 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2764 if(file_exists($upgrade_progress_file)){
2765 include($upgrade_progress_file);
2766 if(!isset($upgrade_config) || $upgrade_config == null){
2767 $upgrade_config = array();
2769 if($upgrade_config != null && sizeof($upgrade_config) >1){
2770 $currArr = $upgrade_config[sizeof($upgrade_config)];
2771 if(is_array($currArr)){
2772 foreach($currArr as $key=>$val){
2780 function currSubStep($currStep){
2782 if(is_array($currStep)){
2783 foreach($currStep as $key=>$val){
2791 function currUpgradeState($currState){
2793 if(is_array($currState)){
2794 foreach($currState as $key=>$val){
2796 foreach($val as $k=>$v){
2810 function didThisStepRunBefore($step,$SubStep=''){
2811 if($step == null) return;
2812 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2813 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2816 if(file_exists($upgrade_progress_file)){
2817 include($upgrade_progress_file);
2818 if(isset($upgrade_config) && $upgrade_config != null && is_array($upgrade_config) && sizeof($upgrade_config) >0){
2819 for($i=1;$i<=sizeof($upgrade_config);$i++){
2820 if(is_array($upgrade_config[$i])){
2821 foreach($upgrade_config[$i] as $key=>$val){
2823 if(is_array($upgrade_config[$i][$step])){
2825 foreach ($upgrade_config[$i][$step] as $k=>$v){
2827 foreach($v as $k1=>$v1){
2828 if($SubStep != null){
2829 if($SubStep ==$k1 && $v1=='done'){
2836 elseif($SubStep !=null){
2837 if($SubStep==$k && $v=='done'){
2842 elseif($step==$k && $v=='done'){
2848 elseif($val=='done'){
2862 //get and set post install status
2863 function post_install_progress($progArray='',$action=''){
2864 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2865 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2866 if($action=='' || $action=='get'){
2867 //get the state of post install
2868 $currProg = array();
2869 if(file_exists($upgrade_progress_file)){
2870 include($upgrade_progress_file);
2871 if(is_array($upgrade_config[sizeof($upgrade_config)]['commit']['post_install']) && sizeof($upgrade_config[sizeof($upgrade_config)]['commit']['post_install'])>0){
2872 foreach($upgrade_config[sizeof($upgrade_config)]['commit']['post_install'] as $k=>$v){
2879 elseif($action=='set'){
2880 if(!is_dir($upgrade_progress_dir)){
2881 mkdir($upgrade_progress_dir);
2883 if(file_exists($upgrade_progress_file)){
2884 include($upgrade_progress_file);
2887 fopen($upgrade_progress_file, 'w+');
2889 if(!is_array($upgrade_config[sizeof($upgrade_config)]['commit']['post_install'])){
2890 $upgrade_config[sizeof($upgrade_config)]['commit']['post_install']=array();
2891 $upgrade_config[sizeof($upgrade_config)]['commit']['post_install']['post_install'] = 'in_progress';
2893 if($progArray != null && is_array($progArray)){
2894 foreach($progArray as $key=>$val){
2895 $upgrade_config[sizeof($upgrade_config)]['commit']['post_install'][$key]=$val;
2898 if(is_writable($upgrade_progress_file) && write_array_to_file( "upgrade_config", $upgrade_config,
2899 $upgrade_progress_file)) {
2900 //writing to the file
2905 function repairDBForUpgrade($execute=false,$path=''){
2907 global $current_user, $beanFiles;
2909 set_time_limit(3600);
2911 $db = &DBManagerFactory::getInstance();
2913 VardefManager::clearVardef();
2914 require_once('include/ListView/ListView.php');
2915 foreach ($beanFiles as $bean => $file) {
2916 require_once ($file);
2917 $focus = new $bean ();
2918 $sql .= $db->repairTable($focus, $execute);
2922 $olddictionary = $dictionary;
2923 unset ($dictionary);
2924 include ('modules/TableDictionary.php');
2925 foreach ($dictionary as $meta) {
2926 $tablename = $meta['table'];
2927 $fielddefs = $meta['fields'];
2928 $indices = $meta['indices'];
2929 $sql .= $db->repairTableParams($tablename, $fielddefs, $indices, $execute);
2932 foreach (explode("\n", $sql) as $line) {
2933 if (!empty ($line) && substr($line, -2) != "*/") {
2936 $qry_str .= $line . "\n";
2947 preg_replace('#(/\*.+?\*/\n*)#', '', $qry_str)
2949 logThis("*******START EXECUTING DB UPGRADE QUERIES***************",$path);
2950 logThis($sql,$path);
2951 logThis("*******END EXECUTING DB UPGRADE QUERIES****************",$path);
2960 * upgradeUserPreferences
2961 * This method updates the user_preferences table and sets the pages/dashlets for users
2962 * which have ACL access to Trackers so that the Tracker dashlets are set in their user perferences
2965 function upgradeUserPreferences() {
2966 global $sugar_config, $sugar_version;
2967 $uw_strings = return_module_language($GLOBALS['current_language'], 'UpgradeWizard');
2969 $localization = new Localization();
2970 $localeCoreDefaults = $localization->getLocaleConfigDefaults();
2972 // check the current system wide default_locale_name_format and add it to the list if it's not there
2973 if(empty($sugar_config['name_formats'])) {
2974 $sugar_config['name_formats'] = $localeCoreDefaults['name_formats'];
2975 if(!rebuildConfigFile($sugar_config, $sugar_version)) {
2976 $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
2980 $currentDefaultLocaleNameFormat = $sugar_config['default_locale_name_format'];
2982 if ($localization->isAllowedNameFormat($currentDefaultLocaleNameFormat)) {
2983 upgradeLocaleNameFormat($currentDefaultLocaleNameFormat);
2985 $sugar_config['default_locale_name_format'] = $localeCoreDefaults['default_locale_name_format'];
2986 if(!rebuildConfigFile($sugar_config, $sugar_version)) {
2987 $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
2989 $localization->createInvalidLocaleNameFormatUpgradeNotice();
2992 $db = &DBManagerFactory::getInstance();
2993 $result = $db->query("SELECT id FROM users where deleted = '0'");
2994 while($row = $db->fetchByAssoc($result))
2996 $current_user = new User();
2997 $current_user->retrieve($row['id']);
2999 // 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
3000 $currentUserNameFormat = $current_user->getPreference('default_locale_name_format');
3001 if ($localization->isAllowedNameFormat($currentUserNameFormat)) {
3002 upgradeLocaleNameFormat($currentUserNameFormat);
3004 $current_user->setPreference('default_locale_name_format', 's f l', 0, 'global');
3005 $current_user->savePreferencesToDB();
3013 * Checks if a locale name format is part of the default list, if not adds it to the config
3014 * @param $name_format string a local name format string such as 's f l'
3015 * @return bool true on successful write to config file, false on failure;
3017 function upgradeLocaleNameFormat($name_format) {
3018 global $sugar_config, $sugar_version;
3020 $localization = new Localization();
3021 $localeConfigDefaults = $localization->getLocaleConfigDefaults();
3023 $uw_strings = return_module_language($GLOBALS['current_language'], 'UpgradeWizard');
3024 if(empty($sugar_config['name_formats'])) {
3025 $sugar_config['name_formats'] = $localeConfigDefaults['name_formats'];
3026 if(!rebuildConfigFile($sugar_config, $sugar_version)) {
3027 $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
3030 if (!in_array($name_format, $sugar_config['name_formats'])) {
3031 $new_config = sugarArrayMerge($sugar_config['name_formats'], array($name_format=>$name_format));
3032 $sugar_config['name_formats'] = $new_config;
3033 if(!rebuildConfigFile($sugar_config, $sugar_version)) {
3034 $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
3043 function add_custom_modules_favorites_search(){
3044 $module_directories = scandir('modules');
3046 foreach($module_directories as $module_dir){
3047 if($module_dir == '.' || $module_dir == '..' || !is_dir("modules/{$module_dir}")){
3052 preg_match('/^[a-z0-9]{1,5}_[a-z0-9_]+$/i' , $module_dir, $matches);
3054 // Make sure the module was created by module builder
3055 if(empty($matches)){
3059 $full_module_dir = "modules/{$module_dir}/";
3060 $read_searchdefs_from = "{$full_module_dir}/metadata/searchdefs.php";
3061 $read_SearchFields_from = "{$full_module_dir}/metadata/SearchFields.php";
3062 $read_custom_SearchFields_from = "custom/{$full_module_dir}/metadata/SearchFields.php";
3064 // Studio can possibly override this file, so we check for a custom version of it
3065 if(file_exists("custom/{$full_module_dir}/metadata/searchdefs.php")){
3066 $read_searchdefs_from = "custom/{$full_module_dir}/metadata/searchdefs.php";
3069 if(file_exists($read_searchdefs_from) && file_exists($read_SearchFields_from)){
3072 require($read_searchdefs_from);
3073 foreach($searchdefs[$module_dir]['layout']['basic_search'] as $sf_array){
3074 if(isset($sf_array['name']) && $sf_array['name'] == 'favorites_only'){
3079 require($read_SearchFields_from);
3080 if(isset($searchFields[$module_dir]['favorites_only'])){
3084 if(!$found_sf1 && !$found_sf2){
3085 $searchdefs[$module_dir]['layout']['basic_search']['favorites_only'] = array('name' => 'favorites_only','label' => 'LBL_FAVORITES_FILTER','type' => 'bool',);
3086 $searchdefs[$module_dir]['layout']['advanced_search']['favorites_only'] = array('name' => 'favorites_only','label' => 'LBL_FAVORITES_FILTER','type' => 'bool',);
3087 $searchFields[$module_dir]['favorites_only'] = array(
3088 'query_type'=>'format',
3089 'operator' => 'subquery',
3090 'subquery' => 'SELECT sugarfavorites.record_id FROM sugarfavorites
3091 WHERE sugarfavorites.deleted=0
3092 and sugarfavorites.module = \''.$module_dir.'\'
3093 and sugarfavorites.assigned_user_id = \'{0}\'',
3094 'db_field'=>array('id')
3097 if(!is_dir("custom/{$full_module_dir}/metadata")){
3098 mkdir_recursive("custom/{$full_module_dir}/metadata");
3100 $success_sf1 = write_array_to_file('searchdefs', $searchdefs, "custom/{$full_module_dir}/metadata/searchdefs.php");
3101 $success_sf2 = write_array_to_file('searchFields', $searchFields, "{$full_module_dir}/metadata/SearchFields.php");
3104 logThis("add_custom_modules_favorites_search failed for searchdefs.php for {$module_dir}");
3107 logThis("add_custom_modules_favorites_search failed for SearchFields.php for {$module_dir}");
3109 if($success_sf1 && $success_sf2){
3110 logThis("add_custom_modules_favorites_search successfully updated searchdefs and searchFields for {$module_dir}");
3119 * upgradeModulesForTeamsets
3121 * This method adds the team_set_id values to the module tables that have the new team_set_id column
3122 * added through the SugarCRM 5.5.x upgrade process. It also adds the values into the team_sets and
3123 * team_sets_teams tables.
3125 * @param filter Array of modules to process; empty by default
3127 function upgradeModulesForTeamsets($filter=array()) {
3128 require('include/modules.php');
3129 foreach($beanList as $moduleName=>$beanName) {
3130 if(!empty($filter) && array_search($moduleName, $filter) === false) {
3133 if($moduleName == 'TeamMemberships' || $moduleName == 'ForecastOpportunities'){
3136 $bean = loadBean($moduleName);
3138 empty($bean->table_name)) {
3142 $FieldArray = $GLOBALS['db']->helper->get_columns($bean->table_name);
3143 if(!isset($FieldArray['team_id'])) {
3147 upgradeTeamColumn($bean, 'team_id');
3151 //Upgrade users table
3152 $bean = loadBean('Users');
3153 upgradeTeamColumn($bean, 'default_team');
3154 $result = $GLOBALS['db']->query("SELECT id FROM teams where deleted=0");
3155 while($row = $GLOBALS['db']->fetchByAssoc($result)) {
3156 $teamset = new TeamSet();
3157 $teamset->addTeams($row['id']);
3164 * Helper function to create a team_set_id column and also set team_set_id column
3165 * to have the value of the $column_name parameter
3167 * @param $bean SugarBean which we are adding team_set_id column to
3168 * @param $column_name The name of the column containing the default team_set_id value
3170 function upgradeTeamColumn($bean, $column_name) {
3171 //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
3172 //module that does not use the SugarObjects
3173 if(empty($bean->field_defs['team_set_id']) && $bean->module_dir != 'Trackers'){
3175 //at this point we could assume that since we have a team_id defined and not a team_set_id that we need to
3176 //add that field and the corresponding relationships
3177 $object = $bean->object_name;
3178 $module = $bean->module_dir;
3179 $object_name = $object;
3180 $_object_name = strtolower($object_name);
3182 if(!empty($GLOBALS['dictionary'][$object]['table'])){
3183 $table_name = $GLOBALS['dictionary'][$object]['table'];
3185 $table_name = strtolower($module);
3188 $path = 'include/SugarObjects/implements/team_security/vardefs.php';
3190 //go through each entry in the vardefs from team_security and unset anything that is already set in the core module
3191 //this will ensure we have the proper ordering.
3192 $fieldDiff = array_diff_assoc($vardefs['fields'], $GLOBALS['dictionary'][$bean->object_name]['fields']);
3194 $file = 'custom/Extension/modules/' . $bean->module_dir. '/Ext/Vardefs/teams.php';
3195 $contents = "<?php\n";
3196 if(!empty($fieldDiff)){
3197 foreach($fieldDiff as $key => $val){
3198 $contents .= "\n\$GLOBALS['dictionary']['". $object . "']['fields']['". $key . "']=" . var_export_helper($val) . ";";
3201 $relationshipDiff = array_diff_assoc($vardefs['relationships'], $GLOBALS['dictionary'][$bean->object_name]['relationships']);
3202 if(!empty($relationshipDiff)){
3203 foreach($relationshipDiff as $key => $val){
3204 $contents .= "\n\$GLOBALS['dictionary']['". $object . "']['relationships']['". $key . "']=" . var_export_helper($val) . ";";
3207 $indexDiff = array_diff_assoc($vardefs['indices'], $GLOBALS['dictionary'][$bean->object_name]['indices']);
3208 if(!empty($indexDiff)){
3209 foreach($indexDiff as $key => $val){
3210 $contents .= "\n\$GLOBALS['dictionary']['". $object . "']['indices']['". $key . "']=" . var_export_helper($val) . ";";
3213 if( $fh = @sugar_fopen( $file, 'wt' ) )
3215 fputs( $fh, $contents);
3220 //we have written out the teams.php into custom/Extension/modules/{$module_dir}/Ext/Vardefs/teams.php'
3221 //now let's merge back into vardefs.ext.php
3222 require_once('ModuleInstall/ModuleInstaller.php');
3223 $mi = new ModuleInstaller();
3224 $mi->merge_files('Ext/Vardefs/', 'vardefs.ext.php');
3225 VardefManager::loadVardef($bean->module_dir, $bean->object_name, true);
3226 $bean->field_defs = $GLOBALS['dictionary'][$bean->object_name]['fields'];
3229 if(isset($bean->field_defs['team_set_id'])) {
3230 //Create the team_set_id column
3231 $FieldArray = $GLOBALS['db']->helper->get_columns($bean->table_name);
3232 if(!isset($FieldArray['team_set_id'])) {
3233 $GLOBALS['db']->addColumn($bean->table_name, $bean->field_defs['team_set_id']);
3235 $indexArray = $GLOBALS['db']->helper->get_indices($bean->table_name);
3237 $indexName = getValidDBName('idx_'.strtolower($bean->table_name).'_tmst_id', true, 34);
3240 'name' => $indexName,
3242 'fields' => array('team_set_id')
3245 if(!isset($indexArray[$indexName])) {
3246 $GLOBALS['db']->addIndexes($bean->table_name, $indexDef);
3249 //Update the table's team_set_id column to have the same values as team_id
3250 $GLOBALS['db']->query("UPDATE {$bean->table_name} SET team_set_id = {$column_name}");
3255 * Update the folder subscription table which confirms to the team security mechanism but
3256 * the class SugarFolders does not extend SugarBean and is therefore never picked up by the
3257 * upgradeModulesForTeamsets function.
3259 function upgradeFolderSubscriptionsTeamSetId()
3261 logThis("In upgradeFolderSubscriptionsTeamSetId()");
3262 $query = "UPDATE folders SET team_set_id = team_id";
3263 $result = $GLOBALS['db']->query($query);
3264 logThis("Finished upgradeFolderSubscriptionsTeamSetId()");
3268 * upgradeModulesForTeam
3270 * This method update the associated_user_id, name, name_2 to the private team records on teams table
3271 * This function is used for upgrade process from 5.1.x and 5.2.x.
3274 function upgradeModulesForTeam() {
3275 logThis("In upgradeModulesForTeam()");
3276 $result = $GLOBALS['db']->query("SELECT id, user_name, first_name, last_name FROM users where deleted=0");
3278 while($row = $GLOBALS['db']->fetchByAssoc($result)) {
3279 $results2 = $GLOBALS['db']->query("SELECT id FROM teams WHERE name = '({$row['user_name']})'");
3281 if(!$assoc = $GLOBALS['db']->fetchByAssoc($results2)) {
3282 //if team does not exist, then lets create the team for this user
3285 $user->retrieve($row['id']);
3286 $team->new_user_created($user);
3287 $team_id = $team->id;
3289 $team_id =$assoc['id'];
3293 $name = is_null($row['first_name'])?'':$row['first_name'];
3294 $name_2 = is_null($row['last_name'])?'':$row['last_name'];
3295 $associated_user_id = $row['id'];
3298 //Ensure team->name is not empty by using team->name_2 if available
3299 if(empty($name) && !empty($name_2)) {
3304 $query = "UPDATE teams SET name = '{$name}', name_2 = '{$name_2}', associated_user_id = '{$associated_user_id}' WHERE id = '{$team_id}'";
3305 $GLOBALS['db']->query($query);
3308 //Update the team_set_id and default_team columns
3309 $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'));
3311 //Update team_set_id
3312 if($ce_to_pro_or_ent) {
3313 $GLOBALS['db']->query("update users set team_set_id = (select teams.id from teams where teams.associated_user_id = users.id)");
3314 $GLOBALS['db']->query("update users set default_team = (select teams.id from teams where teams.associated_user_id = users.id)");
3320 function addNewSystemTabsFromUpgrade($from_dir){
3322 if(isset($_SESSION['upgrade_from_flavor'])){
3324 //check to see if there are any new files that need to be added to systems tab
3325 //retrieve old modules list
3326 logThis('check to see if new modules exist',$path);
3327 $oldModuleList = array();
3328 $newModuleList = array();
3329 include($from_dir.'/include/modules.php');
3330 $oldModuleList = $moduleList;
3331 include('include/modules.php');
3332 $newModuleList = $moduleList;
3334 //include tab controller
3335 require_once('modules/MySettings/TabController.php');
3336 $newTB = new TabController();
3338 //make sure new modules list has a key we can reference directly
3339 $newModuleList = $newTB->get_key_array($newModuleList);
3340 $oldModuleList = $newTB->get_key_array($oldModuleList);
3342 //iterate through list and remove commonalities to get new modules
3343 foreach ($newModuleList as $remove_mod){
3344 if(in_array($remove_mod, $oldModuleList)){
3345 unset($newModuleList[$remove_mod]);
3348 //new modules list now has left over modules which are new to this install, so lets add them to the system tabs
3349 logThis('new modules to add are '.var_export($newModuleList,true),$path);
3351 if(!empty($newModuleList))
3353 //grab the existing system tabs
3354 $tabs = $newTB->get_system_tabs();
3356 //add the new tabs to the array
3357 foreach($newModuleList as $nm ){
3361 $newTB->set_system_tabs($tabs);
3363 logThis('module tabs updated',$path);
3369 * This method attempts to fix dropdown lists that were incorrectly named.
3370 * There were versions of SugarCRM that did not enforce naming convention rules
3371 * for the dropdown list field name. This method attempts to resolve that by
3372 * fixing the language files that may have been affected and then updating the
3373 * fields_meta_data table accordingly. It also refreshes any vardefs that may
3374 * have been affected.
3377 function fix_dropdown_list() {
3378 if(file_exists('custom/include/language')) {
3380 $affected_modules = array();
3381 $affected_keys = array();
3383 getFiles($files, 'custom/include/language', '/\.php$/i');
3384 foreach($files as $file) {
3386 if(file_exists($file . '.bak')) {
3387 $bak_mod_time = filemtime($file . '.bak');
3388 $php_mod_time = filemtime($file);
3389 //We're saying if the .php file was modified 30 seconds no more than php.bak file then we
3390 //run these additional cleanup checks
3391 if($php_mod_time - $bak_mod_time < 30) {
3393 $app_list_strings = array();
3394 $GLOBALS['app_list_strings'] = array();
3395 require($file . '.bak');
3396 $bak_app_list_strings = array_merge($app_list_strings, $GLOBALS['app_list_strings']);
3398 $app_list_strings = array();
3399 $GLOBALS['app_list_strings'] = array();
3401 $php_app_list_strings = array_merge($app_list_strings, $GLOBALS['app_list_strings']);
3403 //Get the file contents
3404 $contents = file_get_contents($file);
3406 //Now simulate a fix for the file before we compare w/ the .php file
3407 //we also append to the $contents
3408 foreach($bak_app_list_strings as $key=>$entry) {
3409 if(preg_match('/([^A-Za-z_])/', $key, $matches) && is_array($entry)) {
3410 $new_key = preg_replace('/[^A-Za-z_]/', '_', $key);
3411 $bak_app_list_strings[$new_key] = $bak_app_list_strings[$key];
3412 unset($bak_app_list_strings[$key]);
3413 //Now if the entry doesn't exists in the .php file, then add to contents
3414 if(!isset($php_app_list_strings[$new_key])) {
3415 $contents .= "\n\$GLOBALS['app_list_strings']['{$new_key}'] = " . var_export_helper($bak_app_list_strings[$new_key]) . ";";
3420 //Now load the .php file to do the comparison
3421 foreach($php_app_list_strings as $key=>$entry) {
3422 if(isset($bak_app_list_strings[$key])) {
3423 $diff = array_diff($bak_app_list_strings[$key], $entry);
3425 //There is a difference, so copy the $bak_app_list_strings version into the .php file
3426 $contents .= "\n\$GLOBALS['app_list_strings']['{$key}'] = " . var_export_helper($bak_app_list_strings[$key]) . ";";
3431 //Now write out the file contents
3432 //Create backup just in case
3433 copy($file, $file . '.php_bak');
3434 $fp = @sugar_fopen($file, 'w');
3436 fwrite($fp, $contents);
3439 $GLOBALS['log']->error("Unable to update file contents in fix_dropdown_list for {$file}");
3444 unset($GLOBALS['app_strings']);
3445 unset($GLOBALS['app_list_strings']);
3446 $app_list_strings = array();
3449 $contents = file_get_contents($file);
3450 if ( !isset($GLOBALS['app_list_strings']) ) {
3451 $GLOBALS['app_list_strings'] = $app_list_strings;
3454 $GLOBALS['app_list_strings'] = array_merge($app_list_strings, $GLOBALS['app_list_strings']);
3457 if(isset($GLOBALS['app_list_strings']) && is_array($GLOBALS['app_list_strings'])) {
3458 foreach($GLOBALS['app_list_strings'] as $key=>$entry) {
3459 if(preg_match('/([^A-Za-z_])/', $key, $matches) && is_array($entry)) {
3460 $result = $GLOBALS['db']->query("SELECT custom_module FROM fields_meta_data WHERE ext1 = '{$key}'");
3461 if(!empty($result)) {
3462 while($row = $GLOBALS['db']->fetchByAssoc($result)) {
3463 $custom_module = $row['custom_module'];
3464 if(!empty($GLOBALS['beanList'][$custom_module])) {
3465 $affected_modules[$custom_module] = $GLOBALS['beanList'][$custom_module];
3470 //Replace all invalid characters with '_' character
3471 $new_key = preg_replace('/[^A-Za-z_]/', '_', $key);
3472 $affected_keys[$key] = $new_key;
3474 $GLOBALS['app_list_strings'][$new_key] = $GLOBALS['app_list_strings'][$key];
3475 unset($GLOBALS['app_list_strings'][$key]);
3477 $pattern_match = "/(\[\s*\'{$key}\'\s*\])/";
3478 $new_key = "['{$new_key}']";
3479 $out = preg_replace($pattern_match, $new_key, $contents);
3485 //This is a check for g => h instances where the file contents were incorrectly written
3486 //and also fixes the scenario where via a UI upgrade, the app_list_strings were incorrectly
3487 //merged with app_list_strings variables declared elsewhere
3489 if(preg_match('/\$GLOBALS\s*\[\s*[\"|\']app_list_strings[\"|\']\s*\]\s*=\s*array\s*\(/', $contents)) {
3490 //Now also remove all the non-custom labels that were added
3491 if(preg_match('/language\/([^\.]+)\.lang\.php$/', $file, $matches)) {
3492 $language = $matches[1];
3494 $app_list_strings = array();
3496 if(file_exists("include/language/$language.lang.php")) {
3497 include("include/language/$language.lang.php");
3499 if(file_exists("include/language/$language.lang.override.php")) {
3500 $app_list_strings = _mergeCustomAppListStrings("include/language/$language.lang.override.php" , $app_list_strings) ;
3502 if(file_exists("custom/application/Ext/Language/$language.ext.lang.php")) {
3503 $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$language.ext.lang.php" , $app_list_strings) ;
3505 if(file_exists("custom/application/Ext/Language/$language.lang.ext.php")) {
3506 $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$language.lang.ext.php" , $app_list_strings) ;
3509 $all_non_custom_include_language_strings = $app_strings;
3510 $all_non_custom_include_language_list_strings = $app_list_strings;
3512 $unset_keys = array();
3513 if(!empty($GLOBALS['app_list_strings'])) {
3514 foreach($GLOBALS['app_list_strings'] as $key=>$value) {
3516 if(isset($all_non_custom_include_language_list_strings[$key])) {
3517 $diff = array_diff($all_non_custom_include_language_list_strings[$key], $GLOBALS['app_list_strings'][$key]);
3520 if(!empty($all_non_custom_include_language_list_strings[$key]) && empty($diff)) {
3521 $unset_keys[] = $key;
3526 foreach($unset_keys as $key) {
3527 unset($GLOBALS['app_list_strings'][$key]);
3530 if(!empty($GLOBALS['app_strings'])) {
3531 foreach($GLOBALS['app_strings'] as $key=>$value) {
3532 if(!empty($all_non_custom_include_language_strings[$key])) {
3533 unset($GLOBALS['app_strings'][$key]);
3537 } //if(preg_match...)
3540 if(!empty($GLOBALS['app_strings'])) {
3541 foreach($GLOBALS['app_strings'] as $key=>$entry) {
3542 $out .= "\n\$GLOBALS['app_strings']['$key']=" . var_export_helper($entry) . ";";
3546 foreach($GLOBALS['app_list_strings'] as $key=>$entry) {
3547 $out .= "\n\$GLOBALS['app_list_strings']['$key']=" . var_export_helper($entry) . ";";
3551 } //if(preg_match...)
3555 //Create a backup just in case
3556 copy($file, $file . '.bak');
3557 $fp = @sugar_fopen($file, 'w');
3562 //If we can't update the file, just return
3563 $GLOBALS['log']->error("Unable to update file contents in fix_dropdown_list.");
3571 //Update db entries (the order matters here... need to process database changes first)
3572 if(!empty($affected_keys)) {
3573 foreach($affected_keys as $old_key=>$new_key) {
3574 $GLOBALS['db']->query("UPDATE fields_meta_data SET ext1 = '{$new_key}' WHERE ext1 = '{$old_key}'");
3578 //Update vardef files for affected modules
3579 if(!empty($affected_modules)) {
3580 foreach($affected_modules as $module=>$object) {
3581 VardefManager::refreshVardefs($module, $object);
3588 function update_iframe_dashlets(){
3589 require_once(sugar_cached('dashlets/dashlets.php'));
3591 $db = DBManagerFactory::getInstance();
3592 $query = "SELECT id, contents, assigned_user_id FROM user_preferences WHERE deleted = 0 AND category = 'Home'";
3593 $result = $db->query($query, true, "Unable to update new default dashlets! ");
3594 while ($row = $db->fetchByAssoc($result)) {
3595 $content = unserialize(base64_decode($row['contents']));
3596 $assigned_user_id = $row['assigned_user_id'];
3597 $record_id = $row['id'];
3599 $current_user = new User();
3600 $current_user->retrieve($row['assigned_user_id']);
3602 if(!empty($content['dashlets']) && !empty($content['pages'])){
3603 $originalDashlets = $content['dashlets'];
3604 foreach($originalDashlets as $key => $ds){
3605 if(!empty($ds['options']['url']) && stristr($ds['options']['url'],'http://www.sugarcrm.com/crm/product/gopro')){
3606 unset($originalDashlets[$key]);
3609 $current_user->setPreference('dashlets', $originalDashlets, 0, 'Home');
3616 * convertImageToText
3618 * This method attempts to convert date type image to text on Microsoft SQL Server.
3619 * This method could NOT be used in any other type of datebases.
3621 function convertImageToText($table_name,$column_name){
3622 $set_lang = "SET LANGUAGE us_english";
3623 $GLOBALS['db']->query($set_lang);
3624 if($GLOBALS['db']->lastError()){
3625 logThis('An error occurred when performing this query-->'.$set_lang);
3627 $q="SELECT data_type
3628 FROM INFORMATION_SCHEMA.Tables T JOIN INFORMATION_SCHEMA.Columns C
3629 ON T.TABLE_NAME = C.TABLE_NAME where T.TABLE_NAME = '$table_name' and C.COLUMN_NAME = '$column_name'";
3630 $res= $GLOBALS['db']->query($q);
3631 if($GLOBALS['db']->lastError()){
3632 logThis('An error occurred when performing this query-->'.$q);
3634 $row= $GLOBALS['db']->fetchByAssoc($res);
3636 if(trim(strtolower($row['data_type'])) == 'image'){
3637 $addContent_temp = "alter table {$table_name} add {$column_name}_temp text null";
3638 $GLOBALS['db']->query($addContent_temp);
3639 if($GLOBALS['db']->lastError()){
3640 logThis('An error occurred when performing this query-->'.$addContent_temp);
3642 $qN = "select count=datalength({$column_name}), id, {$column_name} from {$table_name}";
3643 $result = $GLOBALS['db']->query($qN);
3644 while($row = $GLOBALS['db']->fetchByAssoc($result)){
3645 if($row['count'] >8000){
3646 $contentLength = $row['count'];
3649 $convertedContent = '';
3650 while($contentLength >0){
3651 $stepsQuery = "select cont=convert(varchar(max), convert(varbinary(8000), substring({$column_name},{$start},{$next}))) from {$table_name} where id= '{$row['id']}'";
3652 $steContQ = $GLOBALS['db']->query($stepsQuery);
3653 if($GLOBALS['db']->lastError()){
3654 logThis('An error occurred when performing this query-->'.$stepsQuery);
3656 $stepCont = $GLOBALS['db']->fetchByAssoc($steContQ);
3657 if(isset($stepCont['cont'])){
3658 $convertedContent = $convertedContent.$stepCont['cont'];
3660 $start = $start+$next;
3661 $contentLength = $contentLength - $next;
3663 $addContentDataText="update {$table_name} set {$column_name}_temp = '{$convertedContent}' where id= '{$row['id']}'";
3664 $GLOBALS['db']->query($addContentDataText);
3665 if($GLOBALS['db']->lastError()){
3666 logThis('An error occurred when performing this query-->'.$addContentDataText);
3670 $addContentDataText="update {$table_name} set {$column_name}_temp =
3671 convert(varchar(max), convert(varbinary(8000), {$column_name})) where id= '{$row['id']}'";
3672 $GLOBALS['db']->query($addContentDataText);
3673 if($GLOBALS['db']->lastError()){
3674 logThis('An error occurred when performing this query-->'.$addContentDataText);
3678 //drop the contents now and change contents_temp to contents
3679 $dropColumn = "alter table {$table_name} drop column {$column_name}";
3680 $GLOBALS['db']->query($dropColumn);
3681 if($GLOBALS['db']->lastError()){
3682 logThis('An error occurred when performing this query-->'.$dropColumn);
3684 $changeColumnName = "EXEC sp_rename '{$table_name}.[{$column_name}_temp]','{$column_name}','COLUMN'";
3685 $GLOBALS['db']->query($changeColumnName);
3686 if($GLOBALS['db']->lastError()){
3687 logThis('An error occurred when performing this query-->'.$changeColumnName);
3694 * This method attempts to delete all English inline help files.
3695 * This method was introduced by 5.5.0RC2.
3697 function clearHelpFiles(){
3698 $modulePath = clean_path(getcwd() . '/modules');
3699 $allHelpFiles = array();
3700 getFiles($allHelpFiles, $modulePath, "/en_us.help.*/");
3702 foreach( $allHelpFiles as $the_file ){
3703 if( is_file( $the_file ) ){
3704 unlink( $the_file );
3705 logThis("Deleted file: $the_file");
3713 * upgradeDateTimeFields
3715 * This method came from bug: 39757 where the date_end field is a date field and not a datetime field
3716 * which prevents you from performing timezone offset calculations once the data has been saved.
3718 * @param path String location to log file, empty by default
3720 function upgradeDateTimeFields($path)
3724 $meetingsSql = "UPDATE meetings SET date_end = ".$db->convert("date_start", 'add_time', array('duration_hours', 'duration_minutes'));
3725 $callsSql = "UPDATE calls SET date_end = ".$db->convert("date_start", 'add_time', array('duration_hours', 'duration_minutes'));
3726 logThis('upgradeDateTimeFields Meetings SQL:' . $meetingsSql, $path);
3727 $db->query($meetingsSql);
3729 logThis('upgradeDateTimeFields Calls SQL:' . $callsSql, $path);
3730 $db->query($callsSql);
3734 * upgradeDocumentTypeFields
3737 function upgradeDocumentTypeFields($path){
3741 $documentsSql = "UPDATE documents SET doc_type = 'Sugar' WHERE doc_type IS NULL";
3742 $meetingsSql = "UPDATE meetings SET type = 'Sugar' WHERE type IS NULL";
3744 logThis('upgradeDocumentTypeFields Documents SQL:' . $documentsSql, $path);
3745 $db->query($documentsSql);
3746 logThis('upgradeDocumentTypeFields Meetings SQL:' . $meetingsSql, $path);
3747 $db->query($meetingsSql);
3752 * merge_config_si_settings
3753 * This method checks for the presence of a config_si.php file and, if found, merges the configuration
3754 * settings from the config_si.php file into config.php. If a config_si_location parameter value is not
3755 * supplied it will attempt to discover the config_si.php file location from where the executing script
3758 * @param write_to_upgrade_log boolean optional value to write to the upgradeWizard.log file
3759 * @param config_location String optional value to config.php file location
3760 * @param config_si_location String optional value to config_si.php file location
3761 * @param path String file of the location of log file to write to
3762 * @return boolean value indicating whether or not a merge was attempted with config_si.php file
3764 function merge_config_si_settings($write_to_upgrade_log=false, $config_location='', $config_si_location='', $path='')
3766 if(!empty($config_location) && !file_exists($config_location))
3768 if($write_to_upgrade_log)
3770 logThis('config.php file specified in ' . $config_si_location . ' could not be found. Skip merging', $path);
3773 } else if(empty($config_location)) {
3775 //We are assuming this is from the silentUpgrade scripts so argv[3] will point to SugarCRM install location
3776 if(isset($argv[3]) && is_dir($argv[3]))
3778 $config_location = $argv[3] . DIRECTORY_SEPARATOR . 'config.php';
3782 //If config_location is still empty or if the file cannot be found, skip merging
3783 if(empty($config_location) || !file_exists($config_location))
3785 if($write_to_upgrade_log)
3787 logThis('config.php file at (' . $config_location . ') could not be found. Skip merging.', $path);
3791 if($write_to_upgrade_log)
3793 logThis('Loading config.php file at (' . $config_location . ') for merging.', $path);
3796 include($config_location);
3797 if(empty($sugar_config))
3799 if($write_to_upgrade_log)
3801 logThis('config.php contents are empty. Skip merging.', $path);
3807 if(!empty($config_si_location) && !file_exists($config_si_location))
3809 if($write_to_upgrade_log)
3811 logThis('config_si.php file specified in ' . $config_si_location . ' could not be found. Skip merging', $path);
3814 } else if(empty($config_si_location)) {
3815 if(isset($argv[0]) && is_file($argv[0]))
3817 $php_file = $argv[0];
3818 $p_info = pathinfo($php_file);
3819 $php_dir = (isset($p_info['dirname']) && $p_info['dirname'] != '.') ? $p_info['dirname'] . DIRECTORY_SEPARATOR : '';
3820 $config_si_location = $php_dir . 'config_si.php';
3824 //If config_si_location is still empty or if the file cannot be found, skip merging
3825 if(empty($config_si_location) || !file_exists($config_si_location))
3827 if($write_to_upgrade_log)
3829 logThis('config_si.php file at (' . $config_si_location . ') could not be found. Skip merging.', $path);
3833 if($write_to_upgrade_log)
3835 logThis('Loading config_si.php file at (' . $config_si_location . ') for merging.', $path);
3838 include($config_si_location);
3839 if(empty($sugar_config_si))
3841 if($write_to_upgrade_log)
3843 logThis('config_si.php contents are empty. Skip merging.', $path);
3849 //Now perform the merge operation
3851 foreach($sugar_config_si as $key=>$value)
3853 if(!preg_match('/^setup_/', $key) && !isset($sugar_config[$key]))
3855 if($write_to_upgrade_log)
3857 logThis('Merge key (' . $key . ') with value (' . $value . ')', $path);
3859 $sugar_config[$key] = $value;
3866 if($write_to_upgrade_log)
3868 logThis('Update config.php file with new values', $path);
3871 if(!write_array_to_file("sugar_config", $sugar_config, $config_location)) {
3872 if($write_to_upgrade_log)
3874 logThis('*** ERROR: could not write to config.php', $path);
3879 if($write_to_upgrade_log)
3881 logThis('config.php values are in sync with config_si.php values. Skipped merging.');
3886 if($write_to_upgrade_log)
3888 logThis('End merge_config_si_settings', $path);
3895 * upgrade_connectors
3897 * This function handles support for upgrading connectors it is invoked from both end.php and silentUpgrade_step2.php
3900 function upgrade_connectors() {
3901 require_once('include/connectors/utils/ConnectorUtils.php');
3902 if(!ConnectorUtils::updateMetaDataFiles()) {
3903 $GLOBALS['log']->fatal('Cannot update metadata files for connectors');
3906 //Delete the custom connectors.php file if it exists so that it may be properly rebuilt
3907 if(file_exists('custom/modules/Connectors/metadata/connectors.php'))
3909 unlink('custom/modules/Connectors/metadata/connectors.php');
3914 * Enable the InsideView connector for the four default modules.
3916 function upgradeEnableInsideViewConnector($path='')
3918 logThis('Begin upgradeEnableInsideViewConnector', $path);
3920 // Load up the existing mapping and hand it to the InsideView connector to have it setup the correct logic hooks
3921 $mapFile = 'modules/Connectors/connectors/sources/ext/rest/insideview/mapping.php';
3922 if ( file_exists('custom/'.$mapFile) ) {
3923 logThis('Found CUSTOM mappings', $path);
3924 require('custom/'.$mapFile);
3926 logThis('Used default mapping', $path);
3930 require_once('include/connectors/sources/SourceFactory.php');
3931 $source = SourceFactory::getSource('ext_rest_insideview');
3933 // $mapping is brought in from the mapping.php file above
3934 $source->saveMappingHook($mapping);
3936 require_once('include/connectors/utils/ConnectorUtils.php');
3937 ConnectorUtils::installSource('ext_rest_insideview');
3939 // Now time to set the various modules to active, because this part ignores the default config
3940 require(CONNECTOR_DISPLAY_CONFIG_FILE);
3941 // $modules_sources come from that config file
3942 foreach ( $source->allowedModuleList as $module ) {
3943 $modules_sources[$module]['ext_rest_insideview'] = 'ext_rest_insideview';
3945 if(!write_array_to_file('modules_sources', $modules_sources, CONNECTOR_DISPLAY_CONFIG_FILE)) {
3946 //Log error and return empty array
3947 logThis("Cannot write \$modules_sources to " . CONNECTOR_DISPLAY_CONFIG_FILE,$path);
3950 logThis('End upgradeEnableInsideViewConnector', $path);
3954 function repair_long_relationship_names($path='')
3956 logThis("Begin repair_long_relationship_names", $path);
3957 require_once 'modules/ModuleBuilder/parsers/relationships/DeployedRelationships.php' ;
3958 $GLOBALS['mi_remove_tables'] = false;
3960 foreach($GLOBALS['moduleList'] as $module)
3962 $relationships = new DeployedRelationships ($module) ;
3963 foreach($relationships->getRelationshipList() as $rel_name)
3965 if (strlen($rel_name) > 27 && empty($touched[$rel_name]))
3967 logThis("Rebuilding relationship fields for $rel_name", $path);
3968 $touched[$rel_name] = true;
3969 $rel_obj = $relationships->get($rel_name);
3970 $rel_obj->setReadonly(false);
3971 $relationships->delete($rel_name);
3972 $relationships->save();
3973 $relationships->add($rel_obj);
3974 $relationships->save();
3975 $relationships->build () ;
3979 logThis("End repair_long_relationship_names", $path);
3982 function removeSilentUpgradeVarsCache(){
3983 global $silent_upgrade_vars_loaded;
3985 $cacheFileDir = "{$GLOBALS['sugar_config']['cache_dir']}/silentUpgrader";
3986 $cacheFile = "{$cacheFileDir}/silentUpgradeCache.php";
3988 if(file_exists($cacheFile)){
3992 $silent_upgrade_vars_loaded = array(); // Set to empty to reset it
3997 function loadSilentUpgradeVars(){
3998 global $silent_upgrade_vars_loaded;
4000 if(empty($silent_upgrade_vars_loaded)){
4001 $cacheFile = "{$GLOBALS['sugar_config']['cache_dir']}/silentUpgrader/silentUpgradeCache.php";
4002 // We have no pre existing vars
4003 if(!file_exists($cacheFile)){
4004 // Set the vars array so it's loaded
4005 $silent_upgrade_vars_loaded = array('vars' => array());
4008 require_once($cacheFile);
4009 $silent_upgrade_vars_loaded = $silent_upgrade_vars_cache;
4016 function writeSilentUpgradeVars(){
4017 global $silent_upgrade_vars_loaded;
4019 if(empty($silent_upgrade_vars_loaded)){
4020 return false; // You should have set some values before trying to write the silent upgrade vars
4023 $cacheFileDir = "{$GLOBALS['sugar_config']['cache_dir']}/silentUpgrader";
4024 $cacheFile = "{$cacheFileDir}/silentUpgradeCache.php";
4026 require_once('include/dir_inc.php');
4027 if(!mkdir_recursive($cacheFileDir)){
4030 require_once('include/utils/file_utils.php');
4031 if(!write_array_to_file('silent_upgrade_vars_cache', $silent_upgrade_vars_loaded, $cacheFile, 'w')){
4033 logThis("WARNING: writeSilentUpgradeVars could not write to {$cacheFile}", $path);
4040 function setSilentUpgradeVar($var, $value){
4041 if(!loadSilentUpgradeVars()){
4045 global $silent_upgrade_vars_loaded;
4047 $silent_upgrade_vars_loaded['vars'][$var] = $value;
4052 function getSilentUpgradeVar($var){
4053 if(!loadSilentUpgradeVars()){
4057 global $silent_upgrade_vars_loaded;
4059 if(!isset($silent_upgrade_vars_loaded['vars'][$var])){
4063 return $silent_upgrade_vars_loaded['vars'][$var];
4069 * add_unified_search_to_custom_modules_vardefs
4071 * This method calls the repair code to remove the unified_search_modules.php fiel
4074 function add_unified_search_to_custom_modules_vardefs()
4076 if(file_exists($cachefile = sugar_cached('modules/unified_search_modules.php')))
4084 * change from using the older SugarCache in 6.1 and below to the new one in 6.2
4086 function upgradeSugarCache($file)
4088 global $sugar_config;
4089 $cacheUploadUpgradesTemp = mk_temp_dir(sugar_cached('upgrades/temp'));
4091 unzip($file, $cacheUploadUpgradesTemp);
4093 if(!file_exists(clean_path("{$cacheUploadUpgradesTemp}/manifest.php"))) {
4094 logThis("*** ERROR: no manifest file detected while bootstraping upgrade wizard files!");
4097 include(clean_path("{$cacheUploadUpgradesTemp}/manifest.php"));
4100 $from_dir = "{$cacheUploadUpgradesTemp}/{$manifest['copy_files']['from_dir']}";
4101 $allFiles = array();
4102 if(file_exists("$from_dir/include/SugarCache")) {
4103 $allFiles = findAllFiles("$from_dir/include/SugarCache", $allFiles);
4105 if(file_exists("$from_dir/include/database")) {
4106 $allFiles = findAllFiles("$from_dir/include/database", $allFiles);
4108 if(file_exists("$from_dir/include/utils/external_cache.php")) {
4109 $allFiles[] = "$from_dir/include/utils/external_cache.php";
4111 if(file_exists("$from_dir/include/utils/sugar_file_utils.php")) {
4112 $allFiles[] = "$from_dir/include/utils/sugar_file_utils.php";
4114 if(file_exists("$from_dir/include/utils/sugar_file_utils.php")) {
4115 $allFiles[] = "$from_dir/include/utils/sugar_file_utils.php";
4118 foreach($allFiles as $k => $file) {
4119 $destFile = str_replace($from_dir."/", "", $file);
4120 if(!is_dir(dirname($destFile))) {
4121 mkdir_recursive(dirname($destFile)); // make sure the directory exists
4123 if ( stristr($file,'uw_main.tpl') )
4124 logThis('Skipping "'.$file.'" - file copy will during commit step.');
4126 logThis('updating UpgradeWizard code: '.$destFile);
4127 copy_recursive($file, $destFile);
4134 * upgradeDisplayedTabsAndSubpanels
4136 * @param $version String value of current system version (pre upgrade)
4138 function upgradeDisplayedTabsAndSubpanels($version)
4140 if($version < '620')
4142 logThis('start upgrading system displayed tabs and subpanels');
4143 require_once('modules/MySettings/TabController.php');
4144 $tc = new TabController();
4146 //grab the existing system tabs
4147 $tabs = $tc->get_tabs_system();
4149 //add Calls, Meetings, Tasks, Notes, Prospects (Targets) and ProspectLists (Target Lists)
4150 //to displayed tabs unless explicitly set to hidden
4151 $modules_to_add = array('Calls', 'Meetings', 'Tasks', 'Notes', 'Prospects', 'ProspectLists');
4152 $added_tabs = array();
4154 foreach($modules_to_add as $module)
4156 $tabs[0][$module] = $module;
4157 $added_tabs[] = $module;
4160 logThis('calling set_system_tabs on TabController to add tabs: ' . var_export($added_tabs, true));
4161 $tc->set_system_tabs($tabs[0]);
4162 logThis('finish upgrading system displayed tabs and subpanels');
4168 * unlinkUpgradeFiles
4169 * This is a helper function to clean up
4171 * @param $version String value of current system version (pre upgrade)
4173 function unlinkUpgradeFiles($version)
4175 if(!isset($version))
4180 //First check if we even have the scripts_for_patch/files_to_remove directory
4181 require_once('modules/UpgradeWizard/UpgradeRemoval.php');
4184 if(empty($_SESSION['unzip_dir']))
4186 global $sugar_config;
4187 $base_upgrade_dir = $sugar_config['upload_dir'] . "/upgrades";
4188 $base_tmp_upgrade_dir = "$base_upgrade_dir/temp";
4189 $_SESSION['unzip_dir'] = mk_temp_dir( $base_tmp_upgrade_dir );
4193 if(isset($_SESSION['unzip_dir']) && file_exists($_SESSION['unzip_dir'].'/scripts/files_to_remove'))
4195 $files_to_remove = glob($_SESSION['unzip_dir'].'/scripts/files_to_remove/*.php');
4197 foreach($files_to_remove as $script)
4199 if(preg_match('/UpgradeRemoval(\d+)x\.php/', $script, $matches))
4201 $checkVersion = $matches[1] + 1; //Increment by one to check everything equal or below the target version
4202 $upgradeClass = 'UpgradeRemoval' . $matches[1] . 'x';
4203 require_once($_SESSION['unzip_dir'].'/scripts/files_to_remove/' . $upgradeClass . '.php');
4205 //Check to make sure we should load and run this UpgradeRemoval instance
4206 if($checkVersion <= $version && class_exists($upgradeClass))
4208 $upgradeInstance = new $upgradeClass();
4209 if($upgradeInstance instanceof UpgradeRemoval)
4211 logThis('Running UpgradeRemoval instance ' . $upgradeClass);
4212 logThis('Files will be backed up to custom/backup');
4213 $files = $upgradeInstance->getFilesToRemove($version);
4214 foreach($files as $file)
4218 $upgradeInstance->processFilesToRemove($files);
4225 //Check if we have a custom directory
4226 if(file_exists('custom/scripts/files_to_remove'))
4229 $files_to_remove = glob('custom/scripts/files_to_remove/*.php');
4231 foreach($files_to_remove as $script)
4233 if(preg_match('/\/files_to_remove\/(.*?)\.php$/', $script, $matches))
4235 require_once($script);
4236 $upgradeClass = $matches[1];
4238 if(!class_exists($upgradeClass))
4243 $upgradeInstance = new $upgradeClass();
4244 if($upgradeInstance instanceof UpgradeRemoval)
4246 logThis('Running Custom UpgradeRemoval instance ' . $upgradeClass);
4247 $files = $upgradeInstance->getFilesToRemove($version);
4248 foreach($files as $file)
4252 $upgradeInstance->processFilesToRemove($files);
4260 if (!function_exists("getValidDBName"))
4263 * Return a version of $proposed that can be used as a column name in any of our supported databases
4264 * 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)
4265 * @param string $name Proposed name for the column
4266 * @param string $ensureUnique
4267 * @return string Valid column name trimmed to right length and with invalid characters removed
4269 function getValidDBName ($name, $ensureUnique = false, $maxLen = 30)
4271 // first strip any invalid characters - all but alphanumerics and -
4272 $name = preg_replace ( '/[^\w-]+/i', '', $name ) ;
4273 $len = strlen ( $name ) ;
4277 $md5str = md5($name);
4278 $tail = substr ( $name, -11) ;
4279 $temp = substr($md5str , strlen($md5str)-4 );
4280 $result = substr ( $name, 0, 10) . $temp . $tail ;
4281 }else if ($len > ($maxLen - 5))
4283 $result = substr ( $name, 0, 11) . substr ( $name, 11 - $maxLen + 5);
4285 return strtolower ( $result ) ;
4292 * Get UW directories
4293 * Provides compatibility with both 6.3 and pre-6.3 setup
4295 function getUWDirs()
4297 if(!class_exists('UploadStream')) {
4298 // we're still running the old code
4299 global $sugar_config;
4300 return array($sugar_config['upload_dir'] . "/upgrades", $sugar_config['cache_dir'] . "upload/upgrades/temp");
4302 if(!in_array("upload", stream_get_wrappers())) {
4303 UploadStream::register(); // just in case file was copied, but not run
4305 return array("upload://upgrades", sugar_cached("upgrades/temp"));
4310 * Whether directory exists within list of directories to skip
4311 * @param string $dir dir to be checked
4312 * @param array $skipDirs list with skipped dirs
4315 function whetherNeedToSkipDir($dir, $skipDirs)
4317 foreach($skipDirs as $skipMe) {
4318 if(strpos( clean_path($dir), $skipMe ) !== false) {
4328 * @param silentUpgrade boolean flag indicating whether or not we should treat running the SugarSpriteBuilder as an upgrade operation
4331 function rebuildSprites($fromUpgrade=true)
4333 require_once('modules/Administration/SugarSpriteBuilder.php');
4334 $sb = new SugarSpriteBuilder();
4335 $sb->cssMinify = true;
4336 $sb->fromSilentUpgrade = $fromUpgrade;
4337 $sb->silentRun = $fromUpgrade;
4339 // add common image directories
4340 $sb->addDirectory('default', 'include/images');
4341 $sb->addDirectory('default', 'themes/default/images');
4342 $sb->addDirectory('default', 'themes/default/images/SugarLogic');
4344 // add all theme image directories
4345 if($dh = opendir('themes'))
4347 while (($dir = readdir($dh)) !== false)
4349 if ($dir != "." && $dir != ".." && $dir != 'default' && is_dir('themes/'.$dir)) {
4350 $sb->addDirectory($dir, "themes/{$dir}/images");
4356 // generate the sprite goodies
4357 // everything is saved into cache/sprites
4358 $sb->createSprites();
4363 * repairSearchFields
4365 * This method goes through the list of SearchFields files based and calls TemplateRange::repairCustomSearchFields
4366 * method on the files in an attempt to ensure the range search attributes are properly set in SearchFields.php.
4368 * @param $globString String value used for glob search defaults to searching for all SearchFields.php files in modules directory
4369 * @param $path String value used to point to log file should logging be required. Defaults to empty.
4372 function repairSearchFields($globString='modules/*/metadata/SearchFields.php', $path='')
4376 logThis('Begin repairSearchFields', $path);
4379 require_once('include/dir_inc.php');
4380 require_once('modules/DynamicFields/templates/Fields/TemplateRange.php');
4381 require('include/modules.php');
4384 $searchFieldsFiles = glob($globString);
4386 foreach($searchFieldsFiles as $file)
4388 if(preg_match('/modules\/(.*?)\/metadata\/SearchFields\.php/', $file, $matches) && isset($beanList[$matches[1]]))
4390 $module = $matches[1];
4391 $beanName = $beanList[$module];
4392 VardefManager::loadVardef($module, $beanName);
4393 if(isset($GLOBALS['dictionary'][$beanName]['fields']))
4397 logThis('Calling TemplateRange::repairCustomSearchFields for module ' . $module, $path);
4399 TemplateRange::repairCustomSearchFields($GLOBALS['dictionary'][$beanName]['fields'], $module);
4406 logThis('End repairSearchFields', $path);
4411 * repairUpgradeHistoryTable
4413 * This is a helper function used in the upgrade process to fix upgrade_history entries so that the filename column points
4414 * to the new upload directory location introduced in 6.4 versions
4416 function repairUpgradeHistoryTable()
4418 require_once('modules/Configurator/Configurator.php');
4420 global $sugar_config;
4422 //Now upgrade the upgrade_history table entries
4423 $results = $GLOBALS['db']->query('SELECT id, filename FROM upgrade_history');
4424 $upload_dir = $sugar_config['cache_dir'].'upload/';
4426 //Create regular expression string to
4427 $match = '/^' . str_replace('/', '\/', $upload_dir) . '(.*?)$/';
4429 while(($row = $GLOBALS['db']->fetchByAssoc($results)))
4431 $file = str_replace('//', '/', $row['filename']); //Strip out double-paths that may exist
4433 if(!empty($file) && preg_match($match, $file, $matches))
4435 //Update new file location to use the new $sugar_config['upload_dir'] value
4436 $new_file_location = $sugar_config['upload_dir'] . $matches[1];
4437 $GLOBALS['db']->query("UPDATE upgrade_history SET filename = '{$new_file_location}' WHERE id = '{$row['id']}'");