my_date("Y")+5) { $year = my_date("Y"); } // Then the month if($month < 1 || $month > 12) { $month = my_date("n"); } $weekdays = fetch_weekday_structure($calendar['startofweek']); $calendar_permissions = get_calendar_permissions($calendar['cid']); $month_link = get_calendar_link($calendar['cid'], $year, $month); $next_month = get_next_month($month, $year); $prev_month = get_prev_month($month, $year); $month_start_weekday = gmdate("w", gmmktime(0, 0, 0, $month, $calendar['startofweek']+1, $year)); $prev_month_days = gmdate("t", gmmktime(0, 0, 0, $prev_month['month'], 1, $prev_month['year'])); if($month_start_weekday != $weekdays[0] || $calendar['startofweek'] != 0) { $prev_days = $day = gmdate("t", gmmktime(0, 0, 0, $prev_month['month'], 1, $prev_month['year'])); $day -= array_search(($month_start_weekday), $weekdays); $day += $calendar['startofweek']+1; if($day > $prev_month_days+1) { // Go one week back $day -= 7; } $calendar_month = $prev_month['month']; $calendar_year = $prev_month['year']; } else { $day = $calendar['startofweek']+1; $calendar_month = $month; $calendar_year = $year; } // So now we fetch events for this month $start_timestamp = gmmktime(0, 0, 0, $calendar_month, $day, $year); $num_days = gmdate("t", gmmktime(0, 0, 0, $month, 1, $year)); $end_timestamp = gmmktime(23, 59, 59, $month, $num_days, $year); if(!$events_cache) { $events_cache = get_events($calendar, $start_timestamp, $end_timestamp, $calendar_permissions['canmoderateevents']); } $today = my_date("dnY"); // Build weekday headers $weekday_headers = ''; foreach($weekdays as $weekday) { $weekday_name = fetch_weekday_name($weekday, true); eval("\$weekday_headers .= \"".$templates->get("calendar_mini_weekdayheader")."\";"); } $in_month = 0; $day_bits = $calendar_rows = ''; for($row = 0; $row < 6; ++$row) // Iterate weeks (each week gets a row) { foreach($weekdays as $weekday_id => $weekday) { // Current month always starts on 1st row if($row == 0 && $day == $calendar['startofweek']+1) { $in_month = 1; $calendar_month = $month; $calendar_year = $year; } else if($calendar_month == $prev_month['month'] && $day > $prev_month_days) { $day = 1; $in_month = 1; $calendar_month = $month; $calendar_year = $year; } else if($day > $num_days && $calendar_month != $prev_month['month']) { $in_month = 0; $calendar_month = $next_month['month']; $calendar_year = $next_month['year']; $day = 1; if($calendar_month == $month) { $in_month = 1; } } if($weekday_id == 0) { $week_stamp = gmmktime(0, 0, 0, $calendar_month, $day, $calendar_year); $week_link = get_calendar_week_link($calendar['cid'], $week_stamp); } if($weekday_id == 0 && $calendar_month == $next_month['month']) { break; } $link_to_day = false; // Any events on this specific day? if(!empty($events_cache["$day-$calendar_month-$calendar_year"])) { $link_to_day = true; } // Is the current day if($day.$calendar_month.$year == $today && $month == $calendar_month) { $day_class = "trow_sep"; } // Not in this month else if($in_month == 0) { $day_class = "trow1"; } // Just a normal day in this month else { $day_class = "trow2"; } if($link_to_day) { $calendar['link'] = get_calendar_link($calendar['cid'], $calendar_year, $calendar_month, $day); eval("\$day_link = \"".$templates->get("calendar_mini_weekrow_day_link")."\";"); } else { $day_link = $day; } eval("\$day_bits .= \"".$templates->get("calendar_mini_weekrow_day")."\";"); ++$day; } if($day_bits) { eval("\$calendar_rows .= \"".$templates->get("calendar_mini_weekrow")."\";"); } $day_bits = ""; } eval("\$mini_calendar = \"".$templates->get("calendar_mini")."\";"); return $mini_calendar; } /** * Cache available calendars in to memory or return the cached calendars * * @return array Cached calendars */ function cache_calendars() { global $db; static $calendar_cache; if(is_array($calendar_cache)) { return $calendar_cache; } $query = $db->simple_select("calendars", "*", "", array("order_by" => "disporder", "order_dir" => "asc")); while($calendar = $db->fetch_array($query)) { $calendar_cache[$calendar['cid']] = $calendar; } return $calendar_cache; } /** * Fetch the calendar permissions for the current user for one or more calendars * * @param int $cid Optional calendar ID. If none specified, permissions for all calendars are returned * @return array Array of permissions */ function get_calendar_permissions($cid=0) { global $db, $mybb; static $calendar_permissions; $calendars = cache_calendars(); $group_permissions = array( "canviewcalendar" => $mybb->usergroup['canviewcalendar'], "canaddevents" => $mybb->usergroup['canaddevents'], "canbypasseventmod" => $mybb->usergroup['canbypasseventmod'], "canmoderateevents" => $mybb->usergroup['canmoderateevents'] ); if(!is_array($calendars)) { return $group_permissions; } $gid = $mybb->user['usergroup']; if(isset($mybb->user['additionalgroups'])) { $gid .= ",".$mybb->user['additionalgroups']; } if(!is_array($calendar_permissions)) { $calendar_permissions = array(); $query = $db->simple_select("calendarpermissions", "*"); while($permission = $db->fetch_array($query)) { $calendar_permissions[$permission['cid']][$permission['gid']] = $permission; } // Add in our usergroup permissions (if custom ones are set, these aren't added) if(is_array($calendar_permissions)) { foreach($calendar_permissions as $calendar => $permission) { if(is_array($calendar_permissions[$calendar][$mybb->user['usergroup']])) { // Already has permissions set continue; } // Use the group permissions! $calendar_permissions[$calendar][$mybb->user['usergroup']] = $group_permissions; $calendar_permissions[$calendar][$mybb->user['usergroup']]['cid'] = $calendar; $calendar_permissions[$calendar][$mybb->user['usergroup']]['gid'] = $mybb->user['usergroup']; } } } if($cid > 0) { if(isset($calendar_permissions[$cid])) { $permissions = fetch_calendar_permissions($cid, $gid, $calendar_permissions[$cid]); } if(empty($permissions)) { $permissions = $group_permissions; } } else { foreach($calendars as $calendar) { if(isset($calendar_permissions[$calendar['cid']])) { $permissions[$calendar['cid']] = fetch_calendar_permissions($calendar['cid'], $gid, $calendar_permissions[$calendar['cid']]); } if(empty($permissions[$calendar['cid']])) { $permissions[$calendar['cid']] = $group_permissions; } } } return $permissions; } /** * Fetch the calendar permissions * * @param int $cid Calendar ID * @param string $gid User group ID, comma seperated * @param array Array of permissions for this calendar and group * @return array|void Array of current permissions or nothing if an error occured */ function fetch_calendar_permissions($cid, $gid, $calendar_permissions) { $groups = explode(",", $gid); if(!is_array($calendar_permissions)) { return; } $current_permissions = array(); foreach($groups as $gid) { // If this calendar has permissions set for this group if($calendar_permissions[$gid]) { $level_permissions = $calendar_permissions[$gid]; foreach($level_permissions as $permission => $access) { if($access >= $current_permissions[$permission] || ($access == "yes" && $current_permissions[$permission] == "no") || !$current_permissions[$permission]) { $current_permissions[$permission] = $access; } } } } if(count($current_permissions) == 0) { return; } return $current_permissions; } /** * Build a calendar select list to jump between calendars * * @param int $selected The selected calendar ID * @return string The calendar select */ function build_calendar_jump($selected=0) { global $db, $mybb, $templates, $lang, $gobutton; $calendar_permissions = get_calendar_permissions(); $calendars = cache_calendars(); if(!is_array($calendars)) { return; } $jump_options = ''; foreach($calendars as $calendar) { if($calendar_permissions[$calendar['cid']]['canviewcalendar'] == 0) { continue; } $calendar['name'] = htmlspecialchars_uni($calendar['name']); $sel = ""; if($selected == $calendar['cid'] || ($selected == 0 && $calendar['disporder'] == 1)) { $sel = "selected=\"selected\""; } eval("\$jump_options .= \"".$templates->get("calendar_jump_option")."\";"); } eval("\$calendar_jump = \"".$templates->get("calendar_jump")."\";"); return $calendar_jump; } /** * Fetch the next calendar month from a specified month/year * * @param int $month The month * @param int $year The year * @return array Array of the next month and next year */ function get_next_month($month, $year) { global $monthnames; if($month == 12) { $nextmonth = 1; $nextyear = $year+1; } else { $nextmonth = $month+1; $nextyear = $year; } return array("month" => $nextmonth, "year" => $nextyear, "name" => $monthnames[$nextmonth]); } /** * Fetch the previous calendar month from a specified month/year * * @param int $month The month * @param int $year The year * @return array Array of the previous month and previous year */ function get_prev_month($month, $year) { global $monthnames; if($month == 1) { $prevmonth = 12; $prevyear = $year-1; } else { $prevmonth = $month-1; $prevyear = $year; } return array("month" => $prevmonth, "year" => $prevyear, "name" => $monthnames[$prevmonth]); } /** * Fetch the events for a specific calendar and date range * * @param int $calendar The calendar ID * @param int $start Start time stamp * @param int $end End time stmap * @param int $unapproved 1 to fetch unapproved events too * @param int $private The user ID to fetch private events for (0 fetches none) * @return array Array of events */ function get_events($calendar, $start, $end, $unapproved=0, $private=1) { global $db, $mybb; // We take in to account timezones here - we either add 14 hours or subtract 12 hours from our GMT time ranges $start -= 12*3600; $end += 14*3600; $visible_where = ''; if($unapproved != 1) { $visible_where = " AND e.visible='1'"; } $events_cache = array(); $query = $db->query(" SELECT u.*, e.* FROM ".TABLE_PREFIX."events e LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=e.uid) WHERE e.cid='{$calendar['cid']}' {$visible_where} AND ((e.endtime>={$start} AND e.starttime<={$end}) OR (e.endtime=0 AND e.starttime>={$start} AND e.starttime<={$end})) AND ((e.uid='{$mybb->user['uid']}' AND private='1') OR private!='1') ORDER BY endtime DESC "); while($event = $db->fetch_array($query)) { if($event['ignoretimezone'] == 0) { $offset = (float)$event['timezone']; } else { $offset = (float)$mybb->user['timezone']; } $event['starttime_user'] = $event['starttime']+($offset*3600); // Single day event if($event['endtime'] == 0) { $event_date = gmdate("j-n-Y", $event['starttime_user']); $events_cache[$event_date][] = $event; } // Ranged event else { $event_date = explode("-", gmdate("j-n-Y", $event['starttime_user'])); $event['endtime_user'] = $event['endtime']+($offset*3600); $event['weekday_start'] = $calendar['startofweek']; $start_day = gmmktime(0, 0, 0, $event_date[1], $event_date[0], $event_date[2]); $event['repeats'] = my_unserialize($event['repeats']); // Event does not repeat - just goes over a few days if($event['repeats']['repeats'] == 0) { if($start_day < $start) { $range_start = gmmktime(0, 0, 0, gmdate("n", $start), gmdate("j", $start), gmdate("Y", $start)); } else { $range_start = $start_day; } } else { $range_start = fetch_next_occurance($event, array("start" => $start, "end" => $end), $start_day, true); } $first = ""; $event_date = explode("-", gmdate("j-n-Y", $range_start)); // Get rid of hour/minutes because sometimes they cause the events to stretch into the next day $range_end = gmmktime(23, 59, 59, gmdate("n", $event['endtime_user']), gmdate("j", $event['endtime_user']), gmdate("Y", $event['endtime_user'])); while($range_start < $range_end) { // Outside the dates we care about, break! (No unnecessary looping here!) if($range_start > $end || !$range_start) { break; } if($range_start >= $start) { $day_date = gmdate("j-n-Y", $range_start); if($first && $day_date != "{$first}") { $events_cache[$day_date][] = &$events_cache["{$first}"][$count]; } else if(!$first) { if(!isset($events_cache[$day_date]) || !is_array($events_cache[$day_date])) { $events_cache[$day_date] = array(); } $count = count($events_cache[$day_date]); $first = $day_date; $events_cache[$day_date][] = $event; } } if($event['repeats']['repeats'] == 0) { $range_start += 86400; } else { $range_start = fetch_next_occurance($event, array("start" => $start, "end" => $end), $range_start); } } } } return $events_cache; } /** * Fetch the birthdays for one or more months or a specific day * * @param int|array $months Integer of the month or array of months * @param int $day Day of the specific month (if only one month specified above) * @return array Array of birthdays */ function get_birthdays($months, $day=0) { global $db; $year = my_date("Y"); $feb_fix = 0; if(!is_array($months)) { $months = array($months); } foreach($months as $month) { if($day) { $day_where = "{$day}-{$month}"; } else { $day_where = "%-{$month}"; } if($month == 3 && ($day == 1 || !$day) && my_date("L", gmmktime(0, 0, 0, $month, 1, $year)) != 1) { $where[] = "birthday LIKE '29-2%' OR birthday='29-2'"; $feb_fix = 1; } $where[] = "birthday LIKE '{$day_where}-%' OR birthday LIKE '{$day_where}'"; } $where = implode(" OR ", $where); $bdays = array(); $query = $db->simple_select("users", "uid, username, birthday, birthdayprivacy, usergroup, displaygroup", $where); while($user = $db->fetch_array($query)) { $bday = explode("-", $user['birthday']); if($bday[2] && $bday[2] < $year) { $user['age'] = $year - $bday[2]; } if($feb_fix == 1 && $bday[0] == 29 && $bday[1] == 2) { $bdays["1-3"][] = $user; } else { $bdays["$bday[0]-$bday[1]"][] = $user; } } if($day) { if(!isset($bdays["$day-$month"])) { return array(); } return $bdays["$day-$month"]; } return $bdays; } /** * Fetch an ordered list of weekdays depended on a specified starting day * * @param int $week_start The weekday we want to start the week with * @return array Ordered list of weekdays dependant on start of week */ function fetch_weekday_structure($week_start) { switch($week_start) { case "1": $weekdays = array(1,2,3,4,5,6,0); break; case "2": $weekdays = array(2,3,4,5,6,0,1); break; case "3": $weekdays = array(3,4,5,6,0,1,2); break; case "4": $weekdays = array(4,5,6,0,1,2,3); break; case "5": $weekdays = array(5,6,0,1,2,3,4); break; case "6": $weekdays = array(6,0,1,2,3,4,5); break; default: $weekdays = array(0,1,2,3,4,5,6); break; } return $weekdays; } /** * Fetch a weekday name based on a number * * @param int $weekday The weekday number * @param boolean $short True to fetch the short name ('S'), false to fetch full name * @return string The weekday name */ function fetch_weekday_name($weekday, $short=false) { global $lang; switch($weekday) { case 1: $weekday_name = $lang->monday; $short_weekday_name = $lang->short_monday; break; case 2: $weekday_name = $lang->tuesday; $short_weekday_name = $lang->short_tuesday; break; case 3: $weekday_name = $lang->wednesday; $short_weekday_name = $lang->short_wednesday; break; case 4: $weekday_name = $lang->thursday; $short_weekday_name = $lang->short_thursday; break; case 5: $weekday_name = $lang->friday; $short_weekday_name = $lang->short_friday; break; case 6: $weekday_name = $lang->saturday; $short_weekday_name = $lang->short_saturday; break; case 0: $weekday_name = $lang->sunday; $short_weekday_name = $lang->short_sunday; break; } if($short == true) { return $short_weekday_name; } else { return $weekday_name; } } /** * Fetches the next occurance for a repeating event. * * @param array $event The event array * @param array $range The range of start/end timestamps * @param int $last_occurance The last occurance of this event * @param boolean $first True if this is our first iteration of this function (Does some special optimised calculations on false) * @return int The next occurance timestamp */ function fetch_next_occurance($event, $range, $last_occurance, $first=false) { $new_time = $last_occurance; $repeats = $event['repeats']; $start_day = explode("-", gmdate("j-n-Y", $event['starttime_user'])); $start_date = gmmktime(0, 0, 0, $start_day[1], $start_day[0], $start_day[2]); if($repeats['repeats'] == 0) { $new_time += 86400; } // Repeats daily else if($repeats['repeats'] == 1) { // If this isn't the first time we've called this function then we can just tack on the time since $last_occurance if($first == false) { $new_time += 86400*$repeats['days']; } else { // Need to count it out if($range['start'] > $event['starttime']) { $days_since = ceil(($range['start']-$start_date)/86400); $occurances = floor($days_since/$repeats['days']); $next_date = $occurances*$repeats['days']; $new_time = $event['starttime']+(86400*$next_date); } else { $new_time = $start_date; } } } // Repeats on weekdays only else if($repeats['repeats'] == 2) { if($first == false) { $last_dow = gmdate("w", $last_occurance); // Last day of week = friday, +3 gives monday if($last_dow == 5) { $new_time += 86400*3; } // Still in week, add a day else { $new_time += 86400; } } // First loop with start date else { if($range['start'] < $event['starttime']) { $start = $event['starttime']; } else { $start = $range['start']; } $first_dow = gmdate("w", $start); if($first_dow == 6) { $new_time = $start + (86400*2); } else if($first_dow == 0) { $new_time = $start + 86400; } else { $new_time = $start; } } } // Repeats weekly else if($repeats['repeats'] == 3) { $weekdays = fetch_weekday_structure($event['weekday_start']); $last_dow = gmdate("w", $last_occurance); if($first == true) { $last_dow = -1; $start_day = gmdate('w', $last_occurance); if(in_array($start_day, $weekdays)) { $next_dow = 0; } } else { foreach($repeats['days'] as $weekday) { if($weekday > $last_dow) { $next_dow = $weekday; break; } } } if(!isset($next_dow)) { // Fetch first weekday $first = $repeats['days'][0]*86400; $new_time += $first; // Increase x weeks $new_time += (7-$last_dow)*86400; $new_time += (($repeats['weeks']-1)*604800); } else { // Next day of week exists if($last_dow > 0) { $day_diff = $next_dow-$last_dow; } else { $day_diff = $next_dow; } $new_time += $day_diff*86400; } } // Repeats monthly else if($repeats['repeats'] == 4) { $last_month = gmdate("n", $last_occurance); $last_year = gmdate("Y", $last_occurance); $last_day = gmdate("j", $last_occurance); $last_num_days = gmdate("t", $last_occurance); // X of every Y months if($repeats['day']) { if($first == true) { if($last_day <= $repeats['day']) { $new_time = gmmktime(0, 0, 0, $last_month, $repeats['day'], $last_year); } else { $new_time = gmmktime(0, 0, 0, $last_month+1, $repeats['day'], $last_year); if($new_time > $event['endtime']) { return false; } } } else { $new_time = gmmktime(0, 0, 0, $last_month+$repeats['months'], $repeats['day'], $last_year); } } // The 1st/etc (weekday) of every X months else { if($first == true) { $new_time = fetch_weekday_monthly_repetition($repeats, $last_month, $last_year); if($new_time < $last_occurance) { $new_time = fetch_weekday_monthly_repetition($repeats, $last_month+1, $last_year); } } else { $new_time = fetch_weekday_monthly_repetition($repeats, $last_month+$repeats['months'], $last_year); } } } // Repeats yearly else if($repeats['repeats'] == 5) { $last_year = gmdate("Y", $last_occurance); // Repeats on (day) of (month) every (years) if($repeats['day']) { if($first == true) { $new_time = gmmktime(0, 0, 0, $repeats['month'], $repeats['day'], $last_year); if($new_time < $last_occurance) { $new_time = gmmktime(0, 0, 0, $repeats['month'], $repeats['day'], $last_year+1); } } else { $new_time = gmmktime(0, 0, 0, $repeats['month'], $repeats['day'], $last_year+$repeats['years']); } } // The 1st/etc (weekday) of (month) every (years) else { if($first == true) { $new_time = fetch_weekday_monthly_repetition($repeats, $repeats['month'], $last_year); if($new_time < $last_occurance) { $new_time = fetch_weekday_monthly_repetition($repeats, $repeats['month'], $last_year+1); } } else { $new_time = fetch_weekday_monthly_repetition($repeats, $repeats['month'], $last_year+$repeats['years']); } } } return $new_time; } /** * Fetch a friendly repetition value for a specific event (Repeats every x months etc) * * @param array $event The array of the event * @return string The friendly repetition string */ function fetch_friendly_repetition($event) { global $lang; $monthnames = array( "offset", $lang->month_1, $lang->month_2, $lang->month_3, $lang->month_4, $lang->month_5, $lang->month_6, $lang->month_7, $lang->month_8, $lang->month_9, $lang->month_10, $lang->month_11, $lang->month_12 ); if(!is_array($event['repeats'])) { $event['repeats'] = my_unserialize($event['repeats']); if(!is_array($event['repeats'])) { return false; } } $repeats = $event['repeats']; switch($repeats) { case 1: if($repeats['days'] <= 1) { return $lang->repeats_every_day; } return $lang->sprintf($lang->repeats_every_x_days, $event['repeats']['days']); break; case 2: return $lang->repeats_on_weekdays; break; case 3: if($event['repeats']['days'] || count($event['repeats']['days']) == 7) { $weekdays = null; foreach($event['repeats']['days'] as $id => $weekday) { $weekday_name = fetch_weekday_name($weekday); if($event['repeats']['days'][$id+1] && $weekday) { $weekdays .= $lang->comma; } else if(!$event['repeats']['days'][$id+1] && $weekday) { $weekdays .= " {$lang->and} "; } $weekdays .= $weekday_name; } } if($event['repeats']['weeks'] == 1) { if($weekdays) { return $lang->sprintf($lang->every_week_on_days, $weekdays); } else { return $lang->sprintf($lang->every_week); } } else { if($weekdays) { return $lang->sprintf($lang->every_x_weeks_on_days, $event['repeats']['weeks'], $weekdays); } else { return $lang->sprintf($lang->every_x_weeks, $event['repeats']['weeks']); } } break; case 4: if($event['repeats']['day']) { if($event['repeats']['months'] == 1) { return $lang->sprintf($lang->every_month_on_day, $event['repeats']['day']); } else { return $lang->sprintf($lang->every_x_months_on_day, $event['repeats']['day'], $event['repeats']['months']); } } else { $weekday_name = fetch_weekday_name($event['repeats']['weekday']); $occurance = "weekday_occurance_".$event['repeats']['occurance']; $occurance = $lang->$occurance; if($event['repeats']['months'] == 1) { return $lang->sprintf($lang->every_month_on_weekday, $occurance, $weekday_name); } else { return $lang->sprintf($lang->every_x_months_on_weekday, $occurance, $weekday_name, $event['repeats']['months']); } } break; case 5: $month = $monthnames[$event['repeats']['month']]; if($event['repeats']['day']) { if($event['repeats']['years'] == 1) { return $lang->sprintf($lang->every_year_on_day, $event['repeats']['day'], $month); } else { return $lang->sprintf($lang->every_x_years_on_day, $event['repeats']['day'], $month, $event['repeats']['years']); } } else { $weekday_name = fetch_weekday_name($event['repeats']['weekday']); $occurance = "weekday_occurance_".$event['repeats']['occurance']; $occurance = $lang->$occurance; if($event['repeats']['years'] == 1) { return $lang->sprintf($lang->every_year_on_weekday, $occurance, $weekday_name, $month); } else { return $lang->sprintf($lang->every_x_year_on_weekday, $occurance, $weekday_name, $month, $event['repeats']['years']); } } break; } } /** * Fetch a timestamp for "the first/second etc weekday" for a month. * * @param array $repeats The repetition array from the event * @param int $month The month of the year * @param int $year The year * @return int The UNIX timestamp */ function fetch_weekday_monthly_repetition($repeats, $month, $year) { $first_last = gmmktime(0, 0, 0, $month, 1, $year); $first_dow = gmdate("w", $first_last); $day = 1+($repeats['weekday']-$first_dow); if($day < 1) { $day += 7; } if($repeats['occurance'] != "last") { $day += ($repeats['occurance']-1)*7; } else { $last_dow = gmdate("w", gmmktime(0, 0, 0, $month, gmdate("t", $first_last), $year)); $day = (gmdate("t", $first_last)-$last_dow)+$repeats['weekday']; if($day > gmdate("t", $first_dow)) { $day -= 7; } } return gmmktime(0, 0, 0, $month, $day, $year); }