OSDN Git Service

初回コミット(v2.6.17.1)
[magic3/magic3.git] / widgets / wiki_main / include / plugin / showrss.inc.php
1 <?php
2 /**
3  * showrssプラグイン
4  *
5  * PHP versions 5
6  *
7  * LICENSE: This source file is licensed under the terms of the GNU General Public License.
8  *
9  * @package    Magic3 Framework
10  * @author     平田直毅(Naoki Hirata) <naoki@aplo.co.jp>
11  * @copyright  Copyright 2006-2010 Magic3 Project.
12  * @license    http://www.gnu.org/copyleft/gpl.html  GPL License
13  * @version    SVN: $Id: showrss.inc.php 3474 2010-08-13 10:36:48Z fishbone $
14  * @link       http://www.magic3.org
15  */
16 // Copyright (C):
17 //     2002-2006 PukiWiki Developers Team
18 //     2002      PANDA <panda@arino.jp>
19 //     (Original)hiro_do3ob@yahoo.co.jp
20 // License: GPL, same as PukiWiki
21 //
22 // Show RSS (of remote site) plugin
23 // NOTE:
24 //    * This plugin needs 'PHP xml extension'
25 //    * Cache data will be stored as CACHE_DIR/*.tmp
26
27 define('PLUGIN_SHOWRSS_USAGE', '#showrss(URI-to-RSS[,default|menubar|recent[,Cache-lifetime[,Show-timestamp]]])');
28
29 // Show related extensions are found or not
30 function plugin_showrss_action()
31 {
32         if (PKWK_SAFE_MODE) die_message('PKWK_SAFE_MODE prohibit this');
33
34         $body = '';
35         foreach(array('xml', 'mbstring') as $extension){
36                 $$extension = extension_loaded($extension) ?
37                         '&color(green){Found};' :
38                         '&color(red){Not found};';
39                 $body .= '| ' . $extension . ' extension | ' . $$extension . ' |' . "\n";
40         }
41         return array('msg' => 'showrss_info', 'body' => convert_html($body));
42 }
43
44 function plugin_showrss_convert()
45 {
46         static $_xml;
47
48         if (! isset($_xml)) $_xml = extension_loaded('xml');
49         if (! $_xml) return '#showrss: xml extension is not found<br />' . "\n";
50
51         $num = func_num_args();
52         if ($num == 0) return PLUGIN_SHOWRSS_USAGE . '<br />' . "\n";
53
54         $argv = func_get_args();
55         $timestamp = FALSE;
56         $cachehour = 0;
57         $template = $uri = '';
58         switch ($num) {
59         case 4: $timestamp = (trim($argv[3]) == '1');   /*FALLTHROUGH*/
60         case 3: $cachehour = trim($argv[2]);            /*FALLTHROUGH*/
61         case 2: $template  = strtolower(trim($argv[1]));/*FALLTHROUGH*/
62         case 1: $uri       = trim($argv[0]);
63         }
64
65         $class = ($template == '' || $template == 'default') ? 'ShowRSS_html' : 'ShowRSS_html_' . $template;
66         if (! is_numeric($cachehour))
67                 return '#showrss: Cache-lifetime seems not numeric: ' . htmlspecialchars($cachehour) . '<br />' . "\n";
68         if (! class_exists($class))
69                 return '#showrss: Template not found: ' . htmlspecialchars($template) . '<br />' . "\n";
70         if (! is_url($uri))
71                 return '#showrss: Seems not URI: ' . htmlspecialchars($uri) . '<br />' . "\n";
72
73         list($rss, $time) = plugin_showrss_get_rss($uri, $cachehour);
74         if ($rss === FALSE) return '#showrss: Failed fetching RSS from the server<br />' . "\n";
75
76         $time = '';
77         if ($timestamp > 0) {
78                 $time = '<p style="font-size:10px; font-weight:bold">Last-Modified:' .
79                         get_date('Y/m/d H:i:s', $time) .  '</p>';
80         }
81
82         $obj = new $class($rss);
83         return $obj->toString($time);
84 }
85
86 // Create HTML from RSS array()
87 class ShowRSS_html
88 {
89         var $items = array();
90         var $class = '';
91
92         function ShowRSS_html($rss)
93         {
94                 foreach ($rss as $date=>$items) {
95                         foreach ($items as $item) {
96                                 $link  = $item['LINK'];
97                                 $title = $item['TITLE'];
98                                 $passage = get_passage($item['_TIMESTAMP']);
99                                 $link = '<a href="' . $link . '" title="' .  $title . ' ' .
100                                         $passage . '" rel="nofollow">' . $title . '</a>';
101                                 $this->items[$date][] = $this->format_link($link);
102                         }
103                 }
104         }
105
106         function format_link($link)
107         {
108                 return $link . '<br />' . "\n";
109         }
110
111         function format_list($date, $str)
112         {
113                 return $str;
114         }
115
116         function format_body($str)
117         {
118                 return $str;
119         }
120
121         function toString($timestamp)
122         {
123                 $retval = '';
124                 foreach ($this->items as $date=>$items)
125                         $retval .= $this->format_list($date, join('', $items));
126                 $retval = $this->format_body($retval);
127                 return <<<EOD
128 <div{$this->class}>
129 $retval$timestamp
130 </div>
131 EOD;
132         }
133 }
134
135 class ShowRSS_html_menubar extends ShowRSS_html
136 {
137         var $class = ' class="small"';
138
139         function format_link($link) {
140                 return '<li>' . $link . '</li>' . "\n";
141         }
142
143         function format_body($str) {
144                 return '<ul class="recent_list">' . "\n" . $str . '</ul>' . "\n";
145         }
146 }
147
148 class ShowRSS_html_recent extends ShowRSS_html
149 {
150         var $class = ' class="small"';
151
152         function format_link($link) {
153                 return '<li>' . $link . '</li>' . "\n";
154         }
155
156         function format_list($date, $str) {
157                 return '<strong>' . $date . '</strong>' . "\n" .
158                         '<ul class="recent_list">' . "\n" . $str . '</ul>' . "\n";
159         }
160 }
161
162 // Get and save RSS
163 function plugin_showrss_get_rss($target, $cachehour)
164 {
165         $buf  = '';
166         $time = NULL;
167         if ($cachehour) {
168                 // Remove expired cache
169                 plugin_showrss_cache_expire($cachehour);
170
171                 // Get the cache not expired
172                 $filename = CACHE_DIR . encode($target) . '.tmp';
173                 if (is_readable($filename)) {
174                         $buf  = join('', file($filename));
175                         $time = filemtime($filename) - LOCALZONE;
176                 }
177         }
178
179         if ($time === NULL) {
180                 // Newly get RSS
181                 $data = http_request($target);
182                 if ($data['rc'] !== 200)
183                         return array(FALSE, 0);
184
185                 $buf = $data['data'];
186                 $time = UTIME;
187
188                 // Save RSS into cache
189                 if ($cachehour) {
190                         $fp = fopen($filename, 'w');
191                         fwrite($fp, $buf);
192                         fclose($fp);
193                 }
194         }
195
196         // Parse
197         $obj = new ShowRSS_XML();
198         return array($obj->parse($buf),$time);
199 }
200
201 // Remove cache if expired limit exeed
202 function plugin_showrss_cache_expire($cachehour)
203 {
204         $expire = $cachehour * 60 * 60; // Hour
205         $dh = dir(CACHE_DIR);
206         while (($file = $dh->read()) !== FALSE) {
207                 if (substr($file, -4) != '.tmp') continue;
208                 $file = CACHE_DIR . $file;
209                 $last = time() - filemtime($file);
210                 if ($last > $expire) unlink($file);
211         }
212         $dh->close();
213 }
214
215 // Get RSS and array() them
216 class ShowRSS_XML
217 {
218         var $items;
219         var $item;
220         var $is_item;
221         var $tag;
222         var $encoding;
223
224         function parse($buf)
225         {
226                 $this->items   = array();
227                 $this->item    = array();
228                 $this->is_item = FALSE;
229                 $this->tag     = '';
230
231                 // Detect encoding
232                 $matches = array();
233                 if(preg_match('/<\?xml [^>]*\bencoding="([a-z0-9-_]+)"/i', $buf, $matches)) {
234                         $this->encoding = $matches[1];
235                 } else {
236                         $this->encoding = mb_detect_encoding($buf);
237                 }
238
239                 // Normalize to UTF-8 / ASCII
240                 if (! in_array(strtolower($this->encoding), array('us-ascii', 'iso-8859-1', 'utf-8'))) {
241                         $buf = mb_convert_encoding($buf, 'utf-8', $this->encoding);
242                         $this->encoding = 'utf-8';
243                 }
244
245                 // Parsing
246                 $xml_parser = xml_parser_create($this->encoding);
247                 xml_set_element_handler($xml_parser, array($this, 'start_element'), array($this, 'end_element'));
248                 xml_set_character_data_handler($xml_parser, array($this, 'character_data'));
249                 if (! xml_parse($xml_parser, $buf, 1)) {
250                         return(sprintf('XML error: %s at line %d in %s',
251                                 xml_error_string(xml_get_error_code($xml_parser)),
252                                 xml_get_current_line_number($xml_parser), $buf));
253                 }
254                 xml_parser_free($xml_parser);
255
256                 return $this->items;
257         }
258
259         function escape($str)
260         {
261                 // Unescape already-escaped chars (&lt;, &gt;, &amp;, ...) in RSS body before htmlspecialchars()
262                 $str = strtr($str, array_flip(get_html_translation_table(ENT_COMPAT)));
263                 // Escape
264                 $str = htmlspecialchars($str);
265                 // Encoding conversion
266                 $str = mb_convert_encoding($str, SOURCE_ENCODING, $this->encoding);
267                 return trim($str);
268         }
269
270         // Tag start
271         function start_element($parser, $name, $attrs)
272         {
273                 if ($this->is_item) {
274                         $this->tag     = $name;
275                 } else if ($name == 'ITEM') {
276                         $this->is_item = TRUE;
277                 }
278         }
279
280         // Tag end
281         function end_element($parser, $name)
282         {
283                 if (! $this->is_item || $name != 'ITEM') return;
284
285                 $item = array_map(array($this, 'escape'), $this->item);
286                 $this->item = array();
287
288                 if (isset($item['DC:DATE'])) {
289                         $time = plugin_showrss_get_timestamp($item['DC:DATE']);
290                         
291                 } else if (isset($item['PUBDATE'])) {
292                         $time = plugin_showrss_get_timestamp($item['PUBDATE']);
293                         
294                 } else if (isset($item['DESCRIPTION']) &&
295                         ($description = trim($item['DESCRIPTION'])) != '' &&
296                         ($time = strtotime($description)) != -1) {
297                                 $time -= LOCALZONE;
298
299                 } else {
300                         $time = time() - LOCALZONE;
301                 }
302                 $item['_TIMESTAMP'] = $time;
303                 $date = get_date('Y-m-d', $item['_TIMESTAMP']);
304
305                 $this->items[$date][] = $item;
306                 $this->is_item        = FALSE;
307         }
308
309         function character_data($parser, $data)
310         {
311                 if (! $this->is_item) return;
312                 if (! isset($this->item[$this->tag])) $this->item[$this->tag] = '';
313                 $this->item[$this->tag] .= $data;
314         }
315 }
316
317 function plugin_showrss_get_timestamp($str)
318 {
319         $str = trim($str);
320         if ($str == '') return UTIME;
321
322         $matches = array();
323         if (preg_match('/(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2})(([+-])(\d{2}):(\d{2}))?/', $str, $matches)) {
324                 $time = strtotime($matches[1] . ' ' . $matches[2]);
325                 if ($time == -1) {
326                         $time = UTIME;
327                 } else if ($matches[3]) {
328                         $diff = ($matches[5] * 60 + $matches[6]) * 60;
329                         $time += ($matches[4] == '-' ? $diff : -$diff);
330                 }
331                 return $time;
332         } else {
333                 $time = strtotime($str);
334                 return ($time == -1) ? UTIME : $time - LOCALZONE;
335         }
336 }
337 ?>