Вход Регистрация
Файл: admin/applications/core/modules_admin/applications/hooks.php
Строк: 2591
<?php
/**
 * <pre>
 * Invision Power Services
 * IP.Board v3.3.3
 * Hooks Management
 * Last Updated: $Date: 2012-05-31 11:34:45 -0400 (Thu, 31 May 2012) $
 * </pre>
 *
 * @author         $Author: ips_terabyte $
 * @copyright    (c) 2001 - 2009 Invision Power Services, Inc.
 * @license        http://www.invisionpower.com/company/standards.php#license
 * @package        IP.Board
 * @subpackage    Core
 * @link        http://www.invisionpower.com
 * @since        3.0.0
 * @version        $Revision: 10844 $
 */

if ( ! defined'IN_ACP' ) )
{
    print 
"<h1>Incorrect access</h1>You cannot access this file directly. If you have recently upgraded, make sure you upgraded 'admin.php'.";
    exit();
}

class 
admin_core_applications_hooks extends ipsCommand
{
    
/**
     * Skin object
     *
     * @var        object            Skin templates
     */
    
protected $html;
    
    
/**
     * Hooks library
     *
     * @var        object            Hooks library
     */
    
protected $hooksFunctions;
    
    
/**
     * Existing hooks
     *
     * @var        array             Existing hooks
     */
    
protected $hooks;    
    
    
/**
     * Array of all the cache versions
     * for the required applications
     * 
     * @var    $cachedVersions
     */
    
protected $cachedVersions = array();
    
    
/**
     * Main class entry point
     *
     * @param    object        ipsRegistry reference
     * @return    @e void        [Outputs to screen]
     */
    
public function doExecuteipsRegistry $registry 
    {
        
//-----------------------------------------
        // Load skin
        //-----------------------------------------
        
        
$this->html $this->registry->output->loadTemplate('cp_skin_applications');
        
        
//-----------------------------------------
        // Load hooks library
        //-----------------------------------------
        
        
$classToLoad IPSLib::loadLibraryIPSLib::getAppDir('core') . '/sources/classes/hooksFunctions.php''hooksFunctions' );
        
$this->hooksFunctions = new $classToLoad$registry );
        
        
// lang already loaded by hookFunctions
        //$this->registry->class_localization->loadLanguageFile( array( 'admin_applications' ), 'core' );

        //-----------------------------------------
        // Set up stuff
        //-----------------------------------------
        
        
$this->form_code    $this->html->form_code    'module=applications&amp;section=hooks&amp;';
        
$this->form_code_js    $this->html->form_code_js    'module=applications&section=hooks&';
        
        
//-----------------------------------------
        // What to do...
        //-----------------------------------------
        
        
switch( $this->request['do'] )
        {
            case 
'reenable_all_hooks':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg'hooks_manage' );
                
$this->_reenableAllHooks();
            break;
            case 
'disable_all_hooks':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg'hooks_manage' );
                
$this->_disableAllHooks();
            break;
                
            break;
            case 
'disable_hook':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg'hooks_manage' );
                
$this->_disableHook();
            break;
            case 
'enable_hook':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg'hooks_manage' );
                
$this->_enableHook();
            break;
            
            case 
'uninstall_hook':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg'hooks_delete' );
                
$this->_uninstallHook();
            break;
            case 
'install_hook':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg'hooks_manage' );
                
$this->_installHook();
            break;
            
            case 
'reorder':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg'hooks_manage' );
                
$this->_reorder();
            break;
            
            case 
'view_details':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg'hooks_manage' );
                
$this->_viewDetails();
            break;
            
            case 
'check_requirements':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg'hooks_manage' );
                
$this->_checkRequirements();
            break;
            
            case 
'export_hook':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg'hooks_manage' );
                
$this->_exportHook();
            break;
            
            case 
'do_export_hook':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg'hooks_manage' );
                
$this->_doExportHook();
            break;
            
            case 
'create_hook':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg'hooks_manage' );
                
$this->_hookForm'add' );
            break;
            
            case 
'edit_hook':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg'hooks_manage' );
                
$this->_hookForm'edit' );
            break;
            
            case 
'do_create_hook':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg'hooks_manage' );
                
$this->_hookSave'add' );
            break;
            
            case 
'do_edit_hook':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg'hooks_manage' );
                
$this->_hookSave'edit' );
            break;
            
            case 
'removeDeadCaches':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg'hooks_manage' );
                
$this->removeDeadCaches();
            break;

            case 
'reimport_apps':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg'hooks_manage' );
                
$this->reimportAppHooks();
            break;

            case 
'hooks_overview':
            default:
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg'hooks_manage' );
                
$this->request['do'] = 'hooks_overview';
                
$this->_hooksOverview();
            break;
        }
        
        
//-----------------------------------------
        // Pass to CP output hander
        //-----------------------------------------
        
        
$this->registry->getClass('output')->html_main .= $this->registry->getClass('output')->global_template->global_frame_wrapper();
        
$this->registry->getClass('output')->sendOutput();
    }
    
    
/**
     * Reimport all hooks for all installed applications
     *
     * @return    @e void
     */
    
protected function reimportAppHooks()
    {
        
$stats    = array( 'inserted' => 0'updated' => 0'skipped' => );
        
        foreach( 
ipsRegistry::$applications as $app )
        {
            
$_stats    $this->installAppHooks$app['app_directory'] );
            
            
$stats['inserted']    = $stats['inserted'] + $_stats['inserted'];
            
$stats['updated']    = $stats['updated'] + $_stats['updated'];
            
$stats['skipped']    = $stats['skipped'] + $_stats['skipped'];
        }
        
        
/* Rebuild cache */
        
$this->rebuildHooksCache();
        
        
/* Rebuild global caches */
        
try
        {
            
IPSLib::cacheGlobalCaches();
        }
        catch( 
Exception $e ){}
        
        
/* Flag skins for recache */
        
require_once( IPS_ROOT_PATH 'sources/classes/skins/skinFunctions.php' );/*noLibHook*/
        
require_once( IPS_ROOT_PATH 'sources/classes/skins/skinCaching.php' );/*noLibHook*/
        
$skinCaching = new skinCaching$this->registry );
        
$skinCaching->flagSetForRecache();
        
        
/* Redirect */
        
$this->registry->output->global_message sprintf$this->lang->words['app_hooks_rebuilt'], $stats['inserted'], $stats['updated'], $stats['skipped'] );
        
$this->registry->output->silentRedirectWithMessage$this->settings['base_url'] . $this->form_code '&amp;do=hooks_overview' );
    }
    
    
/**
     * Rebuild skins following hook import that included a template
     *
     * @return    @e void
     */
    
protected function removeDeadCaches()
    {
        
$messages = array();
        
$keep      = array();
        
$unlink      = array();
        
        
/* Grab all current hooks caches */
        
$this->DB->build( array( 'select' => '*',
                                 
'from'   => 'core_hooks_files' ) );
                                
        
$this->DB->execute();
        
        while( 
$row $this->DB->fetch() )
        {
            
$keep[] = $row['hook_file_stored'];
        }
        
        try
        {
            foreach( new 
DirectoryIteratorIPS_HOOKS_PATH ) as $file )
            {
                if ( ! 
$file->isDot() )
                {
                    
$_name $file->getFileName();
                    
                    if ( 
preg_match"#_[a-z0-9]{32}.php$#"$_name ) )
                    {
                        if ( ! 
in_array$_name$keep ) )
                        {
                            
$unlink[] = $_name;
                        }
                    }
                }
            }
        } catch ( 
Exception $e ) { print $e->getMessage(); }
        
        
/* Anything to unlink? */
        
if ( count$unlink ) )
        {
            foreach( 
$unlink as $file )
            {
                @
unlinkIPS_HOOKS_PATH $file );
            }
        }
        
        
/* Print message */
        
$this->registry->output->global_message sprintf$this->lang->words['hook_removed_files'], count$unlink ) ) . '<br />' implode'<br />'$unlink );
        
$this->_hooksOverview();
    }

    
/**
     * Reorder hooks
     *
     * @return    @e void        [Outputs to screen]
     */
    
protected function _reorder()
    {
        
//-----------------------------------------
        // INIT
        //-----------------------------------------

        
$classToLoad IPSLib::loadLibraryIPS_KERNEL_PATH 'classAjax.php''classAjax' );
        
$ajax         = new $classToLoad();
        
        
//-----------------------------------------
        // Checks...
        //-----------------------------------------

        
if( $this->registry->adminFunctions->checkSecurityKey$this->request['md5check'], true ) === false )
        {
            
$ajax->returnString$this->lang->words['postform_badmd5'] );
        }
         
         
//-----------------------------------------
         // Save new position
         //-----------------------------------------

         
$position    1;
         
         if( 
is_array($this->request['hooks']) AND count($this->request['hooks']) )
         {
             
/* Reset all hooks to 0 temporarily */
             
$this->DB->update'core_hooks', array( 'hook_position' => ) );
             
             foreach( 
$this->request['hooks'] as $this_id )
             {
                 
$this->DB->update'core_hooks', array( 'hook_position' => $position ), 'hook_id=' $this_id );
                 
                 
$position++;
             }
         }
         
        
$this->rebuildHooksCache();

         
$ajax->returnString('OK');
    }
    
    
/**
     * Install a new hook
     *
     * @return   void
     */
    
protected function _installHook()
    {
        
//-----------------------------------------
        // Get uploaded schtuff
        //-----------------------------------------

        
$tmp_name $_FILES['FILE_UPLOAD']['name'];
        
$tmp_name preg_replace"#.gz$#"""$tmp_name );
        
        
$content  ipsRegistry::getClass('adminFunctions')->importXml$tmp_name );
        
        if( ! 
$content )
        {
            
$this->registry->output->showError$this->lang->words['h_noxml'], 1110 );
        }

        
$this->installHook$contentTRUEFALSE );
        
        
/* Rebuild cache */
        
$this->rebuildHooksCache();
        
        
/* Rebuild global caches */
        
try
        {
            
IPSLib::cacheGlobalCaches();
        }
        catch( 
Exception $e ){}
        
        
/* Flag skins for recache */
        
require_once( IPS_ROOT_PATH 'sources/classes/skins/skinFunctions.php' );/*noLibHook*/
        
require_once( IPS_ROOT_PATH 'sources/classes/skins/skinCaching.php' );/*noLibHook*/
        
$skinCaching = new skinCaching$this->registry );
        
$skinCaching->flagSetForRecache();
        
        
/* Redirect */
        
$this->registry->output->silentRedirectWithMessage$this->settings['base_url'] . $this->form_code '&amp;do=hooks_overview' );
    }
    
    
/**
     * Function mostly used in installer/upgrader
     * Inserts new hooks
     *
     * @param    string        Application to install hooks for
     */
    
public function installAppHooks$app )
    {
        static 
$hooks    = array();

        
$msgs    = array( 'inserted' => 0'updated' => 0'skipped' => );
        
$xmlData = array();
        
$path    IPSLib::getAppDir$app ) . '/xml';
        
        if ( 
is_file$path '/hooks.xml' ) AND is_dir$path '/hooks' ) )
        {
            if( !
count($hooks) )
            {
                
/* Fetch current hooks */
                
$this->DB->build( array( 'select' => '*',
                                         
'from'   => 'core_hooks' ) );
                
$this->DB->execute();
                
                while( 
$row $this->DB->fetch() )
                {
                    if ( 
$row['hook_key'] )
                    {
                        
$hooks$row['hook_key'] ] = $row;
                    }
                }
            }
            
            
/* Alright. We're in. Read the XML file */
            
require_once( IPS_KERNEL_PATH 'classXML.php' );/*noLibHook*/
            
$xml    = new classXMLIPS_DOC_CHAR_SET );

            
/* Grab wrapper file */
            
$xml->load(  $path '/hooks.xml' );

            foreach( 
$xml->fetchElements('hook') as $data )
            {
                
$xmlData[] = $xml->fetchElementsFromRecord$data );
            }

            
/* Examine XML */
            
if ( is_array$xmlData ) AND count$xmlData ) )
            {
                foreach( 
$xmlData as $x )
                {
                    if ( 
is_file$path '/hooks/' $x['file'] ) )
                    {
                        
$xml->load(  $path '/hooks/' $x['file'] );
                        
                        foreach( 
$xml->fetchElements('config') as $data )
                        {
                            
$config    $xml->fetchElementsFromRecord$data );
                        }
                        
                        if ( ! isset( 
$hooks$config['hook_key'] ] ) )
                        {
                            
/* Add it */
                            
$msgs['inserted']++;
                            
$this->installHookfile_get_contents$path '/hooks/' $x['file'] ), FALSEFALSE$x['enabled'] );
                        } 
                        else
                        {
                            
$this->installHookfile_get_contents$path '/hooks/' $x['file'] ), FALSEFALSE$x['enabled'] );
                            
$msgs['updated']++;
                        }
                    }
                }
            }
        }
        
        return 
$msgs;
    }
    
    
/**
     * Public install hook so we can use it in the installer and elsewhere
     *
     * @param    string        XML data
     * @param    boolean        Add message to output->global_message
     * @param    boolean        Allow skins to recache
     * @param    int            Install enabled
     * @return    @e void
     */
    
public function installHook$content$addMessage=FALSE$allowSkinRecache=TRUE$enabled=)
    {
        
//-----------------------------------------
        // Hooks directory writable?
        //-----------------------------------------
        
        
if( !is_writableIPS_HOOKS_PATH ) )
        {
            if( !
$addMessage )
            {
                return 
false;
            }

            
$this->registry->output->showError$this->lang->words['h_dir_notwritable'], 111159 );
        }
        
        
//-----------------------------------------
        // Got our hooks?
        //-----------------------------------------
        
        
if( !is_array($this->hooks) OR !count($this->hooks) )
        {
            
$this->DB->build( array( 'select' => '*''from' => 'core_hooks' ) );
            
$this->DB->execute();
            
            while( 
$r $this->DB->fetch() )
            {
                
$this->hooks$r['hook_key'] ]    = $r;
            }
        }

        
//-----------------------------------------
        // Get xml mah-do-dah
        //-----------------------------------------
        
        
require_once( IPS_KERNEL_PATH 'classXML.php' );/*noLibHook*/
        
$xml    = new classXMLIPS_DOC_CHAR_SET );
        
        
//-----------------------------------------
        // Unpack the datafile
        //-----------------------------------------
        
        
$xml->loadXML$content );

        foreach( 
$xml->fetchElements('config') as $data )
        {
            
$config    $xml->fetchElementsFromRecord$data );

            if( !
count($config) )
            {
                
$this->registry->output->showError$this->lang->words['h_xmlwrong'], 1111 );
            }
        }
        
        
//-----------------------------------------
        // Temp
        //-----------------------------------------
        
        
$tempExtraData unserialize$config['hook_extra_data'] );

        
//-----------------------------------------
        // Set config
        //-----------------------------------------
        
        
