1<?php 2 3/** 4 * Plugin facebookwall: Displays status messages on a facebook wall. 5 * 6 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 7 * @version 1.2 8 * @date September 2016 9 * @author J. Drost-Tenfelde <info@drost-tenfelde.de> 10 * 11 * This plugin uses Facebook Graph API v2.7. 12 * 13 */ 14 15// must be run within Dokuwiki 16if(!defined('DOKU_INC')) die(); 17 18if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 19require_once(DOKU_PLUGIN.'syntax.php'); 20 21// Syntax parameters 22define( "FB_WALL_APPLICATION_ID", "appid" ); // Facebook application id 23define( "FB_WALL_SECRET", "secret" ); // Facebook secret 24define( "FB_WALL_FAN_PAGE_ID", "fanpageid" ); // Facebook page id 25define( "FB_WALL_SHOW_AS", "showAs" ); // Allow alternate displaying of the status messages 26define( "FB_WALL_FROM_DATE", "from" ); // date from which to include the status message 27define( "FB_WALL_TO_DATE", "to" ); // date to which to include status messages 28define( "FB_WALL_NR_ENTRIES", "numberOfEntries" ); // maximum number of entries 29define( "FB_WALL_SORT", "sort" ); // Sort by create date ASC or DESC 30define( "FB_WALL_LIMIT", "limit" ); // Limit size of the description by number of chars 31 32// Configuration parameters 33define( "FB_WALL_DATE_FORMAT", "dformat" ); // Date format 34define( "FB_WALL_TIME_FORMAT", "tformat" ); // Time format 35define( "FB_WALL_TEMPLATE", "template" ); // Template 36define( "FB_WALL_PICTURE_MAX_WIDTH", "maxWidth" ); // Maximum allowed width for attachment picture 37define( "FB_WALL_PICTURE_MAX_HEIGHT", "maxHeight" ); // Maximum allowed height for attachment picture 38 39/** 40 * This plugin retrieves facebook status messages and displays them in HTML. 41 * 42 * Usage: {{facebookwall#appid=1234&secret=12345&fanpageid=12345&showAs=default}} 43 * 44 */ 45class syntax_plugin_facebookwall extends DokuWiki_Syntax_Plugin 46{ 47 function getInfo() { 48 return array( 49 'author' => 'J. Drost-Tenfelde', 50 'email' => 'info@drost-tenfelde.de', 51 'date' => '2012-02-09', 52 'name' => 'facebookwall', 53 'desc' => 'Displays status messages on a facebook wall', 54 'url' => 'http://www.drost-tenfelde.de/?id=dokuwiki:plugins:facebookwall', 55 ); 56 } 57 58 // implement necessary Dokuwiki_Syntax_Plugin methods 59 function getType() { 60 return 'substition'; 61 } 62 63 function getSort() { 64 return 42; 65 } 66 67 function connectTo($mode) { 68 $this->Lexer->addSpecialPattern('\{\{facebookwall.*?\}\}',$mode,'plugin_facebookwall'); 69 } 70 71 function getData($url) { 72 $ch = curl_init(); 73 $timeout = 5; 74 curl_setopt($ch, CURLOPT_URL, $url); 75 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 76 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); 77 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 78 $data = curl_exec($ch); 79 curl_close($ch); 80 return $data; 81 } 82 83 /** 84 * parse parameters from the {{facebookwall#...}} tag. 85 * @return an array that will be passed to the renderer function 86 */ 87 function handle($match, $state, $pos, &$handler) { 88 $match = substr($match, 15, -2); 89 parse_str($match, $params); 90 91 // Make sure the necessary data is set 92 if ( !$params[FB_WALL_APPLICATION_ID] ) { 93 $this->error = $this->getLang('error_appid_not_set'); 94 } 95 if ( !$params[FB_WALL_SECRET] ) { 96 $this->error = $this->getLang('error_secret_not_set'); 97 } 98 if ( !$params[FB_WALL_FAN_PAGE_ID] ) { 99 $this->error = $this->getLang('error_fanpageid_not_set'); 100 } 101 if ( !$params[FB_WALL_SHOW_AS] ) { 102 $params[FB_WALL_SHOW_AS] = 'default'; 103 } 104 if ( !$params[FB_WALL_LIMIT] ) { 105 $params[FB_WALL_LIMIT] = 0; 106 } 107 108 // Max width 109 $maxWidth = $this->getConf( FB_WALL_PICTURE_MAX_WIDTH ); 110 if ( !isset($maxWidth ) || $maxWidth == '' ) { 111 $maxWidth = 999; 112 } 113 $params[FB_WALL_PICTURE_MAX_WIDTH] = $maxWidth; 114 115 // Max height 116 $maxHeight = $this->getConf( FB_WALL_PICTURE_MAX_HEIGHT ); 117 if ( !isset($maxHeight) || $maxHeight== '' ) { 118 $maxHeight = 0; 119 } 120 $params[FB_WALL_PICTURE_MAX_HEIGHT] = $maxHeight; 121 122 // Get the appropriate display template 123 $template = $this->getConf( $params[FB_WALL_SHOW_AS] ); 124 if ( !isset($template ) || $template == '' ) { 125 $template = $this->getConf('default'); 126 } 127 $params[FB_WALL_TEMPLATE] = $template; 128 129 // Get the FROM_DATE parameter 130 if ($params[FB_WALL_FROM_DATE] == 'today') { 131 $from = time(); 132 } 133 else if (preg_match('#(\d\d)/(\d\d)/(\d\d\d\d)#', $params[FB_WALL_FROM_DATE], $fromDate)) { 134 // must be MM/dd/yyyy 135 $from = mktime(0, 0, 0, $fromDate[1], $fromDate[2], $fromDate[3]); 136 } 137 else if (preg_match('/\d+/', $params[FB_WALL_FROM_DATE])) { 138 $from = $params[FB_WALL_FROM_DATE]; 139 } 140 $params[FB_WALL_FROM_DATE] = $from; 141 142 // Get the to parameter 143 if ($params[FB_WALL_TO_DATE] == 'today') { 144 $to = mktime(24, 0, 0, date("m") , date("d"), date("Y")); 145 146 } 147 else if (preg_match('#(\d\d)/(\d\d)/(\d\d\d\d)#', $params[FB_WALL_TO_DATE], $toDate)) { 148 // must be MM/dd/yyyy 149 $to = mktime(0, 0, 0, $toDate[1], $toDate[2], $toDate[3]); 150 } 151 else if (preg_match('/\d+/', $params[FB_WALL_TO_DATE])) { 152 $to = $params[FB_WALL_TO_DATE]; 153 } 154 $params[FB_WALL_TO_DATE] = $to; 155 156 // Sorting 157 if ( !$params[FB_WALL_SORT ] ) { 158 $params[FB_WALL_SORT ] = 'DESC'; 159 } 160 else { 161 if ( $params[FB_WALL_SORT] != 'ASC') { 162 $params[FB_WALL_SORT ] = 'DESC'; 163 } 164 } 165 166 return $params; 167 } 168 169 /** 170 * Retrieves the facebook events and parses them to HTML. 171 */ 172 function render($mode, &$renderer, $data) { 173 global $conf; 174 175 $info = $this->getInfo(); 176 177 $content = ''; 178 179 if ($mode == 'xhtml') { 180 // Catch errors 181 if ($this->error) { 182 $renderer->doc .= 'Error in Plugin '.$info['name'].': '.$this->error; 183 return; 184 } 185 186 // Get the facebook information 187 $fb_app_id = $data[FB_WALL_APPLICATION_ID]; 188 $fb_secret = $data[FB_WALL_SECRET]; 189 $fb_page_id = $data[FB_WALL_FAN_PAGE_ID]; 190 191 // Get the access token using app-id and secret 192 $token_url ="https://graph.facebook.com/oauth/access_token?client_id={$fb_app_id}&client_secret={$fb_secret}&grant_type=client_credentials"; 193 $token_data = $this->getData( $token_url ); 194 195 $elements = split("=", $token_data ); 196 if ( count($elements) < 2) { 197 $renderer->doc .= 'Access token could not be retrieved for Plugin '.$info['name'].': '.$this->error; 198 return; 199 } 200 $fb_access_token = $elements[1]; 201 202 // Get the date format 203 $date_format = $this->getConf(FB_WALL_DATE_FORMAT); 204 $time_format = $this->getConf(FB_WALL_TIME_FORMAT); 205 $datetime_format = $date_format.' '.$time_format; 206 207 $numberOfEntries = $data[FB_WALL_NR_ENTRIES]; 208 209 // Get the time offset 210 //$offset = $this->get_timezone_offset( "America/Los_Angeles" ); 211 $offset = 0; 212 213 $fields = "id,message,picture,link,name,description,type,icon,created_time,from,object_id"; 214 215 $limit = $numberOfEntries + 5; 216 $json_link = "https://graph.facebook.com/{$fb_page_id}/feed?access_token={$fb_access_token}&fields={$fields}&limit={$limit}"; 217 $json = $this->getData( $json_link); 218 219 //$objects = json_decode($json, true, 512, JSON_BIGINT_AS_STRING); 220 $objects = json_decode($json, true); 221 222 // count the number of wallposts 223 $post_count = count($objects['data']); 224 225 // Loop through the events 226 for ($post_index = 0; $post_index < $post_count; $post_index++) { 227 $post = $objects['data'][$post_index]; 228 229 $entry = $data[FB_WALL_TEMPLATE]; 230 231 // If no message was provided, skip to the next 232 if ( !$post['message'] ) { 233 continue; 234 } 235 236 // If the date is lower than the from date, skip to the next 237 if ( isset($data[FB_WALL_FROM_DATE]) && ($post['created_time'] < $data[FB_WALL_FROM_DATE] ) ) { 238 continue; 239 } 240 // If the date is higher than the to data, skip to the next 241 if ( $data[FB_WALL_TO_DATE] && ($post['created_time'] > $data[FB_WALL_TO_DATE] )) { 242 continue; 243 } 244 245 // Limit? 246 if ( isset( $data[FB_WALL_LIMIT]) && ($data[FB_WALL_LIMIT] > 0 ) ) { 247 if ( strlen( $post['message'] ) > $data[FB_WALL_LIMIT] ) { 248 $post['message_short'] = substr( $post['message'], 0, $data[FB_WALL_LIMIT] ).'...'; 249 // Find the first occurance of a space 250 $index = strrpos ( $post['message_short'], ' ' ); 251 $post['message_short'] = substr( $post['message_short'], 0, $index ).'...'; 252 $post['message'] = substr( $post['message_short'], 0, $index ).'...'; 253 } 254 } 255 else { 256 $post['message_short'] = substr( $post['message'], 0, 150 ).'...'; 257 $index = strrpos ( $post['message_short'], ' ' ); 258 $post['message_short'] = substr( $post['message_short'], 0, $index ).'...'; 259 } 260 // Process the message 261 $post['message'] = str_replace("\r\n", '<html><br /></html>', $post['message'] ); 262 $post['message'] = str_replace("\n", '<html><br /></html>', $post['message'] ); 263 $post['message_short'] = str_replace("\r\n", '<html><br /></html>', $post['message_short'] ); 264 $post['message_short'] = str_replace("\n", '<html><br /></html>', $post['message_short'] ); 265 266 $entry = str_replace('{message}', $post['message'], $entry ); 267 $entry = str_replace('{message_short}', $post['message_short'], $entry ); 268 269 // Replace tags in template 270 $entry = str_replace('{date}', date( $date_format, strtotime($post['created_time'])), $entry ); 271 $entry = str_replace('{time}', date( $time_format, strtotime($post['created_time'])), $entry ); 272 $entry = str_replace('{datetime}', date( $datetime_format, strtotime($post['created_time'])), $entry ); 273 $entry = str_replace('{timestamp}', $post['created_time'], $entry ); 274 275 $pic = $post['picture']; 276 // Add a fix for urls with get parameters 277 if ( strpos($pic, '?') > 0 ) 278 { 279 $pic .= '&.png'; 280 } 281 $entry = str_replace('{image}', $pic, $entry ); 282 283 // Url 284 $post_id = $post['id']; 285 $post_values = explode( "_", $post_id); 286 $post_url = "http://www.facebook.com/".$post_values[0]."/posts/".$post_values[1]; 287 $entry = str_replace('{url}', $post_url, $entry ); 288 289 $entry = str_replace('{more}', '[['.$post_url.'|'.$this->getLang('read_more').']]', $entry ); 290 291 // Add the entry to the content 292 $content .= $entry; 293 294 $numberOfEntries--; 295 if ( $numberOfEntries == 0 ) { 296 break; 297 } 298 } 299 300 //$renderer->doc .= $ret; 301 $html = p_render($mode, p_get_instructions( $content ), $info ); 302 $renderer->doc .= $html; 303 304 return true; 305 } 306 return false; 307 } 308 309 function get_timezone_offset($remote_tz, $origin_tz = null) { 310 if($origin_tz === null) { 311 if(!is_string($origin_tz = date_default_timezone_get())) { 312 return false; // A UTC timestamp was returned -- bail out! 313 } 314 } 315 $origin_dtz = new DateTimeZone($origin_tz); 316 $remote_dtz = new DateTimeZone($remote_tz); 317 $origin_dt = new DateTime("now", $origin_dtz); 318 $remote_dt = new DateTime("now", $remote_dtz); 319 $offset = $origin_dtz->getOffset($origin_dt) - $remote_dtz->getOffset($remote_dt); 320 return $offset; 321 } 322 323 /** 324 * Makes a linked image. 325 * 326 * @href link 327 * @alt tooltip 328 * @src location of the image 329 * @data configuration parameters for the plugin. 330 * @conf DokuWiki configuration. 331 * 332 * @return HTML code with linked image. 333 */ 334 function makeImage( $href, $alt, $src, $data, $conf) { 335 $html = '<html><a href="'.$href.'" alt="'.$alt.'" target="'.$conf['target']['extern'].'">'; 336 $html .= '<img src="'.$src.'" align="left"'; 337 338 if ( $data[FB_WALL_PICTURE_MAX_WIDTH] > 0 || $data[FB_WALL_PICTURE_MAX_HEIGHT] > 0) { 339 $html .= ' style="'; 340 if ( $data[FB_WALL_PICTURE_MAX_WIDTH] > 0 ) { 341 $html .= 'max-width: '.$data[FB_WALL_PICTURE_MAX_WIDTH].'px !important;'; 342 } 343 if ( $data[FB_WALL_PICTURE_MAX_HEIGHT] > 0 ) { 344 $html .= 'max-height: '.$data[FB_WALL_PICTURE_MAX_HEIGHT].'px !important;'; 345 } 346 $html .= '"'; 347 } 348 $html .= '/>'; 349 $html .= '</a></html>'; 350 return $html; 351 } 352} 353 354?>