* License: GPL * * http://localhost/pukiwiki/pukiwiki.php?FrontPage と明確に指定しないと * TrackBack ID の取得はできない * * tb_get_id($page) TrackBack Ping IDを取得 * tb_id2page($tb_id) TrackBack Ping ID からページ名を取得 * tb_get_filename($page) TrackBack Ping データファイル名を取得 * tb_count($page) TrackBack Ping データ個数取得 // pukiwiki.skin.LANG.php * tb_send($page, $data) TrackBack Ping 送信 // file.php * tb_delete($page) TrackBack Ping データ削除 // edit.inc.php * tb_get($file, $key = 1) TrackBack Ping データ入力 * tb_get_rdf($page) 文章中に埋め込むためのrdfをデータを生成 // pukiwiki.php * tb_get_url($url) 文書をGETし、埋め込まれたTrackBack Ping URLを取得 * class TrackBack_XML XMLからTrackBack Ping IDを取得するクラス * == Referer 対応分 == * ref_save($page) Referer データ保存(更新) // pukiwiki.php */ // TrackBack Ping IDを取得 function tb_get_id($page) { return md5($page); } // TrackBack Ping ID からページ名を取得 function tb_id2page($tb_id) { static $pages, $cache = array(); if (isset($cache[$tb_id])) return $cache[$tb_id]; if (! isset($pages)) $pages = get_existpages(); foreach ($pages as $page) { $_tb_id = tb_get_id($page); $cache[$_tb_id] = $page; unset($pages[$page]); if ($_tb_id == $tb_id) return $page; } return FALSE; // Not found } // TrackBack Ping データファイル名を取得 function tb_get_filename($page, $ext = '.txt') { return TRACKBACK_DIR . encode($page) . $ext; } // TrackBack Ping データ個数取得 function tb_count($page, $ext = '.txt') { $filename = tb_get_filename($page, $ext); return file_exists($filename) ? count(file($filename)) : 0; } // TrackBack Ping 送信 function tb_send($page, $data) { global $script, $trackback; if (! $trackback) return; // 処理実行時間制限(php.ini オプション max_execution_time ) if (ini_get('safe_mode') == '0') set_time_limit(0); $data = convert_html($data); // convert_html() 変換結果の タグから URL 抽出 preg_match_all('#href="(https?://[^"]+)"#', $data, $links, PREG_PATTERN_ORDER); // 自ホスト($scriptで始まるurl)を除く $links = preg_grep("/^(?!".preg_quote($script,'/')."\?)./", $links[1]); // リンク無しは終了 if (! is_array($links) || empty($links)) return; $r_page = rawurlencode($page); $excerpt = strip_htmltag(convert_html(get_source($page))); // 自文書の情報 $putdata = array( 'title' => $page, // タイトルはページ名 'url' => "$script?$r_page", // 送信時に再度、rawurlencode される 'excerpt' => mb_strimwidth(preg_replace("/[\r\n]/", ' ', $excerpt), 0, 255, '...'), 'blog_name' => 'PukiWiki/TrackBack 0.1', 'charset' => SOURCE_ENCODING // 送信側文字コード(未既定) ); foreach ($links as $link) { // URL から TrackBack ID を取得する $tb_id = tb_get_url($link); if (empty($tb_id)) continue; // Trackback is not supported $result = http_request($tb_id, 'POST', '', $putdata); // FIXME: エラー処理を行っても、じゃ、どうする?だしなぁ... } } // TrackBack Ping データ削除 function tb_delete($page) { $filename = tb_get_filename($page); if (file_exists($filename)) @unlink($filename); } // TrackBack Ping データ入力 function tb_get($file, $key = 1) { if (! file_exists($file)) return array(); $result = array(); $fp = @fopen($file, 'r'); set_file_buffer($fp, 0); flock($fp, LOCK_EX); rewind($fp); while ($data = @fgetcsv($fp, 8192, ',')) { // $data[$key] = URL $result[rawurldecode($data[$key])] = $data; } flock($fp, LOCK_UN); fclose ($fp); return $result; } // 文章中に trackback:ping を埋め込むためのデータを生成 function tb_get_rdf($page) { global $trackback; if (! $trackback) return ''; $r_page = rawurlencode($page); $tb_id = tb_get_id($page); // $dcdate = substr_replace(get_date('Y-m-d\TH:i:sO', $time), ':', -2, 0); // dc:date="$dcdate" $_script = get_script_uri(); // Get absolute path return << --> EOD; } // 文書をGETし、埋め込まれたTrackBack Ping urlを取得 function tb_get_url($url) { // プロキシを経由する必要があるホストにはpingを送信しない $parse_url = parse_url($url); if (empty($parse_url['host']) || via_proxy($parse_url['host'])) return ''; $data = http_request($url); if ($data['rc'] !== 200) return ''; if (! preg_match_all('#]*>(.*?)#si', $data['data'], $matches, PREG_PATTERN_ORDER)) return ''; $obj = new TrackBack_XML(); foreach ($matches[1] as $body) { $tb_url = $obj->parse($body, $url); if ($tb_url !== FALSE) return $tb_url; } return ''; } // 埋め込まれたデータから TrackBack Ping urlを取得するクラス class TrackBack_XML { var $url; var $tb_url; function parse($buf, $url) { // 初期化 $this->url = $url; $this->tb_url = FALSE; $xml_parser = xml_parser_create(); if ($xml_parser === FALSE) return FALSE; xml_set_element_handler($xml_parser, array(& $this, 'start_element'), array(& $this, 'end_element')); if (! xml_parse($xml_parser, $buf, TRUE)) { /* die(sprintf('XML error: %s at line %d in %s', xml_error_string(xml_get_error_code($xml_parser)), xml_get_current_line_number($xml_parser), $buf )); */ return FALSE; } return $this->tb_url; } function start_element($parser, $name, $attrs) { if ($name !== 'RDF:DESCRIPTION') return; $about = $url = $tb_url = ''; foreach ($attrs as $key=>$value) { switch ($key) { case 'RDF:ABOUT': $about = $value; break; case 'DC:IDENTIFER': case 'DC:IDENTIFIER': $url = $value; break; case 'TRACKBACK:PING': $tb_url = $value; break; } } if ($about == $this->url || $url == $this->url) { $this->tb_url = $tb_url; } } function end_element($parser, $name) {} } // Referer データ保存(更新) function ref_save($page) { global $referer; if (! $referer || empty($_SERVER['HTTP_REFERER'])) return; $url = $_SERVER['HTTP_REFERER']; // URI の妥当性評価 // 自サイト内の場合は処理しない $parse_url = parse_url($url); if (empty($parse_url['host']) || $parse_url['host'] == $_SERVER['HTTP_HOST']) return; // TRACKBACK_DIR の存在と書き込み可能かの確認 if (! is_dir(TRACKBACK_DIR)) die(TRACKBACK_DIR.': No such directory'); if (! is_writable(TRACKBACK_DIR)) die(TRACKBACK_DIR.': Permission denied'); // Referer のデータを更新 if (ereg("[,\"\n\r]", $url)) $url = '"' . str_replace('"', '""', $url) . '"'; $filename = tb_get_filename($page, '.ref'); $data = tb_get($filename, 3); $d_url = rawurldecode($url); if (! isset($data[$d_url])) { // 0:最終更新日時, 1:初回登録日時, 2:参照カウンタ, 3:Referer ヘッダ, 4:利用可否フラグ(1は有効) $data[$d_url] = array(UTIME, UTIME, 0, $url, 1); } $data[$d_url][0] = UTIME; $data[$d_url][2]++; $fp = fopen($filename, 'w'); if ($fp === FALSE) return 1; set_file_buffer($fp, 0); flock($fp, LOCK_EX); rewind($fp); foreach ($data as $line) { fwrite($fp, join(',', $line) . "\n"); } flock($fp, LOCK_UN); fclose($fp); return 0; } ?>