$config = array('hook_name'                => $config['hook_name'],
                        
'hook_desc'                => $config['hook_desc'],
                        
'hook_author'            => $config['hook_author'],
                        
'hook_email'            => $config['hook_email'],
                        
'hook_website'            => $config['hook_website'],
                        
'hook_update_check'        => $config['hook_update_check'],
                        
'hook_requirements'        => $config['hook_requirements'],
                        
'hook_version_human'    => $config['hook_version_human'],
                        
'hook_version_long'        => $config['hook_version_long'],
                        
'hook_key'                => $config['hook_key'],
                        
'hook_global_caches'    => $config['hook_global_caches'],
                        
'hook_enabled'            => $enabled,
                        
'hook_updated'            => IPS_UNIX_TIME_NOW,
                        );

        
$extra_data    = array();

        
//-----------------------------------------
        // Set files
        //-----------------------------------------
        
        
$files        = array();

        foreach( 
$xml->fetchElements('hookfiles') as $node )
        {
            foreach( 
$xml->fetchElements('file'$node) as $_file )
            {
                
$file    $xml->fetchElementsFromRecord$_file );
    
                if( 
$file['hook_type'] )
                {
                    
$files[]     = array(
                                        
'hook_file_real'    => $file['hook_file_real'],
                                        
'hook_type'            => $file['hook_type'],
                                        
'hook_classname'    => $file['hook_classname'],
                                        
'hook_data'            => $file['hook_data'],
                                        
'hooks_source'        => $file['hooks_source'],
                                        );
                }
            }
        }

        
//-----------------------------------------
        // Set the custom script
        //-----------------------------------------

        
$custom         = array();
        
$customClass null;

        foreach( 
$xml->fetchElements('hookextras_custom') as $node )
        {
            foreach( 
$xml->fetchElements('file'$node) as $_file )
            {
                
$file    $xml->fetchElementsFromRecord$_file );
                
                if( 
count($file) )
                {
                    
$custom    = array( 'filename'    => $file['filename'],
                                     
'source'    => $file['source'],
                                    );
                }
            }
        }
        
        
/* Got any custom file to initialize? */
        
if ( $custom['filename'] && $custom['source'] )
        {
            
# Our dirty trick to avoid saving the file on disk just yet...
            
$_custom preg_replace'#^(s*)<?(php)+#i'''$custom['source'] );
            eval(
$_custom);
            
            
$classname str_replace'.php'''$custom['filename'] );
            
            if( 
class_exists$classname ) )
            {
                
$customClass = new $classname$this->registry );
                
                if( 
method_exists$customClass'pre_install' ) )
                {
                    
$customClass->pre_install();
                }
            }
        }
        
        
//-----------------------------------------
        // Set the settings
        //-----------------------------------------
        
        
$settings        = array();
        
$settingGroups    = array();

        foreach( 
$xml->fetchElements('hookextras_settings') as $node )
        {
            foreach( 
$xml->fetchElements('setting'$node) as $_setting )
            {
                
$setting    $xml->fetchElementsFromRecord$_setting );
    
                if( 
$setting['conf_is_title'] == 1)
                {
                    
$settingGroups[]    = array(
                                                
'conf_title_title'        => $setting['conf_title_title'],
                                                
'conf_title_desc'        => $setting['conf_title_desc'],
                                                
'conf_title_noshow'        => $setting['conf_title_noshow'],
                                                
'conf_title_keyword'    => $setting['conf_title_keyword'],
                                                
'conf_title_app'        => $setting['conf_title_app'],
                                                
'conf_title_tab'        => $setting['conf_title_tab'],
                                                );
                }
                else
                {
                    
$settings[]            = array(
                                                
'conf_title'            => $setting['conf_title'],
                                                
'conf_description'        => $setting['conf_description'],
                                                
'conf_group'            => $setting['conf_group'],
                                                
'conf_type'                => $setting['conf_type'],
                                                
'conf_key'                => $setting['conf_key'],
                                                
'conf_default'            => $setting['conf_default'],
                                                
'conf_extra'            => $setting['conf_extra'],
                                                
'conf_evalphp'            => $setting['conf_evalphp'],
                                                
'conf_protected'        => $setting['conf_protected'],
                                                
'conf_position'            => $setting['conf_position'],
                                                
'conf_start_group'        => $setting['conf_start_group'],
                                                
'conf_add_cache'        => $setting['conf_add_cache'],
                                                
'conf_title_keyword'    => $setting['conf_title_keyword'],
                                                );
                }
            }
        }

        
//-----------------------------------------
        // Set the lang bits
        //-----------------------------------------
        
        
$language        = array();

        foreach( 
$xml->fetchElements('hookextras_language') as $node )
        {
            foreach( 
$xml->fetchElements('language'$node) as $_langbit )
            {
                
$langbit    $xml->fetchElementsFromRecord$_langbit );
                
                
$language[]    = array(
                                    
'word_app'        => $langbit['word_app'],
                                    
'word_pack'        => $langbit['word_pack'],
                                    
'word_key'        => $langbit['word_key'],
                                    
'word_default'    => $langbit['word_default'],
                                    
'word_custom'    => $langbit['word_custom'],
                                    
'word_js'        => intval($langbit['word_js']),
                                    );
            }
        }
        
        
//-----------------------------------------
        // Set the modules
        //-----------------------------------------
        
        
$modules        = array();

        foreach( 
$xml->fetchElements('hookextras_modules') as $node )
        {
            foreach( 
$xml->fetchElements('module'$node) as $_module )
            {
                
$module        $xml->fetchElementsFromRecord$_module );
                
$modules[]    = array(
                                    
'sys_module_title'            => $module['sys_module_title'],
                                    
'sys_module_application'    => $module['sys_module_application'],
                                    
'sys_module_key'            => $module['sys_module_key'],
                                    
'sys_module_description'    => $module['sys_module_description'],
                                    
'sys_module_version'        => $module['sys_module_version'],
                                    
'sys_module_protected'        => $module['sys_module_protected'],
                                    
'sys_module_visible'        => $module['sys_module_visible'],
                                    
'sys_module_position'        => $module['sys_module_position'],
                                    
'sys_module_admin'            => $module['sys_module_admin'],
                                    );
            }
        }
        
        
//-----------------------------------------
        // Set the help files
        //-----------------------------------------
        
        
$help            = array();

        foreach( 
$xml->fetchElements('hookextras_help') as $node )
        {
            foreach( 
$xml->fetchElements('help'$node) as $_helpfile )
            {
                
$helpfile    $xml->fetchElementsFromRecord$_helpfile );
                
$help[]        = array(
                                    
'title'            => $helpfile['title'],
                                    
'text'            => $helpfile['text'],
                                    
'description'    => $helpfile['description'],
                                    
'position'        => $helpfile['position'],
                                    );
            }
        }
        
        
//-----------------------------------------
        // Set the templates
        //-----------------------------------------
        
        
$templates        = array();

        foreach( 
$xml->fetchElements('hookextras_templates') as $node )
        {
            foreach( 
$xml->fetchElements('templates'$node) as $_template )
            {
                
$template        $xml->fetchElementsFromRecord$_template );
                
$templates[]    = array(
                                        
'template_set_id'        => 0,
                                        
'template_group'        => $template['template_group'],
                                        
'template_content'        => $template['template_content'],
                                        
'template_name'            => $template['template_name'],
                                        
'template_data'            => $template['template_data'],
                                        
'template_updated'        => $template['template_updated'],
                                        
'template_removable'    => $template['template_removable'],
                                        
'template_added_to'        => intval($template['template_added_to']),
                                        
'template_user_added'    => 1,
                                        
'template_user_edited'  => 0,
                                        
'template_master_key'   => $template['template_master_key'] ? $template['template_master_key'] : 'root',
                                        );
            }
        }
        
        
//-----------------------------------------
        // Set the CSS
        //-----------------------------------------
        
        
$css            = array();

        foreach( 
$xml->fetchElements('hookextras_css') as $node )
        {
            foreach( 
$xml->fetchElements('css'$node) as $_css )
            {
                
$_css    $xml->fetchElementsFromRecord$_css );
                
$css[]    = array(
                                    
'css_set_id'        => 0,
                                    
'css_group'            => $_css['css_group'],
                                    
'css_content'        => $_css['css_content'],
                                    
'css_position'        => $_css['css_position'],
                                    
'css_added_to'        => 1,
                                    
'css_app'            => $_css['css_app'],
                                    
'css_app_hide'        => $_css['css_app_hide'],
                                    
'css_attributes'    => $_css['css_attributes'],
                                    
'css_removed'        => $_css['css_removed'],
                                    
'css_modules'        => $_css['css_modules'],
                                    
'css_master_key'    => $_css['css_master_key'],
                                    );
            }
        }
        
        
//-----------------------------------------
        // Set the Replacements
        //-----------------------------------------
        
        
$replacements    = array();
        
        foreach( 
$xml->fetchElements('hookextras_replacements') as $node )
        {
            foreach( 
$xml->fetchElements('replacements'$node) as $_r )
            {
                
$_r    $xml->fetchElementsFromRecord$_r );
                
$replacements[]    = array(
                                    
'replacement_key'        => $_r['replacement_key'],
                                    
'replacement_content'    => $_r['replacement_content'],
                                    );
            }
        }
        
        
//-----------------------------------------
        // Set the tasks
        //-----------------------------------------
        
        
$tasks            = array();

        foreach( 
$xml->fetchElements('hookextras_tasks') as $node )
        {
            foreach( 
$xml->fetchElements('tasks'$node) as $_task )
            {
                
$task        $xml->fetchElementsFromRecord$_task );
                
$tasks[]    = array(
                                    
'task_title'        => $task['task_title'],
                                    
'task_file'            => $task['task_file'],
                                    
'task_week_day'        => $task['task_week_day'],
                                    
'task_month_day'    => $task['task_month_day'],
                                    
'task_hour'            => $task['task_hour'],
                                    
'task_minute'        => $task['task_minute'],
                                    
'task_cronkey'        => $task['task_cronkey'],
                                    
'task_log'            => $task['task_log'],
                                    
'task_description'    => $task['task_description'],
                                    
'task_enabled'        => $task['task_enabled'],
                                    
'task_key'            => $task['task_key'],
                                    
'task_safemode'        => $task['task_safemode'],
                                    
'task_locked'        => $task['task_locked'],
                                    
'task_application'    => $task['task_application'],
                                    );
            }
        }

        
//-----------------------------------------
        // Set the database changes
        //-----------------------------------------
        
        
$database        = array(
                                
'create'    => array(),
                                
'alter'        => array(),
                                
'update'    => array(),
                                
'insert'    => array(),
                                );

        foreach( 
$xml->fetchElements('hookextras_database_create') as $node )
        {
            foreach( 
$xml->fetchElements('create'$node) as $_table )
            {
                
$table        $xml->fetchElementsFromRecord$_table );
                
$database['create'][]    = array(
                                            
'name'        => $table['name'],
                                            
'fields'    => $table['fields'],
                                            
'tabletype'    => $table['tabletype'],
                                            );
            }
        }

        foreach( 
$xml->fetchElements('hookextras_database_alter') as $node )
        {
            foreach( 
$xml->fetchElements('alter'$node) as $_table )
            {
                
$table        $xml->fetchElementsFromRecord$_table );
                
$database['alter'][]    = array(
                                            
'altertype'    => $table['altertype'],
                                            
'table'        => $table['table'],
                                            
'field'        => $table['field'],
                                            
'newfield'    => $table['newfield'],
                                            
'fieldtype'    => $table['fieldtype'],
                                            
'default'    => $table['default'],
                                            );
            }
        }

        foreach( 
$xml->fetchElements('hookextras_database_update') as $node )
        {
            foreach( 
$xml->fetchElements('update'$node) as $_table )
            {
                
$table        $xml->fetchElementsFromRecord$_table );
                
$database['update'][]    = array(
                                            
'table'        => $table['table'],
                                            
'field'        => $table['field'],
                                            
'newvalue'    => $table['newvalue'],
                                            
'oldvalue'    => $table['oldvalue'],
                                            
'where'        => $table['where'],
                                            );
            }
        }

        foreach( 
$xml->fetchElements('hookextras_database_insert') as $node )
        {
            foreach( 
$xml->fetchElements('insert'$node) as $_table )
            {
                
$table        $xml->fetchElementsFromRecord$_table );
                
$database['insert'][]    = array(
                                            
'table'        => $table['table'],
                                            
'updates'    => $table['updates'],
                                            
'fordelete'    => $table['fordelete'],
                                            );
            }
        }

        
//-----------------------------------------
        // Set some vars for display tallies
        //-----------------------------------------

        
$filesInserted            0;
        
$settingGroupsInserted    0;
        
$settingsInserted        0;
        
$settingsUpdated        0;
        
$languageInserted        0;
        
$languageUpdated        0;
        
$modulesInserted        0;
        
$modulesUpdated            0;
        
$helpInserted            0;
        
$helpUpdated            0;
        
$templatesInserted        0;
        
$templatesUpdated        0;
        
$templateHooks            false;
        
$tasksInserted            0;
        
$tasksUpdated            0;
        
$createQueries            0;
        
$alterQueries            0;
        
$updateQueries            0;
        
$insertQueries            0;
        
$cssInserted            0;
        
$cssUpdated                0;
        
$replacementsInserted    0;
        
$replacementsUpdated    0;
        
        
//-----------------------------------------
        // Insert/update DB records
        //-----------------------------------------
        
        
if( $this->hooks$config['hook_key'] ]['hook_id'] )
        {
            
//-----------------------------------------
            // Don't change enabled/disabled status
            //-----------------------------------------
            
            
unset( $config['hook_enabled'] );
            
            
$this->DB->update'core_hooks'$config'hook_id=' $this->hooks$config['hook_key'] ]['hook_id'] );
            
            
$hook_id    $this->hooks$config['hook_key'] ]['hook_id'];
            
            
$extra_data    unserialize$this->hooks$config['hook_key'] ]['hook_extra_data'] );
            
            
/* Reset DB */
            
$extra_data['database'] = array();
        }
        else
        {
            
$config['hook_installed']            = IPS_UNIX_TIME_NOW;
            
$this->hook$config['hook_key'] ]    = $config;
            
            
$this->DB->insert'core_hooks'$config );
            
            
$hook_id    $this->DB->getInsertId();
            
            
$this->hook$config['hook_key'] ]['hook_id'] = $hook_id;
            
            
$extra_data['display']    = $tempExtraData['display'];
        }

        if( 
count($files) )
        {
            
//-----------------------------------------
            // If we are updating, remove old files
            //-----------------------------------------
            
            
if( $this->hooks$config['hook_key'] ]['hook_id'] )
            {
                
$this->DB->build( array( 'select' => 'hook_file_id, hook_file_stored''from' => 'core_hooks_files''where' => 'hook_hook_id=' $this->hooks$config['hook_key'] ]['hook_id'] ) );
                
$outer $this->DB->execute();
                
                while( 
$r $this->DB->fetch($outer) )
                {
                    @
unlinkIPS_HOOKS_PATH $r['hook_file_stored'] );
                    
$this->DB->delete'core_hooks_files''hook_file_id=' $r['hook_file_id'] );
                }
            }
                
            foreach( 
$files as $file )
            {
                
//-----------------------------------------
                // Store new files
                //-----------------------------------------
                
                
$filename    $file['hook_classname'] . '_' md5uniqidmicrotime(), true ) ) . '.php';
                
                
file_put_contentsIPS_HOOKS_PATH $filename$file['hooks_source'] );
                
