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

Subs-Calendar.php ➔ getUserTimezone()   C

Complexity

Conditions 7
Paths 12

Size

Total Lines 26
Code Lines 13

Duplication

Lines 15
Ratio 57.69 %

Importance

Changes 0
Metric Value
cc 7
eloc 13
nc 12
nop 1
dl 15
loc 26
rs 6.7272
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * This file contains several functions for retrieving and manipulating calendar events, birthdays and holidays.
5
 *
6
 * Simple Machines Forum (SMF)
7
 *
8
 * @package SMF
9
 * @author Simple Machines http://www.simplemachines.org
10
 * @copyright 2016 Simple Machines and individual contributors
11
 * @license http://www.simplemachines.org/about/smf/license.php BSD
12
 *
13
 * @version 2.1 Beta 3
14
 */
15
16
if (!defined('SMF'))
17
	die('No direct access...');
18
19
/**
20
 * Get all birthdays within the given time range.
21
 * finds all the birthdays in the specified range of days.
22
 * works with birthdays set for no year, or any other year, and respects month and year boundaries.
23
 *
24
 * @param string $low_date The low end of the range, inclusive, in YYYY-MM-DD format
25
 * @param string $high_date The high end of the range, inclusive, in YYYY-MM-DD format
26
 * @return array An array of days, each of which is an array of birthday information for the context
27
 */
28
function getBirthdayRange($low_date, $high_date)
29
{
30
	global $smcFunc;
31
32
	// We need to search for any birthday in this range, and whatever year that birthday is on.
33
	$year_low = (int) substr($low_date, 0, 4);
34
	$year_high = (int) substr($high_date, 0, 4);
35
36
	// Collect all of the birthdays for this month.  I know, it's a painful query.
37
	$result = $smcFunc['db_query']('birthday_array', '
38
		SELECT id_member, real_name, YEAR(birthdate) AS birth_year, birthdate
39
		FROM {db_prefix}members
40
		WHERE YEAR(birthdate) != {string:year_one}
41
			AND MONTH(birthdate) != {int:no_month}
42
			AND DAYOFMONTH(birthdate) != {int:no_day}
43
			AND YEAR(birthdate) <= {int:max_year}
44
			AND (
45
				DATE_FORMAT(birthdate, {string:year_low}) BETWEEN {date:low_date} AND {date:high_date}' . ($year_low == $year_high ? '' : '
46
				OR DATE_FORMAT(birthdate, {string:year_high}) BETWEEN {date:low_date} AND {date:high_date}') . '
47
			)
48
			AND is_activated = {int:is_activated}',
49
		array(
50
			'is_activated' => 1,
51
			'no_month' => 0,
52
			'no_day' => 0,
53
			'year_one' => '0001',
54
			'year_low' => $year_low . '-%m-%d',
55
			'year_high' => $year_high . '-%m-%d',
56
			'low_date' => $low_date,
57
			'high_date' => $high_date,
58
			'max_year' => $year_high,
59
		)
60
	);
61
	$bday = array();
62
	while ($row = $smcFunc['db_fetch_assoc']($result))
63
	{
64
		if ($year_low != $year_high)
65
			$age_year = substr($row['birthdate'], 5) < substr($high_date, 5) ? $year_high : $year_low;
66
		else
67
			$age_year = $year_low;
68
69
		$bday[$age_year . substr($row['birthdate'], 4)][] = array(
70
			'id' => $row['id_member'],
71
			'name' => $row['real_name'],
72
			'age' => $row['birth_year'] > 4 && $row['birth_year'] <= $age_year ? $age_year - $row['birth_year'] : null,
73
			'is_last' => false
74
		);
75
	}
76
	$smcFunc['db_free_result']($result);
77
78
	// Set is_last, so the themes know when to stop placing separators.
79 View Code Duplication
	foreach ($bday as $mday => $array)
0 ignored issues
show
Duplication introduced by
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...
80
		$bday[$mday][count($array) - 1]['is_last'] = true;
81
82
	return $bday;
83
}
84
85
/**
86
 * Get all calendar events within the given time range.
87
 *
88
 * - finds all the posted calendar events within a date range.
89
 * - both the earliest_date and latest_date should be in the standard YYYY-MM-DD format.
90
 * - censors the posted event titles.
91
 * - uses the current user's permissions if use_permissions is true, otherwise it does nothing "permission specific"
92
 *
93
 * @param string $low_date The low end of the range, inclusive, in YYYY-MM-DD format
94
 * @param string $high_date The high end of the range, inclusive, in YYYY-MM-DD format
95
 * @param bool $use_permissions Whether to use permissions
96
 * @return array Contextual information if use_permissions is true, and an array of the data needed to build that otherwise
97
 */
98
function getEventRange($low_date, $high_date, $use_permissions = true)
99
{
100
	global $scripturl, $modSettings, $user_info, $smcFunc, $context, $sourcedir;
101
	require_once($sourcedir . '/Subs.php');
102
103
	$low_object = date_create($low_date);
104
	$high_object = date_create($high_date);
105
106
	// Find all the calendar info...
107
	$result = $smcFunc['db_query']('', '
108
		SELECT
109
			cal.id_event, cal.title, cal.id_member, cal.id_topic, cal.id_board,
110
			cal.start_date, cal.end_date, cal.start_time, cal.end_time, cal.timezone, cal.location,
111
			b.member_groups, t.id_first_msg, t.approved, b.id_board
112
		FROM {db_prefix}calendar AS cal
113
			LEFT JOIN {db_prefix}boards AS b ON (b.id_board = cal.id_board)
114
			LEFT JOIN {db_prefix}topics AS t ON (t.id_topic = cal.id_topic)
115
		WHERE cal.start_date <= {date:high_date}
116
			AND cal.end_date >= {date:low_date}' . ($use_permissions ? '
117
			AND (cal.id_board = {int:no_board_link} OR {query_wanna_see_board})' : ''),
118
		array(
119
			'high_date' => $high_date,
120
			'low_date' => $low_date,
121
			'no_board_link' => 0,
122
		)
123
	);
124
	$events = array();
125
	while ($row = $smcFunc['db_fetch_assoc']($result))
126
	{
127
		// If the attached topic is not approved then for the moment pretend it doesn't exist
128
		if (!empty($row['id_first_msg']) && $modSettings['postmod_active'] && !$row['approved'])
129
			continue;
130
131
		// Force a censor of the title - as often these are used by others.
132
		censorText($row['title'], $use_permissions ? false : true);
133
134
		$tz = !empty($row['timezone']) ? $row['timezone'] : getUserTimezone();
135
136
		// Get the various time and date properties for this event
137
		list($start, $end, $allday, $span, $tz_abbrev) = buildEventDatetimes($row);
138
139
		// Sanity check
140 View Code Duplication
		if (!empty($start['error_count']) || !empty($start['warning_count']) || !empty($end['error_count']) || !empty($end['warning_count']))
0 ignored issues
show
Duplication introduced by
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...
141
			continue;
142
143
		// Get set up for the loop
144
		$start_object = date_create($row['start_date'] . (!$allday ? ' ' . $row['start_time'] : ''), timezone_open($tz));
145
		$end_object = date_create($row['end_date'] . (!$allday ? ' ' . $row['end_time'] : ''), timezone_open($tz));
146
		date_timezone_set($start_object, timezone_open(date_default_timezone_get()));
147
		date_timezone_set($end_object, timezone_open(date_default_timezone_get()));
148
		date_time_set($start_object, 0, 0, 0);
149
		date_time_set($end_object, 0, 0, 0);
150
		$start_date_string = date_format($start_object, 'Y-m-d');
151
		$end_date_string = date_format($end_object, 'Y-m-d');
152
153
		$cal_date = ($start_object >= $low_object) ? $start_object : $low_object;
154
		while ($cal_date <= $end_object && $cal_date <= $high_object)
155
		{
156
			$starts_today = (date_format($cal_date, 'Y-m-d') == $start_date_string);
157
			$ends_today = (date_format($cal_date, 'Y-m-d') == $end_date_string);
158
159
			$eventProperties = array(
160
					'id' => $row['id_event'],
161
					'title' => $row['title'],
162
					'year' => $start['year'],
163
					'month' => $start['month'],
164
					'day' => $start['day'],
165
					'hour' => !$allday ? $start['hour'] : null,
166
					'minute' => !$allday ? $start['minute'] : null,
167
					'second' => !$allday ? $start['second'] : null,
168
					'start_date' => $row['start_date'],
169
					'start_date_local' => $start['date_local'],
170
					'start_date_orig' => $start['date_orig'],
171
					'start_time' => !$allday ? $row['start_time'] : null,
172
					'start_time_local' => !$allday ? $start['time_local'] : null,
173
					'start_time_orig' => !$allday ? $start['time_orig'] : null,
174
					'start_timestamp' => $start['timestamp'],
175
					'start_datetime' => $start['datetime'],
176
					'start_iso_gmdate' => $start['iso_gmdate'],
177
					'end_year' => $end['year'],
178
					'end_month' => $end['month'],
179
					'end_day' => $end['day'],
180
					'end_hour' => !$allday ? $end['hour'] : null,
181
					'end_minute' => !$allday ? $end['minute'] : null,
182
					'end_second' => !$allday ? $end['second'] : null,
183
					'end_date' => $row['end_date'],
184
					'end_date_local' => $end['date_local'],
185
					'end_date_orig' => $end['date_orig'],
186
					'end_time' => !$allday ? $row['end_time'] : null,
187
					'end_time_local' => !$allday ? $end['time_local'] : null,
188
					'end_time_orig' => !$allday ? $end['time_orig'] : null,
189
					'end_timestamp' => $end['timestamp'],
190
					'end_datetime' => $end['datetime'],
191
					'end_iso_gmdate' => $end['iso_gmdate'],
192
					'allday' => $allday,
193
					'tz' => !$allday ? $row['timezone'] : null,
194
					'tz_abbrev' => !$allday ? $tz_abbrev : null,
195
					'span' => $span,
196
					'is_last' => false,
197
					'id_board' => $row['id_board'],
198
					'is_selected' => !empty($context['selected_event']) && $context['selected_event'] == $row['id_event'],
199
					'starts_today' => $starts_today,
200
					'ends_today' => $ends_today,
201
					'location' => $row['location'],
202
			);
203
204
			// If we're using permissions (calendar pages?) then just ouput normal contextual style information.
205
			if ($use_permissions)
206
				$events[date_format($cal_date, 'Y-m-d')][] = array_merge($eventProperties, array(
207
					'href' => $row['id_board'] == 0 ? '' : $scripturl . '?topic=' . $row['id_topic'] . '.0',
208
					'link' => $row['id_board'] == 0 ? $row['title'] : '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.0">' . $row['title'] . '</a>',
209
					'can_edit' => allowedTo('calendar_edit_any') || ($row['id_member'] == $user_info['id'] && allowedTo('calendar_edit_own')),
210
					'modify_href' => $scripturl . '?action=' . ($row['id_board'] == 0 ? 'calendar;sa=post;' : 'post;msg=' . $row['id_first_msg'] . ';topic=' . $row['id_topic'] . '.0;calendar;') . 'eventid=' . $row['id_event'] . ';' . $context['session_var'] . '=' . $context['session_id'],
211
					'can_export' => !empty($modSettings['cal_export']) ? true : false,
212
					'export_href' => $scripturl . '?action=calendar;sa=ical;eventid=' . $row['id_event'] . ';' . $context['session_var'] . '=' . $context['session_id'],
213
				));
214
			// Otherwise, this is going to be cached and the VIEWER'S permissions should apply... just put together some info.
215
			else
216
				$events[date_format($cal_date, 'Y-m-d')][] = array_merge($eventProperties, array(
217
					'href' => $row['id_topic'] == 0 ? '' : $scripturl . '?topic=' . $row['id_topic'] . '.0',
218
					'link' => $row['id_topic'] == 0 ? $row['title'] : '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.0">' . $row['title'] . '</a>',
219
					'can_edit' => false,
220
					'can_export' => !empty($modSettings['cal_export']) ? true : false,
221
					'topic' => $row['id_topic'],
222
					'msg' => $row['id_first_msg'],
223
					'poster' => $row['id_member'],
224
					'allowed_groups' => explode(',', $row['member_groups']),
225
				));
226
227
			date_add($cal_date, date_interval_create_from_date_string('1 day'));
228
		}
229
	}
230
	$smcFunc['db_free_result']($result);
231
232
	// If we're doing normal contextual data, go through and make things clear to the templates ;).
233
	if ($use_permissions)
234
	{
235 View Code Duplication
		foreach ($events as $mday => $array)
0 ignored issues
show
Duplication introduced by
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...
236
			$events[$mday][count($array) - 1]['is_last'] = true;
237
	}
238
239
	return $events;
240
}
241
242
/**
243
 * Get all holidays within the given time range.
244
 *
245
 * @param string $low_date The low end of the range, inclusive, in YYYY-MM-DD format
246
 * @param string $high_date The high end of the range, inclusive, in YYYY-MM-DD format
247
 * @return array An array of days, which are all arrays of holiday names.
248
 */
