OSDN Git Service

Correct r1.8. It's useless without index.php
[pukiwiki/pukiwiki.git] / lib / trackback.php
1 <?php
2 // $Id: trackback.php,v 1.7 2004/12/18 14:32:58 henoheno Exp $
3 /*
4  * PukiWiki/TrackBack
5  * (C) 2003-2004 PukiWiki Developer Team
6  * (C) 2003, Katsumi Saito <katsumi@jo1upk.ymt.prug.or.jp>
7  * License: GPL
8  *
9  * http://localhost/pukiwiki/pukiwiki.php?FrontPage ¤ÈÌÀ³Î¤Ë»ØÄꤷ¤Ê¤¤¤È
10  * TrackBack ID ¤Î¼èÆÀ¤Ï¤Ç¤­¤Ê¤¤
11  *
12  * tb_get_id($page)        Get TrackBack Ping ID from page name
13  * tb_id2page($tb_id)      Get page name from TrackBack Ping ID
14  * tb_get_filename($page)  Get file name of TrackBack Ping data
15  * tb_count($page)         Count the number of TrackBack Pings included for the page
16  *                         // pukiwiki.skin.LANG.php
17  * tb_send($page, $data)   Send TrackBack Ping(s) automatically // file.php
18  * tb_delete($page)        Remove TrackBack Ping data // edit.inc.php
19  * tb_get($file, $key = 1) TrackBack Ping ¥Ç¡¼¥¿ÆþÎÏ
20  * tb_get_rdf($page)       Ê¸¾ÏÃæ¤ËËä¤á¹þ¤à¤¿¤á¤Îrdf¤ò¥Ç¡¼¥¿¤òÀ¸À® // pukiwiki.php
21  * tb_get_url($url)        Ê¸½ñ¤òGET¤·¡¢Ëä¤á¹þ¤Þ¤ì¤¿TrackBack Ping URL¤ò¼èÆÀ
22  * class TrackBack_XML     XML¤«¤éTrackBack Ping ID¤ò¼èÆÀ¤¹¤ë¥¯¥é¥¹
23  * == Referer Âбþʬ ==
24  * ref_save($page)         Save or update referer data // pukiwiki.php
25  */
26
27 define('PLUGIN_TRACKBACK_VERSION', 'PukiWiki/TrackBack 0.2');
28
29 // Get TrackBack Ping ID from page name
30 function tb_get_id($page)
31 {
32         return md5($page);
33 }
34
35 // Get page name from TrackBack Ping ID
36 function tb_id2page($tb_id)
37 {
38         static $pages, $cache = array();
39
40         if (isset($cache[$tb_id])) return $cache[$tb_id];
41
42         if (! isset($pages)) $pages = get_existpages();
43
44         foreach ($pages as $page) {
45                 $_tb_id = tb_get_id($page);
46                 $cache[$_tb_id] = $page;
47                 unset($pages[$page]);
48                 if ($tb_id == $_tb_id) return $cache[$tb_id];
49         }
50
51         $cache[$tb_id] = FALSE;
52
53         return $cache[$tb_id]; // Not found
54 }
55
56 // Get file name of TrackBack Ping data
57 function tb_get_filename($page, $ext = '.txt')
58 {
59         return TRACKBACK_DIR . encode($page) . $ext;
60 }
61
62 // Count the number of TrackBack Pings included for the page
63 function tb_count($page, $ext = '.txt')
64 {
65         $filename = tb_get_filename($page, $ext);
66         return file_exists($filename) ? count(file($filename)) : 0;
67 }
68
69 // Send TrackBack Ping(s) automatically
70 // $plus  = Newly added lines may include URLs
71 // $minus = Removed lines may include URLs
72 function tb_send($page, $plus, $minus = '')
73 {
74         global $script, $trackback;
75
76         if (! $trackback) return;
77
78         // Disable 'max execution time' (php.ini: max_execution_time)
79         if (ini_get('safe_mode') == '0') set_time_limit(0);
80
81         // Get URLs from <a>(anchor) tag from convert_html()
82         $links = array();
83         $plus  = convert_html($plus); // WARNING: heavy and may cause side-effect
84         preg_match_all('#href="(https?://[^"]+)"#', $plus, $links, PREG_PATTERN_ORDER);
85         $links = array_unique($links[1]);
86
87         // Reject from minus list
88         if ($minus != '') {
89                 $links_m = array();
90                 $minus = convert_html($minus); // WARNING: heavy and may cause side-effect
91                 preg_match_all('#href="(https?://[^"]+)"#', $minus, $links_m, PREG_PATTERN_ORDER);
92                 $links_m = array_unique($links_m[1]);
93
94                 $links = array_diff($links, $links_m);
95         }
96
97         // Reject own URL (Pattern _NOT_ started with '$script' and '?')
98         $links = preg_grep('/^(?!' . preg_quote($script, '/') . '\?)./', $links);
99
100         // No link, END
101         if (! is_array($links) || empty($links)) return;
102
103         $r_page  = rawurlencode($page);
104         $excerpt = strip_htmltag(convert_html(get_source($page)));
105
106         // Sender's information
107         $putdata = array(
108                 'title'     => $page, // Title = It's page name
109                 'url'       => "$script?$r_page", // will be rawurlencode() at send phase
110                 'excerpt'   => mb_strimwidth(preg_replace("/[\r\n]/", ' ', $excerpt), 0, 255, '...'),
111                 'blog_name' => PLUGIN_TRACKBACK_VERSION,
112                 'charset'   => SOURCE_ENCODING // Ping text encoding (Not defined)
113         );
114
115         foreach ($links as $link) {
116                 $tb_id = tb_get_url($link);  // Get Trackback ID from the URL
117                 if (empty($tb_id)) continue; // Trackback is not supported
118
119                 $result = http_request($tb_id, 'POST', '', $putdata);
120                 // FIXME: Create warning notification space at pukiwiki.skin!
121         }
122 }
123
124 // Remove TrackBack Ping data
125 function tb_delete($page)
126 {
127         $filename = tb_get_filename($page);
128         if (file_exists($filename)) @unlink($filename);
129 }
130
131 // TrackBack Ping ¥Ç¡¼¥¿ÆþÎÏ
132 function tb_get($file, $key = 1)
133 {
134         if (! file_exists($file)) return array();
135
136         $result = array();
137         $fp = @fopen($file, 'r');
138         set_file_buffer($fp, 0);
139         flock($fp, LOCK_EX);
140         rewind($fp);
141         while ($data = @fgetcsv($fp, 8192, ',')) {
142                 // $data[$key] = URL
143                 $result[rawurldecode($data[$key])] = $data;
144         }
145         flock($fp, LOCK_UN);
146         fclose ($fp);
147
148         return $result;
149 }
150
151 // Ê¸¾ÏÃæ¤Ë trackback:ping ¤òËä¤á¹þ¤à¤¿¤á¤Î¥Ç¡¼¥¿¤òÀ¸À®
152 function tb_get_rdf($page)
153 {
154         global $trackback;
155
156         if (! $trackback) return '';
157
158         $r_page = rawurlencode($page);
159         $tb_id  = tb_get_id($page);
160         // $dcdate = substr_replace(get_date('Y-m-d\TH:i:sO', $time), ':', -2, 0);
161         // dc:date="$dcdate"
162
163         $_script = get_script_uri(); // Get absolute path
164
165         return <<<EOD
166 <!--
167 <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
168   xmlns:dc="http://purl.org/dc/elements/1.1/"
169   xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
170  <rdf:Description
171    rdf:about="$_script?$r_page"
172    dc:identifier="$_script?$r_page"
173    dc:title="$page"
174    trackback:ping="$_script?tb_id=$tb_id" />
175 </rdf:RDF>
176 -->
177 EOD;
178 }
179
180 // Ê¸½ñ¤òGET¤·¡¢Ëä¤á¹þ¤Þ¤ì¤¿TrackBack Ping url¤ò¼èÆÀ
181 function tb_get_url($url)
182 {
183         // ¥×¥í¥­¥·¤ò·Ðͳ¤¹¤ëɬÍפ¬¤¢¤ë¥Û¥¹¥È¤Ë¤Ïping¤òÁ÷¿®¤·¤Ê¤¤
184         $parse_url = parse_url($url);
185         if (empty($parse_url['host']) || via_proxy($parse_url['host']))
186                 return '';
187
188         $data = http_request($url);
189         if ($data['rc'] !== 200) return '';
190
191         $matches = array();
192         if (! preg_match_all('#<rdf:RDF[^>]*>(.*?)</rdf:RDF>#si', $data['data'],
193             $matches, PREG_PATTERN_ORDER))
194                 return '';
195
196         $obj = new TrackBack_XML();
197         foreach ($matches[1] as $body) {
198                 $tb_url = $obj->parse($body, $url);
199                 if ($tb_url !== FALSE) return $tb_url;
200         }
201
202         return '';
203 }
204
205 // Ëä¤á¹þ¤Þ¤ì¤¿¥Ç¡¼¥¿¤«¤é TrackBack Ping url¤ò¼èÆÀ¤¹¤ë¥¯¥é¥¹
206 class TrackBack_XML
207 {
208         var $url;
209         var $tb_url;
210
211         function parse($buf, $url)
212         {
213                 // Init
214                 $this->url    = $url;
215                 $this->tb_url = FALSE;
216
217                 $xml_parser = xml_parser_create();
218                 if ($xml_parser === FALSE) return FALSE;
219
220                 xml_set_element_handler($xml_parser, array(& $this, 'start_element'),
221                         array(& $this, 'end_element'));
222
223                 if (! xml_parse($xml_parser, $buf, TRUE)) {
224 /*                      die(sprintf('XML error: %s at line %d in %s',
225                                 xml_error_string(xml_get_error_code($xml_parser)),
226                                 xml_get_current_line_number($xml_parser),
227                                 $buf));
228 */
229                         return FALSE;
230                 }
231
232                 return $this->tb_url;
233         }
234
235         function start_element($parser, $name, $attrs)
236         {
237                 if ($name !== 'RDF:DESCRIPTION') return;
238
239                 $about = $url = $tb_url = '';
240                 foreach ($attrs as $key=>$value) {
241                         switch ($key) {
242                         case 'RDF:ABOUT'     : $about  = $value; break;
243                         case 'DC:IDENTIFER'  : /*FALLTHROUGH*/
244                         case 'DC:IDENTIFIER' : $url    = $value; break;
245                         case 'TRACKBACK:PING': $tb_url = $value; break;
246                         }
247                 }
248                 if ($about == $this->url || $url == $this->url)
249                         $this->tb_url = $tb_url;
250         }
251
252         function end_element($parser, $name) {}
253 }
254
255 // Save or update referer data
256 function ref_save($page)
257 {
258         global $referer;
259
260         if (! $referer || empty($_SERVER['HTTP_REFERER'])) return TRUE;
261
262         $url = $_SERVER['HTTP_REFERER'];
263
264         // Validate URI (Ignore own)
265         $parse_url = parse_url($url);
266         if (empty($parse_url['host']) || $parse_url['host'] == $_SERVER['HTTP_HOST'])
267                 return TRUE;
268
269         if (! is_dir(TRACKBACK_DIR))      die('No such directory: TRACKBACK_DIR');
270         if (! is_writable(TRACKBACK_DIR)) die('Permission denied: TRACKBACK_DIR');
271
272         // Update referer data
273         if (ereg("[,\"\n\r]", $url))
274                 $url = '"' . str_replace('"', '""', $url) . '"';
275
276         $filename = tb_get_filename($page, '.ref');
277         $data     = tb_get($filename, 3);
278         $d_url    = rawurldecode($url);
279         if (! isset($data[$d_url])) {
280                 // 0:ºÇ½ª¹¹¿·Æü»þ, 1:½é²óÅÐÏ¿Æü»þ, 2:»²¾È¥«¥¦¥ó¥¿,
281                 // 3:Referer ¥Ø¥Ã¥À, 4:ÍøÍѲÄÈݥե饰(1¤ÏÍ­¸ú)
282                 $data[$d_url] = array(UTIME, UTIME, 0, $url, 1);
283         }
284         $data[$d_url][0] = UTIME;
285         $data[$d_url][2]++;
286
287         $fp = fopen($filename, 'w');
288         if ($fp === FALSE) return FALSE;        
289         set_file_buffer($fp, 0);
290         flock($fp, LOCK_EX);
291         rewind($fp);
292         foreach ($data as $line)
293                 fwrite($fp, join(',', $line) . "\n");
294         flock($fp, LOCK_UN);
295         fclose($fp);
296
297         return TRUE;
298 }
299 ?>