chmodIPS_HOOKS_PATH $filenameIPS_FILE_PERMISSION );
                
                
$file['hook_file_stored']    = $filename;
                
$file['hook_hook_id']        = $hook_id;
                
                
$this->DB->insert'core_hooks_files'$file );
                
$filesInserted++;
                
                
/* Need to recache skins? */
                
if ( $file['hook_type'] == 'templateHooks' )
                {
                    
$templateHooks true;
                }
            }
        }
        
        
//-----------------------------------------
        // Put custom install/uninstall file
        //-----------------------------------------
        
        
if( is_object($customClass) )
        {
            
$extra_data['display']['custom'] = $custom['filename'];
            
            
file_put_contentsIPS_HOOKS_PATH 'install_' $custom['filename'], $custom['source'] );
            
chmodIPS_HOOKS_PATH 'install_' $custom['filename'], IPS_FILE_PERMISSION );
        }
                
        
//-----------------------------------------
        // (1) Settings
        //-----------------------------------------
        
        
if( count($settingGroups) OR count($settings) )
        {
            
$setting_groups = array();
            
            
$this->DB->build( array( 'select' => '*''from' => 'core_sys_settings_titles' ) );
            
$this->DB->execute();
            
            while( 
$r $this->DB->fetch() )
            {
                
$setting_groups$r['conf_title_id'] ] = $r;
                
$setting_groups_by_key$r['conf_title_keyword'] ] = $r;
            }
            
            
//-----------------------------------------
            // Get current settings.
            //-----------------------------------------
            
            
$this->DB->build( array( 'select' => 'conf_id, conf_key''from' => 'core_sys_conf_settings' ) );
            
$this->DB->execute();
            
            while ( 
$r $this->DB->fetch() )
            {
                
$cur_settings$r['conf_key'] ] = $r['conf_id'];
            }
        }
            
        if( 
count($settingGroups) )
        {
            
$need_to_update = array();
            
            foreach( 
$settingGroups as $data )
            {
                if ( 
$data['conf_title_title'] AND $data['conf_title_keyword'] )
                {
                    
//-----------------------------------------
                    // Get ID based on key
                    //-----------------------------------------
                    
                    
$conf_id $setting_groups_by_key$data['conf_title_keyword'] ]['conf_title_id'];
                    
                    
$save = array( 'conf_title_title'   => $data['conf_title_title'],
                                   
'conf_title_desc'    => $data['conf_title_desc'],
                                   
'conf_title_keyword' => $data['conf_title_keyword'],
                                   
'conf_title_app'     => $data['conf_title_app'],
                                   
'conf_title_tab'        => $data['conf_title_tab'],
                                   
'conf_title_noshow'  => $data['conf_title_noshow']  );
                    
                    
//-----------------------------------------
                    // Not got a row, insert first!
                    //-----------------------------------------
                    
                    
if ( ! $conf_id )
                    {
                        
$this->DB->insert'core_sys_settings_titles'$save );
                        
$conf_id $this->DB->getInsertId();
                        
$settingGroupsInserted++;
                        
$extra_data['settingGroups'][] = $save['conf_title_keyword'];
                    }
                    else
                    {
                        
//-----------------------------------------
                        // Update...
                        //-----------------------------------------
                        
                        
$this->DB->update'core_sys_settings_titles'$save'conf_title_id='.$conf_id );
                    }
                    
                    
//-----------------------------------------
                    // Update settings cache
                    //-----------------------------------------
                    
                    
$save['conf_title_id']                                    = $conf_id;
                    
$setting_groups_by_key$save['conf_title_keyword'] ]    = $save;
                    
$setting_groups$save['conf_title_id'] ]                = $save;
                        
                    
//-----------------------------------------
                    // Set need update...
                    //-----------------------------------------
                    
                    
$need_update[] = $conf_id;
                }
            }
        }
        
        if( 
count($settings) )
        {
            foreach( 
$settings as $idx => $data )
            {
                
$data['conf_group'] = $setting_groups_by_key$data['conf_title_keyword'] ]['conf_title_id'];
                
                
//-----------------------------------------
                // Remove from array
                //-----------------------------------------
                
                
unset( $data['conf_title_keyword'] );
                
                if ( 
$cur_settings$data['conf_key'] ] )
                {
                    
$this->DB->update'core_sys_conf_settings'$data'conf_id='.$cur_settings$data['conf_key'] ] );
                    
$settingsUpdated++;
                }
                else
                {
                    
$this->DB->insert'core_sys_conf_settings'$data );
                    
$settingsInserted++;
                    
$extra_data['settings'][] = $data['conf_key'];
                }
            }
        }
        
        
//-----------------------------------------
        // Update group counts...
        //-----------------------------------------
        
        
if ( count$need_update ) )
        {
            foreach( 
$need_update as $i => $idx )
            {
                
$conf $this->DB->buildAndFetch( array( 'select' => 'count(*) as count''from' => 'core_sys_conf_settings''where' => 'conf_group=' $idx ) );
            
                
$count intval($conf['count']);
                
                
$this->DB->update'core_sys_settings_titles', array( 'conf_title_count' => $count ), 'conf_title_id='.$idx );
            }
        }
        
        if( 
count($settingGroups) OR count($settings) )
        {
            
$this->cache->rebuildCache'settings''global' );
        }

        
//-----------------------------------------
        // (2) Languages
        //-----------------------------------------

        
if( count($language) )
        {
            
$langPacks    = array();
            
            
$this->DB->build( array( 'select' => 'lang_id''from' => 'core_sys_lang' ) );
            
$this->DB->execute();
            
            while( 
$r $this->DB->fetch() )
            {
                
$langPacks[] = $r['lang_id'];
            }

            foreach( 
$language as $langbit )
            {
                foreach( 
$langPacks as $lang_id )
                {
                    
$langbit['lang_id'] = $lang_id;
                    
                    
// See if it exists
                    
$cnt $this->DB->buildAndFetch( array( 'select' => 'word_id''from' => 'core_sys_lang_words''where' => "lang_id={$lang_id} AND word_app='{$langbit['word_app']}' AND word_key='{$langbit['word_key']}' AND word_pack='{$langbit['word_pack']}'" ) );
                    
                    if( 
$cnt['word_id'] )
                    {
                        
$this->DB->update'core_sys_lang_words'$langbit'word_id=' $cnt['word_id'] );
                        
$languageUpdated++;
                    }
                    else
                    {
                        
$this->DB->insert'core_sys_lang_words'$langbit );
                        
$languageInserted++;
                        
$word_id $this->DB->getInsertId();
                        
$extra_data['language'][ $langbit['word_pack'] ][]    = $langbit['word_key'];
                    }
                }
            }
            
            
$classToLoad IPSLib::loadActionOverloaderIPSLib::getAppDir('core') . '/modules_admin/languages/manage_languages.php''admin_core_languages_manage_languages' );
            
$langLib     = new $classToLoad();
            
$langLib->makeRegistryShortcuts$this->registry );
            
            foreach( 
$langPacks as $langId )
            {
                
$langLib->cacheToDisk$langId );
            }
        }
        
        
//-----------------------------------------
        // (3) Modules
        //-----------------------------------------
        
        
if( count($modules) )
        {
            
//-----------------------------------------
            // Get current modules
            //-----------------------------------------
            
$cur_modules = array();
            
$this->DB->build( array( 'select'    => '*',
                                        
'from'    => 'core_sys_module',
                                        
'order'    => 'sys_module_id' ) );
            
            
$this->DB->execute();
            
            while ( 
$r $this->DB->fetch() )
            {
                
$cur_modules$r['sys_module_application'] ][ $r['sys_module_key'] ] = $r['sys_module_id'];
            }
            
            foreach( 
$modules as $module )
            {
                
//-----------------------------------------
                // Insert or update?
                //-----------------------------------------
            
                
if ( $cur_modules$module['sys_module_application'] ][ $module['sys_module_key'] ] )
                {
                    
$this->DB->update'core_sys_module'$module"sys_module_id=" $cur_modules$module['sys_module_application'] ][ $module['sys_module_key'] ] );
                    
$modulesUpdated++;
                }
                else
                {
                    
$this->DB->insert'core_sys_module'$module );
                    
$modulesInserted++;
                    
                    
$extra_data['modules'][] = ( $module['sys_module_admin'] ? 'admin' 'public' ) . '-' $module['sys_module_application'] . '-' $module['sys_module_key'];
                }
            }
            
            
$classToLoad IPSLib::loadActionOverloaderIPSLib::getAppDir('core') . '/modules_admin/applications/applications.php''admin_core_applications_applications' );
            
$moduleLib   = new $classToLoad();
            
$moduleLib->makeRegistryShortcuts$this->registry );
            
$moduleLib->moduleRecache();
            
$moduleLib->applicationsMenuDataRecache();
        }
        
        
//-----------------------------------------
        // (4) Help Files
        //-----------------------------------------
        
        
if( count($help) )
        {
            
$keys        = array();
            
            
$this->DB->build( array( 'select' => 'title''from' => 'faq' ) );
            
$this->DB->execute();
            
            while( 
$r $this->DB->fetch() )
            {
                
$keys[] = $r['title'];
            }

            foreach( 
$help as $entry )
            {
                if( 
in_array$entry['title'], $keys ) )
                {
                    
$this->DB->update'faq'$entry"title='{$entry['title']}'" );
                    
$helpUpdated++;
                }
                else
                {    
                    
$this->DB->insert'faq'$entry );
                    
$helpInserted++;
                    
$help_id $this->DB->getInsertId();
                    
$extra_data['help'][] = $entry['title'];
                }
            }
        }

        
//-----------------------------------------
        // (6) Templates
        //-----------------------------------------
        
        
if( count($templates) )
        {
            
$bits        = array();
            
            
/* Root will always be updated */
            
$this->DB->build( array( 'select' => 'template_name,template_group,template_master_key''from' => 'skin_templates' ) );
            
$this->DB->execute();
            
            while( 
$r $this->DB->fetch() )
            {
                
$bits$r['template_master_key'] ][ $r['template_group'] ][] = $r['template_name'];
            }

            foreach( 
$templates as $template )
            {
                
//-----------------------------------------
                // If template is not in root set, add it to
                // prevent fatal error selecting other skins
                //-----------------------------------------
                
                
if ( $template['template_master_key'] != 'root' && ( !isset($bits['root'][ $template['template_group'] ]) OR !in_array$template['template_name'], $bits['root'][ $template['template_group'] ] ) ) )
                {
                    
$this->DB->insert'skin_templates'array_merge$template, array( 'template_set_id' => 0'template_master_key' => 'root''template_content' => '' ) ) );
                    
                    
$extra_data['templates'][ $template['template_group'] ][ $template['template_name'] ]    = $template['template_name'];
                    
$bits['root'][ $template['template_group'] ][]                                            = $template['template_name'];
                }
                
                
//-----------------------------------------
                // Ignore unknown skin sets
                //-----------------------------------------
                
                
if ( !isset($bits$template['template_master_key'] ]) )
                {
                    continue;
                }
                
                if( isset(
$bits$template['template_master_key'] ][ $template['template_group'] ]) AND in_array$template['template_name'], $bits$template['template_master_key'] ][ $template['template_group'] ] ) )
                {
                    
$template['template_updated'] = IPS_UNIX_TIME_NOW;

                    
$this->DB->update'skin_templates'$template"template_master_key='{$template['template_master_key']}' AND template_group='{$template['template_group']}' AND template_name='{$template['template_name']}'" );
                    
$templatesUpdated++;
                }
                else
                {    
                    
$this->DB->insert'skin_templates'$template );
                    
$templatesInserted++;

                    
$extra_data['templates'][ $template['template_group'] ][ $template['template_name'] ]    = $template['template_name'];
                    
$bits$template['template_master_key'] ][ $template['template_group'] ][]                = $template['template_name'];
                }
            }
        }
        
        
//-----------------------------------------
        // CSS
        //-----------------------------------------
        
        
if( count$css ) )
        {
            
$bits        = array();
            
            
$this->DB->build( array( 'select' => 'css_master_key, css_group''from' => 'skin_css' ) );
            
$this->DB->execute();
            
            while( 
$r $this->DB->fetch() )
            {
                
$bits$r['css_master_key'] ][ $r['css_group'] ] = $r['css_group'];
            }

            foreach( 
$css as $entry )
            {
                
//-----------------------------------------
                // Ignore unknown skin sets
                //-----------------------------------------
                
                
if ( !isset( $bits$entry['css_master_key'] ] ) )
                {
                    continue;
                }
                
                if( 
in_array$entry['css_group'], $bits$entry['css_master_key'] ] ) )
                {
                    
$entry['css_updated']    = IPS_UNIX_TIME_NOW;

                    
$this->DB->update'skin_css'$entry"css_master_key='{$entry['css_master_key']}' AND css_group='{$entry['css_group']}'" );
                    
$cssUpdated++;
                }
                else
                {    
                    
$this->DB->insert'skin_css'$entry );
                    
$cssInserted++;

                    
$extra_data['css'][ $entry['css_group'] ]                    = $entry['css_group'];
                    
$bits$entry['css_master_key'] ][ $entry['css_group'] ]    = $entry['css_group'];
                }
            }
        }
        
        
//-----------------------------------------
        // Skin Replacements
        //-----------------------------------------
                
        
if( count$replacements ) )
        {
            
$bits        = array();
            
            
$this->DB->build( array( 'select' => 'replacement_master_key, replacement_key''from' => 'skin_replacements' ) );
            
$this->DB->execute();
            
            while( 
$r $this->DB->fetch() )
            {
                
$bits$r['replacement_master_key'] ][ $r['replacement_key'] ] = $r['replacement_key'];
            }
            
            foreach( 
$replacements as $entry )
            {
                if ( !isset( 
$bits$entry['replacement_master_key'] ] ) )
                {
                    
$entry['replacement_master_key'] = 'root';
                }
            
                if( 
in_array$entry['replacement_key'], $bits$entry['replacement_master_key'] ] ) )
                {
                    
$this->DB->update'skin_replacements'$entry"replacement_master_key='{$entry['replacement_master_key']}' AND replacement_key='{$entry['replacement_key']}'" );
                    
$replacementsUpdated++;
                }
                else
                {    
                    
$this->DB->insert'skin_replacements'$entry );
                    
$replacementsInserted++;

                    
$extra_data['replacements'][ $entry['replacement_key'] ]        = $entry['replacement_key'];
                }
            }
        }
        
        
//-----------------------------------------
        // (7) Tasks
        //-----------------------------------------
        
        
if( count($tasks) )
        {
            
$keys        = array();
            
            
$this->DB->build( array( 'select' => 'task_key''from' => 'task_manager' ) );
            
$this->DB->execute();
            
            while( 
$r $this->DB->fetch() )
            {
                
$keys[] = $r['task_key'];
            }

            foreach( 
$tasks as $entry )
            {
                if( 
in_array$entry['task_key'], $keys ) )
                {
                    
$this->DB->update'task_manager'$entry"task_key='{$entry['task_key']}'" );
                    
$tasksUpdated++;
                }
                else
                {    
                    
$this->DB->insert'task_manager'$entry );
                    
