Вход Регистрация
Файл: apwa/includes/acp/acp_mods.php
Строк: 2664
<?php
/**
*
* @package automod
* @version $Id$
* @copyright (c) 2008 phpBB Group
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
*
*/

/**
*/
if (!defined('IN_PHPBB'))
{
    exit;
}

/**
* @package automod
*/
class acp_mods
{
    var 
$u_action;
    var 
$parser;
    var 
$mod_root '';
    var 
$store_dir '';
    var 
$mods_dir '';
    var 
$edited_root '';
    var 
$backup_root '';
    var 
$sort_key '';
    var 
$sort_dir '';

    function 
main($id$mode)
    {
        global 
$config$db$user$auth$template$cache;
        global 
$phpbb_root_path$phpEx;
        global 
$ftp_method$test_ftp_connection$test_connection$sort_key$sort_dir;

        include(
"{$phpbb_root_path}includes/functions_transfer.$phpEx");
        include(
"{$phpbb_root_path}includes/editor.$phpEx");
        include(
"{$phpbb_root_path}includes/functions_mods.$phpEx");
        include(
"{$phpbb_root_path}includes/mod_parser.$phpEx");

        
// start the page
        
$user->add_lang(array('install''acp/mods'));

        
$this->tpl_name 'acp_mods';
        
$this->page_title 'ACP_CAT_MODS';
        
$this->store_dir $phpbb_root_path 'store';
        
$this->mods_dir $phpbb_root_path 'store/mods';

        
// get any url vars
        
$action request_var('action''');
        
$mod_id request_var('mod_id'0);
        
$mod_url request_var('mod_url''');
        
$parent request_var('parent'0);

        
//sort keys
        
$sort_key request_var('sk','t');
        
$sort_dir    request_var('sd''a');


        
$mod_path request_var('mod_path''');

        if (
$mod_path)
        {
            
$mod_path htmlspecialchars_decode($mod_path);                // "/my_mod/install.xml" or "/./contrib/blah.xml"
            
$mod_dir substr($mod_path1strpos($mod_path'/'1));    // "my_mod/"

            
$this->mod_root $this->mods_dir '/' $mod_dir;            // "./../store/mods/my_mod/"
            
$this->backup_root "{$this->mod_root}_backups/";            // "./../store/mods/my_mod/_backups/"
            
$this->edited_root "{$this->mod_root}_edited/";            // "./../store/mods/my_mod/_edited/"
        
}

        switch (
$mode)
        {
            case 
'config':
                
$ftp_method        request_var('ftp_method'$config['ftp_method']);
                if (!
$ftp_method || !class_exists($ftp_method))
                {
                    
$ftp_method 'ftp';
                    
$ftp_methods transfer::methods();

                    if (!
in_array('ftp'$ftp_methods))
                    {
                        
$ftp_method $ftp_methods[0];
                    }
                }

                if (isset(
$_POST['submit']) && check_form_key('acp_mods'))
                {
                    
$ftp_host        request_var('host''');
                    
$ftp_username    request_var('username''');
                    
$ftp_password    request_var('password'''); // not stored, used to test connection
                    
$ftp_root_path    request_var('root_path''');
                    
$ftp_port        request_var('port'21);
                    
$ftp_timeout    request_var('timeout'10);
                    
$write_method    request_var('write_method'0);
                    
$file_perms        request_var('file_perms''0644');
                    
$dir_perms        request_var('dir_perms''0755');
                    
$compress_method    request_var('compress_method''');
                    
$preview_changes    request_var('preview_changes'0);


                    
$error '';
                    if (
$write_method == WRITE_DIRECT)
                    {
                        
// the very best method would be to check every file for is_writable
                        
if (!is_writable("{$phpbb_root_path}common.$phpEx") || !is_writable("{$phpbb_root_path}adm/style/acp_groups.html"))
                        {
                            
$error 'FILESYSTEM_NOT_WRITABLE';
                        }
                    }
                    else if (
$write_method == WRITE_FTP)
                    {
                        
// check the correctness of FTP infos
                        
$test_ftp_connection true;
                        
$test_connection false;
                        
test_ftp_connection($ftp_method$test_ftp_connection$test_connection);

                        if (
$test_connection !== true)
                        {
                            
$error $test_connection;
                        }
                    }
                    else if (
$write_method == WRITE_MANUAL)
                    {
                        
// the compress class requires write access to the store/ dir
                        
if (!is_writable($this->store_dir))
                        {
                            
$error 'STORE_NOT_WRITABLE';
                        }
                    }

                    if (empty(
$error))
                    {
                        
set_config('ftp_method',    $ftp_method);
                        
set_config('ftp_host',        $ftp_host);
                        
set_config('ftp_username',    $ftp_username);
                        
set_config('ftp_root_path'$ftp_root_path);
                        
set_config('ftp_port',        $ftp_port);
                        
set_config('ftp_timeout',    $ftp_timeout);
                        
set_config('write_method',    $write_method);
                        
set_config('compress_method',    $compress_method);
                        
set_config('preview_changes',    $preview_changes);
                        
set_config('am_file_perms',        $file_perms);
                        
set_config('am_dir_perms',        $dir_perms);

                        
trigger_error($user->lang['MOD_CONFIG_UPDATED'] . adm_back_link($this->u_action));
                    }
                    else
                    {
                        
$template->assign_var('ERROR'$user->lang[$error]);
                    }
                }
                else if (isset(
$_POST['submit']) && !check_form_key('acp_mods'))
                {
                    
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
                }

                
add_form_key('acp_mods');

                
// implicit else
                
include("{$phpbb_root_path}includes/functions_compress.$phpEx");
                foreach (
compress::methods() as $compress_method)
                {
                    
$template->assign_block_vars('compress', array(
                        
'METHOD'    => $compress_method,
                    ));
                }

                
$requested_data call_user_func(array($ftp_method'data'));
                foreach (
$requested_data as $data => $default)
                {
                    
$default = (!empty($config['ftp_' $data])) ? $config['ftp_' $data] : $default;
                    
$template->assign_block_vars('data', array(
                        
'DATA'        => $data,
                        
'NAME'        => $user->lang[strtoupper($ftp_method '_' $data)],
                        
'EXPLAIN'    => $user->lang[strtoupper($ftp_method '_' $data) . '_EXPLAIN'],
                        
'DEFAULT'    => (!empty($_REQUEST[$data])) ? request_var($data'') : $default
                    
));
                }

                
$template->assign_vars(array(
                    
'S_CONFIG'            => true,
                    
'U_CONFIG'            => $this->u_action '&amp;mode=config',

                    
'UPLOAD_METHOD_FTP'    => ($config['ftp_method'] == 'ftp') ? ' checked="checked"' '',
                    
'UPLOAD_METHOD_FSOCK'=> ($config['ftp_method'] == 'ftp_fsock') ? ' checked="checked"' '',
                    
'WRITE_DIRECT'        => ($config['write_method'] == WRITE_DIRECT) ? ' checked="checked"' '',
                    
'WRITE_FTP'            => ($config['write_method'] == WRITE_FTP) ? ' checked="checked"' '',
                    
'WRITE_MANUAL'        => ($config['write_method'] == WRITE_MANUAL) ? ' checked="checked"' '',

                    
'WRITE_METHOD_DIRECT'    => WRITE_DIRECT,
                    
'WRITE_METHOD_FTP'        => WRITE_FTP,
                    
'WRITE_METHOD_MANUAL'    => WRITE_MANUAL,

                    
'AUTOMOD_VERSION'        => $config['automod_version'],
                    
'COMPRESS_METHOD'        => $config['compress_method'],
                    
'DIR_PERMS'                => $config['am_dir_perms'],
                    
'FILE_PERMS'            => $config['am_file_perms'],
                    
'PREVIEW_CHANGES_YES'    => ($config['preview_changes']) ? ' checked="checked"' '',
                    
'PREVIEW_CHANGES_NO'    => (!$config['preview_changes']) ? ' checked="checked"' '',
                    
'S_HIDE_FTP'            => ($config['write_method'] == WRITE_FTP) ? false true,
                ));
            break;

            case 
'frontend':
                if (
$config['write_method'] == WRITE_FTP)
                {
                    
$ftp_method basename(request_var('method'$config['ftp_method']));
                    if (!
$ftp_method || !class_exists($ftp_method))
                    {
                        
$ftp_method 'ftp';
                        
$ftp_methods transfer::methods();

                        if (!
in_array('ftp'$ftp_methods))
                        {
                            
$ftp_method $ftp_methods[0];
                        }
                    }

                    
$test_connection false;
                    
$test_ftp_connection request_var('test_connection''');
                    if (!empty(
$test_ftp_connection) || in_array($action, array('install''uninstall''upload_mod''delete_mod')))
                    {
                        
test_ftp_connection($ftp_method$test_ftp_connection$test_connection);

                        
// Make sure the login details are correct before continuing
                        
if ($test_connection !== true || !empty($test_ftp_connection))
                        {
                                
$action 'pre_' $action;
                        }
                    }
                }

                
// store/ needs to be world-writable even when FTP is the write method,
                // for extracting uploaded mod zip files
                
if (!is_writable($this->store_dir))
                {
                    
$template->assign_var('S_STORE_WRITABLE_WARN'true);
                }
                
// Otherwise, store/mods/ needs to be writable
                
else if ($config['write_method'] != WRITE_FTP && !is_writable($this->mods_dir))
                {
                    
$template->assign_var('S_MODS_WRITABLE_WARN'true);
                }

                switch (
$action)
                {
                    case 
'pre_install':
                    case 
'install':
                        
$this->install($action$mod_path$parent);
                    break;

                    case 
'pre_uninstall':
                    case 
'uninstall':
                        
$this->uninstall($action$mod_id$parent);
                    break;

                    case 
'details':
                        
$mod_ident = ($mod_id) ? $mod_id $mod_path;
                        
$this->list_details($mod_ident);
                    break;

                    case 
'pre_delete_mod':
                    case 
'delete_mod':
                        
$this->delete_mod($action$mod_path);
                        break;

                    case 
'pre_upload_mod':
                    case 
'upload_mod':
                    default:
                        
$action = (isset($action)) ? $action '';
                        if (!
$this->upload_mod($action))
                        {
                            
$this->list_installed();
                            
$this->list_uninstalled();
                        }
                    break;

                    case 
'download':
                        include (
$phpbb_root_path "includes/functions_compress.$phpEx");
                        
$editor = new editor_manual();

                        
$time request_var('time'0);

                        
// if for some reason the MOD isn't found in the DB...
                        
$download_name 'mod_' $time;
                        
$sql 'SELECT mod_name FROM ' MODS_TABLE '
                            WHERE mod_time = ' 
$time;
                        
$result $db->sql_query($sql);

                        if (
$row $db->sql_fetchrow($result))
                        {
                            
// Always use the English name except for showing the user.
                            
$mod_name localize_title($row['mod_name'], 'en');
                            
$download_name str_replace(' ''_'$mod_name);
                        }

                        
$editor->compress->download("{$this->store_dir}/mod_$time"$download_name);
                        exit;
                    break;
                }

                return;

            break;

        }
    }

    
/**
    * List all the installed mods
    */
    
function list_installed()
    {
        global 
$db$template$user$sort_key$sort_dir;
         
$sort_by_text = array('u' => $user->lang['SORT_NAME'], 't' => $user->lang['SORT_DATE']);

        (
$sort_key == 't')? $sort='mod_time' $s_sort_key='mod_time'$sort='mod_name' $s_sort_key='mod_name';
        (
$sort_dir == 'd') ? $dir='DESC' &  $s_sort_dir='DESC' $dir='ASC' $s_sort_dir='ASC';
        
$limit_days = array();
        
$s_limit_days=$sort_days=$s_limit_days $u_sort_param '';
        
gen_sort_selects($limit_days$sort_by_text$sort_days$sort_key$sort_dir$s_limit_days$s_sort_key$s_sort_dir$u_sort_param);

        
$template->assign_vars(array(
                
'S_SORT_KEY'    => $s_sort_key,
                
'S_SORT_DIR'    => $s_sort_dir,
                
'U_SORT_ACTION'        => $this->u_action ."&amp;$u_sort_param"
        
));
        
// The MOD name is a array so it can't be used as sort key directly.
        
$sql_sort = ($sort_key == 't') ? " ORDER BY mod_time $dir'';
        
$sql 'SELECT mod_name, mod_id, mod_time
            FROM ' 
MODS_TABLE .
            
$sql_sort;
        
$result $db->sql_query($sql);
        
$mod_ary $db->sql_fetchrowset($result);
        
$db->sql_freeresult($result);

        foreach (
$mod_ary as $key => $row)
        {
            if ((
$name_ary = @unserialize($row['mod_name'])) === false)
            {
                
$name_ary['en'] = $row['mod_name'];
            }

            
$mod_ary[$key]['mod_name'] = $name_ary;
        }

        if (
$sort_key != 't')
        {
            
$sort_ary = array();
            foreach (
$mod_ary as $key => $row)
            {
                
$sort_ary[$key] = $row['mod_name']['en'];
            }

            if (
$sort_dir == 'd')
            {
                
arsort($sort_arySORT_STRING);
            }
            else
            {
                
asort($sort_arySORT_STRING);
            }

            foreach (
$sort_ary as $key => $name)
            {
                
$sort_ary[$key] = $mod_ary[$key];
            }

            
$mod_ary $sort_ary;
            unset(
$sort_ary);
        }

        foreach (
$mod_ary as $row)
        {
            
$mod_name localize_title($row['mod_name'], $user->data['user_lang']);
            
$template->assign_block_vars('installed', array(
                
'MOD_ID'        => $row['mod_id'],
                
'MOD_NAME'        => htmlspecialchars($mod_name),

                
'MOD_TIME'      => $user->format_date($row['mod_time']),

                
'U_DETAILS'        => $this->u_action '&amp;action=details&amp;mod_id=' $row['mod_id'],
                
'U_UNINSTALL'    => $this->u_action '&amp;action=pre_uninstall&amp;mod_id=' $row['mod_id'])
            );
        }

        return;
    }

    
/**
    * List all mods available locally
    */
    
function list_uninstalled()
    {
        global 
$phpbb_root_path$db$template$config$user;

        
// get available MOD paths
        
$available_mods $this->find_mods($this->mods_dir1);

        if (!
sizeof($available_mods['main']))
        {
            return;
        }

        
// get installed MOD paths
        
$installed_paths = array();
        
$sql 'SELECT mod_path
            FROM ' 
MODS_TABLE;
        
$result $db->sql_query($sql);
        while (
$row $db->sql_fetchrow($result))
        {
            
$installed_paths[] = $row['mod_path'];
        }
        
$db->sql_freeresult($result);

        
$mod_paths = array();
        foreach (
$available_mods['main'] as $mod_info)
        {
            
$mod_paths[] = $mod_info['href'];
        }

        
// we don't care about any xml files not in the main directory
        
$available_mods array_diff($mod_paths$installed_paths);
        unset(
$installed_paths);
        unset(
$mod_paths);

        
// show only available MODs that paths aren't in the DB
        
foreach ($available_mods as $file)
        {
            
$details $this->mod_details($filefalse);
            
$short_path urlencode(str_replace($this->mods_dir''$details['MOD_PATH']));
            
$mod_name localize_title($details['MOD_NAME'], $user->data['user_lang']);

            
$template->assign_block_vars('uninstalled', array(
                
'MOD_NAME'    => htmlspecialchars($mod_name),
                
'MOD_PATH'    => $short_path,

                
'PHPBB_VERSION'        => $details['PHPBB_VERSION'],
                
'S_PHPBB_VESION'    => ($details['PHPBB_VERSION'] != $config['version']) ? true false,

                
'U_INSTALL'    => $this->u_action "&amp;action=pre_install&amp;mod_path=$short_path",
                
'U_DELETE'    => $this->u_action "&amp;action=pre_delete_mod&amp;mod_path=$short_path",
                
'U_DETAILS'    => $this->u_action "&amp;action=details&amp;mod_path=$short_path",
            ));
        }

        return;
    }

    
/**
    * Lists mod details
    */
    
function list_details($mod_ident)
    {
        global 
$template$config$user;

        
$template->assign_vars(array(
            
'S_DETAILS'    => true,
            
'U_BACK'    => $this->u_action,
        ));

        
$details $this->mod_details($mod_identtrue);

        if (!
is_int($mod_ident) && $details['PHPBB_VERSION'] != $config['version'])
        {
            
$version_warnig sprintf($user->lang['VERSION_WARNING'], $details['PHPBB_VERSION'], $config['version']);

            
$template->assign_vars(array(
                
'VERSION_WARNING'    => $version_warnig,
                
'S_PHPBB_VESION'    => true,
            ));
        }

        if (!empty(
$details['AUTHOR_DETAILS']))
        {
            foreach (
$details['AUTHOR_DETAILS'] as $author_details)
            {
                
$template->assign_block_vars('author_list'$author_details);
            }
            unset(
$details['AUTHOR_DETAILS']);
        }

        
// Display Do-It-Yourself Actions...per the MODX spec,
        // Need to handle the languag later, but it's not saved for now.
        
if (!empty($details['DIY_INSTRUCTIONS']))
        {
            
$template->assign_var('S_DIY'true);

            if (!
is_array($details['DIY_INSTRUCTIONS']))
            {
                
$details['DIY_INSTRUCTIONS'] = array($details['DIY_INSTRUCTIONS']);
            }

            foreach (
$details['DIY_INSTRUCTIONS'] as $instruction)
            {
                
$template->assign_block_vars('diy_instructions', array(
                    
'DIY_INSTRUCTION'    => nl2br($instruction),
                ));
            }
        }

        if (!empty(
$details['MOD_HISTORY']))
        {
            
$template->assign_var('S_CHANGELOG'true);

            foreach (
$details['MOD_HISTORY'] as $mod_version)
            {
                
$template->assign_block_vars('changelog', array(
                    
'VERSION'    => $mod_version['VERSION'],
                    
'DATE'        => $mod_version['DATE'],
                ));

                foreach (
$mod_version['CHANGES'] as $changes)
                {
                    
$template->assign_block_vars('changelog.changes', array(
                        
'CHANGE'    => $changes,
                    ));
                }
            }
        }

        unset(
$details['MOD_HISTORY']);

        
$details['MOD_NAME'] = localize_title($details['MOD_NAME'], $user->data['user_lang']);
        
$details['MOD_NAME'] = htmlspecialchars($details['MOD_NAME']);

        
$template->assign_vars($details);

        if (!empty(
$details['AUTHOR_NOTES']))
        {
            
$template->assign_var('S_AUTHOR_NOTES'true);
        }
        if (!empty(
$details['MOD_INSTALL_TIME']))
        {
            
$template->assign_var('S_INSTALL_TIME'true);
        }

        return;
    }

    
/**
    * Returns array of mod information
    */
    
function mod_details($mod_ident$find_children true$uninstall false)
    {
        global 
$phpbb_root_path$phpEx$user$template$parent_id;

        if (
is_int($mod_ident))
        {
            global 
$db$user;

            
$mod_id = (int) $mod_ident;

            
$sql 'SELECT *
                FROM ' 
MODS_TABLE "
                    WHERE mod_id = 
$mod_id";
            
$result $db->sql_query($sql);
            if (
$row $db->sql_fetchrow($result))
            {
                
// TODO: Yuck, get rid of this.
                
$author_details = array();
                
$author_details[0] = array(
                        
'AUTHOR_NAME'        => $row['mod_author_name'],
                        
'AUTHOR_EMAIL'        => $row['mod_author_email'],
                        
'AUTHOR_WEBSITE'    => $row['mod_author_url'],
                );

                
$actions unserialize($row['mod_actions']);

                
$details = array(
                    
'MOD_ID'            => $row['mod_id'],
                    
'MOD_PATH'            => $row['mod_path'],
                    
'MOD_INSTALL_TIME'    => $user->format_date($row['mod_time']),
//                    'MOD_DEPENDENCIES'    => unserialize($row['mod_dependencies']), // ?
                    
'MOD_NAME'            => $row['mod_name'],
                    
'MOD_DESCRIPTION'    => nl2br($row['mod_description']),
                    
'MOD_VERSION'        => $row['mod_version'],

                    
'DIY_INSTRUCTIONS'    => (!empty($actions['DIY_INSTRUCTIONS'])) ? $actions['DIY_INSTRUCTIONS'] : '',

                    
'AUTHOR_NOTES'        => nl2br($row['mod_author_notes']),
                    
'AUTHOR_DETAILS'    => $author_details,
                );

                
// This is a check for any further XML files to go with this MOD.
                // Obviously, the files must not have been removed for this to work.
                
if (($find_children || $uninstall) && file_exists($row['mod_path']))
                {
                    
$parent_id $mod_id;
                    
$mod_path $row['mod_path'];

                    
$actions = array();

                    
$mod_dir dirname($mod_path);
                    
$this->mod_root $mod_dir '/';

                    
$ext substr(strrchr($mod_path'.'), 1);
                    
$this->parser = new parser($ext);
                    
$this->parser->set_file($mod_path);

                    
// Find and display the available MODX files
                    
$children $this->find_children($mod_path);

                    
$elements = array('language' => array(), 'template' => array());
                    
$found_prosilver false;

                    if (!
$uninstall)
                    {
                        
$this->handle_contrib($children);
                        
$this->handle_language_prompt($children$elements'details');
                        
$this->handle_template_prompt($children$elements'details');

                        
// Now offer to install additional templates
                        
if (isset($children['template']) && sizeof($children['template']))
                        {
                            
// These are the instructions included with the MOD
                            
foreach ($children['template'] as $template_name)
                            {
                                if (!
is_array($template_name))
                                {
                                    continue;
                                }

                                if (
$template_name['realname'] == 'prosilver')
                                {
                                    
$found_prosilver true;
                                }

                                if (
file_exists($this->mod_root $template_name['href']))
                                {
                                    
$xml_file $template_name['href'];
                                }
                                else
                                {
                                    
$xml_file str_replace($this->mods_dir''$mod_dir) . '/' $template_name['href'];
                                }

                                
$template->assign_block_vars('avail_templates', array(
                                    
'TEMPLATE_NAME'    => $template_name['realname'],
                                    
'XML_FILE'        => urlencode($xml_file),
                                ));
                            }
                        }
                    }
                    else
                    {
                        if (isset(
$children['uninstall']) && sizeof($children['uninstall']))
                        {
                            
// Override already exising actions with the ones
                            
global $rev_actions;
                            
$xml_file $mod_dir '/' ltrim($children['uninstall'][0]['href'], './');
                            
$this->parser->set_file($xml_file);
                            
$rev_actions $this->parser->get_actions();
                        }
                    }

                    if (!
$found_prosilver)
                    {
                        
$template->assign_block_vars('avail_templates', array(
                            
'TEMPLATE_NAME'    => 'prosilver',
                            
'XML_FILE'        => basename($mod_path),
                        ));
                    }

                    
$processed_templates = array('prosilver');
                    
$processed_templates += explode(','$row['mod_template']);

                    
// now grab the templates that have not already been processed
                    
$sql 'SELECT template_id, template_path FROM ' STYLES_TEMPLATE_TABLE '
                        WHERE ' 
$db->sql_in_set('template_name'$processed_templatestrue);
                    
$result $db->sql_query($sql);

                    while (
$row $db->sql_fetchrow($result))
                    {
                        
$template->assign_block_vars('board_templates', array(
                            
'TEMPLATE_ID'        => $row['template_id'],
                            
'TEMPLATE_NAME'        => $row['template_path'],
                        ));
                    }

                    
$s_hidden_fields build_hidden_fields(array(
                        
'action'    => ($uninstall) ? 'uninstall' 'pre_install',
                        
'parent'    => $parent_id,
                    ));

                    
$template->assign_vars(array(
                        
'S_FORM_ACTION'        => $this->u_action,
                        
'S_HIDDEN_FIELDS'    => $s_hidden_fields,
                    ));

                    
add_form_key('acp_mods');
                }
            }
            else
            {
                
trigger_error($user->lang['NO_MOD'] . adm_back_link($this->u_action), E_USER_WARNING);
            }
            
$db->sql_freeresult($result);
        }
        else
        {
            
$parent request_var('parent'0);
            if (
$parent)
            {
                global 
$db;
                
// reset the class parameters to refelect the proper directory
                
$sql 'SELECT mod_path FROM ' MODS_TABLE '
                    WHERE mod_id = ' 
. (int) $parent;
                
$result $db->sql_query($sql);

                if (
$row $db->sql_fetchrow($result))
                {
                    
$this->mod_root dirname($row['mod_path']) . '/';
                }
            }

            if (
strpos($mod_ident$this->mods_dir) === false)
            {
                
$mod_ident $this->mods_dir $mod_ident;
            }

            if (!
file_exists($mod_ident))
            {
                
$mod_ident str_replace($this->mods_dir$this->mod_root$mod_ident);
            }

            
$mod_path $mod_ident;
            
$mod_parent 0;

            
$ext substr(strrchr($mod_path'.'), 1);

            
$this->parser = new parser($ext);
            
$this->parser->set_file($mod_path);

            
$details $this->parser->get_details();

            if (
$find_children)
            {
                
$actions = array();
                
$children $this->find_children($mod_path);

                
$elements = array('language' => array(), 'template' => array());

                
$this->handle_contrib($children);
                
$this->handle_language_prompt($children$elements'details');
                
$this->handle_template_prompt($children$elements'details');
            }
        }

        return 
$details;
    }

    
/**
    * Returns complex array of all mod actions
    */
    
function mod_actions($mod_ident)
    {
        global 
$phpbb_root_path$phpEx;

        if (
is_int($mod_ident))
        {
            global 
$db$user;

            
$sql 'SELECT mod_actions, mod_name
                FROM ' 
MODS_TABLE "
                    WHERE mod_id = 
$mod_ident";
            
$result $db->sql_query($sql);
            
$row $db->sql_fetchrow($result);
            
$db->sql_freeresult($result);

            if (
$row)
            {
                
$mod_actions unserialize($row['mod_actions']);

                if (@
unserialize($row['mod_name']) === false)
                {
                    
// On version 1.0.1 and later the mod name is a serialized array.
                    // Earlier it was a string so unserialize will fail.
                    
$mod_actions['EDITS'] = $this->update_edits($mod_actions['EDITS']);
                }

                return(
$mod_actions);
            }
            else
            {
                
trigger_error($user->lang['NO_MOD'] . adm_back_link($this->u_action), E_USER_WARNING);
            }
        }
        else
        {
            if (
strpos($mod_ident$this->mods_dir) === false)
            {
                
$mod_ident $this->mods_dir $mod_ident;
            }

            if (!
file_exists($mod_ident))
            {
                
$mod_ident str_replace($this->mods_dir$this->mod_root$mod_ident);
            }

            
$this->parser->set_file($mod_ident);
            
$actions $this->parser->get_actions();
        }

        return 
$actions;

    }

    
/**
     * Updates inline edits for MODs installed before AutoMOD 1.0.1.
     *
     * @param array $mod_edits, MOD actions directly from the DB.
     * @return mixed uppdated array or false on error.
     */
    
function update_edits($mod_edits)
    {
        if (empty(
$mod_edits))
        {
            return(
false);
        }

        
$updated_ary = array();

        foreach (
$mod_edits as $file => $edits)
        {
            
$updated_ary[$file] = array();
            
$inline false;
            
$key 0;
            
$old_find $find_line '';

            foreach (
$edits as $edit)
            {
                foreach (
$edit as $find => $action)
                {
                    
$first_key key($action); // The first key contains the action or "in-line-edit".

                    
if ($first_key != 'in-line-edit')
                    {
                        if (
$inline)
                        {
                            
$updated_ary[$file][$key++][$find_line] = array('in-line-edit' => $inline_edit);
                            
$inline_edit = array();
                            
$inline false;
                            
$old_find $find_line '';
                        }

                        
$updated_ary[$file][$key++][$find] = $action;
                        
$inline false;
                        continue;
                    }

                    
$inline true;
                    
$inline_edit = (empty($inline_edit)) ? array() : $inline_edit;

                    if (!empty(
$old_find) && !$this->same_line($old_find$find$action['in-line-edit']))
                    {
                        
$updated_ary[$file][$key++][$find_line] = array('in-line-edit' => $inline_edit);
                        
$inline_edit = array();
                    }

                    
$find_line $find;
                    
$old_find $find;
                    
$inline_edit[] = $action['in-line-edit'];
                }
            }

            if (
$inline && !empty($inline_edit))
            {
                
$updated_ary[$file][$key++][$find_line] = array('in-line-edit' => $inline_edit);
                
$inline false;
                
$inline_edit = array();
                
$old_find $find_line '';
            }
        }

        return(
$updated_ary);
    }

    
/**
    * Tries to check if two inline edits are editing the same line.
    *
    * @param string $prev, the find from the previous in-line-edit.
    * @param string $find, the find for the current in-line-edit.
    * @param array $action, the current edit array.
    * @return bool true for identical lines, otherwise false
    */
    
function same_line($prev_find$find$action)
    {
        if (empty(
$prev_find) || empty($find))
        {
            
// If both are empty something is wrong.
            
return(false);
        }

        
// The first key in $action is the in-line-find string
        
$edit_ary        reset($action);        // Array with what to do and what to remove.
        
$inline_find    key($action);    // String to find in $find.

        
$add_ary =    reset($edit_ary);    // $add_ary[0] contains the string to remove from $find
        
$add_str =    $add_ary[0];
        
$inline_action    key($edit_ary);    // What to do.

        // The actions currently supported are in-line-before-add and in-line-after-add.
        // replace and delete will be added later.
        
switch ($inline_action)
        {
            case 
'in-line-replace':
                
// There are no positions stored in the DB so we can not be sure that there
                // is only one occasion of the string added instead of the search string.
                // Keeping count on the previous edits still don't give a 100% guaranty that
                // we are in the right place in the string.
                
$compare str_replace($add_str$inline_find$find);
            break;

            case 
'in-line-before-add':
                
$pos strpos($find$inline_find);
                
$len strlen($add_str);
                
$start $pos $len;
                
$compare substr_replace($find''$start$len);
            break;

            case 
'in-line-after-add':
                
$pos strpos($find$inline_find);
                
$start $pos strlen($inline_find);
                
$compare substr_replace($find''$startstrlen($add_str));
            break;

            case 
'inline-remove':
            default:
                
// inline-remove don't yet work to install with AutoMOD so I assume nobody
                // is trying to remove it either in MODs installed with 1.0.0.1 or earlier.
                
return(false);
            break;
        }

        
$check = ($compare == $prev_find) ? true false;
        return(
$check);
    }

    
/**
    * Install/pre-install a mod
    * Preforms all Edits, Copies, and SQL queries
    */
    
function install($action$mod_path$parent 0)
    {
        global 
$phpbb_root_path$phpEx$db$template$user$config$cache$dest_template;
        global 
$force_install$mod_installed;

        
// Are we forcing a template install?
        
$dest_template $mod_contribs $mod_language '';
        if (isset(
$_POST['template_submit']))
        {
            if (!
check_form_key('acp_mods'))
            {
                
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
            }

            
$mod_path urldecode(request_var('source'''));
            
$dest_template request_var('dest''');

            if (
preg_match('#.*install.*xml$#i'$mod_path))
            {
                
$src_template 'prosilver';
            }
            else
            {
                
preg_match('#([a-z0-9]+)$#i'core_basename($mod_path), $match);
                
$src_template $match[1];
                unset (
$match);
            }
        }

        if (empty(
$mod_path))
        {
            return 
false;    // ERROR
        
}

        
$details $this->mod_details($mod_pathfalse);

        if (!
$parent)
        {
            
// $details['MOD_NAME'] is a array and not knowing what language was used when the MOD was installed,
            // if it was installed with AutoMOD 1.0.0. So need to check all.
            
$sql_where '';
            foreach (
$details['MOD_NAME'] as $mod_name)
            {
                
$sql_where .= (($sql_where == '') ? ' mod_name ' ' OR mod_name ') . $db->sql_like_expression($db->any_char $mod_name $db->any_char);
            }

            
$sql 'SELECT mod_name FROM ' MODS_TABLE "
                WHERE 
$sql_where";
            
$result $db->sql_query($sql);

            if (
$row $db->sql_fetchrow($result))
            {
                
trigger_error('AM_MOD_ALREADY_INSTALLED');
            }
        }
        else if (
$dest_template// implicit && $parent
        
{
            
// Has this template already been processed?
            
$sql 'SELECT mod_name
                    FROM ' 
MODS_TABLE "
                    WHERE mod_id = 
$parent
                        AND mod_template " 
$db->sql_like_expression($db->any_char $dest_template $db->any_char);
            
$result $db->sql_query($sql);

            if (
$row $db->sql_fetchrow($result))
            {
                
trigger_error('AM_MOD_ALREADY_INSTALLED');
            }
            
$db->sql_freeresult($result);
        }
        
// NB: There could and should be cases to check for duplicated MODs and contribs
        // However, there is not appropriate book-keeping in place for those in 1.0.x
        // grab installed contrib and language items from the database
        
if ($parent)
        {
            
$modx_type request_var('type''');
            if (
$modx_type == 'lang')
            {
                
$sql 'SELECT mod_name
                        FROM ' 
MODS_TABLE "
                        WHERE mod_id = 
$parent
                            AND mod_languages " 
$db->sql_like_expression($db->any_char $mod_path $db->any_char);
                
$result $db->sql_query($sql);

                if (
$row $db->sql_fetchrow($result))
                {
                    
trigger_error('AM_MOD_ALREADY_INSTALLED');
                }
                else
                {
                    
$mod_language $mod_path;
                }
                
$db->sql_freeresult($result);
            }
            elseif (
$modx_type == 'contrib')
            {
                
$sql 'SELECT mod_name
                        FROM ' 
MODS_TABLE "
                        WHERE mod_id = 
$parent
                            AND mod_contribs " 
$db->sql_like_expression($db->any_char $mod_path $db->any_char);
                
$result $db->sql_query($sql);

                if (
$row $db->sql_fetchrow($result))
                {
                    
trigger_error('AM_MOD_ALREADY_INSTALLED');
                }
                else
                {
                    
$mod_contribs $mod_path;
                }
                
$db->sql_freeresult($result);
            }
        }

        
$execute_edits = ($action == 'pre_install') ? false true;
        
$write_method 'editor_' determine_write_method(!$execute_edits);
        
$editor = new $write_method();

        
// get FTP information if we need it (or initialize array $hidden_ary)
        
$hidden_ary get_connection_info(!$execute_edits);

        
$actions $this->mod_actions($mod_path);

        if (
$dest_template)
        {
            
$sql 'SELECT template_inherit_path FROM ' STYLES_TEMPLATE_TABLE "
                WHERE template_path = '" 
$db->sql_escape($dest_template) . "'";
            
$result $db->sql_query($sql);

            global 
$dest_inherits;
            
$dest_inherits '';
            if (
$row $db->sql_fetchrow($result))
            {
                
$dest_inherits $row['template_inherit_path'];
            }
            
$db->sql_freeresult($result);

            if (!empty(
$actions['EDITS']))
            {
                foreach (
$actions['EDITS'] as $file => $edits)
                {
                    if (
strpos($file'styles/') === false)
                    {
                        unset(
$actions['EDITS'][$file]);
                    }
                    else if (
$src_template != $dest_template)
                    {
                        
$file_new str_replace($src_template$dest_template$file);
                        
$actions['EDITS'][$file_new] = $edits;
                        unset(
$actions['EDITS'][$file]);
                    }
                }
            }

            if (!empty(
$actions['NEW_FILES']))
            {
                foreach (
$actions['NEW_FILES'] as $src_file => $dest_file)
                {
                    if (
strpos($src_file'styles/') === false)
                    {
                        unset(
$actions['NEW_FILES']);
                    }
                    else
                    {
                        
$actions['NEW_FILES'][$src_file] = str_replace($src_template$dest_template$dest_file);
                    }
                }
            }
        }

        
// only supporting one level of hierarchy here
        
if (!$parent)
        {
            
// check for "child" MODX files and attempt to decide which ones we need
            
$children $this->find_children($mod_path);

            
$elements = array('language' => array(), 'template' => array());

            if (
$execute_edits)
            {
                global 
$mode;
                
$this->handle_dependency($children$mode$mod_path);
            }
            
$this->handle_language_prompt($children$elements$action);
            
$this->handle_merge('language'$actions$children$elements['language']);
            
$this->handle_template_prompt($children$elements$action);
            
$this->handle_merge('template'$actions$children$elements['template']);
        }
        else
        {
            if (
$dest_template)
            {
                
$elements['template'] = array($dest_template);
            }
            elseif (
$mod_language)
            {
                
$elements['language'] = array($mod_path);
            }
            else
            {
                
$elements['contrib'] = array($mod_path);
            }
        }

        
$template->assign_vars(array(
            
'S_INSTALL'        => $execute_edits,
            
'S_PRE_INSTALL'    => !$execute_edits,
            
'MOD_PATH'        => str_replace($this->mod_root''$mod_path),
            
'U_INSTALL'        => $this->u_action '&amp;action=install' . ($parent "&amp;parent=$parent''),
            
'U_RETURN'        => $this->u_action,
            
'U_BACK'        => $this->u_action,
        ));

        if (
$execute_edits)
        {
            
$editor->create_edited_root($this->edited_root);
            
$force_install request_var('force'false);
        }

        
$display = ($execute_edits || $config['preview_changes']) ? true false;

        
// process the actions
        
$mod_installed $this->process_edits($editor$actions$details$execute_edits$displayfalse);

        if (!
$execute_edits)
        {
            
$s_hidden_fields = array('dependency_confirm'    => !empty($_REQUEST['dependency_confirm']));

            if (
$dest_template)
            {
                
$s_hidden_fields['dest'] = $dest_template;
                
$s_hidden_fields['source'] = $mod_path;
                
$s_hidden_fields['template_submit'] = true;
            }

            if (
$parent)
            {
                
$s_hidden_fields['type'] = $modx_type;
            }

            
$template->assign_var('S_HIDDEN_FIELDS'build_hidden_fields($s_hidden_fields));
            
add_form_key('acp_mods');

            return;
        } 
// end pre_install

        // Display Do-It-Yourself Actions...per the MODX spec, these should be displayed last
        
if (!empty($actions['DIY_INSTRUCTIONS']))
        {
            
$template->assign_var('S_DIY'true);

            if (!
is_array($actions['DIY_INSTRUCTIONS']))
            {
                
$actions['DIY_INSTRUCTIONS'] = array($actions['DIY_INSTRUCTIONS']);
            }

            foreach (
$actions['DIY_INSTRUCTIONS'] as $instruction)
            {
                
$template->assign_block_vars('diy_instructions', array(
                    
'DIY_INSTRUCTION'    => nl2br($instruction),
                ));
            }
        }

        if (!empty(
$actions['PHP_INSTALLER']))
        {
            
$template->assign_vars(array(
                
'U_PHP_INSTALLER'   => $phpbb_root_path $actions['PHP_INSTALLER'],
            ));
        }

        if (
$mod_installed || $force_install)
        {
            
// Move edited files back
            
$status $editor->commit_changes($this->edited_root'');

            if (
is_string($status))
            {
                
$mod_installed false;

                
$template->assign_block_vars('error', array(
                    
'ERROR'    => $status,
                ));
            }
        }

        
// The editor class provides more pertinent information regarding edits
        // so we store that as the canonical version, used for uninstalling
        
$actions['EDITS'] = $editor->mod_actions;
        
$editor->clear_actions();

        
// if MOD installed successfully, make a record.
        
if (($mod_installed || $force_install) && !$parent)
        {
            
$mod_name = (is_array($details['MOD_NAME'])) ? serialize($details['MOD_NAME']) : $details['MOD_NAME'];

            
// Insert database data
            
$sql 'INSERT INTO ' MODS_TABLE ' ' $db->sql_build_array('INSERT', array(
                
'mod_time'            => (int) $editor->install_time,
                
// @todo: Are dependencies part of the MODX Spec?
                
'mod_dependencies'    => ''//(string) serialize($details['MOD_DEPENDENCIES']),
                
'mod_name'            => (string) $mod_name,
                
'mod_description'    => (string) $details['MOD_DESCRIPTION'],
                
'mod_version'        => (string) $details['MOD_VERSION'],
                
'mod_path'            => (string) $details['MOD_PATH'],
                
'mod_author_notes'    => (string) $details['AUTHOR_NOTES'],
                
'mod_author_name'    => (string) $details['AUTHOR_DETAILS'][0]['AUTHOR_NAME'],
                
'mod_author_email'    => (string) $details['AUTHOR_DETAILS'][0]['AUTHOR_EMAIL'],
                
'mod_author_url'    => (string) $details['AUTHOR_DETAILS'][0]['AUTHOR_WEBSITE'],
                
'mod_actions'        => (string) serialize($actions),
                
'mod_languages'        => (string) (isset($elements['language']) && sizeof($elements['language'])) ? implode(','$elements['language']) : '',
                
'mod_template'        => (string) (isset($elements['template']) && sizeof($elements['template'])) ? implode(','$elements['template']) : '',
                
'mod_contribs'        => (string) (isset($elements['contrib']) && sizeof($elements['contrib'])) ? implode(','$elements['contrib']) : '',
            ));
            
$db->sql_query($sql);

            
$cache->purge();

            
// Add log
            
$mod_name localize_title($details['MOD_NAME'], 'en');
            
add_log('admin''LOG_MOD_ADD'$mod_name);
        }
        
// in this case, we are installing an additional template or language
        
else if (($mod_installed || $force_install) && $parent)
        {
            
$sql 'SELECT * FROM ' MODS_TABLE " WHERE mod_id = $parent";
            
$result $db->sql_query($sql);

            
$row $db->sql_fetchrow($result);
            
$db->sql_freeresult($result);

            if (!
$row)
            {
                
trigger_error($user->lang['NO_MOD'] . adm_back_link($this->u_action));
            }

            
$sql_ary = array(
                
'mod_version'    => $details['MOD_VERSION'],
            );

            if (!empty(
$elements['language']))
            {
                
$sql_ary['mod_languages'] = (!empty($row['mod_languages'])) ? $row['mod_languages'] . ',' '';
                
$sql_ary['mod_languages'] .= implode(','$elements['language']);
            }
            else
            {
                
$sql_ary['mod_languages'] = $row['mod_languages'];
            }

            if (!empty(
$elements['template']))
            {
                
$sql_ary['mod_template'] = $row['mod_template'] . ',' implode(','$elements['template']);
            }
            else
            {
                
$sql_ary['mod_template'] = $row['mod_template'];
            }

            if (!empty(
$elements['contrib']))
            {
                
$sql_ary['mod_contribs'] = (!empty($row['mod_contribs'])) ? $row['mod_contribs'] . ',' '';
                
$sql_ary['mod_contribs'] .= implode(','$elements['contrib']);
            }
            else
            {
                
$sql_ary['mod_contribs'] = $row['mod_contribs'];
            }

            
$sql_ary['mod_time'] = $editor->install_time;

            
$prior_mod_actions unserialize($row['mod_actions']);
            
$sql_ary['mod_actions'] = serialize(array_merge_recursive($prior_mod_actions$actions));
            unset(
$prior_mod_actions);

            
$sql 'UPDATE ' MODS_TABLE ' SET ' $db->sql_build_array('UPDATE'$sql_ary) . "
                WHERE mod_id = 
$parent";
            
$db->sql_query($sql);

            
add_log('admin''LOG_MOD_CHANGE'htmlspecialchars_decode($row['mod_name']));
        }
        
// there was an error we need to tell the user about
        
else
        {
            
add_form_key('acp_mods');

            if (
$parent)
            {
                
$hidden_ary['parent'] = $parent;
            }

            if (
$dest_template)
            {
                
$hidden_ary['dest'] = $dest_template;
                
$hidden_ary['source'] = $mod_path;
                
$hidden_ary['template_submit'] = true;
            }

            if (
$mod_language || $mod_contribs)
            {
                
$hidden_ary['type'] = $modx_type;
            }

            
$template->assign_vars(array(
                
'S_ERROR'            => true,
                
'S_HIDDEN_FIELDS'    => build_hidden_fields($hidden_ary),
                
'U_RETRY'            => $this->u_action '&amp;action=install&amp;mod_path=' $mod_path,
            ));
        }

        
// if we forced the install of the MOD, we need to let the user know their board could be broken
        
if ($force_install)
        {
            
$template->assign_var('S_FORCE'true);
        }

        if (
$mod_installed || $force_install)
        {
            
// $editor->commit_changes_final don't do anything ATM, but to be compatible with future versions
            
$mod_name localize_title($details['MOD_NAME'], 'en');
            
$editor->commit_changes_final('mod_' $editor->install_timestr_replace(' ''_'$mod_name));
        }
    }

    
/**
    * Uninstall/pre uninstall a mod
    */
    
function uninstall($action$mod_id$parent)
    {
        global 
$phpbb_root_path$phpEx$db$template$user$config;
        global 
$force_install$mod_uninstalled;

        if (!
$mod_id && !$parent)
        {
            return 
false;    // ERROR
        
}

        
// the MOD is more important than additional MODx files
        
if ($parent == $mod_id)
        {
            
$parent 0;
        }

        if (
$parent)
        {
            
// grab installed contrib and language items from the database
            
$sql 'SELECT mod_languages, mod_contribs
                    FROM ' 
MODS_TABLE "
                    WHERE mod_id = 
$parent";
            
$result $db->sql_query($sql);

            if (
$row $db->sql_fetchrow($result))
            {
                
$mod_path request_var('mod_path''');
                if (
in_array($mod_pathexplode(','$row['mod_languages'])))
                {
                    
$elements['languages'] = $mod_path;
                }
                elseif (
in_array($mod_pathexplode(','$row['mod_contribs'])))
                {
                    
$elements['contrib'] = $mod_path;
                }
                else
                {
                    
trigger_error('AM_MOD_NOT_INSTALLED');
                }

            }
            else
            {
                return 
false;
            }
        }

        
// set the class parameters to reflect the proper directory
        
$sql 'SELECT mod_path FROM ' MODS_TABLE '
            WHERE mod_id = ' 
. (($mod_id) ? $mod_id $parent);
        
$result $db->sql_query($sql);

        if (
$row $db->sql_fetchrow($result))
        {
            
$this->mod_root dirname($row['mod_path']) . '/';
            
$this->edited_root "{$this->mod_root}_edited/";
        }
        else
        {
            return 
false;    // ERROR
        
}

        
$execute_edits = ($action == 'pre_uninstall') ? false true;
        
$write_method 'editor_' determine_write_method(!$execute_edits);
        
$editor = new $write_method();

        
// get FTP information if we need it (or initialize array $hidden_ary)
        
$hidden_ary get_connection_info(!$execute_edits);

        if (
$parent)
        {
            
$hidden_ary['parent'] = $parent;
            
$hidden_ary['mod_path'] = $mod_path;
        }

        
$template->assign_vars(array(
            
'S_UNINSTALL'        => $execute_edits,
            
'S_PRE_UNINSTALL'    => !$execute_edits,
            
'L_FORCE_INSTALL'    => $user->lang['FORCE_UNINSTALL'],
            
'MOD_ID'        => $mod_id,
            
'U_UNINSTALL'    => ($parent) ? $this->u_action "&amp;action=uninstall&amp;parent=$parent&mod_path=$mod_path$this->u_action '&amp;action=uninstall&amp;mod_id=' $mod_id,
            
'U_RETURN'        => $this->u_action,
            
'U_BACK'        => $this->u_action,
            
'S_HIDDEN_FIELDS'    => build_hidden_fields($hidden_ary),
        ));

        
// grab actions and details
        
if (!$parent)
        {
            
$details $this->mod_details($mod_idfalsetrue);
            
$actions $this->mod_actions($mod_id);
        }
        else
        {
            
$details $this->mod_details($mod_pathfalse);
            
$actions $this->mod_actions($mod_path);
        }

        if (
$execute_edits)
        {
            
$editor->create_edited_root($this->edited_root);
            
$force_install $force_uninstall request_var('force'false);
        }

        
$display = ($execute_edits || $config['preview_changes']) ? true false;

        
// cleanup edits if we forced the install on a contrib or language
        
if ($parent)
        {
            if (isset(
$actions['EDITS']))
            {
                foreach (
$actions['EDITS'] as $file => $edit_ary)
                {
                    foreach (
$edit_ary as $edit_id => $edit)
                    {
                        foreach (
$edit as $find => $action_ary)
                        {
                            if (empty(
$action_ary))
                            {
                                unset(
$actions['EDITS'][$file][$edit_id][$find]);
                            }
                        }
                    }
                }
            }
        }

        
// process the actions
        
$mod_uninstalled $this->process_edits($editor$actions$details$execute_edits$displaytrue);

        if (!
$execute_edits)
        {
            return;
        } 
// end pre_uninstall

        
if (($mod_uninstalled || $force_uninstall) && !$parent)
        {
            
// Move edited files back
            
$status $editor->commit_changes($this->edited_root'');

            if (
is_string($status))
            {
                
$mod_uninstalled false;

                
$template->assign_block_vars('error', array(
                    
'ERROR'    => $status,
                ));
            }
        }
        elseif ((
$mod_uninstalled || $force_uninstall) && $parent)
        {
            
// Only update the database entries and don't move any files back
            
$sql 'SELECT * FROM ' MODS_TABLE " WHERE mod_id = $parent";
            
$result $db->sql_query($sql);

            
$row $db->sql_fetchrow($result);
            
$db->sql_freeresult($result);

            if (!
$row)
            {
                
trigger_error($user->lang['NO_MOD'] . adm_back_link($this->u_action));
            }

            
$sql_ary = array(
                
'mod_version'    => $details['MOD_VERSION'],
            );

            if (!empty(
$elements['languages']))
            {
                
$sql_ary['mod_languages'] = explode(','$row['mod_languages']);
                foreach (
$sql_ary['mod_languages'] as $key => $value)
                {
                    if (
$value != $elements['languages']);
                    {
                        unset(
$sql_ary['mod_languages'][$key]);
                    }
                }
                
$sql_ary['mod_languages'] = implode(','$sql_ary['mod_languages']);
            }
            else
            {
                
$sql_ary['mod_languages'] = $row['mod_languages'];
            }

            
// let's just not support uninstalling styles edits
            
$sql_ary['mod_template'] = $row['mod_template'];

            if (!empty(
$elements['contrib']))
            {
                
$sql_ary['mod_contribs'] = explode(','$row['mod_contribs']);
                foreach (
$sql_ary['mod_contribs'] as $key => $value)
                {
                    if (
$value != $elements['contrib']);
                    {
                        unset(
$sql_ary['mod_contribs'][$key]);
                    }
                }
                
$sql_ary['mod_contribs'] = implode(','$sql_ary['mod_contribs']);
            }
            else
            {
                
$sql_ary['mod_contribs'] = $row['mod_contribs'];
            }

            
$sql_ary['mod_time'] = $row['mod_time'];

            
//$prior_mod_actions = unserialize($row['mod_actions']);
            //$sql_ary['mod_actions'] = serialize(array_merge_recursive($prior_mod_actions, $actions));
            
$sql_ary['mod_actions'] = $row['mod_actions'];
            
//unset($prior_mod_actions);

            
$sql 'UPDATE ' MODS_TABLE ' SET ' $db->sql_build_array('UPDATE'$sql_ary) . "
                WHERE mod_id = 
$parent";
            
$db->sql_query($sql);

            
$mod_name localize_title($row['mod_name'], $user->data['user_lang']);
            
add_log('admin''LOG_MOD_CHANGE'htmlspecialchars_decode($mod_name));
        }

        
// if we forced uninstall of the MOD, we need to let the user know their board could be broken
        
if ($force_uninstall)
        {
            
$template->assign_var('S_FORCE'true);
        }
        else if (!
$mod_uninstalled)
        {
            
add_form_key('acp_mods');

            
$template->assign_vars(array(
                
'S_ERROR'            => true,
                
'S_HIDDEN_FIELDS'    => build_hidden_fields($hidden_ary),
                
'U_RETRY'            => $this->u_action '&amp;action=uninstall&amp;mod_id=' $mod_id,
            ));
        }

        if (
$mod_uninstalled || $force_uninstall)
        {
            
// Delete from DB
            
$sql 'DELETE FROM ' MODS_TABLE '
                WHERE mod_id = ' 
$mod_id;
            
$db->sql_query($sql);

            
// Add log
            
$mod_name localize_title($details['MOD_NAME'], 'en');
            
$mod_name htmlspecialchars_decode($mod_name);
            
add_log('admin''LOG_MOD_REMOVE'$mod_name);

            
$mod_name localize_title($details['MOD_NAME'], 'en');
            
$editor->commit_changes_final('mod_' $editor->install_timestr_replace(' ''_'$mod_name));
        }
    }

    
/**
    * Returns array of available mod install files in dir (Recursive)
    * @param $dir string - dir to search
    * @param $recurse int - number of levels to recurse
    */
    
function find_mods($dir$recurse false)
    {
        global 
$user;

        if (
$recurse === false)
        {
            
$mods = array('main' => array(), 'contrib' => array(), 'template' => array(), 'language' => array());
            
$recurse 0;
        }
        else
        {
            static 
$mods = array('main' => array(), 'contrib' => array(), 'template' => array(), 'language' => array());
        }

        
// ltrim shouldn't be needed, but some users had problems.  See #44305
        
$dir ltrim($dir'/');

        if (!
file_exists($dir))
        {
            return array();
        }

        if (!
is_readable($dir))
        {
            
trigger_error(sprintf($user->lang['NEED_READ_PERMISSIONS'], $dir), E_USER_WARNING);
        }

        
$dp opendir($dir);
        while ((
$file readdir($dp)) !== false)
        {
            if (
$file[0] != '.' && strpos("$dir/$file"'_edited') === false && strpos("$dir/$file"'_backups') === false)
            {
                
// recurse - we don't want anything within the MODX "root" though
                
if ($recurse && !is_file("$dir/$file") && strpos("$dir/$file"'root') === false)
                {
                    
$mods array_merge($mods$this->find_mods("$dir/$file"$recurse 1));
                }
                
// this might be better as an str function, especially being in a loop
                
else if (preg_match('#.*install.*xml$#i'$file) || (preg_match('#(contrib|templates|languages)#i'$dir$match)) || ($recurse === && strpos($file'.xml') !== false))
                {
                    
// if this is an "extra" MODX file, make a record of it as such
                    // we are assuming the MOD follows MODX packaging standards here
                    
if (strpos($file'.xml') !== false && preg_match('#(contrib|templates|languages)#i'$dir$match))
                    {
                        
// Get rid of the S.  This is a side effect of understanding
                        // MODX 1.0.x and 1.2.x.
                        
$match[1] = rtrim($match[1], 's');

                        
$mods[$match[1]][] = array(
                                    
'href'        => "$dir/$file",
                                    
'realname'    => core_basename($file),
                                    
'title'        => core_basename($file),
                                );
                    }
                    else
                    {
                        
$check end($mods['main']);
                        
$check $check['href'];

                        
// we take the first file alphabetically with install in the filename
                        
if (!$check || dirname($check) == $dir)
                        {
                            if (
preg_match('#.*install.*xml$#i'$file) && preg_match('#.*install.*xml$#i'$check) && strnatcasecmp(basename($check), $file) > 0)
                            {

                                
$index max(0sizeof($mods['main']) - 1);
                                
$mods['main'][$index] = array(
                                    
'href'        => "$dir/$file",
                                    
'realname'    => core_basename($file),
                                    
'title'        => core_basename($file),
                                );

                                break;
                            }
                            else if (
preg_match('#.*install.*xml$#i'$file) && !preg_match('#.*install.*xml$#i'$check))
                            {
                                
$index max(0sizeof($mods['main']) - 1);
                                
$mods['main'][$index] = array(
                                    
'href'        => "$dir/$file",
                                    
'realname'    => core_basename($file),
                                    
'title'        => core_basename($file),
                                );

                                break;
                            }
                        }
                        else
                        {
                            if (
strpos($file'.xml') !== false)
                            {
                                
$mods['main'][] = array(
                                    
'href'        => "$dir/$file",
                                    
'realname'    => core_basename($file),
                                    
'title'        => core_basename($file),
                                );
                            }
                        }
                    }
                }
            }
        }
        
closedir($dp);

        return 
$mods;
    }

    function 
process_edits($editor$actions$details$change false$display true$reverse false)
    {
        global 
$template$user$db$phpbb_root_path$force_install$mod_installed;
        global 
$dest_inherits$dest_template$children$config;

        
$mod_installed true;

        if (
$reverse)
        {
            global 
$rev_actions;

            if (empty(
$rev_actions))
            {
                
// maybe should allow for potential extensions here
                
$actions parser::reverse_edits($actions);
            }
            else
            {
                
$actions $rev_actions;
                unset(
$rev_actions);
            }
        }

        
$template->assign_vars(array(
            
'S_DISPLAY_DETAILS'    => (bool) $display,
            
'S_CHANGE_FILES'    => (bool) $change,
        ));

        if (!empty(
$details['PHPBB_VERSION']) && $details['PHPBB_VERSION'] != $config['version'])
        {
            
$version_warnig sprintf($user->lang['VERSION_WARNING'], $details['PHPBB_VERSION'], $config['version']);

            
$template->assign_vars(array(
                
'VERSION_WARNING'    => $version_warnig,
                
'S_PHPBB_VESION'    => true,
            ));
        }

        if (!empty(
$details['AUTHOR_NOTES']) && $details['AUTHOR_NOTES'] != $user->lang['UNKNOWN_MOD_AUTHOR-NOTES'])
        {
            
$template->assign_vars(array(
                
'S_AUTHOR_NOTES'    => true,

                
'AUTHOR_NOTES'        => nl2br($details['AUTHOR_NOTES']),
            ));
        }

        
// not all MODs will have edits (!)
        
if (isset($actions['EDITS']))
        {
            
$template->assign_var('S_EDITS'true);

            foreach (
$actions['EDITS'] as $filename => $edits)
            {
                
// see if the file to be opened actually exists
                
if (!file_exists("$phpbb_root_path$filename"))
                {
                    
$is_inherit = (strpos($filename'styles/') !== false && !empty($dest_inherits)) ? true false;

                    
$template->assign_block_vars('edit_files', array(
                        
'S_MISSING_FILE'    => ($is_inherit) ? false true,
                        
'INHERIT_MSG'        => ($is_inherit) ? sprintf($user->lang['INHERIT_NO_CHANGE'], $dest_template$dest_inherits) : '',
                        
'FILENAME'            => $filename,
                    ));

                    
$mod_installed = ($is_inherit) ? $mod_installed false;

                    continue;
                }
                else
                {
                    
$template->assign_block_vars('edit_files', array(
                        
'S_SUCCESS'    => false,
                        
'FILENAME'    => $filename,
                    ));

                    
// If installing - not pre_install nor (pre_)uninstall, backup the file
                    // This is to make sure it works with editor_ftp because write_method is
                    // forced to direct when in preview modes, and ignored in editor_manual!
                    
if ($change && !$reverse)
                    {
                        
$status $editor->open_file($filename$this->backup_root);
                    }
                    else
                    {
                        
$status $editor->open_file($filename);
                    }

                    if (
is_string($status))
                    {
                        
$template->assign_block_vars('error', array(
                            
'ERROR'    => $status,
                        ));

                        
$mod_installed false;
                        continue;
                    }

                    
$edit_success true;

                    foreach (
$edits as $finds)
                    {
                        
$comment '';
                        foreach (
$finds as $find => $commands)
                        {
                            if (isset(
$finds['comment']) && !$comment && $finds['comment'] != $user->lang['UNKNOWN_MOD_COMMENT'])
                            {
                                
$comment $finds['comment'];
                                unset(
$finds['comment']);
                            }

                            if (
$find == 'comment')
                            {
                                continue;
                            }

                            
$find_tpl = array(
                                
'FIND_STRING'    => htmlspecialchars($find),
                                
'COMMENT'        => htmlspecialchars($comment),
                            );

                            
$offset_ary $editor->find($find);

                            
// special case for FINDs with no action associated
                            
if (is_null($commands))
                            {
                                continue;
                            }

                            foreach (
$commands as $type => $contents)
                            {
                                if (!
$offset_ary)
                                {
                                    
$offset_ary['start'] = $offset_ary['end'] = false;
                                }

                                
$status false;
                                
$inline_template_ary = array();
                                
$contents_orig $contents;

                                switch (
strtoupper($type))
                                {
                                    case 
'AFTER ADD':
                                        
$status $editor->add_string($find$contents'AFTER'$offset_ary['start'], $offset_ary['end']);
                                    break;

                                    case 
'BEFORE ADD':
                                        
$status $editor->add_string($find$contents'BEFORE'$offset_ary['start'], $offset_ary['end']);
                                    break;

                                    case 
'INCREMENT':
                                    case 
'OPERATION':
                                        
//$contents = "";
                                        
$status $editor->inc_string($find''$contents);
                                    break;

                                    case 
'REPLACE WITH':
                                        
$status $editor->replace_string($find$contents$offset_ary['start'], $offset_ary['end']);
                                    break;

                                    case 
'IN-LINE-EDIT':
                                        
// these aren't quite as straight forward.  Still have multi-level arrays to sort through
                                        
$inline_comment '';
                                        foreach (
$contents as $inline_edit_id => $inline_edit)
                                        {
                                            if (
$inline_edit_id === 'inline-comment')
                                            {
                                                
// This is a special case for tucking comments in the array
                                                
if ($inline_edit != $user->lang['UNKNOWN_MOD_INLINE-COMMENT'])
                                                {
                                                    
$inline_comment $inline_edit;
                                                }
                                                continue;
                                            }

                                            foreach (
$inline_edit as $inline_find => $inline_commands)
                                            {
                                                foreach (
$inline_commands as $inline_action => $inline_contents)
                                                {
                                                    
// inline finds are pretty cantankerous, so do them in the loop
                                                    
$line $editor->inline_find($find$inline_find$offset_ary['start'], $offset_ary['end']);
                                                    if (!
$line)
                                                    {
                                                        
// find failed
                                                        
$status $mod_installed false;

                                                        
$inline_template_ary[] = array(
                                                            
'FIND'        =>    array(

                                                                
'S_SUCCESS'    => $status,

                                                                
'NAME'        => $user->lang[$type],
                                                                
'COMMAND'    => htmlspecialchars($inline_find),
                                                            ),
                                                            
'ACTION'    => array());

                                                        continue 
2;
                                                    }

                                                    
$inline_contents $inline_contents[0];
                                                    
$contents_orig $inline_find;

                                                    switch (
strtoupper($inline_action))
                                                    {
                                                        case 
'IN-LINE-':
                                                            
$editor->last_string_offset $line['string_offset'] + $line['find_length'] - 1;
                                                            
$status true;
                                                            continue 
2;
                                                        break;

                                                        case 
'IN-LINE-BEFORE-ADD':
                                                            
$status $editor->inline_add($find$inline_find$inline_contents'BEFORE'$line['array_offset'], $line['string_offset'], $line['find_length']);
                                                        break;

                                                        case 
'IN-LINE-AFTER-ADD':
                                                            
$status $editor->inline_add($find$inline_find$inline_contents'AFTER'$line['array_offset'], $line['string_offset'], $line['find_length']);
                                                        break;

                                                        case 
'IN-LINE-REPLACE':
                                                        case 
'IN-LINE-REPLACE-WITH':
                                                            
$status $editor->inline_replace($find$inline_find$inline_contents$line['array_offset'], $line['string_offset'], $line['find_length']);
                                                        break;

                                                        case 
'IN-LINE-OPERATION':
                                                            
$status $editor->inc_string($find$inline_find$inline_contents);
                                                        break;

                                                        default:
                                                            
$message sprintf($user->lang['UNRECOGNISED_COMMAND'], $inline_action);
                                                            
trigger_error($messageE_USER_WARNING); // ERROR!
                                                        
break;
                                                    }

                                                    
$inline_template_ary[] = array(
                                                        
'FIND'        =>    array(

                                                            
'S_SUCCESS'    => $status,

                                                            
'NAME'        => $user->lang[$type],
                                                            
'COMMAND'    => (is_array($contents_orig)) ? $user->lang['INVALID_MOD_INSTRUCTION'] : htmlspecialchars($contents_orig),
                                                        ),

                                                        
'ACTION'    => array(

                                                            
'S_SUCCESS'    => $status,

                                                            
'NAME'        => $user->lang[$inline_action],
                                                            
'COMMAND'    => (is_array($inline_contents)) ? $user->lang['INVALID_MOD_INSTRUCTION'] : htmlspecialchars($inline_contents),
                                            
//                'COMMENT'    => $inline_comment, (inline comments aren't actually part of the MODX spec)
                                                        
),
                                                    );
                                                }

                                                if (!
$status)
                                                {
                                                    
$mod_installed false;
                                                }

                                                
$editor->close_inline_edit();
                                            }
                                        }
                                    break;

                                    default:
                                        
$message sprintf($user->lang['UNRECOGNISED_COMMAND'], $type);
                                        
trigger_error($messageE_USER_WARNING); // ERROR!
                                    
break;
                                }

                                
$template->assign_block_vars('edit_files.finds'array_merge($find_tpl, array(
                                    
'S_SUCCESS'        => $status,
                                )));

                                if (!
$status)
                                {
                                    
$edit_success false;
                                    
$mod_installed false;
                                }

                                if (
sizeof($inline_template_ary))
                                {
                                    foreach (
$inline_template_ary as $inline_template)
                                    {
                                        
// We must assign the vars for the FIND first
                                        
$template->assign_block_vars('edit_files.finds.actions'$inline_template['FIND']);

                                        
// And now the vars for the ACTION
                                        
$template->assign_block_vars('edit_files.finds.actions.inline'$inline_template['ACTION']);

                                    }
                                    
$inline_template_ary = array();
                                }
                                else if (!
is_array($contents_orig))
                                {
                                    
$template->assign_block_vars('edit_files.finds.actions', array(
                                        
'S_SUCCESS'    => $status,

                                        
'NAME'        => $user->lang[$type],
                                        
'COMMAND'    => htmlspecialchars($contents_orig),
                                    ));
                                }
                            }
                        }

                        
$editor->close_edit();
                    }

                    
$template->alter_block_array('edit_files', array(
                        
'S_SUCCESS'        => $edit_success,
                    ), 
true'change');
                }

                if (
$change)
                {
                    
$status $editor->close_file("{$this->edited_root}$filename");
                    if (
is_string($status))
                    {
                        
$template->assign_block_vars('error', array(
                            
'ERROR'    => $status,
                        ));

                        
$mod_installed false;
                    }
                }
            }
        } 
// end foreach

        // Move included files
        
if (isset($actions['NEW_FILES']) && !empty($actions['NEW_FILES']))
        {
            
$template->assign_var('S_NEW_FILES'true);

            
// Because foreach operates on a copy of the specified array and not the array itself,
            // we cannot rely on the array pointer while using it, so we use a while loop w/ each()
            // We need array pointer to rewind the loop when is_array($target) (See Ticket #62341)
            
while (list($source$target) = each($actions['NEW_FILES']))
            {
                if (
is_array($target))
                {
                    
// If we've shifted off all targets, we're done w/ that element
                    
if (empty($target))
                    {
                        continue;
                    }

                    
// Shift off first target, then rewind array pointer to get next target
                    
$target array_shift($actions['NEW_FILES'][$source]);
                    
prev($actions['NEW_FILES']);
                }

                if (
$change && ($mod_installed || $force_install))
                {
                    
$status $editor->copy_content($this->mod_root str_replace('*.*'''$source), str_replace('*.*'''$target));

                    if (
$status !== true && !is_null($status))
                    {
                        
$mod_installed false;
                    }

                    
$template->assign_block_vars('new_files', array(
                        
'S_SUCCESS'            => ($status === true) ? true false,
                        
'S_NO_COPY_ATTEMPT'    => (is_null($status)) ? true false,
                        
'SOURCE'            => $source,
                        
'TARGET'            => $target,
                    ));
                }
                else if (
$display && !$change)
                {
                    
$template->assign_block_vars('new_files', array(
                        
'SOURCE'            => $source,
                        
'TARGET'            => $target,
                    ));
                }
                
// To avoid "error" on install page when being asked to force install
                
else if ($change && $display && !$mod_installed && !$force_install)
                {
                    
$template->assign_block_vars('new_files', array(
                        
'S_NO_COPY_ATTEMPT'    => true,
                        
'FILENAME'            => $target,
                    ));
                }
            }
        }

        
// Delete (or reverse-delete) installed files
        
if (!empty($actions['DELETE_FILES']))
        {
            
$template->assign_var('S_REMOVING_FILES'true);

            
// Dealing with a reverse-delete, must heed to the dangers ahead!
            
if ($reverse)
            {
                
$directories = array();
                
$directories['src'] = array();
                
$directories['dst'] = array();
                
$directories['del'] = array();

                
// Because foreach operates on a copy of the specified array and not the array itself,
                // we cannot rely on the array pointer while using it, so we use a while loop w/ each()
                // We need array pointer to rewind the loop when is_array($target) (See Ticket #62341)
                
while (list($source$target) = each($actions['DELETE_FILES']))
                {
                    if (
is_array($target))
                    {
                        
// If we've shifted off all targets, we're done w/ that element
                        
if (empty($target))
                        {
                            continue;
                        }

                        
// Shift off first target, then rewind array pointer to get next target
                        
$target array_shift($actions['DELETE_FILES'][$source]);
                        
prev($actions['DELETE_FILES']);
                    }

                    
// Some MODs include 'umil/', avoid deleting!
                    
if (strpos($target'umil/') === 0)
                    {
                        unset(
$actions['DELETE_FILES'][$source]);
                        continue;
                    }
                    
// MODX used '*.*' or 'dir/*.*'  (Fun!)
                    
else if (strpos($source'*.*') !== false)
                    {
                        
// This could be phpbb_root_path, if "Copy: root/*.* to: *.*" syntax was used
                        // or root/custom_dir if "Copy: root/custom/*.* to: custom/*.*", etc.
                        
$source $this->mod_root str_replace('*.*'''$source);
                        
$target str_replace('*.*'''$target);

                        
// Get all of the files in the source directory
                        
$files find_files($source'.*');
                        
// And translate into destination files
                        
$files str_replace($source$target$files);

                        
// Get all of the sub-directories in the source directory
                        
$directories['src'] = find_files($source'.*'20true);
                        
// And translate it into destination sub-directories
                        
$directories['dst'] = str_replace($source$target$directories['src']);

                        
// Compare source and destination subdirs, if any, in _reverse_ order! (array_pop)
                        
for ($i=0$cnt count($directories['dst']); $i $cnt$i++)
                        {
                            
$dir_source array_pop($directories['src']);
                            
$dir_target array_pop($directories['dst']);

                            
// Some MODs include 'umil/', avoid deleting!
                            
if (strpos($dir_target'umil/') === 0)
                            {
                                continue;
                            }

                            
$src_file_cnt directory_num_files($dir_sourcefalsetrue);
                            
$dst_file_cnt directory_num_files($phpbb_root_path $dir_targetfalsetrue);
                            
$src_dir_cnt directory_num_files($dir_sourcetruetrue);
                            
$dst_dir_cnt directory_num_files($phpbb_root_path $dir_targettruetrue);

                            
// Do we have a match in recursive file count and match in recursive subdir count?
                            // This could be vastly improved..
                            
if ($src_file_cnt == $dst_file_cnt && $src_dir_cnt == $dst_dir_cnt)
                            {
                                
$directories['del'][] = $dir_target;
                            }
                            unset(
$dir_source$dir_target$src_file_cnt$dst_file_cnt$src_dir_cnt$dst_dir_cnt); //cleanup
                        
}

                        foreach (
$files as $file)
                        {
                            
// Some MODs include 'umil/', avoid deleting!
                            
if (strpos($file'umil/') === 0)
                            {
                                continue;
                            }
                            else if (!
file_exists($phpbb_root_path $file) && ($change || $display))
                            {
                                
$template->assign_block_vars('removing_files', array(
                                    
'S_MISSING_FILE'        => true,
                                    
'S_NO_DELETE_ATTEMPT'    => true,
                                    
'FILENAME'                => $file,
                                ));
                            }
                            else if (
$change && ($mod_installed || $force_install))
                            {
                                
$status $editor->remove($file);

                                
$template->assign_block_vars('removing_files', array(
                                    
'S_SUCCESS'                => ($status === true) ? true false,
                                    
'S_NO_DELETE_ATTEMPT'    => (is_null($status)) ? true false,
                                    
'FILENAME'                => $file,
                                ));
                            }
                            else if (
$display && !$change)
                            {
                                
$template->assign_block_vars('removing_files', array(
                                    
'FILENAME'            => $file,
                                ));
                            }
                            
// To avoid "error" on uninstall page when being asked to force
                            
else if ($change && $display && !$mod_installed && !$force_install)
                            {
                                
$template->assign_block_vars('removing_files', array(
                                    
'S_NO_DELETE_ATTEMPT'    => true,
                                    
'FILENAME'                => $file,
                                ));
                            }
                        }
                        unset(
$files); //cleanup
                    
}
                    else if (!
file_exists($phpbb_root_path $target) && ($change || $display))
                    {
                        
$template->assign_block_vars('removing_files', array(
                            
'S_MISSING_FILE'        => true,
                            
'S_NO_DELETE_ATTEMPT'    => true,
                            
'FILENAME'                => $target,
                        ));
                    }
                    else if (
$change && ($mod_installed || $force_install))
                    {
                        
$status $editor->remove($target);

                        
$template->assign_block_vars('removing_files', array(
                            
'S_SUCCESS'                => ($status === true) ? true false,
                            
'S_NO_DELETE_ATTEMPT'    => (is_null($status)) ? true false,
                            
'FILENAME'                => $target,
                        ));
                    }
                    else if (
$display && !$change)
                    {
                        
$template->assign_block_vars('removing_files', array(
                            
'FILENAME'            => $target,
                        ));
                    }
                    
// To avoid "error" on uninstall page when being asked to force
                    
else if ($change && $display && !$mod_installed && !$force_install)
                    {
                        
$template->assign_block_vars('removing_files', array(
                            
'S_NO_DELETE_ATTEMPT'    => true,
                            
'FILENAME'                => $target,
                        ));
                    }
                }

                
// Delete wildcard directories, if any, which should now be empty anyway (no recursive delete needed)
                
if ($cnt count($directories['del']))
                {
                    for (
$i=0$i $cnt$i++)
                    {
                        if (
$change && ($mod_installed || $force_install))
                        {
                            
$status $editor->remove($directories['del'][$i]);

                            
$template->assign_block_vars('removing_files', array(
                                
'S_SUCCESS'                => ($status === true) ? true false,
                                
'S_NO_DELETE_ATTEMPT'    => (is_null($status)) ? true false,
                                
'FILENAME'                => $directories['del'][$i],
                            ));
                        }
                        else if (
$display && !$change)
                        {
                            
$template->assign_block_vars('removing_files', array(
                                
'FILENAME'                => $directories['del'][$i],
                            ));
                        }
                        
// To avoid "error" on uninstall page when being asked to force
                        
else if ($change && $display && !$mod_installed && !$force_install)
                        {
                            
$template->assign_block_vars('removing_files', array(
                                
'S_NO_DELETE_ATTEMPT'    => true,
                                
'FILENAME'                => $directories['del'][$i],
                            ));
                        }
                    }
                    unset(
$directories['del']); //cleanup
                
}
            }
            
// Normal deleting functionality (not in reverse edits mode)
            
else if ($mod_installed || $force_install)
            {
                foreach (
$actions['DELETE_FILES'] as $file)
                {
                    
$wildcards    strpos($file'*.*');
                    
$file        str_replace('*.*'''$file);

                    if (!
file_exists($phpbb_root_path $file) && ($change || $display))
                    {
                        
$template->assign_block_vars('removing_files', array(
                            
'S_MISSING_FILE'        => true,
                            
'S_NO_DELETE_ATTEMPT'    => true,
                            
'FILENAME'                => $file,
                        ));
                    }
                    
// purposely do not use !== false here, because we don't expect wildcards at position 0
                    // if there's no wildcard, make sure it's a file to avoid recursively deleting a directory!!!
                    
else if ($wildcards || is_file($phpbb_root_path $file))
                    {
                        if (
$change)
                        {
                            
// Delete, recursively if needed
                            
$status $editor->remove($filetrue);

                            
$template->assign_block_vars('removing_files', array(
                                
'S_SUCCESS'                => ($status === true) ? true false,
                                
'S_NO_DELETE_ATTEMPT'    => (is_null($status)) ? true false,
                                
'FILENAME'            => $file,
                            ));
                        }
                        else if (
$display)
                        {
                            
$template->assign_block_vars('removing_files', array(
                                
'FILENAME'            => $file,
                            ));
                        }
                    }
                }
            }
        }


        
// Perform SQL queries last -- Queries usually cannot be done a second
        // time, so do them only if the edits were successful.  Still complies
        // with the MODX spec in this location
        
if (!empty($actions['SQL']) && ($mod_installed || $force_install || ($display && !$change)))
        {
            
$template->assign_var('S_SQL'true);

            
parser::parse_sql($actions['SQL']);

            
$db->sql_return_on_error(true);

            foreach (
$actions['SQL'] as $query)
            {
                if (
$change)
                {
                    
$query_success $db->sql_query($query);

                    if (
$query_success)
                    {
                        
$template->assign_block_vars('sql_queries', array(
                            
'S_SUCCESS'    => true,
                            
'QUERY'        => $query,
                        ));
                    }
                    else
                    {
                        
$error $db->sql_error();

                        
$template->assign_block_vars('sql_queries', array(
                            
'S_SUCCESS'    => false,
                            
'QUERY'        => $query,
                            
'ERROR_MSG'    => $error['message'],
                            
'ERROR_CODE'=> $error['code'],
                        ));

                        
$mod_installed false;
                    }
                }
                else if (
$display)
                {
                    
$template->assign_block_vars('sql_queries', array(
                        
'QUERY'    => $query,
                    ));
                }
            }

            
$db->sql_return_on_error(false);
        }
        else
        {
            
$template->assign_var('S_SQL'false);
        }

        return 
$mod_installed;
    }

    
/**
    * Search on the file system for other .xml files that belong to this MOD
    * @param string $mod_path - path to the "main" MODX file, relative to phpBB Root
    */
    
function find_children($mod_path)
    {
        
$children = array();

        if (
$this->parser->get_modx_version() == 1.2)
        {
            
// TODO: eww, yuck ... processing the XML again?
            
$details $this->mod_details($mod_pathfalse);

            
$children $details['CHILDREN'];

            if (isset(
$children['template-lang']))
            {
                if (isset(
$children['template']))
                {
                    
$children['template'] = array_merge($children['template'], $children['template-lang']);
                }
                else
                {
                    
$children['template'] = $children['template-lang'];
                }

                unset(
$children['template-lang']);
            }

            
$child_types = array('contrib''template''language''dependency''uninstall');

            foreach (
$child_types as $type)
            {
                if (empty(
$children[$type]))
                {
                    continue;
                }
                
$child_count sizeof($children[$type]);
                
// Remove duplicate hrefs if they exist (links in multiple languages can cause this)
                
for ($i 1$i $child_count$i++)
                {
                    if (isset(
$children[$type][$i 1]) && $children[$type][$i 1]['href'] == $children[$type][$i]['href'])
                    {
                        unset(
$children[$type][$i]);
                    }
                }
            }
        }
        else if (
$this->parser->get_modx_version() == 1.0)
        {
            
$search_dir = (strpos($mod_path$this->mods_dir) === 0) ? dirname($mod_path) : $this->mods_dir dirname($mod_path);
            
$children $this->find_mods($search_dir5);
        }

        return 
$children;
    }

    function 
handle_dependency(&$children$mode$mod_path)
    {
        if (isset(
$children['dependency']) && sizeof($children['dependency']))
        {
            
// TODO: check for the chance that the MOD has been installed by AutoMOD
            // previously
            
if (confirm_box(true))
            {
                
// do nothing
            
}
            else if (empty(
$_REQUEST['dependency_confirm']) && empty($_REQUEST['force']))
            {
                global 
$user$id;

                
$full_url_list = array();
                
$message '';
                
$children['dependency'] = array_unique($children['dependency']);
                foreach (
$children['dependency'] as $dependency)
                {
                    
//$full_url_list[] = $dependency_url;
                    
$message .= sprintf($user->lang['DEPENDENCY_INSTRUCTIONS'], $dependency['href'], $dependency['title']) . '<br /><br />';
                }

                
confirm_box(false$messagebuild_hidden_fields(array(
                        
'dependency_confirm'    => true,
                        
'mode'        => $mode,
                        
'action'    => 'install',
                        
'mod_path'    => $mod_path,
                )));
            }
        }
    }

    
/**
     * Get all contrib links for the selected language.
     * This functions will be removed.
     */
    
function get_contrib_lang($contrib$lang 'en')
    {
        
$ary = array();

        foreach (
$contrib as $element)
        {
            if (
match_language($lang$element['lang']))
            {
                
$ary[] = $element;
            }
        }

        return(
$ary);
    }

    function 
handle_contrib(&$children)
    {
        global 
$template$parent_id$phpbb_root_path$user$db;

        if (isset(
$children['contrib']) && sizeof($children['contrib']))
        {
            
$template->assign_var('S_CONTRIB_AVAILABLE'true);

            
// Do we have links in the users selected language.
            // Start with getting the Enlgish links.
            
$contrib_en $this->get_contrib_lang($children['contrib']);

            if (
$user->data['user_lang'] == 'en' || sizeof($contrib_en) == sizeof($children['contrib']))
            {
                
// Our user has either English or there is only English links.
                
$children['contrib'] = $contrib_en;
            }
            else
            {
                
// If there are any links in the users language, let's get them.
                
$contrib_lang $this->get_contrib_lang($children['contrib'], $user->data['user_lang']);

                if (!
sizeof($contrib_lang))
                {
                    
// There is no links in the right language, give them the English links.
                    
$children['contrib'] = $contrib_en;
                }
                else
                {
                    
$children['contrib'] = $contrib_lang;
                }
            }

            if (!empty(
$parent_id))
            {
                
// get installed contribs from the database
                
$sql 'SELECT mod_contribs FROM ' MODS_TABLE '
                        WHERE mod_id = ' 
$parent_id;
                
$result $db->sql_query($sql);
                
$mod_contribs $db->sql_fetchfield('mod_contribs');
                
$db->sql_freeresult();
            }

            
$mod_contribs = (!empty($mod_contribs)) ? explode(','$mod_contribs) : array();

            
// there are things like upgrades...we don't care unless the MOD has previously been installed.
            
foreach ($children['contrib'] as $xml_file)
            {
                
// Another hack for supporting both versions of MODX
                
$xml_file = (is_array($xml_file)) ? $xml_file['href'] : str_replace($this->mod_root''$xml_file);

                
$child_details $this->mod_details($xml_filefalse);

                
// don't do the urlencode until after the file is looked up on the
                // filesystem
                
$xml_file urlencode('/' $xml_file);

                if (
in_array(urldecode($xml_file), $mod_contribs))
                {
                    
$child_details['U_UNINSTALL']  = ($parent_id) ? $this->u_action "&amp;action=pre_uninstall&amp;parent=$parent_id&amp;mod_path=$xml_file&amp;type=contrib" '';
                }
                else
                {
                    
$child_details['U_INSTALL'] = ($parent_id) ? $this->u_action "&amp;action=pre_install&amp;parent=$parent_id&amp;mod_path=$xml_file&amp;type=contrib" '';
                }

                
$child_details['MOD_NAME'] = localize_title($child_details['MOD_NAME'], $user->data['user_lang']);
                
$template->assign_block_vars('contrib'$child_details);
            }
        }
    }

    function 
handle_merge($type, &$actions, &$children$process_files)
    {
        if (!isset(
$children[$type]) || !sizeof($process_files))
        {
            return;
        }

        
// add the actions to our $actions array...give praise to array_merge_recursive
        
foreach ($process_files as $key => $name)
        {
            foreach (
$children[$type] as $child_key => $child_data)
            {
                
$root_position strpos($child_data['href'], $this->mod_root);
                if (
$child_data['realname'] == $name && $root_position === false)
                {
                    
$child_filename $this->mod_root ltrim($child_data['href'], './');
                    break;
                }
                else if (
$child_data['realname'] == $name && $root_position === 0)
                {
                    
$child_filename $child_data['href'];
                }

            }

            
$actions_ary $this->mod_actions($child_filename);

            if (!isset(
$actions_ary['NEW_FILES']))
            {
                
$actions array_merge_recursive($actions$actions_ary);
                continue;
            }

            
// perform some cleanup if the MOD author didn't specify the proper root directory
            
foreach ($actions_ary['NEW_FILES'] as $source => $destination)
            {
                
// if the source file does not exist, and languages/ is not at the beginning
                // this is probably only applicable with MODX 1.0.
                
if (!file_exists($this->mod_root $source) && strpos("{$type}s/"$source) === false)
                {
                    
// and it does exist if we force a languages/ into the path
                    
if (file_exists($this->mod_root "{$type}s/" $source))
                    {
                        
// change the array key to include languages
                        
unset($actions_ary['NEW_FILES'][$source]);
                        
$actions_ary['NEW_FILES']["{$type}s/$source"] = $destination;
                    }

                    
// else we let the error handling do its thing
                
}
            }

            
$actions array_merge_recursive($actions$actions_ary);
        }
    }

    function 
handle_language_prompt(&$children, &$elements$action)
    {
        global 
$db$template$parent_id$phpbb_root_path;

        if (isset(
$children['language']) && sizeof($children['language']))
        {
            
// additional languages are available...find out which ones we may want to apply
            
$sql 'SELECT lang_id, lang_iso FROM ' LANG_TABLE;
            
$result $db->sql_query($sql);

            
$installed_languages = array();
            while (
$row $db->sql_fetchrow($result))
            {
                
$installed_languages[$row['lang_id']] = $row['lang_iso'];
            }
            
$db->sql_freeresult($result);

            foreach (
$children['language'] as $key => $tag)
            {
                
// remove useless title from MODX 1.2.0 tags
                
$children['language'][$tag['realname']] = is_array($tag) ? $tag['href'] : $tag;
            }

            
$available_languages array_keys($children['language']);
            
$process_languages $elements['language'] = array_intersect($available_languages$installed_languages);

            
// $unknown_languages are provided for by the MOD, but not installed on the board
            
$unknown_languages array_diff($available_languages$installed_languages);

            
// Inform the user if there are languages provided for by the MOD
            
if (sizeof($children['language']))
            {
                if (!empty(
$parent_id))
                {
                    
// get installed languages from the database
                    
$sql 'SELECT mod_languages FROM ' MODS_TABLE '
                            WHERE mod_id = ' 
$parent_id;
                    
$result $db->sql_query($sql);
                    
$mod_languages $db->sql_fetchfield('mod_languages');
                    
$db->sql_freeresult();
                }

                
$mod_languages = (!empty($mod_languages)) ? explode(','$mod_languages) : array();
                foreach (
$children['language'] as $row)
                {
                    if (
is_string($row))
                    {
                        continue;
                    }

                    
$xml_file = (!empty($row['href'])) ? urlencode($row['href']) : '';

                    
$template->assign_block_vars('unknown_lang', array(
                        
'ENGLISH_NAME'    => $row['title'],
                        
'LOCAL_NAME'    => $row['realname'],
                        
'U_INSTALL'        => (!empty($xml_file) && !in_array($row['href'], $mod_languages) && $parent_id) ? $this->u_action "&amp;action=pre_install&amp;parent=$parent_id&amp;mod_path=$xml_file&amp;type=lang" '',
                        
'U_UNINSTALL'        => (!empty($xml_file) && $parent_id) ? $this->u_action "&amp;action=pre_uninstall&amp;parent=$parent_id&amp;mod_path=$xml_file&amp;type=lang" '',
                    ));
                    unset(
$row);
                }
            }

            return 
$process_languages;
        }
    }

    function 
handle_template_prompt(&$children, &$elements$action)
    {
        global 
$db$template$phpbb_root_path$parent_id;

        if (isset(
$children['template']) && sizeof($children['template']))
        {
            
// additional styles are available for this MOD
            
$sql 'SELECT template_id, template_name FROM ' STYLES_TEMPLATE_TABLE;
            
$result $db->sql_query($sql);

            
$installed_templates = array();
            while (
$row $db->sql_fetchrow($result))
            {
                
$installed_templates[$row['template_id']] = $row['template_name'];
            }
            
$db->sql_freeresult($result);

            foreach (
$children['template'] as $key => $tag)
            {
                
// remove useless title from MODX 1.2.0 tags
                
$children['template'][$tag['realname']] = is_array($tag) ? $tag['href'] : $tag;
            }

            
$available_templates array_keys($children['template']);

            
// $process_templates are those that are installed on the board and provided for by the MOD
            
$process_templates $elements['template'] = array_intersect($available_templates$installed_templates);
        }
    }

    function 
upload_mod($action)
    {
        global 
$phpbb_root_path$phpEx$template$user;

        
$can_upload = (@ini_get('file_uploads') == '0' || strtolower(@ini_get('file_uploads')) == 'off' || !@extension_loaded('zlib')) ? false true;

        
// get FTP information if we need it
        
$hidden_ary get_connection_info(false);

        if (!isset(
$_FILES['modupload']) || $action != 'upload_mod')
        {
            
$template->assign_vars(array(
                
'S_FRONTEND'        => true,
                
'S_MOD_UPLOAD'        => ($can_upload) ? true false,
                
'U_UPLOAD'            => $this->u_action '&amp;action=upload_mod',
                
'S_FORM_ENCTYPE'    => ($can_upload) ? ' enctype="multipart/form-data"' '',
                
'S_HIDDEN_FIELDS'    => build_hidden_fields($hidden_ary),
            ));
            
add_form_key('acp_mods_upload');

            return 
false;
        } 
// end pre_upload_mod

        
if (!check_form_key('acp_mods_upload'))
        {
            
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
        }

        
$user->add_lang('posting');  // For error messages
        
include($phpbb_root_path 'includes/functions_upload.' $phpEx);
        
$upload = new fileupload();
        
$upload->set_allowed_extensions(array('zip'));    // Only allow ZIP files

        
$write_method 'editor_' determine_write_method(false);

        
// For Direct & Manual write methods, make sure store/mods/ directory is writable
        
if ($write_method == 'editor_direct' || $write_method == 'editor_manual')
        {
            if (!
is_writable($this->mods_dir))
            {
                
trigger_error($user->lang['MODS_NOT_WRITABLE'] . adm_back_link($this->u_action), E_USER_WARNING);
            }

            
$write_method 'editor_direct';    // Force Direct method, in the case of manual
            
$upload_dir $this->mods_dir;
        }
        
// FTP method: we still need a known world-writable directory (store/) for zip extraction
        
else if (is_writable($this->store_dir))
        {
            
$upload_dir $this->store_dir;
        }
        else
        {
            
trigger_error($user->lang['STORE_NOT_WRITABLE'] . adm_back_link($this->u_action), E_USER_WARNING);
        }

        
$editor = new $write_method();

        
// Make sure the store/mods/ directory exists and if it doesn't, create it
        
if (!is_dir($this->mods_dir))
        {
            
$editor->recursive_mkdir($this->mods_dir);
        }

        
// Proceed with the upload
        
$file $upload->form_upload('modupload');

        if (empty(
$file->filename))
        {
            
trigger_error($user->lang['NO_UPLOAD_FILE'] . adm_back_link($this->u_action), E_USER_WARNING);
        }
        else if (
$file->init_error || sizeof($file->error))
        {
            
$file->remove();
            
trigger_error((sizeof($file->error) ? implode('<br />'$file->error) : $user->lang['MOD_UPLOAD_INIT_FAIL']) . adm_back_link($this->u_action), E_USER_WARNING);
        }

        
$file->clean_filename('real');
        
$file->move_file(str_replace($phpbb_root_path''$upload_dir), truetrue);

        if (
sizeof($file->error))
        {
            
$file->remove();
            
trigger_error(implode('<br />'$file->error) . adm_back_link($this->u_action), E_USER_WARNING);
        }

        include(
$phpbb_root_path 'includes/functions_compress.' $phpEx);
        
$mod_dir $upload_dir '/' str_replace('.zip'''$file->get('realname'));
        
$compress = new compress_zip('r'$file->destination_file);
        
$compress->extract($mod_dir '_tmp/');
        
$compress->close();
        
$folder_contents scandir($mod_dir '_tmp/'1);  // This ensures dir is at index 0

        
$folder_contents array_diff($folder_contents, array('.''..'));

        
// We need to check if there's only one (main) directory inside the temp MOD directory
        
if (sizeof($folder_contents) == 1)
        {
            
$folder_contents implode(null$folder_contents);
            
$from_dir $mod_dir '_tmp/' $folder_contents;
            
$to_dir $this->mods_dir '/' $folder_contents;
        }
        
// Otherwise assume the temp directory is the main directroy, so change the directory
        // name by moving to a directory without the '_tmp' suffix
        
else if (!is_dir($mod_dir))
        {
            
$from_dir $mod_dir '_tmp/';
            
$to_dir $mod_dir '/';
        }
        
// We should never really get here, but you never know!
        
else
        {
            
trigger_error($user->lang['MOD_UPLOAD_UNRECOGNIZED'] . adm_back_link($this->u_action), E_USER_WARNING);
        }

        
// Copy that directory to the new path
        
$editor->copy_content($from_dir$to_dir);

        
// Finally remove the main tmp extraction directory, directly, just like we created it
        
recursive_unlink($mod_dir '_tmp/');

        
$template->assign_vars(array(
            
'S_MOD_SUCCESSBOX'    => true,
            
'MESSAGE'            => $user->lang['MOD_UPLOAD_SUCCESS'],
            
'U_RETURN'            => $this->u_action,
        ));

        
// Remove the uploaded archive file
        
$file->remove();

        return 
true;
    }

    function 
delete_mod($action$mod_path '')
    {
        global 
$template$user;

        if (!empty(
$mod_path))
        {
            
$mod_path explode('/'str_replace('\', '/', $mod_path));
            $mod_path = (!empty($mod_path[0])) ? $mod_path[0] : $mod_path[1];
        }
        else
        {
            $mod_path = request_var('
mod_delete', '');
        }

        if (empty($mod_path) || !is_dir($this->mods_dir . '
/' . $mod_path))
        {
            return false;    // ERROR
        }

        // get FTP information if we need it
        $hidden_ary = get_connection_info(false);

        $hidden_ary['
mod_delete'] = $mod_path;

        if ($action != '
delete_mod')
        {
            $template->assign_vars(array(
                '
S_MOD_DELETE'        => true,
                '
U_DELETE'            => $this->u_action . '&amp;action=delete_mod',
                '
S_HIDDEN_FIELDS'    => build_hidden_fields($hidden_ary),
            ));
            add_form_key('
acp_mods_delete');

            return;
        } // end pre_delete_mod

        $write_method = '
editor_' . determine_write_method(false);
        // Force Direct method, in the case of manual - just like above in mod_upload()
        $write_method = ($write_method == '
editor_manual') ? 'editor_direct' : $write_method;
        $editor = new $write_method();

        if (!check_form_key('
acp_mods_delete'))
        {
            trigger_error($user->lang['
FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
        }

        $status = $editor->remove("{$this->mods_dir}/{$mod_path}", true);

        if ($status !== true)
        {
            trigger_error($user->lang['
DELETE_ERROR'] . "  $status" . adm_back_link($this->u_action), E_USER_WARNING);
        }

        $template->assign_vars(array(
            '
S_MOD_SUCCESSBOX'    => true,
            '
MESSAGE'            => $user->lang['DELETE_SUCCESS'],
            '
U_RETURN'            => $this->u_action,
        ));
    }
}

?>
Онлайн: 0
Реклама