* Invision Power Services
* IP.Board v3.3.4
* Skin Caching Functions
* Last Updated: $Date: 2012-06-22 07:55:48 -0400 (Fri, 22 Jun 2012) $
*
*
* Owner: Matt
* @author $Author: ips_terabyte $
* @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: 10969 $
*
*/
if ( ! defined( 'IN_IPB' ) )
{
print "
Incorrect access
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{\n\n";
$fileHead .= <<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 .= "\n\n{$funcHooks}\n\n}\n\n";
$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 = '<'.'?'."php\n";
$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 \G\M\T' )." */\n";
$start .= "/* DO NOT EDIT DIRECTLY - THE CHANGES WILL NOT BE */\n";
$start .= "/* WRITTEN TO THE DATABASE AUTOMATICALLY */\n";
$start .= "/*--------------------------------------------------*/\n\n";
$end = "\n\n/*--------------------------------------------------*/\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( "\r\n", "\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
*
* 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
*
*/
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( "\n\n", "\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, '