Файл: IPBMafia.ru_IPB_3.4.6_Final_Rus _Nulled/board/upload/admin/sources/classes/skins/skinCaching.php
Строк: 1630
<?php
/**
* <pre>
* Invision Power Services
* IP.Board v3.4.6
* Skin Caching Functions
* Last Updated: $Date: 2013-05-20 16:38:23 -0400 (Mon, 20 May 2013) $
* </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: 12261 $
*
*/
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 = IPS_PUBLIC_PATH . '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 = IPS_PUBLIC_PATH . '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 ) );
//-----------------------------------------
// Set that it's done
//-----------------------------------------
$this->DB->update( 'skin_collections', array( 'set_updated' => time() ) );
//-----------------------------------------
// Flush IPS CDN
//-----------------------------------------
$this->flushipscdn();
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 = IPS_PUBLIC_PATH . '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, true );
}
$setData = $this->fetchSkinData( $id );
$path = IPS_PUBLIC_PATH . '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, true );
}
$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, true );
}
$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( IPS_PUBLIC_PATH . 'style_css/' ) === TRUE )
{
$good_to_go = 1;
if ( ! is_dir( IPS_PUBLIC_PATH . 'style_css/css_' . $setID ) )
{
if ( ! @ mkdir( IPS_PUBLIC_PATH . 'style_css/css_' . $setID, IPS_FOLDER_PERMISSION ) )
{
$this->_addErrorMessage( sprintf( $this->lang->words['couldnotcreatecssdir'], $setID ) );
return $this->_errorMsgs;
}
else
{
@file_put_contents( IPS_PUBLIC_PATH . 'style_css/css_' . $setID . '/index.html', '' );
@chmod( IPS_PUBLIC_PATH . 'style_css/css_'.$setID, IPS_FOLDER_PERMISSION );
$good_to_go = 1;
}
}
else
{
if ( is_writable( IPS_PUBLIC_PATH . 'style_css/css_' . $setID ) !== TRUE )
{
$this->_addErrorMessage( sprintf( $this->lang->words['cssdirnotwritaaaable'], $setID ) );
$good_to_go = 0;
}
else if ( is_file( IPS_PUBLIC_PATH . 'style_css/css_'.$setID.'/'.$css_group.'.css' ) )
{
if ( is_writable( IPS_PUBLIC_PATH . '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( IPS_PUBLIC_PATH . 'style_css/css_'.$setID.'/'.$css_group.'.css', 'w' ) )
{
fwrite( $FH, $css_content, strlen($css_content) );
fclose( $FH );
@chmod( IPS_PUBLIC_PATH . '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;
}
}