249
function getHolidayRange($low_date, $high_date)
250
{
251
	global $smcFunc;
252
253
	// Get the lowest and highest dates for "all years".
254
	if (substr($low_date, 0, 4) != substr($high_date, 0, 4))
255
		$allyear_part = 'event_date BETWEEN {date:all_year_low} AND {date:all_year_dec}
256
			OR event_date BETWEEN {date:all_year_jan} AND {date:all_year_high}';
257
	else
258
		$allyear_part = 'event_date BETWEEN {date:all_year_low} AND {date:all_year_high}';
259
260
	// Find some holidays... ;).
261
	$result = $smcFunc['db_query']('', '
262
		SELECT event_date, YEAR(event_date) AS year, title
263
		FROM {db_prefix}calendar_holidays
264
		WHERE event_date BETWEEN {date:low_date} AND {date:high_date}
265
			OR ' . $allyear_part,
266
		array(
267
			'low_date' => $low_date,
268
			'high_date' => $high_date,
269
			'all_year_low' => '0004' . substr($low_date, 4),
270
			'all_year_high' => '0004' . substr($high_date, 4),
271
			'all_year_jan' => '0004-01-01',
272
			'all_year_dec' => '0004-12-31',
273
		)
274
	);
275
	$holidays = array();
276
	while ($row = $smcFunc['db_fetch_assoc']($result))
277
	{
278
		if (substr($low_date, 0, 4) != substr($high_date, 0, 4))
279
			$event_year = substr($row['event_date'], 5) < substr($high_date, 5) ? substr($high_date, 0, 4) : substr($low_date, 0, 4);
280
		else
281
			$event_year = substr($low_date, 0, 4);
282
283
		$holidays[$event_year . substr($row['event_date'], 4)][] = $row['title'];
284
	}
285
	$smcFunc['db_free_result']($result);
286
287
	return $holidays;
288
}
289
290
/**
291
 * Does permission checks to see if an event can be linked to a board/topic.
292
 * checks if the current user can link the current topic to the calendar, permissions et al.
293
 * this requires the calendar_post permission, a forum moderator, or a topic starter.
294
 * expects the $topic and $board variables to be set.
295
 * if the user doesn't have proper permissions, an error will be shown.
296
 */
297
function canLinkEvent()
298
{
299
	global $user_info, $topic, $board, $smcFunc;
300
301
	// If you can't post, you can't link.
302
	isAllowedTo('calendar_post');
303
304
	// No board?  No topic?!?
305
	if (empty($board))
306
		fatal_lang_error('missing_board_id', false);
0 ignored issues
show
Documentation introduced by
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...
307
	if (empty($topic))
308
		fatal_lang_error('missing_topic_id', false);
0 ignored issues
show
Documentation introduced by
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...
309
310
	// Administrator, Moderator, or owner.  Period.
311
	if (!allowedTo('admin_forum') && !allowedTo('moderate_board'))
312
	{
313
		// Not admin or a moderator of this board. You better be the owner - or else.
314
		$result = $smcFunc['db_query']('', '
315
			SELECT id_member_started
316
			FROM {db_prefix}topics
317
			WHERE id_topic = {int:current_topic}
318
			LIMIT 1',
319
			array(
320
				'current_topic' => $topic,
321
			)
322
		);
323
		if ($row = $smcFunc['db_fetch_assoc']($result))
324
		{
325
			// Not the owner of the topic.
326
			if ($row['id_member_started'] != $user_info['id'])
327
				fatal_lang_error('not_your_topic', 'user');
328
		}
329
		// Topic/Board doesn't exist.....
330
		else
331
			fatal_lang_error('calendar_no_topic', 'general');
332
		$smcFunc['db_free_result']($result);
333
	}
334
}
335
336
/**
337
 * Returns date information about 'today' relative to the users time offset.
338
 * returns an array with the current date, day, month, and year.
339
 * takes the users time offset into account.
340
 * @return array An array of info about today, based on forum time. Has 'day', 'month', 'year' and 'date' (in YYYY-MM-DD format)
341
 */
342
function getTodayInfo()
343
{
344
	return array(
345
		'day' => (int) strftime('%d', forum_time()),
346
		'month' => (int) strftime('%m', forum_time()),
347
		'year' => (int) strftime('%Y', forum_time()),
348
		'date' => strftime('%Y-%m-%d', forum_time()),
349
	);
350
}
351
352
/**
353
 * Provides information (link, month, year) about the previous and next month.
354
 * @param int $month The month to display
355
 * @param int $year The year
356
 * @param array $calendarOptions An array of calendar options
357
 * @param bool $is_previous Whether this is the previous month
358
 * @return array A large array containing all the information needed to show a calendar grid for the given month
359
 */
360
function getCalendarGrid($month, $year, $calendarOptions, $is_previous = false)
361
{
362
	global $scripturl, $modSettings;
363
364
	// Eventually this is what we'll be returning.
365
	$calendarGrid = array(
366
		'week_days' => array(),
367
		'weeks' => array(),
368
		'short_day_titles' => !empty($calendarOptions['short_day_titles']),
369
		'short_month_titles' => !empty($calendarOptions['short_month_titles']),
370
		'highlight' => array(
371
			'events' => !empty($calendarOptions['highlight']['events']) && !empty($calendarOptions['show_events']) ? $calendarOptions['highlight']['events'] : 0,
372
			'holidays' => !empty($calendarOptions['highlight']['holidays']) && !empty($calendarOptions['show_holidays']) ? $calendarOptions['highlight']['holidays'] : 0,
373
			'birthdays' => !empty($calendarOptions['highlight']['birthdays']) && !empty($calendarOptions['show_birthdays']) ? $calendarOptions['highlight']['birthdays'] : 0,
374
		),
375
		'current_month' => $month,
376
		'current_year' => $year,
377
		'show_next_prev' => !empty($calendarOptions['show_next_prev']),
378
		'show_week_links' => isset($calendarOptions['show_week_links']) ? $calendarOptions['show_week_links'] : 0,
379
		'previous_calendar' => array(
380
			'year' => $month == 1 ? $year - 1 : $year,
381
			'month' => $month == 1 ? 12 : $month - 1,
382
			'disabled' => $modSettings['cal_minyear'] > ($month == 1 ? $year - 1 : $year),
383
		),
384
		'next_calendar' => array(
385
			'year' => $month == 12 ? $year + 1 : $year,
386
			'month' => $month == 12 ? 1 : $month + 1,
387
			'disabled' => $modSettings['cal_maxyear'] < ($month == 12 ? $year + 1 : $year),
388
		),
389
		'size' => empty($modSettings['cal_display_type']) ? 'large' : 'small',
390
	);
391
392
	// Get today's date.
393
	$today = getTodayInfo();
394
395
	// Get information about this month.
396
	$month_info = array(
397
		'first_day' => array(
398
			'day_of_week' => (int) strftime('%w', mktime(0, 0, 0, $month, 1, $year)),
399
			'week_num' => (int) strftime('%U', mktime(0, 0, 0, $month, 1, $year)),
400
			'date' => strftime('%Y-%m-%d', mktime(0, 0, 0, $month, 1, $year)),
401
		),
402
		'last_day' => array(
403
			'day_of_month' => (int) strftime('%d', mktime(0, 0, 0, $month == 12 ? 1 : $month + 1, 0, $month == 12 ? $year + 1 : $year)),
404
			'date' => strftime('%Y-%m-%d', mktime(0, 0, 0, $month == 12 ? 1 : $month + 1, 0, $month == 12 ? $year + 1 : $year)),
405
		),
406
		'first_day_of_year' => (int) strftime('%w', mktime(0, 0, 0, 1, 1, $year)),
407
		'first_day_of_next_year' => (int) strftime('%w', mktime(0, 0, 0, 1, 1, $year + 1)),
408
	);
409
410
	// The number of days the first row is shifted to the right for the starting day.
411
	$nShift = $month_info['first_day']['day_of_week'];
412
413
	$calendarOptions['start_day'] = empty($calendarOptions['start_day']) ? 0 : (int) $calendarOptions['start_day'];
414
415
	// Starting any day other than Sunday means a shift...
416
	if (!empty($calendarOptions['start_day']))
417
	{
418
		$nShift -= $calendarOptions['start_day'];
419
		if ($nShift < 0)
420
			$nShift = 7 + $nShift;
421
	}
422
423
	// Number of rows required to fit the month.
424
	$nRows = floor(($month_info['last_day']['day_of_month'] + $nShift) / 7);
425
	if (($month_info['last_day']['day_of_month'] + $nShift) % 7)
426
		$nRows++;
427
428
	// Fetch the arrays for birthdays, posted events, and holidays.
429
	$bday = $calendarOptions['show_birthdays'] ? getBirthdayRange($month_info['first_day']['date'], $month_info['last_day']['date']) : array();
430
	$events = $calendarOptions['show_events'] ? getEventRange($month_info['first_day']['date'], $month_info['last_day']['date']) : array();
431
	$holidays = $calendarOptions['show_holidays'] ? getHolidayRange($month_info['first_day']['date'], $month_info['last_day']['date']) : array();
432
433
	// Days of the week taking into consideration that they may want it to start on any day.
434
	$count = $calendarOptions['start_day'];
435
	for ($i = 0; $i < 7; $i++)
436
	{
437
		$calendarGrid['week_days'][] = $count;
438
		$count++;
439
		if ($count == 7)
440
			$count = 0;
441
	}
442
443
	// Iterate through each week.
444
	$calendarGrid['weeks'] = array();
445
	for ($nRow = 0; $nRow < $nRows; $nRow++)
446
	{
447
		// Start off the week - and don't let it go above 52, since that's the number of weeks in a year.
448
		$calendarGrid['weeks'][$nRow] = array(
449
			'days' => array(),
450
		);
451
452
		// And figure out all the days.
453
		for ($nCol = 0; $nCol < 7; $nCol++)
454
		{
455
			$nDay = ($nRow * 7) + $nCol - $nShift + 1;
456
457
			if ($nDay < 1 || $nDay > $month_info['last_day']['day_of_month'])
458
				$nDay = 0;
459
460
			$date = sprintf('%04d-%02d-%02d', $year, $month, $nDay);
461
462
			$calendarGrid['weeks'][$nRow]['days'][$nCol] = array(
463
				'day' => $nDay,
464
				'date' => $date,
465
				'is_today' => $date == $today['date'],
466
				'is_first_day' => !empty($calendarOptions['show_week_num']) && (($month_info['first_day']['day_of_week'] + $nDay - 1) % 7 == $calendarOptions['start_day']),
467
				'is_first_of_month' => $nDay === 1,
468
				'holidays' => !empty($holidays[$date]) ? $holidays[$date] : array(),
469
				'events' => !empty($events[$date]) ? $events[$date] : array(),
470
				'birthdays' => !empty($bday[$date]) ? $bday[$date] : array(),
471
			);
472
		}
473
	}
474
475
	// What is the last day of the month?
476
	if ($is_previous === true)
477
		$calendarGrid['last_of_month'] = $month_info['last_day']['day_of_month'];
478
479
	// We'll use the shift in the template.
480
	$calendarGrid['shift'] = $nShift;
481
482
	// Set the previous and the next month's links.
483
	$calendarGrid['previous_calendar']['href'] = $scripturl . '?action=calendar;year=' . $calendarGrid['previous_calendar']['year'] . ';month=' . $calendarGrid['previous_calendar']['month'];
484
	$calendarGrid['next_calendar']['href'] = $scripturl . '?action=calendar;year=' . $calendarGrid['next_calendar']['year'] . ';month=' . $calendarGrid['next_calendar']['month'];
485
486
	return $calendarGrid;
487
}
488
489
/**
490
 * Returns the information needed to show a calendar for the given week.
491
 * @param int $month The month
492
 * @param int $year The year
493
 * @param int $day The day
494
 * @param array $calendarOptions An array of calendar options
495
 * @return array An array of information needed to display the grid for a single week on the calendar
496
 */
