1<?php
2
3/**
4 * Plugin facebookevents: Displays facebook events.
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's 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_EVENTS_APPLICATION_ID", "appid" );
23define( "FB_EVENTS_SECRET", "secret" );
24define( "FB_EVENTS_FAN_PAGE_ID", "fanpageid" );
25define( "FB_EVENTS_SHOW_AS", "showAs" );
26define( "FB_EVENTS_FROM_DATE", "from" );
27define( "FB_EVENTS_TO_DATE", "to" );
28define( "FB_EVENTS_NR_ENTRIES", "numberOfEntries" );
29define( "FB_EVENTS_SHOW_END_TIMES", "showEndTimes" );
30define( "FB_EVENTS_LIMIT", "limit" );
31
32// Configuration parameters
33define( "FB_EVENTS_DATE_FORMAT", "dformat" );
34define( "FB_EVENTS_TIME_FORMAT", "tformat" );
35define( "FB_EVENTS_TEMPLATE", "template" );
36
37/**
38 * This plugin retrieves facebook events and displays them in HTML.
39 *
40 * Usage: {{facebookevents#appid=1234&secret=12345&fanpageid=12345&showAs=default}}
41 *
42 */
43class syntax_plugin_facebookevents extends DokuWiki_Syntax_Plugin
44{
45    function getInfo() {
46      return array(
47        'author' => 'J. Drost-Tenfelde',
48        'email'  => 'info@drost-tenfelde.de',
49        'date'   => '20162-09-29',
50        'name'   => 'facebookevents',
51        'desc'   => 'Displays facebook events as HTML',
52        'url'    => 'https://www.dokuwiki.org/plugin:facebookevents',
53      );
54    }
55
56    // implement necessary Dokuwiki_Syntax_Plugin methods
57    function getType() {
58        return 'substition';
59    }
60
61    function getSort() {
62        return 42;
63    }
64
65    function connectTo($mode) {
66        $this->Lexer->addSpecialPattern('\{\{facebookevents.*?\}\}',$mode,'plugin_facebookevents');
67    }
68
69	function getData($url) {
70		$ch = curl_init();
71		$timeout = 5;
72		curl_setopt($ch, CURLOPT_URL, $url);
73		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
74		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
75		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
76		$data = curl_exec($ch);
77		curl_close($ch);
78		return $data;
79	}
80
81	/**
82	 * parse parameters from the {{facebookevents#...}} tag.
83	 * @return an array that will be passed to the renderer function
84	 */
85	function handle($match, $state, $pos, &$handler) {
86        $match = substr($match, 17, -2);
87		parse_str($match, $params);
88
89		// Make sure the necessary data is set
90		if ( !$params[FB_EVENTS_APPLICATION_ID] ) {
91		  $this->error = $this->getLang('error_appid_not_set');
92        }
93        if ( !$params[FB_EVENTS_SECRET] ) {
94		  $this->error = $this->getLang('error_secret_not_set');
95        }
96        if ( !$params[FB_EVENTS_FAN_PAGE_ID] ) {
97		  $this->error = $this->getLang('error_fanpageid_not_set');
98        }
99        if ( !$params[FB_EVENTS_SHOW_AS] ) {
100            $params[FB_EVENTS_SHOW_AS] = 'default';
101        }
102        if ( !$params[FB_EVENTS_LIMIT] ) {
103            $params[FB_EVENTS_LIMIT] = 0;
104        }
105
106        // Get the appropriate display template
107        $template = $this->getConf( $params[FB_EVENTS_SHOW_AS] );
108        if ( !isset($template ) || $template == '' ) {
109			$template = $this->getConf('default');
110		}
111        $params[FB_EVENTS_TEMPLATE] = $template;
112
113		// From
114		if ($params[FB_EVENTS_FROM_DATE] == 'today') {
115			$from = time();
116		} else if (preg_match('#(\d\d)/(\d\d)/(\d\d\d\d)#', $params[FB_EVENTS_FROM_DATE], $fromDate)) {
117			// must be MM/dd/yyyy
118			$from = mktime(0, 0, 0, $fromDate[2], $fromDate[1], $fromDate[3]);
119		} else if (preg_match('/\d+/', $params[FB_EVENTS_FROM_DATE])) {
120			$from = $params[FB_EVENTS_FROM_DATE];
121		}
122		$params[FB_EVENTS_FROM_DATE] = $from;
123
124        // Get the to parameter
125		if ($params[FB_EVENTS_TO_DATE] == 'today') {
126			$to = mktime(24, 0, 0, date("m") , date("d"), date("Y"));
127
128		} else if (preg_match('#(\d\d)/(\d\d)/(\d\d\d\d)#', $params[FB_EVENTS_TO_DATE], $toDate)) {
129			// must be MM/dd/yyyy
130			$to = mktime(0, 0, 0, $toDate[2], $toDate[1], $toDate[3]);
131		} else if (preg_match('/\d+/', $params[FB_EVENTS_TO_DATE])) {
132			$to = $params[FB_EVENTS_TO_DATE];
133		}
134		$params[FB_EVENTS_TO_DATE] = $to;
135
136		// Sorting
137		if ( !$params[FB_EVENTS_SORT ] ) {
138            $params[FB_EVENTS_SORT ] = 'ASC';
139        }
140        else {
141            if ( $params[FB_EVENTS_SORT] != 'DESC') {
142                $params[FB_EVENTS_SORT ] = 'ASC';
143            }
144        }
145
146		return $params;
147	}
148
149	/**
150	 * Retrieves the facebook events and parses them to HTML.
151	 */
152	function render($mode, &$renderer, $data) {
153        $info = $this->getInfo();
154
155        $content = '';
156
157		if ($mode == 'xhtml') {
158            // Catch errors
159            if ($this->error) {
160                $renderer->doc .= 'Error in Plugin '.$info['name'].': '.$this->error;
161                return;
162            }
163
164			// Get the date format
165            $date_format = $this->getConf(FB_EVENTS_DATE_FORMAT);
166            $time_format = $this->getConf(FB_EVENTS_TIME_FORMAT);
167
168			// Get the facebook information
169			$fb_app_id = $data[FB_EVENTS_APPLICATION_ID];
170			$fb_secret = $data[FB_EVENTS_SECRET];
171			$fb_page_id = $data[FB_EVENTS_FAN_PAGE_ID];
172
173			// Get the access token using app-id and secret
174			$token_url ="https://graph.facebook.com/oauth/access_token?client_id={$fb_app_id}&client_secret={$fb_secret}&grant_type=client_credentials";
175			$token_data = $this->getData( $token_url );
176
177			$elements = split("=", $token_data );
178			if ( count($elements) < 2) {
179				$renderer->doc .= 'Access token could not be retrieved for Plugin '.$info['name'].': '.$this->error;
180				return;
181			}
182			$fb_access_token = $elements[1];
183
184			// Get the events
185			$since_date = $data[FB_EVENTS_FROM_DATE];
186			$until_date = $data[FB_EVENTS_TO_DATE];
187
188			$fb_fields="id,name,description,place,timezone,start_time,end_time,cover";
189
190			$json_link = "https://graph.facebook.com/v2.7/{$fb_page_id}/events/attending/?fields={$fb_fields}&access_token={$fb_access_token}&since={$since_date}&until={$until_date}";
191			$json = $this->getData( $json_link);
192
193			//$objects = json_decode($json, true, 512, JSON_BIGINT_AS_STRING);
194			$objects = json_decode($json, true);
195
196			// count the number of events
197			$event_count = count($objects['data']);
198			$displayed_entries = 0;
199			// Loop through the events
200			for ($index = $event_count - 1; $index >= 0; $index--){
201				$event = $objects['data'][$index];
202
203				date_default_timezone_set($event['timezone']);
204
205				$start_date = date( $date_format, strtotime($event['start_time']));
206				$start_time = date( $time_format, strtotime($event['start_time']));
207
208				if ( !isset($event['end_time'])) {
209					$event['end_time'] = $event['start_time'];
210				}
211				$end_date = date( $date_format, strtotime($event['end_time']));
212				$end_time = date( $time_format, strtotime($event['end_time']));
213
214				$eid = $event['id'];
215				$name = $event['name'];
216
217				$description = isset($event['description']) ? $event['description'] : "";
218				// Limit?
219				if ( isset( $data[FB_EVENTS_LIMIT]) && ($data[FB_EVENTS_LIMIT] > 0 ) ) {
220					if ( strlen( $description ) > $data[FB_EVENTS_LIMIT] ) {
221						$description = substr( $description, 0, $data[FB_EVENTS_LIMIT] );
222						// Find the first occurance of a space
223						$index = strrpos ( $description, ' ' );
224						$description = substr( $description, 0, $index ).'...';
225					}
226				}
227				$description = str_replace("\r\n", '<html><br /></html>', $description );
228				$description = str_replace("\n", '<html><br /></html>', $description );
229
230
231				$pic = isset($event['cover']['source']) ? $event['cover']['source'] : "https://graph.facebook.com/v2.7/{$fb_page_id}/picture";
232				// Add a fix for urls with get parameters
233				if ( strpos($pic, '?') > 0 )
234				{
235					$pic .= '&.png';
236				}
237
238				// place
239				$place_name = isset($event['place']['name']) ? $event['place']['name'] : "";
240				$street = isset($event['place']['location']['street']) ? $event['place']['location']['street'] : "";
241				$city = isset($event['place']['location']['city']) ? $event['place']['location']['city'] : "";
242				$country = isset($event['place']['location']['country']) ? $event['place']['location']['country'] : "";
243				$zip = isset($event['place']['location']['zip']) ? $event['place']['location']['zip'] : "";
244
245				$location="";
246
247				if ( $place_name && $street & $city && $country && $zip){
248					$location = "{$place_name}, {$street}, {$zip} {$city}, {$country}";
249				}
250				else{
251					$location = "Location not set or event data is too old.";
252				}
253
254				// Build the entry
255				$entry = $data['template'];
256
257				// Replace the values
258				$entry = str_replace('{title}', $name, $entry );
259				$entry = str_replace('{description}', $description, $entry );
260				$entry = str_replace('{location}', $location, $entry );
261				$entry = str_replace('{place}', $place_name, $entry );
262				$entry = str_replace('{city}', $city, $entry );
263				$entry = str_replace('{country}', $country, $entry );
264				$entry = str_replace('{zip}', $zip, $entry );
265				$entry = str_replace('{image}', $pic, $entry);
266				$entry = str_replace('{image_large}', $pic, $entry);
267				$entry = str_replace('{image_small}', $pic, $entry);
268				$entry = str_replace('{image_square}', $pic, $entry);
269
270				// DateTime
271				if ( (!isset( $data[FB_EVENTS_SHOW_END_TIMES])) || $data[FB_EVENTS_SHOW_END_TIMES] == '1' ) {
272
273					// Are they the same date?
274					$compare_start_date = date( "Ymd", strtotime($event['start_time']));
275					$compare_end_date = date( "Ymd", strtotime($event['end_time']));
276
277					if ( $compare_start_date == $compare_end_date ) {
278						$datetime_string = $start_date;
279						//if ( isset($event['is_date_only']) && (!$event['is_date_only'])) {
280							$datetime_string = $datetime_string.' '.$start_time.' - '.$end_time;
281
282						//}
283						$entry = str_replace('{date}', $date_string, $entry );
284						$entry = str_replace('{datetime}', $datetime_string, $entry );
285											}
286					else {
287						$date_string = $start_date.' - '.$end_date;
288						$datetime_string = $date_string;
289						//if ( isset($event['is_date_only']) && (!$event['is_date_only'])) {
290							$datetime_string =  $start_date.' '.$start_time.' - '.$end_date.' '.$end_time;
291						//}
292						$entry = str_replace('{date}', $date_string, $entry );
293						$entry = str_replace('{datetime}', $datetime_string, $entry );
294					}
295				}
296				else {
297					$entry = str_replace('{date}', $start_date, $entry );
298					$entry = str_replace('{datetime}', $start_date.' '.$start_time);
299				}
300
301
302				// [[ url | read more ]
303                $event_url = "http://www.facebook.com/events/".$eid;
304                $entry = str_replace('{url}', $event_url, $entry );
305                $entry = str_replace('{more}', '[['.$event_url.'|'.$this->getLang('read_more').']]', $entry );
306
307				// Add the entry to the content
308				$content .= $entry;
309
310				// Only display a maximum number of entries (if set)
311				$displayed_entries++;
312				if ( isset( $data[FB_EVENTS_NR_ENTRIES] ) && $displayed_entries >= $data[FB_EVENTS_NR_ENTRIES] ) {
313					break;
314				}
315			}
316
317			//$renderer->doc .= $ret;
318			$html = p_render($mode, p_get_instructions( $content ), $info );
319			$renderer->doc .= $html;
320
321			// Set the timezone back to the original
322			//date_default_timezone_set($origin_timezone);
323
324			return true;
325		}
326		return false;
327	}
328}
329
330?>