Completed
Push — release-2.1 ( e6c696...22bfba )
by Mathias
07:04
created

Sources/Calendar.php (10 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * This file has only one real task, showing the calendar.
5
 * Original module by Aaron O'Neil - [email protected]
6
 *
7
 * Simple Machines Forum (SMF)
8
 *
9
 * @package SMF
10
 * @author Simple Machines http://www.simplemachines.org
11
 * @copyright 2016 Simple Machines and individual contributors
12
 * @license http://www.simplemachines.org/about/smf/license.php BSD
13
 *
14
 * @version 2.1 Beta 3
15
 */
16
17
if (!defined('SMF'))
18
	die('No direct access...');
19
20
/**
21
 * Show the calendar.
22
 * It loads the specified month's events, holidays, and birthdays.
23
 * It requires the calendar_view permission.
24
 * It depends on the cal_enabled setting, and many of the other cal_ settings.
25
 * It uses the calendar_start_day theme option. (Monday/Sunday)
26
 * It uses the main sub template in the Calendar template.
27
 * It goes to the month and year passed in 'month' and 'year' by get or post.
28
 * It is accessed through ?action=calendar.
29
 * @return void
30
 */
31
function CalendarMain()
32
{
33
	global $txt, $context, $modSettings, $scripturl, $options, $sourcedir, $user_info, $smcFunc;
34
35
	// Permissions, permissions, permissions.
36
	isAllowedTo('calendar_view');
37
38
	// Some global template resources.
39
	$context['calendar_resources'] = array(
40
		'min_year' => $modSettings['cal_minyear'],
41
		'max_year' => $modSettings['cal_maxyear'],
42
	);
43
44
	// Doing something other than calendar viewing?
45
	$subActions = array(
46
		'ical' => 'iCalDownload',
47
		'post' => 'CalendarPost',
48
	);
49
50
	if (isset($_GET['sa']) && isset($subActions[$_GET['sa']]))
51
		return call_helper($subActions[$_GET['sa']]);
52
53
	// You can't do anything if the calendar is off.
54
	if (empty($modSettings['cal_enabled']))
55
		fatal_lang_error('calendar_off', false);
56
57
	// This is gonna be needed...
58
	loadTemplate('Calendar');
59
	loadCSSFile('calendar.css', array('force_current' => false, 'validate' => true, 'rtl' => 'calendar.rtl.css'), 'smf_calendar');
60
61
	// Did the specify an individual event ID? If so, let's splice the year/month in to what we would otherwise be doing.
62
	if (isset($_GET['event']))
63
	{
64
		$evid = (int) $_GET['event'];
65
		if ($evid > 0)
66
		{
67
			$request = $smcFunc['db_query']('', '
68
				SELECT start_date
69
				FROM {db_prefix}calendar
70
				WHERE id_event = {int:event_id}',
71
				array(
72
					'event_id' => $evid,
73
				)
74
			);
75
			if ($row = $smcFunc['db_fetch_assoc']($request))
76
			{
77
				// We know the format is going to be in yyyy-mm-dd from the database, so let's run with that.
78
				list($_REQUEST['year'], $_REQUEST['month']) = explode('-', $row['start_date']);
79
				$_REQUEST['year'] = (int) $_REQUEST['year'];
80
				$_REQUEST['month'] = (int) $_REQUEST['month'];
81
82
				// And we definitely don't want weekly view.
83
				unset ($_GET['viewweek']);
84
85
				// We might use this later.
86
				$context['selected_event'] = $evid;
87
			}
88
			$smcFunc['db_free_result']($request);
89
		}
90
		unset ($_GET['event']);
91
	}
92
93
	// Set the page title to mention the calendar ;).
94
	$context['page_title'] = $txt['calendar'];
95
96
	// Is this a week view?
97
	$context['view_week'] = isset($_GET['viewweek']);
98
99
	// Don't let search engines index weekly calendar pages.
100
	if ($context['view_week'])
101
		$context['robot_no_index'] = true;
102
103
	// Get the current day of month...
104
	require_once($sourcedir . '/Subs-Calendar.php');
105
	$today = getTodayInfo();
106
107
	// If the month and year are not passed in, use today's date as a starting point.
108
	$curPage = array(
109
		'day' => isset($_REQUEST['day']) ? (int) $_REQUEST['day'] : $today['day'],
110
		'month' => isset($_REQUEST['month']) ? (int) $_REQUEST['month'] : $today['month'],
111
		'year' => isset($_REQUEST['year']) ? (int) $_REQUEST['year'] : $today['year']
112
	);
113
114
	// Make sure the year and month are in valid ranges.
115
	if ($curPage['month'] < 1 || $curPage['month'] > 12)
116
		fatal_lang_error('invalid_month', false);
117 View Code Duplication
	if ($curPage['year'] < $modSettings['cal_minyear'] || $curPage['year'] > $modSettings['cal_maxyear'])
118
		fatal_lang_error('invalid_year', false);
119
	// If we have a day clean that too.
120
	if ($context['view_week'])
121
	{
122
		// Note $isValid is -1 < PHP 5.1
123
		$isValid = mktime(0, 0, 0, $curPage['month'], $curPage['day'], $curPage['year']);
124
		if ($curPage['day'] > 31 || !$isValid || $isValid == -1)
125
			fatal_lang_error('invalid_day', false);
126
	}
127
128
	// Load all the context information needed to show the calendar grid.
129
	$calendarOptions = array(
130
		'start_day' => !empty($options['calendar_start_day']) ? $options['calendar_start_day'] : 0,
131
		'show_birthdays' => in_array($modSettings['cal_showbdays'], array(1, 2)),
132
		'show_events' => in_array($modSettings['cal_showevents'], array(1, 2)),
133
		'show_holidays' => in_array($modSettings['cal_showholidays'], array(1, 2)),
134
		'highlight' => array(
135
			'events' => isset($modSettings['cal_highlight_events']) ? $modSettings['cal_highlight_events'] : 0,
136
			'holidays' => isset($modSettings['cal_highlight_holidays']) ? $modSettings['cal_highlight_holidays'] : 0,
137
			'birthdays' => isset($modSettings['cal_highlight_birthdays']) ? $modSettings['cal_highlight_birthdays'] : 0,
138
		),
139
		'show_week_num' => true,
140
		'short_day_titles' => !empty($modSettings['cal_short_days']),
141
		'short_month_titles' => !empty($modSettings['cal_short_months']),
142
		'show_next_prev' => !empty($modSettings['cal_prev_next_links']),
143
		'show_week_links' => isset($modSettings['cal_week_links']) ? $modSettings['cal_week_links'] : 0,
144
	);
145
146
	// Load up the main view.
147
	if ($context['view_week'])
148
		$context['calendar_grid_main'] = getCalendarWeek($curPage['month'], $curPage['year'], $curPage['day'], $calendarOptions);
149
	else
150
		$context['calendar_grid_main'] = getCalendarGrid($curPage['month'], $curPage['year'], $calendarOptions);
151
152
	// Load up the previous and next months.
153
	$context['calendar_grid_current'] = getCalendarGrid($curPage['month'], $curPage['year'], $calendarOptions);
154
155
	// Only show previous month if it isn't pre-January of the min-year
156 View Code Duplication
	if ($context['calendar_grid_current']['previous_calendar']['year'] > $modSettings['cal_minyear'] || $curPage['month'] != 1)
157
		$context['calendar_grid_prev'] = getCalendarGrid($context['calendar_grid_current']['previous_calendar']['month'], $context['calendar_grid_current']['previous_calendar']['year'], $calendarOptions, true);
158
159
	// Only show next month if it isn't post-December of the max-year
160 View Code Duplication
	if ($context['calendar_grid_current']['next_calendar']['year'] < $modSettings['cal_maxyear'] || $curPage['month'] != 12)
161
		$context['calendar_grid_next'] = getCalendarGrid($context['calendar_grid_current']['next_calendar']['month'], $context['calendar_grid_current']['next_calendar']['year'], $calendarOptions);
162
163
	// Basic template stuff.
164
	$context['allow_calendar_event'] = allowedTo('calendar_post');
165
166
	// If you don't allow events not linked to posts and you're not an admin, we have more work to do...
167 View Code Duplication
	if ($context['allow_calendar_event'] && empty($modSettings['cal_allow_unlinked']) && !$user_info['is_admin'])
168
	{
169
		$boards_can_post = boardsAllowedTo('post_new');
170
		$context['allow_calendar_event'] &= !empty($boards_can_post);
171
	}
172
173
	$context['can_post'] = $context['allow_calendar_event'];
174
	$context['current_day'] = $curPage['day'];
175
	$context['current_month'] = $curPage['month'];
176
	$context['current_year'] = $curPage['year'];
177
	$context['show_all_birthdays'] = isset($_GET['showbd']);
178
	$context['blocks_disabled'] = !empty($modSettings['cal_disable_prev_next']) ? 1 : 0;
179
180
	// Set the page title to mention the month or week, too
181
	$context['page_title'] .= ' - ' . ($context['view_week'] ? $context['calendar_grid_main']['week_title'] : $txt['months'][$context['current_month']] . ' ' . $context['current_year']);
182
183
	// Load up the linktree!
184
	$context['linktree'][] = array(
185
		'url' => $scripturl . '?action=calendar',
186
		'name' => $txt['calendar']
187
	);
188
	// Add the current month to the linktree.
189
	$context['linktree'][] = array(
190
		'url' => $scripturl . '?action=calendar;year=' . $context['current_year'] . ';month=' . $context['current_month'],
191
		'name' => $txt['months'][$context['current_month']] . ' ' . $context['current_year']
192
	);
193
	// If applicable, add the current week to the linktree.
194
	if ($context['view_week'])
195
		$context['linktree'][] = array(
196
			'url' => $scripturl . '?action=calendar;viewweek;year=' . $context['current_year'] . ';month=' . $context['current_month'] . ';day=' . $context['current_day'],
197
			'name' => $context['calendar_grid_main']['week_title'],
198
		);
199
200
	// Build the calendar button array.
201
	$context['calendar_buttons'] = array();
202
203
	if ($context['can_post'])
204
		$context['calendar_buttons']['post_event'] = array('text' => 'calendar_post_event', 'image' => 'calendarpe.png', 'url' => $scripturl . '?action=calendar;sa=post;month=' . $context['current_month'] . ';year=' . $context['current_year'] . ';' . $context['session_var'] . '=' . $context['session_id']);
205
206
	// Allow mods to add additional buttons here
207
	call_integration_hook('integrate_calendar_buttons');
208
}
209
210
/**
211
 * This function processes posting/editing/deleting a calendar event.
212
 *
213
 * 	- calls {@link Post.php|Post() Post()} function if event is linked to a post.
214
 *  - calls {@link Subs-Calendar.php|insertEvent() insertEvent()} to insert the event if not linked to post.
215
 *
216
 * It requires the calendar_post permission to use.
217
 * It uses the event_post sub template in the Calendar template.
218
 * It is accessed with ?action=calendar;sa=post.
219
 */
220
function CalendarPost()
221
{
222
	global $context, $txt, $user_info, $sourcedir, $scripturl;
223
	global $modSettings, $topic, $smcFunc, $settings;
224
225
	// Well - can they?
226
	isAllowedTo('calendar_post');
227
228
	// We need these for all kinds of useful functions.
229
	require_once($sourcedir . '/Subs-Calendar.php');
230
	require_once($sourcedir . '/Subs.php');
231
232
	// Cast this for safety...
233
	if (isset($_REQUEST['eventid']))
234
		$_REQUEST['eventid'] = (int) $_REQUEST['eventid'];
235
236
	// We want a fairly compact version of the time, but as close as possible to the user's settings.
237 View Code Duplication
	if (preg_match('~%[HkIlMpPrRSTX](?:[^%]*%[HkIlMpPrRSTX])*~', $user_info['time_format'], $matches) == 0 || empty($matches[0]))
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
238
		$time_string = '%k:%M';
239
	else
240
		$time_string = str_replace(array('%I', '%H', '%S', '%r', '%R', '%T'), array('%l', '%k', '', '%l:%M %p', '%k:%M', '%l:%M'), $matches[0]);
241
242
	$js_time_string = str_replace(
243
		array('%H', '%k', '%I', '%l', '%M', '%p', '%P', '%r',      '%R',  '%S', '%T',    '%X'),
244
		array('H',  'G',  'h',  'g',  'i',  'A',  'a',  'h:i:s A', 'H:i', 's',  'H:i:s', 'H:i:s'),
245
		$time_string
246
	);
247
248
	// Submitting?
249
	if (isset($_POST[$context['session_var']], $_REQUEST['eventid']))
250
	{
251
		checkSession();
252
253
		// Validate the post...
254
		if (!isset($_POST['link_to_board']))
255
			validateEventPost();
256
257
		// If you're not allowed to edit any events, you have to be the poster.
258
		if ($_REQUEST['eventid'] > 0 && !allowedTo('calendar_edit_any'))
259
			isAllowedTo('calendar_edit_' . (!empty($user_info['id']) && getEventPoster($_REQUEST['eventid']) == $user_info['id'] ? 'own' : 'any'));
260
261
		// New - and directing?
262
		if (isset($_POST['link_to_board']) || empty($modSettings['cal_allow_unlinked']))
263
		{
264
			$_REQUEST['calendar'] = 1;
265
			require_once($sourcedir . '/Post.php');
266
			return Post();
267
		}
268
		// New...
269
		elseif ($_REQUEST['eventid'] == -1)
270
		{
271
			$eventOptions = array(
272
				'board' => 0,
273
				'topic' => 0,
274
				'title' => $smcFunc['substr']($_REQUEST['evtitle'], 0, 100),
275
				'location' => $smcFunc['substr']($_REQUEST['event_location'], 0, 255),
276
				'member' => $user_info['id'],
277
			);
278
			insertEvent($eventOptions);
279
		}
280
281
		// Deleting...
282
		elseif (isset($_REQUEST['deleteevent']))
283
			removeEvent($_REQUEST['eventid']);
284
285
		// ... or just update it?
286
		else
287
		{
288
			$eventOptions = array(
289
				'title' => $smcFunc['substr']($_REQUEST['evtitle'], 0, 100),
290
				'location' => $smcFunc['substr']($_REQUEST['event_location'], 0, 255),
291
			);
292
			modifyEvent($_REQUEST['eventid'], $eventOptions);
293
		}
294
295
		updateSettings(array(
296
			'calendar_updated' => time(),
297
		));
298
299
		// No point hanging around here now...
300
		if (isset($_POST['start_date']))
301
		{
302
			$d = date_parse($_POST['start_date']);
303
			$year = $d['year'];
304
			$month = $d['month'];
305
		}
306
		elseif (isset($_POST['start_datetime']))
307
		{
308
			$d = date_parse($_POST['start_datetime']);
309
			$year = $d['year'];
310
			$month = $d['month'];
311
		}
312
		else
313
		{
314
			$today = getdate();
315
			$year = isset($_POST['year']) ? $_POST['year'] : $today['year'];
316
			$month = isset($_POST['month']) ? $_POST['month'] : $today['mon'];
317
		}
318
		redirectexit($scripturl . '?action=calendar;month=' . $month . ';year=' . $year);
319
	}
320
321
	// If we are not enabled... we are not enabled.
322
	if (empty($modSettings['cal_allow_unlinked']) && empty($_REQUEST['eventid']))
323
	{
324
		$_REQUEST['calendar'] = 1;
325
		require_once($sourcedir . '/Post.php');
326
		return Post();
327
	}
328
329
	// New?
330
	if (!isset($_REQUEST['eventid']))
331
	{
332
		$context['event'] = array(
333
			'boards' => array(),
334
			'board' => 0,
335
			'new' => 1,
336
			'eventid' => -1,
337
			'title' => '',
338
			'location' => '',
339
		);
340
341
		$eventDatetimes = getNewEventDatetimes();
342
		$context['event'] = array_merge($context['event'], $eventDatetimes);
343
344
		$context['event']['last_day'] = (int) strftime('%d', mktime(0, 0, 0, $context['event']['month'] == 12 ? 1 : $context['event']['month'] + 1, 0, $context['event']['month'] == 12 ? $context['event']['year'] + 1 : $context['event']['year']));
345
	}
346
	else
347
	{
348
		$context['event'] = getEventProperties($_REQUEST['eventid']);
349
350
		if ($context['event'] === false)
351
			fatal_lang_error('no_access', false);
0 ignored issues
show
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
352
353
		// If it has a board, then they should be editing it within the topic.
354
		if (!empty($context['event']['topic']['id']) && !empty($context['event']['topic']['first_msg']))
355
		{
356
			// We load the board up, for a check on the board access rights...
357
			$topic = $context['event']['topic']['id'];
358
			loadBoard();
359
		}
360
361
		// Make sure the user is allowed to edit this event.
362
		if ($context['event']['member'] != $user_info['id'])
363
			isAllowedTo('calendar_edit_any');
364
		elseif (!allowedTo('calendar_edit_any'))
365
			isAllowedTo('calendar_edit_own');
366
	}
367
368
	// An all day event? Set up some nice defaults in case the user wants to change that
369 View Code Duplication
	if ($context['event']['allday'] == true)
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
370
	{
371
		$context['event']['tz'] = getUserTimezone();
372
		$context['event']['start_time'] = timeformat(time(), $time_string);
0 ignored issues
show
$time_string is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
373
		$context['event']['end_time'] = timeformat(time() + 3600, $time_string);
0 ignored issues
show
$time_string is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
374
	}
375
	// Otherwise, just adjust these to look nice on the input form
376
	else
377
	{
378
		$context['event']['start_time'] = timeformat(strtotime($context['event']['start_iso_gmdate']), $time_string);
0 ignored issues
show
$time_string is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
379
		$context['event']['end_time'] = timeformat(strtotime($context['event']['end_iso_gmdate']), $time_string);
0 ignored issues
show
$time_string is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
380
	}
381
382
	// Need this so the user can select a timezone for the event.
383
	$context['all_timezones'] = smf_list_timezones($context['event']['start_date']);
384
	unset($context['all_timezones']['']);
385
386
	// If the event's timezone is not in SMF's standard list of time zones, prepend it to the list
387 View Code Duplication
	if (!in_array($context['event']['tz'], array_keys($context['all_timezones'])))
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
388
	{
389
		$d = date_create($context['event']['tz']);
390
		$context['all_timezones'] = array($context['event']['tz'] => date_format($d, 'T') . ' - ' . $context['event']['tz'] . ' [UTC' . date_format($d, 'P') . ']') + $context['all_timezones'];
391
	}
392
393
	// Get list of boards that can be posted in.
394
	$boards = boardsAllowedTo('post_new');
395
	if (empty($boards))
396
	{
397
		// You can post new events but can't link them to anything...
398
		$context['event']['categories'] = array();
399
	}
400
	else
401
	{
402
		// Load the list of boards and categories in the context.
403
		require_once($sourcedir . '/Subs-MessageIndex.php');
404
		$boardListOptions = array(
405
			'included_boards' => in_array(0, $boards) ? null : $boards,
406
			'not_redirection' => true,
407
			'use_permissions' => true,
408
			'selected_board' => $modSettings['cal_defaultboard'],
409
		);
410
		$context['event']['categories'] = getBoardList($boardListOptions);
411
	}
412
413
	// Template, sub template, etc.
414
	loadTemplate('Calendar');
415
	$context['sub_template'] = 'event_post';
416
417
	$context['page_title'] = isset($_REQUEST['eventid']) ? $txt['calendar_edit'] : $txt['calendar_post_event'];
418
	$context['linktree'][] = array(
419
		'name' => $context['page_title'],
420
	);
421
422
	loadCSSFile('jquery-ui.datepicker.css', array('defer' => false), 'smf_datepicker');
423
	loadCSSFile('jquery.timepicker.css', array('defer' => false), 'smf_timepicker');
424
	loadJavaScriptFile('jquery-ui.datepicker.min.js', array('defer' => true), 'smf_datepicker');
425
	loadJavaScriptFile('jquery.timepicker.min.js', array('defer' => true), 'smf_timepicker');
426
	loadJavaScriptFile('datepair.min.js', array('defer' => true), 'smf_datepair');
427
	addInlineJavaScript('
428
	$("#allday").click(function(){
429
		$("#start_time").attr("disabled", this.checked);
430
		$("#end_time").attr("disabled", this.checked);
431
		$("#tz").attr("disabled", this.checked);
432
	});
433
	$("#event_time_input .date_input").datepicker({
434
		dateFormat: "yy-mm-dd",
435
		autoSize: true,
436
		isRTL: ' . ($context['right_to_left'] ? 'true' : 'false') . ',
437
		constrainInput: true,
438
		showAnim: "",
439
		showButtonPanel: false,
440
		minDate: "' . $modSettings['cal_minyear'] . '-01-01",
441
		maxDate: "' . $modSettings['cal_maxyear'] . '-12-31",
442
		yearRange: "' . $modSettings['cal_minyear'] . ':' . $modSettings['cal_maxyear'] . '",
443
		hideIfNoPrevNext: true,
444
		monthNames: ["' . implode('", "', $txt['months_titles']) . '"],
445
		monthNamesShort: ["' . implode('", "', $txt['months_short']) . '"],
446
		dayNames: ["' . implode('", "', $txt['days']) . '"],
447
		dayNamesShort: ["' . implode('", "', $txt['days_short']) . '"],
448
		dayNamesMin: ["' . implode('", "', $txt['days_short']) . '"],
449
		prevText: "' . $txt['prev_month'] . '",
450
		nextText: "' . $txt['next_month'] . '",
451
	});
452
	$(".time_input").timepicker({
453
		timeFormat: "' . $js_time_string . '",
454
		showDuration: true,
455
		maxTime: "23:59:59",
456
	});
457
	var date_entry = document.getElementById("event_time_input");
458
	var date_entry_pair = new Datepair(date_entry, {
459
		timeClass: "time_input",
460
		dateClass: "date_input",
461
		parseDate: function (el) {
462
		    var utc = new Date($(el).datepicker("getDate"));
463
		    return utc && new Date(utc.getTime() + (utc.getTimezoneOffset() * 60000));
464
		},
465
		updateDate: function (el, v) {
466
		    $(el).datepicker("setDate", new Date(v.getTime() - (v.getTimezoneOffset() * 60000)));
467
		}
468
	});
469
	', true);
470
}
471
472
/**
473
 * This function offers up a download of an event in iCal 2.0 format.
474
 *
475
 * Follows the conventions in {@link http://tools.ietf.org/html/rfc5546 RFC5546}
476
 * Sets events as all day events since we don't have hourly events
477
 * Will honor and set multi day events
478
 * Sets a sequence number if the event has been modified
479
 *
480
 * @todo .... allow for week or month export files as well?
481
 */
482
function iCalDownload()
483
{
484
	global $smcFunc, $sourcedir, $forum_version, $modSettings, $webmaster_email, $mbname;
485
486
	// You can't export if the calendar export feature is off.
487
	if (empty($modSettings['cal_export']))
488
		fatal_lang_error('calendar_export_off', false);
489
490
	// Goes without saying that this is required.
491
	if (!isset($_REQUEST['eventid']))
492
		fatal_lang_error('no_access', false);
0 ignored issues
show
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
493
494
	// This is kinda wanted.
495
	require_once($sourcedir . '/Subs-Calendar.php');
496
497
	// Load up the event in question and check it exists.
498
	$event = getEventProperties($_REQUEST['eventid']);
499
500
	if ($event === false)
501
		fatal_lang_error('no_access', false);
0 ignored issues
show
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
502
503
	// Check the title isn't too long - iCal requires some formatting if so.
504
	$title = str_split($event['title'], 30);
505
	foreach ($title as $id => $line)
506
	{
507
		if ($id != 0)
508
			$title[$id] = ' ' . $title[$id];
509
		$title[$id] .= "\n";
510
	}
511
512
	// Format the dates.
513
	$datestamp = date('Ymd\THis\Z', time());
514
	$start_date = date_create($event['start_date'] . (isset($event['start_time']) ? ' ' . $event['start_time'] : '') . (isset($event['tz']) ? ' ' . $event['tz'] : ''));
515
	$end_date = date_create($event['end_date'] . (isset($event['end_time']) ? ' ' . $event['end_time'] : '') . (isset($event['tz']) ? ' ' . $event['tz'] : ''));
516
517
	if (!empty($event['start_time']))
518
	{
519
		$datestart = date_format($start_date, 'Ymd\THis');
520
		$dateend = date_format($end_date, 'Ymd\THis');
521
	}
522
	else
523
	{
524
		$datestart = date_format($start_date, 'Ymd');
525
526
		date_add($end_date, date_interval_create_from_date_string('1 day'));
527
		$dateend = date_format($end_date, 'Ymd');
528
	}
529
530
	// This is what we will be sending later
531
	$filecontents = '';
532
	$filecontents .= 'BEGIN:VCALENDAR' . "\n";
533
	$filecontents .= 'METHOD:PUBLISH' . "\n";
534
	$filecontents .= 'PRODID:-//SimpleMachines//SMF ' . (empty($forum_version) ? 2.1 : strtr($forum_version, array('SMF ' => ''))) . '//EN' . "\n";
535
	$filecontents .= 'VERSION:2.0' . "\n";
536
	$filecontents .= 'BEGIN:VEVENT' . "\n";
537
	// @TODO - Should be the members email who created the event rather than $webmaster_email.
538
	$filecontents .= 'ORGANIZER;CN="' . $event['realname'] . '":MAILTO:' . $webmaster_email . "\n";
539
	$filecontents .= 'DTSTAMP:' . $datestamp . "\n";
540
	$filecontents .= 'DTSTART' . (!empty($event['start_time']) ? ';TZID=' . $event['tz'] : ';VALUE=DATE') . ':' . $datestart . "\n";
541
542
	// event has a duration
543
	if ($event['start_iso_gmdate'] != $event['end_iso_gmdate'])
544
		$filecontents .= 'DTEND' . (!empty($event['end_time']) ? ';TZID=' . $event['tz'] : ';VALUE=DATE') . ':' . $dateend . "\n";
545
546
	// event has changed? advance the sequence for this UID
547
	if ($event['sequence'] > 0)
548
		$filecontents .= 'SEQUENCE:' . $event['sequence'] . "\n";
549
550
	if (!empty($event['location']))
551
		$filecontents .= 'LOCATION:' . str_replace(',', '\,', $event['location']) . "\n";
552
553
	$filecontents .= 'SUMMARY:' . implode('', $title);
554
	$filecontents .= 'UID:' . $event['eventid'] . '@' . str_replace(' ', '-', $mbname) . "\n";
555
	$filecontents .= 'END:VEVENT' . "\n";
556
	$filecontents .= 'END:VCALENDAR';
557
558
	// Send some standard headers.
559
	ob_end_clean();
560
	if (!empty($modSettings['enableCompressedOutput']))
561
		@ob_start('ob_gzhandler');
562
	else
563
		ob_start();
564
565
	// Send the file headers
566
	header('Pragma: ');
567
	header('Cache-Control: no-cache');
568
	if (!isBrowser('gecko'))
569
		header('Content-Transfer-Encoding: binary');
570
	header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 525600 * 60) . ' GMT');
571
	header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . 'GMT');
