0) {
//backward compatibility is on
$backwardModules[] = $mod;
}
}
}
$zipPath = clean_path($unzip_dir . '/' . $zip_from_dir);
$newFiles = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(
$zipPath,
RecursiveDirectoryIterator::SKIP_DOTS | RecursiveIteratorIterator::SELF_FIRST
)
);
// handle special do-not-overwrite conditions
$doNotOverwrite = array();
$doNotOverwrite[] = '__stub';
if (isset($_REQUEST['overwrite_files_serial'])) {
$doNotOverwrite = explode('::', $_REQUEST['overwrite_files_serial']);
}
$copiedFiles = array();
$skippedFiles = array();
foreach ($newFiles as $file) {
$cleanFile = str_replace($zipPath, '', (string) $file);
$srcFile = $zipPath . $cleanFile;
$targetFile = clean_path(getcwd() . '/' . $cleanFile);
if ($backwardModules != null && count($backwardModules) >0) {
foreach ($backwardModules as $mod) {
$splitPath = explode('/', trim($cleanFile));
if ('modules' == trim($splitPath[1]) && $mod == trim($splitPath[2])) {
$cleanFile = str_replace('/modules/'.$mod, '/modules/'.$mod.'/.500', $cleanFile);
$targetFile = clean_path(getcwd() . '/' . $cleanFile);
}
}
}
if (!is_dir(dirname((string) $targetFile))) {
mkdir_recursive(dirname((string) $targetFile)); // make sure the directory exists
}
if ((!file_exists($targetFile)) || /* brand new file */
(!in_array($targetFile, $doNotOverwrite)) /* manual diff file */
) {
// handle sugar_version.php
if (strpos((string) $targetFile, 'sugar_version.php') !== false && !preg_match('/\/portal\/sugar_version\.php$/i', (string) $targetFile)) {
logThis('Skipping "sugar_version.php" - file copy will occur at end of successful upgrade', $path);
$_SESSION['sugar_version_file'] = $srcFile;
continue;
}
if (!copy_recursive($srcFile, $targetFile)) {
logThis('*** ERROR: could not copy file: ' . $targetFile, $path);
} else {
$copiedFiles[] = $targetFile;
}
} else {
//logThis('Skipping file: ' . $targetFile, $path);
$skippedFiles[] = $targetFile;
}
}
logThis('File copy done.', $path);
$ret = array();
$ret['copiedFiles'] = $copiedFiles;
$ret['skippedFiles'] = $skippedFiles;
return $ret;
}
//On cancel put back the copied files from 500 to 451 state
function copyFilesOnCancel($step)
{
//place holder for cancel action
}
function removeFileFromPath($file, $path, $deleteNot=array())
{
$removed = 0;
$cur = $path . '/' . $file;
if (file_exists($cur)) {
$del = true;
foreach ($deleteNot as $dn) {
if ($cur == $dn) {
$del = false;
}
}
if ($del) {
unlink($cur);
$removed++;
}
}
if (!file_exists($path)) {
return $removed;
}
$d = dir($path);
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
$next = $path . '/'. $e;
if (substr($e, 0, 1) != '.' && is_dir($next)) {
$removed += removeFileFromPath($file, $next, $deleteNot);
}
}
$d->close(); // from example at http://www.php.net/manual/en/function.dir.php
return $removed;
}
/**
* This function copies/overwrites between directories
*
* @param string the directory name to remove
* @param boolean whether to just empty the given directory, without deleting the given directory.
* @return boolean True/False whether the directory was deleted.
*/
function copyRecursiveBetweenDirectories($from, $to)
{
if (file_exists($from)) {
$modifiedFiles = array();
$modifiedFiles = findAllFiles(clean_path($from), $modifiedFiles);
$cwd = clean_path(getcwd());
foreach ($modifiedFiles as $file) {
$srcFile = clean_path($file);
if (strpos((string) $srcFile, ".svn") === false) {
$targetFile = str_replace($from, $to, (string) $srcFile);
if (!is_dir(dirname($targetFile))) {
mkdir_recursive(dirname($targetFile)); // make sure the directory exists
}
// handle sugar_version.php
if (strpos($targetFile, 'sugar_version.php') !== false && !preg_match('/\/portal\/sugar_version\.php$/i', $targetFile)) {
logThis('Skipping "sugar_version.php" - file copy will occur at end of successful upgrade', $targetFile);
$_SESSION['sugar_version_file'] = $srcFile;
continue;
}
if (!copy_recursive($srcFile, $targetFile)) {
logThis("*** ERROR: could not copy file $srcFile to $targetFile");
}
}
}
}
}
function deleteDirectory($dirname, $only_empty=false)
{
if (!is_dir($dirname)) {
return false;
}
$dscan = array(realpath($dirname));
$darr = array();
while (!empty($dscan)) {
$dcur = array_pop($dscan);
$darr[] = $dcur;
if ($d=opendir($dcur)) {
while ($f=readdir($d)) {
if ($f=='.' || $f=='..') {
continue;
}
$f=$dcur.'/'.$f;
if (is_dir($f)) {
$dscan[] = $f;
} else {
unlink($f);
}
}
closedir($d);
}
}
$i_until = ($only_empty)? 1 : 0;
for ($i=count($darr)-1; $i>=$i_until; $i--) {
if (rmdir($darr[$i])) {
logThis('Success :Copying file to destination: ' . $darr[$i]);
} else {
logThis('Copy problem:Copying file to destination: ' . $darr[$i]);
}
}
return (($only_empty)? ((is_countable(scandir) ? count(scandir) : 0)<=2) : (!is_dir($dirname)));
}
/**
* Get all the customized modules. Compare the file md5s with the base md5s
* If a file has been modified then put the module in the list of customized
* modules. Show the list in the preflight check UI.
*/
function deleteAndOverWriteSelectedFiles($unzip_dir, $zip_from_dir, $delete_dirs)
{
if ($delete_dirs != null) {
foreach ($delete_dirs as $del_dir) {
deleteDirectory($del_dir);
$newFiles = findAllFiles(clean_path($unzip_dir . '/' . $zip_from_dir.'/'.$del_dir), array());
$zipPath = clean_path($unzip_dir . '/' . $zip_from_dir.'/'.$del_dir);
$copiedFiles = array();
$skippedFiles = array();
foreach ($newFiles as $file) {
$cleanFile = str_replace($zipPath, '', (string) $file);
$srcFile = $zipPath . $cleanFile;
$targetFile = clean_path(getcwd() . '/' . $cleanFile);
if (!is_dir(dirname((string) $targetFile))) {
mkdir_recursive(dirname((string) $targetFile)); // make sure the directory exists
}
if (!file_exists($targetFile)) {
// handle sugar_version.php
if (strpos((string) $targetFile, 'sugar_version.php') !== false) {
logThis('Skipping sugar_version.php - file copy will occur at end of successful upgrade');
$_SESSION['sugar_version_file'] = $srcFile;
continue;
}
//logThis('Copying file to destination: ' . $targetFile);
if (!copy_recursive($srcFile, $targetFile)) {
logThis('*** ERROR: could not copy file: ' . $targetFile);
} else {
$copiedFiles[] = $targetFile;
}
} else {
//logThis('Skipping file: ' . $targetFile);
$skippedFiles[] = $targetFile;
}
}
}
}
$ret = array();
$ret['copiedFiles'] = $copiedFiles;
$ret['skippedFiles'] = $skippedFiles;
return $ret;
}
//Default is empty the directory. For removing set it to false
// to use this function to totally remove a directory, write:
// recursive_remove_directory('path/to/directory/to/delete',FALSE);
// to use this function to empty a directory, write:
// recursive_remove_directory('path/to/full_directory');
function recursive_empty_or_remove_directory($directory, $exclude_dirs=null, $exclude_files=null, $empty=true)
{
// if the path has a slash at the end we remove it here
if (substr((string) $directory, -1) == '/') {
$directory = substr((string) $directory, 0, -1);
}
// if the path is not valid or is not a directory ...
if (!file_exists($directory) || !is_dir($directory)) {
// ... we return false and exit the function
return false;
// ... if the path is not readable
} elseif (!is_readable($directory)) {
// ... we return false and exit the function
return false;
// ... else if the path is readable
} else {
// we open the directory
$handle = opendir($directory);
// and scan through the items inside
while (false !== ($item = readdir($handle))) {
// if the filepointer is not the current directory
// or the parent directory
if ($item != '.' && $item != '..') {
// we build the new path to delete
$path = $directory.'/'.$item;
// if the new path is a directory
//add another check if the dir is in the list to exclude delete
if (is_dir($path) && $exclude_dirs != null && in_array($path, $exclude_dirs)) {
//do nothing
} else {
if (is_dir($path)) {
// we call this function with the new path
recursive_empty_or_remove_directory($path);
}
// if the new path is a file
else {
// we remove the file
if ($exclude_files != null && in_array($path, $exclude_files)) {
//do nothing
} else {
unlink($path);
}
}
}
}
}
// close the directory
closedir($handle);
// if the option to empty is not set to true
if ($empty == false) {
// try to delete the now empty directory
if (!rmdir($directory)) {
// return false if not possible
return false;
}
}
// return success
return true;
}
}
// ------------------------------------------------------------
function getAllCustomizedModules()
{
require_once('files.md5');
$return_array = array();
$modules = getAllModules();
foreach ($modules as $mod) {
//find all files in each module if the files have been modified
//as compared to the base version then add the module to the
//customized modules array
$modFiles = findAllFiles(clean_path(getcwd())."/modules/$mod", array());
foreach ($modFiles as $file) {
$fileContents = file_get_contents($file);
$file = str_replace(clean_path(getcwd()), '', (string) $file);
if ($md5_string['./' . $file]) {
if (md5($fileContents) != $md5_string['./' . $file]) {
//A file has been customized in the module. Put the module into the
// customized modules array.
echo 'Changed File'.$file;
$return_array[$mod];
break;
}
} else {
// This is a new file in user's version and indicates that module has been
//customized. Put the module in the customized array.
echo 'New File'.$file;
$return_array[$mod];
break;
}
}
} //foreach
return $return_array;
}
/**
* Array of all Modules in the version being upgraded
* This method returns an Array of all modules
* @return $modules Array of modules.
*/
function getAllModules()
{
$modules = array();
$d = dir('modules');
while ($e = $d->read()) {
if (substr($e, 0, 1) == '.' || !is_dir('modules/' . $e)) {
continue;
}
$modules[] = $e;
}
return $modules;
}
//Remove files with the smae md5
function removeMd5MatchingFiles($deleteNot=array())
{
$md5_string = array();
if (file_exists(clean_path(getcwd().'/files.md5'))) {
require(clean_path(getcwd().'/files.md5'));
}
$modulesAll = getAllModules();
foreach ($modulesAll as $mod) {
$allModFiles = array();
if (is_dir('modules/'.$mod)) {
$allModFiles = findAllFiles('modules/'.$mod, $allModFiles);
foreach ($allModFiles as $file) {
if (file_exists($file) && !in_array(basename((string) $file), $deleteNot)) {
if (isset($md5_string['./'.$file])) {
$fileContents = file_get_contents($file);
if (md5($fileContents) == $md5_string['./'.$file]) {
unlink($file);
}
}
}
}
}
}
}
/**
* Handles requirements for creating reminder Tasks and Emails
* @param array skippedFiles Array of files that were not overwriten and must be manually mereged.
* @param string path Optional full path to alternate upgradeWizard log.
*/
function commitHandleReminders($skippedFiles, $path='')
{
global $mod_strings;
global $current_user;
if (empty($mod_strings)) {
$mod_strings = return_module_language('en_us', 'UpgradeWizard');
}
if (empty($current_user->id)) {
$current_user->getSystemUser();
}
if ((is_countable($skippedFiles) ? count($skippedFiles) : 0) > 0) {
$desc = $mod_strings['LBL_UW_COMMIT_ADD_TASK_OVERVIEW'] . "\n\n";
$desc .= $mod_strings['LBL_UW_COMMIT_ADD_TASK_DESC_1'];
$desc .= $_SESSION['uw_restore_dir'] . "\n\n";
$desc .= $mod_strings['LBL_UW_COMMIT_ADD_TASK_DESC_2'] . "\n\n";
foreach ($skippedFiles as $file) {
$desc .= $file . "\n";
}
//MFH #13468
/// Not using new TimeDate stuff here because it needs to be compatible with 6.0
$nowDate = gmdate('Y-m-d');
$nowTime = gmdate('H:i:s');
$nowDateTime = $nowDate . ' ' . $nowTime;
if ($_REQUEST['addTaskReminder'] == 'remind') {
logThis('Adding Task for admin for manual merge.', $path);
$task = BeanFactory::newBean('Tasks');
$task->name = $mod_strings['LBL_UW_COMMIT_ADD_TASK_NAME'];
$task->description = $desc;
$task->date_due = $nowDate;
$task->time_due = $nowTime;
$task->priority = 'High';
$task->status = 'Not Started';
$task->assigned_user_id = $current_user->id;
$task->created_by = $current_user->id;
$task->date_entered = $nowDateTime;
$task->date_modified = $nowDateTime;
$task->save();
}
if ($_REQUEST['addEmailReminder'] == 'remind') {
logThis('Sending Reminder for admin for manual merge.', $path);
$email = BeanFactory::newBean('Emails');
$email->assigned_user_id = $current_user->id;
$email->name = $mod_strings['LBL_UW_COMMIT_ADD_TASK_NAME'];
$email->description = $desc;
$email->description_html = nl2br($desc);
$email->from_name = $current_user->full_name;
$email->from_addr = $current_user->email1;
isValidEmailAddress($email->from_addr);
$email->to_addrs_arr = $email->parse_addrs($current_user->email1, '', '', '');
$email->cc_addrs_arr = array();
$email->bcc_addrs_arr = array();
$email->date_entered = $nowDateTime;
$email->date_modified = $nowDateTime;
$email->send();
$email->save();
}
}
}
function deleteCache()
{
//Clean modules from cache
$cachedir = sugar_cached('modules');
if (is_dir($cachedir)) {
$allModFiles = array();
$allModFiles = findAllFiles($cachedir, $allModFiles, true);
foreach ($allModFiles as $file) {
if (file_exists($file)) {
if (is_dir($file)) {
rmdir_recursive($file);
} else {
unlink($file);
}
}
}
}
//Clean jsLanguage from cache
$cachedir = sugar_cached('jsLanguage');
if (is_dir($cachedir)) {
$allModFiles = array();
$allModFiles = findAllFiles($cachedir, $allModFiles);
foreach ($allModFiles as $file) {
if (file_exists($file)) {
unlink($file);
}
}
}
//Clean smarty from cache
$cachedir = sugar_cached('smarty');
if (is_dir($cachedir)) {
$allModFiles = array();
$allModFiles = findAllFiles($cachedir, $allModFiles);
foreach ($allModFiles as $file) {
if (file_exists($file)) {
unlink($file);
}
}
}
//Rebuild dashlets cache
require_once('include/Dashlets/DashletCacheBuilder.php');
$dc = new DashletCacheBuilder();
$dc->buildCache();
}
function deleteChance()
{
//Clean folder from cache
if (is_dir('include/SugarObjects/templates/chance')) {
rmdir_recursive('include/SugarObjects/templates/chance');
}
if (is_dir('include/SugarObjects/templates/chance')) {
if (!isset($_SESSION['chance'])) {
$_SESSION['chance'] = '';
}
$_SESSION['chance'] = 'include/SugarObjects/templates/chance';
//rename('include/SugarObjects/templates/chance','include/SugarObjects/templates/chance_removeit');
}
}
/**
* upgradeUWFiles
* This function copies upgrade wizard files from new patch if that dir exists
*
* @param $file String path to uploaded zip file
*/
function upgradeUWFiles($file)
{
$manifest = [];
$cacheUploadUpgradesTemp = mk_temp_dir(sugar_cached("upgrades/temp"));
unzip($file, $cacheUploadUpgradesTemp);
if (!file_exists("$cacheUploadUpgradesTemp/manifest.php")) {
logThis("*** ERROR: no manifest file detected while bootstraping upgrade wizard files!");
return;
}
include("$cacheUploadUpgradesTemp/manifest.php");
$allFiles = array();
$from_dir = "{$cacheUploadUpgradesTemp}/{$manifest['copy_files']['from_dir']}";
// Localization
if (file_exists("$from_dir/include/Localization/Localization.php")) {
$allFiles[] = "$from_dir/include/Localization/Localization.php";
}
// upgradeWizard
if (file_exists("$from_dir/modules/UpgradeWizard")) {
$allFiles[] = findAllFiles("$from_dir/modules/UpgradeWizard", []);
}
// moduleInstaller
if (file_exists("$from_dir/ModuleInstall")) {
$allFiles[] = findAllFiles("$from_dir/ModuleInstall", []);
}
if (file_exists("$from_dir/include/javascript/yui")) {
$allFiles[] = findAllFiles("$from_dir/include/javascript/yui", []);
}
if (file_exists("$from_dir/HandleAjaxCall.php")) {
$allFiles[] = "$from_dir/HandleAjaxCall.php";
}
if (file_exists("$from_dir/include/SugarTheme")) {
$allFiles[] = findAllFiles("$from_dir/include/SugarTheme", []);
}
if (file_exists("$from_dir/include/SugarCache")) {
$allFiles[] = findAllFiles("$from_dir/include/SugarCache", []);
}
if (file_exists("$from_dir/include/utils/external_cache.php")) {
$allFiles[] = "$from_dir/include/utils/external_cache.php";
}
if (file_exists("$from_dir/include/file_utils.php")) {
$allFiles[] = "$from_dir/include/file_utils.php";
}
if (file_exists("$from_dir/include/upload_file.php")) {
$allFiles[] = "$from_dir/include/upload_file.php";
}
if (file_exists("$from_dir/include/utils/sugar_file_utils.php")) {
$allFiles[] = "$from_dir/include/utils/sugar_file_utils.php";
}
if (file_exists("$from_dir/include/utils/autoloader.php")) {
$allFiles[] = "$from_dir/include/utils/autoloader.php";
}
if (file_exists("$from_dir/include/UploadFile.php")) {
$allFiles[] = "$from_dir/include/UploadFile.php";
}
if (file_exists("$from_dir/include/SugarTheme/SugarTheme.php")) {
$allFiles[] = "$from_dir/include/SugarTheme/SugarTheme.php";
}
// add extra files to post upgrade process
if (file_exists(realpath("$from_dir/../scripts/files_to_add_post.php"))) {
include(realpath("$from_dir/../scripts/files_to_add_post.php"));
if (isset($filesToAddPost) && is_array($filesToAddPost) && $filesToAddPost) {
foreach ($filesToAddPost as $file) {
if (file_exists("$from_dir/$file")) {
$allFiles[] = "$from_dir/$file";
$GLOBALS['log']->info("File added to post upgrade: $from_dir/$file");
} else {
$GLOBALS['log']->error("File not found for post upgrade: $from_dir/$file");
}
}
}
}
// check custom changes and alert the user before upgrade
if ($filesInCustom = checkCustomOverrides($from_dir)) {
global $mod_strings;
$alertMessage = $mod_strings["LBL_UPGRD_CSTM_CHK"];
echo "
$alertMessage
";
foreach ($filesInCustom as $fileInCustom) {
echo "- $fileInCustom => custom/$fileInCustom
";
}
echo "
";
}
upgradeUWFilesCopy($allFiles, $from_dir);
}
/**
* find files in custom folder if it also in upgrade pack
*
* @param string $fromDir uploaded temp directory
* @return array filelist (or empty array if there is no any)
*/
function checkCustomOverrides($fromDir)
{
$ret = array();
logThis(' -------------- Check Custom Overrides ------------- ');
$path = realpath($fromDir);
logThis("Upload temp directory: $fromDir");
// read all upgrade files
$objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST);
foreach ($objects as $name => $object) {
// check only files (folder doesn't matter)
if (!is_dir($name)) {
// get the original file name
$orig = str_replace("$fromDir/", '', (string) $name);
// original file exists?
if (file_exists($orig)) {
// custom for this file exists?
if (file_exists("custom/$orig")) {
// grab the customized files
logThis("A file in upgrade pack found in custom folder: $orig");
$ret[] = $orig;
}
}
}
}
return $ret;
}
/**
* upgradeUWFilesCopy
*
* This function recursively copies files from the upgradeUWFiles Array
* @see upgradeUWFiles
*
* @param array $allFiles Array of files to copy over after zip file has been uploaded
* @param string $from_dir Source directory
*/
function upgradeUWFilesCopy($allFiles, $from_dir)
{
foreach ($allFiles as $file) {
if (is_array($file)) {
upgradeUWFilesCopy($file, $from_dir);
} else {
$destFile = str_replace($from_dir."/", "", (string) $file);
if (!is_dir(dirname($destFile))) {
mkdir_recursive(dirname($destFile)); // make sure the directory exists
}
if (stristr((string) $file, 'uw_main.tpl')) {
logThis('Skipping "'.$file.'" - file copy will during commit step.');
} else {
logThis('updating UpgradeWizard code: '.$destFile);
copy_recursive($file, $destFile);
}
}
}
}
/**
* gets valid patch file names that exist in upload/upgrade/patch/
*/
function getValidPatchName($returnFull = true)
{
global $base_upgrade_dir;
global $mod_strings;
global $uh;
global $sugar_version;
global $sugar_config;
$uh = new UpgradeHistory();
list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
$return = array();
// scan for new files (that are not installed)
logThis('finding new files for upgrade');
$upgrade_content = '';
$upgrade_contents = findAllFiles($base_upgrade_dir, array(), false, 'zip');
//other variations of zip file i.e. ZIP, zIp,zIP,Zip,ZIp,ZiP
$ready = "\n";
$ready .= "
|
{$mod_strings['LBL_ML_NAME']}
|
{$mod_strings['LBL_ML_TYPE']}
|
{$mod_strings['LBL_ML_VERSION']}
|
{$mod_strings['LBL_ML_PUBLISHED']}
|
{$mod_strings['LBL_ML_UNINSTALLABLE']}
|
{$mod_strings['LBL_ML_DESCRIPTION']}
|
";
$disabled = '';
// assume old patches are there.
$upgradeToVersion = array(); // fill with valid patches - we will only use the latest qualified found patch
// cn: bug 10609 - notices for uninitialized variables
$icon = '';
$name = '';
$type = '';
$version = '';
$published_date = '';
$uninstallable = '';
$description = '';
$disabled = '';
foreach ($upgrade_contents as $upgrade_content) {
if (!preg_match("#.*\.zip\$#i", (string) $upgrade_content)) {
continue;
}
$the_base = basename((string) $upgrade_content);
$the_md5 = md5_file($upgrade_content);
$md5_matches = $uh->findByMd5($the_md5);
/* 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.
* Edge-case: manual upgrade with a FTP of a patch; UH table has no entry for it. Assume nothing. :( */
if (0 == (is_countable($md5_matches) ? count($md5_matches) : 0)) {
$target_manifest = remove_file_extension($upgrade_content) . '-manifest.php';
if(!file_exists($target_manifest) || !is_readable($target_manifest)){
logThis("*** Error, Cannot read manifest [ {$upgrade_content} ]");
continue;
}
require_once($target_manifest);
if (empty($manifest['version'])) {
logThis("*** Potential error: patch found with no version [ {$upgrade_content} ]");
continue;
}
if (!isset($manifest['type']) || $manifest['type'] != 'patch') {
logThis("*** Potential error: patch found with either no 'type' or non-patch type [ {$upgrade_content} ]");
continue;
}
$upgradeToVersion[$manifest['version']] = urlencode($upgrade_content);
$name = empty($manifest['name']) ? $upgrade_content : $manifest['name'];
$version = empty($manifest['version']) ? '' : $manifest['version'];
$published_date = empty($manifest['published_date']) ? '' : $manifest['published_date'];
$icon = '';
$description = empty($manifest['description']) ? 'None' : $manifest['description'];
$uninstallable = empty($manifest['is_uninstallable']) ? 'No' : 'Yes';
$type = getUITextForType($manifest['type']);
$manifest_type = $manifest['type'];
if (empty($manifest['icon'])) {
$icon = getImageForType($manifest['type']);
} else {
$path_parts = pathinfo((string) $manifest['icon']);
$icon = "
";
}
}
}
// cn: bug 10488 use the NEWEST upgrade/patch available when running upgrade wizard.
ksort($upgradeToVersion);
$upgradeToVersion = array_values($upgradeToVersion);
$newest = array_pop($upgradeToVersion);
$_SESSION['install_file'] = urldecode($newest); // in-case it was there from a prior.
logThis("*** UW using [ {$_SESSION['install_file']} ] as source for patch files.");
$cleanUpgradeContent = urlencode($_SESSION['install_file']);
// cn: 10606 - cannot upload a patch file since this returned always.
if (!empty($cleanUpgradeContent)) {
$ready .= "$icon | $name | $type | $version | $published_date | $uninstallable | $description | \n";
$ready .=<<
eoq;
$disabled = "DISABLED";
}
if (empty($cleanUpgradeContent)) {
$ready .= "None | \n";
$ready .= "\n";
}
$ready .= "
\n";
$return['ready'] = $ready;
$return['disabled'] = $disabled;
if ($returnFull) {
return $return;
}
}
/**
* finalizes upgrade by setting upgrade versions in DB (config table) and sugar_version.php
* @return bool true on success
*/
function updateVersions($version)
{
$db = DBManagerFactory::getInstance();
global $sugar_config;
global $path;
logThis('At updateVersions()... updating config table and sugar_version.php.', $path);
// handle file copy
if (isset($_SESSION['sugar_version_file']) && !empty($_SESSION['sugar_version_file'])) {
if (!copy($_SESSION['sugar_version_file'], clean_path(getcwd().'/sugar_version.php'))) {
logThis('*** ERROR: sugar_version.php could not be copied to destination! Cannot complete upgrade', $path);
return false;
} else {
logThis('sugar_version.php successfully updated!', $path);
}
} else {
logThis('*** ERROR: no sugar_version.php file location found! - cannot complete upgrade...', $path);
return false;
}
$q1 = "DELETE FROM config WHERE category = 'info' AND name = 'sugar_version'";
$q2 = "INSERT INTO config (category, name, value) VALUES ('info', 'sugar_version', '{$version}')";
logThis('Deleting old DB version info from config table.', $path);
$db->query($q1);
logThis('Inserting updated version info into config table.', $path);
$db->query($q2);
logThis('updateVersions() complete.', $path);
return true;
}
/**
* gets a module's lang pack - does not need to be a SugarModule
* @param lang string Language
* @param module string Path to language folder
* @return array mod_strings
*/
function getModuleLanguagePack($lang, $module)
{
$mod_strings = array();
if (!empty($lang) && !empty($module)) {
$langPack = clean_path(getcwd().'/'.$module.'/language/'.$lang.'.lang.php');
$langPackEn = clean_path(getcwd().'/'.$module.'/language/en_us.lang.php');
if (file_exists($langPack)) {
include($langPack);
} elseif (file_exists($langPackEn)) {
include($langPackEn);
}
}
return $mod_strings;
}
/**
* checks system compliance for 4.5+ codebase
* @return array Mixed values
*/
function checkSystemCompliance()
{
global $sugar_config;
global $current_language;
$db = DBManagerFactory::getInstance();
global $mod_strings;
global $app_strings;
if (!defined('SUGARCRM_MIN_MEM')) {
define('SUGARCRM_MIN_MEM', 40);
}
$installer_mod_strings = getModuleLanguagePack($current_language, './install');
$ret = array();
$ret['error_found'] = false;
// PHP version
if (check_php_version() === -1) {
$ret['phpVersion'] = "{$installer_mod_strings['ERR_CHECKSYS_PHP_INVALID_VER']} ".constant('PHP_VERSION')." )";
$ret['error_found'] = true;
}
if (check_php_version() === 0) {
$ret['phpVersion'] = "{$installer_mod_strings['LBL_CURRENT_PHP_VERSION']} ".constant('PHP_VERSION').". ";
$ret['phpVersion'] .= $mod_strings['LBL_RECOMMENDED_PHP_VERSION_1'].constant('SUITECRM_PHP_REC_VERSION').$mod_strings['LBL_RECOMMENDED_PHP_VERSION_2'].'';
$ret['warn_found'] = true;
}
if (check_php_version() === 1) {
$ret['phpVersion'] = "{$installer_mod_strings['LBL_CHECKSYS_PHP_OK']} ".constant('PHP_VERSION')." )";
}
// database and connect
$canInstall = $db->canInstall();
if ($canInstall !== true) {
$ret['error_found'] = true;
if ((is_countable($canInstall) ? count($canInstall) : 0) == 1) {
$ret['dbVersion'] = "" . $installer_mod_strings[$canInstall[0]] . "";
} else {
$ret['dbVersion'] = "" . sprintf($installer_mod_strings[$canInstall[0]], $canInstall[1]) . "";
}
}
// XML Parsing
if (function_exists('xml_parser_create')) {
$ret['xmlStatus'] = "{$installer_mod_strings['LBL_CHECKSYS_OK']}";
} else {
$ret['xmlStatus'] = "{$installer_mod_strings['LBL_CHECKSYS_NOT_AVAILABLE']}";
$ret['error_found'] = true;
}
// cURL
if (function_exists('curl_init')) {
$ret['curlStatus'] = "{$installer_mod_strings['LBL_CHECKSYS_OK']}";
} else {
$ret['curlStatus'] = "{$installer_mod_strings['ERR_CHECKSYS_CURL']}";
$ret['error_found'] = false;
}
// mbstrings
if (function_exists('mb_strlen')) {
$ret['mbstringStatus'] = "{$installer_mod_strings['LBL_CHECKSYS_OK']}";
} else {
$ret['mbstringStatus'] = "{$installer_mod_strings['ERR_CHECKSYS_MBSTRING']}";
$ret['error_found'] = true;
}
// imap
if (function_exists('imap_open')) {
$ret['imapStatus'] = "{$installer_mod_strings['LBL_CHECKSYS_OK']}";
} else {
$ret['imapStatus'] = "{$installer_mod_strings['ERR_CHECKSYS_IMAP']}";
$ret['error_found'] = false;
}
// memory limit
$ret['memory_msg'] = "";
$memory_limit = "-1";//ini_get('memory_limit');
$sugarMinMem = constant('SUGARCRM_MIN_MEM');
// logic based on: http://us2.php.net/manual/en/ini.core.php#ini.memory-limit
if ($memory_limit == "") { // memory_limit disabled at compile time, no memory limit
$ret['memory_msg'] = "{$installer_mod_strings['LBL_CHECKSYS_MEM_OK']}";
} elseif ($memory_limit === "-1") { // memory_limit enabled, but set to unlimited
$ret['memory_msg'] = "{$installer_mod_strings['LBL_CHECKSYS_MEM_UNLIMITED']}";
} else {
rtrim($memory_limit, 'M');
$memory_limit_int = (int) $memory_limit;
if ($memory_limit_int < constant('SUGARCRM_MIN_MEM')) {
$ret['memory_msg'] = "{$installer_mod_strings['ERR_CHECKSYS_MEM_LIMIT_1']}" . constant('SUGARCRM_MIN_MEM') . "{$installer_mod_strings['ERR_CHECKSYS_MEM_LIMIT_2']}";
$ret['error_found'] = true;
} else {
$ret['memory_msg'] = "{$installer_mod_strings['LBL_CHECKSYS_OK']} ({$memory_limit})";
}
}
// zip support
if (!class_exists("ZipArchive")) {
$ret['ZipStatus'] = "{$installer_mod_strings['ERR_CHECKSYS_ZIP']}";
$ret['error_found'] = true;
} else {
$ret['ZipStatus'] = "{$installer_mod_strings['LBL_CHECKSYS_OK']}";
}
// PCRE
if (defined('PCRE_VERSION')) {
if (version_compare(PCRE_VERSION, '7.0') < 0) {
$ret['pcreVersion'] = "{$installer_mod_strings['ERR_CHECKSYS_PCRE_VER']}";
$ret['error_found'] = true;
} else {
$ret['pcreVersion'] = "{$installer_mod_strings['LBL_CHECKSYS_OK']}";
}
} else {
$ret['pcreVersion'] = "{$installer_mod_strings['ERR_CHECKSYS_PCRE']}";
$ret['error_found'] = true;
}
// Suhosin allow to use upload://
$ret['stream_msg'] = '';
if (UploadStream::getSuhosinStatus() == true) {
$ret['stream_msg'] = "{$installer_mod_strings['LBL_CHECKSYS_OK']}";
} else {
$ret['stream_msg'] = "{$app_strings['ERR_SUHOSIN']}";
$ret['error_found'] = true;
}
/* mbstring.func_overload
$ret['mbstring.func_overload'] = '';
$mb = ini_get('mbstring.func_overload');
if($mb > 1) {
$ret['mbstring.func_overload'] = "{$mod_strings['ERR_UW_MBSTRING_FUNC_OVERLOAD']}";
$ret['error_found'] = true;
}
*/
return $ret;
}
/**
* is a file that we blow away automagically
*/
function isAutoOverwriteFile($file)
{
$overwriteDirs = array(
'./sugar_version.php',
'./modules/UpgradeWizard/uw_main.tpl',
);
$file = trim('.'.str_replace(clean_path(getcwd()), '', (string) $file));
if (in_array($file, $overwriteDirs)) {
return true;
}
$fileExtension = substr(strrchr($file, "."), 1);
if ($fileExtension == 'tpl' || $fileExtension == 'html') {
return false;
}
return true;
}
/**
* flatfile logger
*/
function logThis($entry, $path='')
{
global $mod_strings;
if (file_exists('include/utils/sugar_file_utils.php')) {
require_once('include/utils/sugar_file_utils.php');
}
$log = empty($path) ? clean_path(getcwd().'/../../logs/upgrade.log') : clean_path($path);
// create if not exists
if (!file_exists($log)) {
if (function_exists('sugar_fopen')) {
$fp = @sugar_fopen($log, 'w+'); // attempts to create file
} else {
$fp = fopen($log, 'wb+'); // attempts to create file
}
if (!is_resource($fp)) {
$GLOBALS['log']->fatal('UpgradeWizard could not create the upgradeWizard.log file');
die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
}
} else {
if (function_exists('sugar_fopen')) {
$fp = @sugar_fopen($log, 'a+'); // write pointer at end of file
} else {
$fp = @fopen($log, 'ab+'); // write pointer at end of file
}
if (!is_resource($fp)) {
$GLOBALS['log']->fatal('UpgradeWizard could not open/lock upgradeWizard.log file');
die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
}
}
$line = date('r').' [UpgradeWizard] - '.$entry."\n";
if (@fwrite($fp, $line) === false) {
$GLOBALS['log']->fatal('UpgradeWizard could not write to upgradeWizard.log: '.$entry);
die($mod_strings['ERR_UW_LOG_FILE_UNWRITABLE']);
}
if (is_resource($fp)) {
if (function_exists('sugar_fclose')) {
sugar_fclose($fp);
} else {
fclose($fp);
}
}
}
/**
* @params : none
* @author: nsingh
* @desc This function is to be used in the upgrade process to preserve changes/customaizations made to pre 5.1 quickcreate layout.
* 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
* was automatically picked up by the quick create. [Addresses Bug 21469]
* This function will check if customizations were made, and will create quickcreatedefs.php in the /cutom/working/$module_name directory.
**/
function updateQuickCreateDefs()
{
if (file_exists(__DIR__.'/../../include/utils/sugar_file_utils.php')) {
require_once(__DIR__.'/../../include/utils/sugar_file_utils.php');
}
$d = dir('modules');
$studio_modules = array();
while ($e = $d->read()) { //collect all studio modules.
if (substr($e, 0, 1) == '.' || !is_dir('modules/' . $e)) {
continue;
}
if (file_exists('modules/' . $e . '/metadata/studio.php')) {
$studio_modules[] = $e;
}
}
foreach ($studio_modules as $modname) { //for each studio enabled module
//Check !exists modules/$modname/metadata/quickcreatedefs.php &&
//exists custom/$modname/editviewdefs.php (module was customized) &&
//!exists custom/$modname/quickcreateviewdefs.php
$editviewdefs = "custom/working/modules/".$modname."/metadata/editviewdefs.php";
$quickcreatedefs = "custom/working/modules/".$modname."/metadata/quickcreatedefs.php";
if (!file_exists("modules/".$modname."/metadata/quickcreatedefs.php") &&
file_exists($editviewdefs) &&
!file_exists($quickcreatedefs)) {
//clone editviewdef and save it in custom/working/modules/metadata
$GLOBALS['log']->debug("Copying editviewdefs.php as quickcreatedefs.php for the $modname module in custom/working/modules/$modname/metadata!");
if (copy($editviewdefs, $quickcreatedefs)) {
if (file_exists($quickcreatedefs) && is_readable($quickcreatedefs)) {
$file = file($quickcreatedefs);
//replace 'EditView' with 'QuickCreate'
if (function_exists('sugar_fopen')) {
$fp = sugar_fopen($quickcreatedefs, 'wb');
} else {
$fp = fopen($quickcreatedefs, 'wb');
}
foreach ($file as &$line) {
if (preg_match('/^\s*\'EditView\'\s*=>\s*$/', (string) $line) > 0) {
$line = "'QuickCreate' =>\n";
}
fwrite($fp, $line);
}
//write back.
if (function_exists('sugar_fclose')) {
sugar_fclose($fp);
} else {
fclose($fp);
}
} else {
$GLOBALS['log']->debug("Failed to replace 'EditView' with QuickCreate because $quickcreatedefs is either not readable or does not exist.");
}
} else {
$GLOBALS['log']->debug("Failed to copy $editviewdefs to $quickcreatedefs!");
}
}
}
}
/**
* test perms for CREATE queries
*/
function testPermsCreate($db, $out)
{
logThis('Checking CREATE TABLE permissions...');
global $mod_strings;
if (!$db->checkPrivilege("CREATE TABLE")) {
logThis('cannot CREATE TABLE!');
$out['db']['dbNoCreate'] = true;
$out['dbOut'] .= "
{$mod_strings['LBL_UW_DB_NO_CREATE']} |
";
}
return $out;
}
/**
* test perms for INSERT
*/
function testPermsInsert($db, $out, $skip=false)
{
logThis('Checking INSERT INTO permissions...');
global $mod_strings;
if (!$db->checkPrivilege("INSERT")) {
logThis('cannot INSERT INTO!');
$out['db']['dbNoInsert'] = true;
$out['dbOut'] .= "{$mod_strings['LBL_UW_DB_NO_INSERT']} |
";
}
return $out;
}
/**
* test perms for UPDATE TABLE
*/
function testPermsUpdate($db, $out, $skip=false)
{
logThis('Checking UPDATE TABLE permissions...');
global $mod_strings;
if (!$db->checkPrivilege("UPDATE")) {
logThis('cannot UPDATE TABLE!');
$out['db']['dbNoUpdate'] = true;
$out['dbOut'] .= "{$mod_strings['LBL_UW_DB_NO_UPDATE']} |
";
}
return $out;
}
/**
* test perms for SELECT
*/
function testPermsSelect($db, $out, $skip=false)
{
logThis('Checking SELECT permissions...');
global $mod_strings;
if (!$db->checkPrivilege("SELECT")) {
logThis('cannot SELECT!');
$out['db']['dbNoSelect'] = true;
$out['dbOut'] .= "{$mod_strings['LBL_UW_DB_NO_SELECT']} |
";
}
return $out;
}
/**
* test perms for DELETE
*/
function testPermsDelete($db, $out, $skip=false)
{
logThis('Checking DELETE FROM permissions...');
global $mod_strings;
if (!$db->checkPrivilege("DELETE")) {
logThis('cannot DELETE FROM!');
$out['db']['dbNoDelete'] = true;
$out['dbOut'] .= "{$mod_strings['LBL_UW_DB_NO_DELETE']} |
";
}
return $out;
}
/**
* test perms for ALTER TABLE ADD COLUMN
*/
function testPermsAlterTableAdd($db, $out, $skip=false)
{
logThis('Checking ALTER TABLE ADD COLUMN permissions...');
global $mod_strings;
if (!$db->checkPrivilege("ADD COLUMN")) {
logThis('cannot ADD COLUMN!');
$out['db']['dbNoAddColumn'] = true;
$out['dbOut'] .= "{$mod_strings['LBL_UW_DB_NO_ADD_COLUMN']} |
";
}
return $out;
}
/**
* test perms for ALTER TABLE ADD COLUMN
*/
function testPermsAlterTableChange($db, $out, $skip=false)
{
logThis('Checking ALTER TABLE CHANGE COLUMN permissions...');
global $mod_strings;
if (!$db->checkPrivilege("CHANGE COLUMN")) {
logThis('cannot CHANGE COLUMN!');
$out['db']['dbNoChangeColumn'] = true;
$out['dbOut'] .= "{$mod_strings['LBL_UW_DB_NO_CHANGE_COLUMN']} |
";
}
return $out;
}
/**
* test perms for ALTER TABLE DROP COLUMN
*/
function testPermsAlterTableDrop($db, $out, $skip=false)
{
logThis('Checking ALTER TABLE DROP COLUMN permissions...');
global $mod_strings;
if (!$db->checkPrivilege("DROP COLUMN")) {
logThis('cannot DROP COLUMN!');
$out['db']['dbNoDropColumn'] = true;
$out['dbOut'] .= "{$mod_strings['LBL_UW_DB_NO_DROP_COLUMN']} |
";
}
return $out;
}
/**
* test perms for DROP TABLE
*/
function testPermsDropTable($db, $out, $skip=false)
{
logThis('Checking DROP TABLE permissions...');
global $mod_strings;
if (!$db->checkPrivilege("DROP TABLE")) {
logThis('cannot DROP TABLE!');
$out['db']['dbNoDropTable'] = true;
$out['dbOut'] .= "{$mod_strings['LBL_UW_DB_NO_DROP_TABLE']} |
";
}
return $out;
}
function getFormattedError($error, $query)
{
$error = "".$error;
$error .= "::{$query}
";
return $error;
}
/**
* parses a query finding the table name
* @param string query The query
* @return string table The table
*/
function getTableFromQuery($query)
{
$standardQueries = array('ALTER TABLE', 'DROP TABLE', 'CREATE TABLE', 'INSERT INTO', 'UPDATE', 'DELETE FROM');
$query = preg_replace("/[^A-Za-z0-9\_\s]/", "", (string) $query);
$query = trim(str_replace($standardQueries, '', $query));
$firstSpc = strpos($query, " ");
$end = ($firstSpc > 0) ? $firstSpc : strlen($query);
$table = substr($query, 0, $end);
return $table;
}
//prelicense check
function preLicenseCheck()
{
$manifest = [];
$cwd = null;
require_once('modules/UpgradeWizard/uw_files.php');
global $sugar_config;
global $mod_strings;
global $sugar_version;
if (empty($sugar_version)) {
require('sugar_version.php');
}
if (!isset($_SESSION['unzip_dir']) || empty($_SESSION['unzip_dir'])) {
logThis('unzipping files in upgrade archive...');
$errors = array();
list($base_upgrade_dir, $base_tmp_upgrade_dir) = getUWDirs();
$unzip_dir = '';
//also come up with mechanism to read from upgrade-progress file
if (!isset($_SESSION['install_file']) || empty($_SESSION['install_file']) || !is_file($_SESSION['install_file'])) {
if (file_exists(clean_path($base_tmp_upgrade_dir)) && $handle = opendir(clean_path($base_tmp_upgrade_dir))) {
while (false !== ($file = readdir($handle))) {
if ($file !="." && $file !="..") {
if (is_file($base_tmp_upgrade_dir."/".$file."/manifest.php")) {
require_once($base_tmp_upgrade_dir."/".$file."/manifest.php");
$package_name= $manifest['copy_files']['from_dir'];
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")) {
$unzip_dir = $base_tmp_upgrade_dir."/".$file;
if (file_exists("$base_upgrade_dir/patch/".$package_name.'.zip')) {
$_SESSION['install_file'] = $package_name.".zip";
break;
}
}
}
}
}
}
}
if (empty($_SESSION['install_file'])) {
unlinkUWTempFiles();
resetUwSession();
echo 'Upload File not found so redirecting to Upgrade Start ';
$redirect_new_wizard = $sugar_config['site_url' ].'/index.php?module=UpgradeWizard&action=index';
echo '