Passed
Push — release-2.1 ( 0c2197...207d2d )
by Jeremy
05:47
created

Calendar.php ➔ iCalDownload()   F

Complexity

Conditions 20
Paths 18432

Size

Total Lines 105

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 20
nc 18432
nop 0
dl 0
loc 105
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 2018 Simple Machines and individual contributors
12
 * @license http://www.simplemachines.org/about/smf/license.php BSD
13
 *
14
 * @version 2.1 Beta 4
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
				$_REQUEST['start_date'] = $row['start_date'];
78
79
				// We might use this later.
80
				$context['selected_event'] = $evid;
81
			}
82
			$smcFunc['db_free_result']($request);
83
		}
84
		unset ($_GET['event']);
85
	}
86
87
	// Set the page title to mention the calendar ;).
88
	$context['page_title'] = $txt['calendar'];
89
90
	// Ensure a default view is defined
91
	if (empty($modSettings['calendar_default_view']))
92
		$modSettings['calendar_default_view'] = 'viewlist';
93
94
	// What view do we want?
95
	if (isset($_GET['viewweek']))
96
		$context['calendar_view'] = 'viewweek';
97
	elseif (isset($_GET['viewmonth']))
98
		$context['calendar_view'] = 'viewmonth';
99
	elseif (isset($_GET['viewlist']))
100
		$context['calendar_view'] = 'viewlist';
101
	else
102
		$context['calendar_view'] = $modSettings['calendar_default_view'];
103
104
	// Don't let search engines index the non-default calendar pages
105
	if ($context['calendar_view'] !== $modSettings['calendar_default_view'])
106
		$context['robot_no_index'] = true;
107
108
	// Get the current day of month...
109
	require_once($sourcedir . '/Subs-Calendar.php');
110
	$today = getTodayInfo();
111
112
	// Need a start date for all views
113
	if (!empty($_REQUEST['start_date']))
114
	{
115
		$start_parsed = date_parse($_REQUEST['start_date']);
116
		if (empty($start_parsed['error_count']) && empty($start_parsed['warning_count']))
117
		{
118
			$_REQUEST['year'] = $start_parsed['year'];
119
			$_REQUEST['month'] = $start_parsed['month'];
120
			$_REQUEST['day'] = $start_parsed['day'];
121
		}
122
	}
123
	$year = !empty($_REQUEST['year']) ? (int) $_REQUEST['year'] : $today['year'];
124
	$month = !empty($_REQUEST['month']) ? (int) $_REQUEST['month'] : $today['month'];
125
	$day = !empty($_REQUEST['day']) ? (int) $_REQUEST['day'] : (!empty($_REQUEST['month']) ? 1 : $today['day']);
126
127
	$start_object = checkdate($month, $day, $year) === true ? date_create(implode('-', array($year, $month, $day))) : date_create(implode('-', array($today['year'], $today['month'], $today['day'])));
128
129
	// Need an end date for the list view
130
	if (!empty($_REQUEST['end_date']))
131
	{
132
		$end_parsed = date_parse($_REQUEST['end_date']);
133
		if (empty($end_parsed['error_count']) && empty($end_parsed['warning_count']))
134
		{
135
			$_REQUEST['end_year'] = $end_parsed['year'];
136
			$_REQUEST['end_month'] = $end_parsed['month'];
137
			$_REQUEST['end_day'] = $end_parsed['day'];
138
		}
139
	}
140
	$end_year = !empty($_REQUEST['end_year']) ? (int) $_REQUEST['end_year'] : null;
141
	$end_month = !empty($_REQUEST['end_month']) ? (int) $_REQUEST['end_month'] : null;
142
	$end_day = !empty($_REQUEST['end_day']) ? (int) $_REQUEST['end_day'] : null;
143
144
	$end_object = checkdate($end_month, $end_day, $end_year) === true ? date_create(implode('-', array($end_year, $end_month, $end_day))) : null;
145
146
	if (empty($end_object) || $start_object >= $end_object)