572
	header('Accept-Ranges: bytes');
573
	header('Connection: close');
574
	header('Content-Disposition: attachment; filename="' . $event['title'] . '.ics"');
575
	if (empty($modSettings['enableCompressedOutput']))
576
		header('Content-Length: ' . $smcFunc['strlen']($filecontents));
577
578
	// This is a calendar item!
579
	header('Content-Type: text/calendar');
580
581
	// Chuck out the card.
582
	echo $filecontents;
583
584
	// Off we pop - lovely!
585
	obExit(false);
586
}
587
588
/**
589
 * Nothing to see here. Move along.
590
 */
591
function clock()
592
{
593
	global $settings, $context, $scripturl;
594
595
	$context['onimg'] = $settings['images_url'] . '/bbc/bbc_bg.png';
596
	$context['offimg'] = $settings['images_url'] . '/bbc/bbc_hoverbg.png';
597
598
	$context['page_title'] = 'Anyone know what time it is?';
599
	$context['linktree'][] = array(
600
			'url' => $scripturl . '?action=clock',
601
			'name' => 'Clock',
602
	);
603
	$context['robot_no_index'] = true;
604
605
	$omfg = isset($_REQUEST['omfg']);
606
	$bcd = !isset($_REQUEST['rb']) && !isset($_REQUEST['omfg']) && !isset($_REQUEST['time']);
607
608
	loadTemplate('Calendar');
609
610
	if ($bcd)
611
	{
612
		$context['sub_template'] = 'bcd';
613
		$context['linktree'][] = array('url' => $scripturl . '?action=clock;bcd', 'name' => 'BCD');
614
		$context['clockicons'] = safe_unserialize(base64_decode('YTo2OntzOjI6ImgxIjthOjI6e2k6MDtpOjI7aToxO2k6MTt9czoyOiJoMiI7YTo0OntpOjA7aTo4O2k6MTtpOjQ7aToyO2k6MjtpOjM7aToxO31zOjI6Im0xIjthOjM6e2k6MDtpOjQ7aToxO2k6MjtpOjI7aToxO31zOjI6Im0yIjthOjQ6e2k6MDtpOjg7aToxO2k6NDtpOjI7aToyO2k6MztpOjE7fXM6MjoiczEiO2E6Mzp7aTowO2k6NDtpOjE7aToyO2k6MjtpOjE7fXM6MjoiczIiO2E6NDp7aTowO2k6ODtpOjE7aTo0O2k6MjtpOjI7aTozO2k6MTt9fQ=='));
615
	}
616
	elseif (!$omfg && !isset($_REQUEST['time']))
617
	{
618
		$context['sub_template'] = 'hms';
619
		$context['linktree'][] = array('url' => $scripturl . '?action=clock', 'name' => 'Binary');
620
		$context['clockicons'] = safe_unserialize(base64_decode('YTozOntzOjE6ImgiO2E6NTp7aTowO2k6MTY7aToxO2k6ODtpOjI7aTo0O2k6MztpOjI7aTo0O2k6MTt9czoxOiJtIjthOjY6e2k6MDtpOjMyO2k6MTtpOjE2O2k6MjtpOjg7aTozO2k6NDtpOjQ7aToyO2k6NTtpOjE7fXM6MToicyI7YTo2OntpOjA7aTozMjtpOjE7aToxNjtpOjI7aTo4O2k6MztpOjQ7aTo0O2k6MjtpOjU7aToxO319'));
621
	}
622
	elseif ($omfg)
623
	{
624
		$context['sub_template'] = 'omfg';
625
		$context['linktree'][] = array('url' => $scripturl . '?action=clock;omfg', 'name' => 'OMFG');
626
		$context['clockicons'] = safe_unserialize(base64_decode('YTo2OntzOjQ6InllYXIiO2E6Nzp7aTowO2k6NjQ7aToxO2k6MzI7aToyO2k6MTY7aTozO2k6ODtpOjQ7aTo0O2k6NTtpOjI7aTo2O2k6MTt9czo1OiJtb250aCI7YTo0OntpOjA7aTo4O2k6MTtpOjQ7aToyO2k6MjtpOjM7aToxO31zOjM6ImRheSI7YTo1OntpOjA7aToxNjtpOjE7aTo4O2k6MjtpOjQ7aTozO2k6MjtpOjQ7aToxO31zOjQ6ImhvdXIiO2E6NTp7aTowO2k6MTY7aToxO2k6ODtpOjI7aTo0O2k6MztpOjI7aTo0O2k6MTt9czozOiJtaW4iO2E6Njp7aTowO2k6MzI7aToxO2k6MTY7aToyO2k6ODtpOjM7aTo0O2k6NDtpOjI7aTo1O2k6MTt9czozOiJzZWMiO2E6Njp7aTowO2k6MzI7aToxO2k6MTY7aToyO2k6ODtpOjM7aTo0O2k6NDtpOjI7aTo1O2k6MTt9fQ=='));
627
	}
628
	elseif (isset($_REQUEST['time']))
629
	{
630
		$context['sub_template'] = 'thetime';
631
		$time = getdate($_REQUEST['time'] == 'now' ? time() : (int) $_REQUEST['time']);
632
		$year = $time['year'] % 100;
633
		$month = $time['mon'];
634
		$day = $time['mday'];
635
		$hour = $time['hours'];
636
		$min = $time['minutes'];
637
		$sec = $time['seconds'];
638
		$context['linktree'][] = array('url' => $scripturl . '?action=clock;time=' . $_REQUEST['time'], 'name' => 'Requested Time');
639
		$context['clockicons'] = array(
640
			'year' => array(
641
				64 => false,
642
				32 => false,
643
				16 => false,
644
				8  => false,
645
				4  => false,
646
				2  => false,
647
				1  => false
648
			),
649
			'month' => array(
650
				8  => false,
651
				4  => false,
652
				2  => false,
653
				1  => false
654
			),
655
			'day' => array(
656
				16 => false,
657
				4  => false,
658
				8  => false,
659
				2  => false,
660
				1  => false
661
			),
662
			'hour' => array(
663
				32 => false,
664
				16 => false,
665
				8  => false,
666
				4  => false,
667
				2  => false,
668
				1  => false
669
			),
670
			'min' => array(
671
				32 => false,
672
				16 => false,
673
				8  => false,
674
				4  => false,
675
				2  => false,
676
				1  => false
677
			),
678
			'sec' => array(
679
				32 => false,
680
				16 => false,
681
				8  => false,
682
				4  => false,
683
				2  => false,
684
				1  => false
685
			),
686
		);
687
688
		foreach ($context['clockicons'] as $t => $vs)
689
			foreach ($vs as $v => $dumb)
690
			{
691
				if ($$t >= $v)
692
				{
693
					$$t -= $v;
694
					$context['clockicons'][$t][$v] = true;
695
				}
696
			}
697
	}
698
}
699
700
?>
701