<?php
if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );
/**
* Get the upgrade folder path
*
* @param string Name of folder with current downloaded version
* @return string The upgrade folder path (No slash at the end)
*/
function get_upgrade_folder_path( $version_folder_name )
{
global $upgrade_path;
if( empty( $version_folder_name ) || ! file_exists( $upgrade_path.$version_folder_name ) )
{ // Don't allow an invalid upgrade folder
debug_die( 'Invalid name of upgrade folder' );
}
// Use a root path by default:
$upgrade_folder_path = $upgrade_path.$version_folder_name;
if( $dir_handle = @opendir( $upgrade_folder_path ) )
{
while( ( $dir_name = readdir( $dir_handle ) ) !== false )
{
$dir_path = $upgrade_folder_path.'/'.$dir_name;
if( is_dir( $dir_path ) && preg_match( '#^b2evolution#i', $dir_name ) )
{ // Use any folder which name is started with "b2evolution":
if( file_exists( $dir_path.'/blogs' ) )
{ // Use 'b2evolution*/blogs' folder:
$upgrade_folder_path = $dir_path.'/blogs';
break;
}
elseif( file_exists( $dir_path.'/site' ) )
{ // Use 'b2evolution*/site' folder:
$upgrade_folder_path = $dir_path.'/site';
break;
}
elseif( file_exists( $dir_path ) )
{ // Use 'b2evolution*' folder:
$upgrade_folder_path = $dir_path;
break;
}
}
}
closedir( $dir_handle );
}
return $upgrade_folder_path;
}
/**
* Check version of downloaded upgrade vs. current version
*
* @param new version dir name
* @return array|NULL NULL - version is new, Array - version is old or same,
* keys 'error' => 'old' or 'same', 'message' - Message text
*/
function check_version( $new_version_dir )
{
global $rsc_url, $upgrade_path, $conf_path;
$new_version_file = get_upgrade_folder_path( $new_version_dir ).'/conf/_application.php';
if( ! file_exists( $new_version_file ) )
{ // Invalid structure of the downloaded upgrade package
debug_die( '/conf/_application.php not found in /b2evolution/blogs/ nor /b2evolution/site/ nor /b2evolution/! You may have downloaded an invalid ZIP package.' );
}
require( $new_version_file );
$vc = evo_version_compare( $app_version, $GLOBALS['app_version'] );
if( $vc < 0 )
{
$result = 'old';
}
elseif( $vc == 0 )
{
if( $app_date == $GLOBALS['app_date'] )
{
$result = 'same';
}
elseif( $app_date < $GLOBALS['app_date'] )
{
$result = 'old';
}
}
if( empty( $result ) )
{ // New version:
return NULL;
}
elseif( $result == 'old' )
{ // Old version:
return array(
'error' => 'old',
'message' => TB_('This is an old version!').'<br />'
.'Current: '.$GLOBALS['app_version'].' '.$GLOBALS['app_date'].'<br />'
.'About to install: '.$app_version.' '.$app_date.'<br />'
.TB_('You should NOT install this older version.')
);
}
elseif( $result == 'same' )
{ // Same version:
return array(
'error' => 'same',
'message' => TB_('This package is already installed!').'<br />'
.TB_('No upgrade is needed at this time. You might force a re-install if you want to force a cleanup.')
);
}
}
/**
* Enable/disable maintenance mode
*
* @param boolean Do we want to enable or disable maintenance mode?
* @param string Mode: 'all', 'install', 'upgrade'
* @param string maintenance mode message
* @param boolean TRUE to don't print out a message status
*/
function switch_maintenance_mode( $enable, $mode = 'all', $msg = '', $silent = false )
{
global $conf_path;
static $maintenance_mode = 'unknown';
switch( $mode )
{
case 'install':
// Use maintenance mode except of install actions
$maintenance_mode_file = 'imaintenance.html';
break;
case 'upgrade':
// Use maintenance mode except of upgrade actions
$maintenance_mode_file = 'umaintenance.html';
break;
default:
// Use full maintenance mode
$maintenance_mode_file = 'maintenance.html';
break;
}
if( $enable )
{ // Create maintenance file
echo '<p>'.TB_('Switching to maintenance mode...');
evo_flush();
$content = '<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Site temporarily down for maintenance.</title>
</head>
<body>
<h1>503 Service Unavailable</h1>
<p>'.$msg.'</p>
<hr />
<p>Site administrators: please view the source of this page for details.</p>
<!--
If you need to manually put b2evolution OUT of maintenance mode, delete or rename the file
/conf/maintenance.html or /conf/imaintenance.html or /conf/umaintenance.html .
The presence of any of these files will make b2evolution show it is in maintenance mode.
WARNING: If you just had an upgrade fail in the middle of it, it is a very bad idea to just
get out of maintenance mode without immdiately restoring a DB backup first. Continuing without
a clean DB may make it impossible to ever ugrade your b2evolution in the future.
-->
</body>
</html>';
if( save_to_file( $content, $conf_path.$maintenance_mode_file, 'w+' ) )
{ // Maintenance file has been created
echo ' OK.</p>';
}
else
{ // Maintenance file has not been created
echo '</p><p style="color:red"><evo:error>'.sprintf( TB_('Unable to switch to maintenance mode. Maintenance file can\'t be created: «%s»'), $maintenance_mode_file ).'</evo:error></p>';
evo_flush();
return false;
}
}
else
{ // Delete maintenance file
if( $maintenance_mode == 'unknown' ){
if( ! $silent )
{
echo '<p>'.TB_('Switching out of maintenance mode...');
$maintenance_mode = 'disable';
}
// Delete a maintenance file if it exists and writable:
if( is_writable( $conf_path.$maintenance_mode_file ) && @unlink( $conf_path.$maintenance_mode_file ) )
{ // Unlink was successful:
if( ! $silent )
{ // Dispaly OK message:
echo ' OK.</p>';
evo_flush();
}
}
else
{ // Unlink failed:
echo '</p><p style="color:red"><evo:error>'.sprintf( TB_('Unable to delete maintenance file: «%s»'), $maintenance_mode_file ).'</evo:error></p>';
evo_flush();
return false;
}
}
}
return true;
}
/**
* Enable/disable maintenance lock
*
* @param boolean true if maintenance lock need to be enabled
* @return bollean true on success, false otherwise
*/
function switch_maintenance_lock( $enable )
{
global $Settings;
if( $Settings->get( 'system_lock' ) != $enable )
{ // Enable system lock
$Settings->set( 'system_lock', $enable );
return $Settings->dbupdate();
}
return true;
}
/**
* Prepare maintenance directory
*
* @param string directory path
* @param boolean create .htaccess file with 'deny from all' text
* @return boolean
*/
function prepare_maintenance_dir( $dir_name, $deny_access = true )
{
// echo '<p>'.TB_('Checking destination directory: ').$dir_name.'</p>';
if( !file_exists( $dir_name ) )
{ // We can create directory
if ( ! mkdir_r( $dir_name ) )
{
echo '<p style="color:red">'.sprintf( TB_('Unable to create «%s» directory.'), $dir_name ).'</p>';
evo_flush();
return false;
}
}
if( $deny_access )
{ // Create .htaccess file
echo '<p>'.TB_('Checking .htaccess denial for directory: ').$dir_name;
evo_flush();
$htaccess_name = $dir_name.'.htaccess';
if( !file_exists( $htaccess_name ) )
{ // We can create .htaccess file
if( ! save_to_file( 'deny from all', $htaccess_name, 'w' ) )
{
echo '</p><p style="color:red">'.sprintf( TB_('Unable to create «%s» file in directory.'), $htaccess_name ).'</p>';
evo_flush();
return false;
}
if( ! file_exists($dir_name.'index.html') )
{ // Create index.html to disable directory browsing
save_to_file( '', $dir_name.'index.html', 'w' );
}
}
echo ' : OK.</p>';
evo_flush();
// fp> TODO: make sure "deny all" actually works by trying to request the directory through HTTP
}
return true;
}
/**
* Unpack ZIP archive to destination directory
*
* @param string source file path
* @param string destination directory path
* @param boolean true if create destination directory
* @param string Zip file name
* @param boolean TRUE to print error, FALSE to return error
* @return boolean|string TRUE on success, FALSE|string on error
*/
function unpack_archive( $src_file, $dest_dir, $mk_dest_dir = false, $src_file_name = '', $print_error = true )
{
global $Settings, $current_User, $basepath, $upgrade_path;
if( ! check_user_perm( 'files', 'all' ) )
{ // No permission to unzip files:
$error = '<span class="text-danger">'.TB_('You don\'t have permission to UNZIP files automatically on the server.').'</span>';
if( check_user_perm( 'users', 'edit' ) )
{ // Link to edit permissions:
global $admin_url;
$error .= ' ('.sprintf( TB_('You can change this <a %s>here</a>'), 'href="'.$admin_url.'?ctrl=groups&action=edit&grp_ID='.$current_User->get( 'grp_ID' ).'#fieldset_wrapper_file"' ).')';
}
$error = '<p>'.$error.'</p>';
if( $print_error )
{ // Print error:
echo $error;
evo_flush();
return false;
}
else
{ // Return error message:
return $error;
}
}
if( strpos( $src_file, '://' ) !== false )
{ // Deny ZIP file from urls:
$invalid_path_error = sprintf( TB_('Path must not contain %s'), '<code>://</code>' );
}
else
{ // Check if ZIP path is inside $basepath or $upgrade_path:
$canonical_path = get_canonical_path( $src_file );
if( strpos( $canonical_path, $basepath ) !== 0 &&
strpos( $canonical_path, get_canonical_path( $upgrade_path ) ) !== 0 )
{ // ZIP file path must be started with $basepath or $upgrade_path:
$invalid_path_error = sprintf( TB_('Path is outside %s and outside %s.'), '$basepath=<code>'.$basepath.'</code>', '$upgrade_path=<code>'.$upgrade_path.'</code>' );
}
}
if( isset( $invalid_path_error ) )
{ // Don't allow wrong ZIP file path:
$error = '<p class="text-danger">'.sprintf( TB_('Invalid ZIP file path %s:'), '<code>'.$src_file.'</code>' ).' '.$invalid_path_error.'</p>';
if( $print_error )
{ // Print error:
echo $error;
evo_flush();
return false;
}
else
{ // Return error message:
return $error;
}
}
if( ! file_exists( $dest_dir ) && ! mkdir_r( $dest_dir ) )
{ // Destination directory doesn't exist and it couldn't be created:
$error = '<p class="text-danger">'.sprintf( TB_('Unable to create «%s» directory to extract files from ZIP archive.'), $dest_dir ).'</p>';
if( $print_error )
{ // Print error:
echo $error;
evo_flush();
return false;
}
else
{ // Return error message:
return $error;
}
}
if( class_exists( 'ZipArchive' ) )
{ // Unpack using 'ZipArchive' extension:
$ZipArchive = new ZipArchive();
if( $ZipArchive->open( $src_file ) &&
$ZipArchive->extractTo( $dest_dir ) )
{ // Change rights for unpacked folders and files after successful unpacking:
chmod_r( $dest_dir );
$ZipArchive->close();
}
else
{
$error = '<p class="text-danger">'
.sprintf( TB_('Error: %s'), $ZipArchive->getStatusString() ).'<br />'
.sprintf( TB_('Unable to decompress «%s» ZIP archive.'), ( empty( $src_file_name ) ? $src_file : $src_file_name ) )
.'</p>';
if( $print_error )
{ // Print error:
echo $error;
evo_flush();
return false;
}
else
{ // Return error message:
return $error;
}
}
}
else
{
debug_die( 'Unable to decompress the file because there is no \'ZipArchive\' extension installed in your PHP!' );
}
return true;
}
/**
* Pack ZIP archive from destination directory/file
*
* @param string Path of new archive
* @param string Directory path where files are located
* @param string|array Files which should be added into ZIP archive
* @param string|array Sub-directory name where files should added inside ZIP relative, Use empty to add in root of the ZIP archive; May be array: 0 key is for all files/folders, other key - for custom files/folders
* @param array|string Exclude folders and files from folders with these names, 'subdirs' - to exclude ALL subfolders
* @param string Type of log: 'print', 'msg_error'
* @return boolean TRUE on success
*/
function pack_archive( $archive_path, $source_dir_path, $files, $add_in_subdirs = '', $exclude_folder_names = array(), $log_type = 'print' )
{
global $Settings, $Messages;
if( ! class_exists( 'ZipArchive' ) )
{ // Stop when no installed extension:
debug_die( 'Unable to compress the files because there is no \'ZipArchive\' extension installed in your PHP!' );
}
if( file_exists( $archive_path ) )
{ // Don't try to create ZIP if same file already exists:
$log_msg = sprintf( TB_('File %s already exists.'), '<code>'.$archive_path.'</code>' );
if( $log_type == 'print' )
{
echo '<p class="text-danger">'.$log_msg.'</p>';
evo_flush();
}
elseif( $log_type == 'msg_error' )
{
$Messages->add( $log_msg, 'error' );
}
return false;
}
// Pack using 'ZipArchive' extension:
$ZipArchive = new ZipArchive();
if( $ZipArchive->open( $archive_path, ZipArchive::CREATE ) !== TRUE )
{ // Cannot create new ZIP archive:
$log_msg = sprintf( TB_('Error: %s'), $ZipArchive->getStatusString() ).'<br />'
.sprintf( TB_('Unable to create ZIP archive %s.'), '<code>'.$archive_path.'</code>' );
if( $log_type == 'print' )
{
echo '<p class="text-danger">'.$log_msg.'</p>';
evo_flush();
}
elseif( $log_type == 'msg_error' )
{
$Messages->add( $log_msg, 'error' );
}
return false;
}
if( ! is_array( $files ) )
{ // Make array from single file:
$files = array( $files );
}
$source_dir_path_length = strlen( $source_dir_path );
if( ! is_array( $add_in_subdirs ) )
{
$add_in_subdirs = array( $add_in_subdirs );
}
foreach( $add_in_subdirs as $a => $add_in_subdir )
{
if( ! empty( $add_in_subdir ) )
{ // Format sub-directory:
$add_in_subdirs[ $a ] = trim( $add_in_subdir, '/' ).'/';
}
}
if( is_array( $exclude_folder_names ) )
{ // Initialize array to exclude subfolders by name:
foreach( $exclude_folder_names as $e => $exclude_folder_name )
{
$exclude_folder_names[ $e ] = preg_quote( trim( $exclude_folder_name, '/' ) );
}
$exclude_folder_names_regexp = empty( $exclude_folder_names ) ? false : '#(^|/)'.implode( '|', $exclude_folder_names ).'(/|$)#';
}
else
{
$exclude_folder_names_regexp = false;
}
$zip_result = true;
foreach( $files as $file )
{ // Add files into archive:
if( $log_type == 'print' )
{
echo sprintf( TB_('Adding «<strong>%s</strong>» to ZIP file...'), $source_dir_path.$file );
evo_flush();
}
$add_in_subdir = isset( $add_in_subdirs[ $file ] ) ? $add_in_subdirs[ $file ] : $add_in_subdirs[0];
if( is_dir( $source_dir_path.$file ) )
{ // Add directory:
if( $exclude_folder_names_regexp !== false &&
preg_match( $exclude_folder_names_regexp, $file ) )
{ // Skip file by excluded folder name:
continue;
}
$file_result = $ZipArchive->addEmptyDir( '/'.$add_in_subdir.trim( $file, '/' ) );
if( $file_result && ( $dir_files = get_filenames( $source_dir_path.$file, array( 'inc_evocache' => true, 'recurse' => ( $exclude_folder_names !== 'subdirs' ), ) ) ) )
{ // Add files of the directory:
foreach( $dir_files as $dir_file )
{
$rel_dir_file_path = '/'.$add_in_subdir.substr( $dir_file, $source_dir_path_length );
if( $exclude_folder_names_regexp !== false &&
preg_match( $exclude_folder_names_regexp, $rel_dir_file_path ) )
{ // Skip file by excluded folder name:
continue;
}
if( is_dir( $dir_file ) )
{ // Add empty sub-directory:
if( $exclude_folder_names !== 'subdirs' )
{
$file_result = $ZipArchive->addEmptyDir( $rel_dir_file_path ) && $file_result;
}
}
else
{ // Add file:
$file_result = $ZipArchive->addFile( $dir_file, $rel_dir_file_path ) && $file_result;
}
}
}
}
else
{ // Add file:
$file_result = $ZipArchive->addFile( $source_dir_path.$file, '/'.$add_in_subdir.$file );
}
if( $file_result )
{ // Display success result:
if( $log_type == 'print' )
{
echo ' OK.<br />';
evo_flush();
}
}
else
{ // Display error:
$log_msg = sprintf( TB_('Error: %s'), $ZipArchive->getStatusString() );
if( $log_type == 'print' )
{
echo ' <span class="text-danger">'.$log_msg.'</span>.<br />';
evo_flush();
}
elseif( $log_type == 'msg_error' )
{
$Messages->add( $log_msg, 'error' );
}
}
$zip_result = $zip_result && $file_result;
}
if( $log_type == 'print' )
{
echo sprintf( TB_('Compressing «<strong>%s</strong>»...'), $archive_path );
evo_flush();
}
$ZipArchive->close();
if( $log_type == 'print' )
{
echo ' OK.<br />';
}
// Set rights for new created ZIP file:
@chmod( $archive_path, octdec( $Settings->get( 'fm_default_chmod_file' ) ) );
return $zip_result;
}
/**
* Download ZIP archive
*
* @param string Path of the archive
*/
function download_archive( $archive_path )
{
if( ! file_exists( $archive_path ) ||
! preg_match( '/\.zip$/', $archive_path ) )
{ // Don't try to download not existing of not ZIP file:
return false;;
}
$archive_content = file_get_contents( $archive_path );
header( 'Content-Type: application/zip' );
header( 'Content-Disposition: attachment; filename="'.basename( $archive_path ).'"' );
header( 'Content-Length: '.strlen( $archive_content ) );
header( 'Content-Transfer-Encoding: binary' );
header( 'Cache-Control: no-cache, must-revalidate, max-age=60' );
header( 'Expires: 0' );
echo $archive_content;
}
/**
* Verify that destination files can be overwritten
*
* @param string source directory
* @param string destination directory
* @param string action name
* @param boolean overwrite
* @param array read only file list
*/
function verify_overwrite( $src, $dest, $action = '', $overwrite = true, & $read_only_list )
{
global $basepath, $Settings;
/**
* Result of this function is FALSE when some error was detected
* @var boolean
*/
$result = true;
$dir = opendir( $src );
if( $dir === false )
{ // $dir is not a valid directory or it can not be opened due to permission restrictions
echo '<div class="red">The «'.htmlspecialchars( $src ).'» is not a valid direcotry or the directory can not be opened due to permission restrictions or filesystem errors.</div>';
return false;
}
$dir_list = array();
$file_list = array();
while( false !== ( $file = readdir( $dir ) ) )
{
if ( ( $file != '.' ) && ( $file != '..' ) )
{
$srcfile = $src.'/'.$file;
$destfile = $dest.'/'.$file;
if( isset( $read_only_list ) && file_exists( $destfile ) && !is_writable( $destfile ) )
{ // Folder or file is not writable
$read_only_list[] = $destfile;
}
if ( is_dir( $srcfile ) )
{
$dir_list[$srcfile] = $destfile;
}
elseif( $overwrite )
{ // Add to overwrite
$file_list[$srcfile] = $destfile;
}
}
}
$config_ignore_files = get_upgrade_config( 'ignore' );
$config_softmove_files = get_upgrade_config( 'softmove');
$config_forcemove_files = get_upgrade_config( 'forcemove' );
if( ! empty( $action ) && $action == 'Copying' )
{ // Display errors about config file or the unknown and incorrect commands from config file
$config_has_errors = false;
if( is_string( $config_ignore_files ) )
{ // Config file has some errors, but the upgrade should not fail because of that
echo '<div class="red">'.$config_ignore_files.'</div>';
$config_has_errors = true;
}
else
{
$config_unknown_commands = get_upgrade_config( 'unknown' );
$config_incorrect_commands = get_upgrade_config( 'incorrect' );
if( ! empty( $config_unknown_commands ) && is_array( $config_unknown_commands ) )
{ // Unknown commands
foreach( $config_unknown_commands as $config_unknown_command )
{
echo '<div class="red">'.sprintf( TB_('Unknown policy command: %s'), $config_unknown_command ).'</div>';
}
$config_has_errors = true;
}
if( ! empty( $config_incorrect_commands ) && is_array( $config_incorrect_commands ) )
{ // Incorrect commands
foreach( $config_incorrect_commands as $config_incorrect_command )
{
echo '<div class="red">'.sprintf( TB_('Incorrect policy command: %s'), $config_incorrect_command ).'</div>';
}
$config_has_errors = true;
}
}
if( $config_has_errors )
{ // The upgrade config file contains the errors, Stop the upgrading process
echo '<div class="red">'.sprintf( TB_('To continue the upgrade process please fix the issues of the file %s or delete it.'), '<code>'.get_upgrade_config_file_name().'</code>' ).'</div>';
return false;
}
}
foreach( $dir_list as $src_dir => $dest_dir )
{
$dest_dir_name = str_replace( $basepath, '', $dest_dir );
// Detect if we should ignore this folder
$ignore_dir = $overwrite && is_array( $config_ignore_files ) && in_array( $dest_dir_name, $config_ignore_files );
$dir_success = false;
if( !empty( $action ) )
{
if( $ignore_dir )
{ // Ignore folder
echo '<div class="orange">'.sprintf( TB_('Ignoring %s because of %s'), '«<b>'.$dest_dir.'</b>»', '<code>'.get_upgrade_config_file_name().'</code>' ).'</div>';
}
else
{ // progressive display of what backup is doing
echo $action.' «<strong>'.$dest_dir.'</strong>»...';
$dir_success = true;
}
evo_flush();
}
elseif( $ignore_dir )
{ // This subfolder must be ingored, Display message about this
echo '<div class="orange">'.sprintf( TB_('Ignoring %s because of %s'), '«<b>'.$dest_dir_name.'</b>»', '<code>'.get_upgrade_config_file_name().'</code>' ).'</div>';
$dir_success = false;
evo_flush();
}
if( $ignore_dir )
{ // Skip the ignored folder
continue;
}
if( $overwrite && !file_exists( $dest_dir ) )
{
// Create destination directory
if( ! evo_mkdir( $dest_dir ) )
{ // No permission to create a folder
echo '<div class="red">'.sprintf( TB_('Unavailable creating of folder %s, probably no permissions.'), '«<b>'.$dest_dir_name.'</b>»' ).'</div>';
$result = false;
$dir_success = false;
evo_flush();
continue;
}
}
if( $dir_success )
{
echo ' OK.<br />';
evo_flush();
}
$result = $result && verify_overwrite( $src_dir, $dest_dir, '', $overwrite, $read_only_list );
}
foreach( $file_list as $src_file => $dest_file )
{ // Overwrite destination file
$dest_file_name = str_replace( $basepath, '', $dest_file );
if( is_array( $config_ignore_files ) && in_array( $dest_file_name, $config_ignore_files ) )
{ // Ignore this file
echo '<div class="orange">'.sprintf( TB_('Ignoring %s because of %s'), '«<b>'.$dest_file_name.'</b>»', '<code>'.get_upgrade_config_file_name().'</code>' ).'</div>';
evo_flush();
continue;
}
if( is_array( $config_softmove_files ) && !empty( $config_softmove_files[ $dest_file_name ] ) )
{ // Action 'softmove': This file should be copied to other location with saving old file
$copy_file_name = $config_softmove_files[ $dest_file_name ];
// Don't rewrite old file
$rewrite_old_file = false;
}
if( is_array( $config_forcemove_files ) && !empty( $config_forcemove_files[ $dest_file_name ] ) )
{ // Action 'forcemove': This file should be copied to other location with rewriting old file
$copy_file_name = $config_forcemove_files[ $dest_file_name ];
// Rewrite old file
$rewrite_old_file = true;
}
if( ! empty( $copy_file_name ) )
{ // This file is marked in config to copy to other location
$copy_file = $basepath.$copy_file_name;
if( ! $rewrite_old_file && file_exists( $copy_file ) )
{ // Display warning if we cannot rewrite an existing file
echo '<div class="orange">'.sprintf( TB_('Ignoring softmove of %s because %s is already in place (see %s)'),
'«<b>'.$dest_file_name.'</b>»',
'«<b>'.$copy_file_name.'</b>»',
'<code>'.get_upgrade_config_file_name().'</code>' ).'</div>';
evo_flush();
unset( $copy_file_name );
continue; // Skip this file
}
else
{ // We can copy this file to other location
echo '<div class="orange">'.sprintf( TB_('Moving %s to %s as stated in %s'),
'«<b>'.$dest_file_name.'</b>»',
'«<b>'.$copy_file_name.'</b>»',
'<code>'.get_upgrade_config_file_name().'</code>' ).'</div>';
evo_flush();
// Set new location for a moving file
$dest_file = $copy_file;
$dest_file_name = $copy_file_name;
unset( $copy_file_name );
}
}
// Copying
if( ! @copy( $src_file, $dest_file ) )
{ // Display error if a copy command is unavailable
echo '<div class="red">'.sprintf( TB_('Unavailable copying to %s, probably no permissions.'), '«<b>'.$dest_file_name.'</b>»' ).'</div>';
$result = false;
evo_flush();
}
else
{ // Change rights for new file:
@chmod( $dest_file, octdec( $Settings->get( 'fm_default_chmod_file' ) ) );
}
}
closedir( $dir );
return $result;
}
/**
* Convert aliases to real table names as table backup works with real table names
* @param mixed aliases
* @return mixed
*/
function aliases_to_tables( $aliases )
{
global $DB;
if( is_array( $aliases ) )
{
$tables = array();
foreach( $aliases as $alias )
{
$tables[] = preg_replace( $DB->dbaliases, $DB->dbreplaces, $alias );
}
return $tables;
}
elseif( $aliases == '*' )
{
return $aliases;
}
else
{
return preg_replace( $DB->dbaliases, $DB->dbreplaces, $aliases );
}
}
/**
* Check if the upgrade config file exists and display error message if config doesn't exist
*
* @return boolean TRUE if config exists
*/
function check_upgrade_config( $display_message = false )
{
global $conf_path;
if( ! file_exists( $conf_path.'upgrade_policy.conf' ) )
{ // No upgrade config file
if( $display_message )
{ // Display error message:
global $Messages;
$Messages->add( TB_('WARNING: <code>upgrade_policy.conf</code> not found. We will use <code>/conf/upgrade_policy_sample.conf</code> by default but it is highly recommended you duplicate this file to <code>upgrade_policy.conf</code> and check its contents to make sure the upgrade policy is appropriate for your particluar site.'), 'warning' );
}
return false;
}
return true;
}
/**
* Get file name of the upgrade config depending on what exists
*
* @return string
*/
function get_upgrade_config_file_name()
{
global $conf_path;
if( file_exists( $conf_path.'upgrade_policy.conf' ) )
{ // Use custom file firstly:
return 'upgrade_policy.conf';
}
else
{ // Use sample file:
return 'upgrade_policy_sample.conf';
}
}
/**
* Get a list of files and folders that must be ignored/removed on upgrade
*
* @param string Type of action: 'ignore', 'remove', 'softmove', 'forcemove'
* 'unknown' - Stores all unknown actions
* 'incorrect' - Stores all incorrect actions
* @return array|string List of files and folders | Error message
*/
function get_upgrade_config( $action )
{
global $conf_path, $upgrade_policy_config;
if( ! isset( $upgrade_policy_config ) )
{ // Init global array first time
$upgrade_policy_config = array();
}
elseif( is_string( $upgrade_policy_config ) )
{ // Return error about config file
return $upgrade_policy_config;
}
if( isset( $upgrade_policy_config[ $action ] ) )
{ // The config files were already initialized before, Don't make it twice
return $upgrade_policy_config[ $action ];
}
$config_handle = @fopen( $conf_path.get_upgrade_config_file_name(), 'r' );
if( ! $config_handle )
{ // No permissions to open file
$upgrade_policy_config = sprintf( TB_('No permission to open the %s file.'), '<code>'.get_upgrade_config_file_name().'</code>' );
return $upgrade_policy_config;
}
// Get content from config file
$config_content = '';
while( !feof( $config_handle ) )
{
$config_content .= fgets( $config_handle, 4096 );
}
fclose( $config_handle );
if( empty( $config_content ) )
{ // Config file is empty for required action
$upgrade_policy_config = sprintf( TB_('The %s file is empty.'), '<code>'.get_upgrade_config_file_name().'</code>' );
return $upgrade_policy_config;
}
// Only these actions are available in the upgrade_policy.conf
$available_actions = array( 'ignore', 'remove', 'softmove', 'forcemove' );
$all_actions = array_merge( $available_actions, array( 'unknown', 'incorrect' ) );
foreach( $all_actions as $available_action )
{ // Init array for all actions only first time
if( !isset( $upgrade_policy_config[ $available_action ] ) )
{
$upgrade_policy_config[ $available_action ] = array();
}
}
$config_content = str_replace( "\r", '', $config_content );
$config_content = explode( "\n", $config_content );
foreach( $config_content as $config_line )
{
if( substr( $config_line, 0, 1 ) == ';' )
{ // This line is comment text, Skip it
continue;
}
$config_line = trim( $config_line );
$config_line_params = explode( ' ', $config_line );
$line_action = $config_line_params[0];
if( in_array( $line_action, $available_actions ) )
{ // This line has an available action
if( empty( $config_line_params[1] ) )
{ // Incorrect command
$upgrade_policy_config[ 'incorrect' ][] = $config_line;
continue;
}
if( $line_action == 'softmove' || $line_action == 'forcemove' )
{ // These actions have two params
if( empty( $config_line_params[1] ) || empty( $config_line_params[2] ) )
{ // Incorrect command
$upgrade_policy_config[ 'incorrect' ][] = $config_line;
continue;
}
$upgrade_policy_config[ $line_action ][ $config_line_params[1] ] = $config_line_params[2];
}
else
{ // Actions 'ignore' & 'remove' have only one param
$upgrade_policy_config[ $line_action ][] = $config_line_params[1];
}
}
elseif( !empty( $line_action ) )
{ // Also save all unknown actions to display error
$upgrade_policy_config[ 'unknown' ][] = $config_line;
}
}
return $upgrade_policy_config[ $action ];
}
/**
* Remove files/folders after upgrade, See file upgrade_policy.conf
*/
function remove_after_upgrade()
{
global $basepath, $conf_path;
$upgrade_removed_files = get_upgrade_config( 'remove' );
echo '<h4>'.TB_('Cleaning up...').'</h4>';
evo_flush();
if( is_string( $upgrade_removed_files ) )
{ // Errors on opening of upgrade_policy.conf
$config_error = $upgrade_removed_files;
}
elseif( empty( $upgrade_removed_files ) )
{ // No files/folders to remove, Exit here
$config_error = sprintf( TB_('No "remove" sections have been defined in the file %s.'), '<code>'.get_upgrade_config_file_name().'</code>' );
}
if( !empty( $config_error ) )
{ // Display config error
echo '<div class="red">';
echo $config_error;
echo ' '.TB_('No cleanup is being done. You should manually remove the <code>/install</code> folder and check for other unwanted files...');
echo '</div>';
return;
}
foreach( $upgrade_removed_files as $file_path )
{
$file_path = $basepath.$file_path;
$log_message = sprintf( TB_('Removing %s as stated in %s...'), '<code>'.$file_path.'</code>', '<code>'.get_upgrade_config_file_name().'</code>' ).' ';
$success = true;
if( file_exists( $file_path ) )
{ // File exists
if( is_dir( $file_path ) )
{ // Remove folder recursively
if( rmdir_r( $file_path ) )
{ // Success
$log_message .= TB_('OK');
}
else
{ // Failed
$log_message .= TB_('Failed').': '.TB_('No permissions to delete the folder');
$success = false;
}
}
elseif( is_writable( $file_path ) )
{ // Remove file
if( @unlink( $file_path ) )
{ // Success
$log_message .= TB_('OK');
}
else
{ // Failed
$log_message .= TB_('Failed').': '.TB_('No permissions to delete the file');
$success = false;
}
}
else
{ // File is not writable
$log_message .= TB_('Failed').': '.TB_('No permissions to delete the file');
$success = false;
}
}
else
{ // No file/folder
$log_message .= TB_('Failed').': '.TB_('No file found');
$success = false;
}
echo $success ? $log_message.'<br />' : '<div class="orange">'.$log_message.'</div>';
evo_flush();
}
}
/**
* Get affected paths
*
* @param string Path
* @return string
*/
function get_affected_paths( $path )
{
global $basepath;
$affected_paths = TB_('Affected paths:').' ';
if( is_array( $path ) )
{
$paths = array();
foreach( $path as $p )
$paths[] = no_trailing_slash( $p );
$affected_paths .= implode( ', ', $paths );
}
elseif( $path == '*' )
{
$filename_params = array(
'inc_files' => false,
'recurse' => false,
'basename' => true,
);
$affected_paths .= implode( ', ', get_filenames( $basepath, $filename_params ) );
}
else
{
$affected_paths .= no_trailing_slash( $path );
}
return $affected_paths;
}
/**
* Get affected tables
*
* @param string Table
* @return string
*/
function get_affected_tables( $table )
{
global $DB;
$affected_tables = TB_('Affected tables:').' ';
if( is_array( $table ) )
{
$affected_tables .= implode( ', ', aliases_to_tables( $table ) );
}
elseif( $table == '*' )
{
// Get tables what should be excluded from full tables list:
global $backup_tables;
$exclude_tables = array();
foreach( $backup_tables as $backup_data )
{
if( isset( $backup_data['included'] ) &&
! $backup_data['included'] &&
is_array( $backup_data['table'] ) )
{
$exclude_tables = array_merge( $exclude_tables, aliases_to_tables( $backup_data['table'] ) );
}
}
$tables = array();
foreach( $DB->get_results( 'SHOW TABLES', ARRAY_N ) as $row )
{
if( ! in_array( $row[0], $exclude_tables ) )
{
$tables[] = $row[0];
}
}
$affected_tables .= implode( ', ', $tables );
}
else
{
$affected_tables .= aliases_to_tables( $table );
}
return $affected_tables;
}
/**
* Get html template of steps panel
*
* @param array Steps
* @param integer Current step
* @return string
*/
function get_tool_steps( $steps, $current_step )
{
if( empty( $steps ) || empty( $current_step ) )
{ // Bad input data
return '';
}
$r = '<div class="tool_steps">';
foreach( $steps as $step_num => $step_title )
{
$r .= '<div class="step'
.( $step_num == $current_step ? ' current' : '' )
.( $step_num < $current_step ? ' completed' : '' ).'">'
.'<div>'.$step_num
.( $step_num < $current_step ? '<span>✓</span>' : '' )
.'</div>'
.$step_title
.'</div>';
}
$r .= '</div>';
return $r;
}
/**
* Display steps panel
*
* @param integer Current step
* @param string Type: 'auto', 'git'
*/
function autoupgrade_display_steps( $current_step, $type = '' )
{
$steps = array(
1 => $type == 'git' ? TB_('Connect to Git') : TB_('Check for updates'),
2 => TB_('Download'),
3 => TB_('Unzip'),
4 => TB_('Ready to upgrade'),
5 => TB_('Backup & Upgrade'),
6 => TB_('Installer script'),
);
echo get_tool_steps( $steps, $current_step );
}
?>