OSDN Git Service

This commit was generated by cvs2svn to compensate for changes in r4,
[nucleus-jp/nucleus-jp-ancient.git] / utf8 / nucleus / libs / skinie.php
1 <?php
2 /**
3   * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
4   * Copyright (C) 2002-2004 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   *     This class contains two classes that can be used for importing and 
13   *     exporting Nucleus skins: SKINIMPORT and SKINEXPORT
14   *
15   * $Id: skinie.php,v 1.1.1.1 2005-02-28 07:14:53 kimitake Exp $
16   */
17
18 class SKINIMPORT {
19
20         // hardcoded value (see constructor). When 1, interesting info about the
21         // parsing process is sent to the output
22         var $debug;
23         
24         // parser/file pointer
25         var $parser;
26         var $fp;
27         
28         // which data has been read?
29         var $metaDataRead;
30         var $allRead;   
31         
32         // extracted data
33         var $skins;
34         var $templates;
35         var $info;
36         
37         // to maintain track of where we are inside the XML file
38         var $inXml;
39         var $inData;
40         var $inMeta;
41         var $inSkin;
42         var $inTemplate;
43         var $currentName;
44         var $currentPartName;
45         var $cdata;     
46         
47         
48         
49         /**
50          * constructor initializes data structures
51          */
52         function SKINIMPORT() {
53                 // disable magic_quotes_runtime if it's turned on
54                 set_magic_quotes_runtime(0);
55         
56                 // debugging mode?
57                 $this->debug = 0;
58         
59                 $this->reset();
60                 
61         }
62         
63         function reset() {
64         if ($this->parser)
65                 xml_parser_free($this->parser);
66                 
67                 // XML file pointer
68                 $this->fp = 0;          
69                 
70                 // which data has been read?
71                 $this->metaDataRead = 0;
72                 $this->allRead = 0;
73
74                 // to maintain track of where we are inside the XML file
75                 $this->inXml = 0;
76                 $this->inData = 0;
77                 $this->inMeta = 0;
78                 $this->inSkin = 0;
79                 $this->inTemplate = 0;
80                 $this->currentName = '';
81                 $this->currentPartName = '';
82                 
83                 // character data pile
84                 $this->cdata = '';
85                 
86                 // list of skinnames and templatenames (will be array of array)
87                 $this->skins = array();
88                 $this->templates = array();
89                 
90                 // extra info included in the XML files (e.g. installation notes)
91                 $this->info = '';
92                 
93                 // init XML parser
94                 $this->parser = xml_parser_create();
95                 xml_set_object($this->parser, $this);
96                 xml_set_element_handler($this->parser, 'startElement', 'endElement');
97                 xml_set_character_data_handler($this->parser, 'characterData');
98                 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
99
100         }       
101         
102         /**
103          * Reads an XML file into memory
104          *
105          * @param $filename
106          *              Which file to read
107          * @param $metaOnly
108          *              Set to 1 when only the metadata needs to be read (optional, default 0)
109          */
110         function readFile($filename, $metaOnly = 0) {
111                 // open file
112                 $this->fp = @fopen($filename, 'r');
113                 if (!$this->fp) return 'Failed to open file/URL';
114
115                 // here we go!
116                 $this->inXml = 1;
117
118                 while (!feof($this->fp)) {
119                         $tempbuffer .= fread($this->fp, 4096);
120                 }
121                 fclose($this->fp);
122
123 /*
124         [2004-08-04] dekarma - Took this out since it messes up good XML if it has skins/templates
125                                with CDATA sections. need to investigate consequences.
126                                see bug [ 999914 ] Import fails (multiple skins in XML/one of them with CDATA)
127         
128                 // backwards compatibility with the non-wellformed skinbackup.xml files
129                 // generated by v2/v3 (when CDATA sections were present in skins)
130                 // split up those CDATA sections into multiple ones
131                 $tempbuffer = preg_replace_callback(
132                         "/(<!\[CDATA\[[^]]*?<!\[CDATA\[[^]]*)((?:\]\].*?<!\[CDATA.*?)*)(\]\])(.*\]\])/ms",
133                         create_function(
134                                 '$matches',
135                                 'return $matches[1] . preg_replace("/(\]\])(.*?<!\[CDATA)/ms","]]]]><![CDATA[$2",$matches[2])."]]]]><![CDATA[".$matches[4];'
136                         ),
137                         $tempbuffer
138                 );              
139 */
140                 $temp = tmpfile();
141                 fwrite($temp, $tempbuffer);
142                 rewind($temp);
143
144                 while ( ($buffer = fread($temp, 4096) ) && (!$metaOnly || ($metaOnly && !$this->metaDataRead))) {
145                         $err = xml_parse( $this->parser, $buffer, feof($temp) );
146                         if (!$err && $this->debug)
147                                 echo 'ERROR: ', xml_error_string(xml_get_error_code($this->parser)), '<br />';
148                 }
149
150                 // all done
151                 $this->inXml = 0;
152                 fclose($temp);
153         }       
154         
155         /**
156          * Returns the list of skin names
157          */
158         function getSkinNames() {
159                 return array_keys($this->skins);
160         }
161
162         /**
163          * Returns the list of template names
164          */
165         function getTemplateNames() {
166                 return array_keys($this->templates);
167         }       
168         
169         /**
170          * Returns the extra information included in the XML file
171          */
172         function getInfo() {
173                 return $this->info;
174         }
175         
176         /**
177          * Writes the skins and templates to the database 
178          *
179          * @param $allowOverwrite
180          *              set to 1 when allowed to overwrite existing skins with the same name
181          *              (default = 0)
182          */
183         function writeToDatabase($allowOverwrite = 0) {
184                 $existingSkins = $this->checkSkinNameClashes();
185                 $existingTemplates = $this->checkTemplateNameClashes();
186                 
187                 // if not allowed to overwrite, check if any nameclashes exists
188                 if (!$allowOverwrite) {
189                         if ((sizeof($existingSkins) > 0) || (sizeof($existingTemplates) > 0))
190                                 return 'Name clashes detected, re-run with allowOverwrite = 1 to force overwrite';
191                 }
192                 
193                 foreach ($this->skins as $skinName => $data) {
194                         // 1. if exists: delete all part data, update desc data
195                         //    if not exists: create desc
196                         if (in_array($skinName, $existingSkins)) {
197                                 $skinObj = SKIN::createFromName($skinName);
198                                 
199                                 // delete all parts of the skin
200                                 $skinObj->deleteAllParts();
201                                 
202                                 // update general info
203                                 $skinObj->updateGeneralInfo($skinName, $data['description'], $data['type'], $data['includeMode'], $data['includePrefix']);
204                         } else {
205                                 $skinid = SKIN::createNew($skinName, $data['description'], $data['type'], $data['includeMode'], $data['includePrefix']);
206                                 $skinObj = new SKIN($skinid);
207                         }
208                         
209                         // 2. add parts
210                         foreach ($data['parts'] as $partName => $partContent) {
211                                 $skinObj->update($partName, $partContent);
212                         }
213                 }
214                 
215                 foreach ($this->templates as $templateName => $data) {
216                         // 1. if exists: delete all part data, update desc data
217                         //    if not exists: create desc
218                         if (in_array($templateName, $existingTemplates)) {
219                                 $templateObj = TEMPLATE::createFromName($templateName);
220                                 
221                                 // delete all parts of the template
222                                 $templateObj->deleteAllParts();
223                                 
224                                 // update general info
225                                 $templateObj->updateGeneralInfo($templateName, $data['description']);
226                         } else {
227                                 $templateid = TEMPLATE::createNew($templateName, $data['description']);
228                                 $templateObj = new TEMPLATE($templateid);
229                         }
230                         
231                         // 2. add parts
232                         foreach ($data['parts'] as $partName => $partContent) {
233                                 $templateObj->update($partName, $partContent);
234                         }                       
235                 }
236         
237                         
238         }
239         
240         /**
241           * returns an array of all the skin nameclashes (empty array when no name clashes)
242           */
243         function checkSkinNameClashes() {
244                 $clashes = array();
245                 
246                 foreach ($this->skins as $skinName => $data) {
247                         if (SKIN::exists($skinName))
248                                 array_push($clashes, $skinName);
249                 }
250                 
251                 return $clashes;
252         }
253         
254         /**
255           * returns an array of all the template nameclashes 
256           * (empty array when no name clashes)
257           */
258         function checkTemplateNameClashes() {
259                 $clashes = array();
260                 
261                 foreach ($this->templates as $templateName => $data) {
262                         if (TEMPLATE::exists($templateName))
263                                 array_push($clashes, $templateName);
264                 }
265                 
266                 return $clashes;
267         }
268                 
269         /**
270          * Called by XML parser for each new start element encountered
271          */
272         function startElement($parser, $name, $attrs) {
273                 if ($this->debug) echo 'START: ', $name, '<br />';
274                 
275                 switch ($name) {
276                         case 'nucleusskin':
277                                 $this->inData = 1;
278                                 break;
279                         case 'meta':
280                                 $this->inMeta = 1;
281                                 break;
282                         case 'info':
283                                 // no action needed
284                                 break;
285                         case 'skin':
286                                 if (!$this->inMeta) {
287                                         $this->inSkin = 1;
288                                         $this->currentName = $attrs['name'];
289                                         $this->skins[$this->currentName]['type'] = $attrs['type'];
290                                         $this->skins[$this->currentName]['includeMode'] = $attrs['includeMode'];
291                                         $this->skins[$this->currentName]['includePrefix'] = $attrs['includePrefix'];                                    
292                                         $this->skins[$this->currentName]['parts'] = array();                                                                            
293                                 } else {
294                                         $this->skins[$attrs['name']] = array();                         
295                                         $this->skins[$attrs['name']]['parts'] = array();                                                                        
296                                 }
297                                 break;
298                         case 'template':
299                                 if (!$this->inMeta) {
300                                         $this->inTemplate = 1;
301                                         $this->currentName = $attrs['name'];
302                                         $this->templates[$this->currentName]['parts'] = array();                                                                                                                        
303                                 } else {
304                                         $this->templates[$attrs['name']] = array();                             
305                                         $this->templates[$attrs['name']]['parts'] = array();                                                                    
306                                 }
307                                 break;
308                         case 'description':
309                                 // no action needed
310                                 break;
311                         case 'part':
312                                 $this->currentPartName = $attrs['name'];
313                                 break;
314                         default:
315                                 echo 'UNEXPECTED TAG: ' , $name , '<br />';
316                                 break;
317                 }
318                 
319                 // character data never contains other tags
320                 $this->clearCharacterData(); 
321                 
322         }
323
324         /**
325           * Called by the XML parser for each closing tag encountered
326           */
327         function endElement($parser, $name) {
328                 if ($this->debug) echo 'END: ', $name, '<br />';
329                 
330                 switch ($name) {
331                         case 'nucleusskin':
332                                 $this->inData = 0;
333                                 $this->allRead = 1;
334                                 break;
335                         case 'meta':
336                                 $this->inMeta = 0;
337                                 $this->metaDataRead = 1;
338                                 break;
339                         case 'info':
340                                 $this->info = $this->getCharacterData();
341                         case 'skin':
342                                 if (!$this->inMeta) $this->inSkin = 0;
343                                 break;
344                         case 'template':
345                                 if (!$this->inMeta) $this->inTemplate = 0;                      
346                                 break;
347                         case 'description':
348                                 if ($this->inSkin) {
349                                         $this->skins[$this->currentName]['description'] = $this->getCharacterData();
350                                 } else {
351                                         $this->templates[$this->currentName]['description'] = $this->getCharacterData();                                
352                                 }
353                                 break;
354                         case 'part':
355                                 if ($this->inSkin) {
356                                         $this->skins[$this->currentName]['parts'][$this->currentPartName] = $this->getCharacterData();
357                                 } else {
358                                         $this->templates[$this->currentName]['parts'][$this->currentPartName] = $this->getCharacterData();                              
359                                 }
360                                 break;
361                         default:
362                                 echo 'UNEXPECTED TAG: ' , $name, '<br />';
363                                 break;
364                 }
365                 $this->clearCharacterData();
366
367         }
368         
369         /**
370          * Called by XML parser for data inside elements
371          */
372         function characterData ($parser, $data) {
373                 if ($this->debug) echo 'NEW DATA: ', htmlspecialchars($data), '<br />';
374                 $this->cdata .= $data;
375         }
376         
377         /**
378          * Returns the data collected so far
379          */
380         function getCharacterData() {
381                 return $this->cdata;
382         }
383         
384         /**
385          * Clears the data buffer
386          */
387         function clearCharacterData() {
388                 $this->cdata = '';
389         }
390         
391         /**
392          * Static method that looks for importable XML files in subdirs of the given dir
393          */
394         function searchForCandidates($dir) {
395                 $candidates = array();
396
397                 $dirhandle = opendir($dir);
398                 while ($filename = readdir($dirhandle)) {
399                         if (@is_dir($dir . $filename) && ($filename != '.') && ($filename != '..')) {
400                                 $xml_file = $dir . $filename . '/skinbackup.xml';
401                                 if (file_exists($xml_file) && is_readable($xml_file)) {
402                                         $candidates[$filename] = $filename; //$xml_file;
403                                 } 
404
405                                 // backwards compatibility                      
406                                 $xml_file = $dir . $filename . '/skindata.xml';
407                                 if (file_exists($xml_file) && is_readable($xml_file)) {
408                                         $candidates[$filename] = $filename; //$xml_file;
409                                 } 
410                         }
411                 }
412                 closedir($dirhandle);
413                 
414                 return $candidates;
415         
416         }
417          
418         
419 }
420
421
422 class SKINEXPORT {
423
424         var $templates;
425         var $skins;
426         var $info;
427         
428         /**
429          * Constructor initializes data structures
430          */
431         function SKINEXPORT() {
432                 // list of templateIDs to export
433                 $this->templates = array();
434                 
435                 // list of skinIDs to export
436                 $this->skins = array();
437                 
438                 // extra info to be in XML file
439                 $this->info = '';
440         }
441         
442         /**
443          * Adds a template to be exported
444          *
445          * @param id
446          *              template ID
447          * @result false when no such ID exists
448          */
449         function addTemplate($id) {
450                 if (!TEMPLATE::existsID($id)) return 0;
451         
452                 $this->templates[$id] = TEMPLATE::getNameFromId($id);
453                 
454                 return 1;
455         }
456         
457         /**
458          * Adds a skin to be exported
459          *
460          * @param id 
461          *              skin ID
462          * @result false when no such ID exists
463          */     
464         function addSkin($id) {
465                 if (!SKIN::existsID($id)) return 0;
466                 
467                 $this->skins[$id] = SKIN::getNameFromId($id);
468                 
469                 return 1;
470         }
471         
472         /**
473          * Sets the extra info to be included in the exported file
474          */
475         function setInfo($info) {
476                 $this->info = $info;
477         }
478         
479         
480         /**
481          * Outputs the XML contents of the export file
482          *
483          * @param $setHeaders
484          *              set to 0 if you don't want to send out headers
485          *              (optional, default 1)
486          */
487         function export($setHeaders = 1) {
488                 if ($setHeaders) {
489                         // make sure the mimetype is correct, and that the data does not show up 
490                         // in the browser, but gets saved into and XML file (popup download window)
491                         header('Content-Type: text/xml');
492                         header('Content-Disposition: attachment; filename="skinbackup.xml"');
493                         header('Expires: 0');
494                         header('Pragma: no-cache');
495                 }
496         
497                 echo "<nucleusskin>\n";
498         
499                 // meta
500                 echo "\t<meta>\n";
501                         // skins
502                         foreach ($this->skins as $skinId => $skinName) {
503                                 echo "\t\t", '<skin name="',htmlspecialchars($skinName),'" />',"\n";
504                         }
505                         // templates
506                         foreach ($this->templates as $templateId => $templateName) {
507                                 echo "\t\t", '<template name="',htmlspecialchars($templateName),'" />',"\n";
508                         }
509                         // extra info
510                         if ($this->info)
511                                 echo "\t\t<info><![CDATA[",$this->info,"]]></info>\n";
512                 echo "\t</meta>\n\n\n";
513                 
514                 // contents skins
515                 foreach ($this->skins as $skinId => $skinName) {
516                         $skinId = intval($skinId);
517                         $skinObj = new SKIN($skinId);
518                         
519                         echo "\t", '<skin name="',htmlspecialchars($skinName),'" type="',htmlspecialchars($skinObj->getContentType()),'" includeMode="',htmlspecialchars($skinObj->getIncludeMode()),'" includePrefix="',htmlspecialchars($skinObj->getIncludePrefix()),'">',"\n";
520                         
521                         echo "\t\t", '<description>',htmlspecialchars($skinObj->getDescription()),'</description>',"\n";
522                         
523                         $res = sql_query('SELECT stype, scontent FROM '.sql_table('skin').' WHERE sdesc='.$skinId);
524                         while ($partObj = mysql_fetch_object($res)) {
525                                 echo "\t\t",'<part name="',htmlspecialchars($partObj->stype),'">';
526                                 echo '<![CDATA[', $this->escapeCDATA($partObj->scontent),']]>';
527                                 echo "</part>\n\n";
528                         }
529                         
530                         echo "\t</skin>\n\n\n";
531                 }
532                 
533                 // contents templates
534                 foreach ($this->templates as $templateId => $templateName) {
535                         $templateId = intval($templateId);
536                         
537                         echo "\t",'<template name="',htmlspecialchars($templateName),'">',"\n";
538                         
539                         echo "\t\t",'<description>',htmlspecialchars(TEMPLATE::getDesc($templateId)),'</description>',"\n";                     
540                         
541                         $res = sql_query('SELECT tpartname, tcontent FROM '.sql_table('template').' WHERE tdesc='.$templateId);
542                         while ($partObj = mysql_fetch_object($res)) {
543                                 echo "\t\t",'<part name="',htmlspecialchars($partObj->tpartname),'">';
544                                 echo '<![CDATA[', $this->escapeCDATA($partObj->tcontent) ,']]>';
545                                 echo '</part>',"\n\n";
546                         }
547                         
548                         echo "\t</template>\n\n\n";
549                 }               
550                 
551                 echo '</nucleusskin>';
552         }
553         
554         /**
555          * Escapes CDATA content so it can be included in another CDATA section
556          */
557         function escapeCDATA($cdata)
558         {
559                 return preg_replace('/]]>/', ']]]]><![CDATA[>', $cdata);
560                 
561         }
562 }
563
564 ?>