497
function getCalendarWeek($month, $year, $day, $calendarOptions)
498
{
499
	global $scripturl, $modSettings, $txt;
500
501
	// Get today's date.
502
	$today = getTodayInfo();
503
504
	// What is the actual "start date" for the passed day.
505
	$calendarOptions['start_day'] = empty($calendarOptions['start_day']) ? 0 : (int) $calendarOptions['start_day'];
506
	$day_of_week = (int) strftime('%w', mktime(0, 0, 0, $month, $day, $year));
507
	if ($day_of_week != $calendarOptions['start_day'])
508
	{
509
		// Here we offset accordingly to get things to the real start of a week.
510
		$date_diff = $day_of_week - $calendarOptions['start_day'];
511
		if ($date_diff < 0)
512
			$date_diff += 7;
513
		$new_timestamp = mktime(0, 0, 0, $month, $day, $year) - $date_diff * 86400;
514
		$day = (int) strftime('%d', $new_timestamp);
515
		$month = (int) strftime('%m', $new_timestamp);
516
		$year = (int) strftime('%Y', $new_timestamp);
517
	}
518
519
	// Now start filling in the calendar grid.
520
	$calendarGrid = array(
521
		'show_next_prev' => !empty($calendarOptions['show_next_prev']),
522
		// Previous week is easy - just step back one day.
523
		'previous_week' => array(
524
			'year' => $day == 1 ? ($month == 1 ? $year - 1 : $year) : $year,
525
			'month' => $day == 1 ? ($month == 1 ? 12 : $month - 1) : $month,
526
			'day' => $day == 1 ? 28 : $day - 1,
527
			'disabled' => $day < 7 && $modSettings['cal_minyear'] > ($month == 1 ? $year - 1 : $year),
528
		),
529
		'next_week' => array(
530
			'disabled' => $day > 25 && $modSettings['cal_maxyear'] < ($month == 12 ? $year + 1 : $year),
531
		),
532
		'size' => empty($modSettings['cal_display_type']) ? 'large' : 'small',
533
	);
534
535
	// The next week calculation requires a bit more work.
536
	$curTimestamp = mktime(0, 0, 0, $month, $day, $year);
537
	$nextWeekTimestamp = $curTimestamp + 604800;
538
	$calendarGrid['next_week']['day'] = (int) strftime('%d', $nextWeekTimestamp);
539
	$calendarGrid['next_week']['month'] = (int) strftime('%m', $nextWeekTimestamp);
540
	$calendarGrid['next_week']['year'] = (int) strftime('%Y', $nextWeekTimestamp);
541
542
	// Fetch the arrays for birthdays, posted events, and holidays.
543
	$startDate = strftime('%Y-%m-%d', $curTimestamp);
544
	$endDate = strftime('%Y-%m-%d', $nextWeekTimestamp);
545
	$bday = $calendarOptions['show_birthdays'] ? getBirthdayRange($startDate, $endDate) : array();
546
	$events = $calendarOptions['show_events'] ? getEventRange($startDate, $endDate) : array();
547
	$holidays = $calendarOptions['show_holidays'] ? getHolidayRange($startDate, $endDate) : array();
548
549
	// An adjustment value to apply to all calculated week numbers.
550
	if (!empty($calendarOptions['show_week_num']))
551
	{
552
		$first_day_of_year = (int) strftime('%w', mktime(0, 0, 0, 1, 1, $year));
0 ignored issues
show
Unused Code introduced by
$first_day_of_year is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
553
		$first_day_of_next_year = (int) strftime('%w', mktime(0, 0, 0, 1, 1, $year + 1));
0 ignored issues
show
Unused Code introduced by
$first_day_of_next_year is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
554
		$last_day_of_last_year = (int) strftime('%w', mktime(0, 0, 0, 12, 31, $year - 1));
0 ignored issues
show
Unused Code introduced by
$last_day_of_last_year is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
555
556
		$timestamp = mktime(0, 0, 0, $month, $day, $year);
557
		$calendarGrid['week_title'] = sprintf($txt['calendar_week_beginning'], date('F', $timestamp), date('j', $timestamp), date('Y', $timestamp));
558
	}
559
560
	// This holds all the main data - there is at least one month!
561
	$calendarGrid['months'] = array();
562
	$lastDay = 99;
563
	$curDay = $day;
564
	$curDayOfWeek = $calendarOptions['start_day'];
565
	for ($i = 0; $i < 7; $i++)
566
	{
567
		// Have we gone into a new month (Always happens first cycle too)
568
		if ($lastDay > $curDay)
569
		{
570
			$curMonth = $lastDay == 99 ? $month : ($month == 12 ? 1 : $month + 1);
571
			$curYear = $lastDay == 99 ? $year : ($curMonth == 1 && $month == 12 ? $year + 1 : $year);
572
			$calendarGrid['months'][$curMonth] = array(
573
				'current_month' => $curMonth,
574
				'current_year' => $curYear,
575
				'days' => array(),
576
			);
577
		}
578
579
		// Add todays information to the pile!
580
		$date = sprintf('%04d-%02d-%02d', $curYear, $curMonth, $curDay);
0 ignored issues
show
Bug introduced by
The variable $curYear does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $curMonth does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
581
582
		$calendarGrid['months'][$curMonth]['days'][$curDay] = array(
583
			'day' => $curDay,
584
			'day_of_week' => $curDayOfWeek,
585
			'date' => $date,
586
			'is_today' => $date == $today['date'],
587
			'holidays' => !empty($holidays[$date]) ? $holidays[$date] : array(),
588
			'events' => !empty($events[$date]) ? $events[$date] : array(),
589
			'birthdays' => !empty($bday[$date]) ? $bday[$date] : array()
590
		);
591
592
		// Make the last day what the current day is and work out what the next day is.
593
		$lastDay = $curDay;
594
		$curTimestamp += 86400;
595
		$curDay = (int) strftime('%d', $curTimestamp);
596
597
		// Also increment the current day of the week.
598
		$curDayOfWeek = $curDayOfWeek >= 6 ? 0 : ++$curDayOfWeek;
599
	}
600
601
	// Set the previous and the next week's links.
602
	$calendarGrid['previous_week']['href'] = $scripturl . '?action=calendar;viewweek;year=' . $calendarGrid['previous_week']['year'] . ';month=' . $calendarGrid['previous_week']['month'] . ';day=' . $calendarGrid['previous_week']['day'];
603
	$calendarGrid['next_week']['href'] = $scripturl . '?action=calendar;viewweek;year=' . $calendarGrid['next_week']['year'] . ';month=' . $calendarGrid['next_week']['month'] . ';day=' . $calendarGrid['next_week']['day'];
604
605
	return $calendarGrid;
606
}
607
608
/**
609
 * Retrieve all events for the given days, independently of the users offset.
610
 * cache callback function used to retrieve the birthdays, holidays, and events between now and now + days_to_index.
611
 * widens the search range by an extra 24 hours to support time offset shifts.
612
 * used by the cache_getRecentEvents function to get the information needed to calculate the events taking the users time offset into account.
613
 *
614
 * @param int $days_to_index How many days' worth of info to index
615
 * @return array An array containing the data that was cached as well as an expression to calculate whether the data should be refreshed and when it expires
616
 */