147
	{
148
		$num_days_shown = empty($modSettings['cal_days_for_index']) || $modSettings['cal_days_for_index'] < 1 ? 1 : $modSettings['cal_days_for_index'];
149
150
		$end_object = date_create(date_format($start_object, 'Y-m-d'));
151
152
		date_add($end_object, date_interval_create_from_date_string($num_days_shown . ' days'));
153
	}
154
155
	$curPage = array(
156
		'year' => date_format($start_object, 'Y'),
157
		'month' => date_format($start_object, 'n'),
158
		'day' => date_format($start_object, 'j'),
159
		'start_date' => date_format($start_object, 'Y-m-d'),
160
		'end_year' => date_format($end_object, 'Y'),
161
		'end_month' => date_format($end_object, 'n'),
162
		'end_day' => date_format($end_object, 'j'),
163
		'end_date' => date_format($end_object, 'Y-m-d'),
164
	);
165
166
	// Make sure the year and month are in valid ranges.
167
	if ($curPage['month'] < 1 || $curPage['month'] > 12)
168
		fatal_lang_error('invalid_month', false);
169
	if ($curPage['year'] < $modSettings['cal_minyear'] || $curPage['year'] > $modSettings['cal_maxyear'])
170
		fatal_lang_error('invalid_year', false);
171
	// If we have a day clean that too.
172
	if ($context['calendar_view'] != 'viewmonth')
173
	{
174
		$isValid = checkdate($curPage['month'], $curPage['day'], $curPage['year']);
175
		if (!$isValid)
176
			fatal_lang_error('invalid_day', false);
177
	}
178
179
	// Load all the context information needed to show the calendar grid.
180
	$calendarOptions = array(
181
		'start_day' => !empty($options['calendar_start_day']) ? $options['calendar_start_day'] : 0,
182
		'show_birthdays' => in_array($modSettings['cal_showbdays'], array(1, 2)),
183
		'show_events' => in_array($modSettings['cal_showevents'], array(1, 2)),
184
		'show_holidays' => in_array($modSettings['cal_showholidays'], array(1, 2)),
185
		'highlight' => array(
186
			'events' => isset($modSettings['cal_highlight_events']) ? $modSettings['cal_highlight_events'] : 0,
187
			'holidays' => isset($modSettings['cal_highlight_holidays']) ? $modSettings['cal_highlight_holidays'] : 0,
188
			'birthdays' => isset($modSettings['cal_highlight_birthdays']) ? $modSettings['cal_highlight_birthdays'] : 0,
189
		),
190
		'show_week_num' => true,
191
		'short_day_titles' => !empty($modSettings['cal_short_days']),
192
		'short_month_titles' => !empty($modSettings['cal_short_months']),
193
		'show_next_prev' => !empty($modSettings['cal_prev_next_links']),
194
		'show_week_links' => isset($modSettings['cal_week_links']) ? $modSettings['cal_week_links'] : 0,
195
	);
196
197
	// Load up the main view.
198
	if ($context['calendar_view'] == 'viewlist')
199
		$context['calendar_grid_main'] = getCalendarList($curPage['start_date'], $curPage['end_date'], $calendarOptions);
200
	elseif ($context['calendar_view'] == 'viewweek')
201
		$context['calendar_grid_main'] = getCalendarWeek($curPage['month'], $curPage['year'], $curPage['day'], $calendarOptions);
202
	else
203
		$context['calendar_grid_main'] = getCalendarGrid($curPage['month'], $curPage['year'], $calendarOptions);
204
205
	// Load up the previous and next months.
206
	$context['calendar_grid_current'] = getCalendarGrid($curPage['month'], $curPage['year'], $calendarOptions);
207
208
	// Only show previous month if it isn't pre-January of the min-year
209
	if ($context['calendar_grid_current']['previous_calendar']['year'] > $modSettings['cal_minyear'] || $curPage['month'] != 1)
210
		$context['calendar_grid_prev'] = getCalendarGrid($context['calendar_grid_current']['previous_calendar']['month'], $context['calendar_grid_current']['previous_calendar']['year'], $calendarOptions, true);
