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