[ Index ]

PHP Cross Reference of Nucleus CMS v3.51 code documentation

title

Body

[close]

/nucleus/libs/ -> skinie.php (source)

   1  <?php
   2  /*

   3   * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)

   4   * Copyright (C) 2002-2009 The Nucleus Group

   5   *

   6   * This program is free software; you can redistribute it and/or

   7   * modify it under the terms of the GNU General Public License

   8   * as published by the Free Software Foundation; either version 2

   9   * of the License, or (at your option) any later version.

  10   * (see nucleus/documentation/index.html#license for more info)

  11   */
  12  /**

  13   *    This class contains two classes that can be used for importing and

  14   *    exporting Nucleus skins: SKINIMPORT and SKINEXPORT

  15   *

  16   * @license http://nucleuscms.org/license.txt GNU General Public License

  17   * @copyright Copyright (C) 2002-2009 The Nucleus Group

  18   * @version $Id: skinie.php 1389 2009-07-18 08:50:07Z shizuki $

  19   */
  20  
  21  class SKINIMPORT {
  22  
  23      // hardcoded value (see constructor). When 1, interesting info about the

  24      // parsing process is sent to the output

  25      var $debug;
  26  
  27      // parser/file pointer

  28      var $parser;
  29      var $fp;
  30  
  31      // which data has been read?

  32      var $metaDataRead;
  33      var $allRead;
  34  
  35      // extracted data

  36      var $skins;
  37      var $templates;
  38      var $info;
  39  
  40      // to maintain track of where we are inside the XML file

  41      var $inXml;
  42      var $inData;
  43      var $inMeta;
  44      var $inSkin;
  45      var $inTemplate;
  46      var $currentName;
  47      var $currentPartName;
  48      var $cdata;
  49  
  50  
  51  
  52      /**

  53       * constructor initializes data structures

  54       */
  55  	function SKINIMPORT() {
  56          // disable magic_quotes_runtime if it's turned on

  57          set_magic_quotes_runtime(0);
  58  
  59          // debugging mode?

  60          $this->debug = 0;
  61  
  62          $this->reset();
  63  
  64      }
  65  
  66  	function reset() {
  67          if ($this->parser)
  68              xml_parser_free($this->parser);
  69  
  70          // XML file pointer

  71          $this->fp = 0;
  72  
  73          // which data has been read?

  74          $this->metaDataRead = 0;
  75          $this->allRead = 0;
  76  
  77          // to maintain track of where we are inside the XML file

  78          $this->inXml = 0;
  79          $this->inData = 0;
  80          $this->inMeta = 0;
  81          $this->inSkin = 0;
  82          $this->inTemplate = 0;
  83          $this->currentName = '';
  84          $this->currentPartName = '';
  85  
  86          // character data pile

  87          $this->cdata = '';
  88  
  89          // list of skinnames and templatenames (will be array of array)

  90          $this->skins = array();
  91          $this->templates = array();
  92  
  93          // extra info included in the XML files (e.g. installation notes)

  94          $this->info = '';
  95  
  96          // init XML parser

  97          $this->parser = xml_parser_create();
  98          xml_set_object($this->parser, $this);
  99          xml_set_element_handler($this->parser, 'startElement', 'endElement');
 100          xml_set_character_data_handler($this->parser, 'characterData');
 101          xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
 102  
 103      }
 104  
 105      /**

 106       * Reads an XML file into memory

 107       *

 108       * @param $filename

 109       *        Which file to read

 110       * @param $metaOnly

 111       *        Set to 1 when only the metadata needs to be read (optional, default 0)

 112       */
 113  	function readFile($filename, $metaOnly = 0) {
 114          // open file

 115          $this->fp = @fopen($filename, 'r');
 116          if (!$this->fp) {
 117              return _SKINIE_ERROR_FAILEDOPEN_FILEURL;
 118          }
 119  
 120          // here we go!

 121          $this->inXml = 1;
 122  
 123          $tempbuffer = null;
 124  
 125          while (!feof($this->fp)) {
 126              $tempbuffer .= fread($this->fp, 4096);
 127          }
 128          fclose($this->fp);
 129  
 130  /*

 131      [2004-08-04] dekarma - Took this out since it messes up good XML if it has skins/templates

 132                             with CDATA sections. need to investigate consequences.

 133                             see bug [ 999914 ] Import fails (multiple skins in XML/one of them with CDATA)

 134  

 135          // backwards compatibility with the non-wellformed skinbackup.xml files

 136          // generated by v2/v3 (when CDATA sections were present in skins)

 137          // split up those CDATA sections into multiple ones

 138          $tempbuffer = preg_replace_callback(

 139              "/(<!\[CDATA\[[^]]*?<!\[CDATA\[[^]]*)((?:\]\].*?<!\[CDATA.*?)*)(\]\])(.*\]\])/ms",

 140              create_function(

 141                  '$matches',

 142                  'return $matches[1] . preg_replace("/(\]\])(.*?<!\[CDATA)/ms","]]]]><![CDATA[$2",$matches[2])."]]]]><![CDATA[".$matches[4];'

 143              ),

 144              $tempbuffer

 145          );

 146  */
 147          $temp = tmpfile();
 148          fwrite($temp, $tempbuffer);
 149          rewind($temp);
 150  
 151          while ( ($buffer = fread($temp, 4096) ) && (!$metaOnly || ($metaOnly && !$this->metaDataRead))) {
 152              $err = xml_parse( $this->parser, $buffer, feof($temp) );
 153              if (!$err && $this->debug) {
 154                  echo 'ERROR: ', xml_error_string(xml_get_error_code($this->parser)), '<br />';
 155              }
 156          }
 157  
 158          // all done

 159          $this->inXml = 0;
 160          fclose($temp);
 161      }
 162  
 163      /**

 164       * Returns the list of skin names

 165       */
 166  	function getSkinNames() {
 167          return array_keys($this->skins);
 168      }
 169  
 170      /**

 171       * Returns the list of template names

 172       */
 173  	function getTemplateNames() {
 174          return array_keys($this->templates);
 175      }
 176  
 177      /**

 178       * Returns the extra information included in the XML file

 179       */
 180  	function getInfo() {
 181          return $this->info;
 182      }
 183  
 184      /**

 185       * Writes the skins and templates to the database

 186       *

 187       * @param $allowOverwrite

 188       *        set to 1 when allowed to overwrite existing skins with the same name

 189       *        (default = 0)

 190       */
 191  	function writeToDatabase($allowOverwrite = 0) {
 192          $existingSkins = $this->checkSkinNameClashes();
 193          $existingTemplates = $this->checkTemplateNameClashes();
 194  
 195          // if not allowed to overwrite, check if any nameclashes exists

 196          if (!$allowOverwrite) {
 197              if ((sizeof($existingSkins) > 0) || (sizeof($existingTemplates) > 0)) {
 198                  return _SKINIE_NAME_CLASHES_DETECTED;
 199              }
 200          }
 201  
 202          foreach ($this->skins as $skinName => $data) {
 203              // 1. if exists: delete all part data, update desc data

 204              //    if not exists: create desc

 205              if (in_array($skinName, $existingSkins)) {
 206                  $skinObj = SKIN::createFromName($skinName);
 207  
 208                  // delete all parts of the skin

 209                  $skinObj->deleteAllParts();
 210  
 211                  // update general info

 212                  $skinObj->updateGeneralInfo(
 213                      $skinName,
 214                      $data['description'],
 215                      $data['type'],
 216                      $data['includeMode'],
 217                      $data['includePrefix']
 218                  );
 219              } else {
 220                  $skinid = SKIN::createNew(
 221                      $skinName,
 222                      $data['description'],
 223                      $data['type'],
 224                      $data['includeMode'],
 225                      $data['includePrefix']
 226                  );
 227                  $skinObj = new SKIN($skinid);
 228              }
 229  
 230              // 2. add parts

 231              foreach ($data['parts'] as $partName => $partContent) {
 232                  $skinObj->update($partName, $partContent);
 233              }
 234          }
 235  
 236          foreach ($this->templates as $templateName => $data) {
 237              // 1. if exists: delete all part data, update desc data

 238              //    if not exists: create desc

 239              if (in_array($templateName, $existingTemplates)) {
 240                  $templateObj = TEMPLATE::createFromName($templateName);
 241  
 242                  // delete all parts of the template

 243                  $templateObj->deleteAllParts();
 244  
 245                  // update general info

 246                  $templateObj->updateGeneralInfo($templateName, $data['description']);
 247              } else {
 248                  $templateid = TEMPLATE::createNew($templateName, $data['description']);
 249                  $templateObj = new TEMPLATE($templateid);
 250              }
 251  
 252              // 2. add parts

 253              foreach ($data['parts'] as $partName => $partContent) {
 254                  $templateObj->update($partName, $partContent);
 255              }
 256          }
 257  
 258  
 259      }
 260  
 261      /**

 262        * returns an array of all the skin nameclashes (empty array when no name clashes)

 263        */
 264  	function checkSkinNameClashes() {
 265          $clashes = array();
 266  
 267          foreach ($this->skins as $skinName => $data) {
 268              if (SKIN::exists($skinName)) {
 269                  array_push($clashes, $skinName);
 270              }
 271          }
 272  
 273          return $clashes;
 274      }
 275  
 276      /**

 277        * returns an array of all the template nameclashes

 278        * (empty array when no name clashes)

 279        */
 280  	function checkTemplateNameClashes() {
 281          $clashes = array();
 282  
 283          foreach ($this->templates as $templateName => $data) {
 284              if (TEMPLATE::exists($templateName)) {
 285                  array_push($clashes, $templateName);
 286              }
 287          }
 288  
 289          return $clashes;
 290      }
 291  
 292      /**

 293       * Called by XML parser for each new start element encountered

 294       */
 295  	function startElement($parser, $name, $attrs) {
 296          foreach($attrs as $key=>$value) {
 297              $attrs[$key]=htmlspecialchars($value,ENT_QUOTES);
 298          }
 299  
 300          if ($this->debug) {
 301              echo 'START: ', htmlspecialchars($name), '<br />';
 302          }
 303  
 304          switch ($name) {
 305              case 'nucleusskin':
 306                  $this->inData = 1;
 307                  break;
 308              case 'meta':
 309                  $this->inMeta = 1;
 310                  break;
 311              case 'info':
 312                  // no action needed

 313                  break;
 314              case 'skin':
 315                  if (!$this->inMeta) {
 316                      $this->inSkin = 1;
 317                      $this->currentName = $attrs['name'];
 318                      $this->skins[$this->currentName]['type'] = $attrs['type'];
 319                      $this->skins[$this->currentName]['includeMode'] = $attrs['includeMode'];
 320                      $this->skins[$this->currentName]['includePrefix'] = $attrs['includePrefix'];
 321                      $this->skins[$this->currentName]['parts'] = array();
 322                  } else {
 323                      $this->skins[$attrs['name']] = array();
 324                      $this->skins[$attrs['name']]['parts'] = array();
 325                  }
 326                  break;
 327              case 'template':
 328                  if (!$this->inMeta) {
 329                      $this->inTemplate = 1;
 330                      $this->currentName = $attrs['name'];
 331                      $this->templates[$this->currentName]['parts'] = array();
 332                  } else {
 333                      $this->templates[$attrs['name']] = array();
 334                      $this->templates[$attrs['name']]['parts'] = array();
 335                  }
 336                  break;
 337              case 'description':
 338                  // no action needed

 339                  break;
 340              case 'part':
 341                  $this->currentPartName = $attrs['name'];
 342                  break;
 343              default:
 344                  echo _SKINIE_SEELEMENT_UNEXPECTEDTAG . htmlspecialchars($name, ENT_QUOTES) , '<br />';
 345                  break;
 346          }
 347  
 348          // character data never contains other tags

 349          $this->clearCharacterData();
 350  
 351      }
 352  
 353      /**

 354        * Called by the XML parser for each closing tag encountered

 355        */
 356  	function endElement($parser, $name) {
 357          if ($this->debug) {
 358              echo 'END: ' . htmlspecialchars($name, ENT_QUOTES) . '<br />';
 359          }
 360  
 361          switch ($name) {
 362              case 'nucleusskin':
 363                  $this->inData = 0;
 364                  $this->allRead = 1;
 365                  break;
 366              case 'meta':
 367                  $this->inMeta = 0;
 368                  $this->metaDataRead = 1;
 369                  break;
 370              case 'info':
 371                  $this->info = $this->getCharacterData();
 372              case 'skin':
 373                  if (!$this->inMeta) {
 374                      $this->inSkin = 0;
 375                  }
 376                  break;
 377              case 'template':
 378                  if (!$this->inMeta) {
 379                      $this->inTemplate = 0;
 380                  }
 381                  break;
 382              case 'description':
 383                  if ($this->inSkin) {
 384                      $this->skins[$this->currentName]['description'] = $this->getCharacterData();
 385                  } else {
 386                      $this->templates[$this->currentName]['description'] = $this->getCharacterData();
 387                  }
 388                  break;
 389              case 'part':
 390                  if ($this->inSkin) {
 391                      $this->skins[$this->currentName]['parts'][$this->currentPartName] = $this->getCharacterData();
 392                  } else {
 393                      $this->templates[$this->currentName]['parts'][$this->currentPartName] = $this->getCharacterData();
 394                  }
 395                  break;
 396              default:
 397                  echo _SKINIE_SEELEMENT_UNEXPECTEDTAG . htmlspecialchars($name, ENT_QUOTES) . '<br />';
 398                  break;
 399          }
 400          $this->clearCharacterData();
 401  
 402      }
 403  
 404      /**

 405       * Called by XML parser for data inside elements

 406       */
 407  	function characterData ($parser, $data) {
 408          if ($this->debug) {
 409              echo 'NEW DATA: ' . htmlspecialchars($data, ENT_QUOTES) . '<br />';
 410          }
 411          $this->cdata .= $data;
 412      }
 413  
 414      /**

 415       * Returns the data collected so far

 416       */
 417  	function getCharacterData() {
 418          return $this->cdata;
 419      }
 420  
 421      /**

 422       * Clears the data buffer

 423       */
 424  	function clearCharacterData() {
 425          $this->cdata = '';
 426      }
 427  
 428      /**

 429       * Static method that looks for importable XML files in subdirs of the given dir

 430       */
 431  	function searchForCandidates($dir) {
 432          $candidates = array();
 433  
 434          $dirhandle = opendir($dir);
 435          while ($filename = readdir($dirhandle)) {
 436              if (@is_dir($dir . $filename) && ($filename != '.') && ($filename != '..')) {
 437                  $xml_file = $dir . $filename . '/skinbackup.xml';
 438                  if (file_exists($xml_file) && is_readable($xml_file)) {
 439                      $candidates[$filename] = $filename; //$xml_file;

 440                  }
 441  
 442                  // backwards compatibility

 443                  $xml_file = $dir . $filename . '/skindata.xml';
 444                  if (file_exists($xml_file) && is_readable($xml_file)) {
 445                      $candidates[$filename] = $filename; //$xml_file;

 446                  }
 447              }
 448          }
 449          closedir($dirhandle);
 450  
 451          return $candidates;
 452  
 453      }
 454  
 455  
 456  }
 457  
 458  
 459  class SKINEXPORT {
 460  
 461      var $templates;
 462      var $skins;
 463      var $info;
 464  
 465      /**

 466       * Constructor initializes data structures

 467       */
 468  	function SKINEXPORT() {
 469          // list of templateIDs to export

 470          $this->templates = array();
 471  
 472          // list of skinIDs to export

 473          $this->skins = array();
 474  
 475          // extra info to be in XML file

 476          $this->info = '';
 477      }
 478  
 479      /**

 480       * Adds a template to be exported

 481       *

 482       * @param id

 483       *        template ID

 484       * @result false when no such ID exists

 485       */
 486  	function addTemplate($id) {
 487          if (!TEMPLATE::existsID($id)) {
 488              return 0;
 489          }
 490  
 491  
 492          $this->templates[$id] = TEMPLATE::getNameFromId($id);
 493  
 494          return 1;
 495      }
 496  
 497      /**

 498       * Adds a skin to be exported

 499       *

 500       * @param id

 501       *        skin ID

 502       * @result false when no such ID exists

 503       */
 504  	function addSkin($id) {
 505          if (!SKIN::existsID($id)) {
 506              return 0;
 507          }
 508  
 509          $this->skins[$id] = SKIN::getNameFromId($id);
 510  
 511          return 1;
 512      }
 513  
 514      /**

 515       * Sets the extra info to be included in the exported file

 516       */
 517  	function setInfo($info) {
 518          $this->info = $info;
 519      }
 520  
 521  
 522      /**

 523       * Outputs the XML contents of the export file

 524       *

 525       * @param $setHeaders

 526       *        set to 0 if you don't want to send out headers

 527       *        (optional, default 1)

 528       */
 529  	function export($setHeaders = 1) {
 530          if ($setHeaders) {
 531              // make sure the mimetype is correct, and that the data does not show up

 532              // in the browser, but gets saved into and XML file (popup download window)

 533              header('Content-Type: text/xml');
 534              header('Content-Disposition: attachment; filename="skinbackup.xml"');
 535              header('Expires: 0');
 536              header('Pragma: no-cache');
 537          }
 538  
 539          echo "<nucleusskin>\n";
 540  
 541          // meta

 542          echo "\t<meta>\n";
 543              // skins

 544              foreach ($this->skins as $skinId => $skinName) {
 545                  echo "\t\t", '<skin name="',htmlspecialchars($skinName, ENT_QUOTES),'" />',"\n";
 546              }
 547              // templates

 548              foreach ($this->templates as $templateId => $templateName) {
 549                  echo "\t\t", '<template name="',htmlspecialchars($templateName, ENT_QUOTES),'" />',"\n";
 550              }
 551              // extra info

 552              if ($this->info)
 553                  echo "\t\t<info><![CDATA[",$this->info,"]]></info>\n";
 554          echo "\t</meta>\n\n\n";
 555  
 556          // contents skins

 557          foreach ($this->skins as $skinId => $skinName) {
 558              $skinId = intval($skinId);
 559              $skinObj = new SKIN($skinId);
 560  
 561              echo "\t", '<skin name="',htmlspecialchars($skinName),'" type="',htmlspecialchars($skinObj->getContentType()),'" includeMode="',htmlspecialchars($skinObj->getIncludeMode()),'" includePrefix="',htmlspecialchars($skinObj->getIncludePrefix()),'">',"\n";
 562  
 563              echo "\t\t", '<description>',htmlspecialchars($skinObj->getDescription()),'</description>',"\n";
 564  
 565              $res = sql_query('SELECT stype, scontent FROM '.sql_table('skin').' WHERE sdesc='.$skinId);
 566              while ($partObj = sql_fetch_object($res)) {
 567                  echo "\t\t",'<part name="',htmlspecialchars($partObj->stype),'">';
 568                  echo '<![CDATA[', $this->escapeCDATA($partObj->scontent),']]>';
 569                  echo "</part>\n\n";
 570              }
 571  
 572              echo "\t</skin>\n\n\n";
 573          }
 574  
 575          // contents templates

 576          foreach ($this->templates as $templateId => $templateName) {
 577              $templateId = intval($templateId);
 578  
 579              echo "\t",'<template name="',htmlspecialchars($templateName),'">',"\n";
 580  
 581              echo "\t\t",'<description>',htmlspecialchars(TEMPLATE::getDesc($templateId)),'</description>',"\n";
 582  
 583              $res = sql_query('SELECT tpartname, tcontent FROM '.sql_table('template').' WHERE tdesc='.$templateId);
 584              while ($partObj = sql_fetch_object($res)) {
 585                  echo "\t\t",'<part name="',htmlspecialchars($partObj->tpartname),'">';
 586                  echo '<![CDATA[', $this->escapeCDATA($partObj->tcontent) ,']]>';
 587                  echo '</part>',"\n\n";
 588              }
 589  
 590              echo "\t</template>\n\n\n";
 591          }
 592  
 593          echo '</nucleusskin>';
 594      }
 595  
 596      /**

 597       * Escapes CDATA content so it can be included in another CDATA section

 598       */
 599  	function escapeCDATA($cdata)
 600      {
 601          return preg_replace('/]]>/', ']]]]><![CDATA[>', $cdata);
 602  
 603      }
 604  }
 605  
 606  ?>


Generated: Sun Aug 1 03:56:06 2010
Open Source related documentation for developers.