PageRenderTime 43ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/inc/functions_calendar.php

https://bitbucket.org/KamranMackey/mybb
PHP | 1069 lines | 850 code | 77 blank | 142 comment | 196 complexity | 8c5d48371720a77f62c1588b698a389c MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /**
  3. * MyBB 1.6
  4. * Copyright 2010 MyBB Group, All Rights Reserved
  5. *
  6. * Website: http://mybb.com
  7. * License: http://mybb.com/about/license
  8. *
  9. * $Id$
  10. */
  11. /**
  12. * Build a mini calendar for a specific month
  13. *
  14. * @param array The calendar array for the calendar
  15. * @param int The month of the year
  16. * @param int The year
  17. * @param array Optional events cache for this calendar
  18. * @return string The built mini calendar
  19. */
  20. function build_mini_calendar($calendar, $month, $year, &$events_cache)
  21. {
  22. global $events_cache, $mybb, $templates, $theme, $monthnames;
  23. // Incoming month/year?
  24. if(!$year || $year > my_date("Y")+5)
  25. {
  26. $year = my_date("Y");
  27. }
  28. // Then the month
  29. if($month < 1 || $month > 12)
  30. {
  31. $month = my_date("n");
  32. }
  33. $weekdays = fetch_weekday_structure($calendar['startofweek']);
  34. $calendar_permissions = get_calendar_permissions($calendar['cid']);
  35. $month_link = get_calendar_link($calendar['cid'], $year, $month);
  36. $next_month = get_next_month($month, $year);
  37. $prev_month = get_prev_month($month, $year);
  38. $month_start_weekday = gmdate("w", gmmktime(0, 0, 0, $month, $calendar['startofweek']+1, $year));
  39. if($month_start_weekday != $weekdays[0] || $calendar['startofweek'] != 0)
  40. {
  41. $day = gmdate("t", gmmktime(0, 0, 0, $prev_month['month'], 1, $prev_month['year']));
  42. $day -= array_search(($month_start_weekday), $weekdays);
  43. $day += $calendar['startofweek']+1;
  44. $calendar_month = $prev_month['month'];
  45. $calendar_year = $prev_month['year'];
  46. if($day > 31 && $calendar['startofweek'] == 1 && $prev_month_days == 30)
  47. {
  48. // We need to fix it for these days
  49. $day = 25;
  50. }
  51. }
  52. else
  53. {
  54. $day = $calendar['startofweek']+1;
  55. $calendar_month = $month;
  56. $calendar_year = $year;
  57. }
  58. $prev_month_days = gmdate("t", gmmktime(0, 0, 0, $prev_month['month'], 1, $prev_month['year']));
  59. // So now we fetch events for this month
  60. $start_timestamp = gmmktime(0, 0, 0, $calendar_month, $day, $year);
  61. $num_days = gmdate("t", gmmktime(0, 0, 0, $month, 1, $year));
  62. $end_timestamp = gmmktime(23, 59, 59, $month, $num_days, $year);
  63. if(!$events_cache)
  64. {
  65. $events_cache = get_events($calendar['cid'], $start_timestamp, $end_timestamp, $calendar_permissions['canmoderateevents']);
  66. }
  67. $today = my_date("dnY");
  68. // Build weekday headers
  69. foreach($weekdays as $weekday)
  70. {
  71. $weekday_name = fetch_weekday_name($weekday, true);
  72. eval("\$weekday_headers .= \"".$templates->get("calendar_mini_weekdayheader")."\";");
  73. }
  74. for($row = 0; $row < 6; ++$row) // Iterate weeks (each week gets a row)
  75. {
  76. foreach($weekdays as $weekday_id => $weekday)
  77. {
  78. // Current month always starts on 1st row
  79. if($row == 0 && $day == $calendar['startofweek']+1)
  80. {
  81. $in_month = 1;
  82. $calendar_month = $month;
  83. $calendar_year = $year;
  84. }
  85. else if($calendar_month == $prev_month['month'] && $day > $prev_month_days)
  86. {
  87. $day = 1;
  88. $in_month = 1;
  89. $calendar_month = $month;
  90. $calendar_year = $year;
  91. }
  92. else if($day > $num_days && $calendar_month != $prev_month['month'])
  93. {
  94. $in_month = 0;
  95. $calendar_month = $next_month['month'];
  96. $calendar_year = $next_month['year'];
  97. $day = 1;
  98. if($calendar_month == $month)
  99. {
  100. $in_month = 1;
  101. }
  102. }
  103. if($weekday_id == 0)
  104. {
  105. $week_stamp = gmmktime(0, 0, 0, $calendar_month, $day, $calendar_year);
  106. $week_link = get_calendar_week_link($calendar['cid'], $week_stamp);
  107. }
  108. if($weekday_id == 0 && $calendar_month == $next_month['month'])
  109. {
  110. break;
  111. }
  112. // Any events on this specific day?
  113. if(@count($events_cache["$day-$calendar_month-$calendar_year"]) > 0)
  114. {
  115. $link_to_day = true;
  116. }
  117. // Is the current day
  118. if($day.$calendar_month.$year == $today && $month == $calendar_month)
  119. {
  120. $day_class = "trow_sep";
  121. }
  122. // Not in this month
  123. else if($in_month == 0)
  124. {
  125. $day_class = "trow1";
  126. }
  127. // Just a normal day in this month
  128. else
  129. {
  130. $day_class = "trow2";
  131. }
  132. if($link_to_day)
  133. {
  134. $day_link = "<a href=\"".get_calendar_link($calendar['cid'], $calendar_year, $calendar_month, $day)."\">{$day}</a>";
  135. }
  136. else
  137. {
  138. $day_link = $day;
  139. }
  140. eval("\$day_bits .= \"".$templates->get("calendar_mini_weekrow_day")."\";");
  141. $link_to_day = false;
  142. ++$day;
  143. }
  144. if($day_bits)
  145. {
  146. eval("\$calendar_rows .= \"".$templates->get("calendar_mini_weekrow")."\";");
  147. }
  148. $day_bits = "";
  149. }
  150. eval("\$mini_calendar .= \"".$templates->get("calendar_mini")."\";");
  151. return $mini_calendar;
  152. }
  153. /**
  154. * Cache available calendars in to memory or return the cached calendars
  155. *
  156. * @return array Cached calendars
  157. */
  158. function cache_calendars()
  159. {
  160. global $db;
  161. static $calendar_cache;
  162. if(is_array($calendar_cache))
  163. {
  164. return $calendar_cache;
  165. }
  166. $query = $db->simple_select("calendars", "*", "", array("order_by" => "disporder", "order_dir" => "asc"));
  167. while($calendar = $db->fetch_array($query))
  168. {
  169. $calendar_cache[$calendar['cid']] = $calendar;
  170. }
  171. return $calendar_cache;
  172. }
  173. /**
  174. * Fetch the calendar permissions for the current user for one or more calendars
  175. *
  176. * @param int Optional calendar ID. If none specified, permissions for all calendars are returned
  177. * @return array Array of permissions
  178. */
  179. function get_calendar_permissions($cid=0)
  180. {
  181. global $db, $mybb;
  182. static $calendar_permissions;
  183. $calendars = cache_calendars();
  184. $group_permissions = array(
  185. "canviewcalendar" => $mybb->usergroup['canviewcalendar'],
  186. "canaddevents" => $mybb->usergroup['canaddevents'],
  187. "canbypasseventmod" => $mybb->usergroup['canbypasseventmod'],
  188. "canmoderateevents" => $mybb->usergroup['canmoderateevents']
  189. );
  190. if(!is_array($calendars))
  191. {
  192. return $group_permissions;
  193. }
  194. $gid = $mybb->user['usergroup'];
  195. if(isset($mybb->user['additionalgroups']))
  196. {
  197. $gid .= ",".$mybb->user['additionalgroups'];
  198. }
  199. if(!is_array($calendar_permissions))
  200. {
  201. $calendar_permissions = array();
  202. $query = $db->simple_select("calendarpermissions", "*");
  203. while($permission = $db->fetch_array($query))
  204. {
  205. $calendar_permissions[$permission['cid']][$permission['gid']] = $permission;
  206. }
  207. // Add in our usergroup permissions (if custom ones are set, these aren't added)
  208. if(is_array($calendar_permissions))
  209. {
  210. foreach($calendar_permissions as $calendar => $permission)
  211. {
  212. if(is_array($calendar_permissions[$calendar][$mybb->user['usergroup']]))
  213. {
  214. // Already has permissions set
  215. continue;
  216. }
  217. // Use the group permissions!
  218. $calendar_permissions[$calendar][$mybb->user['usergroup']] = $group_permissions;
  219. $calendar_permissions[$calendar][$mybb->user['usergroup']]['cid'] = $calendar;
  220. $calendar_permissions[$calendar][$mybb->user['usergroup']]['gid'] = $mybb->user['usergroup'];
  221. }
  222. }
  223. }
  224. if($cid > 0)
  225. {
  226. $permissions = fetch_calendar_permissions($cid, $gid, $calendar_permissions[$cid]);
  227. if(!$permissions)
  228. {
  229. $permissions = $group_permissions;
  230. }
  231. }
  232. else
  233. {
  234. foreach($calendars as $calendar)
  235. {
  236. $permissions[$calendar['cid']] = fetch_calendar_permissions($calendar['cid'], $gid, $calendar_permissions[$calendar['cid']]);
  237. if(!$permissions[$calendar['cid']])
  238. {
  239. $permissions[$calendar['cid']] = $group_permissions;
  240. }
  241. }
  242. }
  243. return $permissions;
  244. }
  245. /**
  246. *
  247. */
  248. function fetch_calendar_permissions($cid, $gid, $calendar_permissions)
  249. {
  250. $groups = explode(",", $gid);
  251. if(!is_array($calendar_permissions))
  252. {
  253. return;
  254. }
  255. $current_permissions = array();
  256. foreach($groups as $gid)
  257. {
  258. // If this calendar has permissions set for this group
  259. if($calendar_permissions[$gid])
  260. {
  261. $level_permissions = $calendar_permissions[$gid];
  262. foreach($level_permissions as $permission => $access)
  263. {
  264. if($access >= $current_permissions[$permission] || ($access == "yes" && $current_permissions[$permission] == "no") || !$current_permissions[$permission])
  265. {
  266. $current_permissions[$permission] = $access;
  267. }
  268. }
  269. }
  270. }
  271. if(count($current_permissions) == 0)
  272. {
  273. return;
  274. }
  275. return $current_permissions;
  276. }
  277. /**
  278. * Build a calendar select list to jump between calendars
  279. *
  280. * @param int The selected calendar ID
  281. * @return string The calendar select
  282. */
  283. function build_calendar_jump($selected=0)
  284. {
  285. global $db, $mybb;
  286. $calendar_permissions = get_calendar_permissions();
  287. $calendars = cache_calendars();
  288. if(!is_array($calendars))
  289. {
  290. return;
  291. }
  292. foreach($calendars as $calendar)
  293. {
  294. if($calendar_permissions[$calendar['cid']]['canviewcalendar'] == 0)
  295. {
  296. continue;
  297. }
  298. $calendar['name'] = htmlspecialchars_uni($calendar['name']);
  299. $sel = "";
  300. if($selected == $calendar['cid'] || ($selected == 0 && $calendar['disporder'] == 1))
  301. {
  302. $sel = "selected=\"selected\"";
  303. }
  304. $jump_options .= "<option value=\"{$calendar['cid']}\" $sel>{$calendar['name']}</option>\n";
  305. }
  306. return "<select name=\"calendar\">\n{$jump_options}</select>";
  307. }
  308. /**
  309. * Fetch the next calendar month from a specified month/year
  310. *
  311. * @param int The month
  312. * @param int The year
  313. * @return array Array of the next month and next year
  314. */
  315. function get_next_month($month, $year)
  316. {
  317. global $monthnames;
  318. if($month == 12)
  319. {
  320. $nextmonth = 1;
  321. $nextyear = $year+1;
  322. }
  323. else
  324. {
  325. $nextmonth = $month+1;
  326. $nextyear = $year;
  327. }
  328. return array("month" => $nextmonth, "year" => $nextyear, "name" => $monthnames[$nextmonth]);
  329. }
  330. /**
  331. * Fetch the previous calendar month from a specified month/year
  332. *
  333. * @param int The month
  334. * @param int The year
  335. * @return array Array of the previous month and previous year
  336. */
  337. function get_prev_month($month, $year)
  338. {
  339. global $monthnames;
  340. if($month == 1)
  341. {
  342. $prevmonth = 12;
  343. $prevyear = $year-1;
  344. }
  345. else
  346. {
  347. $prevmonth = $month-1;
  348. $prevyear = $year;
  349. }
  350. return array("month" => $prevmonth, "year" => $prevyear, "name" => $monthnames[$prevmonth]);
  351. }
  352. /**
  353. * Fetch the events for a specific calendar and date range
  354. *
  355. * @param int The calendar ID
  356. * @param int Start time stamp
  357. * @param int End time stmap
  358. * @param int 1 to fetch unapproved events too
  359. * @param int The user ID to fetch private events for (0 fetches none)
  360. * @return array Array of events
  361. */
  362. function get_events($calendar, $start, $end, $unapproved=0, $private=1)
  363. {
  364. global $db, $mybb;
  365. // We take in to account timezones here - we add/subtract 12 hours from our GMT time ranges
  366. $start -= 12*3600;
  367. $end += 12*3600;
  368. if($unapproved != 1)
  369. {
  370. $visible_where = " AND e.visible='1'";
  371. }
  372. $query = $db->query("
  373. SELECT u.*, e.*
  374. FROM ".TABLE_PREFIX."events e
  375. LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=e.uid)
  376. WHERE e.cid='{$calendar}' {$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')
  377. ORDER BY endtime DESC
  378. ");
  379. while($event = $db->fetch_array($query))
  380. {
  381. if($event['ignoretimezone'] == 0)
  382. {
  383. $offset = $event['timezone'];
  384. }
  385. else
  386. {
  387. $offset = $mybb->user['timezone'];
  388. }
  389. $event['starttime_user'] = $event['starttime']+($offset*3600);
  390. // Single day event
  391. if($event['endtime'] == 0)
  392. {
  393. $event_date = gmdate("j-n-Y", $event['starttime_user']);
  394. $events_cache[$event_date][] = $event;
  395. }
  396. // Ranged event
  397. else
  398. {
  399. $event_date = explode("-", gmdate("j-n-Y", $event['starttime_user']));
  400. $event['endtime_user'] = $event['endtime']+($offset*3600);
  401. $event['weekday_start'] = $calendar['weekstart'];
  402. $start_day = gmmktime(0, 0, 0, $event_date[1], $event_date[0], $event_date[2]);
  403. $event['repeats'] = @unserialize($event['repeats']);
  404. // Event does not repeat - just goes over a few days
  405. if($event['repeats']['repeats'] == 0)
  406. {
  407. if($start_day < $start)
  408. {
  409. $range_start = gmmktime(0, 0, 0, gmdate("n", $start), gmdate("j", $start), gmdate("Y", $start));
  410. }
  411. else
  412. {
  413. $range_start = $start_day;
  414. }
  415. }
  416. else
  417. {
  418. $range_start = fetch_next_occurance($event, array("start" => $start, "end" => $end), $start_day, true);
  419. }
  420. $first = "";
  421. $event_date = explode("-", gmdate("j-n-Y", $range_start));
  422. // Get rid of hour/minutes because sometimes they cause the events to stretch into the next day
  423. $range_end = gmmktime(23, 59, 59, gmdate("n", $event['endtime_user']), gmdate("j", $event['endtime_user']), gmdate("Y", $event['endtime_user']));
  424. while($range_start < $range_end)
  425. {
  426. // Outside the dates we care about, break! (No unnecessary looping here!)
  427. if($range_start > $end || !$range_start)
  428. {
  429. break;
  430. }
  431. if($range_start >= $start)
  432. {
  433. $day_date = gmdate("j-n-Y", $range_start);
  434. if($first && $day_date != "{$first}")
  435. {
  436. $events_cache[$day_date][] = &$events_cache["{$first}"][$count];
  437. }
  438. else if(!$first)
  439. {
  440. $count = count($events_cache["{$day_date}"]);
  441. $first = $day_date;
  442. $events_cache["{$day_date}"][] = $event;
  443. }
  444. }
  445. if($event['repeats']['repeats'] == 0)
  446. {
  447. $range_start += 86400;
  448. }
  449. else
  450. {
  451. $range_start = fetch_next_occurance($event, array("start" => $start, "end" => $end), $range_start);
  452. }
  453. }
  454. }
  455. }
  456. return $events_cache;
  457. }
  458. /**
  459. * Fetch the birthdays for one or more months or a specific day
  460. *
  461. * @param mixed Integer of the month or array of months
  462. * @param int Day of the specific month (if only one month specified above)
  463. * @return array Array of birthdays
  464. */
  465. function get_birthdays($months, $day="")
  466. {
  467. global $db;
  468. $year = my_date("Y");
  469. if(!is_array($months))
  470. {
  471. $months = array($months);
  472. }
  473. foreach($months as $month)
  474. {
  475. if($day)
  476. {
  477. $day_where = "{$day}-{$month}";
  478. }
  479. else
  480. {
  481. $day_where = "%-{$month}";
  482. }
  483. if($month == 3 && ($day == 1 || !$day) && my_date("L", gmmktime(0, 0, 0, $month, 1, $year)) != 1)
  484. {
  485. $where[] = "birthday LIKE '29-2%' OR birthday='29-2'";
  486. $feb_fix = 1;
  487. }
  488. $where[] = "birthday LIKE '{$day_where}-%' OR birthday LIKE '{$day_where}'";
  489. }
  490. $where = implode(" OR ", $where);
  491. $query = $db->simple_select("users", "uid, username, birthday, birthdayprivacy, usergroup, displaygroup", $where);
  492. while($user = $db->fetch_array($query))
  493. {
  494. $bday = explode("-", $user['birthday']);
  495. if($bday[2] && $bday[2] < $year)
  496. {
  497. $user['age'] = $year - $bday[2];
  498. }
  499. if($feb_fix == 1 && $bday[0] == 29 && $bday[1] == 2)
  500. {
  501. $bdays["1-3"][] = $user;
  502. }
  503. else
  504. {
  505. $bdays["$bday[0]-$bday[1]"][] = $user;
  506. }
  507. }
  508. if($day)
  509. {
  510. return $bdays["$day-$month"];
  511. }
  512. return $bdays;
  513. }
  514. /**
  515. * Fetch an ordered list of weekdays depended on a specified starting day
  516. *
  517. * @param int The weekday we want to start the week with
  518. * @return array Ordered list of weekdays dependant on start of week
  519. */
  520. function fetch_weekday_structure($week_start)
  521. {
  522. switch($week_start)
  523. {
  524. case "1":
  525. $weekdays = array(1,2,3,4,5,6,0);
  526. break;
  527. case "2":
  528. $weekdays = array(2,3,4,5,6,0,1);
  529. break;
  530. case "3":
  531. $weekdays = array(3,4,5,6,0,1,2);
  532. break;
  533. case "4":
  534. $weekdays = array(4,5,6,0,1,2,3);
  535. break;
  536. case "5":
  537. $weekdays = array(5,6,0,1,2,3,4);
  538. break;
  539. case "6":
  540. $weekdays = array(6,0,1,2,3,4,5);
  541. break;
  542. default:
  543. $weekdays = array(0,1,2,3,4,5,6);
  544. break;
  545. }
  546. return $weekdays;
  547. }
  548. /**
  549. * Fetch a weekday name based on a number
  550. *
  551. * @param int The weekday number
  552. * @param boolean True to fetch the short name ('S'), false to fetch full name
  553. * @param string The weekday name
  554. */
  555. function fetch_weekday_name($weekday, $short=false)
  556. {
  557. global $lang;
  558. switch($weekday)
  559. {
  560. case 1:
  561. $weekday_name = $lang->monday;
  562. $short_weekday_name = $lang->short_monday;
  563. break;
  564. case 2:
  565. $weekday_name = $lang->tuesday;
  566. $short_weekday_name = $lang->short_tuesday;
  567. break;
  568. case 3:
  569. $weekday_name = $lang->wednesday;
  570. $short_weekday_name = $lang->short_wednesday;
  571. break;
  572. case 4:
  573. $weekday_name = $lang->thursday;
  574. $short_weekday_name = $lang->short_thursday;
  575. break;
  576. case 5:
  577. $weekday_name = $lang->friday;
  578. $short_weekday_name = $lang->short_friday;
  579. break;
  580. case 6:
  581. $weekday_name = $lang->saturday;
  582. $short_weekday_name = $lang->short_saturday;
  583. break;
  584. case 0:
  585. $weekday_name = $lang->sunday;
  586. $short_weekday_name = $lang->short_sunday;
  587. break;
  588. }
  589. if($short == true)
  590. {
  591. return $short_weekday_name;
  592. }
  593. else
  594. {
  595. return $weekday_name;
  596. }
  597. }
  598. /**
  599. * Fetches the next occurance for a repeating event.
  600. *
  601. * @param array The event array
  602. * @param array The range of start/end timestamps
  603. * @param int The last occurance of this event
  604. * @param boolean True if this is our first iteration of this function (Does some special optimised calculations on false)
  605. * @return int The next occurance timestamp
  606. */
  607. function fetch_next_occurance($event, $range, $last_occurance, $first=false)
  608. {
  609. $new_time = $last_occurance;
  610. $repeats = $event['repeats'];
  611. $start_day = explode("-", gmdate("j-n-Y", $event['starttime_user']));
  612. $start_date = gmmktime(0, 0, 0, $start_day[1], $start_day[0], $start_day[2]);
  613. if($repeats['repeats'] == 0)
  614. {
  615. $new_time += 86400;
  616. }
  617. // Repeats daily
  618. else if($repeats['repeats'] == 1)
  619. {
  620. // If this isn't the first time we've called this function then we can just tack on the time since $last_occurance
  621. if($first == false)
  622. {
  623. $new_time += 86400*$repeats['days'];
  624. }
  625. else
  626. {
  627. // Need to count it out
  628. if($range['start'] > $event['starttime'])
  629. {
  630. $days_since = ceil(($range['start']-$start_date)/86400);
  631. $occurances = floor($days_since/$repeats['days']);
  632. $next_date = $occurances*$repeats['days'];
  633. $new_time = $event['starttime']+(86400*$next_date);
  634. }
  635. else
  636. {
  637. $new_time = $start_date;
  638. }
  639. }
  640. }
  641. // Repeats on weekdays only
  642. else if($repeats['repeats'] == 2)
  643. {
  644. if($first == false)
  645. {
  646. $last_dow = gmdate("w", $last_occurance);
  647. // Last day of week = friday, +3 gives monday
  648. if($last_dow == 5)
  649. {
  650. $new_time += 86400*3;
  651. }
  652. // Still in week, add a day
  653. else
  654. {
  655. $new_time += 86400;
  656. }
  657. }
  658. // First loop with start date
  659. else
  660. {
  661. if($range['start'] < $event['starttime'])
  662. {
  663. $start = $event['starttime'];
  664. }
  665. else
  666. {
  667. $start = $range['start'];
  668. }
  669. $first_dow = gmdate("w", $start);
  670. if($first_dow == 6)
  671. {
  672. $new_time = $start + (86400*2);
  673. }
  674. else if($first_dow == 0)
  675. {
  676. $new_time = $start + 86400;
  677. }
  678. else
  679. {
  680. $new_time = $start;
  681. }
  682. }
  683. }
  684. // Repeats weekly
  685. else if($repeats['repeats'] == 3)
  686. {
  687. $weekdays = fetch_weekday_structure($event['weekday_start']);
  688. $last_dow = gmdate("w", $last_occurance);
  689. if($first == true)
  690. {
  691. $last_dow = -1;
  692. $start_day = gmdate('w', $last_occurance);
  693. if(in_array($start_day, $weekdays))
  694. {
  695. $next_dow = 0;
  696. }
  697. }
  698. else
  699. {
  700. foreach($repeats['days'] as $weekday)
  701. {
  702. if($weekday > $last_dow)
  703. {
  704. $next_dow = $weekday;
  705. break;
  706. }
  707. }
  708. }
  709. if(!isset($next_dow))
  710. {
  711. // Fetch first weekday
  712. $first = $repeats['days'][0]*86400;
  713. $new_time += $first;
  714. // Increase x weeks
  715. $new_time += (7-$last_dow)*86400;
  716. $new_time += (($repeats['weeks']-1)*604800);
  717. }
  718. else
  719. {
  720. // Next day of week exists
  721. if($last_dow > 0)
  722. {
  723. $day_diff = $next_dow-$last_dow;
  724. }
  725. else
  726. {
  727. $day_diff = $next_dow;
  728. }
  729. $new_time += $day_diff*86400;
  730. }
  731. }
  732. // Repeats monthly
  733. else if($repeats['repeats'] == 4)
  734. {
  735. $last_month = gmdate("n", $last_occurance);
  736. $last_year = gmdate("Y", $last_occurance);
  737. $last_day = gmdate("j", $last_occurance);
  738. $last_num_days = gmdate("t", $last_occurance);
  739. // X of every Y months
  740. if($repeats['day'])
  741. {
  742. if($first == true)
  743. {
  744. if($last_day <= $repeats['day'])
  745. {
  746. $new_time = gmmktime(0, 0, 0, $last_month, $repeats['day'], $last_year);
  747. }
  748. else
  749. {
  750. $new_time = gmmktime(0, 0, 0, $last_month+1, $repeats['day'], $last_year);
  751. if($new_time > $event['endtime'])
  752. {
  753. return false;
  754. }
  755. }
  756. }
  757. else
  758. {
  759. $new_time = gmmktime(0, 0, 0, $last_month+$repeats['months'], $repeats['day'], $last_year);
  760. }
  761. }
  762. // The 1st/etc (weekday) of every X months
  763. else
  764. {
  765. if($first == true)
  766. {
  767. $new_time = fetch_weekday_monthly_repetition($repeats, $last_month, $last_year);
  768. if($new_time < $last_occurance)
  769. {
  770. $new_time = fetch_weekday_monthly_repetition($repeats, $last_month+1, $last_year);
  771. }
  772. }
  773. else
  774. {
  775. $new_time = fetch_weekday_monthly_repetition($repeats, $last_month+$repeats['months'], $last_year);
  776. }
  777. }
  778. }
  779. // Repeats yearly
  780. else if($repeats['repeats'] == 5)
  781. {
  782. $last_year = gmdate("Y", $last_occurance);
  783. // Repeats on (day) of (month) every (years)
  784. if($repeats['day'])
  785. {
  786. if($first == true)
  787. {
  788. $new_time = gmmktime(0, 0, 0, $repeats['month'], $repeats['day'], $last_year);
  789. if($new_time < $last_occurance)
  790. {
  791. $new_time = gmmktime(0, 0, 0, $repeats['month'], $repeats['day'], $last_year+1);
  792. }
  793. }
  794. else
  795. {
  796. $new_time = gmmktime(0, 0, 0, $repeats['month'], $repeats['day'], $last_year+$repeats['years']);
  797. }
  798. }
  799. // The 1st/etc (weekday) of (month) every (years)
  800. else
  801. {
  802. if($first == true)
  803. {
  804. $new_time = fetch_weekday_monthly_repetition($repeats, $repeats['month'], $last_year);
  805. if($new_time < $last_occurance)
  806. {
  807. $new_time = fetch_weekday_monthly_repetition($repeats, $repeats['month'], $last_year+1);
  808. }
  809. }
  810. else
  811. {
  812. $new_time = fetch_weekday_monthly_repetition($repeats, $repeats['month'], $last_year+$repeats['years']);
  813. }
  814. }
  815. }
  816. return $new_time;
  817. }
  818. /**
  819. * Fetch a friendly repetition value for a specific event (Repeats every x months etc)
  820. *
  821. * @param array The array of the event
  822. * @return string The friendly repetition string
  823. */
  824. function fetch_friendly_repetition($event)
  825. {
  826. global $lang;
  827. $monthnames = array(
  828. "offset",
  829. $lang->month_1,
  830. $lang->month_2,
  831. $lang->month_3,
  832. $lang->month_4,
  833. $lang->month_5,
  834. $lang->month_6,
  835. $lang->month_7,
  836. $lang->month_8,
  837. $lang->month_9,
  838. $lang->month_10,
  839. $lang->month_11,
  840. $lang->month_12
  841. );
  842. if(!is_array($event['repeats']))
  843. {
  844. $event['repeats'] = @unserialize($event['repeats']);
  845. if(!is_array($event['repeats']))
  846. {
  847. return false;
  848. }
  849. }
  850. $repeats = $event['repeats'];
  851. switch($repeats['repeats'])
  852. {
  853. case 1:
  854. if($repeats['days'] <= 1)
  855. {
  856. return $lang->repeats_every_day;
  857. }
  858. return $lang->sprintf($lang->repeats_every_x_days, $event['repeats']['days']);
  859. break;
  860. case 2:
  861. return $lang->repeats_on_weekdays;
  862. break;
  863. case 3:
  864. if($event['repeats']['days'] || count($event['repeats']['days']) == 7)
  865. {
  866. foreach($event['repeats']['days'] as $id => $weekday)
  867. {
  868. $weekday_name = fetch_weekday_name($weekday);
  869. if($event['repeats']['days'][$id+1] && $weekdays)
  870. {
  871. $weekdays .= $lang->comma;
  872. }
  873. else if(!$event['repeats']['days'][$id+1] && $weekdays)
  874. {
  875. $weekdays .= " {$lang->and} ";
  876. }
  877. $weekdays .= $weekday_name;
  878. }
  879. }
  880. if($event['repeats']['weeks'] == 1)
  881. {
  882. if($weekdays)
  883. {
  884. return $lang->sprintf($lang->every_week_on_days, $weekdays);
  885. }
  886. else
  887. {
  888. return $lang->sprintf($lang->every_week);
  889. }
  890. }
  891. else
  892. {
  893. if($weekdays)
  894. {
  895. return $lang->sprintf($lang->every_x_weeks_on_days, $event['repeats']['weeks'], $weekdays);
  896. }
  897. else
  898. {
  899. return $lang->sprintf($lang->every_x_weeks, $event['repeats']['weeks']);
  900. }
  901. }
  902. break;
  903. case 4:
  904. if($event['repeats']['day'])
  905. {
  906. if($event['repeats']['months'] == 1)
  907. {
  908. return $lang->sprintf($lang->every_month_on_day, $event['repeats']['day']);
  909. }
  910. else
  911. {
  912. return $lang->sprintf($lang->every_x_months_on_day, $event['repeats']['day'], $event['repeats']['months']);
  913. }
  914. }
  915. else
  916. {
  917. $weekday_name = fetch_weekday_name($event['repeats']['weekday']);
  918. $occurance = "weekday_occurance_".$event['repeats']['occurance'];
  919. $occurance = $lang->$occurance;
  920. if($event['repeats']['months'] == 1)
  921. {
  922. return $lang->sprintf($lang->every_month_on_weekday, $occurance, $weekday_name);
  923. }
  924. else
  925. {
  926. return $lang->sprintf($lang->every_x_months_on_weekday, $occurance, $weekday_name, $event['repeats']['months']);
  927. }
  928. }
  929. break;
  930. case 5:
  931. $month = $monthnames[$event['repeats']['month']];
  932. if($event['repeats']['day'])
  933. {
  934. if($event['repeats']['years'] == 1)
  935. {
  936. return $lang->sprintf($lang->every_year_on_day, $event['repeats']['day'], $month);
  937. }
  938. else
  939. {
  940. return $lang->sprintf($lang->every_x_years_on_day, $event['repeats']['day'], $month, $event['repeats']['years']);
  941. }
  942. }
  943. else
  944. {
  945. $weekday_name = fetch_weekday_name($event['repeats']['weekday']);
  946. $occurance = "weekday_occurance_".$event['repeats']['occurance'];
  947. $occurance = $lang->$occurance;
  948. if($event['repeats']['years'] == 1)
  949. {
  950. return $lang->sprintf($lang->every_year_on_weekday, $occurance, $weekday_name, $month);
  951. }
  952. else
  953. {
  954. return $lang->sprintf($lang->every_x_year_on_weekday, $occurance, $weekday_name, $month, $event['repeats']['years']);
  955. }
  956. }
  957. break;
  958. }
  959. }
  960. /**
  961. * Fetch a timestamp for "the first/second etc weekday" for a month.
  962. *
  963. * @param array The repetition array from the event
  964. * @param int The month of the year
  965. * @param int The year
  966. * @return int The UNIX timestamp
  967. */
  968. function fetch_weekday_monthly_repetition($repeats, $month, $year)
  969. {
  970. $first_last = gmmktime(0, 0, 0, $month, 1, $year);
  971. $first_dow = gmdate("w", $first_last);
  972. $day = 1+($repeats['weekday']-$first_dow);
  973. if($day < 1)
  974. {
  975. $day += 7;
  976. }
  977. if($repeats['occurance'] != "last")
  978. {
  979. $day += ($repeats['occurance']-1)*7;
  980. }
  981. else
  982. {
  983. $last_dow = gmdate("w", gmmktime(0, 0, 0, $month, gmdate("t", $first_last), $year));
  984. $day = (gmdate("t", $first_last)-$last_dow)+$repeats['weekday'];
  985. if($day > gmdate("t", $first_dow))
  986. {
  987. $day -= 7;
  988. }
  989. }
  990. return gmmktime(0, 0, 0, $month, $day, $year);
  991. }
  992. ?>