$tasksInserted++;
                    
$task_id $this->DB->getInsertId();
                    
$extra_data['tasks'][] = $entry['task_key'];
                }
            }
        }
        
        
//-----------------------------------------
        // (8) Create new tables
        //-----------------------------------------
        
        
if( count($database['create']) )
        {
            foreach(
$database['create'] as $create )
            {
                
$query    "CREATE TABLE {$this->settings['sql_tbl_prefix']}{$create['name']} (
                            
{$create['fields']}
                            )"
;
                
                if( 
$create['tabletype'] )
                {
                    
$query .= " ENGINE=" $create['tabletype'];
                }
                else if( 
$this->settings['sql_driver'] == 'mysql' AND $this->settings['mysql_tbl_type'] )
                {
                    
$query .= " ENGINE=" $this->settings['mysql_tbl_type'];
                }
                
                
//-----------------------------------------
                // Fix prefix
                //-----------------------------------------

                
$this->DB->return_die true;
                
$this->DB->query$query );
                
$this->DB->return_die false;
                
$createQueries++;
                
                
$extra_data['database']['create'][] = $create;
            }
        }

        
//-----------------------------------------
        // (9) Alter tables
        //-----------------------------------------
        
        
if( count($database['alter']) )
        {
            foreach( 
$database['alter'] as $alter )
            {
                
$this->DB->return_die true;
                
                switch( 
$alter['altertype'] )
                {
                    case 
'remove':
                        
$this->DB->dropField$alter['table'], $alter['field'] );
                    break;
                    
                    case 
'add':
                        
$this->DB->addField$alter['table'], $alter['field'], $alter['fieldtype'], $alter['default'] );
                    break;
                    
                    case 
'change':
                        
$this->DB->changeField$alter['table'], $alter['field'], $alter['newfield'], $alter['fieldtype'], $alter['default'] );
                    break;
                }
                
                
$this->DB->return_die false;
                
$alterQueries++;
                
$extra_data['database']['alter'][] = $alter;
            }
        }
        
        
//-----------------------------------------
        // (10) Run update queries
        //-----------------------------------------
        
        
if( count($database['update']) )
        {
            foreach( 
$database['update'] as $update )
            {
                
$this->DB->return_die true;
                
$this->DB->update$update['table'], array( $update['field'] => $update['newvalue'] ), html_entity_decode$update['where'], ENT_QUOTES ) );
                
$this->DB->return_die false;
                
$updateQueries++;
                
$extra_data['database']['update'][] = $update;
            }
        }
        
        
//-----------------------------------------
        // (11) Run insert queries
        //-----------------------------------------
        
    //    if( !$this->hooks[ $config['hook_key'] ]['hook_id'] )
    //    {
            
if( count($database['insert']) )
            {
                foreach( 
$database['insert'] as $insert )
                {
                    
$fields        = array();
                    
$content    explode','$insert['updates'] );
                    
                    foreach( 
$content as $value )
                    {
                        list( 
$field$toInsert ) = explode'='$value );
                        
                        
$fieldstrim($field) ] = str_replace'~C~'','$toInsert );
                    }

                    
$this->DB->return_die true;
                    
$this->DB->insert$insert['table'], $fields );
                    
$this->DB->return_die false;
                    
$insertQueries++;
                    
$extra_data['database']['insert'][] = $insert;
                }
            }
    
//    }
        
        /* Got an install function to run too? */
        
if( is_object($customClass) )
        {
            if( 
method_exists$customClass'install' ) )
            {
                
$customClass->install();
            }
        }
        
        if( 
count($extra_data) )
        {
            
$this->DB->update'core_hooks', array( 'hook_extra_data' => serialize$extra_data ) ), 'hook_id=' $hook_id );
        }
                    
        
//print_r($config);
        //print_r($files);
        //print_r($custom);
        //print_r($settingGroups);
        //print_r($settings);
        //print_r($language);
        //print_r($modules);
        //print_r($templates);
        //print_r($tasks);
        //print_r($help);
        //print_r($database);

        
if ( $addMessage )
        {
            
$_tempMsg = <<<EOF
        <strong>{$this->lang->words['h_newhookin']}</strong>
        <ul>
            <li>
{$filesInserted} {$this->lang->words['h_filesin']}</li>
            <li>
{$settingGroupsInserted} {$this->lang->words['h_settinggin']}</li>
            <li>
{$settingsInserted} {$this->lang->words['h_settingin']}</li>
            <li>
{$settingsUpdated} {$this->lang->words['h_settingup']}</li>
            <li>
{$languageInserted} {$this->lang->words['h_langbitin']}</li>
            <li>
{$languageUpdated} {$this->lang->words['h_langbitup']}</li>
            <li>
{$modulesInserted} {$this->lang->words['h_modin']}</li>
            <li>
{$modulesUpdated} {$this->lang->words['h_modup']}</li>
            <li>
{$helpInserted} {$this->lang->words['h_helpin']}</li>
            <li>
{$helpUpdated} {$this->lang->words['h_helpup']}</li>
            <li>
{$templatesInserted} {$this->lang->words['h_tempin']}</li>
            <li>
{$templatesUpdated} {$this->lang->words['h_tempup']}</li>
            <li>
{$cssInserted} {$this->lang->words['h_cssin']}</li>
            <li>
{$cssUpdated} {$this->lang->words['h_cssup']}</li>
            <li>
{$replacementsInserted} {$this->lang->words['h_replacementsin']}</li>
            <li>
{$replacementsUpdated} {$this->lang->words['h_replacementsup']}</li>
            <li>
{$tasksInserted} {$this->lang->words['h_taskin']}</li>
            <li>
{$tasksUpdated} {$this->lang->words['h_taskup']}</li>
            <li>
{$createQueries} {$this->lang->words['h_dbcreated']}</li>
            <li>
{$alterQueries} {$this->lang->words['h_dbaltered']}</li>
            <li>
{$updateQueries} {$this->lang->words['h_updateran']}</li>
            <li>
{$insertQueries} {$this->lang->words['h_insertran']}</li>
        </ul>
EOF;

            
$this->registry->output->setMessage$_tempMsg);
        }
        
        
//-----------------------------------------
        // Got some skin recaching to do...
        //-----------------------------------------
        
        
if( $allowSkinRecache === TRUE AND ( $templatesInserted OR $templatesUpdated OR $templateHooks OR $cssUpdated OR $cssInserted ) )
        {
            
/* Rebuild cache */
            
$this->rebuildHooksCache();
            
            
/* Flag skins for recache */
            
require_once( IPS_ROOT_PATH 'sources/classes/skins/skinFunctions.php' );/*noLibHook*/
            
require_once( IPS_ROOT_PATH 'sources/classes/skins/skinCaching.php' );/*noLibHook*/
            
$skinCaching = new skinCaching$this->registry );
            
$skinCaching->flagSetForRecache();
        }
    }

    
/**
     * Show the form to export a hook
     *
     * @return   void
     */
    
protected function _exportHook()
    {
        
/* Get the hook */
        
$id    intval($this->request['id']);
        
        if( !
$id )
        {
            
$this->registry->output->showError$this->lang->words['h_noexport'], 1112 );
        }
        
        
$hookData $this->DB->buildAndFetch( array( 'select' => '*''from' => 'core_hooks''where' => 'hook_id=' $id ) );
        
        if( !
$hookData['hook_id'] )
        {
            
$this->registry->output->showError$this->lang->words['h_noexport'], 1113 );
        }
        
        
/* Set defaults */
        
$hookData['hook_extra_data'] = unserialize$hookData['hook_extra_data'] );

        
/* Output */
        
$this->registry->output->html .= $this->html->hooksExport$hookData );
    }
    
    
/**
     * Actually export the damn hook already
     * Sorry, it has been a long day...
     *
     * @return    @e void
     */
    
protected function _doExportHook()
    {
        
//-----------------------------------------
        // Get hook
        //-----------------------------------------
        
        
$id    intval($this->request['id']);
        
        if( !
$id )
        {
            
$this->registry->output->showError$this->lang->words['h_noexport'], 1114 );
        }
        
        
$hookData    $this->DB->buildAndFetch( array( 'select' => '*''from' => 'core_hooks''where' => 'hook_id=' $id ) );
        
        if( !
$hookData['hook_id'] )
        {
            
$this->registry->output->showError$this->lang->words['h_noexport'], 1115 );
        }
        
        
$extra_data    unserialize$hookData['hook_extra_data'] );
        
        
//-----------------------------------------
        // Get hook files
        //-----------------------------------------
        
        
$files = array();
        
$index 1;
        
        
$this->DB->build( array( 'select' => '*''from' => 'core_hooks_files''where' => 'hook_hook_id=' $id'order' => 'hook_file_id ASC' ) );
        
$this->DB->execute();
        
        while( 
$r $this->DB->fetch() )
        {
            
$files$index ]    = $r;
            
$index++;
        }

        
//-----------------------------------------
        // Get XML class
        //-----------------------------------------
        
        
require_once( IPS_KERNEL_PATH.'classXML.php' );/*noLibHook*/

        
$xml = new classXMLIPS_DOC_CHAR_SET );
        
        
$xml->newXMLDocument();
        
$xml->addElement'hookexport' );

        
//-----------------------------------------
        // Put hook data in export
        //-----------------------------------------
        
        
$xml->addElement'hookdata''hookexport' );
        
$content    = array();
        
        foreach( 
$hookData as $k => $v )
        {
            if( 
in_array$k, array( 'hook_id''hook_enabled''hook_installed''hook_updated''hook_position' ) ) )
            {
                continue;
            }
            
            
$content$k ] = $v;
        }
        
        
$xml->addElementAsRecord'hookdata''config'$content );
        
        
//-----------------------------------------
        // Put hook files in export
        //-----------------------------------------
        
        
$xml->addElement'hookfiles''hookexport' );

        foreach( 
$files as $index => $r )
        {
            
$content    = array();
            
            foreach( 
$r as $k => $v )
            {
                if( 
in_array$k, array( 'hook_file_id''hook_hook_id''hook_file_stored''hooks_source' ) ) )
                {
                    continue;
                }
                
                
$content$k ] = $v;
            }
            
            
$source    is_fileIPS_HOOKS_PATH $r['hook_file_stored'] ) ? file_get_contentsIPS_HOOKS_PATH $r['hook_file_stored'] ) : '';
            
            if ( !empty(
$source) && in_array$r['hook_type'], array( 'skinHooks''commandHooks''libraryHooks' ) ) )
            {
                
$source    $this->_cleanSource$source );
            }

            
$content['hooks_source'] = $source;

            
$xml->addElementAsRecord'hookfiles''file'$content );
        }

        
//-----------------------------------------
        // Custom install/uninstall script?
        //-----------------------------------------
        
        
if( $extra_data['custom'] )
        {
            
$content    = array();
            
$xml->addElement'hookextras_custom''hookexport' );
        
            
$content['filename']    = $extra_data['custom'];
            
$content['source']        = is_fileIPS_HOOKS_PATH 'install_' $extra_data['custom'] ) ? file_get_contentsIPS_HOOKS_PATH 'install_' $extra_data['custom'] ) : '';
            
            
$xml->addElementAsRecord'hookextras_custom''file'$content );
        }
        
        
//-----------------------------------------
        // Settings or setting groups?
        //-----------------------------------------
        
        
$entry        = array();
        
$_groups    = array();
        
$_settings    = array();
        
$titles        = array();
        
$content    = array();
        
        
$xml->addElement'hookextras_settings''hookexport' );
        
        
# Store group ids and setting ids for entire setting groups
        
if( is_array($extra_data['settingGroups']) AND count($extra_data['settingGroups']) )
        {
            
$_groups    $extra_data['settingGroups'];
            
$_groupIds    = array();
            
            
$this->DB->build( array( 'select' => 'conf_title_id''from' => 'core_sys_settings_titles''where' => "conf_title_keyword IN('" implode"','"$_groups ) . "')" ) );
            
$this->DB->execute();
            
            while( 
$rr $this->DB->fetch() )
            {
                
$_groupIds[] = $rr['conf_title_id'];
            }
            
            if( 
count($_groupIds) )
            {
                
$this->DB->build( array( 'select' => 'conf_key''from' => 'core_sys_conf_settings''where' => 'conf_group IN(' implode','$_groupIds ) . ')' ) );
                
$this->DB->execute();
                
                while( 
$setting $this->DB->fetch() )
                {
                    
$_settings[] = $setting['conf_key'];
                }
            }
        }
        
        
# Store group ids and setting ids for indvidual settings
        
if( is_array($extra_data['settings']) AND count($extra_data['settings']) )
        {
            foreach( 
$extra_data['settings'] as $_aSetting )
            {
                
$_settings[] = $_aSetting;
            }
            
            
$this->DB->build( array( 'select'    => 't.conf_title_keyword'
                                     
'from'        => array( 'core_sys_settings_titles' => 't' ), 
                                     
'where'    => "c.conf_key IN('" implode"','"$extra_data['settings'] ) . "')",
                                     
'add_join'    => array(
                                                         array(
                                                             
'from'    => array( 'core_sys_conf_settings' => 'c' ),
                                                             
'where'    => 'c.conf_group=t.conf_title_id',
                                                             
'type'    => 'left',
                                                             )
                                                         )
                            )        );
            
$this->DB->execute();
            
            while( 
$group $this->DB->fetch() )
            {
                
$_groups[] = $group['conf_title_keyword'];
            }
        }
        
        if( 
count($_groups) )
        {
            
# Now get the group data for the XML file
            
$this->DB->build( array( 'select' => '*''from' => 'core_sys_settings_titles''where' => "conf_title_keyword IN('" implode"','"$_groups ) . "')" ) );
            
$this->DB->execute();
            
            while( 
$r $this->DB->fetch() )
            {
                
$content    = array();
                
                
$titles$r['conf_title_id'] ] = $r['conf_title_keyword'];
                
                
$content['conf_is_title']    = 1;
                
                foreach( 
$r as $k => $v )
                {
                    if( 
in_array$k, array( 'conf_title_tab''conf_title_keyword''conf_title_title''conf_title_desc''conf_title_app''conf_title_noshow' ) ) )
                    {
                        
$content$k ] = $v;
                    }
                }

                
$xml->addElementAsRecord'hookextras_settings''setting'$content );
            }
        }
        
        if( 
count($_settings) )
        {
            
# Now get the group data for the XML file
            
$this->DB->build( array( 'select' => '*''from' => 'core_sys_conf_settings''where' => "conf_key IN('" implode"','"$_settings ) . "')" ) );
            
$this->DB->execute();
            
            while( 
$r $this->DB->fetch() )
            {
                
$r['conf_value']            = '';
                
$r['conf_title_keyword']    = $titles$r['conf_group'] ];
                
$r['conf_is_title']            = 0;

                
$xml->addElementAsRecord'hookextras_settings''setting'$r );
            }
        }

        
//-----------------------------------------
        // Language strings/files
        //-----------------------------------------
        
        
