OSDN Git Service

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