1<?php 2 3/** 4 * Internal helper functions for use with the DokuWiki Linkback Plugin. 5 * 6 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 7 * @author Gina Haeussge <osd@foosel.net> 8 * @link http://wiki.foosel.net/snippets/dokuwiki/linkback 9 */ 10 11// must be run within Dokuwiki 12if (!defined('DOKU_INC')) 13 die(); 14 15if (!defined('DOKU_LF')) 16 define('DOKU_LF', "\n"); 17if (!defined('DOKU_TAB')) 18 define('DOKU_TAB', "\t"); 19 20require_once (DOKU_INC . 'inc/init.php'); 21require_once (DOKU_INC . 'inc/common.php'); 22require_once (DOKU_INC . 'inc/mail.php'); 23require_once (DOKU_PLUGIN . 'linkback/http.php'); 24 25class tools_plugin_linkback extends DokuWiki_Plugin { 26 27 function DokuWiki_Linkback_Interface() { 28 $this->DokuWiki_Plugin(); 29 } 30 31 /** 32 * Retrieves a favicon for the given page. 33 */ 34 function getFavicon($url, $page) { 35 $urlparts = parse_url($url); 36 37 $regex = '!<link rel="(shortcut )?icon" href="([^"]+)" ?/?>!'; 38 if (preg_match($regex, $page, $match)) { 39 $icon = $match[2]; 40 if (!preg_match("#^(http://)?[^/]+#i", $icon)) { 41 $icon = $urlparts['scheme'] . '://' . $urlparts['host'] . (($icon[0]) == '/' ? '' : '/') . $icon; 42 } 43 return $icon; 44 } 45 46 $icon = $urlparts['scheme'] . '://' . $urlparts['host'] . '/favicon.ico'; 47 48 $http_client = new LinkbackHTTPClient(); 49 $http_client->sendRequest($icon, array (), 'HEAD'); 50 if ($http_client->status == 200) 51 return $icon; 52 else 53 return $this->getConf('favicon_default'); 54 } 55 56 /** 57 * Retrieves $conf['range']kB of $url and returns headers and retrieved body. 58 */ 59 function getPage($url) { 60 $range = $this->getConf('range') * 1024; 61 62 $http_client = new LinkbackHTTPClient(); 63 $http_client->headers['Range'] = 'bytes=0-' . $range; 64 $http_client->max_bodysize = $range; 65 $http_client->max_bodysize_limit = true; 66 67 $retval = $http_client->get($url, true); 68 69 return array ( 70 'success' => $retval, 71 'headers' => $http_client->resp_headers, 72 'body' => $http_client->resp_body, 73 'error' => $http_client->error, 74 'status' => $http_client->status, 75 ); 76 } 77 78 /** 79 * Sends a notify mail on new linkback 80 * 81 * @param string $ID id of the wiki page for which the 82 * linkback was received 83 * @param array $comment data array of the new linkback 84 * 85 * @author Andreas Gohr <andi@splitbrain.org> 86 * @author Esther Brunner <wikidesign@gmail.com> 87 * @author Gina Haeussge <osd@foosel.net> 88 */ 89 function notify($ID, $linkback) { 90 global $conf; 91 92 if (!$conf['notify']) 93 return; 94 $to = $conf['notify']; 95 $text = io_readFile($this->localFN('subscribermail')); 96 97 $search = array ( 98 '@PAGE@', 99 '@TITLE@', 100 '@DATE@', 101 '@URL@', 102 '@TEXT@', 103 '@UNSUBSCRIBE@', 104 '@DOKUWIKIURL@', 105 '@PAGEURL@', 106 107 ); 108 $replace = array ( 109 $ID, 110 $conf['title'], 111 strftime($conf['dformat'], $linkback['received']), 112 $linkback['url'], 113 $linkback['excerpt'], 114 wl($ID, 'do=unsubscribe', true, '&'), 115 DOKU_URL, 116 wl($ID, '', true), 117 ); 118 $text = str_replace($search, $replace, $text); 119 120 $subject = '[' . $conf['title'] . '] ' . $this->getLang('mail_newlinkback'); 121 122 mail_send($to, $subject, $text, $conf['mailfrom'], ''); 123 124 } 125 126 /** 127 * Adds an entry to the linkbacks changelog 128 * 129 * @author Esther Brunner <wikidesign@gmail.com> 130 * @author Ben Coburn <btcoburn@silicodon.net> 131 * @author Gina Haeussge <osd@foosel.net> 132 */ 133 function addLogEntry($date, $id, $type = 'cl', $summary = '', $extra = '') { 134 global $conf; 135 136 $changelog = $conf['metadir'] . '/_linkbacks.changes'; 137 138 if (!$date) 139 $date = time(); //use current time if none supplied 140 $remote = $_SERVER['REMOTE_ADDR']; 141 $user = $_SERVER['REMOTE_USER']; 142 143 $strip = array ( 144 "\t", 145 "\n" 146 ); 147 $logline = array ( 148 'date' => $date, 149 'ip' => $remote, 150 'type' => str_replace($strip, 151 '', 152 $type 153 ), 'id' => $id, 'user' => $user, 'sum' => str_replace($strip, '', $summary), 'extra' => str_replace($strip, '', $extra)); 154 155 // add changelog line 156 $logline = implode("\t", $logline) . "\n"; 157 io_saveFile($changelog, $logline, true); //global changelog cache 158 $this->_trimRecentCommentsLog($changelog); 159 } 160 161 /** 162 * Trims the recent comments cache to the last $conf['changes_days'] recent 163 * changes or $conf['recent'] items, which ever is larger. 164 * The trimming is only done once a day. 165 * 166 * @author Ben Coburn <btcoburn@silicodon.net> 167 */ 168 function _trimRecentCommentsLog($changelog) { 169 global $conf; 170 171 if (@ file_exists($changelog) && (filectime($changelog) + 86400) < time() && !@ file_exists($changelog . 172 '_tmp')) { 173 174 io_lock($changelog); 175 $lines = file($changelog); 176 if (count($lines) < $conf['recent']) { 177 // nothing to trim 178 io_unlock($changelog); 179 return true; 180 } 181 182 io_saveFile($changelog . '_tmp', ''); // presave tmp as 2nd lock 183 $trim_time = time() - $conf['recent_days'] * 86400; 184 $out_lines = array (); 185 186 $linecount = count($lines); 187 for ($i = 0; $i < $linecount; $i++) { 188 $log = parseChangelogLine($lines[$i]); 189 if ($log === false) 190 continue; // discard junk 191 if ($log['date'] < $trim_time) { 192 $old_lines[$log['date'] . ".$i"] = $lines[$i]; // keep old lines for now (append .$i to prevent key collisions) 193 } else { 194 $out_lines[$log['date'] . ".$i"] = $lines[$i]; // definitely keep these lines 195 } 196 } 197 198 // sort the final result, it shouldn't be necessary, 199 // however the extra robustness in making the changelog cache self-correcting is worth it 200 ksort($out_lines); 201 $extra = $conf['recent'] - count($out_lines); // do we need extra lines do bring us up to minimum 202 if ($extra > 0) { 203 ksort($old_lines); 204 $out_lines = array_merge(array_slice($old_lines, - $extra), $out_lines); 205 } 206 207 // save trimmed changelog 208 io_saveFile($changelog . '_tmp', implode('', $out_lines)); 209 @ unlink($changelog); 210 if (!rename($changelog . '_tmp', $changelog)) { 211 // rename failed so try another way... 212 io_unlock($changelog); 213 io_saveFile($changelog, implode('', $out_lines)); 214 @ unlink($changelog . '_tmp'); 215 } else { 216 io_unlock($changelog); 217 } 218 return true; 219 } 220 } 221 222 function addProcessLogEntry($data) { 223 global $conf; 224 225 io_saveFile($conf['cachedir'].'/linkback.log',join("\n",$data)."\n\n",true); 226 } 227 228} 229