$entry        = array();
        
        
$xml->addElement'hookextras_language''hookexport' );
        
        if( 
is_array($extra_data['language']) AND count($extra_data['language']) )
        {
            foreach( 
$extra_data['language'] as $file => $strings )
            {
                
$bits explode'_'$file );
                
$app  $bits[0];
                
$pack str_replace$app.'_'''$file );
                
                
$this->DB->build( array( 'select' => '*''from' => 'core_sys_lang_words''where' => "word_app='{$app}' AND word_pack='{$pack}' AND word_key IN('" implode"','"$strings ) . "')" ) );
                
$this->DB->execute();
                
                while( 
$r $this->DB->fetch() )
                {
                    
$content    = array();
                    
                    foreach( 
$r as $k => $v )
                    {
                        if( !
in_array$k, array( 'word_app''word_pack''word_key''word_default' ) ) )
                        {
                            continue;
                        }
                        
                        
$content$k ] = $v;
                    }
    
                    
$xml->addElementAsRecord'hookextras_language''language'$content );
                }
            }
        }

        
//-----------------------------------------
        // Modules
        //-----------------------------------------

        
$xml->addElement'hookextras_modules''hookexport' );
        
        if( 
is_array($extra_data['modules']) AND count($extra_data['modules']) )
        {
            foreach ( 
$extra_data['modules'] as $module )
            {
                list( 
$_side$_app$_module ) = explode'-'$module );
                
$_is_admin = ( $_side == 'admin' ) ? 0;
                
                
$this->DB->build( array( 'select' => '*''from' => 'core_sys_module''where' => "sys_module_application='{$_app}' AND sys_module_key='{$_module}' AND sys_module_admin={$_is_admin}) );
                
$this->DB->execute();
                
                while( 
$r $this->DB->fetch() )
                {
                    unset(
$r['sys_module_id']);
                    
                    
$xml->addElementAsRecord'hookextras_modules''module'$r );
                }
            }
        }
        
        
//-----------------------------------------
        // Help files
        //-----------------------------------------

        
$xml->addElement'hookextras_help''hookexport' );
        
        if( 
is_array($extra_data['help']) AND count($extra_data['help']) )
        {
            
$this->DB->build( array( 'select' => '*''from' => 'faq''where' => "title IN('" implode"','"$extra_data['help'] ) . "')" ) );
            
$this->DB->execute();
            
            while( 
$r $this->DB->fetch() )
            {
                unset(
$r['id']);

                
$xml->addElementAsRecord'hookextras_help''help'$r );
            }
        }
        
        
//-----------------------------------------
        // Skin templates
        //-----------------------------------------

        
$remapData    $this->registry->output->buildRemapDatatrue );

        
$xml->addElement'hookextras_templates''hookexport' );
                
        if( 
is_array($extra_data['templates']) AND count($extra_data['templates']) )
        {
            foreach( 
$extra_data['templates'] as $file => $templates )
            {
                
$this->DB->build( array( 'select' => '*''from' => 'skin_templates''where' => "template_set_id IN ('" implode"','"$remapData['export'] ) . "') AND template_master_key != '' AND template_group='{$file}' AND template_name IN('" implode"','"$templates ) . "')" ) );
                
$this->DB->execute();
                
                while( 
$r $this->DB->fetch() )
                {
                    unset(
$r['template_id']);
                    unset(
$r['template_set_id']);
    
                    
$xml->addElementAsRecord'hookextras_templates''templates'$r );
                }
            }
        }
        
        
//-----------------------------------------
        // CSS
        //-----------------------------------------

        
$xml->addElement'hookextras_css''hookexport' );
                
        if( 
is_array$extra_data['css'] ) AND count $extra_data['css'] ) )
        {
            
$this->DB->build( array( 'select' => '*''from' => 'skin_css''where' => "css_set_id IN ('" implode"','"$remapData['export'] ) . "') AND css_master_key != '' AND css_group IN('" implode"','"$extra_data['css'] ) . "')" ) );
            
$this->DB->execute();
            
            while( 
$r $this->DB->fetch() )
            {
                unset(
$r['css_id']);
                unset(
$r['css_set_id']);

                
$xml->addElementAsRecord'hookextras_css''css'$r );
            }
        }
        
        
//-----------------------------------------
        // Replacements
        //-----------------------------------------

        
$xml->addElement'hookextras_replacements''hookexport' );
                
        if( 
is_array$extra_data['replacements'] ) AND count $extra_data['replacements'] ) )
        {
            
$this->DB->build( array( 'select' => '*''from' => 'skin_replacements''where' => "replacement_key IN('" implode"','"$extra_data['replacements'] ) . "')"'group' => 'replacement_key' ) );
            
            
$this->DB->execute();
            
            while( 
$r $this->DB->fetch() )
            {
                unset(
$r['replacement_id']);
                unset(
$r['replacement_set_id']);

                
$xml->addElementAsRecord'hookextras_replacements''replacements'$r );
            }
        }

        
//-----------------------------------------
        // Tasks
        //-----------------------------------------

        
$xml->addElement'hookextras_tasks''hookexport' );
                
        if( 
is_array($extra_data['tasks']) AND count($extra_data['tasks']) )
        {
            
$this->DB->build( array( 'select' => '*''from' => 'task_manager''where' => "task_key IN('" implode"','"$extra_data['tasks'] ) . "')" ) );
            
$this->DB->execute();
            
            while( 
$r $this->DB->fetch() )
            {
                unset(
$r['task_id']);
                unset(
$r['task_next_run']);

                
$xml->addElementAsRecord'hookextras_tasks''tasks'$r );
            }
        }

        
//-----------------------------------------
        // Database changes
        //-----------------------------------------

        
$xml->addElement'hookextras_database_create''hookexport' );
        
        if( 
is_array($extra_data['database']['create']) AND count($extra_data['database']['create']) )
        {
            foreach( 
$extra_data['database']['create'] as $create_query )
            {
                
$xml->addElementAsRecord'hookextras_database_create''create'$create_query );
            }
        }

        
$xml->addElement'hookextras_database_alter''hookexport' );
        
        if( 
is_array($extra_data['database']['alter']) AND count($extra_data['database']['alter']) )
        {
            foreach( 
$extra_data['database']['alter'] as $alter_query )
            {
                
$xml->addElementAsRecord'hookextras_database_alter''alter'$alter_query );
            }
        }

        
$xml->addElement'hookextras_database_update''hookexport' );
        
        if( 
is_array($extra_data['database']['update']) AND count($extra_data['database']['update']) )
        {
            foreach( 
$extra_data['database']['update'] as $update_query )
            {
                
$xml->addElementAsRecord'hookextras_database_update''update'$update_query );
            }
        }

        
$xml->addElement'hookextras_database_insert''hookexport' );
        
        if( 
is_array($extra_data['database']['insert']) AND count($extra_data['database']['insert']) )
        {
            foreach( 
$extra_data['database']['insert'] as $insert_query )
            {
                
$xml->addElementAsRecord'hookextras_database_insert''insert'$insert_query );
            }
        }

        
//-----------------------------------------
        // Print to browser
        //-----------------------------------------

        
$this->registry->output->showDownload$xml->fetchDocument(), $hookData['hook_key'] . '.xml''');
    }
    
    
/**
     * Clean source code for export..
     *
     * @param    string            Hook source code
     * @return    string            "Cleaned" source code
     */
    
protected function _cleanSource$source )
    {
        
$source preg_replace"/classs+(S+)s+extendss+(S+)/i""class \1 extends (~extends~)"$source );
        
        return 
$source;
    }
    
    
/**
     * Fix hook positions
     *
     * @return   @e void
     */
    
protected function _fixPositions()
    {
        
/* Init vars */
        
$new_order   0;
        
$usedActions = array();

        
$this->DB->build( array( 'select' => 'hook_id, hook_position''from' => 'core_hooks''where' => 'hook_enabled=1''order' => 'hook_position ASC' ) );
        
$qid $this->DB->execute();

        while ( 
$hook $this->DB->fetch$qid ) )
        {
            
$new_order++;
            
$this->DB->update'core_hooks', array ( 'hook_position' => $new_order ), "hook_id={$hook['hook_id']});
            
            
$this->DB->build( array( 'select' => '*''from' => 'core_hooks_files''where' => "hook_type IN ('commandHooks', 'skinHooks', 'libraryHooks' ) AND hook_hook_id=" $hook['hook_id'] ) );
            
$this->DB->execute();
        
            while( 
$file $this->DB->fetch() )
            {
                if( 
$file['hooks_source'] )
                {
                    
$source $this->_cleanSource$file['hooks_source'] );
                }
                else
                {
                    
$source is_fileIPS_HOOKS_PATH $file['hook_file_stored'] ) ? file_get_contentsIPS_HOOKS_PATH $file['hook_file_stored'] ) : '';
                    
                    if( 
$source )
                    {
                         
$source $this->_cleanSource$source );
                    }
                }
                
                if( 
$source )
                {
                    
$hook_data    unserialize$file['hook_data'] );
                    
$overload    $hook_data['classToOverload'];
                    
$newClass    $overload;
                    
                    
$app = ( $file['hook_type'] == 'libraryHooks' ) ? trim($hook_data['libApplication']) : '~_NO_APP_~';
                    
                    if( isset( 
$usedActions$app ][ $overload ] ) )
                    {
                        
$newClass $usedActions$app ][ $overload ];
                    }
                    else if( 
$file['hook_type'] == 'skinHooks' )
                    {
                        
$newClass .= "(~id~)";
                    }
                    
                    
$source str_replace"(~extends~)"$newClass$source );
                    
                    
file_put_contentsIPS_HOOKS_PATH $file['hook_file_stored'], $source );
                    
                    
$usedActions$app ][ $hook_data['classToOverload'] ] = $file['hook_classname'];
                }
            }
        }
    }
    
    
/**
     * Check if there is an update for a hook
     *
     * @param    string         URL to check
     * @param    string        Long version number
     * @return    bool
     */
    
public function _updateAvailable$url$version )
    {
        if( empty(
$url) || $version === '' )
        {
            return 
false;
        }
        
        
$classToLoad IPSLib::loadLibraryIPS_KERNEL_PATH '/classFileManagement.php''classFileManagement' );
        
$checker = new $classToLoad();
        
        
/* Timeout to prevent page from taking too long */
        
$checker->timeout 5;
        
        
/* Setup url and check */
        
$url  str_replace'php&''php?'$url );
        
$url .= '&boardVersion=' IPB_LONG_VERSION '&version=' $version;
        
        
$return $checker->getFileContents$url );
        
        
/* Return the content (if valid) or return 'no update' */
        
return ( strpos$return'0' ) === || strpos$return'1' ) === ) ? explode'|'$return ) : array( );
    }
    
    
/**
     * Sorts hooks by their position
     * (this is used to avoid a mysql filesort)
     * 
     * @param    array        $a        First hook data
     * @param    array        $b        Second hook data
     * @return    @e integer
     */
    
protected function sortHooksByPosition$a$b )
    {
        if ( 
$a['hook_position'] == $b['hook_position'] )
        {
            return 
0;
        }
        
        return ( 
$a['hook_position'] < $b['hook_position'] ) ? -1;
    }
    
    
/**
     * Hooks overview
     *
     * @return    @e void        [Outputs to screen]
     */
    
public function _hooksOverview()
    {
        
/* INI */
        
$hooksFound            = array( 'installed' => array(), 'uninstalled' => array() );
        
$hookwarnings        0;
        
$hookUpdates        0;
        
$checkUpdates        = !empty( $this->request['checkUpdates'] ) ? true false;
        
$message            '';
        
$confGroupIdsToLoad    = array();
        
$confGroupKeysToLoad= array();
        
        
/* Get current hooks */
        
$this->DB->build( array( 'select' => '*''from' => 'core_hooks' ) );
        
$outer    $this->DB->execute();
        
        while( 
$r $this->DB->fetch($outer) )
        {
            
/* Format some dates */
            
$r['_updated']   = $this->registry->getClass('class_localization')->formatTime$r['hook_updated'] );
            
$r['_installed'] = $this->registry->getClass('class_localization')->formatTime$r['hook_installed'] );
            
            
/* Got updates? */
            
if ( $r['hook_update_check'] && $checkUpdates === true )
            {
                
$r['hook_update_available'] = $this->_updateAvailable$r['hook_update_check'], $r['hook_version_long'] );
                
                if ( 
$r['hook_update_available'][0] )
                {
                    
$hookUpdates++;
                }
            }
            else
            {
                
$r['hook_update_available']    = array( );
            }
            
            
/* Got some setting groups to take care of? */
            
$r['_has_setting_links'] = null;
            
$r['_hook_extra_data']   = IPSLib::isSerialized($r['hook_extra_data']) ? unserialize($r['hook_extra_data']) : array();
            
            if ( 
is_array($r['_hook_extra_data']['settingGroups']) && count($r['_hook_extra_data']['settingGroups']) )
            {
                
$r['_has_setting_links'] = array();
                
                foreach( 
$r['_hook_extra_data']['settingGroups'] as $_group )
                {
                    
$confGroupKeysToLoad$_group ] = $_group;
                }
            }
            
            if ( 
is_array($r['_hook_extra_data']['settings']) && count($r['_hook_extra_data']['settings']) )
            {
                
$r['_has_setting_links'] = array();
                
                
$this->DB->build( array( 'select' => 'conf_group, conf_key''from' => 'core_sys_conf_settings''where' => "conf_key IN ('" implode"','"$r['_hook_extra_data']['settings'] ) . "')" ) );
                
$this->DB->execute();
                
                while( 
$hsg $this->DB->fetch() )
                {
                    
$confGroupIdsToLoad$hsg['conf_key'] ] = $hsg['conf_group'];
                }
            }
            
            
/* Check requirements */
            
$r['_require_errors'] = $this->checkHookRequirements$r );
            
            
/* Store */
            
if( $r['hook_enabled'] )
            {
                if ( 
count($r['_require_errors']) )
                {
                    
$hookwarnings++;
                }
                
                
$hooksFound['installed'][ $r['hook_id'] ]    = $r;
            }
            else
            {
                
$hooksFound['uninstalled'][ $r['hook_id'] ]    = $r;
            }
        }
        
        
/* Got groups to load? */
        
$where = array();
        
        if ( 
count($confGroupKeysToLoad) )
        {
            
$where[] = "conf_title_keyword IN ('" implode"','"$confGroupKeysToLoad ) . "')";
        }
        
        if ( 
count($confGroupIdsToLoad) )
        {
            
$where[] = "conf_title_id IN (" implode","$confGroupIdsToLoad ) . ")";
        }
        
        if ( 
count($where) )
        {
            
$confGroupsLoaded = array();
            
            
$this->DB->build( array( 'select' => '*''from' => 'core_sys_settings_titles''where' => implode' OR '$where ) ) );
            
$this->DB->execute();
            
            while( 
$gr $this->DB->fetch() )
            {
                if ( empty(
$gr['conf_title_noshow']) )
                {
                    
$confGroupsLoaded['ids'][ $gr['conf_title_id'] ]        = $gr;
                    
$confGroupsLoaded['keys'][ $gr['conf_title_keyword'] ]    = & $confGroupsLoaded['ids'][ $gr['conf_title_id'] ];
                }
            }
            
            
