2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4 * SugarCRM Community Edition is a customer relationship management program developed by
5 * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
7 * This program is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Affero General Public License version 3 as published by the
9 * Free Software Foundation with the addition of the following permission added
10 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
19 * You should have received a copy of the GNU Affero General Public License along with
20 * this program; if not, see http://www.gnu.org/licenses or write to the Free
21 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
27 * The interactive user interfaces in modified source and object code versions
28 * of this program must display Appropriate Legal Notices, as required under
29 * Section 5 of the GNU Affero General Public License version 3.
31 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32 * these Appropriate Legal Notices must retain the display of the "Powered by
33 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34 * technical reasons, the Appropriate Legal Notices must display the words
35 * "Powered by SugarCRM".
36 ********************************************************************************/
42 * 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>";
1137 // Suhosin allow to use upload://
1138 $ret['stream_msg'] = '';
1139 if (UploadStream::getSuhosinStatus() == true)
1141 $ret['stream_msg'] = "<b><span class=\"go\">{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1145 $ret['stream_msg'] = "<b><span class=\"stop\">{$app_strings['ERR_SUHOSIN']}</span></b>";
1146 $ret['error_found'] = true;
1149 /* mbstring.func_overload
1150 $ret['mbstring.func_overload'] = '';
1151 $mb = ini_get('mbstring.func_overload');
1154 $ret['mbstring.func_overload'] = "<b><span class=\"stop\">{$mod_strings['ERR_UW_MBSTRING_FUNC_OVERLOAD']}</b>";
1155 $ret['error_found'] = true;
1163 * is a file that we blow away automagically
1165 function isAutoOverwriteFile($file) {
1166 $overwriteDirs = array(
1167 './sugar_version.php',
1168 './modules/UpgradeWizard/uw_main.tpl',
1170 $file = trim('.'.str_replace(clean_path(getcwd()), '', $file));
1172 if(in_array($file, $overwriteDirs)) {
1176 $fileExtension = substr(strrchr($file, "."), 1);
1177 if($fileExtension == 'tpl' || $fileExtension == 'html') {
1187 function logThis($entry, $path='') {
1188 global $mod_strings;
1189 if(file_exists('include/utils/sugar_file_utils.php')){
1190 require_once('include/utils/sugar_file_utils.php');
1192 $log = empty($path) ? clean_path(getcwd().'/upgradeWizard.log') : clean_path($path);
1194 // create if not exists
1195 if(!file_exists($log)) {
1196 if(function_exists('sugar_fopen')){
1197 $fp = @sugar_fopen($log, 'w+'); // attempts to create file
1200 $fp = fopen($log, 'w+'); // attempts to create file
1202 if(!is_resource($fp)) {
1203 $GLOBALS['log']->fatal('UpgradeWizard could not create the upgradeWizard.log file');
1204 die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
1207 if(function_exists('sugar_fopen')){
1208 $fp = @sugar_fopen($log, 'a+'); // write pointer at end of file
1211 $fp = @fopen($log, 'a+'); // write pointer at end of file
1214 if(!is_resource($fp)) {
1215 $GLOBALS['log']->fatal('UpgradeWizard could not open/lock upgradeWizard.log file');
1216 die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
1220 $line = date('r').' [UpgradeWizard] - '.$entry."\n";
1222 if(@fwrite($fp, $line) === false) {
1223 $GLOBALS['log']->fatal('UpgradeWizard could not write to upgradeWizard.log: '.$entry);
1224 die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
1227 if(is_resource($fp)) {
1235 * @desc This function is to be used in the upgrade process to preserve changes/customaizations made to pre 5.1 quickcreate layout.
1236 * 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
1237 * was automatically picked up by the quick create. [Addresses Bug 21469]
1238 * This function will check if customizations were made, and will create quickcreatedefs.php in the /cutom/working/$module_name directory.
1240 function updateQuickCreateDefs(){
1241 $d = dir('modules');
1242 $studio_modules = array();
1244 while($e = $d->read()){ //collect all studio modules.
1245 if(substr($e, 0, 1) == '.' || !is_dir('modules/' . $e))continue;
1246 if(file_exists('modules/' . $e . '/metadata/studio.php'))
1248 array_push($studio_modules, $e);
1252 foreach( $studio_modules as $modname ){ //for each studio enabled module
1253 //Check !exists modules/$modname/metadata/quickcreatedefs.php &&
1254 //exists custom/$modname/editviewdefs.php (module was customized) &&
1255 //!exists custom/$modname/quickcreateviewdefs.php
1257 $editviewdefs = "custom/working/modules/".$modname."/metadata/editviewdefs.php";
1258 $quickcreatedefs = "custom/working/modules/".$modname."/metadata/quickcreatedefs.php";
1260 if ( !file_exists("modules/".$modname."/metadata/quickcreatedefs.php") &&
1261 file_exists($editviewdefs) &&
1262 !file_exists($quickcreatedefs) ){
1263 //clone editviewdef and save it in custom/working/modules/metadata
1264 $GLOBALS['log']->debug("Copying editviewdefs.php as quickcreatedefs.php for the $modname module in custom/working/modules/$modname/metadata!");
1265 if(copy( $editviewdefs, $quickcreatedefs)){
1266 if(file_exists($quickcreatedefs) && is_readable($quickcreatedefs)){
1267 $file = file($quickcreatedefs);
1268 //replace 'EditView' with 'QuickCreate'
1269 $fp = fopen($quickcreatedefs,'w');
1270 foreach($file as &$line){
1271 if(preg_match('/^\s*\'EditView\'\s*=>\s*$/', $line) > 0){
1272 $line = "'QuickCreate' =>\n";
1280 $GLOBALS['log']->debug("Failed to replace 'EditView' with QuickCreate because $quickcreatedefs is either not readable or does not exist.");
1283 $GLOBALS['log']->debug("Failed to copy $editviewdefs to $quickcreatedefs!");
1290 * test perms for CREATE queries
1292 function testPermsCreate($db, $out) {
1293 logThis('Checking CREATE TABLE permissions...');
1294 global $mod_strings;
1296 if(!$db->checkPrivilege("CREATE TABLE")) {
1297 logThis('cannot CREATE TABLE!');
1298 $out['db']['dbNoCreate'] = true;
1299 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_CREATE']}</span></td></tr>";
1305 * test perms for INSERT
1307 function testPermsInsert($db, $out, $skip=false) {
1308 logThis('Checking INSERT INTO permissions...');
1309 global $mod_strings;
1311 if(!$db->checkPrivilege("INSERT")) {
1312 logThis('cannot INSERT INTO!');
1313 $out['db']['dbNoInsert'] = true;
1314 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_INSERT']}</span></td></tr>";
1321 * test perms for UPDATE TABLE
1323 function testPermsUpdate($db, $out, $skip=false) {
1324 logThis('Checking UPDATE TABLE permissions...');
1325 global $mod_strings;
1326 if(!$db->checkPrivilege("UPDATE")) {
1327 logThis('cannot UPDATE TABLE!');
1328 $out['db']['dbNoUpdate'] = true;
1329 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_UPDATE']}</span></td></tr>";
1336 * test perms for SELECT
1338 function testPermsSelect($db, $out, $skip=false) {
1339 logThis('Checking SELECT permissions...');
1340 global $mod_strings;
1341 if(!$db->checkPrivilege("SELECT")) {
1342 logThis('cannot SELECT!');
1343 $out['db']['dbNoSelect'] = true;
1344 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_SELECT']}</span></td></tr>";
1350 * test perms for DELETE
1352 function testPermsDelete($db, $out, $skip=false) {
1353 logThis('Checking DELETE FROM permissions...');
1354 global $mod_strings;
1355 if(!$db->checkPrivilege("DELETE")) {
1356 logThis('cannot DELETE FROM!');
1357 $out['db']['dbNoDelete'] = true;
1358 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_DELETE']}</span></td></tr>";
1365 * test perms for ALTER TABLE ADD COLUMN
1367 function testPermsAlterTableAdd($db, $out, $skip=false) {
1368 logThis('Checking ALTER TABLE ADD COLUMN permissions...');
1369 global $mod_strings;
1370 if(!$db->checkPrivilege("ADD COLUMN")) {
1371 logThis('cannot ADD COLUMN!');
1372 $out['db']['dbNoAddColumn'] = true;
1373 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_ADD_COLUMN']}</span></td></tr>";
1379 * test perms for ALTER TABLE ADD COLUMN
1381 function testPermsAlterTableChange($db, $out, $skip=false) {
1382 logThis('Checking ALTER TABLE CHANGE COLUMN permissions...');
1383 global $mod_strings;
1384 if(!$db->checkPrivilege("CHANGE COLUMN")) {
1385 logThis('cannot CHANGE COLUMN!');
1386 $out['db']['dbNoChangeColumn'] = true;
1387 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_CHANGE_COLUMN']}</span></td></tr>";
1393 * test perms for ALTER TABLE DROP COLUMN
1395 function testPermsAlterTableDrop($db, $out, $skip=false) {
1396 logThis('Checking ALTER TABLE DROP COLUMN permissions...');
1397 global $mod_strings;
1398 if(!$db->checkPrivilege("DROP COLUMN")) {
1399 logThis('cannot DROP COLUMN!');
1400 $out['db']['dbNoDropColumn'] = true;
1401 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_DROP_COLUMN']}</span></td></tr>";
1408 * test perms for DROP TABLE
1410 function testPermsDropTable($db, $out, $skip=false) {
1411 logThis('Checking DROP TABLE permissions...');
1412 global $mod_strings;
1413 if(!$db->checkPrivilege("DROP TABLE")) {
1414 logThis('cannot DROP TABLE!');
1415 $out['db']['dbNoDropTable'] = true;
1416 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_DROP_TABLE']}</span></td></tr>";
1421 function getFormattedError($error, $query) {
1422 $error = "<div><b>".$error;
1423 $error .= "</b>::{$query}</div>";
1429 * parses a query finding the table name
1430 * @param string query The query
1431 * @return string table The table
1433 function getTableFromQuery($query) {
1434 $standardQueries = array('ALTER TABLE', 'DROP TABLE', 'CREATE TABLE', 'INSERT INTO', 'UPDATE', 'DELETE FROM');
1435 $query = preg_replace("/[^A-Za-z0-9\_\s]/", "", $query);
1436 $query = trim(str_replace($standardQueries, '', $query));
1438 $firstSpc = strpos($query, " ");
1439 $end = ($firstSpc > 0) ? $firstSpc : strlen($query);
1440 $table = substr($query, 0, $end);
1447 function preLicenseCheck() {
1448 require_once('modules/UpgradeWizard/uw_files.php');
1450 global $sugar_config;
1451 global $mod_strings;
1452 global $sugar_version;
1454 if (empty($sugar_version))
1456 require('sugar_version.php');
1459 if(!isset($_SESSION['unzip_dir']) || empty($_SESSION['unzip_dir'])) {
1460 logThis('unzipping files in upgrade archive...');
1462 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
1464 //also come up with mechanism to read from upgrade-progress file
1465 if(!isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !is_file($_SESSION['install_file'])) {
1466 if (file_exists(clean_path($base_tmp_upgrade_dir)) && $handle = opendir(clean_path($base_tmp_upgrade_dir))) {
1467 while (false !== ($file = readdir($handle))) {
1468 if($file !="." && $file !="..") {
1469 if(is_file($base_tmp_upgrade_dir."/".$file."/manifest.php")){
1470 require_once($base_tmp_upgrade_dir."/".$file."/manifest.php");
1471 $package_name= $manifest['copy_files']['from_dir'];
1472 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")){
1473 $unzip_dir = $base_tmp_upgrade_dir."/".$file;
1474 if(file_exists("$base_upgrade_dir/patch/".$package_name.'.zip')){
1475 $_SESSION['install_file'] = $package_name.".zip";
1484 if(empty($_SESSION['install_file'])){
1485 unlinkUWTempFiles();
1487 echo 'Upload File not found so redirecting to Upgrade Start ';
1488 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1489 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1490 $upgrade_directories_not_found =<<<eoq
1491 <table cellpadding="3" cellspacing="0" border="0">
1493 <th colspan="2" align="left">
1494 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1499 $uwMain = $upgrade_directories_not_found;
1502 $install_file = "$base_upgrade_dir/patch/".basename(urldecode( $_SESSION['install_file'] ));
1504 if(empty($unzip_dir)){
1505 $unzip_dir = mk_temp_dir( $base_tmp_upgrade_dir );
1507 $zip_from_dir = ".";
1509 $zip_force_copy = array();
1512 logThis('Could not create a temporary directory using mk_temp_dir( $base_tmp_upgrade_dir )');
1513 die($mod_strings['ERR_UW_NO_CREATE_TMP_DIR']);
1516 //double check whether unzipped .
1517 if(file_exists($unzip_dir ."/scripts") && file_exists($unzip_dir."/manifest.php")){
1521 unzip( $install_file, $unzip_dir );
1524 // assumption -- already validated manifest.php at time of upload
1525 require_once( "$unzip_dir/manifest.php" );
1527 if( isset( $manifest['copy_files']['from_dir'] ) && $manifest['copy_files']['from_dir'] != "" ){
1528 $zip_from_dir = $manifest['copy_files']['from_dir'];
1530 if( isset( $manifest['copy_files']['to_dir'] ) && $manifest['copy_files']['to_dir'] != "" ){
1531 $zip_to_dir = $manifest['copy_files']['to_dir'];
1533 if( isset( $manifest['copy_files']['force_copy'] ) && $manifest['copy_files']['force_copy'] != "" ){
1534 $zip_force_copy = $manifest['copy_files']['force_copy'];
1536 if( isset( $manifest['version'] ) ){
1537 $version = $manifest['version'];
1539 if( !is_writable( "config.php" ) ){
1540 return $mod_strings['ERR_UW_CONFIG'];
1543 $_SESSION['unzip_dir'] = clean_path($unzip_dir);
1544 $_SESSION['zip_from_dir'] = clean_path($zip_from_dir);
1545 logThis('unzip done.');
1547 $unzip_dir = $_SESSION['unzip_dir'];
1548 $zip_from_dir = $_SESSION['zip_from_dir'];
1551 //check if $_SESSION['unzip_dir'] and $_SESSION['zip_from_dir'] exist
1552 if(!isset($_SESSION['unzip_dir']) || !file_exists($_SESSION['unzip_dir'])
1553 || !isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !file_exists($_SESSION['install_file'])){
1555 unlinkUWTempFiles();
1557 echo 'Upload File not found so redirecting to Upgrade Start ';
1558 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1559 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1560 $upgrade_directories_not_found =<<<eoq
1561 <table cellpadding="3" cellspacing="0" border="0">
1563 <th colspan="2" align="left">
1564 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1569 $uwMain = $upgrade_directories_not_found;
1573 logThis ('is SugarConfig there '.file_exists(clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarObjects/SugarConfig.php")));
1574 if(file_exists(clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarObjects/SugarConfig.php"))) {
1575 $file = clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarObjects/SugarConfig.php");
1576 $destFile = str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), $cwd, $file);
1577 if(!is_dir(dirname($destFile))) {
1578 mkdir_recursive(dirname($destFile)); // make sure the directory exists
1580 copy($file,$destFile);
1581 //also copy include utils array utils
1582 $file = clean_path($unzip_dir.'/'.$zip_from_dir."/include/utils/array_utils.php");
1583 $destFile = str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), $cwd, $file);
1584 if(!is_dir(dirname($destFile))) {
1585 mkdir_recursive(dirname($destFile)); // make sure the directory exists
1587 copy($file,$destFile);
1592 function preflightCheck() {
1593 require_once('modules/UpgradeWizard/uw_files.php');
1595 global $sugar_config;
1596 global $mod_strings;
1597 global $sugar_version;
1599 if (empty($sugar_version))
1601 require('sugar_version.php');
1604 unset($_SESSION['rebuild_relationships']);
1605 unset($_SESSION['rebuild_extensions']);
1607 // don't bother if are rechecking
1608 $manualDiff = array();
1609 if(!isset($_SESSION['unzip_dir']) || empty($_SESSION['unzip_dir'])) {
1610 logThis('unzipping files in upgrade archive...');
1612 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
1614 //Following is if User logged out unexpectedly and then logged into UpgradeWizard again.
1615 //also come up with mechanism to read from upgrade-progress file.
1616 if(!isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !is_file($_SESSION['install_file'])) {
1617 if (file_exists($base_tmp_upgrade_dir) && $handle = opendir($base_tmp_upgrade_dir)) {
1618 while (false !== ($file = readdir($handle))) {
1619 if($file !="." && $file !="..") {
1620 if(is_file($base_tmp_upgrade_dir."/".$file."/manifest.php")){
1621 require_once($base_tmp_upgrade_dir."/".$file."/manifest.php");
1622 $package_name= $manifest['copy_files']['from_dir'];
1623 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")){
1624 $unzip_dir = $base_tmp_upgrade_dir."/".$file;
1625 if(file_exists("$base_upgrade_dir/patch/".$package_name.'.zip')){
1626 $_SESSION['install_file'] = $package_name.".zip";
1635 if(empty($_SESSION['install_file'])){
1636 unlinkUWTempFiles();
1638 echo 'Upload File not found so redirecting to Upgrade Start ';
1639 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1640 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1641 $upgrade_directories_not_found =<<<eoq
1642 <table cellpadding="3" cellspacing="0" border="0">
1644 <th colspan="2" align="left">
1645 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1650 $uwMain = $upgrade_directories_not_found;
1654 $install_file = "$base_upgrade_dir/patch/".basename(urldecode( $_SESSION['install_file'] ));
1656 if(empty($unzip_dir)){
1657 $unzip_dir = mk_temp_dir( $base_tmp_upgrade_dir );
1659 $zip_from_dir = ".";
1661 $zip_force_copy = array();
1664 logThis('Could not create a temporary directory using mk_temp_dir( $base_tmp_upgrade_dir )');
1665 die($mod_strings['ERR_UW_NO_CREATE_TMP_DIR']);
1668 //double check whether unzipped .
1669 if(file_exists($unzip_dir ."/scripts") && file_exists($unzip_dir."/manifest.php")){
1673 unzip( $install_file, $unzip_dir );
1676 // assumption -- already validated manifest.php at time of upload
1677 require_once( "$unzip_dir/manifest.php" );
1679 if( isset( $manifest['copy_files']['from_dir'] ) && $manifest['copy_files']['from_dir'] != "" ){
1680 $zip_from_dir = $manifest['copy_files']['from_dir'];
1682 if( isset( $manifest['copy_files']['to_dir'] ) && $manifest['copy_files']['to_dir'] != "" ){
1683 $zip_to_dir = $manifest['copy_files']['to_dir'];
1685 if( isset( $manifest['copy_files']['force_copy'] ) && $manifest['copy_files']['force_copy'] != "" ){
1686 $zip_force_copy = $manifest['copy_files']['force_copy'];
1688 if( isset( $manifest['version'] ) ){
1689 $version = $manifest['version'];
1691 if( !is_writable( "config.php" ) ){
1692 return $mod_strings['ERR_UW_CONFIG'];
1695 $_SESSION['unzip_dir'] = clean_path($unzip_dir);
1696 $_SESSION['zip_from_dir'] = clean_path($zip_from_dir);
1698 //logThis('unzip done.');
1700 $unzip_dir = $_SESSION['unzip_dir'];
1701 $zip_from_dir = $_SESSION['zip_from_dir'];
1703 //check if $_SESSION['unzip_dir'] and $_SESSION['zip_from_dir'] exist
1704 if(!isset($_SESSION['unzip_dir']) || !file_exists($_SESSION['unzip_dir'])
1705 || !isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !file_exists($_SESSION['install_file'])){
1707 unlinkUWTempFiles();
1709 echo 'Upload File not found so redirecting to Upgrade Start ';
1710 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1711 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1712 $upgrade_directories_not_found =<<<eoq
1713 <table cellpadding="3" cellspacing="0" border="0">
1715 <th colspan="2" align="left">
1716 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1721 $uwMain = $upgrade_directories_not_found;
1724 //copy minimum required files
1725 fileCopy('include/utils/sugar_file_utils.php');
1727 $upgradeFiles = findAllFiles(clean_path("$unzip_dir/$zip_from_dir"), array());
1728 $cache_html_files= array();
1731 $md5_string = array();
1732 if(file_exists(clean_path(getcwd().'/files.md5'))){
1733 require(clean_path(getcwd().'/files.md5'));
1736 // file preflight checks
1737 logThis('verifying md5 checksums for files...');
1738 foreach($upgradeFiles as $file) {
1739 if(in_array(str_replace(clean_path("$unzip_dir/$zip_from_dir") . "/", '', $file), $uw_files))
1740 continue; // skip already loaded files
1742 if(strpos($file, '.md5'))
1743 continue; // skip md5 file
1745 // normalize file paths
1746 $file = clean_path($file);
1748 // check that we can move/delete the upgraded file
1749 if(!is_writable($file)) {
1750 $errors[] = $mod_strings['ERR_UW_FILE_NOT_WRITABLE'].": ".$file;
1752 // check that destination files are writable
1753 $destFile = getcwd().str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), '', $file);
1755 if(is_file($destFile)) { // of course it needs to exist first...
1756 if(!is_writable($destFile)) {
1757 $errors[] = $mod_strings['ERR_UW_FILE_NOT_WRITABLE'].": ".$destFile;
1761 ///////////////////////////////////////////////////////////////////////
1763 // compare md5s and build up a manual merge list
1764 $targetFile = clean_path(".".str_replace(getcwd(),'',$destFile));
1766 if(is_file($destFile)) {
1767 if(strpos($targetFile, '.php')) {
1768 // handle PHP files that were hit with the security regex
1770 if(function_exists('sugar_fopen')){
1771 $fp = sugar_fopen($destFile, 'r');
1774 $fp = fopen($destFile, 'r');
1776 $filesize = filesize($destFile);
1778 $fileContents = stream_get_contents($fp);
1779 $targetMd5 = md5($fileContents);
1782 $targetMd5 = md5_file($destFile);
1786 if(isset($md5_string[$targetFile]) && $md5_string[$targetFile] != $targetMd5) {
1787 logThis('found a file with a differing md5: ['.$targetFile.']');
1788 $manualDiff[] = $destFile;
1791 ///////////////////////////////////////////////////////////////////////
1793 logThis('md5 verification done.');
1794 $errors['manual'] = $manualDiff;
1799 function fileCopy($file_path){
1800 if(file_exists(clean_path($_SESSION['unzip_dir'].'/'.$_SESSION['zip_from_dir'].'/'.$file_path))) {
1801 $file = clean_path($_SESSION['unzip_dir'].'/'.$_SESSION['zip_from_dir'].'/'.$file_path);
1802 $destFile = str_replace(clean_path($_SESSION['unzip_dir'].'/'.$_SESSION['zip_from_dir']), clean_path(getcwd()), $file);
1803 if(!is_dir(dirname($destFile))) {
1804 mkdir_recursive(dirname($destFile)); // make sure the directory exists
1806 copy_recursive($file,$destFile);
1809 function getChecklist($steps, $step) {
1810 global $mod_strings;
1812 $skip = array('start', 'cancel', 'uninstall','end');
1815 $ret = '<table cellpadding="3" cellspacing="4" border="0">';
1816 $ret .= '<tr><th colspan="3" align="left">'.$mod_strings['LBL_UW_CHECKLIST'].':</th></tr>';
1817 foreach($steps['desc'] as $k => $desc) {
1818 if(in_array($steps['files'][$j], $skip)) {
1823 //$status = "<span class='error'>{$mod_strings['LBL_UW_INCOMPLETE']}</span>";
1825 $desc_mod_post = '';
1827 if(isset($_SESSION['step'][$steps['files'][$k]]) && $_SESSION['step'][$steps['files'][$k]] == 'success') {
1828 //$status = $mod_strings['LBL_UW_COMPLETE'];
1832 if($k == $_REQUEST['step']) {
1833 //$status = $mod_strings['LBL_UW_IN_PROGRESS'];
1834 $desc_mod_pre = "<font color=blue><i>";
1835 $desc_mod_post = "</i></font>";
1838 $ret .= "<tr><td> </td><td><b>{$i}: {$desc_mod_pre}{$desc}{$desc_mod_post}</b></td>";
1839 $ret .= "<td id={$steps['files'][$j]}><i></i></td></tr>";
1847 function prepSystemForUpgrade() {
1848 global $sugar_config;
1849 global $sugar_flavor;
1850 global $mod_strings;
1851 global $current_language;
1853 global $base_upgrade_dir;
1854 global $base_tmp_upgrade_dir;
1855 list($p_base_upgrade_dir, $p_base_tmp_upgrade_dir) = getUWDirs();
1856 ///////////////////////////////////////////////////////////////////////////////
1857 //// Make sure variables exist
1858 if(empty($base_upgrade_dir)){
1859 $base_upgrade_dir = $p_base_upgrade_dir;
1861 if(empty($base_tmp_upgrade_dir)){
1862 $base_tmp_upgrade_dir = $p_base_tmp_upgrade_dir;
1864 sugar_mkdir($base_tmp_upgrade_dir, 0775, true);
1865 if(!isset($subdirs) || empty($subdirs)){
1866 $subdirs = array('full', 'langpack', 'module', 'patch', 'theme');
1869 $upgrade_progress_dir = $base_tmp_upgrade_dir;
1870 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
1871 if(file_exists($upgrade_progress_file)){
1872 if(function_exists('get_upgrade_progress') && function_exists('didThisStepRunBefore')){
1873 if(didThisStepRunBefore('end')){
1874 include($upgrade_progress_file);
1875 unset($upgrade_config);
1876 unlink($upgrade_progress_file);
1881 // increase the cuttoff time to 1 hour
1882 ini_set("max_execution_time", "3600");
1884 // make sure dirs exist
1885 if($subdirs != null){
1886 foreach($subdirs as $subdir) {
1887 sugar_mkdir("$base_upgrade_dir/$subdir", 0775, true);
1890 // array of special scripts that are executed during (un)installation-- key is type of script, value is filename
1891 if(!defined('SUGARCRM_PRE_INSTALL_FILE')) {
1892 define('SUGARCRM_PRE_INSTALL_FILE', 'scripts/pre_install.php');
1893 define('SUGARCRM_POST_INSTALL_FILE', 'scripts/post_install.php');
1894 define('SUGARCRM_PRE_UNINSTALL_FILE', 'scripts/pre_uninstall.php');
1895 define('SUGARCRM_POST_UNINSTALL_FILE', 'scripts/post_uninstall.php');
1898 $script_files = array(
1899 "pre-install" => constant('SUGARCRM_PRE_INSTALL_FILE'),
1900 "post-install" => constant('SUGARCRM_POST_INSTALL_FILE'),
1901 "pre-uninstall" => constant('SUGARCRM_PRE_UNINSTALL_FILE'),
1902 "post-uninstall" => constant('SUGARCRM_POST_UNINSTALL_FILE'),
1905 // check that the upload limit is set to 6M or greater
1906 define('SUGARCRM_MIN_UPLOAD_MAX_FILESIZE_BYTES', 6 * 1024 * 1024); // 6 Megabytes
1907 $upload_max_filesize = ini_get('upload_max_filesize');
1908 $upload_max_filesize_bytes = return_bytes($upload_max_filesize);
1910 if($upload_max_filesize_bytes < constant('SUGARCRM_MIN_UPLOAD_MAX_FILESIZE_BYTES')) {
1911 $GLOBALS['log']->debug("detected upload_max_filesize: $upload_max_filesize");
1912 $admin_strings = return_module_language($current_language, 'Administration');
1913 echo '<p class="error">'.$admin_strings['MSG_INCREASE_UPLOAD_MAX_FILESIZE'].' '.get_cfg_var('cfg_file_path')."</p>\n";
1917 if ( !function_exists('extractFile') ) {
1918 function extractFile($zip_file, $file_in_zip) {
1919 global $base_tmp_upgrade_dir;
1922 $absolute_base_tmp_upgrade_dir = clean_path($base_tmp_upgrade_dir);
1923 $relative_base_tmp_upgrade_dir = clean_path(str_replace(clean_path(getcwd()), '', $absolute_base_tmp_upgrade_dir));
1925 // mk_temp_dir expects relative pathing
1926 $my_zip_dir = mk_temp_dir($relative_base_tmp_upgrade_dir);
1928 unzip_file($zip_file, $file_in_zip, $my_zip_dir);
1930 return("$my_zip_dir/$file_in_zip");
1934 if ( !function_exists('extractManifest') ) {
1935 function extractManifest($zip_file) {
1936 logThis('extracting manifest.');
1937 return(extractFile($zip_file, "manifest.php"));
1941 if ( !function_exists('getInstallType') ) {
1942 function getInstallType($type_string) {
1945 $subdirs = array('full', 'langpack', 'module', 'patch', 'theme', 'temp');
1946 foreach($subdirs as $subdir) {
1947 if(preg_match("#/$subdir/#", $type_string)) {
1951 // return empty if no match
1956 function getImageForType($type) {
1958 global $mod_strings;
1963 $icon = SugarThemeRegistry::current()->getImage("Upgrade", "",null,null,'.gif',$mod_strings['LBL_UPGRADE']);
1966 $icon = SugarThemeRegistry::current()->getImage("LanguagePacks", "",null,null,'.gif',$mod_strings['LBL_LANGPACKS']);
1969 $icon = SugarThemeRegistry::current()->getImage("ModuleLoader", "",null,null,'.gif',$mod_strings['LBL_MODULELOADER']);
1972 $icon = SugarThemeRegistry::current()->getImage("PatchUpgrades", "",null,null,'.gif',$mod_strings['LBL_PATCHUPGRADES']);
1975 $icon = SugarThemeRegistry::current()->getImage("Themes", "",null,null,'.gif',$mod_strings['LBL_THEMES']);
1983 if ( !function_exists('getLanguagePackName') ) {
1984 function getLanguagePackName($the_file) {
1985 require_once("$the_file");
1986 if(isset($app_list_strings["language_pack_name"])) {
1987 return($app_list_strings["language_pack_name"]);
1993 function getUITextForType($type) {
1994 if($type == "full") {
1995 return("Full Upgrade");
1997 if($type == "langpack") {
1998 return("Language Pack");
2000 if($type == "module") {
2003 if($type == "patch") {
2006 if($type == "theme") {
2011 if ( !function_exists('validate_manifest') ) {
2013 * Verifies a manifest from a patch or module to be compatible with the current Sugar version and flavor
2014 * @param array manifest Standard manifest array
2015 * @return string Error message, blank on success
2017 function validate_manifest($manifest) {
2018 logThis('validating manifest.php file');
2019 // takes a manifest.php manifest array and validates contents
2021 global $sugar_version;
2022 global $sugar_flavor;
2023 global $mod_strings;
2025 if(!isset($manifest['type'])) {
2026 return $mod_strings['ERROR_MANIFEST_TYPE'];
2029 $type = $manifest['type'];
2031 if(getInstallType("/$type/") == "") {
2032 return $mod_strings['ERROR_PACKAGE_TYPE']. ": '" . $type . "'.";
2035 if(isset($manifest['acceptable_sugar_versions'])) {
2036 $version_ok = false;
2037 $matches_empty = true;
2038 if(isset($manifest['acceptable_sugar_versions']['exact_matches'])) {
2039 $matches_empty = false;
2040 foreach($manifest['acceptable_sugar_versions']['exact_matches'] as $match) {
2041 if($match == $sugar_version) {
2046 if(!$version_ok && isset($manifest['acceptable_sugar_versions']['regex_matches'])) {
2047 $matches_empty = false;
2048 foreach($manifest['acceptable_sugar_versions']['regex_matches'] as $match) {
2049 if(preg_match("/$match/", $sugar_version)) {
2055 if(!$matches_empty && !$version_ok) {
2056 return $mod_strings['ERROR_VERSION_INCOMPATIBLE']."<br />".
2057 $mod_strings['ERR_UW_VERSION'].$sugar_version;
2061 if(isset($manifest['acceptable_sugar_flavors']) && sizeof($manifest['acceptable_sugar_flavors']) > 0) {
2063 foreach($manifest['acceptable_sugar_flavors'] as $match) {
2064 if($match == $sugar_flavor) {
2069 return $mod_strings['ERROR_FLAVOR_INCOMPATIBLE']."<br />".
2070 $mod_strings['ERR_UW_FLAVOR'].$sugar_flavor."<br />".
2071 $mod_strings['ERR_UW_FLAVOR_2'].$manifest['acceptable_sugar_flavors'][0];
2079 function unlinkUploadFiles() {
2081 // logThis('at unlinkUploadFiles()');
2083 // if(isset($_SESSION['install_file']) && !empty($_SESSION['install_file'])) {
2084 // $upload = $_SESSION['install_file'];
2086 // if(is_file($upload)) {
2087 // logThis('unlinking ['.$upload.']');
2088 // @unlink($upload);
2094 * deletes files created by unzipping a package
2096 function unlinkUWTempFiles() {
2097 global $sugar_config;
2100 logThis('at unlinkUWTempFiles()');
2102 list($upgDir, $tempDir) = getUWDirs();
2104 if(file_exists($tempDir) && is_dir($tempDir)){
2105 $files = findAllFiles($tempDir, array(), false);
2107 foreach($files as $file) {
2108 if(!is_dir($file)) {
2109 //logThis('unlinking ['.$file.']', $path);
2114 $files = findAllFiles($tempDir, array(), true);
2115 foreach($files as $dir) {
2117 //logThis('removing dir ['.$dir.']', $path);
2121 $cacheFile = sugar_cached("modules/UpgradeWizard/_persistence.php");
2122 if(is_file($cacheFile)) {
2123 logThis("Unlinking Upgrade cache file: '_persistence.php'", $path);
2124 @unlink($cacheFile);
2127 logThis("finished!");
2131 * finds all files in the passed path, but skips select directories
2132 * @param string dir Relative path
2133 * @param array the_array Collections of found files/dirs
2134 * @param bool include_dir True if we want to include directories in the
2135 * returned collection
2137 function uwFindAllFiles($dir, $theArray, $includeDirs=false, $skipDirs=array(), $echo=false) {
2139 if (whetherNeedToSkipDir($dir, $skipDirs))
2144 if (!is_dir($dir)) { return $theArray; } // Bug # 46035, just checking for valid dir
2146 if ($d === false) { return $theArray; } // Bug # 46035, more checking
2148 while($f = $d->read()) {
2149 // bug 40793 Skip Directories array in upgradeWizard does not function correctly
2150 if($f == "." || $f == ".." || whetherNeedToSkipDir("$dir/$f", $skipDirs)) { // skip *nix self/parent
2154 // for AJAX length count
2160 if(is_dir("$dir/$f")) {
2161 if($includeDirs) { // add the directory if flagged
2162 $theArray[] = clean_path("$dir/$f");
2166 $theArray = uwFindAllFiles("$dir/$f/", $theArray, $includeDirs, $skipDirs, $echo);
2168 $theArray[] = clean_path("$dir/$f");
2181 * unset's UW's Session Vars
2183 function resetUwSession() {
2184 logThis('resetting $_SESSION');
2186 if(isset($_SESSION['committed']))
2187 unset($_SESSION['committed']);
2188 if(isset($_SESSION['sugar_version_file']))
2189 unset($_SESSION['sugar_version_file']);
2190 if(isset($_SESSION['upgrade_complete']))
2191 unset($_SESSION['upgrade_complete']);
2192 if(isset($_SESSION['allTables']))
2193 unset($_SESSION['allTables']);
2194 if(isset($_SESSION['alterCustomTableQueries']))
2195 unset($_SESSION['alterCustomTableQueries']);
2196 if(isset($_SESSION['skip_zip_upload']))
2197 unset($_SESSION['skip_zip_upload']);
2198 if(isset($_SESSION['install_file']))
2199 unset($_SESSION['install_file']);
2200 if(isset($_SESSION['unzip_dir']))
2201 unset($_SESSION['unzip_dir']);
2202 if(isset($_SESSION['zip_from_dir']))
2203 unset($_SESSION['zip_from_dir']);
2204 if(isset($_SESSION['overwrite_files']))
2205 unset($_SESSION['overwrite_files']);
2206 if(isset($_SESSION['schema_change']))
2207 unset($_SESSION['schema_change']);
2208 if(isset($_SESSION['uw_restore_dir']))
2209 unset($_SESSION['uw_restore_dir']);
2210 if(isset($_SESSION['step']))
2211 unset($_SESSION['step']);
2212 if(isset($_SESSION['files']))
2213 unset($_SESSION['files']);
2214 if(isset($_SESSION['Upgraded451Wizard'])){
2215 unset($_SESSION['Upgraded451Wizard']);
2217 if(isset($_SESSION['Initial_451to500_Step'])){
2218 unset($_SESSION['Initial_451to500_Step']);
2220 if(isset($_SESSION['license_shown']))
2221 unset($_SESSION['license_shown']);
2222 if(isset($_SESSION['sugarMergeRunResults']))
2223 unset($_SESSION['sugarMergeRunResults']);
2227 * runs rebuild scripts
2229 function UWrebuild() {
2233 //CCL - Comment this block out, it is called in end.php
2234 logThis('Rebuilding everything...', $path);
2235 require_once('modules/Administration/QuickRepairAndRebuild.php');
2236 $randc = new RepairAndClear();
2237 $randc->repairAndClearAll(array('clearAll'),array(translate('LBL_ALL_MODULES')), false, false);
2239 $query = "DELETE FROM versions WHERE name='Rebuild Extensions'";
2241 logThis('Registering rebuild record: '.$query, $path);
2242 logThis('Rebuild done.', $path);
2244 // insert a new database row to show the rebuild extensions is done
2245 $id = create_guid();
2246 $gmdate = gmdate('Y-m-d H:i:s');
2247 $date_entered = db_convert("'$gmdate'", 'datetime');
2248 $query = 'INSERT INTO versions (id, deleted, date_entered, date_modified, modified_user_id, created_by, name, file_version, db_version) '
2249 . "VALUES ('$id', '0', $date_entered, $date_entered, '1', '1', 'Rebuild Extensions', '4.0.0', '4.0.0')";
2251 logThis('Registering rebuild record in versions table: '.$query, $path);
2254 function getCustomTables() {
2257 return $db->tablesLike('%_cstm');
2260 function alterCustomTables($customTables)
2265 function getAllTables() {
2267 return $db->getTablesArray();
2270 function printAlterTableSql($tables)
2272 $alterTableSql = '';
2274 foreach($tables as $table)
2275 $alterTableSql .= "ALTER TABLE " . $table . " CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;" . "\n";
2277 return $alterTableSql;
2280 function executeConvertTablesSql($tables)
2284 foreach($tables as $table){
2285 $query = "ALTER TABLE " . $table . " CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci";
2287 logThis("Sending query: ".$query);
2288 $db->query($query);//, true, "An error has occured while performing db query. See log file for details.<br>");
2294 function testThis() {
2295 $files = uwFindAllFiles(getcwd().'/test', array());
2297 $out = "<table cellpadding='1' cellspacing='0' border='0'>\n";
2300 foreach($files as $file) {
2301 $relativeFile = clean_path(str_replace(getcwd().'/test', '', $file));
2302 $relativeFile = ($relativeFile{0} == '/') ? substr($relativeFile, 1, strlen($relativeFile)) : $relativeFile;
2304 $relativePath = dirname($relativeFile);
2306 if($relativePath == $priorPath) { // same dir, new file
2307 $out .= "<tr><td>".basename($relativeFile)."</td></tr>";
2308 $priorPath = $relativePath;
2322 function testThis2($dir, $id=0, $hide=false) {
2323 global $mod_strings;
2325 $dh = opendir($dir);
2328 $doHide = ($hide) ? 'none' : '';
2329 $out = "<div id='{$id}' style='display:{$doHide};'>";
2330 $out .= "<table cellpadding='1' cellspacing='0' style='border:0px solid #ccc'>\n";
2332 while($file = readdir($dh)) {
2333 if($file == '.' || $file == '..' || $file == 'CVS' || $file == '.cvsignore')
2336 if(is_dir($path.'/'.$file)) {
2337 $file = $path.'/'.$file;
2338 $newI = create_guid();
2339 $out .= "<tr><td valign='top'><a href='javascript:toggleNwFiles(\"{$newI}\");'>".SugarThemeRegistry::current()->getImage("Workflow", "", null, null, ".gif", $mod_strings['LBL_WORKFLOW'])."</a></td>\n";
2340 $out .= "<td valign='top'><b><a href='javascript:toggleNwFiles(\"{$newI}\");'>".basename($file)."</a></b></td></tr>";
2341 $out .= "<tr><td></td><td valign='top'>".testThis2($file, $newI, true)."</td></tr>";
2343 $out .= "<tr><td valign='top'> </td>\n";
2344 $out .= "<td valign='top'>".basename($file)."</td></tr>";
2348 $out .= "</tr></table>";
2359 function testThis3(&$files, $id, $hide, $previousPath = '') {
2360 if(!is_array($files) || empty($files))
2365 global $mod_strings;
2366 // expecting full path here
2367 foreach($files as $k => $file) {
2368 $file = str_replace(getcwd(), '', $file);
2369 $path = dirname($file);
2370 $fileName = basename($file);
2372 if($fileName == 'CVS' || $fileName == '.cvsignore')
2375 if($path == $previousPath) { // same directory
2376 // new row for each file
2377 $out .= "<tr><td valign='top' align='left'> </td>";
2378 $out .= "<td valign='top' align='left'>{$fileName}</td></tr>";
2379 } else { // new directory
2381 $out .= "<tr><td valign='top'><a href='javascript:toggleNwFiles(\"{$newI}\");'>".SugarThemeRegistry::current()->getImage("Workflow", "", null, null, ".gif", $mod_strings['LBL_WORKFLOW'])."</a></td>\n";
2382 $out .= "<td valign='top'><b><a href='javascript:toggleNwFiles(\"{$newI}\");'>".$fileName."</a></b></td></tr>";
2383 $recurse = testThis3($files, $newI, true, $previousPath);
2384 $out .= "<tr><td></td><td valign='top'>".$recurse."</td></tr>";
2387 $previousPath = $path;
2389 $display = ($hide) ? 'none' : '';
2391 <div id="{$id}" style="display:{$display}">
2392 <table cellpadding='1' cellspacing='0' border='0' style='border:1px solid #ccc'>
2401 function testThis4($filePath, $fileNodes=array(), $fileName='') {
2402 $path = dirname($filePath);
2403 $file = basename($filePath);
2405 $exFile = explode('/', $path);
2407 foreach($exFile as $pathSegment) {
2408 if(is_array($fileNodes[$pathSegment])) { // path already processed
2410 } else { // newly found path
2411 $fileNodes[$pathSegment] = array();
2414 if($fileName != '') {
2415 $fileNodes[$pathSegment][] = $fileName;
2424 ///////////////////////////////////////////////////////////////////////////////
2425 //// SYSTEM CHECK FUNCTIONS
2427 * generates an array with all files in the SugarCRM root directory, skipping
2429 * @return array files Array of files with absolute paths
2431 function getFilesForPermsCheck() {
2432 global $sugar_config;
2434 logThis('Got JSON call to find all files...');
2435 $filesNotWritable = array();
2436 $filesNWPerms = array();
2438 // add directories here that should be skipped when doing file permissions checks (cache/upload is the nasty one)
2440 $sugar_config['upload_dir'],
2442 $files = uwFindAllFiles(".", array(), true, $skipDirs, true);
2447 * checks files for permissions
2448 * @param array files Array of files with absolute paths
2449 * @return string result of check
2451 function checkFiles($files, $echo=false) {
2452 global $mod_strings;
2453 $filesNotWritable = array();
2456 <a href='javascript:void(0); toggleNwFiles(\"filesNw\");'>{$mod_strings['LBL_UW_SHOW_NW_FILES']}</a>
2457 <div id='filesNw' style='display:none;'>
2458 <table cellpadding='3' cellspacing='0' border='0'>
2460 <th align='left'>{$mod_strings['LBL_UW_FILE']}</th>
2461 <th align='left'>{$mod_strings['LBL_UW_FILE_PERMS']}</th>
2462 <th align='left'>{$mod_strings['LBL_UW_FILE_OWNER']}</th>
2463 <th align='left'>{$mod_strings['LBL_UW_FILE_GROUP']}</th>
2466 $isWindows = is_windows();
2467 foreach($files as $file) {
2470 if(!is_writable_windows($file)) {
2471 logThis('WINDOWS: File ['.$file.'] not readable - saving for display');
2472 // don't warn yet - we're going to use this to check against replacement files
2473 // aw: commented out; it's a hack to allow upgrade wizard to continue on windows... will fix later
2474 /*$filesNotWritable[$i] = $file;
2475 $filesNWPerms[$i] = substr(sprintf('%o',fileperms($file)), -4);
2476 $filesOut .= "<tr>".
2477 "<td><span class='error'>{$file}</span></td>".
2478 "<td>{$filesNWPerms[$i]}</td>".
2479 "<td>".$mod_strings['ERR_UW_CANNOT_DETERMINE_USER']."</td>".
2480 "<td>".$mod_strings['ERR_UW_CANNOT_DETERMINE_GROUP']."</td>".
2484 if(!is_writable($file)) {
2485 logThis('File ['.$file.'] not writable - saving for display');
2486 // don't warn yet - we're going to use this to check against replacement files
2487 $filesNotWritable[$i] = $file;
2488 $filesNWPerms[$i] = substr(sprintf('%o',fileperms($file)), -4);
2489 $owner = posix_getpwuid(fileowner($file));
2490 $group = posix_getgrgid(filegroup($file));
2491 $filesOut .= "<tr>".
2492 "<td><span class='error'>{$file}</span></td>".
2493 "<td>{$filesNWPerms[$i]}</td>".
2494 "<td>".$owner['name']."</td>".
2495 "<td>".$group['name']."</td>".
2502 $filesOut .= '</table></div>';
2504 $errors['files']['filesNotWritable'] = (count($filesNotWritable) > 0) ? true : false;
2505 if(count($filesNotWritable) < 1) {
2506 $filesOut = "{$mod_strings['LBL_UW_FILE_NO_ERRORS']}";
2512 function deletePackageOnCancel(){
2513 global $mod_strings;
2514 global $sugar_config;
2515 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
2516 logThis('running delete');
2517 if(!isset($_SESSION['install_file']) || ($_SESSION['install_file'] == "")) {
2518 logThis('ERROR: trying to delete non-existent file: ['.$_REQUEST['install_file'].']');
2519 $error = $mod_strings['ERR_UW_NO_FILE_UPLOADED'];
2521 // delete file in upgrades/patch
2522 $delete_me = "$base_upgrade_dir/patch/".basename(urldecode( $_REQUEST['install_file'] ));
2523 if(@unlink($delete_me)) {
2524 //logThis('unlinking: '.$delete_me);
2525 $out = basename($delete_me).$mod_strings['LBL_UW_FILE_DELETED'];
2527 logThis('ERROR: could not delete ['.$delete_me.']');
2528 $error = $mod_strings['ERR_UW_FILE_NOT_DELETED'].$delete_me;
2531 if(!empty($error)) {
2532 $out = "<b><span class='error'>{$error}</span></b><br />";
2536 function handleExecuteSqlKeys($db, $tableName, $disable)
2538 if(empty($tableName)) return true;
2539 if(is_callable(array($db, "supports"))) {
2541 return $disable?$db->disableKeys($tableName):$db->enableKeys($tableName);
2544 $op = $disable?"DISABLE":"ENABLE";
2545 return $db->query("ALTER TABLE $tableName $op KEYS");
2549 function parseAndExecuteSqlFile($sqlScript,$forStepQuery='',$resumeFromQuery='')
2551 global $sugar_config;
2552 $alterTableSchema = '';
2553 $sqlErrors = array();
2554 if(!isset($_SESSION['sqlSkippedQueries'])){
2555 $_SESSION['sqlSkippedQueries'] = array();
2557 $db = DBManagerFactory::getInstance();
2558 $disable_keys = ($db->dbType == "mysql"); // have to use old way for now for upgrades
2559 if(strpos($resumeFromQuery,",") != false){
2560 $resumeFromQuery = explode(",",$resumeFromQuery);
2562 if(file_exists($sqlScript)) {
2563 $fp = fopen($sqlScript, 'r');
2564 $contents = stream_get_contents($fp);
2565 $anyScriptChanges =$contents;
2566 $resumeAfterFound = false;
2570 while($line = fgets($fp)) {
2571 if(strpos($line, '--') === false) {
2572 $completeLine .= " ".trim($line);
2573 if(strpos($line, ';') !== false) {
2575 $query = str_replace(';','',$completeLine);
2576 //if resume from query is not null then find out from where
2577 //it should start executing the query.
2579 if($query != null && $resumeFromQuery != null){
2580 if(!$resumeAfterFound){
2581 if(strpos($query,",") != false){
2582 $queArray = explode(",",$query);
2583 for($i=0;$i<sizeof($resumeFromQuery);$i++){
2584 if(strcasecmp(trim($resumeFromQuery[$i]),trim($queArray[$i]))==0){
2585 $resumeAfterFound = true;
2587 $resumeAfterFound = false;
2593 elseif(strcasecmp(trim($resumeFromQuery),trim($query))==0){
2594 $resumeAfterFound = true;
2597 if($resumeAfterFound){
2600 // if $count=1 means it is just found so skip the query. Run the next one
2601 if($query != null && $resumeAfterFound && $count >1){
2602 $tableName = getAlterTable($query);
2605 handleExecuteSqlKeys($db, $tableName, true);
2608 if($db->checkError()){
2609 //put in the array to use later on
2610 $_SESSION['sqlSkippedQueries'][] = $query;
2614 handleExecuteSqlKeys($db, $tableName, false);
2616 $progQuery[$forStepQuery]=$query;
2617 post_install_progress($progQuery,$action='set');
2620 elseif($query != null){
2621 $tableName = getAlterTable($query);
2624 handleExecuteSqlKeys($db, $tableName, true);
2629 handleExecuteSqlKeys($db, $tableName, false);
2631 $progQuery[$forStepQuery]=$query;
2632 post_install_progress($progQuery,$action='set');
2633 if($db->checkError()){
2634 //put in the array to use later on
2635 $_SESSION['sqlSkippedQueries'][] = $query;
2647 function getAlterTable($query){
2648 $query = strtolower($query);
2649 if (preg_match('/^\s*alter\s+table\s+/', $query)) {
2650 $sqlArray = explode(" ", $query);
2651 $key = array_search('table', $sqlArray);
2652 return $sqlArray[($key+1)];
2658 function set_upgrade_vars(){
2659 logThis('setting session variables...');
2660 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2661 if(!is_dir($upgrade_progress_dir)){
2662 mkdir_recursive($upgrade_progress_dir);
2664 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2665 if(file_exists($upgrade_progress_file)){
2666 include($upgrade_progress_file);
2669 fopen($upgrade_progress_file, 'w+');
2671 if(!isset($upgrade_config) || $upgrade_config == null){
2672 $upgrade_config = array();
2673 $upgrade_config[1]['upgrade_vars']=array();
2675 if(isset($upgrade_config[1]) && isset($upgrade_config[1]['upgrade_vars']) && !is_array($upgrade_config[1]['upgrade_vars'])){
2676 $upgrade_config[1]['upgrade_vars'] = array();
2679 if(!isset($upgrade_vars) || $upgrade_vars == NULL){
2680 $upgrade_vars = array();
2682 if(isset($_SESSION['unzip_dir']) && !empty($_SESSION['unzip_dir']) && file_exists($_SESSION['unzip_dir'])){
2683 $upgrade_vars['unzip_dir']=$_SESSION['unzip_dir'];
2685 if(isset($_SESSION['install_file']) && !empty($_SESSION['install_file']) && file_exists($_SESSION['install_file'])){
2686 $upgrade_vars['install_file']=$_SESSION['install_file'];
2688 if(isset($_SESSION['Upgraded451Wizard']) && !empty($_SESSION['Upgraded451Wizard'])){
2689 $upgrade_vars['Upgraded451Wizard']=$_SESSION['Upgraded451Wizard'];
2691 if(isset($_SESSION['license_shown']) && !empty($_SESSION['license_shown'])){
2692 $upgrade_vars['license_shown']=$_SESSION['license_shown'];
2694 if(isset($_SESSION['Initial_451to500_Step']) && !empty($_SESSION['Initial_451to500_Step'])){
2695 $upgrade_vars['Initial_451to500_Step']=$_SESSION['Initial_451to500_Step'];
2697 if(isset($_SESSION['zip_from_dir']) && !empty($_SESSION['zip_from_dir'])){
2698 $upgrade_vars['zip_from_dir']=$_SESSION['zip_from_dir'];
2700 //place into the upgrade_config array and rewrite config array only if new values are being inserted
2701 if(isset($upgrade_vars) && $upgrade_vars != null && sizeof($upgrade_vars) > 0){
2702 foreach($upgrade_vars as $key=>$val){
2703 if($key != null && $val != null){
2704 $upgrade_config[1]['upgrade_vars'][$key]=$upgrade_vars[$key];
2707 ksort($upgrade_config);
2708 if(is_writable($upgrade_progress_file) && write_array_to_file( "upgrade_config", $upgrade_config,
2709 $upgrade_progress_file)) {
2710 //writing to the file
2715 function initialize_session_vars(){
2716 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2717 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2718 if(file_exists($upgrade_progress_file)){
2719 include($upgrade_progress_file);
2720 if(isset($upgrade_config) && $upgrade_config != null && is_array($upgrade_config) && sizeof($upgrade_config) >0){
2721 $currVarsArray=$upgrade_config[1]['upgrade_vars'];
2722 //print_r($currVarsArray);
2723 if(isset($currVarsArray) && $currVarsArray != null && is_array($currVarsArray) && sizeof($currVarsArray)>0){
2724 foreach($currVarsArray as $key=>$val){
2725 if($key != null && $val !=null){
2726 //set session variables
2727 $_SESSION[$key]=$val;
2736 //track the upgrade progress on each step
2737 //track the upgrade progress on each step
2738 function set_upgrade_progress($currStep,$currState,$currStepSub='',$currStepSubState=''){
2740 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2741 if(!is_dir($upgrade_progress_dir)){
2742 mkdir_recursive($upgrade_progress_dir);
2744 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2745 if(file_exists($upgrade_progress_file)){
2746 include($upgrade_progress_file);
2749 if(function_exists('sugar_fopen')){
2750 sugar_fopen($upgrade_progress_file, 'w+');
2753 fopen($upgrade_progress_file, 'w+');
2756 if(!isset($upgrade_config) || $upgrade_config == null){
2757 $upgrade_config = array();
2758 $upgrade_config[1]['upgrade_vars']=array();
2760 if(!is_array($upgrade_config[1]['upgrade_vars'])){
2761 $upgrade_config[1]['upgrade_vars'] = array();
2763 if($currStep != null && $currState != null){
2764 if(sizeof($upgrade_config) > 0){
2765 if($currStepSub != null && $currStepSubState !=null){
2766 //check if new status to be set or update
2767 //get the latest in array. since it has sub components prepare an array
2768 if(!empty($upgrade_config[sizeof($upgrade_config)][$currStep]) && is_array($upgrade_config[sizeof($upgrade_config)][$currStep])){
2769 $latestStepSub = currSubStep($upgrade_config[sizeof($upgrade_config)][$currStep]);
2770 if($latestStepSub == $currStepSub){
2771 $upgrade_config[sizeof($upgrade_config)][$currStep][$latestStepSub]=$currStepSubState;
2772 $upgrade_config[sizeof($upgrade_config)][$currStep][$currStep] = $currState;
2775 $upgrade_config[sizeof($upgrade_config)][$currStep][$currStepSub]=$currStepSubState;
2776 $upgrade_config[sizeof($upgrade_config)][$currStep][$currStep] = $currState;
2780 $currArray = array();
2781 $currArray[$currStep] = $currState;
2782 $currArray[$currStepSub] = $currStepSubState;
2783 $upgrade_config[sizeof($upgrade_config)+1][$currStep] = $currArray;
2787 //get the current upgrade progress
2788 $latestStep = get_upgrade_progress();
2789 //set the upgrade progress
2790 if($latestStep == $currStep){
2791 //update the current step with new progress status
2792 $upgrade_config[sizeof($upgrade_config)][$latestStep]=$currState;
2796 $upgrade_config[sizeof($upgrade_config)+1][$currStep]=$currState;
2798 // now check if there elements within array substeps
2802 //set the upgrade progress (just starting)
2803 $upgrade_config[sizeof($upgrade_config)+1][$currStep]= $currState;
2806 if(is_writable($upgrade_progress_file) && write_array_to_file( "upgrade_config", $upgrade_config,
2807 $upgrade_progress_file)) {
2808 //writing to the file
2814 function get_upgrade_progress(){
2815 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2816 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2819 if(file_exists($upgrade_progress_file)){
2820 include($upgrade_progress_file);
2821 if(!isset($upgrade_config) || $upgrade_config == null){
2822 $upgrade_config = array();
2824 if($upgrade_config != null && sizeof($upgrade_config) >1){
2825 $currArr = $upgrade_config[sizeof($upgrade_config)];
2826 if(is_array($currArr)){
2827 foreach($currArr as $key=>$val){
2835 function currSubStep($currStep){
2837 if(is_array($currStep)){
2838 foreach($currStep as $key=>$val){
2846 function currUpgradeState($currState){
2848 if(is_array($currState)){
2849 foreach($currState as $key=>$val){
2851 foreach($val as $k=>$v){
2865 function didThisStepRunBefore($step,$SubStep=''){
2866 if($step == null) return;
2867 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2868 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2871 if(file_exists($upgrade_progress_file)){
2872 include($upgrade_progress_file);
2873 if(isset($upgrade_config) && $upgrade_config != null && is_array($upgrade_config) && sizeof($upgrade_config) >0){
2874 for($i=1;$i<=sizeof($upgrade_config);$i++){
2875 if(is_array($upgrade_config[$i])){
2876 foreach($upgrade_config[$i] as $key=>$val){
2878 if(is_array($upgrade_config[$i][$step])){
2880 foreach ($upgrade_config[$i][$step] as $k=>$v){
2882 foreach($v as $k1=>$v1){
2883 if($SubStep != null){
2884 if($SubStep ==$k1 && $v1=='done'){
2891 elseif($SubStep !=null){
2892 if($SubStep==$k && $v=='done'){
2897 elseif($step==$k && $v=='done'){
2903 elseif($val=='done'){
2917 //get and set post install status
2918 function post_install_progress($progArray='',$action=''){
2919 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2920 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2921 if($action=='' || $action=='get'){
2922 //get the state of post install
2923 $currProg = array();
2924 if(file_exists($upgrade_progress_file)){
2925 include($upgrade_progress_file);
2926 if(is_array($upgrade_config[sizeof($upgrade_config)]['commit']['post_install']) && sizeof($upgrade_config[sizeof($upgrade_config)]['commit']['post_install'])>0){
2927 foreach($upgrade_config[sizeof($upgrade_config)]['commit']['post_install'] as $k=>$v){
2934 elseif($action=='set'){
2935 if(!is_dir($upgrade_progress_dir)){
2936 mkdir($upgrade_progress_dir);
2938 if(file_exists($upgrade_progress_file)){
2939 include($upgrade_progress_file);
2942 fopen($upgrade_progress_file, 'w+');
2944 if(!is_array($upgrade_config[sizeof($upgrade_config)]['commit']['post_install'])){
2945 $upgrade_config[sizeof($upgrade_config)]['commit']['post_install']=array();
2946 $upgrade_config[sizeof($upgrade_config)]['commit']['post_install']['post_install'] = 'in_progress';
2948 if($progArray != null && is_array($progArray)){
2949 foreach($progArray as $key=>$val){
2950 $upgrade_config[sizeof($upgrade_config)]['commit']['post_install'][$key]=$val;
2953 if(is_writable($upgrade_progress_file) && write_array_to_file( "upgrade_config", $upgrade_config,
2954 $upgrade_progress_file)) {
2955 //writing to the file
2960 function repairDBForUpgrade($execute=false,$path=''){
2962 global $current_user, $beanFiles;
2964 set_time_limit(3600);
2966 $db = &DBManagerFactory::getInstance();
2968 VardefManager::clearVardef();
2969 require_once('include/ListView/ListView.php');
2970 foreach ($beanFiles as $bean => $file) {
2971 require_once ($file);
2972 $focus = new $bean ();
2973 $sql .= $db->repairTable($focus, $execute);
2977 $olddictionary = $dictionary;
2978 unset ($dictionary);
2979 include ('modules/TableDictionary.php');
2980 foreach ($dictionary as $meta) {
2981 $tablename = $meta['table'];
2982 $fielddefs = $meta['fields'];
2983 $indices = $meta['indices'];
2984 $sql .= $db->repairTableParams($tablename, $fielddefs, $indices, $execute);
2987 foreach (explode("\n", $sql) as $line) {
2988 if (!empty ($line) && substr($line, -2) != "*/") {
2991 $qry_str .= $line . "\n";
3002 preg_replace('#(/\*.+?\*/\n*)#', '', $qry_str)
3004 logThis("*******START EXECUTING DB UPGRADE QUERIES***************",$path);
3005 logThis($sql,$path);
3006 logThis("*******END EXECUTING DB UPGRADE QUERIES****************",$path);
3015 * upgradeUserPreferences
3016 * This method updates the user_preferences table and sets the pages/dashlets for users
3017 * which have ACL access to Trackers so that the Tracker dashlets are set in their user perferences
3020 function upgradeUserPreferences() {
3021 global $sugar_config, $sugar_version;
3022 $uw_strings = return_module_language($GLOBALS['current_language'], 'UpgradeWizard');
3024 $localization = new Localization();
3025 $localeCoreDefaults = $localization->getLocaleConfigDefaults();
3027 // check the current system wide default_locale_name_format and add it to the list if it's not there
3028 if(empty($sugar_config['name_formats'])) {
3029 $sugar_config['name_formats'] = $localeCoreDefaults['name_formats'];
3030 if(!rebuildConfigFile($sugar_config, $sugar_version)) {
3031 $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
3035 $currentDefaultLocaleNameFormat = $sugar_config['default_locale_name_format'];
3037 if ($localization->isAllowedNameFormat($currentDefaultLocaleNameFormat)) {
3038 upgradeLocaleNameFormat($currentDefaultLocaleNameFormat);
3040 $sugar_config['default_locale_name_format'] = $localeCoreDefaults['default_locale_name_format'];
3041 if(!rebuildConfigFile($sugar_config, $sugar_version)) {
3042 $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
3044 $localization->createInvalidLocaleNameFormatUpgradeNotice();
3047 $db = &DBManagerFactory::getInstance();
3048 $result = $db->query("SELECT id FROM users where deleted = '0'");
3049 while($row = $db->fetchByAssoc($result))
3051 $current_user = new User();
3052 $current_user->retrieve($row['id']);
3054 // 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
3055 $currentUserNameFormat = $current_user->getPreference('default_locale_name_format');
3056 if ($localization->isAllowedNameFormat($currentUserNameFormat)) {
3057 upgradeLocaleNameFormat($currentUserNameFormat);
3059 $current_user->setPreference('default_locale_name_format', 's f l', 0, 'global');
3060 $current_user->savePreferencesToDB();
3064 if(!$current_user->getPreference('calendar_publish_key')) {
3065 // set publish key if not set already
3066 $current_user->setPreference('calendar_publish_key', create_guid());
3071 // we need to force save the changes to disk, otherwise we lose them.
3074 $current_user->savePreferencesToDB();
3082 * Checks if a locale name format is part of the default list, if not adds it to the config
3083 * @param $name_format string a local name format string such as 's f l'
3084 * @return bool true on successful write to config file, false on failure;
3086 function upgradeLocaleNameFormat($name_format) {
3087 global $sugar_config, $sugar_version;
3089 $localization = new Localization();
3090 $localeConfigDefaults = $localization->getLocaleConfigDefaults();
3092 $uw_strings = return_module_language($GLOBALS['current_language'], 'UpgradeWizard');
3093 if(empty($sugar_config['name_formats'])) {
3094 $sugar_config['name_formats'] = $localeConfigDefaults['name_formats'];
3095 if(!rebuildConfigFile($sugar_config, $sugar_version)) {
3096 $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
3099 if (!in_array($name_format, $sugar_config['name_formats'])) {
3100 $new_config = sugarArrayMerge($sugar_config['name_formats'], array($name_format=>$name_format));
3101 $sugar_config['name_formats'] = $new_config;
3102 if(!rebuildConfigFile($sugar_config, $sugar_version)) {
3103 $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
3112 function add_custom_modules_favorites_search(){
3113 $module_directories = scandir('modules');
3115 foreach($module_directories as $module_dir){
3116 if($module_dir == '.' || $module_dir == '..' || !is_dir("modules/{$module_dir}")){
3121 preg_match('/^[a-z0-9]{1,5}_[a-z0-9_]+$/i' , $module_dir, $matches);
3123 // Make sure the module was created by module builder
3124 if(empty($matches)){
3128 $full_module_dir = "modules/{$module_dir}/";
3129 $read_searchdefs_from = "{$full_module_dir}/metadata/searchdefs.php";
3130 $read_SearchFields_from = "{$full_module_dir}/metadata/SearchFields.php";
3131 $read_custom_SearchFields_from = "custom/{$full_module_dir}/metadata/SearchFields.php";
3133 // Studio can possibly override this file, so we check for a custom version of it
3134 if(file_exists("custom/{$full_module_dir}/metadata/searchdefs.php")){
3135 $read_searchdefs_from = "custom/{$full_module_dir}/metadata/searchdefs.php";
3138 if(file_exists($read_searchdefs_from) && file_exists($read_SearchFields_from)){
3141 require($read_searchdefs_from);
3142 foreach($searchdefs[$module_dir]['layout']['basic_search'] as $sf_array){
3143 if(isset($sf_array['name']) && $sf_array['name'] == 'favorites_only'){
3148 require($read_SearchFields_from);
3149 if(isset($searchFields[$module_dir]['favorites_only'])){
3153 if(!$found_sf1 && !$found_sf2){
3154 $searchdefs[$module_dir]['layout']['basic_search']['favorites_only'] = array('name' => 'favorites_only','label' => 'LBL_FAVORITES_FILTER','type' => 'bool',);
3155 $searchdefs[$module_dir]['layout']['advanced_search']['favorites_only'] = array('name' => 'favorites_only','label' => 'LBL_FAVORITES_FILTER','type' => 'bool',);
3156 $searchFields[$module_dir]['favorites_only'] = array(
3157 'query_type'=>'format',
3158 'operator' => 'subquery',
3159 'subquery' => 'SELECT sugarfavorites.record_id FROM sugarfavorites
3160 WHERE sugarfavorites.deleted=0
3161 and sugarfavorites.module = \''.$module_dir.'\'
3162 and sugarfavorites.assigned_user_id = \'{0}\'',
3163 'db_field'=>array('id')
3166 if(!is_dir("custom/{$full_module_dir}/metadata")){
3167 mkdir_recursive("custom/{$full_module_dir}/metadata");
3169 $success_sf1 = write_array_to_file('searchdefs', $searchdefs, "custom/{$full_module_dir}/metadata/searchdefs.php");
3170 $success_sf2 = write_array_to_file('searchFields', $searchFields, "{$full_module_dir}/metadata/SearchFields.php");
3173 logThis("add_custom_modules_favorites_search failed for searchdefs.php for {$module_dir}");
3176 logThis("add_custom_modules_favorites_search failed for SearchFields.php for {$module_dir}");
3178 if($success_sf1 && $success_sf2){
3179 logThis("add_custom_modules_favorites_search successfully updated searchdefs and searchFields for {$module_dir}");
3188 * upgradeModulesForTeamsets
3190 * This method adds the team_set_id values to the module tables that have the new team_set_id column
3191 * added through the SugarCRM 5.5.x upgrade process. It also adds the values into the team_sets and
3192 * team_sets_teams tables.
3194 * @param filter Array of modules to process; empty by default
3196 function upgradeModulesForTeamsets($filter=array()) {
3197 require('include/modules.php');
3198 foreach($beanList as $moduleName=>$beanName) {
3199 if(!empty($filter) && array_search($moduleName, $filter) === false) {
3202 if($moduleName == 'TeamMemberships' || $moduleName == 'ForecastOpportunities'){
3205 $bean = loadBean($moduleName);
3207 empty($bean->table_name)) {
3211 $FieldArray = $GLOBALS['db']->helper->get_columns($bean->table_name);
3212 if(!isset($FieldArray['team_id'])) {
3216 upgradeTeamColumn($bean, 'team_id');
3220 //Upgrade users table
3221 $bean = loadBean('Users');
3222 upgradeTeamColumn($bean, 'default_team');
3223 $result = $GLOBALS['db']->query("SELECT id FROM teams where deleted=0");
3224 while($row = $GLOBALS['db']->fetchByAssoc($result)) {
3225 $teamset = new TeamSet();
3226 $teamset->addTeams($row['id']);
3233 * Helper function to create a team_set_id column and also set team_set_id column
3234 * to have the value of the $column_name parameter
3236 * @param $bean SugarBean which we are adding team_set_id column to
3237 * @param $column_name The name of the column containing the default team_set_id value
3239 function upgradeTeamColumn($bean, $column_name) {
3240 //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
3241 //module that does not use the SugarObjects
3242 if(empty($bean->field_defs['team_set_id']) && $bean->module_dir != 'Trackers'){
3244 //at this point we could assume that since we have a team_id defined and not a team_set_id that we need to
3245 //add that field and the corresponding relationships
3246 $object = $bean->object_name;
3247 $module = $bean->module_dir;
3248 $object_name = $object;
3249 $_object_name = strtolower($object_name);
3251 if(!empty($GLOBALS['dictionary'][$object]['table'])){
3252 $table_name = $GLOBALS['dictionary'][$object]['table'];
3254 $table_name = strtolower($module);
3257 $path = 'include/SugarObjects/implements/team_security/vardefs.php';
3259 //go through each entry in the vardefs from team_security and unset anything that is already set in the core module
3260 //this will ensure we have the proper ordering.
3261 $fieldDiff = array_diff_assoc($vardefs['fields'], $GLOBALS['dictionary'][$bean->object_name]['fields']);
3263 $file = 'custom/Extension/modules/' . $bean->module_dir. '/Ext/Vardefs/teams.php';
3264 $contents = "<?php\n";
3265 if(!empty($fieldDiff)){
3266 foreach($fieldDiff as $key => $val){
3267 $contents .= "\n\$GLOBALS['dictionary']['". $object . "']['fields']['". $key . "']=" . var_export_helper($val) . ";";
3270 $relationshipDiff = array_diff_assoc($vardefs['relationships'], $GLOBALS['dictionary'][$bean->object_name]['relationships']);
3271 if(!empty($relationshipDiff)){
3272 foreach($relationshipDiff as $key => $val){
3273 $contents .= "\n\$GLOBALS['dictionary']['". $object . "']['relationships']['". $key . "']=" . var_export_helper($val) . ";";
3276 $indexDiff = array_diff_assoc($vardefs['indices'], $GLOBALS['dictionary'][$bean->object_name]['indices']);
3277 if(!empty($indexDiff)){
3278 foreach($indexDiff as $key => $val){
3279 $contents .= "\n\$GLOBALS['dictionary']['". $object . "']['indices']['". $key . "']=" . var_export_helper($val) . ";";
3282 if( $fh = @sugar_fopen( $file, 'wt' ) )
3284 fputs( $fh, $contents);
3289 //we have written out the teams.php into custom/Extension/modules/{$module_dir}/Ext/Vardefs/teams.php'
3290 //now let's merge back into vardefs.ext.php
3291 require_once('ModuleInstall/ModuleInstaller.php');
3292 $mi = new ModuleInstaller();
3293 $mi->merge_files('Ext/Vardefs/', 'vardefs.ext.php');
3294 VardefManager::loadVardef($bean->module_dir, $bean->object_name, true);
3295 $bean->field_defs = $GLOBALS['dictionary'][$bean->object_name]['fields'];
3298 if(isset($bean->field_defs['team_set_id'])) {
3299 //Create the team_set_id column
3300 $FieldArray = $GLOBALS['db']->helper->get_columns($bean->table_name);
3301 if(!isset($FieldArray['team_set_id'])) {
3302 $GLOBALS['db']->addColumn($bean->table_name, $bean->field_defs['team_set_id']);
3304 $indexArray = $GLOBALS['db']->helper->get_indices($bean->table_name);
3306 $indexName = getValidDBName('idx_'.strtolower($bean->table_name).'_tmst_id', true, 34);
3309 'name' => $indexName,
3311 'fields' => array('team_set_id')
3314 if(!isset($indexArray[$indexName])) {
3315 $GLOBALS['db']->addIndexes($bean->table_name, $indexDef);
3318 //Update the table's team_set_id column to have the same values as team_id
3319 $GLOBALS['db']->query("UPDATE {$bean->table_name} SET team_set_id = {$column_name}");
3324 * Update the folder subscription table which confirms to the team security mechanism but
3325 * the class SugarFolders does not extend SugarBean and is therefore never picked up by the
3326 * upgradeModulesForTeamsets function.
3328 function upgradeFolderSubscriptionsTeamSetId()
3330 logThis("In upgradeFolderSubscriptionsTeamSetId()");
3331 $query = "UPDATE folders SET team_set_id = team_id";
3332 $result = $GLOBALS['db']->query($query);
3333 logThis("Finished upgradeFolderSubscriptionsTeamSetId()");
3337 * upgradeModulesForTeam
3339 * This method update the associated_user_id, name, name_2 to the private team records on teams table
3340 * This function is used for upgrade process from 5.1.x and 5.2.x.
3343 function upgradeModulesForTeam() {
3344 logThis("In upgradeModulesForTeam()");
3345 $result = $GLOBALS['db']->query("SELECT id, user_name, first_name, last_name FROM users where deleted=0");
3347 while($row = $GLOBALS['db']->fetchByAssoc($result)) {
3348 $results2 = $GLOBALS['db']->query("SELECT id FROM teams WHERE name = '({$row['user_name']})'");
3350 if(!$assoc = $GLOBALS['db']->fetchByAssoc($results2)) {
3351 //if team does not exist, then lets create the team for this user
3354 $user->retrieve($row['id']);
3355 $team->new_user_created($user);
3356 $team_id = $team->id;
3358 $team_id =$assoc['id'];
3362 $name = is_null($row['first_name'])?'':$row['first_name'];
3363 $name_2 = is_null($row['last_name'])?'':$row['last_name'];
3364 $associated_user_id = $row['id'];
3367 //Ensure team->name is not empty by using team->name_2 if available
3368 if(empty($name) && !empty($name_2)) {
3373 $query = "UPDATE teams SET name = '{$name}', name_2 = '{$name_2}', associated_user_id = '{$associated_user_id}' WHERE id = '{$team_id}'";
3374 $GLOBALS['db']->query($query);
3377 //Update the team_set_id and default_team columns
3378 $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'));
3380 //Update team_set_id
3381 if($ce_to_pro_or_ent) {
3382 $GLOBALS['db']->query("update users set team_set_id = (select teams.id from teams where teams.associated_user_id = users.id)");
3383 $GLOBALS['db']->query("update users set default_team = (select teams.id from teams where teams.associated_user_id = users.id)");
3389 function addNewSystemTabsFromUpgrade($from_dir){
3391 if(isset($_SESSION['upgrade_from_flavor'])){
3393 //check to see if there are any new files that need to be added to systems tab
3394 //retrieve old modules list
3395 logThis('check to see if new modules exist',$path);
3396 $oldModuleList = array();
3397 $newModuleList = array();
3398 include($from_dir.'/include/modules.php');
3399 $oldModuleList = $moduleList;
3400 include('include/modules.php');
3401 $newModuleList = $moduleList;
3403 //include tab controller
3404 require_once('modules/MySettings/TabController.php');
3405 $newTB = new TabController();
3407 //make sure new modules list has a key we can reference directly
3408 $newModuleList = $newTB->get_key_array($newModuleList);
3409 $oldModuleList = $newTB->get_key_array($oldModuleList);
3411 //iterate through list and remove commonalities to get new modules
3412 foreach ($newModuleList as $remove_mod){
3413 if(in_array($remove_mod, $oldModuleList)){
3414 unset($newModuleList[$remove_mod]);
3417 //new modules list now has left over modules which are new to this install, so lets add them to the system tabs
3418 logThis('new modules to add are '.var_export($newModuleList,true),$path);
3420 if(!empty($newModuleList))
3422 //grab the existing system tabs
3423 $tabs = $newTB->get_system_tabs();
3425 //add the new tabs to the array
3426 foreach($newModuleList as $nm ){
3430 $newTB->set_system_tabs($tabs);
3432 logThis('module tabs updated',$path);
3438 * This method attempts to fix dropdown lists that were incorrectly named.
3439 * There were versions of SugarCRM that did not enforce naming convention rules
3440 * for the dropdown list field name. This method attempts to resolve that by
3441 * fixing the language files that may have been affected and then updating the
3442 * fields_meta_data table accordingly. It also refreshes any vardefs that may
3443 * have been affected.
3446 function fix_dropdown_list() {
3447 if(file_exists('custom/include/language')) {
3449 $affected_modules = array();
3450 $affected_keys = array();
3452 getFiles($files, 'custom/include/language', '/\.php$/i');
3453 foreach($files as $file) {
3455 if(file_exists($file . '.bak')) {
3456 $bak_mod_time = filemtime($file . '.bak');
3457 $php_mod_time = filemtime($file);
3458 //We're saying if the .php file was modified 30 seconds no more than php.bak file then we
3459 //run these additional cleanup checks
3460 if($php_mod_time - $bak_mod_time < 30) {
3462 $app_list_strings = array();
3463 $GLOBALS['app_list_strings'] = array();
3464 require($file . '.bak');
3465 $bak_app_list_strings = array_merge($app_list_strings, $GLOBALS['app_list_strings']);
3467 $app_list_strings = array();
3468 $GLOBALS['app_list_strings'] = array();
3470 $php_app_list_strings = array_merge($app_list_strings, $GLOBALS['app_list_strings']);
3472 //Get the file contents
3473 $contents = file_get_contents($file);
3475 //Now simulate a fix for the file before we compare w/ the .php file
3476 //we also append to the $contents
3477 foreach($bak_app_list_strings as $key=>$entry) {
3478 if(preg_match('/([^A-Za-z_])/', $key, $matches) && is_array($entry)) {
3479 $new_key = preg_replace('/[^A-Za-z_]/', '_', $key);
3480 $bak_app_list_strings[$new_key] = $bak_app_list_strings[$key];
3481 unset($bak_app_list_strings[$key]);
3482 //Now if the entry doesn't exists in the .php file, then add to contents
3483 if(!isset($php_app_list_strings[$new_key])) {
3484 $contents .= "\n\$GLOBALS['app_list_strings']['{$new_key}'] = " . var_export_helper($bak_app_list_strings[$new_key]) . ";";
3489 //Now load the .php file to do the comparison
3490 foreach($php_app_list_strings as $key=>$entry) {
3491 if(isset($bak_app_list_strings[$key])) {
3492 $diff = array_diff($bak_app_list_strings[$key], $entry);
3494 //There is a difference, so copy the $bak_app_list_strings version into the .php file
3495 $contents .= "\n\$GLOBALS['app_list_strings']['{$key}'] = " . var_export_helper($bak_app_list_strings[$key]) . ";";
3500 //Now write out the file contents
3501 //Create backup just in case
3502 copy($file, $file . '.php_bak');
3503 $fp = @sugar_fopen($file, 'w');
3505 fwrite($fp, $contents);
3508 $GLOBALS['log']->error("Unable to update file contents in fix_dropdown_list for {$file}");
3513 unset($GLOBALS['app_strings']);
3514 unset($GLOBALS['app_list_strings']);
3515 $app_list_strings = array();
3518 $contents = file_get_contents($file);
3519 if ( !isset($GLOBALS['app_list_strings']) ) {
3520 $GLOBALS['app_list_strings'] = $app_list_strings;
3523 $GLOBALS['app_list_strings'] = array_merge($app_list_strings, $GLOBALS['app_list_strings']);
3526 if(isset($GLOBALS['app_list_strings']) && is_array($GLOBALS['app_list_strings'])) {
3527 foreach($GLOBALS['app_list_strings'] as $key=>$entry) {
3528 if(preg_match('/([^A-Za-z_])/', $key, $matches) && is_array($entry)) {
3529 $result = $GLOBALS['db']->query("SELECT custom_module FROM fields_meta_data WHERE ext1 = '{$key}'");
3530 if(!empty($result)) {
3531 while($row = $GLOBALS['db']->fetchByAssoc($result)) {
3532 $custom_module = $row['custom_module'];
3533 if(!empty($GLOBALS['beanList'][$custom_module])) {
3534 $affected_modules[$custom_module] = $GLOBALS['beanList'][$custom_module];
3539 //Replace all invalid characters with '_' character
3540 $new_key = preg_replace('/[^A-Za-z_]/', '_', $key);
3541 $affected_keys[$key] = $new_key;
3543 $GLOBALS['app_list_strings'][$new_key] = $GLOBALS['app_list_strings'][$key];
3544 unset($GLOBALS['app_list_strings'][$key]);
3546 $pattern_match = "/(\[\s*\'{$key}\'\s*\])/";
3547 $new_key = "['{$new_key}']";
3548 $out = preg_replace($pattern_match, $new_key, $contents);
3554 //This is a check for g => h instances where the file contents were incorrectly written
3555 //and also fixes the scenario where via a UI upgrade, the app_list_strings were incorrectly
3556 //merged with app_list_strings variables declared elsewhere
3558 if(preg_match('/\$GLOBALS\s*\[\s*[\"|\']app_list_strings[\"|\']\s*\]\s*=\s*array\s*\(/', $contents)) {
3559 //Now also remove all the non-custom labels that were added
3560 if(preg_match('/language\/([^\.]+)\.lang\.php$/', $file, $matches)) {
3561 $language = $matches[1];
3563 $app_list_strings = array();
3565 if(file_exists("include/language/$language.lang.php")) {
3566 include("include/language/$language.lang.php");
3568 if(file_exists("include/language/$language.lang.override.php")) {
3569 $app_list_strings = _mergeCustomAppListStrings("include/language/$language.lang.override.php" , $app_list_strings) ;
3571 if(file_exists("custom/application/Ext/Language/$language.ext.lang.php")) {
3572 $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$language.ext.lang.php" , $app_list_strings) ;
3574 if(file_exists("custom/application/Ext/Language/$language.lang.ext.php")) {
3575 $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$language.lang.ext.php" , $app_list_strings) ;
3578 $all_non_custom_include_language_strings = $app_strings;
3579 $all_non_custom_include_language_list_strings = $app_list_strings;
3581 $unset_keys = array();
3582 if(!empty($GLOBALS['app_list_strings'])) {
3583 foreach($GLOBALS['app_list_strings'] as $key=>$value) {
3585 if(isset($all_non_custom_include_language_list_strings[$key])) {
3586 $diff = array_diff($all_non_custom_include_language_list_strings[$key], $GLOBALS['app_list_strings'][$key]);
3589 if(!empty($all_non_custom_include_language_list_strings[$key]) && empty($diff)) {
3590 $unset_keys[] = $key;
3595 foreach($unset_keys as $key) {
3596 unset($GLOBALS['app_list_strings'][$key]);
3599 if(!empty($GLOBALS['app_strings'])) {
3600 foreach($GLOBALS['app_strings'] as $key=>$value) {
3601 if(!empty($all_non_custom_include_language_strings[$key])) {
3602 unset($GLOBALS['app_strings'][$key]);
3606 } //if(preg_match...)
3609 if(!empty($GLOBALS['app_strings'])) {
3610 foreach($GLOBALS['app_strings'] as $key=>$entry) {
3611 $out .= "\n\$GLOBALS['app_strings']['$key']=" . var_export_helper($entry) . ";";
3615 foreach($GLOBALS['app_list_strings'] as $key=>$entry) {
3616 $out .= "\n\$GLOBALS['app_list_strings']['$key']=" . var_export_helper($entry) . ";";
3620 } //if(preg_match...)
3624 //Create a backup just in case
3625 copy($file, $file . '.bak');
3626 $fp = @sugar_fopen($file, 'w');
3631 //If we can't update the file, just return
3632 $GLOBALS['log']->error("Unable to update file contents in fix_dropdown_list.");
3640 //Update db entries (the order matters here... need to process database changes first)
3641 if(!empty($affected_keys)) {
3642 foreach($affected_keys as $old_key=>$new_key) {
3643 $GLOBALS['db']->query("UPDATE fields_meta_data SET ext1 = '{$new_key}' WHERE ext1 = '{$old_key}'");
3647 //Update vardef files for affected modules
3648 if(!empty($affected_modules)) {
3649 foreach($affected_modules as $module=>$object) {
3650 VardefManager::refreshVardefs($module, $object);
3657 function update_iframe_dashlets(){
3658 require_once(sugar_cached('dashlets/dashlets.php'));
3660 $db = DBManagerFactory::getInstance();
3661 $query = "SELECT id, contents, assigned_user_id FROM user_preferences WHERE deleted = 0 AND category = 'Home'";
3662 $result = $db->query($query, true, "Unable to update new default dashlets! ");
3663 while ($row = $db->fetchByAssoc($result)) {
3664 $content = unserialize(base64_decode($row['contents']));
3665 $assigned_user_id = $row['assigned_user_id'];
3666 $record_id = $row['id'];
3668 $current_user = new User();
3669 $current_user->retrieve($row['assigned_user_id']);
3671 if(!empty($content['dashlets']) && !empty($content['pages'])){
3672 $originalDashlets = $content['dashlets'];
3673 foreach($originalDashlets as $key => $ds){
3674 if(!empty($ds['options']['url']) && stristr($ds['options']['url'],'http://www.sugarcrm.com/crm/product/gopro')){
3675 unset($originalDashlets[$key]);
3678 $current_user->setPreference('dashlets', $originalDashlets, 0, 'Home');
3685 * convertImageToText
3687 * This method attempts to convert date type image to text on Microsoft SQL Server.
3688 * This method could NOT be used in any other type of datebases.
3690 function convertImageToText($table_name,$column_name){
3691 $set_lang = "SET LANGUAGE us_english";
3692 $GLOBALS['db']->query($set_lang);
3693 if($GLOBALS['db']->lastError()){
3694 logThis('An error occurred when performing this query-->'.$set_lang);
3696 $q="SELECT data_type
3697 FROM INFORMATION_SCHEMA.Tables T JOIN INFORMATION_SCHEMA.Columns C
3698 ON T.TABLE_NAME = C.TABLE_NAME where T.TABLE_NAME = '$table_name' and C.COLUMN_NAME = '$column_name'";
3699 $res= $GLOBALS['db']->query($q);
3700 if($GLOBALS['db']->lastError()){
3701 logThis('An error occurred when performing this query-->'.$q);
3703 $row= $GLOBALS['db']->fetchByAssoc($res);
3705 if(trim(strtolower($row['data_type'])) == 'image'){
3706 $addContent_temp = "alter table {$table_name} add {$column_name}_temp text null";
3707 $GLOBALS['db']->query($addContent_temp);
3708 if($GLOBALS['db']->lastError()){
3709 logThis('An error occurred when performing this query-->'.$addContent_temp);
3711 $qN = "select count=datalength({$column_name}), id, {$column_name} from {$table_name}";
3712 $result = $GLOBALS['db']->query($qN);
3713 while($row = $GLOBALS['db']->fetchByAssoc($result)){
3714 if($row['count'] >8000){
3715 $contentLength = $row['count'];
3718 $convertedContent = '';
3719 while($contentLength >0){
3720 $stepsQuery = "select cont=convert(varchar(max), convert(varbinary(8000), substring({$column_name},{$start},{$next}))) from {$table_name} where id= '{$row['id']}'";
3721 $steContQ = $GLOBALS['db']->query($stepsQuery);
3722 if($GLOBALS['db']->lastError()){
3723 logThis('An error occurred when performing this query-->'.$stepsQuery);
3725 $stepCont = $GLOBALS['db']->fetchByAssoc($steContQ);
3726 if(isset($stepCont['cont'])){
3727 $convertedContent = $convertedContent.$stepCont['cont'];
3729 $start = $start+$next;
3730 $contentLength = $contentLength - $next;
3732 $addContentDataText="update {$table_name} set {$column_name}_temp = '{$convertedContent}' where id= '{$row['id']}'";
3733 $GLOBALS['db']->query($addContentDataText);
3734 if($GLOBALS['db']->lastError()){
3735 logThis('An error occurred when performing this query-->'.$addContentDataText);
3739 $addContentDataText="update {$table_name} set {$column_name}_temp =
3740 convert(varchar(max), convert(varbinary(8000), {$column_name})) where id= '{$row['id']}'";
3741 $GLOBALS['db']->query($addContentDataText);
3742 if($GLOBALS['db']->lastError()){
3743 logThis('An error occurred when performing this query-->'.$addContentDataText);
3747 //drop the contents now and change contents_temp to contents
3748 $dropColumn = "alter table {$table_name} drop column {$column_name}";
3749 $GLOBALS['db']->query($dropColumn);
3750 if($GLOBALS['db']->lastError()){
3751 logThis('An error occurred when performing this query-->'.$dropColumn);
3753 $changeColumnName = "EXEC sp_rename '{$table_name}.[{$column_name}_temp]','{$column_name}','COLUMN'";
3754 $GLOBALS['db']->query($changeColumnName);
3755 if($GLOBALS['db']->lastError()){
3756 logThis('An error occurred when performing this query-->'.$changeColumnName);
3763 * This method attempts to delete all English inline help files.
3764 * This method was introduced by 5.5.0RC2.
3766 function clearHelpFiles(){
3767 $modulePath = clean_path(getcwd() . '/modules');
3768 $allHelpFiles = array();
3769 getFiles($allHelpFiles, $modulePath, "/en_us.help.*/");
3771 foreach( $allHelpFiles as $the_file ){
3772 if( is_file( $the_file ) ){
3773 unlink( $the_file );
3774 logThis("Deleted file: $the_file");
3782 * upgradeDateTimeFields
3784 * This method came from bug: 39757 where the date_end field is a date field and not a datetime field
3785 * which prevents you from performing timezone offset calculations once the data has been saved.
3787 * @param path String location to log file, empty by default
3789 function upgradeDateTimeFields($path)
3793 $meetingsSql = "UPDATE meetings SET date_end = ".$db->convert("date_start", 'add_time', array('duration_hours', 'duration_minutes'));
3794 $callsSql = "UPDATE calls SET date_end = ".$db->convert("date_start", 'add_time', array('duration_hours', 'duration_minutes'));
3795 logThis('upgradeDateTimeFields Meetings SQL:' . $meetingsSql, $path);
3796 $db->query($meetingsSql);
3798 logThis('upgradeDateTimeFields Calls SQL:' . $callsSql, $path);
3799 $db->query($callsSql);
3803 * upgradeDocumentTypeFields
3806 function upgradeDocumentTypeFields($path){
3810 $documentsSql = "UPDATE documents SET doc_type = 'Sugar' WHERE doc_type IS NULL";
3811 $meetingsSql = "UPDATE meetings SET type = 'Sugar' WHERE type IS NULL";
3813 logThis('upgradeDocumentTypeFields Documents SQL:' . $documentsSql, $path);
3814 $db->query($documentsSql);
3815 logThis('upgradeDocumentTypeFields Meetings SQL:' . $meetingsSql, $path);
3816 $db->query($meetingsSql);
3821 * merge_config_si_settings
3822 * This method checks for the presence of a config_si.php file and, if found, merges the configuration
3823 * settings from the config_si.php file into config.php. If a config_si_location parameter value is not
3824 * supplied it will attempt to discover the config_si.php file location from where the executing script
3827 * @param write_to_upgrade_log boolean optional value to write to the upgradeWizard.log file
3828 * @param config_location String optional value to config.php file location
3829 * @param config_si_location String optional value to config_si.php file location
3830 * @param path String file of the location of log file to write to
3831 * @return boolean value indicating whether or not a merge was attempted with config_si.php file
3833 function merge_config_si_settings($write_to_upgrade_log=false, $config_location='', $config_si_location='', $path='')
3835 if(!empty($config_location) && !file_exists($config_location))
3837 if($write_to_upgrade_log)
3839 logThis('config.php file specified in ' . $config_si_location . ' could not be found. Skip merging', $path);
3842 } else if(empty($config_location)) {
3844 //We are assuming this is from the silentUpgrade scripts so argv[3] will point to SugarCRM install location
3845 if(isset($argv[3]) && is_dir($argv[3]))
3847 $config_location = $argv[3] . DIRECTORY_SEPARATOR . 'config.php';
3851 //If config_location is still empty or if the file cannot be found, skip merging
3852 if(empty($config_location) || !file_exists($config_location))
3854 if($write_to_upgrade_log)
3856 logThis('config.php file at (' . $config_location . ') could not be found. Skip merging.', $path);
3860 if($write_to_upgrade_log)
3862 logThis('Loading config.php file at (' . $config_location . ') for merging.', $path);
3865 include($config_location);
3866 if(empty($sugar_config))
3868 if($write_to_upgrade_log)
3870 logThis('config.php contents are empty. Skip merging.', $path);
3876 if(!empty($config_si_location) && !file_exists($config_si_location))
3878 if($write_to_upgrade_log)
3880 logThis('config_si.php file specified in ' . $config_si_location . ' could not be found. Skip merging', $path);
3883 } else if(empty($config_si_location)) {
3884 if(isset($argv[0]) && is_file($argv[0]))
3886 $php_file = $argv[0];
3887 $p_info = pathinfo($php_file);
3888 $php_dir = (isset($p_info['dirname']) && $p_info['dirname'] != '.') ? $p_info['dirname'] . DIRECTORY_SEPARATOR : '';
3889 $config_si_location = $php_dir . 'config_si.php';
3893 //If config_si_location is still empty or if the file cannot be found, skip merging
3894 if(empty($config_si_location) || !file_exists($config_si_location))
3896 if($write_to_upgrade_log)
3898 logThis('config_si.php file at (' . $config_si_location . ') could not be found. Skip merging.', $path);
3902 if($write_to_upgrade_log)
3904 logThis('Loading config_si.php file at (' . $config_si_location . ') for merging.', $path);
3907 include($config_si_location);
3908 if(empty($sugar_config_si))
3910 if($write_to_upgrade_log)
3912 logThis('config_si.php contents are empty. Skip merging.', $path);
3918 //Now perform the merge operation
3920 foreach($sugar_config_si as $key=>$value)
3922 if(!preg_match('/^setup_/', $key) && !isset($sugar_config[$key]))
3924 if($write_to_upgrade_log)
3926 logThis('Merge key (' . $key . ') with value (' . $value . ')', $path);
3928 $sugar_config[$key] = $value;
3935 if($write_to_upgrade_log)
3937 logThis('Update config.php file with new values', $path);
3940 if(!write_array_to_file("sugar_config", $sugar_config, $config_location)) {
3941 if($write_to_upgrade_log)
3943 logThis('*** ERROR: could not write to config.php', $path);
3948 if($write_to_upgrade_log)
3950 logThis('config.php values are in sync with config_si.php values. Skipped merging.', $path);
3955 if($write_to_upgrade_log)
3957 logThis('End merge_config_si_settings', $path);
3964 * upgrade_connectors
3966 * This function handles support for upgrading connectors it is invoked from both end.php and silentUpgrade_step2.php
3969 function upgrade_connectors() {
3970 require_once('include/connectors/utils/ConnectorUtils.php');
3971 if(!ConnectorUtils::updateMetaDataFiles()) {
3972 $GLOBALS['log']->fatal('Cannot update metadata files for connectors');
3975 //Delete the custom connectors.php file if it exists so that it may be properly rebuilt
3976 if(file_exists('custom/modules/Connectors/metadata/connectors.php'))
3978 unlink('custom/modules/Connectors/metadata/connectors.php');
3983 * Enable the InsideView connector for the four default modules.
3985 function upgradeEnableInsideViewConnector($path='')
3987 logThis('Begin upgradeEnableInsideViewConnector', $path);
3989 // Load up the existing mapping and hand it to the InsideView connector to have it setup the correct logic hooks
3990 $mapFile = 'modules/Connectors/connectors/sources/ext/rest/insideview/mapping.php';
3991 if ( file_exists('custom/'.$mapFile) ) {
3992 logThis('Found CUSTOM mappings', $path);
3993 require('custom/'.$mapFile);
3995 logThis('Used default mapping', $path);
3999 require_once('include/connectors/sources/SourceFactory.php');
4000 $source = SourceFactory::getSource('ext_rest_insideview');
4002 // $mapping is brought in from the mapping.php file above
4003 $source->saveMappingHook($mapping);
4005 require_once('include/connectors/utils/ConnectorUtils.php');
4006 ConnectorUtils::installSource('ext_rest_insideview');
4008 // Now time to set the various modules to active, because this part ignores the default config
4009 require(CONNECTOR_DISPLAY_CONFIG_FILE);
4010 // $modules_sources come from that config file
4011 foreach ( $source->allowedModuleList as $module ) {
4012 $modules_sources[$module]['ext_rest_insideview'] = 'ext_rest_insideview';
4014 if(!write_array_to_file('modules_sources', $modules_sources, CONNECTOR_DISPLAY_CONFIG_FILE)) {
4015 //Log error and return empty array
4016 logThis("Cannot write \$modules_sources to " . CONNECTOR_DISPLAY_CONFIG_FILE,$path);
4019 logThis('End upgradeEnableInsideViewConnector', $path);
4023 function repair_long_relationship_names($path='')
4025 logThis("Begin repair_long_relationship_names", $path);
4026 require_once 'modules/ModuleBuilder/parsers/relationships/DeployedRelationships.php' ;
4027 $GLOBALS['mi_remove_tables'] = false;
4029 foreach($GLOBALS['moduleList'] as $module)
4031 $relationships = new DeployedRelationships ($module) ;
4032 foreach($relationships->getRelationshipList() as $rel_name)
4034 if (strlen($rel_name) > 27 && empty($touched[$rel_name]))
4036 logThis("Rebuilding relationship fields for $rel_name", $path);
4037 $touched[$rel_name] = true;
4038 $rel_obj = $relationships->get($rel_name);
4039 $rel_obj->setReadonly(false);
4040 $relationships->delete($rel_name);
4041 $relationships->save();
4042 $relationships->add($rel_obj);
4043 $relationships->save();
4044 $relationships->build () ;
4048 logThis("End repair_long_relationship_names", $path);
4051 function removeSilentUpgradeVarsCache(){
4052 global $silent_upgrade_vars_loaded;
4054 $cacheFileDir = "{$GLOBALS['sugar_config']['cache_dir']}/silentUpgrader";
4055 $cacheFile = "{$cacheFileDir}/silentUpgradeCache.php";
4057 if(file_exists($cacheFile)){
4061 $silent_upgrade_vars_loaded = array(); // Set to empty to reset it
4066 function loadSilentUpgradeVars(){
4067 global $silent_upgrade_vars_loaded;
4069 if(empty($silent_upgrade_vars_loaded)){
4070 $cacheFile = "{$GLOBALS['sugar_config']['cache_dir']}/silentUpgrader/silentUpgradeCache.php";
4071 // We have no pre existing vars
4072 if(!file_exists($cacheFile)){
4073 // Set the vars array so it's loaded
4074 $silent_upgrade_vars_loaded = array('vars' => array());
4077 require_once($cacheFile);
4078 $silent_upgrade_vars_loaded = $silent_upgrade_vars_cache;
4085 function writeSilentUpgradeVars(){
4086 global $silent_upgrade_vars_loaded;
4088 if(empty($silent_upgrade_vars_loaded)){
4089 return false; // You should have set some values before trying to write the silent upgrade vars
4092 $cacheFileDir = "{$GLOBALS['sugar_config']['cache_dir']}/silentUpgrader";
4093 $cacheFile = "{$cacheFileDir}/silentUpgradeCache.php";
4095 require_once('include/dir_inc.php');
4096 if(!mkdir_recursive($cacheFileDir)){
4099 require_once('include/utils/file_utils.php');
4100 if(!write_array_to_file('silent_upgrade_vars_cache', $silent_upgrade_vars_loaded, $cacheFile, 'w')){
4102 logThis("WARNING: writeSilentUpgradeVars could not write to {$cacheFile}", $path);
4109 function setSilentUpgradeVar($var, $value){
4110 if(!loadSilentUpgradeVars()){
4114 global $silent_upgrade_vars_loaded;
4116 $silent_upgrade_vars_loaded['vars'][$var] = $value;
4121 function getSilentUpgradeVar($var){
4122 if(!loadSilentUpgradeVars()){
4126 global $silent_upgrade_vars_loaded;
4128 if(!isset($silent_upgrade_vars_loaded['vars'][$var])){
4132 return $silent_upgrade_vars_loaded['vars'][$var];
4138 * add_unified_search_to_custom_modules_vardefs
4140 * This method calls the repair code to remove the unified_search_modules.php fiel
4143 function add_unified_search_to_custom_modules_vardefs()
4145 if(file_exists($cachefile = sugar_cached('modules/unified_search_modules.php')))
4153 * change from using the older SugarCache in 6.1 and below to the new one in 6.2
4155 function upgradeSugarCache($file)
4157 global $sugar_config;
4158 $cacheUploadUpgradesTemp = mk_temp_dir(sugar_cached('upgrades/temp'));
4160 unzip($file, $cacheUploadUpgradesTemp);
4162 if(!file_exists(clean_path("{$cacheUploadUpgradesTemp}/manifest.php"))) {
4163 logThis("*** ERROR: no manifest file detected while bootstraping upgrade wizard files!");
4166 include(clean_path("{$cacheUploadUpgradesTemp}/manifest.php"));
4169 $from_dir = "{$cacheUploadUpgradesTemp}/{$manifest['copy_files']['from_dir']}";
4170 $allFiles = array();
4171 if(file_exists("$from_dir/include/SugarCache")) {
4172 $allFiles = findAllFiles("$from_dir/include/SugarCache", $allFiles);
4174 if(file_exists("$from_dir/include/database")) {
4175 $allFiles = findAllFiles("$from_dir/include/database", $allFiles);
4177 if(file_exists("$from_dir/include/utils/external_cache.php")) {
4178 $allFiles[] = "$from_dir/include/utils/external_cache.php";
4180 if(file_exists("$from_dir/include/utils/sugar_file_utils.php")) {
4181 $allFiles[] = "$from_dir/include/utils/sugar_file_utils.php";
4183 if(file_exists("$from_dir/include/utils/sugar_file_utils.php")) {
4184 $allFiles[] = "$from_dir/include/utils/sugar_file_utils.php";
4186 if(file_exists("$from_dir/include/utils/autoloader.php")) {
4187 $allFiles[] = "$from_dir/include/utils/autoloader.php";
4190 foreach($allFiles as $k => $file) {
4191 $destFile = str_replace($from_dir."/", "", $file);
4192 if(!is_dir(dirname($destFile))) {
4193 mkdir_recursive(dirname($destFile)); // make sure the directory exists
4195 if ( stristr($file,'uw_main.tpl') )
4196 logThis('Skipping "'.$file.'" - file copy will during commit step.');
4198 logThis('updating UpgradeWizard code: '.$destFile);
4199 copy_recursive($file, $destFile);
4205 * unlinkUpgradeFiles
4206 * This is a helper function to clean up
4208 * @param $version String value of current system version (pre upgrade)
4210 function unlinkUpgradeFiles($version)
4212 if(!isset($version))
4217 //First check if we even have the scripts_for_patch/files_to_remove directory
4218 require_once('modules/UpgradeWizard/UpgradeRemoval.php');
4221 if(empty($_SESSION['unzip_dir']))
4223 global $sugar_config;
4224 $base_upgrade_dir = $sugar_config['upload_dir'] . "/upgrades";
4225 $base_tmp_upgrade_dir = "$base_upgrade_dir/temp";
4226 $_SESSION['unzip_dir'] = mk_temp_dir( $base_tmp_upgrade_dir );
4230 if(isset($_SESSION['unzip_dir']) && file_exists($_SESSION['unzip_dir'].'/scripts/files_to_remove'))
4232 $files_to_remove = glob($_SESSION['unzip_dir'].'/scripts/files_to_remove/*.php');
4234 foreach($files_to_remove as $script)
4236 if(preg_match('/UpgradeRemoval(\d+)x\.php/', $script, $matches))
4238 $upgradeClass = 'UpgradeRemoval' . $matches[1] . 'x';
4239 require_once($_SESSION['unzip_dir'].'/scripts/files_to_remove/' . $upgradeClass . '.php');
4240 if (class_exists($upgradeClass) == false)
4245 //Check to make sure we should load and run this UpgradeRemoval instance
4246 $upgradeInstance = new $upgradeClass();
4247 if ($upgradeInstance instanceof UpgradeRemoval && version_compare($upgradeInstance->version, $version, '<='))
4249 logThis('Running UpgradeRemoval instance ' . $upgradeClass);
4250 logThis('Files will be backed up to custom/backup');
4251 $files = $upgradeInstance->getFilesToRemove($version);
4252 foreach($files as $file)
4256 $upgradeInstance->processFilesToRemove($files);
4262 //Check if we have a custom directory
4263 if(file_exists('custom/scripts/files_to_remove'))
4266 $files_to_remove = glob('custom/scripts/files_to_remove/*.php');
4268 foreach($files_to_remove as $script)
4270 if(preg_match('/\/files_to_remove\/(.*?)\.php$/', $script, $matches))
4272 require_once($script);
4273 $upgradeClass = $matches[1];
4275 if(!class_exists($upgradeClass))
4280 $upgradeInstance = new $upgradeClass();
4281 if($upgradeInstance instanceof UpgradeRemoval)
4283 logThis('Running Custom UpgradeRemoval instance ' . $upgradeClass);
4284 $files = $upgradeInstance->getFilesToRemove($version);
4285 foreach($files as $file)
4289 $upgradeInstance->processFilesToRemove($files);
4297 if (!function_exists("getValidDBName"))
4300 * Return a version of $proposed that can be used as a column name in any of our supported databases
4301 * 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)
4302 * @param string $name Proposed name for the column
4303 * @param string $ensureUnique
4304 * @return string Valid column name trimmed to right length and with invalid characters removed
4306 function getValidDBName ($name, $ensureUnique = false, $maxLen = 30)
4308 // first strip any invalid characters - all but alphanumerics and -
4309 $name = preg_replace ( '/[^\w-]+/i', '', $name ) ;
4310 $len = strlen ( $name ) ;
4314 $md5str = md5($name);
4315 $tail = substr ( $name, -11) ;
4316 $temp = substr($md5str , strlen($md5str)-4 );
4317 $result = substr ( $name, 0, 10) . $temp . $tail ;
4318 }else if ($len > ($maxLen - 5))
4320 $result = substr ( $name, 0, 11) . substr ( $name, 11 - $maxLen + 5);
4322 return strtolower ( $result ) ;
4329 * Get UW directories
4330 * Provides compatibility with both 6.3 and pre-6.3 setup
4332 function getUWDirs()
4334 if(!class_exists('UploadStream')) {
4335 // we're still running the old code
4336 global $sugar_config;
4337 return array($sugar_config['upload_dir'] . "/upgrades", $sugar_config['cache_dir'] . "upload/upgrades/temp");
4339 if(!in_array("upload", stream_get_wrappers())) {
4340 UploadStream::register(); // just in case file was copied, but not run
4342 return array("upload://upgrades", sugar_cached("upgrades/temp"));
4347 * Whether directory exists within list of directories to skip
4348 * @param string $dir dir to be checked
4349 * @param array $skipDirs list with skipped dirs
4352 function whetherNeedToSkipDir($dir, $skipDirs)
4354 foreach($skipDirs as $skipMe) {
4355 if(strpos( clean_path($dir), $skipMe ) !== false) {
4365 * @param silentUpgrade boolean flag indicating whether or not we should treat running the SugarSpriteBuilder as an upgrade operation
4368 function rebuildSprites($fromUpgrade=true)
4370 require_once('modules/Administration/SugarSpriteBuilder.php');
4371 $sb = new SugarSpriteBuilder();
4372 $sb->cssMinify = true;
4373 $sb->fromSilentUpgrade = $fromUpgrade;
4374 $sb->silentRun = $fromUpgrade;
4376 // add common image directories
4377 $sb->addDirectory('default', 'include/images');
4378 $sb->addDirectory('default', 'themes/default/images');
4379 $sb->addDirectory('default', 'themes/default/images/SugarLogic');
4381 // add all theme image directories
4382 if($dh = opendir('themes'))
4384 while (($dir = readdir($dh)) !== false)
4386 if ($dir != "." && $dir != ".." && $dir != 'default' && is_dir('themes/'.$dir)) {
4387 $sb->addDirectory($dir, "themes/{$dir}/images");
4393 // add all theme custom image directories
4394 $custom_themes_dir = "custom/themes";
4395 if (is_dir($custom_themes_dir)) {
4396 if($dh = opendir($custom_themes_dir))
4398 while (($dir = readdir($dh)) !== false)
4400 //Since the custom theme directories don't require an images directory
4401 // we check for it implicitly
4402 if ($dir != "." && $dir != ".." && is_dir('custom/themes/'.$dir."/images")) {
4403 $sb->addDirectory($dir, "custom/themes/{$dir}/images");
4410 // generate the sprite goodies
4411 // everything is saved into cache/sprites
4412 $sb->createSprites();
4417 * repairSearchFields
4419 * This method goes through the list of SearchFields files based and calls TemplateRange::repairCustomSearchFields
4420 * method on the files in an attempt to ensure the range search attributes are properly set in SearchFields.php.
4422 * @param $globString String value used for glob search defaults to searching for all SearchFields.php files in modules directory
4423 * @param $path String value used to point to log file should logging be required. Defaults to empty.
4426 function repairSearchFields($globString='modules/*/metadata/SearchFields.php', $path='')
4430 logThis('Begin repairSearchFields', $path);
4433 require_once('include/dir_inc.php');
4434 require_once('modules/DynamicFields/templates/Fields/TemplateRange.php');
4435 require('include/modules.php');
4438 $searchFieldsFiles = glob($globString);
4440 foreach($searchFieldsFiles as $file)
4442 if(preg_match('/modules\/(.*?)\/metadata\/SearchFields\.php/', $file, $matches) && isset($beanList[$matches[1]]))
4444 $module = $matches[1];
4445 $beanName = $beanList[$module];
4446 VardefManager::loadVardef($module, $beanName);
4447 if(isset($GLOBALS['dictionary'][$beanName]['fields']))
4451 logThis('Calling TemplateRange::repairCustomSearchFields for module ' . $module, $path);
4453 TemplateRange::repairCustomSearchFields($GLOBALS['dictionary'][$beanName]['fields'], $module);
4460 logThis('End repairSearchFields', $path);
4465 * repairUpgradeHistoryTable
4467 * This is a helper function used in the upgrade process to fix upgrade_history entries so that the filename column points
4468 * to the new upload directory location introduced in 6.4 versions
4470 function repairUpgradeHistoryTable()
4472 require_once('modules/Configurator/Configurator.php');
4474 global $sugar_config;
4476 //Now upgrade the upgrade_history table entries
4477 $results = $GLOBALS['db']->query('SELECT id, filename FROM upgrade_history');
4478 $upload_dir = $sugar_config['cache_dir'].'upload/';
4480 //Create regular expression string to
4481 $match = '/^' . str_replace('/', '\/', $upload_dir) . '(.*?)$/';
4483 while(($row = $GLOBALS['db']->fetchByAssoc($results)))
4485 $file = str_replace('//', '/', $row['filename']); //Strip out double-paths that may exist
4487 if(!empty($file) && preg_match($match, $file, $matches))
4489 //Update new file location to use the new $sugar_config['upload_dir'] value
4490 $new_file_location = $sugar_config['upload_dir'] . $matches[1];
4491 $GLOBALS['db']->query("UPDATE upgrade_history SET filename = '{$new_file_location}' WHERE id = '{$row['id']}'");