OSDN Git Service

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