/* Merge back the data */
            
foreach( $hooksFound as $rk => $rt )
            {
                foreach( 
$rt as $sk => $st )
                {
                    if ( 
is_array($st['_has_setting_links']) )
                    {
                        if ( 
is_array($st['_hook_extra_data']['settingGroups']) && count($st['_hook_extra_data']['settingGroups']) )
                        {
                            foreach( 
$st['_hook_extra_data']['settingGroups'] as $_group )
                            {
                                if ( isset(
$confGroupsLoaded['keys'][ $_group ]) )
                                {
                                    
$hooksFound$rk ][ $sk ]['_has_setting_links'][ $confGroupsLoaded['keys'][ $_group ]['conf_title_id'] ] = $confGroupsLoaded['keys'][ $_group ]['conf_title_title'];
                                }
                            }
                        }
                        
                        if ( 
is_array($st['_hook_extra_data']['settings']) && count($st['_hook_extra_data']['settings']) )
                        {
                            foreach( 
$st['_hook_extra_data']['settings'] as $_id )
                            {
                                if ( isset(
$confGroupsLoaded['ids'][ $confGroupIdsToLoad$_id ] ]) )
                                {
                                    
$hooksFound$rk ][ $sk ]['_has_setting_links'][ $confGroupIdsToLoad$_id ] ] = $confGroupsLoaded['ids'][ $confGroupIdsToLoad$_id ] ]['conf_title_title'];
                                }
                            }
                        }
                    }
                }
            }
        }
        
        
/* Got updates to show? */
        
if ( $checkUpdates === true )
        {
            
$message = ( $hookUpdates == ) ? $this->lang->words['updates_string_single'] : sprintf$this->lang->words['updates_string_more'], $hookUpdates );
        }
        
        if ( 
count($hooksFound['installed']) )
        {
            
uasort$hooksFound['installed'], array( $this'sortHooksByPosition' ) );
        }
        
        
/* Output */
        
$this->registry->output->html .= $this->html->hooksOverview$hooksFound$hookwarnings$message );
    }
    
    
/**
     * Disables all hook
     *
     * @return    @e void        [Outputs to screen]
     */
    
protected function _disableAllHooks()
    {
        
/* INIT */
        
$activeHookIds = array();
        
        
/* Query Enabled Hooks */
        
$this->DB->build( array( 'select' => 'hook_id''from' => 'core_hooks''where' => "hook_enabled=1" ) );
        
$this->DB->execute();
        
        while( 
$r $this->DB->fetch() )
        {
            
$activeHookIds[] = $r['hook_id'];
        }
        
        
/* Make sure there were active hooks */
        
if( ! count$activeHookIds ) )
        {
            
$this->registry->output->global_message $this->lang->words['hook_disable_all_none'];
            
$this->_hooksOverview();
            return;
        }
        
        
/* Disable hooks */
        
$this->DB->update'core_hooks', array( 'hook_enabled' => ), 'hook_id IN( ' implode','$activeHookIds ) . ' ) ' );
        
        
/* Save to cache */
        
$this->cache->setCache'disabledHooksCache'$activeHookIds, array( 'array' => ) );
        
        
/* Rebuild cache */
        
$this->rebuildHooksCache();
        
        
/* All Done */
        
$this->registry->output->global_message $this->lang->words['hook_disabled_all'];
        
$this->registry->output->silentRedirectWithMessage$this->settings['base_url'] . $this->form_code '&amp;do=hooks_overview' );
    }
    
    
/**
     * Re-enable all hook
     *
     * @return    @e void        [Outputs to screen]
     */
    
protected function _reenableAllHooks()
    {
        
/* INIT */
        
$activeHookIds $this->cache->getCache'disabledHooksCache' );
        
        
/* Make sure there were active hooks */
        
if( ! count$activeHookIds ) )
        {
            
$this->registry->output->global_message $this->lang->words['hook_enable_all_none'];
            
$this->_hooksOverview();
            return;
        }
        
        
/* Disable hooks */
        
$this->DB->update'core_hooks', array( 'hook_enabled' => ), 'hook_id IN( ' implode','$activeHookIds ) . ' ) ' );
        
        
/* Save to cache */
        
$this->cache->setCache'disabledHooksCache', array(), array( 'array' => ) );
        
        
/* Rebuild cache */
        
$this->rebuildHooksCache();
        
        
/* Flag skins for recache */
        
require_once( IPS_ROOT_PATH 'sources/classes/skins/skinFunctions.php' );/*noLibHook*/
        
require_once( IPS_ROOT_PATH 'sources/classes/skins/skinCaching.php' );/*noLibHook*/
        
$skinCaching = new skinCaching$this->registry );
        
        
/* Flag all for recache */
        
$skinCaching->flagSetForRecache();
        
        
/* All Done */
        
$this->registry->output->global_message $this->lang->words['hook_reenable_all'];
        
$this->registry->output->silentRedirectWithMessage$this->settings['base_url'] . $this->form_code '&amp;do=hooks_overview' );
    }
    
    
/**
     * Disables a hook
     *
     * @return    @e void        [Outputs to screen]
     */
    
protected function _disableHook()
    {
        
/* INI */
        
$hook_id intval$this->request['id'] );
        
        if( !
$hook_id )
        {
            
$this->registry->output->showError$this->lang->words['h_noedit'], '1118.D' );
        }
        
        
$hookData $this->DB->buildAndFetch( array( 'select' => '*''from' => 'core_hooks''where' => 'hook_id=' $hook_id ) );
        
        if( !
$hookData['hook_id'] )
        {
            
$this->registry->output->showError$this->lang->words['h_noedit'], '1119.D' );
        }
        
        
/* Do update */
        
$this->DB->update'core_hooks', array( 'hook_enabled' => 0'hook_position' => ), "hook_id={$hookData['hook_id']});
        
        
/* Rebuild cache */
        
$this->rebuildHooksCache();
        
        
/* Rebuild global caches */
        
try
        {
            
IPSLib::cacheGlobalCaches();
        }
        catch( 
Exception $e ){}
        
        
/* Flag skins for recache */
        
require_once( IPS_ROOT_PATH 'sources/classes/skins/skinFunctions.php' );/*noLibHook*/
        
require_once( IPS_ROOT_PATH 'sources/classes/skins/skinCaching.php' );/*noLibHook*/
        
$skinCaching = new skinCaching$this->registry );
        
$skinCaching->flagSetForRecache();
        
        
/* Redirect */
        
$this->registry->output->setMessage$this->lang->words['h_hasbeendisabled'] );
        
$this->registry->output->silentRedirectWithMessage$this->settings['base_url'] . $this->form_code '&amp;do=hooks_overview' );
    }    
    
    
/**
     * Enables a hook
     *
     * @return    @e void        [Outputs to screen]
     */
    
protected function _enableHook()
    {
        
/* INI */
        
$hook_id intval($this->request['id']);
        
        if( !
$hook_id )
        {
            
$this->registry->output->showError$this->lang->words['h_noedit'], '1118.E' );
        }
        
        
$hookData $this->DB->buildAndFetch( array( 'select' => '*''from' => 'core_hooks''where' => 'hook_id=' $hook_id ) );
        
        if( !
$hookData['hook_id'] )
        {
            
$this->registry->output->showError$this->lang->words['h_noedit'], '1119.E' );
        }
        
        
/* Check for requirements */
        
if ( empty($this->request['skipRequirements']) )
        {
            
$errors $this->checkHookRequirements$hookData );
            
            if ( 
count($errors) )
            {
                
$this->registry->output->silentRedirectWithMessage$this->settings['base_url'] . $this->form_code '&amp;do=check_requirements&amp;fromInstall=1&amp;id='.$hook_id );
            }
        }
        
        
/* Do update */
        
$this->DB->update'core_hooks', array( 'hook_enabled' => ), "hook_id={$hookData['hook_id']});
        
        
/* Rebuild cache */
        
$this->rebuildHooksCache();
        
        
/* Rebuild global caches */
        
try
        {
            
IPSLib::cacheGlobalCaches();
        }
        catch( 
Exception $e ){}
        
        
/* Flag skins for recache */
        
require_once( IPS_ROOT_PATH 'sources/classes/skins/skinFunctions.php' );/*noLibHook*/
        
require_once( IPS_ROOT_PATH 'sources/classes/skins/skinCaching.php' );/*noLibHook*/
        
$skinCaching = new skinCaching$this->registry );
        
$skinCaching->flagSetForRecache();
        
        
/* Redirect */
        
$this->registry->output->global_message $this->lang->words['h_hasbeenenabled'];
        
$this->registry->output->silentRedirectWithMessage$this->settings['base_url'] . $this->form_code '&amp;do=hooks_overview' );
    }
    
    
/**
     * Uninstall a hook
     *
     * @return    @e void        [Outputs to screen]
     */
    
protected function _uninstallHook()
    {
        
/* Init vars */
        
$hook_id    intval$this->request['id'] );
        
        
$hook        $this->DB->buildAndFetch( array( 'select' => '*''from' => 'core_hooks''where' => 'hook_id=' $hook_id ) );
        
$extra_data    unserialize$hook['hook_extra_data'] );
        
        if ( ! 
$hook['hook_id'] )
        {
            
$this->registry->output->global_message $this->lang->words['h_hasbeenun'];
            
$this->registry->output->silentRedirectWithMessage$this->settings['base_url'] . $this->form_code '&amp;do=hooks_overview' );
        }
        
        
/* Got any custom file to initialize? */
        
$_customFile '';
        
$customClass null;
        
        if ( 
$extra_data['display']['custom'] )
        {
            
$_customFile IPS_HOOKS_PATH 'install_' $extra_data['display']['custom'];
            
            if( 
is_file$_customFile ) )
            {
                require_once( 
$_customFile );/*noLibHook*/
                
                
$classname str_replace'.php'''$extra_data['display']['custom'] );
                
                if( 
class_exists$classname ) )
                {
                    
$customClass = new $classname$this->registry );
                    
                    if( 
method_exists$customClass'pre_uninstall' ) )
                    {
                        
$customClass->pre_uninstall();
                    }
                }
            }
        }
        
        
/* Get associated files */
        
$this->DB->build( array( 'select' => 'hook_file_stored''from' => 'core_hooks_files''where' => 'hook_hook_id=' $hook_id ) );
        
$this->DB->execute();
        
        while( 
$r $this->DB->fetch() )
        {
            @
unlinkIPS_HOOKS_PATH $r['hook_file_stored'] );
        }
        
        
/* Delete hook file entries */
        
$this->DB->delete'core_hooks_files'"hook_hook_id={$hook_id});
        
        
//-----------------------------------------
        // Settings or setting groups?
        //-----------------------------------------
        
        
if( count($extra_data['settingGroups']) )
        {
            
$this->DB->delete'core_sys_settings_titles'"conf_title_keyword IN('" implode"','"$extra_data['settingGroups'] ) . "')" );
        }
        
        if( 
count($extra_data['settings']) )
        {
            
$this->DB->delete'core_sys_conf_settings'"conf_key IN('" implode"','"$extra_data['settings'] ) . "')" );
        }
        
        
$this->cache->rebuildCache'settings''global' );
        
        
//-----------------------------------------
        // Language strings/files
        //-----------------------------------------
        
        
if( count($extra_data['language']) )
        {
            foreach( 
$extra_data['language'] as $file => $bit )
            {
                
$this->DB->delete'core_sys_lang_words'"word_pack='{$file}' AND word_key IN('" implode"','"$bit ) . "')" );
            }
            
            
$langPacks    = array();
            
            
$this->DB->build( array( 'select' => 'lang_id''from' => 'core_sys_lang' ) );
            
$this->DB->execute();
            
            while( 
$r $this->DB->fetch() )
            {
                
$langPacks[] = $r['lang_id'];
            }
            
            
$classToLoad IPSLib::loadActionOverloaderIPSLib::getAppDir('core') . '/modules_admin/languages/manage_languages.php''admin_core_languages_manage_languages' );
            
$langLib     = new $classToLoad();
            
$langLib->makeRegistryShortcuts$this->registry );
            
            foreach( 
$langPacks as $langId )
            {
                
$langLib->cacheToDisk$langId );
            }
        }
        
        
//-----------------------------------------
        // Modules
        //-----------------------------------------
        
        
if( count($extra_data['modules']) )
        {
            foreach( 
$extra_data['modules'] as $module )
            {
                list( 
$_side$_app$_module ) = explode'-'$module );
                
$_is_admin = ( $_side == 'admin' ) ? 0;
                
                
$this->DB->delete'core_sys_module'"sys_module_application='{$_app}' AND sys_module_key='{$_module}' AND sys_module_admin={$_is_admin});
            }
            
            
$this->cache->rebuildCache'module_cache''global' );
            
$this->cache->rebuildCache'app_menu_cache''global' );
        }
        
        
//-----------------------------------------
        // Help files
        //-----------------------------------------
        
        
if( count($extra_data['help']) )
        {
            
$this->DB->delete'faq'"title IN('" implode"','"$extra_data['help'] ) . "')" );
        }
        
        
//-----------------------------------------
        // Skin templates
        //-----------------------------------------
        
        
if( count($extra_data['templates']) )
        {
            foreach( 
$extra_data['templates'] as $group => $bits )
            {
                
$this->DB->delete'skin_templates'"template_group='{$group}' AND template_name IN('" implode"','"$bits ) . "')" );
            }

            require_once( 
IPS_ROOT_PATH 'sources/classes/skins/skinFunctions.php' );/*noLibHook*/
            
require_once( IPS_ROOT_PATH 'sources/classes/skins/skinCaching.php' );/*noLibHook*/
            
$skinCaching = new skinCaching$this->registry );
            
$skinCaching->rebuildPHPTemplates);
        }
        
        
//-----------------------------------------
        // CSS
        //-----------------------------------------
        
        
if( count$extra_data['css'] ) )
        {
            
$this->DB->delete'skin_css'"css_group IN('" implode"','"$extra_data['css'] ) . "')" );
            
            if( ! 
$skinCaching )
            {
                require_once( 
IPS_ROOT_PATH 'sources/classes/skins/skinFunctions.php' );/*noLibHook*/
                
require_once( IPS_ROOT_PATH 'sources/classes/skins/skinCaching.php' );/*noLibHook*/
                
$skinCaching = new skinCaching$this->registry );
            }
            
            
$skinCaching->rebuildCSSCache);
        }
        
        
//-----------------------------------------
        // Tasks
        //-----------------------------------------
        
        
if( count($extra_data['tasks']) )
        {
            
$this->DB->delete'task_manager'"task_key IN('" implode"','"$extra_data['tasks'] ) . "')" );
        }
        
        
//-----------------------------------------
        // Database changes
        //-----------------------------------------
        
        
