Вход Регистрация
Файл: admin/sources/classes/skins/skinCaching.php
Строк: 1625
<?php

/**
 * <pre>
 * Invision Power Services
 * IP.Board v3.3.3
 * Skin Caching Functions
 * Last Updated: $Date: 2012-05-10 16:10:13 -0400 (Thu, 10 May 2012) $
 * </pre>
 *
 * Owner: Matt
 * @author         $Author: bfarber $
 * @copyright    (c) 2001 - 2009 Invision Power Services, Inc.
 * @license        http://www.invisionpower.com/company/standards.php#license
 * @package        IP.Board
 * @link        http://www.invisionpower.com
 * @since        9th July 2008
 * @version        $Revision: 10721 $
 *
 */

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

/**
* Ensure that class functions is loaded
*/
if ( ! class_exists( 'skinFunctions' ) )
{
    require_once( 
dirname( __FILE__ ) . '/skinFunctions.php' );/*noLibHook*/
}

class 
skinCaching extends skinFunctions
{
    
/**#@+
     * Registry objects
     *
     * @access    protected
     * @var        object
     */    
    
protected $registry;
    protected 
$DB;
    protected 
$settings;
    protected 
$request;
    protected 
$lang;
    protected 
$member;
    protected 
$memberData;
    protected 
$cache;
    protected 
$caches;
    
/**#@-*/

    /**
     * Array of CSS needing to be rebuilt
     *
     * @access    protected
     * @var        array
     */    
    
protected $_cssNeedToRebuildArray = array();
    
    
/**
     * Ignore children when recaching ...
     * @var boolean
     */
    
protected $_ignoreChildrenWhenRecaching = false;
    
    
/**
     * Recache skin sets on shutdown
     * @var    bool
     */
     
protected $_recacheSkinsCache    = false;
     
     
/**
      * Remember which skins we've already flagged for recache
      * @var    array
      */
     
protected $_flaggedForRecache    = array();
    
    
/**
     * Constructor
     *
     * @access    public
     * @param    object        Registry object
     * @return    @e void
     */
    
public function __construct( ipsRegistry $registry )
    {
        
/* Make object */
        
parent::__construct( $registry );
    }
    
    
/**
     * Set ignore children when recaching
     * @param boolean $val
     */
    
public function setIgnoreChildrenWhenRecaching( $val )
    {
        
$this->_ignoreChildrenWhenRecaching = ( ! empty( $val ) ) ? true : false;
    }
    
    
/**
     * Get ignore children when recaching
     * @return boolean
     */
    
public function getIgnoreChildrenWhenRecaching()
    {
        return 
$this->_ignoreChildrenWhenRecaching;
    }
    
    
/**
     * Rebuild Replacements cache
     *
     * @access    public
     * @param    int        Skin set id to rebuild
     * @return    boolean
     */
    
public function rebuildReplacementsCache( $setID )
    {
        
//-----------------------------------------
        // INIT
        //-----------------------------------------
    
        
$skinSetData = $this->fetchSkinData( $setID );
        
        
$this->_resetErrorHandle();
        
$this->_resetMessageHandle();
        
        
//-----------------------------------------
        // Push the current skin set ID onto the beginnging
        //-----------------------------------------

        
if ( is_numeric( $setID ) )
        {
            
array_unshift( $skinSetData['_childTree'], $setID );
        }
        else
        {
            
array_unshift( $skinSetData['_childTree'], 0 );
        }
        
        
//-----------------------------------------
        // Remove current caches
        //-----------------------------------------
        
        
$this->DB->delete( 'skin_cache', 'cache_type='replacements' AND cache_set_id IN (' . implode( ",", $skinSetData['_childTree'] ) . ')' );
        
        
//-----------------------------------------
        // Loop through and rebuild
        //-----------------------------------------
        
        
foreach( $skinSetData['_childTree'] as $_setID )
        {
            
/* Bit of a fiddle here... */
            
if ( ! is_numeric( $setID ) AND $_setID == 0 )
            {
                
/* We mean a master set, then */
                
$_setID = $setID;
            }
            
            
/* If this is a child skin, just flag for recache */
            
if ( $_setID != $setID )
            {
                if ( 
$this->getIgnoreChildrenWhenRecaching() === false )
                {
                    
$this->flagSetForRecache( $_setID, true );
                }
                
                continue;
            }
            
            
$__replacements = $this->fetchReplacements( $_setID );
            
$_replacements  = array();
            
            
/* Strip out unneeded stuff */
            
foreach( $__replacements as $id => $data )
            {
                
$_replacements[ $data['replacement_key'] ] = $data['replacement_content'];
            }
            
            
/* Update skin cache */
            
$this->DB->insert( 'skin_cache', array( 'cache_updated' => time(),
                                                    
'cache_set_id'  => $_setID,
                                                     
'cache_type'    => 'replacements',
                                                    
'cache_content' => serialize( $_replacements ) ) );

            
$this->cache->putWithCacheLib( 'Skin_Store_' . $_setID, array(), 1 );
        }
        
        return 
TRUE;
    }
    
    
/**
     * Rebuild PHP Templates
     *
     * @access    public
     * @param    int            Skin set ID
     * @param    string        [Optional: Rebuild only selected skin group template file]
     * @return    array         Messages
     */
    
public function rebuildPHPTemplates( $setID, $groupOnly='' )
    {
        
//-----------------------------------------
        // INIT
        //-----------------------------------------
    
        
$skinSetData = $this->fetchSkinData( $setID );
        
        
$skinSetData['set_image_dir'] = ( $skinSetData['set_image_dir'] ) ? $skinSetData['set_image_dir'] : 'master';
        
        
/* These are not always set up correctly */
        
$this->settings['img_url']            = ( $this->settings['img_url'] )        ? $this->settings['img_url'] : $this->settings['_original_base_url'] . '/' . PUBLIC_DIRECTORY . '/style_images/' . $skinSetData['set_image_dir'];
        
$this->settings['img_url_no_dir']    = ( $this->settings['img_url_no_dir'] ) ? $this->settings['img_url_no_dir'] : $this->settings['_original_base_url'] . '/' . PUBLIC_DIRECTORY . '/style_images/';

        
/* Remove dead template caches */
        
$this->removeDeadPHPCaches( $setID );
        
        
$this->_resetErrorHandle();
        
$this->_resetMessageHandle();
        
        
//-----------------------------------------
        // Push the current skin set ID onto the beginnging
        //-----------------------------------------
    
        
array_unshift( $skinSetData['_childTree'], $setID );

        
//-----------------------------------------
        // Loop through and rebuild
        //-----------------------------------------
    
        
foreach( $skinSetData['_childTree'] as $_setID )
        {
            
/* If this is a child skin, just flag for recache */
            
if ( $_setID != $setID )
            {
                if ( 
$this->getIgnoreChildrenWhenRecaching() === false )
                {
                    
$this->flagSetForRecache( $_setID, true );
                }
                
                continue;
            }
            
            
//-----------------------------------------
            // Get template set titles
            //-----------------------------------------
            
            
$groupTitles = $this->fetchTemplates( $_setID, 'groupNames' );
            
$allHooks    = $this->fetchSkinHooks();
            
            
/* Update DB row */
            
$this->DB->update( 'skin_collections', array( 'set_updated' => time() ), 'set_id=' . intval( $_setID ) );
                
            foreach ( 
$groupTitles as $name => $group )
            {
                
/* Separated $out into two variables, needed to build the sections independently to fix bug #21574 */
                
$fileHead    = '';
                
$fileBody    = '';
                
                
//-----------------------------------------
                // Skip if we're only updating one group..
                //-----------------------------------------
                
                
if ( $groupOnly != '' )
                {
                    if ( 
$groupOnly != $group['template_group'] )
                    {
                        continue;
                    }
                }
                
                
$fileHead  = "class {$group['template_group']}_{$_setID} extends skinMaster{nn";
                
$fileHead .= <<<EOF
/**
* Construct
*/
function __construct( ipsRegistry 
$registry )
{
    parent::__construct( 
$registry );
    
EOF;
                
                
$templates = $this->fetchTemplates( $_setID, 'groupTemplates', $group['template_group'] );

                foreach (
$templates as $func_name => $data )
                {
                    
$this->registry->templateEngine->setWorkingGroup( $group['template_group'] );
                    
                    
$fileBody .= $this->registry->templateEngine->convertHtmlToPhp( $data['template_name'], $data['template_data'], $data['template_content'] ) ."n";
                }
                
                
//-----------------------------------------
                // Function Hooks
                //------------------------------------------
                
$funcHooks = '$this->_funcHooks = array();' . "n";
        
                if( 
is_array( $this->registry->templateEngine->_hookIds[ $group['template_group'] ] ) )
                {
                    foreach( 
$this->registry->templateEngine->_hookIds[ $group['template_group'] ] as $func_name => $hookIds )
                    {
                        if( 
is_array( $hookIds ) && count( $hookIds ) )
                        {
                            
$funcHooks .= "$this->_funcHooks['{$func_name}'] = array(".implode( ',', $hookIds ).");n";
                        }
                    }
                }
                
                
$fileHead    .= "nn{$funcHooks}nn}nn";
                
$out         = $fileHead . $fileBody . "n}n";

                
/* This would be better off within the templateEngine really cos $out now contains the entire class */
                
$out = $this->stripUnneededHooks( $out, $allHooks[ $group['template_group'] ] );
                
                
//-----------------------------------------
                // Update DB Cache
                //-----------------------------------------
                
                
$this->DB->delete( 'skin_cache', 'cache_set_id=' . $_setID . " AND cache_type='phptemplate' AND cache_value_1='" . $group['template_group'] . "'" );
                
                
$this->DB->insert( 'skin_cache', array( 'cache_updated' => time(),
                                                           
'cache_type'    => 'phptemplate',
                                                           
'cache_set_id'  => $_setID,
                                                           
'cache_key_1'   => 'group',
                                                           
'cache_value_1' => $group['template_group'],
                                                           
'cache_content' => $out ) );
                                                           
                
                
//-----------------------------------------
                // Write to the flatfile
                //-----------------------------------------
                
                
$start  = '<'.'?'."phpn";
                
$start .= "/*--------------------------------------------------*/n";
                
$start .= "/* FILE GENERATED BY INVISION POWER BOARD 3         */n";
                
$start .= "/* CACHE FILE: Skin set id: {$_setID}               */n";
                
$start .= "/* CACHE FILE: Generated: ".gmdate( 'D, d M Y H:i:s GMT' )." */n";
                
$start .= "/* DO NOT EDIT DIRECTLY - THE CHANGES WILL NOT BE   */n";
                
$start .= "/* WRITTEN TO THE DATABASE AUTOMATICALLY            */n";
                
$start .= "/*--------------------------------------------------*/nn";
                
                
$end    = "nn/*--------------------------------------------------*/n";
                
$end   .= "/* END OF FILE                                      */n";
                
$end   .= "/*--------------------------------------------------*/n";
                
$end   .= "n?".">";
                
                if ( 
$this->fetchErrorMessages() === FALSE )
                {
                    
$this->_writePHPTemplate( $_setID, $group['template_group'], $start.$out.$end );
                }
                
                
$this->cache->putWithCacheLib( 'Skin_Store_' . $_setID, array(), 1 );
            }
            
            
$this->_addMessage( sprintf( $this->lang->words['finishedcachinghtml'], $_setID ) );
        }
        
        
/* Rebuild skin cache */
        
$this->rebuildSkinSetsCache();
        
        return 
TRUE;
    }
    
    
/**
     * Removes dead PHP cache files
     *
     * @access    public
     * @param    int        Set ID
     * @return    int        No. files unlinked
     */
    
public function removeDeadPHPCaches( $setID )
    {
        
//-----------------------------------------
        // INIT
        //-----------------------------------------
        
        
$phpKeep   = array();
        
$phpThrow  = array();
        
$phpUnlink = array();

        
//-----------------------------------------
        // Get skin set data
        //-----------------------------------------
        
        
$skinSetData = $this->fetchSkinData( $setID );
        
        
$tree = array_merge( $skinSetData['_parentTree'], $skinSetData['_childTree'] );
        
        
array_unshift( $tree, $setID );
        
        
//-----------------------------------------
        // Get PHP
        //-----------------------------------------
        
        
$this->DB->build( array( 'select' => '*',
                                       
'from'   => 'skin_collections',
                                       
'where'  => 'set_id IN (' . implode( ",", $tree ) . ")" ) );
                                    
        
$i = $this->DB->execute();
        
        while( 
$row = $this->DB->fetch( $i ) )
        {
            
$_php = $this->fetchTemplates( $row['set_id'], 'groupNames' );

            foreach( 
$_php as $name => $php )
            {
                
$phpKeep[ $row['set_id'] ][ $name ] = $name;
            }
        }
        
        
//-----------------------------------------
        // Get cached PHP
        //-----------------------------------------
        
        
$this->DB->build( array( 'select' => '*',
                                       
'from'   => 'skin_cache',
                                       
'where'  => "cache_type='phptemplate' AND cache_set_id IN (" . implode( ",", $tree ) . ")" ) );
                                    
        
$this->DB->execute();
        
        while( 
$row = $this->DB->fetch() )
        {
            if ( ( 
is_array( $phpKeep[ $row['cache_set_id'] ] ) ) AND ( ! in_array( $row['cache_value_1'], $phpKeep[ $row['cache_set_id'] ] ) ) )
            {
                
$phpThrow[] = $row['cache_id'];
            }
        }
        
        
//-----------------------------------------
        // Delete...
        //-----------------------------------------
        
        
if ( count( $phpThrow ) )
        {
            
$this->DB->delete( 'skin_cache', 'cache_id IN (' . implode( ",", $phpThrow ) . ')' );
        }
        
        
//-----------------------------------------
        // Check flat files...
        //-----------------------------------------
        
        
foreach( $phpKeep as $_setID => $data )
        {
            if ( ( 
$_setID != $setID ) && $this->getIgnoreChildrenWhenRecaching() === true )
            {
                continue;
            }
                
            
$_path = IPS_CACHE_PATH . 'cache/skin_cache/cacheid_' . $_setID;
            
            if ( 
is_dir( $_path ) )
            {
                try
                {
                    foreach( new 
DirectoryIterator( $_path ) as $file )
                    {
                        if ( ! 
$file->isDot() AND ! $file->isDir() )
                        {
                            
$_name = $file->getFileName();
                    
                            if ( 
substr( $_name, -4 ) == '.php' )
                            {
                                
$phpName = substr( $_name, 0, -4 );
                            
                                if ( ( 
is_array( $phpKeep[ $_setID ] ) ) AND ! in_array( $phpName, $phpKeep[ $_setID ] ) )
                                {
                                    
$phpUnlink[] = $_path . '/' . $_name;
                                }
                            }
                        }
                    }
                } catch ( 
Exception $e ) {}
            }
        }
        
        
//-----------------------------------------
        // Unlink...
        //-----------------------------------------
        
        
if ( count( $phpUnlink ) )
        {
            foreach( 
$phpUnlink as $path )
            {
                @
unlink( $path );
            }
        }
        
        return 
count( $phpUnlink );
    }
    
    
/**
     * Removes dead CSS cache files
     *
     * @access    public
     * @param    int        Set ID
     * @return    int        No. files unlinked
     */
    
public function removeDeadCSSCaches( $setID )
    {
        
//-----------------------------------------
        // INIT
        //-----------------------------------------
        
        
$cssKeep   = array();
        
$cssThrow  = array();
        
$cssUnlink = array();
        
        
//-----------------------------------------
        // Get skin set data
        //-----------------------------------------
        
        
$skinSetData = $this->fetchSkinData( $setID );
        
        
$tree = array_merge( $skinSetData['_parentTree'], $skinSetData['_childTree'] );
        
        
array_unshift( $tree, $setID );
        
        
//-----------------------------------------
        // Get CSS
        //-----------------------------------------
        
        
$this->DB->build( array( 'select' => '*',
                                       
'from'   => 'skin_collections',
                                       
'where'  => 'set_id IN (' . implode( ",", $tree ) . ")" ) );
                                    
        
$i = $this->DB->execute();
        
        while( 
$row = $this->DB->fetch( $i ) )
        {
            
$_css = $this->fetchCSS( $row['set_id'] );

            foreach( 
$_css as $name => $css )
            {
                
$cssKeep[ $row['set_id'] ][ $css['css_group'] ] = $css['css_group'];
            }
        }
        
        
//-----------------------------------------
        // Get cached CSS
        //-----------------------------------------
        
        
$this->DB->build( array( 'select' => '*',
                                       
'from'   => 'skin_cache',
                                       
'where'  => "cache_type='css' AND cache_set_id IN (" . implode( ",", $tree ) . ")" ) );
                                    
        
$this->DB->execute();
        
        while( 
$row = $this->DB->fetch() )
        {
            if ( ( 
is_array( $cssKeep[ $row['cache_set_id'] ] ) ) AND ( ! in_array( $row['cache_value_1'], $cssKeep[ $row['cache_set_id'] ] ) ) )
            {
                
$cssThrow[] = $row['cache_id'];
            }
        }
        
        
//-----------------------------------------
        // Delete...
        //-----------------------------------------
        
        
if ( count( $cssThrow ) )
        {
            
$this->DB->delete( 'skin_cache', 'cache_id IN (' . implode( ",", $cssThrow ) . ')' );
        }
        
        
//-----------------------------------------
        // Check flat files...
        //-----------------------------------------
        
        
foreach( $cssKeep as $_setID => $data )
        {
            if ( ( 
$_setID != $setID ) && $this->getIgnoreChildrenWhenRecaching() === true )
            {
                continue;
            }
            
            
$_path = DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_css/css_' . $_setID;
            
            if ( 
is_dir( $_path ) )
            {
                try
                {
                    foreach( new 
DirectoryIterator( $_path ) as $file )
                    {
                        if ( ! 
$file->isDot() AND ! $file->isDir() )
                        {
                            
$_name = $file->getFileName();
                    
                            if ( 
substr( $_name, -4 ) == '.css' )
                            {
                                
$cssName = substr( $_name, 0, -4 );
                            
                                if ( ( 
is_array( $cssKeep[ $_setID ] ) ) AND ! in_array( $cssName, $cssKeep[ $_setID ] ) )
                                {
                                    
$cssUnlink[] = $_path . '/' . $_name;
                                }
                            }
                        }
                    }
                } catch ( 
Exception $e ) {}
            }
            
            
$this->cache->putWithCacheLib( 'Skin_Store_' . $_setID, array(), 1 );
        }
        
        
//-----------------------------------------
        // Unlink...
        //-----------------------------------------
        
        
if ( count( $cssUnlink ) )
        {
            foreach( 
$cssUnlink as $path )
            {
                @
unlink( $path );
            }
        }
        
        return 
count( $cssUnlink );
    }
    
    
    
/**
     * Rebuild CSS cache, skin set cache and writes out any flat files
     *
     * @access    public
     * @param    int        [Optional Skin set id to rebuild. If no value given, all skin sets are rebuilt]
     * @param    boolean    Force rebuild regardless of if it requires it
     * @return    @e void
     */
    
public function rebuildCSS( $setID, $forceRebuild=FALSE )
    {
        
//-----------------------------------------
        // Rebuild CSS cache
        //-----------------------------------------
        
        
$this->rebuildCSSCache( $setID, $forceRebuild );
        
        
//-----------------------------------------
        // Rewrite CSS files
        //-----------------------------------------
        
        
$this->rebuildCSSFlatFiles( $setID, $forceRebuild );
    }
    
    
/**
     * Rebuild CSS flat files
     *
     * @access    public
     * @param    int        [Optional Skin set id to rebuild. If no value given, all skin sets are rebuilt]
     * @param    boolean    Force rebuild regardless of if it requires it
     * @return    boolean
     */
    
public function rebuildCSSFlatFiles( $setID, $forceRebuild=FALSE )
    {
        
$skinSetData = $this->fetchSkinData( $setID );
        
        
$this->_resetErrorHandle();
        
$this->_resetMessageHandle();
        
        
//-----------------------------------------
        // Push the current skin set ID onto the beginnging
        //-----------------------------------------
        
        
if ( is_numeric( $setID ) )
        {
            
array_unshift( $skinSetData['_childTree'], $setID );
        }
        
        
//-----------------------------------------
        // Fetch CSS that needs to be rebuilt
        //-----------------------------------------
        
        
$needToRebuild = $this->_CSSNeedToRebuild( $skinSetData['_childTree'], $setID, $forceRebuild );
        
        if ( ! 
count( $needToRebuild ) )
        {
            return 
TRUE;
        }
        
        
//-----------------------------------------
        // Get the data from the cache...
        //-----------------------------------------
        
        
$this->DB->build( array( 'select' => '*',
                                 
'from'   => 'skin_cache',
                                 
'where'  => 'cache_type='css' AND cache_set_id IN (' . implode( ",", $skinSetData['_childTree'] ) . ')',
                                 
'order'  => 'cache_set_id ASC' ) );
        
        
$i = $this->DB->execute();
        
        while( 
$css = $this->DB->fetch( $i ) )
        {
            
$_setID = $css['cache_set_id'];
            
$_group = $css['cache_value_1'];
            
$_css   = $css['cache_content'];
            
            if ( ! 
count( $needToRebuild[ $_setID ] ) )
            {
                return 
TRUE;
            }
            
            
$_keys    = array_keys( $needToRebuild[ $_setID ] );
            
            if ( ! 
count( $_keys ) )
            {
                return 
TRUE;
            }
            
            if ( ! 
in_array( $_group, $_keys ) )
            {
                continue;
            }
            
            
/* If this is a child skin, just flag for recache */
            
if ( $_setID != $setID )
            {
                if ( 
$this->getIgnoreChildrenWhenRecaching() === false )
                {
                    
$this->flagSetForRecache( $_setID, true );
                }
                
                continue;
            }
            
            
IPSDebug::addLogMessage( "Attempting to write CSS " . $_setID . ", " . $_group . ".css", 'css' );
            
            
$this->_writeCSSFile( $_setID, $_group, $_css );
            
            
/* Any problems?  */
            
if ( $this->fetchErrorMessages() !== FALSE )
            {
                
/* Flag as using inline */
                
$this->flagSetAsNonCachedCSS( $_setID );
                return 
FALSE;
            }
            
            
IPSDebug::addLogMessage( "Written CSS " . $_setID . ", " . $_group . ".css", 'css' );
        }
        
        return 
TRUE;
    }
    
    
/**
     * Rebuild CSS cache
     *
     * @access    public
     * @param    int        Skin set id to rebuild
     * @param    boolean    Force rebuild regardless of if it requires it
     * @return    boolean
     */
    
public function rebuildCSSCache( $setID, $forceRebuild=FALSE )
    {
        
//-----------------------------------------
        // INIT
        //-----------------------------------------
        
        
$cssSkinCollections         = array();
        
$skinSetData                = $this->fetchSkinData( $setID );
        
$cachedCSS                    = array();
        
$thisCSS                    = array();
        
$needToRebuild                = array();
        
        
$this->_resetErrorHandle();
        
$this->_resetMessageHandle();
        
        
//-----------------------------------------
        // Push the current skin set ID onto the beginnging
        //-----------------------------------------
        
        
if ( is_numeric( $setID ) )
        {
            
array_unshift( $skinSetData['_childTree'], $setID );
        }
        
        
//-----------------------------------------
        // Fetch CSS that needs to be rebuilt
        //-----------------------------------------
    
        
$needToRebuild = $this->_CSSNeedToRebuild( $skinSetData['_childTree'], $setID, $forceRebuild );

        
IPSDebug::addLogMessage( "Set ID: " . $setID . " - " . serialize( $needToRebuild ), 'css' );
        
        
//-----------------------------------------
        // Loop through and rebuild
        //-----------------------------------------
        
        
foreach( array_keys( $needToRebuild ) as $_setID )
        {
            
$_css            = $this->fetchCSS( $_setID );
            
$_skinSetData    = $this->fetchSkinData( $_setID );
            
            
/* If this is a child skin, just flag for recache */
            
if ( $_setID != $setID )
            {
                if ( 
$this->getIgnoreChildrenWhenRecaching() === false )
                {
                    
$this->flagSetForRecache( $_setID, true );
                }
                
                continue;
            }
            
            foreach( 
$_css as $name => $css )
            {
                if ( ! 
in_array( $name, array_keys( $needToRebuild[ $_setID ] ) ) )
                {
                    continue;
                }
                                
                
$this->DB->delete( 'skin_cache', 'cache_type='css' AND cache_set_id=' . $_setID . " AND cache_value_1='" . addslashes( $name ) . "'" );
                
                
/* Build skin set row*/
                
$cssSkinCollections[ $_setID ][ $css['css_position'] . '.' . $css['css_id'] ] = array( 'css_group' => $css['css_group'], 'css_position' => $css['css_position'] );
                
                
/* Update skin cache */
                
$this->DB->insert( 'skin_cache', array( 'cache_updated' => time(),
                                                        
'cache_set_id'  => $_setID,
                                                         
'cache_type'    => 'css',
                                                        
'cache_key_1'   => 'name',
                                                        
'cache_value_1' => $css['css_group'],
                                                        
'cache_key_2'   => 'position',
                                                        
'cache_value_2' => $css['css_position'],
                                                        
'cache_key_3'   => 'setBy',
                                                        
'cache_value_3' => $css['css_set_id'],
                                                        
'cache_key_4'   => 'appInfo',
                                                        
'cache_value_4' => $css['css_app'] . '-' . $css['css_app_hide'],
                                                        
'cache_key_5'   => 'attributes',
                                                        
'cache_value_5' => $css['css_attributes'],
                                                        
'cache_key_6'   => 'modules',
                                                        
'cache_value_6' => $css['css_modules'],
                                                        
'cache_content' => $this->_CSS_fromDBtoFile( $css['css_content'], $_skinSetData )
                                                        
//'cache_content' => $css['css_content']
                                                        
) ) ;
            }
            
            
$this->cache->putWithCacheLib( 'Skin_Store_' . $_setID, array(), 1 );
        }
        
        
//-----------------------------------------
        // Finally, remove any cached items that no
        // longer 'exist' (since been deleted, etc)
        //-----------------------------------------
        
        
$_css = $this->fetchCSS( $setID );
        
$_del = array();
        
        
/* Get cached items */
        
$this->DB->build( array( 'select' => '*',
                                 
'from'   => 'skin_cache',
                                 
'where'  => 'cache_type='css' AND cache_set_id=' . $setID ) );
        
$this->DB->execute();
        
        while( 
$row = $this->DB->fetch() )
        {
            if ( ! 
$_css[ $row['cache_value_1'] ] )
            {
                
$_del[] = $row['cache_value_1'];
            }
        }
        
        if ( 
count( $_del ) )
        {
            
$this->DB->delete( 'skin_cache', 'cache_type='css' AND cache_set_id=' . $setID . " AND cache_value_1 IN('" . implode( "','", $_del ) . "')" );
        }
        
        
//-----------------------------------------
        // Update skin sets
        //-----------------------------------------
    
        
if ( count( $cssSkinCollections ) )
        {
            foreach( 
$cssSkinCollections as $setID => $data )
            {
                
$this->DB->update( 'skin_collections', array( 'set_css_groups' => serialize( $cssSkinCollections[ $setID ] ) ), 'set_id='. $setID );
                
                
$this->cache->putWithCacheLib( 'Skin_Store_' . $setID, array(), 1 );
            }
        }
        
        
/* Recache skin sets */
        
$this->rebuildSkinSetsCache();
        
        return 
TRUE;
    }
    
    
/**
     * Flag skin as not able to serve cached CSS
     *
     * @access    public
     * @return    boolean
     */
    
public function flagSetAsNonCachedCSS( $setId=null )
    {
        
/* Update DB row */
        
if ( $setId !== null )
        {
            
$this->DB->update( 'skin_collections', array( 'set_css_inline' => 1 ), 'set_id=' . intval( $setId ) );
        }
        
        
/* Build cache */
        
$this->rebuildSkinSetsCache();
        
        return 
TRUE;
    }
    
    
/**
     * Rebuild master replacements from cache/skin_cache/master_skin/_replacements.inc
     *
     * @access    public
     * @return    bool
     */
    
public function rebuildMasterReplacements( $setId=0 )
    {
        
/* Set directory */
        
$setId          = is_numeric( $setId ) ? intval( $setId ) : trim( $setId );
        
$dir          = IPS_CACHE_PATH . 'cache/skin_cache/' . $this->remapData['templates'][ $setId ];
        
$messages     = array();
        
        
//-----------------------------------------
        // Master file exists?
        //-----------------------------------------
        
        
if ( ! is_file( $dir . '/_replacements.inc' ) )
        {
            return 
FALSE;
        }
        
        
//-----------------------------------------
        // Remove current CSS
        //-----------------------------------------
        
        
if ( ! is_numeric( $setId ) )
        {
            
$this->DB->delete( 'skin_replacements', "replacement_master_key='" . $setId . "'" );
        }
        else
        {
            
$this->DB->delete( 'skin_replacements', "replacement_set_id='" . intval($setId) . "'" );
        }
        
        
//-----------------------------------------
        // Grab file
        //-----------------------------------------
        
        
$replacements = array();
        include( 
$dir . '/_replacements.inc' );/*noLibHook*/
        
        
if ( !is_array($replacements) || !count($replacements) )
        {
            return 
FALSE;
        }
        
        
//-----------------------------------------
        // Get proper set key/id
        //-----------------------------------------
        
        
$set_id        = ( is_numeric( $setId ) ) ? $setId : $this->fetchSetIdByKey( $setId );
        
$set_key    = '';
        
        if( 
$this->isMasterSet( $setId ) )
        {
            
$set_key    = ( is_numeric( $setId ) ) ? $this->fetchSetKeyById( $setId ) : $setId;
        }
        
        
//-----------------------------------------
        // Insert
        //-----------------------------------------
        
        
foreach( $replacements as $k => $v )
        {
            
$messages[] = $this->lang->words['basicimportedpre'] . $k;
            
            
$this->DB->insert( 'skin_replacements', array( 'replacement_key'        => $k,
                                                              
'replacement_content'    => $v,
                                                              
'replacement_master_key' => $set_key,
                                                           
'replacement_set_id'     => $set_id,
                                                           
'replacement_added_to'   => 0 ) );
        }
        
        
$this->cache->putWithCacheLib( 'Skin_Store_' . $setId, array(), 1 );
        
        return 
$messages;
    }
    
    
/**
     * Rebuild master CSS from the .css files in /public/style_css/master_skin/
     *
     * @access    public
     * @param    int        Skin set ID
     * @return    array     Array of messages
     * Exception Codes:
     * NOT_MASTER_SKIN:    Set ID is not linked to a master skin directory
     * NO_SUCH_DIR:        {master_skin_dir} directory cannot be found
     */
    
public function rebuildMasterCSS( $setId=0 )
    {
        
/* Set directory */
        
$setId          = is_numeric( $setId ) ? intval( $setId ) : trim( $setId );
        
$cssDir   = DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_css/' . $this->remapData['css'][ $setId ];
        
$messages = array();
        
$css      = array();
        
        
/* Got the master skin dir? */
        
if ( ! $this->remapData['css'][ $setId ] )
        {
            throw new 
Exception( "NOT_MASTER_SKIN" );
        }
        
        if ( ! 
is_dir( $cssDir ) )
        {
            throw new 
Exception( "NO_SUCH_DIR" );
        }
        
        if ( ! 
is_readable($cssDir) )
        {
            throw new 
Exception( "CANNOT_READ" );
        }
        
        
/* Remove current CSS... */
        
if ( is_numeric( $setId ) )
        {
            
$this->DB->delete( 'skin_css', 'css_set_id=' . $setId );
        }
        else
        {
            
$this->DB->delete( 'skin_css', 'css_master_key='' . $setId . ''' );
        }
        
        
/* Fetch all template bits. NOW */
        
if ( is_numeric( $setId ) AND $setId > 0 )
        {
            
$css = $this->fetchCSS( $setId );
        }
        
        
//-----------------------------------------
        // Set key and ID
        //-----------------------------------------
        
        
$set_id        = ( is_numeric( $setId ) ) ? $setId : $this->fetchSetIdByKey( $setId );
        
$set_key    = '';
        
        if( 
$this->isMasterSet( $setId ) )
        {
            
$set_key    = ( is_numeric( $setId ) ) ? $this->fetchSetKeyById( $setId ) : $setId;
        }
        
        
//-----------------------------------------
        // Recurse over the directory
        //-----------------------------------------
        
try
        {
            foreach( new 
DirectoryIterator( $cssDir ) as $file )
            {
                if ( ! 
$file->isDot() AND ! $file->isDir() )
                {
                    
$_name = $file->getFileName();
                    
                    if ( 
substr( $_name, -4 ) == '.css' )
                    {
                        
$cssName        = substr( $_name, 0, -4 );
                        
$cssContent        = @file_get_contents( $cssDir . '/' . $_name );
                        
$_css_added_to    = 0;
                        
$cssContent        = str_replace( array( "rn", "r" ), "n", $cssContent );
                        
                        
/* Encode */
                        
$cssContent        = IPSText::encodeForXml( $cssContent );
                    
                        
$messages[]        = $this->lang->words['basicimportedpre'] . $cssName;
                            
                        
$cssData        = $this->_CSS_fetchImportBlock( $cssContent );
                        
$cssContent        = $this->_CSS_fromFileToDB( $cssContent );
                        
                        
/* 'Master' bit? */
                        
if ( ! $css[ $cssName ] )
                        {
                            
$_css_added_to = $set_id;
                        }
                        
                        
$this->DB->insert( 'skin_css', array( 'css_updated'        => time(),
                                                              
'css_set_id'        => $set_id,
                                                              
'css_added_to'    => $_css_added_to,
                                                              
'css_app'            => $cssData['css_app'],
                                                              
'css_app_hide'    => intval( $cssData['css_app_hide'] ),
                                                              
'css_modules'        => trim( $cssData['css_modules'] ),
                                                              
'css_position'    => intval( $cssData['css_position'] ),
                                                              
'css_attributes'    => $cssData['css_attributes'],
                                                              
'css_master_key'    => $set_key,
                                                              
'css_group'        => $cssName,
                                                              
'css_content'        => $cssContent ) );
                    }
                }
            }
        } catch ( 
Exception $e ) {}
        
        
/* Recache */
        
if ( is_numeric( $setId ) AND $setId )
        {
            
$this->rebuildCSS( $setId );
            
$this->removeDeadCSSCaches( $setId );
            
            
$this->cache->putWithCacheLib( 'Skin_Store_' . $setId, array(), 1 );
        }
        
        return 
$messages;
    }
    
    
/**
     * Rebuilds the master 0 skin from the PHP files in /cache/{master_skin_dir}/
     *
     * @access     public
     * @param    int            Set ID to rebuild from
     * @return    array         Array of messages
     * <code>
     * Exception Codes:
     * NOT_MASTER_SKIN:    Set ID is not linked to a master skin directory
     * NO_SUCH_DIR:        {master_skin_dir} directory cannot be found
     * CANNOT_READ:        cannot read the {master_skin_dir} directory
     * </code>
     */
    
public function rebuildMasterFromPHP( $setId=0 )
    {
        
//-----------------------------------------
        // INIT
        //-----------------------------------------
        
        
$setId          = is_numeric( $setId ) ? intval( $setId ) : trim( $setId );
        
$script_token = 0;
        
$script_jump  = 0;
        
$skin_dir     = IPS_CACHE_PATH . "cache/skin_cache/" . $this->remapData['templates'][ $setId ];
        
$flag         = 0;
        
$messages     = array();
        
$templates      = array();
        
        
/* Got the master skin dir? */
        
if ( ! $this->remapData['templates'][ $setId ] )
        {
            throw new 
Exception( "NOT_MASTER_SKIN" );
        }
        
        if ( ! 
is_dir( $skin_dir ) )
        {
            throw new 
Exception( "NO_SUCH_DIR" );
        }
        
        if ( ! 
is_readable($skin_dir) )
        {
            throw new 
Exception( "CANNOT_READ" );
        }
        
        
/* Remove current templates... */
        
if ( is_numeric( $setId ) )
        {
            
$this->DB->delete( 'skin_templates', 'template_set_id=' . $setId );
        }
        else
        {
            
$this->DB->delete( 'skin_templates', 'template_master_key='' . $setId . ''' );
        }
        
        
/* Fetch all template bits. NOW */
        
if ( is_numeric( $setId ) AND $setId > 0 )
        {
            
$templates = $this->fetchTemplates( $setId, 'allTemplates' );
        }
        
        
//-----------------------------------------
        // Set key and ID
        //-----------------------------------------
        
        
$set_id        = ( is_numeric( $setId ) ) ? $setId : $this->fetchSetIdByKey( $setId );
        
$set_key    = '';
        
        if( 
$this->isMasterSet( $setId ) )
        {
            
$set_key    = ( is_numeric( $setId ) ) ? $this->fetchSetKeyById( $setId ) : $setId;
        }
                
        
/* Loop through the directory */
        
try
        {
            foreach( new 
DirectoryIterator( $skin_dir ) as $file )
            {
                if ( ! 
$file->isDot() AND ! $file->isDir() )
                {
                    
$_name = $file->getFileName();
                                        
                    if ( 
substr( $_name, -4 ) == '.php' )
                    {
                        
$name  = substr( $_name, 0, -4 );
                        
$fdata = @file_get_contents( $skin_dir . "/" . $_name );
                        
                        if ( ! 
$fdata )
                        {
                            
$messages[] = sprintf( $this->lang->words['couldnotopenfile'], $_name );
                            continue;
                        }
                        
                        
$fdata = str_replace( "r", "n", $fdata );
                        
$fdata = str_replace( "nn", "n", $fdata );
                        
                        if ( ! 
preg_match( "/n/", $fdata ) )
                        {
                            
$messages[] = sprintf( $this->lang->words['couldnotfindlineeol'], $_name );
                            continue;
                        }
                        
                        
$farray        = explode( "n", $fdata );
                        
$functions    = array();
                        
$added        = 0;
                        
$updated    = 0;
                        
                        foreach( 
$farray as $f )
                        {
                            
//-----------------------------------------
                            // Skip javascript functions...
                            //-----------------------------------------
                            
                            
if ( stristr( $f, '<script' ) )
                            {
                                
$script_token = 1;
                                
$script_jump  = 0;
                            }
                            
                            if ( 
stristr( $f, '</script>' ) )
                            {
                                
$script_token = 0;
                                
$script_jump  = 0;
                            }
                            
                            
//-----------------------------------------
                            // If, in the middle?
                            //-----------------------------------------
                            
                            
if ( $script_token AND $script_jump == 0 )
                            {
                                if ( 
preg_match( '#<if test=['"]#', $f ) )
                                {
                                    
$script_jump  = 1;
                                    
$script_token = 0;
                                }
                            }
                            
                            if ( 
$script_token == 0 AND $script_jump == 1 )
                            {
                                if ( preg_match( "
#</if>#", $f ) )
                                
{
                                    
$script_jump  = 0;
                                    
$script_token = 1;
                                }
                            }
                            
                            
//-----------------------------------------
                            // NOT IN JS
                            //-----------------------------------------
                            
                            
if ( ! $script_token )
                            {
                                if ( 
preg_match( '/^functions*([w_]+)s*((.*))/i', $f, $matches ) )
                                {
                                    
$functions[ $matches[1] ]   = '';
                                    
$config[ $matches[1] ]      = $matches[2];
                                    
$flag                       = $matches[1];
                                    continue;
                                }
                            }
                            
//-----------------------------------------
                            // ARE IN JS
                            //-----------------------------------------
                            
else
                            {
                                
# Make JS safe (UBE - Ugly, but effective)
                                
$f = preg_replace( '#ifs+?(#is'  , "i~f~(~"   , $f );
                                
$f = str_ireplace( 'else'      , "e~lse~"   , $f );
                                
$f = preg_replace( '#elses+?if#is', "e~lse~i~f", $f );
                            }
                                
                            if ( 
$flag )
                            {
                                
$functions[ $flag ] .= $f."n";
                                continue;
                            }
                        }
                        
                        
$final = "";
                        
$flag  = 0;
                        
                        foreach( 
$functions as $fname => $ftext )
                        {
                            
preg_match( "#//--starthtml--//(.+?)//--endhtml--//#s", $ftext, $matches );

                            
$content = $this->registry->templateEngine->convertPhpToHtml($matches[1]);
                            
                            
//-----------------------------------------
                            // Unconvert JS
                            //-----------------------------------------
                            
                            
$content = str_replace( "i~f~(~"   , "if ("   , $content );
                            
$content = str_replace( "e~lse~"   , "else"   , $content );
                            
$content = str_replace( "e~lse~i~f", "else if", $content );
                            
                            
/* Encode */
                            
$content = IPSText::encodeForXml( $content );
                                
                            
/* Build array */
                            
$array = array( 'template_set_id'     => $set_id,
                                            
'template_group'      => $name,
                                            
'template_content'    => $content,
                                            
'template_name'       => $fname,
                                            
'template_data'       => trim($config[$fname]),
                                            
'template_updated'    => time(),
                                            
'template_removable'  => ( is_numeric( $setId ) AND $setId ) ? 1 : 0,
                                            
'template_master_key' => $set_key,
                                            
'template_added_to'   => $set_id );
                                                                        
                            
                            if ( ! 
$setId )
                            {
                                
$added++;

                                
/* All new bits go to 'master' skin */
                                
$array['template_set_id']        = 0;
                                
$array['template_added_to']        = 0;
                                
$array['template_master_key']    = 'root';

                                
$this->DB->insert( 'skin_templates', $array );
                            }
                            else
                            {
                                
/* Compare for changes? */
                                
if ( IPSText::contentToMd5( $templates[ $name ][ strtolower( $fname ) ]['template_content'] ) != IPSText::contentToMd5( $content ) )
                                {
                                    
/* It's changed, so update. We create a new row as it might be inherited */
                                    
$updated++;
                                    
$this->DB->insert( 'skin_templates', $array );
                                }
                            }
                        }
                    
                        
$messages[] = sprintf( $this->lang->words['tplbitimported'], $name, $added, $updated );
                        
$functions  = array();
                    }
                }
            }
        } catch ( 
Exception $e ) {}

        
/* Recache */
        
if ( is_numeric( $setId ) AND $setId )
        {
            
$this->rebuildPHPTemplates( $setId );
            
$this->removeDeadPHPCaches( $setId );
            
            
$this->cache->putWithCacheLib( 'Skin_Store_' . $setId, array(), 1 );
        }
        
        if ( 
$set_key == 'mobile' )
        {
            
$this->rebuildMobileSkinUserAgentsFromSetDataXml();
        }
        
        
/* Return */
        
$messages[] = $this->lang->words['cpltrebuildfromcaches'];
        
        return 
$messages;
    }
    
    
/**
     * Flag skin as needing recache
     *
     * @param    int        Set ID
     * @param    bool    Skip rebuild skin sets cache
     * @return    boolean
     */
    
public function flagSetForRecache( $setId=null, $skipRebuild=false )
    {
        
/* If we're already flagged, just return
            @link    http://community.invisionpower.com/tracker/issue-31472-skin-recaching-optimizations */
        
$_key    = md5( $setId . $skipRebuild );
        
        if ( isset(
$this->_flaggedForRecache[ $_key ]) )
        {
            return 
true;
        }
        
        
$this->_flaggedForRecache[ $_key ]    = 1;
        
        
/* Update DB row */
        
if ( $setId !== null )
        {
            
$this->DB->update( 'skin_collections', array( 'set_updated' => -2 ), 'set_id=' . intval( $setId ) );
        }
        else
        {
            
$this->DB->update( 'skin_collections', array( 'set_updated' => -2 ) );
        }
        
        
/* Build cache */
        
if( ! $skipRebuild )
        {
            
$this->rebuildSkinSetsCache();
        }
        
        return 
TRUE;
    }
    
    
/**
     * Flag skin as needing recache
     *
     * @access    public
     * @return    boolean
     */
    
public function flagSetAsRecaching( $setId=null )
    {
        
/* Update DB row */
        
if ( $setId !== null )
        {
            
$this->DB->update( 'skin_collections', array( 'set_updated' => -1 ), 'set_id=' . intval( $setId ) );
        }
        else
        {
            
$this->DB->update( 'skin_collections', array( 'set_updated' => -1 ) );
        }
        
        
/* Build cache */
        
$this->rebuildSkinSetsCache();
        
        return 
TRUE;
    }
    
    
    
/**
     * We set a flag to rebuild the skin sets cache on shutdown.  We do it this way to ensure we only rebuild the cache once per page load.
     *
     * @link    http://community.invisionpower.com/tracker/issue-31472-skin-recaching-optimizations
     * @access    public
     * @return    boolean
     */
    
public function rebuildSkinSetsCache()
    {
        if( !
$this->_recacheSkinsCache )
        {
            
$this->_recacheSkinsCache    = true;
            
            
register_shutdown_function( array( $this, '__rebuildSkinSetsCache' ) );
        }
    }
    
    
/**
     * Rebuild skinsets cache in the cache_store table
     *
     * @access    public
     * @return    boolean
     */
    
public function __rebuildSkinSetsCache()
    {
        
        
//-----------------------------------------
        // INIT
        //-----------------------------------------

        
$cache = array();
        
        
//-----------------------------------------
        // Get skins
        //-----------------------------------------
        
        
$this->DB->build( array( 'select' => '*',
                                 
'from'   => 'skin_collections',
                                 
'order'  => 'set_order, set_id' ) );
        
$this->DB->execute();
        
        while( 
$row = $this->DB->fetch() )
        {
            
$cache[ $row['set_id'] ] = $row;
        }

        
//-----------------------------------------
        // Save the cache
        //-----------------------------------------
        
        
$this->cache->setCache( 'skinsets', $cache, array( 'array' => 1, 'donow' => 1 ) );
        
        return 
TRUE;
    }
    
    
/**
     * Recache output formats
     *
     * @access    public
     * @return    boolean
     */
    
public function rebuildOutputFormatCaches()
    {
        
$formats = $this->fetchOutputFormats();
        
        
$this->registry->cache()->setCache( 'outputformats', $formats, array( 'donow' => 1, 'array' => 1 ) );
        
        return 
TRUE;
    }
    
    
/**
     * Recache URL remaps
     *
     * @access    public
     * @return    boolean
     */
    
public function rebuildURLMapCache()
    {
        
//-----------------------------------------
        // INIT
        //-----------------------------------------
        
        
$cache = array();
        
        
$this->DB->build( array( 'select' => '*',
                                 
'from'   => 'skin_url_mapping' ) );
        
        
$this->DB->execute();
        
        while( 
$r = $this->DB->fetch() )
        {
            
$cache[ $r['map_id'] ] = $r;
        }
        
        
$this->registry->cache()->setCache( 'skin_remap', $cache, array( 'donow' => 1, 'array' => 1 ) );
        
        return 
TRUE;
    }
    
    
/**
     * Fetch Directory CSS
     * Fetchs and parses directory straight from the directory
     * Used for IN_DEV skins currently.
     *
     * @access    public
     * @param    string        Dir to read from
     * @return    array         Array of data
     */
    
public function fetchDirectoryCSS( $dir )
    {
        
/* Set directory */
        
$css      = array();
        
$cssDir   = DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_css/' . $dir;
        
$messages = array();

        if ( ! 
is_dir( $cssDir ) )
        {
            return 
$css;
        }

        if ( ! 
is_readable($cssDir) )
        {
            return 
$css;
        }

        
//-----------------------------------------
        // Recurse over the directory
        //-----------------------------------------

        
try
        {
            foreach( new 
DirectoryIterator( $cssDir ) as $file )
            {
                if ( ! 
$file->isDot() AND ! $file->isDir() )
                {
                    
$_name = $file->getFileName();
            
                    if ( 
substr( $_name, -4 ) == '.css' )
                    {
                        
$cssName    = substr( $_name, 0, -4 );
                        
$cssContent = @file_get_contents( $cssDir . '/' . $_name );
            
                        
$cssContent = str_replace( array( "rn", "r" ), "n", $cssContent );
            
                        
$messages[] = $this->lang->words['basicimportedpre'] . $cssName;
            
                        
$cssData    = $this->_CSS_fetchImportBlock( $cssContent );
                        
$cssContent = $this->_CSS_fromFileToDB( $cssContent );
            
                        
$css[ $cssName ] = array( 'css_updated'    => time(),
                                                  
'css_set_id'     => 0,
                                                  
'css_added_to'   => 0,
                                                  
'css_app'        => $cssData['css_app'],
                                                  
'css_app_hide'   => intval( isset( $cssData['css_app_hide'] ) ? $cssData['css_app_hide'] : 0 ),
                                                  
'css_position'   => intval( isset( $cssData['css_position'] ) ? $cssData['css_position'] : 0 ),
                                                  
'css_modules'    => isset( $cssData['css_modules'] )    ? $cssData['css_modules'] : '',
                                                  
'css_attributes' => isset( $cssData['css_attributes'] ) ? $cssData['css_attributes'] : '',
                                                  
'css_group'      => $cssName,
                                                  
'css_content'    => $cssContent );
                    }
                }
            }
        } catch ( 
Exception $e ) {}

        return 
$css;
    }
    
    
/**
     * Write out skin templates in the master format
     * IN_DEV tool, currently.
     *
     * @access    public
     * @param    int            Skin ID to write out
     * @param    string        Directory to write into. Directory must be in /public/style_css/
     * @return    array         Array of messages
     * Exception Codes:
     * IN_DEV_OFF                IN_DEV constant is not enabled
     * NO_SUCH_SKIN_SET            Skin set of $id does not exist
     * DIR_DOES_NOT_EXIST        Directory does not exist in /cache/skin_cache
     * CANNOT_WRITE_DIR            Directory cannot be written into
     */
    
public function writeMasterSkinCss( $id, $dir )
    {
        
/* Checkin' */
        
if ( ! IN_DEV )
        {
            throw new 
Exception( 'IN_DEV_OFF' );
        }
        
        if ( ! 
is_numeric( $id ) )
        {
            
$id = $this->fetchSetIdByKey( $id );
        }
        
        
$setData = $this->fetchSkinData( $id );
        
        
$path    = DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_css/' . $dir;
        
$msgs    = array();
        
        if ( ! isset( 
$setData['set_id'] ) )
        {
            throw new 
Exception( 'NO_SUCH_SKIN_SET' );
        }
        
        if ( ! 
is_dir( $path ) )
        {
            throw new 
Exception( 'DIR_DOES_NOT_EXIST' );
        }
        
        if ( ! 
is_writeable( $path ) )
        {
            throw new 
Exception( 'CANNOT_WRITE_DIR' );
        }
        
        
/* Fetch CSS */
        
$css = $this->fetchCSS( $id, FALSE );
    
        
/* Write it.. */
        
if ( is_array( $css ) )
        {
            foreach( 
$css as $group => $data )
            {
                
$_block = $this->_masterWrite_createCssBlock( $data );
                
                
/**
                 * @link    http://community.invisionpower.com/tracker/issue-36016-exported-master-css-files-are-compressed/
                 */
                
$setData['set_minify'] = 0;
                
                if ( @
file_put_contents( $path . '/' . $data['css_group'] . '.css', $_block . $this->_CSS_fromDBtoFile( $data['css_content'], $setData ) ) )
                {
                    
$msgs[] = $this->lang->words['basicwrittenpre'] . $data['css_group'] . '.css';
                }
                else
                {
                    
$msgs[] = $this->lang->words['basiccouldnotwrite'] . $data['css_group'] . '.css';
                }
            }
        }
        
        return 
$msgs;
    }
    
    
/**
     * Write out replacements in the master format
     * IN_DEV tool, currently.
     *
     * @access    public
     * @param    int            Skin ID to write out
     * @param    string        Directory to write into. Directory must be in /public/style_css/
     * @return    array         Array of messages
     * Exception Codes:
     * IN_DEV_OFF                IN_DEV constant is not enabled
     * NO_SUCH_SKIN_SET            Skin set of $id does not exist
     * DIR_DOES_NOT_EXIST        Directory does not exist in /cache/skin_cache
     * CANNOT_WRITE_DIR            Directory cannot be written into
     */
    
public function writeMasterSkinReplacements( $id, $dir )
    {
        
/* Checkin' */
        
if ( ! IN_DEV )
        {
            throw new 
Exception( 'IN_DEV_OFF' );
        }
        
        if ( ! 
is_numeric( $id ) )
        {
            
$id = $this->fetchSetIdByKey( $id );
        }
        
        
$setData = $this->fetchSkinData( $id );
        
        
$path    = IPS_CACHE_PATH . 'cache/skin_cache/' . $dir;
        
$msgs    = array();
        
        if ( ! isset( 
$setData['set_id'] ) )
        {
            throw new 
Exception( 'NO_SUCH_SKIN_SET' );
        }
        
        if ( ! 
is_dir( $path ) )
        {
            throw new 
Exception( 'DIR_DOES_NOT_EXIST' );
        }
        
        if ( ! 
is_writeable( $path ) )
        {
            throw new 
Exception( 'CANNOT_WRITE_DIR' );
        }
        
        
/* Fetch Replacements */
        
$replacements = $this->fetchReplacements( $id );

        
/* Write it.. */
        
if ( is_array( $replacements ) )
        {
            
$content = "<" . "?phpnn$replacements = array(nn";
            
            foreach( 
$replacements as $k => $data )
            {
                
$content .= "n'" . $k . "'                => "" . str_replace( '"', '\"', $data['replacement_content'] ) . '",';
            }
            
            $content .= "n);nn?>";
            
            if ( @file_put_contents( $path . '
/_replacements.inc', $content ) )
            {
                $msgs[] = $this->lang->words['
basicwrittenpre'] . $path . '/_replacements.inc';
            }
            else
            {
                $msgs[] = $this->lang->words['
basiccouldnotwrite'] . $path . '/_replacements.inc';
            }
        }
        
        return $msgs;
    }
    
    /**
     * Write out skin templates in the master format
     * IN_DEV tool, currently.
     *
     * @access    public
     * @param    int            Skin ID to write out
     * @param    string        Directory to write into. Directory must be in /cache/skin_cache/
     * @return    array         Array of messages
     * Exception Codes:
     * IN_DEV_OFF                IN_DEV constant is not enabled
     * NO_SUCH_SKIN_SET            Skin set of $id does not exist
     * DIR_DOES_NOT_EXIST        Directory does not exist in /cache/skin_cache
     * CANNOT_WRITE_DIR            Directory cannot be written into
     */
    public function writeMasterSkin( $id, $dir )
    {
        /* Checkin' 
*/
        if ( ! 
IN_DEV )
        {
            throw new 
Exception( 'IN_DEV_OFF' );
        }
        
        if ( ! 
is_numeric( $id ) )
        {
            
$id = $this->fetchSetIdByKey( $id );
        }
        
        
$setData = $this->fetchSkinData( $id );
        
        
$path    = IPS_CACHE_PATH . 'cache/skin_cache/' . $dir;
        
$msgs    = array();
        
        if ( ! isset( 
$setData['set_id'] ) )
        {
            throw new 
Exception( 'NO_SUCH_SKIN_SET' );
        }
        
        if ( ! 
is_dir( $path ) )
        {
            throw new 
Exception( 'DIR_DOES_NOT_EXIST' );
        }
        
        if ( ! 
is_writeable( $path ) )
        {
            throw new 
Exception( 'CANNOT_WRITE_DIR' );
        }
        
        
/* Fetch all template bits. NOW */
        
$templates = $this->fetchTemplates( $id, 'allTemplates' );
        
        
/* Loop through */
        
foreach( $templates as $group => $data )
        {
            
$_file    = $group . '.php';
            
$_content = '';
            
            foreach( 
$templates[ $group ] as $_name => $_data )
            {
                
$_content .= $this->_masterWrite_format( $_data );
            }
            
            if ( 
$_content )
            {
                
$_content = $this->_masterWrite_wrap( $_content );
                
                if ( ! @
file_put_contents( $path . '/' . $_file, $_content ) )
                {
                    
$msgs[] = $this->lang->words['basiccouldnotwrite'] . $path . '/' . $_file;
                }
                else
                {
                    @
chmod( $path . '/' . $_file, IPS_FILE_PERMISSION );
                    
$msgs[] = $this->lang->words['basicwrittenpre'] . $path . '/' . $_file;
                }
            }
            else
            {
                
$msgs[] = $this->lang->words['basicnothingtowritepre'] . $path . '/' . $_file;
            }
        }
        
        return 
$msgs;
    }
    
    
/**
     * Creates CSS master block 
     * 
     * @access    protected
     * @param    array          Array  of CSS data from the DB
     * @return    string
     */
    
protected function _masterWrite_createCssBlock( $data )
    {
        
$block = array();
        
        if ( isset( 
$data['css_position'] ) )
        {
            
$block[] = "<css_position>" . $data['css_position'] . "</css_position>";
        }
        
        if ( isset( 
$data['css_app'] ) )
        {
            
$block[] = "<css_app>" . $data['css_app'] . "</css_app>";
        }
        
        if ( isset( 
$data['css_modules'] ) )
        {
            
$block[] = "<css_modules>" . $data['css_modules'] . "</css_modules>";
        }
        
        if ( isset( 
$data['css_app_hide'] ) )
        {
            
$block[] = "<css_app_hide>" . $data['css_app_hide'] . "</css_app_hide>";
        }
        
        if ( isset( 
$data['css_attributes'] ) )
        {
            
$block[] = "<css_attributes>" . $data['css_attributes'] . "</css_attributes>";
        }
        
        if ( 
count( $block ) )
        {
            
$_block  = implode( "n", $block );
            
$content = <<<EOF
/*<IPS_IMPORT_BLOCK>
DO NOT REMOVE OR ALTER THIS PLEASE. IT IS REMOVED AUTOMATICALLY BY THE IMPORT ROUTINE.
$_block
</IPS_IMPORT_BLOCK>*/

EOF;
            return 
$content;
        }
    }
    
    
/**
     * Wrap content for a master skin function
     *
     * @access    protected
     * @param    array        Template bit data
     * @param    string        Content
     */
    
protected function _masterWrite_format( $data )
    {
        
$_open  = '<<<EOF';
        
$_close = 'EOF';
        
$return = <<<EOF
//===========================================================================
// Name: 
{$data['template_name']}
//===========================================================================
function 
{$data['template_name']}({$data['template_data']}) {
$IPBHTML = "";
//--starthtml--//
$IPBHTML .= $_open
{$data['template_content']}
$_close;
//--endhtml--//
return 
$IPBHTML;
}


EOF;
        return 
$return;
    }
    
    
/**
     * Wrap content for a master skin class
     *
     * @access    protected
     * @param    string        Content
     * @param    string        Content
     */
    
protected function _masterWrite_wrap( $content )
    {
        
$_date  = gmdate( 'r' );
        
$return = <<<EOF
<?php
/**
 * Master skin file
 * Written: 
$_date
 */
class skin_global_1 extends output {
$content
}
?>
EOF;
        return 
$return;
    }
    
    
/**
     * Write a CSS cache file
     *
     * @access    protected
     * @param    int            Skin set ID
     * @param    string        Group  Name
     * @param    string        CSS content
     * @return    @e void
     */
    
protected function _writeCSSFile( $setID, $css_group, $css_content )
    {
        
//-----------------------------------------
        // INIT
        //-----------------------------------------
        
        
$skinSetData = $this->fetchSkinData( $setID );
        
$css_content = $this->_CSS_fromDBtoFile( $css_content, $skinSetData );
        
$return     = 0;
        
$good_to_go = 0;

        if ( ! 
SAFE_MODE_ON )
        {
            
$good_to_go = 1;

            if ( 
is_writeable( DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_css/' ) === TRUE )
            {
                
$good_to_go = 1;

                if ( ! 
is_dir( DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_css/css_' . $setID ) )
                {
                    if ( ! @ 
mkdir( DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_css/css_' . $setID, IPS_FOLDER_PERMISSION ) )
                    {
                        
$this->_addErrorMessage( sprintf( $this->lang->words['couldnotcreatecssdir'], $setID ) );
                        return 
$this->_errorMsgs;
                    }
                    else
                    {
                        @
file_put_contents( DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_css/css_' . $setID . '/index.html', '' );
                        @
chmod( DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_css/css_'.$setID, IPS_FOLDER_PERMISSION );
                        
$good_to_go = 1;
                    }
                }
                else
                {
                    if ( 
is_writable( DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_css/css_' . $setID ) !== TRUE )
                    {
                        
$this->_addErrorMessage( sprintf( $this->lang->words['cssdirnotwritaaaable'], $setID ) );
                        
$good_to_go = 0;
                    }
                    else if ( 
is_file( DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_css/css_'.$setID.'/'.$css_group.'.css' ) )
                    {
                        if ( 
is_writable( DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_css/css_'.$setID.'/'.$css_group.'.css' ) !== TRUE )
                        {
                            
$this->_addErrorMessage( sprintf( $this->lang->words['cssfilenotwriteable'], $setID, $css_group ) );
                            
$good_to_go = 0;
                        }
                        else
                        {
                            
$good_to_go = 1;
                        }
                    }
                    else
                    {
                        
$good_to_go = 1;
                    }
                }
            }
            else
            {
                
$this->_addErrorMessage( sprintf( $this->lang->words['fatalnotwreite'], DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY ) );
                
$good_to_go = 0;
            }
        }
        else
        {
            
$this->_addErrorMessage( $this->lang->words['safemodeenablednow'] );
            
$good_to_go = 0;
        }

        
//-----------------------------------------
        // Write...
        //-----------------------------------------

        
if ( $good_to_go )
        {
            if ( 
$FH = @fopen( DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_css/css_'.$setID.'/'.$css_group.'.css', 'w' ) )
            {
                
fwrite( $FH, $css_content, strlen($css_content) );
                
fclose( $FH );
                @
chmod( DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_css/css_'.$setID.'/'.$css_group.'.css', IPS_FILE_PERMISSION );

                
$this->_addMessage( $this->lang->words['basicwrittenpre']. "skin_cache/css_{$setID}/{$css_group}.css" );
            }
            else
            {
                
$this->_addErrorMessage( sprintf( $this->lang->words['cssfilenotwriteable'], $setID, $css_group ) );
            }
        }
    }
        
    
/**
     * Write a PHP template cache file
     *
     * @access    protected
     * @param    int            Skin set ID
     * @param    string        Group  Name
     * @param    string        Template content
     * @return    array         Array of messages
     */
    
protected function _writePHPTemplate( $setID, $groupName, $content )
    {
        
//-----------------------------------------
        // INIT
        //-----------------------------------------
        
        
$return     = 0;
        
$good_to_go = 0;
    
        if ( ! 
SAFE_MODE_ON )
        {
            
$good_to_go = 1;
            
            if ( 
IPSLib::isWritable( IPS_CACHE_PATH.'cache/skin_cache/' ) === TRUE )
            {
                
$good_to_go = 1;
                
                if ( ! 
is_dir( IPS_CACHE_PATH.'cache/skin_cache/cacheid_'.$setID ) )
                {
                    if ( ! @ 
mkdir( IPS_CACHE_PATH.'cache/skin_cache/cacheid_'.$setID, IPS_FOLDER_PERMISSION ) )
                    {
                        
$this->_addErrorMessage( sprintf( $this->lang->words['fatalnotemplatew'], $setID ) );
                        return;
                    }
                    else
                    {
                        @
file_put_contents( IPS_CACHE_PATH.'cache/skin_cache/cacheid_' . $setID . '/index.html', '' );
                        @
chmod( IPS_CACHE_PATH.'cache/skin_cache/cacheid_'.$setID, IPS_FOLDER_PERMISSION );
                        
$good_to_go = 1;
                    }
                }
                else
                {
                    if ( 
is_file( IPS_CACHE_PATH.'cache/skin_cache/cacheid_'.$setID.'/'.$groupName.'.php' ) )
                    {
                        if ( 
IPSLib::isWritable( IPS_CACHE_PATH.'cache/skin_cache/cacheid_'.$setID.'/'.$groupName.'.php' ) !== TRUE )
                        {
                            
$this->_addErrorMessage( sprintf( $this->lang->words['templatefilenowrite'], $setID, $groupName ) );
                            
$good_to_go = 0;
                        }
                        else
                        {
                            
$good_to_go = 1;
                        }
                    }
                    else
                    {
                        
$good_to_go = 1;
                    }
                }
            }
            else
            {
                
$this->_addErrorMessage( sprintf( $this->lang->words['fatalnotemplsafe'], IPS_CACHE_PATH ) );
            }
        }
        
        
//-----------------------------------------
        // Write...
        //-----------------------------------------
        
        
if ( $good_to_go )
        {
            if ( 
$FH = @fopen( IPS_CACHE_PATH.'cache/skin_cache/cacheid_'.$setID.'/'.$groupName.'.php', 'w' ) )
            {
                
fwrite( $FH, $content, strlen($content) );
                
fclose( $FH );
                @
chmod( IPS_CACHE_PATH.'cache/skin_cache/cacheid_'.$setID.'/'.$groupName.'.php', IPS_FILE_PERMISSION );
                
                
$this->_addMessage( $this->lang->words['basicwrittenpre'] . "skin_cache/cacheid_{$setID}/{$groupName}.php" );
            }
            else
            {
                
$this->_addErrorMessage( sprintf( $this->lang->words['templatefilenowrite'], $setID, $groupName ) );
            }
        }
    }
    
    
/**
     * Strip all unneeded hooks
     *
     * @access    public
     * @param    string            Template HTML
     * @param    array             Array of hook data
     * @return    string            Processed template HTML
     */
    
public function stripUnneededHooks( $html, $hooks )
    {
        if ( 
is_array( $hooks ) and count( $hooks ) )
        { 
            
/* First, make safe hooks we want to keep */
            
foreach( $hooks as $hook )
            { 
                if ( 
$hook['_commentTag'] )
                {
                    
$html = str_replace( '<!--hook.' . $hook['_commentTag'] . '-->', '{!--hook.' . $hook['_commentTag'] . '--}', $html );
                }
            }
            
            
/* Remove all hooks */
            
$html = preg_replace( '#<!--hook.([^>]+?)-->#', '', $html );
            
            
/* Restore saved hooks */
            
foreach( $hooks as $hook )
            {
                if ( 
$hook['_commentTag'] )
                {
                    
$html = str_replace( '{!--hook.' . $hook['_commentTag'] . '--}', '<!--hook.' . $hook['_commentTag'] . '-->', $html );
                }
            }
        }
        else
        {
            
/* No hooks, so remove all */
            
$html = preg_replace( '#<!--hook.([^>]+?)-->#', '', $html );
        }
        
        return 
$html;
    }
    
    
/**
     * Fetch inline data from a master CSS
     *
     * @access    protected
     * @param    string        Raw CSS
     * @return    array
     */
    
protected function _CSS_fetchImportBlock( $cssContent )
    {
        
$return = array( 'css_app'      => '',
                         
'css_app_hide' => 0 );
                        
        
/*<IPS_IMPORT_BLOCK>
        DO NOT REMOVE OR ALTER THIS PLEASE. IT IS REMOVED AUTOMATICALLY BY THE IMPORT ROUTINE.
        <css_app>blog</css_app>
        <css_app_hide>1</css_app_hide>
        </IPS_IMPORT_BLOCK>*/
        
        /* Fetch the data block */
        
if ( strstr( $cssContent, '<IPS_IMPORT_BLOCK>' ) ) 
        {
            
preg_match( '#/*<IPS_IMPORT_BLOCK>(.+?)</IPS_IMPORT_BLOCK>*/#is', $cssContent, $match );
            
            if ( 
$match[0] )
            {
                
preg_match( "#<css_app>(.+?)</css_app>#", $match[0], $cssAppMatch );
                
$return['css_app'] = trim( $cssAppMatch[1] );
            
                
preg_match( "#<css_app_hide>(.+?)</css_app_hide>#", $match[0], $cssAppHide );
                
$return['css_app_hide'] = intval( trim( $cssAppHide[1] ) );
                
                
preg_match( "#<css_position>(.+?)</css_position>#", $match[0], $cssPosition );
                
$return['css_position'] = intval( trim( $cssPosition[1] ) );
                
                
preg_match( "#<css_attributes>(.+?)</css_attributes>#", $match[0], $cssAttr );
                
$return['css_attributes'] = trim( $cssAttr[1] );
                
                
preg_match( "#<css_modules>(.+?)</css_modules>#", $match[0], $cssModules );
                
$return['css_modules'] = isset( $cssModules[1] ) ? trim( $cssModules[1] ) : '';
            }
        }
        
        return 
$return;
    }
    
    
/**
     * Convert CSS from flatfiles to the DB version
     *
     * @access    protected
     * @param    string        Raw CSS
     * @return    string        Processed CSS
     */
    
protected function _CSS_fromFileToDB( $cssContent )
    {
        
/* Fetch the data block */
        
if ( strstr( $cssContent, '<IPS_IMPORT_BLOCK>' ) ) 
        {
            
preg_match( '#/*<IPS_IMPORT_BLOCK>(.+?)</IPS_IMPORT_BLOCK>*/#is', $cssContent, $match );
            
            if ( 
$match[0] )
            {
                
/* And remove it */
                
$cssContent = trim( str_replace( $match[0], '', $cssContent ) );
            }
        }
        
        
/* remove phpdoc style comments */
        
$cssContent = preg_replace( '#/**(s+?)(.+?)n(s+?)?*/#s', '', $cssContent );
        
        
$cssContent = preg_replace( '#url(("|')?.+?style_images/([dw]+?)/#i', "url(\1{style_images_url}/", $cssContent );
        
$cssContent = preg_replace( '#url(("|')?/style_images/([dw]+?)#i'  , "url(\1{style_images_url}/", $cssContent );
        
        
return $cssContent;
    }
    
    
/**
     * Convert CSS from DB to the flatfiles version
     *
     * @access    protected
     * @param    string        Raw CSS
     * @return    string        Processed CSS
     */
    
protected function _CSS_fromDBtoFile( $cssContent, $skinData )
    {
        
$skinData['set_image_dir'] = ( $skinData['set_image_dir'] ) ? $skinData['set_image_dir'] : 'master';

        
/* These are not always set up correctly */
        
$this->settings['img_url']            = ( $this->settings['img_url'] )        ? $this->settings['img_url'] : $this->settings['_original_base_url'] . '/' . PUBLIC_DIRECTORY . '/style_images/' . $skinData['set_image_dir'];
        
$this->settings['img_url_no_dir']    = ( $this->settings['img_url_no_dir'] ) ? $this->settings['img_url_no_dir'] : $this->settings['_original_base_url'] . '/' . PUBLIC_DIRECTORY . '/style_images/';

        
//-----------------------------------------
        // Fix up style images stuff
        //-----------------------------------------
        
        
$cssContent = preg_replace( '#([(|s*|'])(style_images/)#', '\1{style_images_url}', $cssContent );
        
$cssContent = str_replace( '{style_images_url}', $this->settings['img_url_no_dir'] . $skinData['set_image_dir'], $cssContent );
        
        
//-----------------------------------------
        // And honor image url
        //-----------------------------------------
    
        
if ( $this->settings['ipb_img_url'] )
        {
            if ( ! 
preg_match( "#/$#", $this->settings['ipb_img_url'] ) )
            {
                
$this->settings['ipb_img_url'] .= '/';
            }

            
$cssContent = preg_replace( '#url(('|")?../../style_images/#', "url(\1" . $this->settings['ipb_img_url'] . "/style_images/", $cssContent );
        }

        //-----------------------------------------
        // Minify CSS?
        //-----------------------------------------
        
        if ( 
$skinData['set_minify'] )
        {
            
$cssContent = $this->minify( $cssContent, 'css' );
        }
        
        return 
$cssContent;
    }
    
    /**
     * Determine which CSS files need rebuilding
     *
     * @access    protected
     * @param    array         Array of child skins (including current setID)
     * @param    int         Set ID we're recaching
     * @param    boolean     Force all css sets to recache
     * @return    array         Array of items to rebuild
     */
    protected function _CSSNeedToRebuild( 
$childTree, $setID, $forceRebuild=FALSE )
    {
        //-----------------------------------------
        // Already been 'ere?
        //-----------------------------------------
        
        if ( is_array( 
$this->_cssNeedToRebuildArray[ $setID ] ) )
        {
            return 
$this->_cssNeedToRebuildArray[ $setID ];
        }
        
        
$cachedCSS        = array();
        
$thisCSS        = array();
        
$needToRebuild    = array();
        
        //-----------------------------------------
        // Fetch cached CSS data - need to add parent tree and select parent css first
        //-----------------------------------------
        
        /* Do we need a parent? */
        
$setData = $this->fetchSkinData( $setID );
    
        if ( count( 
$setData['_parentTree'] ) )
        {
            /* Allow parent data to be overwritten by child data */
            
$this->DB->build( array( 'select' => '*',
                                      'from'   => 'skin_cache',
                                      'where'  => "
cache_type='css' AND cache_set_id IN (" . implode( ',', $setData['_parentTree'] ) . ')' ) );
                                    
            
$this->DB->execute();
            
            while( 
$row = $this->DB->fetch() )
            {
                
$row['cache_content'] = md5( $row['cache_content'] );
                
$cachedCSS[ $row['cache_set_id'] ][ $row['cache_value_1'] ] = $row;
            }
        }
        
        
$this->DB->build( array( 'select' => '*',
                                 'from'   => 'skin_cache',
                                 'where'  => "
cache_type='css' AND cache_set_id IN (" . implode( ',', $childTree ) . ')' ) );
                                    
        
$this->DB->execute();
        
        while( 
$row = $this->DB->fetch() )
        {
            
$row['cache_content'] = md5( $row['cache_content'] );
            
$cachedCSS[ $row['cache_set_id'] ][ $row['cache_value_1'] ] = $row;
        }
    
        //-----------------------------------------
        // Fetch all CSS data for this skin set and master
        //-----------------------------------------
        
        
$this->DB->build( array( 'select' => '*',
                                 'from'   => 'skin_css',
                                 'where'  => "
css_set_id IN( 0, " . $setID . ' )' ) );
                                    
        
$this->DB->execute();
        
        while( 
$row = $this->DB->fetch() )
        {
            
$row['css_content'] = md5( $row['css_content'] );
            
            
$thisCSS[ $row['css_set_id'] ][ $row['css_group'] ] = $row;
        }
        
        /* Add in parent skins */
        if ( count( 
$setData['_parentTree'] ) )
        {
            
$childTree = array_merge( $childTree, $setData['_parentTree'] );
        }
        
        //-----------------------------------------
        // First off, any caches missing?
        //-----------------------------------------

        foreach( 
$childTree as $_setID )
        {
            if ( 
$_setID > 0 AND is_array( $thisCSS[ $_setID ] ) )
            {
                foreach( 
$thisCSS[ $_setID ] as $group => $data )
                {
                    if ( ! is_array( 
$cachedCSS[ $_setID ][ $group ] ) OR $forceRebuild === TRUE )
                    {
                        /* Not currently cached. Needs to be recached */
                        
$needToRebuild[ $_setID ][ $group ] = 2;
                        continue;
                    }
                }
            }
            
            if ( 
$_setID > 0 )
            {
                /* We have no caches at all... */
                if ( is_array( 
$thisCSS[0] ) )
                {
                    foreach( 
$thisCSS[0] as $group => $data )
                    {
                        if ( ! is_array( 
$cachedCSS[ $_setID ][ $group ] ) OR $forceRebuild === TRUE )
                        {
                            /* Not currently cached. Needs to be recached */
                            
$needToRebuild[ $_setID ][ $group ] = 2;
                            continue;
                        }
                    }
                }
            }
        }
    
        //-----------------------------------------
        // Forcing the issue?
        //-----------------------------------------
        
        if ( 
$forceRebuild === TRUE )
        {
            
$this->_cssNeedToRebuildArray[ $setID ] = $needToRebuild;
            
            return 
$needToRebuild;
        }
        
        //-----------------------------------------
        // Now check to see if there are any that
        // inherit directly from any CSS in this set
        //-----------------------------------------
        
        if( is_array(
$cachedCSS) AND count($cachedCSS) )
        {
            foreach( 
$cachedCSS as $_setID => $_data )
            {
                foreach( 
$_data as $group => $cacheData )
                {
                    if ( 
$cacheData['cache_key_3'] != 'setBy' )
                    { 
                        
$needToRebuild[ $_setID ][ $group ] = 1;
                    }
                    else if ( 
$cacheData['cache_set_id'] == $setID )
                    {
                        /* This CSS is from our skin set, so recache */
                        
$needToRebuild[ $_setID ][ $group ] = 1;
                    }
                    else if ( 
$cacheData['cache_set_id'] == $_setID )
                    {
                        /* This CSS is from our child tree, so recache */
                        
$needToRebuild[ $_setID ][ $group ] = 1;
                    }
                    else if ( 
$cacheData['cache_value_3'] == $setID )
                    {
                        /* This CSS inherits our skin set, so recache */
                        
$needToRebuild[ $_setID ][ $group ] = 1;
                    }
                    
                    /* Now lets see if there are any parent CSS that need to be added */
                    if ( count( 
$setData['_parentTree'] ) )
                    {
                        foreach( 
$setData['_parentTree'] as $id )
                        {
                            if ( 
$cacheData['cache_key_3'] == 'setBy' && $cacheData['cache_value_3'] == $id )
                            { 
                                /* Add to current set id */
                                
$needToRebuild[ $setID ][ $group ] = 1;
                            }
                        }
                    }
                }
            }
        }
        
        /* Finally, we don't want to recache parents so remove them */
        if ( count( 
$setData['_parentTree'] ) )
        {
            foreach( 
$setData['_parentTree'] as $id )
            {
                if ( is_array( 
$needToRebuild[ $id ] ) )
                {
                    unset( 
$needToRebuild[ $id ] );
                }
            }
        }

        
$this->_cssNeedToRebuildArray[ $setID ] = $needToRebuild;
        
        return 
$needToRebuild;
    }
    
}
Онлайн: 2
Реклама