skinie.php

Go to the documentation of this file.
00001 <?php
00002 /*
00003  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
00004  * Copyright (C) 2002-2007 The Nucleus Group
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  * (see nucleus/documentation/index.html#license for more info)
00011  */
00022 class SKINIMPORT {
00023 
00024         // hardcoded value (see constructor). When 1, interesting info about the
00025         // parsing process is sent to the output
00026         var $debug;
00027 
00028         // parser/file pointer
00029         var $parser;
00030         var $fp;
00031 
00032         // which data has been read?
00033         var $metaDataRead;
00034         var $allRead;
00035 
00036         // extracted data
00037         var $skins;
00038         var $templates;
00039         var $info;
00040 
00041         // to maintain track of where we are inside the XML file
00042         var $inXml;
00043         var $inData;
00044         var $inMeta;
00045         var $inSkin;
00046         var $inTemplate;
00047         var $currentName;
00048         var $currentPartName;
00049         var $cdata;
00050 
00051 
00052 
00056         function SKINIMPORT() {
00057                 // disable magic_quotes_runtime if it's turned on
00058                 set_magic_quotes_runtime(0);
00059 
00060                 // debugging mode?
00061                 $this->debug = 0;
00062 
00063                 $this->reset();
00064 
00065         }
00066 
00067         function reset() {
00068                 if ($this->parser)
00069                         xml_parser_free($this->parser);
00070 
00071                 // XML file pointer
00072                 $this->fp = 0;
00073 
00074                 // which data has been read?
00075                 $this->metaDataRead = 0;
00076                 $this->allRead = 0;
00077 
00078                 // to maintain track of where we are inside the XML file
00079                 $this->inXml = 0;
00080                 $this->inData = 0;
00081                 $this->inMeta = 0;
00082                 $this->inSkin = 0;
00083                 $this->inTemplate = 0;
00084                 $this->currentName = '';
00085                 $this->currentPartName = '';
00086 
00087                 // character data pile
00088                 $this->cdata = '';
00089 
00090                 // list of skinnames and templatenames (will be array of array)
00091                 $this->skins = array();
00092                 $this->templates = array();
00093 
00094                 // extra info included in the XML files (e.g. installation notes)
00095                 $this->info = '';
00096 
00097                 // init XML parser
00098                 $this->parser = xml_parser_create();
00099                 xml_set_object($this->parser, $this);
00100                 xml_set_element_handler($this->parser, 'startElement', 'endElement');
00101                 xml_set_character_data_handler($this->parser, 'characterData');
00102                 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
00103 
00104         }
00105 
00114         function readFile($filename, $metaOnly = 0) {
00115                 // open file
00116                 $this->fp = @fopen($filename, 'r');
00117                 if (!$this->fp) return 'Failed to open file/URL';
00118 
00119                 // here we go!
00120                 $this->inXml = 1;
00121 
00122                 $tempbuffer = null;
00123 
00124                 while (!feof($this->fp)) {
00125                         $tempbuffer .= fread($this->fp, 4096);
00126                 }
00127                 fclose($this->fp);
00128 
00129 /*
00130         [2004-08-04] dekarma - Took this out since it messes up good XML if it has skins/templates
00131                                                    with CDATA sections. need to investigate consequences.
00132                                                    see bug [ 999914 ] Import fails (multiple skins in XML/one of them with CDATA)
00133 
00134                 // backwards compatibility with the non-wellformed skinbackup.xml files
00135                 // generated by v2/v3 (when CDATA sections were present in skins)
00136                 // split up those CDATA sections into multiple ones
00137                 $tempbuffer = preg_replace_callback(
00138                         "/(<!\[CDATA\[[^]]*?<!\[CDATA\[[^]]*)((?:\]\].*?<!\[CDATA.*?)*)(\]\])(.*\]\])/ms",
00139                         create_function(
00140                                 '$matches',
00141                                 'return $matches[1] . preg_replace("/(\]\])(.*?<!\[CDATA)/ms","]]]]><![CDATA[$2",$matches[2])."]]]]><![CDATA[".$matches[4];'
00142                         ),
00143                         $tempbuffer
00144                 );
00145 */
00146                 $temp = tmpfile();
00147                 fwrite($temp, $tempbuffer);
00148                 rewind($temp);
00149 
00150                 while ( ($buffer = fread($temp, 4096) ) && (!$metaOnly || ($metaOnly && !$this->metaDataRead))) {
00151                         $err = xml_parse( $this->parser, $buffer, feof($temp) );
00152                         if (!$err && $this->debug)
00153                                 echo 'ERROR: ', xml_error_string(xml_get_error_code($this->parser)), '<br />';
00154                 }
00155 
00156                 // all done
00157                 $this->inXml = 0;
00158                 fclose($temp);
00159         }
00160 
00164         function getSkinNames() {
00165                 return array_keys($this->skins);
00166         }
00167 
00171         function getTemplateNames() {
00172                 return array_keys($this->templates);
00173         }
00174 
00178         function getInfo() {
00179                 return $this->info;
00180         }
00181 
00189         function writeToDatabase($allowOverwrite = 0) {
00190                 $existingSkins = $this->checkSkinNameClashes();
00191                 $existingTemplates = $this->checkTemplateNameClashes();
00192 
00193                 // if not allowed to overwrite, check if any nameclashes exists
00194                 if (!$allowOverwrite) {
00195                         if ((sizeof($existingSkins) > 0) || (sizeof($existingTemplates) > 0))
00196                                 return 'Name clashes detected, re-run with allowOverwrite = 1 to force overwrite';
00197                 }
00198 
00199                 foreach ($this->skins as $skinName => $data) {
00200                         // 1. if exists: delete all part data, update desc data
00201                         //    if not exists: create desc
00202                         if (in_array($skinName, $existingSkins)) {
00203                                 $skinObj = SKIN::createFromName($skinName);
00204 
00205                                 // delete all parts of the skin
00206                                 $skinObj->deleteAllParts();
00207 
00208                                 // update general info
00209                                 $skinObj->updateGeneralInfo($skinName, $data['description'], $data['type'], $data['includeMode'], $data['includePrefix']);
00210                         } else {
00211                                 $skinid = SKIN::createNew($skinName, $data['description'], $data['type'], $data['includeMode'], $data['includePrefix']);
00212                                 $skinObj = new SKIN($skinid);
00213                         }
00214 
00215                         // 2. add parts
00216                         foreach ($data['parts'] as $partName => $partContent) {
00217                                 $skinObj->update($partName, $partContent);
00218                         }
00219                 }
00220 
00221                 foreach ($this->templates as $templateName => $data) {
00222                         // 1. if exists: delete all part data, update desc data
00223                         //    if not exists: create desc
00224                         if (in_array($templateName, $existingTemplates)) {
00225                                 $templateObj = TEMPLATE::createFromName($templateName);
00226 
00227                                 // delete all parts of the template
00228                                 $templateObj->deleteAllParts();
00229 
00230                                 // update general info
00231                                 $templateObj->updateGeneralInfo($templateName, $data['description']);
00232                         } else {
00233                                 $templateid = TEMPLATE::createNew($templateName, $data['description']);
00234                                 $templateObj = new TEMPLATE($templateid);
00235                         }
00236 
00237                         // 2. add parts
00238                         foreach ($data['parts'] as $partName => $partContent) {
00239                                 $templateObj->update($partName, $partContent);
00240                         }
00241                 }
00242 
00243 
00244         }
00245 
00249         function checkSkinNameClashes() {
00250                 $clashes = array();
00251 
00252                 foreach ($this->skins as $skinName => $data) {
00253                         if (SKIN::exists($skinName))
00254                                 array_push($clashes, $skinName);
00255                 }
00256 
00257                 return $clashes;
00258         }
00259 
00264         function checkTemplateNameClashes() {
00265                 $clashes = array();
00266 
00267                 foreach ($this->templates as $templateName => $data) {
00268                         if (TEMPLATE::exists($templateName))
00269                                 array_push($clashes, $templateName);
00270                 }
00271 
00272                 return $clashes;
00273         }
00274 
00278         function startElement($parser, $name, $attrs) {
00279                 foreach($attrs as $key=>$value) $attrs[$key]=htmlspecialchars($value,ENT_QUOTES);
00280 
00281                 if ($this->debug) echo 'START: ', htmlspecialchars($name), '<br />';
00282 
00283                 switch ($name) {
00284                         case 'nucleusskin':
00285                                 $this->inData = 1;
00286                                 break;
00287                         case 'meta':
00288                                 $this->inMeta = 1;
00289                                 break;
00290                         case 'info':
00291                                 // no action needed
00292                                 break;
00293                         case 'skin':
00294                                 if (!$this->inMeta) {
00295                                         $this->inSkin = 1;
00296                                         $this->currentName = $attrs['name'];
00297                                         $this->skins[$this->currentName]['type'] = $attrs['type'];
00298                                         $this->skins[$this->currentName]['includeMode'] = $attrs['includeMode'];
00299                                         $this->skins[$this->currentName]['includePrefix'] = $attrs['includePrefix'];
00300                                         $this->skins[$this->currentName]['parts'] = array();
00301                                 } else {
00302                                         $this->skins[$attrs['name']] = array();
00303                                         $this->skins[$attrs['name']]['parts'] = array();
00304                                 }
00305                                 break;
00306                         case 'template':
00307                                 if (!$this->inMeta) {
00308                                         $this->inTemplate = 1;
00309                                         $this->currentName = $attrs['name'];
00310                                         $this->templates[$this->currentName]['parts'] = array();
00311                                 } else {
00312                                         $this->templates[$attrs['name']] = array();
00313                                         $this->templates[$attrs['name']]['parts'] = array();
00314                                 }
00315                                 break;
00316                         case 'description':
00317                                 // no action needed
00318                                 break;
00319                         case 'part':
00320                                 $this->currentPartName = $attrs['name'];
00321                                 break;
00322                         default:
00323                                 echo 'UNEXPECTED TAG: ' , htmlspecialchars($name) , '<br />';
00324                                 break;
00325                 }
00326 
00327                 // character data never contains other tags
00328                 $this->clearCharacterData();
00329 
00330         }
00331 
00335         function endElement($parser, $name) {
00336                 if ($this->debug) echo 'END: ', htmlspecialchars($name), '<br />';
00337 
00338                 switch ($name) {
00339                         case 'nucleusskin':
00340                                 $this->inData = 0;
00341                                 $this->allRead = 1;
00342                                 break;
00343                         case 'meta':
00344                                 $this->inMeta = 0;
00345                                 $this->metaDataRead = 1;
00346                                 break;
00347                         case 'info':
00348                                 $this->info = $this->getCharacterData();
00349                         case 'skin':
00350                                 if (!$this->inMeta) $this->inSkin = 0;
00351                                 break;
00352                         case 'template':
00353                                 if (!$this->inMeta) $this->inTemplate = 0;
00354                                 break;
00355                         case 'description':
00356                                 if ($this->inSkin) {
00357                                         $this->skins[$this->currentName]['description'] = $this->getCharacterData();
00358                                 } else {
00359                                         $this->templates[$this->currentName]['description'] = $this->getCharacterData();
00360                                 }
00361                                 break;
00362                         case 'part':
00363                                 if ($this->inSkin) {
00364                                         $this->skins[$this->currentName]['parts'][$this->currentPartName] = $this->getCharacterData();
00365                                 } else {
00366                                         $this->templates[$this->currentName]['parts'][$this->currentPartName] = $this->getCharacterData();
00367                                 }
00368                                 break;
00369                         default:
00370                                 echo 'UNEXPECTED TAG: ' , htmlspecialchars($name), '<br />';
00371                                 break;
00372                 }
00373                 $this->clearCharacterData();
00374 
00375         }
00376 
00380         function characterData ($parser, $data) {
00381                 if ($this->debug) echo 'NEW DATA: ', htmlspecialchars($data), '<br />';
00382                 $this->cdata .= $data;
00383         }
00384 
00388         function getCharacterData() {
00389                 return $this->cdata;
00390         }
00391 
00395         function clearCharacterData() {
00396                 $this->cdata = '';
00397         }
00398 
00402         function searchForCandidates($dir) {
00403                 $candidates = array();
00404 
00405                 $dirhandle = opendir($dir);
00406                 while ($filename = readdir($dirhandle)) {
00407                         if (@is_dir($dir . $filename) && ($filename != '.') && ($filename != '..')) {
00408                                 $xml_file = $dir . $filename . '/skinbackup.xml';
00409                                 if (file_exists($xml_file) && is_readable($xml_file)) {
00410                                         $candidates[$filename] = $filename; //$xml_file;
00411                                 }
00412 
00413                                 // backwards compatibility
00414                                 $xml_file = $dir . $filename . '/skindata.xml';
00415                                 if (file_exists($xml_file) && is_readable($xml_file)) {
00416                                         $candidates[$filename] = $filename; //$xml_file;
00417                                 }
00418                         }
00419                 }
00420                 closedir($dirhandle);
00421 
00422                 return $candidates;
00423 
00424         }
00425 
00426 
00427 }
00428 
00429 
00430 class SKINEXPORT {
00431 
00432         var $templates;
00433         var $skins;
00434         var $info;
00435 
00439         function SKINEXPORT() {
00440                 // list of templateIDs to export
00441                 $this->templates = array();
00442 
00443                 // list of skinIDs to export
00444                 $this->skins = array();
00445 
00446                 // extra info to be in XML file
00447                 $this->info = '';
00448         }
00449 
00457         function addTemplate($id) {
00458                 if (!TEMPLATE::existsID($id)) return 0;
00459 
00460                 $this->templates[$id] = TEMPLATE::getNameFromId($id);
00461 
00462                 return 1;
00463         }
00464 
00472         function addSkin($id) {
00473                 if (!SKIN::existsID($id)) return 0;
00474 
00475                 $this->skins[$id] = SKIN::getNameFromId($id);
00476 
00477                 return 1;
00478         }
00479 
00483         function setInfo($info) {
00484                 $this->info = $info;
00485         }
00486 
00487 
00495         function export($setHeaders = 1) {
00496                 if ($setHeaders) {
00497                         // make sure the mimetype is correct, and that the data does not show up
00498                         // in the browser, but gets saved into and XML file (popup download window)
00499                         header('Content-Type: text/xml');
00500                         header('Content-Disposition: attachment; filename="skinbackup.xml"');
00501                         header('Expires: 0');
00502                         header('Pragma: no-cache');
00503                 }
00504 
00505                 echo "<nucleusskin>\n";
00506 
00507                 // meta
00508                 echo "\t<meta>\n";
00509                         // skins
00510                         foreach ($this->skins as $skinId => $skinName) {
00511                                 echo "\t\t", '<skin name="',htmlspecialchars($skinName),'" />',"\n";
00512                         }
00513                         // templates
00514                         foreach ($this->templates as $templateId => $templateName) {
00515                                 echo "\t\t", '<template name="',htmlspecialchars($templateName),'" />',"\n";
00516                         }
00517                         // extra info
00518                         if ($this->info)
00519                                 echo "\t\t<info><![CDATA[",$this->info,"]]></info>\n";
00520                 echo "\t</meta>\n\n\n";
00521 
00522                 // contents skins
00523                 foreach ($this->skins as $skinId => $skinName) {
00524                         $skinId = intval($skinId);
00525                         $skinObj = new SKIN($skinId);
00526 
00527                         echo "\t", '<skin name="',htmlspecialchars($skinName),'" type="',htmlspecialchars($skinObj->getContentType()),'" includeMode="',htmlspecialchars($skinObj->getIncludeMode()),'" includePrefix="',htmlspecialchars($skinObj->getIncludePrefix()),'">',"\n";
00528 
00529                         echo "\t\t", '<description>',htmlspecialchars($skinObj->getDescription()),'</description>',"\n";
00530 
00531                         $res = sql_query('SELECT stype, scontent FROM '.sql_table('skin').' WHERE sdesc='.$skinId);
00532                         while ($partObj = mysql_fetch_object($res)) {
00533                                 echo "\t\t",'<part name="',htmlspecialchars($partObj->stype),'">';
00534                                 echo '<![CDATA[', $this->escapeCDATA($partObj->scontent),']]>';
00535                                 echo "</part>\n\n";
00536                         }
00537 
00538                         echo "\t</skin>\n\n\n";
00539                 }
00540 
00541                 // contents templates
00542                 foreach ($this->templates as $templateId => $templateName) {
00543                         $templateId = intval($templateId);
00544 
00545                         echo "\t",'<template name="',htmlspecialchars($templateName),'">',"\n";
00546 
00547                         echo "\t\t",'<description>',htmlspecialchars(TEMPLATE::getDesc($templateId)),'</description>',"\n";
00548 
00549                         $res = sql_query('SELECT tpartname, tcontent FROM '.sql_table('template').' WHERE tdesc='.$templateId);
00550                         while ($partObj = mysql_fetch_object($res)) {
00551                                 echo "\t\t",'<part name="',htmlspecialchars($partObj->tpartname),'">';
00552                                 echo '<![CDATA[', $this->escapeCDATA($partObj->tcontent) ,']]>';
00553                                 echo '</part>',"\n\n";
00554                         }
00555 
00556                         echo "\t</template>\n\n\n";
00557                 }
00558 
00559                 echo '</nucleusskin>';
00560         }
00561 
00565         function escapeCDATA($cdata)
00566         {
00567                 return preg_replace('/]]>/', ']]]]><![CDATA[>', $cdata);
00568 
00569         }
00570 }
00571 
00572 ?>



Generated on Wed Jun 25 17:25:59 2008 by  doxygen 1.5.5