if( is_array($extra_data['database']['create']) AND count($extra_data['database']['create']) )
        {
            foreach( 
$extra_data['database']['create'] as $create_query )
            {
                
$this->DB->return_die    true;
                
$this->DB->dropTable$create_query['name'] );
                
$this->DB->return_die    false;
            }
        }
        
        if( 
is_array($extra_data['database']['alter']) AND count($extra_data['database']['alter']) )
        {
            foreach( 
$extra_data['database']['alter'] as $alter_query )
            {
                
$this->DB->return_die    true;
                
                if( 
$alter_query['altertype'] == 'add' )
                {
                    if( 
$this->DB->checkForField$alter_query['field'], $alter_query['table'] ) )
                    {
                        
$this->DB->dropField$alter_query['table'], $alter_query['field'] );
                    }
                }
                else if( 
$alter_query['altertype'] == 'change' )
                {
                    if( 
$this->DB->checkForField$alter_query['newfield'], $alter_query['table'] ) )
                    {
                        
$this->DB->changeField$alter_query['table'] , $alter_query['newfield'], $alter_query['field'], $alter_query['fieldtype'], $alter_query['default'] );
                    }
                }
                
                
$this->DB->return_die    false;
            }
        }
        
        if( 
is_array($extra_data['database']['update']) AND count($extra_data['database']['update']) )
        {
            foreach( 
$extra_data['database']['update'] as $update_query )
            {
                
$this->DB->return_die    true;
                
$this->DB->update$update_query['table'], array( $update_query['field'] => $update_query['oldvalue'] ), $update_query['where'] );
                
$this->DB->return_die    false;
            }
        }
        
        if( 
is_array($extra_data['database']['insert']) AND count($extra_data['database']['insert']) )
        {
            foreach( 
$extra_data['database']['insert'] as $insert_query )
            {
                if( 
$insert_query['fordelete'] )
                {
                    
$this->DB->return_die    true;
                    
$this->DB->delete$insert_query['table'], $insert_query['fordelete'] );
                    
$this->DB->return_die    false;
                }
            }
        }
        
        
//-----------------------------------------
        // Custom install/uninstall script?
        //-----------------------------------------
        
        
if ( $_customFile )
        {
            if( 
is_object($customClass) && method_exists$customClass'uninstall' ) )
            {
                
$customClass->uninstall();
            }
            
            @
unlink$_customFile );
        }
        
        
/* Delete main hook entry */
        
$this->DB->delete'core_hooks'"hook_id={$hook_id});
        
        
$this->rebuildHooksCache();
        
        
/* Done */
        
$this->registry->output->global_message $this->lang->words['h_hasbeenun'];
        
$this->registry->output->silentRedirectWithMessage$this->settings['base_url'] . $this->form_code '&amp;do=hooks_overview' );
    }    
    
    
/**
     * Hook add/edit form
     * This dynamic form allows users to associate multiple files with a single hook.
     *
     * @param    string        [add|edit]
     * @return    @e void        [Outputs to screen]
     */
    
protected function _hookForm$type='add' )
    {
        
/* Init vars */
        
$form            = array();
        
$files            = array();
        
$hookData        = array();
        
$requirements    = array();
        
$entryPoints    = array( 'foreach' => array( array( 'outer.pre'$this->lang->words['h_outerpre'] ),
                                                     array( 
'inner.pre'$this->lang->words['h_innerpre'] ),
                                                     array( 
'inner.post'$this->lang->words['h_innerpost'] ),
                                                     array( 
'outer.post'$this->lang->words['h_outerpost'] )
                                                    ),
                                 
'if' => array( array( 'pre.startif'$this->lang->words['h_prestartif'] ),
                                                array( 
'post.startif'$this->lang->words['h_poststartif'] ),
                                                array( 
'pre.else'$this->lang->words['h_preelse']),
                                                array( 
'post.else'$this->lang->words['h_postelse'] ),
                                                array( 
'pre.endif'$this->lang->words['h_preendif'] ),
                                                array( 
'post.endif'$this->lang->words['h_postendif'] )
                                                )
                                );
        
        
/* Edit time? */
        
if( $type == 'edit' )
        {
            
$id    intval($this->request['id']);
            
            if( !
$id )
            {
                
$this->registry->output->showError$this->lang->words['h_noedit'], 1116 );
            }
            
            
$hookData $this->DB->buildAndFetch( array( 'select' => '*''from' => 'core_hooks''where' => 'hook_id=' $id ) );
            
            if( !
$hookData['hook_id'] )
            {
                
$this->registry->output->showError$this->lang->words['h_noedit'], 1117 );
            }
            
            
/* Sort out extra stuff and requirements */
            
$hookData['hook_extra_data']    = unserialize$hookData['hook_extra_data'] );
            
$hookData['hook_requirements']    = unserialize$hookData['hook_requirements'] );
            
            
/* Old data? - @todo: we should remove that around 3.3(4?) */
            
if ( ! isset($hookData['hook_requirements']['required_applications']['core']) && isset($hookData['hook_requirements']['hook_ipb_version_min']) && ( $hookData['hook_requirements']['hook_ipb_version_min'] > || $hookData['hook_requirements']['hook_ipb_version_max'] > ) )
            {
                
$requirements['core'] = array( 'min_version' => intval($hookData['hook_requirements']['hook_ipb_version_min']), 'max_version' => intval($hookData['hook_requirements']['hook_ipb_version_max']) );
            }
            
            if ( 
is_array($hookData['hook_requirements']['required_applications']) && count($hookData['hook_requirements']['required_applications']) )
            {
                
/* Get the setup class */
                
require_once( IPS_ROOT_PATH 'setup/sources/base/setup.php' );/*noLibHook*/
                
                
foreach( $hookData['hook_requirements']['required_applications'] as $appKey => $versionData )
                {
                    
/* Fetch and check versions */
                    
if ( !isset($this->cachedVersions$appKey ]) )
                    {
                        
$this->cachedVersions$appKey ] = IPSSetUp::fetchXmlAppVersions$appKey );
                    }
                    
                    
$_versions $this->cachedVersions$appKey ];
                    
                    
krsort($_versions);
                    
                    
/* Setup our default 'no version' value */
                    
$versions = array( array( 0$this->lang->words['h_any_version'] ) );
                    
                    foreach( 
$_versions as $long => $human )
                    {
                        if ( 
$long 30000 && in_array$appKey, array( 'core''forums''members' ) ) )
                        {
                            continue;
                        }
                        
                        
$versions[] = array( $long$human );
                    }
                    
                    
$versionData['_versions'] = $versions;
                    
$requirements$appKey ]  = $versionData;
                }
            }
            
            
/* Sort out hook files */
            
$index        1;
            
$skinGroups $this->hooksFunctions->getSkinGroups();
            
            
$this->DB->build( array( 'select' => '*''from' => 'core_hooks_files''where' => 'hook_hook_id=' $id ) );
            
$outer $this->DB->execute();
            
            
/* Get them outside the while cycle to prevent warnings */
            
$_dataHooks IPSLib::getDataHookLocations();
            
            while( 
$r $this->DB->fetch($outer) )
            {
                
$r['hook_data']        = unserialize$r['hook_data'] );

                if( 
$r['hook_type'] == 'templateHooks' )
                {
                    
$templates    $this->hooksFunctions->getSkinMethods$r['hook_data']['skinGroup'] );
                    
$hookIds    $this->hooksFunctions->getHookIds$r['hook_data']['skinFunction'], $r['hook_data']['type'] );
                    
                    
$r['_skinDropdown']        = $this->registry->output->formDropdown"skinGroup[{$index}]"$skinGroups$r['hook_data']['skinGroup'], "skinGroup[{$index}]""onchange='getTemplatesForAdd({$index});'" );
                    
$r['_templateDropdown']    = $this->registry->output->formDropdown"skinFunction[{$index}]"$templates$r['hook_data']['skinFunction'], "skinFunction[{$index}]""onchange='getTypeOfHook({$index});'" );
                    
$r['_hookTypeDropdown']    = $this->registry->output->formDropdown"type[{$index}]", array( array( 0$this->lang->words['a_selectone'] ), array( 'foreach'$this->lang->words['hook_foreach_loop'] ), array( 'if'$this->lang->words['hook_if_statement'] ) ), $r['hook_data']['type'], "type[{$index}]""onchange='getHookIds({$index});'" );
                    
$r['_hookIdsDropdown']    = $this->registry->output->formDropdown"id[{$index}]"$hookIds$r['hook_data']['id'], "id[{$index}]""onchange='getHookEntryPoints({$index});'" );
                    
$r['_hookEPDropdown']    = $this->registry->output->formDropdown"position[{$index}]"$r['hook_data']['type'] == 'foreach' $entryPoints['foreach'] : $entryPoints['if'], $r['hook_data']['position'] );
                }
                
                if( 
$r['hook_type'] == 'dataHooks' )
                {
                    
$r['_dataLocationDropdown']    = $this->registry->output->formDropdown"dataLocation[{$index}]"$_dataHooks$r['hook_data']['dataLocation'] );
                }
                
                
$files$index ] = $r;
                
$index++;
            }
            
            
$action 'do_edit_hook';
        }
        else
        {
            
$action 'do_create_hook';
        }
        
        
/* Info */
        
foreach( array( 'hook_name''hook_desc''hook_key''hook_version_human''hook_version_long''hook_author''hook_email''hook_website''hook_update_check' ) as $_hook_key )
        {
            
$form$_hook_key ] = $this->registry->output->formSimpleInput$_hook_key , isset($this->request$_hook_key ]) ? $this->request$_hook_key ] : $hookData$_hook_key ], 60 );
        }
        
        
/* Requirements */
        
foreach( array( 'hook_php_version_min''hook_php_version_max' ) as $_version_key )
        {
            
$form$_version_key ] = $this->registry->output->formSimpleInput$_version_key , isset($this->request$_version_key ]) ? $this->request$_version_key ] : $hookData['hook_requirements'][ $_version_key ], 20 );
        }
        
        
/* Setup the global caches DD */
        
$_caches = array();
        
        
$this->DB->build( array( 'select' => 'cs_key',
                                 
'from'   => 'cache_store',
                                 
'order'  => 'cs_key ASC'
                         
)        );
        
$this->DB->execute();
        
        while( 
$gc $this->DB->fetch() )
        {
            
$_caches[] = array( $gc['cs_key'], $gc['cs_key'] );
        }
        
        
sort$_caches );
        
        
$form['hook_global_caches'] = $this->registry->output->formMultiDropdown'hook_global_caches[]'$_caches, isset($_POST['hook_global_caches']) ? $_POST['hook_global_caches'] : explode(',',$hookData['hook_global_caches']), 15 );
        
        
/* Get some data for the javascript */
        
$form['jsDataTypes']  = IPSText::br2nl$this->registry->output->formDropdown"type[#{index}]", array( array( 0$this->lang->words['a_selectone'] ), array( 'foreach'$this->lang->words['hook_foreach_loop'] ), array( 'if'$this->lang->words['hook_if_statement'] ) ), ''"type[#{index}]""onchange='getHookIds(#{index});'" ) );
        
$form['jsDataPoints'] = IPSText::br2nl$this->registry->output->formDropdown"position[#{index}]"$r['hook_data']['type'] == 'foreach' $entryPoints['foreach'] : $entryPoints['if'] ) );
        
        
/* Output */
        
$this->registry->output->html .= $this->html->hookForm$form$action$hookData$files$requirements );
    }

    
/**
     * Hook add/edit save
     * Save the new (or updated) hook record
     *
     * @param    string        [add|edit]
     * @return    @e void        [Outputs to screen]
     */
    
protected function _hookSave$type='add' )
    {
        
/* Init vars */
        
$hookData   = array();
        
$newFiles    = array();
        
$requireApp    = array();
        
$_hookFiles    = array();
        
$extraKey   '';
        
        
/* Get data if we are editing */
        
if( $type == 'edit' )
        {
            
$id    intval($this->request['hook_id']);
            
            if( !
$id )
            {
                
$this->registry->output->showError$this->lang->words['h_noedit'], 1118 );
            }
            
            
$hookData $this->DB->buildAndFetch( array( 'select' => '*''from' => 'core_hooks''where' => 'hook_id=' $id ) );
            
            if( !
$hookData['hook_id'] )
            {
                
$this->registry->output->showError$this->lang->words['h_noedit'], 1119 );
            }
            
            
$extraKey ' AND hook_id != ' $hookData['hook_id'];
        }
        
        
/* Error Checking */
        
if( ! $this->request['hook_name'] )
        {
            
$errors[] = $this->lang->words['hook_form_no_title'];
        }
        
        if( empty( 
$this->request['hook_key'] ) )
        {
            
$errors[] = $this->lang->words['hook_form_no_key'];
        }
        else
        {
            
$keyCheck $this->DB->buildAndFetch( array( 'select' => 'count(*) as found''from' => 'core_hooks''where' => "hook_key='" $this->DB->addSlashes$this->request['hook_key'] ) . "'" $extraKey ) );
            
            if ( 
$keyCheck['found'] > )
            {
                
$errors[] = $this->lang->words['hook_form_dupe_key'];
            }
        }
        
        
/* Got any errors? */
        
if ( is_array$errors ) && count$errors ) )
        {
            
$this->registry->output->global_error implode'<br />'$errors );
            
$this->_hookForm();
            return;
        }
        
        
/* Not IN_DEV? */
        
if ( ! IN_DEV )
        {
            
$this->DB->build( array( 'select' => '*''from' => 'core_hooks_files''where' => 'hook_hook_id=' intval($this->request['hook_id']) ) );
            
$this->DB->execute();
            
            while( 
$_r $this->DB->fetch() )
            {
                
$_hookFiles$_r['hook_classname'] ] = $_r['hook_file_stored'];
            }
        }
        
        
/* Check for requirements */
        
if ( is_array$this->request['requireApp'] ) AND count$this->request['requireApp'] ) )
        {
            foreach( 
$this->request['requireApp'] as $_index => $app_key )
            {
                if ( 
$app_key )
                {
                    
$minVersion intval($this->request['minVersion'][ $_index ]);
                    
$maxVersion intval($this->request['maxVersion'][ $_index ]);
                    
                    
$requireApp$app_key ] = array( 'app_name'        => ipsRegistry::$applications$app_key ]['app_title'],
                                                     
'min_version'    => $minVersion,
                                                     
'max_version'    => $maxVersion
                                                    
);
                }
            }
        }
        
        
/* Check for files */
        
if ( is_array$this->request['file'] ) AND count$this->request['file'] ) )
        {
            foreach( 
$this->request['file'] as $index => $file )
            {
                if ( 
$file )
                {
                    
$newFiles$index ]    = array('hook_file_real'    => $file,
                                                
'hook_type'            => $this->request['hook_type'][ $index ],
                                                
'hook_classname'    => $this->request['hook_classname'][ $index ],
                                                
'hook_data'            => serialize( array('dataLocation'        => trim$this->request['dataLocation'][ $index ] ),
                                                                                        
'libApplication'    => trim$this->request['libApplication'][ $index ] ),
                                                                                        
'classToOverload'    => trim($this->request['classToOverload'][ $index ]),
                                                                                        
'skinGroup'            => $this->request['skinGroup'][ $index ],
                                                                                        
'skinFunction'        => $this->request['skinFunction'][ $index ],
                                                                                        
'type'                => $this->request['type'][ $index ],
                                                                                        
'id'                => $this->request['id'][ $index ],
                                                                                        
'position'            => $this->request['position'][ $index ],
                                                                                        )
                                                                                 )
                                                );

                    
