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-2011 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/modules/UpgradeWizard")) {
678 $allFiles[] = findAllFiles("$from_dir/modules/UpgradeWizard", $allFiles);
681 if(file_exists("$from_dir/ModuleInstall")) {
682 $allFiles[] = findAllFiles("$from_dir/ModuleInstall", $allFiles);
684 if(file_exists("$from_dir/include/javascript/yui")) {
685 $allFiles[] = findAllFiles("$from_dir/include/javascript/yui", $allFiles);
687 if(file_exists("$from_dir/HandleAjaxCall.php")) {
688 $allFiles[] = "$from_dir/HandleAjaxCall.php";
690 if(file_exists("$from_dir/include/SugarTheme")) {
691 $allFiles[] = findAllFiles("$from_dir/include/SugarTheme", $allFiles);
693 if(file_exists("$from_dir/include/SugarCache")) {
694 $allFiles[] = findAllFiles("$from_dir/include/SugarCache", $allFiles);
696 if(file_exists("$from_dir/include/utils/external_cache.php")) {
697 $allFiles[] = "$from_dir/include/utils/external_cache.php";
699 if(file_exists("$from_dir/include/upload_file.php")) {
700 $allFiles[] = "$from_dir/include/upload_file.php";
702 if(file_exists("$from_dir/include/file_utils.php")) {
703 $allFiles[] = "$from_dir/include/file_utils.php";
705 if(file_exists("$from_dir/include/upload_file.php")) {
706 $allFiles[] = "$from_dir/include/upload_file.php";
708 if(file_exists("$from_dir/include/utils/sugar_file_utils.php")) {
709 $allFiles[] = "$from_dir/include/utils/sugar_file_utils.php";
712 if(file_exists("$from_dir/modules/Users")) {
713 $allFiles[] = findAllFiles("$from_dir/modules/Users", $allFiles);
716 upgradeUWFilesCopy($allFiles, $from_dir);
722 * This function recursively copies files from the upgradeUWFiles Array
723 * @see upgradeUWFiles
725 * @param array $allFiles Array of files to copy over after zip file has been uploaded
726 * @param string $from_dir Source directory
728 function upgradeUWFilesCopy($allFiles, $from_dir)
730 foreach($allFiles as $file)
734 upgradeUWFilesCopy($file, $from_dir);
736 $destFile = str_replace($from_dir."/", "", $file);
737 if(!is_dir(dirname($destFile))) {
738 mkdir_recursive(dirname($destFile)); // make sure the directory exists
741 if(stristr($file,'uw_main.tpl'))
742 logThis('Skipping "'.$file.'" - file copy will during commit step.');
744 logThis('updating UpgradeWizard code: '.$destFile);
745 copy_recursive($file, $destFile);
754 * gets valid patch file names that exist in upload/upgrade/patch/
756 function getValidPatchName($returnFull = true) {
757 global $base_upgrade_dir;
760 global $sugar_version;
761 global $sugar_config;
762 $uh = new UpgradeHistory();
763 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
766 // scan for new files (that are not installed)
767 logThis('finding new files for upgrade');
768 $upgrade_content = '';
769 $upgrade_contents = findAllFiles($base_upgrade_dir, array(), false, 'zip');
770 //other variations of zip file i.e. ZIP, zIp,zIP,Zip,ZIp,ZiP
777 <b>{$mod_strings['LBL_ML_NAME']}</b>
780 <b>{$mod_strings['LBL_ML_TYPE']}</b>
783 <b>{$mod_strings['LBL_ML_VERSION']}</b>
786 <b>{$mod_strings['LBL_ML_PUBLISHED']}</b>
789 <b>{$mod_strings['LBL_ML_UNINSTALLABLE']}</b>
792 <b>{$mod_strings['LBL_ML_DESCRIPTION']}</b>
797 // assume old patches are there.
798 $upgradeToVersion = array(); // fill with valid patches - we will only use the latest qualified found patch
800 // cn: bug 10609 - notices for uninitialized variables
805 $published_date = '';
810 foreach($upgrade_contents as $upgrade_content) {
811 if(!preg_match("#.*\.zip\$#i", $upgrade_content)) {
815 $the_base = basename($upgrade_content);
816 $the_md5 = md5_file($upgrade_content);
818 $md5_matches = $uh->findByMd5($the_md5);
820 /* 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.
821 * Edge-case: manual upgrade with a FTP of a patch; UH table has no entry for it. Assume nothing. :( */
822 if(0 == sizeof($md5_matches)) {
823 $target_manifest = remove_file_extension( $upgrade_content ) . '-manifest.php';
824 require_once($target_manifest);
826 if(empty($manifest['version'])) {
827 logThis("*** Potential error: patch found with no version [ {$upgrade_content} ]");
830 if(!isset($manifest['type']) || $manifest['type'] != 'patch') {
831 logThis("*** Potential error: patch found with either no 'type' or non-patch type [ {$upgrade_content} ]");
835 $upgradeToVersion[$manifest['version']] = urlencode($upgrade_content);
837 $name = empty($manifest['name']) ? $upgrade_content : $manifest['name'];
838 $version = empty($manifest['version']) ? '' : $manifest['version'];
839 $published_date = empty($manifest['published_date']) ? '' : $manifest['published_date'];
841 $description = empty($manifest['description']) ? 'None' : $manifest['description'];
842 $uninstallable = empty($manifest['is_uninstallable']) ? 'No' : 'Yes';
843 $type = getUITextForType( $manifest['type'] );
844 $manifest_type = $manifest['type'];
846 if(empty($manifest['icon'])) {
847 $icon = getImageForType( $manifest['type'] );
849 $path_parts = pathinfo( $manifest['icon'] );
850 $icon = "<!--not_in_theme!--><img src=\"" . remove_file_extension( $upgrade_content ) . "-icon." . $path_parts['extension'] . "\">";
855 // cn: bug 10488 use the NEWEST upgrade/patch available when running upgrade wizard.
856 ksort($upgradeToVersion);
857 $upgradeToVersion = array_values($upgradeToVersion);
858 $newest = array_pop($upgradeToVersion);
859 $_SESSION['install_file'] = urldecode($newest); // in-case it was there from a prior.
860 logThis("*** UW using [ {$_SESSION['install_file']} ] as source for patch files.");
862 $cleanUpgradeContent = urlencode($_SESSION['install_file']);
864 // cn: 10606 - cannot upload a patch file since this returned always.
865 if(!empty($cleanUpgradeContent)) {
866 $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";
869 <form action="index.php" method="post">
870 <input type="hidden" name="module" value="UpgradeWizard">
871 <input type="hidden" name="action" value="index">
872 <input type="hidden" name="step" value="{$_REQUEST['step']}">
873 <input type="hidden" name="run" value="delete">
874 <input type=hidden name="install_file" value="{$cleanUpgradeContent}" />
875 <input type=submit value="{$mod_strings['LBL_BUTTON_DELETE']}" />
879 $disabled = "DISABLED";
884 if(empty($cleanUpgradeContent)){
885 $ready .= "<tr><td colspan='7'><i>None</i></td>\n";
886 $ready .= "</table>\n";
888 $ready .= "<br></ul>\n";
890 $return['ready'] = $ready;
891 $return['disabled'] = $disabled;
900 * finalizes upgrade by setting upgrade versions in DB (config table) and sugar_version.php
901 * @return bool true on success
903 function updateVersions($version) {
905 global $sugar_config;
908 logThis('At updateVersions()... updating config table and sugar_version.php.', $path);
911 if(isset($_SESSION['sugar_version_file']) && !empty($_SESSION['sugar_version_file'])) {
912 if(!copy($_SESSION['sugar_version_file'], clean_path(getcwd().'/sugar_version.php'))) {
913 logThis('*** ERROR: sugar_version.php could not be copied to destination! Cannot complete upgrade', $path);
916 logThis('sugar_version.php successfully updated!', $path);
919 logThis('*** ERROR: no sugar_version.php file location found! - cannot complete upgrade...', $path);
923 $q1 = "DELETE FROM config WHERE category = 'info' AND name = 'sugar_version'";
924 $q2 = "INSERT INTO config (category, name, value) VALUES ('info', 'sugar_version', '{$version}')";
926 logThis('Deleting old DB version info from config table.', $path);
929 logThis('Inserting updated version info into config table.', $path);
932 logThis('updateVersions() complete.', $path);
939 * gets a module's lang pack - does not need to be a SugarModule
940 * @param lang string Language
941 * @param module string Path to language folder
942 * @return array mod_strings
944 function getModuleLanguagePack($lang, $module) {
945 $mod_strings = array();
947 if(!empty($lang) && !empty($module)) {
948 $langPack = clean_path(getcwd().'/'.$module.'/language/'.$lang.'.lang.php');
949 $langPackEn = clean_path(getcwd().'/'.$module.'/language/en_us.lang.php');
951 if(file_exists($langPack))
952 include_once($langPack);
953 elseif(file_exists($langPackEn))
954 include_once($langPackEn);
960 * checks system compliance for 4.5+ codebase
961 * @return array Mixed values
963 function checkSystemCompliance() {
964 global $sugar_config;
965 global $current_language;
969 if(!defined('SUGARCRM_MIN_MEM')) {
970 define('SUGARCRM_MIN_MEM', 40);
973 $installer_mod_strings = getModuleLanguagePack($current_language, './install');
975 $ret['error_found'] = false;
978 $php_version = constant('PHP_VERSION');
979 $check_php_version_result = check_php_version($php_version);
981 switch($check_php_version_result) {
983 $ret['phpVersion'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_PHP_INVALID_VER']} {$php_version} )</span></b>";
984 $ret['error_found'] = true;
987 $ret['phpVersion'] = "<b><span class=go>{$installer_mod_strings['ERR_CHECKSYS_PHP_UNSUPPORTED']} {$php_version} )</span></b>";
990 $ret['phpVersion'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_PHP_OK']} {$php_version} )</span></b>";
994 // database and connect
996 if($db->dbType == 'mysql')
998 if(version_compare($v, '4.1.2') < 0) {
999 $ret['error_found'] = true;
1000 $ret['mysqlVersion'] = "<b><span class=stop>".$mod_strings['ERR_UW_MYSQL_VERSION'].$v."</span></b>";
1002 } elseif($db->dbType == 'oci8') {
1003 if(!preg_match("/Oracle9i|Oracle Database 10g|11/i", $v)) {
1004 $ret['error_found'] = true;
1005 $ret['ociVersion'] = "<b><span class=stop>".$mod_strings['ERR_UW_OCI8_VERSION'].$v."</span></b>";
1011 if(function_exists('xml_parser_create')) {
1012 $ret['xmlStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1014 $ret['xmlStatus'] = "<b><span class=stop>{$installer_mod_strings['LBL_CHECKSYS_NOT_AVAILABLE']}</span></b>";
1015 $ret['error_found'] = true;
1019 if(function_exists('curl_init')) {
1020 $ret['curlStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1022 $ret['curlStatus'] = "<b><span class=go>{$installer_mod_strings['ERR_CHECKSYS_CURL']}</span></b>";
1023 $ret['error_found'] = false;
1027 if(function_exists('mb_strlen')) {
1028 $ret['mbstringStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1030 $ret['mbstringStatus'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_MBSTRING']}</span></b>";
1031 $ret['error_found'] = true;
1035 if(function_exists('imap_open')) {
1036 $ret['imapStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1038 $ret['imapStatus'] = "<b><span class=go>{$installer_mod_strings['ERR_CHECKSYS_IMAP']}</span></b>";
1039 $ret['error_found'] = false;
1044 if('1' == ini_get('safe_mode')) {
1045 $ret['safeModeStatus'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_SAFE_MODE']}</span></b>";
1046 $ret['error_found'] = true;
1048 $ret['safeModeStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1052 // call time pass by ref
1053 if('1' == ini_get('allow_call_time_pass_reference')) {
1054 $ret['callTimeStatus'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_CALL_TIME']}</span></b>";
1055 //continue upgrading
1057 $ret['callTimeStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1061 $ret['memory_msg'] = "";
1062 $memory_limit = "-1";//ini_get('memory_limit');
1063 $sugarMinMem = constant('SUGARCRM_MIN_MEM');
1064 // logic based on: http://us2.php.net/manual/en/ini.core.php#ini.memory-limit
1065 if( $memory_limit == "" ){ // memory_limit disabled at compile time, no memory limit
1066 $ret['memory_msg'] = "<b><span class=\"go\">{$installer_mod_strings['LBL_CHECKSYS_MEM_OK']}</span></b>";
1067 } elseif( $memory_limit == "-1" ){ // memory_limit enabled, but set to unlimited
1068 $ret['memory_msg'] = "<b><span class=\"go\">{$installer_mod_strings['LBL_CHECKSYS_MEM_UNLIMITED']}</span></b>";
1070 rtrim($memory_limit, 'M');
1071 $memory_limit_int = (int) $memory_limit;
1072 if( $memory_limit_int < constant('SUGARCRM_MIN_MEM') ){
1073 $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>";
1074 $ret['error_found'] = true;
1076 $ret['memory_msg'] = "<b><span class=\"go\">{$installer_mod_strings['LBL_CHECKSYS_OK']} ({$memory_limit})</span></b>";
1080 /* mbstring.func_overload
1081 $ret['mbstring.func_overload'] = '';
1082 $mb = ini_get('mbstring.func_overload');
1085 $ret['mbstring.func_overload'] = "<b><span class=\"stop\">{$mod_strings['ERR_UW_MBSTRING_FUNC_OVERLOAD']}</b>";
1086 $ret['error_found'] = true;
1094 * is a file that we blow away automagically
1096 function isAutoOverwriteFile($file) {
1097 $overwriteDirs = array(
1098 './sugar_version.php',
1099 './modules/UpgradeWizard/uw_main.tpl',
1101 $file = trim('.'.str_replace(clean_path(getcwd()), '', $file));
1103 if(in_array($file, $overwriteDirs)) {
1107 $fileExtension = substr(strrchr($file, "."), 1);
1108 if($fileExtension == 'tpl' || $fileExtension == 'html') {
1118 function logThis($entry, $path='') {
1119 global $mod_strings;
1120 if(file_exists('include/utils/sugar_file_utils.php')){
1121 require_once('include/utils/sugar_file_utils.php');
1123 $log = empty($path) ? clean_path(getcwd().'/upgradeWizard.log') : clean_path($path);
1125 // create if not exists
1126 if(!file_exists($log)) {
1127 if(function_exists('sugar_fopen')){
1128 $fp = @sugar_fopen($log, 'w+'); // attempts to create file
1131 $fp = fopen($log, 'w+'); // attempts to create file
1133 if(!is_resource($fp)) {
1134 $GLOBALS['log']->fatal('UpgradeWizard could not create the upgradeWizard.log file');
1135 die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
1138 if(function_exists('sugar_fopen')){
1139 $fp = @sugar_fopen($log, 'a+'); // write pointer at end of file
1142 $fp = @fopen($log, 'a+'); // write pointer at end of file
1145 if(!is_resource($fp)) {
1146 $GLOBALS['log']->fatal('UpgradeWizard could not open/lock upgradeWizard.log file');
1147 die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
1151 $line = date('r').' [UpgradeWizard] - '.$entry."\n";
1153 if(@fwrite($fp, $line) === false) {
1154 $GLOBALS['log']->fatal('UpgradeWizard could not write to upgradeWizard.log: '.$entry);
1155 die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
1158 if(is_resource($fp)) {
1166 * @desc This function is to be used in the upgrade process to preserve changes/customaizations made to pre 5.1 quickcreate layout.
1167 * 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
1168 * was automatically picked up by the quick create. [Addresses Bug 21469]
1169 * This function will check if customizations were made, and will create quickcreatedefs.php in the /cutom/working/$module_name directory.
1171 function updateQuickCreateDefs(){
1172 $d = dir('modules');
1173 $studio_modules = array();
1175 while($e = $d->read()){ //collect all studio modules.
1176 if(substr($e, 0, 1) == '.' || !is_dir('modules/' . $e))continue;
1177 if(file_exists('modules/' . $e . '/metadata/studio.php'))
1179 array_push($studio_modules, $e);
1183 foreach( $studio_modules as $modname ){ //for each studio enabled module
1184 //Check !exists modules/$modname/metadata/quickcreatedefs.php &&
1185 //exists custom/$modname/editviewdefs.php (module was customized) &&
1186 //!exists custom/$modname/quickcreateviewdefs.php
1188 $editviewdefs = "custom/working/modules/".$modname."/metadata/editviewdefs.php";
1189 $quickcreatedefs = "custom/working/modules/".$modname."/metadata/quickcreatedefs.php";
1191 if ( !file_exists("modules/".$modname."/metadata/quickcreatedefs.php") &&
1192 file_exists($editviewdefs) &&
1193 !file_exists($quickcreatedefs) ){
1194 //clone editviewdef and save it in custom/working/modules/metadata
1195 $GLOBALS['log']->debug("Copying editviewdefs.php as quickcreatedefs.php for the $modname module in custom/working/modules/$modname/metadata!");
1196 if(copy( $editviewdefs, $quickcreatedefs)){
1197 if(file_exists($quickcreatedefs) && is_readable($quickcreatedefs)){
1198 $file = file($quickcreatedefs);
1199 //replace 'EditView' with 'QuickCreate'
1200 $fp = fopen($quickcreatedefs,'w');
1201 foreach($file as &$line){
1202 if(preg_match('/^\s*\'EditView\'\s*=>\s*$/', $line) > 0){
1203 $line = "'QuickCreate' =>\n";
1211 $GLOBALS['log']->debug("Failed to replace 'EditView' with QuickCreate because $quickcreatedefs is either not readable or does not exist.");
1214 $GLOBALS['log']->debug("Failed to copy $editviewdefs to $quickcreatedefs!");
1221 * test perms for CREATE queries
1223 function testPermsCreate($db, $out) {
1224 logThis('Checking CREATE TABLE permissions...');
1225 global $mod_strings;
1227 if(!$db->checkPrivilege("CREATE TABLE")) {
1228 logThis('cannot CREATE TABLE!');
1229 $out['db']['dbNoCreate'] = true;
1230 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_CREATE']}</span></td></tr>";
1236 * test perms for INSERT
1238 function testPermsInsert($db, $out, $skip=false) {
1239 logThis('Checking INSERT INTO permissions...');
1240 global $mod_strings;
1242 if(!$db->checkPrivilege("INSERT")) {
1243 logThis('cannot INSERT INTO!');
1244 $out['db']['dbNoInsert'] = true;
1245 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_INSERT']}</span></td></tr>";
1252 * test perms for UPDATE TABLE
1254 function testPermsUpdate($db, $out, $skip=false) {
1255 logThis('Checking UPDATE TABLE permissions...');
1256 global $mod_strings;
1257 if(!$db->checkPrivilege("UPDATE")) {
1258 logThis('cannot UPDATE TABLE!');
1259 $out['db']['dbNoUpdate'] = true;
1260 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_UPDATE']}</span></td></tr>";
1267 * test perms for SELECT
1269 function testPermsSelect($db, $out, $skip=false) {
1270 logThis('Checking SELECT permissions...');
1271 global $mod_strings;
1272 if(!$db->checkPrivilege("SELECT")) {
1273 logThis('cannot SELECT!');
1274 $out['db']['dbNoSelect'] = true;
1275 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_SELECT']}</span></td></tr>";
1281 * test perms for DELETE
1283 function testPermsDelete($db, $out, $skip=false) {
1284 logThis('Checking DELETE FROM permissions...');
1285 global $mod_strings;
1286 if(!$db->checkPrivilege("DELETE")) {
1287 logThis('cannot DELETE FROM!');
1288 $out['db']['dbNoDelete'] = true;
1289 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_DELETE']}</span></td></tr>";
1296 * test perms for ALTER TABLE ADD COLUMN
1298 function testPermsAlterTableAdd($db, $out, $skip=false) {
1299 logThis('Checking ALTER TABLE ADD COLUMN permissions...');
1300 global $mod_strings;
1301 if(!$db->checkPrivilege("ADD COLUMN")) {
1302 logThis('cannot ADD COLUMN!');
1303 $out['db']['dbNoAddColumn'] = true;
1304 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_ADD_COLUMN']}</span></td></tr>";
1310 * test perms for ALTER TABLE ADD COLUMN
1312 function testPermsAlterTableChange($db, $out, $skip=false) {
1313 logThis('Checking ALTER TABLE CHANGE COLUMN permissions...');
1314 global $mod_strings;
1315 if(!$db->checkPrivilege("CHANGE COLUMN")) {
1316 logThis('cannot CHANGE COLUMN!');
1317 $out['db']['dbNoChangeColumn'] = true;
1318 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_CHANGE_COLUMN']}</span></td></tr>";
1324 * test perms for ALTER TABLE DROP COLUMN
1326 function testPermsAlterTableDrop($db, $out, $skip=false) {
1327 logThis('Checking ALTER TABLE DROP COLUMN permissions...');
1328 global $mod_strings;
1329 if(!$db->checkPrivilege("DROP COLUMN")) {
1330 logThis('cannot DROP COLUMN!');
1331 $out['db']['dbNoDropColumn'] = true;
1332 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_DROP_COLUMN']}</span></td></tr>";
1339 * test perms for DROP TABLE
1341 function testPermsDropTable($db, $out, $skip=false) {
1342 logThis('Checking DROP TABLE permissions...');
1343 global $mod_strings;
1344 if(!$db->checkPrivilege("DROP TABLE")) {
1345 logThis('cannot DROP TABLE!');
1346 $out['db']['dbNoDropTable'] = true;
1347 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_DROP_TABLE']}</span></td></tr>";
1352 function getFormattedError($error, $query) {
1353 $error = "<div><b>".$error;
1354 $error .= "</b>::{$query}</div>";
1360 * parses a query finding the table name
1361 * @param string query The query
1362 * @return string table The table
1364 function getTableFromQuery($query) {
1365 $standardQueries = array('ALTER TABLE', 'DROP TABLE', 'CREATE TABLE', 'INSERT INTO', 'UPDATE', 'DELETE FROM');
1366 $query = preg_replace("/[^A-Za-z0-9\_\s]/", "", $query);
1367 $query = trim(str_replace($standardQueries, '', $query));
1369 $firstSpc = strpos($query, " ");
1370 $end = ($firstSpc > 0) ? $firstSpc : strlen($query);
1371 $table = substr($query, 0, $end);
1378 function preLicenseCheck() {
1379 require_once('modules/UpgradeWizard/uw_files.php');
1381 global $sugar_config;
1382 global $mod_strings;
1383 global $sugar_version;
1385 if(!isset($sugar_version) || empty($sugar_version)) {
1386 require_once('./sugar_version.php');
1389 if(!isset($_SESSION['unzip_dir']) || empty($_SESSION['unzip_dir'])) {
1390 logThis('unzipping files in upgrade archive...');
1392 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
1394 //also come up with mechanism to read from upgrade-progress file
1395 if(!isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !is_file($_SESSION['install_file'])) {
1396 if (file_exists(clean_path($base_tmp_upgrade_dir)) && $handle = opendir(clean_path($base_tmp_upgrade_dir))) {
1397 while (false !== ($file = readdir($handle))) {
1398 if($file !="." && $file !="..") {
1399 if(is_file($base_tmp_upgrade_dir."/".$file."/manifest.php")){
1400 require_once($base_tmp_upgrade_dir."/".$file."/manifest.php");
1401 $package_name= $manifest['copy_files']['from_dir'];
1402 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")){
1403 $unzip_dir = $base_tmp_upgrade_dir."/".$file;
1404 if(file_exists("$base_upgrade_dir/patch/".$package_name.'.zip')){
1405 $_SESSION['install_file'] = $package_name.".zip";
1414 if(empty($_SESSION['install_file'])){
1415 unlinkUWTempFiles();
1417 echo 'Upload File not found so redirecting to Upgrade Start ';
1418 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1419 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1420 $upgrade_directories_not_found =<<<eoq
1421 <table cellpadding="3" cellspacing="0" border="0">
1423 <th colspan="2" align="left">
1424 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1429 $uwMain = $upgrade_directories_not_found;
1432 $install_file = "$base_upgrade_dir/patch/".basename(urldecode( $_SESSION['install_file'] ));
1434 if(empty($unzip_dir)){
1435 $unzip_dir = mk_temp_dir( $base_tmp_upgrade_dir );
1437 $zip_from_dir = ".";
1439 $zip_force_copy = array();
1442 logThis('Could not create a temporary directory using mk_temp_dir( $base_tmp_upgrade_dir )');
1443 die($mod_strings['ERR_UW_NO_CREATE_TMP_DIR']);
1446 //double check whether unzipped .
1447 if(file_exists($unzip_dir ."/scripts") && file_exists($unzip_dir."/manifest.php")){
1451 unzip( $install_file, $unzip_dir );
1454 // assumption -- already validated manifest.php at time of upload
1455 require_once( "$unzip_dir/manifest.php" );
1457 if( isset( $manifest['copy_files']['from_dir'] ) && $manifest['copy_files']['from_dir'] != "" ){
1458 $zip_from_dir = $manifest['copy_files']['from_dir'];
1460 if( isset( $manifest['copy_files']['to_dir'] ) && $manifest['copy_files']['to_dir'] != "" ){
1461 $zip_to_dir = $manifest['copy_files']['to_dir'];
1463 if( isset( $manifest['copy_files']['force_copy'] ) && $manifest['copy_files']['force_copy'] != "" ){
1464 $zip_force_copy = $manifest['copy_files']['force_copy'];
1466 if( isset( $manifest['version'] ) ){
1467 $version = $manifest['version'];
1469 if( !is_writable( "config.php" ) ){
1470 return $mod_strings['ERR_UW_CONFIG'];
1473 $_SESSION['unzip_dir'] = clean_path($unzip_dir);
1474 $_SESSION['zip_from_dir'] = clean_path($zip_from_dir);
1475 logThis('unzip done.');
1477 $unzip_dir = $_SESSION['unzip_dir'];
1478 $zip_from_dir = $_SESSION['zip_from_dir'];
1481 //check if $_SESSION['unzip_dir'] and $_SESSION['zip_from_dir'] exist
1482 if(!isset($_SESSION['unzip_dir']) || !file_exists($_SESSION['unzip_dir'])
1483 || !isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !file_exists($_SESSION['install_file'])){
1485 unlinkUWTempFiles();
1487 echo 'Upload File not found so redirecting to Upgrade Start ';
1488 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1489 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1490 $upgrade_directories_not_found =<<<eoq
1491 <table cellpadding="3" cellspacing="0" border="0">
1493 <th colspan="2" align="left">
1494 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1499 $uwMain = $upgrade_directories_not_found;
1503 $parserFiles = array();
1505 if(file_exists(clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarFields"))) {
1506 $parserFiles = findAllFiles(clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarFields"), $parserFiles);
1509 $cwd = clean_path(getcwd());
1510 foreach($parserFiles as $file) {
1511 $srcFile = clean_path($file);
1512 //$targetFile = clean_path(getcwd() . '/' . $srcFile);
1513 if (strpos($srcFile,".svn") !== false) {
1517 $targetFile = str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), $cwd, $srcFile);
1519 if(!is_dir(dirname($targetFile))) {
1520 mkdir_recursive(dirname($targetFile)); // make sure the directory exists
1523 if(!file_exists($targetFile))
1525 // handle sugar_version.php
1526 // C.L. - Added check for portal directory
1527 if(strpos($targetFile, 'sugar_version.php') !== false && !preg_match('/\/portal\/sugar_version\.php$/i', $targetFile)) {
1528 logThis('Skipping "sugar_version.php" - file copy will occur at end of successful upgrade', $path);
1529 $_SESSION['sugar_version_file'] = $srcFile;
1533 if(!copy($srcFile, $targetFile)) {
1534 logThis('*** ERROR: could not copy file: ' . $targetFile);
1536 $copiedFiles[] = $targetFile;
1542 //Also copy the SugarMerge files
1543 if(file_exists(clean_path($unzip_dir.'/'.$zip_from_dir."/UpgradeWizard510Files"))) {
1544 $parserFiles = findAllFiles(clean_path($unzip_dir.'/'.$zip_from_dir."/UpgradeWizard510Files"), $parserFiles);
1545 foreach($parserFiles as $file) {
1546 $srcFile = clean_path($file);
1547 if (strpos($srcFile,".svn") !== false) {
1550 $targetFile = str_replace(clean_path($unzip_dir.'/'.$zip_from_dir."/UpgradeWizard510Files"), $cwd, $srcFile);
1551 if(!is_dir(dirname($targetFile))) {
1552 mkdir_recursive(dirname($targetFile)); // make sure the directory exists
1554 logThis('updating UpgradeWizard code: '.$targetFile);
1555 copy_recursive($file, $targetFile);
1559 logThis ('is SugarConfig there '.file_exists(clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarObjects/SugarConfig.php")));
1560 if(file_exists(clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarObjects/SugarConfig.php"))) {
1561 $file = clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarObjects/SugarConfig.php");
1562 $destFile = str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), $cwd, $file);
1563 if(!is_dir(dirname($destFile))) {
1564 mkdir_recursive(dirname($destFile)); // make sure the directory exists
1566 copy($file,$destFile);
1567 //also copy include utils array utils
1568 $file = clean_path($unzip_dir.'/'.$zip_from_dir."/include/utils/array_utils.php");
1569 $destFile = str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), $cwd, $file);
1570 if(!is_dir(dirname($destFile))) {
1571 mkdir_recursive(dirname($destFile)); // make sure the directory exists
1573 copy($file,$destFile);
1578 function preflightCheck() {
1579 require_once('modules/UpgradeWizard/uw_files.php');
1581 global $sugar_config;
1582 global $mod_strings;
1583 global $sugar_version;
1585 if(!isset($sugar_version) || empty($sugar_version)) {
1586 require_once('./sugar_version.php');
1589 unset($_SESSION['rebuild_relationships']);
1590 unset($_SESSION['rebuild_extensions']);
1592 // don't bother if are rechecking
1593 $manualDiff = array();
1594 if(!isset($_SESSION['unzip_dir']) || empty($_SESSION['unzip_dir'])) {
1595 logThis('unzipping files in upgrade archive...');
1597 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
1599 //Following is if User logged out unexpectedly and then logged into UpgradeWizard again.
1600 //also come up with mechanism to read from upgrade-progress file.
1601 if(!isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !is_file($_SESSION['install_file'])) {
1602 if (file_exists($base_tmp_upgrade_dir) && $handle = opendir($base_tmp_upgrade_dir)) {
1603 while (false !== ($file = readdir($handle))) {
1604 if($file !="." && $file !="..") {
1605 if(is_file($base_tmp_upgrade_dir."/".$file."/manifest.php")){
1606 require_once($base_tmp_upgrade_dir."/".$file."/manifest.php");
1607 $package_name= $manifest['copy_files']['from_dir'];
1608 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")){
1609 $unzip_dir = $base_tmp_upgrade_dir."/".$file;
1610 if(file_exists("$base_upgrade_dir/patch/".$package_name.'.zip')){
1611 $_SESSION['install_file'] = $package_name.".zip";
1620 if(empty($_SESSION['install_file'])){
1621 unlinkUWTempFiles();
1623 echo 'Upload File not found so redirecting to Upgrade Start ';
1624 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1625 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1626 $upgrade_directories_not_found =<<<eoq
1627 <table cellpadding="3" cellspacing="0" border="0">
1629 <th colspan="2" align="left">
1630 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1635 $uwMain = $upgrade_directories_not_found;
1639 $install_file = "$base_upgrade_dir/patch/".basename(urldecode( $_SESSION['install_file'] ));
1641 if(empty($unzip_dir)){
1642 $unzip_dir = mk_temp_dir( $base_tmp_upgrade_dir );
1644 $zip_from_dir = ".";
1646 $zip_force_copy = array();
1649 logThis('Could not create a temporary directory using mk_temp_dir( $base_tmp_upgrade_dir )');
1650 die($mod_strings['ERR_UW_NO_CREATE_TMP_DIR']);
1653 //double check whether unzipped .
1654 if(file_exists($unzip_dir ."/scripts") && file_exists($unzip_dir."/manifest.php")){
1658 unzip( $install_file, $unzip_dir );
1661 // assumption -- already validated manifest.php at time of upload
1662 require_once( "$unzip_dir/manifest.php" );
1664 if( isset( $manifest['copy_files']['from_dir'] ) && $manifest['copy_files']['from_dir'] != "" ){
1665 $zip_from_dir = $manifest['copy_files']['from_dir'];
1667 if( isset( $manifest['copy_files']['to_dir'] ) && $manifest['copy_files']['to_dir'] != "" ){
1668 $zip_to_dir = $manifest['copy_files']['to_dir'];
1670 if( isset( $manifest['copy_files']['force_copy'] ) && $manifest['copy_files']['force_copy'] != "" ){
1671 $zip_force_copy = $manifest['copy_files']['force_copy'];
1673 if( isset( $manifest['version'] ) ){
1674 $version = $manifest['version'];
1676 if( !is_writable( "config.php" ) ){
1677 return $mod_strings['ERR_UW_CONFIG'];
1680 $_SESSION['unzip_dir'] = clean_path($unzip_dir);
1681 $_SESSION['zip_from_dir'] = clean_path($zip_from_dir);
1683 //logThis('unzip done.');
1685 $unzip_dir = $_SESSION['unzip_dir'];
1686 $zip_from_dir = $_SESSION['zip_from_dir'];
1688 //check if $_SESSION['unzip_dir'] and $_SESSION['zip_from_dir'] exist
1689 if(!isset($_SESSION['unzip_dir']) || !file_exists($_SESSION['unzip_dir'])
1690 || !isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !file_exists($_SESSION['install_file'])){
1692 unlinkUWTempFiles();
1694 echo 'Upload File not found so redirecting to Upgrade Start ';
1695 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1696 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1697 $upgrade_directories_not_found =<<<eoq
1698 <table cellpadding="3" cellspacing="0" border="0">
1700 <th colspan="2" align="left">
1701 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1706 $uwMain = $upgrade_directories_not_found;
1709 //copy minimum required files
1710 fileCopy('include/utils/sugar_file_utils.php');
1712 $upgradeFiles = findAllFiles(clean_path("$unzip_dir/$zip_from_dir"), array());
1713 $cache_html_files= array();
1716 $md5_string = array();
1717 if(file_exists(clean_path(getcwd().'/files.md5'))){
1718 require(clean_path(getcwd().'/files.md5'));
1721 // file preflight checks
1722 logThis('verifying md5 checksums for files...');
1723 foreach($upgradeFiles as $file) {
1724 if(in_array(str_replace(clean_path("$unzip_dir/$zip_from_dir") . "/", '', $file), $uw_files))
1725 continue; // skip already loaded files
1727 if(strpos($file, '.md5'))
1728 continue; // skip md5 file
1730 // normalize file paths
1731 $file = clean_path($file);
1733 // check that we can move/delete the upgraded file
1734 if(!is_writable($file)) {
1735 $errors[] = $mod_strings['ERR_UW_FILE_NOT_WRITABLE'].": ".$file;
1737 // check that destination files are writable
1738 $destFile = getcwd().str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), '', $file);
1740 if(is_file($destFile)) { // of course it needs to exist first...
1741 if(!is_writable($destFile)) {
1742 $errors[] = $mod_strings['ERR_UW_FILE_NOT_WRITABLE'].": ".$destFile;
1746 ///////////////////////////////////////////////////////////////////////
1748 // compare md5s and build up a manual merge list
1749 $targetFile = clean_path(".".str_replace(getcwd(),'',$destFile));
1751 if(is_file($destFile)) {
1752 if(strpos($targetFile, '.php')) {
1753 // handle PHP files that were hit with the security regex
1755 if(function_exists('sugar_fopen')){
1756 $fp = sugar_fopen($destFile, 'r');
1759 $fp = fopen($destFile, 'r');
1761 $filesize = filesize($destFile);
1763 $fileContents = stream_get_contents($fp);
1764 $targetMd5 = md5($fileContents);
1767 $targetMd5 = md5_file($destFile);
1771 if(isset($md5_string[$targetFile]) && $md5_string[$targetFile] != $targetMd5) {
1772 logThis('found a file with a differing md5: ['.$targetFile.']');
1773 $manualDiff[] = $destFile;
1776 ///////////////////////////////////////////////////////////////////////
1778 logThis('md5 verification done.');
1779 $errors['manual'] = $manualDiff;
1784 function fileCopy($file_path){
1785 if(file_exists(clean_path($_SESSION['unzip_dir'].'/'.$_SESSION['zip_from_dir'].'/'.$file_path))) {
1786 $file = clean_path($_SESSION['unzip_dir'].'/'.$_SESSION['zip_from_dir'].'/'.$file_path);
1787 $destFile = str_replace(clean_path($_SESSION['unzip_dir'].'/'.$_SESSION['zip_from_dir']), clean_path(getcwd()), $file);
1788 if(!is_dir(dirname($destFile))) {
1789 mkdir_recursive(dirname($destFile)); // make sure the directory exists
1791 copy_recursive($file,$destFile);
1794 function getChecklist($steps, $step) {
1795 global $mod_strings;
1797 $skip = array('start', 'cancel', 'uninstall','end');
1800 $ret = '<table cellpadding="3" cellspacing="4" border="0">';
1801 $ret .= '<tr><th colspan="3" align="left">'.$mod_strings['LBL_UW_CHECKLIST'].':</th></tr>';
1802 foreach($steps['desc'] as $k => $desc) {
1803 if(in_array($steps['files'][$j], $skip)) {
1808 //$status = "<span class='error'>{$mod_strings['LBL_UW_INCOMPLETE']}</span>";
1810 $desc_mod_post = '';
1812 if(isset($_SESSION['step'][$steps['files'][$k]]) && $_SESSION['step'][$steps['files'][$k]] == 'success') {
1813 //$status = $mod_strings['LBL_UW_COMPLETE'];
1817 if($k == $_REQUEST['step']) {
1818 //$status = $mod_strings['LBL_UW_IN_PROGRESS'];
1819 $desc_mod_pre = "<font color=blue><i>";
1820 $desc_mod_post = "</i></font>";
1823 $ret .= "<tr><td> </td><td><b>{$i}: {$desc_mod_pre}{$desc}{$desc_mod_post}</b></td>";
1824 $ret .= "<td id={$steps['files'][$j]}><i></i></td></tr>";
1832 function prepSystemForUpgrade() {
1833 global $sugar_config;
1834 global $sugar_flavor;
1835 global $mod_strings;
1837 global $base_upgrade_dir;
1838 global $base_tmp_upgrade_dir;
1839 list($p_base_upgrade_dir, $p_base_tmp_upgrade_dir) = getUWDirs();
1840 ///////////////////////////////////////////////////////////////////////////////
1841 //// Make sure variables exist
1842 if(empty($base_upgrade_dir)){
1843 $base_upgrade_dir = $p_base_upgrade_dir;
1845 if(empty($base_tmp_upgrade_dir)){
1846 $base_tmp_upgrade_dir = $p_base_tmp_upgrade_dir;
1848 sugar_mkdir($base_tmp_upgrade_dir, 0775, true);
1849 if(!isset($subdirs) || empty($subdirs)){
1850 $subdirs = array('full', 'langpack', 'module', 'patch', 'theme');
1853 $upgrade_progress_dir = $base_tmp_upgrade_dir;
1854 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
1855 if(file_exists($upgrade_progress_file)){
1856 if(function_exists('get_upgrade_progress') && function_exists('didThisStepRunBefore')){
1857 if(didThisStepRunBefore('end')){
1858 include($upgrade_progress_file);
1859 unset($upgrade_config);
1860 unlink($upgrade_progress_file);
1865 // increase the cuttoff time to 1 hour
1866 ini_set("max_execution_time", "3600");
1868 // make sure dirs exist
1869 if($subdirs != null){
1870 foreach($subdirs as $subdir) {
1871 sugar_mkdir("$base_upgrade_dir/$subdir", 0775, true);
1874 // array of special scripts that are executed during (un)installation-- key is type of script, value is filename
1875 if(!defined('SUGARCRM_PRE_INSTALL_FILE')) {
1876 define('SUGARCRM_PRE_INSTALL_FILE', 'scripts/pre_install.php');
1877 define('SUGARCRM_POST_INSTALL_FILE', 'scripts/post_install.php');
1878 define('SUGARCRM_PRE_UNINSTALL_FILE', 'scripts/pre_uninstall.php');
1879 define('SUGARCRM_POST_UNINSTALL_FILE', 'scripts/post_uninstall.php');
1882 $script_files = array(
1883 "pre-install" => constant('SUGARCRM_PRE_INSTALL_FILE'),
1884 "post-install" => constant('SUGARCRM_POST_INSTALL_FILE'),
1885 "pre-uninstall" => constant('SUGARCRM_PRE_UNINSTALL_FILE'),
1886 "post-uninstall" => constant('SUGARCRM_POST_UNINSTALL_FILE'),
1889 // check that the upload limit is set to 6M or greater
1890 define('SUGARCRM_MIN_UPLOAD_MAX_FILESIZE_BYTES', 6 * 1024 * 1024); // 6 Megabytes
1891 $upload_max_filesize = ini_get('upload_max_filesize');
1892 $upload_max_filesize_bytes = return_bytes($upload_max_filesize);
1894 if($upload_max_filesize_bytes < constant('SUGARCRM_MIN_UPLOAD_MAX_FILESIZE_BYTES')) {
1895 $GLOBALS['log']->debug("detected upload_max_filesize: $upload_max_filesize");
1897 echo '<p class="error">'.$mod_strings['MSG_INCREASE_UPLOAD_MAX_FILESIZE'].' '.get_cfg_var('cfg_file_path')."</p>\n";
1901 if ( !function_exists('extractFile') ) {
1902 function extractFile($zip_file, $file_in_zip) {
1903 global $base_tmp_upgrade_dir;
1906 $absolute_base_tmp_upgrade_dir = clean_path($base_tmp_upgrade_dir);
1907 $relative_base_tmp_upgrade_dir = clean_path(str_replace(clean_path(getcwd()), '', $absolute_base_tmp_upgrade_dir));
1909 // mk_temp_dir expects relative pathing
1910 $my_zip_dir = mk_temp_dir($relative_base_tmp_upgrade_dir);
1912 unzip_file($zip_file, $file_in_zip, $my_zip_dir);
1914 return("$my_zip_dir/$file_in_zip");
1918 if ( !function_exists('extractManifest') ) {
1919 function extractManifest($zip_file) {
1920 logThis('extracting manifest.');
1921 return(extractFile($zip_file, "manifest.php"));
1925 if ( !function_exists('getInstallType') ) {
1926 function getInstallType($type_string) {
1929 $subdirs = array('full', 'langpack', 'module', 'patch', 'theme', 'temp');
1930 foreach($subdirs as $subdir) {
1931 if(preg_match("#/$subdir/#", $type_string)) {
1935 // return empty if no match
1940 function getImageForType($type) {
1942 global $mod_strings;
1947 $icon = SugarThemeRegistry::current()->getImage("Upgrade", "",null,null,'.gif',$mod_strings['LBL_UPGRADE']);
1950 $icon = SugarThemeRegistry::current()->getImage("LanguagePacks", "",null,null,'.gif',$mod_strings['LBL_LANGPACKS']);
1953 $icon = SugarThemeRegistry::current()->getImage("ModuleLoader", "",null,null,'.gif',$mod_strings['LBL_MODULELOADER']);
1956 $icon = SugarThemeRegistry::current()->getImage("PatchUpgrades", "",null,null,'.gif',$mod_strings['LBL_PATCHUPGRADES']);
1959 $icon = SugarThemeRegistry::current()->getImage("Themes", "",null,null,'.gif',$mod_strings['LBL_THEMES']);
1967 if ( !function_exists('getLanguagePackName') ) {
1968 function getLanguagePackName($the_file) {
1969 require_once("$the_file");
1970 if(isset($app_list_strings["language_pack_name"])) {
1971 return($app_list_strings["language_pack_name"]);
1977 function getUITextForType($type) {
1978 if($type == "full") {
1979 return("Full Upgrade");
1981 if($type == "langpack") {
1982 return("Language Pack");
1984 if($type == "module") {
1987 if($type == "patch") {
1990 if($type == "theme") {
1995 if ( !function_exists('validate_manifest') ) {
1997 * Verifies a manifest from a patch or module to be compatible with the current Sugar version and flavor
1998 * @param array manifest Standard manifest array
1999 * @return string Error message, blank on success
2001 function validate_manifest($manifest) {
2002 logThis('validating manifest.php file');
2003 // takes a manifest.php manifest array and validates contents
2005 global $sugar_version;
2006 global $sugar_flavor;
2007 global $mod_strings;
2009 if(!isset($manifest['type'])) {
2010 return $mod_strings['ERROR_MANIFEST_TYPE'];
2013 $type = $manifest['type'];
2015 if(getInstallType("/$type/") == "") {
2016 return $mod_strings['ERROR_PACKAGE_TYPE']. ": '" . $type . "'.";
2019 if(isset($manifest['acceptable_sugar_versions'])) {
2020 $version_ok = false;
2021 $matches_empty = true;
2022 if(isset($manifest['acceptable_sugar_versions']['exact_matches'])) {
2023 $matches_empty = false;
2024 foreach($manifest['acceptable_sugar_versions']['exact_matches'] as $match) {
2025 if($match == $sugar_version) {
2030 if(!$version_ok && isset($manifest['acceptable_sugar_versions']['regex_matches'])) {
2031 $matches_empty = false;
2032 foreach($manifest['acceptable_sugar_versions']['regex_matches'] as $match) {
2033 if(preg_match("/$match/", $sugar_version)) {
2039 if(!$matches_empty && !$version_ok) {
2040 return $mod_strings['ERROR_VERSION_INCOMPATIBLE']."<br />".
2041 $mod_strings['ERR_UW_VERSION'].$sugar_version;
2045 if(isset($manifest['acceptable_sugar_flavors']) && sizeof($manifest['acceptable_sugar_flavors']) > 0) {
2047 foreach($manifest['acceptable_sugar_flavors'] as $match) {
2048 if($match == $sugar_flavor) {
2053 return $mod_strings['ERROR_FLAVOR_INCOMPATIBLE']."<br />".
2054 $mod_strings['ERR_UW_FLAVOR'].$sugar_flavor."<br />".
2055 $mod_strings['ERR_UW_FLAVOR_2'].$manifest['acceptable_sugar_flavors'][0];
2063 function unlinkUploadFiles() {
2065 // logThis('at unlinkUploadFiles()');
2067 // if(isset($_SESSION['install_file']) && !empty($_SESSION['install_file'])) {
2068 // $upload = $_SESSION['install_file'];
2070 // if(is_file($upload)) {
2071 // logThis('unlinking ['.$upload.']');
2072 // @unlink($upload);
2078 * deletes files created by unzipping a package
2080 function unlinkUWTempFiles() {
2081 global $sugar_config;
2084 logThis('at unlinkUWTempFiles()');
2086 list($upgDir, $tempDir) = getUWDirs();
2088 if(file_exists($tempDir) && is_dir($tempDir)){
2089 $files = findAllFiles($tempDir, array(), false);
2091 foreach($files as $file) {
2092 if(!is_dir($file)) {
2093 //logThis('unlinking ['.$file.']', $path);
2098 $files = findAllFiles($tempDir, array(), true);
2099 foreach($files as $dir) {
2101 //logThis('removing dir ['.$dir.']', $path);
2105 $cacheFile = sugar_cached("modules/UpgradeWizard/_persistence.php");
2106 if(is_file($cacheFile)) {
2107 logThis("Unlinking Upgrade cache file: '_persistence.php'", $path);
2108 @unlink($cacheFile);
2111 logThis("finished!");
2115 * finds all files in the passed path, but skips select directories
2116 * @param string dir Relative path
2117 * @param array the_array Collections of found files/dirs
2118 * @param bool include_dir True if we want to include directories in the
2119 * returned collection
2121 function uwFindAllFiles($dir, $theArray, $includeDirs=false, $skipDirs=array(), $echo=false) {
2123 if (whetherNeedToSkipDir($dir, $skipDirs))
2128 if (!is_dir($dir)) { return $theArray; } // Bug # 46035, just checking for valid dir
2130 if ($d === false) { return $theArray; } // Bug # 46035, more checking
2132 while($f = $d->read()) {
2133 // bug 40793 Skip Directories array in upgradeWizard does not function correctly
2134 if($f == "." || $f == ".." || whetherNeedToSkipDir("$dir/$f", $skipDirs)) { // skip *nix self/parent
2138 // for AJAX length count
2144 if(is_dir("$dir/$f")) {
2145 if($includeDirs) { // add the directory if flagged
2146 $theArray[] = clean_path("$dir/$f");
2150 $theArray = uwFindAllFiles("$dir/$f/", $theArray, $includeDirs, $skipDirs, $echo);
2152 $theArray[] = clean_path("$dir/$f");
2165 * unset's UW's Session Vars
2167 function resetUwSession() {
2168 logThis('resetting $_SESSION');
2170 if(isset($_SESSION['committed']))
2171 unset($_SESSION['committed']);
2172 if(isset($_SESSION['sugar_version_file']))
2173 unset($_SESSION['sugar_version_file']);
2174 if(isset($_SESSION['upgrade_complete']))
2175 unset($_SESSION['upgrade_complete']);
2176 if(isset($_SESSION['allTables']))
2177 unset($_SESSION['allTables']);
2178 if(isset($_SESSION['alterCustomTableQueries']))
2179 unset($_SESSION['alterCustomTableQueries']);
2180 if(isset($_SESSION['skip_zip_upload']))
2181 unset($_SESSION['skip_zip_upload']);
2182 if(isset($_SESSION['sugar_version_file']))
2183 unset($_SESSION['sugar_version_file']);
2184 if(isset($_SESSION['install_file']))
2185 unset($_SESSION['install_file']);
2186 if(isset($_SESSION['unzip_dir']))
2187 unset($_SESSION['unzip_dir']);
2188 if(isset($_SESSION['zip_from_dir']))
2189 unset($_SESSION['zip_from_dir']);
2190 if(isset($_SESSION['overwrite_files']))
2191 unset($_SESSION['overwrite_files']);
2192 if(isset($_SESSION['schema_change']))
2193 unset($_SESSION['schema_change']);
2194 if(isset($_SESSION['uw_restore_dir']))
2195 unset($_SESSION['uw_restore_dir']);
2196 if(isset($_SESSION['step']))
2197 unset($_SESSION['step']);
2198 if(isset($_SESSION['files']))
2199 unset($_SESSION['files']);
2200 if(isset($_SESSION['Upgraded451Wizard'])){
2201 unset($_SESSION['Upgraded451Wizard']);
2203 if(isset($_SESSION['Initial_451to500_Step'])){
2204 unset($_SESSION['Initial_451to500_Step']);
2206 if(isset($_SESSION['license_shown']))
2207 unset($_SESSION['license_shown']);
2208 if(isset($_SESSION['sugarMergeRunResults']))
2209 unset($_SESSION['sugarMergeRunResults']);
2213 * runs rebuild scripts
2215 function UWrebuild() {
2219 //CCL - Comment this block out, it is called in end.php
2220 logThis('Rebuilding everything...', $path);
2221 require_once('modules/Administration/QuickRepairAndRebuild.php');
2222 $randc = new RepairAndClear();
2223 $randc->repairAndClearAll(array('clearAll'),array(translate('LBL_ALL_MODULES')), false, false);
2225 $query = "DELETE FROM versions WHERE name='Rebuild Extensions'";
2227 logThis('Registering rebuild record: '.$query, $path);
2228 logThis('Rebuild done.', $path);
2230 // insert a new database row to show the rebuild extensions is done
2231 $id = create_guid();
2232 $gmdate = gmdate('Y-m-d H:i:s');
2233 $date_entered = db_convert("'$gmdate'", 'datetime');
2234 $query = 'INSERT INTO versions (id, deleted, date_entered, date_modified, modified_user_id, created_by, name, file_version, db_version) '
2235 . "VALUES ('$id', '0', $date_entered, $date_entered, '1', '1', 'Rebuild Extensions', '4.0.0', '4.0.0')";
2237 logThis('Registering rebuild record in versions table: '.$query, $path);
2240 function getCustomTables() {
2243 return $db->tablesLike('%_cstm');
2246 function alterCustomTables($customTables)
2251 function getAllTables() {
2253 return $db->getTablesArray();
2256 function printAlterTableSql($tables)
2258 $alterTableSql = '';
2260 foreach($tables as $table)
2261 $alterTableSql .= "ALTER TABLE " . $table . " CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;" . "\n";
2263 return $alterTableSql;
2266 function executeConvertTablesSql($tables)
2270 foreach($tables as $table){
2271 $query = "ALTER TABLE " . $table . " CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci";
2273 logThis("Sending query: ".$query);
2274 $db->query($query);//, true, "An error has occured while performing db query. See log file for details.<br>");
2280 function testThis() {
2281 $files = uwFindAllFiles(getcwd().'/test', array());
2283 $out = "<table cellpadding='1' cellspacing='0' border='0'>\n";
2286 foreach($files as $file) {
2287 $relativeFile = clean_path(str_replace(getcwd().'/test', '', $file));
2288 $relativeFile = ($relativeFile{0} == '/') ? substr($relativeFile, 1, strlen($relativeFile)) : $relativeFile;
2290 $relativePath = dirname($relativeFile);
2292 if($relativePath == $priorPath) { // same dir, new file
2293 $out .= "<tr><td>".basename($relativeFile)."</td></tr>";
2294 $priorPath = $relativePath;
2308 function testThis2($dir, $id=0, $hide=false) {
2309 global $mod_strings;
2311 $dh = opendir($dir);
2314 $doHide = ($hide) ? 'none' : '';
2315 $out = "<div id='{$id}' style='display:{$doHide};'>";
2316 $out .= "<table cellpadding='1' cellspacing='0' border='0' style='border:0px solid #ccc'>\n";
2318 while($file = readdir($dh)) {
2319 if($file == '.' || $file == '..' || $file == 'CVS' || $file == '.cvsignore')
2322 if(is_dir($path.'/'.$file)) {
2323 $file = $path.'/'.$file;
2324 $newI = create_guid();
2325 $out .= "<tr><td valign='top'><a href='javascript:toggleNwFiles(\"{$newI}\");'>".SugarThemeRegistry::current()->getImage("Workflow", "", null, null, ".gif", $mod_strings['LBL_WORKFLOW'])."</a></td>\n";
2326 $out .= "<td valign='top'><b><a href='javascript:toggleNwFiles(\"{$newI}\");'>".basename($file)."</a></b></td></tr>";
2327 $out .= "<tr><td></td><td valign='top'>".testThis2($file, $newI, true)."</td></tr>";
2329 $out .= "<tr><td valign='top'> </td>\n";
2330 $out .= "<td valign='top'>".basename($file)."</td></tr>";
2334 $out .= "</tr></table>";
2345 function testThis3(&$files, $id, $hide, $previousPath = '') {
2346 if(!is_array($files) || empty($files))
2351 global $mod_strings;
2352 // expecting full path here
2353 foreach($files as $k => $file) {
2354 $file = str_replace(getcwd(), '', $file);
2355 $path = dirname($file);
2356 $fileName = basename($file);
2358 if($fileName == 'CVS' || $fileName == '.cvsignore')
2361 if($path == $previousPath) { // same directory
2362 // new row for each file
2363 $out .= "<tr><td valign='top' align='left'> </td>";
2364 $out .= "<td valign='top' align='left'>{$fileName}</td></tr>";
2365 } else { // new directory
2367 $out .= "<tr><td valign='top'><a href='javascript:toggleNwFiles(\"{$newI}\");'>".SugarThemeRegistry::current()->getImage("Workflow", "", null, null, ".gif", $mod_strings['LBL_WORKFLOW'])."</a></td>\n";
2368 $out .= "<td valign='top'><b><a href='javascript:toggleNwFiles(\"{$newI}\");'>".$fileName."</a></b></td></tr>";
2369 $recurse = testThis3($files, $newI, true, $previousPath);
2370 $out .= "<tr><td></td><td valign='top'>".$recurse."</td></tr>";
2373 $previousPath = $path;
2375 $display = ($hide) ? 'none' : '';
2377 <div id="{$id}" style="display:{$display}">
2378 <table cellpadding='1' cellspacing='0' border='0' style='border:1px solid #ccc'>
2387 function testThis4($filePath, $fileNodes=array(), $fileName='') {
2388 $path = dirname($filePath);
2389 $file = basename($filePath);
2391 $exFile = explode('/', $path);
2393 foreach($exFile as $pathSegment) {
2394 if(is_array($fileNodes[$pathSegment])) { // path already processed
2396 } else { // newly found path
2397 $fileNodes[$pathSegment] = array();
2400 if($fileName != '') {
2401 $fileNodes[$pathSegment][] = $fileName;
2410 ///////////////////////////////////////////////////////////////////////////////
2411 //// SYSTEM CHECK FUNCTIONS
2413 * generates an array with all files in the SugarCRM root directory, skipping
2415 * @return array files Array of files with absolute paths
2417 function getFilesForPermsCheck() {
2418 global $sugar_config;
2420 logThis('Got JSON call to find all files...');
2421 $filesNotWritable = array();
2422 $filesNWPerms = array();
2424 // add directories here that should be skipped when doing file permissions checks (cache/upload is the nasty one)
2426 $sugar_config['upload_dir'],
2428 $files = uwFindAllFiles(".", array(), true, $skipDirs, true);
2433 * checks files for permissions
2434 * @param array files Array of files with absolute paths
2435 * @return string result of check
2437 function checkFiles($files, $echo=false) {
2438 global $mod_strings;
2439 $filesNotWritable = array();
2442 <a href='javascript:void(0); toggleNwFiles(\"filesNw\");'>{$mod_strings['LBL_UW_SHOW_NW_FILES']}</a>
2443 <div id='filesNw' style='display:none;'>
2444 <table cellpadding='3' cellspacing='0' border='0'>
2446 <th align='left'>{$mod_strings['LBL_UW_FILE']}</th>
2447 <th align='left'>{$mod_strings['LBL_UW_FILE_PERMS']}</th>
2448 <th align='left'>{$mod_strings['LBL_UW_FILE_OWNER']}</th>
2449 <th align='left'>{$mod_strings['LBL_UW_FILE_GROUP']}</th>
2452 $isWindows = is_windows();
2453 foreach($files as $file) {
2456 if(!is_writable_windows($file)) {
2457 logThis('WINDOWS: File ['.$file.'] not readable - saving for display');
2458 // don't warn yet - we're going to use this to check against replacement files
2459 // aw: commented out; it's a hack to allow upgrade wizard to continue on windows... will fix later
2460 /*$filesNotWritable[$i] = $file;
2461 $filesNWPerms[$i] = substr(sprintf('%o',fileperms($file)), -4);
2462 $filesOut .= "<tr>".
2463 "<td><span class='error'>{$file}</span></td>".
2464 "<td>{$filesNWPerms[$i]}</td>".
2465 "<td>".$mod_strings['ERR_UW_CANNOT_DETERMINE_USER']."</td>".
2466 "<td>".$mod_strings['ERR_UW_CANNOT_DETERMINE_GROUP']."</td>".
2470 if(!is_writable($file)) {
2471 logThis('File ['.$file.'] not writable - saving for display');
2472 // don't warn yet - we're going to use this to check against replacement files
2473 $filesNotWritable[$i] = $file;
2474 $filesNWPerms[$i] = substr(sprintf('%o',fileperms($file)), -4);
2475 $owner = posix_getpwuid(fileowner($file));
2476 $group = posix_getgrgid(filegroup($file));
2477 $filesOut .= "<tr>".
2478 "<td><span class='error'>{$file}</span></td>".
2479 "<td>{$filesNWPerms[$i]}</td>".
2480 "<td>".$owner['name']."</td>".
2481 "<td>".$group['name']."</td>".
2488 $filesOut .= '</table></div>';
2490 $errors['files']['filesNotWritable'] = (count($filesNotWritable) > 0) ? true : false;
2491 if(count($filesNotWritable) < 1) {
2492 $filesOut = "{$mod_strings['LBL_UW_FILE_NO_ERRORS']}";
2498 function deletePackageOnCancel(){
2499 global $mod_strings;
2500 global $sugar_config;
2501 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
2502 logThis('running delete');
2503 if(!isset($_SESSION['install_file']) || ($_SESSION['install_file'] == "")) {
2504 logThis('ERROR: trying to delete non-existent file: ['.$_REQUEST['install_file'].']');
2505 $error = $mod_strings['ERR_UW_NO_FILE_UPLOADED'];
2507 // delete file in upgrades/patch
2508 $delete_me = "$base_upgrade_dir/patch/".basename(urldecode( $_REQUEST['install_file'] ));
2509 if(@unlink($delete_me)) {
2510 //logThis('unlinking: '.$delete_me);
2511 $out = basename($delete_me).$mod_strings['LBL_UW_FILE_DELETED'];
2513 logThis('ERROR: could not delete ['.$delete_me.']');
2514 $error = $mod_strings['ERR_UW_FILE_NOT_DELETED'].$delete_me;
2517 if(!empty($error)) {
2518 $out = "<b><span class='error'>{$error}</span></b><br />";
2522 function parseAndExecuteSqlFile($sqlScript,$forStepQuery='',$resumeFromQuery='')
2524 global $sugar_config;
2525 $alterTableSchema = '';
2526 $sqlErrors = array();
2527 if(!isset($_SESSION['sqlSkippedQueries'])){
2528 $_SESSION['sqlSkippedQueries'] = array();
2530 $db = DBManagerFactory::getInstance();
2531 $disable_keys = $db->supports("disable_keys");
2532 if(strpos($resumeFromQuery,",") != false){
2533 $resumeFromQuery = explode(",",$resumeFromQuery);
2535 if(file_exists($sqlScript)) {
2536 $fp = fopen($sqlScript, 'r');
2537 $contents = stream_get_contents($fp);
2538 $anyScriptChanges =$contents;
2539 $resumeAfterFound = false;
2543 while($line = fgets($fp)) {
2544 if(strpos($line, '--') === false) {
2545 $completeLine .= " ".trim($line);
2546 if(strpos($line, ';') !== false) {
2548 $query = str_replace(';','',$completeLine);
2549 //if resume from query is not null then find out from where
2550 //it should start executing the query.
2552 if($query != null && $resumeFromQuery != null){
2553 if(!$resumeAfterFound){
2554 if(strpos($query,",") != false){
2555 $queArray = explode(",",$query);
2556 for($i=0;$i<sizeof($resumeFromQuery);$i++){
2557 if(strcasecmp(trim($resumeFromQuery[$i]),trim($queArray[$i]))==0){
2558 $resumeAfterFound = true;
2560 $resumeAfterFound = false;
2566 elseif(strcasecmp(trim($resumeFromQuery),trim($query))==0){
2567 $resumeAfterFound = true;
2570 if($resumeAfterFound){
2573 // if $count=1 means it is just found so skip the query. Run the next one
2574 if($query != null && $resumeAfterFound && $count >1){
2575 $tableName = getAlterTable($query);
2576 if($disable_keys && !empty($tableName))
2578 $db->disableKeys($tableName);
2581 if($db->checkError()){
2582 //put in the array to use later on
2583 $_SESSION['sqlSkippedQueries'][] = $query;
2585 if($disable_keys && !empty($tableName))
2587 $db->enableKeys($tableName);
2589 $progQuery[$forStepQuery]=$query;
2590 post_install_progress($progQuery,$action='set');
2593 elseif($query != null){
2594 $tableName = getAlterTable($query);
2595 if($disable_keys && !empty($tableName))
2597 $db->disableKeys($tableName);
2600 if($disable_keys && !empty($tableName))
2602 $db->enableKeys($tableName);
2604 $progQuery[$forStepQuery]=$query;
2605 post_install_progress($progQuery,$action='set');
2606 if($db->checkError()){
2607 //put in the array to use later on
2608 $_SESSION['sqlSkippedQueries'][] = $query;
2620 function getAlterTable($query){
2621 $query = strtolower($query);
2622 if (preg_match('/^\s*alter\s+table\s+/', $query)) {
2623 $sqlArray = explode(" ", $query);
2624 $key = array_search('table', $sqlArray);
2625 return $sqlArray[($key+1)];
2631 function set_upgrade_vars(){
2632 logThis('setting session variables...');
2633 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2634 if(!is_dir($upgrade_progress_dir)){
2635 mkdir_recursive($upgrade_progress_dir);
2637 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2638 if(file_exists($upgrade_progress_file)){
2639 include($upgrade_progress_file);
2642 fopen($upgrade_progress_file, 'w+');
2644 if(!isset($upgrade_config) || $upgrade_config == null){
2645 $upgrade_config = array();
2646 $upgrade_config[1]['upgrade_vars']=array();
2648 if(isset($upgrade_config[1]) && isset($upgrade_config[1]['upgrade_vars']) && !is_array($upgrade_config[1]['upgrade_vars'])){
2649 $upgrade_config[1]['upgrade_vars'] = array();
2652 if(!isset($upgrade_vars) || $upgrade_vars == NULL){
2653 $upgrade_vars = array();
2655 if(isset($_SESSION['unzip_dir']) && !empty($_SESSION['unzip_dir']) && file_exists($_SESSION['unzip_dir'])){
2656 $upgrade_vars['unzip_dir']=$_SESSION['unzip_dir'];
2658 if(isset($_SESSION['install_file']) && !empty($_SESSION['install_file']) && file_exists($_SESSION['install_file'])){
2659 $upgrade_vars['install_file']=$_SESSION['install_file'];
2661 if(isset($_SESSION['Upgraded451Wizard']) && !empty($_SESSION['Upgraded451Wizard'])){
2662 $upgrade_vars['Upgraded451Wizard']=$_SESSION['Upgraded451Wizard'];
2664 if(isset($_SESSION['license_shown']) && !empty($_SESSION['license_shown'])){
2665 $upgrade_vars['license_shown']=$_SESSION['license_shown'];
2667 if(isset($_SESSION['Initial_451to500_Step']) && !empty($_SESSION['Initial_451to500_Step'])){
2668 $upgrade_vars['Initial_451to500_Step']=$_SESSION['Initial_451to500_Step'];
2670 if(isset($_SESSION['zip_from_dir']) && !empty($_SESSION['zip_from_dir'])){
2671 $upgrade_vars['zip_from_dir']=$_SESSION['zip_from_dir'];
2673 //place into the upgrade_config array and rewrite config array only if new values are being inserted
2674 if(isset($upgrade_vars) && $upgrade_vars != null && sizeof($upgrade_vars) > 0){
2675 foreach($upgrade_vars as $key=>$val){
2676 if($key != null && $val != null){
2677 $upgrade_config[1]['upgrade_vars'][$key]=$upgrade_vars[$key];
2680 ksort($upgrade_config);
2681 if(is_writable($upgrade_progress_file) && write_array_to_file( "upgrade_config", $upgrade_config,
2682 $upgrade_progress_file)) {
2683 //writing to the file
2688 function initialize_session_vars(){
2689 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2690 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2691 if(file_exists($upgrade_progress_file)){
2692 include($upgrade_progress_file);
2693 if(isset($upgrade_config) && $upgrade_config != null && is_array($upgrade_config) && sizeof($upgrade_config) >0){
2694 $currVarsArray=$upgrade_config[1]['upgrade_vars'];
2695 //print_r($currVarsArray);
2696 if(isset($currVarsArray) && $currVarsArray != null && is_array($currVarsArray) && sizeof($currVarsArray)>0){
2697 foreach($currVarsArray as $key=>$val){
2698 if($key != null && $val !=null){
2699 //set session variables
2700 $_SESSION[$key]=$val;
2709 //track the upgrade progress on each step
2710 //track the upgrade progress on each step
2711 function set_upgrade_progress($currStep,$currState,$currStepSub='',$currStepSubState=''){
2713 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2714 if(!is_dir($upgrade_progress_dir)){
2715 mkdir_recursive($upgrade_progress_dir);
2717 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2718 if(file_exists($upgrade_progress_file)){
2719 include($upgrade_progress_file);
2722 if(function_exists('sugar_fopen')){
2723 sugar_fopen($upgrade_progress_file, 'w+');
2726 fopen($upgrade_progress_file, 'w+');
2729 if(!isset($upgrade_config) || $upgrade_config == null){
2730 $upgrade_config = array();
2731 $upgrade_config[1]['upgrade_vars']=array();
2733 if(!is_array($upgrade_config[1]['upgrade_vars'])){
2734 $upgrade_config[1]['upgrade_vars'] = array();
2736 if($currStep != null && $currState != null){
2737 if(sizeof($upgrade_config) > 0){
2738 if($currStepSub != null && $currStepSubState !=null){
2739 //check if new status to be set or update
2740 //get the latest in array. since it has sub components prepare an array
2741 if(!empty($upgrade_config[sizeof($upgrade_config)][$currStep]) && is_array($upgrade_config[sizeof($upgrade_config)][$currStep])){
2742 $latestStepSub = currSubStep($upgrade_config[sizeof($upgrade_config)][$currStep]);
2743 if($latestStepSub == $currStepSub){
2744 $upgrade_config[sizeof($upgrade_config)][$currStep][$latestStepSub]=$currStepSubState;
2745 $upgrade_config[sizeof($upgrade_config)][$currStep][$currStep] = $currState;
2748 $upgrade_config[sizeof($upgrade_config)][$currStep][$currStepSub]=$currStepSubState;
2749 $upgrade_config[sizeof($upgrade_config)][$currStep][$currStep] = $currState;
2753 $currArray = array();
2754 $currArray[$currStep] = $currState;
2755 $currArray[$currStepSub] = $currStepSubState;
2756 $upgrade_config[sizeof($upgrade_config)+1][$currStep] = $currArray;
2760 //get the current upgrade progress
2761 $latestStep = get_upgrade_progress();
2762 //set the upgrade progress
2763 if($latestStep == $currStep){
2764 //update the current step with new progress status
2765 $upgrade_config[sizeof($upgrade_config)][$latestStep]=$currState;
2769 $upgrade_config[sizeof($upgrade_config)+1][$currStep]=$currState;
2771 // now check if there elements within array substeps
2775 //set the upgrade progress (just starting)
2776 $upgrade_config[sizeof($upgrade_config)+1][$currStep]= $currState;
2779 if(is_writable($upgrade_progress_file) && write_array_to_file( "upgrade_config", $upgrade_config,
2780 $upgrade_progress_file)) {
2781 //writing to the file
2787 function get_upgrade_progress(){
2788 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2789 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2792 if(file_exists($upgrade_progress_file)){
2793 include($upgrade_progress_file);
2794 if(!isset($upgrade_config) || $upgrade_config == null){
2795 $upgrade_config = array();
2797 if($upgrade_config != null && sizeof($upgrade_config) >1){
2798 $currArr = $upgrade_config[sizeof($upgrade_config)];
2799 if(is_array($currArr)){
2800 foreach($currArr as $key=>$val){
2808 function currSubStep($currStep){
2810 if(is_array($currStep)){
2811 foreach($currStep as $key=>$val){
2819 function currUpgradeState($currState){
2821 if(is_array($currState)){
2822 foreach($currState as $key=>$val){
2824 foreach($val as $k=>$v){
2838 function didThisStepRunBefore($step,$SubStep=''){
2839 if($step == null) return;
2840 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2841 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2844 if(file_exists($upgrade_progress_file)){
2845 include($upgrade_progress_file);
2846 if(isset($upgrade_config) && $upgrade_config != null && is_array($upgrade_config) && sizeof($upgrade_config) >0){
2847 for($i=1;$i<=sizeof($upgrade_config);$i++){
2848 if(is_array($upgrade_config[$i])){
2849 foreach($upgrade_config[$i] as $key=>$val){
2851 if(is_array($upgrade_config[$i][$step])){
2853 foreach ($upgrade_config[$i][$step] as $k=>$v){
2855 foreach($v as $k1=>$v1){
2856 if($SubStep != null){
2857 if($SubStep ==$k1 && $v1=='done'){
2864 elseif($SubStep !=null){
2865 if($SubStep==$k && $v=='done'){
2870 elseif($step==$k && $v=='done'){
2876 elseif($val=='done'){
2890 //get and set post install status
2891 function post_install_progress($progArray='',$action=''){
2892 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2893 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2894 if($action=='' || $action=='get'){
2895 //get the state of post install
2896 $currProg = array();
2897 if(file_exists($upgrade_progress_file)){
2898 include($upgrade_progress_file);
2899 if(is_array($upgrade_config[sizeof($upgrade_config)]['commit']['post_install']) && sizeof($upgrade_config[sizeof($upgrade_config)]['commit']['post_install'])>0){
2900 foreach($upgrade_config[sizeof($upgrade_config)]['commit']['post_install'] as $k=>$v){
2907 elseif($action=='set'){
2908 if(!is_dir($upgrade_progress_dir)){
2909 mkdir($upgrade_progress_dir);
2911 if(file_exists($upgrade_progress_file)){
2912 include($upgrade_progress_file);
2915 fopen($upgrade_progress_file, 'w+');
2917 if(!is_array($upgrade_config[sizeof($upgrade_config)]['commit']['post_install'])){
2918 $upgrade_config[sizeof($upgrade_config)]['commit']['post_install']=array();
2919 $upgrade_config[sizeof($upgrade_config)]['commit']['post_install']['post_install'] = 'in_progress';
2921 if($progArray != null && is_array($progArray)){
2922 foreach($progArray as $key=>$val){
2923 $upgrade_config[sizeof($upgrade_config)]['commit']['post_install'][$key]=$val;
2926 if(is_writable($upgrade_progress_file) && write_array_to_file( "upgrade_config", $upgrade_config,
2927 $upgrade_progress_file)) {
2928 //writing to the file
2933 function repairDBForUpgrade($execute=false,$path=''){
2935 global $current_user, $beanFiles;
2937 set_time_limit(3600);
2939 $db = &DBManagerFactory::getInstance();
2941 VardefManager::clearVardef();
2942 require_once('include/ListView/ListView.php');
2943 foreach ($beanFiles as $bean => $file) {
2944 require_once ($file);
2945 $focus = new $bean ();
2946 $sql .= $db->repairTable($focus, $execute);
2950 $olddictionary = $dictionary;
2951 unset ($dictionary);
2952 include ('modules/TableDictionary.php');
2953 foreach ($dictionary as $meta) {
2954 $tablename = $meta['table'];
2955 $fielddefs = $meta['fields'];
2956 $indices = $meta['indices'];
2957 $sql .= $db->repairTableParams($tablename, $fielddefs, $indices, $execute);
2960 foreach (explode("\n", $sql) as $line) {
2961 if (!empty ($line) && substr($line, -2) != "*/") {
2964 $qry_str .= $line . "\n";
2975 preg_replace('#(/\*.+?\*/\n*)#', '', $qry_str)
2977 logThis("*******START EXECUTING DB UPGRADE QUERIES***************",$path);
2978 logThis($sql,$path);
2979 logThis("*******END EXECUTING DB UPGRADE QUERIES****************",$path);
2988 * upgradeUserPreferences
2989 * This method updates the user_preferences table and sets the pages/dashlets for users
2990 * which have ACL access to Trackers so that the Tracker dashlets are set in their user perferences
2993 function upgradeUserPreferences() {
2995 // check the current system wide default_locale_name_format and add it to the list if it's not there
2996 global $sugar_config;
2997 upgradeLocaleNameFormat($sugar_config['default_locale_name_format']);
2999 $db = &DBManagerFactory::getInstance();
3000 $result = $db->query("SELECT id FROM users where deleted = '0'");
3001 while($row = $db->fetchByAssoc($result))
3003 $current_user = new User();
3005 // 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
3006 upgradeLocaleNameFormat($current_user->getPreference('default_locale_name_format'));
3012 * Checks if a locale name format is part of the default list, if not adds it to the config
3013 * @param $name_format string a local name format string such as 's f l'
3014 * @return bool true on successful write to config file, false on failure;
3016 function upgradeLocaleNameFormat($name_format) {
3017 global $sugar_config, $sugar_version, $mod_strings;
3018 if (!in_array($name_format, $sugar_config['name_formats'])) {
3019 $new_config = sugarArrayMerge($sugar_config['name_formats'], array($name_format=>$name_format));
3020 $sugar_config['name_formats'] = $new_config;
3021 if(!rebuildConfigFile($sugar_config, $sugar_version)) {
3022 logThis('*** ERROR: could not write config.php! - upgrade will fail!');
3023 $errors[] = $mod_strings['ERR_UW_CONFIG_WRITE'];
3032 function add_custom_modules_favorites_search(){
3033 $module_directories = scandir('modules');
3035 foreach($module_directories as $module_dir){
3036 if($module_dir == '.' || $module_dir == '..' || !is_dir("modules/{$module_dir}")){
3041 preg_match('/^[a-z0-9]{1,5}_[a-z0-9_]+$/i' , $module_dir, $matches);
3043 // Make sure the module was created by module builder
3044 if(empty($matches)){
3048 $full_module_dir = "modules/{$module_dir}/";
3049 $read_searchdefs_from = "{$full_module_dir}/metadata/searchdefs.php";
3050 $read_SearchFields_from = "{$full_module_dir}/metadata/SearchFields.php";
3051 $read_custom_SearchFields_from = "custom/{$full_module_dir}/metadata/SearchFields.php";
3053 // Studio can possibly override this file, so we check for a custom version of it
3054 if(file_exists("custom/{$full_module_dir}/metadata/searchdefs.php")){
3055 $read_searchdefs_from = "custom/{$full_module_dir}/metadata/searchdefs.php";
3058 if(file_exists($read_searchdefs_from) && file_exists($read_SearchFields_from)){
3061 require($read_searchdefs_from);
3062 foreach($searchdefs[$module_dir]['layout']['basic_search'] as $sf_array){
3063 if(isset($sf_array['name']) && $sf_array['name'] == 'favorites_only'){
3068 require($read_SearchFields_from);
3069 if(isset($searchFields[$module_dir]['favorites_only'])){
3073 if(!$found_sf1 && !$found_sf2){
3074 $searchdefs[$module_dir]['layout']['basic_search']['favorites_only'] = array('name' => 'favorites_only','label' => 'LBL_FAVORITES_FILTER','type' => 'bool',);
3075 $searchdefs[$module_dir]['layout']['advanced_search']['favorites_only'] = array('name' => 'favorites_only','label' => 'LBL_FAVORITES_FILTER','type' => 'bool',);
3076 $searchFields[$module_dir]['favorites_only'] = array(
3077 'query_type'=>'format',
3078 'operator' => 'subquery',
3079 'subquery' => 'SELECT sugarfavorites.record_id FROM sugarfavorites
3080 WHERE sugarfavorites.deleted=0
3081 and sugarfavorites.module = \''.$module_dir.'\'
3082 and sugarfavorites.assigned_user_id = \'{0}\'',
3083 'db_field'=>array('id')
3086 if(!is_dir("custom/{$full_module_dir}/metadata")){
3087 mkdir_recursive("custom/{$full_module_dir}/metadata");
3089 $success_sf1 = write_array_to_file('searchdefs', $searchdefs, "custom/{$full_module_dir}/metadata/searchdefs.php");
3090 $success_sf2 = write_array_to_file('searchFields', $searchFields, "{$full_module_dir}/metadata/SearchFields.php");
3093 logThis("add_custom_modules_favorites_search failed for searchdefs.php for {$module_dir}");
3096 logThis("add_custom_modules_favorites_search failed for SearchFields.php for {$module_dir}");
3098 if($success_sf1 && $success_sf2){
3099 logThis("add_custom_modules_favorites_search successfully updated searchdefs and searchFields for {$module_dir}");
3108 * upgradeModulesForTeamsets
3110 * This method adds the team_set_id values to the module tables that have the new team_set_id column
3111 * added through the SugarCRM 5.5.x upgrade process. It also adds the values into the team_sets and
3112 * team_sets_teams tables.
3114 * @param filter Array of modules to process; empty by default
3116 function upgradeModulesForTeamsets($filter=array()) {
3117 require('include/modules.php');
3118 foreach($beanList as $moduleName=>$beanName) {
3119 if(!empty($filter) && array_search($moduleName, $filter) === false) {
3122 if($moduleName == 'TeamMemberships' || $moduleName == 'ForecastOpportunities'){
3125 $bean = loadBean($moduleName);
3127 empty($bean->table_name)) {
3131 $FieldArray = $GLOBALS['db']->helper->get_columns($bean->table_name);
3132 if(!isset($FieldArray['team_id'])) {
3136 upgradeTeamColumn($bean, 'team_id');
3140 //Upgrade users table
3141 $bean = loadBean('Users');
3142 upgradeTeamColumn($bean, 'default_team');
3143 $result = $GLOBALS['db']->query("SELECT id FROM teams where deleted=0");
3144 while($row = $GLOBALS['db']->fetchByAssoc($result)) {
3145 $teamset = new TeamSet();
3146 $teamset->addTeams($row['id']);
3153 * Helper function to create a team_set_id column and also set team_set_id column
3154 * to have the value of the $column_name parameter
3156 * @param $bean SugarBean which we are adding team_set_id column to
3157 * @param $column_name The name of the column containing the default team_set_id value
3159 function upgradeTeamColumn($bean, $column_name) {
3160 //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
3161 //module that does not use the SugarObjects
3162 if(empty($bean->field_defs['team_set_id']) && $bean->module_dir != 'Trackers'){
3164 //at this point we could assume that since we have a team_id defined and not a team_set_id that we need to
3165 //add that field and the corresponding relationships
3166 $object = $bean->object_name;
3167 $module = $bean->module_dir;
3168 $object_name = $object;
3169 $_object_name = strtolower($object_name);
3171 if(!empty($GLOBALS['dictionary'][$object]['table'])){
3172 $table_name = $GLOBALS['dictionary'][$object]['table'];
3174 $table_name = strtolower($module);
3177 $path = 'include/SugarObjects/implements/team_security/vardefs.php';
3179 //go through each entry in the vardefs from team_security and unset anything that is already set in the core module
3180 //this will ensure we have the proper ordering.
3181 $fieldDiff = array_diff_assoc($vardefs['fields'], $GLOBALS['dictionary'][$bean->object_name]['fields']);
3183 $file = 'custom/Extension/modules/' . $bean->module_dir. '/Ext/Vardefs/teams.php';
3184 $contents = "<?php\n";
3185 if(!empty($fieldDiff)){
3186 foreach($fieldDiff as $key => $val){
3187 $contents .= "\n\$GLOBALS['dictionary']['". $object . "']['fields']['". $key . "']=" . var_export_helper($val) . ";";
3190 $relationshipDiff = array_diff_assoc($vardefs['relationships'], $GLOBALS['dictionary'][$bean->object_name]['relationships']);
3191 if(!empty($relationshipDiff)){
3192 foreach($relationshipDiff as $key => $val){
3193 $contents .= "\n\$GLOBALS['dictionary']['". $object . "']['relationships']['". $key . "']=" . var_export_helper($val) . ";";
3196 $indexDiff = array_diff_assoc($vardefs['indices'], $GLOBALS['dictionary'][$bean->object_name]['indices']);
3197 if(!empty($indexDiff)){
3198 foreach($indexDiff as $key => $val){
3199 $contents .= "\n\$GLOBALS['dictionary']['". $object . "']['indices']['". $key . "']=" . var_export_helper($val) . ";";
3202 if( $fh = @sugar_fopen( $file, 'wt' ) )
3204 fputs( $fh, $contents);
3209 //we have written out the teams.php into custom/Extension/modules/{$module_dir}/Ext/Vardefs/teams.php'
3210 //now let's merge back into vardefs.ext.php
3211 require_once('ModuleInstall/ModuleInstaller.php');
3212 $mi = new ModuleInstaller();
3213 $mi->merge_files('Ext/Vardefs/', 'vardefs.ext.php');
3214 VardefManager::loadVardef($bean->module_dir, $bean->object_name, true);
3215 $bean->field_defs = $GLOBALS['dictionary'][$bean->object_name]['fields'];
3218 if(isset($bean->field_defs['team_set_id'])) {
3219 //Create the team_set_id column
3220 $FieldArray = $GLOBALS['db']->helper->get_columns($bean->table_name);
3221 if(!isset($FieldArray['team_set_id'])) {
3222 $GLOBALS['db']->addColumn($bean->table_name, $bean->field_defs['team_set_id']);
3224 $indexArray = $GLOBALS['db']->helper->get_indices($bean->table_name);
3226 $indexName = getValidDBName('idx_'.strtolower($bean->table_name).'_tmst_id', true, 34);
3229 'name' => $indexName,
3231 'fields' => array('team_set_id')
3234 if(!isset($indexArray[$indexName])) {
3235 $GLOBALS['db']->addIndexes($bean->table_name, $indexDef);
3238 //Update the table's team_set_id column to have the same values as team_id
3239 $GLOBALS['db']->query("UPDATE {$bean->table_name} SET team_set_id = {$column_name}");
3244 * Update the folder subscription table which confirms to the team security mechanism but
3245 * the class SugarFolders does not extend SugarBean and is therefore never picked up by the
3246 * upgradeModulesForTeamsets function.
3248 function upgradeFolderSubscriptionsTeamSetId()
3250 logThis("In upgradeFolderSubscriptionsTeamSetId()");
3251 $query = "UPDATE folders SET team_set_id = team_id";
3252 $result = $GLOBALS['db']->query($query);
3253 logThis("Finished upgradeFolderSubscriptionsTeamSetId()");
3257 * upgradeModulesForTeam
3259 * This method update the associated_user_id, name, name_2 to the private team records on teams table
3260 * This function is used for upgrade process from 5.1.x and 5.2.x.
3263 function upgradeModulesForTeam() {
3264 logThis("In upgradeModulesForTeam()");
3265 $result = $GLOBALS['db']->query("SELECT id, user_name, first_name, last_name FROM users where deleted=0");
3267 while($row = $GLOBALS['db']->fetchByAssoc($result)) {
3268 $results2 = $GLOBALS['db']->query("SELECT id FROM teams WHERE name = '({$row['user_name']})'");
3270 if(!$assoc = $GLOBALS['db']->fetchByAssoc($results2)) {
3271 //if team does not exist, then lets create the team for this user
3274 $user->retrieve($row['id']);
3275 $team->new_user_created($user);
3276 $team_id = $team->id;
3278 $team_id =$assoc['id'];
3282 $name = is_null($row['first_name'])?'':$row['first_name'];
3283 $name_2 = is_null($row['last_name'])?'':$row['last_name'];
3284 $associated_user_id = $row['id'];
3287 //Ensure team->name is not empty by using team->name_2 if available
3288 if(empty($name) && !empty($name_2)) {
3293 $query = "UPDATE teams SET name = '{$name}', name_2 = '{$name_2}', associated_user_id = '{$associated_user_id}' WHERE id = '{$team_id}'";
3294 $GLOBALS['db']->query($query);
3297 //Update the team_set_id and default_team columns
3298 $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'));
3300 //Update team_set_id
3301 if($ce_to_pro_or_ent) {
3302 $GLOBALS['db']->query("update users set team_set_id = (select teams.id from teams where teams.associated_user_id = users.id)");
3303 $GLOBALS['db']->query("update users set default_team = (select teams.id from teams where teams.associated_user_id = users.id)");
3309 function addNewSystemTabsFromUpgrade($from_dir){
3311 if(isset($_SESSION['upgrade_from_flavor'])){
3313 //check to see if there are any new files that need to be added to systems tab
3314 //retrieve old modules list
3315 logThis('check to see if new modules exist',$path);
3316 $oldModuleList = array();
3317 $newModuleList = array();
3318 include($from_dir.'/include/modules.php');
3319 $oldModuleList = $moduleList;
3320 include('include/modules.php');
3321 $newModuleList = $moduleList;
3323 //include tab controller
3324 require_once('modules/MySettings/TabController.php');
3325 $newTB = new TabController();
3327 //make sure new modules list has a key we can reference directly
3328 $newModuleList = $newTB->get_key_array($newModuleList);
3329 $oldModuleList = $newTB->get_key_array($oldModuleList);
3331 //iterate through list and remove commonalities to get new modules
3332 foreach ($newModuleList as $remove_mod){
3333 if(in_array($remove_mod, $oldModuleList)){
3334 unset($newModuleList[$remove_mod]);
3337 //new modules list now has left over modules which are new to this install, so lets add them to the system tabs
3338 logThis('new modules to add are '.var_export($newModuleList,true),$path);
3340 if(!empty($newModuleList))
3342 //grab the existing system tabs
3343 $tabs = $newTB->get_system_tabs();
3345 //add the new tabs to the array
3346 foreach($newModuleList as $nm ){
3350 $newTB->set_system_tabs($tabs);
3352 logThis('module tabs updated',$path);
3358 * This method attempts to fix dropdown lists that were incorrectly named.
3359 * There were versions of SugarCRM that did not enforce naming convention rules
3360 * for the dropdown list field name. This method attempts to resolve that by
3361 * fixing the language files that may have been affected and then updating the
3362 * fields_meta_data table accordingly. It also refreshes any vardefs that may
3363 * have been affected.
3366 function fix_dropdown_list() {
3367 if(file_exists('custom/include/language')) {
3369 $affected_modules = array();
3370 $affected_keys = array();
3372 getFiles($files, 'custom/include/language', '/\.php$/i');
3373 foreach($files as $file) {
3375 if(file_exists($file . '.bak')) {
3376 $bak_mod_time = filemtime($file . '.bak');
3377 $php_mod_time = filemtime($file);
3378 //We're saying if the .php file was modified 30 seconds no more than php.bak file then we
3379 //run these additional cleanup checks
3380 if($php_mod_time - $bak_mod_time < 30) {
3382 $app_list_strings = array();
3383 $GLOBALS['app_list_strings'] = array();
3384 require($file . '.bak');
3385 $bak_app_list_strings = array_merge($app_list_strings, $GLOBALS['app_list_strings']);
3387 $app_list_strings = array();
3388 $GLOBALS['app_list_strings'] = array();
3390 $php_app_list_strings = array_merge($app_list_strings, $GLOBALS['app_list_strings']);
3392 //Get the file contents
3393 $contents = file_get_contents($file);
3395 //Now simulate a fix for the file before we compare w/ the .php file
3396 //we also append to the $contents
3397 foreach($bak_app_list_strings as $key=>$entry) {
3398 if(preg_match('/([^A-Za-z_])/', $key, $matches) && is_array($entry)) {
3399 $new_key = preg_replace('/[^A-Za-z_]/', '_', $key);
3400 $bak_app_list_strings[$new_key] = $bak_app_list_strings[$key];
3401 unset($bak_app_list_strings[$key]);
3402 //Now if the entry doesn't exists in the .php file, then add to contents
3403 if(!isset($php_app_list_strings[$new_key])) {
3404 $contents .= "\n\$GLOBALS['app_list_strings']['{$new_key}'] = " . var_export_helper($bak_app_list_strings[$new_key]) . ";";
3409 //Now load the .php file to do the comparison
3410 foreach($php_app_list_strings as $key=>$entry) {
3411 if(isset($bak_app_list_strings[$key])) {
3412 $diff = array_diff($bak_app_list_strings[$key], $entry);
3414 //There is a difference, so copy the $bak_app_list_strings version into the .php file
3415 $contents .= "\n\$GLOBALS['app_list_strings']['{$key}'] = " . var_export_helper($bak_app_list_strings[$key]) . ";";
3420 //Now write out the file contents
3421 //Create backup just in case
3422 copy($file, $file . '.php_bak');
3423 $fp = @sugar_fopen($file, 'w');
3425 fwrite($fp, $contents);
3428 $GLOBALS['log']->error("Unable to update file contents in fix_dropdown_list for {$file}");
3433 unset($GLOBALS['app_strings']);
3434 unset($GLOBALS['app_list_strings']);
3435 $app_list_strings = array();
3438 $contents = file_get_contents($file);
3439 if ( !isset($GLOBALS['app_list_strings']) ) {
3440 $GLOBALS['app_list_strings'] = $app_list_strings;
3443 $GLOBALS['app_list_strings'] = array_merge($app_list_strings, $GLOBALS['app_list_strings']);
3446 if(isset($GLOBALS['app_list_strings']) && is_array($GLOBALS['app_list_strings'])) {
3447 foreach($GLOBALS['app_list_strings'] as $key=>$entry) {
3448 if(preg_match('/([^A-Za-z_])/', $key, $matches) && is_array($entry)) {
3449 $result = $GLOBALS['db']->query("SELECT custom_module FROM fields_meta_data WHERE ext1 = '{$key}'");
3450 if(!empty($result)) {
3451 while($row = $GLOBALS['db']->fetchByAssoc($result)) {
3452 $custom_module = $row['custom_module'];
3453 if(!empty($GLOBALS['beanList'][$custom_module])) {
3454 $affected_modules[$custom_module] = $GLOBALS['beanList'][$custom_module];
3459 //Replace all invalid characters with '_' character
3460 $new_key = preg_replace('/[^A-Za-z_]/', '_', $key);
3461 $affected_keys[$key] = $new_key;
3463 $GLOBALS['app_list_strings'][$new_key] = $GLOBALS['app_list_strings'][$key];
3464 unset($GLOBALS['app_list_strings'][$key]);
3466 $pattern_match = "/(\[\s*\'{$key}\'\s*\])/";
3467 $new_key = "['{$new_key}']";
3468 $out = preg_replace($pattern_match, $new_key, $contents);
3474 //This is a check for g => h instances where the file contents were incorrectly written
3475 //and also fixes the scenario where via a UI upgrade, the app_list_strings were incorrectly
3476 //merged with app_list_strings variables declared elsewhere
3478 if(preg_match('/\$GLOBALS\s*\[\s*[\"|\']app_list_strings[\"|\']\s*\]\s*=\s*array\s*\(/', $contents)) {
3479 //Now also remove all the non-custom labels that were added
3480 if(preg_match('/language\/([^\.]+)\.lang\.php$/', $file, $matches)) {
3481 $language = $matches[1];
3483 $app_list_strings = array();
3485 if(file_exists("include/language/$language.lang.php")) {
3486 include("include/language/$language.lang.php");
3488 if(file_exists("include/language/$language.lang.override.php")) {
3489 $app_list_strings = _mergeCustomAppListStrings("include/language/$language.lang.override.php" , $app_list_strings) ;
3491 if(file_exists("custom/application/Ext/Language/$language.ext.lang.php")) {
3492 $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$language.ext.lang.php" , $app_list_strings) ;
3494 if(file_exists("custom/application/Ext/Language/$language.lang.ext.php")) {
3495 $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$language.lang.ext.php" , $app_list_strings) ;
3498 $all_non_custom_include_language_strings = $app_strings;
3499 $all_non_custom_include_language_list_strings = $app_list_strings;
3501 $unset_keys = array();
3502 if(!empty($GLOBALS['app_list_strings'])) {
3503 foreach($GLOBALS['app_list_strings'] as $key=>$value) {
3505 if(isset($all_non_custom_include_language_list_strings[$key])) {
3506 $diff = array_diff($all_non_custom_include_language_list_strings[$key], $GLOBALS['app_list_strings'][$key]);
3509 if(!empty($all_non_custom_include_language_list_strings[$key]) && empty($diff)) {
3510 $unset_keys[] = $key;
3515 foreach($unset_keys as $key) {
3516 unset($GLOBALS['app_list_strings'][$key]);
3519 if(!empty($GLOBALS['app_strings'])) {
3520 foreach($GLOBALS['app_strings'] as $key=>$value) {
3521 if(!empty($all_non_custom_include_language_strings[$key])) {
3522 unset($GLOBALS['app_strings'][$key]);
3526 } //if(preg_match...)
3529 if(!empty($GLOBALS['app_strings'])) {
3530 foreach($GLOBALS['app_strings'] as $key=>$entry) {
3531 $out .= "\n\$GLOBALS['app_strings']['$key']=" . var_export_helper($entry) . ";";
3535 foreach($GLOBALS['app_list_strings'] as $key=>$entry) {
3536 $out .= "\n\$GLOBALS['app_list_strings']['$key']=" . var_export_helper($entry) . ";";
3540 } //if(preg_match...)
3544 //Create a backup just in case
3545 copy($file, $file . '.bak');
3546 $fp = @sugar_fopen($file, 'w');
3551 //If we can't update the file, just return
3552 $GLOBALS['log']->error("Unable to update file contents in fix_dropdown_list.");
3560 //Update db entries (the order matters here... need to process database changes first)
3561 if(!empty($affected_keys)) {
3562 foreach($affected_keys as $old_key=>$new_key) {
3563 $GLOBALS['db']->query("UPDATE fields_meta_data SET ext1 = '{$new_key}' WHERE ext1 = '{$old_key}'");
3567 //Update vardef files for affected modules
3568 if(!empty($affected_modules)) {
3569 foreach($affected_modules as $module=>$object) {
3570 VardefManager::refreshVardefs($module, $object);
3577 function update_iframe_dashlets(){
3578 require_once(sugar_cached('dashlets/dashlets.php'));
3580 $db = DBManagerFactory::getInstance();
3581 $query = "SELECT id, contents, assigned_user_id FROM user_preferences WHERE deleted = 0 AND category = 'Home'";
3582 $result = $db->query($query, true, "Unable to update new default dashlets! ");
3583 while ($row = $db->fetchByAssoc($result)) {
3584 $content = unserialize(base64_decode($row['contents']));
3585 $assigned_user_id = $row['assigned_user_id'];
3586 $record_id = $row['id'];
3588 $current_user = new User();
3589 $current_user->retrieve($row['assigned_user_id']);
3591 if(!empty($content['dashlets']) && !empty($content['pages'])){
3592 $originalDashlets = $content['dashlets'];
3593 foreach($originalDashlets as $key => $ds){
3594 if(!empty($ds['options']['url']) && stristr($ds['options']['url'],'http://www.sugarcrm.com/crm/product/gopro')){
3595 unset($originalDashlets[$key]);
3598 $current_user->setPreference('dashlets', $originalDashlets, 0, 'Home');
3605 * convertImageToText
3607 * This method attempts to convert date type image to text on Microsoft SQL Server.
3608 * This method could NOT be used in any other type of datebases.
3610 function convertImageToText($table_name,$column_name){
3611 $set_lang = "SET LANGUAGE us_english";
3612 $GLOBALS['db']->query($set_lang);
3613 if($GLOBALS['db']->lastError()){
3614 logThis('An error occurred when performing this query-->'.$set_lang);
3616 $q="SELECT data_type
3617 FROM INFORMATION_SCHEMA.Tables T JOIN INFORMATION_SCHEMA.Columns C
3618 ON T.TABLE_NAME = C.TABLE_NAME where T.TABLE_NAME = '$table_name' and C.COLUMN_NAME = '$column_name'";
3619 $res= $GLOBALS['db']->query($q);
3620 if($GLOBALS['db']->lastError()){
3621 logThis('An error occurred when performing this query-->'.$q);
3623 $row= $GLOBALS['db']->fetchByAssoc($res);
3625 if(trim(strtolower($row['data_type'])) == 'image'){
3626 $addContent_temp = "alter table {$table_name} add {$column_name}_temp text null";
3627 $GLOBALS['db']->query($addContent_temp);
3628 if($GLOBALS['db']->lastError()){
3629 logThis('An error occurred when performing this query-->'.$addContent_temp);
3631 $qN = "select count=datalength({$column_name}), id, {$column_name} from {$table_name}";
3632 $result = $GLOBALS['db']->query($qN);
3633 while($row = $GLOBALS['db']->fetchByAssoc($result)){
3634 if($row['count'] >8000){
3635 $contentLength = $row['count'];
3638 $convertedContent = '';
3639 while($contentLength >0){
3640 $stepsQuery = "select cont=convert(varchar(max), convert(varbinary(8000), substring({$column_name},{$start},{$next}))) from {$table_name} where id= '{$row['id']}'";
3641 $steContQ = $GLOBALS['db']->query($stepsQuery);
3642 if($GLOBALS['db']->lastError()){
3643 logThis('An error occurred when performing this query-->'.$stepsQuery);
3645 $stepCont = $GLOBALS['db']->fetchByAssoc($steContQ);
3646 if(isset($stepCont['cont'])){
3647 $convertedContent = $convertedContent.$stepCont['cont'];
3649 $start = $start+$next;
3650 $contentLength = $contentLength - $next;
3652 $addContentDataText="update {$table_name} set {$column_name}_temp = '{$convertedContent}' where id= '{$row['id']}'";
3653 $GLOBALS['db']->query($addContentDataText);
3654 if($GLOBALS['db']->lastError()){
3655 logThis('An error occurred when performing this query-->'.$addContentDataText);
3659 $addContentDataText="update {$table_name} set {$column_name}_temp =
3660 convert(varchar(max), convert(varbinary(8000), {$column_name})) where id= '{$row['id']}'";
3661 $GLOBALS['db']->query($addContentDataText);
3662 if($GLOBALS['db']->lastError()){
3663 logThis('An error occurred when performing this query-->'.$addContentDataText);
3667 //drop the contents now and change contents_temp to contents
3668 $dropColumn = "alter table {$table_name} drop column {$column_name}";
3669 $GLOBALS['db']->query($dropColumn);
3670 if($GLOBALS['db']->lastError()){
3671 logThis('An error occurred when performing this query-->'.$dropColumn);
3673 $changeColumnName = "EXEC sp_rename '{$table_name}.[{$column_name}_temp]','{$column_name}','COLUMN'";
3674 $GLOBALS['db']->query($changeColumnName);
3675 if($GLOBALS['db']->lastError()){
3676 logThis('An error occurred when performing this query-->'.$changeColumnName);
3683 * This method attempts to delete all English inline help files.
3684 * This method was introduced by 5.5.0RC2.
3686 function clearHelpFiles(){
3687 $modulePath = clean_path(getcwd() . '/modules');
3688 $allHelpFiles = array();
3689 getFiles($allHelpFiles, $modulePath, "/en_us.help.*/");
3691 foreach( $allHelpFiles as $the_file ){
3692 if( is_file( $the_file ) ){
3693 unlink( $the_file );
3694 logThis("Deleted file: $the_file");
3702 * upgradeDateTimeFields
3704 * This method came from bug: 39757 where the date_end field is a date field and not a datetime field
3705 * which prevents you from performing timezone offset calculations once the data has been saved.
3707 * @param path String location to log file, empty by default
3709 function upgradeDateTimeFields($path)
3713 $meetingsSql = "UPDATE meetings SET date_end = ".$db->convert("date_start", 'add_time', array('duration_hours', 'duration_minutes'));
3714 $callsSql = "UPDATE calls SET date_end = ".$db->convert("date_start", 'add_time', array('duration_hours', 'duration_minutes'));
3715 logThis('upgradeDateTimeFields Meetings SQL:' . $meetingsSql, $path);
3716 $db->query($meetingsSql);
3718 logThis('upgradeDateTimeFields Calls SQL:' . $callsSql, $path);
3719 $db->query($callsSql);
3723 * upgradeDocumentTypeFields
3726 function upgradeDocumentTypeFields($path){
3730 $documentsSql = "UPDATE documents SET doc_type = 'Sugar' WHERE doc_type IS NULL";
3731 $meetingsSql = "UPDATE meetings SET type = 'Sugar' WHERE type IS NULL";
3733 logThis('upgradeDocumentTypeFields Documents SQL:' . $documentsSql, $path);
3734 $db->query($documentsSql);
3735 logThis('upgradeDocumentTypeFields Meetings SQL:' . $meetingsSql, $path);
3736 $db->query($meetingsSql);
3741 * merge_config_si_settings
3742 * This method checks for the presence of a config_si.php file and, if found, merges the configuration
3743 * settings from the config_si.php file into config.php. If a config_si_location parameter value is not
3744 * supplied it will attempt to discover the config_si.php file location from where the executing script
3747 * @param write_to_upgrade_log boolean optional value to write to the upgradeWizard.log file
3748 * @param config_location String optional value to config.php file location
3749 * @param config_si_location String optional value to config_si.php file location
3750 * @param path String file of the location of log file to write to
3751 * @return boolean value indicating whether or not a merge was attempted with config_si.php file
3753 function merge_config_si_settings($write_to_upgrade_log=false, $config_location='', $config_si_location='', $path='')
3755 if(!empty($config_location) && !file_exists($config_location))
3757 if($write_to_upgrade_log)
3759 logThis('config.php file specified in ' . $config_si_location . ' could not be found. Skip merging', $path);
3762 } else if(empty($config_location)) {
3764 //We are assuming this is from the silentUpgrade scripts so argv[3] will point to SugarCRM install location
3765 if(isset($argv[3]) && is_dir($argv[3]))
3767 $config_location = $argv[3] . DIRECTORY_SEPARATOR . 'config.php';
3771 //If config_location is still empty or if the file cannot be found, skip merging
3772 if(empty($config_location) || !file_exists($config_location))
3774 if($write_to_upgrade_log)
3776 logThis('config.php file at (' . $config_location . ') could not be found. Skip merging.', $path);
3780 if($write_to_upgrade_log)
3782 logThis('Loading config.php file at (' . $config_location . ') for merging.', $path);
3785 include($config_location);
3786 if(empty($sugar_config))
3788 if($write_to_upgrade_log)
3790 logThis('config.php contents are empty. Skip merging.', $path);
3796 if(!empty($config_si_location) && !file_exists($config_si_location))
3798 if($write_to_upgrade_log)
3800 logThis('config_si.php file specified in ' . $config_si_location . ' could not be found. Skip merging', $path);
3803 } else if(empty($config_si_location)) {
3804 if(isset($argv[0]) && is_file($argv[0]))
3806 $php_file = $argv[0];
3807 $p_info = pathinfo($php_file);
3808 $php_dir = (isset($p_info['dirname']) && $p_info['dirname'] != '.') ? $p_info['dirname'] . DIRECTORY_SEPARATOR : '';
3809 $config_si_location = $php_dir . 'config_si.php';
3813 //If config_si_location is still empty or if the file cannot be found, skip merging
3814 if(empty($config_si_location) || !file_exists($config_si_location))
3816 if($write_to_upgrade_log)
3818 logThis('config_si.php file at (' . $config_si_location . ') could not be found. Skip merging.', $path);
3822 if($write_to_upgrade_log)
3824 logThis('Loading config_si.php file at (' . $config_si_location . ') for merging.', $path);
3827 include($config_si_location);
3828 if(empty($sugar_config_si))
3830 if($write_to_upgrade_log)
3832 logThis('config_si.php contents are empty. Skip merging.', $path);
3838 //Now perform the merge operation
3840 foreach($sugar_config_si as $key=>$value)
3842 if(!preg_match('/^setup_/', $key) && !isset($sugar_config[$key]))
3844 if($write_to_upgrade_log)
3846 logThis('Merge key (' . $key . ') with value (' . $value . ')', $path);
3848 $sugar_config[$key] = $value;
3855 if($write_to_upgrade_log)
3857 logThis('Update config.php file with new values', $path);
3860 if(!write_array_to_file("sugar_config", $sugar_config, $config_location)) {
3861 if($write_to_upgrade_log)
3863 logThis('*** ERROR: could not write to config.php', $path);
3868 if($write_to_upgrade_log)
3870 logThis('config.php values are in sync with config_si.php values. Skipped merging.');
3875 if($write_to_upgrade_log)
3877 logThis('End merge_config_si_settings', $path);
3884 * upgrade_connectors
3885 * This function handles support for upgrading connectors, in particular the Hoovers connector
3886 * that needs the wsdl and endpoint modifications in the config.php file as well as the search
3887 * term change (from bal.specialtyCriteria.companyKeyword to bal.specialtyCriteria.companyName).
3888 * @param $path String variable for the log path
3890 function upgrade_connectors($path='') {
3891 logThis('Begin upgrade_connectors', $path);
3893 $filePath = 'custom/modules/Connectors/connectors/sources/ext/soap/hoovers/config.php';
3894 if(file_exists($filePath))
3896 logThis("{$filePath} file", $path);
3898 if(!is_null($config))
3901 if(isset($config['properties']['hoovers_endpoint']))
3903 $config['properties']['hoovers_endpoint'] = 'http://hapi.hoovers.com/HooversAPI-33';
3907 if(isset($config['properties']['hoovers_wsdl']))
3909 $config['properties']['hoovers_wsdl'] = 'http://hapi.hoovers.com/HooversAPI-33/hooversAPI/hooversAPI.wsdl';
3915 if(!write_array_to_file('config', $config, $filePath)) {
3916 logThis("Could not write new configuration to {$filePath} file", $path);
3918 logThis('Modified file successfully with new configuration entries', $path);
3924 $filePath = 'custom/modules/Connectors/connectors/sources/ext/soap/hoovers/vardefs.php';
3925 if(file_exists($filePath))
3927 logThis("Modifying {$filePath} file", $path);
3929 $fileContents = file_get_contents($filePath);
3930 $out = str_replace('bal.specialtyCriteria.companyKeyword', 'bal.specialtyCriteria.companyName', $fileContents);
3931 file_put_contents($filePath, $out);
3934 logThis('End upgrade_connectors', $path);
3938 * Enable the InsideView connector for the four default modules.
3940 function upgradeEnableInsideViewConnector($path='')
3942 logThis('Begin upgradeEnableInsideViewConnector', $path);
3944 // Load up the existing mapping and hand it to the InsideView connector to have it setup the correct logic hooks
3945 $mapFile = 'modules/Connectors/connectors/sources/ext/rest/insideview/mapping.php';
3946 if ( file_exists('custom/'.$mapFile) ) {
3947 logThis('Found CUSTOM mappings', $path);
3948 require('custom/'.$mapFile);
3950 logThis('Used default mapping', $path);
3954 require_once('include/connectors/sources/SourceFactory.php');
3955 $source = SourceFactory::getSource('ext_rest_insideview');
3957 // $mapping is brought in from the mapping.php file above
3958 $source->saveMappingHook($mapping);
3960 require_once('include/connectors/utils/ConnectorUtils.php');
3961 ConnectorUtils::installSource('ext_rest_insideview');
3963 // Now time to set the various modules to active, because this part ignores the default config
3964 require(CONNECTOR_DISPLAY_CONFIG_FILE);
3965 // $modules_sources come from that config file
3966 foreach ( $source->allowedModuleList as $module ) {
3967 $modules_sources[$module]['ext_rest_insideview'] = 'ext_rest_insideview';
3969 if(!write_array_to_file('modules_sources', $modules_sources, CONNECTOR_DISPLAY_CONFIG_FILE)) {
3970 //Log error and return empty array
3971 logThis("Cannot write \$modules_sources to " . CONNECTOR_DISPLAY_CONFIG_FILE,$path);
3974 logThis('End upgradeEnableInsideViewConnector', $path);
3978 function repair_long_relationship_names($path='')
3980 logThis("Begin repair_long_relationship_names", $path);
3981 require_once 'modules/ModuleBuilder/parsers/relationships/DeployedRelationships.php' ;
3982 $GLOBALS['mi_remove_tables'] = false;
3984 foreach($GLOBALS['moduleList'] as $module)
3986 $relationships = new DeployedRelationships ($module) ;
3987 foreach($relationships->getRelationshipList() as $rel_name)
3989 if (strlen($rel_name) > 27 && empty($touched[$rel_name]))
3991 logThis("Rebuilding relationship fields for $rel_name", $path);
3992 $touched[$rel_name] = true;
3993 $rel_obj = $relationships->get($rel_name);
3994 $rel_obj->setReadonly(false);
3995 $relationships->delete($rel_name);
3996 $relationships->save();
3997 $relationships->add($rel_obj);
3998 $relationships->save();
3999 $relationships->build () ;
4003 logThis("End repair_long_relationship_names", $path);
4006 function removeSilentUpgradeVarsCache(){
4007 global $silent_upgrade_vars_loaded;
4009 $cacheFileDir = "{$GLOBALS['sugar_config']['cache_dir']}/silentUpgrader";
4010 $cacheFile = "{$cacheFileDir}/silentUpgradeCache.php";
4012 if(file_exists($cacheFile)){
4016 $silent_upgrade_vars_loaded = array(); // Set to empty to reset it
4021 function loadSilentUpgradeVars(){
4022 global $silent_upgrade_vars_loaded;
4024 if(empty($silent_upgrade_vars_loaded)){
4025 $cacheFile = "{$GLOBALS['sugar_config']['cache_dir']}/silentUpgrader/silentUpgradeCache.php";
4026 // We have no pre existing vars
4027 if(!file_exists($cacheFile)){
4028 // Set the vars array so it's loaded
4029 $silent_upgrade_vars_loaded = array('vars' => array());
4032 require_once($cacheFile);
4033 $silent_upgrade_vars_loaded = $silent_upgrade_vars_cache;
4040 function writeSilentUpgradeVars(){
4041 global $silent_upgrade_vars_loaded;
4043 if(empty($silent_upgrade_vars_loaded)){
4044 return false; // You should have set some values before trying to write the silent upgrade vars
4047 $cacheFileDir = "{$GLOBALS['sugar_config']['cache_dir']}/silentUpgrader";
4048 $cacheFile = "{$cacheFileDir}/silentUpgradeCache.php";
4050 require_once('include/dir_inc.php');
4051 if(!mkdir_recursive($cacheFileDir)){
4054 require_once('include/utils/file_utils.php');
4055 if(!write_array_to_file('silent_upgrade_vars_cache', $silent_upgrade_vars_loaded, $cacheFile, 'w')){
4057 logThis("WARNING: writeSilentUpgradeVars could not write to {$cacheFile}", $path);
4064 function setSilentUpgradeVar($var, $value){
4065 if(!loadSilentUpgradeVars()){
4069 global $silent_upgrade_vars_loaded;
4071 $silent_upgrade_vars_loaded['vars'][$var] = $value;
4076 function getSilentUpgradeVar($var){
4077 if(!loadSilentUpgradeVars()){
4081 global $silent_upgrade_vars_loaded;
4083 if(!isset($silent_upgrade_vars_loaded['vars'][$var])){
4087 return $silent_upgrade_vars_loaded['vars'][$var];
4093 * add_unified_search_to_custom_modules_vardefs
4095 * This method calls the repair code to remove the unified_search_modules.php fiel
4098 function add_unified_search_to_custom_modules_vardefs()
4100 if(file_exists($cachefile = sugar_cached('modules/unified_search_modules.php')))
4108 * change from using the older SugarCache in 6.1 and below to the new one in 6.2
4110 function upgradeSugarCache($file)
4112 global $sugar_config;
4113 $cacheUploadUpgradesTemp = mk_temp_dir(sugar_cached('upgrades/temp'));
4115 unzip($file, $cacheUploadUpgradesTemp);
4117 if(!file_exists(clean_path("{$cacheUploadUpgradesTemp}/manifest.php"))) {
4118 logThis("*** ERROR: no manifest file detected while bootstraping upgrade wizard files!");
4121 include(clean_path("{$cacheUploadUpgradesTemp}/manifest.php"));
4124 $from_dir = "{$cacheUploadUpgradesTemp}/{$manifest['copy_files']['from_dir']}";
4125 $allFiles = array();
4126 if(file_exists("$from_dir/include/SugarCache")) {
4127 $allFiles = findAllFiles("$from_dir/include/SugarCache", $allFiles);
4129 if(file_exists("$from_dir/include/database")) {
4130 $allFiles = findAllFiles("$from_dir/include/database", $allFiles);
4132 if(file_exists("$from_dir/include/utils/external_cache.php")) {
4133 $allFiles[] = "$from_dir/include/utils/external_cache.php";
4135 if(file_exists("$from_dir/include/utils/sugar_file_utils.php")) {
4136 $allFiles[] = "$from_dir/include/utils/sugar_file_utils.php";
4138 if(file_exists("$from_dir/include/utils/sugar_file_utils.php")) {
4139 $allFiles[] = "$from_dir/include/utils/sugar_file_utils.php";
4142 foreach($allFiles as $k => $file) {
4143 $destFile = str_replace($from_dir."/", "", $file);
4144 if(!is_dir(dirname($destFile))) {
4145 mkdir_recursive(dirname($destFile)); // make sure the directory exists
4147 if ( stristr($file,'uw_main.tpl') )
4148 logThis('Skipping "'.$file.'" - file copy will during commit step.');
4150 logThis('updating UpgradeWizard code: '.$destFile);
4151 copy_recursive($file, $destFile);
4158 * upgradeDisplayedTabsAndSubpanels
4160 * @param $version String value of current system version (pre upgrade)
4162 function upgradeDisplayedTabsAndSubpanels($version)
4164 if($version < '620')
4166 logThis('start upgrading system displayed tabs and subpanels');
4167 require_once('modules/MySettings/TabController.php');
4168 $tc = new TabController();
4170 //grab the existing system tabs
4171 $tabs = $tc->get_tabs_system();
4173 //add Calls, Meetings, Tasks, Notes, Prospects (Targets) and ProspectLists (Target Lists)
4174 //to displayed tabs unless explicitly set to hidden
4175 $modules_to_add = array('Calls', 'Meetings', 'Tasks', 'Notes', 'Prospects', 'ProspectLists');
4176 $added_tabs = array();
4178 foreach($modules_to_add as $module)
4180 $tabs[0][$module] = $module;
4181 $added_tabs[] = $module;
4184 logThis('calling set_system_tabs on TabController to add tabs: ' . var_export($added_tabs, true));
4185 $tc->set_system_tabs($tabs[0]);
4186 logThis('finish upgrading system displayed tabs and subpanels');
4192 * unlinkUpgradeFiles
4193 * This is a helper function to clean up
4195 * @param $version String value of current system version (pre upgrade)
4197 function unlinkUpgradeFiles($version)
4199 if(!isset($version))
4204 //First check if we even have the scripts_for_patch/files_to_remove directory
4205 require_once('modules/UpgradeWizard/UpgradeRemoval.php');
4208 if(empty($_SESSION['unzip_dir']))
4210 global $sugar_config;
4211 $base_upgrade_dir = $sugar_config['upload_dir'] . "/upgrades";
4212 $base_tmp_upgrade_dir = "$base_upgrade_dir/temp";
4213 $_SESSION['unzip_dir'] = mk_temp_dir( $base_tmp_upgrade_dir );
4217 if(isset($_SESSION['unzip_dir']) && file_exists($_SESSION['unzip_dir'].'/scripts/files_to_remove'))
4219 $files_to_remove = glob($_SESSION['unzip_dir'].'/scripts/files_to_remove/*.php');
4221 foreach($files_to_remove as $script)
4223 if(preg_match('/UpgradeRemoval(\d+)x\.php/', $script, $matches))
4225 $checkVersion = $matches[1] + 1; //Increment by one to check everything equal or below the target version
4226 $upgradeClass = 'UpgradeRemoval' . $matches[1] . 'x';
4227 require_once($_SESSION['unzip_dir'].'/scripts/files_to_remove/' . $upgradeClass . '.php');
4229 //Check to make sure we should load and run this UpgradeRemoval instance
4230 if($checkVersion <= $version && class_exists($upgradeClass))
4232 $upgradeInstance = new $upgradeClass();
4233 if($upgradeInstance instanceof UpgradeRemoval)
4235 logThis('Running UpgradeRemoval instance ' . $upgradeClass);
4236 logThis('Files will be backed up to custom/backup');
4237 $files = $upgradeInstance->getFilesToRemove($version);
4238 foreach($files as $file)
4242 $upgradeInstance->processFilesToRemove($files);
4249 //Check if we have a custom directory
4250 if(file_exists('custom/scripts/files_to_remove'))
4253 $files_to_remove = glob('custom/scripts/files_to_remove/*.php');
4255 foreach($files_to_remove as $script)
4257 if(preg_match('/\/files_to_remove\/(.*?)\.php$/', $script, $matches))
4259 require_once($script);
4260 $upgradeClass = $matches[1];
4262 if(!class_exists($upgradeClass))
4267 $upgradeInstance = new $upgradeClass();
4268 if($upgradeInstance instanceof UpgradeRemoval)
4270 logThis('Running Custom UpgradeRemoval instance ' . $upgradeClass);
4271 $files = $upgradeInstance->getFilesToRemove($version);
4272 foreach($files as $file)
4276 $upgradeInstance->processFilesToRemove($files);
4284 if (!function_exists("getValidDBName"))
4287 * Return a version of $proposed that can be used as a column name in any of our supported databases
4288 * 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)
4289 * @param string $name Proposed name for the column
4290 * @param string $ensureUnique
4291 * @return string Valid column name trimmed to right length and with invalid characters removed
4293 function getValidDBName ($name, $ensureUnique = false, $maxLen = 30)
4295 // first strip any invalid characters - all but alphanumerics and -
4296 $name = preg_replace ( '/[^\w-]+/i', '', $name ) ;
4297 $len = strlen ( $name ) ;
4301 $md5str = md5($name);
4302 $tail = substr ( $name, -11) ;
4303 $temp = substr($md5str , strlen($md5str)-4 );
4304 $result = substr ( $name, 0, 10) . $temp . $tail ;
4305 }else if ($len > ($maxLen - 5))
4307 $result = substr ( $name, 0, 11) . substr ( $name, 11 - $maxLen + 5);
4309 return strtolower ( $result ) ;
4316 * Get UW directories
4317 * Provides compatibility with both 6.3 and pre-6.3 setup
4319 function getUWDirs()
4321 if(!class_exists('UploadStream')) {
4322 // we're still running the old code
4323 global $sugar_config;
4324 return array($sugar_config['upload_dir'] . "/upgrades", $sugar_config['cache_dir'] . "upload/upgrades/temp");
4326 if(!in_array("upload", stream_get_wrappers())) {
4327 UploadStream::register(); // just in case file was copied, but not run
4329 return array("upload://upgrades", sugar_cached("upgrades/temp"));
4334 * Whether directory exists within list of directories to skip
4335 * @param string $dir dir to be checked
4336 * @param array $skipDirs list with skipped dirs
4339 function whetherNeedToSkipDir($dir, $skipDirs)
4341 foreach($skipDirs as $skipMe) {
4342 if(strpos( clean_path($dir), $skipMe ) !== false) {
4352 * @param silentUpgrade boolean flag indicating whether or not we should treat running the SugarSpriteBuilder as an upgrade operation
4355 function rebuildSprites($fromUpgrade=true)
4357 require_once('modules/Administration/SugarSpriteBuilder.php');
4358 $sb = new SugarSpriteBuilder();
4359 $sb->cssMinify = true;
4360 $sb->fromSilentUpgrade = $fromUpgrade;
4361 $sb->silentRun = $fromUpgrade;
4363 // add common image directories
4364 $sb->addDirectory('default', 'include/images');
4365 $sb->addDirectory('default', 'themes/default/images');
4366 $sb->addDirectory('default', 'themes/default/images/SugarLogic');
4368 // add all theme image directories
4369 if($dh = opendir('themes'))
4371 while (($dir = readdir($dh)) !== false)
4373 if ($dir != "." && $dir != ".." && $dir != 'default' && is_dir('themes/'.$dir)) {
4374 $sb->addDirectory($dir, "themes/{$dir}/images");
4380 // generate the sprite goodies
4381 // everything is saved into cache/sprites
4382 $sb->createSprites();