| [ Index ] |
PHP Cross Reference of Nucleus CMS v3.51 code documentation |
[Summary view] [Print] [Text view]
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 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Sun Aug 1 03:56:06 2010 |