211
212
	// Only show next month if it isn't post-December of the max-year
213
	if ($context['calendar_grid_current']['next_calendar']['year'] < $modSettings['cal_maxyear'] || $curPage['month'] != 12)
214
		$context['calendar_grid_next'] = getCalendarGrid($context['calendar_grid_current']['next_calendar']['month'], $context['calendar_grid_current']['next_calendar']['year'], $calendarOptions);
215
216
	// Basic template stuff.
217
	$context['allow_calendar_event'] = allowedTo('calendar_post');
218
219
	// If you don't allow events not linked to posts and you're not an admin, we have more work to do...
220
	if ($context['allow_calendar_event'] && empty($modSettings['cal_allow_unlinked']) && !$user_info['is_admin'])
221
	{
222
		$boards_can_post = boardsAllowedTo('post_new');
223
		$context['allow_calendar_event'] &= !empty($boards_can_post);
224
	}
225
226
	$context['can_post'] = $context['allow_calendar_event'];
227
	$context['current_day'] = $curPage['day'];
228
	$context['current_month'] = $curPage['month'];
229
	$context['current_year'] = $curPage['year'];
230
	$context['show_all_birthdays'] = isset($_GET['showbd']);
231
	$context['blocks_disabled'] = !empty($modSettings['cal_disable_prev_next']) ? 1 : 0;
232
233
	// Set the page title to mention the month or week, too
234
	if ($context['calendar_view'] != 'viewlist')
235
		$context['page_title'] .= ' - ' . ($context['calendar_view'] == 'viewweek' ? $context['calendar_grid_main']['week_title'] : $txt['months'][$context['current_month']] . ' ' . $context['current_year']);
236
237
	// Load up the linktree!
238
	$context['linktree'][] = array(
239
		'url' => $scripturl . '?action=calendar',
240
		'name' => $txt['calendar']
241
	);
242
	// Add the current month to the linktree.
243
	$context['linktree'][] = array(
244
		'url' => $scripturl . '?action=calendar;year=' . $context['current_year'] . ';month=' . $context['current_month'],
245
		'name' => $txt['months'][$context['current_month']] . ' ' . $context['current_year']
246
	);
247
	// If applicable, add the current week to the linktree.
248
	if ($context['calendar_view'] == 'viewweek')
249
		$context['linktree'][] = array(
250
			'url' => $scripturl . '?action=calendar;viewweek;year=' . $context['current_year'] . ';month=' . $context['current_month'] . ';day=' . $context['current_day'],
251
			'name' => $context['calendar_grid_main']['week_title'],
252
		);
253
254
	// Build the calendar button array.
255
	$context['calendar_buttons'] = array();
256
257
	if ($context['can_post'])
258
		$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']);
259
260
	// Allow mods to add additional buttons here
261
	call_integration_hook('integrate_calendar_buttons');
262
}
263
264
/**
265
 * This function processes posting/editing/deleting a calendar event.
266
 *
267
 * 	- calls {@link Post.php|Post() Post()} function if event is linked to a post.
268
 *  - calls {@link Subs-Calendar.php|insertEvent() insertEvent()} to insert the event if not linked to post.
269
 *
270
 * It requires the calendar_post permission to use.
271
 * It uses the event_post sub template in the Calendar template.
272
 * It is accessed with ?action=calendar;sa=post.
273
 */
