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-2013 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 * Implodes some parts of version with specified delimiter, beta & rc parts are removed all time
44 * @example ('6.5.6') returns 656
45 * @example ('6.5.6beta2') returns 656
46 * @example ('6.5.6rc3') returns 656
47 * @example ('6.6.0.1') returns 6601
48 * @example ('6.5.6', 3, 'x') returns 65x
49 * @example ('6', 3, '', '.') returns 6.0.0
51 * @param string $version like 6, 6.2, 6.5.0beta1, 6.6.0rc1, 6.5.7 (separated by dot)
52 * @param int $size number of the first parts of version which are requested
53 * @param string $lastSymbol replace last part of version by some string
54 * @param string $delimiter delimiter for result
57 function implodeVersion($version, $size = 0, $lastSymbol = '', $delimiter = '')
59 preg_match('/^\d+(\.\d+)*/', $version, $parsedVersion);
60 if (empty($parsedVersion)) {
64 $parsedVersion = $parsedVersion[0];
65 $parsedVersion = explode('.', $parsedVersion);
68 $size = count($parsedVersion);
71 $parsedVersion = array_pad($parsedVersion, $size, 0);
72 $parsedVersion = array_slice($parsedVersion, 0, $size);
73 if ($lastSymbol !== '') {
74 array_pop($parsedVersion);
75 array_push($parsedVersion, $lastSymbol);
78 return implode($delimiter, $parsedVersion);
82 * Helper function for upgrade - get path from upload:// name
86 function getUploadRelativeName($path)
88 if(class_exists('UploadFile')) {
89 return UploadFile::realpath($path);
91 if(substr($path, 0, 9) == "upload://") {
92 $path = rtrim($GLOBALS['sugar_config']['upload_dir'], "/\\")."/".substr($path, 9);
98 * Backs-up files that are targeted for patch/upgrade to a restore directory
99 * @param string rest_dir Full path to the directory containing the original, replaced files.
100 * @param string install_file Full path to the uploaded patch/upgrade zip file
101 * @param string unzip_dir Full path to the unzipped files in a temporary directory
102 * @param string zip_from_dir Name of directory that the unzipped files containing the actuall replacement files
103 * @param array errors Collection of errors to be displayed at end of process
104 * @param string path Optional full path to the log file.
105 * @return array errors
107 function commitMakeBackupFiles($rest_dir, $install_file, $unzip_dir, $zip_from_dir, $errors, $path='') {
109 // create restore file directory
110 sugar_mkdir($rest_dir, 0775, true);
112 if(file_exists($rest_dir) && is_dir($rest_dir)){
113 logThis('backing up files to be overwritten...', $path);
114 $newFiles = findAllFiles(clean_path($unzip_dir . '/' . $zip_from_dir), array());
116 // keep this around for canceling
117 $_SESSION['uw_restore_dir'] = getUploadRelativeName($rest_dir);
119 foreach ($newFiles as $file) {
120 if (strpos($file, 'md5'))
123 // get name of current file to place in restore directory
124 $cleanFile = str_replace(clean_path($unzip_dir . '/' . $zip_from_dir), '', $file);
126 // make sure the directory exists
127 $cleanDir = $rest_dir . '/' . dirname($cleanFile);
128 sugar_mkdir($cleanDir, 0775, true);
129 $oldFile = clean_path(getcwd() . '/' . $cleanFile);
131 // only copy restore files for replacements - ignore new files from patch
132 if (is_file($oldFile)) {
133 if (is_writable($rest_dir)) {
134 logThis('Backing up file: ' . $oldFile, $path);
135 if (!copy($oldFile, $rest_dir . '/' . $cleanFile)) {
136 logThis('*** ERROR: could not backup file: ' . $oldFile, $path);
137 $errors[] = "{$mod_strings['LBL_UW_BACKUP']}::{$mod_strings['ERR_UW_FILE_NOT_COPIED']}: {$oldFile}";
139 $backupFilesExist = true;
143 logThis('*** ERROR: directory not writable: ' . $rest_dir, $path);
144 $errors[] = "{$mod_strings['LBL_UW_BACKUP']}::{$mod_strings['ERR_UW_DIR_NOT_WRITABLE']}: {$oldFile}";
149 logThis('file backup done.', $path);
154 * Copies files from the unzipped patch to the destination.
155 * @param string unzip_dir Full path to the temporary directory created during unzip operation.
156 * @param string zip_from_dir Name of folder containing the unzipped files; usually the name of the Patch without the
158 * @param string path Optional full path to alternate upgradeWizard log file.
159 * @return array Two element array containing to $copiedFiles and $skippedFiles.
164 function commitCopyNewFiles($unzip_dir, $zip_from_dir, $path='') {
165 logThis('Starting file copy process...', $path);
166 global $sugar_version;
169 $modules = getAllModules();
170 $backwardModules = array();
171 foreach($modules as $mod){
172 if(is_dir(clean_path(getcwd().'/modules/'.$mod.'/.500'))){
174 $files= findAllFiles(clean_path(getcwd().'/modules/'.$mod.'/.500'),$files);
175 if(sizeof($files) >0){
176 //backward compatibility is on
177 $backwardModules[] = $mod;
182 $newFiles = findAllFiles(clean_path($unzip_dir . '/' . $zip_from_dir), array());
183 $zipPath = clean_path($unzip_dir . '/' . $zip_from_dir);
185 // handle special do-not-overwrite conditions
186 $doNotOverwrite = array();
187 $doNotOverwrite[] = '__stub';
188 if(isset($_REQUEST['overwrite_files_serial'])) {
189 $doNotOverwrite = explode('::', $_REQUEST['overwrite_files_serial']);
192 $copiedFiles = array();
193 $skippedFiles = array();
195 foreach($newFiles as $file) {
196 $cleanFile = str_replace($zipPath, '', $file);
197 $srcFile = $zipPath . $cleanFile;
198 $targetFile = clean_path(getcwd() . '/' . $cleanFile);
199 if($backwardModules != null && sizeof($backwardModules) >0){
200 foreach($backwardModules as $mod){
201 $splitPath = explode('/',trim($cleanFile));
202 if('modules' == trim($splitPath[1]) && $mod == trim($splitPath[2])){
203 $cleanFile = str_replace('/modules/'.$mod, '/modules/'.$mod.'/.500', $cleanFile);
204 $targetFile = clean_path(getcwd() . '/' . $cleanFile);
208 if(!is_dir(dirname($targetFile))) {
209 mkdir_recursive(dirname($targetFile)); // make sure the directory exists
212 if((!file_exists($targetFile)) || /* brand new file */
213 (!in_array($targetFile, $doNotOverwrite)) /* manual diff file */
215 // handle sugar_version.php
216 if(strpos($targetFile, 'sugar_version.php') !== false && !preg_match('/\/portal\/sugar_version\.php$/i', $targetFile)) {
217 logThis('Skipping "sugar_version.php" - file copy will occur at end of successful upgrade', $path);
218 $_SESSION['sugar_version_file'] = $srcFile;
222 //logThis('Copying file to destination: ' . $targetFile, $path);
224 if(!copy($srcFile, $targetFile)) {
225 logThis('*** ERROR: could not copy file: ' . $targetFile, $path);
227 $copiedFiles[] = $targetFile;
230 //logThis('Skipping file: ' . $targetFile, $path);
231 $skippedFiles[] = $targetFile;
234 logThis('File copy done.', $path);
237 $ret['copiedFiles'] = $copiedFiles;
238 $ret['skippedFiles'] = $skippedFiles;
244 //On cancel put back the copied files from 500 to 451 state
245 function copyFilesOnCancel($step){
246 //place hoder for cancel action
251 function removeFileFromPath($file,$path, $deleteNot=array()){
253 $cur = $path . '/' . $file;
254 if(file_exists($cur)){
256 foreach($deleteNot as $dn){
266 if(!file_exists($path))return $removed;
268 while(false !== ($e = $d->read())){ // Fixed bug. !== is required to literally match the type and value of false, so that a filename that could evaluate and cast to false, ie "false" or "0", still allows the while loop to continue. From example at http://www.php.net/manual/en/function.dir.php
269 $next = $path . '/'. $e;
270 if(substr($e, 0, 1) != '.' && is_dir($next)){
271 $removed += removeFileFromPath($file, $next, $deleteNot);
274 $d->close(); // from example at http://www.php.net/manual/en/function.dir.php
279 * This function copies/overwrites between directories
281 * @param string the directory name to remove
282 * @param boolean whether to just empty the given directory, without deleting the given directory.
283 * @return boolean True/False whether the directory was deleted.
286 function copyRecursiveBetweenDirectories($from,$to){
287 if(file_exists($from)){
288 $modifiedFiles = array();
289 $modifiedFiles = findAllFiles(clean_path($from), $modifiedFiles);
290 $cwd = clean_path(getcwd());
291 foreach($modifiedFiles as $file) {
292 $srcFile = clean_path($file);
293 if (strpos($srcFile,".svn") === false) {
294 $targetFile = str_replace($from, $to, $srcFile);
296 if(!is_dir(dirname($targetFile))) {
297 mkdir_recursive(dirname($targetFile)); // make sure the directory exists
300 // handle sugar_version.php
301 if(strpos($targetFile, 'sugar_version.php') !== false && !preg_match('/\/portal\/sugar_version\.php$/i', $targetFile)) {
302 logThis('Skipping "sugar_version.php" - file copy will occur at end of successful upgrade', $targetFile);
303 $_SESSION['sugar_version_file'] = $srcFile;
307 if(!copy($srcFile, $targetFile)) {
308 logThis("*** ERROR: could not copy file $srcFile to $targetFile");
315 function deleteDirectory($dirname,$only_empty=false) {
316 if (!is_dir($dirname))
318 $dscan = array(realpath($dirname));
320 while (!empty($dscan)) {
321 $dcur = array_pop($dscan);
323 if ($d=opendir($dcur)) {
324 while ($f=readdir($d)) {
325 if ($f=='.' || $f=='..')
336 $i_until = ($only_empty)? 1 : 0;
337 for ($i=count($darr)-1; $i>=$i_until; $i--) {
338 if (rmdir($darr[$i]))
339 logThis('Success :Copying file to destination: ' . $darr[$i]);
341 logThis('Copy problem:Copying file to destination: ' . $darr[$i]);
343 return (($only_empty)? (count(scandir)<=2) : (!is_dir($dirname)));
346 * Get all the customized modules. Compare the file md5s with the base md5s
347 * If a file has been modified then put the module in the list of customized
348 * modules. Show the list in the preflight check UI.
351 function deleteAndOverWriteSelectedFiles($unzip_dir, $zip_from_dir,$delete_dirs){
352 if($delete_dirs != null){
353 foreach($delete_dirs as $del_dir){
354 deleteDirectory($del_dir);
355 $newFiles = findAllFiles(clean_path($unzip_dir . '/' . $zip_from_dir.'/'.$del_dir), array());
356 $zipPath = clean_path($unzip_dir . '/' . $zip_from_dir.'/'.$del_dir);
357 $copiedFiles = array();
358 $skippedFiles = array();
360 foreach($newFiles as $file) {
361 $cleanFile = str_replace($zipPath, '', $file);
362 $srcFile = $zipPath . $cleanFile;
363 $targetFile = clean_path(getcwd() . '/' . $cleanFile);
365 if(!is_dir(dirname($targetFile))) {
366 mkdir_recursive(dirname($targetFile)); // make sure the directory exists
369 if(!file_exists($targetFile)){
370 // handle sugar_version.php
371 if(strpos($targetFile, 'sugar_version.php') !== false) {
372 logThis('Skipping sugar_version.php - file copy will occur at end of successful upgrade');
373 $_SESSION['sugar_version_file'] = $srcFile;
377 //logThis('Copying file to destination: ' . $targetFile);
379 if(!copy($srcFile, $targetFile)) {
380 logThis('*** ERROR: could not copy file: ' . $targetFile);
382 $copiedFiles[] = $targetFile;
385 //logThis('Skipping file: ' . $targetFile);
386 $skippedFiles[] = $targetFile;
392 $ret['copiedFiles'] = $copiedFiles;
393 $ret['skippedFiles'] = $skippedFiles;
398 //Default is empty the directory. For removing set it to false
399 // to use this function to totally remove a directory, write:
400 // recursive_remove_directory('path/to/directory/to/delete',FALSE);
402 // to use this function to empty a directory, write:
403 // recursive_remove_directory('path/to/full_directory');
405 function recursive_empty_or_remove_directory($directory, $exclude_dirs=null,$exclude_files=null,$empty=TRUE)
407 // if the path has a slash at the end we remove it here
408 if(substr($directory,-1) == '/')
410 $directory = substr($directory,0,-1);
413 // if the path is not valid or is not a directory ...
414 if(!file_exists($directory) || !is_dir($directory))
416 // ... we return false and exit the function
419 // ... if the path is not readable
420 }elseif(!is_readable($directory))
422 // ... we return false and exit the function
425 // ... else if the path is readable
428 // we open the directory
429 $handle = opendir($directory);
431 // and scan through the items inside
432 while (FALSE !== ($item = readdir($handle)))
434 // if the filepointer is not the current directory
435 // or the parent directory
436 if($item != '.' && $item != '..')
438 // we build the new path to delete
439 $path = $directory.'/'.$item;
441 // if the new path is a directory
442 //add another check if the dir is in the list to exclude delete
443 if(is_dir($path) && $exclude_dirs != null && in_array($path,$exclude_dirs)){
446 else if(is_dir($path))
448 // we call this function with the new path
449 recursive_empty_or_remove_directory($path);
451 // if the new path is a file
453 // we remove the file
454 if($exclude_files != null && in_array($path,$exclude_files)){
463 // close the directory
466 // if the option to empty is not set to true
469 // try to delete the now empty directory
470 if(!rmdir($directory))
472 // return false if not possible
480 // ------------------------------------------------------------
485 function getAllCustomizedModules() {
487 require_once('files.md5');
489 $return_array = array();
490 $modules = getAllModules();
491 foreach($modules as $mod) {
492 //find all files in each module if the files have been modified
493 //as compared to the base version then add the module to the
494 //customized modules array
495 $modFiles = findAllFiles(clean_path(getcwd())."/modules/$mod", array());
496 foreach($modFiles as $file){
497 $fileContents = file_get_contents($file);
498 $file = str_replace(clean_path(getcwd()),'',$file);
499 if($md5_string['./' . $file]){
500 if(md5($fileContents) != $md5_string['./' . $file]) {
501 //A file has been customized in the module. Put the module into the
502 // customized modules array.
503 echo 'Changed File'.$file;
509 // This is a new file in user's version and indicates that module has been
510 //customized. Put the module in the customized array.
511 echo 'New File'.$file;
518 return $return_array;
522 * Array of all Modules in the version bein upgraded
523 * This method returns an Array of all modules
524 * @return $modules Array of modules.
526 function getAllModules() {
529 while($e = $d->read()){
530 if(substr($e, 0, 1) == '.' || !is_dir('modules/' . $e))continue;
536 //Remove files with the smae md5
538 function removeMd5MatchingFiles($deleteNot=array()){
540 $md5_string = array();
541 if(file_exists(clean_path(getcwd().'/files.md5'))){
542 require(clean_path(getcwd().'/files.md5'));
544 $modulesAll = getAllModules();
545 foreach($modulesAll as $mod){
546 $allModFiles = array();
547 if(is_dir('modules/'.$mod)){
548 $allModFiles = findAllFiles('modules/'.$mod,$allModFiles);
549 foreach($allModFiles as $file){
550 if(file_exists($file) && !in_array(basename($file),$deleteNot)){
551 if(isset($md5_string['./'.$file])) {
552 $fileContents = file_get_contents($file);
553 if(md5($fileContents) == $md5_string['./'.$file]) {
564 * Handles requirements for creating reminder Tasks and Emails
565 * @param array skippedFiles Array of files that were not overwriten and must be manually mereged.
566 * @param string path Optional full path to alternate upgradeWizard log.
568 function commitHandleReminders($skippedFiles, $path='') {
570 global $current_user;
572 if(empty($mod_strings))
573 $mod_strings = return_module_language('en_us', 'UpgradeWizard');
575 if(empty($current_user->id)) {
576 $current_user->getSystemUser();
579 if(count($skippedFiles) > 0) {
580 $desc = $mod_strings['LBL_UW_COMMIT_ADD_TASK_OVERVIEW'] . "\n\n";
581 $desc .= $mod_strings['LBL_UW_COMMIT_ADD_TASK_DESC_1'];
582 $desc .= $_SESSION['uw_restore_dir'] . "\n\n";
583 $desc .= $mod_strings['LBL_UW_COMMIT_ADD_TASK_DESC_2'] . "\n\n";
585 foreach($skippedFiles as $file) {
586 $desc .= $file . "\n";
590 /// Not using new TimeDate stuff here because it needs to be compatible with 6.0
591 $nowDate = gmdate('Y-m-d');
592 $nowTime = gmdate('H:i:s');
593 $nowDateTime = $nowDate . ' ' . $nowTime;
595 if($_REQUEST['addTaskReminder'] == 'remind') {
596 logThis('Adding Task for admin for manual merge.', $path);
599 $task->name = $mod_strings['LBL_UW_COMMIT_ADD_TASK_NAME'];
600 $task->description = $desc;
601 $task->date_due = $nowDate;
602 $task->time_due = $nowTime;
603 $task->priority = 'High';
604 $task->status = 'Not Started';
605 $task->assigned_user_id = $current_user->id;
606 $task->created_by = $current_user->id;
607 $task->date_entered = $nowDateTime;
608 $task->date_modified = $nowDateTime;
612 if($_REQUEST['addEmailReminder'] == 'remind') {
613 logThis('Sending Reminder for admin for manual merge.', $path);
615 $email = new Email();
616 $email->assigned_user_id = $current_user->id;
617 $email->name = $mod_strings['LBL_UW_COMMIT_ADD_TASK_NAME'];
618 $email->description = $desc;
619 $email->description_html = nl2br($desc);
620 $email->from_name = $current_user->full_name;
621 $email->from_addr = $current_user->email1;
622 $email->to_addrs_arr = $email->parse_addrs($current_user->email1, '', '', '');
623 $email->cc_addrs_arr = array();
624 $email->bcc_addrs_arr = array();
625 $email->date_entered = $nowDateTime;
626 $email->date_modified = $nowDateTime;
633 function deleteCache(){
634 //Clean modules from cache
635 $cachedir = sugar_cached('modules');
636 if(is_dir($cachedir)){
637 $allModFiles = array();
638 $allModFiles = findAllFiles($cachedir,$allModFiles, true);
639 foreach($allModFiles as $file) {
640 if(file_exists($file)) {
642 rmdir_recursive($file);
651 //Clean jsLanguage from cache
652 $cachedir = sugar_cached('jsLanguage');
653 if(is_dir($cachedir)){
654 $allModFiles = array();
655 $allModFiles = findAllFiles($cachedir,$allModFiles);
656 foreach($allModFiles as $file){
657 if(file_exists($file)){
662 //Clean smarty from cache
663 $cachedir = sugar_cached('smarty');
664 if(is_dir($cachedir)){
665 $allModFiles = array();
666 $allModFiles = findAllFiles($cachedir,$allModFiles);
667 foreach($allModFiles as $file){
668 if(file_exists($file)){
673 //Rebuild dashlets cache
674 require_once('include/Dashlets/DashletCacheBuilder.php');
675 $dc = new DashletCacheBuilder();
679 function deleteChance(){
680 //Clean folder from cache
681 if(is_dir('include/SugarObjects/templates/chance')){
682 rmdir_recursive('include/SugarObjects/templates/chance');
684 if(is_dir('include/SugarObjects/templates/chance')){
685 if(!isset($_SESSION['chance'])){
686 $_SESSION['chance'] = '';
688 $_SESSION['chance'] = 'include/SugarObjects/templates/chance';
689 //rename('include/SugarObjects/templates/chance','include/SugarObjects/templates/chance_removeit');
697 * This function copies upgrade wizard files from new patch if that dir exists
699 * @param $file String path to uploaded zip file
701 function upgradeUWFiles($file) {
702 $cacheUploadUpgradesTemp = mk_temp_dir(sugar_cached("upgrades/temp"));
704 unzip($file, $cacheUploadUpgradesTemp);
706 if(!file_exists("$cacheUploadUpgradesTemp/manifest.php")) {
707 logThis("*** ERROR: no manifest file detected while bootstraping upgrade wizard files!");
710 include("$cacheUploadUpgradesTemp/manifest.php");
714 $from_dir = "{$cacheUploadUpgradesTemp}/{$manifest['copy_files']['from_dir']}";
717 if(file_exists("$from_dir/include/Localization/Localization.php")) {
718 $allFiles[] = "$from_dir/include/Localization/Localization.php";
721 if(file_exists("$from_dir/modules/UpgradeWizard")) {
722 $allFiles[] = findAllFiles("$from_dir/modules/UpgradeWizard", $allFiles);
725 if(file_exists("$from_dir/ModuleInstall")) {
726 $allFiles[] = findAllFiles("$from_dir/ModuleInstall", $allFiles);
728 if(file_exists("$from_dir/include/javascript/yui")) {
729 $allFiles[] = findAllFiles("$from_dir/include/javascript/yui", $allFiles);
731 if(file_exists("$from_dir/HandleAjaxCall.php")) {
732 $allFiles[] = "$from_dir/HandleAjaxCall.php";
734 if(file_exists("$from_dir/include/SugarTheme")) {
735 $allFiles[] = findAllFiles("$from_dir/include/SugarTheme", $allFiles);
737 if(file_exists("$from_dir/include/SugarCache")) {
738 $allFiles[] = findAllFiles("$from_dir/include/SugarCache", $allFiles);
740 if(file_exists("$from_dir/include/utils/external_cache.php")) {
741 $allFiles[] = "$from_dir/include/utils/external_cache.php";
743 if(file_exists("$from_dir/include/upload_file.php")) {
744 $allFiles[] = "$from_dir/include/upload_file.php";
746 if(file_exists("$from_dir/include/file_utils.php")) {
747 $allFiles[] = "$from_dir/include/file_utils.php";
749 if(file_exists("$from_dir/include/upload_file.php")) {
750 $allFiles[] = "$from_dir/include/upload_file.php";
752 if(file_exists("$from_dir/include/utils/sugar_file_utils.php")) {
753 $allFiles[] = "$from_dir/include/utils/sugar_file_utils.php";
755 if(file_exists("$from_dir/include/utils/autoloader.php")) {
756 $allFiles[] = "$from_dir/include/utils/autoloader.php";
759 upgradeUWFilesCopy($allFiles, $from_dir);
765 * This function recursively copies files from the upgradeUWFiles Array
766 * @see upgradeUWFiles
768 * @param array $allFiles Array of files to copy over after zip file has been uploaded
769 * @param string $from_dir Source directory
771 function upgradeUWFilesCopy($allFiles, $from_dir)
773 foreach($allFiles as $file)
777 upgradeUWFilesCopy($file, $from_dir);
779 $destFile = str_replace($from_dir."/", "", $file);
780 if(!is_dir(dirname($destFile))) {
781 mkdir_recursive(dirname($destFile)); // make sure the directory exists
784 if(stristr($file,'uw_main.tpl'))
785 logThis('Skipping "'.$file.'" - file copy will during commit step.');
787 logThis('updating UpgradeWizard code: '.$destFile);
788 copy_recursive($file, $destFile);
797 * gets valid patch file names that exist in upload/upgrade/patch/
799 function getValidPatchName($returnFull = true) {
800 global $base_upgrade_dir;
803 global $sugar_version;
804 global $sugar_config;
805 $uh = new UpgradeHistory();
806 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
809 // scan for new files (that are not installed)
810 logThis('finding new files for upgrade');
811 $upgrade_content = '';
812 $upgrade_contents = findAllFiles($base_upgrade_dir, array(), false, 'zip');
813 //other variations of zip file i.e. ZIP, zIp,zIP,Zip,ZIp,ZiP
820 <b>{$mod_strings['LBL_ML_NAME']}</b>
823 <b>{$mod_strings['LBL_ML_TYPE']}</b>
826 <b>{$mod_strings['LBL_ML_VERSION']}</b>
829 <b>{$mod_strings['LBL_ML_PUBLISHED']}</b>
832 <b>{$mod_strings['LBL_ML_UNINSTALLABLE']}</b>
835 <b>{$mod_strings['LBL_ML_DESCRIPTION']}</b>
840 // assume old patches are there.
841 $upgradeToVersion = array(); // fill with valid patches - we will only use the latest qualified found patch
843 // cn: bug 10609 - notices for uninitialized variables
848 $published_date = '';
853 foreach($upgrade_contents as $upgrade_content) {
854 if(!preg_match("#.*\.zip\$#i", $upgrade_content)) {
858 $the_base = basename($upgrade_content);
859 $the_md5 = md5_file($upgrade_content);
861 $md5_matches = $uh->findByMd5($the_md5);
863 /* 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.
864 * Edge-case: manual upgrade with a FTP of a patch; UH table has no entry for it. Assume nothing. :( */
865 if(0 == sizeof($md5_matches)) {
866 $target_manifest = remove_file_extension( $upgrade_content ) . '-manifest.php';
867 require_once($target_manifest);
869 if(empty($manifest['version'])) {
870 logThis("*** Potential error: patch found with no version [ {$upgrade_content} ]");
873 if(!isset($manifest['type']) || $manifest['type'] != 'patch') {
874 logThis("*** Potential error: patch found with either no 'type' or non-patch type [ {$upgrade_content} ]");
878 $upgradeToVersion[$manifest['version']] = urlencode($upgrade_content);
880 $name = empty($manifest['name']) ? $upgrade_content : $manifest['name'];
881 $version = empty($manifest['version']) ? '' : $manifest['version'];
882 $published_date = empty($manifest['published_date']) ? '' : $manifest['published_date'];
884 $description = empty($manifest['description']) ? 'None' : $manifest['description'];
885 $uninstallable = empty($manifest['is_uninstallable']) ? 'No' : 'Yes';
886 $type = getUITextForType( $manifest['type'] );
887 $manifest_type = $manifest['type'];
889 if(empty($manifest['icon'])) {
890 $icon = getImageForType( $manifest['type'] );
892 $path_parts = pathinfo( $manifest['icon'] );
893 $icon = "<!--not_in_theme!--><img src=\"" . remove_file_extension( $upgrade_content ) . "-icon." . $path_parts['extension'] . "\">";
898 // cn: bug 10488 use the NEWEST upgrade/patch available when running upgrade wizard.
899 ksort($upgradeToVersion);
900 $upgradeToVersion = array_values($upgradeToVersion);
901 $newest = array_pop($upgradeToVersion);
902 $_SESSION['install_file'] = urldecode($newest); // in-case it was there from a prior.
903 logThis("*** UW using [ {$_SESSION['install_file']} ] as source for patch files.");
905 $cleanUpgradeContent = urlencode($_SESSION['install_file']);
907 // cn: 10606 - cannot upload a patch file since this returned always.
908 if(!empty($cleanUpgradeContent)) {
909 $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";
912 <form action="index.php" method="post">
913 <input type="hidden" name="module" value="UpgradeWizard">
914 <input type="hidden" name="action" value="index">
915 <input type="hidden" name="step" value="{$_REQUEST['step']}">
916 <input type="hidden" name="run" value="delete">
917 <input type=hidden name="install_file" value="{$cleanUpgradeContent}" />
918 <input type=submit value="{$mod_strings['LBL_BUTTON_DELETE']}" />
922 $disabled = "DISABLED";
927 if(empty($cleanUpgradeContent)){
928 $ready .= "<tr><td colspan='7'><i>None</i></td>\n";
929 $ready .= "</table>\n";
931 $ready .= "<br></ul>\n";
933 $return['ready'] = $ready;
934 $return['disabled'] = $disabled;
943 * finalizes upgrade by setting upgrade versions in DB (config table) and sugar_version.php
944 * @return bool true on success
946 function updateVersions($version) {
948 global $sugar_config;
951 logThis('At updateVersions()... updating config table and sugar_version.php.', $path);
954 if(isset($_SESSION['sugar_version_file']) && !empty($_SESSION['sugar_version_file'])) {
955 if(!copy($_SESSION['sugar_version_file'], clean_path(getcwd().'/sugar_version.php'))) {
956 logThis('*** ERROR: sugar_version.php could not be copied to destination! Cannot complete upgrade', $path);
959 logThis('sugar_version.php successfully updated!', $path);
962 logThis('*** ERROR: no sugar_version.php file location found! - cannot complete upgrade...', $path);
966 $q1 = "DELETE FROM config WHERE category = 'info' AND name = 'sugar_version'";
967 $q2 = "INSERT INTO config (category, name, value) VALUES ('info', 'sugar_version', '{$version}')";
969 logThis('Deleting old DB version info from config table.', $path);
972 logThis('Inserting updated version info into config table.', $path);
975 logThis('updateVersions() complete.', $path);
982 * gets a module's lang pack - does not need to be a SugarModule
983 * @param lang string Language
984 * @param module string Path to language folder
985 * @return array mod_strings
987 function getModuleLanguagePack($lang, $module) {
988 $mod_strings = array();
990 if(!empty($lang) && !empty($module)) {
991 $langPack = clean_path(getcwd().'/'.$module.'/language/'.$lang.'.lang.php');
992 $langPackEn = clean_path(getcwd().'/'.$module.'/language/en_us.lang.php');
994 if (file_exists($langPack))
998 elseif (file_exists($langPackEn))
1000 include($langPackEn);
1004 return $mod_strings;
1007 * checks system compliance for 4.5+ codebase
1008 * @return array Mixed values
1010 function checkSystemCompliance() {
1011 global $sugar_config;
1012 global $current_language;
1014 global $mod_strings;
1015 global $app_strings;
1017 if(!defined('SUGARCRM_MIN_MEM')) {
1018 define('SUGARCRM_MIN_MEM', 40);
1021 $installer_mod_strings = getModuleLanguagePack($current_language, './install');
1023 $ret['error_found'] = false;
1026 $php_version = constant('PHP_VERSION');
1027 $check_php_version_result = check_php_version($php_version);
1029 switch($check_php_version_result) {
1031 $ret['phpVersion'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_PHP_INVALID_VER']} {$php_version} )</span></b>";
1032 $ret['error_found'] = true;
1035 $ret['phpVersion'] = "<b><span class=go>{$installer_mod_strings['ERR_CHECKSYS_PHP_UNSUPPORTED']} {$php_version} )</span></b>";
1038 $ret['phpVersion'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_PHP_OK']} {$php_version} )</span></b>";
1042 // database and connect
1043 $canInstall = $db->canInstall();
1044 if ($canInstall !== true)
1046 $ret['error_found'] = true;
1047 if (count($canInstall) == 1)
1049 $ret['dbVersion'] = "<b><span class=stop>" . $installer_mod_strings[$canInstall[0]] . "</span></b>";
1053 $ret['dbVersion'] = "<b><span class=stop>" . sprintf($installer_mod_strings[$canInstall[0]], $canInstall[1]) . "</span></b>";
1058 if(function_exists('xml_parser_create')) {
1059 $ret['xmlStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1061 $ret['xmlStatus'] = "<b><span class=stop>{$installer_mod_strings['LBL_CHECKSYS_NOT_AVAILABLE']}</span></b>";
1062 $ret['error_found'] = true;
1066 if(function_exists('curl_init')) {
1067 $ret['curlStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1069 $ret['curlStatus'] = "<b><span class=go>{$installer_mod_strings['ERR_CHECKSYS_CURL']}</span></b>";
1070 $ret['error_found'] = false;
1074 if(function_exists('mb_strlen')) {
1075 $ret['mbstringStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1077 $ret['mbstringStatus'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_MBSTRING']}</span></b>";
1078 $ret['error_found'] = true;
1082 if(function_exists('imap_open')) {
1083 $ret['imapStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1085 $ret['imapStatus'] = "<b><span class=go>{$installer_mod_strings['ERR_CHECKSYS_IMAP']}</span></b>";
1086 $ret['error_found'] = false;
1091 if('1' == ini_get('safe_mode')) {
1092 $ret['safeModeStatus'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_SAFE_MODE']}</span></b>";
1093 $ret['error_found'] = true;
1095 $ret['safeModeStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1099 // call time pass by ref
1100 if('1' == ini_get('allow_call_time_pass_reference')) {
1101 $ret['callTimeStatus'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_CALL_TIME']}</span></b>";
1102 //continue upgrading
1104 $ret['callTimeStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1108 $ret['memory_msg'] = "";
1109 $memory_limit = "-1";//ini_get('memory_limit');
1110 $sugarMinMem = constant('SUGARCRM_MIN_MEM');
1111 // logic based on: http://us2.php.net/manual/en/ini.core.php#ini.memory-limit
1112 if( $memory_limit == "" ){ // memory_limit disabled at compile time, no memory limit
1113 $ret['memory_msg'] = "<b><span class=\"go\">{$installer_mod_strings['LBL_CHECKSYS_MEM_OK']}</span></b>";
1114 } elseif( $memory_limit == "-1" ){ // memory_limit enabled, but set to unlimited
1115 $ret['memory_msg'] = "<b><span class=\"go\">{$installer_mod_strings['LBL_CHECKSYS_MEM_UNLIMITED']}</span></b>";
1117 rtrim($memory_limit, 'M');
1118 $memory_limit_int = (int) $memory_limit;
1119 if( $memory_limit_int < constant('SUGARCRM_MIN_MEM') ){
1120 $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>";
1121 $ret['error_found'] = true;
1123 $ret['memory_msg'] = "<b><span class=\"go\">{$installer_mod_strings['LBL_CHECKSYS_OK']} ({$memory_limit})</span></b>";
1127 if (!class_exists("ZipArchive"))
1129 $ret['ZipStatus'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_ZIP']}</span></b>";
1130 $ret['error_found'] = true;
1132 $ret['ZipStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1136 if(defined('PCRE_VERSION')) {
1137 if (version_compare(PCRE_VERSION, '7.0') < 0) {
1138 $ret['pcreVersion'] = "<b><span class='stop'>{$installer_mod_strings['ERR_CHECKSYS_PCRE_VER']}</span></b>";
1139 $ret['error_found'] = true;
1142 $ret['pcreVersion'] = "<b><span class='go'>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1145 $ret['pcreVersion'] = "<b><span class='stop'><b>{$installer_mod_strings['ERR_CHECKSYS_PCRE']}</span></b>";
1146 $ret['error_found'] = true;
1149 // Suhosin allow to use upload://
1150 $ret['stream_msg'] = '';
1151 if (UploadStream::getSuhosinStatus() == true)
1153 $ret['stream_msg'] = "<b><span class=\"go\">{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1157 $ret['stream_msg'] = "<b><span class=\"stop\">{$app_strings['ERR_SUHOSIN']}</span></b>";
1158 $ret['error_found'] = true;
1161 /* mbstring.func_overload
1162 $ret['mbstring.func_overload'] = '';
1163 $mb = ini_get('mbstring.func_overload');
1166 $ret['mbstring.func_overload'] = "<b><span class=\"stop\">{$mod_strings['ERR_UW_MBSTRING_FUNC_OVERLOAD']}</b>";
1167 $ret['error_found'] = true;
1175 * is a file that we blow away automagically
1177 function isAutoOverwriteFile($file) {
1178 $overwriteDirs = array(
1179 './sugar_version.php',
1180 './modules/UpgradeWizard/uw_main.tpl',
1182 $file = trim('.'.str_replace(clean_path(getcwd()), '', $file));
1184 if(in_array($file, $overwriteDirs)) {
1188 $fileExtension = substr(strrchr($file, "."), 1);
1189 if($fileExtension == 'tpl' || $fileExtension == 'html') {
1199 function logThis($entry, $path='') {
1200 global $mod_strings;
1201 if(file_exists('include/utils/sugar_file_utils.php')){
1202 require_once('include/utils/sugar_file_utils.php');
1204 $log = empty($path) ? clean_path(getcwd().'/upgradeWizard.log') : clean_path($path);
1206 // create if not exists
1207 if(!file_exists($log)) {
1208 if(function_exists('sugar_fopen')){
1209 $fp = @sugar_fopen($log, 'w+'); // attempts to create file
1212 $fp = fopen($log, 'w+'); // attempts to create file
1214 if(!is_resource($fp)) {
1215 $GLOBALS['log']->fatal('UpgradeWizard could not create the upgradeWizard.log file');
1216 die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
1219 if(function_exists('sugar_fopen')){
1220 $fp = @sugar_fopen($log, 'a+'); // write pointer at end of file
1223 $fp = @fopen($log, 'a+'); // write pointer at end of file
1226 if(!is_resource($fp)) {
1227 $GLOBALS['log']->fatal('UpgradeWizard could not open/lock upgradeWizard.log file');
1228 die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
1232 $line = date('r').' [UpgradeWizard] - '.$entry."\n";
1234 if(@fwrite($fp, $line) === false) {
1235 $GLOBALS['log']->fatal('UpgradeWizard could not write to upgradeWizard.log: '.$entry);
1236 die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
1239 if(is_resource($fp)) {
1247 * @desc This function is to be used in the upgrade process to preserve changes/customaizations made to pre 5.1 quickcreate layout.
1248 * 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
1249 * was automatically picked up by the quick create. [Addresses Bug 21469]
1250 * This function will check if customizations were made, and will create quickcreatedefs.php in the /cutom/working/$module_name directory.
1252 function updateQuickCreateDefs(){
1253 $d = dir('modules');
1254 $studio_modules = array();
1256 while($e = $d->read()){ //collect all studio modules.
1257 if(substr($e, 0, 1) == '.' || !is_dir('modules/' . $e))continue;
1258 if(file_exists('modules/' . $e . '/metadata/studio.php'))
1260 array_push($studio_modules, $e);
1264 foreach( $studio_modules as $modname ){ //for each studio enabled module
1265 //Check !exists modules/$modname/metadata/quickcreatedefs.php &&
1266 //exists custom/$modname/editviewdefs.php (module was customized) &&
1267 //!exists custom/$modname/quickcreateviewdefs.php
1269 $editviewdefs = "custom/working/modules/".$modname."/metadata/editviewdefs.php";
1270 $quickcreatedefs = "custom/working/modules/".$modname."/metadata/quickcreatedefs.php";
1272 if ( !file_exists("modules/".$modname."/metadata/quickcreatedefs.php") &&
1273 file_exists($editviewdefs) &&
1274 !file_exists($quickcreatedefs) ){
1275 //clone editviewdef and save it in custom/working/modules/metadata
1276 $GLOBALS['log']->debug("Copying editviewdefs.php as quickcreatedefs.php for the $modname module in custom/working/modules/$modname/metadata!");
1277 if(copy( $editviewdefs, $quickcreatedefs)){
1278 if(file_exists($quickcreatedefs) && is_readable($quickcreatedefs)){
1279 $file = file($quickcreatedefs);
1280 //replace 'EditView' with 'QuickCreate'
1281 $fp = fopen($quickcreatedefs,'w');
1282 foreach($file as &$line){
1283 if(preg_match('/^\s*\'EditView\'\s*=>\s*$/', $line) > 0){
1284 $line = "'QuickCreate' =>\n";
1292 $GLOBALS['log']->debug("Failed to replace 'EditView' with QuickCreate because $quickcreatedefs is either not readable or does not exist.");
1295 $GLOBALS['log']->debug("Failed to copy $editviewdefs to $quickcreatedefs!");
1302 * test perms for CREATE queries
1304 function testPermsCreate($db, $out) {
1305 logThis('Checking CREATE TABLE permissions...');
1306 global $mod_strings;
1308 if(!$db->checkPrivilege("CREATE TABLE")) {
1309 logThis('cannot CREATE TABLE!');
1310 $out['db']['dbNoCreate'] = true;
1311 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_CREATE']}</span></td></tr>";
1317 * test perms for INSERT
1319 function testPermsInsert($db, $out, $skip=false) {
1320 logThis('Checking INSERT INTO permissions...');
1321 global $mod_strings;
1323 if(!$db->checkPrivilege("INSERT")) {
1324 logThis('cannot INSERT INTO!');
1325 $out['db']['dbNoInsert'] = true;
1326 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_INSERT']}</span></td></tr>";
1333 * test perms for UPDATE TABLE
1335 function testPermsUpdate($db, $out, $skip=false) {
1336 logThis('Checking UPDATE TABLE permissions...');
1337 global $mod_strings;
1338 if(!$db->checkPrivilege("UPDATE")) {
1339 logThis('cannot UPDATE TABLE!');
1340 $out['db']['dbNoUpdate'] = true;
1341 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_UPDATE']}</span></td></tr>";
1348 * test perms for SELECT
1350 function testPermsSelect($db, $out, $skip=false) {
1351 logThis('Checking SELECT permissions...');
1352 global $mod_strings;
1353 if(!$db->checkPrivilege("SELECT")) {
1354 logThis('cannot SELECT!');
1355 $out['db']['dbNoSelect'] = true;
1356 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_SELECT']}</span></td></tr>";
1362 * test perms for DELETE
1364 function testPermsDelete($db, $out, $skip=false) {
1365 logThis('Checking DELETE FROM permissions...');
1366 global $mod_strings;
1367 if(!$db->checkPrivilege("DELETE")) {
1368 logThis('cannot DELETE FROM!');
1369 $out['db']['dbNoDelete'] = true;
1370 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_DELETE']}</span></td></tr>";
1377 * test perms for ALTER TABLE ADD COLUMN
1379 function testPermsAlterTableAdd($db, $out, $skip=false) {
1380 logThis('Checking ALTER TABLE ADD COLUMN permissions...');
1381 global $mod_strings;
1382 if(!$db->checkPrivilege("ADD COLUMN")) {
1383 logThis('cannot ADD COLUMN!');
1384 $out['db']['dbNoAddColumn'] = true;
1385 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_ADD_COLUMN']}</span></td></tr>";
1391 * test perms for ALTER TABLE ADD COLUMN
1393 function testPermsAlterTableChange($db, $out, $skip=false) {
1394 logThis('Checking ALTER TABLE CHANGE COLUMN permissions...');
1395 global $mod_strings;
1396 if(!$db->checkPrivilege("CHANGE COLUMN")) {
1397 logThis('cannot CHANGE COLUMN!');
1398 $out['db']['dbNoChangeColumn'] = true;
1399 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_CHANGE_COLUMN']}</span></td></tr>";
1405 * test perms for ALTER TABLE DROP COLUMN
1407 function testPermsAlterTableDrop($db, $out, $skip=false) {
1408 logThis('Checking ALTER TABLE DROP COLUMN permissions...');
1409 global $mod_strings;
1410 if(!$db->checkPrivilege("DROP COLUMN")) {
1411 logThis('cannot DROP COLUMN!');
1412 $out['db']['dbNoDropColumn'] = true;
1413 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_DROP_COLUMN']}</span></td></tr>";
1420 * test perms for DROP TABLE
1422 function testPermsDropTable($db, $out, $skip=false) {
1423 logThis('Checking DROP TABLE permissions...');
1424 global $mod_strings;
1425 if(!$db->checkPrivilege("DROP TABLE")) {
1426 logThis('cannot DROP TABLE!');
1427 $out['db']['dbNoDropTable'] = true;
1428 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_DROP_TABLE']}</span></td></tr>";
1433 function getFormattedError($error, $query) {
1434 $error = "<div><b>".$error;
1435 $error .= "</b>::{$query}</div>";
1441 * parses a query finding the table name
1442 * @param string query The query
1443 * @return string table The table
1445 function getTableFromQuery($query) {
1446 $standardQueries = array('ALTER TABLE', 'DROP TABLE', 'CREATE TABLE', 'INSERT INTO', 'UPDATE', 'DELETE FROM');
1447 $query = preg_replace("/[^A-Za-z0-9\_\s]/", "", $query);
1448 $query = trim(str_replace($standardQueries, '', $query));
1450 $firstSpc = strpos($query, " ");
1451 $end = ($firstSpc > 0) ? $firstSpc : strlen($query);
1452 $table = substr($query, 0, $end);
1459 function preLicenseCheck() {
1460 require_once('modules/UpgradeWizard/uw_files.php');
1462 global $sugar_config;
1463 global $mod_strings;
1464 global $sugar_version;
1466 if (empty($sugar_version))
1468 require('sugar_version.php');
1471 if(!isset($_SESSION['unzip_dir']) || empty($_SESSION['unzip_dir'])) {
1472 logThis('unzipping files in upgrade archive...');
1474 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
1476 //also come up with mechanism to read from upgrade-progress file
1477 if(!isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !is_file($_SESSION['install_file'])) {
1478 if (file_exists(clean_path($base_tmp_upgrade_dir)) && $handle = opendir(clean_path($base_tmp_upgrade_dir))) {
1479 while (false !== ($file = readdir($handle))) {
1480 if($file !="." && $file !="..") {
1481 if(is_file($base_tmp_upgrade_dir."/".$file."/manifest.php")){
1482 require_once($base_tmp_upgrade_dir."/".$file."/manifest.php");
1483 $package_name= $manifest['copy_files']['from_dir'];
1484 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")){
1485 $unzip_dir = $base_tmp_upgrade_dir."/".$file;
1486 if(file_exists("$base_upgrade_dir/patch/".$package_name.'.zip')){
1487 $_SESSION['install_file'] = $package_name.".zip";
1496 if(empty($_SESSION['install_file'])){
1497 unlinkUWTempFiles();
1499 echo 'Upload File not found so redirecting to Upgrade Start ';
1500 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1501 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1502 $upgrade_directories_not_found =<<<eoq
1503 <table cellpadding="3" cellspacing="0" border="0">
1505 <th colspan="2" align="left">
1506 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1511 $uwMain = $upgrade_directories_not_found;
1514 $install_file = "$base_upgrade_dir/patch/".basename(urldecode( $_SESSION['install_file'] ));
1516 if(empty($unzip_dir)){
1517 $unzip_dir = mk_temp_dir( $base_tmp_upgrade_dir );
1519 $zip_from_dir = ".";
1521 $zip_force_copy = array();
1524 logThis('Could not create a temporary directory using mk_temp_dir( $base_tmp_upgrade_dir )');
1525 die($mod_strings['ERR_UW_NO_CREATE_TMP_DIR']);
1528 //double check whether unzipped .
1529 if(file_exists($unzip_dir ."/scripts") && file_exists($unzip_dir."/manifest.php")){
1533 unzip( $install_file, $unzip_dir );
1536 // assumption -- already validated manifest.php at time of upload
1537 require_once( "$unzip_dir/manifest.php" );
1539 if( isset( $manifest['copy_files']['from_dir'] ) && $manifest['copy_files']['from_dir'] != "" ){
1540 $zip_from_dir = $manifest['copy_files']['from_dir'];
1542 if( isset( $manifest['copy_files']['to_dir'] ) && $manifest['copy_files']['to_dir'] != "" ){
1543 $zip_to_dir = $manifest['copy_files']['to_dir'];
1545 if( isset( $manifest['copy_files']['force_copy'] ) && $manifest['copy_files']['force_copy'] != "" ){
1546 $zip_force_copy = $manifest['copy_files']['force_copy'];
1548 if( isset( $manifest['version'] ) ){
1549 $version = $manifest['version'];
1551 if( !is_writable( "config.php" ) ){
1552 return $mod_strings['ERR_UW_CONFIG'];
1555 $_SESSION['unzip_dir'] = clean_path($unzip_dir);
1556 $_SESSION['zip_from_dir'] = clean_path($zip_from_dir);
1557 logThis('unzip done.');
1559 $unzip_dir = $_SESSION['unzip_dir'];
1560 $zip_from_dir = $_SESSION['zip_from_dir'];
1563 //check if $_SESSION['unzip_dir'] and $_SESSION['zip_from_dir'] exist
1564 if(!isset($_SESSION['unzip_dir']) || !file_exists($_SESSION['unzip_dir'])
1565 || !isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !file_exists($_SESSION['install_file'])){
1567 unlinkUWTempFiles();
1569 echo 'Upload File not found so redirecting to Upgrade Start ';
1570 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1571 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1572 $upgrade_directories_not_found =<<<eoq
1573 <table cellpadding="3" cellspacing="0" border="0">
1575 <th colspan="2" align="left">
1576 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1581 $uwMain = $upgrade_directories_not_found;
1585 logThis ('is SugarConfig there '.file_exists(clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarObjects/SugarConfig.php")));
1586 if(file_exists(clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarObjects/SugarConfig.php"))) {
1587 $file = clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarObjects/SugarConfig.php");
1588 $destFile = str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), $cwd, $file);
1589 if(!is_dir(dirname($destFile))) {
1590 mkdir_recursive(dirname($destFile)); // make sure the directory exists
1592 copy($file,$destFile);
1593 //also copy include utils array utils
1594 $file = clean_path($unzip_dir.'/'.$zip_from_dir."/include/utils/array_utils.php");
1595 $destFile = str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), $cwd, $file);
1596 if(!is_dir(dirname($destFile))) {
1597 mkdir_recursive(dirname($destFile)); // make sure the directory exists
1599 copy($file,$destFile);
1604 function preflightCheck() {
1605 require_once('modules/UpgradeWizard/uw_files.php');
1607 global $sugar_config;
1608 global $mod_strings;
1609 global $sugar_version;
1611 if (empty($sugar_version))
1613 require('sugar_version.php');
1616 unset($_SESSION['rebuild_relationships']);
1617 unset($_SESSION['rebuild_extensions']);
1619 // don't bother if are rechecking
1620 $manualDiff = array();
1621 if(!isset($_SESSION['unzip_dir']) || empty($_SESSION['unzip_dir'])) {
1622 logThis('unzipping files in upgrade archive...');
1624 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
1626 //Following is if User logged out unexpectedly and then logged into UpgradeWizard again.
1627 //also come up with mechanism to read from upgrade-progress file.
1628 if(!isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !is_file($_SESSION['install_file'])) {
1629 if (file_exists($base_tmp_upgrade_dir) && $handle = opendir($base_tmp_upgrade_dir)) {
1630 while (false !== ($file = readdir($handle))) {
1631 if($file !="." && $file !="..") {
1632 if(is_file($base_tmp_upgrade_dir."/".$file."/manifest.php")){
1633 require_once($base_tmp_upgrade_dir."/".$file."/manifest.php");
1634 $package_name= $manifest['copy_files']['from_dir'];
1635 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")){
1636 $unzip_dir = $base_tmp_upgrade_dir."/".$file;
1637 if(file_exists("$base_upgrade_dir/patch/".$package_name.'.zip')){
1638 $_SESSION['install_file'] = $package_name.".zip";
1647 if(empty($_SESSION['install_file'])){
1648 unlinkUWTempFiles();
1650 echo 'Upload File not found so redirecting to Upgrade Start ';
1651 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1652 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1653 $upgrade_directories_not_found =<<<eoq
1654 <table cellpadding="3" cellspacing="0" border="0">
1656 <th colspan="2" align="left">
1657 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1662 $uwMain = $upgrade_directories_not_found;
1666 $install_file = "$base_upgrade_dir/patch/".basename(urldecode( $_SESSION['install_file'] ));
1668 if(empty($unzip_dir)){
1669 $unzip_dir = mk_temp_dir( $base_tmp_upgrade_dir );
1671 $zip_from_dir = ".";
1673 $zip_force_copy = array();
1676 logThis('Could not create a temporary directory using mk_temp_dir( $base_tmp_upgrade_dir )');
1677 die($mod_strings['ERR_UW_NO_CREATE_TMP_DIR']);
1680 //double check whether unzipped .
1681 if(file_exists($unzip_dir ."/scripts") && file_exists($unzip_dir."/manifest.php")){
1685 unzip( $install_file, $unzip_dir );
1688 // assumption -- already validated manifest.php at time of upload
1689 require_once( "$unzip_dir/manifest.php" );
1691 if( isset( $manifest['copy_files']['from_dir'] ) && $manifest['copy_files']['from_dir'] != "" ){
1692 $zip_from_dir = $manifest['copy_files']['from_dir'];
1694 if( isset( $manifest['copy_files']['to_dir'] ) && $manifest['copy_files']['to_dir'] != "" ){
1695 $zip_to_dir = $manifest['copy_files']['to_dir'];
1697 if( isset( $manifest['copy_files']['force_copy'] ) && $manifest['copy_files']['force_copy'] != "" ){
1698 $zip_force_copy = $manifest['copy_files']['force_copy'];
1700 if( isset( $manifest['version'] ) ){
1701 $version = $manifest['version'];
1703 if( !is_writable( "config.php" ) ){
1704 return $mod_strings['ERR_UW_CONFIG'];
1707 $_SESSION['unzip_dir'] = clean_path($unzip_dir);
1708 $_SESSION['zip_from_dir'] = clean_path($zip_from_dir);
1710 //logThis('unzip done.');
1712 $unzip_dir = $_SESSION['unzip_dir'];
1713 $zip_from_dir = $_SESSION['zip_from_dir'];
1715 //check if $_SESSION['unzip_dir'] and $_SESSION['zip_from_dir'] exist
1716 if(!isset($_SESSION['unzip_dir']) || !file_exists($_SESSION['unzip_dir'])
1717 || !isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !file_exists($_SESSION['install_file'])){
1719 unlinkUWTempFiles();
1721 echo 'Upload File not found so redirecting to Upgrade Start ';
1722 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1723 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1724 $upgrade_directories_not_found =<<<eoq
1725 <table cellpadding="3" cellspacing="0" border="0">
1727 <th colspan="2" align="left">
1728 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1733 $uwMain = $upgrade_directories_not_found;
1736 //copy minimum required files
1737 fileCopy('include/utils/sugar_file_utils.php');
1739 $upgradeFiles = findAllFiles(clean_path("$unzip_dir/$zip_from_dir"), array());
1740 $cache_html_files= array();
1743 $md5_string = array();
1744 if(file_exists(clean_path(getcwd().'/files.md5'))){
1745 require(clean_path(getcwd().'/files.md5'));
1748 // file preflight checks
1749 logThis('verifying md5 checksums for files...');
1750 foreach($upgradeFiles as $file) {
1751 if(in_array(str_replace(clean_path("$unzip_dir/$zip_from_dir") . "/", '', $file), $uw_files))
1752 continue; // skip already loaded files
1754 if(strpos($file, '.md5'))
1755 continue; // skip md5 file
1757 // normalize file paths
1758 $file = clean_path($file);
1760 // check that we can move/delete the upgraded file
1761 if(!is_writable($file)) {
1762 $errors[] = $mod_strings['ERR_UW_FILE_NOT_WRITABLE'].": ".$file;
1764 // check that destination files are writable
1765 $destFile = getcwd().str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), '', $file);
1767 if(is_file($destFile)) { // of course it needs to exist first...
1768 if(!is_writable($destFile)) {
1769 $errors[] = $mod_strings['ERR_UW_FILE_NOT_WRITABLE'].": ".$destFile;
1773 ///////////////////////////////////////////////////////////////////////
1775 // compare md5s and build up a manual merge list
1776 $targetFile = clean_path(".".str_replace(getcwd(),'',$destFile));
1778 if(is_file($destFile)) {
1779 if(strpos($targetFile, '.php')) {
1780 // handle PHP files that were hit with the security regex
1782 if(function_exists('sugar_fopen')){
1783 $fp = sugar_fopen($destFile, 'r');
1786 $fp = fopen($destFile, 'r');
1788 $filesize = filesize($destFile);
1790 $fileContents = stream_get_contents($fp);
1791 $targetMd5 = md5($fileContents);
1794 $targetMd5 = md5_file($destFile);
1798 if(isset($md5_string[$targetFile]) && $md5_string[$targetFile] != $targetMd5) {
1799 logThis('found a file with a differing md5: ['.$targetFile.']');
1800 $manualDiff[] = $destFile;
1803 ///////////////////////////////////////////////////////////////////////
1805 logThis('md5 verification done.');
1806 $errors['manual'] = $manualDiff;
1811 function fileCopy($file_path){
1812 if(file_exists(clean_path($_SESSION['unzip_dir'].'/'.$_SESSION['zip_from_dir'].'/'.$file_path))) {
1813 $file = clean_path($_SESSION['unzip_dir'].'/'.$_SESSION['zip_from_dir'].'/'.$file_path);
1814 $destFile = str_replace(clean_path($_SESSION['unzip_dir'].'/'.$_SESSION['zip_from_dir']), clean_path(getcwd()), $file);
1815 if(!is_dir(dirname($destFile))) {
1816 mkdir_recursive(dirname($destFile)); // make sure the directory exists
1818 copy_recursive($file,$destFile);
1821 function getChecklist($steps, $step) {
1822 global $mod_strings;
1824 $skip = array('start', 'cancel', 'uninstall','end');
1827 $ret = '<table cellpadding="3" cellspacing="4" border="0">';
1828 $ret .= '<tr><th colspan="3" align="left">'.$mod_strings['LBL_UW_CHECKLIST'].':</th></tr>';
1829 foreach($steps['desc'] as $k => $desc) {
1830 if(in_array($steps['files'][$j], $skip)) {
1835 //$status = "<span class='error'>{$mod_strings['LBL_UW_INCOMPLETE']}</span>";
1837 $desc_mod_post = '';
1839 if(isset($_SESSION['step'][$steps['files'][$k]]) && $_SESSION['step'][$steps['files'][$k]] == 'success') {
1840 //$status = $mod_strings['LBL_UW_COMPLETE'];
1844 if($k == $_REQUEST['step']) {
1845 //$status = $mod_strings['LBL_UW_IN_PROGRESS'];
1846 $desc_mod_pre = "<font color=blue><i>";
1847 $desc_mod_post = "</i></font>";
1850 $ret .= "<tr><td> </td><td><b>{$i}: {$desc_mod_pre}{$desc}{$desc_mod_post}</b></td>";
1851 $ret .= "<td id={$steps['files'][$j]}><i></i></td></tr>";
1859 function prepSystemForUpgrade() {
1860 global $sugar_config;
1861 global $sugar_flavor;
1862 global $mod_strings;
1863 global $current_language;
1865 global $base_upgrade_dir;
1866 global $base_tmp_upgrade_dir;
1867 list($p_base_upgrade_dir, $p_base_tmp_upgrade_dir) = getUWDirs();
1868 ///////////////////////////////////////////////////////////////////////////////
1869 //// Make sure variables exist
1870 if(empty($base_upgrade_dir)){
1871 $base_upgrade_dir = $p_base_upgrade_dir;
1873 if(empty($base_tmp_upgrade_dir)){
1874 $base_tmp_upgrade_dir = $p_base_tmp_upgrade_dir;
1876 sugar_mkdir($base_tmp_upgrade_dir, 0775, true);
1877 if(!isset($subdirs) || empty($subdirs)){
1878 $subdirs = array('full', 'langpack', 'module', 'patch', 'theme');
1881 $upgrade_progress_dir = $base_tmp_upgrade_dir;
1882 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
1883 if(file_exists($upgrade_progress_file)){
1884 if(function_exists('get_upgrade_progress') && function_exists('didThisStepRunBefore')){
1885 if(didThisStepRunBefore('end')){
1886 include($upgrade_progress_file);
1887 unset($upgrade_config);
1888 unlink($upgrade_progress_file);
1893 // increase the cuttoff time to 1 hour
1894 ini_set("max_execution_time", "3600");
1896 // make sure dirs exist
1897 if($subdirs != null){
1898 foreach($subdirs as $subdir) {
1899 sugar_mkdir("$base_upgrade_dir/$subdir", 0775, true);
1902 // array of special scripts that are executed during (un)installation-- key is type of script, value is filename
1903 if(!defined('SUGARCRM_PRE_INSTALL_FILE')) {
1904 define('SUGARCRM_PRE_INSTALL_FILE', 'scripts/pre_install.php');
1905 define('SUGARCRM_POST_INSTALL_FILE', 'scripts/post_install.php');
1906 define('SUGARCRM_PRE_UNINSTALL_FILE', 'scripts/pre_uninstall.php');
1907 define('SUGARCRM_POST_UNINSTALL_FILE', 'scripts/post_uninstall.php');
1910 $script_files = array(
1911 "pre-install" => constant('SUGARCRM_PRE_INSTALL_FILE'),
1912 "post-install" => constant('SUGARCRM_POST_INSTALL_FILE'),
1913 "pre-uninstall" => constant('SUGARCRM_PRE_UNINSTALL_FILE'),
1914 "post-uninstall" => constant('SUGARCRM_POST_UNINSTALL_FILE'),
1917 // check that the upload limit is set to 6M or greater
1918 define('SUGARCRM_MIN_UPLOAD_MAX_FILESIZE_BYTES', 6 * 1024 * 1024); // 6 Megabytes
1919 $upload_max_filesize = ini_get('upload_max_filesize');
1920 $upload_max_filesize_bytes = return_bytes($upload_max_filesize);
1922 if($upload_max_filesize_bytes < constant('SUGARCRM_MIN_UPLOAD_MAX_FILESIZE_BYTES')) {
1923 $GLOBALS['log']->debug("detected upload_max_filesize: $upload_max_filesize");
1924 $admin_strings = return_module_language($current_language, 'Administration');
1925 echo '<p class="error">'.$admin_strings['MSG_INCREASE_UPLOAD_MAX_FILESIZE'].' '.get_cfg_var('cfg_file_path')."</p>\n";
1929 if ( !function_exists('extractFile') ) {
1930 function extractFile($zip_file, $file_in_zip) {
1931 global $base_tmp_upgrade_dir;
1934 $absolute_base_tmp_upgrade_dir = clean_path($base_tmp_upgrade_dir);
1935 $relative_base_tmp_upgrade_dir = clean_path(str_replace(clean_path(getcwd()), '', $absolute_base_tmp_upgrade_dir));
1937 // mk_temp_dir expects relative pathing
1938 $my_zip_dir = mk_temp_dir($relative_base_tmp_upgrade_dir);
1940 unzip_file($zip_file, $file_in_zip, $my_zip_dir);
1942 return("$my_zip_dir/$file_in_zip");
1946 if ( !function_exists('extractManifest') ) {
1947 function extractManifest($zip_file) {
1948 logThis('extracting manifest.');
1949 return(extractFile($zip_file, "manifest.php"));
1953 if ( !function_exists('getInstallType') ) {
1954 function getInstallType($type_string) {
1957 $subdirs = array('full', 'langpack', 'module', 'patch', 'theme', 'temp');
1958 foreach($subdirs as $subdir) {
1959 if(preg_match("#/$subdir/#", $type_string)) {
1963 // return empty if no match
1968 function getImageForType($type) {
1970 global $mod_strings;
1975 $icon = SugarThemeRegistry::current()->getImage("Upgrade", "",null,null,'.gif',$mod_strings['LBL_UPGRADE']);
1978 $icon = SugarThemeRegistry::current()->getImage("LanguagePacks", "",null,null,'.gif',$mod_strings['LBL_LANGPACKS']);
1981 $icon = SugarThemeRegistry::current()->getImage("ModuleLoader", "",null,null,'.gif',$mod_strings['LBL_MODULELOADER']);
1984 $icon = SugarThemeRegistry::current()->getImage("PatchUpgrades", "",null,null,'.gif',$mod_strings['LBL_PATCHUPGRADES']);
1987 $icon = SugarThemeRegistry::current()->getImage("Themes", "",null,null,'.gif',$mod_strings['LBL_THEMES']);
1995 if ( !function_exists('getLanguagePackName') ) {
1996 function getLanguagePackName($the_file) {
1997 require_once("$the_file");
1998 if(isset($app_list_strings["language_pack_name"])) {
1999 return($app_list_strings["language_pack_name"]);
2005 function getUITextForType($type) {
2006 if($type == "full") {
2007 return("Full Upgrade");
2009 if($type == "langpack") {
2010 return("Language Pack");
2012 if($type == "module") {
2015 if($type == "patch") {
2018 if($type == "theme") {
2023 if ( !function_exists('validate_manifest') ) {
2025 * Verifies a manifest from a patch or module to be compatible with the current Sugar version and flavor
2026 * @param array manifest Standard manifest array
2027 * @return string Error message, blank on success
2029 function validate_manifest($manifest) {
2030 logThis('validating manifest.php file');
2031 // takes a manifest.php manifest array and validates contents
2033 global $sugar_version;
2034 global $sugar_flavor;
2035 global $mod_strings;
2037 if(!isset($manifest['type'])) {
2038 return $mod_strings['ERROR_MANIFEST_TYPE'];
2041 $type = $manifest['type'];
2043 if(getInstallType("/$type/") == "") {
2044 return $mod_strings['ERROR_PACKAGE_TYPE']. ": '" . $type . "'.";
2047 if(isset($manifest['acceptable_sugar_versions'])) {
2048 $version_ok = false;
2049 $matches_empty = true;
2050 if(isset($manifest['acceptable_sugar_versions']['exact_matches'])) {
2051 $matches_empty = false;
2052 foreach($manifest['acceptable_sugar_versions']['exact_matches'] as $match) {
2053 if($match == $sugar_version) {
2058 if(!$version_ok && isset($manifest['acceptable_sugar_versions']['regex_matches'])) {
2059 $matches_empty = false;
2060 foreach($manifest['acceptable_sugar_versions']['regex_matches'] as $match) {
2061 if(preg_match("/$match/", $sugar_version)) {
2067 if(!$matches_empty && !$version_ok) {
2068 return $mod_strings['ERROR_VERSION_INCOMPATIBLE']."<br />".
2069 $mod_strings['ERR_UW_VERSION'].$sugar_version;
2073 if(isset($manifest['acceptable_sugar_flavors']) && sizeof($manifest['acceptable_sugar_flavors']) > 0) {
2075 foreach($manifest['acceptable_sugar_flavors'] as $match) {
2076 if($match == $sugar_flavor) {
2081 return $mod_strings['ERROR_FLAVOR_INCOMPATIBLE']."<br />".
2082 $mod_strings['ERR_UW_FLAVOR'].$sugar_flavor."<br />".
2083 $mod_strings['ERR_UW_FLAVOR_2'].$manifest['acceptable_sugar_flavors'][0];
2091 function unlinkUploadFiles() {
2093 // logThis('at unlinkUploadFiles()');
2095 // if(isset($_SESSION['install_file']) && !empty($_SESSION['install_file'])) {
2096 // $upload = $_SESSION['install_file'];
2098 // if(is_file($upload)) {
2099 // logThis('unlinking ['.$upload.']');
2100 // @unlink($upload);
2106 * deletes files created by unzipping a package
2108 function unlinkUWTempFiles() {
2109 global $sugar_config;
2112 logThis('at unlinkUWTempFiles()');
2114 list($upgDir, $tempDir) = getUWDirs();
2116 if(file_exists($tempDir) && is_dir($tempDir)){
2117 $files = findAllFiles($tempDir, array(), false);
2119 foreach($files as $file) {
2120 if(!is_dir($file)) {
2121 //logThis('unlinking ['.$file.']', $path);
2126 $files = findAllFiles($tempDir, array(), true);
2127 foreach($files as $dir) {
2129 //logThis('removing dir ['.$dir.']', $path);
2133 $cacheFile = sugar_cached("modules/UpgradeWizard/_persistence.php");
2134 if(is_file($cacheFile)) {
2135 logThis("Unlinking Upgrade cache file: '_persistence.php'", $path);
2136 @unlink($cacheFile);
2139 logThis("finished!");
2143 * finds all files in the passed path, but skips select directories
2144 * @param string dir Relative path
2145 * @param array the_array Collections of found files/dirs
2146 * @param bool include_dir True if we want to include directories in the
2147 * returned collection
2149 function uwFindAllFiles($dir, $theArray, $includeDirs=false, $skipDirs=array(), $echo=false) {
2151 if (whetherNeedToSkipDir($dir, $skipDirs))
2156 if (!is_dir($dir)) { return $theArray; } // Bug # 46035, just checking for valid dir
2158 if ($d === false) { return $theArray; } // Bug # 46035, more checking
2160 while($f = $d->read()) {
2161 // bug 40793 Skip Directories array in upgradeWizard does not function correctly
2162 if($f == "." || $f == ".." || whetherNeedToSkipDir("$dir/$f", $skipDirs)) { // skip *nix self/parent
2166 // for AJAX length count
2172 if(is_dir("$dir/$f")) {
2173 if($includeDirs) { // add the directory if flagged
2174 $theArray[] = clean_path("$dir/$f");
2178 $theArray = uwFindAllFiles("$dir/$f/", $theArray, $includeDirs, $skipDirs, $echo);
2180 $theArray[] = clean_path("$dir/$f");
2193 * unset's UW's Session Vars
2195 function resetUwSession() {
2196 logThis('resetting $_SESSION');
2198 if(isset($_SESSION['committed']))
2199 unset($_SESSION['committed']);
2200 if(isset($_SESSION['sugar_version_file']))
2201 unset($_SESSION['sugar_version_file']);
2202 if(isset($_SESSION['upgrade_complete']))
2203 unset($_SESSION['upgrade_complete']);
2204 if(isset($_SESSION['allTables']))
2205 unset($_SESSION['allTables']);
2206 if(isset($_SESSION['alterCustomTableQueries']))
2207 unset($_SESSION['alterCustomTableQueries']);
2208 if(isset($_SESSION['skip_zip_upload']))
2209 unset($_SESSION['skip_zip_upload']);
2210 if(isset($_SESSION['install_file']))
2211 unset($_SESSION['install_file']);
2212 if(isset($_SESSION['unzip_dir']))
2213 unset($_SESSION['unzip_dir']);
2214 if(isset($_SESSION['zip_from_dir']))
2215 unset($_SESSION['zip_from_dir']);
2216 if(isset($_SESSION['overwrite_files']))
2217 unset($_SESSION['overwrite_files']);
2218 if(isset($_SESSION['schema_change']))
2219 unset($_SESSION['schema_change']);
2220 if(isset($_SESSION['uw_restore_dir']))
2221 unset($_SESSION['uw_restore_dir']);
2222 if(isset($_SESSION['step']))
2223 unset($_SESSION['step']);
2224 if(isset($_SESSION['files']))
2225 unset($_SESSION['files']);
2226 if(isset($_SESSION['Upgraded451Wizard'])){
2227 unset($_SESSION['Upgraded451Wizard']);
2229 if(isset($_SESSION['Initial_451to500_Step'])){
2230 unset($_SESSION['Initial_451to500_Step']);
2232 if(isset($_SESSION['license_shown']))
2233 unset($_SESSION['license_shown']);
2234 if(isset($_SESSION['sugarMergeRunResults']))
2235 unset($_SESSION['sugarMergeRunResults']);
2239 * runs rebuild scripts
2241 function UWrebuild() {
2245 //CCL - Comment this block out, it is called in end.php
2246 logThis('Rebuilding everything...', $path);
2247 require_once('modules/Administration/QuickRepairAndRebuild.php');
2248 $randc = new RepairAndClear();
2249 $randc->repairAndClearAll(array('clearAll'),array(translate('LBL_ALL_MODULES')), false, false);
2251 $query = "DELETE FROM versions WHERE name='Rebuild Extensions'";
2253 logThis('Registering rebuild record: '.$query, $path);
2254 logThis('Rebuild done.', $path);
2256 // insert a new database row to show the rebuild extensions is done
2257 $id = create_guid();
2258 $gmdate = gmdate('Y-m-d H:i:s');
2259 $date_entered = db_convert("'$gmdate'", 'datetime');
2260 $query = 'INSERT INTO versions (id, deleted, date_entered, date_modified, modified_user_id, created_by, name, file_version, db_version) '
2261 . "VALUES ('$id', '0', $date_entered, $date_entered, '1', '1', 'Rebuild Extensions', '4.0.0', '4.0.0')";
2263 logThis('Registering rebuild record in versions table: '.$query, $path);
2266 function getCustomTables() {
2269 return $db->tablesLike('%_cstm');
2272 function alterCustomTables($customTables)
2277 function getAllTables() {
2279 return $db->getTablesArray();
2282 function printAlterTableSql($tables)
2284 $alterTableSql = '';
2286 foreach($tables as $table)
2287 $alterTableSql .= "ALTER TABLE " . $table . " CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;" . "\n";
2289 return $alterTableSql;
2292 function executeConvertTablesSql($tables)
2296 foreach($tables as $table){
2297 $query = "ALTER TABLE " . $table . " CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci";
2299 logThis("Sending query: ".$query);
2300 $db->query($query);//, true, "An error has occured while performing db query. See log file for details.<br>");
2306 function testThis() {
2307 $files = uwFindAllFiles(getcwd().'/test', array());
2309 $out = "<table cellpadding='1' cellspacing='0' border='0'>\n";
2312 foreach($files as $file) {
2313 $relativeFile = clean_path(str_replace(getcwd().'/test', '', $file));
2314 $relativeFile = ($relativeFile{0} == '/') ? substr($relativeFile, 1, strlen($relativeFile)) : $relativeFile;
2316 $relativePath = dirname($relativeFile);
2318 if($relativePath == $priorPath) { // same dir, new file
2319 $out .= "<tr><td>".basename($relativeFile)."</td></tr>";
2320 $priorPath = $relativePath;
2334 function testThis2($dir, $id=0, $hide=false) {
2335 global $mod_strings;
2337 $dh = opendir($dir);
2340 $doHide = ($hide) ? 'none' : '';
2341 $out = "<div id='{$id}' style='display:{$doHide};'>";
2342 $out .= "<table cellpadding='1' cellspacing='0' style='border:0px solid #ccc'>\n";
2344 while($file = readdir($dh)) {
2345 if($file == '.' || $file == '..' || $file == 'CVS' || $file == '.cvsignore')
2348 if(is_dir($path.'/'.$file)) {
2349 $file = $path.'/'.$file;
2350 $newI = create_guid();
2351 $out .= "<tr><td valign='top'><a href='javascript:toggleNwFiles(\"{$newI}\");'>".SugarThemeRegistry::current()->getImage("Workflow", "", null, null, ".gif", $mod_strings['LBL_WORKFLOW'])."</a></td>\n";
2352 $out .= "<td valign='top'><b><a href='javascript:toggleNwFiles(\"{$newI}\");'>".basename($file)."</a></b></td></tr>";
2353 $out .= "<tr><td></td><td valign='top'>".testThis2($file, $newI, true)."</td></tr>";
2355 $out .= "<tr><td valign='top'> </td>\n";
2356 $out .= "<td valign='top'>".basename($file)."</td></tr>";
2360 $out .= "</tr></table>";
2371 function testThis3(&$files, $id, $hide, $previousPath = '') {
2372 if(!is_array($files) || empty($files))
2377 global $mod_strings;
2378 // expecting full path here
2379 foreach($files as $k => $file) {
2380 $file = str_replace(getcwd(), '', $file);
2381 $path = dirname($file);
2382 $fileName = basename($file);
2384 if($fileName == 'CVS' || $fileName == '.cvsignore')
2387 if($path == $previousPath) { // same directory
2388 // new row for each file
2389 $out .= "<tr><td valign='top' align='left'> </td>";
2390 $out .= "<td valign='top' align='left'>{$fileName}</td></tr>";
2391 } else { // new directory
2393 $out .= "<tr><td valign='top'><a href='javascript:toggleNwFiles(\"{$newI}\");'>".SugarThemeRegistry::current()->getImage("Workflow", "", null, null, ".gif", $mod_strings['LBL_WORKFLOW'])."</a></td>\n";
2394 $out .= "<td valign='top'><b><a href='javascript:toggleNwFiles(\"{$newI}\");'>".$fileName."</a></b></td></tr>";
2395 $recurse = testThis3($files, $newI, true, $previousPath);
2396 $out .= "<tr><td></td><td valign='top'>".$recurse."</td></tr>";
2399 $previousPath = $path;
2401 $display = ($hide) ? 'none' : '';
2403 <div id="{$id}" style="display:{$display}">
2404 <table cellpadding='1' cellspacing='0' border='0' style='border:1px solid #ccc'>
2413 function testThis4($filePath, $fileNodes=array(), $fileName='') {
2414 $path = dirname($filePath);
2415 $file = basename($filePath);
2417 $exFile = explode('/', $path);
2419 foreach($exFile as $pathSegment) {
2420 if(is_array($fileNodes[$pathSegment])) { // path already processed
2422 } else { // newly found path
2423 $fileNodes[$pathSegment] = array();
2426 if($fileName != '') {
2427 $fileNodes[$pathSegment][] = $fileName;
2436 ///////////////////////////////////////////////////////////////////////////////
2437 //// SYSTEM CHECK FUNCTIONS
2439 * generates an array with all files in the SugarCRM root directory, skipping
2441 * @return array files Array of files with absolute paths
2443 function getFilesForPermsCheck() {
2444 global $sugar_config;
2446 logThis('Got JSON call to find all files...');
2447 $filesNotWritable = array();
2448 $filesNWPerms = array();
2450 // add directories here that should be skipped when doing file permissions checks (cache/upload is the nasty one)
2452 $sugar_config['upload_dir'],
2454 $files = uwFindAllFiles(".", array(), true, $skipDirs, true);
2459 * checks files for permissions
2460 * @param array files Array of files with absolute paths
2461 * @return string result of check
2463 function checkFiles($files, $echo=false) {
2464 global $mod_strings;
2465 $filesNotWritable = array();
2468 <a href='javascript:void(0); toggleNwFiles(\"filesNw\");'>{$mod_strings['LBL_UW_SHOW_NW_FILES']}</a>
2469 <div id='filesNw' style='display:none;'>
2470 <table cellpadding='3' cellspacing='0' border='0'>
2472 <th align='left'>{$mod_strings['LBL_UW_FILE']}</th>
2473 <th align='left'>{$mod_strings['LBL_UW_FILE_PERMS']}</th>
2474 <th align='left'>{$mod_strings['LBL_UW_FILE_OWNER']}</th>
2475 <th align='left'>{$mod_strings['LBL_UW_FILE_GROUP']}</th>
2478 $isWindows = is_windows();
2479 foreach($files as $file) {
2482 if(!is_writable_windows($file)) {
2483 logThis('WINDOWS: File ['.$file.'] not readable - saving for display');
2484 // don't warn yet - we're going to use this to check against replacement files
2485 // aw: commented out; it's a hack to allow upgrade wizard to continue on windows... will fix later
2486 /*$filesNotWritable[$i] = $file;
2487 $filesNWPerms[$i] = substr(sprintf('%o',fileperms($file)), -4);
2488 $filesOut .= "<tr>".
2489 "<td><span class='error'>{$file}</span></td>".
2490 "<td>{$filesNWPerms[$i]}</td>".
2491 "<td>".$mod_strings['ERR_UW_CANNOT_DETERMINE_USER']."</td>".
2492 "<td>".$mod_strings['ERR_UW_CANNOT_DETERMINE_GROUP']."</td>".
2496 if(!is_writable($file)) {
2497 logThis('File ['.$file.'] not writable - saving for display');
2498 // don't warn yet - we're going to use this to check against replacement files
2499 $filesNotWritable[$i] = $file;
2500 $filesNWPerms[$i] = substr(sprintf('%o',fileperms($file)), -4);
2501 $owner = posix_getpwuid(fileowner($file));
2502 $group = posix_getgrgid(filegroup($file));
2503 $filesOut .= "<tr>".
2504 "<td><span class='error'>{$file}</span></td>".
2505 "<td>{$filesNWPerms[$i]}</td>".
2506 "<td>".$owner['name']."</td>".
2507 "<td>".$group['name']."</td>".
2514 $filesOut .= '</table></div>';
2516 $errors['files']['filesNotWritable'] = (count($filesNotWritable) > 0) ? true : false;
2517 if(count($filesNotWritable) < 1) {
2518 $filesOut = "{$mod_strings['LBL_UW_FILE_NO_ERRORS']}";
2524 function deletePackageOnCancel(){
2525 global $mod_strings;
2526 global $sugar_config;
2527 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
2528 logThis('running delete');
2529 if(!isset($_SESSION['install_file']) || ($_SESSION['install_file'] == "")) {
2530 logThis('ERROR: trying to delete non-existent file: ['.$_REQUEST['install_file'].']');
2531 $error = $mod_strings['ERR_UW_NO_FILE_UPLOADED'];
2533 // delete file in upgrades/patch
2534 $delete_me = "$base_upgrade_dir/patch/".basename(urldecode( $_REQUEST['install_file'] ));
2535 if(@unlink($delete_me)) {
2536 //logThis('unlinking: '.$delete_me);
2537 $out = basename($delete_me).$mod_strings['LBL_UW_FILE_DELETED'];
2539 logThis('ERROR: could not delete ['.$delete_me.']');
2540 $error = $mod_strings['ERR_UW_FILE_NOT_DELETED'].$delete_me;
2543 if(!empty($error)) {
2544 $out = "<b><span class='error'>{$error}</span></b><br />";
2548 function handleExecuteSqlKeys($db, $tableName, $disable)
2550 if(empty($tableName)) return true;
2551 if(is_callable(array($db, "supports"))) {
2553 return $disable?$db->disableKeys($tableName):$db->enableKeys($tableName);
2556 $op = $disable?"DISABLE":"ENABLE";
2557 return $db->query("ALTER TABLE $tableName $op KEYS");
2561 function parseAndExecuteSqlFile($sqlScript,$forStepQuery='',$resumeFromQuery='')
2563 global $sugar_config;
2564 $alterTableSchema = '';
2565 $sqlErrors = array();
2566 if(!isset($_SESSION['sqlSkippedQueries'])){
2567 $_SESSION['sqlSkippedQueries'] = array();
2569 $db = DBManagerFactory::getInstance();
2570 $disable_keys = ($db->dbType == "mysql"); // have to use old way for now for upgrades
2571 if(strpos($resumeFromQuery,",") != false){
2572 $resumeFromQuery = explode(",",$resumeFromQuery);
2574 if(file_exists($sqlScript)) {
2575 $fp = fopen($sqlScript, 'r');
2576 $contents = stream_get_contents($fp);
2577 $anyScriptChanges =$contents;
2578 $resumeAfterFound = false;
2582 while($line = fgets($fp)) {
2583 if(strpos($line, '--') === false) {
2584 $completeLine .= " ".trim($line);
2585 if(strpos($line, ';') !== false) {
2587 $query = str_replace(';','',$completeLine);
2588 //if resume from query is not null then find out from where
2589 //it should start executing the query.
2591 if($query != null && $resumeFromQuery != null){
2592 if(!$resumeAfterFound){
2593 if(strpos($query,",") != false){
2594 $queArray = explode(",",$query);
2595 for($i=0;$i<sizeof($resumeFromQuery);$i++){
2596 if(strcasecmp(trim($resumeFromQuery[$i]),trim($queArray[$i]))==0){
2597 $resumeAfterFound = true;
2599 $resumeAfterFound = false;
2605 elseif(strcasecmp(trim($resumeFromQuery),trim($query))==0){
2606 $resumeAfterFound = true;
2609 if($resumeAfterFound){
2612 // if $count=1 means it is just found so skip the query. Run the next one
2613 if($query != null && $resumeAfterFound && $count >1){
2614 $tableName = getAlterTable($query);
2617 handleExecuteSqlKeys($db, $tableName, true);
2620 if($db->checkError()){
2621 //put in the array to use later on
2622 $_SESSION['sqlSkippedQueries'][] = $query;
2626 handleExecuteSqlKeys($db, $tableName, false);
2628 $progQuery[$forStepQuery]=$query;
2629 post_install_progress($progQuery,$action='set');
2632 elseif($query != null){
2633 $tableName = getAlterTable($query);
2636 handleExecuteSqlKeys($db, $tableName, true);
2641 handleExecuteSqlKeys($db, $tableName, false);
2643 $progQuery[$forStepQuery]=$query;
2644 post_install_progress($progQuery,$action='set');
2645 if($db->checkError()){
2646 //put in the array to use later on
2647 $_SESSION['sqlSkippedQueries'][] = $query;
2659 function getAlterTable($query){
2660 $query = strtolower($query);
2661 if (preg_match('/^\s*alter\s+table\s+/', $query)) {
2662 $sqlArray = explode(" ", $query);
2663 $key = array_search('table', $sqlArray);
2664 return $sqlArray[($key+1)];
2670 function set_upgrade_vars(){
2671 logThis('setting session variables...');
2672 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2673 if(!is_dir($upgrade_progress_dir)){
2674 mkdir_recursive($upgrade_progress_dir);
2676 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2677 if(file_exists($upgrade_progress_file)){
2678 include($upgrade_progress_file);
2681 fopen($upgrade_progress_file, 'w+');
2683 if(!isset($upgrade_config) || $upgrade_config == null){
2684 $upgrade_config = array();
2685 $upgrade_config[1]['upgrade_vars']=array();
2687 if(isset($upgrade_config[1]) && isset($upgrade_config[1]['upgrade_vars']) && !is_array($upgrade_config[1]['upgrade_vars'])){
2688 $upgrade_config[1]['upgrade_vars'] = array();
2691 if(!isset($upgrade_vars) || $upgrade_vars == NULL){
2692 $upgrade_vars = array();
2694 if(isset($_SESSION['unzip_dir']) && !empty($_SESSION['unzip_dir']) && file_exists($_SESSION['unzip_dir'])){
2695 $upgrade_vars['unzip_dir']=$_SESSION['unzip_dir'];
2697 if(isset($_SESSION['install_file']) && !empty($_SESSION['install_file']) && file_exists($_SESSION['install_file'])){
2698 $upgrade_vars['install_file']=$_SESSION['install_file'];
2700 if(isset($_SESSION['Upgraded451Wizard']) && !empty($_SESSION['Upgraded451Wizard'])){
2701 $upgrade_vars['Upgraded451Wizard']=$_SESSION['Upgraded451Wizard'];
2703 if(isset($_SESSION['license_shown']) && !empty($_SESSION['license_shown'])){
2704 $upgrade_vars['license_shown']=$_SESSION['license_shown'];
2706 if(isset($_SESSION['Initial_451to500_Step']) && !empty($_SESSION['Initial_451to500_Step'])){
2707 $upgrade_vars['Initial_451to500_Step']=$_SESSION['Initial_451to500_Step'];
2709 if(isset($_SESSION['zip_from_dir']) && !empty($_SESSION['zip_from_dir'])){
2710 $upgrade_vars['zip_from_dir']=$_SESSION['zip_from_dir'];
2712 //place into the upgrade_config array and rewrite config array only if new values are being inserted
2713 if(isset($upgrade_vars) && $upgrade_vars != null && sizeof($upgrade_vars) > 0){
2714 foreach($upgrade_vars as $key=>$val){
2715 if($key != null && $val != null){
2716 $upgrade_config[1]['upgrade_vars'][$key]=$upgrade_vars[$key];
2719 ksort($upgrade_config);
2720 if(is_writable($upgrade_progress_file) && write_array_to_file( "upgrade_config", $upgrade_config,
2721 $upgrade_progress_file)) {
2722 //writing to the file
2727 function initialize_session_vars(){
2728 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2729 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2730 if(file_exists($upgrade_progress_file)){
2731 include($upgrade_progress_file);
2732 if(isset($upgrade_config) && $upgrade_config != null && is_array($upgrade_config) && sizeof($upgrade_config) >0){
2733 $currVarsArray=$upgrade_config[1]['upgrade_vars'];
2734 //print_r($currVarsArray);
2735 if(isset($currVarsArray) && $currVarsArray != null && is_array($currVarsArray) && sizeof($currVarsArray)>0){
2736 foreach($currVarsArray as $key=>$val){
2737 if($key != null && $val !=null){
2738 //set session variables
2739 $_SESSION[$key]=$val;
2748 //track the upgrade progress on each step
2749 //track the upgrade progress on each step
2750 function set_upgrade_progress($currStep,$currState,$currStepSub='',$currStepSubState=''){
2752 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2753 if(!is_dir($upgrade_progress_dir)){
2754 mkdir_recursive($upgrade_progress_dir);
2756 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2757 if(file_exists($upgrade_progress_file)){
2758 include($upgrade_progress_file);
2761 if(function_exists('sugar_fopen')){
2762 sugar_fopen($upgrade_progress_file, 'w+');
2765 fopen($upgrade_progress_file, 'w+');
2768 if(!isset($upgrade_config) || $upgrade_config == null){
2769 $upgrade_config = array();
2770 $upgrade_config[1]['upgrade_vars']=array();
2772 if(!is_array($upgrade_config[1]['upgrade_vars'])){
2773 $upgrade_config[1]['upgrade_vars'] = array();
2775 if($currStep != null && $currState != null){
2776 if(sizeof($upgrade_config) > 0){
2777 if($currStepSub != null && $currStepSubState !=null){
2778 //check if new status to be set or update
2779 //get the latest in array. since it has sub components prepare an array
2780 if(!empty($upgrade_config[sizeof($upgrade_config)][$currStep]) && is_array($upgrade_config[sizeof($upgrade_config)][$currStep])){
2781 $latestStepSub = currSubStep($upgrade_config[sizeof($upgrade_config)][$currStep]);
2782 if($latestStepSub == $currStepSub){
2783 $upgrade_config[sizeof($upgrade_config)][$currStep][$latestStepSub]=$currStepSubState;
2784 $upgrade_config[sizeof($upgrade_config)][$currStep][$currStep] = $currState;
2787 $upgrade_config[sizeof($upgrade_config)][$currStep][$currStepSub]=$currStepSubState;
2788 $upgrade_config[sizeof($upgrade_config)][$currStep][$currStep] = $currState;
2792 $currArray = array();
2793 $currArray[$currStep] = $currState;
2794 $currArray[$currStepSub] = $currStepSubState;
2795 $upgrade_config[sizeof($upgrade_config)+1][$currStep] = $currArray;
2799 //get the current upgrade progress
2800 $latestStep = get_upgrade_progress();
2801 //set the upgrade progress
2802 if($latestStep == $currStep){
2803 //update the current step with new progress status
2804 $upgrade_config[sizeof($upgrade_config)][$latestStep]=$currState;
2808 $upgrade_config[sizeof($upgrade_config)+1][$currStep]=$currState;
2810 // now check if there elements within array substeps
2814 //set the upgrade progress (just starting)
2815 $upgrade_config[sizeof($upgrade_config)+1][$currStep]= $currState;
2818 if(is_writable($upgrade_progress_file) && write_array_to_file( "upgrade_config", $upgrade_config,
2819 $upgrade_progress_file)) {
2820 //writing to the file
2826 function get_upgrade_progress(){
2827 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2828 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2831 if(file_exists($upgrade_progress_file)){
2832 include($upgrade_progress_file);
2833 if(!isset($upgrade_config) || $upgrade_config == null){
2834 $upgrade_config = array();
2836 if($upgrade_config != null && sizeof($upgrade_config) >1){
2837 $currArr = $upgrade_config[sizeof($upgrade_config)];
2838 if(is_array($currArr)){
2839 foreach($currArr as $key=>$val){
2847 function currSubStep($currStep){
2849 if(is_array($currStep)){
2850 foreach($currStep as $key=>$val){
2858 function currUpgradeState($currState){
2860 if(is_array($currState)){
2861 foreach($currState as $key=>$val){
2863 foreach($val as $k=>$v){
2877 function didThisStepRunBefore($step,$SubStep=''){
2878 if($step == null) return;
2879 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2880 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2883 if(file_exists($upgrade_progress_file)){
2884 include($upgrade_progress_file);
2885 if(isset($upgrade_config) && $upgrade_config != null && is_array($upgrade_config) && sizeof($upgrade_config) >0){
2886 for($i=1;$i<=sizeof($upgrade_config);$i++){
2887 if(is_array($upgrade_config[$i])){
2888 foreach($upgrade_config[$i] as $key=>$val){
2890 if(is_array($upgrade_config[$i][$step])){
2892 foreach ($upgrade_config[$i][$step] as $k=>$v){
2894 foreach($v as $k1=>$v1){
2895 if($SubStep != null){
2896 if($SubStep ==$k1 && $v1=='done'){
2903 elseif($SubStep !=null){
2904 if($SubStep==$k && $v=='done'){
2909 elseif($step==$k && $v=='done'){
2915 elseif($val=='done'){
2929 //get and set post install status
2930 function post_install_progress($progArray='',$action=''){
2931 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2932 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2933 if($action=='' || $action=='get'){
2934 //get the state of post install
2935 $currProg = array();
2936 if(file_exists($upgrade_progress_file)){
2937 include($upgrade_progress_file);
2938 if(is_array($upgrade_config[sizeof($upgrade_config)]['commit']['post_install']) && sizeof($upgrade_config[sizeof($upgrade_config)]['commit']['post_install'])>0){
2939 foreach($upgrade_config[sizeof($upgrade_config)]['commit']['post_install'] as $k=>$v){
2946 elseif($action=='set'){
2947 if(!is_dir($upgrade_progress_dir)){
2948 mkdir($upgrade_progress_dir);
2950 if(file_exists($upgrade_progress_file)){
2951 include($upgrade_progress_file);
2954 fopen($upgrade_progress_file, 'w+');
2956 if(!is_array($upgrade_config[sizeof($upgrade_config)]['commit']['post_install'])){
2957 $upgrade_config[sizeof($upgrade_config)]['commit']['post_install']=array();
2958 $upgrade_config[sizeof($upgrade_config)]['commit']['post_install']['post_install'] = 'in_progress';
2960 if($progArray != null && is_array($progArray)){
2961 foreach($progArray as $key=>$val){
2962 $upgrade_config[sizeof($upgrade_config)]['commit']['post_install'][$key]=$val;
2965 if(is_writable($upgrade_progress_file) && write_array_to_file( "upgrade_config", $upgrade_config,
2966 $upgrade_progress_file)) {
2967 //writing to the file
2972 function repairDBForUpgrade($execute=false,$path=''){
2974 global $current_user, $beanFiles;
2976 set_time_limit(3600);
2978 $db = &DBManagerFactory::getInstance();
2980 VardefManager::clearVardef();
2981 require_once('include/ListView/ListView.php');
2982 foreach ($beanFiles as $bean => $file) {
2983 require_once ($file);
2984 $focus = new $bean ();
2985 $sql .= $db->repairTable($focus, $execute);
2989 $olddictionary = $dictionary;
2990 unset ($dictionary);
2991 include ('modules/TableDictionary.php');
2992 foreach ($dictionary as $meta) {
2993 $tablename = $meta['table'];
2994 $fielddefs = $meta['fields'];
2995 $indices = $meta['indices'];
2996 $sql .= $db->repairTableParams($tablename, $fielddefs, $indices, $execute);
2999 foreach (explode("\n", $sql) as $line) {
3000 if (!empty ($line) && substr($line, -2) != "*/") {
3003 $qry_str .= $line . "\n";
3014 preg_replace('#(/\*.+?\*/\n*)#', '', $qry_str)
3016 logThis("*******START EXECUTING DB UPGRADE QUERIES***************",$path);
3017 logThis($sql,$path);
3018 logThis("*******END EXECUTING DB UPGRADE QUERIES****************",$path);
3027 * upgradeUserPreferences
3028 * This method updates the user_preferences table and sets the pages/dashlets for users
3029 * which have ACL access to Trackers so that the Tracker dashlets are set in their user perferences
3032 function upgradeUserPreferences() {
3033 global $sugar_config, $sugar_version;
3034 $uw_strings = return_module_language($GLOBALS['current_language'], 'UpgradeWizard');
3036 $localization = new Localization();
3037 $localeCoreDefaults = $localization->getLocaleConfigDefaults();
3039 // check the current system wide default_locale_name_format and add it to the list if it's not there
3040 if(empty($sugar_config['name_formats'])) {
3041 $sugar_config['name_formats'] = $localeCoreDefaults['name_formats'];
3042 if(!rebuildConfigFile($sugar_config, $sugar_version)) {
3043 $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
3047 $currentDefaultLocaleNameFormat = $sugar_config['default_locale_name_format'];
3049 if ($localization->isAllowedNameFormat($currentDefaultLocaleNameFormat)) {
3050 upgradeLocaleNameFormat($currentDefaultLocaleNameFormat);
3052 $sugar_config['default_locale_name_format'] = $localeCoreDefaults['default_locale_name_format'];
3053 if(!rebuildConfigFile($sugar_config, $sugar_version)) {
3054 $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
3056 $localization->createInvalidLocaleNameFormatUpgradeNotice();
3059 $db = &DBManagerFactory::getInstance();
3060 $result = $db->query("SELECT id FROM users where deleted = '0'");
3061 while($row = $db->fetchByAssoc($result))
3063 $current_user = new User();
3064 $current_user->retrieve($row['id']);
3066 // 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
3067 $currentUserNameFormat = $current_user->getPreference('default_locale_name_format');
3068 if ($localization->isAllowedNameFormat($currentUserNameFormat)) {
3069 upgradeLocaleNameFormat($currentUserNameFormat);
3071 $current_user->setPreference('default_locale_name_format', 's f l', 0, 'global');
3072 $current_user->savePreferencesToDB();
3076 if(!$current_user->getPreference('calendar_publish_key')) {
3077 // set publish key if not set already
3078 $current_user->setPreference('calendar_publish_key', create_guid());
3083 // we need to force save the changes to disk, otherwise we lose them.
3086 $current_user->savePreferencesToDB();
3094 * Checks if a locale name format is part of the default list, if not adds it to the config
3095 * @param $name_format string a local name format string such as 's f l'
3096 * @return bool true on successful write to config file, false on failure;
3098 function upgradeLocaleNameFormat($name_format) {
3099 global $sugar_config, $sugar_version;
3101 $localization = new Localization();
3102 $localeConfigDefaults = $localization->getLocaleConfigDefaults();
3104 $uw_strings = return_module_language($GLOBALS['current_language'], 'UpgradeWizard');
3105 if(empty($sugar_config['name_formats'])) {
3106 $sugar_config['name_formats'] = $localeConfigDefaults['name_formats'];
3107 if(!rebuildConfigFile($sugar_config, $sugar_version)) {
3108 $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
3111 if (!in_array($name_format, $sugar_config['name_formats'])) {
3112 $new_config = sugarArrayMerge($sugar_config['name_formats'], array($name_format=>$name_format));
3113 $sugar_config['name_formats'] = $new_config;
3114 if(!rebuildConfigFile($sugar_config, $sugar_version)) {
3115 $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
3124 function add_custom_modules_favorites_search(){
3125 $module_directories = scandir('modules');
3127 foreach($module_directories as $module_dir){
3128 if($module_dir == '.' || $module_dir == '..' || !is_dir("modules/{$module_dir}")){
3133 preg_match('/^[a-z0-9]{1,5}_[a-z0-9_]+$/i' , $module_dir, $matches);
3135 // Make sure the module was created by module builder
3136 if(empty($matches)){
3140 $full_module_dir = "modules/{$module_dir}/";
3141 $read_searchdefs_from = "{$full_module_dir}/metadata/searchdefs.php";
3142 $read_SearchFields_from = "{$full_module_dir}/metadata/SearchFields.php";
3143 $read_custom_SearchFields_from = "custom/{$full_module_dir}/metadata/SearchFields.php";
3145 // Studio can possibly override this file, so we check for a custom version of it
3146 if(file_exists("custom/{$full_module_dir}/metadata/searchdefs.php")){
3147 $read_searchdefs_from = "custom/{$full_module_dir}/metadata/searchdefs.php";
3150 if(file_exists($read_searchdefs_from) && file_exists($read_SearchFields_from)){
3153 require($read_searchdefs_from);
3154 foreach($searchdefs[$module_dir]['layout']['basic_search'] as $sf_array){
3155 if(isset($sf_array['name']) && $sf_array['name'] == 'favorites_only'){
3160 require($read_SearchFields_from);
3161 if(isset($searchFields[$module_dir]['favorites_only'])){
3165 if(!$found_sf1 && !$found_sf2){
3166 $searchdefs[$module_dir]['layout']['basic_search']['favorites_only'] = array('name' => 'favorites_only','label' => 'LBL_FAVORITES_FILTER','type' => 'bool',);
3167 $searchdefs[$module_dir]['layout']['advanced_search']['favorites_only'] = array('name' => 'favorites_only','label' => 'LBL_FAVORITES_FILTER','type' => 'bool',);
3168 $searchFields[$module_dir]['favorites_only'] = array(
3169 'query_type'=>'format',
3170 'operator' => 'subquery',
3171 'subquery' => 'SELECT sugarfavorites.record_id FROM sugarfavorites
3172 WHERE sugarfavorites.deleted=0
3173 and sugarfavorites.module = \''.$module_dir.'\'
3174 and sugarfavorites.assigned_user_id = \'{0}\'',
3175 'db_field'=>array('id')
3178 if(!is_dir("custom/{$full_module_dir}/metadata")){
3179 mkdir_recursive("custom/{$full_module_dir}/metadata");
3181 $success_sf1 = write_array_to_file('searchdefs', $searchdefs, "custom/{$full_module_dir}/metadata/searchdefs.php");
3182 $success_sf2 = write_array_to_file('searchFields', $searchFields, "{$full_module_dir}/metadata/SearchFields.php");
3185 logThis("add_custom_modules_favorites_search failed for searchdefs.php for {$module_dir}");
3188 logThis("add_custom_modules_favorites_search failed for SearchFields.php for {$module_dir}");
3190 if($success_sf1 && $success_sf2){
3191 logThis("add_custom_modules_favorites_search successfully updated searchdefs and searchFields for {$module_dir}");
3200 * upgradeModulesForTeamsets
3202 * This method adds the team_set_id values to the module tables that have the new team_set_id column
3203 * added through the SugarCRM 5.5.x upgrade process. It also adds the values into the team_sets and
3204 * team_sets_teams tables.
3206 * @param filter Array of modules to process; empty by default
3208 function upgradeModulesForTeamsets($filter=array()) {
3209 require('include/modules.php');
3210 foreach($beanList as $moduleName=>$beanName) {
3211 if(!empty($filter) && array_search($moduleName, $filter) === false) {
3214 if($moduleName == 'TeamMemberships' || $moduleName == 'ForecastOpportunities'){
3217 $bean = loadBean($moduleName);
3219 empty($bean->table_name)) {
3223 $FieldArray = $GLOBALS['db']->helper->get_columns($bean->table_name);
3224 if(!isset($FieldArray['team_id'])) {
3228 upgradeTeamColumn($bean, 'team_id');
3232 //Upgrade users table
3233 $bean = loadBean('Users');
3234 upgradeTeamColumn($bean, 'default_team');
3235 $result = $GLOBALS['db']->query("SELECT id FROM teams where deleted=0");
3236 while($row = $GLOBALS['db']->fetchByAssoc($result)) {
3237 $teamset = new TeamSet();
3238 $teamset->addTeams($row['id']);
3245 * Helper function to create a team_set_id column and also set team_set_id column
3246 * to have the value of the $column_name parameter
3248 * @param $bean SugarBean which we are adding team_set_id column to
3249 * @param $column_name The name of the column containing the default team_set_id value
3251 function upgradeTeamColumn($bean, $column_name) {
3252 //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
3253 //module that does not use the SugarObjects
3254 if(empty($bean->field_defs['team_set_id']) && $bean->module_dir != 'Trackers'){
3256 //at this point we could assume that since we have a team_id defined and not a team_set_id that we need to
3257 //add that field and the corresponding relationships
3258 $object = $bean->object_name;
3259 $module = $bean->module_dir;
3260 $object_name = $object;
3261 $_object_name = strtolower($object_name);
3263 if(!empty($GLOBALS['dictionary'][$object]['table'])){
3264 $table_name = $GLOBALS['dictionary'][$object]['table'];
3266 $table_name = strtolower($module);
3269 $path = 'include/SugarObjects/implements/team_security/vardefs.php';
3271 //go through each entry in the vardefs from team_security and unset anything that is already set in the core module
3272 //this will ensure we have the proper ordering.
3273 $fieldDiff = array_diff_assoc($vardefs['fields'], $GLOBALS['dictionary'][$bean->object_name]['fields']);
3275 $file = 'custom/Extension/modules/' . $bean->module_dir. '/Ext/Vardefs/teams.php';
3276 $contents = "<?php\n";
3277 if(!empty($fieldDiff)){
3278 foreach($fieldDiff as $key => $val){
3279 $contents .= "\n\$GLOBALS['dictionary']['". $object . "']['fields']['". $key . "']=" . var_export_helper($val) . ";";
3282 $relationshipDiff = array_diff_assoc($vardefs['relationships'], $GLOBALS['dictionary'][$bean->object_name]['relationships']);
3283 if(!empty($relationshipDiff)){
3284 foreach($relationshipDiff as $key => $val){
3285 $contents .= "\n\$GLOBALS['dictionary']['". $object . "']['relationships']['". $key . "']=" . var_export_helper($val) . ";";
3288 $indexDiff = array_diff_assoc($vardefs['indices'], $GLOBALS['dictionary'][$bean->object_name]['indices']);
3289 if(!empty($indexDiff)){
3290 foreach($indexDiff as $key => $val){
3291 $contents .= "\n\$GLOBALS['dictionary']['". $object . "']['indices']['". $key . "']=" . var_export_helper($val) . ";";
3294 if( $fh = @sugar_fopen( $file, 'wt' ) )
3296 fputs( $fh, $contents);
3301 //we have written out the teams.php into custom/Extension/modules/{$module_dir}/Ext/Vardefs/teams.php'
3302 //now let's merge back into vardefs.ext.php
3303 require_once('ModuleInstall/ModuleInstaller.php');
3304 $mi = new ModuleInstaller();
3305 $mi->merge_files('Ext/Vardefs/', 'vardefs.ext.php');
3306 VardefManager::loadVardef($bean->module_dir, $bean->object_name, true);
3307 $bean->field_defs = $GLOBALS['dictionary'][$bean->object_name]['fields'];
3310 if(isset($bean->field_defs['team_set_id'])) {
3311 //Create the team_set_id column
3312 $FieldArray = $GLOBALS['db']->helper->get_columns($bean->table_name);
3313 if(!isset($FieldArray['team_set_id'])) {
3314 $GLOBALS['db']->addColumn($bean->table_name, $bean->field_defs['team_set_id']);
3316 $indexArray = $GLOBALS['db']->helper->get_indices($bean->table_name);
3318 $indexName = getValidDBName('idx_'.strtolower($bean->table_name).'_tmst_id', true, 34);
3321 'name' => $indexName,
3323 'fields' => array('team_set_id')
3326 if(!isset($indexArray[$indexName])) {
3327 $GLOBALS['db']->addIndexes($bean->table_name, $indexDef);
3330 //Update the table's team_set_id column to have the same values as team_id
3331 $GLOBALS['db']->query("UPDATE {$bean->table_name} SET team_set_id = {$column_name}");
3336 * Update the folder subscription table which confirms to the team security mechanism but
3337 * the class SugarFolders does not extend SugarBean and is therefore never picked up by the
3338 * upgradeModulesForTeamsets function.
3340 function upgradeFolderSubscriptionsTeamSetId()
3342 logThis("In upgradeFolderSubscriptionsTeamSetId()");
3343 $query = "UPDATE folders SET team_set_id = team_id";
3344 $result = $GLOBALS['db']->query($query);
3345 logThis("Finished upgradeFolderSubscriptionsTeamSetId()");
3349 * upgradeModulesForTeam
3351 * This method update the associated_user_id, name, name_2 to the private team records on teams table
3352 * This function is used for upgrade process from 5.1.x and 5.2.x.
3355 function upgradeModulesForTeam() {
3356 logThis("In upgradeModulesForTeam()");
3357 $result = $GLOBALS['db']->query("SELECT id, user_name, first_name, last_name FROM users where deleted=0");
3359 while($row = $GLOBALS['db']->fetchByAssoc($result)) {
3360 $results2 = $GLOBALS['db']->query("SELECT id FROM teams WHERE name = '({$row['user_name']})'");
3362 if(!$assoc = $GLOBALS['db']->fetchByAssoc($results2)) {
3363 //if team does not exist, then lets create the team for this user
3366 $user->retrieve($row['id']);
3367 $team->new_user_created($user);
3368 $team_id = $team->id;
3370 $team_id =$assoc['id'];
3374 $name = is_null($row['first_name'])?'':$row['first_name'];
3375 $name_2 = is_null($row['last_name'])?'':$row['last_name'];
3376 $associated_user_id = $row['id'];
3379 //Ensure team->name is not empty by using team->name_2 if available
3380 if(empty($name) && !empty($name_2)) {
3385 $query = "UPDATE teams SET name = '{$name}', name_2 = '{$name_2}', associated_user_id = '{$associated_user_id}' WHERE id = '{$team_id}'";
3386 $GLOBALS['db']->query($query);
3389 //Update the team_set_id and default_team columns
3390 $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'));
3392 //Update team_set_id
3393 if($ce_to_pro_or_ent) {
3394 $GLOBALS['db']->query("update users set team_set_id = (select teams.id from teams where teams.associated_user_id = users.id)");
3395 $GLOBALS['db']->query("update users set default_team = (select teams.id from teams where teams.associated_user_id = users.id)");
3401 function addNewSystemTabsFromUpgrade($from_dir){
3403 if(isset($_SESSION['upgrade_from_flavor'])){
3405 //check to see if there are any new files that need to be added to systems tab
3406 //retrieve old modules list
3407 logThis('check to see if new modules exist',$path);
3408 $oldModuleList = array();
3409 $newModuleList = array();
3410 include($from_dir.'/include/modules.php');
3411 $oldModuleList = $moduleList;
3412 include('include/modules.php');
3413 $newModuleList = $moduleList;
3415 //include tab controller
3416 require_once('modules/MySettings/TabController.php');
3417 $newTB = new TabController();
3419 //make sure new modules list has a key we can reference directly
3420 $newModuleList = $newTB->get_key_array($newModuleList);
3421 $oldModuleList = $newTB->get_key_array($oldModuleList);
3423 //iterate through list and remove commonalities to get new modules
3424 foreach ($newModuleList as $remove_mod){
3425 if(in_array($remove_mod, $oldModuleList)){
3426 unset($newModuleList[$remove_mod]);
3429 //new modules list now has left over modules which are new to this install, so lets add them to the system tabs
3430 logThis('new modules to add are '.var_export($newModuleList,true),$path);
3432 if(!empty($newModuleList))
3434 //grab the existing system tabs
3435 $tabs = $newTB->get_system_tabs();
3437 //add the new tabs to the array
3438 foreach($newModuleList as $nm ){
3442 $newTB->set_system_tabs($tabs);
3444 logThis('module tabs updated',$path);
3450 * This method attempts to fix dropdown lists that were incorrectly named.
3451 * There were versions of SugarCRM that did not enforce naming convention rules
3452 * for the dropdown list field name. This method attempts to resolve that by
3453 * fixing the language files that may have been affected and then updating the
3454 * fields_meta_data table accordingly. It also refreshes any vardefs that may
3455 * have been affected.
3458 function fix_dropdown_list() {
3459 if(file_exists('custom/include/language')) {
3461 $affected_modules = array();
3462 $affected_keys = array();
3464 getFiles($files, 'custom/include/language', '/\.php$/i');
3465 foreach($files as $file) {
3467 if(file_exists($file . '.bak')) {
3468 $bak_mod_time = filemtime($file . '.bak');
3469 $php_mod_time = filemtime($file);
3470 //We're saying if the .php file was modified 30 seconds no more than php.bak file then we
3471 //run these additional cleanup checks
3472 if($php_mod_time - $bak_mod_time < 30) {
3474 $app_list_strings = array();
3475 $GLOBALS['app_list_strings'] = array();
3476 require($file . '.bak');
3477 $bak_app_list_strings = array_merge($app_list_strings, $GLOBALS['app_list_strings']);
3479 $app_list_strings = array();
3480 $GLOBALS['app_list_strings'] = array();
3482 $php_app_list_strings = array_merge($app_list_strings, $GLOBALS['app_list_strings']);
3484 //Get the file contents
3485 $contents = file_get_contents($file);
3487 //Now simulate a fix for the file before we compare w/ the .php file
3488 //we also append to the $contents
3489 foreach($bak_app_list_strings as $key=>$entry) {
3490 if(preg_match('/([^A-Za-z_])/', $key, $matches) && is_array($entry)) {
3491 $new_key = preg_replace('/[^A-Za-z_]/', '_', $key);
3492 $bak_app_list_strings[$new_key] = $bak_app_list_strings[$key];
3493 unset($bak_app_list_strings[$key]);
3494 //Now if the entry doesn't exists in the .php file, then add to contents
3495 if(!isset($php_app_list_strings[$new_key])) {
3496 $contents .= "\n\$GLOBALS['app_list_strings']['{$new_key}'] = " . var_export_helper($bak_app_list_strings[$new_key]) . ";";
3501 //Now load the .php file to do the comparison
3502 foreach($php_app_list_strings as $key=>$entry) {
3503 if(isset($bak_app_list_strings[$key])) {
3504 $diff = array_diff($bak_app_list_strings[$key], $entry);
3506 //There is a difference, so copy the $bak_app_list_strings version into the .php file
3507 $contents .= "\n\$GLOBALS['app_list_strings']['{$key}'] = " . var_export_helper($bak_app_list_strings[$key]) . ";";
3512 //Now write out the file contents
3513 //Create backup just in case
3514 copy($file, $file . '.php_bak');
3515 $fp = @sugar_fopen($file, 'w');
3517 fwrite($fp, $contents);
3520 $GLOBALS['log']->error("Unable to update file contents in fix_dropdown_list for {$file}");
3525 unset($GLOBALS['app_strings']);
3526 unset($GLOBALS['app_list_strings']);
3527 $app_list_strings = array();
3530 $contents = file_get_contents($file);
3531 if ( !isset($GLOBALS['app_list_strings']) ) {
3532 $GLOBALS['app_list_strings'] = $app_list_strings;
3535 $GLOBALS['app_list_strings'] = array_merge($app_list_strings, $GLOBALS['app_list_strings']);
3538 if(isset($GLOBALS['app_list_strings']) && is_array($GLOBALS['app_list_strings'])) {
3539 foreach($GLOBALS['app_list_strings'] as $key=>$entry) {
3540 if(preg_match('/([^A-Za-z_])/', $key, $matches) && is_array($entry)) {
3541 $result = $GLOBALS['db']->query("SELECT custom_module FROM fields_meta_data WHERE ext1 = '{$key}'");
3542 if(!empty($result)) {
3543 while($row = $GLOBALS['db']->fetchByAssoc($result)) {
3544 $custom_module = $row['custom_module'];
3545 if(!empty($GLOBALS['beanList'][$custom_module])) {
3546 $affected_modules[$custom_module] = $GLOBALS['beanList'][$custom_module];
3551 //Replace all invalid characters with '_' character
3552 $new_key = preg_replace('/[^A-Za-z_]/', '_', $key);
3553 $affected_keys[$key] = $new_key;
3555 $GLOBALS['app_list_strings'][$new_key] = $GLOBALS['app_list_strings'][$key];
3556 unset($GLOBALS['app_list_strings'][$key]);
3558 $pattern_match = "/(\[\s*\'{$key}\'\s*\])/";
3559 $new_key = "['{$new_key}']";
3560 $out = preg_replace($pattern_match, $new_key, $contents);
3566 //This is a check for g => h instances where the file contents were incorrectly written
3567 //and also fixes the scenario where via a UI upgrade, the app_list_strings were incorrectly
3568 //merged with app_list_strings variables declared elsewhere
3570 if(preg_match('/\$GLOBALS\s*\[\s*[\"|\']app_list_strings[\"|\']\s*\]\s*=\s*array\s*\(/', $contents)) {
3571 //Now also remove all the non-custom labels that were added
3572 if(preg_match('/language\/([^\.]+)\.lang\.php$/', $file, $matches)) {
3573 $language = $matches[1];
3575 $app_list_strings = array();
3577 if(file_exists("include/language/$language.lang.php")) {
3578 include("include/language/$language.lang.php");
3580 if(file_exists("include/language/$language.lang.override.php")) {
3581 $app_list_strings = _mergeCustomAppListStrings("include/language/$language.lang.override.php" , $app_list_strings) ;
3583 if(file_exists("custom/application/Ext/Language/$language.ext.lang.php")) {
3584 $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$language.ext.lang.php" , $app_list_strings) ;
3586 if(file_exists("custom/application/Ext/Language/$language.lang.ext.php")) {
3587 $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$language.lang.ext.php" , $app_list_strings) ;
3590 $all_non_custom_include_language_strings = $app_strings;
3591 $all_non_custom_include_language_list_strings = $app_list_strings;
3593 $unset_keys = array();
3594 if(!empty($GLOBALS['app_list_strings'])) {
3595 foreach($GLOBALS['app_list_strings'] as $key=>$value) {
3597 if(isset($all_non_custom_include_language_list_strings[$key])) {
3598 $diff = array_diff($all_non_custom_include_language_list_strings[$key], $GLOBALS['app_list_strings'][$key]);
3601 if(!empty($all_non_custom_include_language_list_strings[$key]) && empty($diff)) {
3602 $unset_keys[] = $key;
3607 foreach($unset_keys as $key) {
3608 unset($GLOBALS['app_list_strings'][$key]);
3611 if(!empty($GLOBALS['app_strings'])) {
3612 foreach($GLOBALS['app_strings'] as $key=>$value) {
3613 if(!empty($all_non_custom_include_language_strings[$key])) {
3614 unset($GLOBALS['app_strings'][$key]);
3618 } //if(preg_match...)
3621 if(!empty($GLOBALS['app_strings'])) {
3622 foreach($GLOBALS['app_strings'] as $key=>$entry) {
3623 $out .= "\n\$GLOBALS['app_strings']['$key']=" . var_export_helper($entry) . ";";
3627 foreach($GLOBALS['app_list_strings'] as $key=>$entry) {
3628 $out .= "\n\$GLOBALS['app_list_strings']['$key']=" . var_export_helper($entry) . ";";
3632 } //if(preg_match...)
3636 //Create a backup just in case
3637 copy($file, $file . '.bak');
3638 $fp = @sugar_fopen($file, 'w');
3643 //If we can't update the file, just return
3644 $GLOBALS['log']->error("Unable to update file contents in fix_dropdown_list.");
3652 //Update db entries (the order matters here... need to process database changes first)
3653 if(!empty($affected_keys)) {
3654 foreach($affected_keys as $old_key=>$new_key) {
3655 $GLOBALS['db']->query("UPDATE fields_meta_data SET ext1 = '{$new_key}' WHERE ext1 = '{$old_key}'");
3659 //Update vardef files for affected modules
3660 if(!empty($affected_modules)) {
3661 foreach($affected_modules as $module=>$object) {
3662 VardefManager::refreshVardefs($module, $object);
3669 function update_iframe_dashlets(){
3670 require_once(sugar_cached('dashlets/dashlets.php'));
3672 $db = DBManagerFactory::getInstance();
3673 $query = "SELECT id, contents, assigned_user_id FROM user_preferences WHERE deleted = 0 AND category = 'Home'";
3674 $result = $db->query($query, true, "Unable to update new default dashlets! ");
3675 while ($row = $db->fetchByAssoc($result)) {
3676 $content = unserialize(base64_decode($row['contents']));
3677 $assigned_user_id = $row['assigned_user_id'];
3678 $record_id = $row['id'];
3680 $current_user = new User();
3681 $current_user->retrieve($row['assigned_user_id']);
3683 if(!empty($content['dashlets']) && !empty($content['pages'])){
3684 $originalDashlets = $content['dashlets'];
3685 foreach($originalDashlets as $key => $ds){
3686 if(!empty($ds['options']['url']) && stristr($ds['options']['url'],'https://www.sugarcrm.com/crm/product/gopro')){
3687 unset($originalDashlets[$key]);
3690 $current_user->setPreference('dashlets', $originalDashlets, 0, 'Home');
3697 * convertImageToText
3699 * This method attempts to convert date type image to text on Microsoft SQL Server.
3700 * This method could NOT be used in any other type of datebases.
3702 function convertImageToText($table_name,$column_name){
3703 $set_lang = "SET LANGUAGE us_english";
3704 $GLOBALS['db']->query($set_lang);
3705 if($GLOBALS['db']->lastError()){
3706 logThis('An error occurred when performing this query-->'.$set_lang);
3708 $q="SELECT data_type
3709 FROM INFORMATION_SCHEMA.Tables T JOIN INFORMATION_SCHEMA.Columns C
3710 ON T.TABLE_NAME = C.TABLE_NAME where T.TABLE_NAME = '$table_name' and C.COLUMN_NAME = '$column_name'";
3711 $res= $GLOBALS['db']->query($q);
3712 if($GLOBALS['db']->lastError()){
3713 logThis('An error occurred when performing this query-->'.$q);
3715 $row= $GLOBALS['db']->fetchByAssoc($res);
3717 if(trim(strtolower($row['data_type'])) == 'image'){
3718 $addContent_temp = "alter table {$table_name} add {$column_name}_temp text null";
3719 $GLOBALS['db']->query($addContent_temp);
3720 if($GLOBALS['db']->lastError()){
3721 logThis('An error occurred when performing this query-->'.$addContent_temp);
3723 $qN = "select count=datalength({$column_name}), id, {$column_name} from {$table_name}";
3724 $result = $GLOBALS['db']->query($qN);
3725 while($row = $GLOBALS['db']->fetchByAssoc($result)){
3726 if($row['count'] >8000){
3727 $contentLength = $row['count'];
3730 $convertedContent = '';
3731 while($contentLength >0){
3732 $stepsQuery = "select cont=convert(varchar(max), convert(varbinary(8000), substring({$column_name},{$start},{$next}))) from {$table_name} where id= '{$row['id']}'";
3733 $steContQ = $GLOBALS['db']->query($stepsQuery);
3734 if($GLOBALS['db']->lastError()){
3735 logThis('An error occurred when performing this query-->'.$stepsQuery);
3737 $stepCont = $GLOBALS['db']->fetchByAssoc($steContQ);
3738 if(isset($stepCont['cont'])){
3739 $convertedContent = $convertedContent.$stepCont['cont'];
3741 $start = $start+$next;
3742 $contentLength = $contentLength - $next;
3744 $addContentDataText="update {$table_name} set {$column_name}_temp = '{$convertedContent}' where id= '{$row['id']}'";
3745 $GLOBALS['db']->query($addContentDataText);
3746 if($GLOBALS['db']->lastError()){
3747 logThis('An error occurred when performing this query-->'.$addContentDataText);
3751 $addContentDataText="update {$table_name} set {$column_name}_temp =
3752 convert(varchar(max), convert(varbinary(8000), {$column_name})) where id= '{$row['id']}'";
3753 $GLOBALS['db']->query($addContentDataText);
3754 if($GLOBALS['db']->lastError()){
3755 logThis('An error occurred when performing this query-->'.$addContentDataText);
3759 //drop the contents now and change contents_temp to contents
3760 $dropColumn = "alter table {$table_name} drop column {$column_name}";
3761 $GLOBALS['db']->query($dropColumn);
3762 if($GLOBALS['db']->lastError()){
3763 logThis('An error occurred when performing this query-->'.$dropColumn);
3765 $changeColumnName = "EXEC sp_rename '{$table_name}.[{$column_name}_temp]','{$column_name}','COLUMN'";
3766 $GLOBALS['db']->query($changeColumnName);
3767 if($GLOBALS['db']->lastError()){
3768 logThis('An error occurred when performing this query-->'.$changeColumnName);
3775 * This method attempts to delete all English inline help files.
3776 * This method was introduced by 5.5.0RC2.
3778 function clearHelpFiles(){
3779 $modulePath = clean_path(getcwd() . '/modules');
3780 $allHelpFiles = array();
3781 getFiles($allHelpFiles, $modulePath, "/en_us.help.*/");
3783 foreach( $allHelpFiles as $the_file ){
3784 if( is_file( $the_file ) ){
3785 unlink( $the_file );
3786 logThis("Deleted file: $the_file");
3794 * upgradeDateTimeFields
3796 * This method came from bug: 39757 where the date_end field is a date field and not a datetime field
3797 * which prevents you from performing timezone offset calculations once the data has been saved.
3799 * @param path String location to log file, empty by default
3801 function upgradeDateTimeFields($path)
3805 $meetingsSql = "UPDATE meetings SET date_end = ".$db->convert("date_start", 'add_time', array('duration_hours', 'duration_minutes'));
3806 $callsSql = "UPDATE calls SET date_end = ".$db->convert("date_start", 'add_time', array('duration_hours', 'duration_minutes'));
3807 logThis('upgradeDateTimeFields Meetings SQL:' . $meetingsSql, $path);
3808 $db->query($meetingsSql);
3810 logThis('upgradeDateTimeFields Calls SQL:' . $callsSql, $path);
3811 $db->query($callsSql);
3815 * upgradeDocumentTypeFields
3818 function upgradeDocumentTypeFields($path){
3822 $documentsSql = "UPDATE documents SET doc_type = 'Sugar' WHERE doc_type IS NULL";
3823 $meetingsSql = "UPDATE meetings SET type = 'Sugar' WHERE type IS NULL";
3825 logThis('upgradeDocumentTypeFields Documents SQL:' . $documentsSql, $path);
3826 $db->query($documentsSql);
3827 logThis('upgradeDocumentTypeFields Meetings SQL:' . $meetingsSql, $path);
3828 $db->query($meetingsSql);
3833 * merge_config_si_settings
3834 * This method checks for the presence of a config_si.php file and, if found, merges the configuration
3835 * settings from the config_si.php file into config.php. If a config_si_location parameter value is not
3836 * supplied it will attempt to discover the config_si.php file location from where the executing script
3839 * @param write_to_upgrade_log boolean optional value to write to the upgradeWizard.log file
3840 * @param config_location String optional value to config.php file location
3841 * @param config_si_location String optional value to config_si.php file location
3842 * @param path String file of the location of log file to write to
3843 * @return boolean value indicating whether or not a merge was attempted with config_si.php file
3845 function merge_config_si_settings($write_to_upgrade_log=false, $config_location='', $config_si_location='', $path='')
3847 if(!empty($config_location) && !file_exists($config_location))
3849 if($write_to_upgrade_log)
3851 logThis('config.php file specified in ' . $config_si_location . ' could not be found. Skip merging', $path);
3854 } else if(empty($config_location)) {
3856 //We are assuming this is from the silentUpgrade scripts so argv[3] will point to SugarCRM install location
3857 if(isset($argv[3]) && is_dir($argv[3]))
3859 $config_location = $argv[3] . DIRECTORY_SEPARATOR . 'config.php';
3863 //If config_location is still empty or if the file cannot be found, skip merging
3864 if(empty($config_location) || !file_exists($config_location))
3866 if($write_to_upgrade_log)
3868 logThis('config.php file at (' . $config_location . ') could not be found. Skip merging.', $path);
3872 if($write_to_upgrade_log)
3874 logThis('Loading config.php file at (' . $config_location . ') for merging.', $path);
3877 include($config_location);
3878 if(empty($sugar_config))
3880 if($write_to_upgrade_log)
3882 logThis('config.php contents are empty. Skip merging.', $path);
3888 if(!empty($config_si_location) && !file_exists($config_si_location))
3890 if($write_to_upgrade_log)
3892 logThis('config_si.php file specified in ' . $config_si_location . ' could not be found. Skip merging', $path);
3895 } else if(empty($config_si_location)) {
3896 if(isset($argv[0]) && is_file($argv[0]))
3898 $php_file = $argv[0];
3899 $p_info = pathinfo($php_file);
3900 $php_dir = (isset($p_info['dirname']) && $p_info['dirname'] != '.') ? $p_info['dirname'] . DIRECTORY_SEPARATOR : '';
3901 $config_si_location = $php_dir . 'config_si.php';
3905 //If config_si_location is still empty or if the file cannot be found, skip merging
3906 if(empty($config_si_location) || !file_exists($config_si_location))
3908 if($write_to_upgrade_log)
3910 logThis('config_si.php file at (' . $config_si_location . ') could not be found. Skip merging.', $path);
3914 if($write_to_upgrade_log)
3916 logThis('Loading config_si.php file at (' . $config_si_location . ') for merging.', $path);
3919 include($config_si_location);
3920 if(empty($sugar_config_si))
3922 if($write_to_upgrade_log)
3924 logThis('config_si.php contents are empty. Skip merging.', $path);
3930 //Now perform the merge operation
3932 foreach($sugar_config_si as $key=>$value)
3934 if(!preg_match('/^setup_/', $key) && !isset($sugar_config[$key]))
3936 if($write_to_upgrade_log)
3938 logThis('Merge key (' . $key . ') with value (' . $value . ')', $path);
3940 $sugar_config[$key] = $value;
3947 if($write_to_upgrade_log)
3949 logThis('Update config.php file with new values', $path);
3952 if(!write_array_to_file("sugar_config", $sugar_config, $config_location)) {
3953 if($write_to_upgrade_log)
3955 logThis('*** ERROR: could not write to config.php', $path);
3960 if($write_to_upgrade_log)
3962 logThis('config.php values are in sync with config_si.php values. Skipped merging.', $path);
3967 if($write_to_upgrade_log)
3969 logThis('End merge_config_si_settings', $path);
3976 * upgrade_connectors
3978 * This function handles support for upgrading connectors it is invoked from both end.php and silentUpgrade_step2.php
3981 function upgrade_connectors() {
3982 require_once('include/connectors/utils/ConnectorUtils.php');
3983 remove_linkedin_config();
3985 if(!ConnectorUtils::updateMetaDataFiles()) {
3986 $GLOBALS['log']->fatal('Cannot update metadata files for connectors');
3989 //Delete the custom connectors.php file if it exists so that it may be properly rebuilt
3990 if(file_exists('custom/modules/Connectors/metadata/connectors.php'))
3992 unlink('custom/modules/Connectors/metadata/connectors.php');
3995 remove_linkedin_connector();
3999 * remove_linkedin_config
4001 * This function removes linkedin config from custom/modules/Connectors/metadata/display_config.php, linkedin connector is removed in 6.5.16
4004 function remove_linkedin_config()
4006 $display_file = 'custom/modules/Connectors/metadata/display_config.php';
4008 if (file_exists($display_file)) {
4009 require($display_file);
4011 if (!empty($modules_sources)) {
4012 foreach ($modules_sources as $module => $config) {
4013 if (isset($config['ext_rest_linkedin'])) {
4014 unset($modules_sources[$module]['ext_rest_linkedin']);
4017 if(!write_array_to_file('modules_sources', $modules_sources, $display_file)) {
4019 $GLOBALS['log']->fatal("Cannot write \$modules_sources to " . $display_file);
4024 $search_file = 'custom/modules/Connectors/metadata/searchdefs.php';
4026 if (file_exists($search_file)) {
4027 require($search_file);
4029 if (isset($searchdefs['ext_rest_linkedin'])) {
4030 unset($searchdefs['ext_rest_linkedin']);
4032 if(!write_array_to_file('searchdefs', $searchdefs, $search_file)) {
4034 $GLOBALS['log']->fatal("Cannot write \$searchdefs to " . $search_file);
4041 * remove_linkedin_connector
4043 * This function removes linkedin connector from upgrade, linkedin connector is removed in 6.5.16
4046 function remove_linkedin_connector() {
4048 if (file_exists('modules/Connectors/connectors/formatters/ext/rest/linkedin')) {
4049 deleteDirectory('modules/Connectors/connectors/formatters/ext/rest/linkedin');
4052 if (file_exists('modules/Connectors/connectors/sources/ext/rest/linkedin')) {
4053 deleteDirectory('modules/Connectors/connectors/sources/ext/rest/linkedin');
4056 if (file_exists('custom/modules/Connectors/connectors/sources/ext/rest/linkedin')) {
4057 deleteDirectory('custom/modules/Connectors/connectors/sources/ext/rest/linkedin');
4060 if (file_exists('include/externalAPI/LinkedIn')) {
4061 deleteDirectory('include/externalAPI/LinkedIn');
4067 * Enable the InsideView connector for the four default modules.
4069 function upgradeEnableInsideViewConnector($path='')
4071 logThis('Begin upgradeEnableInsideViewConnector', $path);
4073 // Load up the existing mapping and hand it to the InsideView connector to have it setup the correct logic hooks
4074 $mapFile = 'modules/Connectors/connectors/sources/ext/rest/insideview/mapping.php';
4075 if ( file_exists('custom/'.$mapFile) ) {
4076 logThis('Found CUSTOM mappings', $path);
4077 require('custom/'.$mapFile);
4079 logThis('Used default mapping', $path);
4083 require_once('include/connectors/sources/SourceFactory.php');
4084 $source = SourceFactory::getSource('ext_rest_insideview');
4086 // $mapping is brought in from the mapping.php file above
4087 $source->saveMappingHook($mapping);
4089 require_once('include/connectors/utils/ConnectorUtils.php');
4090 ConnectorUtils::installSource('ext_rest_insideview');
4092 // Now time to set the various modules to active, because this part ignores the default config
4093 require(CONNECTOR_DISPLAY_CONFIG_FILE);
4094 // $modules_sources come from that config file
4095 foreach ( $source->allowedModuleList as $module ) {
4096 $modules_sources[$module]['ext_rest_insideview'] = 'ext_rest_insideview';
4098 if(!write_array_to_file('modules_sources', $modules_sources, CONNECTOR_DISPLAY_CONFIG_FILE)) {
4099 //Log error and return empty array
4100 logThis("Cannot write \$modules_sources to " . CONNECTOR_DISPLAY_CONFIG_FILE,$path);
4103 logThis('End upgradeEnableInsideViewConnector', $path);
4107 function repair_long_relationship_names($path='')
4109 logThis("Begin repair_long_relationship_names", $path);
4110 require_once 'modules/ModuleBuilder/parsers/relationships/DeployedRelationships.php' ;
4111 $GLOBALS['mi_remove_tables'] = false;
4113 foreach($GLOBALS['moduleList'] as $module)
4115 $relationships = new DeployedRelationships ($module) ;
4116 foreach($relationships->getRelationshipList() as $rel_name)
4118 if (strlen($rel_name) > 27 && empty($touched[$rel_name]))
4120 logThis("Rebuilding relationship fields for $rel_name", $path);
4121 $touched[$rel_name] = true;
4122 $rel_obj = $relationships->get($rel_name);
4123 $rel_obj->setReadonly(false);
4124 $relationships->delete($rel_name);
4125 $relationships->save();
4126 $relationships->add($rel_obj);
4127 $relationships->save();
4128 $relationships->build () ;
4132 logThis("End repair_long_relationship_names", $path);
4135 function removeSilentUpgradeVarsCache(){
4136 global $silent_upgrade_vars_loaded;
4138 $cacheFileDir = "{$GLOBALS['sugar_config']['cache_dir']}/silentUpgrader";
4139 $cacheFile = "{$cacheFileDir}/silentUpgradeCache.php";
4141 if(file_exists($cacheFile)){
4145 $silent_upgrade_vars_loaded = array(); // Set to empty to reset it
4150 function loadSilentUpgradeVars(){
4151 global $silent_upgrade_vars_loaded;
4153 if(empty($silent_upgrade_vars_loaded)){
4154 $cacheFile = "{$GLOBALS['sugar_config']['cache_dir']}/silentUpgrader/silentUpgradeCache.php";
4155 // We have no pre existing vars
4156 if(!file_exists($cacheFile)){
4157 // Set the vars array so it's loaded
4158 $silent_upgrade_vars_loaded = array('vars' => array());
4161 require_once($cacheFile);
4162 $silent_upgrade_vars_loaded = $silent_upgrade_vars_cache;
4169 function writeSilentUpgradeVars(){
4170 global $silent_upgrade_vars_loaded;
4172 if(empty($silent_upgrade_vars_loaded)){
4173 return false; // You should have set some values before trying to write the silent upgrade vars
4176 $cacheFileDir = "{$GLOBALS['sugar_config']['cache_dir']}/silentUpgrader";
4177 $cacheFile = "{$cacheFileDir}/silentUpgradeCache.php";
4179 require_once('include/dir_inc.php');
4180 if(!mkdir_recursive($cacheFileDir)){
4183 require_once('include/utils/file_utils.php');
4184 if(!write_array_to_file('silent_upgrade_vars_cache', $silent_upgrade_vars_loaded, $cacheFile, 'w')){
4186 logThis("WARNING: writeSilentUpgradeVars could not write to {$cacheFile}", $path);
4193 function setSilentUpgradeVar($var, $value){
4194 if(!loadSilentUpgradeVars()){
4198 global $silent_upgrade_vars_loaded;
4200 $silent_upgrade_vars_loaded['vars'][$var] = $value;
4205 function getSilentUpgradeVar($var){
4206 if(!loadSilentUpgradeVars()){
4210 global $silent_upgrade_vars_loaded;
4212 if(!isset($silent_upgrade_vars_loaded['vars'][$var])){
4216 return $silent_upgrade_vars_loaded['vars'][$var];
4222 * add_unified_search_to_custom_modules_vardefs
4224 * This method calls the repair code to remove the unified_search_modules.php fiel
4227 function add_unified_search_to_custom_modules_vardefs()
4229 if(file_exists($cachefile = sugar_cached('modules/unified_search_modules.php')))
4237 * change from using the older SugarCache in 6.1 and below to the new one in 6.2
4239 function upgradeSugarCache($file)
4241 global $sugar_config;
4242 $cacheUploadUpgradesTemp = mk_temp_dir(sugar_cached('upgrades/temp'));
4244 unzip($file, $cacheUploadUpgradesTemp);
4246 if(!file_exists(clean_path("{$cacheUploadUpgradesTemp}/manifest.php"))) {
4247 logThis("*** ERROR: no manifest file detected while bootstraping upgrade wizard files!");
4250 include(clean_path("{$cacheUploadUpgradesTemp}/manifest.php"));
4253 $from_dir = "{$cacheUploadUpgradesTemp}/{$manifest['copy_files']['from_dir']}";
4254 $allFiles = array();
4255 if(file_exists("$from_dir/include/SugarCache")) {
4256 $allFiles = findAllFiles("$from_dir/include/SugarCache", $allFiles);
4258 if(file_exists("$from_dir/include/database")) {
4259 $allFiles = findAllFiles("$from_dir/include/database", $allFiles);
4261 if(file_exists("$from_dir/include/utils/external_cache.php")) {
4262 $allFiles[] = "$from_dir/include/utils/external_cache.php";
4264 if(file_exists("$from_dir/include/utils/sugar_file_utils.php")) {
4265 $allFiles[] = "$from_dir/include/utils/sugar_file_utils.php";
4267 if(file_exists("$from_dir/include/utils/sugar_file_utils.php")) {
4268 $allFiles[] = "$from_dir/include/utils/sugar_file_utils.php";
4270 if(file_exists("$from_dir/include/utils/autoloader.php")) {
4271 $allFiles[] = "$from_dir/include/utils/autoloader.php";
4274 foreach($allFiles as $k => $file) {
4275 $destFile = str_replace($from_dir."/", "", $file);
4276 if(!is_dir(dirname($destFile))) {
4277 mkdir_recursive(dirname($destFile)); // make sure the directory exists
4279 if ( stristr($file,'uw_main.tpl') )
4280 logThis('Skipping "'.$file.'" - file copy will during commit step.');
4282 logThis('updating UpgradeWizard code: '.$destFile);
4283 copy_recursive($file, $destFile);
4289 * unlinkUpgradeFiles
4290 * This is a helper function to clean up
4292 * @param $version String value of current system version (pre upgrade)
4294 function unlinkUpgradeFiles($version)
4296 if(!isset($version))
4301 //First check if we even have the scripts_for_patch/files_to_remove directory
4302 require_once('modules/UpgradeWizard/UpgradeRemoval.php');
4305 if(empty($_SESSION['unzip_dir']))
4307 global $sugar_config;
4308 $base_upgrade_dir = $sugar_config['upload_dir'] . "/upgrades";
4309 $base_tmp_upgrade_dir = "$base_upgrade_dir/temp";
4310 $_SESSION['unzip_dir'] = mk_temp_dir( $base_tmp_upgrade_dir );
4314 if(isset($_SESSION['unzip_dir']) && file_exists($_SESSION['unzip_dir'].'/scripts/files_to_remove'))
4316 $files_to_remove = glob($_SESSION['unzip_dir'].'/scripts/files_to_remove/*.php');
4318 foreach($files_to_remove as $script)
4320 if(preg_match('/UpgradeRemoval(\d+)x\.php/', $script, $matches))
4322 $upgradeClass = 'UpgradeRemoval' . $matches[1] . 'x';
4323 require_once($_SESSION['unzip_dir'].'/scripts/files_to_remove/' . $upgradeClass . '.php');
4324 if (class_exists($upgradeClass) == false)
4329 //Check to make sure we should load and run this UpgradeRemoval instance
4330 $upgradeInstance = new $upgradeClass();
4331 if ($upgradeInstance instanceof UpgradeRemoval && version_compare($upgradeInstance->version, $version, '<='))
4333 logThis('Running UpgradeRemoval instance ' . $upgradeClass);
4334 logThis('Files will be backed up to custom/backup');
4335 $files = $upgradeInstance->getFilesToRemove($version);
4336 foreach($files as $file)
4340 $upgradeInstance->processFilesToRemove($files);
4346 //Check if we have a custom directory
4347 if(file_exists('custom/scripts/files_to_remove'))
4350 $files_to_remove = glob('custom/scripts/files_to_remove/*.php');
4352 foreach($files_to_remove as $script)
4354 if(preg_match('/\/files_to_remove\/(.*?)\.php$/', $script, $matches))
4356 require_once($script);
4357 $upgradeClass = $matches[1];
4359 if(!class_exists($upgradeClass))
4364 $upgradeInstance = new $upgradeClass();
4365 if($upgradeInstance instanceof UpgradeRemoval)
4367 logThis('Running Custom UpgradeRemoval instance ' . $upgradeClass);
4368 $files = $upgradeInstance->getFilesToRemove($version);
4369 foreach($files as $file)
4373 $upgradeInstance->processFilesToRemove($files);
4381 if (!function_exists("getValidDBName"))
4384 * Return a version of $proposed that can be used as a column name in any of our supported databases
4385 * 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)
4386 * @param string $name Proposed name for the column
4387 * @param string $ensureUnique
4388 * @return string Valid column name trimmed to right length and with invalid characters removed
4390 function getValidDBName ($name, $ensureUnique = false, $maxLen = 30)
4392 // first strip any invalid characters - all but alphanumerics and -
4393 $name = preg_replace ( '/[^\w-]+/i', '', $name ) ;
4394 $len = strlen ( $name ) ;
4398 $md5str = md5($name);
4399 $tail = substr ( $name, -11) ;
4400 $temp = substr($md5str , strlen($md5str)-4 );
4401 $result = substr ( $name, 0, 10) . $temp . $tail ;
4402 }else if ($len > ($maxLen - 5))
4404 $result = substr ( $name, 0, 11) . substr ( $name, 11 - $maxLen + 5);
4406 return strtolower ( $result ) ;
4413 * Get UW directories
4414 * Provides compatibility with both 6.3 and pre-6.3 setup
4416 function getUWDirs()
4418 if(!class_exists('UploadStream')) {
4419 // we're still running the old code
4420 global $sugar_config;
4421 return array($sugar_config['upload_dir'] . "/upgrades", $sugar_config['cache_dir'] . "upload/upgrades/temp");
4423 if(!in_array("upload", stream_get_wrappers())) {
4424 UploadStream::register(); // just in case file was copied, but not run
4426 return array("upload://upgrades", sugar_cached("upgrades/temp"));
4431 * Whether directory exists within list of directories to skip
4432 * @param string $dir dir to be checked
4433 * @param array $skipDirs list with skipped dirs
4436 function whetherNeedToSkipDir($dir, $skipDirs)
4438 foreach($skipDirs as $skipMe) {
4439 if(strpos( clean_path($dir), $skipMe ) !== false) {
4449 * @param silentUpgrade boolean flag indicating whether or not we should treat running the SugarSpriteBuilder as an upgrade operation
4452 function rebuildSprites($fromUpgrade=true)
4454 require_once('modules/Administration/SugarSpriteBuilder.php');
4455 $sb = new SugarSpriteBuilder();
4456 $sb->cssMinify = true;
4457 $sb->fromSilentUpgrade = $fromUpgrade;
4458 $sb->silentRun = $fromUpgrade;
4460 // add common image directories
4461 $sb->addDirectory('default', 'include/images');
4462 $sb->addDirectory('default', 'themes/default/images');
4463 $sb->addDirectory('default', 'themes/default/images/SugarLogic');
4465 // add all theme image directories
4466 if($dh = opendir('themes'))
4468 while (($dir = readdir($dh)) !== false)
4470 if ($dir != "." && $dir != ".." && $dir != 'default' && is_dir('themes/'.$dir)) {
4471 $sb->addDirectory($dir, "themes/{$dir}/images");
4477 // add all theme custom image directories
4478 $custom_themes_dir = "custom/themes";
4479 if (is_dir($custom_themes_dir)) {
4480 if($dh = opendir($custom_themes_dir))
4482 while (($dir = readdir($dh)) !== false)
4484 //Since the custom theme directories don't require an images directory
4485 // we check for it implicitly
4486 if ($dir != "." && $dir != ".." && is_dir('custom/themes/'.$dir."/images")) {
4487 $sb->addDirectory($dir, "custom/themes/{$dir}/images");
4494 // generate the sprite goodies
4495 // everything is saved into cache/sprites
4496 $sb->createSprites();
4501 * repairSearchFields
4503 * This method goes through the list of SearchFields files based and calls TemplateRange::repairCustomSearchFields
4504 * method on the files in an attempt to ensure the range search attributes are properly set in SearchFields.php.
4506 * @param $globString String value used for glob search defaults to searching for all SearchFields.php files in modules directory
4507 * @param $path String value used to point to log file should logging be required. Defaults to empty.
4510 function repairSearchFields($globString='modules/*/metadata/SearchFields.php', $path='')
4514 logThis('Begin repairSearchFields', $path);
4517 require_once('include/dir_inc.php');
4518 require_once('modules/DynamicFields/templates/Fields/TemplateRange.php');
4519 require('include/modules.php');
4522 $searchFieldsFiles = glob($globString);
4524 foreach($searchFieldsFiles as $file)
4526 if(preg_match('/modules\/(.*?)\/metadata\/SearchFields\.php/', $file, $matches) && isset($beanList[$matches[1]]))
4528 $module = $matches[1];
4529 $beanName = $beanList[$module];
4530 VardefManager::loadVardef($module, $beanName);
4531 if(isset($GLOBALS['dictionary'][$beanName]['fields']))
4535 logThis('Calling TemplateRange::repairCustomSearchFields for module ' . $module, $path);
4537 TemplateRange::repairCustomSearchFields($GLOBALS['dictionary'][$beanName]['fields'], $module);
4544 logThis('End repairSearchFields', $path);
4549 * repairUpgradeHistoryTable
4551 * This is a helper function used in the upgrade process to fix upgrade_history entries so that the filename column points
4552 * to the new upload directory location introduced in 6.4 versions
4554 function repairUpgradeHistoryTable()
4556 require_once('modules/Configurator/Configurator.php');
4558 global $sugar_config;
4560 //Now upgrade the upgrade_history table entries
4561 $results = $GLOBALS['db']->query('SELECT id, filename FROM upgrade_history');
4562 $upload_dir = $sugar_config['cache_dir'].'upload/';
4564 //Create regular expression string to
4565 $match = '/^' . str_replace('/', '\/', $upload_dir) . '(.*?)$/';
4567 while(($row = $GLOBALS['db']->fetchByAssoc($results)))
4569 $file = str_replace('//', '/', $row['filename']); //Strip out double-paths that may exist
4571 if(!empty($file) && preg_match($match, $file, $matches))
4573 //Update new file location to use the new $sugar_config['upload_dir'] value
4574 $new_file_location = $sugar_config['upload_dir'] . $matches[1];
4575 $GLOBALS['db']->query("UPDATE upgrade_history SET filename = '{$new_file_location}' WHERE id = '{$row['id']}'");