2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4 * SugarCRM Community Edition is a customer relationship management program developed by
5 * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
7 * This program is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Affero General Public License version 3 as published by the
9 * Free Software Foundation with the addition of the following permission added
10 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
19 * You should have received a copy of the GNU Affero General Public License along with
20 * this program; if not, see http://www.gnu.org/licenses or write to the Free
21 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
27 * The interactive user interfaces in modified source and object code versions
28 * of this program must display Appropriate Legal Notices, as required under
29 * Section 5 of the GNU Affero General Public License version 3.
31 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32 * these Appropriate Legal Notices must retain the display of the "Powered by
33 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34 * technical reasons, the Appropriate Legal Notices must display the words
35 * "Powered by SugarCRM".
36 ********************************************************************************/
42 * Helper function for upgrade - get path from upload:// name
46 function getUploadRelativeName($path)
48 if(class_exists('UploadFile')) {
49 return UploadFile::realpath($path);
51 if(substr($path, 0, 9) == "upload://") {
52 $path = rtrim($GLOBALS['sugar_config']['upload_dir'], "/\\")."/".substr($path, 9);
58 * Backs-up files that are targeted for patch/upgrade to a restore directory
59 * @param string rest_dir Full path to the directory containing the original, replaced files.
60 * @param string install_file Full path to the uploaded patch/upgrade zip file
61 * @param string unzip_dir Full path to the unzipped files in a temporary directory
62 * @param string zip_from_dir Name of directory that the unzipped files containing the actuall replacement files
63 * @param array errors Collection of errors to be displayed at end of process
64 * @param string path Optional full path to the log file.
65 * @return array errors
67 function commitMakeBackupFiles($rest_dir, $install_file, $unzip_dir, $zip_from_dir, $errors, $path='') {
69 // create restore file directory
70 sugar_mkdir($rest_dir, 0775, true);
72 if(file_exists($rest_dir) && is_dir($rest_dir)){
73 logThis('backing up files to be overwritten...', $path);
74 $newFiles = findAllFiles(clean_path($unzip_dir . '/' . $zip_from_dir), array());
76 // keep this around for canceling
77 $_SESSION['uw_restore_dir'] = getUploadRelativeName($rest_dir);
79 foreach ($newFiles as $file) {
80 if (strpos($file, 'md5'))
83 // get name of current file to place in restore directory
84 $cleanFile = str_replace(clean_path($unzip_dir . '/' . $zip_from_dir), '', $file);
86 // make sure the directory exists
87 $cleanDir = $rest_dir . '/' . dirname($cleanFile);
88 sugar_mkdir($cleanDir, 0775, true);
89 $oldFile = clean_path(getcwd() . '/' . $cleanFile);
91 // only copy restore files for replacements - ignore new files from patch
92 if (is_file($oldFile)) {
93 if (is_writable($rest_dir)) {
94 logThis('Backing up file: ' . $oldFile, $path);
95 if (!copy($oldFile, $rest_dir . '/' . $cleanFile)) {
96 logThis('*** ERROR: could not backup file: ' . $oldFile, $path);
97 $errors[] = "{$mod_strings['LBL_UW_BACKUP']}::{$mod_strings['ERR_UW_FILE_NOT_COPIED']}: {$oldFile}";
99 $backupFilesExist = true;
103 logThis('*** ERROR: directory not writable: ' . $rest_dir, $path);
104 $errors[] = "{$mod_strings['LBL_UW_BACKUP']}::{$mod_strings['ERR_UW_DIR_NOT_WRITABLE']}: {$oldFile}";
109 logThis('file backup done.', $path);
114 * Copies files from the unzipped patch to the destination.
115 * @param string unzip_dir Full path to the temporary directory created during unzip operation.
116 * @param string zip_from_dir Name of folder containing the unzipped files; usually the name of the Patch without the
118 * @param string path Optional full path to alternate upgradeWizard log file.
119 * @return array Two element array containing to $copiedFiles and $skippedFiles.
124 function commitCopyNewFiles($unzip_dir, $zip_from_dir, $path='') {
125 logThis('Starting file copy process...', $path);
126 global $sugar_version;
128 if(substr($sugar_version,0,1) >= 5){
129 $modules = getAllModules();
130 $backwardModules = array();
131 foreach($modules as $mod){
132 if(is_dir(clean_path(getcwd().'/modules/'.$mod.'/.500'))){
134 $files= findAllFiles(clean_path(getcwd().'/modules/'.$mod.'/.500'),$files);
135 if(sizeof($files) >0){
136 //backward compatibility is on
137 $backwardModules[] = $mod;
143 $newFiles = findAllFiles(clean_path($unzip_dir . '/' . $zip_from_dir), array());
144 $zipPath = clean_path($unzip_dir . '/' . $zip_from_dir);
146 // handle special do-not-overwrite conditions
147 $doNotOverwrite = array();
148 $doNotOverwrite[] = '__stub';
149 if(isset($_REQUEST['overwrite_files_serial'])) {
150 $doNotOverwrite = explode('::', $_REQUEST['overwrite_files_serial']);
153 $copiedFiles = array();
154 $skippedFiles = array();
156 foreach($newFiles as $file) {
157 $cleanFile = str_replace($zipPath, '', $file);
158 $srcFile = $zipPath . $cleanFile;
159 $targetFile = clean_path(getcwd() . '/' . $cleanFile);
160 if($backwardModules != null && sizeof($backwardModules) >0){
161 foreach($backwardModules as $mod){
162 $splitPath = explode('/',trim($cleanFile));
163 if('modules' == trim($splitPath[1]) && $mod == trim($splitPath[2])){
164 $cleanFile = str_replace('/modules/'.$mod, '/modules/'.$mod.'/.500', $cleanFile);
165 $targetFile = clean_path(getcwd() . '/' . $cleanFile);
169 if(!is_dir(dirname($targetFile))) {
170 mkdir_recursive(dirname($targetFile)); // make sure the directory exists
173 if((!file_exists($targetFile)) || /* brand new file */
174 (!in_array($targetFile, $doNotOverwrite)) /* manual diff file */
176 // handle sugar_version.php
177 if(strpos($targetFile, 'sugar_version.php') !== false && !preg_match('/\/portal\/sugar_version\.php$/i', $targetFile)) {
178 logThis('Skipping "sugar_version.php" - file copy will occur at end of successful upgrade', $path);
179 $_SESSION['sugar_version_file'] = $srcFile;
183 //logThis('Copying file to destination: ' . $targetFile, $path);
185 if(!copy($srcFile, $targetFile)) {
186 logThis('*** ERROR: could not copy file: ' . $targetFile, $path);
188 $copiedFiles[] = $targetFile;
191 //logThis('Skipping file: ' . $targetFile, $path);
192 $skippedFiles[] = $targetFile;
195 logThis('File copy done.', $path);
198 $ret['copiedFiles'] = $copiedFiles;
199 $ret['skippedFiles'] = $skippedFiles;
205 //On cancel put back the copied files from 500 to 451 state
206 function copyFilesOnCancel($step){
207 //place hoder for cancel action
212 function removeFileFromPath($file,$path, $deleteNot=array()){
214 $cur = $path . '/' . $file;
215 if(file_exists($cur)){
217 foreach($deleteNot as $dn){
227 if(!file_exists($path))return $removed;
229 while(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
230 $next = $path . '/'. $e;
231 if(substr($e, 0, 1) != '.' && is_dir($next)){
232 $removed += removeFileFromPath($file, $next, $deleteNot);
235 $d->close(); // from example at http://www.php.net/manual/en/function.dir.php
240 * This function copies/overwrites between directories
242 * @param string the directory name to remove
243 * @param boolean whether to just empty the given directory, without deleting the given directory.
244 * @return boolean True/False whether the directory was deleted.
247 function copyRecursiveBetweenDirectories($from,$to){
248 if(file_exists($from)){
249 $modifiedFiles = array();
250 $modifiedFiles = findAllFiles(clean_path($from), $modifiedFiles);
251 $cwd = clean_path(getcwd());
252 foreach($modifiedFiles as $file) {
253 $srcFile = clean_path($file);
254 if (strpos($srcFile,".svn") === false) {
255 $targetFile = str_replace($from, $to, $srcFile);
257 if(!is_dir(dirname($targetFile))) {
258 mkdir_recursive(dirname($targetFile)); // make sure the directory exists
261 // handle sugar_version.php
262 if(strpos($targetFile, 'sugar_version.php') !== false && !preg_match('/\/portal\/sugar_version\.php$/i', $targetFile)) {
263 logThis('Skipping "sugar_version.php" - file copy will occur at end of successful upgrade', $targetFile);
264 $_SESSION['sugar_version_file'] = $srcFile;
268 if(!copy($srcFile, $targetFile)) {
269 logThis("*** ERROR: could not copy file $srcFile to $targetFile");
276 function deleteDirectory($dirname,$only_empty=false) {
277 if (!is_dir($dirname))
279 $dscan = array(realpath($dirname));
281 while (!empty($dscan)) {
282 $dcur = array_pop($dscan);
284 if ($d=opendir($dcur)) {
285 while ($f=readdir($d)) {
286 if ($f=='.' || $f=='..')
297 $i_until = ($only_empty)? 1 : 0;
298 for ($i=count($darr)-1; $i>=$i_until; $i--) {
299 if (rmdir($darr[$i]))
300 logThis('Success :Copying file to destination: ' . $darr[$i]);
302 logThis('Copy problem:Copying file to destination: ' . $darr[$i]);
304 return (($only_empty)? (count(scandir)<=2) : (!is_dir($dirname)));
307 * Get all the customized modules. Compare the file md5s with the base md5s
308 * If a file has been modified then put the module in the list of customized
309 * modules. Show the list in the preflight check UI.
312 function deleteAndOverWriteSelectedFiles($unzip_dir, $zip_from_dir,$delete_dirs){
313 if($delete_dirs != null){
314 foreach($delete_dirs as $del_dir){
315 deleteDirectory($del_dir);
316 $newFiles = findAllFiles(clean_path($unzip_dir . '/' . $zip_from_dir.'/'.$del_dir), array());
317 $zipPath = clean_path($unzip_dir . '/' . $zip_from_dir.'/'.$del_dir);
318 $copiedFiles = array();
319 $skippedFiles = array();
321 foreach($newFiles as $file) {
322 $cleanFile = str_replace($zipPath, '', $file);
323 $srcFile = $zipPath . $cleanFile;
324 $targetFile = clean_path(getcwd() . '/' . $cleanFile);
326 if(!is_dir(dirname($targetFile))) {
327 mkdir_recursive(dirname($targetFile)); // make sure the directory exists
330 if(!file_exists($targetFile)){
331 // handle sugar_version.php
332 if(strpos($targetFile, 'sugar_version.php') !== false) {
333 logThis('Skipping sugar_version.php - file copy will occur at end of successful upgrade');
334 $_SESSION['sugar_version_file'] = $srcFile;
338 //logThis('Copying file to destination: ' . $targetFile);
340 if(!copy($srcFile, $targetFile)) {
341 logThis('*** ERROR: could not copy file: ' . $targetFile);
343 $copiedFiles[] = $targetFile;
346 //logThis('Skipping file: ' . $targetFile);
347 $skippedFiles[] = $targetFile;
353 $ret['copiedFiles'] = $copiedFiles;
354 $ret['skippedFiles'] = $skippedFiles;
359 //Default is empty the directory. For removing set it to false
360 // to use this function to totally remove a directory, write:
361 // recursive_remove_directory('path/to/directory/to/delete',FALSE);
363 // to use this function to empty a directory, write:
364 // recursive_remove_directory('path/to/full_directory');
366 function recursive_empty_or_remove_directory($directory, $exclude_dirs=null,$exclude_files=null,$empty=TRUE)
368 // if the path has a slash at the end we remove it here
369 if(substr($directory,-1) == '/')
371 $directory = substr($directory,0,-1);
374 // if the path is not valid or is not a directory ...
375 if(!file_exists($directory) || !is_dir($directory))
377 // ... we return false and exit the function
380 // ... if the path is not readable
381 }elseif(!is_readable($directory))
383 // ... we return false and exit the function
386 // ... else if the path is readable
389 // we open the directory
390 $handle = opendir($directory);
392 // and scan through the items inside
393 while (FALSE !== ($item = readdir($handle)))
395 // if the filepointer is not the current directory
396 // or the parent directory
397 if($item != '.' && $item != '..')
399 // we build the new path to delete
400 $path = $directory.'/'.$item;
402 // if the new path is a directory
403 //add another check if the dir is in the list to exclude delete
404 if(is_dir($path) && $exclude_dirs != null && in_array($path,$exclude_dirs)){
407 else if(is_dir($path))
409 // we call this function with the new path
410 recursive_empty_or_remove_directory($path);
412 // if the new path is a file
414 // we remove the file
415 if($exclude_files != null && in_array($path,$exclude_files)){
424 // close the directory
427 // if the option to empty is not set to true
430 // try to delete the now empty directory
431 if(!rmdir($directory))
433 // return false if not possible
441 // ------------------------------------------------------------
446 function getAllCustomizedModules() {
448 require_once('files.md5');
450 $return_array = array();
451 $modules = getAllModules();
452 foreach($modules as $mod) {
453 //find all files in each module if the files have been modified
454 //as compared to the base version then add the module to the
455 //customized modules array
456 $modFiles = findAllFiles(clean_path(getcwd())."/modules/$mod", array());
457 foreach($modFiles as $file){
458 $fileContents = file_get_contents($file);
459 $file = str_replace(clean_path(getcwd()),'',$file);
460 if($md5_string['./' . $file]){
461 if(md5($fileContents) != $md5_string['./' . $file]) {
462 //A file has been customized in the module. Put the module into the
463 // customized modules array.
464 echo 'Changed File'.$file;
470 // This is a new file in user's version and indicates that module has been
471 //customized. Put the module in the customized array.
472 echo 'New File'.$file;
479 return $return_array;
483 * Array of all Modules in the version bein upgraded
484 * This method returns an Array of all modules
485 * @return $modules Array of modules.
487 function getAllModules() {
490 while($e = $d->read()){
491 if(substr($e, 0, 1) == '.' || !is_dir('modules/' . $e))continue;
497 //Remove files with the smae md5
499 function removeMd5MatchingFiles($deleteNot=array()){
501 $md5_string = array();
502 if(file_exists(clean_path(getcwd().'/files.md5'))){
503 require(clean_path(getcwd().'/files.md5'));
505 $modulesAll = getAllModules();
506 foreach($modulesAll as $mod){
507 $allModFiles = array();
508 if(is_dir('modules/'.$mod)){
509 $allModFiles = findAllFiles('modules/'.$mod,$allModFiles);
510 foreach($allModFiles as $file){
511 if(file_exists($file) && !in_array(basename($file),$deleteNot)){
512 if(isset($md5_string['./'.$file])) {
513 $fileContents = file_get_contents($file);
514 if(md5($fileContents) == $md5_string['./'.$file]) {
525 * Handles requirements for creating reminder Tasks and Emails
526 * @param array skippedFiles Array of files that were not overwriten and must be manually mereged.
527 * @param string path Optional full path to alternate upgradeWizard log.
529 function commitHandleReminders($skippedFiles, $path='') {
531 global $current_user;
533 if(empty($mod_strings))
534 $mod_strings = return_module_language('en_us', 'UpgradeWizard');
536 if(empty($current_user->id)) {
537 $current_user->getSystemUser();
540 if(count($skippedFiles) > 0) {
541 $desc = $mod_strings['LBL_UW_COMMIT_ADD_TASK_OVERVIEW'] . "\n\n";
542 $desc .= $mod_strings['LBL_UW_COMMIT_ADD_TASK_DESC_1'];
543 $desc .= $_SESSION['uw_restore_dir'] . "\n\n";
544 $desc .= $mod_strings['LBL_UW_COMMIT_ADD_TASK_DESC_2'] . "\n\n";
546 foreach($skippedFiles as $file) {
547 $desc .= $file . "\n";
551 /// Not using new TimeDate stuff here because it needs to be compatible with 6.0
552 $nowDate = gmdate('Y-m-d');
553 $nowTime = gmdate('H:i:s');
554 $nowDateTime = $nowDate . ' ' . $nowTime;
556 if($_REQUEST['addTaskReminder'] == 'remind') {
557 logThis('Adding Task for admin for manual merge.', $path);
560 $task->name = $mod_strings['LBL_UW_COMMIT_ADD_TASK_NAME'];
561 $task->description = $desc;
562 $task->date_due = $nowDate;
563 $task->time_due = $nowTime;
564 $task->priority = 'High';
565 $task->status = 'Not Started';
566 $task->assigned_user_id = $current_user->id;
567 $task->created_by = $current_user->id;
568 $task->date_entered = $nowDateTime;
569 $task->date_modified = $nowDateTime;
573 if($_REQUEST['addEmailReminder'] == 'remind') {
574 logThis('Sending Reminder for admin for manual merge.', $path);
576 $email = new Email();
577 $email->assigned_user_id = $current_user->id;
578 $email->name = $mod_strings['LBL_UW_COMMIT_ADD_TASK_NAME'];
579 $email->description = $desc;
580 $email->description_html = nl2br($desc);
581 $email->from_name = $current_user->full_name;
582 $email->from_addr = $current_user->email1;
583 $email->to_addrs_arr = $email->parse_addrs($current_user->email1, '', '', '');
584 $email->cc_addrs_arr = array();
585 $email->bcc_addrs_arr = array();
586 $email->date_entered = $nowDateTime;
587 $email->date_modified = $nowDateTime;
594 function deleteCache(){
595 //Clean modules from cache
596 $cachedir = sugar_cached('modules');
597 if(is_dir($cachedir)){
598 $allModFiles = array();
599 $allModFiles = findAllFiles($cachedir,$allModFiles, true);
600 foreach($allModFiles as $file) {
601 if(file_exists($file)) {
603 rmdir_recursive($file);
612 //Clean jsLanguage from cache
613 $cachedir = sugar_cached('jsLanguage');
614 if(is_dir($cachedir)){
615 $allModFiles = array();
616 $allModFiles = findAllFiles($cachedir,$allModFiles);
617 foreach($allModFiles as $file){
618 if(file_exists($file)){
623 //Clean smarty from cache
624 $cachedir = sugar_cached('smarty');
625 if(is_dir($cachedir)){
626 $allModFiles = array();
627 $allModFiles = findAllFiles($cachedir,$allModFiles);
628 foreach($allModFiles as $file){
629 if(file_exists($file)){
634 //Rebuild dashlets cache
635 require_once('include/Dashlets/DashletCacheBuilder.php');
636 $dc = new DashletCacheBuilder();
640 function deleteChance(){
641 //Clean folder from cache
642 if(is_dir('include/SugarObjects/templates/chance')){
643 rmdir_recursive('include/SugarObjects/templates/chance');
645 if(is_dir('include/SugarObjects/templates/chance')){
646 if(!isset($_SESSION['chance'])){
647 $_SESSION['chance'] = '';
649 $_SESSION['chance'] = 'include/SugarObjects/templates/chance';
650 //rename('include/SugarObjects/templates/chance','include/SugarObjects/templates/chance_removeit');
658 * This function copies upgrade wizard files from new patch if that dir exists
660 * @param $file String path to uploaded zip file
662 function upgradeUWFiles($file) {
663 $cacheUploadUpgradesTemp = mk_temp_dir(sugar_cached("upgrades/temp"));
665 unzip($file, $cacheUploadUpgradesTemp);
667 if(!file_exists("$cacheUploadUpgradesTemp/manifest.php")) {
668 logThis("*** ERROR: no manifest file detected while bootstraping upgrade wizard files!");
671 include("$cacheUploadUpgradesTemp/manifest.php");
675 $from_dir = "{$cacheUploadUpgradesTemp}/{$manifest['copy_files']['from_dir']}";
678 if(file_exists("$from_dir/include/Localization/Localization.php")) {
679 $allFiles[] = "$from_dir/include/Localization/Localization.php";
682 if(file_exists("$from_dir/modules/UpgradeWizard")) {
683 $allFiles[] = findAllFiles("$from_dir/modules/UpgradeWizard", $allFiles);
686 if(file_exists("$from_dir/ModuleInstall")) {
687 $allFiles[] = findAllFiles("$from_dir/ModuleInstall", $allFiles);
689 if(file_exists("$from_dir/include/javascript/yui")) {
690 $allFiles[] = findAllFiles("$from_dir/include/javascript/yui", $allFiles);
692 if(file_exists("$from_dir/HandleAjaxCall.php")) {
693 $allFiles[] = "$from_dir/HandleAjaxCall.php";
695 if(file_exists("$from_dir/include/SugarTheme")) {
696 $allFiles[] = findAllFiles("$from_dir/include/SugarTheme", $allFiles);
698 if(file_exists("$from_dir/include/SugarCache")) {
699 $allFiles[] = findAllFiles("$from_dir/include/SugarCache", $allFiles);
701 if(file_exists("$from_dir/include/utils/external_cache.php")) {
702 $allFiles[] = "$from_dir/include/utils/external_cache.php";
704 if(file_exists("$from_dir/include/upload_file.php")) {
705 $allFiles[] = "$from_dir/include/upload_file.php";
707 if(file_exists("$from_dir/include/file_utils.php")) {
708 $allFiles[] = "$from_dir/include/file_utils.php";
710 if(file_exists("$from_dir/include/upload_file.php")) {
711 $allFiles[] = "$from_dir/include/upload_file.php";
713 if(file_exists("$from_dir/include/utils/sugar_file_utils.php")) {
714 $allFiles[] = "$from_dir/include/utils/sugar_file_utils.php";
717 if(file_exists("$from_dir/modules/Users")) {
718 $allFiles[] = findAllFiles("$from_dir/modules/Users", $allFiles);
721 upgradeUWFilesCopy($allFiles, $from_dir);
727 * This function recursively copies files from the upgradeUWFiles Array
728 * @see upgradeUWFiles
730 * @param array $allFiles Array of files to copy over after zip file has been uploaded
731 * @param string $from_dir Source directory
733 function upgradeUWFilesCopy($allFiles, $from_dir)
735 foreach($allFiles as $file)
739 upgradeUWFilesCopy($file, $from_dir);
741 $destFile = str_replace($from_dir."/", "", $file);
742 if(!is_dir(dirname($destFile))) {
743 mkdir_recursive(dirname($destFile)); // make sure the directory exists
746 if(stristr($file,'uw_main.tpl'))
747 logThis('Skipping "'.$file.'" - file copy will during commit step.');
749 logThis('updating UpgradeWizard code: '.$destFile);
750 copy_recursive($file, $destFile);
759 * gets valid patch file names that exist in upload/upgrade/patch/
761 function getValidPatchName($returnFull = true) {
762 global $base_upgrade_dir;
765 global $sugar_version;
766 global $sugar_config;
767 $uh = new UpgradeHistory();
768 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
771 // scan for new files (that are not installed)
772 logThis('finding new files for upgrade');
773 $upgrade_content = '';
774 $upgrade_contents = findAllFiles($base_upgrade_dir, array(), false, 'zip');
775 //other variations of zip file i.e. ZIP, zIp,zIP,Zip,ZIp,ZiP
782 <b>{$mod_strings['LBL_ML_NAME']}</b>
785 <b>{$mod_strings['LBL_ML_TYPE']}</b>
788 <b>{$mod_strings['LBL_ML_VERSION']}</b>
791 <b>{$mod_strings['LBL_ML_PUBLISHED']}</b>
794 <b>{$mod_strings['LBL_ML_UNINSTALLABLE']}</b>
797 <b>{$mod_strings['LBL_ML_DESCRIPTION']}</b>
802 // assume old patches are there.
803 $upgradeToVersion = array(); // fill with valid patches - we will only use the latest qualified found patch
805 // cn: bug 10609 - notices for uninitialized variables
810 $published_date = '';
815 foreach($upgrade_contents as $upgrade_content) {
816 if(!preg_match("#.*\.zip\$#i", $upgrade_content)) {
820 $the_base = basename($upgrade_content);
821 $the_md5 = md5_file($upgrade_content);
823 $md5_matches = $uh->findByMd5($the_md5);
825 /* 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.
826 * Edge-case: manual upgrade with a FTP of a patch; UH table has no entry for it. Assume nothing. :( */
827 if(0 == sizeof($md5_matches)) {
828 $target_manifest = remove_file_extension( $upgrade_content ) . '-manifest.php';
829 require_once($target_manifest);
831 if(empty($manifest['version'])) {
832 logThis("*** Potential error: patch found with no version [ {$upgrade_content} ]");
835 if(!isset($manifest['type']) || $manifest['type'] != 'patch') {
836 logThis("*** Potential error: patch found with either no 'type' or non-patch type [ {$upgrade_content} ]");
840 $upgradeToVersion[$manifest['version']] = urlencode($upgrade_content);
842 $name = empty($manifest['name']) ? $upgrade_content : $manifest['name'];
843 $version = empty($manifest['version']) ? '' : $manifest['version'];
844 $published_date = empty($manifest['published_date']) ? '' : $manifest['published_date'];
846 $description = empty($manifest['description']) ? 'None' : $manifest['description'];
847 $uninstallable = empty($manifest['is_uninstallable']) ? 'No' : 'Yes';
848 $type = getUITextForType( $manifest['type'] );
849 $manifest_type = $manifest['type'];
851 if(empty($manifest['icon'])) {
852 $icon = getImageForType( $manifest['type'] );
854 $path_parts = pathinfo( $manifest['icon'] );
855 $icon = "<!--not_in_theme!--><img src=\"" . remove_file_extension( $upgrade_content ) . "-icon." . $path_parts['extension'] . "\">";
860 // cn: bug 10488 use the NEWEST upgrade/patch available when running upgrade wizard.
861 ksort($upgradeToVersion);
862 $upgradeToVersion = array_values($upgradeToVersion);
863 $newest = array_pop($upgradeToVersion);
864 $_SESSION['install_file'] = urldecode($newest); // in-case it was there from a prior.
865 logThis("*** UW using [ {$_SESSION['install_file']} ] as source for patch files.");
867 $cleanUpgradeContent = urlencode($_SESSION['install_file']);
869 // cn: 10606 - cannot upload a patch file since this returned always.
870 if(!empty($cleanUpgradeContent)) {
871 $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";
874 <form action="index.php" method="post">
875 <input type="hidden" name="module" value="UpgradeWizard">
876 <input type="hidden" name="action" value="index">
877 <input type="hidden" name="step" value="{$_REQUEST['step']}">
878 <input type="hidden" name="run" value="delete">
879 <input type=hidden name="install_file" value="{$cleanUpgradeContent}" />
880 <input type=submit value="{$mod_strings['LBL_BUTTON_DELETE']}" />
884 $disabled = "DISABLED";
889 if(empty($cleanUpgradeContent)){
890 $ready .= "<tr><td colspan='7'><i>None</i></td>\n";
891 $ready .= "</table>\n";
893 $ready .= "<br></ul>\n";
895 $return['ready'] = $ready;
896 $return['disabled'] = $disabled;
905 * finalizes upgrade by setting upgrade versions in DB (config table) and sugar_version.php
906 * @return bool true on success
908 function updateVersions($version) {
910 global $sugar_config;
913 logThis('At updateVersions()... updating config table and sugar_version.php.', $path);
916 if(isset($_SESSION['sugar_version_file']) && !empty($_SESSION['sugar_version_file'])) {
917 if(!copy($_SESSION['sugar_version_file'], clean_path(getcwd().'/sugar_version.php'))) {
918 logThis('*** ERROR: sugar_version.php could not be copied to destination! Cannot complete upgrade', $path);
921 logThis('sugar_version.php successfully updated!', $path);
924 logThis('*** ERROR: no sugar_version.php file location found! - cannot complete upgrade...', $path);
928 $q1 = "DELETE FROM config WHERE category = 'info' AND name = 'sugar_version'";
929 $q2 = "INSERT INTO config (category, name, value) VALUES ('info', 'sugar_version', '{$version}')";
931 logThis('Deleting old DB version info from config table.', $path);
934 logThis('Inserting updated version info into config table.', $path);
937 logThis('updateVersions() complete.', $path);
944 * gets a module's lang pack - does not need to be a SugarModule
945 * @param lang string Language
946 * @param module string Path to language folder
947 * @return array mod_strings
949 function getModuleLanguagePack($lang, $module) {
950 $mod_strings = array();
952 if(!empty($lang) && !empty($module)) {
953 $langPack = clean_path(getcwd().'/'.$module.'/language/'.$lang.'.lang.php');
954 $langPackEn = clean_path(getcwd().'/'.$module.'/language/en_us.lang.php');
956 if (file_exists($langPack))
960 elseif (file_exists($langPackEn))
962 include($langPackEn);
969 * checks system compliance for 4.5+ codebase
970 * @return array Mixed values
972 function checkSystemCompliance() {
973 global $sugar_config;
974 global $current_language;
979 if(!defined('SUGARCRM_MIN_MEM')) {
980 define('SUGARCRM_MIN_MEM', 40);
983 $installer_mod_strings = getModuleLanguagePack($current_language, './install');
985 $ret['error_found'] = false;
988 $php_version = constant('PHP_VERSION');
989 $check_php_version_result = check_php_version($php_version);
991 switch($check_php_version_result) {
993 $ret['phpVersion'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_PHP_INVALID_VER']} {$php_version} )</span></b>";
994 $ret['error_found'] = true;
997 $ret['phpVersion'] = "<b><span class=go>{$installer_mod_strings['ERR_CHECKSYS_PHP_UNSUPPORTED']} {$php_version} )</span></b>";
1000 $ret['phpVersion'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_PHP_OK']} {$php_version} )</span></b>";
1004 // database and connect
1005 $canInstall = $db->canInstall();
1006 if ($canInstall !== true)
1008 $ret['error_found'] = true;
1009 if (count($canInstall) == 1)
1011 $ret['dbVersion'] = "<b><span class=stop>" . $installer_mod_strings[$canInstall[0]] . "</span></b>";
1015 $ret['dbVersion'] = "<b><span class=stop>" . sprintf($installer_mod_strings[$canInstall[0]], $canInstall[1]) . "</span></b>";
1020 if(function_exists('xml_parser_create')) {
1021 $ret['xmlStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1023 $ret['xmlStatus'] = "<b><span class=stop>{$installer_mod_strings['LBL_CHECKSYS_NOT_AVAILABLE']}</span></b>";
1024 $ret['error_found'] = true;
1028 if(function_exists('curl_init')) {
1029 $ret['curlStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1031 $ret['curlStatus'] = "<b><span class=go>{$installer_mod_strings['ERR_CHECKSYS_CURL']}</span></b>";
1032 $ret['error_found'] = false;
1036 if(function_exists('mb_strlen')) {
1037 $ret['mbstringStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1039 $ret['mbstringStatus'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_MBSTRING']}</span></b>";
1040 $ret['error_found'] = true;
1044 if(function_exists('imap_open')) {
1045 $ret['imapStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1047 $ret['imapStatus'] = "<b><span class=go>{$installer_mod_strings['ERR_CHECKSYS_IMAP']}</span></b>";
1048 $ret['error_found'] = false;
1053 if('1' == ini_get('safe_mode')) {
1054 $ret['safeModeStatus'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_SAFE_MODE']}</span></b>";
1055 $ret['error_found'] = true;
1057 $ret['safeModeStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1061 // call time pass by ref
1062 if('1' == ini_get('allow_call_time_pass_reference')) {
1063 $ret['callTimeStatus'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_CALL_TIME']}</span></b>";
1064 //continue upgrading
1066 $ret['callTimeStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1070 $ret['memory_msg'] = "";
1071 $memory_limit = "-1";//ini_get('memory_limit');
1072 $sugarMinMem = constant('SUGARCRM_MIN_MEM');
1073 // logic based on: http://us2.php.net/manual/en/ini.core.php#ini.memory-limit
1074 if( $memory_limit == "" ){ // memory_limit disabled at compile time, no memory limit
1075 $ret['memory_msg'] = "<b><span class=\"go\">{$installer_mod_strings['LBL_CHECKSYS_MEM_OK']}</span></b>";
1076 } elseif( $memory_limit == "-1" ){ // memory_limit enabled, but set to unlimited
1077 $ret['memory_msg'] = "<b><span class=\"go\">{$installer_mod_strings['LBL_CHECKSYS_MEM_UNLIMITED']}</span></b>";
1079 rtrim($memory_limit, 'M');
1080 $memory_limit_int = (int) $memory_limit;
1081 if( $memory_limit_int < constant('SUGARCRM_MIN_MEM') ){
1082 $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>";
1083 $ret['error_found'] = true;
1085 $ret['memory_msg'] = "<b><span class=\"go\">{$installer_mod_strings['LBL_CHECKSYS_OK']} ({$memory_limit})</span></b>";
1089 if (!class_exists("ZipArchive"))
1091 $ret['ZipStatus'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_ZIP']}</span></b>";
1092 $ret['error_found'] = true;
1094 $ret['ZipStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1099 // Suhosin allow to use upload://
1100 $ret['stream_msg'] = '';
1101 if (UploadStream::getSuhosinStatus() == true)
1103 $ret['stream_msg'] = "<b><span class=\"go\">{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1107 $ret['stream_msg'] = "<b><span class=\"stop\">{$app_strings['ERR_SUHOSIN']}</span></b>";
1108 $ret['error_found'] = true;
1111 /* mbstring.func_overload
1112 $ret['mbstring.func_overload'] = '';
1113 $mb = ini_get('mbstring.func_overload');
1116 $ret['mbstring.func_overload'] = "<b><span class=\"stop\">{$mod_strings['ERR_UW_MBSTRING_FUNC_OVERLOAD']}</b>";
1117 $ret['error_found'] = true;
1125 * is a file that we blow away automagically
1127 function isAutoOverwriteFile($file) {
1128 $overwriteDirs = array(
1129 './sugar_version.php',
1130 './modules/UpgradeWizard/uw_main.tpl',
1132 $file = trim('.'.str_replace(clean_path(getcwd()), '', $file));
1134 if(in_array($file, $overwriteDirs)) {
1138 $fileExtension = substr(strrchr($file, "."), 1);
1139 if($fileExtension == 'tpl' || $fileExtension == 'html') {
1149 function logThis($entry, $path='') {
1150 global $mod_strings;
1151 if(file_exists('include/utils/sugar_file_utils.php')){
1152 require_once('include/utils/sugar_file_utils.php');
1154 $log = empty($path) ? clean_path(getcwd().'/upgradeWizard.log') : clean_path($path);
1156 // create if not exists
1157 if(!file_exists($log)) {
1158 if(function_exists('sugar_fopen')){
1159 $fp = @sugar_fopen($log, 'w+'); // attempts to create file
1162 $fp = fopen($log, 'w+'); // attempts to create file
1164 if(!is_resource($fp)) {
1165 $GLOBALS['log']->fatal('UpgradeWizard could not create the upgradeWizard.log file');
1166 die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
1169 if(function_exists('sugar_fopen')){
1170 $fp = @sugar_fopen($log, 'a+'); // write pointer at end of file
1173 $fp = @fopen($log, 'a+'); // write pointer at end of file
1176 if(!is_resource($fp)) {
1177 $GLOBALS['log']->fatal('UpgradeWizard could not open/lock upgradeWizard.log file');
1178 die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
1182 $line = date('r').' [UpgradeWizard] - '.$entry."\n";
1184 if(@fwrite($fp, $line) === false) {
1185 $GLOBALS['log']->fatal('UpgradeWizard could not write to upgradeWizard.log: '.$entry);
1186 die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
1189 if(is_resource($fp)) {
1197 * @desc This function is to be used in the upgrade process to preserve changes/customaizations made to pre 5.1 quickcreate layout.
1198 * 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
1199 * was automatically picked up by the quick create. [Addresses Bug 21469]
1200 * This function will check if customizations were made, and will create quickcreatedefs.php in the /cutom/working/$module_name directory.
1202 function updateQuickCreateDefs(){
1203 $d = dir('modules');
1204 $studio_modules = array();
1206 while($e = $d->read()){ //collect all studio modules.
1207 if(substr($e, 0, 1) == '.' || !is_dir('modules/' . $e))continue;
1208 if(file_exists('modules/' . $e . '/metadata/studio.php'))
1210 array_push($studio_modules, $e);
1214 foreach( $studio_modules as $modname ){ //for each studio enabled module
1215 //Check !exists modules/$modname/metadata/quickcreatedefs.php &&
1216 //exists custom/$modname/editviewdefs.php (module was customized) &&
1217 //!exists custom/$modname/quickcreateviewdefs.php
1219 $editviewdefs = "custom/working/modules/".$modname."/metadata/editviewdefs.php";
1220 $quickcreatedefs = "custom/working/modules/".$modname."/metadata/quickcreatedefs.php";
1222 if ( !file_exists("modules/".$modname."/metadata/quickcreatedefs.php") &&
1223 file_exists($editviewdefs) &&
1224 !file_exists($quickcreatedefs) ){
1225 //clone editviewdef and save it in custom/working/modules/metadata
1226 $GLOBALS['log']->debug("Copying editviewdefs.php as quickcreatedefs.php for the $modname module in custom/working/modules/$modname/metadata!");
1227 if(copy( $editviewdefs, $quickcreatedefs)){
1228 if(file_exists($quickcreatedefs) && is_readable($quickcreatedefs)){
1229 $file = file($quickcreatedefs);
1230 //replace 'EditView' with 'QuickCreate'
1231 $fp = fopen($quickcreatedefs,'w');
1232 foreach($file as &$line){
1233 if(preg_match('/^\s*\'EditView\'\s*=>\s*$/', $line) > 0){
1234 $line = "'QuickCreate' =>\n";
1242 $GLOBALS['log']->debug("Failed to replace 'EditView' with QuickCreate because $quickcreatedefs is either not readable or does not exist.");
1245 $GLOBALS['log']->debug("Failed to copy $editviewdefs to $quickcreatedefs!");
1252 * test perms for CREATE queries
1254 function testPermsCreate($db, $out) {
1255 logThis('Checking CREATE TABLE permissions...');
1256 global $mod_strings;
1258 if(!$db->checkPrivilege("CREATE TABLE")) {
1259 logThis('cannot CREATE TABLE!');
1260 $out['db']['dbNoCreate'] = true;
1261 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_CREATE']}</span></td></tr>";
1267 * test perms for INSERT
1269 function testPermsInsert($db, $out, $skip=false) {
1270 logThis('Checking INSERT INTO permissions...');
1271 global $mod_strings;
1273 if(!$db->checkPrivilege("INSERT")) {
1274 logThis('cannot INSERT INTO!');
1275 $out['db']['dbNoInsert'] = true;
1276 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_INSERT']}</span></td></tr>";
1283 * test perms for UPDATE TABLE
1285 function testPermsUpdate($db, $out, $skip=false) {
1286 logThis('Checking UPDATE TABLE permissions...');
1287 global $mod_strings;
1288 if(!$db->checkPrivilege("UPDATE")) {
1289 logThis('cannot UPDATE TABLE!');
1290 $out['db']['dbNoUpdate'] = true;
1291 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_UPDATE']}</span></td></tr>";
1298 * test perms for SELECT
1300 function testPermsSelect($db, $out, $skip=false) {
1301 logThis('Checking SELECT permissions...');
1302 global $mod_strings;
1303 if(!$db->checkPrivilege("SELECT")) {
1304 logThis('cannot SELECT!');
1305 $out['db']['dbNoSelect'] = true;
1306 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_SELECT']}</span></td></tr>";
1312 * test perms for DELETE
1314 function testPermsDelete($db, $out, $skip=false) {
1315 logThis('Checking DELETE FROM permissions...');
1316 global $mod_strings;
1317 if(!$db->checkPrivilege("DELETE")) {
1318 logThis('cannot DELETE FROM!');
1319 $out['db']['dbNoDelete'] = true;
1320 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_DELETE']}</span></td></tr>";
1327 * test perms for ALTER TABLE ADD COLUMN
1329 function testPermsAlterTableAdd($db, $out, $skip=false) {
1330 logThis('Checking ALTER TABLE ADD COLUMN permissions...');
1331 global $mod_strings;
1332 if(!$db->checkPrivilege("ADD COLUMN")) {
1333 logThis('cannot ADD COLUMN!');
1334 $out['db']['dbNoAddColumn'] = true;
1335 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_ADD_COLUMN']}</span></td></tr>";
1341 * test perms for ALTER TABLE ADD COLUMN
1343 function testPermsAlterTableChange($db, $out, $skip=false) {
1344 logThis('Checking ALTER TABLE CHANGE COLUMN permissions...');
1345 global $mod_strings;
1346 if(!$db->checkPrivilege("CHANGE COLUMN")) {
1347 logThis('cannot CHANGE COLUMN!');
1348 $out['db']['dbNoChangeColumn'] = true;
1349 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_CHANGE_COLUMN']}</span></td></tr>";
1355 * test perms for ALTER TABLE DROP COLUMN
1357 function testPermsAlterTableDrop($db, $out, $skip=false) {
1358 logThis('Checking ALTER TABLE DROP COLUMN permissions...');
1359 global $mod_strings;
1360 if(!$db->checkPrivilege("DROP COLUMN")) {
1361 logThis('cannot DROP COLUMN!');
1362 $out['db']['dbNoDropColumn'] = true;
1363 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_DROP_COLUMN']}</span></td></tr>";
1370 * test perms for DROP TABLE
1372 function testPermsDropTable($db, $out, $skip=false) {
1373 logThis('Checking DROP TABLE permissions...');
1374 global $mod_strings;
1375 if(!$db->checkPrivilege("DROP TABLE")) {
1376 logThis('cannot DROP TABLE!');
1377 $out['db']['dbNoDropTable'] = true;
1378 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_DROP_TABLE']}</span></td></tr>";
1383 function getFormattedError($error, $query) {
1384 $error = "<div><b>".$error;
1385 $error .= "</b>::{$query}</div>";
1391 * parses a query finding the table name
1392 * @param string query The query
1393 * @return string table The table
1395 function getTableFromQuery($query) {
1396 $standardQueries = array('ALTER TABLE', 'DROP TABLE', 'CREATE TABLE', 'INSERT INTO', 'UPDATE', 'DELETE FROM');
1397 $query = preg_replace("/[^A-Za-z0-9\_\s]/", "", $query);
1398 $query = trim(str_replace($standardQueries, '', $query));
1400 $firstSpc = strpos($query, " ");
1401 $end = ($firstSpc > 0) ? $firstSpc : strlen($query);
1402 $table = substr($query, 0, $end);
1409 function preLicenseCheck() {
1410 require_once('modules/UpgradeWizard/uw_files.php');
1412 global $sugar_config;
1413 global $mod_strings;
1414 global $sugar_version;
1416 if(!isset($sugar_version) || empty($sugar_version)) {
1417 require_once('./sugar_version.php');
1420 if(!isset($_SESSION['unzip_dir']) || empty($_SESSION['unzip_dir'])) {
1421 logThis('unzipping files in upgrade archive...');
1423 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
1425 //also come up with mechanism to read from upgrade-progress file
1426 if(!isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !is_file($_SESSION['install_file'])) {
1427 if (file_exists(clean_path($base_tmp_upgrade_dir)) && $handle = opendir(clean_path($base_tmp_upgrade_dir))) {
1428 while (false !== ($file = readdir($handle))) {
1429 if($file !="." && $file !="..") {
1430 if(is_file($base_tmp_upgrade_dir."/".$file."/manifest.php")){
1431 require_once($base_tmp_upgrade_dir."/".$file."/manifest.php");
1432 $package_name= $manifest['copy_files']['from_dir'];
1433 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")){
1434 $unzip_dir = $base_tmp_upgrade_dir."/".$file;
1435 if(file_exists("$base_upgrade_dir/patch/".$package_name.'.zip')){
1436 $_SESSION['install_file'] = $package_name.".zip";
1445 if(empty($_SESSION['install_file'])){
1446 unlinkUWTempFiles();
1448 echo 'Upload File not found so redirecting to Upgrade Start ';
1449 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1450 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1451 $upgrade_directories_not_found =<<<eoq
1452 <table cellpadding="3" cellspacing="0" border="0">
1454 <th colspan="2" align="left">
1455 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1460 $uwMain = $upgrade_directories_not_found;
1463 $install_file = "$base_upgrade_dir/patch/".basename(urldecode( $_SESSION['install_file'] ));
1465 if(empty($unzip_dir)){
1466 $unzip_dir = mk_temp_dir( $base_tmp_upgrade_dir );
1468 $zip_from_dir = ".";
1470 $zip_force_copy = array();
1473 logThis('Could not create a temporary directory using mk_temp_dir( $base_tmp_upgrade_dir )');
1474 die($mod_strings['ERR_UW_NO_CREATE_TMP_DIR']);
1477 //double check whether unzipped .
1478 if(file_exists($unzip_dir ."/scripts") && file_exists($unzip_dir."/manifest.php")){
1482 unzip( $install_file, $unzip_dir );
1485 // assumption -- already validated manifest.php at time of upload
1486 require_once( "$unzip_dir/manifest.php" );
1488 if( isset( $manifest['copy_files']['from_dir'] ) && $manifest['copy_files']['from_dir'] != "" ){
1489 $zip_from_dir = $manifest['copy_files']['from_dir'];
1491 if( isset( $manifest['copy_files']['to_dir'] ) && $manifest['copy_files']['to_dir'] != "" ){
1492 $zip_to_dir = $manifest['copy_files']['to_dir'];
1494 if( isset( $manifest['copy_files']['force_copy'] ) && $manifest['copy_files']['force_copy'] != "" ){
1495 $zip_force_copy = $manifest['copy_files']['force_copy'];
1497 if( isset( $manifest['version'] ) ){
1498 $version = $manifest['version'];
1500 if( !is_writable( "config.php" ) ){
1501 return $mod_strings['ERR_UW_CONFIG'];
1504 $_SESSION['unzip_dir'] = clean_path($unzip_dir);
1505 $_SESSION['zip_from_dir'] = clean_path($zip_from_dir);
1506 logThis('unzip done.');
1508 $unzip_dir = $_SESSION['unzip_dir'];
1509 $zip_from_dir = $_SESSION['zip_from_dir'];
1512 //check if $_SESSION['unzip_dir'] and $_SESSION['zip_from_dir'] exist
1513 if(!isset($_SESSION['unzip_dir']) || !file_exists($_SESSION['unzip_dir'])
1514 || !isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !file_exists($_SESSION['install_file'])){
1516 unlinkUWTempFiles();
1518 echo 'Upload File not found so redirecting to Upgrade Start ';
1519 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1520 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1521 $upgrade_directories_not_found =<<<eoq
1522 <table cellpadding="3" cellspacing="0" border="0">
1524 <th colspan="2" align="left">
1525 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1530 $uwMain = $upgrade_directories_not_found;
1534 logThis ('is SugarConfig there '.file_exists(clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarObjects/SugarConfig.php")));
1535 if(file_exists(clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarObjects/SugarConfig.php"))) {
1536 $file = clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarObjects/SugarConfig.php");
1537 $destFile = str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), $cwd, $file);
1538 if(!is_dir(dirname($destFile))) {
1539 mkdir_recursive(dirname($destFile)); // make sure the directory exists
1541 copy($file,$destFile);
1542 //also copy include utils array utils
1543 $file = clean_path($unzip_dir.'/'.$zip_from_dir."/include/utils/array_utils.php");
1544 $destFile = str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), $cwd, $file);
1545 if(!is_dir(dirname($destFile))) {
1546 mkdir_recursive(dirname($destFile)); // make sure the directory exists
1548 copy($file,$destFile);
1553 function preflightCheck() {
1554 require_once('modules/UpgradeWizard/uw_files.php');
1556 global $sugar_config;
1557 global $mod_strings;
1558 global $sugar_version;
1560 if(!isset($sugar_version) || empty($sugar_version)) {
1561 require_once('./sugar_version.php');
1564 unset($_SESSION['rebuild_relationships']);
1565 unset($_SESSION['rebuild_extensions']);
1567 // don't bother if are rechecking
1568 $manualDiff = array();
1569 if(!isset($_SESSION['unzip_dir']) || empty($_SESSION['unzip_dir'])) {
1570 logThis('unzipping files in upgrade archive...');
1572 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
1574 //Following is if User logged out unexpectedly and then logged into UpgradeWizard again.
1575 //also come up with mechanism to read from upgrade-progress file.
1576 if(!isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !is_file($_SESSION['install_file'])) {
1577 if (file_exists($base_tmp_upgrade_dir) && $handle = opendir($base_tmp_upgrade_dir)) {
1578 while (false !== ($file = readdir($handle))) {
1579 if($file !="." && $file !="..") {
1580 if(is_file($base_tmp_upgrade_dir."/".$file."/manifest.php")){
1581 require_once($base_tmp_upgrade_dir."/".$file."/manifest.php");
1582 $package_name= $manifest['copy_files']['from_dir'];
1583 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")){
1584 $unzip_dir = $base_tmp_upgrade_dir."/".$file;
1585 if(file_exists("$base_upgrade_dir/patch/".$package_name.'.zip')){
1586 $_SESSION['install_file'] = $package_name.".zip";
1595 if(empty($_SESSION['install_file'])){
1596 unlinkUWTempFiles();
1598 echo 'Upload File not found so redirecting to Upgrade Start ';
1599 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1600 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1601 $upgrade_directories_not_found =<<<eoq
1602 <table cellpadding="3" cellspacing="0" border="0">
1604 <th colspan="2" align="left">
1605 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1610 $uwMain = $upgrade_directories_not_found;
1614 $install_file = "$base_upgrade_dir/patch/".basename(urldecode( $_SESSION['install_file'] ));
1616 if(empty($unzip_dir)){
1617 $unzip_dir = mk_temp_dir( $base_tmp_upgrade_dir );
1619 $zip_from_dir = ".";
1621 $zip_force_copy = array();
1624 logThis('Could not create a temporary directory using mk_temp_dir( $base_tmp_upgrade_dir )');
1625 die($mod_strings['ERR_UW_NO_CREATE_TMP_DIR']);
1628 //double check whether unzipped .
1629 if(file_exists($unzip_dir ."/scripts") && file_exists($unzip_dir."/manifest.php")){
1633 unzip( $install_file, $unzip_dir );
1636 // assumption -- already validated manifest.php at time of upload
1637 require_once( "$unzip_dir/manifest.php" );
1639 if( isset( $manifest['copy_files']['from_dir'] ) && $manifest['copy_files']['from_dir'] != "" ){
1640 $zip_from_dir = $manifest['copy_files']['from_dir'];
1642 if( isset( $manifest['copy_files']['to_dir'] ) && $manifest['copy_files']['to_dir'] != "" ){
1643 $zip_to_dir = $manifest['copy_files']['to_dir'];
1645 if( isset( $manifest['copy_files']['force_copy'] ) && $manifest['copy_files']['force_copy'] != "" ){
1646 $zip_force_copy = $manifest['copy_files']['force_copy'];
1648 if( isset( $manifest['version'] ) ){
1649 $version = $manifest['version'];
1651 if( !is_writable( "config.php" ) ){
1652 return $mod_strings['ERR_UW_CONFIG'];
1655 $_SESSION['unzip_dir'] = clean_path($unzip_dir);
1656 $_SESSION['zip_from_dir'] = clean_path($zip_from_dir);
1658 //logThis('unzip done.');
1660 $unzip_dir = $_SESSION['unzip_dir'];
1661 $zip_from_dir = $_SESSION['zip_from_dir'];
1663 //check if $_SESSION['unzip_dir'] and $_SESSION['zip_from_dir'] exist
1664 if(!isset($_SESSION['unzip_dir']) || !file_exists($_SESSION['unzip_dir'])
1665 || !isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !file_exists($_SESSION['install_file'])){
1667 unlinkUWTempFiles();
1669 echo 'Upload File not found so redirecting to Upgrade Start ';
1670 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1671 echo '<form name="redirect" action="' .$redirect_new_wizard. '" method="POST">';
1672 $upgrade_directories_not_found =<<<eoq
1673 <table cellpadding="3" cellspacing="0" border="0">
1675 <th colspan="2" align="left">
1676 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1681 $uwMain = $upgrade_directories_not_found;
1684 //copy minimum required files
1685 fileCopy('include/utils/sugar_file_utils.php');
1687 $upgradeFiles = findAllFiles(clean_path("$unzip_dir/$zip_from_dir"), array());
1688 $cache_html_files= array();
1691 $md5_string = array();
1692 if(file_exists(clean_path(getcwd().'/files.md5'))){
1693 require(clean_path(getcwd().'/files.md5'));
1696 // file preflight checks
1697 logThis('verifying md5 checksums for files...');
1698 foreach($upgradeFiles as $file) {
1699 if(in_array(str_replace(clean_path("$unzip_dir/$zip_from_dir") . "/", '', $file), $uw_files))
1700 continue; // skip already loaded files
1702 if(strpos($file, '.md5'))
1703 continue; // skip md5 file
1705 // normalize file paths
1706 $file = clean_path($file);
1708 // check that we can move/delete the upgraded file
1709 if(!is_writable($file)) {
1710 $errors[] = $mod_strings['ERR_UW_FILE_NOT_WRITABLE'].": ".$file;
1712 // check that destination files are writable
1713 $destFile = getcwd().str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), '', $file);
1715 if(is_file($destFile)) { // of course it needs to exist first...
1716 if(!is_writable($destFile)) {
1717 $errors[] = $mod_strings['ERR_UW_FILE_NOT_WRITABLE'].": ".$destFile;
1721 ///////////////////////////////////////////////////////////////////////
1723 // compare md5s and build up a manual merge list
1724 $targetFile = clean_path(".".str_replace(getcwd(),'',$destFile));
1726 if(is_file($destFile)) {
1727 if(strpos($targetFile, '.php')) {
1728 // handle PHP files that were hit with the security regex
1730 if(function_exists('sugar_fopen')){
1731 $fp = sugar_fopen($destFile, 'r');
1734 $fp = fopen($destFile, 'r');
1736 $filesize = filesize($destFile);
1738 $fileContents = stream_get_contents($fp);
1739 $targetMd5 = md5($fileContents);
1742 $targetMd5 = md5_file($destFile);
1746 if(isset($md5_string[$targetFile]) && $md5_string[$targetFile] != $targetMd5) {
1747 logThis('found a file with a differing md5: ['.$targetFile.']');
1748 $manualDiff[] = $destFile;
1751 ///////////////////////////////////////////////////////////////////////
1753 logThis('md5 verification done.');
1754 $errors['manual'] = $manualDiff;
1759 function fileCopy($file_path){
1760 if(file_exists(clean_path($_SESSION['unzip_dir'].'/'.$_SESSION['zip_from_dir'].'/'.$file_path))) {
1761 $file = clean_path($_SESSION['unzip_dir'].'/'.$_SESSION['zip_from_dir'].'/'.$file_path);
1762 $destFile = str_replace(clean_path($_SESSION['unzip_dir'].'/'.$_SESSION['zip_from_dir']), clean_path(getcwd()), $file);
1763 if(!is_dir(dirname($destFile))) {
1764 mkdir_recursive(dirname($destFile)); // make sure the directory exists
1766 copy_recursive($file,$destFile);
1769 function getChecklist($steps, $step) {
1770 global $mod_strings;
1772 $skip = array('start', 'cancel', 'uninstall','end');
1775 $ret = '<table cellpadding="3" cellspacing="4" border="0">';
1776 $ret .= '<tr><th colspan="3" align="left">'.$mod_strings['LBL_UW_CHECKLIST'].':</th></tr>';
1777 foreach($steps['desc'] as $k => $desc) {
1778 if(in_array($steps['files'][$j], $skip)) {
1783 //$status = "<span class='error'>{$mod_strings['LBL_UW_INCOMPLETE']}</span>";
1785 $desc_mod_post = '';
1787 if(isset($_SESSION['step'][$steps['files'][$k]]) && $_SESSION['step'][$steps['files'][$k]] == 'success') {
1788 //$status = $mod_strings['LBL_UW_COMPLETE'];
1792 if($k == $_REQUEST['step']) {
1793 //$status = $mod_strings['LBL_UW_IN_PROGRESS'];
1794 $desc_mod_pre = "<font color=blue><i>";
1795 $desc_mod_post = "</i></font>";
1798 $ret .= "<tr><td> </td><td><b>{$i}: {$desc_mod_pre}{$desc}{$desc_mod_post}</b></td>";
1799 $ret .= "<td id={$steps['files'][$j]}><i></i></td></tr>";
1807 function prepSystemForUpgrade() {
1808 global $sugar_config;
1809 global $sugar_flavor;
1810 global $mod_strings;
1811 global $current_language;
1813 global $base_upgrade_dir;
1814 global $base_tmp_upgrade_dir;
1815 list($p_base_upgrade_dir, $p_base_tmp_upgrade_dir) = getUWDirs();
1816 ///////////////////////////////////////////////////////////////////////////////
1817 //// Make sure variables exist
1818 if(empty($base_upgrade_dir)){
1819 $base_upgrade_dir = $p_base_upgrade_dir;
1821 if(empty($base_tmp_upgrade_dir)){
1822 $base_tmp_upgrade_dir = $p_base_tmp_upgrade_dir;
1824 sugar_mkdir($base_tmp_upgrade_dir, 0775, true);
1825 if(!isset($subdirs) || empty($subdirs)){
1826 $subdirs = array('full', 'langpack', 'module', 'patch', 'theme');
1829 $upgrade_progress_dir = $base_tmp_upgrade_dir;
1830 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
1831 if(file_exists($upgrade_progress_file)){
1832 if(function_exists('get_upgrade_progress') && function_exists('didThisStepRunBefore')){
1833 if(didThisStepRunBefore('end')){
1834 include($upgrade_progress_file);
1835 unset($upgrade_config);
1836 unlink($upgrade_progress_file);
1841 // increase the cuttoff time to 1 hour
1842 ini_set("max_execution_time", "3600");
1844 // make sure dirs exist
1845 if($subdirs != null){
1846 foreach($subdirs as $subdir) {
1847 sugar_mkdir("$base_upgrade_dir/$subdir", 0775, true);
1850 // array of special scripts that are executed during (un)installation-- key is type of script, value is filename
1851 if(!defined('SUGARCRM_PRE_INSTALL_FILE')) {
1852 define('SUGARCRM_PRE_INSTALL_FILE', 'scripts/pre_install.php');
1853 define('SUGARCRM_POST_INSTALL_FILE', 'scripts/post_install.php');
1854 define('SUGARCRM_PRE_UNINSTALL_FILE', 'scripts/pre_uninstall.php');
1855 define('SUGARCRM_POST_UNINSTALL_FILE', 'scripts/post_uninstall.php');
1858 $script_files = array(
1859 "pre-install" => constant('SUGARCRM_PRE_INSTALL_FILE'),
1860 "post-install" => constant('SUGARCRM_POST_INSTALL_FILE'),
1861 "pre-uninstall" => constant('SUGARCRM_PRE_UNINSTALL_FILE'),
1862 "post-uninstall" => constant('SUGARCRM_POST_UNINSTALL_FILE'),
1865 // check that the upload limit is set to 6M or greater
1866 define('SUGARCRM_MIN_UPLOAD_MAX_FILESIZE_BYTES', 6 * 1024 * 1024); // 6 Megabytes
1867 $upload_max_filesize = ini_get('upload_max_filesize');
1868 $upload_max_filesize_bytes = return_bytes($upload_max_filesize);
1870 if($upload_max_filesize_bytes < constant('SUGARCRM_MIN_UPLOAD_MAX_FILESIZE_BYTES')) {
1871 $GLOBALS['log']->debug("detected upload_max_filesize: $upload_max_filesize");
1872 $admin_strings = return_module_language($current_language, 'Administration');
1873 echo '<p class="error">'.$admin_strings['MSG_INCREASE_UPLOAD_MAX_FILESIZE'].' '.get_cfg_var('cfg_file_path')."</p>\n";
1877 if ( !function_exists('extractFile') ) {
1878 function extractFile($zip_file, $file_in_zip) {
1879 global $base_tmp_upgrade_dir;
1882 $absolute_base_tmp_upgrade_dir = clean_path($base_tmp_upgrade_dir);
1883 $relative_base_tmp_upgrade_dir = clean_path(str_replace(clean_path(getcwd()), '', $absolute_base_tmp_upgrade_dir));
1885 // mk_temp_dir expects relative pathing
1886 $my_zip_dir = mk_temp_dir($relative_base_tmp_upgrade_dir);
1888 unzip_file($zip_file, $file_in_zip, $my_zip_dir);
1890 return("$my_zip_dir/$file_in_zip");
1894 if ( !function_exists('extractManifest') ) {
1895 function extractManifest($zip_file) {
1896 logThis('extracting manifest.');
1897 return(extractFile($zip_file, "manifest.php"));
1901 if ( !function_exists('getInstallType') ) {
1902 function getInstallType($type_string) {
1905 $subdirs = array('full', 'langpack', 'module', 'patch', 'theme', 'temp');
1906 foreach($subdirs as $subdir) {
1907 if(preg_match("#/$subdir/#", $type_string)) {
1911 // return empty if no match
1916 function getImageForType($type) {
1918 global $mod_strings;
1923 $icon = SugarThemeRegistry::current()->getImage("Upgrade", "",null,null,'.gif',$mod_strings['LBL_UPGRADE']);
1926 $icon = SugarThemeRegistry::current()->getImage("LanguagePacks", "",null,null,'.gif',$mod_strings['LBL_LANGPACKS']);
1929 $icon = SugarThemeRegistry::current()->getImage("ModuleLoader", "",null,null,'.gif',$mod_strings['LBL_MODULELOADER']);
1932 $icon = SugarThemeRegistry::current()->getImage("PatchUpgrades", "",null,null,'.gif',$mod_strings['LBL_PATCHUPGRADES']);
1935 $icon = SugarThemeRegistry::current()->getImage("Themes", "",null,null,'.gif',$mod_strings['LBL_THEMES']);
1943 if ( !function_exists('getLanguagePackName') ) {
1944 function getLanguagePackName($the_file) {
1945 require_once("$the_file");
1946 if(isset($app_list_strings["language_pack_name"])) {
1947 return($app_list_strings["language_pack_name"]);
1953 function getUITextForType($type) {
1954 if($type == "full") {
1955 return("Full Upgrade");
1957 if($type == "langpack") {
1958 return("Language Pack");
1960 if($type == "module") {
1963 if($type == "patch") {
1966 if($type == "theme") {
1971 if ( !function_exists('validate_manifest') ) {
1973 * Verifies a manifest from a patch or module to be compatible with the current Sugar version and flavor
1974 * @param array manifest Standard manifest array
1975 * @return string Error message, blank on success
1977 function validate_manifest($manifest) {
1978 logThis('validating manifest.php file');
1979 // takes a manifest.php manifest array and validates contents
1981 global $sugar_version;
1982 global $sugar_flavor;
1983 global $mod_strings;
1985 if(!isset($manifest['type'])) {
1986 return $mod_strings['ERROR_MANIFEST_TYPE'];
1989 $type = $manifest['type'];
1991 if(getInstallType("/$type/") == "") {
1992 return $mod_strings['ERROR_PACKAGE_TYPE']. ": '" . $type . "'.";
1995 if(isset($manifest['acceptable_sugar_versions'])) {
1996 $version_ok = false;
1997 $matches_empty = true;
1998 if(isset($manifest['acceptable_sugar_versions']['exact_matches'])) {
1999 $matches_empty = false;
2000 foreach($manifest['acceptable_sugar_versions']['exact_matches'] as $match) {
2001 if($match == $sugar_version) {
2006 if(!$version_ok && isset($manifest['acceptable_sugar_versions']['regex_matches'])) {
2007 $matches_empty = false;
2008 foreach($manifest['acceptable_sugar_versions']['regex_matches'] as $match) {
2009 if(preg_match("/$match/", $sugar_version)) {
2015 if(!$matches_empty && !$version_ok) {
2016 return $mod_strings['ERROR_VERSION_INCOMPATIBLE']."<br />".
2017 $mod_strings['ERR_UW_VERSION'].$sugar_version;
2021 if(isset($manifest['acceptable_sugar_flavors']) && sizeof($manifest['acceptable_sugar_flavors']) > 0) {
2023 foreach($manifest['acceptable_sugar_flavors'] as $match) {
2024 if($match == $sugar_flavor) {
2029 return $mod_strings['ERROR_FLAVOR_INCOMPATIBLE']."<br />".
2030 $mod_strings['ERR_UW_FLAVOR'].$sugar_flavor."<br />".
2031 $mod_strings['ERR_UW_FLAVOR_2'].$manifest['acceptable_sugar_flavors'][0];
2039 function unlinkUploadFiles() {
2041 // logThis('at unlinkUploadFiles()');
2043 // if(isset($_SESSION['install_file']) && !empty($_SESSION['install_file'])) {
2044 // $upload = $_SESSION['install_file'];
2046 // if(is_file($upload)) {
2047 // logThis('unlinking ['.$upload.']');
2048 // @unlink($upload);
2054 * deletes files created by unzipping a package
2056 function unlinkUWTempFiles() {
2057 global $sugar_config;
2060 logThis('at unlinkUWTempFiles()');
2062 list($upgDir, $tempDir) = getUWDirs();
2064 if(file_exists($tempDir) && is_dir($tempDir)){
2065 $files = findAllFiles($tempDir, array(), false);
2067 foreach($files as $file) {
2068 if(!is_dir($file)) {
2069 //logThis('unlinking ['.$file.']', $path);
2074 $files = findAllFiles($tempDir, array(), true);
2075 foreach($files as $dir) {
2077 //logThis('removing dir ['.$dir.']', $path);
2081 $cacheFile = sugar_cached("modules/UpgradeWizard/_persistence.php");
2082 if(is_file($cacheFile)) {
2083 logThis("Unlinking Upgrade cache file: '_persistence.php'", $path);
2084 @unlink($cacheFile);
2087 logThis("finished!");
2091 * finds all files in the passed path, but skips select directories
2092 * @param string dir Relative path
2093 * @param array the_array Collections of found files/dirs
2094 * @param bool include_dir True if we want to include directories in the
2095 * returned collection
2097 function uwFindAllFiles($dir, $theArray, $includeDirs=false, $skipDirs=array(), $echo=false) {
2099 if (whetherNeedToSkipDir($dir, $skipDirs))
2104 if (!is_dir($dir)) { return $theArray; } // Bug # 46035, just checking for valid dir
2106 if ($d === false) { return $theArray; } // Bug # 46035, more checking
2108 while($f = $d->read()) {
2109 // bug 40793 Skip Directories array in upgradeWizard does not function correctly
2110 if($f == "." || $f == ".." || whetherNeedToSkipDir("$dir/$f", $skipDirs)) { // skip *nix self/parent
2114 // for AJAX length count
2120 if(is_dir("$dir/$f")) {
2121 if($includeDirs) { // add the directory if flagged
2122 $theArray[] = clean_path("$dir/$f");
2126 $theArray = uwFindAllFiles("$dir/$f/", $theArray, $includeDirs, $skipDirs, $echo);
2128 $theArray[] = clean_path("$dir/$f");
2141 * unset's UW's Session Vars
2143 function resetUwSession() {
2144 logThis('resetting $_SESSION');
2146 if(isset($_SESSION['committed']))
2147 unset($_SESSION['committed']);
2148 if(isset($_SESSION['sugar_version_file']))
2149 unset($_SESSION['sugar_version_file']);
2150 if(isset($_SESSION['upgrade_complete']))
2151 unset($_SESSION['upgrade_complete']);
2152 if(isset($_SESSION['allTables']))
2153 unset($_SESSION['allTables']);
2154 if(isset($_SESSION['alterCustomTableQueries']))
2155 unset($_SESSION['alterCustomTableQueries']);
2156 if(isset($_SESSION['skip_zip_upload']))
2157 unset($_SESSION['skip_zip_upload']);
2158 if(isset($_SESSION['sugar_version_file']))
2159 unset($_SESSION['sugar_version_file']);
2160 if(isset($_SESSION['install_file']))
2161 unset($_SESSION['install_file']);
2162 if(isset($_SESSION['unzip_dir']))
2163 unset($_SESSION['unzip_dir']);
2164 if(isset($_SESSION['zip_from_dir']))
2165 unset($_SESSION['zip_from_dir']);
2166 if(isset($_SESSION['overwrite_files']))
2167 unset($_SESSION['overwrite_files']);
2168 if(isset($_SESSION['schema_change']))
2169 unset($_SESSION['schema_change']);
2170 if(isset($_SESSION['uw_restore_dir']))
2171 unset($_SESSION['uw_restore_dir']);
2172 if(isset($_SESSION['step']))
2173 unset($_SESSION['step']);
2174 if(isset($_SESSION['files']))
2175 unset($_SESSION['files']);
2176 if(isset($_SESSION['Upgraded451Wizard'])){
2177 unset($_SESSION['Upgraded451Wizard']);
2179 if(isset($_SESSION['Initial_451to500_Step'])){
2180 unset($_SESSION['Initial_451to500_Step']);
2182 if(isset($_SESSION['license_shown']))
2183 unset($_SESSION['license_shown']);
2184 if(isset($_SESSION['sugarMergeRunResults']))
2185 unset($_SESSION['sugarMergeRunResults']);
2189 * runs rebuild scripts
2191 function UWrebuild() {
2195 //CCL - Comment this block out, it is called in end.php
2196 logThis('Rebuilding everything...', $path);
2197 require_once('modules/Administration/QuickRepairAndRebuild.php');
2198 $randc = new RepairAndClear();
2199 $randc->repairAndClearAll(array('clearAll'),array(translate('LBL_ALL_MODULES')), false, false);
2201 $query = "DELETE FROM versions WHERE name='Rebuild Extensions'";
2203 logThis('Registering rebuild record: '.$query, $path);
2204 logThis('Rebuild done.', $path);
2206 // insert a new database row to show the rebuild extensions is done
2207 $id = create_guid();
2208 $gmdate = gmdate('Y-m-d H:i:s');
2209 $date_entered = db_convert("'$gmdate'", 'datetime');
2210 $query = 'INSERT INTO versions (id, deleted, date_entered, date_modified, modified_user_id, created_by, name, file_version, db_version) '
2211 . "VALUES ('$id', '0', $date_entered, $date_entered, '1', '1', 'Rebuild Extensions', '4.0.0', '4.0.0')";
2213 logThis('Registering rebuild record in versions table: '.$query, $path);
2216 function getCustomTables() {
2219 return $db->tablesLike('%_cstm');
2222 function alterCustomTables($customTables)
2227 function getAllTables() {
2229 return $db->getTablesArray();
2232 function printAlterTableSql($tables)
2234 $alterTableSql = '';
2236 foreach($tables as $table)
2237 $alterTableSql .= "ALTER TABLE " . $table . " CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;" . "\n";
2239 return $alterTableSql;
2242 function executeConvertTablesSql($tables)
2246 foreach($tables as $table){
2247 $query = "ALTER TABLE " . $table . " CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci";
2249 logThis("Sending query: ".$query);
2250 $db->query($query);//, true, "An error has occured while performing db query. See log file for details.<br>");
2256 function testThis() {
2257 $files = uwFindAllFiles(getcwd().'/test', array());
2259 $out = "<table cellpadding='1' cellspacing='0' border='0'>\n";
2262 foreach($files as $file) {
2263 $relativeFile = clean_path(str_replace(getcwd().'/test', '', $file));
2264 $relativeFile = ($relativeFile{0} == '/') ? substr($relativeFile, 1, strlen($relativeFile)) : $relativeFile;
2266 $relativePath = dirname($relativeFile);
2268 if($relativePath == $priorPath) { // same dir, new file
2269 $out .= "<tr><td>".basename($relativeFile)."</td></tr>";
2270 $priorPath = $relativePath;
2284 function testThis2($dir, $id=0, $hide=false) {
2285 global $mod_strings;
2287 $dh = opendir($dir);
2290 $doHide = ($hide) ? 'none' : '';
2291 $out = "<div id='{$id}' style='display:{$doHide};'>";
2292 $out .= "<table cellpadding='1' cellspacing='0' style='border:0px solid #ccc'>\n";
2294 while($file = readdir($dh)) {
2295 if($file == '.' || $file == '..' || $file == 'CVS' || $file == '.cvsignore')
2298 if(is_dir($path.'/'.$file)) {
2299 $file = $path.'/'.$file;
2300 $newI = create_guid();
2301 $out .= "<tr><td valign='top'><a href='javascript:toggleNwFiles(\"{$newI}\");'>".SugarThemeRegistry::current()->getImage("Workflow", "", null, null, ".gif", $mod_strings['LBL_WORKFLOW'])."</a></td>\n";
2302 $out .= "<td valign='top'><b><a href='javascript:toggleNwFiles(\"{$newI}\");'>".basename($file)."</a></b></td></tr>";
2303 $out .= "<tr><td></td><td valign='top'>".testThis2($file, $newI, true)."</td></tr>";
2305 $out .= "<tr><td valign='top'> </td>\n";
2306 $out .= "<td valign='top'>".basename($file)."</td></tr>";
2310 $out .= "</tr></table>";
2321 function testThis3(&$files, $id, $hide, $previousPath = '') {
2322 if(!is_array($files) || empty($files))
2327 global $mod_strings;
2328 // expecting full path here
2329 foreach($files as $k => $file) {
2330 $file = str_replace(getcwd(), '', $file);
2331 $path = dirname($file);
2332 $fileName = basename($file);
2334 if($fileName == 'CVS' || $fileName == '.cvsignore')
2337 if($path == $previousPath) { // same directory
2338 // new row for each file
2339 $out .= "<tr><td valign='top' align='left'> </td>";
2340 $out .= "<td valign='top' align='left'>{$fileName}</td></tr>";
2341 } else { // new directory
2343 $out .= "<tr><td valign='top'><a href='javascript:toggleNwFiles(\"{$newI}\");'>".SugarThemeRegistry::current()->getImage("Workflow", "", null, null, ".gif", $mod_strings['LBL_WORKFLOW'])."</a></td>\n";
2344 $out .= "<td valign='top'><b><a href='javascript:toggleNwFiles(\"{$newI}\");'>".$fileName."</a></b></td></tr>";
2345 $recurse = testThis3($files, $newI, true, $previousPath);
2346 $out .= "<tr><td></td><td valign='top'>".$recurse."</td></tr>";
2349 $previousPath = $path;
2351 $display = ($hide) ? 'none' : '';
2353 <div id="{$id}" style="display:{$display}">
2354 <table cellpadding='1' cellspacing='0' border='0' style='border:1px solid #ccc'>
2363 function testThis4($filePath, $fileNodes=array(), $fileName='') {
2364 $path = dirname($filePath);
2365 $file = basename($filePath);
2367 $exFile = explode('/', $path);
2369 foreach($exFile as $pathSegment) {
2370 if(is_array($fileNodes[$pathSegment])) { // path already processed
2372 } else { // newly found path
2373 $fileNodes[$pathSegment] = array();
2376 if($fileName != '') {
2377 $fileNodes[$pathSegment][] = $fileName;
2386 ///////////////////////////////////////////////////////////////////////////////
2387 //// SYSTEM CHECK FUNCTIONS
2389 * generates an array with all files in the SugarCRM root directory, skipping
2391 * @return array files Array of files with absolute paths
2393 function getFilesForPermsCheck() {
2394 global $sugar_config;
2396 logThis('Got JSON call to find all files...');
2397 $filesNotWritable = array();
2398 $filesNWPerms = array();
2400 // add directories here that should be skipped when doing file permissions checks (cache/upload is the nasty one)
2402 $sugar_config['upload_dir'],
2404 $files = uwFindAllFiles(".", array(), true, $skipDirs, true);
2409 * checks files for permissions
2410 * @param array files Array of files with absolute paths
2411 * @return string result of check
2413 function checkFiles($files, $echo=false) {
2414 global $mod_strings;
2415 $filesNotWritable = array();
2418 <a href='javascript:void(0); toggleNwFiles(\"filesNw\");'>{$mod_strings['LBL_UW_SHOW_NW_FILES']}</a>
2419 <div id='filesNw' style='display:none;'>
2420 <table cellpadding='3' cellspacing='0' border='0'>
2422 <th align='left'>{$mod_strings['LBL_UW_FILE']}</th>
2423 <th align='left'>{$mod_strings['LBL_UW_FILE_PERMS']}</th>
2424 <th align='left'>{$mod_strings['LBL_UW_FILE_OWNER']}</th>
2425 <th align='left'>{$mod_strings['LBL_UW_FILE_GROUP']}</th>
2428 $isWindows = is_windows();
2429 foreach($files as $file) {
2432 if(!is_writable_windows($file)) {
2433 logThis('WINDOWS: File ['.$file.'] not readable - saving for display');
2434 // don't warn yet - we're going to use this to check against replacement files
2435 // aw: commented out; it's a hack to allow upgrade wizard to continue on windows... will fix later
2436 /*$filesNotWritable[$i] = $file;
2437 $filesNWPerms[$i] = substr(sprintf('%o',fileperms($file)), -4);
2438 $filesOut .= "<tr>".
2439 "<td><span class='error'>{$file}</span></td>".
2440 "<td>{$filesNWPerms[$i]}</td>".
2441 "<td>".$mod_strings['ERR_UW_CANNOT_DETERMINE_USER']."</td>".
2442 "<td>".$mod_strings['ERR_UW_CANNOT_DETERMINE_GROUP']."</td>".
2446 if(!is_writable($file)) {
2447 logThis('File ['.$file.'] not writable - saving for display');
2448 // don't warn yet - we're going to use this to check against replacement files
2449 $filesNotWritable[$i] = $file;
2450 $filesNWPerms[$i] = substr(sprintf('%o',fileperms($file)), -4);
2451 $owner = posix_getpwuid(fileowner($file));
2452 $group = posix_getgrgid(filegroup($file));
2453 $filesOut .= "<tr>".
2454 "<td><span class='error'>{$file}</span></td>".
2455 "<td>{$filesNWPerms[$i]}</td>".
2456 "<td>".$owner['name']."</td>".
2457 "<td>".$group['name']."</td>".
2464 $filesOut .= '</table></div>';
2466 $errors['files']['filesNotWritable'] = (count($filesNotWritable) > 0) ? true : false;
2467 if(count($filesNotWritable) < 1) {
2468 $filesOut = "{$mod_strings['LBL_UW_FILE_NO_ERRORS']}";
2474 function deletePackageOnCancel(){
2475 global $mod_strings;
2476 global $sugar_config;
2477 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
2478 logThis('running delete');
2479 if(!isset($_SESSION['install_file']) || ($_SESSION['install_file'] == "")) {
2480 logThis('ERROR: trying to delete non-existent file: ['.$_REQUEST['install_file'].']');
2481 $error = $mod_strings['ERR_UW_NO_FILE_UPLOADED'];
2483 // delete file in upgrades/patch
2484 $delete_me = "$base_upgrade_dir/patch/".basename(urldecode( $_REQUEST['install_file'] ));
2485 if(@unlink($delete_me)) {
2486 //logThis('unlinking: '.$delete_me);
2487 $out = basename($delete_me).$mod_strings['LBL_UW_FILE_DELETED'];
2489 logThis('ERROR: could not delete ['.$delete_me.']');
2490 $error = $mod_strings['ERR_UW_FILE_NOT_DELETED'].$delete_me;
2493 if(!empty($error)) {
2494 $out = "<b><span class='error'>{$error}</span></b><br />";
2498 function handleExecuteSqlKeys($db, $tableName, $disable)
2500 if(empty($tableName)) return true;
2501 if(is_callable(array($db, "supports"))) {
2503 return $disable?$db->disableKeys($tableName):$db->enableKeys($tableName);
2506 $op = $disable?"DISABLE":"ENABLE";
2507 return $db->query("ALTER TABLE $tableName $op KEYS");
2511 function parseAndExecuteSqlFile($sqlScript,$forStepQuery='',$resumeFromQuery='')
2513 global $sugar_config;
2514 $alterTableSchema = '';
2515 $sqlErrors = array();
2516 if(!isset($_SESSION['sqlSkippedQueries'])){
2517 $_SESSION['sqlSkippedQueries'] = array();
2519 $db = DBManagerFactory::getInstance();
2520 $disable_keys = ($db->dbType == "mysql"); // have to use old way for now for upgrades
2521 if(strpos($resumeFromQuery,",") != false){
2522 $resumeFromQuery = explode(",",$resumeFromQuery);
2524 if(file_exists($sqlScript)) {
2525 $fp = fopen($sqlScript, 'r');
2526 $contents = stream_get_contents($fp);
2527 $anyScriptChanges =$contents;
2528 $resumeAfterFound = false;
2532 while($line = fgets($fp)) {
2533 if(strpos($line, '--') === false) {
2534 $completeLine .= " ".trim($line);
2535 if(strpos($line, ';') !== false) {
2537 $query = str_replace(';','',$completeLine);
2538 //if resume from query is not null then find out from where
2539 //it should start executing the query.
2541 if($query != null && $resumeFromQuery != null){
2542 if(!$resumeAfterFound){
2543 if(strpos($query,",") != false){
2544 $queArray = explode(",",$query);
2545 for($i=0;$i<sizeof($resumeFromQuery);$i++){
2546 if(strcasecmp(trim($resumeFromQuery[$i]),trim($queArray[$i]))==0){
2547 $resumeAfterFound = true;
2549 $resumeAfterFound = false;
2555 elseif(strcasecmp(trim($resumeFromQuery),trim($query))==0){
2556 $resumeAfterFound = true;
2559 if($resumeAfterFound){
2562 // if $count=1 means it is just found so skip the query. Run the next one
2563 if($query != null && $resumeAfterFound && $count >1){
2564 $tableName = getAlterTable($query);
2567 handleExecuteSqlKeys($db, $tableName, true);
2570 if($db->checkError()){
2571 //put in the array to use later on
2572 $_SESSION['sqlSkippedQueries'][] = $query;
2576 handleExecuteSqlKeys($db, $tableName, false);
2578 $progQuery[$forStepQuery]=$query;
2579 post_install_progress($progQuery,$action='set');
2582 elseif($query != null){
2583 $tableName = getAlterTable($query);
2586 handleExecuteSqlKeys($db, $tableName, true);
2591 handleExecuteSqlKeys($db, $tableName, false);
2593 $progQuery[$forStepQuery]=$query;
2594 post_install_progress($progQuery,$action='set');
2595 if($db->checkError()){
2596 //put in the array to use later on
2597 $_SESSION['sqlSkippedQueries'][] = $query;
2609 function getAlterTable($query){
2610 $query = strtolower($query);
2611 if (preg_match('/^\s*alter\s+table\s+/', $query)) {
2612 $sqlArray = explode(" ", $query);
2613 $key = array_search('table', $sqlArray);
2614 return $sqlArray[($key+1)];
2620 function set_upgrade_vars(){
2621 logThis('setting session variables...');
2622 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2623 if(!is_dir($upgrade_progress_dir)){
2624 mkdir_recursive($upgrade_progress_dir);
2626 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2627 if(file_exists($upgrade_progress_file)){
2628 include($upgrade_progress_file);
2631 fopen($upgrade_progress_file, 'w+');
2633 if(!isset($upgrade_config) || $upgrade_config == null){
2634 $upgrade_config = array();
2635 $upgrade_config[1]['upgrade_vars']=array();
2637 if(isset($upgrade_config[1]) && isset($upgrade_config[1]['upgrade_vars']) && !is_array($upgrade_config[1]['upgrade_vars'])){
2638 $upgrade_config[1]['upgrade_vars'] = array();
2641 if(!isset($upgrade_vars) || $upgrade_vars == NULL){
2642 $upgrade_vars = array();
2644 if(isset($_SESSION['unzip_dir']) && !empty($_SESSION['unzip_dir']) && file_exists($_SESSION['unzip_dir'])){
2645 $upgrade_vars['unzip_dir']=$_SESSION['unzip_dir'];
2647 if(isset($_SESSION['install_file']) && !empty($_SESSION['install_file']) && file_exists($_SESSION['install_file'])){
2648 $upgrade_vars['install_file']=$_SESSION['install_file'];
2650 if(isset($_SESSION['Upgraded451Wizard']) && !empty($_SESSION['Upgraded451Wizard'])){
2651 $upgrade_vars['Upgraded451Wizard']=$_SESSION['Upgraded451Wizard'];
2653 if(isset($_SESSION['license_shown']) && !empty($_SESSION['license_shown'])){
2654 $upgrade_vars['license_shown']=$_SESSION['license_shown'];
2656 if(isset($_SESSION['Initial_451to500_Step']) && !empty($_SESSION['Initial_451to500_Step'])){
2657 $upgrade_vars['Initial_451to500_Step']=$_SESSION['Initial_451to500_Step'];
2659 if(isset($_SESSION['zip_from_dir']) && !empty($_SESSION['zip_from_dir'])){
2660 $upgrade_vars['zip_from_dir']=$_SESSION['zip_from_dir'];
2662 //place into the upgrade_config array and rewrite config array only if new values are being inserted
2663 if(isset($upgrade_vars) && $upgrade_vars != null && sizeof($upgrade_vars) > 0){
2664 foreach($upgrade_vars as $key=>$val){
2665 if($key != null && $val != null){
2666 $upgrade_config[1]['upgrade_vars'][$key]=$upgrade_vars[$key];
2669 ksort($upgrade_config);
2670 if(is_writable($upgrade_progress_file) && write_array_to_file( "upgrade_config", $upgrade_config,
2671 $upgrade_progress_file)) {
2672 //writing to the file
2677 function initialize_session_vars(){
2678 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2679 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2680 if(file_exists($upgrade_progress_file)){
2681 include($upgrade_progress_file);
2682 if(isset($upgrade_config) && $upgrade_config != null && is_array($upgrade_config) && sizeof($upgrade_config) >0){
2683 $currVarsArray=$upgrade_config[1]['upgrade_vars'];
2684 //print_r($currVarsArray);
2685 if(isset($currVarsArray) && $currVarsArray != null && is_array($currVarsArray) && sizeof($currVarsArray)>0){
2686 foreach($currVarsArray as $key=>$val){
2687 if($key != null && $val !=null){
2688 //set session variables
2689 $_SESSION[$key]=$val;
2698 //track the upgrade progress on each step
2699 //track the upgrade progress on each step
2700 function set_upgrade_progress($currStep,$currState,$currStepSub='',$currStepSubState=''){
2702 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2703 if(!is_dir($upgrade_progress_dir)){
2704 mkdir_recursive($upgrade_progress_dir);
2706 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2707 if(file_exists($upgrade_progress_file)){
2708 include($upgrade_progress_file);
2711 if(function_exists('sugar_fopen')){
2712 sugar_fopen($upgrade_progress_file, 'w+');
2715 fopen($upgrade_progress_file, 'w+');
2718 if(!isset($upgrade_config) || $upgrade_config == null){
2719 $upgrade_config = array();
2720 $upgrade_config[1]['upgrade_vars']=array();
2722 if(!is_array($upgrade_config[1]['upgrade_vars'])){
2723 $upgrade_config[1]['upgrade_vars'] = array();
2725 if($currStep != null && $currState != null){
2726 if(sizeof($upgrade_config) > 0){
2727 if($currStepSub != null && $currStepSubState !=null){
2728 //check if new status to be set or update
2729 //get the latest in array. since it has sub components prepare an array
2730 if(!empty($upgrade_config[sizeof($upgrade_config)][$currStep]) && is_array($upgrade_config[sizeof($upgrade_config)][$currStep])){
2731 $latestStepSub = currSubStep($upgrade_config[sizeof($upgrade_config)][$currStep]);
2732 if($latestStepSub == $currStepSub){
2733 $upgrade_config[sizeof($upgrade_config)][$currStep][$latestStepSub]=$currStepSubState;
2734 $upgrade_config[sizeof($upgrade_config)][$currStep][$currStep] = $currState;
2737 $upgrade_config[sizeof($upgrade_config)][$currStep][$currStepSub]=$currStepSubState;
2738 $upgrade_config[sizeof($upgrade_config)][$currStep][$currStep] = $currState;
2742 $currArray = array();
2743 $currArray[$currStep] = $currState;
2744 $currArray[$currStepSub] = $currStepSubState;
2745 $upgrade_config[sizeof($upgrade_config)+1][$currStep] = $currArray;
2749 //get the current upgrade progress
2750 $latestStep = get_upgrade_progress();
2751 //set the upgrade progress
2752 if($latestStep == $currStep){
2753 //update the current step with new progress status
2754 $upgrade_config[sizeof($upgrade_config)][$latestStep]=$currState;
2758 $upgrade_config[sizeof($upgrade_config)+1][$currStep]=$currState;
2760 // now check if there elements within array substeps
2764 //set the upgrade progress (just starting)
2765 $upgrade_config[sizeof($upgrade_config)+1][$currStep]= $currState;
2768 if(is_writable($upgrade_progress_file) && write_array_to_file( "upgrade_config", $upgrade_config,
2769 $upgrade_progress_file)) {
2770 //writing to the file
2776 function get_upgrade_progress(){
2777 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2778 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2781 if(file_exists($upgrade_progress_file)){
2782 include($upgrade_progress_file);
2783 if(!isset($upgrade_config) || $upgrade_config == null){
2784 $upgrade_config = array();
2786 if($upgrade_config != null && sizeof($upgrade_config) >1){
2787 $currArr = $upgrade_config[sizeof($upgrade_config)];
2788 if(is_array($currArr)){
2789 foreach($currArr as $key=>$val){
2797 function currSubStep($currStep){
2799 if(is_array($currStep)){
2800 foreach($currStep as $key=>$val){
2808 function currUpgradeState($currState){
2810 if(is_array($currState)){
2811 foreach($currState as $key=>$val){
2813 foreach($val as $k=>$v){
2827 function didThisStepRunBefore($step,$SubStep=''){
2828 if($step == null) return;
2829 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2830 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2833 if(file_exists($upgrade_progress_file)){
2834 include($upgrade_progress_file);
2835 if(isset($upgrade_config) && $upgrade_config != null && is_array($upgrade_config) && sizeof($upgrade_config) >0){
2836 for($i=1;$i<=sizeof($upgrade_config);$i++){
2837 if(is_array($upgrade_config[$i])){
2838 foreach($upgrade_config[$i] as $key=>$val){
2840 if(is_array($upgrade_config[$i][$step])){
2842 foreach ($upgrade_config[$i][$step] as $k=>$v){
2844 foreach($v as $k1=>$v1){
2845 if($SubStep != null){
2846 if($SubStep ==$k1 && $v1=='done'){
2853 elseif($SubStep !=null){
2854 if($SubStep==$k && $v=='done'){
2859 elseif($step==$k && $v=='done'){
2865 elseif($val=='done'){
2879 //get and set post install status
2880 function post_install_progress($progArray='',$action=''){
2881 $upgrade_progress_dir = sugar_cached('upgrades/temp');
2882 $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2883 if($action=='' || $action=='get'){
2884 //get the state of post install
2885 $currProg = array();
2886 if(file_exists($upgrade_progress_file)){
2887 include($upgrade_progress_file);
2888 if(is_array($upgrade_config[sizeof($upgrade_config)]['commit']['post_install']) && sizeof($upgrade_config[sizeof($upgrade_config)]['commit']['post_install'])>0){
2889 foreach($upgrade_config[sizeof($upgrade_config)]['commit']['post_install'] as $k=>$v){
2896 elseif($action=='set'){
2897 if(!is_dir($upgrade_progress_dir)){
2898 mkdir($upgrade_progress_dir);
2900 if(file_exists($upgrade_progress_file)){
2901 include($upgrade_progress_file);
2904 fopen($upgrade_progress_file, 'w+');
2906 if(!is_array($upgrade_config[sizeof($upgrade_config)]['commit']['post_install'])){
2907 $upgrade_config[sizeof($upgrade_config)]['commit']['post_install']=array();
2908 $upgrade_config[sizeof($upgrade_config)]['commit']['post_install']['post_install'] = 'in_progress';
2910 if($progArray != null && is_array($progArray)){
2911 foreach($progArray as $key=>$val){
2912 $upgrade_config[sizeof($upgrade_config)]['commit']['post_install'][$key]=$val;
2915 if(is_writable($upgrade_progress_file) && write_array_to_file( "upgrade_config", $upgrade_config,
2916 $upgrade_progress_file)) {
2917 //writing to the file
2922 function repairDBForUpgrade($execute=false,$path=''){
2924 global $current_user, $beanFiles;
2926 set_time_limit(3600);
2928 $db = &DBManagerFactory::getInstance();
2930 VardefManager::clearVardef();
2931 require_once('include/ListView/ListView.php');
2932 foreach ($beanFiles as $bean => $file) {
2933 require_once ($file);
2934 $focus = new $bean ();
2935 $sql .= $db->repairTable($focus, $execute);
2939 $olddictionary = $dictionary;
2940 unset ($dictionary);
2941 include ('modules/TableDictionary.php');
2942 foreach ($dictionary as $meta) {
2943 $tablename = $meta['table'];
2944 $fielddefs = $meta['fields'];
2945 $indices = $meta['indices'];
2946 $sql .= $db->repairTableParams($tablename, $fielddefs, $indices, $execute);
2949 foreach (explode("\n", $sql) as $line) {
2950 if (!empty ($line) && substr($line, -2) != "*/") {
2953 $qry_str .= $line . "\n";
2964 preg_replace('#(/\*.+?\*/\n*)#', '', $qry_str)
2966 logThis("*******START EXECUTING DB UPGRADE QUERIES***************",$path);
2967 logThis($sql,$path);
2968 logThis("*******END EXECUTING DB UPGRADE QUERIES****************",$path);
2977 * upgradeUserPreferences
2978 * This method updates the user_preferences table and sets the pages/dashlets for users
2979 * which have ACL access to Trackers so that the Tracker dashlets are set in their user perferences
2982 function upgradeUserPreferences() {
2983 global $sugar_config, $sugar_version;
2984 $uw_strings = return_module_language($GLOBALS['current_language'], 'UpgradeWizard');
2986 $localization = new Localization();
2987 $localeCoreDefaults = $localization->getLocaleConfigDefaults();
2989 // check the current system wide default_locale_name_format and add it to the list if it's not there
2990 if(empty($sugar_config['name_formats'])) {
2991 $sugar_config['name_formats'] = $localeCoreDefaults['name_formats'];
2992 if(!rebuildConfigFile($sugar_config, $sugar_version)) {
2993 $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
2997 $currentDefaultLocaleNameFormat = $sugar_config['default_locale_name_format'];
2999 if ($localization->isAllowedNameFormat($currentDefaultLocaleNameFormat)) {
3000 upgradeLocaleNameFormat($currentDefaultLocaleNameFormat);
3002 $sugar_config['default_locale_name_format'] = $localeCoreDefaults['default_locale_name_format'];
3003 if(!rebuildConfigFile($sugar_config, $sugar_version)) {
3004 $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
3006 $localization->createInvalidLocaleNameFormatUpgradeNotice();
3009 $db = &DBManagerFactory::getInstance();
3010 $result = $db->query("SELECT id FROM users where deleted = '0'");
3011 while($row = $db->fetchByAssoc($result))
3013 $current_user = new User();
3014 $current_user->retrieve($row['id']);
3016 // 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
3017 $currentUserNameFormat = $current_user->getPreference('default_locale_name_format');
3018 if ($localization->isAllowedNameFormat($currentUserNameFormat)) {
3019 upgradeLocaleNameFormat($currentUserNameFormat);
3021 $current_user->setPreference('default_locale_name_format', 's f l', 0, 'global');
3022 $current_user->savePreferencesToDB();
3030 * Checks if a locale name format is part of the default list, if not adds it to the config
3031 * @param $name_format string a local name format string such as 's f l'
3032 * @return bool true on successful write to config file, false on failure;
3034 function upgradeLocaleNameFormat($name_format) {
3035 global $sugar_config, $sugar_version;
3037 $localization = new Localization();
3038 $localeConfigDefaults = $localization->getLocaleConfigDefaults();
3040 $uw_strings = return_module_language($GLOBALS['current_language'], 'UpgradeWizard');
3041 if(empty($sugar_config['name_formats'])) {
3042 $sugar_config['name_formats'] = $localeConfigDefaults['name_formats'];
3043 if(!rebuildConfigFile($sugar_config, $sugar_version)) {
3044 $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
3047 if (!in_array($name_format, $sugar_config['name_formats'])) {
3048 $new_config = sugarArrayMerge($sugar_config['name_formats'], array($name_format=>$name_format));
3049 $sugar_config['name_formats'] = $new_config;
3050 if(!rebuildConfigFile($sugar_config, $sugar_version)) {
3051 $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
3060 function add_custom_modules_favorites_search(){
3061 $module_directories = scandir('modules');
3063 foreach($module_directories as $module_dir){
3064 if($module_dir == '.' || $module_dir == '..' || !is_dir("modules/{$module_dir}")){
3069 preg_match('/^[a-z0-9]{1,5}_[a-z0-9_]+$/i' , $module_dir, $matches);
3071 // Make sure the module was created by module builder
3072 if(empty($matches)){
3076 $full_module_dir = "modules/{$module_dir}/";
3077 $read_searchdefs_from = "{$full_module_dir}/metadata/searchdefs.php";
3078 $read_SearchFields_from = "{$full_module_dir}/metadata/SearchFields.php";
3079 $read_custom_SearchFields_from = "custom/{$full_module_dir}/metadata/SearchFields.php";
3081 // Studio can possibly override this file, so we check for a custom version of it
3082 if(file_exists("custom/{$full_module_dir}/metadata/searchdefs.php")){
3083 $read_searchdefs_from = "custom/{$full_module_dir}/metadata/searchdefs.php";
3086 if(file_exists($read_searchdefs_from) && file_exists($read_SearchFields_from)){
3089 require($read_searchdefs_from);
3090 foreach($searchdefs[$module_dir]['layout']['basic_search'] as $sf_array){
3091 if(isset($sf_array['name']) && $sf_array['name'] == 'favorites_only'){
3096 require($read_SearchFields_from);
3097 if(isset($searchFields[$module_dir]['favorites_only'])){
3101 if(!$found_sf1 && !$found_sf2){
3102 $searchdefs[$module_dir]['layout']['basic_search']['favorites_only'] = array('name' => 'favorites_only','label' => 'LBL_FAVORITES_FILTER','type' => 'bool',);
3103 $searchdefs[$module_dir]['layout']['advanced_search']['favorites_only'] = array('name' => 'favorites_only','label' => 'LBL_FAVORITES_FILTER','type' => 'bool',);
3104 $searchFields[$module_dir]['favorites_only'] = array(
3105 'query_type'=>'format',
3106 'operator' => 'subquery',
3107 'subquery' => 'SELECT sugarfavorites.record_id FROM sugarfavorites
3108 WHERE sugarfavorites.deleted=0
3109 and sugarfavorites.module = \''.$module_dir.'\'
3110 and sugarfavorites.assigned_user_id = \'{0}\'',
3111 'db_field'=>array('id')
3114 if(!is_dir("custom/{$full_module_dir}/metadata")){
3115 mkdir_recursive("custom/{$full_module_dir}/metadata");
3117 $success_sf1 = write_array_to_file('searchdefs', $searchdefs, "custom/{$full_module_dir}/metadata/searchdefs.php");
3118 $success_sf2 = write_array_to_file('searchFields', $searchFields, "{$full_module_dir}/metadata/SearchFields.php");
3121 logThis("add_custom_modules_favorites_search failed for searchdefs.php for {$module_dir}");
3124 logThis("add_custom_modules_favorites_search failed for SearchFields.php for {$module_dir}");
3126 if($success_sf1 && $success_sf2){
3127 logThis("add_custom_modules_favorites_search successfully updated searchdefs and searchFields for {$module_dir}");
3136 * upgradeModulesForTeamsets
3138 * This method adds the team_set_id values to the module tables that have the new team_set_id column
3139 * added through the SugarCRM 5.5.x upgrade process. It also adds the values into the team_sets and
3140 * team_sets_teams tables.
3142 * @param filter Array of modules to process; empty by default
3144 function upgradeModulesForTeamsets($filter=array()) {
3145 require('include/modules.php');
3146 foreach($beanList as $moduleName=>$beanName) {
3147 if(!empty($filter) && array_search($moduleName, $filter) === false) {
3150 if($moduleName == 'TeamMemberships' || $moduleName == 'ForecastOpportunities'){
3153 $bean = loadBean($moduleName);
3155 empty($bean->table_name)) {
3159 $FieldArray = $GLOBALS['db']->helper->get_columns($bean->table_name);
3160 if(!isset($FieldArray['team_id'])) {
3164 upgradeTeamColumn($bean, 'team_id');
3168 //Upgrade users table
3169 $bean = loadBean('Users');
3170 upgradeTeamColumn($bean, 'default_team');
3171 $result = $GLOBALS['db']->query("SELECT id FROM teams where deleted=0");
3172 while($row = $GLOBALS['db']->fetchByAssoc($result)) {
3173 $teamset = new TeamSet();
3174 $teamset->addTeams($row['id']);
3181 * Helper function to create a team_set_id column and also set team_set_id column
3182 * to have the value of the $column_name parameter
3184 * @param $bean SugarBean which we are adding team_set_id column to
3185 * @param $column_name The name of the column containing the default team_set_id value
3187 function upgradeTeamColumn($bean, $column_name) {
3188 //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
3189 //module that does not use the SugarObjects
3190 if(empty($bean->field_defs['team_set_id']) && $bean->module_dir != 'Trackers'){
3192 //at this point we could assume that since we have a team_id defined and not a team_set_id that we need to
3193 //add that field and the corresponding relationships
3194 $object = $bean->object_name;
3195 $module = $bean->module_dir;
3196 $object_name = $object;
3197 $_object_name = strtolower($object_name);
3199 if(!empty($GLOBALS['dictionary'][$object]['table'])){
3200 $table_name = $GLOBALS['dictionary'][$object]['table'];
3202 $table_name = strtolower($module);
3205 $path = 'include/SugarObjects/implements/team_security/vardefs.php';
3207 //go through each entry in the vardefs from team_security and unset anything that is already set in the core module
3208 //this will ensure we have the proper ordering.
3209 $fieldDiff = array_diff_assoc($vardefs['fields'], $GLOBALS['dictionary'][$bean->object_name]['fields']);
3211 $file = 'custom/Extension/modules/' . $bean->module_dir. '/Ext/Vardefs/teams.php';
3212 $contents = "<?php\n";
3213 if(!empty($fieldDiff)){
3214 foreach($fieldDiff as $key => $val){
3215 $contents .= "\n\$GLOBALS['dictionary']['". $object . "']['fields']['". $key . "']=" . var_export_helper($val) . ";";
3218 $relationshipDiff = array_diff_assoc($vardefs['relationships'], $GLOBALS['dictionary'][$bean->object_name]['relationships']);
3219 if(!empty($relationshipDiff)){
3220 foreach($relationshipDiff as $key => $val){
3221 $contents .= "\n\$GLOBALS['dictionary']['". $object . "']['relationships']['". $key . "']=" . var_export_helper($val) . ";";
3224 $indexDiff = array_diff_assoc($vardefs['indices'], $GLOBALS['dictionary'][$bean->object_name]['indices']);
3225 if(!empty($indexDiff)){
3226 foreach($indexDiff as $key => $val){
3227 $contents .= "\n\$GLOBALS['dictionary']['". $object . "']['indices']['". $key . "']=" . var_export_helper($val) . ";";
3230 if( $fh = @sugar_fopen( $file, 'wt' ) )
3232 fputs( $fh, $contents);
3237 //we have written out the teams.php into custom/Extension/modules/{$module_dir}/Ext/Vardefs/teams.php'
3238 //now let's merge back into vardefs.ext.php
3239 require_once('ModuleInstall/ModuleInstaller.php');
3240 $mi = new ModuleInstaller();
3241 $mi->merge_files('Ext/Vardefs/', 'vardefs.ext.php');
3242 VardefManager::loadVardef($bean->module_dir, $bean->object_name, true);
3243 $bean->field_defs = $GLOBALS['dictionary'][$bean->object_name]['fields'];
3246 if(isset($bean->field_defs['team_set_id'])) {
3247 //Create the team_set_id column
3248 $FieldArray = $GLOBALS['db']->helper->get_columns($bean->table_name);
3249 if(!isset($FieldArray['team_set_id'])) {
3250 $GLOBALS['db']->addColumn($bean->table_name, $bean->field_defs['team_set_id']);
3252 $indexArray = $GLOBALS['db']->helper->get_indices($bean->table_name);
3254 $indexName = getValidDBName('idx_'.strtolower($bean->table_name).'_tmst_id', true, 34);
3257 'name' => $indexName,
3259 'fields' => array('team_set_id')
3262 if(!isset($indexArray[$indexName])) {
3263 $GLOBALS['db']->addIndexes($bean->table_name, $indexDef);
3266 //Update the table's team_set_id column to have the same values as team_id
3267 $GLOBALS['db']->query("UPDATE {$bean->table_name} SET team_set_id = {$column_name}");
3272 * Update the folder subscription table which confirms to the team security mechanism but
3273 * the class SugarFolders does not extend SugarBean and is therefore never picked up by the
3274 * upgradeModulesForTeamsets function.
3276 function upgradeFolderSubscriptionsTeamSetId()
3278 logThis("In upgradeFolderSubscriptionsTeamSetId()");
3279 $query = "UPDATE folders SET team_set_id = team_id";
3280 $result = $GLOBALS['db']->query($query);
3281 logThis("Finished upgradeFolderSubscriptionsTeamSetId()");
3285 * upgradeModulesForTeam
3287 * This method update the associated_user_id, name, name_2 to the private team records on teams table
3288 * This function is used for upgrade process from 5.1.x and 5.2.x.
3291 function upgradeModulesForTeam() {
3292 logThis("In upgradeModulesForTeam()");
3293 $result = $GLOBALS['db']->query("SELECT id, user_name, first_name, last_name FROM users where deleted=0");
3295 while($row = $GLOBALS['db']->fetchByAssoc($result)) {
3296 $results2 = $GLOBALS['db']->query("SELECT id FROM teams WHERE name = '({$row['user_name']})'");
3298 if(!$assoc = $GLOBALS['db']->fetchByAssoc($results2)) {
3299 //if team does not exist, then lets create the team for this user
3302 $user->retrieve($row['id']);
3303 $team->new_user_created($user);
3304 $team_id = $team->id;
3306 $team_id =$assoc['id'];
3310 $name = is_null($row['first_name'])?'':$row['first_name'];
3311 $name_2 = is_null($row['last_name'])?'':$row['last_name'];
3312 $associated_user_id = $row['id'];
3315 //Ensure team->name is not empty by using team->name_2 if available
3316 if(empty($name) && !empty($name_2)) {
3321 $query = "UPDATE teams SET name = '{$name}', name_2 = '{$name_2}', associated_user_id = '{$associated_user_id}' WHERE id = '{$team_id}'";
3322 $GLOBALS['db']->query($query);
3325 //Update the team_set_id and default_team columns
3326 $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'));
3328 //Update team_set_id
3329 if($ce_to_pro_or_ent) {
3330 $GLOBALS['db']->query("update users set team_set_id = (select teams.id from teams where teams.associated_user_id = users.id)");
3331 $GLOBALS['db']->query("update users set default_team = (select teams.id from teams where teams.associated_user_id = users.id)");
3337 function addNewSystemTabsFromUpgrade($from_dir){
3339 if(isset($_SESSION['upgrade_from_flavor'])){
3341 //check to see if there are any new files that need to be added to systems tab
3342 //retrieve old modules list
3343 logThis('check to see if new modules exist',$path);
3344 $oldModuleList = array();
3345 $newModuleList = array();
3346 include($from_dir.'/include/modules.php');
3347 $oldModuleList = $moduleList;
3348 include('include/modules.php');
3349 $newModuleList = $moduleList;
3351 //include tab controller
3352 require_once('modules/MySettings/TabController.php');
3353 $newTB = new TabController();
3355 //make sure new modules list has a key we can reference directly
3356 $newModuleList = $newTB->get_key_array($newModuleList);
3357 $oldModuleList = $newTB->get_key_array($oldModuleList);
3359 //iterate through list and remove commonalities to get new modules
3360 foreach ($newModuleList as $remove_mod){
3361 if(in_array($remove_mod, $oldModuleList)){
3362 unset($newModuleList[$remove_mod]);
3365 //new modules list now has left over modules which are new to this install, so lets add them to the system tabs
3366 logThis('new modules to add are '.var_export($newModuleList,true),$path);
3368 if(!empty($newModuleList))
3370 //grab the existing system tabs
3371 $tabs = $newTB->get_system_tabs();
3373 //add the new tabs to the array
3374 foreach($newModuleList as $nm ){
3378 $newTB->set_system_tabs($tabs);
3380 logThis('module tabs updated',$path);
3386 * This method attempts to fix dropdown lists that were incorrectly named.
3387 * There were versions of SugarCRM that did not enforce naming convention rules
3388 * for the dropdown list field name. This method attempts to resolve that by
3389 * fixing the language files that may have been affected and then updating the
3390 * fields_meta_data table accordingly. It also refreshes any vardefs that may
3391 * have been affected.
3394 function fix_dropdown_list() {
3395 if(file_exists('custom/include/language')) {
3397 $affected_modules = array();
3398 $affected_keys = array();
3400 getFiles($files, 'custom/include/language', '/\.php$/i');
3401 foreach($files as $file) {
3403 if(file_exists($file . '.bak')) {
3404 $bak_mod_time = filemtime($file . '.bak');
3405 $php_mod_time = filemtime($file);
3406 //We're saying if the .php file was modified 30 seconds no more than php.bak file then we
3407 //run these additional cleanup checks
3408 if($php_mod_time - $bak_mod_time < 30) {
3410 $app_list_strings = array();
3411 $GLOBALS['app_list_strings'] = array();
3412 require($file . '.bak');
3413 $bak_app_list_strings = array_merge($app_list_strings, $GLOBALS['app_list_strings']);
3415 $app_list_strings = array();
3416 $GLOBALS['app_list_strings'] = array();
3418 $php_app_list_strings = array_merge($app_list_strings, $GLOBALS['app_list_strings']);
3420 //Get the file contents
3421 $contents = file_get_contents($file);
3423 //Now simulate a fix for the file before we compare w/ the .php file
3424 //we also append to the $contents
3425 foreach($bak_app_list_strings as $key=>$entry) {
3426 if(preg_match('/([^A-Za-z_])/', $key, $matches) && is_array($entry)) {
3427 $new_key = preg_replace('/[^A-Za-z_]/', '_', $key);
3428 $bak_app_list_strings[$new_key] = $bak_app_list_strings[$key];
3429 unset($bak_app_list_strings[$key]);
3430 //Now if the entry doesn't exists in the .php file, then add to contents
3431 if(!isset($php_app_list_strings[$new_key])) {
3432 $contents .= "\n\$GLOBALS['app_list_strings']['{$new_key}'] = " . var_export_helper($bak_app_list_strings[$new_key]) . ";";
3437 //Now load the .php file to do the comparison
3438 foreach($php_app_list_strings as $key=>$entry) {
3439 if(isset($bak_app_list_strings[$key])) {
3440 $diff = array_diff($bak_app_list_strings[$key], $entry);
3442 //There is a difference, so copy the $bak_app_list_strings version into the .php file
3443 $contents .= "\n\$GLOBALS['app_list_strings']['{$key}'] = " . var_export_helper($bak_app_list_strings[$key]) . ";";
3448 //Now write out the file contents
3449 //Create backup just in case
3450 copy($file, $file . '.php_bak');
3451 $fp = @sugar_fopen($file, 'w');
3453 fwrite($fp, $contents);
3456 $GLOBALS['log']->error("Unable to update file contents in fix_dropdown_list for {$file}");
3461 unset($GLOBALS['app_strings']);
3462 unset($GLOBALS['app_list_strings']);
3463 $app_list_strings = array();
3466 $contents = file_get_contents($file);
3467 if ( !isset($GLOBALS['app_list_strings']) ) {
3468 $GLOBALS['app_list_strings'] = $app_list_strings;
3471 $GLOBALS['app_list_strings'] = array_merge($app_list_strings, $GLOBALS['app_list_strings']);
3474 if(isset($GLOBALS['app_list_strings']) && is_array($GLOBALS['app_list_strings'])) {
3475 foreach($GLOBALS['app_list_strings'] as $key=>$entry) {
3476 if(preg_match('/([^A-Za-z_])/', $key, $matches) && is_array($entry)) {
3477 $result = $GLOBALS['db']->query("SELECT custom_module FROM fields_meta_data WHERE ext1 = '{$key}'");
3478 if(!empty($result)) {
3479 while($row = $GLOBALS['db']->fetchByAssoc($result)) {
3480 $custom_module = $row['custom_module'];
3481 if(!empty($GLOBALS['beanList'][$custom_module])) {
3482 $affected_modules[$custom_module] = $GLOBALS['beanList'][$custom_module];
3487 //Replace all invalid characters with '_' character
3488 $new_key = preg_replace('/[^A-Za-z_]/', '_', $key);
3489 $affected_keys[$key] = $new_key;
3491 $GLOBALS['app_list_strings'][$new_key] = $GLOBALS['app_list_strings'][$key];
3492 unset($GLOBALS['app_list_strings'][$key]);
3494 $pattern_match = "/(\[\s*\'{$key}\'\s*\])/";
3495 $new_key = "['{$new_key}']";
3496 $out = preg_replace($pattern_match, $new_key, $contents);
3502 //This is a check for g => h instances where the file contents were incorrectly written
3503 //and also fixes the scenario where via a UI upgrade, the app_list_strings were incorrectly
3504 //merged with app_list_strings variables declared elsewhere
3506 if(preg_match('/\$GLOBALS\s*\[\s*[\"|\']app_list_strings[\"|\']\s*\]\s*=\s*array\s*\(/', $contents)) {
3507 //Now also remove all the non-custom labels that were added
3508 if(preg_match('/language\/([^\.]+)\.lang\.php$/', $file, $matches)) {
3509 $language = $matches[1];
3511 $app_list_strings = array();
3513 if(file_exists("include/language/$language.lang.php")) {
3514 include("include/language/$language.lang.php");
3516 if(file_exists("include/language/$language.lang.override.php")) {
3517 $app_list_strings = _mergeCustomAppListStrings("include/language/$language.lang.override.php" , $app_list_strings) ;
3519 if(file_exists("custom/application/Ext/Language/$language.ext.lang.php")) {
3520 $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$language.ext.lang.php" , $app_list_strings) ;
3522 if(file_exists("custom/application/Ext/Language/$language.lang.ext.php")) {
3523 $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$language.lang.ext.php" , $app_list_strings) ;
3526 $all_non_custom_include_language_strings = $app_strings;
3527 $all_non_custom_include_language_list_strings = $app_list_strings;
3529 $unset_keys = array();
3530 if(!empty($GLOBALS['app_list_strings'])) {
3531 foreach($GLOBALS['app_list_strings'] as $key=>$value) {
3533 if(isset($all_non_custom_include_language_list_strings[$key])) {
3534 $diff = array_diff($all_non_custom_include_language_list_strings[$key], $GLOBALS['app_list_strings'][$key]);
3537 if(!empty($all_non_custom_include_language_list_strings[$key]) && empty($diff)) {
3538 $unset_keys[] = $key;
3543 foreach($unset_keys as $key) {
3544 unset($GLOBALS['app_list_strings'][$key]);
3547 if(!empty($GLOBALS['app_strings'])) {
3548 foreach($GLOBALS['app_strings'] as $key=>$value) {
3549 if(!empty($all_non_custom_include_language_strings[$key])) {
3550 unset($GLOBALS['app_strings'][$key]);
3554 } //if(preg_match...)
3557 if(!empty($GLOBALS['app_strings'])) {
3558 foreach($GLOBALS['app_strings'] as $key=>$entry) {
3559 $out .= "\n\$GLOBALS['app_strings']['$key']=" . var_export_helper($entry) . ";";
3563 foreach($GLOBALS['app_list_strings'] as $key=>$entry) {
3564 $out .= "\n\$GLOBALS['app_list_strings']['$key']=" . var_export_helper($entry) . ";";
3568 } //if(preg_match...)
3572 //Create a backup just in case
3573 copy($file, $file . '.bak');
3574 $fp = @sugar_fopen($file, 'w');
3579 //If we can't update the file, just return
3580 $GLOBALS['log']->error("Unable to update file contents in fix_dropdown_list.");
3588 //Update db entries (the order matters here... need to process database changes first)
3589 if(!empty($affected_keys)) {
3590 foreach($affected_keys as $old_key=>$new_key) {
3591 $GLOBALS['db']->query("UPDATE fields_meta_data SET ext1 = '{$new_key}' WHERE ext1 = '{$old_key}'");
3595 //Update vardef files for affected modules
3596 if(!empty($affected_modules)) {
3597 foreach($affected_modules as $module=>$object) {
3598 VardefManager::refreshVardefs($module, $object);
3605 function update_iframe_dashlets(){
3606 require_once(sugar_cached('dashlets/dashlets.php'));
3608 $db = DBManagerFactory::getInstance();
3609 $query = "SELECT id, contents, assigned_user_id FROM user_preferences WHERE deleted = 0 AND category = 'Home'";
3610 $result = $db->query($query, true, "Unable to update new default dashlets! ");
3611 while ($row = $db->fetchByAssoc($result)) {
3612 $content = unserialize(base64_decode($row['contents']));
3613 $assigned_user_id = $row['assigned_user_id'];
3614 $record_id = $row['id'];
3616 $current_user = new User();
3617 $current_user->retrieve($row['assigned_user_id']);
3619 if(!empty($content['dashlets']) && !empty($content['pages'])){
3620 $originalDashlets = $content['dashlets'];
3621 foreach($originalDashlets as $key => $ds){
3622 if(!empty($ds['options']['url']) && stristr($ds['options']['url'],'http://www.sugarcrm.com/crm/product/gopro')){
3623 unset($originalDashlets[$key]);
3626 $current_user->setPreference('dashlets', $originalDashlets, 0, 'Home');
3633 * convertImageToText
3635 * This method attempts to convert date type image to text on Microsoft SQL Server.
3636 * This method could NOT be used in any other type of datebases.
3638 function convertImageToText($table_name,$column_name){
3639 $set_lang = "SET LANGUAGE us_english";
3640 $GLOBALS['db']->query($set_lang);
3641 if($GLOBALS['db']->lastError()){
3642 logThis('An error occurred when performing this query-->'.$set_lang);
3644 $q="SELECT data_type
3645 FROM INFORMATION_SCHEMA.Tables T JOIN INFORMATION_SCHEMA.Columns C
3646 ON T.TABLE_NAME = C.TABLE_NAME where T.TABLE_NAME = '$table_name' and C.COLUMN_NAME = '$column_name'";
3647 $res= $GLOBALS['db']->query($q);
3648 if($GLOBALS['db']->lastError()){
3649 logThis('An error occurred when performing this query-->'.$q);
3651 $row= $GLOBALS['db']->fetchByAssoc($res);
3653 if(trim(strtolower($row['data_type'])) == 'image'){
3654 $addContent_temp = "alter table {$table_name} add {$column_name}_temp text null";
3655 $GLOBALS['db']->query($addContent_temp);
3656 if($GLOBALS['db']->lastError()){
3657 logThis('An error occurred when performing this query-->'.$addContent_temp);
3659 $qN = "select count=datalength({$column_name}), id, {$column_name} from {$table_name}";
3660 $result = $GLOBALS['db']->query($qN);
3661 while($row = $GLOBALS['db']->fetchByAssoc($result)){
3662 if($row['count'] >8000){
3663 $contentLength = $row['count'];
3666 $convertedContent = '';
3667 while($contentLength >0){
3668 $stepsQuery = "select cont=convert(varchar(max), convert(varbinary(8000), substring({$column_name},{$start},{$next}))) from {$table_name} where id= '{$row['id']}'";
3669 $steContQ = $GLOBALS['db']->query($stepsQuery);
3670 if($GLOBALS['db']->lastError()){
3671 logThis('An error occurred when performing this query-->'.$stepsQuery);
3673 $stepCont = $GLOBALS['db']->fetchByAssoc($steContQ);
3674 if(isset($stepCont['cont'])){
3675 $convertedContent = $convertedContent.$stepCont['cont'];
3677 $start = $start+$next;
3678 $contentLength = $contentLength - $next;
3680 $addContentDataText="update {$table_name} set {$column_name}_temp = '{$convertedContent}' where id= '{$row['id']}'";
3681 $GLOBALS['db']->query($addContentDataText);
3682 if($GLOBALS['db']->lastError()){
3683 logThis('An error occurred when performing this query-->'.$addContentDataText);
3687 $addContentDataText="update {$table_name} set {$column_name}_temp =
3688 convert(varchar(max), convert(varbinary(8000), {$column_name})) where id= '{$row['id']}'";
3689 $GLOBALS['db']->query($addContentDataText);
3690 if($GLOBALS['db']->lastError()){
3691 logThis('An error occurred when performing this query-->'.$addContentDataText);
3695 //drop the contents now and change contents_temp to contents
3696 $dropColumn = "alter table {$table_name} drop column {$column_name}";
3697 $GLOBALS['db']->query($dropColumn);
3698 if($GLOBALS['db']->lastError()){
3699 logThis('An error occurred when performing this query-->'.$dropColumn);
3701 $changeColumnName = "EXEC sp_rename '{$table_name}.[{$column_name}_temp]','{$column_name}','COLUMN'";
3702 $GLOBALS['db']->query($changeColumnName);
3703 if($GLOBALS['db']->lastError()){
3704 logThis('An error occurred when performing this query-->'.$changeColumnName);
3711 * This method attempts to delete all English inline help files.
3712 * This method was introduced by 5.5.0RC2.
3714 function clearHelpFiles(){
3715 $modulePath = clean_path(getcwd() . '/modules');
3716 $allHelpFiles = array();
3717 getFiles($allHelpFiles, $modulePath, "/en_us.help.*/");
3719 foreach( $allHelpFiles as $the_file ){
3720 if( is_file( $the_file ) ){
3721 unlink( $the_file );
3722 logThis("Deleted file: $the_file");
3730 * upgradeDateTimeFields
3732 * This method came from bug: 39757 where the date_end field is a date field and not a datetime field
3733 * which prevents you from performing timezone offset calculations once the data has been saved.
3735 * @param path String location to log file, empty by default
3737 function upgradeDateTimeFields($path)
3741 $meetingsSql = "UPDATE meetings SET date_end = ".$db->convert("date_start", 'add_time', array('duration_hours', 'duration_minutes'));
3742 $callsSql = "UPDATE calls SET date_end = ".$db->convert("date_start", 'add_time', array('duration_hours', 'duration_minutes'));
3743 logThis('upgradeDateTimeFields Meetings SQL:' . $meetingsSql, $path);
3744 $db->query($meetingsSql);
3746 logThis('upgradeDateTimeFields Calls SQL:' . $callsSql, $path);
3747 $db->query($callsSql);
3751 * upgradeDocumentTypeFields
3754 function upgradeDocumentTypeFields($path){
3758 $documentsSql = "UPDATE documents SET doc_type = 'Sugar' WHERE doc_type IS NULL";
3759 $meetingsSql = "UPDATE meetings SET type = 'Sugar' WHERE type IS NULL";
3761 logThis('upgradeDocumentTypeFields Documents SQL:' . $documentsSql, $path);
3762 $db->query($documentsSql);
3763 logThis('upgradeDocumentTypeFields Meetings SQL:' . $meetingsSql, $path);
3764 $db->query($meetingsSql);
3769 * merge_config_si_settings
3770 * This method checks for the presence of a config_si.php file and, if found, merges the configuration
3771 * settings from the config_si.php file into config.php. If a config_si_location parameter value is not
3772 * supplied it will attempt to discover the config_si.php file location from where the executing script
3775 * @param write_to_upgrade_log boolean optional value to write to the upgradeWizard.log file
3776 * @param config_location String optional value to config.php file location
3777 * @param config_si_location String optional value to config_si.php file location
3778 * @param path String file of the location of log file to write to
3779 * @return boolean value indicating whether or not a merge was attempted with config_si.php file
3781 function merge_config_si_settings($write_to_upgrade_log=false, $config_location='', $config_si_location='', $path='')
3783 if(!empty($config_location) && !file_exists($config_location))
3785 if($write_to_upgrade_log)
3787 logThis('config.php file specified in ' . $config_si_location . ' could not be found. Skip merging', $path);
3790 } else if(empty($config_location)) {
3792 //We are assuming this is from the silentUpgrade scripts so argv[3] will point to SugarCRM install location
3793 if(isset($argv[3]) && is_dir($argv[3]))
3795 $config_location = $argv[3] . DIRECTORY_SEPARATOR . 'config.php';
3799 //If config_location is still empty or if the file cannot be found, skip merging
3800 if(empty($config_location) || !file_exists($config_location))
3802 if($write_to_upgrade_log)
3804 logThis('config.php file at (' . $config_location . ') could not be found. Skip merging.', $path);
3808 if($write_to_upgrade_log)
3810 logThis('Loading config.php file at (' . $config_location . ') for merging.', $path);
3813 include($config_location);
3814 if(empty($sugar_config))
3816 if($write_to_upgrade_log)
3818 logThis('config.php contents are empty. Skip merging.', $path);
3824 if(!empty($config_si_location) && !file_exists($config_si_location))
3826 if($write_to_upgrade_log)
3828 logThis('config_si.php file specified in ' . $config_si_location . ' could not be found. Skip merging', $path);
3831 } else if(empty($config_si_location)) {
3832 if(isset($argv[0]) && is_file($argv[0]))
3834 $php_file = $argv[0];
3835 $p_info = pathinfo($php_file);
3836 $php_dir = (isset($p_info['dirname']) && $p_info['dirname'] != '.') ? $p_info['dirname'] . DIRECTORY_SEPARATOR : '';
3837 $config_si_location = $php_dir . 'config_si.php';
3841 //If config_si_location is still empty or if the file cannot be found, skip merging
3842 if(empty($config_si_location) || !file_exists($config_si_location))
3844 if($write_to_upgrade_log)
3846 logThis('config_si.php file at (' . $config_si_location . ') could not be found. Skip merging.', $path);
3850 if($write_to_upgrade_log)
3852 logThis('Loading config_si.php file at (' . $config_si_location . ') for merging.', $path);
3855 include($config_si_location);
3856 if(empty($sugar_config_si))
3858 if($write_to_upgrade_log)
3860 logThis('config_si.php contents are empty. Skip merging.', $path);
3866 //Now perform the merge operation
3868 foreach($sugar_config_si as $key=>$value)
3870 if(!preg_match('/^setup_/', $key) && !isset($sugar_config[$key]))
3872 if($write_to_upgrade_log)
3874 logThis('Merge key (' . $key . ') with value (' . $value . ')', $path);
3876 $sugar_config[$key] = $value;
3883 if($write_to_upgrade_log)
3885 logThis('Update config.php file with new values', $path);
3888 if(!write_array_to_file("sugar_config", $sugar_config, $config_location)) {
3889 if($write_to_upgrade_log)
3891 logThis('*** ERROR: could not write to config.php', $path);
3896 if($write_to_upgrade_log)
3898 logThis('config.php values are in sync with config_si.php values. Skipped merging.');
3903 if($write_to_upgrade_log)
3905 logThis('End merge_config_si_settings', $path);
3912 * upgrade_connectors
3914 * This function handles support for upgrading connectors it is invoked from both end.php and silentUpgrade_step2.php
3917 function upgrade_connectors() {
3918 require_once('include/connectors/utils/ConnectorUtils.php');
3919 if(!ConnectorUtils::updateMetaDataFiles()) {
3920 $GLOBALS['log']->fatal('Cannot update metadata files for connectors');
3923 //Delete the custom connectors.php file if it exists so that it may be properly rebuilt
3924 if(file_exists('custom/modules/Connectors/metadata/connectors.php'))
3926 unlink('custom/modules/Connectors/metadata/connectors.php');
3931 * Enable the InsideView connector for the four default modules.
3933 function upgradeEnableInsideViewConnector($path='')
3935 logThis('Begin upgradeEnableInsideViewConnector', $path);
3937 // Load up the existing mapping and hand it to the InsideView connector to have it setup the correct logic hooks
3938 $mapFile = 'modules/Connectors/connectors/sources/ext/rest/insideview/mapping.php';
3939 if ( file_exists('custom/'.$mapFile) ) {
3940 logThis('Found CUSTOM mappings', $path);
3941 require('custom/'.$mapFile);
3943 logThis('Used default mapping', $path);
3947 require_once('include/connectors/sources/SourceFactory.php');
3948 $source = SourceFactory::getSource('ext_rest_insideview');
3950 // $mapping is brought in from the mapping.php file above
3951 $source->saveMappingHook($mapping);
3953 require_once('include/connectors/utils/ConnectorUtils.php');
3954 ConnectorUtils::installSource('ext_rest_insideview');
3956 // Now time to set the various modules to active, because this part ignores the default config
3957 require(CONNECTOR_DISPLAY_CONFIG_FILE);
3958 // $modules_sources come from that config file
3959 foreach ( $source->allowedModuleList as $module ) {
3960 $modules_sources[$module]['ext_rest_insideview'] = 'ext_rest_insideview';
3962 if(!write_array_to_file('modules_sources', $modules_sources, CONNECTOR_DISPLAY_CONFIG_FILE)) {
3963 //Log error and return empty array
3964 logThis("Cannot write \$modules_sources to " . CONNECTOR_DISPLAY_CONFIG_FILE,$path);
3967 logThis('End upgradeEnableInsideViewConnector', $path);
3971 function repair_long_relationship_names($path='')
3973 logThis("Begin repair_long_relationship_names", $path);
3974 require_once 'modules/ModuleBuilder/parsers/relationships/DeployedRelationships.php' ;
3975 $GLOBALS['mi_remove_tables'] = false;
3977 foreach($GLOBALS['moduleList'] as $module)
3979 $relationships = new DeployedRelationships ($module) ;
3980 foreach($relationships->getRelationshipList() as $rel_name)
3982 if (strlen($rel_name) > 27 && empty($touched[$rel_name]))
3984 logThis("Rebuilding relationship fields for $rel_name", $path);
3985 $touched[$rel_name] = true;
3986 $rel_obj = $relationships->get($rel_name);
3987 $rel_obj->setReadonly(false);
3988 $relationships->delete($rel_name);
3989 $relationships->save();
3990 $relationships->add($rel_obj);
3991 $relationships->save();
3992 $relationships->build () ;
3996 logThis("End repair_long_relationship_names", $path);
3999 function removeSilentUpgradeVarsCache(){
4000 global $silent_upgrade_vars_loaded;
4002 $cacheFileDir = "{$GLOBALS['sugar_config']['cache_dir']}/silentUpgrader";
4003 $cacheFile = "{$cacheFileDir}/silentUpgradeCache.php";
4005 if(file_exists($cacheFile)){
4009 $silent_upgrade_vars_loaded = array(); // Set to empty to reset it
4014 function loadSilentUpgradeVars(){
4015 global $silent_upgrade_vars_loaded;
4017 if(empty($silent_upgrade_vars_loaded)){
4018 $cacheFile = "{$GLOBALS['sugar_config']['cache_dir']}/silentUpgrader/silentUpgradeCache.php";
4019 // We have no pre existing vars
4020 if(!file_exists($cacheFile)){
4021 // Set the vars array so it's loaded
4022 $silent_upgrade_vars_loaded = array('vars' => array());
4025 require_once($cacheFile);
4026 $silent_upgrade_vars_loaded = $silent_upgrade_vars_cache;
4033 function writeSilentUpgradeVars(){
4034 global $silent_upgrade_vars_loaded;
4036 if(empty($silent_upgrade_vars_loaded)){
4037 return false; // You should have set some values before trying to write the silent upgrade vars
4040 $cacheFileDir = "{$GLOBALS['sugar_config']['cache_dir']}/silentUpgrader";
4041 $cacheFile = "{$cacheFileDir}/silentUpgradeCache.php";
4043 require_once('include/dir_inc.php');
4044 if(!mkdir_recursive($cacheFileDir)){
4047 require_once('include/utils/file_utils.php');
4048 if(!write_array_to_file('silent_upgrade_vars_cache', $silent_upgrade_vars_loaded, $cacheFile, 'w')){
4050 logThis("WARNING: writeSilentUpgradeVars could not write to {$cacheFile}", $path);
4057 function setSilentUpgradeVar($var, $value){
4058 if(!loadSilentUpgradeVars()){
4062 global $silent_upgrade_vars_loaded;
4064 $silent_upgrade_vars_loaded['vars'][$var] = $value;
4069 function getSilentUpgradeVar($var){
4070 if(!loadSilentUpgradeVars()){
4074 global $silent_upgrade_vars_loaded;
4076 if(!isset($silent_upgrade_vars_loaded['vars'][$var])){
4080 return $silent_upgrade_vars_loaded['vars'][$var];
4086 * add_unified_search_to_custom_modules_vardefs
4088 * This method calls the repair code to remove the unified_search_modules.php fiel
4091 function add_unified_search_to_custom_modules_vardefs()
4093 if(file_exists($cachefile = sugar_cached('modules/unified_search_modules.php')))
4101 * change from using the older SugarCache in 6.1 and below to the new one in 6.2
4103 function upgradeSugarCache($file)
4105 global $sugar_config;
4106 $cacheUploadUpgradesTemp = mk_temp_dir(sugar_cached('upgrades/temp'));
4108 unzip($file, $cacheUploadUpgradesTemp);
4110 if(!file_exists(clean_path("{$cacheUploadUpgradesTemp}/manifest.php"))) {
4111 logThis("*** ERROR: no manifest file detected while bootstraping upgrade wizard files!");
4114 include(clean_path("{$cacheUploadUpgradesTemp}/manifest.php"));
4117 $from_dir = "{$cacheUploadUpgradesTemp}/{$manifest['copy_files']['from_dir']}";
4118 $allFiles = array();
4119 if(file_exists("$from_dir/include/SugarCache")) {
4120 $allFiles = findAllFiles("$from_dir/include/SugarCache", $allFiles);
4122 if(file_exists("$from_dir/include/database")) {
4123 $allFiles = findAllFiles("$from_dir/include/database", $allFiles);
4125 if(file_exists("$from_dir/include/utils/external_cache.php")) {
4126 $allFiles[] = "$from_dir/include/utils/external_cache.php";
4128 if(file_exists("$from_dir/include/utils/sugar_file_utils.php")) {
4129 $allFiles[] = "$from_dir/include/utils/sugar_file_utils.php";
4131 if(file_exists("$from_dir/include/utils/sugar_file_utils.php")) {
4132 $allFiles[] = "$from_dir/include/utils/sugar_file_utils.php";
4135 foreach($allFiles as $k => $file) {
4136 $destFile = str_replace($from_dir."/", "", $file);
4137 if(!is_dir(dirname($destFile))) {
4138 mkdir_recursive(dirname($destFile)); // make sure the directory exists
4140 if ( stristr($file,'uw_main.tpl') )
4141 logThis('Skipping "'.$file.'" - file copy will during commit step.');
4143 logThis('updating UpgradeWizard code: '.$destFile);
4144 copy_recursive($file, $destFile);
4151 * upgradeDisplayedTabsAndSubpanels
4153 * @param $version String value of current system version (pre upgrade)
4155 function upgradeDisplayedTabsAndSubpanels($version)
4157 if($version < '620')
4159 logThis('start upgrading system displayed tabs and subpanels');
4160 require_once('modules/MySettings/TabController.php');
4161 $tc = new TabController();
4163 //grab the existing system tabs
4164 $tabs = $tc->get_tabs_system();
4166 //add Calls, Meetings, Tasks, Notes, Prospects (Targets) and ProspectLists (Target Lists)
4167 //to displayed tabs unless explicitly set to hidden
4168 $modules_to_add = array('Calls', 'Meetings', 'Tasks', 'Notes', 'Prospects', 'ProspectLists');
4169 $added_tabs = array();
4171 foreach($modules_to_add as $module)
4173 $tabs[0][$module] = $module;
4174 $added_tabs[] = $module;
4177 logThis('calling set_system_tabs on TabController to add tabs: ' . var_export($added_tabs, true));
4178 $tc->set_system_tabs($tabs[0]);
4179 logThis('finish upgrading system displayed tabs and subpanels');
4185 * unlinkUpgradeFiles
4186 * This is a helper function to clean up
4188 * @param $version String value of current system version (pre upgrade)
4190 function unlinkUpgradeFiles($version)
4192 if(!isset($version))
4197 //First check if we even have the scripts_for_patch/files_to_remove directory
4198 require_once('modules/UpgradeWizard/UpgradeRemoval.php');
4201 if(empty($_SESSION['unzip_dir']))
4203 global $sugar_config;
4204 $base_upgrade_dir = $sugar_config['upload_dir'] . "/upgrades";
4205 $base_tmp_upgrade_dir = "$base_upgrade_dir/temp";
4206 $_SESSION['unzip_dir'] = mk_temp_dir( $base_tmp_upgrade_dir );
4210 if(isset($_SESSION['unzip_dir']) && file_exists($_SESSION['unzip_dir'].'/scripts/files_to_remove'))
4212 $files_to_remove = glob($_SESSION['unzip_dir'].'/scripts/files_to_remove/*.php');
4214 foreach($files_to_remove as $script)
4216 if(preg_match('/UpgradeRemoval(\d+)x\.php/', $script, $matches))
4218 $checkVersion = $matches[1] + 1; //Increment by one to check everything equal or below the target version
4219 $upgradeClass = 'UpgradeRemoval' . $matches[1] . 'x';
4220 require_once($_SESSION['unzip_dir'].'/scripts/files_to_remove/' . $upgradeClass . '.php');
4222 //Check to make sure we should load and run this UpgradeRemoval instance
4223 if($checkVersion <= $version && class_exists($upgradeClass))
4225 $upgradeInstance = new $upgradeClass();
4226 if($upgradeInstance instanceof UpgradeRemoval)
4228 logThis('Running UpgradeRemoval instance ' . $upgradeClass);
4229 logThis('Files will be backed up to custom/backup');
4230 $files = $upgradeInstance->getFilesToRemove($version);
4231 foreach($files as $file)
4235 $upgradeInstance->processFilesToRemove($files);
4242 //Check if we have a custom directory
4243 if(file_exists('custom/scripts/files_to_remove'))
4246 $files_to_remove = glob('custom/scripts/files_to_remove/*.php');
4248 foreach($files_to_remove as $script)
4250 if(preg_match('/\/files_to_remove\/(.*?)\.php$/', $script, $matches))
4252 require_once($script);
4253 $upgradeClass = $matches[1];
4255 if(!class_exists($upgradeClass))
4260 $upgradeInstance = new $upgradeClass();
4261 if($upgradeInstance instanceof UpgradeRemoval)
4263 logThis('Running Custom UpgradeRemoval instance ' . $upgradeClass);
4264 $files = $upgradeInstance->getFilesToRemove($version);
4265 foreach($files as $file)
4269 $upgradeInstance->processFilesToRemove($files);
4277 if (!function_exists("getValidDBName"))
4280 * Return a version of $proposed that can be used as a column name in any of our supported databases
4281 * 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)
4282 * @param string $name Proposed name for the column
4283 * @param string $ensureUnique
4284 * @return string Valid column name trimmed to right length and with invalid characters removed
4286 function getValidDBName ($name, $ensureUnique = false, $maxLen = 30)
4288 // first strip any invalid characters - all but alphanumerics and -
4289 $name = preg_replace ( '/[^\w-]+/i', '', $name ) ;
4290 $len = strlen ( $name ) ;
4294 $md5str = md5($name);
4295 $tail = substr ( $name, -11) ;
4296 $temp = substr($md5str , strlen($md5str)-4 );
4297 $result = substr ( $name, 0, 10) . $temp . $tail ;
4298 }else if ($len > ($maxLen - 5))
4300 $result = substr ( $name, 0, 11) . substr ( $name, 11 - $maxLen + 5);
4302 return strtolower ( $result ) ;
4309 * Get UW directories
4310 * Provides compatibility with both 6.3 and pre-6.3 setup
4312 function getUWDirs()
4314 if(!class_exists('UploadStream')) {
4315 // we're still running the old code
4316 global $sugar_config;
4317 return array($sugar_config['upload_dir'] . "/upgrades", $sugar_config['cache_dir'] . "upload/upgrades/temp");
4319 if(!in_array("upload", stream_get_wrappers())) {
4320 UploadStream::register(); // just in case file was copied, but not run
4322 return array("upload://upgrades", sugar_cached("upgrades/temp"));
4327 * Whether directory exists within list of directories to skip
4328 * @param string $dir dir to be checked
4329 * @param array $skipDirs list with skipped dirs
4332 function whetherNeedToSkipDir($dir, $skipDirs)
4334 foreach($skipDirs as $skipMe) {
4335 if(strpos( clean_path($dir), $skipMe ) !== false) {
4345 * @param silentUpgrade boolean flag indicating whether or not we should treat running the SugarSpriteBuilder as an upgrade operation
4348 function rebuildSprites($fromUpgrade=true)
4350 require_once('modules/Administration/SugarSpriteBuilder.php');
4351 $sb = new SugarSpriteBuilder();
4352 $sb->cssMinify = true;
4353 $sb->fromSilentUpgrade = $fromUpgrade;
4354 $sb->silentRun = $fromUpgrade;
4356 // add common image directories
4357 $sb->addDirectory('default', 'include/images');
4358 $sb->addDirectory('default', 'themes/default/images');
4359 $sb->addDirectory('default', 'themes/default/images/SugarLogic');
4361 // add all theme image directories
4362 if($dh = opendir('themes'))
4364 while (($dir = readdir($dh)) !== false)
4366 if ($dir != "." && $dir != ".." && $dir != 'default' && is_dir('themes/'.$dir)) {
4367 $sb->addDirectory($dir, "themes/{$dir}/images");
4373 // add all theme custom image directories
4374 $custom_themes_dir = "custom/themes";
4375 if (is_dir($custom_themes_dir)) {
4376 if($dh = opendir($custom_themes_dir))
4378 while (($dir = readdir($dh)) !== false)
4380 //Since the custom theme directories don't require an images directory
4381 // we check for it implicitly
4382 if ($dir != "." && $dir != ".." && is_dir('custom/themes/'.$dir."/images")) {
4383 $sb->addDirectory($dir, "custom/themes/{$dir}/images");
4390 // generate the sprite goodies
4391 // everything is saved into cache/sprites
4392 $sb->createSprites();
4397 * repairSearchFields
4399 * This method goes through the list of SearchFields files based and calls TemplateRange::repairCustomSearchFields
4400 * method on the files in an attempt to ensure the range search attributes are properly set in SearchFields.php.
4402 * @param $globString String value used for glob search defaults to searching for all SearchFields.php files in modules directory
4403 * @param $path String value used to point to log file should logging be required. Defaults to empty.
4406 function repairSearchFields($globString='modules/*/metadata/SearchFields.php', $path='')
4410 logThis('Begin repairSearchFields', $path);
4413 require_once('include/dir_inc.php');
4414 require_once('modules/DynamicFields/templates/Fields/TemplateRange.php');
4415 require('include/modules.php');
4418 $searchFieldsFiles = glob($globString);
4420 foreach($searchFieldsFiles as $file)
4422 if(preg_match('/modules\/(.*?)\/metadata\/SearchFields\.php/', $file, $matches) && isset($beanList[$matches[1]]))
4424 $module = $matches[1];
4425 $beanName = $beanList[$module];
4426 VardefManager::loadVardef($module, $beanName);
4427 if(isset($GLOBALS['dictionary'][$beanName]['fields']))
4431 logThis('Calling TemplateRange::repairCustomSearchFields for module ' . $module, $path);
4433 TemplateRange::repairCustomSearchFields($GLOBALS['dictionary'][$beanName]['fields'], $module);
4440 logThis('End repairSearchFields', $path);
4445 * repairUpgradeHistoryTable
4447 * This is a helper function used in the upgrade process to fix upgrade_history entries so that the filename column points
4448 * to the new upload directory location introduced in 6.4 versions
4450 function repairUpgradeHistoryTable()
4452 require_once('modules/Configurator/Configurator.php');
4454 global $sugar_config;
4456 //Now upgrade the upgrade_history table entries
4457 $results = $GLOBALS['db']->query('SELECT id, filename FROM upgrade_history');
4458 $upload_dir = $sugar_config['cache_dir'].'upload/';
4460 //Create regular expression string to
4461 $match = '/^' . str_replace('/', '\/', $upload_dir) . '(.*?)$/';
4463 while(($row = $GLOBALS['db']->fetchByAssoc($results)))
4465 $file = str_replace('//', '/', $row['filename']); //Strip out double-paths that may exist
4467 if(!empty($file) && preg_match($match, $file, $matches))
4469 //Update new file location to use the new $sugar_config['upload_dir'] value
4470 $new_file_location = $sugar_config['upload_dir'] . $matches[1];
4471 $GLOBALS['db']->query("UPDATE upgrade_history SET filename = '{$new_file_location}' WHERE id = '{$row['id']}'");