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