617
function cache_getOffsetIndependentEvents($days_to_index)
618
{
619
	$low_date = strftime('%Y-%m-%d', forum_time(false) - 24 * 3600);
620
	$high_date = strftime('%Y-%m-%d', forum_time(false) + $days_to_index * 24 * 3600);
621
622
	return array(
623
		'data' => array(
624
			'holidays' => getHolidayRange($low_date, $high_date),
625
			'birthdays' => getBirthdayRange($low_date, $high_date),
626
			'events' => getEventRange($low_date, $high_date, false),
627
		),
628
		'refresh_eval' => 'return \'' . strftime('%Y%m%d', forum_time(false)) . '\' != strftime(\'%Y%m%d\', forum_time(false)) || (!empty($modSettings[\'calendar_updated\']) && ' . time() . ' < $modSettings[\'calendar_updated\']);',
629
		'expires' => time() + 3600,
630
	);
631
}
632
633
/**
634
 * cache callback function used to retrieve the upcoming birthdays, holidays, and events within the given period, taking into account the users time offset.
635
 * Called from the BoardIndex to display the current day's events on the board index
636
 * used by the board index and SSI to show the upcoming events.
637
 * @param array $eventOptions An array of event options. Only 'num_days_shown' is used here
638
 * @return array An array containing the info that was cached as well as a few other relevant things
639
 */
