Issues (1014)

Sources/Calendar.php (3 issues)

Labels
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 https://www.simplemachines.org
11
 * @copyright 2022 Simple Machines and individual contributors
12
 * @license https://www.simplemachines.org/about/smf/license.php BSD
13
 *
14
 * @version 2.1.2
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
 *
30
 * @return void
31
 */
32
function CalendarMain()
33
{
34
	global $txt, $context, $modSettings, $scripturl, $options, $sourcedir, $user_info, $smcFunc;
35
36
	// Permissions, permissions, permissions.
37
	isAllowedTo('calendar_view');
38
39
	// Some global template resources.
40
	$context['calendar_resources'] = array(
41
		'min_year' => $modSettings['cal_minyear'],
42
		'max_year' => $modSettings['cal_maxyear'],
43
	);
44
45
	// Doing something other than calendar viewing?
46
	$subActions = array(
47
		'ical' => 'iCalDownload',
48
		'post' => 'CalendarPost',
49
	);
50
51
	if (isset($_GET['sa']) && isset($subActions[$_GET['sa']]))
52
		return call_helper($subActions[$_GET['sa']]);
53
54
	// You can't do anything if the calendar is off.
55
	if (empty($modSettings['cal_enabled']))
56
		fatal_lang_error('calendar_off', false);
57
58
	// This is gonna be needed...
59
	loadTemplate('Calendar');
60
	loadCSSFile('calendar.css', array('force_current' => false, 'validate' => true, 'rtl' => 'calendar.rtl.css'), 'smf_calendar');
61
62
	// Did the specify an individual event ID? If so, let's splice the year/month in to what we would otherwise be doing.
63
	if (isset($_GET['event']))
64
	{
65
		$evid = (int) $_GET['event'];
66
		if ($evid > 0)
67
		{
68
			$request = $smcFunc['db_query']('', '
69
				SELECT start_date
70
				FROM {db_prefix}calendar
71
				WHERE id_event = {int:event_id}',
72
				array(
73
					'event_id' => $evid,
74
				)
75
			);
76
			if ($row = $smcFunc['db_fetch_assoc']($request))
77
			{
78
				$_REQUEST['start_date'] = $row['start_date'];
79
80
				// We might use this later.
81
				$context['selected_event'] = $evid;
82
			}
83
			$smcFunc['db_free_result']($request);
84
		}
85
		unset ($_GET['event']);
86
	}
87
88
	// Set the page title to mention the calendar ;).
89
	$context['page_title'] = $txt['calendar'];
90
91
	// Ensure a default view is defined
92
	if (empty($options['calendar_default_view']))
93
		$options['calendar_default_view'] = 'viewlist';
94
95
	// What view do we want?
96
	if (isset($_GET['viewweek']))
97
		$context['calendar_view'] = 'viewweek';
98
	elseif (isset($_GET['viewmonth']))
99
		$context['calendar_view'] = 'viewmonth';
100
	elseif (isset($_GET['viewlist']))
101
		$context['calendar_view'] = 'viewlist';
102
	else
103
		$context['calendar_view'] = $options['calendar_default_view'];
104
105
	// Don't let search engines index the non-default calendar pages
106
	if ($context['calendar_view'] !== $options['calendar_default_view'])
107
		$context['robot_no_index'] = true;
108
109
	// Get the current day of month...
110
	require_once($sourcedir . '/Subs-Calendar.php');
111
	$today = getTodayInfo();
112
113
	// Need a start date for all views
114
	if (!empty($_REQUEST['start_date']))
115
	{
116
		$start_parsed = date_parse(str_replace(',', '', convertDateToEnglish($_REQUEST['start_date'])));
117
		if (empty($start_parsed['error_count']) && empty($start_parsed['warning_count']))
118
		{
119
			$_REQUEST['year'] = $start_parsed['year'];
120
			$_REQUEST['month'] = $start_parsed['month'];
121
			$_REQUEST['day'] = $start_parsed['day'];
122
		}
123
	}
124
	$year = !empty($_REQUEST['year']) ? (int) $_REQUEST['year'] : $today['year'];
125
	$month = !empty($_REQUEST['month']) ? (int) $_REQUEST['month'] : $today['month'];
126
	$day = !empty($_REQUEST['day']) ? (int) $_REQUEST['day'] : (!empty($_REQUEST['month']) ? 1 : $today['day']);
127
128
	$start_object = checkdate($month, $day, $year) === true ? date_create(implode('-', array($year, $month, $day)) . ' ' . getUserTimezone()) : date_create(implode('-', array($today['year'], $today['month'], $today['day'])) . ' ' . getUserTimezone());
129
130
	// Need an end date for the list view
131
	if (!empty($_REQUEST['end_date']))
132
	{
133
		$end_parsed = date_parse(str_replace(',', '', convertDateToEnglish($_REQUEST['end_date'])));
134
		if (empty($end_parsed['error_count']) && empty($end_parsed['warning_count']))
135
		{
136
			$_REQUEST['end_year'] = $end_parsed['year'];
137
			$_REQUEST['end_month'] = $end_parsed['month'];
138
			$_REQUEST['end_day'] = $end_parsed['day'];
139
		}
140
	}
141
	$end_year = !empty($_REQUEST['end_year']) ? (int) $_REQUEST['end_year'] : null;
142
	$end_month = !empty($_REQUEST['end_month']) ? (int) $_REQUEST['end_month'] : null;
143
	$end_day = !empty($_REQUEST['end_day']) ? (int) $_REQUEST['end_day'] : null;
144
145
	$end_object = null;
146
147
	if (isset($end_month, $end_day, $end_year) && checkdate($end_month, $end_day, $end_year))
148
	{
149
		$end_object = date_create(implode('-', array($end_year, $end_month, $end_day)) . ' ' . getUserTimezone());
150
	}
151
152
	if (empty($end_object) || $start_object >= $end_object)
153
	{
154
		$num_days_shown = empty($modSettings['cal_days_for_index']) || $modSettings['cal_days_for_index'] < 1 ? 1 : $modSettings['cal_days_for_index'];
155
156
		$end_object = date_create(date_format($start_object, 'Y-m-d') . ' ' . getUserTimezone());
157
158
		date_add($end_object, date_interval_create_from_date_string($num_days_shown . ' days'));
159
	}
160
161
	$curPage = array(
162
		'year' => date_format($start_object, 'Y'),
163
		'month' => date_format($start_object, 'n'),
164
		'day' => date_format($start_object, 'j'),
165
		'start_date' => date_format($start_object, 'Y-m-d'),
166
		'end_year' => date_format($end_object, 'Y'),
167
		'end_month' => date_format($end_object, 'n'),
168
		'end_day' => date_format($end_object, 'j'),
169
		'end_date' => date_format($end_object, 'Y-m-d'),
170
	);
171
172
	// Make sure the year and month are in valid ranges.
173
	if ($curPage['month'] < 1 || $curPage['month'] > 12)
174
		fatal_lang_error('invalid_month', false);
175
	if ($curPage['year'] < $modSettings['cal_minyear'] || $curPage['year'] > $modSettings['cal_maxyear'])
176
		fatal_lang_error('invalid_year', false);
177
	// If we have a day clean that too.
178
	if ($context['calendar_view'] != 'viewmonth')
179
	{
180
		$isValid = checkdate($curPage['month'], $curPage['day'], $curPage['year']);
181
		if (!$isValid)
182
			fatal_lang_error('invalid_day', false);
183
	}
184
185
	// Load all the context information needed to show the calendar grid.
186
	$calendarOptions = array(
187
		'start_day' => !empty($options['calendar_start_day']) ? $options['calendar_start_day'] : 0,
188
		'show_birthdays' => in_array($modSettings['cal_showbdays'], array(1, 2)),
189
		'show_events' => in_array($modSettings['cal_showevents'], array(1, 2)),
190
		'show_holidays' => in_array($modSettings['cal_showholidays'], array(1, 2)),
191
		'show_week_num' => true,
192
		'short_day_titles' => !empty($modSettings['cal_short_days']),
193
		'short_month_titles' => !empty($modSettings['cal_short_months']),
194
		'show_next_prev' => !empty($modSettings['cal_prev_next_links']),
195
		'show_week_links' => isset($modSettings['cal_week_links']) ? $modSettings['cal_week_links'] : 0,
196
	);
197
198
	// Load up the main view.
199
	if ($context['calendar_view'] == 'viewlist')
200
		$context['calendar_grid_main'] = getCalendarList($curPage['start_date'], $curPage['end_date'], $calendarOptions);
201
	elseif ($context['calendar_view'] == 'viewweek')
202
		$context['calendar_grid_main'] = getCalendarWeek($curPage['start_date'], $calendarOptions);
203
	else
204
		$context['calendar_grid_main'] = getCalendarGrid($curPage['start_date'], $calendarOptions);
205
206
	// Load up the previous and next months.
207
	$context['calendar_grid_current'] = getCalendarGrid($curPage['start_date'], $calendarOptions, false, false);
208
209
	// Only show previous month if it isn't pre-January of the min-year
210
	if ($context['calendar_grid_current']['previous_calendar']['year'] > $modSettings['cal_minyear'] || $curPage['month'] != 1)
211
		$context['calendar_grid_prev'] = getCalendarGrid($context['calendar_grid_current']['previous_calendar']['start_date'], $calendarOptions, true, false);
212
213
	// Only show next month if it isn't post-December of the max-year
214
	if ($context['calendar_grid_current']['next_calendar']['year'] < $modSettings['cal_maxyear'] || $curPage['month'] != 12)
215
		$context['calendar_grid_next'] = getCalendarGrid($context['calendar_grid_current']['next_calendar']['start_date'], $calendarOptions, false, false);
216
217
	// Basic template stuff.
218
	$context['allow_calendar_event'] = allowedTo('calendar_post');
219
220
	// If you don't allow events not linked to posts and you're not an admin, we have more work to do...
221
	if ($context['allow_calendar_event'] && empty($modSettings['cal_allow_unlinked']) && !$user_info['is_admin'])
222
	{
223
		$boards_can_post = boardsAllowedTo('post_new');
224
		$context['allow_calendar_event'] &= !empty($boards_can_post);
225
	}
226
227
	$context['can_post'] = $context['allow_calendar_event'];
228
	$context['current_day'] = $curPage['day'];
229
	$context['current_month'] = $curPage['month'];
230
	$context['current_year'] = $curPage['year'];
231
	$context['show_all_birthdays'] = isset($_GET['showbd']);
232
	$context['blocks_disabled'] = !empty($modSettings['cal_disable_prev_next']) ? 1 : 0;
233
234
	// Set the page title to mention the month or week, too
235
	if ($context['calendar_view'] != 'viewlist')
236
		$context['page_title'] .= ' - ' . ($context['calendar_view'] == 'viewweek' ? $context['calendar_grid_main']['week_title'] : $txt['months_titles'][$context['current_month']] . ' ' . $context['current_year']);
237
238
	// Load up the linktree!
239
	$context['linktree'][] = array(
240
		'url' => $scripturl . '?action=calendar',
241
		'name' => $txt['calendar']
242
	);
243
	// Add the current month to the linktree.
244
	$context['linktree'][] = array(
245
		'url' => $scripturl . '?action=calendar;year=' . $context['current_year'] . ';month=' . $context['current_month'],
246
		'name' => $txt['months_titles'][$context['current_month']] . ' ' . $context['current_year']
247
	);
248
	// If applicable, add the current week to the linktree.
249
	if ($context['calendar_view'] == 'viewweek')
250
		$context['linktree'][] = array(
251
			'url' => $scripturl . '?action=calendar;viewweek;year=' . $context['current_year'] . ';month=' . $context['current_month'] . ';day=' . $context['current_day'],
252
			'name' => $context['calendar_grid_main']['week_title'],
253
		);
254
255
	// Build the calendar button array.
256
	$context['calendar_buttons'] = array();
257
258
	if ($context['can_post'])
259
		$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']);
260
261
	// Allow mods to add additional buttons here
262
	call_integration_hook('integrate_calendar_buttons');
263
}
264
265
/**
266
 * This function processes posting/editing/deleting a calendar event.
267
 *
268
 * 	- calls {@link Post.php|Post() Post()} function if event is linked to a post.
269
 *  - calls {@link Subs-Calendar.php|insertEvent() insertEvent()} to insert the event if not linked to post.
270
 *
271
 * It requires the calendar_post permission to use.
272
 * It uses the event_post sub template in the Calendar template.
273
 * It is accessed with ?action=calendar;sa=post.
274
 */
