]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - modules/UpgradeWizard/uw_utils.php
Release 6.5.0beta4
[Github/sugarcrm.git] / modules / UpgradeWizard / uw_utils.php
1 <?php
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.
6  * 
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.
13  * 
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
17  * details.
18  * 
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
22  * 02110-1301 USA.
23  * 
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.
26  * 
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.
30  * 
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  ********************************************************************************/
37
38
39
40
41 /**
42  * Helper function for upgrade - get path from upload:// name
43  * @param string $path
44  * return string
45  */
46 function getUploadRelativeName($path)
47 {
48     if(class_exists('UploadFile')) {
49         return UploadFile::realpath($path);
50     }
51     if(substr($path, 0, 9) == "upload://") {
52         $path = rtrim($GLOBALS['sugar_config']['upload_dir'], "/\\")."/".substr($path, 9);
53     }
54     return $path;
55 }
56
57 /**
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
66  */
67 function commitMakeBackupFiles($rest_dir, $install_file, $unzip_dir, $zip_from_dir, $errors, $path='') {
68         global $mod_strings;
69         // create restore file directory
70         sugar_mkdir($rest_dir, 0775, true);
71
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());
75
76                 // keep this around for canceling
77                 $_SESSION['uw_restore_dir'] = getUploadRelativeName($rest_dir);
78
79                 foreach ($newFiles as $file) {
80                         if (strpos($file, 'md5'))
81                                 continue;
82
83                         // get name of current file to place in restore directory
84                         $cleanFile = str_replace(clean_path($unzip_dir . '/' . $zip_from_dir), '', $file);
85
86                         // make sure the directory exists
87                         $cleanDir = $rest_dir . '/' . dirname($cleanFile);
88                         sugar_mkdir($cleanDir, 0775, true);
89                         $oldFile = clean_path(getcwd() . '/' . $cleanFile);
90
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}";
98                                         } else {
99                                                 $backupFilesExist = true;
100                                         }
101
102                                 } else {
103                                         logThis('*** ERROR: directory not writable: ' . $rest_dir, $path);
104                                         $errors[] = "{$mod_strings['LBL_UW_BACKUP']}::{$mod_strings['ERR_UW_DIR_NOT_WRITABLE']}: {$oldFile}";
105                                 }
106                         }
107                 }
108     }
109         logThis('file backup done.', $path);
110         return $errors;
111 }
112
113 /**
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
117  * extension.
118  * @param string path Optional full path to alternate upgradeWizard log file.
119  * @return array Two element array containing to $copiedFiles and $skippedFiles.
120  */
121
122
123
124 function commitCopyNewFiles($unzip_dir, $zip_from_dir, $path='') {
125         logThis('Starting file copy process...', $path);
126         global $sugar_version;
127         $backwardModules='';
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'))){
133                                         $files = array();
134                                 $files= findAllFiles(clean_path(getcwd().'/modules/'.$mod.'/.500'),$files);
135                                 if(sizeof($files) >0){
136                                         //backward compatibility is on
137                                                 $backwardModules[] = $mod;
138                                 }
139                            }
140                         }
141        }
142
143         $newFiles = findAllFiles(clean_path($unzip_dir . '/' . $zip_from_dir), array());
144         $zipPath = clean_path($unzip_dir . '/' . $zip_from_dir);
145
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']);
151         }
152
153         $copiedFiles = array();
154         $skippedFiles = array();
155
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);
166                                 }
167                         }
168                 }
169                 if(!is_dir(dirname($targetFile))) {
170                         mkdir_recursive(dirname($targetFile)); // make sure the directory exists
171                 }
172
173                 if((!file_exists($targetFile)) || /* brand new file */
174                         (!in_array($targetFile, $doNotOverwrite)) /* manual diff file */
175                         ) {
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;
180                                 continue;
181                         }
182
183                         //logThis('Copying file to destination: ' . $targetFile, $path);
184
185                         if(!copy($srcFile, $targetFile)) {
186                                 logThis('*** ERROR: could not copy file: ' . $targetFile, $path);
187                         } else {
188                                 $copiedFiles[] = $targetFile;
189                         }
190                 } else {
191                         //logThis('Skipping file: ' . $targetFile, $path);
192                         $skippedFiles[] = $targetFile;
193                 }
194         }
195         logThis('File copy done.', $path);
196
197         $ret = array();
198         $ret['copiedFiles'] = $copiedFiles;
199         $ret['skippedFiles'] = $skippedFiles;
200
201         return $ret;
202 }
203
204
205 //On cancel put back the copied files from 500 to 451 state
206 function copyFilesOnCancel($step){
207 //place hoder for cancel action
208
209 }
210
211
212 function removeFileFromPath($file,$path, $deleteNot=array()){
213                 $removed = 0;
214                 $cur = $path . '/' . $file;
215                 if(file_exists($cur)){
216                         $del = true;
217                         foreach($deleteNot as $dn){
218                                 if($cur == $dn){
219                                         $del = false;
220                                 }
221                         }
222                         if($del){
223                                 unlink($cur);
224                                 $removed++;
225                         }
226                 }
227                 if(!file_exists($path))return $removed;
228                 $d = dir($path);
229                 while($e = $d->read()){
230                         $next = $path . '/'. $e;
231                         if(substr($e, 0, 1) != '.' && is_dir($next)){
232                                 $removed += removeFileFromPath($file, $next, $deleteNot);
233                         }
234                 }
235                 return $removed;
236         }
237
238 /**
239  * This function copies/overwrites between directories
240  *
241  * @param string the directory name to remove
242  * @param boolean whether to just empty the given directory, without deleting the given directory.
243  * @return boolean True/False whether the directory was deleted.
244  */
245
246 function copyRecursiveBetweenDirectories($from,$to){
247         if(file_exists($from)){
248                 $modifiedFiles = array();
249                 $modifiedFiles = findAllFiles(clean_path($from), $modifiedFiles);
250                 $cwd = clean_path(getcwd());
251                 foreach($modifiedFiles as $file) {
252                         $srcFile = clean_path($file);
253             if (strpos($srcFile,".svn") === false) {
254                         $targetFile = str_replace($from, $to, $srcFile);
255
256                                 if(!is_dir(dirname($targetFile))) {
257                                         mkdir_recursive(dirname($targetFile)); // make sure the directory exists
258                                 }
259
260                                         // handle sugar_version.php
261                                         if(strpos($targetFile, 'sugar_version.php') !== false && !preg_match('/\/portal\/sugar_version\.php$/i', $targetFile)) {
262                                                 logThis('Skipping "sugar_version.php" - file copy will occur at end of successful upgrade', $targetFile);
263                                                 $_SESSION['sugar_version_file'] = $srcFile;
264                                                 continue;
265                                         }
266
267                                         if(!copy($srcFile, $targetFile)) {
268                                                 logThis("*** ERROR: could not copy file $srcFile to $targetFile");
269                                         }
270                 }
271                  }
272         }
273 }
274
275 function deleteDirectory($dirname,$only_empty=false) {
276     if (!is_dir($dirname))
277         return false;
278     $dscan = array(realpath($dirname));
279     $darr = array();
280     while (!empty($dscan)) {
281         $dcur = array_pop($dscan);
282         $darr[] = $dcur;
283         if ($d=opendir($dcur)) {
284             while ($f=readdir($d)) {
285                 if ($f=='.' || $f=='..')
286                     continue;
287                 $f=$dcur.'/'.$f;
288                 if (is_dir($f))
289                     $dscan[] = $f;
290                 else
291                     unlink($f);
292             }
293             closedir($d);
294         }
295     }
296     $i_until = ($only_empty)? 1 : 0;
297     for ($i=count($darr)-1; $i>=$i_until; $i--) {
298         if (rmdir($darr[$i]))
299             logThis('Success :Copying file to destination: ' . $darr[$i]);
300         else
301             logThis('Copy problem:Copying file to destination: ' . $darr[$i]);
302     }
303     return (($only_empty)? (count(scandir)<=2) : (!is_dir($dirname)));
304 }
305 /**
306  * Get all the customized modules. Compare the file md5s with the base md5s
307  * If a file has been modified then put the module in the list of customized
308  * modules. Show the list in the preflight check UI.
309  */
310
311 function deleteAndOverWriteSelectedFiles($unzip_dir, $zip_from_dir,$delete_dirs){
312         if($delete_dirs != null){
313                 foreach($delete_dirs as $del_dir){
314                         deleteDirectory($del_dir);
315                         $newFiles = findAllFiles(clean_path($unzip_dir . '/' . $zip_from_dir.'/'.$del_dir), array());
316                         $zipPath = clean_path($unzip_dir . '/' . $zip_from_dir.'/'.$del_dir);
317                         $copiedFiles = array();
318                         $skippedFiles = array();
319
320                         foreach($newFiles as $file) {
321                                 $cleanFile = str_replace($zipPath, '', $file);
322                                 $srcFile = $zipPath . $cleanFile;
323                                 $targetFile = clean_path(getcwd() . '/' . $cleanFile);
324
325                                 if(!is_dir(dirname($targetFile))) {
326                                         mkdir_recursive(dirname($targetFile)); // make sure the directory exists
327                                 }
328
329                                 if(!file_exists($targetFile)){
330                                         // handle sugar_version.php
331                                         if(strpos($targetFile, 'sugar_version.php') !== false) {
332                                                 logThis('Skipping sugar_version.php - file copy will occur at end of successful upgrade');
333                                                 $_SESSION['sugar_version_file'] = $srcFile;
334                                                 continue;
335                                         }
336
337                                         //logThis('Copying file to destination: ' . $targetFile);
338
339                                         if(!copy($srcFile, $targetFile)) {
340                                                 logThis('*** ERROR: could not copy file: ' . $targetFile);
341                                         } else {
342                                                 $copiedFiles[] = $targetFile;
343                                         }
344                                 } else {
345                                         //logThis('Skipping file: ' . $targetFile);
346                                         $skippedFiles[] = $targetFile;
347                                 }
348                           }
349                 }
350         }
351         $ret = array();
352         $ret['copiedFiles'] = $copiedFiles;
353         $ret['skippedFiles'] = $skippedFiles;
354
355         return $ret;
356 }
357
358 //Default is empty the directory. For removing set it to false
359 // to use this function to totally remove a directory, write:
360 // recursive_remove_directory('path/to/directory/to/delete',FALSE);
361
362 // to use this function to empty a directory, write:
363 // recursive_remove_directory('path/to/full_directory');
364
365 function recursive_empty_or_remove_directory($directory, $exclude_dirs=null,$exclude_files=null,$empty=TRUE)
366 {
367         // if the path has a slash at the end we remove it here
368         if(substr($directory,-1) == '/')
369         {
370                 $directory = substr($directory,0,-1);
371         }
372
373         // if the path is not valid or is not a directory ...
374         if(!file_exists($directory) || !is_dir($directory))
375         {
376                 // ... we return false and exit the function
377                 return FALSE;
378
379         // ... if the path is not readable
380         }elseif(!is_readable($directory))
381         {
382                 // ... we return false and exit the function
383                 return FALSE;
384
385         // ... else if the path is readable
386         }else{
387
388                 // we open the directory
389                 $handle = opendir($directory);
390
391                 // and scan through the items inside
392                 while (FALSE !== ($item = readdir($handle)))
393                 {
394                         // if the filepointer is not the current directory
395                         // or the parent directory
396                         if($item != '.' && $item != '..')
397                         {
398                                 // we build the new path to delete
399                                 $path = $directory.'/'.$item;
400
401                                 // if the new path is a directory
402                                 //add another check if the dir is in the list to exclude delete
403                                 if(is_dir($path) && $exclude_dirs != null && in_array($path,$exclude_dirs)){
404                                     //do nothing
405                                 }
406                                 else if(is_dir($path))
407                                 {
408                                         // we call this function with the new path
409                                         recursive_empty_or_remove_directory($path);
410                                 }
411                                 // if the new path is a file
412                                 else{
413                                         // we remove the file
414                                         if($exclude_files != null && in_array($path,$exclude_files)){
415                            //do nothing
416                                         }
417                                         else{
418                                                 unlink($path);
419                                     }
420                                 }
421                         }
422                 }
423                 // close the directory
424                 closedir($handle);
425
426                 // if the option to empty is not set to true
427                 if($empty == FALSE)
428                 {
429                         // try to delete the now empty directory
430                         if(!rmdir($directory))
431                         {
432                                 // return false if not possible
433                                 return FALSE;
434                         }
435                 }
436                 // return success
437                 return TRUE;
438         }
439 }
440 // ------------------------------------------------------------
441
442
443
444
445 function getAllCustomizedModules() {
446
447                 require_once('files.md5');
448
449             $return_array = array();
450             $modules = getAllModules();
451             foreach($modules as $mod) {
452                    //find all files in each module if the files have been modified
453                    //as compared to the base version then add the module to the
454                    //customized modules array
455                    $modFiles = findAllFiles(clean_path(getcwd())."/modules/$mod", array());
456                foreach($modFiles as $file){
457                   $fileContents = file_get_contents($file);
458                    $file = str_replace(clean_path(getcwd()),'',$file);
459                   if($md5_string['./' . $file]){
460                           if(md5($fileContents) != $md5_string['./' . $file]) {
461                              //A file has been customized in the module. Put the module into the
462                              // customized modules array.
463                              echo 'Changed File'.$file;
464                                   $return_array[$mod];
465                                   break;
466                           }
467                   }
468                   else{
469                         // This is a new file in user's version and indicates that module has been
470                         //customized. Put the module in the customized array.
471                        echo 'New File'.$file;
472                        $return_array[$mod];
473                        break;
474                   }
475                }
476             } //foreach
477
478                 return $return_array;
479         }
480
481     /**
482      * Array of all Modules in the version bein upgraded
483      * This method returns an Array of all modules
484      * @return $modules Array of modules.
485      */
486         function getAllModules() {
487                 $modules = array();
488                 $d = dir('modules');
489                 while($e = $d->read()){
490                         if(substr($e, 0, 1) == '.' || !is_dir('modules/' . $e))continue;
491                         $modules[] = $e;
492                 }
493                 return $modules;
494         }
495
496 //Remove files with the smae md5
497
498 function removeMd5MatchingFiles($deleteNot=array()){
499
500         $md5_string = array();
501         if(file_exists(clean_path(getcwd().'/files.md5'))){
502                 require(clean_path(getcwd().'/files.md5'));
503         }
504     $modulesAll = getAllModules();
505      foreach($modulesAll as $mod){
506               $allModFiles = array();
507               if(is_dir('modules/'.$mod)){
508               $allModFiles = findAllFiles('modules/'.$mod,$allModFiles);
509                foreach($allModFiles as $file){
510                         if(file_exists($file) && !in_array(basename($file),$deleteNot)){
511                                  if(isset($md5_string['./'.$file])) {
512                                   $fileContents = file_get_contents($file);
513                                   if(md5($fileContents) == $md5_string['./'.$file]) {
514                                         unlink($file);
515                                   }
516                               }
517                     }
518            }
519            }
520    }
521 }
522
523 /**
524  * Handles requirements for creating reminder Tasks and Emails
525  * @param array skippedFiles Array of files that were not overwriten and must be manually mereged.
526  * @param string path Optional full path to alternate upgradeWizard log.
527  */
528 function commitHandleReminders($skippedFiles, $path='') {
529         global $mod_strings;
530         global $current_user;
531
532         if(empty($mod_strings))
533                 $mod_strings = return_module_language('en_us', 'UpgradeWizard');
534
535         if(empty($current_user->id)) {
536                 $current_user->getSystemUser();
537         }
538
539         if(count($skippedFiles) > 0) {
540                 $desc = $mod_strings['LBL_UW_COMMIT_ADD_TASK_OVERVIEW'] . "\n\n";
541                 $desc .= $mod_strings['LBL_UW_COMMIT_ADD_TASK_DESC_1'];
542                 $desc .= $_SESSION['uw_restore_dir'] . "\n\n";
543                 $desc .= $mod_strings['LBL_UW_COMMIT_ADD_TASK_DESC_2'] . "\n\n";
544
545                 foreach($skippedFiles as $file) {
546                         $desc .= $file . "\n";
547                 }
548
549                 //MFH #13468
550                 /// Not using new TimeDate stuff here because it needs to be compatible with 6.0
551                 $nowDate = gmdate('Y-m-d');
552                 $nowTime = gmdate('H:i:s');
553                 $nowDateTime = $nowDate . ' ' . $nowTime;
554
555                 if($_REQUEST['addTaskReminder'] == 'remind') {
556                         logThis('Adding Task for admin for manual merge.', $path);
557
558                         $task = new Task();
559                         $task->name = $mod_strings['LBL_UW_COMMIT_ADD_TASK_NAME'];
560                         $task->description = $desc;
561                         $task->date_due = $nowDate;
562                         $task->time_due = $nowTime;
563                         $task->priority = 'High';
564                         $task->status = 'Not Started';
565                         $task->assigned_user_id = $current_user->id;
566                         $task->created_by = $current_user->id;
567                         $task->date_entered = $nowDateTime;
568                         $task->date_modified = $nowDateTime;
569                         $task->save();
570                 }
571
572                 if($_REQUEST['addEmailReminder'] == 'remind') {
573                         logThis('Sending Reminder for admin for manual merge.', $path);
574
575                         $email = new Email();
576                         $email->assigned_user_id = $current_user->id;
577                         $email->name = $mod_strings['LBL_UW_COMMIT_ADD_TASK_NAME'];
578                         $email->description = $desc;
579                         $email->description_html = nl2br($desc);
580                         $email->from_name = $current_user->full_name;
581                         $email->from_addr = $current_user->email1;
582                         $email->to_addrs_arr = $email->parse_addrs($current_user->email1, '', '', '');
583                         $email->cc_addrs_arr = array();
584                         $email->bcc_addrs_arr = array();
585                         $email->date_entered = $nowDateTime;
586                         $email->date_modified = $nowDateTime;
587                         $email->send();
588                         $email->save();
589                 }
590         }
591 }
592
593 function deleteCache(){
594         //Clean modules from cache
595         $cachedir = sugar_cached('modules');
596         if(is_dir($cachedir)){
597                 $allModFiles = array();
598                 $allModFiles = findAllFiles($cachedir,$allModFiles, true);
599                 foreach($allModFiles as $file) {
600                 if(file_exists($file)) {
601                         if(is_dir($file)) {
602                                   rmdir_recursive($file);
603                         } else {
604                           unlink($file);
605                }
606                 }
607             }
608
609         }
610
611         //Clean jsLanguage from cache
612         $cachedir = sugar_cached('jsLanguage');
613         if(is_dir($cachedir)){
614                 $allModFiles = array();
615                 $allModFiles = findAllFiles($cachedir,$allModFiles);
616            foreach($allModFiles as $file){
617                         if(file_exists($file)){
618                                 unlink($file);
619                         }
620                 }
621         }
622         //Clean smarty from cache
623         $cachedir = sugar_cached('smarty');
624         if(is_dir($cachedir)){
625                 $allModFiles = array();
626                 $allModFiles = findAllFiles($cachedir,$allModFiles);
627            foreach($allModFiles as $file){
628                 if(file_exists($file)){
629                                 unlink($file);
630                 }
631            }
632         }
633         //Rebuild dashlets cache
634         require_once('include/Dashlets/DashletCacheBuilder.php');
635         $dc = new DashletCacheBuilder();
636     $dc->buildCache();
637 }
638
639 function deleteChance(){
640         //Clean folder from cache
641         if(is_dir('include/SugarObjects/templates/chance')){
642                 rmdir_recursive('include/SugarObjects/templates/chance');
643          }
644         if(is_dir('include/SugarObjects/templates/chance')){
645                 if(!isset($_SESSION['chance'])){
646                         $_SESSION['chance'] = '';
647                 }
648                 $_SESSION['chance'] = 'include/SugarObjects/templates/chance';
649                 //rename('include/SugarObjects/templates/chance','include/SugarObjects/templates/chance_removeit');
650         }
651 }
652
653
654
655 /**
656  * upgradeUWFiles
657  * This function copies upgrade wizard files from new patch if that dir exists
658  *
659  * @param $file String path to uploaded zip file
660  */
661 function upgradeUWFiles($file) {
662     $cacheUploadUpgradesTemp = mk_temp_dir(sugar_cached("upgrades/temp"));
663
664         unzip($file, $cacheUploadUpgradesTemp);
665
666         if(!file_exists("$cacheUploadUpgradesTemp/manifest.php")) {
667                 logThis("*** ERROR: no manifest file detected while bootstraping upgrade wizard files!");
668                 return;
669         } else {
670                 include("$cacheUploadUpgradesTemp/manifest.php");
671         }
672
673         $allFiles = array();
674         $from_dir = "{$cacheUploadUpgradesTemp}/{$manifest['copy_files']['from_dir']}";
675
676     // Localization
677     if(file_exists("$from_dir/include/Localization/Localization.php")) {
678         $allFiles[] = "$from_dir/include/Localization/Localization.php";
679     }
680     // upgradeWizard
681     if(file_exists("$from_dir/modules/UpgradeWizard")) {
682         $allFiles[] = findAllFiles("$from_dir/modules/UpgradeWizard", $allFiles);
683     }
684     // moduleInstaller
685     if(file_exists("$from_dir/ModuleInstall")) {
686         $allFiles[] = findAllFiles("$from_dir/ModuleInstall", $allFiles);
687     }
688     if(file_exists("$from_dir/include/javascript/yui")) {
689         $allFiles[] = findAllFiles("$from_dir/include/javascript/yui", $allFiles);
690     }
691     if(file_exists("$from_dir/HandleAjaxCall.php")) {
692         $allFiles[] = "$from_dir/HandleAjaxCall.php";
693     }
694     if(file_exists("$from_dir/include/SugarTheme")) {
695         $allFiles[] = findAllFiles("$from_dir/include/SugarTheme", $allFiles);
696     }
697     if(file_exists("$from_dir/include/SugarCache")) {
698         $allFiles[] = findAllFiles("$from_dir/include/SugarCache", $allFiles);
699     }
700     if(file_exists("$from_dir/include/utils/external_cache.php")) {
701         $allFiles[] = "$from_dir/include/utils/external_cache.php";
702     }
703     if(file_exists("$from_dir/include/upload_file.php")) {
704         $allFiles[] = "$from_dir/include/upload_file.php";
705     }
706     if(file_exists("$from_dir/include/file_utils.php")) {
707         $allFiles[] = "$from_dir/include/file_utils.php";
708     }
709     if(file_exists("$from_dir/include/upload_file.php")) {
710         $allFiles[] = "$from_dir/include/upload_file.php";
711     }
712     if(file_exists("$from_dir/include/utils/sugar_file_utils.php")) {
713         $allFiles[] = "$from_dir/include/utils/sugar_file_utils.php";
714     }
715     // users
716     if(file_exists("$from_dir/modules/Users")) {
717         $allFiles[] = findAllFiles("$from_dir/modules/Users", $allFiles);
718     }
719
720     upgradeUWFilesCopy($allFiles, $from_dir);
721 }
722
723 /**
724  * upgradeUWFilesCopy
725  *
726  * This function recursively copies files from the upgradeUWFiles Array
727  * @see upgradeUWFiles
728  *
729  * @param array $allFiles Array of files to copy over after zip file has been uploaded
730  * @param string $from_dir Source directory
731  */
732 function upgradeUWFilesCopy($allFiles, $from_dir)
733 {
734    foreach($allFiles as $file)
735    {
736        if(is_array($file))
737        {
738            upgradeUWFilesCopy($file, $from_dir);
739        } else {
740            $destFile = str_replace($from_dir."/", "", $file);
741            if(!is_dir(dirname($destFile))) {
742               mkdir_recursive(dirname($destFile)); // make sure the directory exists
743            }
744
745            if(stristr($file,'uw_main.tpl'))
746               logThis('Skipping "'.$file.'" - file copy will during commit step.');
747            else {
748               logThis('updating UpgradeWizard code: '.$destFile);
749               copy_recursive($file, $destFile);
750            }
751        }
752    }
753 }
754
755
756
757 /**
758  * gets valid patch file names that exist in upload/upgrade/patch/
759  */
760 function getValidPatchName($returnFull = true) {
761         global $base_upgrade_dir;
762         global $mod_strings;
763         global $uh;
764         global $sugar_version;
765     global $sugar_config;
766     $uh = new UpgradeHistory();
767     list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
768     $return = array();
769
770         // scan for new files (that are not installed)
771         logThis('finding new files for upgrade');
772         $upgrade_content = '';
773         $upgrade_contents = findAllFiles($base_upgrade_dir, array(), false, 'zip');
774         //other variations of zip file i.e. ZIP, zIp,zIP,Zip,ZIp,ZiP
775         $ready = "<ul>\n";
776         $ready .= "
777                 <table>
778                         <tr>
779                                 <td></td>
780                                 <td align=left>
781                                         <b>{$mod_strings['LBL_ML_NAME']}</b>
782                                 </td>
783                                 <td align=left>
784                                         <b>{$mod_strings['LBL_ML_TYPE']}</b>
785                                 </td>
786                                 <td align=left>
787                                         <b>{$mod_strings['LBL_ML_VERSION']}</b>
788                                 </td>
789                                 <td align=left>
790                                         <b>{$mod_strings['LBL_ML_PUBLISHED']}</b>
791                                 </td>
792                                 <td align=left>
793                                         <b>{$mod_strings['LBL_ML_UNINSTALLABLE']}</b>
794                                 </td>
795                                 <td align=left>
796                                         <b>{$mod_strings['LBL_ML_DESCRIPTION']}</b>
797                                 </td>
798                         </tr>";
799         $disabled = '';
800
801         // assume old patches are there.
802         $upgradeToVersion = array(); // fill with valid patches - we will only use the latest qualified found patch
803
804         // cn: bug 10609 - notices for uninitialized variables
805         $icon = '';
806         $name = '';
807         $type = '';
808         $version = '';
809         $published_date = '';
810         $uninstallable = '';
811         $description = '';
812         $disabled = '';
813
814         foreach($upgrade_contents as $upgrade_content) {
815                 if(!preg_match("#.*\.zip\$#i", $upgrade_content)) {
816                         continue;
817                 }
818
819                 $the_base = basename($upgrade_content);
820                 $the_md5 = md5_file($upgrade_content);
821
822                 $md5_matches = $uh->findByMd5($the_md5);
823
824                 /* If a patch is in the /patch dir AND has no record in the upgrade_history table we assume that it's the one we want.
825                  * Edge-case: manual upgrade with a FTP of a patch; UH table has no entry for it.  Assume nothing. :( */
826                 if(0 == sizeof($md5_matches)) {
827                         $target_manifest = remove_file_extension( $upgrade_content ) . '-manifest.php';
828                         require_once($target_manifest);
829
830                         if(empty($manifest['version'])) {
831                                 logThis("*** Potential error: patch found with no version [ {$upgrade_content} ]");
832                                 continue;
833                         }
834                         if(!isset($manifest['type']) || $manifest['type'] != 'patch') {
835                                 logThis("*** Potential error: patch found with either no 'type' or non-patch type [ {$upgrade_content} ]");
836                                 continue;
837                         }
838
839                         $upgradeToVersion[$manifest['version']] = urlencode($upgrade_content);
840
841                         $name = empty($manifest['name']) ? $upgrade_content : $manifest['name'];
842                         $version = empty($manifest['version']) ? '' : $manifest['version'];
843                         $published_date = empty($manifest['published_date']) ? '' : $manifest['published_date'];
844                         $icon = '';
845                         $description = empty($manifest['description']) ? 'None' : $manifest['description'];
846                         $uninstallable = empty($manifest['is_uninstallable']) ? 'No' : 'Yes';
847                         $type = getUITextForType( $manifest['type'] );
848                         $manifest_type = $manifest['type'];
849
850                         if(empty($manifest['icon'])) {
851                                 $icon = getImageForType( $manifest['type'] );
852                         } else {
853                                 $path_parts = pathinfo( $manifest['icon'] );
854                                 $icon = "<!--not_in_theme!--><img src=\"" . remove_file_extension( $upgrade_content ) . "-icon." . $path_parts['extension'] . "\">";
855                         }
856             }
857         }
858
859         // cn: bug 10488 use the NEWEST upgrade/patch available when running upgrade wizard.
860         ksort($upgradeToVersion);
861         $upgradeToVersion = array_values($upgradeToVersion);
862         $newest = array_pop($upgradeToVersion);
863         $_SESSION['install_file'] = urldecode($newest); // in-case it was there from a prior.
864         logThis("*** UW using [ {$_SESSION['install_file']} ] as source for patch files.");
865
866         $cleanUpgradeContent = urlencode($_SESSION['install_file']);
867
868         // cn: 10606 - cannot upload a patch file since this returned always.
869         if(!empty($cleanUpgradeContent)) {
870                 $ready .= "<tr><td>$icon</td><td>$name</td><td>$type</td><td>$version</td><td>$published_date</td><td>$uninstallable</td><td>$description</td>\n";
871                 $ready .=<<<eoq
872                 <td>
873                                 <form action="index.php" method="post">
874                                         <input type="hidden" name="module" value="UpgradeWizard">
875                                         <input type="hidden" name="action" value="index">
876                                         <input type="hidden" name="step" value="{$_REQUEST['step']}">
877                                         <input type="hidden" name="run" value="delete">
878                                 <input type=hidden name="install_file" value="{$cleanUpgradeContent}" />
879                                 <input type=submit value="{$mod_strings['LBL_BUTTON_DELETE']}" />
880                                 </form>
881                         </td></table>
882 eoq;
883                 $disabled = "DISABLED";
884         }
885
886
887
888         if(empty($cleanUpgradeContent)){
889             $ready .= "<tr><td colspan='7'><i>None</i></td>\n";
890                 $ready .= "</table>\n";
891         }
892         $ready .= "<br></ul>\n";
893
894         $return['ready'] = $ready;
895         $return['disabled'] = $disabled;
896
897         if($returnFull) {
898                 return $return;
899         }
900 }
901
902
903 /**
904  * finalizes upgrade by setting upgrade versions in DB (config table) and sugar_version.php
905  * @return bool true on success
906  */
907 function updateVersions($version) {
908         global $db;
909         global $sugar_config;
910         global $path;
911
912         logThis('At updateVersions()... updating config table and sugar_version.php.', $path);
913
914         // handle file copy
915         if(isset($_SESSION['sugar_version_file']) && !empty($_SESSION['sugar_version_file'])) {
916                 if(!copy($_SESSION['sugar_version_file'], clean_path(getcwd().'/sugar_version.php'))) {
917                         logThis('*** ERROR: sugar_version.php could not be copied to destination! Cannot complete upgrade', $path);
918                         return false;
919                 } else {
920                         logThis('sugar_version.php successfully updated!', $path);
921                 }
922         } else {
923                 logThis('*** ERROR: no sugar_version.php file location found! - cannot complete upgrade...', $path);
924                 return false;
925         }
926
927         $q1 = "DELETE FROM config WHERE category = 'info' AND name = 'sugar_version'";
928         $q2 = "INSERT INTO config (category, name, value) VALUES ('info', 'sugar_version', '{$version}')";
929
930         logThis('Deleting old DB version info from config table.', $path);
931         $db->query($q1);
932
933         logThis('Inserting updated version info into config table.', $path);
934         $db->query($q2);
935
936         logThis('updateVersions() complete.', $path);
937         return true;
938 }
939
940
941
942 /**
943  * gets a module's lang pack - does not need to be a SugarModule
944  * @param lang string Language
945  * @param module string Path to language folder
946  * @return array mod_strings
947  */
948 function getModuleLanguagePack($lang, $module) {
949         $mod_strings = array();
950
951         if(!empty($lang) && !empty($module)) {
952                 $langPack = clean_path(getcwd().'/'.$module.'/language/'.$lang.'.lang.php');
953                 $langPackEn = clean_path(getcwd().'/'.$module.'/language/en_us.lang.php');
954
955                 if(file_exists($langPack))
956                         include_once($langPack);
957                 elseif(file_exists($langPackEn))
958                         include_once($langPackEn);
959         }
960
961         return $mod_strings;
962 }
963 /**
964  * checks system compliance for 4.5+ codebase
965  * @return array Mixed values
966  */
967 function checkSystemCompliance() {
968         global $sugar_config;
969         global $current_language;
970         global $db;
971         global $mod_strings;
972
973         if(!defined('SUGARCRM_MIN_MEM')) {
974                 define('SUGARCRM_MIN_MEM', 40);
975         }
976
977         $installer_mod_strings = getModuleLanguagePack($current_language, './install');
978         $ret = array();
979         $ret['error_found'] = false;
980
981         // PHP version
982         $php_version = constant('PHP_VERSION');
983         $check_php_version_result = check_php_version($php_version);
984
985         switch($check_php_version_result) {
986                 case -1:
987                         $ret['phpVersion'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_PHP_INVALID_VER']} {$php_version} )</span></b>";
988                         $ret['error_found'] = true;
989                         break;
990                 case 0:
991                         $ret['phpVersion'] = "<b><span class=go>{$installer_mod_strings['ERR_CHECKSYS_PHP_UNSUPPORTED']} {$php_version} )</span></b>";
992                         break;
993                 case 1:
994                         $ret['phpVersion'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_PHP_OK']} {$php_version} )</span></b>";
995                         break;
996         }
997
998         // database and connect
999     $v = $db->version();
1000         if($db->dbType == 'mysql')
1001     {
1002         if(version_compare($v, '4.1.2') < 0) {
1003                         $ret['error_found'] = true;
1004                         $ret['mysqlVersion'] = "<b><span class=stop>".$mod_strings['ERR_UW_MYSQL_VERSION'].$v."</span></b>";
1005             }
1006         } elseif($db->dbType == 'oci8') {
1007             if(!preg_match("/Oracle9i|Oracle Database 10g|11/i", $v)) {
1008                         $ret['error_found'] = true;
1009                         $ret['ociVersion'] = "<b><span class=stop>".$mod_strings['ERR_UW_OCI8_VERSION'].$v."</span></b>";
1010             }
1011         }
1012
1013
1014         // XML Parsing
1015         if(function_exists('xml_parser_create')) {
1016                 $ret['xmlStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1017         } else {
1018                 $ret['xmlStatus'] = "<b><span class=stop>{$installer_mod_strings['LBL_CHECKSYS_NOT_AVAILABLE']}</span></b>";
1019                 $ret['error_found'] = true;
1020         }
1021
1022         // cURL
1023         if(function_exists('curl_init')) {
1024                 $ret['curlStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1025         } else {
1026                 $ret['curlStatus'] = "<b><span class=go>{$installer_mod_strings['ERR_CHECKSYS_CURL']}</span></b>";
1027                 $ret['error_found'] = false;
1028         }
1029
1030         // mbstrings
1031         if(function_exists('mb_strlen')) {
1032                 $ret['mbstringStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1033         } else {
1034                 $ret['mbstringStatus'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_MBSTRING']}</span></b>";
1035                 $ret['error_found'] = true;
1036         }
1037
1038         // imap
1039         if(function_exists('imap_open')) {
1040                 $ret['imapStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1041         } else {
1042                 $ret['imapStatus'] = "<b><span class=go>{$installer_mod_strings['ERR_CHECKSYS_IMAP']}</span></b>";
1043                 $ret['error_found'] = false;
1044         }
1045
1046
1047         // safe mode
1048         if('1' == ini_get('safe_mode')) {
1049                 $ret['safeModeStatus'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_SAFE_MODE']}</span></b>";
1050                 $ret['error_found'] = true;
1051         } else {
1052                 $ret['safeModeStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1053         }
1054
1055
1056         // call time pass by ref
1057     if('1' == ini_get('allow_call_time_pass_reference')) {
1058                 $ret['callTimeStatus'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_CALL_TIME']}</span></b>";
1059                 //continue upgrading
1060         } else {
1061                 $ret['callTimeStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1062         }
1063
1064         // memory limit
1065         $ret['memory_msg']     = "";
1066         $memory_limit   = "-1";//ini_get('memory_limit');
1067         $sugarMinMem = constant('SUGARCRM_MIN_MEM');
1068         // logic based on: http://us2.php.net/manual/en/ini.core.php#ini.memory-limit
1069         if( $memory_limit == "" ){          // memory_limit disabled at compile time, no memory limit
1070             $ret['memory_msg'] = "<b><span class=\"go\">{$installer_mod_strings['LBL_CHECKSYS_MEM_OK']}</span></b>";
1071         } elseif( $memory_limit == "-1" ){   // memory_limit enabled, but set to unlimited
1072             $ret['memory_msg'] = "<b><span class=\"go\">{$installer_mod_strings['LBL_CHECKSYS_MEM_UNLIMITED']}</span></b>";
1073         } else {
1074             rtrim($memory_limit, 'M');
1075             $memory_limit_int = (int) $memory_limit;
1076             if( $memory_limit_int < constant('SUGARCRM_MIN_MEM') ){
1077                 $ret['memory_msg'] = "<b><span class=\"stop\">{$installer_mod_strings['ERR_CHECKSYS_MEM_LIMIT_1']}" . constant('SUGARCRM_MIN_MEM') . "{$installer_mod_strings['ERR_CHECKSYS_MEM_LIMIT_2']}</span></b>";
1078                         $ret['error_found'] = true;
1079             } else {
1080                         $ret['memory_msg'] = "<b><span class=\"go\">{$installer_mod_strings['LBL_CHECKSYS_OK']} ({$memory_limit})</span></b>";
1081             }
1082         }
1083
1084         /* mbstring.func_overload
1085         $ret['mbstring.func_overload'] = '';
1086         $mb = ini_get('mbstring.func_overload');
1087
1088         if($mb > 1) {
1089                 $ret['mbstring.func_overload'] = "<b><span class=\"stop\">{$mod_strings['ERR_UW_MBSTRING_FUNC_OVERLOAD']}</b>";
1090                 $ret['error_found'] = true;
1091         }
1092         */
1093         return $ret;
1094 }
1095
1096
1097 /**
1098  * is a file that we blow away automagically
1099  */
1100 function isAutoOverwriteFile($file) {
1101         $overwriteDirs = array(
1102                 './sugar_version.php',
1103                 './modules/UpgradeWizard/uw_main.tpl',
1104         );
1105         $file = trim('.'.str_replace(clean_path(getcwd()), '', $file));
1106
1107         if(in_array($file, $overwriteDirs)) {
1108                 return true;
1109         }
1110
1111         $fileExtension = substr(strrchr($file, "."), 1);
1112         if($fileExtension == 'tpl' || $fileExtension == 'html') {
1113                 return false;
1114         }
1115
1116         return true;
1117 }
1118
1119 /**
1120  * flatfile logger
1121  */
1122 function logThis($entry, $path='') {
1123         global $mod_strings;
1124         if(file_exists('include/utils/sugar_file_utils.php')){
1125                 require_once('include/utils/sugar_file_utils.php');
1126         }
1127                 $log = empty($path) ? clean_path(getcwd().'/upgradeWizard.log') : clean_path($path);
1128
1129                 // create if not exists
1130                 if(!file_exists($log)) {
1131                         if(function_exists('sugar_fopen')){
1132                                 $fp = @sugar_fopen($log, 'w+'); // attempts to create file
1133                      }
1134                      else{
1135                                 $fp = fopen($log, 'w+'); // attempts to create file
1136                      }
1137                         if(!is_resource($fp)) {
1138                                 $GLOBALS['log']->fatal('UpgradeWizard could not create the upgradeWizard.log file');
1139                                 die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
1140                         }
1141                 } else {
1142                         if(function_exists('sugar_fopen')){
1143                                 $fp = @sugar_fopen($log, 'a+'); // write pointer at end of file
1144                      }
1145                      else{
1146                                 $fp = @fopen($log, 'a+'); // write pointer at end of file
1147                      }
1148
1149                         if(!is_resource($fp)) {
1150                                 $GLOBALS['log']->fatal('UpgradeWizard could not open/lock upgradeWizard.log file');
1151                                 die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
1152                         }
1153                 }
1154
1155                 $line = date('r').' [UpgradeWizard] - '.$entry."\n";
1156
1157                 if(@fwrite($fp, $line) === false) {
1158                         $GLOBALS['log']->fatal('UpgradeWizard could not write to upgradeWizard.log: '.$entry);
1159                         die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
1160                 }
1161
1162                 if(is_resource($fp)) {
1163                         fclose($fp);
1164                 }
1165 }
1166
1167 /**
1168         *  @params : none
1169         *  @author: nsingh
1170         *  @desc This function is to be used in the upgrade process to preserve changes/customaizations made to pre 5.1 quickcreate layout.
1171         *  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
1172         *  was automatically picked up by the quick create. [Addresses Bug 21469]
1173         *  This function will check if customizations were made, and will create quickcreatedefs.php in the /cutom/working/$module_name directory.
1174         **/
1175 function updateQuickCreateDefs(){
1176         $d = dir('modules');
1177         $studio_modules = array();
1178
1179         while($e = $d->read()){ //collect all studio modules.
1180                 if(substr($e, 0, 1) == '.' || !is_dir('modules/' . $e))continue;
1181                 if(file_exists('modules/' . $e . '/metadata/studio.php'))
1182                 {
1183                         array_push($studio_modules, $e);
1184                 }
1185         }
1186
1187         foreach( $studio_modules as $modname ){ //for each studio enabled module
1188                 //Check !exists modules/$modname/metadata/quickcreatedefs.php &&
1189                 //exists custom/$modname/editviewdefs.php (module was customized) &&
1190                 //!exists custom/$modname/quickcreateviewdefs.php
1191
1192                 $editviewdefs = "custom/working/modules/".$modname."/metadata/editviewdefs.php";
1193                 $quickcreatedefs = "custom/working/modules/".$modname."/metadata/quickcreatedefs.php";
1194
1195                 if ( !file_exists("modules/".$modname."/metadata/quickcreatedefs.php") &&
1196                          file_exists($editviewdefs) &&
1197                          !file_exists($quickcreatedefs) ){
1198                                 //clone editviewdef and save it in custom/working/modules/metadata
1199                                 $GLOBALS['log']->debug("Copying editviewdefs.php as quickcreatedefs.php for the $modname module in custom/working/modules/$modname/metadata!");
1200                                 if(copy( $editviewdefs, $quickcreatedefs)){
1201                                         if(file_exists($quickcreatedefs) && is_readable($quickcreatedefs)){
1202                                                 $file = file($quickcreatedefs);
1203                                                 //replace 'EditView' with 'QuickCreate'
1204                                                 $fp = fopen($quickcreatedefs,'w');
1205                                                 foreach($file as &$line){
1206                                                         if(preg_match('/^\s*\'EditView\'\s*=>\s*$/', $line) > 0){
1207                                                                 $line = "'QuickCreate' =>\n";
1208                                                         }
1209                                                         fwrite($fp, $line);
1210                                                 }
1211                                                 //write back.
1212                                                 fclose($fp);
1213                                         }
1214                                         else{
1215                                                 $GLOBALS['log']->debug("Failed to replace 'EditView' with QuickCreate because $quickcreatedefs is either not readable or does not exist.");
1216                                         }
1217                                 }else{
1218                                         $GLOBALS['log']->debug("Failed to copy $editviewdefs to $quickcreatedefs!");
1219                                 }
1220                 }
1221         }
1222 }
1223
1224 /**
1225  * test perms for CREATE queries
1226  */
1227 function testPermsCreate($db, $out) {
1228         logThis('Checking CREATE TABLE permissions...');
1229         global $mod_strings;
1230
1231         if(!$db->checkPrivilege("CREATE TABLE")) {
1232         logThis('cannot CREATE TABLE!');
1233                 $out['db']['dbNoCreate'] = true;
1234                 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_CREATE']}</span></td></tr>";
1235         }
1236     return $out;
1237 }
1238
1239 /**
1240  * test perms for INSERT
1241  */
1242 function testPermsInsert($db, $out, $skip=false) {
1243         logThis('Checking INSERT INTO permissions...');
1244         global $mod_strings;
1245
1246         if(!$db->checkPrivilege("INSERT")) {
1247                 logThis('cannot INSERT INTO!');
1248                 $out['db']['dbNoInsert'] = true;
1249                 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_INSERT']}</span></td></tr>";
1250     }
1251     return $out;
1252 }
1253
1254
1255 /**
1256  * test perms for UPDATE TABLE
1257  */
1258 function testPermsUpdate($db, $out, $skip=false) {
1259         logThis('Checking UPDATE TABLE permissions...');
1260         global $mod_strings;
1261         if(!$db->checkPrivilege("UPDATE")) {
1262                                         logThis('cannot UPDATE TABLE!');
1263                                         $out['db']['dbNoUpdate'] = true;
1264                                         $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_UPDATE']}</span></td></tr>";
1265     }
1266     return $out;
1267 }
1268
1269
1270 /**
1271  * test perms for SELECT
1272  */
1273 function testPermsSelect($db, $out, $skip=false) {
1274         logThis('Checking SELECT permissions...');
1275         global $mod_strings;
1276         if(!$db->checkPrivilege("SELECT")) {
1277                                 logThis('cannot SELECT!');
1278                                 $out['db']['dbNoSelect'] = true;
1279                                 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_SELECT']}</span></td></tr>";
1280     }
1281     return $out;
1282 }
1283
1284 /**
1285  * test perms for DELETE
1286  */
1287 function testPermsDelete($db, $out, $skip=false) {
1288         logThis('Checking DELETE FROM permissions...');
1289         global $mod_strings;
1290         if(!$db->checkPrivilege("DELETE")) {
1291                                 logThis('cannot DELETE FROM!');
1292                                 $out['db']['dbNoDelete'] = true;
1293                                 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_DELETE']}</span></td></tr>";
1294     }
1295     return $out;
1296 }
1297
1298
1299 /**
1300  * test perms for ALTER TABLE ADD COLUMN
1301  */
1302 function testPermsAlterTableAdd($db, $out, $skip=false) {
1303         logThis('Checking ALTER TABLE ADD COLUMN permissions...');
1304         global $mod_strings;
1305         if(!$db->checkPrivilege("ADD COLUMN")) {
1306                                 logThis('cannot ADD COLUMN!');
1307                                 $out['db']['dbNoAddColumn'] = true;
1308                                 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_ADD_COLUMN']}</span></td></tr>";
1309     }
1310     return $out;
1311 }
1312
1313 /**
1314  * test perms for ALTER TABLE ADD COLUMN
1315  */
1316 function testPermsAlterTableChange($db, $out, $skip=false) {
1317         logThis('Checking ALTER TABLE CHANGE COLUMN permissions...');
1318         global $mod_strings;
1319         if(!$db->checkPrivilege("CHANGE COLUMN")) {
1320                                 logThis('cannot CHANGE COLUMN!');
1321                                 $out['db']['dbNoChangeColumn'] = true;
1322                                 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_CHANGE_COLUMN']}</span></td></tr>";
1323     }
1324     return $out;
1325 }
1326
1327 /**
1328  * test perms for ALTER TABLE DROP COLUMN
1329  */
1330 function testPermsAlterTableDrop($db, $out, $skip=false) {
1331         logThis('Checking ALTER TABLE DROP COLUMN permissions...');
1332         global $mod_strings;
1333         if(!$db->checkPrivilege("DROP COLUMN")) {
1334                                 logThis('cannot DROP COLUMN!');
1335                                 $out['db']['dbNoDropColumn'] = true;
1336                                 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_DROP_COLUMN']}</span></td></tr>";
1337     }
1338     return $out;
1339 }
1340
1341
1342 /**
1343  * test perms for DROP TABLE
1344  */
1345 function testPermsDropTable($db, $out, $skip=false) {
1346         logThis('Checking DROP TABLE permissions...');
1347         global $mod_strings;
1348         if(!$db->checkPrivilege("DROP TABLE")) {
1349                                 logThis('cannot DROP TABLE!');
1350                                 $out['db']['dbNoDropTable'] = true;
1351                                 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_DROP_TABLE']}</span></td></tr>";
1352     }
1353     return $out;
1354 }
1355
1356 function getFormattedError($error, $query) {
1357         $error = "<div><b>".$error;
1358         $error .= "</b>::{$query}</div>";
1359
1360         return $error;
1361 }
1362
1363 /**
1364  * parses a query finding the table name
1365  * @param string query The query
1366  * @return string table The table
1367  */
1368 function getTableFromQuery($query) {
1369         $standardQueries = array('ALTER TABLE', 'DROP TABLE', 'CREATE TABLE', 'INSERT INTO', 'UPDATE', 'DELETE FROM');
1370         $query = preg_replace("/[^A-Za-z0-9\_\s]/", "", $query);
1371         $query = trim(str_replace($standardQueries, '', $query));
1372
1373         $firstSpc = strpos($query, " ");
1374         $end = ($firstSpc > 0) ? $firstSpc : strlen($query);
1375         $table = substr($query, 0, $end);
1376
1377         return $table;
1378 }
1379
1380 //prelicense check
1381
1382 function preLicenseCheck() {
1383         require_once('modules/UpgradeWizard/uw_files.php');
1384
1385         global $sugar_config;
1386         global $mod_strings;
1387         global $sugar_version;
1388
1389         if(!isset($sugar_version) || empty($sugar_version)) {
1390                 require_once('./sugar_version.php');
1391         }
1392
1393 if(!isset($_SESSION['unzip_dir']) || empty($_SESSION['unzip_dir'])) {
1394                 logThis('unzipping files in upgrade archive...');
1395                 $errors                                 = array();
1396                 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
1397                 $unzip_dir = '';
1398                 //also come up with mechanism to read from upgrade-progress file
1399                 if(!isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !is_file($_SESSION['install_file'])) {
1400                         if (file_exists(clean_path($base_tmp_upgrade_dir)) && $handle = opendir(clean_path($base_tmp_upgrade_dir))) {
1401                                 while (false !== ($file = readdir($handle))) {
1402                                 if($file !="." && $file !="..") {
1403                                          if(is_file($base_tmp_upgrade_dir."/".$file."/manifest.php")){
1404                                                 require_once($base_tmp_upgrade_dir."/".$file."/manifest.php");
1405                                                 $package_name= $manifest['copy_files']['from_dir'];
1406                                                 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")){
1407                                                         $unzip_dir = $base_tmp_upgrade_dir."/".$file;
1408                                                         if(file_exists("$base_upgrade_dir/patch/".$package_name.'.zip')){
1409                                                                 $_SESSION['install_file'] = $package_name.".zip";
1410                                                                 break;
1411                                                         }
1412                                                 }
1413                                           }
1414                                 }
1415                         }
1416                         }
1417                 }
1418         if(empty($_SESSION['install_file'])){
1419                 unlinkUWTempFiles();
1420                 resetUwSession();
1421                 echo 'Upload File not found so redirecting to Upgrade Start ';
1422                 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1423                 echo '<form name="redirect" action="' .$redirect_new_wizard. '"  method="POST">';
1424 $upgrade_directories_not_found =<<<eoq
1425         <table cellpadding="3" cellspacing="0" border="0">
1426                 <tr>
1427                         <th colspan="2" align="left">
1428                                 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1429                         </th>
1430                 </tr>
1431         </table>
1432 eoq;
1433 $uwMain = $upgrade_directories_not_found;
1434                                 return '';
1435         }
1436                 $install_file                   = "$base_upgrade_dir/patch/".basename(urldecode( $_SESSION['install_file'] ));
1437                 $show_files                             = true;
1438                 if(empty($unzip_dir)){
1439                         $unzip_dir                              = mk_temp_dir( $base_tmp_upgrade_dir );
1440                 }
1441                 $zip_from_dir                   = ".";
1442                 $zip_to_dir                             = ".";
1443                 $zip_force_copy                 = array();
1444
1445                 if(!$unzip_dir){
1446                         logThis('Could not create a temporary directory using mk_temp_dir( $base_tmp_upgrade_dir )');
1447                         die($mod_strings['ERR_UW_NO_CREATE_TMP_DIR']);
1448                 }
1449
1450                 //double check whether unzipped .
1451                 if(file_exists($unzip_dir ."/scripts") && file_exists($unzip_dir."/manifest.php")){
1452                 //already unzipped
1453                 }
1454                 else{
1455                         unzip( $install_file, $unzip_dir );
1456                 }
1457
1458                 // assumption -- already validated manifest.php at time of upload
1459                 require_once( "$unzip_dir/manifest.php" );
1460
1461                 if( isset( $manifest['copy_files']['from_dir'] ) && $manifest['copy_files']['from_dir'] != "" ){
1462                     $zip_from_dir   = $manifest['copy_files']['from_dir'];
1463                 }
1464                 if( isset( $manifest['copy_files']['to_dir'] ) && $manifest['copy_files']['to_dir'] != "" ){
1465                     $zip_to_dir     = $manifest['copy_files']['to_dir'];
1466                 }
1467                 if( isset( $manifest['copy_files']['force_copy'] ) && $manifest['copy_files']['force_copy'] != "" ){
1468                     $zip_force_copy     = $manifest['copy_files']['force_copy'];
1469                 }
1470                 if( isset( $manifest['version'] ) ){
1471                     $version    = $manifest['version'];
1472                 }
1473                 if( !is_writable( "config.php" ) ){
1474                         return $mod_strings['ERR_UW_CONFIG'];
1475                 }
1476
1477                 $_SESSION['unzip_dir'] = clean_path($unzip_dir);
1478                 $_SESSION['zip_from_dir'] = clean_path($zip_from_dir);
1479                 logThis('unzip done.');
1480         } else {
1481                 $unzip_dir = $_SESSION['unzip_dir'];
1482                 $zip_from_dir = $_SESSION['zip_from_dir'];
1483         }
1484
1485     //check if $_SESSION['unzip_dir'] and $_SESSION['zip_from_dir'] exist
1486         if(!isset($_SESSION['unzip_dir']) || !file_exists($_SESSION['unzip_dir'])
1487                 || !isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !file_exists($_SESSION['install_file'])){
1488                     //redirect to start
1489             unlinkUWTempFiles();
1490                 resetUwSession();
1491                 echo 'Upload File not found so redirecting to Upgrade Start ';
1492                 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1493                 echo '<form name="redirect" action="' .$redirect_new_wizard. '"  method="POST">';
1494 $upgrade_directories_not_found =<<<eoq
1495         <table cellpadding="3" cellspacing="0" border="0">
1496                 <tr>
1497                         <th colspan="2" align="left">
1498                                 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1499                         </th>
1500                 </tr>
1501         </table>
1502 eoq;
1503 $uwMain = $upgrade_directories_not_found;
1504                                 return '';
1505         }
1506
1507     logThis ('is SugarConfig there '.file_exists(clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarObjects/SugarConfig.php")));
1508         if(file_exists(clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarObjects/SugarConfig.php"))) {
1509                 $file = clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarObjects/SugarConfig.php");
1510                 $destFile = str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), $cwd, $file);
1511                 if(!is_dir(dirname($destFile))) {
1512                         mkdir_recursive(dirname($destFile)); // make sure the directory exists
1513                 }
1514         copy($file,$destFile);
1515         //also copy include utils array utils
1516         $file = clean_path($unzip_dir.'/'.$zip_from_dir."/include/utils/array_utils.php");
1517                 $destFile = str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), $cwd, $file);
1518                 if(!is_dir(dirname($destFile))) {
1519                         mkdir_recursive(dirname($destFile)); // make sure the directory exists
1520                 }
1521         copy($file,$destFile);
1522         }
1523 }
1524
1525
1526 function preflightCheck() {
1527         require_once('modules/UpgradeWizard/uw_files.php');
1528
1529         global $sugar_config;
1530         global $mod_strings;
1531         global $sugar_version;
1532
1533         if(!isset($sugar_version) || empty($sugar_version)) {
1534                 require_once('./sugar_version.php');
1535         }
1536
1537         unset($_SESSION['rebuild_relationships']);
1538         unset($_SESSION['rebuild_extensions']);
1539
1540         // don't bother if are rechecking
1541         $manualDiff                     = array();
1542         if(!isset($_SESSION['unzip_dir']) || empty($_SESSION['unzip_dir'])) {
1543                 logThis('unzipping files in upgrade archive...');
1544                 $errors                                 = array();
1545                 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
1546                 $unzip_dir = '';
1547                 //Following is if User logged out unexpectedly and then logged into UpgradeWizard again.
1548                 //also come up with mechanism to read from upgrade-progress file.
1549                 if(!isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !is_file($_SESSION['install_file'])) {
1550                         if (file_exists($base_tmp_upgrade_dir) && $handle = opendir($base_tmp_upgrade_dir)) {
1551                         while (false !== ($file = readdir($handle))) {
1552                                 if($file !="." && $file !="..") {
1553                                          if(is_file($base_tmp_upgrade_dir."/".$file."/manifest.php")){
1554                                                 require_once($base_tmp_upgrade_dir."/".$file."/manifest.php");
1555                                                 $package_name= $manifest['copy_files']['from_dir'];
1556                                                 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")){
1557                                                         $unzip_dir = $base_tmp_upgrade_dir."/".$file;
1558                                                         if(file_exists("$base_upgrade_dir/patch/".$package_name.'.zip')){
1559                                                                 $_SESSION['install_file'] = $package_name.".zip";
1560                                                                 break;
1561                                                         }
1562                                                 }
1563                                           }
1564                                 }
1565                         }
1566                         }
1567                 }
1568         if(empty($_SESSION['install_file'])){
1569                 unlinkUWTempFiles();
1570                 resetUwSession();
1571                 echo 'Upload File not found so redirecting to Upgrade Start ';
1572                 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1573                 echo '<form name="redirect" action="' .$redirect_new_wizard. '"  method="POST">';
1574 $upgrade_directories_not_found =<<<eoq
1575         <table cellpadding="3" cellspacing="0" border="0">
1576                 <tr>
1577                         <th colspan="2" align="left">
1578                                 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1579                         </th>
1580                 </tr>
1581         </table>
1582 eoq;
1583 $uwMain = $upgrade_directories_not_found;
1584                                 return '';
1585
1586         }
1587                 $install_file                   = "$base_upgrade_dir/patch/".basename(urldecode( $_SESSION['install_file'] ));
1588                 $show_files                             = true;
1589                 if(empty($unzip_dir)){
1590                         $unzip_dir                              = mk_temp_dir( $base_tmp_upgrade_dir );
1591                 }
1592                 $zip_from_dir                   = ".";
1593                 $zip_to_dir                             = ".";
1594                 $zip_force_copy                 = array();
1595
1596                 if(!$unzip_dir){
1597                         logThis('Could not create a temporary directory using mk_temp_dir( $base_tmp_upgrade_dir )');
1598                         die($mod_strings['ERR_UW_NO_CREATE_TMP_DIR']);
1599                 }
1600
1601                 //double check whether unzipped .
1602                 if(file_exists($unzip_dir ."/scripts") && file_exists($unzip_dir."/manifest.php")){
1603                 //already unzipped
1604                 }
1605                 else{
1606                         unzip( $install_file, $unzip_dir );
1607                 }
1608
1609                 // assumption -- already validated manifest.php at time of upload
1610                 require_once( "$unzip_dir/manifest.php" );
1611
1612                 if( isset( $manifest['copy_files']['from_dir'] ) && $manifest['copy_files']['from_dir'] != "" ){
1613                     $zip_from_dir   = $manifest['copy_files']['from_dir'];
1614                 }
1615                 if( isset( $manifest['copy_files']['to_dir'] ) && $manifest['copy_files']['to_dir'] != "" ){
1616                     $zip_to_dir     = $manifest['copy_files']['to_dir'];
1617                 }
1618                 if( isset( $manifest['copy_files']['force_copy'] ) && $manifest['copy_files']['force_copy'] != "" ){
1619                     $zip_force_copy     = $manifest['copy_files']['force_copy'];
1620                 }
1621                 if( isset( $manifest['version'] ) ){
1622                     $version    = $manifest['version'];
1623                 }
1624                 if( !is_writable( "config.php" ) ){
1625                         return $mod_strings['ERR_UW_CONFIG'];
1626                 }
1627
1628                 $_SESSION['unzip_dir'] = clean_path($unzip_dir);
1629                 $_SESSION['zip_from_dir'] = clean_path($zip_from_dir);
1630
1631          //logThis('unzip done.');
1632         } else {
1633                 $unzip_dir = $_SESSION['unzip_dir'];
1634                 $zip_from_dir = $_SESSION['zip_from_dir'];
1635         }
1636         //check if $_SESSION['unzip_dir'] and $_SESSION['zip_from_dir'] exist
1637         if(!isset($_SESSION['unzip_dir']) || !file_exists($_SESSION['unzip_dir'])
1638                 || !isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !file_exists($_SESSION['install_file'])){
1639                     //redirect to start
1640             unlinkUWTempFiles();
1641                 resetUwSession();
1642                 echo 'Upload File not found so redirecting to Upgrade Start ';
1643                 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1644                 echo '<form name="redirect" action="' .$redirect_new_wizard. '"  method="POST">';
1645 $upgrade_directories_not_found =<<<eoq
1646         <table cellpadding="3" cellspacing="0" border="0">
1647                 <tr>
1648                         <th colspan="2" align="left">
1649                                 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1650                         </th>
1651                 </tr>
1652         </table>
1653 eoq;
1654 $uwMain = $upgrade_directories_not_found;
1655                                 return '';
1656         }
1657         //copy minimum required files
1658         fileCopy('include/utils/sugar_file_utils.php');
1659
1660         $upgradeFiles = findAllFiles(clean_path("$unzip_dir/$zip_from_dir"), array());
1661         $cache_html_files= array();
1662
1663         // get md5 sums
1664         $md5_string = array();
1665         if(file_exists(clean_path(getcwd().'/files.md5'))){
1666                 require(clean_path(getcwd().'/files.md5'));
1667         }
1668
1669         // file preflight checks
1670         logThis('verifying md5 checksums for files...');
1671         foreach($upgradeFiles as $file) {
1672                 if(in_array(str_replace(clean_path("$unzip_dir/$zip_from_dir") . "/", '', $file), $uw_files))
1673                         continue; // skip already loaded files
1674
1675                 if(strpos($file, '.md5'))
1676                         continue; // skip md5 file
1677
1678                 // normalize file paths
1679                 $file = clean_path($file);
1680
1681                 // check that we can move/delete the upgraded file
1682                 if(!is_writable($file)) {
1683                         $errors[] = $mod_strings['ERR_UW_FILE_NOT_WRITABLE'].": ".$file;
1684                 }
1685                 // check that destination files are writable
1686                 $destFile = getcwd().str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), '', $file);
1687
1688                 if(is_file($destFile)) { // of course it needs to exist first...
1689                         if(!is_writable($destFile)) {
1690                                 $errors[] = $mod_strings['ERR_UW_FILE_NOT_WRITABLE'].": ".$destFile;
1691                         }
1692                 }
1693
1694                 ///////////////////////////////////////////////////////////////////////
1695                 ////    DIFFS
1696                 // compare md5s and build up a manual merge list
1697                 $targetFile = clean_path(".".str_replace(getcwd(),'',$destFile));
1698                 $targetMd5 = '0';
1699                 if(is_file($destFile)) {
1700                         if(strpos($targetFile, '.php')) {
1701                                 // handle PHP files that were hit with the security regex
1702                                 $fp = '';
1703                                 if(function_exists('sugar_fopen')){
1704                                         $fp = sugar_fopen($destFile, 'r');
1705                                 }
1706                                 else{
1707                                         $fp = fopen($destFile, 'r');
1708                                 }
1709                                 $filesize = filesize($destFile);
1710                                 if($filesize > 0) {
1711                                         $fileContents = stream_get_contents($fp);
1712                                         $targetMd5 = md5($fileContents);
1713                                 }
1714                         } else {
1715                                 $targetMd5 = md5_file($destFile);
1716                         }
1717                 }
1718
1719                 if(isset($md5_string[$targetFile]) && $md5_string[$targetFile] != $targetMd5) {
1720                         logThis('found a file with a differing md5: ['.$targetFile.']');
1721                         $manualDiff[] = $destFile;
1722                 }
1723                 ////    END DIFFS
1724                 ///////////////////////////////////////////////////////////////////////
1725         }
1726         logThis('md5 verification done.');
1727         $errors['manual'] = $manualDiff;
1728
1729         return $errors;
1730 }
1731
1732 function fileCopy($file_path){
1733         if(file_exists(clean_path($_SESSION['unzip_dir'].'/'.$_SESSION['zip_from_dir'].'/'.$file_path))) {
1734                 $file = clean_path($_SESSION['unzip_dir'].'/'.$_SESSION['zip_from_dir'].'/'.$file_path);
1735                 $destFile = str_replace(clean_path($_SESSION['unzip_dir'].'/'.$_SESSION['zip_from_dir']),  clean_path(getcwd()), $file);
1736         if(!is_dir(dirname($destFile))) {
1737                 mkdir_recursive(dirname($destFile)); // make sure the directory exists
1738                 }
1739                 copy_recursive($file,$destFile);
1740         }
1741 }
1742 function getChecklist($steps, $step) {
1743         global $mod_strings;
1744
1745         $skip = array('start', 'cancel', 'uninstall','end');
1746         $j=0;
1747         $i=1;
1748         $ret  = '<table cellpadding="3" cellspacing="4" border="0">';
1749         $ret .= '<tr><th colspan="3" align="left">'.$mod_strings['LBL_UW_CHECKLIST'].':</th></tr>';
1750         foreach($steps['desc'] as $k => $desc) {
1751                 if(in_array($steps['files'][$j], $skip)) {
1752                         $j++;
1753                         continue;
1754                 }
1755
1756                 //$status = "<span class='error'>{$mod_strings['LBL_UW_INCOMPLETE']}</span>";
1757                 $desc_mod_pre = '';
1758                 $desc_mod_post = '';
1759                 /*
1760                 if(isset($_SESSION['step'][$steps['files'][$k]]) && $_SESSION['step'][$steps['files'][$k]] == 'success') {
1761                         //$status = $mod_strings['LBL_UW_COMPLETE'];
1762                 }
1763                 */
1764
1765                 if($k == $_REQUEST['step']) {
1766                         //$status = $mod_strings['LBL_UW_IN_PROGRESS'];
1767                         $desc_mod_pre = "<font color=blue><i>";
1768                         $desc_mod_post = "</i></font>";
1769                 }
1770
1771                 $ret .= "<tr><td>&nbsp;</td><td><b>{$i}: {$desc_mod_pre}{$desc}{$desc_mod_post}</b></td>";
1772                 $ret .= "<td id={$steps['files'][$j]}><i></i></td></tr>";
1773                 $i++;
1774                 $j++;
1775         }
1776         $ret .= "</table>";
1777         return $ret;
1778 }
1779
1780 function prepSystemForUpgrade() {
1781         global $sugar_config;
1782         global $sugar_flavor;
1783         global $mod_strings;
1784     global $current_language;
1785         global $subdirs;
1786         global $base_upgrade_dir;
1787         global $base_tmp_upgrade_dir;
1788     list($p_base_upgrade_dir, $p_base_tmp_upgrade_dir) = getUWDirs();
1789         ///////////////////////////////////////////////////////////////////////////////
1790         ////    Make sure variables exist
1791         if(empty($base_upgrade_dir)){
1792                 $base_upgrade_dir       = $p_base_upgrade_dir;
1793         }
1794         if(empty($base_tmp_upgrade_dir)){
1795                 $base_tmp_upgrade_dir   = $p_base_tmp_upgrade_dir;
1796         }
1797         sugar_mkdir($base_tmp_upgrade_dir, 0775, true);
1798         if(!isset($subdirs) || empty($subdirs)){
1799                 $subdirs = array('full', 'langpack', 'module', 'patch', 'theme');
1800         }
1801
1802     $upgrade_progress_dir = $base_tmp_upgrade_dir;
1803     $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
1804     if(file_exists($upgrade_progress_file)){
1805         if(function_exists('get_upgrade_progress') && function_exists('didThisStepRunBefore')){
1806                 if(didThisStepRunBefore('end')){
1807                         include($upgrade_progress_file);
1808                         unset($upgrade_config);
1809                         unlink($upgrade_progress_file);
1810                 }
1811         }
1812     }
1813
1814     // increase the cuttoff time to 1 hour
1815         ini_set("max_execution_time", "3600");
1816
1817     // make sure dirs exist
1818         if($subdirs != null){
1819                 foreach($subdirs as $subdir) {
1820                     sugar_mkdir("$base_upgrade_dir/$subdir", 0775, true);
1821                 }
1822         }
1823         // array of special scripts that are executed during (un)installation-- key is type of script, value is filename
1824         if(!defined('SUGARCRM_PRE_INSTALL_FILE')) {
1825                 define('SUGARCRM_PRE_INSTALL_FILE', 'scripts/pre_install.php');
1826                 define('SUGARCRM_POST_INSTALL_FILE', 'scripts/post_install.php');
1827                 define('SUGARCRM_PRE_UNINSTALL_FILE', 'scripts/pre_uninstall.php');
1828                 define('SUGARCRM_POST_UNINSTALL_FILE', 'scripts/post_uninstall.php');
1829         }
1830
1831         $script_files = array(
1832                 "pre-install" => constant('SUGARCRM_PRE_INSTALL_FILE'),
1833                 "post-install" => constant('SUGARCRM_POST_INSTALL_FILE'),
1834                 "pre-uninstall" => constant('SUGARCRM_PRE_UNINSTALL_FILE'),
1835                 "post-uninstall" => constant('SUGARCRM_POST_UNINSTALL_FILE'),
1836         );
1837
1838         // check that the upload limit is set to 6M or greater
1839         define('SUGARCRM_MIN_UPLOAD_MAX_FILESIZE_BYTES', 6 * 1024 * 1024);  // 6 Megabytes
1840         $upload_max_filesize = ini_get('upload_max_filesize');
1841         $upload_max_filesize_bytes = return_bytes($upload_max_filesize);
1842
1843         if($upload_max_filesize_bytes < constant('SUGARCRM_MIN_UPLOAD_MAX_FILESIZE_BYTES')) {
1844                 $GLOBALS['log']->debug("detected upload_max_filesize: $upload_max_filesize");
1845         $admin_strings = return_module_language($current_language, 'Administration');
1846                 echo '<p class="error">'.$admin_strings['MSG_INCREASE_UPLOAD_MAX_FILESIZE'].' '.get_cfg_var('cfg_file_path')."</p>\n";
1847         }
1848 }
1849
1850 if ( !function_exists('extractFile') ) {
1851 function extractFile($zip_file, $file_in_zip) {
1852     global $base_tmp_upgrade_dir;
1853
1854         // strip cwd
1855         $absolute_base_tmp_upgrade_dir = clean_path($base_tmp_upgrade_dir);
1856         $relative_base_tmp_upgrade_dir = clean_path(str_replace(clean_path(getcwd()), '', $absolute_base_tmp_upgrade_dir));
1857
1858     // mk_temp_dir expects relative pathing
1859     $my_zip_dir = mk_temp_dir($relative_base_tmp_upgrade_dir);
1860
1861     unzip_file($zip_file, $file_in_zip, $my_zip_dir);
1862
1863     return("$my_zip_dir/$file_in_zip");
1864 }
1865 }
1866
1867 if ( !function_exists('extractManifest') ) {
1868 function extractManifest($zip_file) {
1869         logThis('extracting manifest.');
1870     return(extractFile($zip_file, "manifest.php"));
1871 }
1872 }
1873
1874 if ( !function_exists('getInstallType') ) {
1875 function getInstallType($type_string) {
1876     // detect file type
1877     global $subdirs;
1878         $subdirs = array('full', 'langpack', 'module', 'patch', 'theme', 'temp');
1879     foreach($subdirs as $subdir) {
1880         if(preg_match("#/$subdir/#", $type_string)) {
1881             return($subdir);
1882         }
1883     }
1884     // return empty if no match
1885     return("");
1886 }
1887 }
1888
1889 function getImageForType($type) {
1890     global $image_path;
1891     global $mod_strings;
1892
1893     $icon = "";
1894     switch($type) {
1895         case "full":
1896             $icon = SugarThemeRegistry::current()->getImage("Upgrade", "",null,null,'.gif',$mod_strings['LBL_UPGRADE']);
1897             break;
1898         case "langpack":
1899             $icon = SugarThemeRegistry::current()->getImage("LanguagePacks", "",null,null,'.gif',$mod_strings['LBL_LANGPACKS']);
1900             break;
1901         case "module":
1902             $icon = SugarThemeRegistry::current()->getImage("ModuleLoader", "",null,null,'.gif',$mod_strings['LBL_MODULELOADER']);
1903             break;
1904         case "patch":
1905             $icon = SugarThemeRegistry::current()->getImage("PatchUpgrades", "",null,null,'.gif',$mod_strings['LBL_PATCHUPGRADES']);
1906             break;
1907         case "theme":
1908             $icon = SugarThemeRegistry::current()->getImage("Themes", "",null,null,'.gif',$mod_strings['LBL_THEMES']);
1909             break;
1910         default:
1911             break;
1912     }
1913     return($icon);
1914 }
1915
1916 if ( !function_exists('getLanguagePackName') ) {
1917 function getLanguagePackName($the_file) {
1918     require_once("$the_file");
1919     if(isset($app_list_strings["language_pack_name"])) {
1920         return($app_list_strings["language_pack_name"]);
1921     }
1922     return("");
1923 }
1924 }
1925
1926 function getUITextForType($type) {
1927     if($type == "full") {
1928         return("Full Upgrade");
1929     }
1930     if($type == "langpack") {
1931         return("Language Pack");
1932     }
1933     if($type == "module") {
1934         return("Module");
1935     }
1936     if($type == "patch") {
1937         return("Patch");
1938     }
1939     if($type == "theme") {
1940         return("Theme");
1941     }
1942 }
1943
1944 if ( !function_exists('validate_manifest') ) {
1945 /**
1946  * Verifies a manifest from a patch or module to be compatible with the current Sugar version and flavor
1947  * @param array manifest Standard manifest array
1948  * @return string Error message, blank on success
1949  */
1950 function validate_manifest($manifest) {
1951         logThis('validating manifest.php file');
1952     // takes a manifest.php manifest array and validates contents
1953     global $subdirs;
1954     global $sugar_version;
1955     global $sugar_flavor;
1956         global $mod_strings;
1957
1958     if(!isset($manifest['type'])) {
1959         return $mod_strings['ERROR_MANIFEST_TYPE'];
1960     }
1961
1962     $type = $manifest['type'];
1963
1964     if(getInstallType("/$type/") == "") {
1965                 return $mod_strings['ERROR_PACKAGE_TYPE']. ": '" . $type . "'.";
1966     }
1967
1968     if(isset($manifest['acceptable_sugar_versions'])) {
1969         $version_ok = false;
1970         $matches_empty = true;
1971         if(isset($manifest['acceptable_sugar_versions']['exact_matches'])) {
1972             $matches_empty = false;
1973             foreach($manifest['acceptable_sugar_versions']['exact_matches'] as $match) {
1974                 if($match == $sugar_version) {
1975                     $version_ok = true;
1976                 }
1977             }
1978         }
1979         if(!$version_ok && isset($manifest['acceptable_sugar_versions']['regex_matches'])) {
1980             $matches_empty = false;
1981             foreach($manifest['acceptable_sugar_versions']['regex_matches'] as $match) {
1982                 if(preg_match("/$match/", $sugar_version)) {
1983                     $version_ok = true;
1984                 }
1985             }
1986         }
1987
1988         if(!$matches_empty && !$version_ok) {
1989             return $mod_strings['ERROR_VERSION_INCOMPATIBLE']."<br />".
1990             $mod_strings['ERR_UW_VERSION'].$sugar_version;
1991         }
1992     }
1993
1994     if(isset($manifest['acceptable_sugar_flavors']) && sizeof($manifest['acceptable_sugar_flavors']) > 0) {
1995         $flavor_ok = false;
1996         foreach($manifest['acceptable_sugar_flavors'] as $match) {
1997             if($match == $sugar_flavor) {
1998                 $flavor_ok = true;
1999             }
2000         }
2001         if(!$flavor_ok) {
2002             return $mod_strings['ERROR_FLAVOR_INCOMPATIBLE']."<br />".
2003             $mod_strings['ERR_UW_FLAVOR'].$sugar_flavor."<br />".
2004             $mod_strings['ERR_UW_FLAVOR_2'].$manifest['acceptable_sugar_flavors'][0];
2005         }
2006     }
2007
2008     return '';
2009 }
2010 }
2011
2012 function unlinkUploadFiles() {
2013         return;
2014 //      logThis('at unlinkUploadFiles()');
2015 //
2016 //      if(isset($_SESSION['install_file']) && !empty($_SESSION['install_file'])) {
2017 //              $upload = $_SESSION['install_file'];
2018 //
2019 //              if(is_file($upload)) {
2020 //                      logThis('unlinking ['.$upload.']');
2021 //                      @unlink($upload);
2022 //              }
2023 //      }
2024 }
2025
2026 /**
2027  * deletes files created by unzipping a package
2028  */
2029 function unlinkUWTempFiles() {
2030         global $sugar_config;
2031         global $path;
2032
2033         logThis('at unlinkUWTempFiles()');
2034         $tempDir='';
2035         list($upgDir, $tempDir) = getUWDirs();
2036
2037     if(file_exists($tempDir) && is_dir($tempDir)){
2038                 $files = findAllFiles($tempDir, array(), false);
2039                 rsort($files);
2040                 foreach($files as $file) {
2041                         if(!is_dir($file)) {
2042                                 //logThis('unlinking ['.$file.']', $path);
2043                                 @unlink($file);
2044                         }
2045                 }
2046                 // now do dirs
2047                 $files = findAllFiles($tempDir, array(), true);
2048                 foreach($files as $dir) {
2049                         if(is_dir($dir)) {
2050                                 //logThis('removing dir ['.$dir.']', $path);
2051                                 @rmdir($dir);
2052                         }
2053                 }
2054                 $cacheFile = sugar_cached("modules/UpgradeWizard/_persistence.php");
2055                 if(is_file($cacheFile)) {
2056                         logThis("Unlinking Upgrade cache file: '_persistence.php'", $path);
2057                         @unlink($cacheFile);
2058                 }
2059         }
2060         logThis("finished!");
2061 }
2062
2063 /**
2064  * finds all files in the passed path, but skips select directories
2065  * @param string dir Relative path
2066  * @param array the_array Collections of found files/dirs
2067  * @param bool include_dir True if we want to include directories in the
2068  * returned collection
2069  */
2070 function uwFindAllFiles($dir, $theArray, $includeDirs=false, $skipDirs=array(), $echo=false) {
2071         // check skips
2072     if (whetherNeedToSkipDir($dir, $skipDirs))
2073         {
2074             return $theArray;
2075         }
2076
2077     if (!is_dir($dir)) { return $theArray; }   // Bug # 46035, just checking for valid dir
2078         $d = dir($dir);
2079     if ($d === false)  { return $theArray; }   // Bug # 46035, more checking
2080
2081         while($f = $d->read()) {
2082                                         // bug 40793 Skip Directories array in upgradeWizard does not function correctly
2083             if($f == "." || $f == ".." || whetherNeedToSkipDir("$dir/$f", $skipDirs)) { // skip *nix self/parent
2084                 continue;
2085             }
2086
2087                 // for AJAX length count
2088         if($echo) {
2089                 echo '.';
2090                 ob_flush();
2091         }
2092
2093             if(is_dir("$dir/$f")) {
2094                         if($includeDirs) { // add the directory if flagged
2095                                 $theArray[] = clean_path("$dir/$f");
2096                         }
2097
2098                         // recurse in
2099                 $theArray = uwFindAllFiles("$dir/$f/", $theArray, $includeDirs, $skipDirs, $echo);
2100             } else {
2101                 $theArray[] = clean_path("$dir/$f");
2102             }
2103
2104
2105         }
2106         rsort($theArray);
2107         $d->close();
2108         return $theArray;
2109 }
2110
2111
2112
2113 /**
2114  * unset's UW's Session Vars
2115  */
2116 function resetUwSession() {
2117         logThis('resetting $_SESSION');
2118
2119         if(isset($_SESSION['committed']))
2120                 unset($_SESSION['committed']);
2121         if(isset($_SESSION['sugar_version_file']))
2122                 unset($_SESSION['sugar_version_file']);
2123         if(isset($_SESSION['upgrade_complete']))
2124                 unset($_SESSION['upgrade_complete']);
2125         if(isset($_SESSION['allTables']))
2126                 unset($_SESSION['allTables']);
2127         if(isset($_SESSION['alterCustomTableQueries']))
2128                 unset($_SESSION['alterCustomTableQueries']);
2129         if(isset($_SESSION['skip_zip_upload']))
2130                 unset($_SESSION['skip_zip_upload']);
2131         if(isset($_SESSION['sugar_version_file']))
2132                 unset($_SESSION['sugar_version_file']);
2133         if(isset($_SESSION['install_file']))
2134                 unset($_SESSION['install_file']);
2135         if(isset($_SESSION['unzip_dir']))
2136                 unset($_SESSION['unzip_dir']);
2137         if(isset($_SESSION['zip_from_dir']))
2138                 unset($_SESSION['zip_from_dir']);
2139         if(isset($_SESSION['overwrite_files']))
2140                 unset($_SESSION['overwrite_files']);
2141         if(isset($_SESSION['schema_change']))
2142                 unset($_SESSION['schema_change']);
2143         if(isset($_SESSION['uw_restore_dir']))
2144                 unset($_SESSION['uw_restore_dir']);
2145         if(isset($_SESSION['step']))
2146                 unset($_SESSION['step']);
2147         if(isset($_SESSION['files']))
2148                 unset($_SESSION['files']);
2149         if(isset($_SESSION['Upgraded451Wizard'])){
2150                 unset($_SESSION['Upgraded451Wizard']);
2151         }
2152         if(isset($_SESSION['Initial_451to500_Step'])){
2153                 unset($_SESSION['Initial_451to500_Step']);
2154         }
2155         if(isset($_SESSION['license_shown']))
2156                 unset($_SESSION['license_shown']);
2157     if(isset($_SESSION['sugarMergeRunResults']))
2158                 unset($_SESSION['sugarMergeRunResults']);
2159 }
2160
2161 /**
2162  * runs rebuild scripts
2163  */
2164 function UWrebuild() {
2165         global $db;
2166         global $path;
2167         /*
2168         //CCL - Comment this block out, it is called in end.php
2169         logThis('Rebuilding everything...', $path);
2170         require_once('modules/Administration/QuickRepairAndRebuild.php');
2171         $randc = new RepairAndClear();
2172     $randc->repairAndClearAll(array('clearAll'),array(translate('LBL_ALL_MODULES')), false, false);
2173     */
2174         $query = "DELETE FROM versions WHERE name='Rebuild Extensions'";
2175         $db->query($query);
2176         logThis('Registering rebuild record: '.$query, $path);
2177         logThis('Rebuild done.', $path);
2178
2179         // insert a new database row to show the rebuild extensions is done
2180         $id = create_guid();
2181         $gmdate = gmdate('Y-m-d H:i:s');
2182         $date_entered = db_convert("'$gmdate'", 'datetime');
2183         $query = 'INSERT INTO versions (id, deleted, date_entered, date_modified, modified_user_id, created_by, name, file_version, db_version) '
2184                 . "VALUES ('$id', '0', $date_entered, $date_entered, '1', '1', 'Rebuild Extensions', '4.0.0', '4.0.0')";
2185         $db->query($query);
2186         logThis('Registering rebuild record in versions table: '.$query, $path);
2187 }
2188
2189 function getCustomTables() {
2190         global $db;
2191
2192     return $db->tablesLike('%_cstm');
2193 }
2194
2195 function alterCustomTables($customTables)
2196 {
2197         return array();
2198 }
2199
2200 function getAllTables() {
2201         global $db;
2202     return $db->getTablesArray();
2203 }
2204
2205 function printAlterTableSql($tables)
2206 {
2207         $alterTableSql = '';
2208
2209         foreach($tables as $table)
2210                 $alterTableSql .= "ALTER TABLE " . $table . " CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;" . "\n";
2211
2212         return $alterTableSql;
2213 }
2214
2215 function executeConvertTablesSql($tables)
2216 {
2217         global $db;
2218
2219         foreach($tables as $table){
2220                 $query = "ALTER TABLE " . $table . " CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci";
2221                 if(!empty($table)){
2222                         logThis("Sending query: ".$query);
2223             $db->query($query);//, true, "An error has occured while performing db query.  See log file for details.<br>");
2224          }
2225         }
2226         return true;
2227 }
2228
2229 function testThis() {
2230         $files = uwFindAllFiles(getcwd().'/test', array());
2231
2232         $out = "<table cellpadding='1' cellspacing='0' border='0'>\n";
2233
2234         $priorPath = '';
2235         foreach($files as $file) {
2236                 $relativeFile = clean_path(str_replace(getcwd().'/test', '', $file));
2237                 $relativeFile = ($relativeFile{0} == '/') ? substr($relativeFile, 1, strlen($relativeFile)) : $relativeFile;
2238
2239                 $relativePath = dirname($relativeFile);
2240
2241                 if($relativePath == $priorPath) { // same dir, new file
2242                         $out .= "<tr><td>".basename($relativeFile)."</td></tr>";
2243                         $priorPath = $relativePath;
2244                 } else { // new dir
2245
2246                 }
2247         }
2248
2249         $out .= "</table>";
2250
2251         echo $out;
2252 }
2253
2254
2255
2256
2257 function testThis2($dir, $id=0, $hide=false) {
2258     global $mod_strings;
2259         $path = $dir;
2260         $dh = opendir($dir);
2261         rewinddir($dh);
2262
2263         $doHide = ($hide) ? 'none' : '';
2264         $out = "<div id='{$id}' style='display:{$doHide};'>";
2265         $out .= "<table cellpadding='1' cellspacing='0' style='border:0px solid #ccc'>\n";
2266
2267         while($file = readdir($dh)) {
2268                 if($file == '.' || $file == '..' || $file == 'CVS' || $file == '.cvsignore')
2269                         continue;
2270
2271                 if(is_dir($path.'/'.$file)) {
2272                         $file = $path.'/'.$file;
2273                         $newI = create_guid();
2274                         $out .= "<tr><td valign='top'><a href='javascript:toggleNwFiles(\"{$newI}\");'>".SugarThemeRegistry::current()->getImage("Workflow", "", null, null, ".gif", $mod_strings['LBL_WORKFLOW'])."</a></td>\n";
2275                         $out .= "<td valign='top'><b><a href='javascript:toggleNwFiles(\"{$newI}\");'>".basename($file)."</a></b></td></tr>";
2276                         $out .= "<tr><td></td><td valign='top'>".testThis2($file, $newI, true)."</td></tr>";
2277                 } else {
2278                         $out .= "<tr><td valign='top'>&nbsp;</td>\n";
2279                         $out .= "<td valign='top'>".basename($file)."</td></tr>";
2280                 }
2281         }
2282
2283         $out .= "</tr></table>";
2284         $out .= "</div>";
2285
2286         closedir($dh);
2287         return $out;
2288 }
2289
2290
2291
2292
2293
2294 function testThis3(&$files, $id, $hide, $previousPath = '') {
2295         if(!is_array($files) || empty($files))
2296                 return '';
2297
2298         $out = '';
2299
2300     global $mod_strings;
2301         // expecting full path here
2302         foreach($files as $k => $file) {
2303                 $file = str_replace(getcwd(), '', $file);
2304                 $path = dirname($file);
2305                 $fileName = basename($file);
2306
2307                 if($fileName == 'CVS' || $fileName == '.cvsignore')
2308                         continue;
2309
2310                 if($path == $previousPath) { // same directory
2311                         // new row for each file
2312                         $out .= "<tr><td valign='top' align='left'>&nbsp;</td>";
2313                         $out .= "<td valign='top' align='left'>{$fileName}</td></tr>";
2314                 } else { // new directory
2315                         $newI = $k;
2316                         $out .= "<tr><td valign='top'><a href='javascript:toggleNwFiles(\"{$newI}\");'>".SugarThemeRegistry::current()->getImage("Workflow", "", null, null, ".gif", $mod_strings['LBL_WORKFLOW'])."</a></td>\n";
2317                         $out .= "<td valign='top'><b><a href='javascript:toggleNwFiles(\"{$newI}\");'>".$fileName."</a></b></td></tr>";
2318                         $recurse = testThis3($files, $newI, true, $previousPath);
2319                         $out .= "<tr><td></td><td valign='top'>".$recurse."</td></tr>";
2320                 }
2321
2322                 $previousPath = $path;
2323         }
2324         $display = ($hide) ? 'none' : '';
2325         $ret = <<<eoq
2326         <div id="{$id}" style="display:{$display}">
2327         <table cellpadding='1' cellspacing='0' border='0' style='border:1px solid #ccc'>
2328                 {$out}
2329         </table>
2330         </div>
2331 eoq;
2332         return $ret;
2333 }
2334
2335
2336 function testThis4($filePath, $fileNodes=array(), $fileName='') {
2337         $path = dirname($filePath);
2338         $file = basename($filePath);
2339
2340         $exFile = explode('/', $path);
2341
2342         foreach($exFile as $pathSegment) {
2343                 if(is_array($fileNodes[$pathSegment])) { // path already processed
2344
2345                 } else { // newly found path
2346                         $fileNodes[$pathSegment] = array();
2347                 }
2348
2349                 if($fileName != '') {
2350                         $fileNodes[$pathSegment][] = $fileName;
2351                 }
2352         }
2353
2354         return $fileNodes;
2355 }
2356
2357
2358
2359 ///////////////////////////////////////////////////////////////////////////////
2360 ////    SYSTEM CHECK FUNCTIONS
2361 /**
2362  * generates an array with all files in the SugarCRM root directory, skipping
2363  * cache/
2364  * @return array files Array of files with absolute paths
2365  */
2366 function getFilesForPermsCheck() {
2367         global $sugar_config;
2368
2369         logThis('Got JSON call to find all files...');
2370         $filesNotWritable = array();
2371         $filesNWPerms = array();
2372
2373         // add directories here that should be skipped when doing file permissions checks (cache/upload is the nasty one)
2374         $skipDirs = array(
2375                 $sugar_config['upload_dir'],
2376         );
2377         $files = uwFindAllFiles(".", array(), true, $skipDirs, true);
2378         return $files;
2379 }
2380
2381 /**
2382  * checks files for permissions
2383  * @param array files Array of files with absolute paths
2384  * @return string result of check
2385  */
2386 function checkFiles($files, $echo=false) {
2387         global $mod_strings;
2388         $filesNotWritable = array();
2389         $i=0;
2390         $filesOut = "
2391                 <a href='javascript:void(0); toggleNwFiles(\"filesNw\");'>{$mod_strings['LBL_UW_SHOW_NW_FILES']}</a>
2392                 <div id='filesNw' style='display:none;'>
2393                 <table cellpadding='3' cellspacing='0' border='0'>
2394                 <tr>
2395                         <th align='left'>{$mod_strings['LBL_UW_FILE']}</th>
2396                         <th align='left'>{$mod_strings['LBL_UW_FILE_PERMS']}</th>
2397                         <th align='left'>{$mod_strings['LBL_UW_FILE_OWNER']}</th>
2398                         <th align='left'>{$mod_strings['LBL_UW_FILE_GROUP']}</th>
2399                 </tr>";
2400
2401         $isWindows = is_windows();
2402         foreach($files as $file) {
2403
2404                 if($isWindows) {
2405                         if(!is_writable_windows($file)) {
2406                                 logThis('WINDOWS: File ['.$file.'] not readable - saving for display');
2407                                 // don't warn yet - we're going to use this to check against replacement files
2408         // aw: commented out; it's a hack to allow upgrade wizard to continue on windows... will fix later
2409                                 /*$filesNotWritable[$i] = $file;
2410                                 $filesNWPerms[$i] = substr(sprintf('%o',fileperms($file)), -4);
2411                                 $filesOut .= "<tr>".
2412                                                                 "<td><span class='error'>{$file}</span></td>".
2413                                                                 "<td>{$filesNWPerms[$i]}</td>".
2414                                                                 "<td>".$mod_strings['ERR_UW_CANNOT_DETERMINE_USER']."</td>".
2415                                                                 "<td>".$mod_strings['ERR_UW_CANNOT_DETERMINE_GROUP']."</td>".
2416                                                           "</tr>";*/
2417                         }
2418                 } else {
2419                         if(!is_writable($file)) {
2420                                 logThis('File ['.$file.'] not writable - saving for display');
2421                                 // don't warn yet - we're going to use this to check against replacement files
2422                                 $filesNotWritable[$i] = $file;
2423                                 $filesNWPerms[$i] = substr(sprintf('%o',fileperms($file)), -4);
2424                                 $owner = posix_getpwuid(fileowner($file));
2425                                 $group = posix_getgrgid(filegroup($file));
2426                                 $filesOut .= "<tr>".
2427                                                                 "<td><span class='error'>{$file}</span></td>".
2428                                                                 "<td>{$filesNWPerms[$i]}</td>".
2429                                                                 "<td>".$owner['name']."</td>".
2430                                                                 "<td>".$group['name']."</td>".
2431                                                           "</tr>";
2432                         }
2433                 }
2434                 $i++;
2435         }
2436
2437         $filesOut .= '</table></div>';
2438         // not a stop error
2439         $errors['files']['filesNotWritable'] = (count($filesNotWritable) > 0) ? true : false;
2440         if(count($filesNotWritable) < 1) {
2441                 $filesOut = "{$mod_strings['LBL_UW_FILE_NO_ERRORS']}";
2442         }
2443
2444         return $filesOut;
2445 }
2446
2447 function deletePackageOnCancel(){
2448         global $mod_strings;
2449         global $sugar_config;
2450         list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
2451         logThis('running delete');
2452     if(!isset($_SESSION['install_file']) || ($_SESSION['install_file'] == "")) {
2453         logThis('ERROR: trying to delete non-existent file: ['.$_REQUEST['install_file'].']');
2454         $error = $mod_strings['ERR_UW_NO_FILE_UPLOADED'];
2455     }
2456     // delete file in upgrades/patch
2457     $delete_me = "$base_upgrade_dir/patch/".basename(urldecode( $_REQUEST['install_file'] ));
2458     if(@unlink($delete_me)) {
2459         //logThis('unlinking: '.$delete_me);
2460         $out = basename($delete_me).$mod_strings['LBL_UW_FILE_DELETED'];
2461     } else {
2462         logThis('ERROR: could not delete ['.$delete_me.']');
2463                 $error = $mod_strings['ERR_UW_FILE_NOT_DELETED'].$delete_me;
2464     }
2465
2466     if(!empty($error)) {
2467                 $out = "<b><span class='error'>{$error}</span></b><br />";
2468     }
2469 }
2470
2471 function handleExecuteSqlKeys($db, $tableName, $disable)
2472 {
2473     if(empty($tableName)) return true;
2474     if(is_callable(array($db, "supports"))) {
2475         // new API
2476         return $disable?$db->disableKeys($tableName):$db->enableKeys($tableName);
2477     } else {
2478         // old api
2479         $op = $disable?"DISABLE":"ENABLE";
2480         return $db->query("ALTER TABLE $tableName $op KEYS");
2481     }
2482 }
2483
2484 function parseAndExecuteSqlFile($sqlScript,$forStepQuery='',$resumeFromQuery='')
2485 {
2486         global $sugar_config;
2487         $alterTableSchema = '';
2488         $sqlErrors = array();
2489         if(!isset($_SESSION['sqlSkippedQueries'])){
2490                 $_SESSION['sqlSkippedQueries'] = array();
2491         }
2492         $db = DBManagerFactory::getInstance();
2493         $disable_keys = ($db->dbType == "mysql"); // have to use old way for now for upgrades
2494         if(strpos($resumeFromQuery,",") != false){
2495                 $resumeFromQuery = explode(",",$resumeFromQuery);
2496         }
2497         if(file_exists($sqlScript)) {
2498                 $fp = fopen($sqlScript, 'r');
2499                 $contents = stream_get_contents($fp);
2500                 $anyScriptChanges =$contents;
2501                 $resumeAfterFound = false;
2502                 if(rewind($fp)) {
2503                         $completeLine = '';
2504                         $count = 0;
2505                         while($line = fgets($fp)) {
2506                                 if(strpos($line, '--') === false) {
2507                                         $completeLine .= " ".trim($line);
2508                                         if(strpos($line, ';') !== false) {
2509                                                 $query = '';
2510                                                 $query = str_replace(';','',$completeLine);
2511                                                 //if resume from query is not null then find out from where
2512                                                 //it should start executing the query.
2513
2514                                                 if($query != null && $resumeFromQuery != null){
2515                                                         if(!$resumeAfterFound){
2516                                                                 if(strpos($query,",") != false){
2517                                                                         $queArray = explode(",",$query);
2518                                                                         for($i=0;$i<sizeof($resumeFromQuery);$i++){
2519                                                                                 if(strcasecmp(trim($resumeFromQuery[$i]),trim($queArray[$i]))==0){
2520                                                                                         $resumeAfterFound = true;
2521                                                                                 } else {
2522                                                                                         $resumeAfterFound = false;
2523                                                                                         break;
2524                                                                                 }
2525                                                                         }//for
2526
2527                                                                 }
2528                                                                 elseif(strcasecmp(trim($resumeFromQuery),trim($query))==0){
2529                                                                         $resumeAfterFound = true;
2530                                                                 }
2531                                                         }
2532                                                         if($resumeAfterFound){
2533                                                                 $count++;
2534                                                         }
2535                                                         // if $count=1 means it is just found so skip the query. Run the next one
2536                                                         if($query != null && $resumeAfterFound && $count >1){
2537                                                         $tableName = getAlterTable($query);
2538                                                                 if($disable_keys)
2539                                                                 {
2540                                                                         handleExecuteSqlKeys($db, $tableName, true);
2541                                                                 }
2542                                                                 $db->query($query);
2543                                                                 if($db->checkError()){
2544                                                                         //put in the array to use later on
2545                                                                         $_SESSION['sqlSkippedQueries'][] = $query;
2546                                                                 }
2547                                                                 if($disable_keys)
2548                                                                 {
2549                                                                         handleExecuteSqlKeys($db, $tableName, false);
2550                                                                 }
2551                                                                 $progQuery[$forStepQuery]=$query;
2552                                                                 post_install_progress($progQuery,$action='set');
2553                                                         }//if
2554                                                 }
2555                                                 elseif($query != null){
2556                                                         $tableName = getAlterTable($query);
2557                                                         if($disable_keys)
2558                                                         {
2559                                                                 handleExecuteSqlKeys($db, $tableName, true);
2560                                                         }
2561                                                         $db->query($query);
2562                                                         if($disable_keys)
2563                                                         {
2564                                                                 handleExecuteSqlKeys($db, $tableName, false);
2565                                                         }
2566                                                         $progQuery[$forStepQuery]=$query;
2567                                                         post_install_progress($progQuery,$action='set');
2568                                                         if($db->checkError()){
2569                                                                 //put in the array to use later on
2570                                                                 $_SESSION['sqlSkippedQueries'][] = $query;
2571                                                         }
2572                                                 }
2573                                                 $completeLine = '';
2574                                         }
2575                                 }
2576                         }//while
2577                 }
2578         }
2579 }
2580
2581
2582 function getAlterTable($query){
2583         $query = strtolower($query);
2584         if (preg_match('/^\s*alter\s+table\s+/', $query)) {
2585                 $sqlArray = explode(" ", $query);
2586                 $key = array_search('table', $sqlArray);
2587                 return $sqlArray[($key+1)];
2588         }else {
2589                 return '';
2590         }
2591 }
2592
2593 function set_upgrade_vars(){
2594         logThis('setting session variables...');
2595         $upgrade_progress_dir = sugar_cached('upgrades/temp');
2596         if(!is_dir($upgrade_progress_dir)){
2597                 mkdir_recursive($upgrade_progress_dir);
2598         }
2599         $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2600         if(file_exists($upgrade_progress_file)){
2601                 include($upgrade_progress_file);
2602         }
2603         else{
2604                 fopen($upgrade_progress_file, 'w+');
2605         }
2606         if(!isset($upgrade_config) || $upgrade_config == null){
2607                 $upgrade_config = array();
2608                 $upgrade_config[1]['upgrade_vars']=array();
2609         }
2610     if(isset($upgrade_config[1]) && isset($upgrade_config[1]['upgrade_vars']) && !is_array($upgrade_config[1]['upgrade_vars'])){
2611         $upgrade_config[1]['upgrade_vars'] = array();
2612     }
2613
2614         if(!isset($upgrade_vars) || $upgrade_vars == NULL){
2615                 $upgrade_vars = array();
2616         }
2617         if(isset($_SESSION['unzip_dir']) && !empty($_SESSION['unzip_dir']) && file_exists($_SESSION['unzip_dir'])){
2618                 $upgrade_vars['unzip_dir']=$_SESSION['unzip_dir'];
2619         }
2620         if(isset($_SESSION['install_file']) && !empty($_SESSION['install_file']) && file_exists($_SESSION['install_file'])){
2621                 $upgrade_vars['install_file']=$_SESSION['install_file'];
2622         }
2623         if(isset($_SESSION['Upgraded451Wizard']) && !empty($_SESSION['Upgraded451Wizard'])){
2624                 $upgrade_vars['Upgraded451Wizard']=$_SESSION['Upgraded451Wizard'];
2625         }
2626         if(isset($_SESSION['license_shown']) && !empty($_SESSION['license_shown'])){
2627                 $upgrade_vars['license_shown']=$_SESSION['license_shown'];
2628         }
2629         if(isset($_SESSION['Initial_451to500_Step']) && !empty($_SESSION['Initial_451to500_Step'])){
2630                 $upgrade_vars['Initial_451to500_Step']=$_SESSION['Initial_451to500_Step'];
2631         }
2632         if(isset($_SESSION['zip_from_dir']) && !empty($_SESSION['zip_from_dir'])){
2633                 $upgrade_vars['zip_from_dir']=$_SESSION['zip_from_dir'];
2634         }
2635         //place into the upgrade_config array and rewrite config array only if new values are being inserted
2636         if(isset($upgrade_vars) && $upgrade_vars != null && sizeof($upgrade_vars) > 0){
2637                 foreach($upgrade_vars as $key=>$val){
2638                         if($key != null && $val != null){
2639                                 $upgrade_config[1]['upgrade_vars'][$key]=$upgrade_vars[$key];
2640                         }
2641                 }
2642                 ksort($upgrade_config);
2643                 if(is_writable($upgrade_progress_file) && write_array_to_file( "upgrade_config", $upgrade_config,
2644                         $upgrade_progress_file)) {
2645                        //writing to the file
2646                 }
2647     }
2648 }
2649
2650 function initialize_session_vars(){
2651   $upgrade_progress_dir = sugar_cached('upgrades/temp');
2652   $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2653   if(file_exists($upgrade_progress_file)){
2654         include($upgrade_progress_file);
2655         if(isset($upgrade_config) && $upgrade_config != null && is_array($upgrade_config) && sizeof($upgrade_config) >0){
2656                 $currVarsArray=$upgrade_config[1]['upgrade_vars'];
2657                 //print_r($currVarsArray);
2658                 if(isset($currVarsArray) && $currVarsArray != null && is_array($currVarsArray) && sizeof($currVarsArray)>0){
2659                         foreach($currVarsArray as $key=>$val){
2660                                 if($key != null && $val !=null){
2661                                         //set session variables
2662                                         $_SESSION[$key]=$val;
2663                                         //set varibales
2664                                         '$'.$key=$val;
2665                                 }
2666                         }
2667                 }
2668         }
2669   }
2670 }
2671 //track the upgrade progress on each step
2672 //track the upgrade progress on each step
2673 function set_upgrade_progress($currStep,$currState,$currStepSub='',$currStepSubState=''){
2674
2675         $upgrade_progress_dir = sugar_cached('upgrades/temp');
2676         if(!is_dir($upgrade_progress_dir)){
2677                 mkdir_recursive($upgrade_progress_dir);
2678         }
2679         $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2680         if(file_exists($upgrade_progress_file)){
2681                 include($upgrade_progress_file);
2682         }
2683         else{
2684                 if(function_exists('sugar_fopen')){
2685                         sugar_fopen($upgrade_progress_file, 'w+');
2686                 }
2687                 else{
2688                         fopen($upgrade_progress_file, 'w+');
2689                 }
2690         }
2691         if(!isset($upgrade_config) || $upgrade_config == null){
2692                 $upgrade_config = array();
2693                 $upgrade_config[1]['upgrade_vars']=array();
2694         }
2695     if(!is_array($upgrade_config[1]['upgrade_vars'])){
2696         $upgrade_config[1]['upgrade_vars'] = array();
2697     }
2698         if($currStep != null && $currState != null){
2699                 if(sizeof($upgrade_config) > 0){
2700                         if($currStepSub != null && $currStepSubState !=null){
2701                                 //check if new status to be set or update
2702                                 //get the latest in array. since it has sub components prepare an array
2703                                 if(!empty($upgrade_config[sizeof($upgrade_config)][$currStep]) && is_array($upgrade_config[sizeof($upgrade_config)][$currStep])){
2704                                         $latestStepSub = currSubStep($upgrade_config[sizeof($upgrade_config)][$currStep]);
2705                                         if($latestStepSub == $currStepSub){
2706                                                 $upgrade_config[sizeof($upgrade_config)][$currStep][$latestStepSub]=$currStepSubState;
2707                                                 $upgrade_config[sizeof($upgrade_config)][$currStep][$currStep] = $currState;
2708                                         }
2709                                         else{
2710                                                 $upgrade_config[sizeof($upgrade_config)][$currStep][$currStepSub]=$currStepSubState;
2711                                                 $upgrade_config[sizeof($upgrade_config)][$currStep][$currStep] = $currState;
2712                                         }
2713                                 }
2714                                 else{
2715                                         $currArray = array();
2716                                         $currArray[$currStep] = $currState;
2717                                         $currArray[$currStepSub] = $currStepSubState;
2718                                         $upgrade_config[sizeof($upgrade_config)+1][$currStep] = $currArray;
2719                                 }
2720                         }
2721           else{
2722                                 //get the current upgrade progress
2723                                 $latestStep = get_upgrade_progress();
2724                                 //set the upgrade progress
2725                                 if($latestStep == $currStep){
2726                                         //update the current step with new progress status
2727                                         $upgrade_config[sizeof($upgrade_config)][$latestStep]=$currState;
2728                                 }
2729                                 else{
2730                                         //it's a new step
2731                                         $upgrade_config[sizeof($upgrade_config)+1][$currStep]=$currState;
2732                                 }
2733                     // now check if there elements within array substeps
2734           }
2735                 }
2736                 else{
2737                         //set the upgrade progress  (just starting)
2738                         $upgrade_config[sizeof($upgrade_config)+1][$currStep]= $currState;
2739                 }
2740
2741                 if(is_writable($upgrade_progress_file) && write_array_to_file( "upgrade_config", $upgrade_config,
2742                 $upgrade_progress_file)) {
2743                //writing to the file
2744                 }
2745
2746         }
2747 }
2748
2749 function get_upgrade_progress(){
2750         $upgrade_progress_dir = sugar_cached('upgrades/temp');
2751         $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2752         $currState = '';
2753
2754         if(file_exists($upgrade_progress_file)){
2755                 include($upgrade_progress_file);
2756                 if(!isset($upgrade_config) || $upgrade_config == null){
2757                         $upgrade_config = array();
2758                 }
2759                 if($upgrade_config != null && sizeof($upgrade_config) >1){
2760                         $currArr = $upgrade_config[sizeof($upgrade_config)];
2761                         if(is_array($currArr)){
2762                            foreach($currArr as $key=>$val){
2763                                         $currState = $key;
2764                                 }
2765                         }
2766                 }
2767         }
2768         return $currState;
2769 }
2770 function currSubStep($currStep){
2771         $currSubStep = '';
2772         if(is_array($currStep)){
2773        foreach($currStep as $key=>$val){
2774                     if($key != null){
2775                         $currState = $key;
2776                         }
2777            }
2778         }
2779         return $currState;
2780 }
2781 function currUpgradeState($currState){
2782         $currState = '';
2783         if(is_array($currState)){
2784        foreach($currState as $key=>$val){
2785                         if(is_array($val)){
2786                                 foreach($val as $k=>$v){
2787                                         if($k != null){
2788                                                 $currState = $k;
2789                                         }
2790                                 }
2791                         }
2792                         else{
2793                                 $currState = $key;
2794                         }
2795                 }
2796         }
2797         return $currState;
2798 }
2799
2800 function didThisStepRunBefore($step,$SubStep=''){
2801         if($step == null) return;
2802         $upgrade_progress_dir = sugar_cached('upgrades/temp');
2803         $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2804         $currState = '';
2805         $stepRan = false;
2806         if(file_exists($upgrade_progress_file)){
2807                 include($upgrade_progress_file);
2808                 if(isset($upgrade_config) && $upgrade_config != null && is_array($upgrade_config) && sizeof($upgrade_config) >0){
2809                         for($i=1;$i<=sizeof($upgrade_config);$i++){
2810                           if(is_array($upgrade_config[$i])){
2811                                         foreach($upgrade_config[$i] as $key=>$val){
2812                                                 if($key==$step){
2813                                                         if(is_array($upgrade_config[$i][$step])){
2814                                                                 //now process
2815                                                                 foreach ($upgrade_config[$i][$step] as $k=>$v){
2816                                                                         if(is_array($v)){
2817                                                                                 foreach($v as $k1=>$v1){
2818                                                                                         if($SubStep != null){
2819                                                                                                 if($SubStep ==$k1 && $v1=='done'){
2820                                                                                                         $stepRan = true;
2821                                                                                                         break;
2822                                                                                                 }
2823                                                                                         }
2824                                                                                 }//foreach
2825                                                                         }
2826                                                                         elseif($SubStep !=null){
2827                                                                                 if($SubStep==$k && $v=='done'){
2828                                                                                         $stepRan = true;
2829                                                                                         break;
2830                                                                                 }
2831                                                                         }
2832                                                                         elseif($step==$k && $v=='done'){
2833                                                                                 $stepRan = true;
2834                                                                                 break;
2835                                                                         }
2836                                                                 }//foreach
2837                                                         }
2838                                                         elseif($val=='done'){
2839                                                                 $stepRan = true;
2840                                                         }
2841                                                 }
2842                                         }//foreach
2843                                 }
2844                         }//for
2845                 }
2846         }
2847         return $stepRan;
2848 }
2849
2850
2851
2852 //get and set post install status
2853 function post_install_progress($progArray='',$action=''){
2854         $upgrade_progress_dir = sugar_cached('upgrades/temp');
2855         $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2856     if($action=='' || $action=='get'){
2857                 //get the state of post install
2858         $currProg = array();
2859                 if(file_exists($upgrade_progress_file)){
2860                         include($upgrade_progress_file);
2861                         if(is_array($upgrade_config[sizeof($upgrade_config)]['commit']['post_install']) && sizeof($upgrade_config[sizeof($upgrade_config)]['commit']['post_install'])>0){
2862                                 foreach($upgrade_config[sizeof($upgrade_config)]['commit']['post_install'] as $k=>$v){
2863                                         $currProg[$k]=$v;
2864                                 }
2865                         }
2866                 }
2867                 return $currProg;
2868         }
2869         elseif($action=='set'){
2870                 if(!is_dir($upgrade_progress_dir)){
2871                         mkdir($upgrade_progress_dir);
2872                 }
2873                 if(file_exists($upgrade_progress_file)){
2874                         include($upgrade_progress_file);
2875                 }
2876                 else{
2877                         fopen($upgrade_progress_file, 'w+');
2878                 }
2879                 if(!is_array($upgrade_config[sizeof($upgrade_config)]['commit']['post_install'])){
2880                         $upgrade_config[sizeof($upgrade_config)]['commit']['post_install']=array();
2881                         $upgrade_config[sizeof($upgrade_config)]['commit']['post_install']['post_install'] = 'in_progress';
2882                 }
2883                 if($progArray != null && is_array($progArray)){
2884                         foreach($progArray as $key=>$val){
2885                                 $upgrade_config[sizeof($upgrade_config)]['commit']['post_install'][$key]=$val;
2886                         }
2887                 }
2888                 if(is_writable($upgrade_progress_file) && write_array_to_file( "upgrade_config", $upgrade_config,
2889                 $upgrade_progress_file)) {
2890                //writing to the file
2891                 }
2892         }
2893 }
2894
2895 function repairDBForUpgrade($execute=false,$path=''){
2896
2897         global $current_user, $beanFiles;
2898         global $dictionary;
2899         set_time_limit(3600);
2900
2901         $db = &DBManagerFactory::getInstance();
2902         $sql = '';
2903         VardefManager::clearVardef();
2904         require_once('include/ListView/ListView.php');
2905         foreach ($beanFiles as $bean => $file) {
2906                 require_once ($file);
2907                 $focus = new $bean ();
2908                 $sql .= $db->repairTable($focus, $execute);
2909
2910         }
2911         //echo $sql;
2912         $olddictionary = $dictionary;
2913         unset ($dictionary);
2914         include ('modules/TableDictionary.php');
2915         foreach ($dictionary as $meta) {
2916                 $tablename = $meta['table'];
2917                 $fielddefs = $meta['fields'];
2918                 $indices = $meta['indices'];
2919                 $sql .= $db->repairTableParams($tablename, $fielddefs, $indices, $execute);
2920         }
2921          $qry_str = "";
2922           foreach (explode("\n", $sql) as $line) {
2923                   if (!empty ($line) && substr($line, -2) != "*/") {
2924                         $line .= ";";
2925                   }
2926                   $qry_str .= $line . "\n";
2927            }
2928           $sql = str_replace(
2929           array(
2930                 "\n",
2931                 '&#039;',
2932            ),
2933           array(
2934                 '',
2935                 "'",
2936           ),
2937           preg_replace('#(/\*.+?\*/\n*)#', '', $qry_str)
2938           );
2939          logThis("*******START EXECUTING DB UPGRADE QUERIES***************",$path);
2940                 logThis($sql,$path);
2941          logThis("*******END EXECUTING DB UPGRADE QUERIES****************",$path);
2942          if(!$execute){
2943                 return $sql;
2944          }
2945 }
2946
2947
2948
2949 /**
2950  * upgradeUserPreferences
2951  * This method updates the user_preferences table and sets the pages/dashlets for users
2952  * which have ACL access to Trackers so that the Tracker dashlets are set in their user perferences
2953  *
2954  */
2955 function upgradeUserPreferences() {
2956     global $sugar_config, $sugar_version;
2957     $uw_strings = return_module_language($GLOBALS['current_language'], 'UpgradeWizard');
2958
2959     $localization = new Localization();
2960     $localeCoreDefaults = $localization->getLocaleConfigDefaults();
2961
2962     // check the current system wide default_locale_name_format and add it to the list if it's not there
2963     if(empty($sugar_config['name_formats'])) {
2964         $sugar_config['name_formats'] = $localeCoreDefaults['name_formats'];
2965         if(!rebuildConfigFile($sugar_config, $sugar_version)) {
2966             $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
2967         }
2968     }
2969
2970     $currentDefaultLocaleNameFormat = $sugar_config['default_locale_name_format'];
2971
2972     if ($localization->isAllowedNameFormat($currentDefaultLocaleNameFormat)) {
2973         upgradeLocaleNameFormat($currentDefaultLocaleNameFormat);
2974     } else {
2975         $sugar_config['default_locale_name_format'] = $localeCoreDefaults['default_locale_name_format'];
2976         if(!rebuildConfigFile($sugar_config, $sugar_version)) {
2977             $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
2978         }
2979         $localization->createInvalidLocaleNameFormatUpgradeNotice();
2980     }
2981
2982         $db = &DBManagerFactory::getInstance();
2983     $result = $db->query("SELECT id FROM users where deleted = '0'");
2984         while($row = $db->fetchByAssoc($result))
2985     {
2986         $current_user = new User();
2987         $current_user->retrieve($row['id']);
2988
2989         // 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
2990         $currentUserNameFormat = $current_user->getPreference('default_locale_name_format');
2991         if ($localization->isAllowedNameFormat($currentUserNameFormat)) {
2992             upgradeLocaleNameFormat($currentUserNameFormat);
2993         } else {
2994             $current_user->setPreference('default_locale_name_format', 's f l', 0, 'global');
2995             $current_user->savePreferencesToDB();
2996         }
2997
2998         } //while
2999 }
3000
3001
3002 /**
3003  * Checks if a locale name format is part of the default list, if not adds it to the config
3004  * @param $name_format string a local name format string such as 's f l'
3005  * @return bool true on successful write to config file, false on failure;
3006  */
3007 function upgradeLocaleNameFormat($name_format) {
3008     global $sugar_config, $sugar_version;
3009
3010     $localization = new Localization();
3011     $localeConfigDefaults = $localization->getLocaleConfigDefaults();
3012
3013     $uw_strings = return_module_language($GLOBALS['current_language'], 'UpgradeWizard');
3014     if(empty($sugar_config['name_formats'])) {
3015         $sugar_config['name_formats'] = $localeConfigDefaults['name_formats'];
3016         if(!rebuildConfigFile($sugar_config, $sugar_version)) {
3017             $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
3018         }
3019     }
3020     if (!in_array($name_format, $sugar_config['name_formats'])) {
3021         $new_config = sugarArrayMerge($sugar_config['name_formats'], array($name_format=>$name_format));
3022         $sugar_config['name_formats'] = $new_config;
3023         if(!rebuildConfigFile($sugar_config, $sugar_version)) {
3024             $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
3025             return false;
3026         }
3027     }
3028     return true;
3029 }
3030
3031
3032
3033 function add_custom_modules_favorites_search(){
3034     $module_directories = scandir('modules');
3035
3036         foreach($module_directories as $module_dir){
3037                 if($module_dir == '.' || $module_dir == '..' || !is_dir("modules/{$module_dir}")){
3038                         continue;
3039                 }
3040
3041                 $matches = array();
3042                 preg_match('/^[a-z0-9]{1,5}_[a-z0-9_]+$/i' , $module_dir, $matches);
3043
3044                 // Make sure the module was created by module builder
3045                 if(empty($matches)){
3046                         continue;
3047                 }
3048
3049                 $full_module_dir = "modules/{$module_dir}/";
3050                 $read_searchdefs_from = "{$full_module_dir}/metadata/searchdefs.php";
3051                 $read_SearchFields_from = "{$full_module_dir}/metadata/SearchFields.php";
3052                 $read_custom_SearchFields_from = "custom/{$full_module_dir}/metadata/SearchFields.php";
3053
3054                 // Studio can possibly override this file, so we check for a custom version of it
3055                 if(file_exists("custom/{$full_module_dir}/metadata/searchdefs.php")){
3056                         $read_searchdefs_from = "custom/{$full_module_dir}/metadata/searchdefs.php";
3057                 }
3058
3059                 if(file_exists($read_searchdefs_from) && file_exists($read_SearchFields_from)){
3060                         $found_sf1 = false;
3061                         $found_sf2 = false;
3062                         require($read_searchdefs_from);
3063                         foreach($searchdefs[$module_dir]['layout']['basic_search'] as $sf_array){
3064                                 if(isset($sf_array['name']) && $sf_array['name'] == 'favorites_only'){
3065                                         $found_sf1 = true;
3066                                 }
3067                         }
3068
3069                         require($read_SearchFields_from);
3070                         if(isset($searchFields[$module_dir]['favorites_only'])){
3071                                 $found_sf2 = true;
3072                         }
3073
3074                         if(!$found_sf1 && !$found_sf2){
3075                                 $searchdefs[$module_dir]['layout']['basic_search']['favorites_only'] = array('name' => 'favorites_only','label' => 'LBL_FAVORITES_FILTER','type' => 'bool',);
3076                                 $searchdefs[$module_dir]['layout']['advanced_search']['favorites_only'] = array('name' => 'favorites_only','label' => 'LBL_FAVORITES_FILTER','type' => 'bool',);
3077                                 $searchFields[$module_dir]['favorites_only'] = array(
3078                                         'query_type'=>'format',
3079                                         'operator' => 'subquery',
3080                                         'subquery' => 'SELECT sugarfavorites.record_id FROM sugarfavorites
3081                                                                 WHERE sugarfavorites.deleted=0
3082                                                                         and sugarfavorites.module = \''.$module_dir.'\'
3083                                                                         and sugarfavorites.assigned_user_id = \'{0}\'',
3084                                         'db_field'=>array('id')
3085                                 );
3086
3087                                 if(!is_dir("custom/{$full_module_dir}/metadata")){
3088                                         mkdir_recursive("custom/{$full_module_dir}/metadata");
3089                                 }
3090                                 $success_sf1 = write_array_to_file('searchdefs', $searchdefs, "custom/{$full_module_dir}/metadata/searchdefs.php");
3091                                 $success_sf2 = write_array_to_file('searchFields', $searchFields, "{$full_module_dir}/metadata/SearchFields.php");
3092
3093                                 if(!$success_sf1){
3094                                         logThis("add_custom_modules_favorites_search failed for searchdefs.php for {$module_dir}");
3095                                 }
3096                                 if(!$success_sf2){
3097                                         logThis("add_custom_modules_favorites_search failed for SearchFields.php for {$module_dir}");
3098                                 }
3099                                 if($success_sf1 && $success_sf2){
3100                                         logThis("add_custom_modules_favorites_search successfully updated searchdefs and searchFields for {$module_dir}");
3101                                 }
3102                         }
3103                 }
3104         }
3105 }
3106
3107
3108 /**
3109  * upgradeModulesForTeamsets
3110  *
3111  * This method adds the team_set_id values to the module tables that have the new team_set_id column
3112  * added through the SugarCRM 5.5.x upgrade process.  It also adds the values into the team_sets and
3113  * team_sets_teams tables.
3114  *
3115  * @param filter Array of modules to process; empty by default
3116  */
3117 function upgradeModulesForTeamsets($filter=array()) {
3118     require('include/modules.php');
3119         foreach($beanList as $moduleName=>$beanName) {
3120                     if(!empty($filter) && array_search($moduleName, $filter) === false) {
3121                        continue;
3122                     }
3123                 if($moduleName == 'TeamMemberships' || $moduleName == 'ForecastOpportunities'){
3124                 continue;
3125             }
3126                         $bean = loadBean($moduleName);
3127                         if(empty($bean) ||
3128                            empty($bean->table_name)) {
3129                            continue;
3130                         }
3131
3132                         $FieldArray = $GLOBALS['db']->helper->get_columns($bean->table_name);
3133                         if(!isset($FieldArray['team_id'])) {
3134                            continue;
3135                         }
3136
3137                         upgradeTeamColumn($bean, 'team_id');
3138
3139         } //foreach
3140
3141     //Upgrade users table
3142         $bean = loadBean('Users');
3143         upgradeTeamColumn($bean, 'default_team');
3144         $result = $GLOBALS['db']->query("SELECT id FROM teams where deleted=0");
3145         while($row = $GLOBALS['db']->fetchByAssoc($result)) {
3146               $teamset = new TeamSet();
3147               $teamset->addTeams($row['id']);
3148         }
3149 }
3150
3151
3152 /**
3153  * upgradeTeamColumn
3154  * Helper function to create a team_set_id column and also set team_set_id column
3155  * to have the value of the $column_name parameter
3156  *
3157  * @param $bean SugarBean which we are adding team_set_id column to
3158  * @param $column_name The name of the column containing the default team_set_id value
3159  */
3160 function upgradeTeamColumn($bean, $column_name) {
3161         //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
3162         //module that does not use the SugarObjects
3163         if(empty($bean->field_defs['team_set_id']) && $bean->module_dir != 'Trackers'){
3164
3165                 //at this point we could assume that since we have a team_id defined and not a team_set_id that we need to
3166                 //add that field and the corresponding relationships
3167                 $object = $bean->object_name;
3168                 $module = $bean->module_dir;
3169                 $object_name = $object;
3170                 $_object_name = strtolower($object_name);
3171
3172                 if(!empty($GLOBALS['dictionary'][$object]['table'])){
3173                         $table_name = $GLOBALS['dictionary'][$object]['table'];
3174                 }else{
3175                         $table_name = strtolower($module);
3176                 }
3177
3178                 $path = 'include/SugarObjects/implements/team_security/vardefs.php';
3179                 require($path);
3180                 //go through each entry in the vardefs from team_security and unset anything that is already set in the core module
3181                 //this will ensure we have the proper ordering.
3182                 $fieldDiff = array_diff_assoc($vardefs['fields'], $GLOBALS['dictionary'][$bean->object_name]['fields']);
3183
3184                 $file = 'custom/Extension/modules/' . $bean->module_dir. '/Ext/Vardefs/teams.php';
3185                 $contents = "<?php\n";
3186                 if(!empty($fieldDiff)){
3187                         foreach($fieldDiff as $key => $val){
3188                                 $contents .= "\n\$GLOBALS['dictionary']['". $object . "']['fields']['". $key . "']=" . var_export_helper($val) . ";";
3189                         }
3190                 }
3191                 $relationshipDiff = array_diff_assoc($vardefs['relationships'], $GLOBALS['dictionary'][$bean->object_name]['relationships']);
3192                 if(!empty($relationshipDiff)){
3193                         foreach($relationshipDiff as $key => $val){
3194                                 $contents .= "\n\$GLOBALS['dictionary']['". $object . "']['relationships']['". $key . "']=" . var_export_helper($val) . ";";
3195                         }
3196                 }
3197                 $indexDiff = array_diff_assoc($vardefs['indices'], $GLOBALS['dictionary'][$bean->object_name]['indices']);
3198                 if(!empty($indexDiff)){
3199                         foreach($indexDiff as $key => $val){
3200                                         $contents .= "\n\$GLOBALS['dictionary']['". $object . "']['indices']['". $key . "']=" . var_export_helper($val) . ";";
3201                         }
3202                 }
3203                 if( $fh = @sugar_fopen( $file, 'wt' ) )
3204             {
3205                 fputs( $fh, $contents);
3206                 fclose( $fh );
3207             }
3208
3209
3210                 //we have written out the teams.php into custom/Extension/modules/{$module_dir}/Ext/Vardefs/teams.php'
3211                 //now let's merge back into vardefs.ext.php
3212                 require_once('ModuleInstall/ModuleInstaller.php');
3213                 $mi = new ModuleInstaller();
3214                 $mi->merge_files('Ext/Vardefs/', 'vardefs.ext.php');
3215                 VardefManager::loadVardef($bean->module_dir, $bean->object_name, true);
3216                 $bean->field_defs = $GLOBALS['dictionary'][$bean->object_name]['fields'];
3217         }
3218
3219         if(isset($bean->field_defs['team_set_id'])) {
3220                 //Create the team_set_id column
3221                 $FieldArray = $GLOBALS['db']->helper->get_columns($bean->table_name);
3222                 if(!isset($FieldArray['team_set_id'])) {
3223                         $GLOBALS['db']->addColumn($bean->table_name, $bean->field_defs['team_set_id']);
3224                 }
3225                 $indexArray =  $GLOBALS['db']->helper->get_indices($bean->table_name);
3226
3227         $indexName = getValidDBName('idx_'.strtolower($bean->table_name).'_tmst_id', true, 34);
3228         $indexDef = array(
3229                                          array(
3230                                                 'name' => $indexName,
3231                                                 'type' => 'index',
3232                                                 'fields' => array('team_set_id')
3233                                          )
3234                                    );
3235                 if(!isset($indexArray[$indexName])) {
3236                         $GLOBALS['db']->addIndexes($bean->table_name, $indexDef);
3237                 }
3238
3239                 //Update the table's team_set_id column to have the same values as team_id
3240             $GLOBALS['db']->query("UPDATE {$bean->table_name} SET team_set_id = {$column_name}");
3241         }
3242 }
3243
3244 /**
3245  *  Update the folder subscription table which confirms to the team security mechanism but
3246  *  the class SugarFolders does not extend SugarBean and is therefore never picked up by the
3247  *  upgradeModulesForTeamsets function.
3248  */
3249 function upgradeFolderSubscriptionsTeamSetId()
3250 {
3251     logThis("In upgradeFolderSubscriptionsTeamSetId()");
3252     $query = "UPDATE folders SET team_set_id = team_id";
3253     $result = $GLOBALS['db']->query($query);
3254     logThis("Finished upgradeFolderSubscriptionsTeamSetId()");
3255 }
3256
3257 /**
3258  * upgradeModulesForTeam
3259  *
3260  * This method update the associated_user_id, name, name_2 to the private team records on teams table
3261  * This function is used for upgrade process from 5.1.x and 5.2.x.
3262  *
3263  */
3264 function upgradeModulesForTeam() {
3265     logThis("In upgradeModulesForTeam()");
3266     $result = $GLOBALS['db']->query("SELECT id, user_name, first_name, last_name FROM users where deleted=0");
3267
3268     while($row = $GLOBALS['db']->fetchByAssoc($result)) {
3269         $results2 = $GLOBALS['db']->query("SELECT id FROM teams WHERE name = '({$row['user_name']})'");
3270         $assoc = '';
3271                 if(!$assoc = $GLOBALS['db']->fetchByAssoc($results2)) {
3272                         //if team does not exist, then lets create the team for this user
3273                         $team = new Team();
3274                         $user = new User();
3275                         $user->retrieve($row['id']);
3276                         $team->new_user_created($user);
3277                         $team_id = $team->id;
3278                 }else{
3279                         $team_id =$assoc['id'];
3280                 }
3281
3282                         //upgrade the team
3283                         $name = is_null($row['first_name'])?'':$row['first_name'];
3284                         $name_2 = is_null($row['last_name'])?'':$row['last_name'];
3285                         $associated_user_id = $row['id'];
3286
3287                         //Bug 32914
3288                         //Ensure team->name is not empty by using team->name_2 if available
3289                         if(empty($name) && !empty($name_2)) {
3290                            $name = $name_2;
3291                            $name_2 = '';
3292                         }
3293
3294                         $query = "UPDATE teams SET name = '{$name}', name_2 = '{$name_2}', associated_user_id = '{$associated_user_id}' WHERE id = '{$team_id}'";
3295                         $GLOBALS['db']->query($query);
3296     } //while
3297
3298     //Update the team_set_id and default_team columns
3299     $ce_to_pro_or_ent = (isset($_SESSION['upgrade_from_flavor']) && ($_SESSION['upgrade_from_flavor'] == 'SugarCE to SugarPro' || $_SESSION['upgrade_from_flavor'] == 'SugarCE to SugarEnt' || $_SESSION['upgrade_from_flavor'] == 'SugarCE to SugarCorp' || $_SESSION['upgrade_from_flavor'] == 'SugarCE to SugarUlt'));
3300
3301     //Update team_set_id
3302         if($ce_to_pro_or_ent) {
3303            $GLOBALS['db']->query("update users set team_set_id = (select teams.id from teams where teams.associated_user_id = users.id)");
3304            $GLOBALS['db']->query("update users set default_team = (select teams.id from teams where teams.associated_user_id = users.id)");
3305         }
3306
3307 }
3308
3309
3310     function addNewSystemTabsFromUpgrade($from_dir){
3311         global $path;
3312         if(isset($_SESSION['upgrade_from_flavor'])){
3313
3314             //check to see if there are any new files that need to be added to systems tab
3315             //retrieve old modules list
3316             logThis('check to see if new modules exist',$path);
3317             $oldModuleList = array();
3318             $newModuleList = array();
3319             include($from_dir.'/include/modules.php');
3320             $oldModuleList = $moduleList;
3321             include('include/modules.php');
3322             $newModuleList = $moduleList;
3323
3324             //include tab controller
3325             require_once('modules/MySettings/TabController.php');
3326             $newTB = new TabController();
3327
3328             //make sure new modules list has a key we can reference directly
3329             $newModuleList = $newTB->get_key_array($newModuleList);
3330             $oldModuleList = $newTB->get_key_array($oldModuleList);
3331
3332             //iterate through list and remove commonalities to get new modules
3333             foreach ($newModuleList as $remove_mod){
3334                 if(in_array($remove_mod, $oldModuleList)){
3335                     unset($newModuleList[$remove_mod]);
3336                 }
3337             }
3338             //new modules list now has left over modules which are new to this install, so lets add them to the system tabs
3339             logThis('new modules to add are '.var_export($newModuleList,true),$path);
3340
3341             if(!empty($newModuleList))
3342             {
3343                     //grab the existing system tabs
3344                     $tabs = $newTB->get_system_tabs();
3345
3346                     //add the new tabs to the array
3347                     foreach($newModuleList as $nm ){
3348                       $tabs[$nm] = $nm;
3349                     }
3350
3351                     $newTB->set_system_tabs($tabs);
3352             }
3353             logThis('module tabs updated',$path);
3354         }
3355     }
3356
3357     /**
3358      * fix_dropdown_list
3359      * This method attempts to fix dropdown lists that were incorrectly named.
3360      * There were versions of SugarCRM that did not enforce naming convention rules
3361      * for the dropdown list field name.  This method attempts to resolve that by
3362      * fixing the language files that may have been affected and then updating the
3363      * fields_meta_data table accordingly.  It also refreshes any vardefs that may
3364      * have been affected.
3365      *
3366      */
3367         function fix_dropdown_list() {
3368         if(file_exists('custom/include/language')) {
3369            $files = array();
3370            $affected_modules = array();
3371            $affected_keys = array();
3372
3373            getFiles($files, 'custom/include/language', '/\.php$/i');
3374            foreach($files as $file) {
3375
3376               if(file_exists($file . '.bak')) {
3377                  $bak_mod_time = filemtime($file . '.bak');
3378                  $php_mod_time = filemtime($file);
3379                  //We're saying if the .php file was modified 30 seconds no more than php.bak file then we
3380                  //run these additional cleanup checks
3381                  if($php_mod_time - $bak_mod_time < 30) {
3382
3383                         $app_list_strings = array();
3384                         $GLOBALS['app_list_strings'] = array();
3385                         require($file . '.bak');
3386                         $bak_app_list_strings = array_merge($app_list_strings, $GLOBALS['app_list_strings']);
3387
3388                         $app_list_strings = array();
3389                         $GLOBALS['app_list_strings'] = array();
3390                         require($file);
3391                         $php_app_list_strings = array_merge($app_list_strings, $GLOBALS['app_list_strings']);
3392
3393                         //Get the file contents
3394                         $contents = file_get_contents($file);
3395
3396                         //Now simulate a fix for the file before we compare w/ the .php file
3397                         //we also append to the $contents
3398                         foreach($bak_app_list_strings as $key=>$entry) {
3399                                                    if(preg_match('/([^A-Za-z_])/', $key, $matches) && is_array($entry)) {
3400                                                           $new_key = preg_replace('/[^A-Za-z_]/', '_', $key);
3401                                                           $bak_app_list_strings[$new_key] = $bak_app_list_strings[$key];
3402                                                           unset($bak_app_list_strings[$key]);
3403                                                           //Now if the entry doesn't exists in the .php file, then add to contents
3404                                                           if(!isset($php_app_list_strings[$new_key])) {
3405                                                                  $contents .= "\n\$GLOBALS['app_list_strings']['{$new_key}'] = " . var_export_helper($bak_app_list_strings[$new_key]) . ";";
3406                                                           }
3407                                                    } //if
3408                         } //foreach
3409
3410                         //Now load the .php file to do the comparison
3411                         foreach($php_app_list_strings as $key=>$entry) {
3412                                 if(isset($bak_app_list_strings[$key])) {
3413                                         $diff = array_diff($bak_app_list_strings[$key], $entry);
3414                                         if(!empty($diff)) {
3415                                            //There is a difference, so copy the $bak_app_list_strings version into the .php file
3416                                            $contents .= "\n\$GLOBALS['app_list_strings']['{$key}'] = " . var_export_helper($bak_app_list_strings[$key]) . ";";
3417                                         } //if
3418                                 } //if
3419                         } //foreach
3420
3421                         //Now write out the file contents
3422                         //Create backup just in case
3423                         copy($file, $file . '.php_bak');
3424                                         $fp = @sugar_fopen($file, 'w');
3425                         if($fp) {
3426                                fwrite($fp, $contents);
3427                                fclose($fp);
3428                         } else {
3429                            $GLOBALS['log']->error("Unable to update file contents in fix_dropdown_list for {$file}");
3430                         } //if-else
3431                  }
3432               }
3433
3434               unset($GLOBALS['app_strings']);
3435               unset($GLOBALS['app_list_strings']);
3436               $app_list_strings = array();
3437                   require($file);
3438                   $touched = false;
3439                   $contents = file_get_contents($file);
3440                   if ( !isset($GLOBALS['app_list_strings']) ) {
3441                       $GLOBALS['app_list_strings'] = $app_list_strings;
3442                   }
3443                   else {
3444                       $GLOBALS['app_list_strings'] = array_merge($app_list_strings, $GLOBALS['app_list_strings']);
3445                   }
3446
3447                   if(isset($GLOBALS['app_list_strings']) && is_array($GLOBALS['app_list_strings'])) {
3448                          foreach($GLOBALS['app_list_strings'] as $key=>$entry) {
3449                                 if(preg_match('/([^A-Za-z_])/', $key, $matches) && is_array($entry)) {
3450                                    $result = $GLOBALS['db']->query("SELECT custom_module FROM fields_meta_data WHERE ext1 = '{$key}'");
3451                                    if(!empty($result)) {
3452                                           while($row = $GLOBALS['db']->fetchByAssoc($result)) {
3453                                                     $custom_module = $row['custom_module'];
3454                                                     if(!empty($GLOBALS['beanList'][$custom_module])) {
3455                                                    $affected_modules[$custom_module] = $GLOBALS['beanList'][$custom_module];
3456                                                     }
3457                                           } //while
3458                                    }
3459
3460                                    //Replace all invalid characters with '_' character
3461                                    $new_key = preg_replace('/[^A-Za-z_]/', '_', $key);
3462                                    $affected_keys[$key] = $new_key;
3463
3464                                    $GLOBALS['app_list_strings'][$new_key] = $GLOBALS['app_list_strings'][$key];
3465                                    unset($GLOBALS['app_list_strings'][$key]);
3466
3467                                    $pattern_match = "/(\[\s*\'{$key}\'\s*\])/";
3468                                    $new_key = "['{$new_key}']";
3469                                    $out = preg_replace($pattern_match, $new_key, $contents);
3470                                    $contents = $out;
3471                                    $touched = true;
3472                                 } //if
3473                          } //foreach
3474
3475                  //This is a check for g => h instances where the file contents were incorrectly written
3476                  //and also fixes the scenario where via a UI upgrade, the app_list_strings were incorrectly
3477                  //merged with app_list_strings variables declared elsewhere
3478                          if(!$touched) {
3479                                    if(preg_match('/\$GLOBALS\s*\[\s*[\"|\']app_list_strings[\"|\']\s*\]\s*=\s*array\s*\(/', $contents)) {
3480                                           //Now also remove all the non-custom labels that were added
3481                                           if(preg_match('/language\/([^\.]+)\.lang\.php$/', $file, $matches)) {
3482                                                 $language = $matches[1];
3483
3484                                                 $app_list_strings = array();
3485
3486                                         if(file_exists("include/language/$language.lang.php")) {
3487                                                                    include("include/language/$language.lang.php");
3488                                                                 }
3489                                                                 if(file_exists("include/language/$language.lang.override.php")) {
3490                                                                    $app_list_strings =  _mergeCustomAppListStrings("include/language/$language.lang.override.php" , $app_list_strings) ;
3491                                                                 }
3492                                                                 if(file_exists("custom/application/Ext/Language/$language.ext.lang.php")) {
3493                                                                    $app_list_strings =  _mergeCustomAppListStrings("custom/application/Ext/Language/$language.ext.lang.php" , $app_list_strings) ;
3494                                                                 }
3495                                                                 if(file_exists("custom/application/Ext/Language/$language.lang.ext.php")) {
3496                                                                    $app_list_strings =  _mergeCustomAppListStrings("custom/application/Ext/Language/$language.lang.ext.php" , $app_list_strings) ;
3497                                                                 }
3498
3499                                                                 $all_non_custom_include_language_strings = $app_strings;
3500                                                                 $all_non_custom_include_language_list_strings = $app_list_strings;
3501
3502                                                                 $unset_keys = array();
3503                                                                 if(!empty($GLOBALS['app_list_strings'])) {
3504                                                                         foreach($GLOBALS['app_list_strings'] as $key=>$value) {
3505                                                                                 $diff = array();
3506                                                                                 if(isset($all_non_custom_include_language_list_strings[$key])) {
3507                                                                                         $diff = array_diff($all_non_custom_include_language_list_strings[$key], $GLOBALS['app_list_strings'][$key]);
3508                                                                                 }
3509
3510                                                                                 if(!empty($all_non_custom_include_language_list_strings[$key]) && empty($diff)) {
3511                                                                                         $unset_keys[] = $key;
3512                                                                                 }
3513                                                                         }
3514                                                                 }
3515
3516                                                                 foreach($unset_keys as $key) {
3517                                                                         unset($GLOBALS['app_list_strings'][$key]);
3518                                                                 }
3519
3520                                                                 if(!empty($GLOBALS['app_strings'])) {
3521                                                                 foreach($GLOBALS['app_strings'] as $key=>$value) {
3522                                                                                 if(!empty($all_non_custom_include_language_strings[$key])) {
3523                                                                                    unset($GLOBALS['app_strings'][$key]);
3524                                                                                 }
3525                                                                 }
3526                                                                 }
3527                                           } //if(preg_match...)
3528
3529                                       $out = "<?php \n";
3530                                       if(!empty($GLOBALS['app_strings'])) {
3531                                              foreach($GLOBALS['app_strings'] as $key=>$entry) {
3532                                                      $out .= "\n\$GLOBALS['app_strings']['$key']=" . var_export_helper($entry) . ";";
3533                                              }
3534                                       }
3535
3536                                                   foreach($GLOBALS['app_list_strings'] as $key=>$entry) {
3537                                                                   $out .= "\n\$GLOBALS['app_list_strings']['$key']=" . var_export_helper($entry) . ";";
3538                                                   } //foreach
3539
3540                                                   $touched = true;
3541                                    } //if(preg_match...)
3542                          } //if(!$touched)
3543
3544                          if($touched) {
3545                                  //Create a backup just in case
3546                                  copy($file, $file . '.bak');
3547                          $fp = @sugar_fopen($file, 'w');
3548                          if($fp) {
3549                                fwrite($fp, $out);
3550                                fclose($fp);
3551                          } else {
3552                            //If we can't update the file, just return
3553                            $GLOBALS['log']->error("Unable to update file contents in fix_dropdown_list.");
3554                            return;
3555                          }
3556                          } //if($touched)
3557                   } //if
3558
3559            } //foreach($files)
3560
3561            //Update db entries (the order matters here... need to process database changes first)
3562            if(!empty($affected_keys)) {
3563                   foreach($affected_keys as $old_key=>$new_key) {
3564                                   $GLOBALS['db']->query("UPDATE fields_meta_data SET ext1 = '{$new_key}' WHERE ext1 = '{$old_key}'");
3565                   }
3566            }
3567
3568            //Update vardef files for affected modules
3569            if(!empty($affected_modules)) {
3570                   foreach($affected_modules as $module=>$object) {
3571                           VardefManager::refreshVardefs($module, $object);
3572                   }
3573            }
3574         }
3575         }
3576
3577
3578         function update_iframe_dashlets(){
3579                 require_once(sugar_cached('dashlets/dashlets.php'));
3580
3581                 $db = DBManagerFactory::getInstance();
3582                 $query = "SELECT id, contents, assigned_user_id FROM user_preferences WHERE deleted = 0 AND category = 'Home'";
3583                 $result = $db->query($query, true, "Unable to update new default dashlets! ");
3584                 while ($row = $db->fetchByAssoc($result)) {
3585                         $content = unserialize(base64_decode($row['contents']));
3586                         $assigned_user_id = $row['assigned_user_id'];
3587                         $record_id = $row['id'];
3588
3589                         $current_user = new User();
3590                         $current_user->retrieve($row['assigned_user_id']);
3591
3592                         if(!empty($content['dashlets']) && !empty($content['pages'])){
3593                                 $originalDashlets = $content['dashlets'];
3594                                 foreach($originalDashlets as $key => $ds){
3595                                     if(!empty($ds['options']['url']) && stristr($ds['options']['url'],'http://www.sugarcrm.com/crm/product/gopro')){
3596                                                 unset($originalDashlets[$key]);
3597                                         }
3598                                 }
3599                                 $current_user->setPreference('dashlets', $originalDashlets, 0, 'Home');
3600                         }
3601                 }
3602         }
3603
3604
3605     /**
3606      * convertImageToText
3607      * @deprecated
3608      * This method attempts to convert date type image to text on Microsoft SQL Server.
3609      * This method could NOT be used in any other type of datebases.
3610      */
3611         function convertImageToText($table_name,$column_name){
3612                 $set_lang = "SET LANGUAGE us_english";
3613                 $GLOBALS['db']->query($set_lang);
3614             if($GLOBALS['db']->lastError()){
3615             logThis('An error occurred when performing this query-->'.$set_lang);
3616         }
3617        $q="SELECT data_type
3618         FROM INFORMATION_SCHEMA.Tables T JOIN INFORMATION_SCHEMA.Columns C
3619         ON T.TABLE_NAME = C.TABLE_NAME where T.TABLE_NAME = '$table_name' and C.COLUMN_NAME = '$column_name'";
3620        $res= $GLOBALS['db']->query($q);
3621        if($GLOBALS['db']->lastError()){
3622             logThis('An error occurred when performing this query-->'.$q);
3623         }
3624        $row= $GLOBALS['db']->fetchByAssoc($res);
3625
3626      if(trim(strtolower($row['data_type'])) == 'image'){
3627         $addContent_temp = "alter table {$table_name} add {$column_name}_temp text null";
3628         $GLOBALS['db']->query($addContent_temp);
3629         if($GLOBALS['db']->lastError()){
3630             logThis('An error occurred when performing this query-->'.$addContent_temp);
3631         }
3632         $qN = "select count=datalength({$column_name}), id, {$column_name} from {$table_name}";
3633         $result = $GLOBALS['db']->query($qN);
3634         while($row = $GLOBALS['db']->fetchByAssoc($result)){
3635            if($row['count'] >8000){
3636                 $contentLength = $row['count'];
3637                 $start = 1;
3638                 $next=8000;
3639                 $convertedContent = '';
3640                 while($contentLength >0){
3641                     $stepsQuery = "select cont=convert(varchar(max), convert(varbinary(8000), substring({$column_name},{$start},{$next}))) from {$table_name} where id= '{$row['id']}'";
3642                     $steContQ = $GLOBALS['db']->query($stepsQuery);
3643                     if($GLOBALS['db']->lastError()){
3644                         logThis('An error occurred when performing this query-->'.$stepsQuery);
3645                     }
3646                     $stepCont = $GLOBALS['db']->fetchByAssoc($steContQ);
3647                     if(isset($stepCont['cont'])){
3648                         $convertedContent = $convertedContent.$stepCont['cont'];
3649                     }
3650                     $start = $start+$next;
3651                     $contentLength = $contentLength - $next;
3652                 }
3653                 $addContentDataText="update {$table_name} set {$column_name}_temp = '{$convertedContent}' where id= '{$row['id']}'";
3654                 $GLOBALS['db']->query($addContentDataText);
3655                 if($GLOBALS['db']->lastError()){
3656                     logThis('An error occurred when performing this query-->'.$addContentDataText);
3657                 }
3658            }
3659            else{
3660                 $addContentDataText="update {$table_name} set {$column_name}_temp =
3661                 convert(varchar(max), convert(varbinary(8000), {$column_name})) where id= '{$row['id']}'";
3662                 $GLOBALS['db']->query($addContentDataText);
3663                 if($GLOBALS['db']->lastError()){
3664                     logThis('An error occurred when performing this query-->'.$addContentDataText);
3665                 }
3666            }
3667         }
3668         //drop the contents now and change contents_temp to contents
3669         $dropColumn = "alter table {$table_name} drop column {$column_name}";
3670         $GLOBALS['db']->query($dropColumn);
3671         if($GLOBALS['db']->lastError()){
3672             logThis('An error occurred when performing this query-->'.$dropColumn);
3673         }
3674         $changeColumnName = "EXEC sp_rename '{$table_name}.[{$column_name}_temp]','{$column_name}','COLUMN'";
3675         $GLOBALS['db']->query($changeColumnName);
3676         if($GLOBALS['db']->lastError()){
3677             logThis('An error occurred when performing this query-->'.$changeColumnName);
3678         }
3679      }
3680     }
3681
3682          /**
3683      * clearHelpFiles
3684      * This method attempts to delete all English inline help files.
3685      * This method was introduced by 5.5.0RC2.
3686      */
3687     function clearHelpFiles(){
3688                 $modulePath = clean_path(getcwd() . '/modules');
3689                 $allHelpFiles = array();
3690                 getFiles($allHelpFiles, $modulePath, "/en_us.help.*/");
3691
3692                 foreach( $allHelpFiles as $the_file ){
3693                 if( is_file( $the_file ) ){
3694                     unlink( $the_file );
3695                     logThis("Deleted file: $the_file");
3696                 }
3697             }
3698         }
3699
3700
3701
3702         /**
3703          * upgradeDateTimeFields
3704          *
3705          * This method came from bug: 39757 where the date_end field is a date field and not a datetime field
3706          * which prevents you from performing timezone offset calculations once the data has been saved.
3707          *
3708          * @param path String location to log file, empty by default
3709          */
3710         function upgradeDateTimeFields($path)
3711         {
3712                 //bug: 39757
3713                 global $db;
3714                 $meetingsSql = "UPDATE meetings SET date_end = ".$db->convert("date_start", 'add_time', array('duration_hours', 'duration_minutes'));
3715                 $callsSql = "UPDATE calls SET date_end = ".$db->convert("date_start", 'add_time', array('duration_hours', 'duration_minutes'));
3716         logThis('upgradeDateTimeFields Meetings SQL:' . $meetingsSql, $path);
3717                 $db->query($meetingsSql);
3718
3719                 logThis('upgradeDateTimeFields Calls SQL:' . $callsSql, $path);
3720                 $db->query($callsSql);
3721         }
3722
3723         /**
3724          * upgradeDocumentTypeFields
3725          *
3726          */
3727         function upgradeDocumentTypeFields($path){
3728                 //bug: 39757
3729                 global $db;
3730
3731                 $documentsSql = "UPDATE documents SET doc_type = 'Sugar' WHERE doc_type IS NULL";
3732                 $meetingsSql = "UPDATE meetings SET type = 'Sugar' WHERE type IS NULL";
3733
3734                 logThis('upgradeDocumentTypeFields Documents SQL:' . $documentsSql, $path);
3735                 $db->query($documentsSql);
3736                 logThis('upgradeDocumentTypeFields Meetings SQL:' . $meetingsSql, $path);
3737                 $db->query($meetingsSql);
3738         }
3739
3740
3741 /**
3742  * merge_config_si_settings
3743  * This method checks for the presence of a config_si.php file and, if found, merges the configuration
3744  * settings from the config_si.php file into config.php.  If a config_si_location parameter value is not
3745  * supplied it will attempt to discover the config_si.php file location from where the executing script
3746  * was invoked.
3747  *
3748  * @param write_to_upgrade_log boolean optional value to write to the upgradeWizard.log file
3749  * @param config_location String optional value to config.php file location
3750  * @param config_si_location String optional value to config_si.php file location
3751  * @param path String file of the location of log file to write to
3752  * @return boolean value indicating whether or not a merge was attempted with config_si.php file
3753  */
3754 function merge_config_si_settings($write_to_upgrade_log=false, $config_location='', $config_si_location='', $path='')
3755 {
3756         if(!empty($config_location) && !file_exists($config_location))
3757         {
3758                 if($write_to_upgrade_log)
3759                 {
3760                logThis('config.php file specified in ' . $config_si_location . ' could not be found.  Skip merging', $path);
3761                 }
3762             return false;
3763         } else if(empty($config_location)) {
3764                 global $argv;
3765                 //We are assuming this is from the silentUpgrade scripts so argv[3] will point to SugarCRM install location
3766                 if(isset($argv[3]) && is_dir($argv[3]))
3767                 {
3768                         $config_location = $argv[3] . DIRECTORY_SEPARATOR . 'config.php';
3769                 }
3770         }
3771
3772         //If config_location is still empty or if the file cannot be found, skip merging
3773         if(empty($config_location) || !file_exists($config_location))
3774         {
3775            if($write_to_upgrade_log)
3776            {
3777                   logThis('config.php file at (' . $config_location . ') could not be found.  Skip merging.', $path);
3778            }
3779            return false;
3780         } else {
3781            if($write_to_upgrade_log)
3782            {
3783               logThis('Loading config.php file at (' . $config_location . ') for merging.', $path);
3784            }
3785
3786            include($config_location);
3787            if(empty($sugar_config))
3788            {
3789                   if($write_to_upgrade_log)
3790                   {
3791                      logThis('config.php contents are empty.  Skip merging.', $path);
3792                   }
3793                   return false;
3794            }
3795         }
3796
3797         if(!empty($config_si_location) && !file_exists($config_si_location))
3798         {
3799                 if($write_to_upgrade_log)
3800                 {
3801                logThis('config_si.php file specified in ' . $config_si_location . ' could not be found.  Skip merging', $path);
3802                 }
3803             return false;
3804         } else if(empty($config_si_location)) {
3805                 if(isset($argv[0]) && is_file($argv[0]))
3806                 {
3807                         $php_file = $argv[0];
3808                         $p_info = pathinfo($php_file);
3809                         $php_dir = (isset($p_info['dirname']) && $p_info['dirname'] != '.') ?  $p_info['dirname'] . DIRECTORY_SEPARATOR : '';
3810                         $config_si_location = $php_dir . 'config_si.php';
3811                 }
3812         }
3813
3814         //If config_si_location is still empty or if the file cannot be found, skip merging
3815         if(empty($config_si_location) || !file_exists($config_si_location))
3816         {
3817            if($write_to_upgrade_log)
3818            {
3819               logThis('config_si.php file at (' . $config_si_location . ') could not be found.  Skip merging.', $path);
3820            }
3821            return false;
3822         } else {
3823            if($write_to_upgrade_log)
3824            {
3825               logThis('Loading config_si.php file at (' . $config_si_location . ') for merging.', $path);
3826            }
3827
3828            include($config_si_location);
3829            if(empty($sugar_config_si))
3830            {
3831               if($write_to_upgrade_log)
3832                   {
3833                      logThis('config_si.php contents are empty.  Skip merging.', $path);
3834                   }
3835                   return false;
3836            }
3837         }
3838
3839         //Now perform the merge operation
3840         $modified = false;
3841         foreach($sugar_config_si as $key=>$value)
3842         {
3843                 if(!preg_match('/^setup_/', $key) && !isset($sugar_config[$key]))
3844                 {
3845                    if($write_to_upgrade_log)
3846                    {
3847                       logThis('Merge key (' . $key . ') with value (' . $value . ')', $path);
3848                    }
3849                    $sugar_config[$key] = $value;
3850                    $modified = true;
3851                 }
3852         }
3853
3854         if($modified)
3855         {
3856                 if($write_to_upgrade_log)
3857                 {
3858                logThis('Update config.php file with new values', $path);
3859                 }
3860
3861             if(!write_array_to_file("sugar_config", $sugar_config, $config_location)) {
3862                if($write_to_upgrade_log)
3863                    {
3864                   logThis('*** ERROR: could not write to config.php', $path);
3865                    }
3866                    return false;
3867                 }
3868         } else {
3869            if($write_to_upgrade_log)
3870            {
3871               logThis('config.php values are in sync with config_si.php values.  Skipped merging.');
3872            }
3873            return false;
3874         }
3875
3876         if($write_to_upgrade_log)
3877         {
3878            logThis('End merge_config_si_settings', $path);
3879         }
3880         return true;
3881 }
3882
3883
3884 /**
3885  * upgrade_connectors
3886  *
3887  * This function handles support for upgrading connectors it is invoked from both end.php and silentUpgrade_step2.php
3888  *
3889  */
3890 function upgrade_connectors() {
3891     require_once('include/connectors/utils/ConnectorUtils.php');
3892     if(!ConnectorUtils::updateMetaDataFiles()) {
3893        $GLOBALS['log']->fatal('Cannot update metadata files for connectors');
3894     }
3895
3896     //Delete the custom connectors.php file if it exists so that it may be properly rebuilt
3897     if(file_exists('custom/modules/Connectors/metadata/connectors.php'))
3898     {
3899         unlink('custom/modules/Connectors/metadata/connectors.php');
3900     }
3901 }
3902
3903 /**
3904  * Enable the InsideView connector for the four default modules.
3905  */
3906 function upgradeEnableInsideViewConnector($path='')
3907 {
3908     logThis('Begin upgradeEnableInsideViewConnector', $path);
3909
3910     // Load up the existing mapping and hand it to the InsideView connector to have it setup the correct logic hooks
3911     $mapFile = 'modules/Connectors/connectors/sources/ext/rest/insideview/mapping.php';
3912     if ( file_exists('custom/'.$mapFile) ) {
3913         logThis('Found CUSTOM mappings', $path);
3914         require('custom/'.$mapFile);
3915     } else {
3916         logThis('Used default mapping', $path);
3917         require($mapFile);
3918     }
3919
3920     require_once('include/connectors/sources/SourceFactory.php');
3921     $source = SourceFactory::getSource('ext_rest_insideview');
3922
3923     // $mapping is brought in from the mapping.php file above
3924     $source->saveMappingHook($mapping);
3925
3926     require_once('include/connectors/utils/ConnectorUtils.php');
3927     ConnectorUtils::installSource('ext_rest_insideview');
3928
3929     // Now time to set the various modules to active, because this part ignores the default config
3930     require(CONNECTOR_DISPLAY_CONFIG_FILE);
3931     // $modules_sources come from that config file
3932     foreach ( $source->allowedModuleList as $module ) {
3933         $modules_sources[$module]['ext_rest_insideview'] = 'ext_rest_insideview';
3934     }
3935     if(!write_array_to_file('modules_sources', $modules_sources, CONNECTOR_DISPLAY_CONFIG_FILE)) {
3936         //Log error and return empty array
3937         logThis("Cannot write \$modules_sources to " . CONNECTOR_DISPLAY_CONFIG_FILE,$path);
3938     }
3939
3940     logThis('End upgradeEnableInsideViewConnector', $path);
3941
3942 }
3943
3944 function repair_long_relationship_names($path='')
3945 {
3946     logThis("Begin repair_long_relationship_names", $path);
3947     require_once 'modules/ModuleBuilder/parsers/relationships/DeployedRelationships.php' ;
3948     $GLOBALS['mi_remove_tables'] = false;
3949     $touched = array();
3950     foreach($GLOBALS['moduleList'] as $module)
3951     {
3952         $relationships = new DeployedRelationships ($module) ;
3953         foreach($relationships->getRelationshipList() as $rel_name)
3954         {
3955             if (strlen($rel_name) > 27 && empty($touched[$rel_name]))
3956             {
3957                 logThis("Rebuilding relationship fields for $rel_name", $path);
3958                 $touched[$rel_name] = true;
3959                 $rel_obj = $relationships->get($rel_name);
3960                 $rel_obj->setReadonly(false);
3961                 $relationships->delete($rel_name);
3962                 $relationships->save();
3963                 $relationships->add($rel_obj);
3964                 $relationships->save();
3965                 $relationships->build () ;
3966             }
3967         }
3968     }
3969     logThis("End repair_long_relationship_names", $path);
3970 }
3971
3972 function removeSilentUpgradeVarsCache(){
3973     global $silent_upgrade_vars_loaded;
3974
3975     $cacheFileDir = "{$GLOBALS['sugar_config']['cache_dir']}/silentUpgrader";
3976     $cacheFile = "{$cacheFileDir}/silentUpgradeCache.php";
3977
3978     if(file_exists($cacheFile)){
3979         unlink($cacheFile);
3980     }
3981
3982     $silent_upgrade_vars_loaded = array(); // Set to empty to reset it
3983
3984     return true;
3985 }
3986
3987 function loadSilentUpgradeVars(){
3988     global $silent_upgrade_vars_loaded;
3989
3990     if(empty($silent_upgrade_vars_loaded)){
3991         $cacheFile = "{$GLOBALS['sugar_config']['cache_dir']}/silentUpgrader/silentUpgradeCache.php";
3992         // We have no pre existing vars
3993         if(!file_exists($cacheFile)){
3994             // Set the vars array so it's loaded
3995             $silent_upgrade_vars_loaded = array('vars' => array());
3996         }
3997         else{
3998             require_once($cacheFile);
3999             $silent_upgrade_vars_loaded = $silent_upgrade_vars_cache;
4000         }
4001     }
4002
4003     return true;
4004 }
4005
4006 function writeSilentUpgradeVars(){
4007     global $silent_upgrade_vars_loaded;
4008
4009     if(empty($silent_upgrade_vars_loaded)){
4010         return false; // You should have set some values before trying to write the silent upgrade vars
4011     }
4012
4013     $cacheFileDir = "{$GLOBALS['sugar_config']['cache_dir']}/silentUpgrader";
4014     $cacheFile = "{$cacheFileDir}/silentUpgradeCache.php";
4015
4016     require_once('include/dir_inc.php');
4017     if(!mkdir_recursive($cacheFileDir)){
4018         return false;
4019     }
4020     require_once('include/utils/file_utils.php');
4021     if(!write_array_to_file('silent_upgrade_vars_cache', $silent_upgrade_vars_loaded, $cacheFile, 'w')){
4022         global $path;
4023         logThis("WARNING: writeSilentUpgradeVars could not write to {$cacheFile}", $path);
4024         return false;
4025     }
4026
4027     return true;
4028 }
4029
4030 function setSilentUpgradeVar($var, $value){
4031     if(!loadSilentUpgradeVars()){
4032         return false;
4033     }
4034
4035     global $silent_upgrade_vars_loaded;
4036
4037     $silent_upgrade_vars_loaded['vars'][$var] = $value;
4038
4039     return true;
4040 }
4041
4042 function getSilentUpgradeVar($var){
4043     if(!loadSilentUpgradeVars()){
4044         return false;
4045     }
4046
4047     global $silent_upgrade_vars_loaded;
4048
4049     if(!isset($silent_upgrade_vars_loaded['vars'][$var])){
4050         return null;
4051     }
4052     else{
4053         return $silent_upgrade_vars_loaded['vars'][$var];
4054     }
4055 }
4056
4057
4058 /**
4059  * add_unified_search_to_custom_modules_vardefs
4060  *
4061  * This method calls the repair code to remove the unified_search_modules.php fiel
4062  *
4063  */
4064 function add_unified_search_to_custom_modules_vardefs()
4065 {
4066         if(file_exists($cachefile = sugar_cached('modules/unified_search_modules.php')))
4067         {
4068            unlink($cachefile);
4069         }
4070
4071 }
4072
4073 /**
4074  * change from using the older SugarCache in 6.1 and below to the new one in 6.2
4075  */
4076 function upgradeSugarCache($file)
4077 {
4078         global $sugar_config;
4079         $cacheUploadUpgradesTemp = mk_temp_dir(sugar_cached('upgrades/temp'));
4080
4081         unzip($file, $cacheUploadUpgradesTemp);
4082
4083         if(!file_exists(clean_path("{$cacheUploadUpgradesTemp}/manifest.php"))) {
4084                 logThis("*** ERROR: no manifest file detected while bootstraping upgrade wizard files!");
4085                 return;
4086         } else {
4087                 include(clean_path("{$cacheUploadUpgradesTemp}/manifest.php"));
4088         }
4089
4090         $from_dir = "{$cacheUploadUpgradesTemp}/{$manifest['copy_files']['from_dir']}";
4091         $allFiles = array();
4092         if(file_exists("$from_dir/include/SugarCache")) {
4093                 $allFiles = findAllFiles("$from_dir/include/SugarCache", $allFiles);
4094         }
4095         if(file_exists("$from_dir/include/database")) {
4096                 $allFiles = findAllFiles("$from_dir/include/database", $allFiles);
4097         }
4098         if(file_exists("$from_dir/include/utils/external_cache.php")) {
4099                 $allFiles[] = "$from_dir/include/utils/external_cache.php";
4100         }
4101         if(file_exists("$from_dir/include/utils/sugar_file_utils.php")) {
4102                 $allFiles[] = "$from_dir/include/utils/sugar_file_utils.php";
4103         }
4104         if(file_exists("$from_dir/include/utils/sugar_file_utils.php")) {
4105                 $allFiles[] = "$from_dir/include/utils/sugar_file_utils.php";
4106         }
4107
4108         foreach($allFiles as $k => $file) {
4109                 $destFile = str_replace($from_dir."/", "", $file);
4110        if(!is_dir(dirname($destFile))) {
4111                         mkdir_recursive(dirname($destFile)); // make sure the directory exists
4112                 }
4113                 if ( stristr($file,'uw_main.tpl') )
4114             logThis('Skipping "'.$file.'" - file copy will during commit step.');
4115         else {
4116             logThis('updating UpgradeWizard code: '.$destFile);
4117             copy_recursive($file, $destFile);
4118         }
4119         }
4120 }
4121
4122
4123 /**
4124  * upgradeDisplayedTabsAndSubpanels
4125  *
4126  * @param $version String value of current system version (pre upgrade)
4127  */
4128 function upgradeDisplayedTabsAndSubpanels($version)
4129 {
4130         if($version < '620')
4131         {
4132                 logThis('start upgrading system displayed tabs and subpanels');
4133             require_once('modules/MySettings/TabController.php');
4134             $tc = new TabController();
4135
4136             //grab the existing system tabs
4137             $tabs = $tc->get_tabs_system();
4138
4139             //add Calls, Meetings, Tasks, Notes, Prospects (Targets) and ProspectLists (Target Lists)
4140             //to displayed tabs unless explicitly set to hidden
4141             $modules_to_add = array('Calls', 'Meetings', 'Tasks', 'Notes', 'Prospects', 'ProspectLists');
4142             $added_tabs = array();
4143
4144             foreach($modules_to_add as $module)
4145             {
4146                        $tabs[0][$module] = $module;
4147                        $added_tabs[] = $module;
4148             }
4149
4150             logThis('calling set_system_tabs on TabController to add tabs: ' . var_export($added_tabs, true));
4151             $tc->set_system_tabs($tabs[0]);
4152             logThis('finish upgrading system displayed tabs and subpanels');
4153         }
4154 }
4155
4156
4157 /**
4158  * unlinkUpgradeFiles
4159  * This is a helper function to clean up
4160  *
4161  * @param $version String value of current system version (pre upgrade)
4162  */
4163 function unlinkUpgradeFiles($version)
4164 {
4165         if(!isset($version))
4166         {
4167            return;
4168         }
4169
4170     //First check if we even have the scripts_for_patch/files_to_remove directory
4171     require_once('modules/UpgradeWizard/UpgradeRemoval.php');
4172
4173     /*
4174     if(empty($_SESSION['unzip_dir']))
4175     {
4176         global $sugar_config;
4177         $base_upgrade_dir               = $sugar_config['upload_dir'] . "/upgrades";
4178         $base_tmp_upgrade_dir   = "$base_upgrade_dir/temp";
4179         $_SESSION['unzip_dir'] = mk_temp_dir( $base_tmp_upgrade_dir );
4180     }
4181     */
4182
4183     if(isset($_SESSION['unzip_dir']) && file_exists($_SESSION['unzip_dir'].'/scripts/files_to_remove'))
4184     {
4185        $files_to_remove = glob($_SESSION['unzip_dir'].'/scripts/files_to_remove/*.php');
4186
4187        foreach($files_to_remove as $script)
4188        {
4189                 if(preg_match('/UpgradeRemoval(\d+)x\.php/', $script, $matches))
4190                 {
4191                    $checkVersion = $matches[1] + 1; //Increment by one to check everything equal or below the target version
4192                    $upgradeClass = 'UpgradeRemoval' . $matches[1] . 'x';
4193                    require_once($_SESSION['unzip_dir'].'/scripts/files_to_remove/' . $upgradeClass . '.php');
4194
4195                    //Check to make sure we should load and run this UpgradeRemoval instance
4196                    if($checkVersion <= $version && class_exists($upgradeClass))
4197                    {
4198                           $upgradeInstance = new $upgradeClass();
4199                           if($upgradeInstance instanceof UpgradeRemoval)
4200                           {
4201                                   logThis('Running UpgradeRemoval instance ' . $upgradeClass);
4202                                   logThis('Files will be backed up to custom/backup');
4203                                   $files = $upgradeInstance->getFilesToRemove($version);
4204                                   foreach($files as $file)
4205                                   {
4206                                          logThis($file);
4207                                   }
4208                                   $upgradeInstance->processFilesToRemove($files);
4209                           }
4210                    }
4211             }
4212        }
4213     }
4214
4215     //Check if we have a custom directory
4216     if(file_exists('custom/scripts/files_to_remove'))
4217     {
4218        //Now find
4219        $files_to_remove = glob('custom/scripts/files_to_remove/*.php');
4220
4221        foreach($files_to_remove as $script)
4222        {
4223            if(preg_match('/\/files_to_remove\/(.*?)\.php$/', $script, $matches))
4224            {
4225                    require_once($script);
4226                    $upgradeClass  = $matches[1];
4227
4228                    if(!class_exists($upgradeClass))
4229                    {
4230                           continue;
4231                    }
4232
4233                    $upgradeInstance = new $upgradeClass();
4234                    if($upgradeInstance instanceof UpgradeRemoval)
4235                    {
4236                                   logThis('Running Custom UpgradeRemoval instance ' . $upgradeClass);
4237                                   $files = $upgradeInstance->getFilesToRemove($version);
4238                                   foreach($files as $file)
4239                                   {
4240                                          logThis($file);
4241                                   }
4242                                   $upgradeInstance->processFilesToRemove($files);
4243                    }
4244            }
4245        }
4246     }
4247
4248 }
4249
4250 if (!function_exists("getValidDBName"))
4251 {
4252     /*
4253      * Return a version of $proposed that can be used as a column name in any of our supported databases
4254      * 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)
4255      * @param string $name Proposed name for the column
4256      * @param string $ensureUnique
4257      * @return string Valid column name trimmed to right length and with invalid characters removed
4258      */
4259      function getValidDBName ($name, $ensureUnique = false, $maxLen = 30)
4260     {
4261         // first strip any invalid characters - all but alphanumerics and -
4262         $name = preg_replace ( '/[^\w-]+/i', '', $name ) ;
4263         $len = strlen ( $name ) ;
4264         $result = $name;
4265         if ($ensureUnique)
4266         {
4267             $md5str = md5($name);
4268             $tail = substr ( $name, -11) ;
4269             $temp = substr($md5str , strlen($md5str)-4 );
4270             $result = substr ( $name, 0, 10) . $temp . $tail ;
4271         }else if ($len > ($maxLen - 5))
4272         {
4273             $result = substr ( $name, 0, 11) . substr ( $name, 11 - $maxLen + 5);
4274         }
4275         return strtolower ( $result ) ;
4276     }
4277
4278
4279 }
4280
4281 /**
4282  * Get UW directories
4283  * Provides compatibility with both 6.3 and pre-6.3 setup
4284  */
4285 function getUWDirs()
4286 {
4287     if(!class_exists('UploadStream')) {
4288         // we're still running the old code
4289         global $sugar_config;
4290         return array($sugar_config['upload_dir'] . "/upgrades", $sugar_config['cache_dir'] . "upload/upgrades/temp");
4291     } else {
4292         if(!in_array("upload", stream_get_wrappers())) {
4293             UploadStream::register(); // just in case file was copied, but not run
4294         }
4295         return array("upload://upgrades", sugar_cached("upgrades/temp"));
4296     }
4297 }
4298
4299 /**
4300  * Whether directory exists within list of directories to skip
4301  * @param string $dir dir to be checked
4302  * @param array $skipDirs list with skipped dirs
4303  * @return boolean
4304  */
4305 function whetherNeedToSkipDir($dir, $skipDirs)
4306 {
4307     foreach($skipDirs as $skipMe) {
4308                 if(strpos( clean_path($dir), $skipMe ) !== false) {
4309                         return true;
4310                 }
4311         }
4312     return false;
4313 }
4314
4315
4316 /*
4317  * rebuildSprites
4318  * @param silentUpgrade boolean flag indicating whether or not we should treat running the SugarSpriteBuilder as an upgrade operation
4319  *
4320  */
4321 function rebuildSprites($fromUpgrade=true)
4322 {
4323     require_once('modules/Administration/SugarSpriteBuilder.php');
4324     $sb = new SugarSpriteBuilder();
4325     $sb->cssMinify = true;
4326     $sb->fromSilentUpgrade = $fromUpgrade;
4327     $sb->silentRun = $fromUpgrade;
4328
4329     // add common image directories
4330     $sb->addDirectory('default', 'include/images');
4331     $sb->addDirectory('default', 'themes/default/images');
4332     $sb->addDirectory('default', 'themes/default/images/SugarLogic');
4333
4334     // add all theme image directories
4335     if($dh = opendir('themes'))
4336     {
4337         while (($dir = readdir($dh)) !== false)
4338         {
4339             if ($dir != "." && $dir != ".." && $dir != 'default' && is_dir('themes/'.$dir)) {
4340                 $sb->addDirectory($dir, "themes/{$dir}/images");
4341             }
4342         }
4343         closedir($dh);
4344     }
4345
4346     // generate the sprite goodies
4347     // everything is saved into cache/sprites
4348     $sb->createSprites();
4349 }
4350
4351
4352 /**
4353  * repairSearchFields
4354  *
4355  * This method goes through the list of SearchFields files based and calls TemplateRange::repairCustomSearchFields
4356  * method on the files in an attempt to ensure the range search attributes are properly set in SearchFields.php.
4357  *
4358  * @param $globString String value used for glob search defaults to searching for all SearchFields.php files in modules directory
4359  * @param $path String value used to point to log file should logging be required.  Defaults to empty.
4360  *
4361  */
4362 function repairSearchFields($globString='modules/*/metadata/SearchFields.php', $path='')
4363 {
4364         if(!empty($path))
4365         {
4366                 logThis('Begin repairSearchFields', $path);
4367         }
4368
4369         require_once('include/dir_inc.php');
4370         require_once('modules/DynamicFields/templates/Fields/TemplateRange.php');
4371         require('include/modules.php');
4372
4373         global $beanList;
4374         $searchFieldsFiles = glob($globString);
4375
4376         foreach($searchFieldsFiles as $file)
4377         {
4378                 if(preg_match('/modules\/(.*?)\/metadata\/SearchFields\.php/', $file, $matches) && isset($beanList[$matches[1]]))
4379                 {
4380                         $module = $matches[1];
4381                         $beanName = $beanList[$module];
4382                         VardefManager::loadVardef($module, $beanName);
4383                         if(isset($GLOBALS['dictionary'][$beanName]['fields']))
4384                         {
4385                                 if(!empty($path))
4386                                 {
4387                                         logThis('Calling TemplateRange::repairCustomSearchFields for module ' . $module, $path);
4388                                 }
4389                                 TemplateRange::repairCustomSearchFields($GLOBALS['dictionary'][$beanName]['fields'], $module);
4390                         }
4391                 }
4392         }
4393
4394         if(!empty($path))
4395         {
4396                 logThis('End repairSearchFields', $path);
4397         }
4398 }
4399
4400 /**
4401  * repairUpgradeHistoryTable
4402  *
4403  * This is a helper function used in the upgrade process to fix upgrade_history entries so that the filename column points
4404  * to the new upload directory location introduced in 6.4 versions
4405  */
4406 function repairUpgradeHistoryTable()
4407 {
4408     require_once('modules/Configurator/Configurator.php');
4409     new Configurator();
4410     global $sugar_config;
4411
4412     //Now upgrade the upgrade_history table entries
4413     $results = $GLOBALS['db']->query('SELECT id, filename FROM upgrade_history');
4414     $upload_dir = $sugar_config['cache_dir'].'upload/';
4415
4416     //Create regular expression string to
4417     $match = '/^' . str_replace('/', '\/', $upload_dir) . '(.*?)$/';
4418
4419     while(($row = $GLOBALS['db']->fetchByAssoc($results)))
4420     {
4421         $file = str_replace('//', '/', $row['filename']); //Strip out double-paths that may exist
4422
4423         if(!empty($file) && preg_match($match, $file, $matches))
4424         {
4425             //Update new file location to use the new $sugar_config['upload_dir'] value
4426             $new_file_location = $sugar_config['upload_dir'] . $matches[1];
4427             $GLOBALS['db']->query("UPDATE upgrade_history SET filename = '{$new_file_location}' WHERE id = '{$row['id']}'");
4428         }
4429     }
4430
4431 }