640
function cache_getRecentEvents($eventOptions)
641
{
642
	// With the 'static' cached data we can calculate the user-specific data.
643
	$cached_data = cache_quick_get('calendar_index', 'Subs-Calendar.php', 'cache_getOffsetIndependentEvents', array($eventOptions['num_days_shown']));
644
645
	// Get the information about today (from user perspective).
646
	$today = getTodayInfo();
647
648
	$return_data = array(
649
		'calendar_holidays' => array(),
650
		'calendar_birthdays' => array(),
651
		'calendar_events' => array(),
652
	);
653
654
	// Set the event span to be shown in seconds.
655
	$days_for_index = $eventOptions['num_days_shown'] * 86400;
656
657
	// Get the current member time/date.
658
	$now = forum_time();
659
660
	// Holidays between now and now + days.
661
	for ($i = $now; $i < $now + $days_for_index; $i += 86400)
662
	{
663
		if (isset($cached_data['holidays'][strftime('%Y-%m-%d', $i)]))
664
			$return_data['calendar_holidays'] = array_merge($return_data['calendar_holidays'], $cached_data['holidays'][strftime('%Y-%m-%d', $i)]);
665
	}
666
667
	// Happy Birthday, guys and gals!
668
	for ($i = $now; $i < $now + $days_for_index; $i += 86400)
669
	{
670
		$loop_date = strftime('%Y-%m-%d', $i);
671
		if (isset($cached_data['birthdays'][$loop_date]))
672
		{
673
			foreach ($cached_data['birthdays'][$loop_date] as $index => $dummy)
0 ignored issues
show
Bug introduced by
The expression $cached_data['birthdays'][$loop_date] of type string is not traversable.
Loading history...
674
				$cached_data['birthdays'][strftime('%Y-%m-%d', $i)][$index]['is_today'] = $loop_date === $today['date'];
675
			$return_data['calendar_birthdays'] = array_merge($return_data['calendar_birthdays'], $cached_data['birthdays'][$loop_date]);
676
		}
677
	}
678
679
	$duplicates = array();
680
	for ($i = $now; $i < $now + $days_for_index; $i += 86400)
681
	{
682
		// Determine the date of the current loop step.
683
		$loop_date = strftime('%Y-%m-%d', $i);
684
685
		// No events today? Check the next day.
686
		if (empty($cached_data['events'][$loop_date]))
687
			continue;
688
689
		// Loop through all events to add a few last-minute values.
690
		foreach ($cached_data['events'][$loop_date] as $ev => $event)
0 ignored issues
show
Bug introduced by
The expression $cached_data['events'][$loop_date] of type string is not traversable.
Loading history...
691
		{
692
			// Create a shortcut variable for easier access.
693
			$this_event = &$cached_data['events'][$loop_date][$ev];
694
695
			// Skip duplicates.
696
			if (isset($duplicates[$this_event['topic'] . $this_event['title']]))
697
			{
698
				unset($cached_data['events'][$loop_date][$ev]);
699
				continue;
700
			}
701
			else
702
				$duplicates[$this_event['topic'] . $this_event['title']] = true;
703
704
			// Might be set to true afterwards, depending on the permissions.
705
			$this_event['can_edit'] = false;
706
			$this_event['is_today'] = $loop_date === $today['date'];
707
			$this_event['date'] = $loop_date;
708
		}
709
710
		if (!empty($cached_data['events'][$loop_date]))
711
			$return_data['calendar_events'] = array_merge($return_data['calendar_events'], $cached_data['events'][$loop_date]);
712
	}
713
714
	// Mark the last item so that a list separator can be used in the template.
715 View Code Duplication
	for ($i = 0, $n = count($return_data['calendar_birthdays']); $i < $n; $i++)
0 ignored issues
show
Duplication introduced by
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...
716
		$return_data['calendar_birthdays'][$i]['is_last'] = !isset($return_data['calendar_birthdays'][$i + 1]);
717 View Code Duplication
	for ($i = 0, $n = count($return_data['calendar_events']); $i < $n; $i++)
0 ignored issues
show
Duplication introduced by
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...
718
		$return_data['calendar_events'][$i]['is_last'] = !isset($return_data['calendar_events'][$i + 1]);
719
720
	return array(
721
		'data' => $return_data,
722
		'expires' => time() + 3600,
723
		'refresh_eval' => 'return \'' . strftime('%Y%m%d', forum_time(false)) . '\' != strftime(\'%Y%m%d\', forum_time(false)) || (!empty($modSettings[\'calendar_updated\']) && ' . time() . ' < $modSettings[\'calendar_updated\']);',
724
		'post_retri_eval' => '
725
			global $context, $scripturl, $user_info;
726
727
			foreach ($cache_block[\'data\'][\'calendar_events\'] as $k => $event)
728
			{
729
				// Remove events that the user may not see or wants to ignore.
730
				if ((count(array_intersect($user_info[\'groups\'], $event[\'allowed_groups\'])) === 0 && !allowedTo(\'admin_forum\') && !empty($event[\'id_board\'])) || in_array($event[\'id_board\'], $user_info[\'ignoreboards\']))
731
					unset($cache_block[\'data\'][\'calendar_events\'][$k]);
732
				else
733
				{
734
					// Whether the event can be edited depends on the permissions.
735
					$cache_block[\'data\'][\'calendar_events\'][$k][\'can_edit\'] = allowedTo(\'calendar_edit_any\') || ($event[\'poster\'] == $user_info[\'id\'] && allowedTo(\'calendar_edit_own\'));
736
737
					// The added session code makes this URL not cachable.
738
					$cache_block[\'data\'][\'calendar_events\'][$k][\'modify_href\'] = $scripturl . \'?action=\' . ($event[\'topic\'] == 0 ? \'calendar;sa=post;\' : \'post;msg=\' . $event[\'msg\'] . \';topic=\' . $event[\'topic\'] . \'.0;calendar;\') . \'eventid=\' . $event[\'id\'] . \';\' . $context[\'session_var\'] . \'=\' . $context[\'session_id\'];
739
				}
740
			}
741
742
			if (empty($params[0][\'include_holidays\']))
743
				$cache_block[\'data\'][\'calendar_holidays\'] = array();
744
			if (empty($params[0][\'include_birthdays\']))
745
				$cache_block[\'data\'][\'calendar_birthdays\'] = array();
746
			if (empty($params[0][\'include_events\']))
747
				$cache_block[\'data\'][\'calendar_events\'] = array();
748
749
			$cache_block[\'data\'][\'show_calendar\'] = !empty($cache_block[\'data\'][\'calendar_holidays\']) || !empty($cache_block[\'data\'][\'calendar_birthdays\']) || !empty($cache_block[\'data\'][\'calendar_events\']);',
750
	);
751
}
752
753
/**
754
 * Makes sure the calendar post is valid.
755
 */
756
function validateEventPost()
757
{
758
	global $modSettings, $smcFunc;
759
760
	if (!isset($_POST['deleteevent']))
761
	{
762
		// The 2.1 way
763
		if (isset($_POST['start_date']))
764
		{
765
			$d = date_parse($_POST['start_date']);
766 View Code Duplication
			if (!empty($d['error_count']) || !empty($d['warning_count']))
0 ignored issues
show
Duplication introduced by
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...
767
				fatal_lang_error('invalid_date', false);
0 ignored issues
show
Documentation introduced by
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...
768
			if (empty($d['year']))
769
				fatal_lang_error('event_year_missing', false);
0 ignored issues
show
Documentation introduced by
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...
770
			if (empty($d['month']))
771
				fatal_lang_error('event_month_missing', false);
0 ignored issues
show
Documentation introduced by
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...
772
		}
773
		elseif (isset($_POST['start_datetime']))
774
		{
775
			$d = date_parse($_POST['start_datetime']);
776 View Code Duplication
			if (!empty($d['error_count']) || !empty($d['warning_count']))
0 ignored issues
show
Duplication introduced by
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...
777
				fatal_lang_error('invalid_date', false);
0 ignored issues
show
Documentation introduced by
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...
778
			if (empty($d['year']))
779
				fatal_lang_error('event_year_missing', false);
0 ignored issues
show
Documentation introduced by
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...
780
			if (empty($d['month']))
781
				fatal_lang_error('event_month_missing', false);
0 ignored issues
show
Documentation introduced by
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...
782
		}
783
		// The 2.0 way
784
		else
785
		{
786
			// No month?  No year?
787
			if (!isset($_POST['month']))
788
				fatal_lang_error('event_month_missing', false);
0 ignored issues
show
Documentation introduced by
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...
789
			if (!isset($_POST['year']))
790
				fatal_lang_error('event_year_missing', false);
0 ignored issues
show
Documentation introduced by
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...
791
792
			// Check the month and year...
793
			if ($_POST['month'] < 1 || $_POST['month'] > 12)
794
				fatal_lang_error('invalid_month', false);
0 ignored issues
show
Documentation introduced by
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...
795 View Code Duplication
			if ($_POST['year'] < $modSettings['cal_minyear'] || $_POST['year'] > $modSettings['cal_maxyear'])
0 ignored issues
show
Duplication introduced by
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...
796
				fatal_lang_error('invalid_year', false);
0 ignored issues
show
Documentation introduced by
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...
797
		}
798
	}
799
800
	// Make sure they're allowed to post...
801
	isAllowedTo('calendar_post');
802
803
	// If they want to us to calculate an end date, make sure it will fit in an acceptable range.
804
	if (isset($_POST['span']))
805
	{
806
		if (($_POST['span'] < 1) || (!empty($modSettings['cal_maxspan']) && $_POST['span'] > $modSettings['cal_maxspan']))
807
			fatal_lang_error('invalid_days_numb', false);
0 ignored issues
show
Documentation introduced by
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...
808
	}
809
810
	// There is no need to validate the following values if we are just deleting the event.
811
	if (!isset($_POST['deleteevent']))
812
	{
813
		// If we're doing things the 2.0 way, check the day
814
		if (empty($_POST['start_date']) && empty($_POST['start_datetime']))
815
		{
816
			// No day?
817
			if (!isset($_POST['day']))
818
				fatal_lang_error('event_day_missing', false);
0 ignored issues
show
Documentation introduced by
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...
819
820
			// Bad day?
821
			if (!checkdate($_POST['month'], $_POST['day'], $_POST['year']))
822
				fatal_lang_error('invalid_date', false);
0 ignored issues
show
Documentation introduced by
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...
823
		}
824
825
		if (!isset($_POST['evtitle']) && !isset($_POST['subject']))
826
			fatal_lang_error('event_title_missing', false);
0 ignored issues
show
Documentation introduced by
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...
827
		elseif (!isset($_POST['evtitle']))
828
			$_POST['evtitle'] = $_POST['subject'];
829
830
		// No title?
831
		if ($smcFunc['htmltrim']($_POST['evtitle']) === '')
832
			fatal_lang_error('no_event_title', false);
0 ignored issues
show
Documentation introduced by
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...
833 View Code Duplication
		if ($smcFunc['strlen']($_POST['evtitle']) > 100)
0 ignored issues
show
Duplication introduced by
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...
834
			$_POST['evtitle'] = $smcFunc['substr']($_POST['evtitle'], 0, 100);
835
		$_POST['evtitle'] = str_replace(';', '', $_POST['evtitle']);
836
	}
837
}
838
839
/**
840
 * Get the event's poster.
841
 *
842
 * @param int $event_id The ID of the event
843
 * @return int|bool The ID of the poster or false if the event was not found
844
 */
845 View Code Duplication
function getEventPoster($event_id)
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in 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...
846
{
847
	global $smcFunc;
848
849
	// A simple database query, how hard can that be?
850
	$request = $smcFunc['db_query']('', '
851
		SELECT id_member
852
		FROM {db_prefix}calendar
853
		WHERE id_event = {int:id_event}
854
		LIMIT 1',
855
		array(
856
			'id_event' => $event_id,
857
		)
858
	);
859
860
	// No results, return false.
861
	if ($smcFunc['db_num_rows'] === 0)
862
		return false;
863
864
	// Grab the results and return.
865
	list ($poster) = $smcFunc['db_fetch_row']($request);
866
	$smcFunc['db_free_result']($request);
867
	return (int) $poster;
868
}
869
870
/**
871
 * Consolidating the various INSERT statements into this function.
872
 * Inserts the passed event information into the calendar table.
873
 * Allows to either set a time span (in days) or an end_date.
874
 * Does not check any permissions of any sort.
875
 *
876
 * @param array $eventOptions An array of event options ('title', 'span', 'start_date', 'end_date', etc.)
877
 */
878
function insertEvent(&$eventOptions)
879
{
880
	global $smcFunc, $context;
881
882
	// Add special chars to the title.
883
	$eventOptions['title'] = $smcFunc['htmlspecialchars']($eventOptions['title'], ENT_QUOTES);
884
885
	$eventOptions['location'] = isset($eventOptions['location']) ? $smcFunc['htmlspecialchars']($eventOptions['location'], ENT_QUOTES) : '';
886
887
	// Set the start and end dates and times
888
	list($start_date, $end_date, $start_time, $end_time, $tz) = setEventStartEnd($eventOptions);
889
890
	// If no topic and board are given, they are not linked to a topic.
891
	$eventOptions['board'] = isset($eventOptions['board']) ? (int) $eventOptions['board'] : 0;
892
	$eventOptions['topic'] = isset($eventOptions['topic']) ? (int) $eventOptions['topic'] : 0;
893
894
	$event_columns = array(
895
		'id_board' => 'int', 'id_topic' => 'int', 'title' => 'string-60', 'id_member' => 'int',
896
		'start_date' => 'date', 'end_date' => 'date', 'location' => 'string-255',
897
	);
898
	$event_parameters = array(
899
		$eventOptions['board'], $eventOptions['topic'], $eventOptions['title'], $eventOptions['member'],
900
		$start_date, $end_date,
901
	);
902 View Code Duplication
	if (!empty($start_time) && !empty($end_time) && !empty($tz) && in_array($tz, timezone_identifiers_list(DateTimeZone::ALL_WITH_BC)))
0 ignored issues
show
Duplication introduced by
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...
903
	{
904
		$event_columns['start_time'] = 'time';
905
		$event_parameters[] = $start_time;
906
		$event_columns['end_time'] = 'time';
907
		$event_parameters[] = $end_time;
908
		$event_columns['timezone'] = 'string';
909
		$event_parameters[] = $tz;
910
	}
911
912
	call_integration_hook('integrate_create_event', array(&$eventOptions, &$event_columns, &$event_parameters));
913
914
	// Insert the event!
915
	$smcFunc['db_insert']('',
916
		'{db_prefix}calendar',
917
		$event_columns,
918
		$event_parameters,
919
		array('id_event')
920
	);
921
922
	// Store the just inserted id_event for future reference.
923
	$eventOptions['id'] = $smcFunc['db_insert_id']('{db_prefix}calendar', 'id_event');
924
925
	// If this isn't tied to a topic, we need to notify people about it.
926
	if (empty($eventOptions['topic']))
927
	{
928
		$smcFunc['db_insert']('insert',
929
			'{db_prefix}background_tasks',
930
			array('task_file' => 'string', 'task_class' => 'string', 'task_data' => 'string', 'claimed_time' => 'int'),
931
			array('$sourcedir/tasks/EventNew-Notify.php', 'EventNew_Notify_Background', json_encode(array(
932
				'event_title' => $eventOptions['title'],
933
				'event_id' => $eventOptions['id'],
934
				'sender_id' => $eventOptions['member'],
935
				'sender_name' => $eventOptions['member'] == $context['user']['id'] ? $context['user']['name'] : '',
936
				'time' => time(),
937
			)), 0),
938
			array('id_task')
939
		);
940
	}
941
942
	// Update the settings to show something calendar-ish was updated.
943
	updateSettings(array(
944
		'calendar_updated' => time(),
945
	));
946
}
947
948
/**
949
 * modifies an event.
950
 * allows to either set a time span (in days) or an end_date.
951
 * does not check any permissions of any sort.
952
 *
953
 * @param int $event_id The ID of the event
954
 * @param array $eventOptions An array of event information
955
 */
956
function modifyEvent($event_id, &$eventOptions)
957
{
958
	global $smcFunc;
959
960
	// Properly sanitize the title and location
961
	$eventOptions['title'] = $smcFunc['htmlspecialchars']($eventOptions['title'], ENT_QUOTES);
962
	$eventOptions['location'] = $smcFunc['htmlspecialchars']($eventOptions['location'], ENT_QUOTES);
963
964
	// Set the new start and end dates and times
965
	list($start_date, $end_date, $start_time, $end_time, $tz) = setEventStartEnd($eventOptions);
966
967
	$event_columns = array(
968
		'start_date' => '{date:start_date}',
969
		'end_date' => '{date:end_date}',
970
		'title' => 'SUBSTRING({string:title}, 1, 60)',
971
		'id_board' => '{int:id_board}',
972
		'id_topic' => '{int:id_topic}',
973
		'location' => 'SUBSTRING({string:location}, 1, 255)',
974
	);
975
	$event_parameters = array(
976
		'start_date' => $start_date,
977
		'end_date' => $end_date,
978
		'title' => $eventOptions['title'],
979
		'location' => $eventOptions['location'],
980
		'id_board' => isset($eventOptions['board']) ? (int) $eventOptions['board'] : 0,
981
		'id_topic' => isset($eventOptions['topic']) ? (int) $eventOptions['topic'] : 0,
982
	);
983 View Code Duplication
	if (!empty($start_time) && !empty($end_time) && !empty($tz) && in_array($tz, timezone_identifiers_list(DateTimeZone::ALL_WITH_BC)))
0 ignored issues
show
Duplication introduced by
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...
984
	{
985
		$event_columns['start_time'] = '{time:start_time}';
986
		$event_parameters['start_time'] = $start_time;
987
		$event_columns['end_time'] = '{time:end_time}';
988
		$event_parameters['end_time'] = $end_time;
989
		$event_columns['timezone'] = '{string:timezone}';
990
		$event_parameters['timezone'] = $tz;
991
	}
992
993
	// This is to prevent hooks to modify the id of the event
994
	$real_event_id = $event_id;
995
	call_integration_hook('integrate_modify_event', array($event_id, &$eventOptions, &$event_columns, &$event_parameters));
996
997
	$column_clauses = array();
998
	foreach ($event_columns as $col => $crit)
999
		$column_clauses[] = $col . ' = ' . $crit;
1000
1001
	$smcFunc['db_query']('', '
1002
		UPDATE {db_prefix}calendar
1003
		SET
1004
			' . implode(', ', $column_clauses) . '
1005
		WHERE id_event = {int:id_event}',
1006
		array_merge(
1007
			$event_parameters,
1008
			array(
1009
				'id_event' => $real_event_id
1010
			)
1011
		)
1012
	);
1013
1014
	if (empty($start_time) || empty($end_time) || empty($tz) || !in_array($tz, timezone_identifiers_list(DateTimeZone::ALL_WITH_BC)))
1015
	{
1016
		$smcFunc['db_query']('', '
1017
			UPDATE {db_prefix}calendar
1018
			SET start_time = NULL, end_time = NULL, timezone = NULL
1019
			WHERE id_event = {int:id_event}',
1020
			array(
1021
				'id_event' => $real_event_id
1022
			)
1023
		);
1024
	}
1025
1026
	updateSettings(array(
1027
		'calendar_updated' => time(),
1028
	));
1029
}
1030
1031
/**
1032
 * Remove an event
1033
 * removes an event.
1034
 * does no permission checks.
1035
 *
1036
 * @param int $event_id The ID of the event to remove
1037
 */
1038
function removeEvent($event_id)
1039
{
1040
	global $smcFunc;
1041
1042
	$smcFunc['db_query']('', '
1043
		DELETE FROM {db_prefix}calendar
1044
		WHERE id_event = {int:id_event}',
1045
		array(
1046
			'id_event' => $event_id,
1047
		)
1048
	);
1049
1050
	call_integration_hook('integrate_remove_event', array($event_id));
1051
1052
	updateSettings(array(
1053
		'calendar_updated' => time(),
1054
	));
1055
}
1056
1057
/**
1058
 * Gets all the events properties
1059
 *
1060
 * @param int $event_id The ID of the event
1061
 * @return array An array of event information
1062
 */
1063
function getEventProperties($event_id)
1064
{
1065
	global $smcFunc;
1066
1067
	$request = $smcFunc['db_query']('', '
1068
		SELECT
1069
			c.id_event, c.id_board, c.id_topic, c.id_member, c.title,
1070
			c.start_date, c.end_date, c.start_time, c.end_time, c.timezone, c.location,
1071
			t.id_first_msg, t.id_member_started,
1072
			mb.real_name, m.modified_time
1073
		FROM {db_prefix}calendar AS c
1074
			LEFT JOIN {db_prefix}topics AS t ON (t.id_topic = c.id_topic)
1075
			LEFT JOIN {db_prefix}members AS mb ON (mb.id_member = t.id_member_started)
1076
			LEFT JOIN {db_prefix}messages AS m ON (m.id_msg  = t.id_first_msg)
1077
		WHERE c.id_event = {int:id_event}',
1078
		array(
1079
			'id_event' => $event_id,
1080
		)
1081
	);
1082
1083
	// If nothing returned, we are in poo, poo.
1084
	if ($smcFunc['db_num_rows']($request) === 0)
1085
		return false;
1086
1087
	$row = $smcFunc['db_fetch_assoc']($request);
1088
	$smcFunc['db_free_result']($request);
1089
1090
	list($start, $end, $allday, $span, $tz_abbrev) = buildEventDatetimes($row);
1091
1092
	// Sanity check
1093 View Code Duplication
	if (!empty($start['error_count']) || !empty($start['warning_count']) || !empty($end['error_count']) || !empty($end['warning_count']))
0 ignored issues
show
Duplication introduced by
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...
1094
		return false;
1095
1096
	$return_value = array(
1097
		'boards' => array(),
1098
		'board' => $row['id_board'],
1099
		'new' => 0,
1100
		'eventid' => $event_id,
1101
		'year' => $start['year'],
1102
		'month' => $start['month'],
1103
		'day' => $start['day'],
1104
		'hour' => !$allday ? $start['hour'] : null,
1105
		'minute' => !$allday ? $start['minute'] : null,
1106
		'second' => !$allday ? $start['second'] : null,
1107
		'start_date' => $row['start_date'],
1108
		'start_date_local' => $start['date_local'],
1109
		'start_date_orig' => $start['date_orig'],
1110
		'start_time' => !$allday ? $row['start_time'] : null,
1111
		'start_time_local' => !$allday ? $start['time_local'] : null,
1112
		'start_time_orig' => !$allday ? $start['time_orig'] : null,
1113
		'start_timestamp' => $start['timestamp'],
1114
		'start_datetime' => $start['datetime'],
1115
		'start_iso_gmdate' => $start['iso_gmdate'],
1116
		'end_year' => $end['year'],
1117
		'end_month' => $end['month'],
1118
		'end_day' => $end['day'],
1119
		'end_hour' => !$allday ? $end['hour'] : null,
1120
		'end_minute' => !$allday ? $end['minute'] : null,
1121
		'end_second' => !$allday ? $end['second'] : null,
1122
		'end_date' => $row['end_date'],
1123
		'end_date_local' => $end['date_local'],
1124
		'end_date_orig' => $end['date_orig'],
1125
		'end_time' => !$allday ? $row['end_time'] : null,
1126
		'end_time_local' => !$allday ? $end['time_local'] : null,
1127
		'end_time_orig' => !$allday ? $end['time_orig'] : null,
1128
		'end_timestamp' => $end['timestamp'],
1129
		'end_datetime' => $end['datetime'],
1130
		'end_iso_gmdate' => $end['iso_gmdate'],
1131
		'allday' => $allday,
1132
		'tz' => !$allday ? $row['timezone'] : null,
1133
		'tz_abbrev' => !$allday ? $tz_abbrev : null,
1134
		'span' => $span,
1135
		'title' => $row['title'],
1136
		'location' => $row['location'],
1137
		'member' => $row['id_member'],
1138
		'realname' => $row['real_name'],
1139
		'sequence' => $row['modified_time'],
1140
		'topic' => array(
1141
			'id' => $row['id_topic'],
1142
			'member_started' => $row['id_member_started'],
1143
			'first_msg' => $row['id_first_msg'],
1144
		),
1145
	);
1146
1147
	$return_value['last_day'] = (int) strftime('%d', mktime(0, 0, 0, $return_value['month'] == 12 ? 1 : $return_value['month'] + 1, 0, $return_value['month'] == 12 ? $return_value['year'] + 1 : $return_value['year']));
1148
1149
	return $return_value;
1150
}
1151
1152
/**
1153
 * Gets an initial set of date and time values for creating a new event.
1154
 *
1155
 * @return array An array containing an initial set of date and time values for an event.
1156
 */
1157
function getNewEventDatetimes()
1158
{
1159
	$today = getdate();
1160
1161
	$allday = isset($_REQUEST['allday']) ? 1 : (isset($_REQUEST['start_time']) ? 0 : 1);
1162
	$span = isset($_REQUEST['span']) && filter_var($_REQUEST['span'], FILTER_VALIDATE_INT, array('options' => array('min_range' => 0))) ? $_REQUEST['span'] : 1;
1163
1164 View Code Duplication
	if (!empty($_REQUEST['tz']) && in_array($_REQUEST['tz'], timezone_identifiers_list(DateTimeZone::ALL_WITH_BC)))
0 ignored issues
show
Duplication introduced by
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...
1165
		$tz = $_REQUEST['tz'];
1166
	else
1167
		$tz = getUserTimezone();
1168
1169
	// Was the input given as individual parameters?
1170
	$start_year = isset($_REQUEST['year']) ? $_REQUEST['year'] : $today['year'];
1171
	$start_month = isset($_REQUEST['month']) ? $_REQUEST['month'] : $today['mon'];
1172
	$start_day = isset($_REQUEST['day']) ? $_REQUEST['day'] : $today['mday'];
1173
	$start_hour = isset($_REQUEST['hour']) ? $_REQUEST['hour'] : $today['hours'];
1174
	$start_minute = isset($_REQUEST['minute']) ? $_REQUEST['minute'] : $today['minutes'];
1175
	$start_second = isset($_REQUEST['second']) ? $_REQUEST['second'] : $today['seconds'];
1176
	$end_year = isset($_REQUEST['end_year']) ? $_REQUEST['end_year'] : $today['year'];
1177
	$end_month = isset($_REQUEST['end_month']) ? $_REQUEST['end_month'] : $today['mon'];
1178
	$end_day = isset($_REQUEST['end_day']) ? $_REQUEST['end_day'] : $today['mday'];
1179
	$end_hour = isset($_REQUEST['end_hour']) ? $_REQUEST['end_hour'] : ($today['hours'] < 23 ? $today['hours'] + 1 : $today['hours']);
1180
	$end_minute = isset($_REQUEST['end_minute']) ? $_REQUEST['end_minute'] : ($today['hours'] < 23 ? $today['minutes'] : 59);
1181
	$end_second = isset($_REQUEST['end_second']) ? $_REQUEST['end_second'] : 0;
1182
1183
	// ... Or as date strings and time strings? ...
1184
	$start_date = isset($_REQUEST['start_date']) ? $_REQUEST['start_date'] : sprintf('%04d-%02d-%02d', $start_year, $start_month, $start_day);
1185
	$start_time = isset($_REQUEST['start_time']) ? $_REQUEST['start_time'] : sprintf('%02d:%02d:%02d', $start_hour, $start_minute, $start_second);
1186
	$end_date = isset($_REQUEST['end_date']) ? $_REQUEST['end_date'] : sprintf('%04d-%02d-%02d', $end_year, $end_month, $end_day);
1187
	$end_time = isset($_REQUEST['end_time']) ? $_REQUEST['end_time'] : sprintf('%02d:%02d:%02d', $end_hour, $end_minute, $end_second);
1188
1189
	// ... Or as datetime strings?
0 ignored issues
show
Unused Code Comprehensibility introduced by
37% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1190
	$start_datetime = isset($_REQUEST['start_datetime']) ? $_REQUEST['start_datetime'] : $start_date . ' ' . $start_time;
1191
	$end_datetime = isset($_REQUEST['end_datetime']) ? $_REQUEST['end_datetime'] : $end_date . ' ' . $end_time;
1192
1193
	// In case we received conflicting input, use $start_datetime and $end_datetime as the final answer
1194
	$start = date_parse($start_datetime);
1195
	$end = date_parse($end_datetime);
1196
1197
	// Make sure everything is valid
1198
	if ($start['error_count'] == 0 && $start['warning_count'] == 0 && $end['error_count'] == 0 && $end['warning_count'] == 0)
1199
	{
1200
		$row = array(
1201
			'start_date' => sprintf('%04d-%02d-%02d', $start['year'], $start['month'], $start['day']),
1202
			'start_time' => sprintf('%02d:%02d:%02d', $start['hour'], $start['minute'], $start['second']),
1203
			'end_date' => sprintf('%04d-%02d-%02d', $end['year'], $end['month'], $end['day']),
1204
			'end_time' => sprintf('%02d:%02d:%02d', $end['hour'], $end['minute'], $end['second']),
1205
			'timezone' => $tz,
1206
		);
1207
	}
1208
	// Invalid input? Just ignore it and use $today.
1209
	else
1210
	{
1211
		$row = array(
1212
			'start_date' => sprintf('%04d-%02d-%02d', $today['year'], $today['mon'], $today['mday']),
1213
			'start_time' => sprintf('%02d:%02d:%02d', $today['hours'], $today['minutes'], $today['seconds']),
1214
			'start_date' => sprintf('%04d-%02d-%02d', $today['year'], $today['mon'], $today['mday']),
1215
			'end_time' => sprintf('%02d:%02d:%02d', ($today['hours'] < 23 ? $today['hours'] + 1 : $today['hours']), ($today['hours'] < 23 ? $today['minutes'] : 59), $end['second']),
1216
			'timezone' => $tz,
1217
		);
1218
	}
1219
1220
	list($start, $end, $allday, $span, $tz_abbrev) = buildEventDatetimes($row);
1221
1222
	// Default theme only uses some of this info, but others might want it all
1223
	$eventProperties = array(
1224
		'year' => $start['year'],
1225
		'month' => $start['month'],
1226
		'day' => $start['day'],
1227
		'hour' => !$allday ? $start['hour'] : null,
1228
		'minute' => !$allday ? $start['minute'] : null,
1229
		'second' => !$allday ? $start['second'] : null,
1230
		'start_date' => $row['start_date'],
1231
		'start_date_local' => $start['date_local'],
1232
		'start_date_orig' => $start['date_orig'],
1233
		'start_time' => !$allday ? $row['start_time'] : null,
1234
		'start_time_local' => !$allday ? $start['time_local'] : null,
1235
		'start_time_orig' => !$allday ? $start['time_orig'] : null,
1236
		'start_timestamp' => $start['timestamp'],
1237
		'start_datetime' => $start['datetime'],
1238
		'start_iso_gmdate' => $start['iso_gmdate'],
1239
		'end_year' => $end['year'],
1240
		'end_month' => $end['month'],
1241
		'end_day' => $end['day'],
1242
		'end_hour' => !$allday ? $end['hour'] : null,
1243
		'end_minute' => !$allday ? $end['minute'] : null,
1244
		'end_second' => !$allday ? $end['second'] : null,
1245
		'end_date' => $row['end_date'],
1246
		'end_date_local' => $end['date_local'],
1247
		'end_date_orig' => $end['date_orig'],
1248
		'end_time' => !$allday ? $row['end_time'] : null,
1249
		'end_time_local' => !$allday ? $end['time_local'] : null,
1250
		'end_time_orig' => !$allday ? $end['time_orig'] : null,
1251
		'end_timestamp' => $end['timestamp'],
1252
		'end_datetime' => $end['datetime'],
1253
		'end_iso_gmdate' => $end['iso_gmdate'],
1254
		'allday' => $allday,
1255
		'tz' => $tz,
1256
		'tz_abbrev' => !$allday ? $tz_abbrev : null,
1257
		'span' => $span,
1258
	);
1259
1260
	return $eventProperties;
1261
}
1262
1263
/**
1264
 * Set the start and end dates and times for a posted event for insertion into the database.
1265
 * Validates all date and times given to it.
1266
 * Makes sure events do not exceed the maximum allowed duration (if any).
1267
 * If passed an array that defines any time or date parameters, they will be used. Otherwise, gets the values from $_POST.
1268
 *
1269
 * @param array $eventOptions An array of optional time and date parameters (span, start_year, end_month, etc., etc.)
1270
 * @return array An array containing $start_date, $end_date, $start_time, $end_time
1271
 */
1272
function setEventStartEnd($eventOptions = array())
1273
{
1274
	global $modSettings, $user_info;
1275
1276
	// Set $span, in case we need it
1277
	$span = isset($eventOptions['span']) ? $eventOptions['span'] : (isset($_POST['span']) ? $_POST['span'] : 0);
1278
	if ($span > 0)
1279
		$span = !empty($modSettings['cal_maxspan']) ? min($modSettings['cal_maxspan'], $span - 1) : $span - 1;
1280
1281
	// Define the timezone for this event, falling back to the default if not provided
1282
	if (!empty($eventOptions['tz']) && in_array($eventOptions['tz'], timezone_identifiers_list(DateTimeZone::ALL_WITH_BC)))
1283
		$tz = $eventOptions['tz'];
1284 View Code Duplication
	elseif (!empty($_POST['tz']) && in_array($_POST['tz'], timezone_identifiers_list(DateTimeZone::ALL_WITH_BC)))
0 ignored issues
show
Duplication introduced by
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...
1285
		$tz = $_POST['tz'];
1286
	else
1287
		$tz = getUserTimezone();
1288
1289
	// Is this supposed to be an all day event, or should it have specific start and end times?
1290
	if (isset($eventOptions['allday']))
1291
		$allday = $eventOptions['allday'];
1292
	elseif (empty($_POST['allday']))
1293
		$allday = false;
1294
	else
1295
		$allday = true;
1296
1297
	// Input might come as individual parameters...
1298
	$start_year = isset($eventOptions['year']) ? $eventOptions['year'] : (isset($_POST['year']) ? $_POST['year'] : null);
1299
	$start_month = isset($eventOptions['month']) ? $eventOptions['month'] : (isset($_POST['month']) ? $_POST['month'] : null);
1300
	$start_day = isset($eventOptions['day']) ? $eventOptions['day'] : (isset($_POST['day']) ? $_POST['day'] : null);
1301
	$start_hour = isset($eventOptions['hour']) ? $eventOptions['hour'] : (isset($_POST['hour']) ? $_POST['hour'] : null);
1302
	$start_minute = isset($eventOptions['minute']) ? $eventOptions['minute'] : (isset($_POST['minute']) ? $_POST['minute'] : null);
1303
	$start_second = isset($eventOptions['second']) ? $eventOptions['second'] : (isset($_POST['second']) ? $_POST['second'] : null);
1304
	$end_year = isset($eventOptions['end_year']) ? $eventOptions['end_year'] : (isset($_POST['end_year']) ? $_POST['end_year'] : null);
1305
	$end_month = isset($eventOptions['end_month']) ? $eventOptions['end_month'] : (isset($_POST['end_month']) ? $_POST['end_month'] : null);
1306
	$end_day = isset($eventOptions['end_day']) ? $eventOptions['end_day'] : (isset($_POST['end_day']) ? $_POST['end_day'] : null);
1307
	$end_hour = isset($eventOptions['end_hour']) ? $eventOptions['end_hour'] : (isset($_POST['end_hour']) ? $_POST['end_hour'] : null);
1308
	$end_minute = isset($eventOptions['end_minute']) ? $eventOptions['end_minute'] : (isset($_POST['end_minute']) ? $_POST['end_minute'] : null);
1309
	$end_second = isset($eventOptions['end_second']) ? $eventOptions['end_second'] : (isset($_POST['end_second']) ? $_POST['end_second'] : null);
1310
1311
	// ... or as datetime strings ...
1312
	$start_string = isset($eventOptions['start_datetime']) ? $eventOptions['start_datetime'] : (isset($_POST['start_datetime']) ? $_POST['start_datetime'] : null);
1313
	$end_string = isset($eventOptions['end_datetime']) ? $eventOptions['end_datetime'] : (isset($_POST['end_datetime']) ? $_POST['end_datetime'] : null);
1314
1315
	// ... or as date strings and time strings.
1316
	$start_date_string = isset($eventOptions['start_date']) ? $eventOptions['start_date'] : (isset($_POST['start_date']) ? $_POST['start_date'] : null);
1317
	$start_time_string = isset($eventOptions['start_time']) ? $eventOptions['start_time'] : (isset($_POST['start_time']) ? $_POST['start_time'] : null);
1318
	$end_date_string = isset($eventOptions['end_date']) ? $eventOptions['end_date'] : (isset($_POST['end_date']) ? $_POST['end_date'] : null);
1319
	$end_time_string = isset($eventOptions['end_time']) ? $eventOptions['end_time'] : (isset($_POST['end_time']) ? $_POST['end_time'] : null);
1320
1321
	// If the date and time were given in separate strings, combine them
1322
	if (empty($start_string) && isset($start_date_string))
1323
		$start_string = $start_date_string . (isset($start_time_string) ? ' ' . $start_time_string : '');
1324
	if (empty($end_string) && isset($end_date_string))
1325
		$end_string = $end_date_string . (isset($end_time_string) ? ' ' . $end_time_string : '');
1326
1327
	// If some form of string input was given, override individually defined options with it
1328 View Code Duplication
	if (isset($start_string))
0 ignored issues
show
Duplication introduced by
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...
1329
	{
1330
		$start_string_parsed = date_parse($start_string);
1331
		if (empty($start_string_parsed['error_count']) && empty($start_string_parsed['warning_count']))
1332
		{
1333
			if ($start_string_parsed['year'] != false)
1334
			{
1335
				$start_year = $start_string_parsed['year'];
1336
				$start_month = $start_string_parsed['month'];
1337
				$start_day = $start_string_parsed['day'];
1338
			}
1339
			if ($start_string_parsed['hour'] != false)
1340
			{
1341
				$start_hour = $start_string_parsed['hour'];
1342
				$start_minute = $start_string_parsed['minute'];
1343
				$start_second = $start_string_parsed['second'];
1344
			}
1345
		}
1346
	}
1347 View Code Duplication
	if (isset($end_string))
0 ignored issues
show
Duplication introduced by
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...
1348
	{
1349
		$end_string_parsed = date_parse($end_string);
1350
		if (empty($end_string_parsed['error_count']) && empty($end_string_parsed['warning_count']))
1351
		{
1352
			if ($end_string_parsed['year'] != false)
1353
			{
1354
				$end_year = $end_string_parsed['year'];
1355
				$end_month = $end_string_parsed['month'];
1356
				$end_day = $end_string_parsed['day'];
1357
			}
1358
			if ($end_string_parsed['hour'] != false)
1359
			{
1360
				$end_hour = $end_string_parsed['hour'];
1361
				$end_minute = $end_string_parsed['minute'];
1362
				$end_second = $end_string_parsed['second'];
1363
			}
1364
		}
1365
	}
1366
1367
	// Validate input
1368
	$start_date_isvalid = checkdate($start_month, $start_day, $start_year);
1369
	$end_date_isvalid = checkdate($end_month, $end_day, $end_year);
1370
1371
	$start_time_isset = (isset($start_hour) && isset($start_minute) && isset($start_second));
1372
	$d = date_parse(sprintf('%02d:%02d:%02d', $start_hour, $start_minute, $start_second));
1373
	$start_time_isvalid = ($d['error_count'] == 0 && $d['warning_count'] == 0) ? true : false;
1374
1375
	$end_time_isset = (isset($end_hour) && isset($end_minute) && isset($end_second));
1376
	$d = date_parse(sprintf('%02d:%02d:%02d', $end_hour, $end_minute, $end_second));
1377
	$end_time_isvalid = ($d['error_count'] == 0 && $d['warning_count'] == 0) ? true : false;
1378
1379
	// Uh-oh...
1380
	if ($start_date_isvalid === false)
1381
	{
1382
		fatal_lang_error('invalid_date', false);
0 ignored issues
show
Documentation introduced by
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...
1383
	}
1384
1385
	// Make sure we use valid values for everything
1386
	if ($end_date_isvalid === false)
1387
	{
1388
		$end_year = $start_year;
1389
		$end_month = $start_month;
1390
		$end_day = $start_day;
1391
	}
1392
1393
	if ($allday === true || $start_time_isset === false || $start_time_isvalid === false)
1394
	{
1395
		$allday = true;
1396
		$start_hour = 0;
1397
		$start_minute = 0;
1398
		$start_second = 0;
1399
	}
1400
1401
	if ($allday === true || $end_time_isvalid === false || $end_time_isset === false)
1402
	{
1403
		$end_hour = $start_hour;
1404
		$end_minute = $start_minute;
1405
		$end_second = $start_second;
1406
	}
1407
1408
	// Now create our datetime objects
1409
	$start_object = date_create(sprintf('%04d-%02d-%02d %02d:%02d:%02d', $start_year, $start_month, $start_day, $start_hour, $start_minute, $start_second) . ' ' . $tz);
1410
	$end_object = date_create(sprintf('%04d-%02d-%02d %02d:%02d:%02d', $end_year, $end_month, $end_day, $end_hour, $end_minute, $end_second) . ' ' . $tz);
1411
1412
	// Is $end_object too early?
1413
	if ($start_object >= $end_object)
1414
	{
1415
		$end_object = date_create(sprintf('%04d-%02d-%02d %02d:%02d:%02d', $start_year, $start_month, $start_day, $start_hour, $start_minute, $start_second) . ' ' . $tz);
1416
		if ($span > 0)
1417
			date_add($end_object, date_interval_create_from_date_string($span . ' days'));
1418
		else
1419
			date_add($end_object, date_interval_create_from_date_string('1 hour'));
1420
	}
1421
1422
	// Is $end_object too late?
1423
	if (!empty($modSettings['cal_maxspan']))
1424
	{
1425
		$date_diff = date_diff($start_object, $end_object);
1426
		if ($date_diff->days > $modSettings['cal_maxspan'])
1427
		{
1428
			if ($modSettings['cal_maxspan'] > 1)
1429
			{
1430
				$end_object = date_create(sprintf('%04d-%02d-%02d %02d:%02d:%02d', $start_year, $start_month, $start_day, $start_hour, $start_minute, $start_second) . ' ' . $tz);
1431
				date_add($end_object, date_interval_create_from_date_string($modSettings['cal_maxspan'] . ' days'));
1432
			}
1433
			else
1434
				$end_object = date_create(sprintf('%04d-%02d-%02d %02d:%02d:%02d', $start_year, $start_month, $start_day, '11', '59', '59') . ' ' . $tz);
1435
		}
1436
	}
1437
1438
	// Finally, make our strings
1439
	$start_date = date_format($start_object, 'Y-m-d');
1440
	$end_date = date_format($end_object, 'Y-m-d');
1441
1442
	if ($allday == true)
1443
	{
1444
		$start_time = null;
1445
		$end_time = null;
1446
		$tz = null;
1447
	}
1448
	else
1449
	{
1450
		$start_time = date_format($start_object, 'H:i:s');
1451
		$end_time = date_format($end_object, 'H:i:s');
1452
	}
1453
1454
	return array($start_date, $end_date, $start_time, $end_time, $tz);
1455
}
1456
1457
/**
1458
 * Helper function for getEventRange, getEventProperties, getNewEventDatetimes, etc.
1459
 *
1460
 * @param array $row A database row representing an event from the calendar table
1461
 * @return array An array containing the start and end date and time properties for the event
1462
 */
1463
function buildEventDatetimes($row)
1464
{
1465
	global $sourcedir, $user_info;
1466
	require_once($sourcedir . '/Subs.php');
1467
1468
	// First, try to create a better date format, ignoring the "time" elements.
1469
	if (preg_match('~%[AaBbCcDdeGghjmuYy](?:[^%]*%[AaBbCcDdeGghjmuYy])*~', $user_info['time_format'], $matches) == 0 || empty($matches[0]))
1470
		$date_format = '%F';
1471
	else
1472
		$date_format = $matches[0];
1473
1474
	if (empty($row['timezone']))
1475
		$row['timezone'] = getUserTimezone();
1476
1477
	// We want a fairly compact version of the time, but as close as possible to the user's settings.
1478 View Code Duplication
	if (preg_match('~%[HkIlMpPrRSTX](?:[^%]*%[HkIlMpPrRSTX])*~', $user_info['time_format'], $matches) == 0 || empty($matches[0]))
0 ignored issues
show
Duplication introduced by
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...
1479
		$time_format = '%k:%M';
1480
	else
1481
		$time_format = str_replace(array('%I', '%H', '%S', '%r', '%R', '%T'), array('%l', '%k', '', '%l:%M %p', '%k:%M', '%l:%M'), $matches[0]);
1482
1483
	$allday = (empty($row['start_time']) || empty($row['end_time']) || empty($row['timezone']) || !in_array($row['timezone'], timezone_identifiers_list(DateTimeZone::ALL_WITH_BC))) ? true : false;
1484
1485
	$span = 1 + date_interval_format(date_diff(date_create($row['start_date']), date_create($row['end_date'])), '%d');
1486
1487
	$start = date_parse($row['start_date'] . (!$allday ? ' ' . $row['start_time'] : ''));
1488
	$end = date_parse($row['end_date'] . (!$allday ? ' ' . $row['end_time'] : ''));
1489
1490
	$start_object = date_create($row['start_date'] . (!$allday ? ' ' . $row['start_time'] : ''), timezone_open($row['timezone']));
1491
	$end_object = date_create($row['end_date'] . (!$allday ? ' ' . $row['end_time'] : ''), timezone_open($row['timezone']));
1492
1493
	$start['timestamp'] = date_format($start_object, 'U');
1494
	$end['timestamp'] = date_format($end_object, 'U');
1495
1496
	$start['datetime'] = date_format($start_object, 'Y-m-d H:i:s');
1497
	$end['datetime'] = date_format($start_object, 'Y-m-d H:i:s');
1498
1499
	$start['iso_gmdate'] = gmdate('c', $start['timestamp']);
1500
	$end['iso_gmdate'] = gmdate('c', $end['timestamp']);
1501
1502
	$start['date_local'] = timeformat($start['timestamp'], $date_format);
0 ignored issues
show
Documentation introduced by
$date_format 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...
1503
	$start['time_local'] = timeformat($start['timestamp'], $time_format);
0 ignored issues
show
Documentation introduced by
$time_format 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...
1504
	$end['date_local'] = timeformat($end['timestamp'], $date_format);
0 ignored issues
show
Documentation introduced by
$date_format 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...
1505
	$end['time_local'] = timeformat($end['timestamp'], $time_format);
0 ignored issues
show
Documentation introduced by
$time_format 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...
1506
1507
	$start['date_orig'] = timeformat(strtotime(date_format($start_object, 'Y-m-d H:i:s')), $date_format, 'none');
0 ignored issues
show
Documentation introduced by
$date_format 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...
1508
	$start['time_orig'] = timeformat(strtotime(date_format($start_object, 'Y-m-d H:i:s')), $time_format, 'none');
0 ignored issues
show
Documentation introduced by
$time_format 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...
1509
	$end['date_orig'] = timeformat(strtotime(date_format($end_object, 'Y-m-d H:i:s')), $date_format, 'none');
0 ignored issues
show
Documentation introduced by
$date_format 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...
1510
	$end['time_orig'] = timeformat(strtotime(date_format($end_object, 'Y-m-d H:i:s')), $time_format, 'none');
0 ignored issues
show
Documentation introduced by
$time_format 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...
1511
1512
	$tz_abbrev = date_format($start_object, 'T');
1513
1514
	return array($start, $end, $allday, $span, $tz_abbrev);
1515
}
1516
1517
/**
1518
 * Gets a member's selected timezone identifier directly from the database
1519
 *
1520
 * @param int $id_member The member id to look up. If not provided, the current user's id will be used.
1521
 * @return string The timezone identifier string for the user's timezone.
1522
 */
1523
function getUserTimezone($id_member = null)
1524
{
1525
	global $smcFunc, $context, $sourcedir, $user_info, $modSettings;
1526
1527
	if (is_null($id_member) && $user_info['is_guest'] == false)
1528
		$id_member = $context['user']['id'];
1529
1530 View Code Duplication
	if (isset($id_member))
0 ignored issues
show
Duplication introduced by
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...
1531
	{
1532
		$request = $smcFunc['db_query']('', '
1533
			SELECT timezone
1534
			FROM {db_prefix}members
1535
			WHERE id_member = {int:id_member}',
1536
			array(
1537
				'id_member' => $id_member,
1538
			)
1539
		);
1540
		list($timezone) = $smcFunc['db_fetch_row']($request);
1541
		$smcFunc['db_free_result']($request);
1542
	}
1543
1544 View Code Duplication
	if (empty($timezone) || !in_array($timezone, timezone_identifiers_list(DateTimeZone::ALL_WITH_BC)))
0 ignored issues
show
Duplication introduced by
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...
1545
		$timezone = isset($modSettings['default_timezone']) ? $modSettings['default_timezone'] : date_default_timezone_get();
1546
1547
	return $timezone;
1548
}
1549
1550
/**
1551
 * Gets all of the holidays for the listing
1552
 *
1553
 * @param int $start The item to start with (for pagination purposes)
1554
 * @param int $items_per_page How many items to show on each page
1555
 * @param string $sort A string indicating how to sort the results
1556
 * @return array An array of holidays, each of which is an array containing the id, year, month, day and title of the holiday
1557
 */
1558 View Code Duplication
function list_getHolidays($start, $items_per_page, $sort)
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in 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...
1559
{
1560
	global $smcFunc;
1561
1562
	$request = $smcFunc['db_query']('', '
1563
		SELECT id_holiday, YEAR(event_date) AS year, MONTH(event_date) AS month, DAYOFMONTH(event_date) AS day, title
1564
		FROM {db_prefix}calendar_holidays
1565
		ORDER BY {raw:sort}
1566
		LIMIT {int:start}, {int:max}',
1567
		array(
1568
			'sort' => $sort,
1569
			'start' => $start,
1570
			'max' => $items_per_page,
1571
		)
1572
	);
1573
	$holidays = array();
1574
	while ($row = $smcFunc['db_fetch_assoc']($request))
1575
		$holidays[] = $row;
1576
	$smcFunc['db_free_result']($request);
1577
1578
	return $holidays;
1579
}
1580
1581
/**
1582
 * Helper function to get the total number of holidays
1583
 *
1584
 * @return int The total number of holidays
1585
 */
1586
function list_getNumHolidays()
1587
{
1588
	global $smcFunc;
1589
1590
	$request = $smcFunc['db_query']('', '
1591
		SELECT COUNT(*)
1592
		FROM {db_prefix}calendar_holidays',
1593
		array(
1594
		)
1595
	);
1596
	list($num_items) = $smcFunc['db_fetch_row']($request);
1597
	$smcFunc['db_free_result']($request);
1598
1599
	return (int) $num_items;
1600
}
1601
1602
/**
1603
 * Remove a holiday from the calendar
1604
 *
1605
 * @param array $holiday_ids An array of IDs of holidays to delete
1606
 */
1607
function removeHolidays($holiday_ids)
1608
{
1609
	global $smcFunc;
1610
1611
	$smcFunc['db_query']('', '
1612
		DELETE FROM {db_prefix}calendar_holidays
1613
		WHERE id_holiday IN ({array_int:id_holiday})',
1614
		array(
1615
			'id_holiday' => $holiday_ids,
1616
		)
1617
	);
1618
1619
	updateSettings(array(
1620
		'calendar_updated' => time(),
1621
	));
1622
}
1623
1624
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...