275
function CalendarPost()
276
{
277
	global $context, $txt, $user_info, $sourcedir, $scripturl;
278
	global $modSettings, $topic, $smcFunc;
279
280
	// Well - can they?
281
	isAllowedTo('calendar_post');
282
283
	// We need these for all kinds of useful functions.
284
	require_once($sourcedir . '/Subs-Calendar.php');
285
	require_once($sourcedir . '/Subs.php');
286
287
	// Cast this for safety...
288
	if (isset($_REQUEST['eventid']))
289
		$_REQUEST['eventid'] = (int) $_REQUEST['eventid'];
290
291
	// We want a fairly compact version of the time, but as close as possible to the user's settings.
292
	$time_string = strtr(get_date_or_time_format('time'), array(
293
		'%I' => '%l',
294
		'%H' => '%k',
295
		'%S' => '',
296
		'%r' => '%l:%M %p',
297
		'%R' => '%k:%M',
298
		'%T' => '%l:%M',
299
	));
300
301
	$time_string = preg_replace('~:(?=\s|$|%[pPzZ])~', '', $time_string);
302
303
	// Submitting?
304
	if (isset($_POST[$context['session_var']], $_REQUEST['eventid']))
305
	{
306
		checkSession();
307
308
		// Validate the post...
309
		if (!isset($_POST['link_to_board']))
310
			validateEventPost();
311
312
		// If you're not allowed to edit any events, you have to be the poster.
313
		if ($_REQUEST['eventid'] > 0 && !allowedTo('calendar_edit_any'))
314
			isAllowedTo('calendar_edit_' . (!empty($user_info['id']) && getEventPoster($_REQUEST['eventid']) == $user_info['id'] ? 'own' : 'any'));
315
316
		// New - and directing?
317
		if (isset($_POST['link_to_board']) || empty($modSettings['cal_allow_unlinked']))
318
		{
319
			$_REQUEST['calendar'] = 1;
320
			require_once($sourcedir . '/Post.php');
321
			return Post();
322
		}
323
		// New...
324
		elseif ($_REQUEST['eventid'] == -1)
325
		{
326
			$eventOptions = array(
327
				'board' => 0,
328
				'topic' => 0,
329
				'title' => $smcFunc['substr']($_REQUEST['evtitle'], 0, 100),
330
				'location' => $smcFunc['substr']($_REQUEST['event_location'], 0, 255),
331
				'member' => $user_info['id'],
332
			);
333
			insertEvent($eventOptions);
334
		}
335
336
		// Deleting...
337
		elseif (isset($_REQUEST['deleteevent']))
338
			removeEvent($_REQUEST['eventid']);
339
340
		// ... or just update it?
341
		else
342
		{
343
			$eventOptions = array(
344
				'title' => $smcFunc['substr']($_REQUEST['evtitle'], 0, 100),
345
				'location' => $smcFunc['substr']($_REQUEST['event_location'], 0, 255),
346
			);
347
			modifyEvent($_REQUEST['eventid'], $eventOptions);
348
		}
349
350
		updateSettings(array(
351
			'calendar_updated' => time(),
352
		));
353
354
		// No point hanging around here now...
355
		if (isset($_POST['start_date']))
356
		{
357
			$d = date_parse($_POST['start_date']);
358
			$year = $d['year'];
359
			$month = $d['month'];
360
			$day = $d['day'];
361
		}
362
		elseif (isset($_POST['start_datetime']))
363
		{
364
			$d = date_parse($_POST['start_datetime']);
365
			$year = $d['year'];
366
			$month = $d['month'];
367
			$day = $d['day'];
368
		}
369
		else
370
		{
371
			$today = getdate();
372
			$year = isset($_POST['year']) ? $_POST['year'] : $today['year'];
373
			$month = isset($_POST['month']) ? $_POST['month'] : $today['mon'];
374
			$day = isset($_POST['day']) ? $_POST['day'] : $today['mday'];
375
		}
376
		redirectexit($scripturl . '?action=calendar;month=' . $month . ';year=' . $year . ';day=' . $day);
377
	}
378
379
	// If we are not enabled... we are not enabled.
380
	if (empty($modSettings['cal_allow_unlinked']) && empty($_REQUEST['eventid']))
381
	{
382
		$_REQUEST['calendar'] = 1;
383
		require_once($sourcedir . '/Post.php');
384
		return Post();
0 ignored issues
show
Are you sure the usage of Post() is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
385
	}
386
387
	// New?
388
	if (!isset($_REQUEST['eventid']))
389
	{
390
		$context['event'] = array(
391
			'boards' => array(),
392
			'board' => 0,
393
			'new' => 1,
394
			'eventid' => -1,
395
			'title' => '',
396
			'location' => '',
397
		);
398
399
		$eventDatetimes = getNewEventDatetimes();
400
		$context['event'] = array_merge($context['event'], $eventDatetimes);
401
402
		$context['event']['last_day'] = (int) smf_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']));
403
	}
404
	else
405
	{
406
		$context['event'] = getEventProperties($_REQUEST['eventid']);
407
408
		if ($context['event'] === false)
409
			fatal_lang_error('no_access', false);
410
411
		// If it has a board, then they should be editing it within the topic.
412
		if (!empty($context['event']['topic']['id']) && !empty($context['event']['topic']['first_msg']))
413
		{
414
			// We load the board up, for a check on the board access rights...
415
			$topic = $context['event']['topic']['id'];
416
			loadBoard();
417
		}
418
419
		// Make sure the user is allowed to edit this event.
420
		if ($context['event']['member'] != $user_info['id'])
421
			isAllowedTo('calendar_edit_any');
422
		elseif (!allowedTo('calendar_edit_any'))
423
			isAllowedTo('calendar_edit_own');
424
	}
425
426
	// An all day event? Set up some nice defaults in case the user wants to change that
427
	if ($context['event']['allday'] == true)
428
	{
429
		$context['event']['tz'] = getUserTimezone();
430
		$context['event']['start_time'] = timeformat(time(), $time_string);
431
		$context['event']['end_time'] = timeformat(time() + 3600, $time_string);
432
	}
433
	// Otherwise, just adjust these to look nice on the input form
434
	else
435
	{
436
		$context['event']['start_time'] = $context['event']['start_time_orig'];
437
		$context['event']['end_time'] = $context['event']['end_time_orig'];
438
	}
439
440
	// Need this so the user can select a timezone for the event.
441
	$context['all_timezones'] = smf_list_timezones($context['event']['start_date']);
442
443
	// If the event's timezone is not in SMF's standard list of time zones, try to fix it.
444
	if (!isset($context['all_timezones'][$context['event']['tz']]))
445
	{
446
		$later = strtotime('@' . $context['event']['start_timestamp'] . ' + 1 year');
447
		$tzinfo = timezone_transitions_get(timezone_open($context['event']['tz']), $context['event']['start_timestamp'], $later);
448
449
		$found = false;
450
		foreach ($context['all_timezones'] as $possible_tzid => $dummy)
451
		{
452
			// Ignore the "-----" option
453
			if (empty($possible_tzid))
454
				continue;
455
456
			$possible_tzinfo = timezone_transitions_get(timezone_open($possible_tzid), $context['event']['start_timestamp'], $later);
457
458
			if ($tzinfo === $possible_tzinfo)
459
			{
460
				$context['event']['tz'] = $possible_tzid;
461
				$found = true;
462
				break;
463
			}
464
		}
465
466
		// Hm. That's weird. Well, just prepend it to the list and let the user deal with it.
467
		if (!$found)
468
		{
469
			$d = date_create($context['event']['start_datetime'] . ' ' . $context['event']['tz']);
470
			$context['all_timezones'] = array($context['event']['tz'] => '[UTC' . date_format($d, 'P') . '] - ' . $context['event']['tz']) + $context['all_timezones'];
471
		}
472
	}
473
474
	// Get list of boards that can be posted in.
475
	$boards = boardsAllowedTo('post_new');
476
	if (empty($boards))
477
	{
478
		// You can post new events but can't link them to anything...
479
		$context['event']['categories'] = array();
480
	}
481
	else
482
	{
483
		// Load the list of boards and categories in the context.
484
		require_once($sourcedir . '/Subs-MessageIndex.php');
485
		$boardListOptions = array(
486
			'included_boards' => in_array(0, $boards) ? null : $boards,
487
			'not_redirection' => true,
488
			'use_permissions' => true,
489
			'selected_board' => $modSettings['cal_defaultboard'],
490
		);
491
		$context['event']['categories'] = getBoardList($boardListOptions);
492
	}
493
494
	// Template, sub template, etc.
495
	loadTemplate('Calendar');
496
	$context['sub_template'] = 'event_post';
497
498
	$context['page_title'] = isset($_REQUEST['eventid']) ? $txt['calendar_edit'] : $txt['calendar_post_event'];
499
	$context['linktree'][] = array(
500
		'name' => $context['page_title'],
501
	);
502
503
	loadDatePicker('#event_time_input .date_input');
504
	loadTimePicker('#event_time_input .time_input', $time_string);
505
	loadDatePair('#event_time_input', 'date_input', 'time_input');
506
	addInlineJavaScript('
507
	$("#allday").click(function(){
508
		$("#start_time").attr("disabled", this.checked);
509
		$("#end_time").attr("disabled", this.checked);
510
		$("#tz").attr("disabled", this.checked);
511
	});', true);
512
}
513
514
/**
515
 * This function offers up a download of an event in iCal 2.0 format.
516
 *
517
 * Follows the conventions in {@link https://tools.ietf.org/html/rfc5546 RFC5546}
518
 * Sets events as all day events since we don't have hourly events
519
 * Will honor and set multi day events
520
 * Sets a sequence number if the event has been modified
521
 *
522
 * @todo .... allow for week or month export files as well?
523
 */
524
function iCalDownload()
525
{
526
	global $smcFunc, $sourcedir, $modSettings, $webmaster_email, $mbname;
527
528
	// You can't export if the calendar export feature is off.
529
	if (empty($modSettings['cal_export']))
530
		fatal_lang_error('calendar_export_off', false);
531
532
	// Goes without saying that this is required.
533
	if (!isset($_REQUEST['eventid']))
534
		fatal_lang_error('no_access', false);
535
536
	// This is kinda wanted.
537
	require_once($sourcedir . '/Subs-Calendar.php');
538
539
	// Load up the event in question and check it exists.
540
	$event = getEventProperties($_REQUEST['eventid']);
541
542
	if ($event === false)
0 ignored issues
show
The condition $event === false is always false.
Loading history...
543
		fatal_lang_error('no_access', false);
544
545
	// Check the title isn't too long - iCal requires some formatting if so.
546
	$title = str_split($event['title'], 30);
547
	foreach ($title as $id => $line)
548
	{
549
		if ($id != 0)
550
			$title[$id] = ' ' . $title[$id];
551
		$title[$id] .= "\n";
552
	}
553
554
	// Format the dates.
555
	$datestamp = date('Ymd\THis\Z', time());
556
	$start_date = date_create($event['start_date'] . (isset($event['start_time']) ? ' ' . $event['start_time'] : '') . (isset($event['tz']) ? ' ' . $event['tz'] : ''));
557
	$end_date = date_create($event['end_date'] . (isset($event['end_time']) ? ' ' . $event['end_time'] : '') . (isset($event['tz']) ? ' ' . $event['tz'] : ''));
558
559
	if (!empty($event['start_time']))
560
	{
561
		$datestart = date_format($start_date, 'Ymd\THis');
562
		$dateend = date_format($end_date, 'Ymd\THis');
563
	}
564
	else
565
	{
566
		$datestart = date_format($start_date, 'Ymd');
567
568
		date_add($end_date, date_interval_create_from_date_string('1 day'));
569
		$dateend = date_format($end_date, 'Ymd');
570
	}
571
572
	// This is what we will be sending later
573
	$filecontents = '';
574
	$filecontents .= 'BEGIN:VCALENDAR' . "\n";
575
	$filecontents .= 'METHOD:PUBLISH' . "\n";
576
	$filecontents .= 'PRODID:-//SimpleMachines//' . SMF_FULL_VERSION . '//EN' . "\n";
577
	$filecontents .= 'VERSION:2.0' . "\n";
578
	$filecontents .= 'BEGIN:VEVENT' . "\n";
579
	// @TODO - Should be the members email who created the event rather than $webmaster_email.
580
	$filecontents .= 'ORGANIZER;CN="' . $event['realname'] . '":MAILTO:' . $webmaster_email . "\n";
581
	$filecontents .= 'DTSTAMP:' . $datestamp . "\n";
582
	$filecontents .= 'DTSTART' . (!empty($event['start_time']) ? ';TZID=' . $event['tz'] : ';VALUE=DATE') . ':' . $datestart . "\n";
583
584
	// event has a duration
585
	if ($event['start_iso_gmdate'] != $event['end_iso_gmdate'])
586
		$filecontents .= 'DTEND' . (!empty($event['end_time']) ? ';TZID=' . $event['tz'] : ';VALUE=DATE') . ':' . $dateend . "\n";
587
588
	// event has changed? advance the sequence for this UID
589
	if ($event['sequence'] > 0)
590
		$filecontents .= 'SEQUENCE:' . $event['sequence'] . "\n";
591
592
	if (!empty($event['location']))
593
		$filecontents .= 'LOCATION:' . str_replace(',', '\,', $event['location']) . "\n";
594
595
	$filecontents .= 'SUMMARY:' . implode('', $title);
0 ignored issues
show
It seems like $title can also be of type true; however, parameter $pieces of implode() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

595
	$filecontents .= 'SUMMARY:' . implode('', /** @scrutinizer ignore-type */ $title);
Loading history...
596
	$filecontents .= 'UID:' . $event['eventid'] . '@' . str_replace(' ', '-', $mbname) . "\n";
597
	$filecontents .= 'END:VEVENT' . "\n";
598
	$filecontents .= 'END:VCALENDAR';
599
600
	// Send some standard headers.
601
	ob_end_clean();
602
	if (!empty($modSettings['enableCompressedOutput']))
603
		@ob_start('ob_gzhandler');
604
	else
605
		ob_start();
606
607
	// Send the file headers
608
	header('pragma: ');
609
	header('cache-control: no-cache');
610
	if (!isBrowser('gecko'))
611
		header('content-transfer-encoding: binary');
612
	header('expires: ' . gmdate('D, d M Y H:i:s', time() + 525600 * 60) . ' GMT');
613
	header('last-modified: ' . gmdate('D, d M Y H:i:s', time()) . 'GMT');
614
	header('accept-ranges: bytes');
615
	header('connection: close');
616
	header('content-disposition: attachment; filename="' . $event['title'] . '.ics"');
617
	if (empty($modSettings['enableCompressedOutput']))
618
		header('content-length: ' . $smcFunc['strlen']($filecontents));
619
620
	// This is a calendar item!
621
	header('content-type: text/calendar');
622
623
	// Chuck out the card.
624
	echo $filecontents;
625
626
	// Off we pop - lovely!
627
	obExit(false);
628
}
629
630
/**
631
 * Nothing to see here. Move along.
632
 */
633
function clock()
634
{
635
	global $smcFunc, $settings, $context, $scripturl;
636
637
	$context['onimg'] = $settings['images_url'] . '/bbc/bbc_hoverbg.png';
638
	$context['offimg'] = $settings['images_url'] . '/bbc/bbc_bg.png';
639
640
	$context['page_title'] = 'Anyone know what time it is?';
641
	$context['linktree'][] = array(
642
		'url' => $scripturl . '?action=clock',
643
		'name' => 'Clock',
644
	);
645
	$context['robot_no_index'] = true;
646
647
	$omfg = isset($_REQUEST['omfg']);
648
	$bcd = !isset($_REQUEST['rb']) && !isset($_REQUEST['omfg']) && !isset($_REQUEST['time']);
649
650
	loadTemplate('Calendar');
651
652
	if ($bcd)
653
	{
654
		$context['sub_template'] = 'bcd';
655
		$context['linktree'][] = array('url' => $scripturl . '?action=clock;bcd', 'name' => 'BCD');
656
		$context['clockicons'] = $smcFunc['json_decode'](base64_decode('eyJoMSI6WzIsMV0sImgyIjpbOCw0LDIsMV0sIm0xIjpbNCwyLDFdLCJtMiI6WzgsNCwyLDFdLCJzMSI6WzQsMiwxXSwiczIiOls4LDQsMiwxXX0='), true);
657
	}
658
	elseif (!$omfg && !isset($_REQUEST['time']))
659
	{
660
		$context['sub_template'] = 'hms';
661
		$context['linktree'][] = array('url' => $scripturl . '?action=clock', 'name' => 'Binary');
662
		$context['clockicons'] = $smcFunc['json_decode'](base64_decode('eyJoIjpbMTYsOCw0LDIsMV0sIm0iOlszMiwxNiw4LDQsMiwxXSwicyI6WzMyLDE2LDgsNCwyLDFdfQ'), true);
663
	}
664
	elseif ($omfg)
665
	{
666
		$context['sub_template'] = 'omfg';
667
		$context['linktree'][] = array('url' => $scripturl . '?action=clock;omfg', 'name' => 'OMFG');
668
		$context['clockicons'] = $smcFunc['json_decode'](base64_decode('eyJ5ZWFyIjpbNjQsMzIsMTYsOCw0LDIsMV0sIm1vbnRoIjpbOCw0LDIsMV0sImRheSI6WzE2LDgsNCwyLDFdLCJob3VyIjpbMTYsOCw0LDIsMV0sIm1pbiI6WzMyLDE2LDgsNCwyLDFdLCJzZWMiOlszMiwxNiw4LDQsMiwxXX0='), true);
669
	}
670
	elseif (isset($_REQUEST['time']))
671
	{
672
		$context['sub_template'] = 'thetime';
673
		$time = getdate($_REQUEST['time'] == 'now' ? time() : (int) $_REQUEST['time']);
674
		$context['linktree'][] = array('url' => $scripturl . '?action=clock;time=' . $_REQUEST['time'], 'name' => 'Requested Time');
675
		$context['clockicons'] = array(
676
			'year' => array(
677
				64 => false,
678
				32 => false,
679
				16 => false,
680
				8 => false,
681
				4 => false,
682
				2 => false,
683
				1 => false
684
			),
685
			'month' => array(
686
				8 => false,
687
				4 => false,
688
				2 => false,
689
				1 => false
690
			),
691
			'day' => array(
692
				16 => false,
693
				4 => false,
694
				8 => false,
695
				2 => false,
696
				1 => false
697
			),
698
			'hour' => array(
699
				32 => false,
700
				16 => false,
701
				8 => false,
702
				4 => false,
703
				2 => false,
704
				1 => false
705
			),
706
			'min' => array(
707
				32 => false,
708
				16 => false,
709
				8 => false,
710
				4 => false,
711
				2 => false,
712
				1 => false
713
			),
714
			'sec' => array(
715
				32 => false,
716
				16 => false,
717
				8 => false,
718
				4 => false,
719
				2 => false,
720
				1 => false
721
			),
722
		);
723
724
		foreach ($context['clockicons'] as $t => $vs)
725
			foreach ($vs as $v => $dumb)
726
			{
727
				if ($$t >= $v)
728
				{
729
					$$t -= $v;
730
					$context['clockicons'][$t][$v] = true;
731
				}
732
			}
733
	}
734
}
735
736
?>