-<?php
-/*
- * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
- * Copyright (C) 2002-2009 The Nucleus Group
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * (see nucleus/documentation/index.html#license for more info)
- */
-/**
- * This class contains two classes that can be used for importing and
- * exporting Nucleus skins: SKINIMPORT and SKINEXPORT
- *
- * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2009 The Nucleus Group
- * @version $Id: skinie.php 1624 2012-01-09 11:36:20Z sakamocchi $
- */
-
-class SKINIMPORT
-{
- // hardcoded value (see constructor). When 1, interesting info about the
- // parsing process is sent to the output
- private $debug;
-
- // parser/file pointer
- private $parser;
- private $fp;
-
- // parset internal charset, US-ASCII/ISO-8859-1/UTF-8
- private $parse_charset = 'UTF-8';
-
- // which data has been read?
- private $metaDataRead;
- private $allRead;
-
- // extracted data
- private $skins;
- private $templates;
- private $info;
-
- // to maintain track of where we are inside the XML file
- private $inXml;
- private $inData;
- private $inMeta;
- private $inSkin;
- private $inTemplate;
- private $currentName;
- private $currentPartName;
- private $cdata;
-
- /**
- * constructor initializes data structures
- */
- public function __construct()
- {
- // disable magic_quotes_runtime if it's turned on
- //set_magic_quotes_runtime(0);
- if ( version_compare(PHP_VERSION, '5.3.0', '<') )
- {
- ini_set('magic_quotes_runtime', '0');
- }
-
- // debugging mode?
- $this->debug = 0;
-
- $this->reset();
- return;
- }
-
- public function __destruct()
- {
- return;
- }
-
- public function reset()
- {
- if ( $this->parser )
- {
- xml_parser_free($this->parser);
- }
-
- // XML file pointer
- $this->fp = 0;
-
- // which data has been read?
- $this->metaDataRead = 0;
- $this->allRead = 0;
-
- // to maintain track of where we are inside the XML file
- $this->inXml = 0;
- $this->inData = 0;
- $this->inMeta = 0;
- $this->inSkin = 0;
- $this->inTemplate = 0;
- $this->currentName = '';
- $this->currentPartName = '';
-
- // character data pile
- $this->cdata = '';
-
- // list of skinnames and templatenames (will be array of array)
- $this->skins = array();
- $this->templates = array();
-
- // extra info included in the XML files (e.g. installation notes)
- $this->info = '';
-
- // init XML parser, this parser deal with characters as encoded by UTF-8
- $this->parser = xml_parser_create($this->parse_charset);
- xml_set_object($this->parser, $this);
- xml_set_element_handler($this->parser, 'start_element', 'end_element');
- xml_set_character_data_handler($this->parser, 'character_data');
- xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
-
- return;
- }
-
- /**
- * Reads an XML file into memory
- *
- * @param $filename
- * Which file to read
- * @param $metaOnly
- * Set to 1 when only the metadata needs to be read (optional, default 0)
- */
- public function readFile($filename, $metaOnly = 0)
- {
- // open file
- $this->fp = @fopen($filename, 'r');
- if ( !$this->fp )
- {
- return _SKINIE_ERROR_FAILEDOPEN_FILEURL;
- }
-
- // here we go!
- $this->inXml = 1;
-
- $tempbuffer = null;
-
- while ( !feof($this->fp) )
- {
- $tempbuffer .= fread($this->fp, 4096);
- }
- fclose($this->fp);
-
- /*
- * NOTE: conver character set.
- * We hope all characters in the file also includes UTF-8 coded character set,
- * because this PHP extension implements support for James Clark's expat in PHP
- * and it supports juust US-ASCII, ISO-8859-1, UTF-8 character coding scheme.
- */
- if ( i18n::get_current_charset() != $this->parse_charset )
- {
- $tempbuffer = i18n::convert($tempbuffer, i18n::get_current_charset(), $this->parse_charset);
- }
-
- $temp = tmpfile();
- fwrite($temp, $tempbuffer);
- rewind($temp);
-
- while ( ($buffer = fread($temp, 4096) )
- && (!$metaOnly || ($metaOnly && !$this->metaDataRead)) )
- {
- $err = xml_parse( $this->parser, $buffer, feof($temp) );
- if ( !$err && $this->debug )
- {
- echo 'ERROR: ', xml_error_string(xml_get_error_code($this->parser)), '<br />';
- }
- }
-
- // all done
- $this->inXml = 0;
- fclose($temp);
-
- return;
- }
-
- /**
- * Returns the list of skin names
- */
- public function getSkinNames()
- {
- return array_keys($this->skins);
- }
-
- /**
- * Returns the list of template names
- */
- public function getTemplateNames()
- {
- return array_keys($this->templates);
- }
-
- /**
- * Returns the extra information included in the XML file
- */
- public function getInfo()
- {
- return $this->info;
- }
-
- /**
- * Writes the skins and templates to the database
- *
- * @param $allowOverwrite
- * set to 1 when allowed to overwrite existing skins with the same name
- * (default = 0)
- */
- public function writeToDatabase($allowOverwrite = 0)
- {
- $existingSkins = $this->checkSkinNameClashes();
- $existingTemplates = $this->checkTemplateNameClashes();
- $invalidSkinNames = $this->checkSkinNamesValid();
- $invalidTemplateNames = $this->checkTemplateNamesValid();
-
- // if there are invalid skin or template names, stop executioin and return and error
- if ( (sizeof($invalidSkinNames) > 0) || (sizeof($invalidTemplateNames) > 0) )
- {
- $inames_error = "<p>"._SKINIE_INVALID_NAMES_DETECTED."</p>\n";
- $inames_error .= "<ul>";
- foreach( $invalidSkinNames as $sName )
- {
- $inames_error .= "<li>".ENTITY::hsc($sName)."</li>";
- }
- foreach( $invalidTemplateNames as $sName )
- {
- $inames_error .= "<li>".ENTITY::hsc($sName)."</li>";
- }
- $inames_error .= "</ul>";
- return $inames_error;
- }
-
- // if not allowed to overwrite, check if any nameclashes exists
- if ( !$allowOverwrite )
- {
- if ( (sizeof($existingSkins) > 0) || (sizeof($existingTemplates) > 0) )
- {
- return _SKINIE_NAME_CLASHES_DETECTED;
- }
- }
-
- foreach ( $this->skins as $skinName => $data )
- {
- // 1. if exists: delete all part data, update desc data
- // if not exists: create desc
- if ( in_array($skinName, $existingSkins) )
- {
- $skinObj = SKIN::createFromName($skinName);
-
- // delete all parts of the skin
- $skinObj->deleteAllParts();
-
- // update general info
- $skinObj->updateGeneralInfo(
- $skinName,
- $data['description'],
- $data['type'],
- $data['includeMode'],
- $data['includePrefix']
- );
- }
- else
- {
- $skinid = SKIN::createNew(
- $skinName,
- $data['description'],
- $data['type'],
- $data['includeMode'],
- $data['includePrefix']
- );
- $skinObj = new SKIN($skinid);
- }
-
- // 2. add parts
- foreach ( $data['parts'] as $partName => $partContent )
- {
- $skinObj->update($partName, $partContent);
- }
- }
-
- foreach ( $this->templates as $templateName => $data )
- {
- // 1. if exists: delete all part data, update desc data
- // if not exists: create desc
- if ( in_array($templateName, $existingTemplates) )
- {
- $templateObj = TEMPLATE::createFromName($templateName);
-
- // delete all parts of the template
- $templateObj->deleteAllParts();
-
- // update general info
- $templateObj->updateGeneralInfo($templateName, $data['description']);
- }
- else
- {
- $templateid = TEMPLATE::createNew($templateName, $data['description']);
- $templateObj = new TEMPLATE($templateid);
- }
-
- // 2. add parts
- foreach ( $data['parts'] as $partName => $partContent )
- {
- $templateObj->update($partName, $partContent);
- }
- }
- return;
- }
-
- /**
- * returns an array of all the skin nameclashes (empty array when no name clashes)
- */
- public function checkSkinNameClashes()
- {
- $clashes = array();
-
- foreach ( $this->skins as $skinName => $data )
- {
- if ( SKIN::exists($skinName) )
- {
- array_push($clashes, $skinName);
- }
- }
- return $clashes;
- }
-
- /**
- * returns an array of all the template nameclashes
- * (empty array when no name clashes)
- */
- public function checkTemplateNameClashes()
- {
- $clashes = array();
-
- foreach ( $this->templates as $templateName => $data )
- {
- if ( TEMPLATE::exists($templateName) )
- {
- array_push($clashes, $templateName);
- }
- }
- return $clashes;
- }
-
- /**
- * returns an array of all the invalid skin names (empty array when no invalid names )
- */
- private function checkSkinNamesValid()
- {
- $notValid = array();
-
- foreach ( $this->skins as $skinName => $data )
- {
- if ( !isValidSkinName($skinName) )
- {
- array_push($notValid, $skinName);
- }
- }
- return $notValid;
- }
-
- /**
- * returns an array of all the invalid template names (empty array when no invalid names )
- */
- private function checkTemplateNamesValid()
- {
- $notValid = array();
-
- foreach ( $this->templates as $templateName => $data )
- {
- if ( !isValidTemplateName($templateName) )
- {
- array_push($notValid, $templateName);
- }
- }
- return $notValid;
- }
-
- /**
- * Called by XML parser for each new start element encountered
- */
- private function start_element($parser, $name, $attrs)
- {
- foreach( $attrs as $key=>$value )
- {
- if ( $this->parse_charset != i18n::get_current_charset() )
- {
- $name = i18n::convert($name, $this->parse_charset, i18n::get_current_charset());
- $value = i18n::convert($value, $this->parse_charset, i18n::get_current_charset());
- }
-
- $attrs[$key] = $value;
- }
-
- if ( $this->debug )
- {
- echo 'START: ', ENTITY::hsc($name), '<br />';
- }
-
- switch ( $name )
- {
- case 'nucleusskin':
- $this->inData = 1;
- break;
- case 'meta':
- $this->inMeta = 1;
- break;
- case 'info':
- // no action needed
- break;
- case 'skin':
- if ( !$this->inMeta )
- {
- $this->inSkin = 1;
- $this->currentName = $attrs['name'];
- $this->skins[$this->currentName]['type'] = $attrs['type'];
- $this->skins[$this->currentName]['includeMode'] = $attrs['includeMode'];
- $this->skins[$this->currentName]['includePrefix'] = $attrs['includePrefix'];
- $this->skins[$this->currentName]['parts'] = array();
- }
- else
- {
- $this->skins[$attrs['name']] = array();
- $this->skins[$attrs['name']]['parts'] = array();
- }
- break;
- case 'template':
- if ( !$this->inMeta )
- {
- $this->inTemplate = 1;
- $this->currentName = $attrs['name'];
- $this->templates[$this->currentName]['parts'] = array();
- }
- else
- {
- $this->templates[$attrs['name']] = array();
- $this->templates[$attrs['name']]['parts'] = array();
- }
- break;
- case 'description':
- // no action needed
- break;
- case 'part':
- $this->currentPartName = $attrs['name'];
- break;
- default:
- echo _SKINIE_SEELEMENT_UNEXPECTEDTAG . ENTITY::hsc($name) . '<br />';
- break;
- }
- // character data never contains other tags
- $this->clear_character_data();
- return;
- }
-
- /**
- * Called by the XML parser for each closing tag encountered
- */
- private function end_element($parser, $name)
- {
- if ( $this->debug )
- {
- echo 'END: ' . ENTITY::hsc($name) . '<br />';
- }
-
- if ( $this->parse_charset != i18n::get_current_charset() )
- {
- $name = i18n::convert($name, $this->parse_charset, i18n::get_current_charset());
- $charset_data = i18n::convert($this->get_character_data(), $this->parse_charset, i18n::get_current_charset());
- }
- else
- {
- $charset_data = $this->get_character_data();
- }
-
- switch ( $name )
- {
- case 'nucleusskin':
- $this->inData = 0;
- $this->allRead = 1;
- break;
- case 'meta':
- $this->inMeta = 0;
- $this->metaDataRead = 1;
- break;
- case 'info':
- $this->info = $charset_data;
- case 'skin':
- if ( !$this->inMeta )
- {
- $this->inSkin = 0;
- }
- break;
- case 'template':
- if ( !$this->inMeta )
- {
- $this->inTemplate = 0;
- }
- break;
- case 'description':
- if ( $this->inSkin )
- {
- $this->skins[$this->currentName]['description'] = $charset_data;
- }
- else
- {
- $this->templates[$this->currentName]['description'] = $charset_data;
- }
- break;
- case 'part':
- if ( $this->inSkin )
- {
- $this->skins[$this->currentName]['parts'][$this->currentPartName] = $charset_data;
- }
- else
- {
- $this->templates[$this->currentName]['parts'][$this->currentPartName] = $charset_data;
- }
- break;
- default:
- echo _SKINIE_SEELEMENT_UNEXPECTEDTAG . ENTITY::hsc($name) . '<br />';
- break;
- }
- $this->clear_character_data();
- return;
- }
-
- /**
- * Called by XML parser for data inside elements
- */
- private function character_data ($parser, $data)
- {
- if ( $this->debug )
- {
- echo 'NEW DATA: ' . ENTITY::hsc($data) . '<br />';
- }
- $this->cdata .= $data;
- return;
- }
-
- /**
- * Returns the data collected so far
- */
- private function get_character_data()
- {
- return $this->cdata;
- }
-
- /**
- * Clears the data buffer
- */
- private function clear_character_data()
- {
- $this->cdata = '';
- return;
- }
-
- /**
- * Static method that looks for importable XML files in subdirs of the given dir
- */
- static public function searchForCandidates($dir)
- {
- $candidates = array();
-
- $dirhandle = opendir($dir);
- while ( $filename = readdir($dirhandle) )
- {
- if ( @is_dir($dir . $filename) && ($filename != '.') && ($filename != '..') )
- {
- $xml_file = $dir . $filename . '/skinbackup.xml';
- if ( file_exists($xml_file) && is_readable($xml_file) )
- {
- //$xml_file;
- $candidates[$filename] = $filename;
- }
-
- // backwards compatibility
- $xml_file = $dir . $filename . '/skindata.xml';
- if ( file_exists($xml_file) && is_readable($xml_file) )
- {
- //$xml_file;
- $candidates[$filename] = $filename;
- }
- }
- }
- closedir($dirhandle);
- return $candidates;
- }
-}
-
-class SKINEXPORT {
- private $templates;
- private $skins;
- private $info;
-
- /**
- * Constructor initializes data structures
- */
- public function __construct()
- {
- // list of templateIDs to export
- $this->templates = array();
-
- // list of skinIDs to export
- $this->skins = array();
-
- // extra info to be in XML file
- $this->info = '';
- }
-
- /**
- * Adds a template to be exported
- *
- * @param id
- * template ID
- * @result false when no such ID exists
- */
- public function addTemplate($id)
- {
- if ( !TEMPLATE::existsID($id) )
- {
- return 0;
- }
-
- $this->templates[$id] = TEMPLATE::getNameFromId($id);
- return 1;
- }
-
- /**
- * Adds a skin to be exported
- *
- * @param id
- * skin ID
- * @result false when no such ID exists
- */
- public function addSkin($id)
- {
- if ( !SKIN::existsID($id) )
- {
- return 0;
- }
-
- $this->skins[$id] = SKIN::getNameFromId($id);
- return 1;
- }
-
- /**
- * Sets the extra info to be included in the exported file
- */
- public function setInfo($info)
- {
- $this->info = $info;
- }
-
- /**
- * Outputs the XML contents of the export file
- *
- * @param $setHeaders
- * set to 0 if you don't want to send out headers
- * (optional, default 1)
- */
- public function export($setHeaders = 1)
- {
- if ( $setHeaders )
- {
- // make sure the mimetype is correct, and that the data does not show up
- // in the browser, but gets saved into and XML file (popup download window)
- header('Content-Type: text/xml; charset=' . i18n::get_current_charset());
- header('Content-Disposition: attachment; filename="skinbackup.xml"');
- header('Expires: 0');
- header('Pragma: no-cache');
- }
-
- echo "<nucleusskin>\n";
-
- // meta
- echo "\t<meta>\n";
- // skins
- foreach ( $this->skins as $skinId => $skinName )
- {
- echo "\t\t" . '<skin name="' . ENTITY::hsc($skinName) . '" />' . "\n";
- }
- // templates
- foreach ( $this->templates as $templateId => $templateName )
- {
- echo "\t\t" . '<template name="' . ENTITY::hsc($templateName) . '" />' . "\n";
- }
- // extra info
- if ( $this->info )
- {
- echo "\t\t<info><![CDATA[" . $this->info . "]]></info>\n";
- }
- echo "\t</meta>\n\n\n";
-
- // contents skins
- foreach ($this->skins as $skinId => $skinName)
- {
- $skinId = intval($skinId);
- $skinObj = new SKIN($skinId);
-
- echo "\t" . '<skin name="' . ENTITY::hsc($skinName) . '" type="' . ENTITY::hsc($skinObj->getContentType()) . '" includeMode="' . ENTITY::hsc($skinObj->getIncludeMode()) . '" includePrefix="' . ENTITY::hsc($skinObj->getIncludePrefix()) . '">' . "\n";
- echo "\t\t<description>" . ENTITY::hsc($skinObj->getDescription()) . "</description>\n";
-
- $res = sql_query('SELECT stype, scontent FROM '. sql_table('skin') .' WHERE sdesc=' . $skinId);
- while ( $partObj = sql_fetch_object($res) )
- {
- echo "\t\t" . '<part name="',ENTITY::hsc($partObj->stype) . '">';
- echo '<![CDATA[' . $this->escapeCDATA($partObj->scontent) . ']]>';
- echo "</part>\n\n";
- }
- echo "\t</skin>\n\n\n";
- }
-
- // contents templates
- foreach ( $this->templates as $templateId => $templateName )
- {
- $templateId = intval($templateId);
-
- echo "\t" . '<template name="' . ENTITY::hsc($templateName) . '">' . "\n";
- echo "\t\t<description>" . ENTITY::hsc(TEMPLATE::getDesc($templateId)) . "</description>\n";
-
- $res = sql_query('SELECT tpartname, tcontent FROM '. sql_table('template') .' WHERE tdesc=' . $templateId);
- while ( $partObj = sql_fetch_object($res) )
- {
- echo "\t\t" . '<part name="' . ENTITY::hsc($partObj->tpartname) . '">';
- echo '<![CDATA[' . $this->escapeCDATA($partObj->tcontent) . ']]>';
- echo "</part>\n\n";
- }
-
- echo "\t</template>\n\n\n";
- }
- echo '</nucleusskin>';
- }
-
- /**
- * Escapes CDATA content so it can be included in another CDATA section
- */
- private function escapeCDATA($cdata)
- {
- return preg_replace('/]]>/', ']]]]><![CDATA[>', $cdata);
- }
-}
\ No newline at end of file
+<?php\r
+/*\r
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)\r
+ * Copyright (C) 2002-2012 The Nucleus Group\r
+ *\r
+ * This program is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU General Public License\r
+ * as published by the Free Software Foundation; either version 2\r
+ * of the License, or (at your option) any later version.\r
+ * (see nucleus/documentation/index.html#license for more info)\r
+ */\r
+/**\r
+ * This class contains two classes that can be used for importing and\r
+ * exporting Nucleus skins: SKINIMPORT and SKINEXPORT\r
+ *\r
+ * @license http://nucleuscms.org/license.txt GNU General Public License\r
+ * @copyright Copyright (C) 2002-2012 The Nucleus Group\r
+ * @version $Id: skinie.php 1624 2012-01-09 11:36:20Z sakamocchi $\r
+ */\r
+\r
+class SkinImport\r
+{\r
+ // hardcoded value (see constructor). When 1, interesting info about the\r
+ // parsing process is sent to the output\r
+ private $debug;\r
+ \r
+ // parser/file pointer\r
+ private $parser;\r
+ private $fp;\r
+ \r
+ // parset internal charset, US-ASCII/ISO-8859-1/UTF-8\r
+ private $parse_charset = 'UTF-8';\r
+ \r
+ // which data has been read?\r
+ private $metaDataRead;\r
+ private $allRead;\r
+ \r
+ // extracted data\r
+ private $skins;\r
+ private $templates;\r
+ private $info;\r
+ \r
+ // to maintain track of where we are inside the XML file\r
+ private $inXml;\r
+ private $inData;\r
+ private $inMeta;\r
+ private $inSkin;\r
+ private $inTemplate;\r
+ private $currentName;\r
+ private $currentPartName;\r
+ private $cdata;\r
+ \r
+ /**\r
+ * constructor initializes data structures\r
+ */\r
+ public function __construct()\r
+ {\r
+ // disable magic_quotes_runtime if it's turned on\r
+ //set_magic_quotes_runtime(0);\r
+ if ( version_compare(PHP_VERSION, '5.3.0', '<') )\r
+ {\r
+ ini_set('magic_quotes_runtime', '0');\r
+ }\r
+ \r
+ // debugging mode?\r
+ $this->debug = 0;\r
+ \r
+ $this->reset();\r
+ return;\r
+ }\r
+ \r
+ public function __destruct()\r
+ {\r
+ return;\r
+ }\r
+ \r
+ public function reset()\r
+ {\r
+ if ( $this->parser )\r
+ {\r
+ xml_parser_free($this->parser);\r
+ }\r
+ \r
+ // XML file pointer\r
+ $this->fp = 0;\r
+ \r
+ // which data has been read?\r
+ $this->metaDataRead = 0;\r
+ $this->allRead = 0;\r
+ \r
+ // to maintain track of where we are inside the XML file\r
+ $this->inXml = 0;\r
+ $this->inData = 0;\r
+ $this->inMeta = 0;\r
+ $this->inSkin = 0;\r
+ $this->inTemplate = 0;\r
+ $this->currentName = '';\r
+ $this->currentPartName = '';\r
+ \r
+ // character data pile\r
+ $this->cdata = '';\r
+ \r
+ // list of skinnames and templatenames (will be array of array)\r
+ $this->skins = array();\r
+ $this->templates = array();\r
+ \r
+ // extra info included in the XML files (e.g. installation notes)\r
+ $this->info = '';\r
+ \r
+ // init XML parser, this parser deal with characters as encoded by UTF-8\r
+ $this->parser = xml_parser_create($this->parse_charset);\r
+ xml_set_object($this->parser, $this);\r
+ xml_set_element_handler($this->parser, 'start_element', 'end_element');\r
+ xml_set_character_data_handler($this->parser, 'character_data');\r
+ xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);\r
+ \r
+ return;\r
+ }\r
+ \r
+ /**\r
+ * Reads an XML file into memory\r
+ *\r
+ * @param $filename\r
+ * Which file to read\r
+ * @param $metaOnly\r
+ * Set to 1 when only the metadata needs to be read (optional, default 0)\r
+ */\r
+ public function readFile($filename, $metaOnly = 0)\r
+ {\r
+ // open file\r
+ $this->fp = @fopen($filename, 'r');\r
+ if ( !$this->fp )\r
+ {\r
+ return _SKINIE_ERROR_FAILEDOPEN_FILEURL;\r
+ }\r
+ \r
+ // here we go!\r
+ $this->inXml = 1;\r
+ \r
+ $tempbuffer = null;\r
+ \r
+ while ( !feof($this->fp) )\r
+ {\r
+ $tempbuffer .= fread($this->fp, 4096);\r
+ }\r
+ fclose($this->fp);\r
+ \r
+ /*\r
+ * NOTE: conver character set.\r
+ * We hope all characters in the file also includes UTF-8 coded character set,\r
+ * because this PHP extension implements support for James Clark's expat in PHP\r
+ * and it supports juust US-ASCII, ISO-8859-1, UTF-8 character coding scheme.\r
+ */\r
+ if ( i18n::get_current_charset() != $this->parse_charset )\r
+ {\r
+ $tempbuffer = i18n::convert($tempbuffer, i18n::get_current_charset(), $this->parse_charset);\r
+ }\r
+ \r
+ $temp = tmpfile();\r
+ fwrite($temp, $tempbuffer);\r
+ rewind($temp);\r
+ \r
+ while ( ($buffer = fread($temp, 4096) )\r
+ && (!$metaOnly || ($metaOnly && !$this->metaDataRead)) )\r
+ {\r
+ $err = xml_parse( $this->parser, $buffer, feof($temp) );\r
+ if ( !$err && $this->debug )\r
+ {\r
+ echo 'ERROR: ', xml_error_string(xml_get_error_code($this->parser)), '<br />';\r
+ }\r
+ }\r
+ \r
+ // all done\r
+ $this->inXml = 0;\r
+ fclose($temp);\r
+ \r
+ return;\r
+ }\r
+ \r
+ /**\r
+ * Returns the list of skin names\r
+ */\r
+ public function getSkinNames()\r
+ {\r
+ return array_keys($this->skins);\r
+ }\r
+ \r
+ /**\r
+ * Returns the list of template names\r
+ */\r
+ public function getTemplateNames()\r
+ {\r
+ return array_keys($this->templates);\r
+ }\r
+ \r
+ /**\r
+ * Returns the extra information included in the XML file\r
+ */\r
+ public function getInfo()\r
+ {\r
+ return $this->info;\r
+ }\r
+ \r
+ /**\r
+ * Writes the skins and templates to the database\r
+ *\r
+ * @param $allowOverwrite\r
+ * set to 1 when allowed to overwrite existing skins with the same name\r
+ * (default = 0)\r
+ */\r
+ public function writeToDatabase($allowOverwrite = 0)\r
+ {\r
+ $existingSkins = $this->checkSkinNameClashes();\r
+ $existingTemplates = $this->checkTemplateNameClashes();\r
+ $invalidSkinNames = $this->checkSkinNamesValid();\r
+ $invalidTemplateNames = $this->checkTemplateNamesValid();\r
+ \r
+ // if there are invalid skin or template names, stop executioin and return and error\r
+ if ( (sizeof($invalidSkinNames) > 0) || (sizeof($invalidTemplateNames) > 0) )\r
+ {\r
+ $inames_error = "<p>"._SKINIE_INVALID_NAMES_DETECTED."</p>\n";\r
+ $inames_error .= "<ul>";\r
+ foreach( $invalidSkinNames as $sName )\r
+ {\r
+ $inames_error .= "<li>".Entity::hsc($sName)."</li>";\r
+ }\r
+ foreach( $invalidTemplateNames as $sName )\r
+ {\r
+ $inames_error .= "<li>".Entity::hsc($sName)."</li>";\r
+ }\r
+ $inames_error .= "</ul>";\r
+ return $inames_error;\r
+ }\r
+ \r
+ // if not allowed to overwrite, check if any nameclashes exists\r
+ if ( !$allowOverwrite )\r
+ {\r
+ if ( (sizeof($existingSkins) > 0) || (sizeof($existingTemplates) > 0) )\r
+ {\r
+ return _SKINIE_NAME_CLASHES_DETECTED;\r
+ }\r
+ }\r
+ \r
+ foreach ( $this->skins as $skinName => $data )\r
+ {\r
+ // 1. if exists: delete all part data, update desc data\r
+ // if not exists: create desc\r
+ if ( in_array($skinName, $existingSkins) )\r
+ {\r
+ $skinObj = SKIN::createFromName($skinName);\r
+ \r
+ // delete all parts of the skin\r
+ $skinObj->deleteAllParts();\r
+ \r
+ // update general info\r
+ $skinObj->updateGeneralInfo(\r
+ $skinName,\r
+ $data['description'],\r
+ $data['type'],\r
+ $data['includeMode'],\r
+ $data['includePrefix']\r
+ );\r
+ }\r
+ else\r
+ {\r
+ $skinid = SKIN::createNew(\r
+ $skinName,\r
+ $data['description'],\r
+ $data['type'],\r
+ $data['includeMode'],\r
+ $data['includePrefix']\r
+ );\r
+ $skinObj = new SKIN($skinid);\r
+ }\r
+ \r
+ // 2. add parts\r
+ foreach ( $data['parts'] as $partName => $partContent )\r
+ {\r
+ $skinObj->update($partName, $partContent);\r
+ }\r
+ }\r
+ \r
+ foreach ( $this->templates as $templateName => $data )\r
+ {\r
+ // 1. if exists: delete all part data, update desc data\r
+ // if not exists: create desc\r
+ if ( in_array($templateName, $existingTemplates) )\r
+ {\r
+ $templateObj = Template::createFromName($templateName);\r
+ \r
+ // delete all parts of the template\r
+ $templateObj->deleteAllParts();\r
+ \r
+ // update general info\r
+ $templateObj->updateGeneralInfo($templateName, $data['description']);\r
+ }\r
+ else\r
+ {\r
+ $templateid = Template::createNew($templateName, $data['description']);\r
+ $templateObj = new Template($templateid);\r
+ }\r
+ \r
+ // 2. add parts\r
+ foreach ( $data['parts'] as $partName => $partContent )\r
+ {\r
+ $templateObj->update($partName, $partContent);\r
+ }\r
+ }\r
+ return;\r
+ }\r
+ \r
+ /**\r
+ * returns an array of all the skin nameclashes (empty array when no name clashes)\r
+ */\r
+ public function checkSkinNameClashes()\r
+ {\r
+ $clashes = array();\r
+ \r
+ foreach ( $this->skins as $skinName => $data )\r
+ {\r
+ if ( SKIN::exists($skinName) )\r
+ {\r
+ array_push($clashes, $skinName);\r
+ }\r
+ }\r
+ return $clashes;\r
+ }\r
+ \r
+ /**\r
+ * returns an array of all the template nameclashes\r
+ * (empty array when no name clashes)\r
+ */\r
+ public function checkTemplateNameClashes()\r
+ {\r
+ $clashes = array();\r
+ \r
+ foreach ( $this->templates as $templateName => $data )\r
+ {\r
+ if ( Template::exists($templateName) )\r
+ {\r
+ array_push($clashes, $templateName);\r
+ }\r
+ }\r
+ return $clashes;\r
+ }\r
+ \r
+ /**\r
+ * returns an array of all the invalid skin names (empty array when no invalid names )\r
+ */\r
+ private function checkSkinNamesValid()\r
+ {\r
+ $notValid = array();\r
+ \r
+ foreach ( $this->skins as $skinName => $data )\r
+ {\r
+ if ( !isValidSkinName($skinName) )\r
+ {\r
+ array_push($notValid, $skinName);\r
+ }\r
+ }\r
+ return $notValid;\r
+ }\r
+ \r
+ /**\r
+ * returns an array of all the invalid template names (empty array when no invalid names )\r
+ */\r
+ private function checkTemplateNamesValid()\r
+ {\r
+ $notValid = array();\r
+ \r
+ foreach ( $this->templates as $templateName => $data )\r
+ {\r
+ if ( !isValidTemplateName($templateName) )\r
+ {\r
+ array_push($notValid, $templateName);\r
+ }\r
+ }\r
+ return $notValid;\r
+ }\r
+ \r
+ /**\r
+ * Called by XML parser for each new start element encountered\r
+ */\r
+ private function start_element($parser, $name, $attrs)\r
+ {\r
+ foreach( $attrs as $key=>$value )\r
+ {\r
+ if ( $this->parse_charset != i18n::get_current_charset() )\r
+ {\r
+ $name = i18n::convert($name, $this->parse_charset, i18n::get_current_charset());\r
+ $value = i18n::convert($value, $this->parse_charset, i18n::get_current_charset());\r
+ }\r
+ \r
+ $attrs[$key] = $value;\r
+ }\r
+ \r
+ if ( $this->debug )\r
+ {\r
+ echo 'START: ', Entity::hsc($name), '<br />';\r
+ }\r
+ \r
+ switch ( $name )\r
+ {\r
+ case 'nucleusskin':\r
+ $this->inData = 1;\r
+ break;\r
+ case 'meta':\r
+ $this->inMeta = 1;\r
+ break;\r
+ case 'info':\r
+ // no action needed\r
+ break;\r
+ case 'skin':\r
+ if ( !$this->inMeta )\r
+ {\r
+ $this->inSkin = 1;\r
+ $this->currentName = $attrs['name'];\r
+ $this->skins[$this->currentName]['type'] = $attrs['type'];\r
+ $this->skins[$this->currentName]['includeMode'] = $attrs['includeMode'];\r
+ $this->skins[$this->currentName]['includePrefix'] = $attrs['includePrefix'];\r
+ $this->skins[$this->currentName]['parts'] = array();\r
+ }\r
+ else\r
+ {\r
+ $this->skins[$attrs['name']] = array();\r
+ $this->skins[$attrs['name']]['parts'] = array();\r
+ }\r
+ break;\r
+ case 'template':\r
+ if ( !$this->inMeta )\r
+ {\r
+ $this->inTemplate = 1;\r
+ $this->currentName = $attrs['name'];\r
+ $this->templates[$this->currentName]['parts'] = array();\r
+ }\r
+ else\r
+ {\r
+ $this->templates[$attrs['name']] = array();\r
+ $this->templates[$attrs['name']]['parts'] = array();\r
+ }\r
+ break;\r
+ case 'description':\r
+ // no action needed\r
+ break;\r
+ case 'part':\r
+ $this->currentPartName = $attrs['name'];\r
+ break;\r
+ default:\r
+ echo _SKINIE_SEELEMENT_UNEXPECTEDTAG . Entity::hsc($name) . '<br />';\r
+ break;\r
+ }\r
+ // character data never contains other tags\r
+ $this->clear_character_data();\r
+ return;\r
+ }\r
+ \r
+ /**\r
+ * Called by the XML parser for each closing tag encountered\r
+ */\r
+ private function end_element($parser, $name)\r
+ {\r
+ if ( $this->debug )\r
+ {\r
+ echo 'END: ' . Entity::hsc($name) . '<br />';\r
+ }\r
+ \r
+ if ( $this->parse_charset != i18n::get_current_charset() )\r
+ {\r
+ $name = i18n::convert($name, $this->parse_charset, i18n::get_current_charset());\r
+ $charset_data = i18n::convert($this->get_character_data(), $this->parse_charset, i18n::get_current_charset());\r
+ }\r
+ else\r
+ {\r
+ $charset_data = $this->get_character_data();\r
+ }\r
+ \r
+ switch ( $name )\r
+ {\r
+ case 'nucleusskin':\r
+ $this->inData = 0;\r
+ $this->allRead = 1;\r
+ break;\r
+ case 'meta':\r
+ $this->inMeta = 0;\r
+ $this->metaDataRead = 1;\r
+ break;\r
+ case 'info':\r
+ $this->info = $charset_data;\r
+ case 'skin':\r
+ if ( !$this->inMeta )\r
+ {\r
+ $this->inSkin = 0;\r
+ }\r
+ break;\r
+ case 'template':\r
+ if ( !$this->inMeta )\r
+ {\r
+ $this->inTemplate = 0;\r
+ }\r
+ break;\r
+ case 'description':\r
+ if ( $this->inSkin )\r
+ {\r
+ $this->skins[$this->currentName]['description'] = $charset_data;\r
+ }\r
+ else\r
+ {\r
+ $this->templates[$this->currentName]['description'] = $charset_data;\r
+ }\r
+ break;\r
+ case 'part':\r
+ if ( $this->inSkin )\r
+ {\r
+ $this->skins[$this->currentName]['parts'][$this->currentPartName] = $charset_data;\r
+ }\r
+ else\r
+ {\r
+ $this->templates[$this->currentName]['parts'][$this->currentPartName] = $charset_data;\r
+ }\r
+ break;\r
+ default:\r
+ echo _SKINIE_SEELEMENT_UNEXPECTEDTAG . Entity::hsc($name) . '<br />';\r
+ break;\r
+ }\r
+ $this->clear_character_data();\r
+ return;\r
+ }\r
+ \r
+ /**\r
+ * Called by XML parser for data inside elements\r
+ */\r
+ private function character_data ($parser, $data)\r
+ {\r
+ if ( $this->debug )\r
+ {\r
+ echo 'NEW DATA: ' . Entity::hsc($data) . '<br />';\r
+ }\r
+ $this->cdata .= $data;\r
+ return;\r
+ }\r
+ \r
+ /**\r
+ * Returns the data collected so far\r
+ */\r
+ private function get_character_data()\r
+ {\r
+ return $this->cdata;\r
+ }\r
+ \r
+ /**\r
+ * Clears the data buffer\r
+ */\r
+ private function clear_character_data()\r
+ {\r
+ $this->cdata = '';\r
+ return;\r
+ }\r
+ \r
+ /**\r
+ * Static method that looks for importable XML files in subdirs of the given dir\r
+ */\r
+ static public function searchForCandidates($dir)\r
+ {\r
+ $candidates = array();\r
+ \r
+ $dirhandle = opendir($dir);\r
+ while ( $filename = readdir($dirhandle) )\r
+ {\r
+ if ( @is_dir($dir . $filename) && ($filename != '.') && ($filename != '..') )\r
+ {\r
+ $xml_file = $dir . $filename . '/skinbackup.xml';\r
+ if ( file_exists($xml_file) && is_readable($xml_file) )\r
+ {\r
+ //$xml_file;\r
+ $candidates[$filename] = $filename;\r
+ }\r
+ \r
+ // backwards compatibility\r
+ $xml_file = $dir . $filename . '/skindata.xml';\r
+ if ( file_exists($xml_file) && is_readable($xml_file) )\r
+ {\r
+ //$xml_file;\r
+ $candidates[$filename] = $filename;\r
+ }\r
+ }\r
+ }\r
+ closedir($dirhandle);\r
+ return $candidates;\r
+ }\r
+}\r
+\r
+class SkinExport\r
+{\r
+ private $templates;\r
+ private $skins;\r
+ private $info;\r
+ \r
+ /**\r
+ * Constructor initializes data structures\r
+ */\r
+ public function __construct()\r
+ {\r
+ // list of templateIDs to export\r
+ $this->templates = array();\r
+ \r
+ // list of skinIDs to export\r
+ $this->skins = array();\r
+ \r
+ // extra info to be in XML file\r
+ $this->info = '';\r
+ }\r
+ \r
+ /**\r
+ * Adds a template to be exported\r
+ *\r
+ * @param id\r
+ * template ID\r
+ * @result false when no such ID exists\r
+ */\r
+ public function addTemplate($id)\r
+ {\r
+ if ( !Template::existsID($id) )\r
+ {\r
+ return 0;\r
+ }\r
+ \r
+ $this->templates[$id] = Template::getNameFromId($id);\r
+ return 1;\r
+ }\r
+ \r
+ /**\r
+ * Adds a skin to be exported\r
+ *\r
+ * @param id\r
+ * skin ID\r
+ * @result false when no such ID exists\r
+ */\r
+ public function addSkin($id)\r
+ {\r
+ if ( !SKIN::existsID($id) )\r
+ {\r
+ return 0;\r
+ }\r
+ \r
+ $this->skins[$id] = SKIN::getNameFromId($id);\r
+ return 1;\r
+ }\r
+ \r
+ /**\r
+ * Sets the extra info to be included in the exported file\r
+ */\r
+ public function setInfo($info)\r
+ {\r
+ $this->info = $info;\r
+ }\r
+ \r
+ /**\r
+ * Outputs the XML contents of the export file\r
+ *\r
+ * @param $setHeaders\r
+ * set to 0 if you don't want to send out headers\r
+ * (optional, default 1)\r
+ */\r
+ public function export($setHeaders = 1)\r
+ {\r
+ if ( $setHeaders )\r
+ {\r
+ // make sure the mimetype is correct, and that the data does not show up\r
+ // in the browser, but gets saved into and XML file (popup download window)\r
+ header('Content-Type: text/xml; charset=' . i18n::get_current_charset());\r
+ header('Content-Disposition: attachment; filename="skinbackup.xml"');\r
+ header('Expires: 0');\r
+ header('Pragma: no-cache');\r
+ }\r
+ \r
+ echo "<nucleusskin>\n";\r
+ \r
+ // meta\r
+ echo "\t<meta>\n";\r
+ // skins\r
+ foreach ( $this->skins as $skinId => $skinName )\r
+ {\r
+ echo "\t\t" . '<skin name="' . Entity::hsc($skinName) . '" />' . "\n";\r
+ }\r
+ // templates\r
+ foreach ( $this->templates as $templateId => $templateName )\r
+ {\r
+ echo "\t\t" . '<template name="' . Entity::hsc($templateName) . '" />' . "\n";\r
+ }\r
+ // extra info\r
+ if ( $this->info )\r
+ {\r
+ echo "\t\t<info><![CDATA[" . $this->info . "]]></info>\n";\r
+ }\r
+ echo "\t</meta>\n\n\n";\r
+ \r
+ // contents skins\r
+ foreach ($this->skins as $skinId => $skinName)\r
+ {\r
+ $skinId = intval($skinId);\r
+ $skinObj = new SKIN($skinId);\r
+ \r
+ echo "\t" . '<skin name="' . Entity::hsc($skinName) . '" type="' . Entity::hsc($skinObj->getContentType()) . '" includeMode="' . Entity::hsc($skinObj->getIncludeMode()) . '" includePrefix="' . Entity::hsc($skinObj->getIncludePrefix()) . '">' . "\n";\r
+ echo "\t\t<description>" . Entity::hsc($skinObj->getDescription()) . "</description>\n";\r
+ \r
+ $res = DB::getResult('SELECT stype, scontent FROM '. sql_table('skin') .' WHERE sdesc=' . $skinId);\r
+ foreach ( $res as $row )\r
+ {\r
+ echo "\t\t" . '<part name="',Entity::hsc($row['stype']) . '">';\r
+ echo '<![CDATA[' . $this->escapeCDATA($row['scontent']) . ']]>';\r
+ echo "</part>\n\n";\r
+ }\r
+ echo "\t</skin>\n\n\n";\r
+ }\r
+ \r
+ // contents templates\r
+ foreach ( $this->templates as $templateId => $templateName )\r
+ {\r
+ $templateId = intval($templateId);\r
+ \r
+ echo "\t" . '<template name="' . Entity::hsc($templateName) . '">' . "\n";\r
+ echo "\t\t<description>" . Entity::hsc(Template::getDesc($templateId)) . "</description>\n";\r
+ \r
+ $res = DB::getResult('SELECT tpartname, tcontent FROM '. sql_table('template') .' WHERE tdesc=' . $templateId);\r
+ foreach ( $res as $row )\r
+ {\r
+ echo "\t\t" . '<part name="' . Entity::hsc($row['tpartname']) . '">';\r
+ echo '<![CDATA[' . $this->escapeCDATA($row['tcontent']) . ']]>';\r
+ echo "</part>\n\n";\r
+ }\r
+ \r
+ echo "\t</template>\n\n\n";\r
+ }\r
+ echo '</nucleusskin>';\r
+ }\r
+ \r
+ /**\r
+ * Escapes CDATA content so it can be included in another CDATA section\r
+ */\r
+ private function escapeCDATA($cdata)\r
+ {\r
+ return preg_replace('/]]>/', ']]]]><![CDATA[>', $cdata);\r
+ }\r
+}\r