Seditio Source
Root |
./othercms/b2evolution_7.2.3/inc/maintenance/model/_maintenance.funcs.php
<?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: &laquo;%s&raquo;'), $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: &laquo;%s&raquo;'), $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 &laquo;%s&raquo; 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 &laquo;%s&raquo; 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&amp;action=edit&amp;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 &laquo;%s&raquo; 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 &laquo;%s&raquo; 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 &laquo;<strong>%s</strong>&raquo; 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 &laquo;<strong>%s</strong>&raquo;...'), $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 &laquo;'.htmlspecialchars( $src ).'&raquo; 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'), '&laquo;<b>'.$dest_dir.'</b>&raquo;', '<code>'.get_upgrade_config_file_name().'</code>' ).'</div>';
            }
            else
            {
// progressive display of what backup is doing
               
echo $action.' &laquo;<strong>'.$dest_dir.'</strong>&raquo;...';
               
$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'), '&laquo;<b>'.$dest_dir_name.'</b>&raquo;', '<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.'), '&laquo;<b>'.$dest_dir_name.'</b>&raquo;' ).'</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'), '&laquo;<b>'.$dest_file_name.'</b>&raquo;', '<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)'),
                       
'&laquo;<b>'.$dest_file_name.'</b>&raquo;',
                       
'&laquo;<b>'.$copy_file_name.'</b>&raquo;',
                       
'<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'),
                       
'&laquo;<b>'.$dest_file_name.'</b>&raquo;',
                       
'&laquo;<b>'.$copy_file_name.'</b>&raquo;',
                       
'<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.'), '&laquo;<b>'.$dest_file_name.'</b>&raquo;' ).'</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>&#10003;</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 &amp; Upgrade'),
           
6 => TB_('Installer script'),
        );

    echo
get_tool_steps( $steps, $current_step );
}
?>