/**
                     * @link    http://community.invisionpower.com/tracker/issue-22084-hook-edit-does-not-preserve-correct-name/
                     * We don't want to reset the stored name if you are not in developer mode
                     */
                    
if ( IN_DEV )
                    {
                        
$newFiles$index ]['hook_file_stored']    = $file// During import this is a random name, but for devs it's actual file
                    
}
                    else
                    {
                        
$newFiles$index ]['hook_file_stored']    = $_hookFiles$this->request['hook_classname'][ $index ] ] ? $_hookFiles$this->request['hook_classname'][ $index ] ] : $file;
                    }
                }
            }
        }
        
        
/* Get position */
        
if ( $type == 'add' )
        {
            
$position $this->DB->buildAndFetch( array( 'select' => 'MAX(hook_position) as newPos''from' => 'core_hooks' ) );
            
            
$position['newPos'] = intval($position['newPos']) + 1;
        }
        else
        {
            
$position['newPos'] = $hookData['hook_position'];
        }

        
$mainHookRecord    = array('hook_name'                => trim($this->request['hook_name']),
                                
'hook_key'                => substrtrim($this->request['hook_key']), 032 ),
                                
'hook_global_caches'    => ( is_array($this->request['hook_global_caches']) && count($this->request['hook_global_caches']) ) ? implode(','$this->request['hook_global_caches']) : '',
                                
'hook_desc'                => trim($this->request['hook_desc']),
                                
'hook_version_human'    => trim($this->request['hook_version_human']),
                                
'hook_version_long'        => trim($this->request['hook_version_long']),
                                
'hook_author'            => trim($this->request['hook_author']),
                                
'hook_email'            => trim($this->request['hook_email']),
                                
'hook_website'            => trim($this->request['hook_website']),
                                
'hook_update_check'        => trim($this->request['hook_update_check']),
                                
'hook_enabled'            => $type == 'add' $hookData['hook_enabled'],
                                
'hook_installed'        => $type == 'add' IPS_UNIX_TIME_NOW $hookData['hook_installed'],
                                
'hook_updated'            => $type == 'add' IPS_UNIX_TIME_NOW,
                                
'hook_position'            => $position['newPos'],
                                
'hook_requirements'        => serialize( array('required_applications'    => $requireApp,
                                                                            
'hook_php_version_min'    => trim($this->request['hook_php_version_min']),
                                                                            
'hook_php_version_max'    => trim($this->request['hook_php_version_max'])
                                                                            )
                                                                     )
                                );
        
        if( 
$type == 'edit' )
        {
            
$this->DB->update'core_hooks'$mainHookRecord'hook_id=' $hookData['hook_id'] );
            
            
$this->DB->delete'core_hooks_files''hook_hook_id=' $hookData['hook_id'] );
        }
        else
        {
            
$this->DB->insert'core_hooks'$mainHookRecord );
            
            
$hookData['hook_id'] = $this->DB->getInsertId();
        }
        
        foreach( 
$newFiles as $index => $toInsert )
        {
            
$toInsert['hook_hook_id'] = $hookData['hook_id'];
            
            
$this->DB->insert'core_hooks_files'$toInsert );
        }
        
        
/* Rebuild cache */
        
$this->rebuildHooksCache();
        
        
/* Rebuild global caches */
        
try
        {
            
IPSLib::cacheGlobalCaches();
        }
        catch( 
Exception $e ){}
        
        
/* Flag skins for recache */
        
require_once( IPS_ROOT_PATH 'sources/classes/skins/skinFunctions.php' );/*noLibHook*/
        
require_once( IPS_ROOT_PATH 'sources/classes/skins/skinCaching.php' );/*noLibHook*/
        
$skinCaching = new skinCaching$this->registry );
        
$skinCaching->flagSetForRecache();
        
        
/* Redirect */
        
$this->registry->output->setMessage$this->lang->words['h_saved'] );
        
$this->registry->output->silentRedirectWithMessage$this->settings['base_url'] . $this->form_code '&amp;do=hooks_overview' );
    }
    
    
/**
     * View details about a hook
     *
     * @return    @e void        [Outputs to screen]
     */
    
protected function _viewDetails()
    {
        
$id    intval($this->request['id']);
        
        if( !
$id )
        {
            
$this->registry->output->showError$this->lang->words['h_nodetails'], 11110 );
        }
        
        
$hookData $this->DB->buildAndFetch( array( 'select' => '*''from' => 'core_hooks''where' => 'hook_id=' $id ) );
        
        if( !
$hookData['hook_id'] )
        {
            
$this->registry->output->showError$this->lang->words['h_nodetails'], 11111 );
        }
        
        
/* Extra data */
        
$hookData['_updated']         = $this->registry->getClass('class_localization')->formatTime$hookData['hook_updated'] );
        
$hookData['hook_extra_data'] = unserialize$hookData['hook_extra_data'] );
        
        
/* Meets requirements? */
        
$hookData['_require_errors'] = $this->checkHookRequirements$hookData );
        
        
/* Got updates? */
        
if ( $hookData['hook_update_check'] )
        {
            
$hookData['hook_update_available']    = $this->_updateAvailable$hookData['hook_update_check'], $hookData['hook_version_long'] );
        }
        else
        {
            
$hookData['hook_update_available']    = array( );
        }
        
        
/* Get files */
        
$files = array();
        
$index 1;
        
        
$this->DB->build( array( 'select' => '*''from' => 'core_hooks_files''where' => 'hook_hook_id=' $id ) );
        
$this->DB->execute();
        
        while( 
$r $this->DB->fetch() )
        {
            
$r['hook_data']  = unserialize$r['hook_data'] );
            
$files$index ] = $r;
            
$index++;
        }

        
/* Output */
        
$this->registry->output->html .= $this->html->hookDetails$hookData$files );
    }
    
    
/**
     * Check if the hook meets all the requirements
     * 
     * @param    mixed    $hook    Can be an hook ID or an array of the hook data
     * @return    @e array Errors found
     */
    
public function checkHookRequirements$hook )
    {
        
/* Init vars */
        
$hookData = array();
        
$reqsData = array();
        
$errors   = array();
        
        
/* We already have some data? */
        
if ( is_array($hook) && count($hook) )
        {
            
$hookData $hook;
        }
        elseif ( 
is_int($hook) )
        {
            
$hookData $this->DB->buildAndFetch( array( 'select' => '*''from' => 'core_hooks''where' => 'hook_id=' $hook ) );
        }
            
        
/* Requirements are still serialized? */
        
if ( IPSLib::isSerialized($hookData['hook_requirements']) )
        {
            
$hookData['hook_requirements'] = unserialize($hookData['hook_requirements']);
        }
        
        
/* Make our var shorter... */
        
$reqsData = &$hookData['hook_requirements'];
        
        
/* Old data? - @todo: remove this check around 3.3(4?) */
        
if ( ! isset($reqsData['required_applications']['core']) && isset($reqsData['hook_ipb_version_min']) && ( $reqsData['hook_ipb_version_min'] > || $reqsData['hook_ipb_version_max'] > ) )
        {
            
$reqsData['hook_ipb_version_min'] = ( $reqsData['hook_ipb_version_min'] < 30000 ) ? 30000 $reqsData['hook_ipb_version_min'];
            
            
$reqsData['required_applications']['core'] = array( 'min_version' => intval($reqsData['hook_ipb_version_min']), 'max_version' => intval($reqsData['hook_ipb_version_max']) );
        }
        
        
//-----------------------------------------
        // Let's start checking requirements
        //-----------------------------------------
        
        /* PHP */
        
if( $reqsData['hook_php_version_min'] OR $reqsData['hook_php_version_max'] )
        {
            if( 
$reqsData['hook_php_version_min'] AND version_comparePHP_VERSION$reqsData['hook_php_version_min'], '<' ) == true )
            {
                
$errors['php_min'] = sprintf$this->lang->words['h_phpold'],$reqsData['hook_php_version_min'] );
            }
            
            if( 
$reqsData['hook_php_version_max'] AND version_comparePHP_VERSION$reqsData['hook_php_version_max'], '>' ) == true )
            {
                
$errors['php_max'] = sprintf$this->lang->words['h_phpnew'], $reqsData['hook_php_version_max'] );
            }
        }
        
        
/* Additional applications */
        
if ( is_array($reqsData['required_applications']) && count($reqsData['required_applications']) )
        {
            
/* Get the setup class */
            
require_once( IPS_ROOT_PATH 'setup/sources/base/setup.php' );/*noLibHook*/
            
            /* Loop through all apps */
            
foreach( $reqsData['required_applications'] as $appKey => $appData )
            {
                
/* Versions file doesn't exist? */
                
if ( !is_fileIPSLib::getAppDir$appKey ) . '/xml/versions.xml' ) )
                {
                    
$errors$appKey.'_app' ] = sprintf$this->lang->words['hook_require_appnotfound'], $appData['app_name'] );
                }
                
/* App not installed/enabled? */
                
elseif ( !IPSLib::appIsInstalled$appKey ) )
                {
                    
$errors$appKey.'_app' ] = sprintf$this->lang->words['hook_require_appdisabled'], ipsRegistry::$applications$appKey ]['app_title'] );
                }
                elseif ( 
$appData['min_version'] OR $appData['max_version'] )
                {
                    
/* Fetch and check versions */
                    
if ( !isset($this->cachedVersions$appKey ]) )
                    {
                        
$this->cachedVersions$appKey ] = IPSSetUp::fetchXmlAppVersions$appKey );
                    }
                    
                    
$versions $this->cachedVersions$appKey ];
                    
                    if ( 
is_array($versions) && count($versions) )
                    {
                        if ( !isset(
$this->cachedUpgradeInfo$appKey ]) )
                        {
                            
$_key    in_array$appKey, array( 'forums''members' ) ) ? 'core' $appKey;
                            
$this->cachedUpgradeInfo$_key ]    = $this->DB->buildAndFetch( array( 'select' => '*''from' => 'upgrade_history''where' => "upgrade_app='{$_key}'"'order' => 'upgrade_version_id DESC''limit' => array( ) ) );
                            
                            
/* Extra caching for the three core apps */
                            
if( in_array$appKey, array( 'core''forums''members' ) ) )
                            {
                                
$this->cachedUpgradeInfo['core']    = $this->cachedUpgradeInfo$_key ];
                                
$this->cachedUpgradeInfo['forums']    = $this->cachedUpgradeInfo$_key ];
                                
$this->cachedUpgradeInfo['members']    = $this->cachedUpgradeInfo$_key ];
                            }
                        }
                        
                        
/* Do we meet tha requirements? */
                        
if ( $appData['min_version'] AND $this->cachedUpgradeInfo$appKey ]['upgrade_version_id'] < $appData['min_version'] )
                        {
                            
$errors$appKey.'_min' ] = sprintf$this->lang->words['hook_require_tooold'], isset($versions$appData['min_version'] ]) ? $versions$appData['min_version'] ] : $appData['min_version'] );
                        }
                        
                        if ( 
$appData['max_version'] AND $this->cachedUpgradeInfo$appKey ]['upgrade_version_id'] > $appData['max_version'] )
                        {
                            
$errors$appKey.'_max' ] = sprintf$this->lang->words['hook_require_toonew'], isset($versions$appData['max_version'] ]) ? $versions$appData['max_version'] ] : $appData['max_version'] );
                        }
                    }
                }
            }
        }
        
        return 
$errors;
    }
    
    
/**
     * Check if you meet hook requirements
     *
     * @return    @e void        [Outputs to screen]
     */
    
protected function _checkRequirements()
    {
        
$id    intval($this->request['id']);
        
        if( !
$id )
        {
            
$this->registry->output->showError$this->lang->words['h_norequirements'], 11112 );
        }
        
        
$hookData $this->DB->buildAndFetch( array( 'select' => '*''from' => 'core_hooks''where' => 'hook_id=' $id ) );
        
        if( !
$hookData['hook_id'] )
        {
            
$this->registry->output->showError$this->lang->words['h_norequirements'], 11113 );
        }
        
        
/* Get requirements */
        
$hookData['hook_requirements'] = unserialize($hookData['hook_requirements']);
        
        
/* Check requirements */
        
$errors $this->checkHookRequirements$hookData );
        
        
/* Output */
        
$this->registry->output->html .= $this->html->hookRequirements$hookData$errors$this->cachedVersions );
    }
    
    
/**
     * Rebuild hooks cache
     *
     * @return    @e void
     */
    
public function rebuildHooksCache()
    {
        
/* INI */
        
$cache = array( 'commandHooks' => array(), 'skinHooks' => array(), 'templateHooks' => array(), 'dataHooks' => array(), 'libraryHooks' => array() );

        
/* First fix positions */
        
$this->_fixPositions();

        
/* Get current hooks */
        
$this->DB->build( array( 'select'    => 'f.*'
                                 
'from'        => array( 'core_hooks_files' => 'f' ), 
                                 
'where'    => 'c.hook_enabled=1',
                                 
'order'    => 'c.hook_position ASC',
                                 
'add_join'    => array( array( 'select' => 'c.hook_id',
                                                             
'from'   => array( 'core_hooks' => 'c' ),
                                                             
'where'  => 'c.hook_id=f.hook_hook_id',
                                                             
'type'   => 'left' ) )
                            )        );
        
$this->DB->execute();
        
        while( 
$r $this->DB->fetch() )
        {
            
/* Got no main hook id? Weird but skip.. */
            
if ( empty($r['hook_id']) )
            {
                continue;
            }
            
            
/* INIT */
            
$_cache    = array();
            
$data    unserialize$r['hook_data'] );
            
            
/* General Stuff */
            
$_cache    = array( 'filename'  => $r['hook_file_stored'],
                             
'className' => $r['hook_classname']
                            );
            
            
/* Hook type specific stuff */
            
if( $r['hook_type'] == 'templateHooks' )
            {
                
$_cache['type']                = $data['type'];
                
$_cache['skinFunction']        = $data['skinFunction'];
                
$_cache['id']                = $data['id'];
                
$_cache['position']            = $data['position'];
            }
            else if( 
/*$r['hook_type'] == 'dataHooks' OR*/ $r['hook_type'] == 'libraryHooks' )
            {
                
$_cache['classToOverload']    = $data['classToOverload'];
            }
            
            
/* Add to array */
            
if( $r['hook_type'] == 'templateHooks' )
            {
                
$cache$r['hook_type'] ][ $data['skinGroup'] ][] = $_cache;
            }
            else if( 
$r['hook_type'] == 'dataHooks' )
            {
                
$cache$r['hook_type'] ][ $data['dataLocation'] ][] = $_cache;
            }
            else if( 
$r['hook_type'] == 'libraryHooks' )
            {
                
$cache$r['hook_type'] ][ $data['libApplication'] ][ $data['classToOverload'] ][] = $_cache;
            }
            else
            {
                
$cache$r['hook_type'] ][ $data['classToOverload'] ][] = $_cache;
            }
        }
        
        
/* Update the cache */
        
$this->cache->setCache'hooks'$cache, array( 'array' => ) );
    }
}
Онлайн: 0
Реклама