]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - modules/UpgradeWizard/uw_utils.php
Release 6.5.0beta6
[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|^10\./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         // zip support
1084     if (!class_exists("ZipArchive"))
1085     {
1086         $ret['ZipStatus'] = "<b><span class=stop>{$installer_mod_strings['ERR_CHECKSYS_ZIP']}</span></b>";
1087         $ret['error_found'] = true;
1088     } else {
1089         $ret['ZipStatus'] = "<b><span class=go>{$installer_mod_strings['LBL_CHECKSYS_OK']}</span></b>";
1090     }
1091
1092
1093
1094         /* mbstring.func_overload
1095         $ret['mbstring.func_overload'] = '';
1096         $mb = ini_get('mbstring.func_overload');
1097
1098         if($mb > 1) {
1099                 $ret['mbstring.func_overload'] = "<b><span class=\"stop\">{$mod_strings['ERR_UW_MBSTRING_FUNC_OVERLOAD']}</b>";
1100                 $ret['error_found'] = true;
1101         }
1102         */
1103         return $ret;
1104 }
1105
1106
1107 /**
1108  * is a file that we blow away automagically
1109  */
1110 function isAutoOverwriteFile($file) {
1111         $overwriteDirs = array(
1112                 './sugar_version.php',
1113                 './modules/UpgradeWizard/uw_main.tpl',
1114         );
1115         $file = trim('.'.str_replace(clean_path(getcwd()), '', $file));
1116
1117         if(in_array($file, $overwriteDirs)) {
1118                 return true;
1119         }
1120
1121         $fileExtension = substr(strrchr($file, "."), 1);
1122         if($fileExtension == 'tpl' || $fileExtension == 'html') {
1123                 return false;
1124         }
1125
1126         return true;
1127 }
1128
1129 /**
1130  * flatfile logger
1131  */
1132 function logThis($entry, $path='') {
1133         global $mod_strings;
1134         if(file_exists('include/utils/sugar_file_utils.php')){
1135                 require_once('include/utils/sugar_file_utils.php');
1136         }
1137                 $log = empty($path) ? clean_path(getcwd().'/upgradeWizard.log') : clean_path($path);
1138
1139                 // create if not exists
1140                 if(!file_exists($log)) {
1141                         if(function_exists('sugar_fopen')){
1142                                 $fp = @sugar_fopen($log, 'w+'); // attempts to create file
1143                      }
1144                      else{
1145                                 $fp = fopen($log, 'w+'); // attempts to create file
1146                      }
1147                         if(!is_resource($fp)) {
1148                                 $GLOBALS['log']->fatal('UpgradeWizard could not create the upgradeWizard.log file');
1149                                 die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
1150                         }
1151                 } else {
1152                         if(function_exists('sugar_fopen')){
1153                                 $fp = @sugar_fopen($log, 'a+'); // write pointer at end of file
1154                      }
1155                      else{
1156                                 $fp = @fopen($log, 'a+'); // write pointer at end of file
1157                      }
1158
1159                         if(!is_resource($fp)) {
1160                                 $GLOBALS['log']->fatal('UpgradeWizard could not open/lock upgradeWizard.log file');
1161                                 die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
1162                         }
1163                 }
1164
1165                 $line = date('r').' [UpgradeWizard] - '.$entry."\n";
1166
1167                 if(@fwrite($fp, $line) === false) {
1168                         $GLOBALS['log']->fatal('UpgradeWizard could not write to upgradeWizard.log: '.$entry);
1169                         die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
1170                 }
1171
1172                 if(is_resource($fp)) {
1173                         fclose($fp);
1174                 }
1175 }
1176
1177 /**
1178         *  @params : none
1179         *  @author: nsingh
1180         *  @desc This function is to be used in the upgrade process to preserve changes/customaizations made to pre 5.1 quickcreate layout.
1181         *  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
1182         *  was automatically picked up by the quick create. [Addresses Bug 21469]
1183         *  This function will check if customizations were made, and will create quickcreatedefs.php in the /cutom/working/$module_name directory.
1184         **/
1185 function updateQuickCreateDefs(){
1186         $d = dir('modules');
1187         $studio_modules = array();
1188
1189         while($e = $d->read()){ //collect all studio modules.
1190                 if(substr($e, 0, 1) == '.' || !is_dir('modules/' . $e))continue;
1191                 if(file_exists('modules/' . $e . '/metadata/studio.php'))
1192                 {
1193                         array_push($studio_modules, $e);
1194                 }
1195         }
1196
1197         foreach( $studio_modules as $modname ){ //for each studio enabled module
1198                 //Check !exists modules/$modname/metadata/quickcreatedefs.php &&
1199                 //exists custom/$modname/editviewdefs.php (module was customized) &&
1200                 //!exists custom/$modname/quickcreateviewdefs.php
1201
1202                 $editviewdefs = "custom/working/modules/".$modname."/metadata/editviewdefs.php";
1203                 $quickcreatedefs = "custom/working/modules/".$modname."/metadata/quickcreatedefs.php";
1204
1205                 if ( !file_exists("modules/".$modname."/metadata/quickcreatedefs.php") &&
1206                          file_exists($editviewdefs) &&
1207                          !file_exists($quickcreatedefs) ){
1208                                 //clone editviewdef and save it in custom/working/modules/metadata
1209                                 $GLOBALS['log']->debug("Copying editviewdefs.php as quickcreatedefs.php for the $modname module in custom/working/modules/$modname/metadata!");
1210                                 if(copy( $editviewdefs, $quickcreatedefs)){
1211                                         if(file_exists($quickcreatedefs) && is_readable($quickcreatedefs)){
1212                                                 $file = file($quickcreatedefs);
1213                                                 //replace 'EditView' with 'QuickCreate'
1214                                                 $fp = fopen($quickcreatedefs,'w');
1215                                                 foreach($file as &$line){
1216                                                         if(preg_match('/^\s*\'EditView\'\s*=>\s*$/', $line) > 0){
1217                                                                 $line = "'QuickCreate' =>\n";
1218                                                         }
1219                                                         fwrite($fp, $line);
1220                                                 }
1221                                                 //write back.
1222                                                 fclose($fp);
1223                                         }
1224                                         else{
1225                                                 $GLOBALS['log']->debug("Failed to replace 'EditView' with QuickCreate because $quickcreatedefs is either not readable or does not exist.");
1226                                         }
1227                                 }else{
1228                                         $GLOBALS['log']->debug("Failed to copy $editviewdefs to $quickcreatedefs!");
1229                                 }
1230                 }
1231         }
1232 }
1233
1234 /**
1235  * test perms for CREATE queries
1236  */
1237 function testPermsCreate($db, $out) {
1238         logThis('Checking CREATE TABLE permissions...');
1239         global $mod_strings;
1240
1241         if(!$db->checkPrivilege("CREATE TABLE")) {
1242         logThis('cannot CREATE TABLE!');
1243                 $out['db']['dbNoCreate'] = true;
1244                 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_CREATE']}</span></td></tr>";
1245         }
1246     return $out;
1247 }
1248
1249 /**
1250  * test perms for INSERT
1251  */
1252 function testPermsInsert($db, $out, $skip=false) {
1253         logThis('Checking INSERT INTO permissions...');
1254         global $mod_strings;
1255
1256         if(!$db->checkPrivilege("INSERT")) {
1257                 logThis('cannot INSERT INTO!');
1258                 $out['db']['dbNoInsert'] = true;
1259                 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_INSERT']}</span></td></tr>";
1260     }
1261     return $out;
1262 }
1263
1264
1265 /**
1266  * test perms for UPDATE TABLE
1267  */
1268 function testPermsUpdate($db, $out, $skip=false) {
1269         logThis('Checking UPDATE TABLE permissions...');
1270         global $mod_strings;
1271         if(!$db->checkPrivilege("UPDATE")) {
1272                                         logThis('cannot UPDATE TABLE!');
1273                                         $out['db']['dbNoUpdate'] = true;
1274                                         $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_UPDATE']}</span></td></tr>";
1275     }
1276     return $out;
1277 }
1278
1279
1280 /**
1281  * test perms for SELECT
1282  */
1283 function testPermsSelect($db, $out, $skip=false) {
1284         logThis('Checking SELECT permissions...');
1285         global $mod_strings;
1286         if(!$db->checkPrivilege("SELECT")) {
1287                                 logThis('cannot SELECT!');
1288                                 $out['db']['dbNoSelect'] = true;
1289                                 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_SELECT']}</span></td></tr>";
1290     }
1291     return $out;
1292 }
1293
1294 /**
1295  * test perms for DELETE
1296  */
1297 function testPermsDelete($db, $out, $skip=false) {
1298         logThis('Checking DELETE FROM permissions...');
1299         global $mod_strings;
1300         if(!$db->checkPrivilege("DELETE")) {
1301                                 logThis('cannot DELETE FROM!');
1302                                 $out['db']['dbNoDelete'] = true;
1303                                 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_DELETE']}</span></td></tr>";
1304     }
1305     return $out;
1306 }
1307
1308
1309 /**
1310  * test perms for ALTER TABLE ADD COLUMN
1311  */
1312 function testPermsAlterTableAdd($db, $out, $skip=false) {
1313         logThis('Checking ALTER TABLE ADD COLUMN permissions...');
1314         global $mod_strings;
1315         if(!$db->checkPrivilege("ADD COLUMN")) {
1316                                 logThis('cannot ADD COLUMN!');
1317                                 $out['db']['dbNoAddColumn'] = true;
1318                                 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_ADD_COLUMN']}</span></td></tr>";
1319     }
1320     return $out;
1321 }
1322
1323 /**
1324  * test perms for ALTER TABLE ADD COLUMN
1325  */
1326 function testPermsAlterTableChange($db, $out, $skip=false) {
1327         logThis('Checking ALTER TABLE CHANGE COLUMN permissions...');
1328         global $mod_strings;
1329         if(!$db->checkPrivilege("CHANGE COLUMN")) {
1330                                 logThis('cannot CHANGE COLUMN!');
1331                                 $out['db']['dbNoChangeColumn'] = true;
1332                                 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_CHANGE_COLUMN']}</span></td></tr>";
1333     }
1334     return $out;
1335 }
1336
1337 /**
1338  * test perms for ALTER TABLE DROP COLUMN
1339  */
1340 function testPermsAlterTableDrop($db, $out, $skip=false) {
1341         logThis('Checking ALTER TABLE DROP COLUMN permissions...');
1342         global $mod_strings;
1343         if(!$db->checkPrivilege("DROP COLUMN")) {
1344                                 logThis('cannot DROP COLUMN!');
1345                                 $out['db']['dbNoDropColumn'] = true;
1346                                 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_DROP_COLUMN']}</span></td></tr>";
1347     }
1348     return $out;
1349 }
1350
1351
1352 /**
1353  * test perms for DROP TABLE
1354  */
1355 function testPermsDropTable($db, $out, $skip=false) {
1356         logThis('Checking DROP TABLE permissions...');
1357         global $mod_strings;
1358         if(!$db->checkPrivilege("DROP TABLE")) {
1359                                 logThis('cannot DROP TABLE!');
1360                                 $out['db']['dbNoDropTable'] = true;
1361                                 $out['dbOut'] .= "<tr><td align='left'><span class='error'>{$mod_strings['LBL_UW_DB_NO_DROP_TABLE']}</span></td></tr>";
1362     }
1363     return $out;
1364 }
1365
1366 function getFormattedError($error, $query) {
1367         $error = "<div><b>".$error;
1368         $error .= "</b>::{$query}</div>";
1369
1370         return $error;
1371 }
1372
1373 /**
1374  * parses a query finding the table name
1375  * @param string query The query
1376  * @return string table The table
1377  */
1378 function getTableFromQuery($query) {
1379         $standardQueries = array('ALTER TABLE', 'DROP TABLE', 'CREATE TABLE', 'INSERT INTO', 'UPDATE', 'DELETE FROM');
1380         $query = preg_replace("/[^A-Za-z0-9\_\s]/", "", $query);
1381         $query = trim(str_replace($standardQueries, '', $query));
1382
1383         $firstSpc = strpos($query, " ");
1384         $end = ($firstSpc > 0) ? $firstSpc : strlen($query);
1385         $table = substr($query, 0, $end);
1386
1387         return $table;
1388 }
1389
1390 //prelicense check
1391
1392 function preLicenseCheck() {
1393         require_once('modules/UpgradeWizard/uw_files.php');
1394
1395         global $sugar_config;
1396         global $mod_strings;
1397         global $sugar_version;
1398
1399         if(!isset($sugar_version) || empty($sugar_version)) {
1400                 require_once('./sugar_version.php');
1401         }
1402
1403 if(!isset($_SESSION['unzip_dir']) || empty($_SESSION['unzip_dir'])) {
1404                 logThis('unzipping files in upgrade archive...');
1405                 $errors                                 = array();
1406                 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
1407                 $unzip_dir = '';
1408                 //also come up with mechanism to read from upgrade-progress file
1409                 if(!isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !is_file($_SESSION['install_file'])) {
1410                         if (file_exists(clean_path($base_tmp_upgrade_dir)) && $handle = opendir(clean_path($base_tmp_upgrade_dir))) {
1411                                 while (false !== ($file = readdir($handle))) {
1412                                 if($file !="." && $file !="..") {
1413                                          if(is_file($base_tmp_upgrade_dir."/".$file."/manifest.php")){
1414                                                 require_once($base_tmp_upgrade_dir."/".$file."/manifest.php");
1415                                                 $package_name= $manifest['copy_files']['from_dir'];
1416                                                 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")){
1417                                                         $unzip_dir = $base_tmp_upgrade_dir."/".$file;
1418                                                         if(file_exists("$base_upgrade_dir/patch/".$package_name.'.zip')){
1419                                                                 $_SESSION['install_file'] = $package_name.".zip";
1420                                                                 break;
1421                                                         }
1422                                                 }
1423                                           }
1424                                 }
1425                         }
1426                         }
1427                 }
1428         if(empty($_SESSION['install_file'])){
1429                 unlinkUWTempFiles();
1430                 resetUwSession();
1431                 echo 'Upload File not found so redirecting to Upgrade Start ';
1432                 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1433                 echo '<form name="redirect" action="' .$redirect_new_wizard. '"  method="POST">';
1434 $upgrade_directories_not_found =<<<eoq
1435         <table cellpadding="3" cellspacing="0" border="0">
1436                 <tr>
1437                         <th colspan="2" align="left">
1438                                 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1439                         </th>
1440                 </tr>
1441         </table>
1442 eoq;
1443 $uwMain = $upgrade_directories_not_found;
1444                                 return '';
1445         }
1446                 $install_file                   = "$base_upgrade_dir/patch/".basename(urldecode( $_SESSION['install_file'] ));
1447                 $show_files                             = true;
1448                 if(empty($unzip_dir)){
1449                         $unzip_dir                              = mk_temp_dir( $base_tmp_upgrade_dir );
1450                 }
1451                 $zip_from_dir                   = ".";
1452                 $zip_to_dir                             = ".";
1453                 $zip_force_copy                 = array();
1454
1455                 if(!$unzip_dir){
1456                         logThis('Could not create a temporary directory using mk_temp_dir( $base_tmp_upgrade_dir )');
1457                         die($mod_strings['ERR_UW_NO_CREATE_TMP_DIR']);
1458                 }
1459
1460                 //double check whether unzipped .
1461                 if(file_exists($unzip_dir ."/scripts") && file_exists($unzip_dir."/manifest.php")){
1462                 //already unzipped
1463                 }
1464                 else{
1465                         unzip( $install_file, $unzip_dir );
1466                 }
1467
1468                 // assumption -- already validated manifest.php at time of upload
1469                 require_once( "$unzip_dir/manifest.php" );
1470
1471                 if( isset( $manifest['copy_files']['from_dir'] ) && $manifest['copy_files']['from_dir'] != "" ){
1472                     $zip_from_dir   = $manifest['copy_files']['from_dir'];
1473                 }
1474                 if( isset( $manifest['copy_files']['to_dir'] ) && $manifest['copy_files']['to_dir'] != "" ){
1475                     $zip_to_dir     = $manifest['copy_files']['to_dir'];
1476                 }
1477                 if( isset( $manifest['copy_files']['force_copy'] ) && $manifest['copy_files']['force_copy'] != "" ){
1478                     $zip_force_copy     = $manifest['copy_files']['force_copy'];
1479                 }
1480                 if( isset( $manifest['version'] ) ){
1481                     $version    = $manifest['version'];
1482                 }
1483                 if( !is_writable( "config.php" ) ){
1484                         return $mod_strings['ERR_UW_CONFIG'];
1485                 }
1486
1487                 $_SESSION['unzip_dir'] = clean_path($unzip_dir);
1488                 $_SESSION['zip_from_dir'] = clean_path($zip_from_dir);
1489                 logThis('unzip done.');
1490         } else {
1491                 $unzip_dir = $_SESSION['unzip_dir'];
1492                 $zip_from_dir = $_SESSION['zip_from_dir'];
1493         }
1494
1495     //check if $_SESSION['unzip_dir'] and $_SESSION['zip_from_dir'] exist
1496         if(!isset($_SESSION['unzip_dir']) || !file_exists($_SESSION['unzip_dir'])
1497                 || !isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !file_exists($_SESSION['install_file'])){
1498                     //redirect to start
1499             unlinkUWTempFiles();
1500                 resetUwSession();
1501                 echo 'Upload File not found so redirecting to Upgrade Start ';
1502                 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1503                 echo '<form name="redirect" action="' .$redirect_new_wizard. '"  method="POST">';
1504 $upgrade_directories_not_found =<<<eoq
1505         <table cellpadding="3" cellspacing="0" border="0">
1506                 <tr>
1507                         <th colspan="2" align="left">
1508                                 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1509                         </th>
1510                 </tr>
1511         </table>
1512 eoq;
1513 $uwMain = $upgrade_directories_not_found;
1514                                 return '';
1515         }
1516
1517     logThis ('is SugarConfig there '.file_exists(clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarObjects/SugarConfig.php")));
1518         if(file_exists(clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarObjects/SugarConfig.php"))) {
1519                 $file = clean_path($unzip_dir.'/'.$zip_from_dir."/include/SugarObjects/SugarConfig.php");
1520                 $destFile = str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), $cwd, $file);
1521                 if(!is_dir(dirname($destFile))) {
1522                         mkdir_recursive(dirname($destFile)); // make sure the directory exists
1523                 }
1524         copy($file,$destFile);
1525         //also copy include utils array utils
1526         $file = clean_path($unzip_dir.'/'.$zip_from_dir."/include/utils/array_utils.php");
1527                 $destFile = str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), $cwd, $file);
1528                 if(!is_dir(dirname($destFile))) {
1529                         mkdir_recursive(dirname($destFile)); // make sure the directory exists
1530                 }
1531         copy($file,$destFile);
1532         }
1533 }
1534
1535
1536 function preflightCheck() {
1537         require_once('modules/UpgradeWizard/uw_files.php');
1538
1539         global $sugar_config;
1540         global $mod_strings;
1541         global $sugar_version;
1542
1543         if(!isset($sugar_version) || empty($sugar_version)) {
1544                 require_once('./sugar_version.php');
1545         }
1546
1547         unset($_SESSION['rebuild_relationships']);
1548         unset($_SESSION['rebuild_extensions']);
1549
1550         // don't bother if are rechecking
1551         $manualDiff                     = array();
1552         if(!isset($_SESSION['unzip_dir']) || empty($_SESSION['unzip_dir'])) {
1553                 logThis('unzipping files in upgrade archive...');
1554                 $errors                                 = array();
1555                 list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
1556                 $unzip_dir = '';
1557                 //Following is if User logged out unexpectedly and then logged into UpgradeWizard again.
1558                 //also come up with mechanism to read from upgrade-progress file.
1559                 if(!isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !is_file($_SESSION['install_file'])) {
1560                         if (file_exists($base_tmp_upgrade_dir) && $handle = opendir($base_tmp_upgrade_dir)) {
1561                         while (false !== ($file = readdir($handle))) {
1562                                 if($file !="." && $file !="..") {
1563                                          if(is_file($base_tmp_upgrade_dir."/".$file."/manifest.php")){
1564                                                 require_once($base_tmp_upgrade_dir."/".$file."/manifest.php");
1565                                                 $package_name= $manifest['copy_files']['from_dir'];
1566                                                 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")){
1567                                                         $unzip_dir = $base_tmp_upgrade_dir."/".$file;
1568                                                         if(file_exists("$base_upgrade_dir/patch/".$package_name.'.zip')){
1569                                                                 $_SESSION['install_file'] = $package_name.".zip";
1570                                                                 break;
1571                                                         }
1572                                                 }
1573                                           }
1574                                 }
1575                         }
1576                         }
1577                 }
1578         if(empty($_SESSION['install_file'])){
1579                 unlinkUWTempFiles();
1580                 resetUwSession();
1581                 echo 'Upload File not found so redirecting to Upgrade Start ';
1582                 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1583                 echo '<form name="redirect" action="' .$redirect_new_wizard. '"  method="POST">';
1584 $upgrade_directories_not_found =<<<eoq
1585         <table cellpadding="3" cellspacing="0" border="0">
1586                 <tr>
1587                         <th colspan="2" align="left">
1588                                 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1589                         </th>
1590                 </tr>
1591         </table>
1592 eoq;
1593 $uwMain = $upgrade_directories_not_found;
1594                                 return '';
1595
1596         }
1597                 $install_file                   = "$base_upgrade_dir/patch/".basename(urldecode( $_SESSION['install_file'] ));
1598                 $show_files                             = true;
1599                 if(empty($unzip_dir)){
1600                         $unzip_dir                              = mk_temp_dir( $base_tmp_upgrade_dir );
1601                 }
1602                 $zip_from_dir                   = ".";
1603                 $zip_to_dir                             = ".";
1604                 $zip_force_copy                 = array();
1605
1606                 if(!$unzip_dir){
1607                         logThis('Could not create a temporary directory using mk_temp_dir( $base_tmp_upgrade_dir )');
1608                         die($mod_strings['ERR_UW_NO_CREATE_TMP_DIR']);
1609                 }
1610
1611                 //double check whether unzipped .
1612                 if(file_exists($unzip_dir ."/scripts") && file_exists($unzip_dir."/manifest.php")){
1613                 //already unzipped
1614                 }
1615                 else{
1616                         unzip( $install_file, $unzip_dir );
1617                 }
1618
1619                 // assumption -- already validated manifest.php at time of upload
1620                 require_once( "$unzip_dir/manifest.php" );
1621
1622                 if( isset( $manifest['copy_files']['from_dir'] ) && $manifest['copy_files']['from_dir'] != "" ){
1623                     $zip_from_dir   = $manifest['copy_files']['from_dir'];
1624                 }
1625                 if( isset( $manifest['copy_files']['to_dir'] ) && $manifest['copy_files']['to_dir'] != "" ){
1626                     $zip_to_dir     = $manifest['copy_files']['to_dir'];
1627                 }
1628                 if( isset( $manifest['copy_files']['force_copy'] ) && $manifest['copy_files']['force_copy'] != "" ){
1629                     $zip_force_copy     = $manifest['copy_files']['force_copy'];
1630                 }
1631                 if( isset( $manifest['version'] ) ){
1632                     $version    = $manifest['version'];
1633                 }
1634                 if( !is_writable( "config.php" ) ){
1635                         return $mod_strings['ERR_UW_CONFIG'];
1636                 }
1637
1638                 $_SESSION['unzip_dir'] = clean_path($unzip_dir);
1639                 $_SESSION['zip_from_dir'] = clean_path($zip_from_dir);
1640
1641          //logThis('unzip done.');
1642         } else {
1643                 $unzip_dir = $_SESSION['unzip_dir'];
1644                 $zip_from_dir = $_SESSION['zip_from_dir'];
1645         }
1646         //check if $_SESSION['unzip_dir'] and $_SESSION['zip_from_dir'] exist
1647         if(!isset($_SESSION['unzip_dir']) || !file_exists($_SESSION['unzip_dir'])
1648                 || !isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !file_exists($_SESSION['install_file'])){
1649                     //redirect to start
1650             unlinkUWTempFiles();
1651                 resetUwSession();
1652                 echo 'Upload File not found so redirecting to Upgrade Start ';
1653                 $redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
1654                 echo '<form name="redirect" action="' .$redirect_new_wizard. '"  method="POST">';
1655 $upgrade_directories_not_found =<<<eoq
1656         <table cellpadding="3" cellspacing="0" border="0">
1657                 <tr>
1658                         <th colspan="2" align="left">
1659                                 <span class='error'><b>'Upload file missing or has been deleted. Refresh the page to go back to UpgradeWizard start'</b></span>
1660                         </th>
1661                 </tr>
1662         </table>
1663 eoq;
1664 $uwMain = $upgrade_directories_not_found;
1665                                 return '';
1666         }
1667         //copy minimum required files
1668         fileCopy('include/utils/sugar_file_utils.php');
1669
1670         $upgradeFiles = findAllFiles(clean_path("$unzip_dir/$zip_from_dir"), array());
1671         $cache_html_files= array();
1672
1673         // get md5 sums
1674         $md5_string = array();
1675         if(file_exists(clean_path(getcwd().'/files.md5'))){
1676                 require(clean_path(getcwd().'/files.md5'));
1677         }
1678
1679         // file preflight checks
1680         logThis('verifying md5 checksums for files...');
1681         foreach($upgradeFiles as $file) {
1682                 if(in_array(str_replace(clean_path("$unzip_dir/$zip_from_dir") . "/", '', $file), $uw_files))
1683                         continue; // skip already loaded files
1684
1685                 if(strpos($file, '.md5'))
1686                         continue; // skip md5 file
1687
1688                 // normalize file paths
1689                 $file = clean_path($file);
1690
1691                 // check that we can move/delete the upgraded file
1692                 if(!is_writable($file)) {
1693                         $errors[] = $mod_strings['ERR_UW_FILE_NOT_WRITABLE'].": ".$file;
1694                 }
1695                 // check that destination files are writable
1696                 $destFile = getcwd().str_replace(clean_path($unzip_dir.'/'.$zip_from_dir), '', $file);
1697
1698                 if(is_file($destFile)) { // of course it needs to exist first...
1699                         if(!is_writable($destFile)) {
1700                                 $errors[] = $mod_strings['ERR_UW_FILE_NOT_WRITABLE'].": ".$destFile;
1701                         }
1702                 }
1703
1704                 ///////////////////////////////////////////////////////////////////////
1705                 ////    DIFFS
1706                 // compare md5s and build up a manual merge list
1707                 $targetFile = clean_path(".".str_replace(getcwd(),'',$destFile));
1708                 $targetMd5 = '0';
1709                 if(is_file($destFile)) {
1710                         if(strpos($targetFile, '.php')) {
1711                                 // handle PHP files that were hit with the security regex
1712                                 $fp = '';
1713                                 if(function_exists('sugar_fopen')){
1714                                         $fp = sugar_fopen($destFile, 'r');
1715                                 }
1716                                 else{
1717                                         $fp = fopen($destFile, 'r');
1718                                 }
1719                                 $filesize = filesize($destFile);
1720                                 if($filesize > 0) {
1721                                         $fileContents = stream_get_contents($fp);
1722                                         $targetMd5 = md5($fileContents);
1723                                 }
1724                         } else {
1725                                 $targetMd5 = md5_file($destFile);
1726                         }
1727                 }
1728
1729                 if(isset($md5_string[$targetFile]) && $md5_string[$targetFile] != $targetMd5) {
1730                         logThis('found a file with a differing md5: ['.$targetFile.']');
1731                         $manualDiff[] = $destFile;
1732                 }
1733                 ////    END DIFFS
1734                 ///////////////////////////////////////////////////////////////////////
1735         }
1736         logThis('md5 verification done.');
1737         $errors['manual'] = $manualDiff;
1738
1739         return $errors;
1740 }
1741
1742 function fileCopy($file_path){
1743         if(file_exists(clean_path($_SESSION['unzip_dir'].'/'.$_SESSION['zip_from_dir'].'/'.$file_path))) {
1744                 $file = clean_path($_SESSION['unzip_dir'].'/'.$_SESSION['zip_from_dir'].'/'.$file_path);
1745                 $destFile = str_replace(clean_path($_SESSION['unzip_dir'].'/'.$_SESSION['zip_from_dir']),  clean_path(getcwd()), $file);
1746         if(!is_dir(dirname($destFile))) {
1747                 mkdir_recursive(dirname($destFile)); // make sure the directory exists
1748                 }
1749                 copy_recursive($file,$destFile);
1750         }
1751 }
1752 function getChecklist($steps, $step) {
1753         global $mod_strings;
1754
1755         $skip = array('start', 'cancel', 'uninstall','end');
1756         $j=0;
1757         $i=1;
1758         $ret  = '<table cellpadding="3" cellspacing="4" border="0">';
1759         $ret .= '<tr><th colspan="3" align="left">'.$mod_strings['LBL_UW_CHECKLIST'].':</th></tr>';
1760         foreach($steps['desc'] as $k => $desc) {
1761                 if(in_array($steps['files'][$j], $skip)) {
1762                         $j++;
1763                         continue;
1764                 }
1765
1766                 //$status = "<span class='error'>{$mod_strings['LBL_UW_INCOMPLETE']}</span>";
1767                 $desc_mod_pre = '';
1768                 $desc_mod_post = '';
1769                 /*
1770                 if(isset($_SESSION['step'][$steps['files'][$k]]) && $_SESSION['step'][$steps['files'][$k]] == 'success') {
1771                         //$status = $mod_strings['LBL_UW_COMPLETE'];
1772                 }
1773                 */
1774
1775                 if($k == $_REQUEST['step']) {
1776                         //$status = $mod_strings['LBL_UW_IN_PROGRESS'];
1777                         $desc_mod_pre = "<font color=blue><i>";
1778                         $desc_mod_post = "</i></font>";
1779                 }
1780
1781                 $ret .= "<tr><td>&nbsp;</td><td><b>{$i}: {$desc_mod_pre}{$desc}{$desc_mod_post}</b></td>";
1782                 $ret .= "<td id={$steps['files'][$j]}><i></i></td></tr>";
1783                 $i++;
1784                 $j++;
1785         }
1786         $ret .= "</table>";
1787         return $ret;
1788 }
1789
1790 function prepSystemForUpgrade() {
1791         global $sugar_config;
1792         global $sugar_flavor;
1793         global $mod_strings;
1794     global $current_language;
1795         global $subdirs;
1796         global $base_upgrade_dir;
1797         global $base_tmp_upgrade_dir;
1798     list($p_base_upgrade_dir, $p_base_tmp_upgrade_dir) = getUWDirs();
1799         ///////////////////////////////////////////////////////////////////////////////
1800         ////    Make sure variables exist
1801         if(empty($base_upgrade_dir)){
1802                 $base_upgrade_dir       = $p_base_upgrade_dir;
1803         }
1804         if(empty($base_tmp_upgrade_dir)){
1805                 $base_tmp_upgrade_dir   = $p_base_tmp_upgrade_dir;
1806         }
1807         sugar_mkdir($base_tmp_upgrade_dir, 0775, true);
1808         if(!isset($subdirs) || empty($subdirs)){
1809                 $subdirs = array('full', 'langpack', 'module', 'patch', 'theme');
1810         }
1811
1812     $upgrade_progress_dir = $base_tmp_upgrade_dir;
1813     $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
1814     if(file_exists($upgrade_progress_file)){
1815         if(function_exists('get_upgrade_progress') && function_exists('didThisStepRunBefore')){
1816                 if(didThisStepRunBefore('end')){
1817                         include($upgrade_progress_file);
1818                         unset($upgrade_config);
1819                         unlink($upgrade_progress_file);
1820                 }
1821         }
1822     }
1823
1824     // increase the cuttoff time to 1 hour
1825         ini_set("max_execution_time", "3600");
1826
1827     // make sure dirs exist
1828         if($subdirs != null){
1829                 foreach($subdirs as $subdir) {
1830                     sugar_mkdir("$base_upgrade_dir/$subdir", 0775, true);
1831                 }
1832         }
1833         // array of special scripts that are executed during (un)installation-- key is type of script, value is filename
1834         if(!defined('SUGARCRM_PRE_INSTALL_FILE')) {
1835                 define('SUGARCRM_PRE_INSTALL_FILE', 'scripts/pre_install.php');
1836                 define('SUGARCRM_POST_INSTALL_FILE', 'scripts/post_install.php');
1837                 define('SUGARCRM_PRE_UNINSTALL_FILE', 'scripts/pre_uninstall.php');
1838                 define('SUGARCRM_POST_UNINSTALL_FILE', 'scripts/post_uninstall.php');
1839         }
1840
1841         $script_files = array(
1842                 "pre-install" => constant('SUGARCRM_PRE_INSTALL_FILE'),
1843                 "post-install" => constant('SUGARCRM_POST_INSTALL_FILE'),
1844                 "pre-uninstall" => constant('SUGARCRM_PRE_UNINSTALL_FILE'),
1845                 "post-uninstall" => constant('SUGARCRM_POST_UNINSTALL_FILE'),
1846         );
1847
1848         // check that the upload limit is set to 6M or greater
1849         define('SUGARCRM_MIN_UPLOAD_MAX_FILESIZE_BYTES', 6 * 1024 * 1024);  // 6 Megabytes
1850         $upload_max_filesize = ini_get('upload_max_filesize');
1851         $upload_max_filesize_bytes = return_bytes($upload_max_filesize);
1852
1853         if($upload_max_filesize_bytes < constant('SUGARCRM_MIN_UPLOAD_MAX_FILESIZE_BYTES')) {
1854                 $GLOBALS['log']->debug("detected upload_max_filesize: $upload_max_filesize");
1855         $admin_strings = return_module_language($current_language, 'Administration');
1856                 echo '<p class="error">'.$admin_strings['MSG_INCREASE_UPLOAD_MAX_FILESIZE'].' '.get_cfg_var('cfg_file_path')."</p>\n";
1857         }
1858 }
1859
1860 if ( !function_exists('extractFile') ) {
1861 function extractFile($zip_file, $file_in_zip) {
1862     global $base_tmp_upgrade_dir;
1863
1864         // strip cwd
1865         $absolute_base_tmp_upgrade_dir = clean_path($base_tmp_upgrade_dir);
1866         $relative_base_tmp_upgrade_dir = clean_path(str_replace(clean_path(getcwd()), '', $absolute_base_tmp_upgrade_dir));
1867
1868     // mk_temp_dir expects relative pathing
1869     $my_zip_dir = mk_temp_dir($relative_base_tmp_upgrade_dir);
1870
1871     unzip_file($zip_file, $file_in_zip, $my_zip_dir);
1872
1873     return("$my_zip_dir/$file_in_zip");
1874 }
1875 }
1876
1877 if ( !function_exists('extractManifest') ) {
1878 function extractManifest($zip_file) {
1879         logThis('extracting manifest.');
1880     return(extractFile($zip_file, "manifest.php"));
1881 }
1882 }
1883
1884 if ( !function_exists('getInstallType') ) {
1885 function getInstallType($type_string) {
1886     // detect file type
1887     global $subdirs;
1888         $subdirs = array('full', 'langpack', 'module', 'patch', 'theme', 'temp');
1889     foreach($subdirs as $subdir) {
1890         if(preg_match("#/$subdir/#", $type_string)) {
1891             return($subdir);
1892         }
1893     }
1894     // return empty if no match
1895     return("");
1896 }
1897 }
1898
1899 function getImageForType($type) {
1900     global $image_path;
1901     global $mod_strings;
1902
1903     $icon = "";
1904     switch($type) {
1905         case "full":
1906             $icon = SugarThemeRegistry::current()->getImage("Upgrade", "",null,null,'.gif',$mod_strings['LBL_UPGRADE']);
1907             break;
1908         case "langpack":
1909             $icon = SugarThemeRegistry::current()->getImage("LanguagePacks", "",null,null,'.gif',$mod_strings['LBL_LANGPACKS']);
1910             break;
1911         case "module":
1912             $icon = SugarThemeRegistry::current()->getImage("ModuleLoader", "",null,null,'.gif',$mod_strings['LBL_MODULELOADER']);
1913             break;
1914         case "patch":
1915             $icon = SugarThemeRegistry::current()->getImage("PatchUpgrades", "",null,null,'.gif',$mod_strings['LBL_PATCHUPGRADES']);
1916             break;
1917         case "theme":
1918             $icon = SugarThemeRegistry::current()->getImage("Themes", "",null,null,'.gif',$mod_strings['LBL_THEMES']);
1919             break;
1920         default:
1921             break;
1922     }
1923     return($icon);
1924 }
1925
1926 if ( !function_exists('getLanguagePackName') ) {
1927 function getLanguagePackName($the_file) {
1928     require_once("$the_file");
1929     if(isset($app_list_strings["language_pack_name"])) {
1930         return($app_list_strings["language_pack_name"]);
1931     }
1932     return("");
1933 }
1934 }
1935
1936 function getUITextForType($type) {
1937     if($type == "full") {
1938         return("Full Upgrade");
1939     }
1940     if($type == "langpack") {
1941         return("Language Pack");
1942     }
1943     if($type == "module") {
1944         return("Module");
1945     }
1946     if($type == "patch") {
1947         return("Patch");
1948     }
1949     if($type == "theme") {
1950         return("Theme");
1951     }
1952 }
1953
1954 if ( !function_exists('validate_manifest') ) {
1955 /**
1956  * Verifies a manifest from a patch or module to be compatible with the current Sugar version and flavor
1957  * @param array manifest Standard manifest array
1958  * @return string Error message, blank on success
1959  */
1960 function validate_manifest($manifest) {
1961         logThis('validating manifest.php file');
1962     // takes a manifest.php manifest array and validates contents
1963     global $subdirs;
1964     global $sugar_version;
1965     global $sugar_flavor;
1966         global $mod_strings;
1967
1968     if(!isset($manifest['type'])) {
1969         return $mod_strings['ERROR_MANIFEST_TYPE'];
1970     }
1971
1972     $type = $manifest['type'];
1973
1974     if(getInstallType("/$type/") == "") {
1975                 return $mod_strings['ERROR_PACKAGE_TYPE']. ": '" . $type . "'.";
1976     }
1977
1978     if(isset($manifest['acceptable_sugar_versions'])) {
1979         $version_ok = false;
1980         $matches_empty = true;
1981         if(isset($manifest['acceptable_sugar_versions']['exact_matches'])) {
1982             $matches_empty = false;
1983             foreach($manifest['acceptable_sugar_versions']['exact_matches'] as $match) {
1984                 if($match == $sugar_version) {
1985                     $version_ok = true;
1986                 }
1987             }
1988         }
1989         if(!$version_ok && isset($manifest['acceptable_sugar_versions']['regex_matches'])) {
1990             $matches_empty = false;
1991             foreach($manifest['acceptable_sugar_versions']['regex_matches'] as $match) {
1992                 if(preg_match("/$match/", $sugar_version)) {
1993                     $version_ok = true;
1994                 }
1995             }
1996         }
1997
1998         if(!$matches_empty && !$version_ok) {
1999             return $mod_strings['ERROR_VERSION_INCOMPATIBLE']."<br />".
2000             $mod_strings['ERR_UW_VERSION'].$sugar_version;
2001         }
2002     }
2003
2004     if(isset($manifest['acceptable_sugar_flavors']) && sizeof($manifest['acceptable_sugar_flavors']) > 0) {
2005         $flavor_ok = false;
2006         foreach($manifest['acceptable_sugar_flavors'] as $match) {
2007             if($match == $sugar_flavor) {
2008                 $flavor_ok = true;
2009             }
2010         }
2011         if(!$flavor_ok) {
2012             return $mod_strings['ERROR_FLAVOR_INCOMPATIBLE']."<br />".
2013             $mod_strings['ERR_UW_FLAVOR'].$sugar_flavor."<br />".
2014             $mod_strings['ERR_UW_FLAVOR_2'].$manifest['acceptable_sugar_flavors'][0];
2015         }
2016     }
2017
2018     return '';
2019 }
2020 }
2021
2022 function unlinkUploadFiles() {
2023         return;
2024 //      logThis('at unlinkUploadFiles()');
2025 //
2026 //      if(isset($_SESSION['install_file']) && !empty($_SESSION['install_file'])) {
2027 //              $upload = $_SESSION['install_file'];
2028 //
2029 //              if(is_file($upload)) {
2030 //                      logThis('unlinking ['.$upload.']');
2031 //                      @unlink($upload);
2032 //              }
2033 //      }
2034 }
2035
2036 /**
2037  * deletes files created by unzipping a package
2038  */
2039 function unlinkUWTempFiles() {
2040         global $sugar_config;
2041         global $path;
2042
2043         logThis('at unlinkUWTempFiles()');
2044         $tempDir='';
2045         list($upgDir, $tempDir) = getUWDirs();
2046
2047     if(file_exists($tempDir) && is_dir($tempDir)){
2048                 $files = findAllFiles($tempDir, array(), false);
2049                 rsort($files);
2050                 foreach($files as $file) {
2051                         if(!is_dir($file)) {
2052                                 //logThis('unlinking ['.$file.']', $path);
2053                                 @unlink($file);
2054                         }
2055                 }
2056                 // now do dirs
2057                 $files = findAllFiles($tempDir, array(), true);
2058                 foreach($files as $dir) {
2059                         if(is_dir($dir)) {
2060                                 //logThis('removing dir ['.$dir.']', $path);
2061                                 @rmdir($dir);
2062                         }
2063                 }
2064                 $cacheFile = sugar_cached("modules/UpgradeWizard/_persistence.php");
2065                 if(is_file($cacheFile)) {
2066                         logThis("Unlinking Upgrade cache file: '_persistence.php'", $path);
2067                         @unlink($cacheFile);
2068                 }
2069         }
2070         logThis("finished!");
2071 }
2072
2073 /**
2074  * finds all files in the passed path, but skips select directories
2075  * @param string dir Relative path
2076  * @param array the_array Collections of found files/dirs
2077  * @param bool include_dir True if we want to include directories in the
2078  * returned collection
2079  */
2080 function uwFindAllFiles($dir, $theArray, $includeDirs=false, $skipDirs=array(), $echo=false) {
2081         // check skips
2082     if (whetherNeedToSkipDir($dir, $skipDirs))
2083         {
2084             return $theArray;
2085         }
2086
2087     if (!is_dir($dir)) { return $theArray; }   // Bug # 46035, just checking for valid dir
2088         $d = dir($dir);
2089     if ($d === false)  { return $theArray; }   // Bug # 46035, more checking
2090
2091         while($f = $d->read()) {
2092                                         // bug 40793 Skip Directories array in upgradeWizard does not function correctly
2093             if($f == "." || $f == ".." || whetherNeedToSkipDir("$dir/$f", $skipDirs)) { // skip *nix self/parent
2094                 continue;
2095             }
2096
2097                 // for AJAX length count
2098         if($echo) {
2099                 echo '.';
2100                 ob_flush();
2101         }
2102
2103             if(is_dir("$dir/$f")) {
2104                         if($includeDirs) { // add the directory if flagged
2105                                 $theArray[] = clean_path("$dir/$f");
2106                         }
2107
2108                         // recurse in
2109                 $theArray = uwFindAllFiles("$dir/$f/", $theArray, $includeDirs, $skipDirs, $echo);
2110             } else {
2111                 $theArray[] = clean_path("$dir/$f");
2112             }
2113
2114
2115         }
2116         rsort($theArray);
2117         $d->close();
2118         return $theArray;
2119 }
2120
2121
2122
2123 /**
2124  * unset's UW's Session Vars
2125  */
2126 function resetUwSession() {
2127         logThis('resetting $_SESSION');
2128
2129         if(isset($_SESSION['committed']))
2130                 unset($_SESSION['committed']);
2131         if(isset($_SESSION['sugar_version_file']))
2132                 unset($_SESSION['sugar_version_file']);
2133         if(isset($_SESSION['upgrade_complete']))
2134                 unset($_SESSION['upgrade_complete']);
2135         if(isset($_SESSION['allTables']))
2136                 unset($_SESSION['allTables']);
2137         if(isset($_SESSION['alterCustomTableQueries']))
2138                 unset($_SESSION['alterCustomTableQueries']);
2139         if(isset($_SESSION['skip_zip_upload']))
2140                 unset($_SESSION['skip_zip_upload']);
2141         if(isset($_SESSION['sugar_version_file']))
2142                 unset($_SESSION['sugar_version_file']);
2143         if(isset($_SESSION['install_file']))
2144                 unset($_SESSION['install_file']);
2145         if(isset($_SESSION['unzip_dir']))
2146                 unset($_SESSION['unzip_dir']);
2147         if(isset($_SESSION['zip_from_dir']))
2148                 unset($_SESSION['zip_from_dir']);
2149         if(isset($_SESSION['overwrite_files']))
2150                 unset($_SESSION['overwrite_files']);
2151         if(isset($_SESSION['schema_change']))
2152                 unset($_SESSION['schema_change']);
2153         if(isset($_SESSION['uw_restore_dir']))
2154                 unset($_SESSION['uw_restore_dir']);
2155         if(isset($_SESSION['step']))
2156                 unset($_SESSION['step']);
2157         if(isset($_SESSION['files']))
2158                 unset($_SESSION['files']);
2159         if(isset($_SESSION['Upgraded451Wizard'])){
2160                 unset($_SESSION['Upgraded451Wizard']);
2161         }
2162         if(isset($_SESSION['Initial_451to500_Step'])){
2163                 unset($_SESSION['Initial_451to500_Step']);
2164         }
2165         if(isset($_SESSION['license_shown']))
2166                 unset($_SESSION['license_shown']);
2167     if(isset($_SESSION['sugarMergeRunResults']))
2168                 unset($_SESSION['sugarMergeRunResults']);
2169 }
2170
2171 /**
2172  * runs rebuild scripts
2173  */
2174 function UWrebuild() {
2175         global $db;
2176         global $path;
2177         /*
2178         //CCL - Comment this block out, it is called in end.php
2179         logThis('Rebuilding everything...', $path);
2180         require_once('modules/Administration/QuickRepairAndRebuild.php');
2181         $randc = new RepairAndClear();
2182     $randc->repairAndClearAll(array('clearAll'),array(translate('LBL_ALL_MODULES')), false, false);
2183     */
2184         $query = "DELETE FROM versions WHERE name='Rebuild Extensions'";
2185         $db->query($query);
2186         logThis('Registering rebuild record: '.$query, $path);
2187         logThis('Rebuild done.', $path);
2188
2189         // insert a new database row to show the rebuild extensions is done
2190         $id = create_guid();
2191         $gmdate = gmdate('Y-m-d H:i:s');
2192         $date_entered = db_convert("'$gmdate'", 'datetime');
2193         $query = 'INSERT INTO versions (id, deleted, date_entered, date_modified, modified_user_id, created_by, name, file_version, db_version) '
2194                 . "VALUES ('$id', '0', $date_entered, $date_entered, '1', '1', 'Rebuild Extensions', '4.0.0', '4.0.0')";
2195         $db->query($query);
2196         logThis('Registering rebuild record in versions table: '.$query, $path);
2197 }
2198
2199 function getCustomTables() {
2200         global $db;
2201
2202     return $db->tablesLike('%_cstm');
2203 }
2204
2205 function alterCustomTables($customTables)
2206 {
2207         return array();
2208 }
2209
2210 function getAllTables() {
2211         global $db;
2212     return $db->getTablesArray();
2213 }
2214
2215 function printAlterTableSql($tables)
2216 {
2217         $alterTableSql = '';
2218
2219         foreach($tables as $table)
2220                 $alterTableSql .= "ALTER TABLE " . $table . " CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;" . "\n";
2221
2222         return $alterTableSql;
2223 }
2224
2225 function executeConvertTablesSql($tables)
2226 {
2227         global $db;
2228
2229         foreach($tables as $table){
2230                 $query = "ALTER TABLE " . $table . " CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci";
2231                 if(!empty($table)){
2232                         logThis("Sending query: ".$query);
2233             $db->query($query);//, true, "An error has occured while performing db query.  See log file for details.<br>");
2234          }
2235         }
2236         return true;
2237 }
2238
2239 function testThis() {
2240         $files = uwFindAllFiles(getcwd().'/test', array());
2241
2242         $out = "<table cellpadding='1' cellspacing='0' border='0'>\n";
2243
2244         $priorPath = '';
2245         foreach($files as $file) {
2246                 $relativeFile = clean_path(str_replace(getcwd().'/test', '', $file));
2247                 $relativeFile = ($relativeFile{0} == '/') ? substr($relativeFile, 1, strlen($relativeFile)) : $relativeFile;
2248
2249                 $relativePath = dirname($relativeFile);
2250
2251                 if($relativePath == $priorPath) { // same dir, new file
2252                         $out .= "<tr><td>".basename($relativeFile)."</td></tr>";
2253                         $priorPath = $relativePath;
2254                 } else { // new dir
2255
2256                 }
2257         }
2258
2259         $out .= "</table>";
2260
2261         echo $out;
2262 }
2263
2264
2265
2266
2267 function testThis2($dir, $id=0, $hide=false) {
2268     global $mod_strings;
2269         $path = $dir;
2270         $dh = opendir($dir);
2271         rewinddir($dh);
2272
2273         $doHide = ($hide) ? 'none' : '';
2274         $out = "<div id='{$id}' style='display:{$doHide};'>";
2275         $out .= "<table cellpadding='1' cellspacing='0' style='border:0px solid #ccc'>\n";
2276
2277         while($file = readdir($dh)) {
2278                 if($file == '.' || $file == '..' || $file == 'CVS' || $file == '.cvsignore')
2279                         continue;
2280
2281                 if(is_dir($path.'/'.$file)) {
2282                         $file = $path.'/'.$file;
2283                         $newI = create_guid();
2284                         $out .= "<tr><td valign='top'><a href='javascript:toggleNwFiles(\"{$newI}\");'>".SugarThemeRegistry::current()->getImage("Workflow", "", null, null, ".gif", $mod_strings['LBL_WORKFLOW'])."</a></td>\n";
2285                         $out .= "<td valign='top'><b><a href='javascript:toggleNwFiles(\"{$newI}\");'>".basename($file)."</a></b></td></tr>";
2286                         $out .= "<tr><td></td><td valign='top'>".testThis2($file, $newI, true)."</td></tr>";
2287                 } else {
2288                         $out .= "<tr><td valign='top'>&nbsp;</td>\n";
2289                         $out .= "<td valign='top'>".basename($file)."</td></tr>";
2290                 }
2291         }
2292
2293         $out .= "</tr></table>";
2294         $out .= "</div>";
2295
2296         closedir($dh);
2297         return $out;
2298 }
2299
2300
2301
2302
2303
2304 function testThis3(&$files, $id, $hide, $previousPath = '') {
2305         if(!is_array($files) || empty($files))
2306                 return '';
2307
2308         $out = '';
2309
2310     global $mod_strings;
2311         // expecting full path here
2312         foreach($files as $k => $file) {
2313                 $file = str_replace(getcwd(), '', $file);
2314                 $path = dirname($file);
2315                 $fileName = basename($file);
2316
2317                 if($fileName == 'CVS' || $fileName == '.cvsignore')
2318                         continue;
2319
2320                 if($path == $previousPath) { // same directory
2321                         // new row for each file
2322                         $out .= "<tr><td valign='top' align='left'>&nbsp;</td>";
2323                         $out .= "<td valign='top' align='left'>{$fileName}</td></tr>";
2324                 } else { // new directory
2325                         $newI = $k;
2326                         $out .= "<tr><td valign='top'><a href='javascript:toggleNwFiles(\"{$newI}\");'>".SugarThemeRegistry::current()->getImage("Workflow", "", null, null, ".gif", $mod_strings['LBL_WORKFLOW'])."</a></td>\n";
2327                         $out .= "<td valign='top'><b><a href='javascript:toggleNwFiles(\"{$newI}\");'>".$fileName."</a></b></td></tr>";
2328                         $recurse = testThis3($files, $newI, true, $previousPath);
2329                         $out .= "<tr><td></td><td valign='top'>".$recurse."</td></tr>";
2330                 }
2331
2332                 $previousPath = $path;
2333         }
2334         $display = ($hide) ? 'none' : '';
2335         $ret = <<<eoq
2336         <div id="{$id}" style="display:{$display}">
2337         <table cellpadding='1' cellspacing='0' border='0' style='border:1px solid #ccc'>
2338                 {$out}
2339         </table>
2340         </div>
2341 eoq;
2342         return $ret;
2343 }
2344
2345
2346 function testThis4($filePath, $fileNodes=array(), $fileName='') {
2347         $path = dirname($filePath);
2348         $file = basename($filePath);
2349
2350         $exFile = explode('/', $path);
2351
2352         foreach($exFile as $pathSegment) {
2353                 if(is_array($fileNodes[$pathSegment])) { // path already processed
2354
2355                 } else { // newly found path
2356                         $fileNodes[$pathSegment] = array();
2357                 }
2358
2359                 if($fileName != '') {
2360                         $fileNodes[$pathSegment][] = $fileName;
2361                 }
2362         }
2363
2364         return $fileNodes;
2365 }
2366
2367
2368
2369 ///////////////////////////////////////////////////////////////////////////////
2370 ////    SYSTEM CHECK FUNCTIONS
2371 /**
2372  * generates an array with all files in the SugarCRM root directory, skipping
2373  * cache/
2374  * @return array files Array of files with absolute paths
2375  */
2376 function getFilesForPermsCheck() {
2377         global $sugar_config;
2378
2379         logThis('Got JSON call to find all files...');
2380         $filesNotWritable = array();
2381         $filesNWPerms = array();
2382
2383         // add directories here that should be skipped when doing file permissions checks (cache/upload is the nasty one)
2384         $skipDirs = array(
2385                 $sugar_config['upload_dir'],
2386         );
2387         $files = uwFindAllFiles(".", array(), true, $skipDirs, true);
2388         return $files;
2389 }
2390
2391 /**
2392  * checks files for permissions
2393  * @param array files Array of files with absolute paths
2394  * @return string result of check
2395  */
2396 function checkFiles($files, $echo=false) {
2397         global $mod_strings;
2398         $filesNotWritable = array();
2399         $i=0;
2400         $filesOut = "
2401                 <a href='javascript:void(0); toggleNwFiles(\"filesNw\");'>{$mod_strings['LBL_UW_SHOW_NW_FILES']}</a>
2402                 <div id='filesNw' style='display:none;'>
2403                 <table cellpadding='3' cellspacing='0' border='0'>
2404                 <tr>
2405                         <th align='left'>{$mod_strings['LBL_UW_FILE']}</th>
2406                         <th align='left'>{$mod_strings['LBL_UW_FILE_PERMS']}</th>
2407                         <th align='left'>{$mod_strings['LBL_UW_FILE_OWNER']}</th>
2408                         <th align='left'>{$mod_strings['LBL_UW_FILE_GROUP']}</th>
2409                 </tr>";
2410
2411         $isWindows = is_windows();
2412         foreach($files as $file) {
2413
2414                 if($isWindows) {
2415                         if(!is_writable_windows($file)) {
2416                                 logThis('WINDOWS: File ['.$file.'] not readable - saving for display');
2417                                 // don't warn yet - we're going to use this to check against replacement files
2418         // aw: commented out; it's a hack to allow upgrade wizard to continue on windows... will fix later
2419                                 /*$filesNotWritable[$i] = $file;
2420                                 $filesNWPerms[$i] = substr(sprintf('%o',fileperms($file)), -4);
2421                                 $filesOut .= "<tr>".
2422                                                                 "<td><span class='error'>{$file}</span></td>".
2423                                                                 "<td>{$filesNWPerms[$i]}</td>".
2424                                                                 "<td>".$mod_strings['ERR_UW_CANNOT_DETERMINE_USER']."</td>".
2425                                                                 "<td>".$mod_strings['ERR_UW_CANNOT_DETERMINE_GROUP']."</td>".
2426                                                           "</tr>";*/
2427                         }
2428                 } else {
2429                         if(!is_writable($file)) {
2430                                 logThis('File ['.$file.'] not writable - saving for display');
2431                                 // don't warn yet - we're going to use this to check against replacement files
2432                                 $filesNotWritable[$i] = $file;
2433                                 $filesNWPerms[$i] = substr(sprintf('%o',fileperms($file)), -4);
2434                                 $owner = posix_getpwuid(fileowner($file));
2435                                 $group = posix_getgrgid(filegroup($file));
2436                                 $filesOut .= "<tr>".
2437                                                                 "<td><span class='error'>{$file}</span></td>".
2438                                                                 "<td>{$filesNWPerms[$i]}</td>".
2439                                                                 "<td>".$owner['name']."</td>".
2440                                                                 "<td>".$group['name']."</td>".
2441                                                           "</tr>";
2442                         }
2443                 }
2444                 $i++;
2445         }
2446
2447         $filesOut .= '</table></div>';
2448         // not a stop error
2449         $errors['files']['filesNotWritable'] = (count($filesNotWritable) > 0) ? true : false;
2450         if(count($filesNotWritable) < 1) {
2451                 $filesOut = "{$mod_strings['LBL_UW_FILE_NO_ERRORS']}";
2452         }
2453
2454         return $filesOut;
2455 }
2456
2457 function deletePackageOnCancel(){
2458         global $mod_strings;
2459         global $sugar_config;
2460         list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
2461         logThis('running delete');
2462     if(!isset($_SESSION['install_file']) || ($_SESSION['install_file'] == "")) {
2463         logThis('ERROR: trying to delete non-existent file: ['.$_REQUEST['install_file'].']');
2464         $error = $mod_strings['ERR_UW_NO_FILE_UPLOADED'];
2465     }
2466     // delete file in upgrades/patch
2467     $delete_me = "$base_upgrade_dir/patch/".basename(urldecode( $_REQUEST['install_file'] ));
2468     if(@unlink($delete_me)) {
2469         //logThis('unlinking: '.$delete_me);
2470         $out = basename($delete_me).$mod_strings['LBL_UW_FILE_DELETED'];
2471     } else {
2472         logThis('ERROR: could not delete ['.$delete_me.']');
2473                 $error = $mod_strings['ERR_UW_FILE_NOT_DELETED'].$delete_me;
2474     }
2475
2476     if(!empty($error)) {
2477                 $out = "<b><span class='error'>{$error}</span></b><br />";
2478     }
2479 }
2480
2481 function handleExecuteSqlKeys($db, $tableName, $disable)
2482 {
2483     if(empty($tableName)) return true;
2484     if(is_callable(array($db, "supports"))) {
2485         // new API
2486         return $disable?$db->disableKeys($tableName):$db->enableKeys($tableName);
2487     } else {
2488         // old api
2489         $op = $disable?"DISABLE":"ENABLE";
2490         return $db->query("ALTER TABLE $tableName $op KEYS");
2491     }
2492 }
2493
2494 function parseAndExecuteSqlFile($sqlScript,$forStepQuery='',$resumeFromQuery='')
2495 {
2496         global $sugar_config;
2497         $alterTableSchema = '';
2498         $sqlErrors = array();
2499         if(!isset($_SESSION['sqlSkippedQueries'])){
2500                 $_SESSION['sqlSkippedQueries'] = array();
2501         }
2502         $db = DBManagerFactory::getInstance();
2503         $disable_keys = ($db->dbType == "mysql"); // have to use old way for now for upgrades
2504         if(strpos($resumeFromQuery,",") != false){
2505                 $resumeFromQuery = explode(",",$resumeFromQuery);
2506         }
2507         if(file_exists($sqlScript)) {
2508                 $fp = fopen($sqlScript, 'r');
2509                 $contents = stream_get_contents($fp);
2510                 $anyScriptChanges =$contents;
2511                 $resumeAfterFound = false;
2512                 if(rewind($fp)) {
2513                         $completeLine = '';
2514                         $count = 0;
2515                         while($line = fgets($fp)) {
2516                                 if(strpos($line, '--') === false) {
2517                                         $completeLine .= " ".trim($line);
2518                                         if(strpos($line, ';') !== false) {
2519                                                 $query = '';
2520                                                 $query = str_replace(';','',$completeLine);
2521                                                 //if resume from query is not null then find out from where
2522                                                 //it should start executing the query.
2523
2524                                                 if($query != null && $resumeFromQuery != null){
2525                                                         if(!$resumeAfterFound){
2526                                                                 if(strpos($query,",") != false){
2527                                                                         $queArray = explode(",",$query);
2528                                                                         for($i=0;$i<sizeof($resumeFromQuery);$i++){
2529                                                                                 if(strcasecmp(trim($resumeFromQuery[$i]),trim($queArray[$i]))==0){
2530                                                                                         $resumeAfterFound = true;
2531                                                                                 } else {
2532                                                                                         $resumeAfterFound = false;
2533                                                                                         break;
2534                                                                                 }
2535                                                                         }//for
2536
2537                                                                 }
2538                                                                 elseif(strcasecmp(trim($resumeFromQuery),trim($query))==0){
2539                                                                         $resumeAfterFound = true;
2540                                                                 }
2541                                                         }
2542                                                         if($resumeAfterFound){
2543                                                                 $count++;
2544                                                         }
2545                                                         // if $count=1 means it is just found so skip the query. Run the next one
2546                                                         if($query != null && $resumeAfterFound && $count >1){
2547                                                         $tableName = getAlterTable($query);
2548                                                                 if($disable_keys)
2549                                                                 {
2550                                                                         handleExecuteSqlKeys($db, $tableName, true);
2551                                                                 }
2552                                                                 $db->query($query);
2553                                                                 if($db->checkError()){
2554                                                                         //put in the array to use later on
2555                                                                         $_SESSION['sqlSkippedQueries'][] = $query;
2556                                                                 }
2557                                                                 if($disable_keys)
2558                                                                 {
2559                                                                         handleExecuteSqlKeys($db, $tableName, false);
2560                                                                 }
2561                                                                 $progQuery[$forStepQuery]=$query;
2562                                                                 post_install_progress($progQuery,$action='set');
2563                                                         }//if
2564                                                 }
2565                                                 elseif($query != null){
2566                                                         $tableName = getAlterTable($query);
2567                                                         if($disable_keys)
2568                                                         {
2569                                                                 handleExecuteSqlKeys($db, $tableName, true);
2570                                                         }
2571                                                         $db->query($query);
2572                                                         if($disable_keys)
2573                                                         {
2574                                                                 handleExecuteSqlKeys($db, $tableName, false);
2575                                                         }
2576                                                         $progQuery[$forStepQuery]=$query;
2577                                                         post_install_progress($progQuery,$action='set');
2578                                                         if($db->checkError()){
2579                                                                 //put in the array to use later on
2580                                                                 $_SESSION['sqlSkippedQueries'][] = $query;
2581                                                         }
2582                                                 }
2583                                                 $completeLine = '';
2584                                         }
2585                                 }
2586                         }//while
2587                 }
2588         }
2589 }
2590
2591
2592 function getAlterTable($query){
2593         $query = strtolower($query);
2594         if (preg_match('/^\s*alter\s+table\s+/', $query)) {
2595                 $sqlArray = explode(" ", $query);
2596                 $key = array_search('table', $sqlArray);
2597                 return $sqlArray[($key+1)];
2598         }else {
2599                 return '';
2600         }
2601 }
2602
2603 function set_upgrade_vars(){
2604         logThis('setting session variables...');
2605         $upgrade_progress_dir = sugar_cached('upgrades/temp');
2606         if(!is_dir($upgrade_progress_dir)){
2607                 mkdir_recursive($upgrade_progress_dir);
2608         }
2609         $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2610         if(file_exists($upgrade_progress_file)){
2611                 include($upgrade_progress_file);
2612         }
2613         else{
2614                 fopen($upgrade_progress_file, 'w+');
2615         }
2616         if(!isset($upgrade_config) || $upgrade_config == null){
2617                 $upgrade_config = array();
2618                 $upgrade_config[1]['upgrade_vars']=array();
2619         }
2620     if(isset($upgrade_config[1]) && isset($upgrade_config[1]['upgrade_vars']) && !is_array($upgrade_config[1]['upgrade_vars'])){
2621         $upgrade_config[1]['upgrade_vars'] = array();
2622     }
2623
2624         if(!isset($upgrade_vars) || $upgrade_vars == NULL){
2625                 $upgrade_vars = array();
2626         }
2627         if(isset($_SESSION['unzip_dir']) && !empty($_SESSION['unzip_dir']) && file_exists($_SESSION['unzip_dir'])){
2628                 $upgrade_vars['unzip_dir']=$_SESSION['unzip_dir'];
2629         }
2630         if(isset($_SESSION['install_file']) && !empty($_SESSION['install_file']) && file_exists($_SESSION['install_file'])){
2631                 $upgrade_vars['install_file']=$_SESSION['install_file'];
2632         }
2633         if(isset($_SESSION['Upgraded451Wizard']) && !empty($_SESSION['Upgraded451Wizard'])){
2634                 $upgrade_vars['Upgraded451Wizard']=$_SESSION['Upgraded451Wizard'];
2635         }
2636         if(isset($_SESSION['license_shown']) && !empty($_SESSION['license_shown'])){
2637                 $upgrade_vars['license_shown']=$_SESSION['license_shown'];
2638         }
2639         if(isset($_SESSION['Initial_451to500_Step']) && !empty($_SESSION['Initial_451to500_Step'])){
2640                 $upgrade_vars['Initial_451to500_Step']=$_SESSION['Initial_451to500_Step'];
2641         }
2642         if(isset($_SESSION['zip_from_dir']) && !empty($_SESSION['zip_from_dir'])){
2643                 $upgrade_vars['zip_from_dir']=$_SESSION['zip_from_dir'];
2644         }
2645         //place into the upgrade_config array and rewrite config array only if new values are being inserted
2646         if(isset($upgrade_vars) && $upgrade_vars != null && sizeof($upgrade_vars) > 0){
2647                 foreach($upgrade_vars as $key=>$val){
2648                         if($key != null && $val != null){
2649                                 $upgrade_config[1]['upgrade_vars'][$key]=$upgrade_vars[$key];
2650                         }
2651                 }
2652                 ksort($upgrade_config);
2653                 if(is_writable($upgrade_progress_file) && write_array_to_file( "upgrade_config", $upgrade_config,
2654                         $upgrade_progress_file)) {
2655                        //writing to the file
2656                 }
2657     }
2658 }
2659
2660 function initialize_session_vars(){
2661   $upgrade_progress_dir = sugar_cached('upgrades/temp');
2662   $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2663   if(file_exists($upgrade_progress_file)){
2664         include($upgrade_progress_file);
2665         if(isset($upgrade_config) && $upgrade_config != null && is_array($upgrade_config) && sizeof($upgrade_config) >0){
2666                 $currVarsArray=$upgrade_config[1]['upgrade_vars'];
2667                 //print_r($currVarsArray);
2668                 if(isset($currVarsArray) && $currVarsArray != null && is_array($currVarsArray) && sizeof($currVarsArray)>0){
2669                         foreach($currVarsArray as $key=>$val){
2670                                 if($key != null && $val !=null){
2671                                         //set session variables
2672                                         $_SESSION[$key]=$val;
2673                                         //set varibales
2674                                         '$'.$key=$val;
2675                                 }
2676                         }
2677                 }
2678         }
2679   }
2680 }
2681 //track the upgrade progress on each step
2682 //track the upgrade progress on each step
2683 function set_upgrade_progress($currStep,$currState,$currStepSub='',$currStepSubState=''){
2684
2685         $upgrade_progress_dir = sugar_cached('upgrades/temp');
2686         if(!is_dir($upgrade_progress_dir)){
2687                 mkdir_recursive($upgrade_progress_dir);
2688         }
2689         $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2690         if(file_exists($upgrade_progress_file)){
2691                 include($upgrade_progress_file);
2692         }
2693         else{
2694                 if(function_exists('sugar_fopen')){
2695                         sugar_fopen($upgrade_progress_file, 'w+');
2696                 }
2697                 else{
2698                         fopen($upgrade_progress_file, 'w+');
2699                 }
2700         }
2701         if(!isset($upgrade_config) || $upgrade_config == null){
2702                 $upgrade_config = array();
2703                 $upgrade_config[1]['upgrade_vars']=array();
2704         }
2705     if(!is_array($upgrade_config[1]['upgrade_vars'])){
2706         $upgrade_config[1]['upgrade_vars'] = array();
2707     }
2708         if($currStep != null && $currState != null){
2709                 if(sizeof($upgrade_config) > 0){
2710                         if($currStepSub != null && $currStepSubState !=null){
2711                                 //check if new status to be set or update
2712                                 //get the latest in array. since it has sub components prepare an array
2713                                 if(!empty($upgrade_config[sizeof($upgrade_config)][$currStep]) && is_array($upgrade_config[sizeof($upgrade_config)][$currStep])){
2714                                         $latestStepSub = currSubStep($upgrade_config[sizeof($upgrade_config)][$currStep]);
2715                                         if($latestStepSub == $currStepSub){
2716                                                 $upgrade_config[sizeof($upgrade_config)][$currStep][$latestStepSub]=$currStepSubState;
2717                                                 $upgrade_config[sizeof($upgrade_config)][$currStep][$currStep] = $currState;
2718                                         }
2719                                         else{
2720                                                 $upgrade_config[sizeof($upgrade_config)][$currStep][$currStepSub]=$currStepSubState;
2721                                                 $upgrade_config[sizeof($upgrade_config)][$currStep][$currStep] = $currState;
2722                                         }
2723                                 }
2724                                 else{
2725                                         $currArray = array();
2726                                         $currArray[$currStep] = $currState;
2727                                         $currArray[$currStepSub] = $currStepSubState;
2728                                         $upgrade_config[sizeof($upgrade_config)+1][$currStep] = $currArray;
2729                                 }
2730                         }
2731           else{
2732                                 //get the current upgrade progress
2733                                 $latestStep = get_upgrade_progress();
2734                                 //set the upgrade progress
2735                                 if($latestStep == $currStep){
2736                                         //update the current step with new progress status
2737                                         $upgrade_config[sizeof($upgrade_config)][$latestStep]=$currState;
2738                                 }
2739                                 else{
2740                                         //it's a new step
2741                                         $upgrade_config[sizeof($upgrade_config)+1][$currStep]=$currState;
2742                                 }
2743                     // now check if there elements within array substeps
2744           }
2745                 }
2746                 else{
2747                         //set the upgrade progress  (just starting)
2748                         $upgrade_config[sizeof($upgrade_config)+1][$currStep]= $currState;
2749                 }
2750
2751                 if(is_writable($upgrade_progress_file) && write_array_to_file( "upgrade_config", $upgrade_config,
2752                 $upgrade_progress_file)) {
2753                //writing to the file
2754                 }
2755
2756         }
2757 }
2758
2759 function get_upgrade_progress(){
2760         $upgrade_progress_dir = sugar_cached('upgrades/temp');
2761         $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2762         $currState = '';
2763
2764         if(file_exists($upgrade_progress_file)){
2765                 include($upgrade_progress_file);
2766                 if(!isset($upgrade_config) || $upgrade_config == null){
2767                         $upgrade_config = array();
2768                 }
2769                 if($upgrade_config != null && sizeof($upgrade_config) >1){
2770                         $currArr = $upgrade_config[sizeof($upgrade_config)];
2771                         if(is_array($currArr)){
2772                            foreach($currArr as $key=>$val){
2773                                         $currState = $key;
2774                                 }
2775                         }
2776                 }
2777         }
2778         return $currState;
2779 }
2780 function currSubStep($currStep){
2781         $currSubStep = '';
2782         if(is_array($currStep)){
2783        foreach($currStep as $key=>$val){
2784                     if($key != null){
2785                         $currState = $key;
2786                         }
2787            }
2788         }
2789         return $currState;
2790 }
2791 function currUpgradeState($currState){
2792         $currState = '';
2793         if(is_array($currState)){
2794        foreach($currState as $key=>$val){
2795                         if(is_array($val)){
2796                                 foreach($val as $k=>$v){
2797                                         if($k != null){
2798                                                 $currState = $k;
2799                                         }
2800                                 }
2801                         }
2802                         else{
2803                                 $currState = $key;
2804                         }
2805                 }
2806         }
2807         return $currState;
2808 }
2809
2810 function didThisStepRunBefore($step,$SubStep=''){
2811         if($step == null) return;
2812         $upgrade_progress_dir = sugar_cached('upgrades/temp');
2813         $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2814         $currState = '';
2815         $stepRan = false;
2816         if(file_exists($upgrade_progress_file)){
2817                 include($upgrade_progress_file);
2818                 if(isset($upgrade_config) && $upgrade_config != null && is_array($upgrade_config) && sizeof($upgrade_config) >0){
2819                         for($i=1;$i<=sizeof($upgrade_config);$i++){
2820                           if(is_array($upgrade_config[$i])){
2821                                         foreach($upgrade_config[$i] as $key=>$val){
2822                                                 if($key==$step){
2823                                                         if(is_array($upgrade_config[$i][$step])){
2824                                                                 //now process
2825                                                                 foreach ($upgrade_config[$i][$step] as $k=>$v){
2826                                                                         if(is_array($v)){
2827                                                                                 foreach($v as $k1=>$v1){
2828                                                                                         if($SubStep != null){
2829                                                                                                 if($SubStep ==$k1 && $v1=='done'){
2830                                                                                                         $stepRan = true;
2831                                                                                                         break;
2832                                                                                                 }
2833                                                                                         }
2834                                                                                 }//foreach
2835                                                                         }
2836                                                                         elseif($SubStep !=null){
2837                                                                                 if($SubStep==$k && $v=='done'){
2838                                                                                         $stepRan = true;
2839                                                                                         break;
2840                                                                                 }
2841                                                                         }
2842                                                                         elseif($step==$k && $v=='done'){
2843                                                                                 $stepRan = true;
2844                                                                                 break;
2845                                                                         }
2846                                                                 }//foreach
2847                                                         }
2848                                                         elseif($val=='done'){
2849                                                                 $stepRan = true;
2850                                                         }
2851                                                 }
2852                                         }//foreach
2853                                 }
2854                         }//for
2855                 }
2856         }
2857         return $stepRan;
2858 }
2859
2860
2861
2862 //get and set post install status
2863 function post_install_progress($progArray='',$action=''){
2864         $upgrade_progress_dir = sugar_cached('upgrades/temp');
2865         $upgrade_progress_file = $upgrade_progress_dir.'/upgrade_progress.php';
2866     if($action=='' || $action=='get'){
2867                 //get the state of post install
2868         $currProg = array();
2869                 if(file_exists($upgrade_progress_file)){
2870                         include($upgrade_progress_file);
2871                         if(is_array($upgrade_config[sizeof($upgrade_config)]['commit']['post_install']) && sizeof($upgrade_config[sizeof($upgrade_config)]['commit']['post_install'])>0){
2872                                 foreach($upgrade_config[sizeof($upgrade_config)]['commit']['post_install'] as $k=>$v){
2873                                         $currProg[$k]=$v;
2874                                 }
2875                         }
2876                 }
2877                 return $currProg;
2878         }
2879         elseif($action=='set'){
2880                 if(!is_dir($upgrade_progress_dir)){
2881                         mkdir($upgrade_progress_dir);
2882                 }
2883                 if(file_exists($upgrade_progress_file)){
2884                         include($upgrade_progress_file);
2885                 }
2886                 else{
2887                         fopen($upgrade_progress_file, 'w+');
2888                 }
2889                 if(!is_array($upgrade_config[sizeof($upgrade_config)]['commit']['post_install'])){
2890                         $upgrade_config[sizeof($upgrade_config)]['commit']['post_install']=array();
2891                         $upgrade_config[sizeof($upgrade_config)]['commit']['post_install']['post_install'] = 'in_progress';
2892                 }
2893                 if($progArray != null && is_array($progArray)){
2894                         foreach($progArray as $key=>$val){
2895                                 $upgrade_config[sizeof($upgrade_config)]['commit']['post_install'][$key]=$val;
2896                         }
2897                 }
2898                 if(is_writable($upgrade_progress_file) && write_array_to_file( "upgrade_config", $upgrade_config,
2899                 $upgrade_progress_file)) {
2900                //writing to the file
2901                 }
2902         }
2903 }
2904
2905 function repairDBForUpgrade($execute=false,$path=''){
2906
2907         global $current_user, $beanFiles;
2908         global $dictionary;
2909         set_time_limit(3600);
2910
2911         $db = &DBManagerFactory::getInstance();
2912         $sql = '';
2913         VardefManager::clearVardef();
2914         require_once('include/ListView/ListView.php');
2915         foreach ($beanFiles as $bean => $file) {
2916                 require_once ($file);
2917                 $focus = new $bean ();
2918                 $sql .= $db->repairTable($focus, $execute);
2919
2920         }
2921         //echo $sql;
2922         $olddictionary = $dictionary;
2923         unset ($dictionary);
2924         include ('modules/TableDictionary.php');
2925         foreach ($dictionary as $meta) {
2926                 $tablename = $meta['table'];
2927                 $fielddefs = $meta['fields'];
2928                 $indices = $meta['indices'];
2929                 $sql .= $db->repairTableParams($tablename, $fielddefs, $indices, $execute);
2930         }
2931          $qry_str = "";
2932           foreach (explode("\n", $sql) as $line) {
2933                   if (!empty ($line) && substr($line, -2) != "*/") {
2934                         $line .= ";";
2935                   }
2936                   $qry_str .= $line . "\n";
2937            }
2938           $sql = str_replace(
2939           array(
2940                 "\n",
2941                 '&#039;',
2942            ),
2943           array(
2944                 '',
2945                 "'",
2946           ),
2947           preg_replace('#(/\*.+?\*/\n*)#', '', $qry_str)
2948           );
2949          logThis("*******START EXECUTING DB UPGRADE QUERIES***************",$path);
2950                 logThis($sql,$path);
2951          logThis("*******END EXECUTING DB UPGRADE QUERIES****************",$path);
2952          if(!$execute){
2953                 return $sql;
2954          }
2955 }
2956
2957
2958
2959 /**
2960  * upgradeUserPreferences
2961  * This method updates the user_preferences table and sets the pages/dashlets for users
2962  * which have ACL access to Trackers so that the Tracker dashlets are set in their user perferences
2963  *
2964  */
2965 function upgradeUserPreferences() {
2966     global $sugar_config, $sugar_version;
2967     $uw_strings = return_module_language($GLOBALS['current_language'], 'UpgradeWizard');
2968
2969     $localization = new Localization();
2970     $localeCoreDefaults = $localization->getLocaleConfigDefaults();
2971
2972     // check the current system wide default_locale_name_format and add it to the list if it's not there
2973     if(empty($sugar_config['name_formats'])) {
2974         $sugar_config['name_formats'] = $localeCoreDefaults['name_formats'];
2975         if(!rebuildConfigFile($sugar_config, $sugar_version)) {
2976             $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
2977         }
2978     }
2979
2980     $currentDefaultLocaleNameFormat = $sugar_config['default_locale_name_format'];
2981
2982     if ($localization->isAllowedNameFormat($currentDefaultLocaleNameFormat)) {
2983         upgradeLocaleNameFormat($currentDefaultLocaleNameFormat);
2984     } else {
2985         $sugar_config['default_locale_name_format'] = $localeCoreDefaults['default_locale_name_format'];
2986         if(!rebuildConfigFile($sugar_config, $sugar_version)) {
2987             $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
2988         }
2989         $localization->createInvalidLocaleNameFormatUpgradeNotice();
2990     }
2991
2992         $db = &DBManagerFactory::getInstance();
2993     $result = $db->query("SELECT id FROM users where deleted = '0'");
2994         while($row = $db->fetchByAssoc($result))
2995     {
2996         $current_user = new User();
2997         $current_user->retrieve($row['id']);
2998
2999         // 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
3000         $currentUserNameFormat = $current_user->getPreference('default_locale_name_format');
3001         if ($localization->isAllowedNameFormat($currentUserNameFormat)) {
3002             upgradeLocaleNameFormat($currentUserNameFormat);
3003         } else {
3004             $current_user->setPreference('default_locale_name_format', 's f l', 0, 'global');
3005             $current_user->savePreferencesToDB();
3006         }
3007
3008         } //while
3009 }
3010
3011
3012 /**
3013  * Checks if a locale name format is part of the default list, if not adds it to the config
3014  * @param $name_format string a local name format string such as 's f l'
3015  * @return bool true on successful write to config file, false on failure;
3016  */
3017 function upgradeLocaleNameFormat($name_format) {
3018     global $sugar_config, $sugar_version;
3019
3020     $localization = new Localization();
3021     $localeConfigDefaults = $localization->getLocaleConfigDefaults();
3022
3023     $uw_strings = return_module_language($GLOBALS['current_language'], 'UpgradeWizard');
3024     if(empty($sugar_config['name_formats'])) {
3025         $sugar_config['name_formats'] = $localeConfigDefaults['name_formats'];
3026         if(!rebuildConfigFile($sugar_config, $sugar_version)) {
3027             $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
3028         }
3029     }
3030     if (!in_array($name_format, $sugar_config['name_formats'])) {
3031         $new_config = sugarArrayMerge($sugar_config['name_formats'], array($name_format=>$name_format));
3032         $sugar_config['name_formats'] = $new_config;
3033         if(!rebuildConfigFile($sugar_config, $sugar_version)) {
3034             $errors[] = $uw_strings['ERR_UW_CONFIG_WRITE'];
3035             return false;
3036         }
3037     }
3038     return true;
3039 }
3040
3041
3042
3043 function add_custom_modules_favorites_search(){
3044     $module_directories = scandir('modules');
3045
3046         foreach($module_directories as $module_dir){
3047                 if($module_dir == '.' || $module_dir == '..' || !is_dir("modules/{$module_dir}")){
3048                         continue;
3049                 }
3050
3051                 $matches = array();
3052                 preg_match('/^[a-z0-9]{1,5}_[a-z0-9_]+$/i' , $module_dir, $matches);
3053
3054                 // Make sure the module was created by module builder
3055                 if(empty($matches)){
3056                         continue;
3057                 }
3058
3059                 $full_module_dir = "modules/{$module_dir}/";
3060                 $read_searchdefs_from = "{$full_module_dir}/metadata/searchdefs.php";
3061                 $read_SearchFields_from = "{$full_module_dir}/metadata/SearchFields.php";
3062                 $read_custom_SearchFields_from = "custom/{$full_module_dir}/metadata/SearchFields.php";
3063
3064                 // Studio can possibly override this file, so we check for a custom version of it
3065                 if(file_exists("custom/{$full_module_dir}/metadata/searchdefs.php")){
3066                         $read_searchdefs_from = "custom/{$full_module_dir}/metadata/searchdefs.php";
3067                 }
3068
3069                 if(file_exists($read_searchdefs_from) && file_exists($read_SearchFields_from)){
3070                         $found_sf1 = false;
3071                         $found_sf2 = false;
3072                         require($read_searchdefs_from);
3073                         foreach($searchdefs[$module_dir]['layout']['basic_search'] as $sf_array){
3074                                 if(isset($sf_array['name']) && $sf_array['name'] == 'favorites_only'){
3075                                         $found_sf1 = true;
3076                                 }
3077                         }
3078
3079                         require($read_SearchFields_from);
3080                         if(isset($searchFields[$module_dir]['favorites_only'])){
3081                                 $found_sf2 = true;
3082                         }
3083
3084                         if(!$found_sf1 && !$found_sf2){
3085                                 $searchdefs[$module_dir]['layout']['basic_search']['favorites_only'] = array('name' => 'favorites_only','label' => 'LBL_FAVORITES_FILTER','type' => 'bool',);
3086                                 $searchdefs[$module_dir]['layout']['advanced_search']['favorites_only'] = array('name' => 'favorites_only','label' => 'LBL_FAVORITES_FILTER','type' => 'bool',);
3087                                 $searchFields[$module_dir]['favorites_only'] = array(
3088                                         'query_type'=>'format',
3089                                         'operator' => 'subquery',
3090                                         'subquery' => 'SELECT sugarfavorites.record_id FROM sugarfavorites
3091                                                                 WHERE sugarfavorites.deleted=0
3092                                                                         and sugarfavorites.module = \''.$module_dir.'\'
3093                                                                         and sugarfavorites.assigned_user_id = \'{0}\'',
3094                                         'db_field'=>array('id')
3095                                 );
3096
3097                                 if(!is_dir("custom/{$full_module_dir}/metadata")){
3098                                         mkdir_recursive("custom/{$full_module_dir}/metadata");
3099                                 }
3100                                 $success_sf1 = write_array_to_file('searchdefs', $searchdefs, "custom/{$full_module_dir}/metadata/searchdefs.php");
3101                                 $success_sf2 = write_array_to_file('searchFields', $searchFields, "{$full_module_dir}/metadata/SearchFields.php");
3102
3103                                 if(!$success_sf1){
3104                                         logThis("add_custom_modules_favorites_search failed for searchdefs.php for {$module_dir}");
3105                                 }
3106                                 if(!$success_sf2){
3107                                         logThis("add_custom_modules_favorites_search failed for SearchFields.php for {$module_dir}");
3108                                 }
3109                                 if($success_sf1 && $success_sf2){
3110                                         logThis("add_custom_modules_favorites_search successfully updated searchdefs and searchFields for {$module_dir}");
3111                                 }
3112                         }
3113                 }
3114         }
3115 }
3116
3117
3118 /**
3119  * upgradeModulesForTeamsets
3120  *
3121  * This method adds the team_set_id values to the module tables that have the new team_set_id column
3122  * added through the SugarCRM 5.5.x upgrade process.  It also adds the values into the team_sets and
3123  * team_sets_teams tables.
3124  *
3125  * @param filter Array of modules to process; empty by default
3126  */
3127 function upgradeModulesForTeamsets($filter=array()) {
3128     require('include/modules.php');
3129         foreach($beanList as $moduleName=>$beanName) {
3130                     if(!empty($filter) && array_search($moduleName, $filter) === false) {
3131                        continue;
3132                     }
3133                 if($moduleName == 'TeamMemberships' || $moduleName == 'ForecastOpportunities'){
3134                 continue;
3135             }
3136                         $bean = loadBean($moduleName);
3137                         if(empty($bean) ||
3138                            empty($bean->table_name)) {
3139                            continue;
3140                         }
3141
3142                         $FieldArray = $GLOBALS['db']->helper->get_columns($bean->table_name);
3143                         if(!isset($FieldArray['team_id'])) {
3144                            continue;
3145                         }
3146
3147                         upgradeTeamColumn($bean, 'team_id');
3148
3149         } //foreach
3150
3151     //Upgrade users table
3152         $bean = loadBean('Users');
3153         upgradeTeamColumn($bean, 'default_team');
3154         $result = $GLOBALS['db']->query("SELECT id FROM teams where deleted=0");
3155         while($row = $GLOBALS['db']->fetchByAssoc($result)) {
3156               $teamset = new TeamSet();
3157               $teamset->addTeams($row['id']);
3158         }
3159 }
3160
3161
3162 /**
3163  * upgradeTeamColumn
3164  * Helper function to create a team_set_id column and also set team_set_id column
3165  * to have the value of the $column_name parameter
3166  *
3167  * @param $bean SugarBean which we are adding team_set_id column to
3168  * @param $column_name The name of the column containing the default team_set_id value
3169  */
3170 function upgradeTeamColumn($bean, $column_name) {
3171         //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
3172         //module that does not use the SugarObjects
3173         if(empty($bean->field_defs['team_set_id']) && $bean->module_dir != 'Trackers'){
3174
3175                 //at this point we could assume that since we have a team_id defined and not a team_set_id that we need to
3176                 //add that field and the corresponding relationships
3177                 $object = $bean->object_name;
3178                 $module = $bean->module_dir;
3179                 $object_name = $object;
3180                 $_object_name = strtolower($object_name);
3181
3182                 if(!empty($GLOBALS['dictionary'][$object]['table'])){
3183                         $table_name = $GLOBALS['dictionary'][$object]['table'];
3184                 }else{
3185                         $table_name = strtolower($module);
3186                 }
3187
3188                 $path = 'include/SugarObjects/implements/team_security/vardefs.php';
3189                 require($path);
3190                 //go through each entry in the vardefs from team_security and unset anything that is already set in the core module
3191                 //this will ensure we have the proper ordering.
3192                 $fieldDiff = array_diff_assoc($vardefs['fields'], $GLOBALS['dictionary'][$bean->object_name]['fields']);
3193
3194                 $file = 'custom/Extension/modules/' . $bean->module_dir. '/Ext/Vardefs/teams.php';
3195                 $contents = "<?php\n";
3196                 if(!empty($fieldDiff)){
3197                         foreach($fieldDiff as $key => $val){
3198                                 $contents .= "\n\$GLOBALS['dictionary']['". $object . "']['fields']['". $key . "']=" . var_export_helper($val) . ";";
3199                         }
3200                 }
3201                 $relationshipDiff = array_diff_assoc($vardefs['relationships'], $GLOBALS['dictionary'][$bean->object_name]['relationships']);
3202                 if(!empty($relationshipDiff)){
3203                         foreach($relationshipDiff as $key => $val){
3204                                 $contents .= "\n\$GLOBALS['dictionary']['". $object . "']['relationships']['". $key . "']=" . var_export_helper($val) . ";";
3205                         }
3206                 }
3207                 $indexDiff = array_diff_assoc($vardefs['indices'], $GLOBALS['dictionary'][$bean->object_name]['indices']);
3208                 if(!empty($indexDiff)){
3209                         foreach($indexDiff as $key => $val){
3210                                         $contents .= "\n\$GLOBALS['dictionary']['". $object . "']['indices']['". $key . "']=" . var_export_helper($val) . ";";
3211                         }
3212                 }
3213                 if( $fh = @sugar_fopen( $file, 'wt' ) )
3214             {
3215                 fputs( $fh, $contents);
3216                 fclose( $fh );
3217             }
3218
3219
3220                 //we have written out the teams.php into custom/Extension/modules/{$module_dir}/Ext/Vardefs/teams.php'
3221                 //now let's merge back into vardefs.ext.php
3222                 require_once('ModuleInstall/ModuleInstaller.php');
3223                 $mi = new ModuleInstaller();
3224                 $mi->merge_files('Ext/Vardefs/', 'vardefs.ext.php');
3225                 VardefManager::loadVardef($bean->module_dir, $bean->object_name, true);
3226                 $bean->field_defs = $GLOBALS['dictionary'][$bean->object_name]['fields'];
3227         }
3228
3229         if(isset($bean->field_defs['team_set_id'])) {
3230                 //Create the team_set_id column
3231                 $FieldArray = $GLOBALS['db']->helper->get_columns($bean->table_name);
3232                 if(!isset($FieldArray['team_set_id'])) {
3233                         $GLOBALS['db']->addColumn($bean->table_name, $bean->field_defs['team_set_id']);
3234                 }
3235                 $indexArray =  $GLOBALS['db']->helper->get_indices($bean->table_name);
3236
3237         $indexName = getValidDBName('idx_'.strtolower($bean->table_name).'_tmst_id', true, 34);
3238         $indexDef = array(
3239                                          array(
3240                                                 'name' => $indexName,
3241                                                 'type' => 'index',
3242                                                 'fields' => array('team_set_id')
3243                                          )
3244                                    );
3245                 if(!isset($indexArray[$indexName])) {
3246                         $GLOBALS['db']->addIndexes($bean->table_name, $indexDef);
3247                 }
3248
3249                 //Update the table's team_set_id column to have the same values as team_id
3250             $GLOBALS['db']->query("UPDATE {$bean->table_name} SET team_set_id = {$column_name}");
3251         }
3252 }
3253
3254 /**
3255  *  Update the folder subscription table which confirms to the team security mechanism but
3256  *  the class SugarFolders does not extend SugarBean and is therefore never picked up by the
3257  *  upgradeModulesForTeamsets function.
3258  */
3259 function upgradeFolderSubscriptionsTeamSetId()
3260 {
3261     logThis("In upgradeFolderSubscriptionsTeamSetId()");
3262     $query = "UPDATE folders SET team_set_id = team_id";
3263     $result = $GLOBALS['db']->query($query);
3264     logThis("Finished upgradeFolderSubscriptionsTeamSetId()");
3265 }
3266
3267 /**
3268  * upgradeModulesForTeam
3269  *
3270  * This method update the associated_user_id, name, name_2 to the private team records on teams table
3271  * This function is used for upgrade process from 5.1.x and 5.2.x.
3272  *
3273  */
3274 function upgradeModulesForTeam() {
3275     logThis("In upgradeModulesForTeam()");
3276     $result = $GLOBALS['db']->query("SELECT id, user_name, first_name, last_name FROM users where deleted=0");
3277
3278     while($row = $GLOBALS['db']->fetchByAssoc($result)) {
3279         $results2 = $GLOBALS['db']->query("SELECT id FROM teams WHERE name = '({$row['user_name']})'");
3280         $assoc = '';
3281                 if(!$assoc = $GLOBALS['db']->fetchByAssoc($results2)) {
3282                         //if team does not exist, then lets create the team for this user
3283                         $team = new Team();
3284                         $user = new User();
3285                         $user->retrieve($row['id']);
3286                         $team->new_user_created($user);
3287                         $team_id = $team->id;
3288                 }else{
3289                         $team_id =$assoc['id'];
3290                 }
3291
3292                         //upgrade the team
3293                         $name = is_null($row['first_name'])?'':$row['first_name'];
3294                         $name_2 = is_null($row['last_name'])?'':$row['last_name'];
3295                         $associated_user_id = $row['id'];
3296
3297                         //Bug 32914
3298                         //Ensure team->name is not empty by using team->name_2 if available
3299                         if(empty($name) && !empty($name_2)) {
3300                            $name = $name_2;
3301                            $name_2 = '';
3302                         }
3303
3304                         $query = "UPDATE teams SET name = '{$name}', name_2 = '{$name_2}', associated_user_id = '{$associated_user_id}' WHERE id = '{$team_id}'";
3305                         $GLOBALS['db']->query($query);
3306     } //while
3307
3308     //Update the team_set_id and default_team columns
3309     $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'));
3310
3311     //Update team_set_id
3312         if($ce_to_pro_or_ent) {
3313            $GLOBALS['db']->query("update users set team_set_id = (select teams.id from teams where teams.associated_user_id = users.id)");
3314            $GLOBALS['db']->query("update users set default_team = (select teams.id from teams where teams.associated_user_id = users.id)");
3315         }
3316
3317 }
3318
3319
3320     function addNewSystemTabsFromUpgrade($from_dir){
3321         global $path;
3322         if(isset($_SESSION['upgrade_from_flavor'])){
3323
3324             //check to see if there are any new files that need to be added to systems tab
3325             //retrieve old modules list
3326             logThis('check to see if new modules exist',$path);
3327             $oldModuleList = array();
3328             $newModuleList = array();
3329             include($from_dir.'/include/modules.php');
3330             $oldModuleList = $moduleList;
3331             include('include/modules.php');
3332             $newModuleList = $moduleList;
3333
3334             //include tab controller
3335             require_once('modules/MySettings/TabController.php');
3336             $newTB = new TabController();
3337
3338             //make sure new modules list has a key we can reference directly
3339             $newModuleList = $newTB->get_key_array($newModuleList);
3340             $oldModuleList = $newTB->get_key_array($oldModuleList);
3341
3342             //iterate through list and remove commonalities to get new modules
3343             foreach ($newModuleList as $remove_mod){
3344                 if(in_array($remove_mod, $oldModuleList)){
3345                     unset($newModuleList[$remove_mod]);
3346                 }
3347             }
3348             //new modules list now has left over modules which are new to this install, so lets add them to the system tabs
3349             logThis('new modules to add are '.var_export($newModuleList,true),$path);
3350
3351             if(!empty($newModuleList))
3352             {
3353                     //grab the existing system tabs
3354                     $tabs = $newTB->get_system_tabs();
3355
3356                     //add the new tabs to the array
3357                     foreach($newModuleList as $nm ){
3358                       $tabs[$nm] = $nm;
3359                     }
3360
3361                     $newTB->set_system_tabs($tabs);
3362             }
3363             logThis('module tabs updated',$path);
3364         }
3365     }
3366
3367     /**
3368      * fix_dropdown_list
3369      * This method attempts to fix dropdown lists that were incorrectly named.
3370      * There were versions of SugarCRM that did not enforce naming convention rules
3371      * for the dropdown list field name.  This method attempts to resolve that by
3372      * fixing the language files that may have been affected and then updating the
3373      * fields_meta_data table accordingly.  It also refreshes any vardefs that may
3374      * have been affected.
3375      *
3376      */
3377         function fix_dropdown_list() {
3378         if(file_exists('custom/include/language')) {
3379            $files = array();
3380            $affected_modules = array();
3381            $affected_keys = array();
3382
3383            getFiles($files, 'custom/include/language', '/\.php$/i');
3384            foreach($files as $file) {
3385
3386               if(file_exists($file . '.bak')) {
3387                  $bak_mod_time = filemtime($file . '.bak');
3388                  $php_mod_time = filemtime($file);
3389                  //We're saying if the .php file was modified 30 seconds no more than php.bak file then we
3390                  //run these additional cleanup checks
3391                  if($php_mod_time - $bak_mod_time < 30) {
3392
3393                         $app_list_strings = array();
3394                         $GLOBALS['app_list_strings'] = array();
3395                         require($file . '.bak');
3396                         $bak_app_list_strings = array_merge($app_list_strings, $GLOBALS['app_list_strings']);
3397
3398                         $app_list_strings = array();
3399                         $GLOBALS['app_list_strings'] = array();
3400                         require($file);
3401                         $php_app_list_strings = array_merge($app_list_strings, $GLOBALS['app_list_strings']);
3402
3403                         //Get the file contents
3404                         $contents = file_get_contents($file);
3405
3406                         //Now simulate a fix for the file before we compare w/ the .php file
3407                         //we also append to the $contents
3408                         foreach($bak_app_list_strings as $key=>$entry) {
3409                                                    if(preg_match('/([^A-Za-z_])/', $key, $matches) && is_array($entry)) {
3410                                                           $new_key = preg_replace('/[^A-Za-z_]/', '_', $key);
3411                                                           $bak_app_list_strings[$new_key] = $bak_app_list_strings[$key];
3412                                                           unset($bak_app_list_strings[$key]);
3413                                                           //Now if the entry doesn't exists in the .php file, then add to contents
3414                                                           if(!isset($php_app_list_strings[$new_key])) {
3415                                                                  $contents .= "\n\$GLOBALS['app_list_strings']['{$new_key}'] = " . var_export_helper($bak_app_list_strings[$new_key]) . ";";
3416                                                           }
3417                                                    } //if
3418                         } //foreach
3419
3420                         //Now load the .php file to do the comparison
3421                         foreach($php_app_list_strings as $key=>$entry) {
3422                                 if(isset($bak_app_list_strings[$key])) {
3423                                         $diff = array_diff($bak_app_list_strings[$key], $entry);
3424                                         if(!empty($diff)) {
3425                                            //There is a difference, so copy the $bak_app_list_strings version into the .php file
3426                                            $contents .= "\n\$GLOBALS['app_list_strings']['{$key}'] = " . var_export_helper($bak_app_list_strings[$key]) . ";";
3427                                         } //if
3428                                 } //if
3429                         } //foreach
3430
3431                         //Now write out the file contents
3432                         //Create backup just in case
3433                         copy($file, $file . '.php_bak');
3434                                         $fp = @sugar_fopen($file, 'w');
3435                         if($fp) {
3436                                fwrite($fp, $contents);
3437                                fclose($fp);
3438                         } else {
3439                            $GLOBALS['log']->error("Unable to update file contents in fix_dropdown_list for {$file}");
3440                         } //if-else
3441                  }
3442               }
3443
3444               unset($GLOBALS['app_strings']);
3445               unset($GLOBALS['app_list_strings']);
3446               $app_list_strings = array();
3447                   require($file);
3448                   $touched = false;
3449                   $contents = file_get_contents($file);
3450                   if ( !isset($GLOBALS['app_list_strings']) ) {
3451                       $GLOBALS['app_list_strings'] = $app_list_strings;
3452                   }
3453                   else {
3454                       $GLOBALS['app_list_strings'] = array_merge($app_list_strings, $GLOBALS['app_list_strings']);
3455                   }
3456
3457                   if(isset($GLOBALS['app_list_strings']) && is_array($GLOBALS['app_list_strings'])) {
3458                          foreach($GLOBALS['app_list_strings'] as $key=>$entry) {
3459                                 if(preg_match('/([^A-Za-z_])/', $key, $matches) && is_array($entry)) {
3460                                    $result = $GLOBALS['db']->query("SELECT custom_module FROM fields_meta_data WHERE ext1 = '{$key}'");
3461                                    if(!empty($result)) {
3462                                           while($row = $GLOBALS['db']->fetchByAssoc($result)) {
3463                                                     $custom_module = $row['custom_module'];
3464                                                     if(!empty($GLOBALS['beanList'][$custom_module])) {
3465                                                    $affected_modules[$custom_module] = $GLOBALS['beanList'][$custom_module];
3466                                                     }
3467                                           } //while
3468                                    }
3469
3470                                    //Replace all invalid characters with '_' character
3471                                    $new_key = preg_replace('/[^A-Za-z_]/', '_', $key);
3472                                    $affected_keys[$key] = $new_key;
3473
3474                                    $GLOBALS['app_list_strings'][$new_key] = $GLOBALS['app_list_strings'][$key];
3475                                    unset($GLOBALS['app_list_strings'][$key]);
3476
3477                                    $pattern_match = "/(\[\s*\'{$key}\'\s*\])/";
3478                                    $new_key = "['{$new_key}']";
3479                                    $out = preg_replace($pattern_match, $new_key, $contents);
3480                                    $contents = $out;
3481                                    $touched = true;
3482                                 } //if
3483                          } //foreach
3484
3485                  //This is a check for g => h instances where the file contents were incorrectly written
3486                  //and also fixes the scenario where via a UI upgrade, the app_list_strings were incorrectly
3487                  //merged with app_list_strings variables declared elsewhere
3488                          if(!$touched) {
3489                                    if(preg_match('/\$GLOBALS\s*\[\s*[\"|\']app_list_strings[\"|\']\s*\]\s*=\s*array\s*\(/', $contents)) {
3490                                           //Now also remove all the non-custom labels that were added
3491                                           if(preg_match('/language\/([^\.]+)\.lang\.php$/', $file, $matches)) {
3492                                                 $language = $matches[1];
3493
3494                                                 $app_list_strings = array();
3495
3496                                         if(file_exists("include/language/$language.lang.php")) {
3497                                                                    include("include/language/$language.lang.php");
3498                                                                 }
3499                                                                 if(file_exists("include/language/$language.lang.override.php")) {
3500                                                                    $app_list_strings =  _mergeCustomAppListStrings("include/language/$language.lang.override.php" , $app_list_strings) ;
3501                                                                 }
3502                                                                 if(file_exists("custom/application/Ext/Language/$language.ext.lang.php")) {
3503                                                                    $app_list_strings =  _mergeCustomAppListStrings("custom/application/Ext/Language/$language.ext.lang.php" , $app_list_strings) ;
3504                                                                 }
3505                                                                 if(file_exists("custom/application/Ext/Language/$language.lang.ext.php")) {
3506                                                                    $app_list_strings =  _mergeCustomAppListStrings("custom/application/Ext/Language/$language.lang.ext.php" , $app_list_strings) ;
3507                                                                 }
3508
3509                                                                 $all_non_custom_include_language_strings = $app_strings;
3510                                                                 $all_non_custom_include_language_list_strings = $app_list_strings;
3511
3512                                                                 $unset_keys = array();
3513                                                                 if(!empty($GLOBALS['app_list_strings'])) {
3514                                                                         foreach($GLOBALS['app_list_strings'] as $key=>$value) {
3515                                                                                 $diff = array();
3516                                                                                 if(isset($all_non_custom_include_language_list_strings[$key])) {
3517                                                                                         $diff = array_diff($all_non_custom_include_language_list_strings[$key], $GLOBALS['app_list_strings'][$key]);
3518                                                                                 }
3519
3520                                                                                 if(!empty($all_non_custom_include_language_list_strings[$key]) && empty($diff)) {
3521                                                                                         $unset_keys[] = $key;
3522                                                                                 }
3523                                                                         }
3524                                                                 }
3525
3526                                                                 foreach($unset_keys as $key) {
3527                                                                         unset($GLOBALS['app_list_strings'][$key]);
3528                                                                 }
3529
3530                                                                 if(!empty($GLOBALS['app_strings'])) {
3531                                                                 foreach($GLOBALS['app_strings'] as $key=>$value) {
3532                                                                                 if(!empty($all_non_custom_include_language_strings[$key])) {
3533                                                                                    unset($GLOBALS['app_strings'][$key]);
3534                                                                                 }
3535                                                                 }
3536                                                                 }
3537                                           } //if(preg_match...)
3538
3539                                       $out = "<?php \n";
3540                                       if(!empty($GLOBALS['app_strings'])) {
3541                                              foreach($GLOBALS['app_strings'] as $key=>$entry) {
3542                                                      $out .= "\n\$GLOBALS['app_strings']['$key']=" . var_export_helper($entry) . ";";
3543                                              }
3544                                       }
3545
3546                                                   foreach($GLOBALS['app_list_strings'] as $key=>$entry) {
3547                                                                   $out .= "\n\$GLOBALS['app_list_strings']['$key']=" . var_export_helper($entry) . ";";
3548                                                   } //foreach
3549
3550                                                   $touched = true;
3551                                    } //if(preg_match...)
3552                          } //if(!$touched)
3553
3554                          if($touched) {
3555                                  //Create a backup just in case
3556                                  copy($file, $file . '.bak');
3557                          $fp = @sugar_fopen($file, 'w');
3558                          if($fp) {
3559                                fwrite($fp, $out);
3560                                fclose($fp);
3561                          } else {
3562                            //If we can't update the file, just return
3563                            $GLOBALS['log']->error("Unable to update file contents in fix_dropdown_list.");
3564                            return;
3565                          }
3566                          } //if($touched)
3567                   } //if
3568
3569            } //foreach($files)
3570
3571            //Update db entries (the order matters here... need to process database changes first)
3572            if(!empty($affected_keys)) {
3573                   foreach($affected_keys as $old_key=>$new_key) {
3574                                   $GLOBALS['db']->query("UPDATE fields_meta_data SET ext1 = '{$new_key}' WHERE ext1 = '{$old_key}'");
3575                   }
3576            }
3577
3578            //Update vardef files for affected modules
3579            if(!empty($affected_modules)) {
3580                   foreach($affected_modules as $module=>$object) {
3581                           VardefManager::refreshVardefs($module, $object);
3582                   }
3583            }
3584         }
3585         }
3586
3587
3588         function update_iframe_dashlets(){
3589                 require_once(sugar_cached('dashlets/dashlets.php'));
3590
3591                 $db = DBManagerFactory::getInstance();
3592                 $query = "SELECT id, contents, assigned_user_id FROM user_preferences WHERE deleted = 0 AND category = 'Home'";
3593                 $result = $db->query($query, true, "Unable to update new default dashlets! ");
3594                 while ($row = $db->fetchByAssoc($result)) {
3595                         $content = unserialize(base64_decode($row['contents']));
3596                         $assigned_user_id = $row['assigned_user_id'];
3597                         $record_id = $row['id'];
3598
3599                         $current_user = new User();
3600                         $current_user->retrieve($row['assigned_user_id']);
3601
3602                         if(!empty($content['dashlets']) && !empty($content['pages'])){
3603                                 $originalDashlets = $content['dashlets'];
3604                                 foreach($originalDashlets as $key => $ds){
3605                                     if(!empty($ds['options']['url']) && stristr($ds['options']['url'],'http://www.sugarcrm.com/crm/product/gopro')){
3606                                                 unset($originalDashlets[$key]);
3607                                         }
3608                                 }
3609                                 $current_user->setPreference('dashlets', $originalDashlets, 0, 'Home');
3610                         }
3611                 }
3612         }
3613
3614
3615     /**
3616      * convertImageToText
3617      * @deprecated
3618      * This method attempts to convert date type image to text on Microsoft SQL Server.
3619      * This method could NOT be used in any other type of datebases.
3620      */
3621         function convertImageToText($table_name,$column_name){
3622                 $set_lang = "SET LANGUAGE us_english";
3623                 $GLOBALS['db']->query($set_lang);
3624             if($GLOBALS['db']->lastError()){
3625             logThis('An error occurred when performing this query-->'.$set_lang);
3626         }
3627        $q="SELECT data_type
3628         FROM INFORMATION_SCHEMA.Tables T JOIN INFORMATION_SCHEMA.Columns C
3629         ON T.TABLE_NAME = C.TABLE_NAME where T.TABLE_NAME = '$table_name' and C.COLUMN_NAME = '$column_name'";
3630        $res= $GLOBALS['db']->query($q);
3631        if($GLOBALS['db']->lastError()){
3632             logThis('An error occurred when performing this query-->'.$q);
3633         }
3634        $row= $GLOBALS['db']->fetchByAssoc($res);
3635
3636      if(trim(strtolower($row['data_type'])) == 'image'){
3637         $addContent_temp = "alter table {$table_name} add {$column_name}_temp text null";
3638         $GLOBALS['db']->query($addContent_temp);
3639         if($GLOBALS['db']->lastError()){
3640             logThis('An error occurred when performing this query-->'.$addContent_temp);
3641         }
3642         $qN = "select count=datalength({$column_name}), id, {$column_name} from {$table_name}";
3643         $result = $GLOBALS['db']->query($qN);
3644         while($row = $GLOBALS['db']->fetchByAssoc($result)){
3645            if($row['count'] >8000){
3646                 $contentLength = $row['count'];
3647                 $start = 1;
3648                 $next=8000;
3649                 $convertedContent = '';
3650                 while($contentLength >0){
3651                     $stepsQuery = "select cont=convert(varchar(max), convert(varbinary(8000), substring({$column_name},{$start},{$next}))) from {$table_name} where id= '{$row['id']}'";
3652                     $steContQ = $GLOBALS['db']->query($stepsQuery);
3653                     if($GLOBALS['db']->lastError()){
3654                         logThis('An error occurred when performing this query-->'.$stepsQuery);
3655                     }
3656                     $stepCont = $GLOBALS['db']->fetchByAssoc($steContQ);
3657                     if(isset($stepCont['cont'])){
3658                         $convertedContent = $convertedContent.$stepCont['cont'];
3659                     }
3660                     $start = $start+$next;
3661                     $contentLength = $contentLength - $next;
3662                 }
3663                 $addContentDataText="update {$table_name} set {$column_name}_temp = '{$convertedContent}' where id= '{$row['id']}'";
3664                 $GLOBALS['db']->query($addContentDataText);
3665                 if($GLOBALS['db']->lastError()){
3666                     logThis('An error occurred when performing this query-->'.$addContentDataText);
3667                 }
3668            }
3669            else{
3670                 $addContentDataText="update {$table_name} set {$column_name}_temp =
3671                 convert(varchar(max), convert(varbinary(8000), {$column_name})) where id= '{$row['id']}'";
3672                 $GLOBALS['db']->query($addContentDataText);
3673                 if($GLOBALS['db']->lastError()){
3674                     logThis('An error occurred when performing this query-->'.$addContentDataText);
3675                 }
3676            }
3677         }
3678         //drop the contents now and change contents_temp to contents
3679         $dropColumn = "alter table {$table_name} drop column {$column_name}";
3680         $GLOBALS['db']->query($dropColumn);
3681         if($GLOBALS['db']->lastError()){
3682             logThis('An error occurred when performing this query-->'.$dropColumn);
3683         }
3684         $changeColumnName = "EXEC sp_rename '{$table_name}.[{$column_name}_temp]','{$column_name}','COLUMN'";
3685         $GLOBALS['db']->query($changeColumnName);
3686         if($GLOBALS['db']->lastError()){
3687             logThis('An error occurred when performing this query-->'.$changeColumnName);
3688         }
3689      }
3690     }
3691
3692          /**
3693      * clearHelpFiles
3694      * This method attempts to delete all English inline help files.
3695      * This method was introduced by 5.5.0RC2.
3696      */
3697     function clearHelpFiles(){
3698                 $modulePath = clean_path(getcwd() . '/modules');
3699                 $allHelpFiles = array();
3700                 getFiles($allHelpFiles, $modulePath, "/en_us.help.*/");
3701
3702                 foreach( $allHelpFiles as $the_file ){
3703                 if( is_file( $the_file ) ){
3704                     unlink( $the_file );
3705                     logThis("Deleted file: $the_file");
3706                 }
3707             }
3708         }
3709
3710
3711
3712         /**
3713          * upgradeDateTimeFields
3714          *
3715          * This method came from bug: 39757 where the date_end field is a date field and not a datetime field
3716          * which prevents you from performing timezone offset calculations once the data has been saved.
3717          *
3718          * @param path String location to log file, empty by default
3719          */
3720         function upgradeDateTimeFields($path)
3721         {
3722                 //bug: 39757
3723                 global $db;
3724                 $meetingsSql = "UPDATE meetings SET date_end = ".$db->convert("date_start", 'add_time', array('duration_hours', 'duration_minutes'));
3725                 $callsSql = "UPDATE calls SET date_end = ".$db->convert("date_start", 'add_time', array('duration_hours', 'duration_minutes'));
3726         logThis('upgradeDateTimeFields Meetings SQL:' . $meetingsSql, $path);
3727                 $db->query($meetingsSql);
3728
3729                 logThis('upgradeDateTimeFields Calls SQL:' . $callsSql, $path);
3730                 $db->query($callsSql);
3731         }
3732
3733         /**
3734          * upgradeDocumentTypeFields
3735          *
3736          */
3737         function upgradeDocumentTypeFields($path){
3738                 //bug: 39757
3739                 global $db;
3740
3741                 $documentsSql = "UPDATE documents SET doc_type = 'Sugar' WHERE doc_type IS NULL";
3742                 $meetingsSql = "UPDATE meetings SET type = 'Sugar' WHERE type IS NULL";
3743
3744                 logThis('upgradeDocumentTypeFields Documents SQL:' . $documentsSql, $path);
3745                 $db->query($documentsSql);
3746                 logThis('upgradeDocumentTypeFields Meetings SQL:' . $meetingsSql, $path);
3747                 $db->query($meetingsSql);
3748         }
3749
3750
3751 /**
3752  * merge_config_si_settings
3753  * This method checks for the presence of a config_si.php file and, if found, merges the configuration
3754  * settings from the config_si.php file into config.php.  If a config_si_location parameter value is not
3755  * supplied it will attempt to discover the config_si.php file location from where the executing script
3756  * was invoked.
3757  *
3758  * @param write_to_upgrade_log boolean optional value to write to the upgradeWizard.log file
3759  * @param config_location String optional value to config.php file location
3760  * @param config_si_location String optional value to config_si.php file location
3761  * @param path String file of the location of log file to write to
3762  * @return boolean value indicating whether or not a merge was attempted with config_si.php file
3763  */
3764 function merge_config_si_settings($write_to_upgrade_log=false, $config_location='', $config_si_location='', $path='')
3765 {
3766         if(!empty($config_location) && !file_exists($config_location))
3767         {
3768                 if($write_to_upgrade_log)
3769                 {
3770                logThis('config.php file specified in ' . $config_si_location . ' could not be found.  Skip merging', $path);
3771                 }
3772             return false;
3773         } else if(empty($config_location)) {
3774                 global $argv;
3775                 //We are assuming this is from the silentUpgrade scripts so argv[3] will point to SugarCRM install location
3776                 if(isset($argv[3]) && is_dir($argv[3]))
3777                 {
3778                         $config_location = $argv[3] . DIRECTORY_SEPARATOR . 'config.php';
3779                 }
3780         }
3781
3782         //If config_location is still empty or if the file cannot be found, skip merging
3783         if(empty($config_location) || !file_exists($config_location))
3784         {
3785            if($write_to_upgrade_log)
3786            {
3787                   logThis('config.php file at (' . $config_location . ') could not be found.  Skip merging.', $path);
3788            }
3789            return false;
3790         } else {
3791            if($write_to_upgrade_log)
3792            {
3793               logThis('Loading config.php file at (' . $config_location . ') for merging.', $path);
3794            }
3795
3796            include($config_location);
3797            if(empty($sugar_config))
3798            {
3799                   if($write_to_upgrade_log)
3800                   {
3801                      logThis('config.php contents are empty.  Skip merging.', $path);
3802                   }
3803                   return false;
3804            }
3805         }
3806
3807         if(!empty($config_si_location) && !file_exists($config_si_location))
3808         {
3809                 if($write_to_upgrade_log)
3810                 {
3811                logThis('config_si.php file specified in ' . $config_si_location . ' could not be found.  Skip merging', $path);
3812                 }
3813             return false;
3814         } else if(empty($config_si_location)) {
3815                 if(isset($argv[0]) && is_file($argv[0]))
3816                 {
3817                         $php_file = $argv[0];
3818                         $p_info = pathinfo($php_file);
3819                         $php_dir = (isset($p_info['dirname']) && $p_info['dirname'] != '.') ?  $p_info['dirname'] . DIRECTORY_SEPARATOR : '';
3820                         $config_si_location = $php_dir . 'config_si.php';
3821                 }
3822         }
3823
3824         //If config_si_location is still empty or if the file cannot be found, skip merging
3825         if(empty($config_si_location) || !file_exists($config_si_location))
3826         {
3827            if($write_to_upgrade_log)
3828            {
3829               logThis('config_si.php file at (' . $config_si_location . ') could not be found.  Skip merging.', $path);
3830            }
3831            return false;
3832         } else {
3833            if($write_to_upgrade_log)
3834            {
3835               logThis('Loading config_si.php file at (' . $config_si_location . ') for merging.', $path);
3836            }
3837
3838            include($config_si_location);
3839            if(empty($sugar_config_si))
3840            {
3841               if($write_to_upgrade_log)
3842                   {
3843                      logThis('config_si.php contents are empty.  Skip merging.', $path);
3844                   }
3845                   return false;
3846            }
3847         }
3848
3849         //Now perform the merge operation
3850         $modified = false;
3851         foreach($sugar_config_si as $key=>$value)
3852         {
3853                 if(!preg_match('/^setup_/', $key) && !isset($sugar_config[$key]))
3854                 {
3855                    if($write_to_upgrade_log)
3856                    {
3857                       logThis('Merge key (' . $key . ') with value (' . $value . ')', $path);
3858                    }
3859                    $sugar_config[$key] = $value;
3860                    $modified = true;
3861                 }
3862         }
3863
3864         if($modified)
3865         {
3866                 if($write_to_upgrade_log)
3867                 {
3868                logThis('Update config.php file with new values', $path);
3869                 }
3870
3871             if(!write_array_to_file("sugar_config", $sugar_config, $config_location)) {
3872                if($write_to_upgrade_log)
3873                    {
3874                   logThis('*** ERROR: could not write to config.php', $path);
3875                    }
3876                    return false;
3877                 }
3878         } else {
3879            if($write_to_upgrade_log)
3880            {
3881               logThis('config.php values are in sync with config_si.php values.  Skipped merging.');
3882            }
3883            return false;
3884         }
3885
3886         if($write_to_upgrade_log)
3887         {
3888            logThis('End merge_config_si_settings', $path);
3889         }
3890         return true;
3891 }
3892
3893
3894 /**
3895  * upgrade_connectors
3896  *
3897  * This function handles support for upgrading connectors it is invoked from both end.php and silentUpgrade_step2.php
3898  *
3899  */
3900 function upgrade_connectors() {
3901     require_once('include/connectors/utils/ConnectorUtils.php');
3902     if(!ConnectorUtils::updateMetaDataFiles()) {
3903        $GLOBALS['log']->fatal('Cannot update metadata files for connectors');
3904     }
3905
3906     //Delete the custom connectors.php file if it exists so that it may be properly rebuilt
3907     if(file_exists('custom/modules/Connectors/metadata/connectors.php'))
3908     {
3909         unlink('custom/modules/Connectors/metadata/connectors.php');
3910     }
3911 }
3912
3913 /**
3914  * Enable the InsideView connector for the four default modules.
3915  */
3916 function upgradeEnableInsideViewConnector($path='')
3917 {
3918     logThis('Begin upgradeEnableInsideViewConnector', $path);
3919
3920     // Load up the existing mapping and hand it to the InsideView connector to have it setup the correct logic hooks
3921     $mapFile = 'modules/Connectors/connectors/sources/ext/rest/insideview/mapping.php';
3922     if ( file_exists('custom/'.$mapFile) ) {
3923         logThis('Found CUSTOM mappings', $path);
3924         require('custom/'.$mapFile);
3925     } else {
3926         logThis('Used default mapping', $path);
3927         require($mapFile);
3928     }
3929
3930     require_once('include/connectors/sources/SourceFactory.php');
3931     $source = SourceFactory::getSource('ext_rest_insideview');
3932
3933     // $mapping is brought in from the mapping.php file above
3934     $source->saveMappingHook($mapping);
3935
3936     require_once('include/connectors/utils/ConnectorUtils.php');
3937     ConnectorUtils::installSource('ext_rest_insideview');
3938
3939     // Now time to set the various modules to active, because this part ignores the default config
3940     require(CONNECTOR_DISPLAY_CONFIG_FILE);
3941     // $modules_sources come from that config file
3942     foreach ( $source->allowedModuleList as $module ) {
3943         $modules_sources[$module]['ext_rest_insideview'] = 'ext_rest_insideview';
3944     }
3945     if(!write_array_to_file('modules_sources', $modules_sources, CONNECTOR_DISPLAY_CONFIG_FILE)) {
3946         //Log error and return empty array
3947         logThis("Cannot write \$modules_sources to " . CONNECTOR_DISPLAY_CONFIG_FILE,$path);
3948     }
3949
3950     logThis('End upgradeEnableInsideViewConnector', $path);
3951
3952 }
3953
3954 function repair_long_relationship_names($path='')
3955 {
3956     logThis("Begin repair_long_relationship_names", $path);
3957     require_once 'modules/ModuleBuilder/parsers/relationships/DeployedRelationships.php' ;
3958     $GLOBALS['mi_remove_tables'] = false;
3959     $touched = array();
3960     foreach($GLOBALS['moduleList'] as $module)
3961     {
3962         $relationships = new DeployedRelationships ($module) ;
3963         foreach($relationships->getRelationshipList() as $rel_name)
3964         {
3965             if (strlen($rel_name) > 27 && empty($touched[$rel_name]))
3966             {
3967                 logThis("Rebuilding relationship fields for $rel_name", $path);
3968                 $touched[$rel_name] = true;
3969                 $rel_obj = $relationships->get($rel_name);
3970                 $rel_obj->setReadonly(false);
3971                 $relationships->delete($rel_name);
3972                 $relationships->save();
3973                 $relationships->add($rel_obj);
3974                 $relationships->save();
3975                 $relationships->build () ;
3976             }
3977         }
3978     }
3979     logThis("End repair_long_relationship_names", $path);
3980 }
3981
3982 function removeSilentUpgradeVarsCache(){
3983     global $silent_upgrade_vars_loaded;
3984
3985     $cacheFileDir = "{$GLOBALS['sugar_config']['cache_dir']}/silentUpgrader";
3986     $cacheFile = "{$cacheFileDir}/silentUpgradeCache.php";
3987
3988     if(file_exists($cacheFile)){
3989         unlink($cacheFile);
3990     }
3991
3992     $silent_upgrade_vars_loaded = array(); // Set to empty to reset it
3993
3994     return true;
3995 }
3996
3997 function loadSilentUpgradeVars(){
3998     global $silent_upgrade_vars_loaded;
3999
4000     if(empty($silent_upgrade_vars_loaded)){
4001         $cacheFile = "{$GLOBALS['sugar_config']['cache_dir']}/silentUpgrader/silentUpgradeCache.php";
4002         // We have no pre existing vars
4003         if(!file_exists($cacheFile)){
4004             // Set the vars array so it's loaded
4005             $silent_upgrade_vars_loaded = array('vars' => array());
4006         }
4007         else{
4008             require_once($cacheFile);
4009             $silent_upgrade_vars_loaded = $silent_upgrade_vars_cache;
4010         }
4011     }
4012
4013     return true;
4014 }
4015
4016 function writeSilentUpgradeVars(){
4017     global $silent_upgrade_vars_loaded;
4018
4019     if(empty($silent_upgrade_vars_loaded)){
4020         return false; // You should have set some values before trying to write the silent upgrade vars
4021     }
4022
4023     $cacheFileDir = "{$GLOBALS['sugar_config']['cache_dir']}/silentUpgrader";
4024     $cacheFile = "{$cacheFileDir}/silentUpgradeCache.php";
4025
4026     require_once('include/dir_inc.php');
4027     if(!mkdir_recursive($cacheFileDir)){
4028         return false;
4029     }
4030     require_once('include/utils/file_utils.php');
4031     if(!write_array_to_file('silent_upgrade_vars_cache', $silent_upgrade_vars_loaded, $cacheFile, 'w')){
4032         global $path;
4033         logThis("WARNING: writeSilentUpgradeVars could not write to {$cacheFile}", $path);
4034         return false;
4035     }
4036
4037     return true;
4038 }
4039
4040 function setSilentUpgradeVar($var, $value){
4041     if(!loadSilentUpgradeVars()){
4042         return false;
4043     }
4044
4045     global $silent_upgrade_vars_loaded;
4046
4047     $silent_upgrade_vars_loaded['vars'][$var] = $value;
4048
4049     return true;
4050 }
4051
4052 function getSilentUpgradeVar($var){
4053     if(!loadSilentUpgradeVars()){
4054         return false;
4055     }
4056
4057     global $silent_upgrade_vars_loaded;
4058
4059     if(!isset($silent_upgrade_vars_loaded['vars'][$var])){
4060         return null;
4061     }
4062     else{
4063         return $silent_upgrade_vars_loaded['vars'][$var];
4064     }
4065 }
4066
4067
4068 /**
4069  * add_unified_search_to_custom_modules_vardefs
4070  *
4071  * This method calls the repair code to remove the unified_search_modules.php fiel
4072  *
4073  */
4074 function add_unified_search_to_custom_modules_vardefs()
4075 {
4076         if(file_exists($cachefile = sugar_cached('modules/unified_search_modules.php')))
4077         {
4078            unlink($cachefile);
4079         }
4080
4081 }
4082
4083 /**
4084  * change from using the older SugarCache in 6.1 and below to the new one in 6.2
4085  */
4086 function upgradeSugarCache($file)
4087 {
4088         global $sugar_config;
4089         $cacheUploadUpgradesTemp = mk_temp_dir(sugar_cached('upgrades/temp'));
4090
4091         unzip($file, $cacheUploadUpgradesTemp);
4092
4093         if(!file_exists(clean_path("{$cacheUploadUpgradesTemp}/manifest.php"))) {
4094                 logThis("*** ERROR: no manifest file detected while bootstraping upgrade wizard files!");
4095                 return;
4096         } else {
4097                 include(clean_path("{$cacheUploadUpgradesTemp}/manifest.php"));
4098         }
4099
4100         $from_dir = "{$cacheUploadUpgradesTemp}/{$manifest['copy_files']['from_dir']}";
4101         $allFiles = array();
4102         if(file_exists("$from_dir/include/SugarCache")) {
4103                 $allFiles = findAllFiles("$from_dir/include/SugarCache", $allFiles);
4104         }
4105         if(file_exists("$from_dir/include/database")) {
4106                 $allFiles = findAllFiles("$from_dir/include/database", $allFiles);
4107         }
4108         if(file_exists("$from_dir/include/utils/external_cache.php")) {
4109                 $allFiles[] = "$from_dir/include/utils/external_cache.php";
4110         }
4111         if(file_exists("$from_dir/include/utils/sugar_file_utils.php")) {
4112                 $allFiles[] = "$from_dir/include/utils/sugar_file_utils.php";
4113         }
4114         if(file_exists("$from_dir/include/utils/sugar_file_utils.php")) {
4115                 $allFiles[] = "$from_dir/include/utils/sugar_file_utils.php";
4116         }
4117
4118         foreach($allFiles as $k => $file) {
4119                 $destFile = str_replace($from_dir."/", "", $file);
4120        if(!is_dir(dirname($destFile))) {
4121                         mkdir_recursive(dirname($destFile)); // make sure the directory exists
4122                 }
4123                 if ( stristr($file,'uw_main.tpl') )
4124             logThis('Skipping "'.$file.'" - file copy will during commit step.');
4125         else {
4126             logThis('updating UpgradeWizard code: '.$destFile);
4127             copy_recursive($file, $destFile);
4128         }
4129         }
4130 }
4131
4132
4133 /**
4134  * upgradeDisplayedTabsAndSubpanels
4135  *
4136  * @param $version String value of current system version (pre upgrade)
4137  */
4138 function upgradeDisplayedTabsAndSubpanels($version)
4139 {
4140         if($version < '620')
4141         {
4142                 logThis('start upgrading system displayed tabs and subpanels');
4143             require_once('modules/MySettings/TabController.php');
4144             $tc = new TabController();
4145
4146             //grab the existing system tabs
4147             $tabs = $tc->get_tabs_system();
4148
4149             //add Calls, Meetings, Tasks, Notes, Prospects (Targets) and ProspectLists (Target Lists)
4150             //to displayed tabs unless explicitly set to hidden
4151             $modules_to_add = array('Calls', 'Meetings', 'Tasks', 'Notes', 'Prospects', 'ProspectLists');
4152             $added_tabs = array();
4153
4154             foreach($modules_to_add as $module)
4155             {
4156                        $tabs[0][$module] = $module;
4157                        $added_tabs[] = $module;
4158             }
4159
4160             logThis('calling set_system_tabs on TabController to add tabs: ' . var_export($added_tabs, true));
4161             $tc->set_system_tabs($tabs[0]);
4162             logThis('finish upgrading system displayed tabs and subpanels');
4163         }
4164 }
4165
4166
4167 /**
4168  * unlinkUpgradeFiles
4169  * This is a helper function to clean up
4170  *
4171  * @param $version String value of current system version (pre upgrade)
4172  */
4173 function unlinkUpgradeFiles($version)
4174 {
4175         if(!isset($version))
4176         {
4177            return;
4178         }
4179
4180     //First check if we even have the scripts_for_patch/files_to_remove directory
4181     require_once('modules/UpgradeWizard/UpgradeRemoval.php');
4182
4183     /*
4184     if(empty($_SESSION['unzip_dir']))
4185     {
4186         global $sugar_config;
4187         $base_upgrade_dir               = $sugar_config['upload_dir'] . "/upgrades";
4188         $base_tmp_upgrade_dir   = "$base_upgrade_dir/temp";
4189         $_SESSION['unzip_dir'] = mk_temp_dir( $base_tmp_upgrade_dir );
4190     }
4191     */
4192
4193     if(isset($_SESSION['unzip_dir']) && file_exists($_SESSION['unzip_dir'].'/scripts/files_to_remove'))
4194     {
4195        $files_to_remove = glob($_SESSION['unzip_dir'].'/scripts/files_to_remove/*.php');
4196
4197        foreach($files_to_remove as $script)
4198        {
4199                 if(preg_match('/UpgradeRemoval(\d+)x\.php/', $script, $matches))
4200                 {
4201                    $checkVersion = $matches[1] + 1; //Increment by one to check everything equal or below the target version
4202                    $upgradeClass = 'UpgradeRemoval' . $matches[1] . 'x';
4203                    require_once($_SESSION['unzip_dir'].'/scripts/files_to_remove/' . $upgradeClass . '.php');
4204
4205                    //Check to make sure we should load and run this UpgradeRemoval instance
4206                    if($checkVersion <= $version && class_exists($upgradeClass))
4207                    {
4208                           $upgradeInstance = new $upgradeClass();
4209                           if($upgradeInstance instanceof UpgradeRemoval)
4210                           {
4211                                   logThis('Running UpgradeRemoval instance ' . $upgradeClass);
4212                                   logThis('Files will be backed up to custom/backup');
4213                                   $files = $upgradeInstance->getFilesToRemove($version);
4214                                   foreach($files as $file)
4215                                   {
4216                                          logThis($file);
4217                                   }
4218                                   $upgradeInstance->processFilesToRemove($files);
4219                           }
4220                    }
4221             }
4222        }
4223     }
4224
4225     //Check if we have a custom directory
4226     if(file_exists('custom/scripts/files_to_remove'))
4227     {
4228        //Now find
4229        $files_to_remove = glob('custom/scripts/files_to_remove/*.php');
4230
4231        foreach($files_to_remove as $script)
4232        {
4233            if(preg_match('/\/files_to_remove\/(.*?)\.php$/', $script, $matches))
4234            {
4235                    require_once($script);
4236                    $upgradeClass  = $matches[1];
4237
4238                    if(!class_exists($upgradeClass))
4239                    {
4240                           continue;
4241                    }
4242
4243                    $upgradeInstance = new $upgradeClass();
4244                    if($upgradeInstance instanceof UpgradeRemoval)
4245                    {
4246                                   logThis('Running Custom UpgradeRemoval instance ' . $upgradeClass);
4247                                   $files = $upgradeInstance->getFilesToRemove($version);
4248                                   foreach($files as $file)
4249                                   {
4250                                          logThis($file);
4251                                   }
4252                                   $upgradeInstance->processFilesToRemove($files);
4253                    }
4254            }
4255        }
4256     }
4257
4258 }
4259
4260 if (!function_exists("getValidDBName"))
4261 {
4262     /*
4263      * Return a version of $proposed that can be used as a column name in any of our supported databases
4264      * 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)
4265      * @param string $name Proposed name for the column
4266      * @param string $ensureUnique
4267      * @return string Valid column name trimmed to right length and with invalid characters removed
4268      */
4269      function getValidDBName ($name, $ensureUnique = false, $maxLen = 30)
4270     {
4271         // first strip any invalid characters - all but alphanumerics and -
4272         $name = preg_replace ( '/[^\w-]+/i', '', $name ) ;
4273         $len = strlen ( $name ) ;
4274         $result = $name;
4275         if ($ensureUnique)
4276         {
4277             $md5str = md5($name);
4278             $tail = substr ( $name, -11) ;
4279             $temp = substr($md5str , strlen($md5str)-4 );
4280             $result = substr ( $name, 0, 10) . $temp . $tail ;
4281         }else if ($len > ($maxLen - 5))
4282         {
4283             $result = substr ( $name, 0, 11) . substr ( $name, 11 - $maxLen + 5);
4284         }
4285         return strtolower ( $result ) ;
4286     }
4287
4288
4289 }
4290
4291 /**
4292  * Get UW directories
4293  * Provides compatibility with both 6.3 and pre-6.3 setup
4294  */
4295 function getUWDirs()
4296 {
4297     if(!class_exists('UploadStream')) {
4298         // we're still running the old code
4299         global $sugar_config;
4300         return array($sugar_config['upload_dir'] . "/upgrades", $sugar_config['cache_dir'] . "upload/upgrades/temp");
4301     } else {
4302         if(!in_array("upload", stream_get_wrappers())) {
4303             UploadStream::register(); // just in case file was copied, but not run
4304         }
4305         return array("upload://upgrades", sugar_cached("upgrades/temp"));
4306     }
4307 }
4308
4309 /**
4310  * Whether directory exists within list of directories to skip
4311  * @param string $dir dir to be checked
4312  * @param array $skipDirs list with skipped dirs
4313  * @return boolean
4314  */
4315 function whetherNeedToSkipDir($dir, $skipDirs)
4316 {
4317     foreach($skipDirs as $skipMe) {
4318                 if(strpos( clean_path($dir), $skipMe ) !== false) {
4319                         return true;
4320                 }
4321         }
4322     return false;
4323 }
4324
4325
4326 /*
4327  * rebuildSprites
4328  * @param silentUpgrade boolean flag indicating whether or not we should treat running the SugarSpriteBuilder as an upgrade operation
4329  *
4330  */
4331 function rebuildSprites($fromUpgrade=true)
4332 {
4333     require_once('modules/Administration/SugarSpriteBuilder.php');
4334     $sb = new SugarSpriteBuilder();
4335     $sb->cssMinify = true;
4336     $sb->fromSilentUpgrade = $fromUpgrade;
4337     $sb->silentRun = $fromUpgrade;
4338
4339     // add common image directories
4340     $sb->addDirectory('default', 'include/images');
4341     $sb->addDirectory('default', 'themes/default/images');
4342     $sb->addDirectory('default', 'themes/default/images/SugarLogic');
4343
4344     // add all theme image directories
4345     if($dh = opendir('themes'))
4346     {
4347         while (($dir = readdir($dh)) !== false)
4348         {
4349             if ($dir != "." && $dir != ".." && $dir != 'default' && is_dir('themes/'.$dir)) {
4350                 $sb->addDirectory($dir, "themes/{$dir}/images");
4351             }
4352         }
4353         closedir($dh);
4354     }
4355
4356     // generate the sprite goodies
4357     // everything is saved into cache/sprites
4358     $sb->createSprites();
4359 }
4360
4361
4362 /**
4363  * repairSearchFields
4364  *
4365  * This method goes through the list of SearchFields files based and calls TemplateRange::repairCustomSearchFields
4366  * method on the files in an attempt to ensure the range search attributes are properly set in SearchFields.php.
4367  *
4368  * @param $globString String value used for glob search defaults to searching for all SearchFields.php files in modules directory
4369  * @param $path String value used to point to log file should logging be required.  Defaults to empty.
4370  *
4371  */
4372 function repairSearchFields($globString='modules/*/metadata/SearchFields.php', $path='')
4373 {
4374         if(!empty($path))
4375         {
4376                 logThis('Begin repairSearchFields', $path);
4377         }
4378
4379         require_once('include/dir_inc.php');
4380         require_once('modules/DynamicFields/templates/Fields/TemplateRange.php');
4381         require('include/modules.php');
4382
4383         global $beanList;
4384         $searchFieldsFiles = glob($globString);
4385
4386         foreach($searchFieldsFiles as $file)
4387         {
4388                 if(preg_match('/modules\/(.*?)\/metadata\/SearchFields\.php/', $file, $matches) && isset($beanList[$matches[1]]))
4389                 {
4390                         $module = $matches[1];
4391                         $beanName = $beanList[$module];
4392                         VardefManager::loadVardef($module, $beanName);
4393                         if(isset($GLOBALS['dictionary'][$beanName]['fields']))
4394                         {
4395                                 if(!empty($path))
4396                                 {
4397                                         logThis('Calling TemplateRange::repairCustomSearchFields for module ' . $module, $path);
4398                                 }
4399                                 TemplateRange::repairCustomSearchFields($GLOBALS['dictionary'][$beanName]['fields'], $module);
4400                         }
4401                 }
4402         }
4403
4404         if(!empty($path))
4405         {
4406                 logThis('End repairSearchFields', $path);
4407         }
4408 }
4409
4410 /**
4411  * repairUpgradeHistoryTable
4412  *
4413  * This is a helper function used in the upgrade process to fix upgrade_history entries so that the filename column points
4414  * to the new upload directory location introduced in 6.4 versions
4415  */
4416 function repairUpgradeHistoryTable()
4417 {
4418     require_once('modules/Configurator/Configurator.php');
4419     new Configurator();
4420     global $sugar_config;
4421
4422     //Now upgrade the upgrade_history table entries
4423     $results = $GLOBALS['db']->query('SELECT id, filename FROM upgrade_history');
4424     $upload_dir = $sugar_config['cache_dir'].'upload/';
4425
4426     //Create regular expression string to
4427     $match = '/^' . str_replace('/', '\/', $upload_dir) . '(.*?)$/';
4428
4429     while(($row = $GLOBALS['db']->fetchByAssoc($results)))
4430     {
4431         $file = str_replace('//', '/', $row['filename']); //Strip out double-paths that may exist
4432
4433         if(!empty($file) && preg_match($match, $file, $matches))
4434         {
4435             //Update new file location to use the new $sugar_config['upload_dir'] value
4436             $new_file_location = $sugar_config['upload_dir'] . $matches[1];
4437             $GLOBALS['db']->query("UPDATE upgrade_history SET filename = '{$new_file_location}' WHERE id = '{$row['id']}'");
4438         }
4439     }
4440
4441 }