274
function CalendarPost()
275
{
276
	global $context, $txt, $user_info, $sourcedir, $scripturl;
277
	global $modSettings, $topic, $smcFunc;
278
279
	// Well - can they?
280
	isAllowedTo('calendar_post');
281
282
	// We need these for all kinds of useful functions.
283
	require_once($sourcedir . '/Subs-Calendar.php');
284
	require_once($sourcedir . '/Subs.php');
285
286
	// Cast this for safety...
287
	if (isset($_REQUEST['eventid']))
288
		$_REQUEST['eventid'] = (int) $_REQUEST['eventid'];
289
290
	// We want a fairly compact version of the time, but as close as possible to the user's settings.
291
	if (preg_match('~%[HkIlMpPrRSTX](?:[^%]*%[HkIlMpPrRSTX])*~', $user_info['time_format'], $matches) == 0 || empty($matches[0]))
292
		$time_string = '%k:%M';
293
	else
294
		$time_string = str_replace(array('%I', '%H', '%S', '%r', '%R', '%T'), array('%l', '%k', '', '%l:%M %p', '%k:%M', '%l:%M'), $matches[0]);
295
296
	$js_time_string = str_replace(
297
		array('%H', '%k', '%I', '%l', '%M', '%p', '%P', '%r',      '%R',  '%S', '%T',    '%X'),
298
		array('H',  'G',  'h',  'g',  'i',  'A',  'a',  'h:i:s A', 'H:i', 's',  'H:i:s', 'H:i:s'),
299
		$time_string
300
	);
301
302
	// Submitting?
303
	if (isset($_POST[$context['session_var']], $_REQUEST['eventid']))
304
	{
305
		checkSession();
306
307
		// Validate the post...
308
		if (!isset($_POST['link_to_board']))
309
			validateEventPost();
310
311
		// If you're not allowed to edit any events, you have to be the poster.
312
		if ($_REQUEST['eventid'] > 0 && !allowedTo('calendar_edit_any'))
313
			isAllowedTo('calendar_edit_' . (!empty($user_info['id']) && getEventPoster($_REQUEST['eventid']) == $user_info['id'] ? 'own' : 'any'));
314
315
		// New - and directing?
316
		if (isset($_POST['link_to_board']) || empty($modSettings['cal_allow_unlinked']))
317
		{
318
			$_REQUEST['calendar'] = 1;
319
			require_once($sourcedir . '/Post.php');
320
			return Post();
321
		}
322
		// New...
323
		elseif ($_REQUEST['eventid'] == -1)
324
		{
325
			$eventOptions = array(
326
				'board' => 0,
327
				'topic' => 0,
328
				'title' => $smcFunc['substr']($_REQUEST['evtitle'], 0, 100),
329
				'location' => $smcFunc['substr']($_REQUEST['event_location'], 0, 255),
330
				'member' => $user_info['id'],
331
			);
332
			insertEvent($eventOptions);
333
		}
334
335
		// Deleting...
336
		elseif (isset($_REQUEST['deleteevent']))
337
			removeEvent($_REQUEST['eventid']);
338
339
		// ... or just update it?
340
		else
341
		{
342
			$eventOptions = array(
343
				'title' => $smcFunc['substr']($_REQUEST['evtitle'], 0, 100),
344
				'location' => $smcFunc['substr']($_REQUEST['event_location'], 0, 255),
345
			);
346
			modifyEvent($_REQUEST['eventid'], $eventOptions);
347
		}
348
349
		updateSettings(array(
350
			'calendar_updated' => time(),
351
		));
352
353
		// No point hanging around here now...
354
		if (isset($_POST['start_date']))
355
		{
356
			$d = date_parse($_POST['start_date']);
357
			$year = $d['year'];
358
			$month = $d['month'];
359
			$day = $d['day'];
360
		}
361
		elseif (isset($_POST['start_datetime']))
362
		{
363
			$d = date_parse($_POST['start_datetime']);
364
			$year = $d['year'];
365
			$month = $d['month'];
366
			$day = $d['day'];
367
		}
368
		else
369
		{
370
			$today = getdate();
371
			$year = isset($_POST['year']) ? $_POST['year'] : $today['year'];
372
			$month = isset($_POST['month']) ? $_POST['month'] : $today['mon'];
373
			$day = isset($_POST['day']) ? $_POST['day'] : $today['mday'];
374
		}
375
		redirectexit($scripturl . '?action=calendar;month=' . $month . ';year=' . $year . ';day=' . $day);
376
	}
377
378
	// If we are not enabled... we are not enabled.
379
	if (empty($modSettings['cal_allow_unlinked']) && empty($_REQUEST['eventid']))
380
	{
381
		$_REQUEST['calendar'] = 1;
382
		require_once($sourcedir . '/Post.php');
383
		return Post();
0 ignored issues
show
Bug introduced by
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...
384
	}
385
386
	// New?
387
	if (!isset($_REQUEST['eventid']))
388
	{
389
		$context['event'] = array(
390
			'boards' => array(),
391
			'board' => 0,
392
			'new' => 1,
393
			'eventid' => -1,
394
			'title' => '',
395
			'location' => '',
396
		);
397
398
		$eventDatetimes = getNewEventDatetimes();
399
		$context['event'] = array_merge($context['event'], $eventDatetimes);
400
401
		$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']));
402
	}
403
	else
404
	{
405
		$context['event'] = getEventProperties($_REQUEST['eventid']);
406
407
		if ($context['event'] === false)
408
			fatal_lang_error('no_access', false);
409
410
		// If it has a board, then they should be editing it within the topic.
411
		if (!empty($context['event']['topic']['id']) && !empty($context['event']['topic']['first_msg']))
412
		{
413
			// We load the board up, for a check on the board access rights...
414
			$topic = $context['event']['topic']['id'];
415
			loadBoard();
416
		}
417
418
		// Make sure the user is allowed to edit this event.
419
		if ($context['event']['member'] != $user_info['id'])
420
			isAllowedTo('calendar_edit_any');
421
		elseif (!allowedTo('calendar_edit_any'))
422
			isAllowedTo('calendar_edit_own');
423
	}
424
425
	// An all day event? Set up some nice defaults in case the user wants to change that
426
	if ($context['event']['allday'] == true)
427
	{
428
		$context['event']['tz'] = getUserTimezone();
429
		$context['event']['start_time'] = timeformat(time(), $time_string);
0 ignored issues
show
Bug introduced by
It seems like $time_string can also be of type string; however, parameter $show_today of timeformat() does only seem to accept boolean, 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

429
		$context['event']['start_time'] = timeformat(time(), /** @scrutinizer ignore-type */ $time_string);
Loading history...
430
		$context['event']['end_time'] = timeformat(time() + 3600, $time_string);
431
	}
432
	// Otherwise, just adjust these to look nice on the input form
433
	else
434
	{
435
		$context['event']['start_time'] = $context['event']['start_time_orig'];
436
		$context['event']['end_time'] = $context['event']['end_time_orig'];
437
	}
438
439
	// Need this so the user can select a timezone for the event.
440
	$context['all_timezones'] = smf_list_timezones($context['event']['start_date']);
441
	unset($context['all_timezones']['']);
442
443
	// If the event's timezone is not in SMF's standard list of time zones, prepend it to the list
444
	if (!in_array($context['event']['tz'], array_keys($context['all_timezones'])))
445
	{
446
		$d = date_create($context['event']['start_datetime'] . ' ' . $context['event']['tz']);
447
		$context['all_timezones'] = array($context['event']['tz'] => '[UTC' . date_format($d, 'P') . '] - ' . $context['event']['tz']) + $context['all_timezones'];
448
	}
449
450
	// Get list of boards that can be posted in.
451
	$boards = boardsAllowedTo('post_new');
452
	if (empty($boards))
453
	{
454
		// You can post new events but can't link them to anything...
455
		$context['event']['categories'] = array();
456
	}
457
	else
458
	{
459
		// Load the list of boards and categories in the context.
460
		require_once($sourcedir . '/Subs-MessageIndex.php');
461
		$boardListOptions = array(
462
			'included_boards' => in_array(0, $boards) ? null : $boards,
463
			'not_redirection' => true,
464
			'use_permissions' => true,
465
			'selected_board' => $modSettings['cal_defaultboard'],
466
		);
467
		$context['event']['categories'] = getBoardList($boardListOptions);
468
	}
469
470
	// Template, sub template, etc.
471
	loadTemplate('Calendar');
472
	$context['sub_template'] = 'event_post';
473
474
	$context['page_title'] = isset($_REQUEST['eventid']) ? $txt['calendar_edit'] : $txt['calendar_post_event'];
475
	$context['linktree'][] = array(
476
		'name' => $context['page_title'],
477
	);
478
479
	loadCSSFile('jquery-ui.datepicker.css', array(), 'smf_datepicker');
480
	loadCSSFile('jquery.timepicker.css', array(), 'smf_timepicker');
481
	loadJavaScriptFile('jquery-ui.datepicker.min.js', array('defer' => true), 'smf_datepicker');
482
	loadJavaScriptFile('jquery.timepicker.min.js', array('defer' => true), 'smf_timepicker');
483
	loadJavaScriptFile('datepair.min.js', array('defer' => true), 'smf_datepair');
484
	addInlineJavaScript('
485
	$("#allday").click(function(){
486
		$("#start_time").attr("disabled", this.checked);
487
		$("#end_time").attr("disabled", this.checked);
488
		$("#tz").attr("disabled", this.checked);
489
	});
490
	$("#event_time_input .date_input").datepicker({
491
		dateFormat: "yy-mm-dd",
492
		autoSize: true,
493
		isRTL: ' . ($context['right_to_left'] ? 'true' : 'false') . ',
494
		constrainInput: true,
495
		showAnim: "",
496
		showButtonPanel: false,
497
		minDate: "' . $modSettings['cal_minyear'] . '-01-01",
498
		maxDate: "' . $modSettings['cal_maxyear'] . '-12-31",
499
		yearRange: "' . $modSettings['cal_minyear'] . ':' . $modSettings['cal_maxyear'] . '",
500
		hideIfNoPrevNext: true,
501
		monthNames: ["' . implode('", "', $txt['months_titles']) . '"],
502
		monthNamesShort: ["' . implode('", "', $txt['months_short']) . '"],
503
		dayNames: ["' . implode('", "', $txt['days']) . '"],
504
		dayNamesShort: ["' . implode('", "', $txt['days_short']) . '"],
505
		dayNamesMin: ["' . implode('", "', $txt['days_short']) . '"],
506
		prevText: "' . $txt['prev_month'] . '",
507
		nextText: "' . $txt['next_month'] . '",
508
	});
509
	$(".time_input").timepicker({
510
		timeFormat: "' . $js_time_string . '",
511
		showDuration: true,
512
		maxTime: "23:59:59",
513
	});
514
	var date_entry = document.getElementById("event_time_input");
515
	var date_entry_pair = new Datepair(date_entry, {
516
		timeClass: "time_input",
517
		dateClass: "date_input",
518
		parseDate: function (el) {
519
		    var utc = new Date($(el).datepicker("getDate"));
520
		    return utc && new Date(utc.getTime() + (utc.getTimezoneOffset() * 60000));
521
		},
522
		updateDate: function (el, v) {
523
		    $(el).datepicker("setDate", new Date(v.getTime() - (v.getTimezoneOffset() * 60000)));
524
		}
525
	});
526
	', true);
527
}
528
529
/**
530
 * This function offers up a download of an event in iCal 2.0 format.
531
 *
532
 * Follows the conventions in {@link https://tools.ietf.org/html/rfc5546 RFC5546}
533
 * Sets events as all day events since we don't have hourly events
534
 * Will honor and set multi day events
535
 * Sets a sequence number if the event has been modified
536
 *
537
 * @todo .... allow for week or month export files as well?
538
 */
539
function iCalDownload()
540
{
541
	global $smcFunc, $sourcedir, $forum_version, $modSettings, $webmaster_email, $mbname;
542
543
	// You can't export if the calendar export feature is off.
544
	if (empty($modSettings['cal_export']))
545
		fatal_lang_error('calendar_export_off', false);
546
547
	// Goes without saying that this is required.
548
	if (!isset($_REQUEST['eventid']))
549
		fatal_lang_error('no_access', false);
550
551
	// This is kinda wanted.
552
	require_once($sourcedir . '/Subs-Calendar.php');
553
554
	// Load up the event in question and check it exists.
555
	$event = getEventProperties($_REQUEST['eventid']);
556
557
	if ($event === false)
0 ignored issues
show
introduced by
The condition $event === false is always false.
Loading history...
558
		fatal_lang_error('no_access', false);
559
560
	// Check the title isn't too long - iCal requires some formatting if so.
561
	$title = str_split($event['title'], 30);
562
	foreach ($title as $id => $line)
563
	{
564
		if ($id != 0)
565
			$title[$id] = ' ' . $title[$id];
566
		$title[$id] .= "\n";
567
	}
568
569
	// Format the dates.
570
	$datestamp = date('Ymd\THis\Z', time());
571
	$start_date = date_create($event['start_date'] . (isset($event['start_time']) ? ' ' . $event['start_time'] : '') . (isset($event['tz']) ? ' ' . $event['tz'] : ''));
572
	$end_date = date_create($event['end_date'] . (isset($event['end_time']) ? ' ' . $event['end_time'] : '') . (isset($event['tz']) ? ' ' . $event['tz'] : ''));
573
574
	if (!empty($event['start_time']))
575
	{
576
		$datestart = date_format($start_date, 'Ymd\THis');
577
		$dateend = date_format($end_date, 'Ymd\THis');
578
	}
579
	else
580
	{
581
		$datestart = date_format($start_date, 'Ymd');
582
583
		date_add($end_date, date_interval_create_from_date_string('1 day'));
0 ignored issues
show
Bug introduced by
It seems like $end_date can also be of type false; however, parameter $object of date_add() does only seem to accept DateTime, 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

583
		date_add(/** @scrutinizer ignore-type */ $end_date, date_interval_create_from_date_string('1 day'));
Loading history...
584
		$dateend = date_format($end_date, 'Ymd');
585
	}
586
587
	// This is what we will be sending later
588
	$filecontents = '';
589
	$filecontents .= 'BEGIN:VCALENDAR' . "\n";
590
	$filecontents .= 'METHOD:PUBLISH' . "\n";
591
	$filecontents .= 'PRODID:-//SimpleMachines//SMF ' . (empty($forum_version) ? 2.1 : strtr($forum_version, array('SMF ' => ''))) . '//EN' . "\n";
592
	$filecontents .= 'VERSION:2.0' . "\n";
593
	$filecontents .= 'BEGIN:VEVENT' . "\n";
594
	// @TODO - Should be the members email who created the event rather than $webmaster_email.
595
	$filecontents .= 'ORGANIZER;CN="' . $event['realname'] . '":MAILTO:' . $webmaster_email . "\n";
596
	$filecontents .= 'DTSTAMP:' . $datestamp . "\n";
597
	$filecontents .= 'DTSTART' . (!empty($event['start_time']) ? ';TZID=' . $event['tz'] : ';VALUE=DATE') . ':' . $datestart . "\n";
598
599
	// event has a duration
600
	if ($event['start_iso_gmdate'] != $event['end_iso_gmdate'])
601
		$filecontents .= 'DTEND' . (!empty($event['end_time']) ? ';TZID=' . $event['tz'] : ';VALUE=DATE') . ':' . $dateend . "\n";
602
603
	// event has changed? advance the sequence for this UID
604
	if ($event['sequence'] > 0)
605
		$filecontents .= 'SEQUENCE:' . $event['sequence'] . "\n";
606
607
	if (!empty($event['location']))
608
		$filecontents .= 'LOCATION:' . str_replace(',', '\,', $event['location']) . "\n";
609
610
	$filecontents .= 'SUMMARY:' . implode('', $title);
611
	$filecontents .= 'UID:' . $event['eventid'] . '@' . str_replace(' ', '-', $mbname) . "\n";
612
	$filecontents .= 'END:VEVENT' . "\n";
613
	$filecontents .= 'END:VCALENDAR';
614
615
	// Send some standard headers.
616
	ob_end_clean();
617
	if (!empty($modSettings['enableCompressedOutput']))
618
		@ob_start('ob_gzhandler');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for ob_start(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

618
		/** @scrutinizer ignore-unhandled */ @ob_start('ob_gzhandler');

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

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