1<?php 2 3/** 4 * Display component of the DokuWiki Linkback action plugin. Highly influenced by 5 * the discussion plugin of Esther Brunner. 6 * 7 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 8 * @author Gina Haeussge <osd@foosel.net> 9 * @link http://wiki.foosel.net/snippets/dokuwiki/linkback 10 */ 11 12use dokuwiki\Extension\Event; 13 14require_once (DOKU_PLUGIN . 'linkback/tools.php'); 15 16class action_plugin_linkback_display extends DokuWiki_Action_Plugin { 17 18 /** 19 * A little helper. 20 * @var helper_plugin_linkback 21 */ 22 var $tools; 23 24 /** 25 * Constructor 26 */ 27 function __construct() { 28 $this->tools = plugin_load('tools', 'linkback'); 29 } 30 31 /** 32 * Register the eventhandlers. 33 */ 34 function register(Doku_Event_Handler $controller) { 35 $controller->register_hook('TPL_ACT_RENDER', 'AFTER', $this, 'handle_act_render', array ()); 36 $controller->register_hook('RENDERER_CONTENT_POSTPROCESS', 'AFTER', $this, 'handle_content_postprocess', array ()); 37 } 38 39 /** 40 * Handler for the TPL_ACT_RENDER event 41 */ 42 function handle_act_render(Doku_Event $event, $params) { 43 global $ID, $INFO; 44 45 if ($event->data != 'show') 46 return; 47 48 $file = metaFN($ID, '.linkbacks'); 49 $data = array ( 50 'send' => false, 51 'receive' => false, 52 'display' => false, 53 'sentpings' => array (), 54 'receivedpings' => array (), 55 'number' => 0, 56 57 ); 58 59 if (@ file_exists($file)) 60 $data = unserialize(io_readFile($file, false)); 61 62 if (!isset ($_REQUEST['linkback']) || $INFO['perm'] != AUTH_ADMIN) 63 $_REQUEST['linkback'] = 'linkback_show'; 64 65 $lid = isset($_REQUEST['lid']) ? $_REQUEST['lid'] : ''; 66 if (!preg_match('![a-zA-Z0-9]!', $lid)) 67 $_REQUEST['linkback'] = 'linkback_show'; 68 69 switch ($_REQUEST['linkback']) { 70 // toggle show/hide 71 case 'linkback_toggle' : 72 $linkback = $data['receivedpings'][$lid]; 73 $data = $this->_changeLinkbackVisibilities(array($lid), !$linkback['show']); 74 break; 75 // delete linkback 76 case 'linkback_delete' : 77 $data = $this->_deleteLinkbacks(array($lid)); 78 break; 79 // report linkback as ham 80 case 'linkback_ham' : 81 $this->_markLinkbacks(array($lid), false); 82 break; 83 // report linkback as spam 84 case 'linkback_spam' : 85 $this->_markLinkbacks(array($lid), true); 86 break; 87 } 88 89 $this->_show($data); 90 } 91 92 /** 93 * Shows all linkbacks for the current page 94 */ 95 function _show($data) { 96 global $ID; 97 98 if (!$data['display']) 99 return; 100 101 if ((count($data['receivedpings']) == 0) && 102 (!$this->getConf('show_trackback_url') || !$this->getConf('enable_trackback'))) 103 return; 104 105 // section title 106 $title = $this->getLang('linkbacks'); 107 echo '<div class="linkback_wrapper">'; 108 echo '<h2><a name="linkback__section" id="linkback__section">' . $title . '</a></h2>'; 109 if ($this->getConf('show_trackback_url') && $data['receive']) { 110 echo '<div class="level2 hfeed linkback_trackbackurl">'; 111 echo $this->getLang('trackback_url'); 112 echo '<span class="linkback_trackbackurl">' . DOKU_URL . 'lib/plugins/linkback/exe/trackback.php/' . $ID . '</span>'; 113 echo '</div>'; 114 } 115 echo '<div class="level2 hfeed">'; 116 117 // now display the comments 118 if (isset ($data['receivedpings'])) { 119 foreach ($data['receivedpings'] as $key => $ping) { 120 $this->_print($key, $ping); 121 } 122 } 123 124 echo '</div>'; // level2 125 echo '</div>'; // comment_wrapper 126 } 127 128 /** 129 * Prints an individual linkback 130 */ 131 function _print($lid, $linkback, $visible = true) { 132 global $INFO; 133 global $conf; 134 135 if (!is_array($linkback)) 136 return; // corrupt datatype 137 138 if (!$linkback['show']) { // linkback hidden 139 if ($INFO['perm'] == AUTH_ADMIN) { 140 echo '<div class="linkback_hidden">' . NL; 141 } else { 142 return; 143 } 144 } 145 146 $title = $linkback['title']; 147 $url = $linkback['url']; 148 $date = $linkback['received']; 149 $excerpt = $linkback['excerpt']; 150 $icon = $linkback['favicon']; 151 $type = $linkback['type']; 152 153 // linkback head with date and link 154 echo '<div class="hentry"><div class="linkback_head">' . NL . 155 '<a name="linkback__' . $lid . '" id="linkback__' . $lid . '"></a>' . NL . 156 '<span class="sender">'; 157 158 // show favicon image 159 if ($this->getConf('usefavicon')) { 160 if (!$icon) { 161 $icon = $this->getConf('favicon_default'); 162 } 163 164 $size = 16; 165 $src = ml($icon); 166 echo '<img src="' . $src . '" class="medialeft photo" title="' . $url . '"' . 167 ' width="' . $size . '" height="' . $size . '" />' . NL; 168 $style = ' style="margin-left: ' . ($size +14) . 'px;"'; 169 } else { 170 $style = ' style="margin-left: 20px;"'; 171 } 172 173 echo $this->external_link($url, ($linkback['blog_title'] ? $linkback['blog_title'] . ': ' : '') . $title, 'urlextern url fn'); 174 echo '</span>, <abbr class="received" title="' . gmdate('Y-m-d\TH:i:s\Z', $date) . 175 '">' . strftime($conf['dformat'], $date) . '</abbr>'; 176 echo ' (<abbr class="type" title="' . $this->getLang('linkback_type_' . $type) . '">' . $this->getLang('linkback_type_' . $type) . '</abbr>)'; 177 echo NL . '</div>' . NL; // class="linkback_head" 178 179 // main linkback content 180 if (strlen($excerpt) > 0) { 181 echo '<div class="linkback_body entry-content"' . 182 ($this->getConf('usefavicon') ? $style : '') . '>' . NL . 183 $excerpt . NL . '</div>' . NL; // class="linkback_body" 184 } 185 echo '</div>' . NL; // class="hentry" 186 187 echo '<div class="linkback_buttons">' . NL; 188 if ($INFO['perm'] == AUTH_ADMIN) { 189 if (!$linkback['show']) { 190 $label = $this->getLang('btn_show'); 191 } else { 192 $label = $this->getLang('btn_hide'); 193 } 194 195 $this->_button($lid, $label, 'linkback_toggle'); 196 $this->_button($lid, $this->getLang('btn_ham'), 'linkback_ham'); 197 $this->_button($lid, $this->getLang('btn_spam'), 'linkback_spam'); 198 $this->_button($lid, $this->getLang('btn_delete'), 'linkback_delete'); 199 } 200 echo '</div>'; 201 202 echo '<div class="linkback_line" ' . ($this->getConf('usefavicon') ? $style : '') . '> </div>' . NL; 203 204 if (!$linkback['show']) { 205 echo '</div>' . NL; // class="linkback_hidden" 206 } 207 } 208 209 /** 210 * General button function. 211 * 212 * Code mostly taken from the discussion plugin by Esther Brunner. 213 */ 214 function _button($lid, $label, $act) { 215 global $ID; 216?> 217 <form class="button" method="post" action="<?php echo script() ?>"> 218 <div class="no"> 219 <input type="hidden" name="id" value="<?php echo $ID ?>" /> 220 <input type="hidden" name="do" value="show" /> 221 <input type="hidden" name="linkback" value="<?php echo $act ?>" /> 222 <input type="hidden" name="lid" value="<?php echo $lid ?>" /> 223 <input type="submit" value="<?php echo $label ?>" class="button" title="<?php echo $label ?>" /> 224 </div> 225 </form> 226 <?php 227 228 229 return true; 230 } 231 232 /** 233 * Adds a TOC entry for the linkback section. 234 * 235 * Code mostly taken from the discussion plugin by Esther Brunner. 236 */ 237 function handle_content_postprocess(Doku_Event $event, $params) { 238 global $ID; 239 global $conf; 240 241 if ($event->data[0] != 'xhtml') 242 return; // nothing to do for us 243 244 $file = metaFN($ID, '.linkbacks'); 245 if (!@ file_exists($file)) 246 return; 247 $data = unserialize(io_readFile($file, false)); 248 if (!$data['display'] || (count($data['receivedpings']) == 0)) 249 return; // no linkback section 250 251 $pattern = '/<div id="toc__inside">(.*?)<\/div>\s<\/div>/s'; 252 if (!preg_match($pattern, $event->data[1], $match)) 253 return; // no TOC on this page 254 255 $title = $this->getLang('linkbacks'); 256 $section = '#linkback__section'; 257 $level = 3 - $conf['toptoclevel']; 258 259 $item = '<li class="level' . $level . '"><div class="li"><span class="li"><a href="' . 260 $section . '" class="toc">' . $title . '</a></span></div></li>'; 261 262 if ($level == 1) 263 $search = "</ul>\n</div>"; 264 else 265 $search = "</ul>\n</li></ul>\n</div>"; 266 267 $new = str_replace($search, $item . $search, $match[0]); 268 $event->data[1] = preg_replace($pattern, $new, $event->data[1]); 269 } 270 271 function _changeLinkbackVisibilities($lids, $visible) { 272 global $ID; 273 274 $file = metaFN($ID, '.linkbacks'); 275 $data = array ( 276 'send' => false, 277 'receive' => false, 278 'display' => false, 279 'sentpings' => array (), 280 'receivedpings' => array (), 281 'number' => 0, 282 283 ); 284 285 if (@ file_exists($file)) 286 $data = unserialize(io_readFile($file, false)); 287 $update = false; 288 289 foreach ($lids as $lid) { 290 $linkback = $data['receivedpings'][$lid]; 291 if ($linkback['show'] == $visible) 292 continue; 293 294 $linkback['show'] = $visible; 295 if ($linkback['show']) 296 $data['number']++; 297 else 298 $data['number']--; 299 $data['receivedpings'][$lid] = $linkback; 300 $this->tools->addLogEntry($linkback['received'], $ID, (($linkback['show']) ? 'sl' : 'hl'), '', $linkback['lid']); 301 $update = true; 302 } 303 304 if ($update) 305 io_saveFile($file, serialize($data)); 306 return $data; 307 } 308 309 function _deleteLinkbacks($lids) { 310 global $ID; 311 312 $file = metaFN($ID, '.linkbacks'); 313 $data = array ( 314 'send' => false, 315 'receive' => false, 316 'display' => false, 317 'sentpings' => array (), 318 'receivedpings' => array (), 319 'number' => 0, 320 321 ); 322 323 if (@ file_exists($file)) 324 $data = unserialize(io_readFile($file, false)); 325 $update = false; 326 327 foreach ($lids as $lid) { 328 $linkback = $data['receivedpings'][$lid]; 329 unset ($data['receivedpings'][$lid]); 330 if ($linkback['show']) 331 $data['number']--; 332 $this->tools->addLogEntry($linkback['received'], $ID, 'dl', '', $linkback['lid']); 333 $update = true; 334 } 335 336 if ($update) 337 io_saveFile($file, serialize($data)); 338 return $data; 339 } 340 341 function _markLinkbacks($lids, $isSpam) { 342 global $ID; 343 344 $file = metaFN($ID, '.linkbacks'); 345 $data = array ( 346 'send' => false, 347 'receive' => false, 348 'display' => false, 349 'sentpings' => array (), 350 'receivedpings' => array (), 351 'number' => 0, 352 353 ); 354 355 if (@ file_exists($file)) 356 $data = unserialize(io_readFile($file, false)); 357 358 foreach ($lids as $lid) { 359 $linkback = $data['receivedpings'][$lid]; 360 if ($isSpam) { 361 Event::createAndTrigger('ACTION_LINKBACK_SPAM', $linkback); 362 } else { 363 Event::createAndTrigger('ACTION_LINKBACK_HAM', $linkback); 364 } 365 } 366 } 367 368} 369