PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/3.0/modules/webdav/vendor/Sabre/CalDAV/XMLUtil.php

http://github.com/gallery/gallery3-contrib
PHP | 208 lines | 93 code | 39 blank | 76 comment | 15 complexity | 6028e11b2d45bf2b6332f9d317c8af16 MD5 | raw file
Possible License(s): GPL-3.0, GPL-2.0, LGPL-2.1
  1. <?php
  2. /**
  3. * XML utilities for CalDAV
  4. *
  5. * This class contains a few static methods used for parsing certain CalDAV
  6. * requests.
  7. *
  8. * @package Sabre
  9. * @subpackage CalDAV
  10. * @copyright Copyright (C) 2007-2010 Rooftop Solutions. All rights reserved.
  11. * @author Evert Pot (http://www.rooftopsolutions.nl/)
  12. * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
  13. */
  14. class Sabre_CalDAV_XMLUtil {
  15. /**
  16. * This function parses the calendar-query report request body
  17. *
  18. * The body is quite complicated, so we're turning it into a PHP
  19. * array.
  20. *
  21. * The resulting associative array has xpath expressions as keys.
  22. * By default the xpath expressions should simply be checked for existance
  23. * The xpath expressions can point to elements or attributes.
  24. *
  25. * The array values can contain a number of items, which alters the query
  26. * filter.
  27. *
  28. * * time-range. Must also check if the todo or event falls within the
  29. * specified timerange. How this is interpreted depends on
  30. * the type of object (VTODO, VEVENT, VJOURNAL, etc)
  31. * * is-not-defined
  32. * Instead of checking if the attribute or element exist,
  33. * we must check if it doesn't.
  34. * * text-match
  35. * Checks if the value of the attribute or element matches
  36. * the specified value. This is actually another array with
  37. * the 'collation', 'value' and 'negate-condition' items.
  38. *
  39. * Refer to the CalDAV spec for more information.
  40. *
  41. * @param DOMNode $domNode
  42. * @param string $basePath used for recursive calls.
  43. * @param array $filters used for recursive calls.
  44. * @return array
  45. */
  46. static public function parseCalendarQueryFilters($domNode,$basePath = '/c:iCalendar', &$filters = array()) {
  47. foreach($domNode->childNodes as $child) {
  48. switch(Sabre_DAV_XMLUtil::toClarkNotation($child)) {
  49. case '{urn:ietf:params:xml:ns:caldav}comp-filter' :
  50. case '{urn:ietf:params:xml:ns:caldav}prop-filter' :
  51. $filterName = $basePath . '/' . 'c:' . strtolower($child->getAttribute('name'));
  52. $filters[$filterName] = array();
  53. self::parseCalendarQueryFilters($child, $filterName,$filters);
  54. break;
  55. case '{urn:ietf:params:xml:ns:caldav}time-range' :
  56. if ($start = $child->getAttribute('start')) {
  57. $start = self::parseICalendarDateTime($start);
  58. } else {
  59. $start = null;
  60. }
  61. if ($end = $child->getAttribute('end')) {
  62. $end = self::parseICalendarDateTime($end);
  63. } else {
  64. $end = null;
  65. }
  66. if (!is_null($start) && !is_null($end) && $end <= $start) {
  67. throw new Sabre_DAV_Exception_BadRequest('The end-date must be larger than the start-date in the time-range filter');
  68. }
  69. $filters[$basePath]['time-range'] = array(
  70. 'start' => $start,
  71. 'end' => $end
  72. );
  73. break;
  74. case '{urn:ietf:params:xml:ns:caldav}is-not-defined' :
  75. $filters[$basePath]['is-not-defined'] = true;
  76. break;
  77. case '{urn:ietf:params:xml:ns:caldav}param-filter' :
  78. $filterName = $basePath . '/@' . strtolower($child->getAttribute('name'));
  79. $filters[$filterName] = array();
  80. self::parseCalendarQueryFilters($child, $filterName, $filters);
  81. break;
  82. case '{urn:ietf:params:xml:ns:caldav}text-match' :
  83. $collation = $child->getAttribute('collation');
  84. if (!$collation) $collation = 'i;ascii-casemap';
  85. $filters[$basePath]['text-match'] = array(
  86. 'collation' => $collation,
  87. 'negate-condition' => $child->getAttribute('negate-condition')==='yes',
  88. 'value' => $child->nodeValue,
  89. );
  90. break;
  91. }
  92. }
  93. return $filters;
  94. }
  95. /**
  96. * Parses an iCalendar (rfc5545) formatted datetime and returns a DateTime object
  97. *
  98. * Specifying a reference timezone is optional. It will only be used
  99. * if the non-UTC format is used. The argument is used as a reference, the
  100. * returned DateTime object will still be in the UTC timezone.
  101. *
  102. * @param string $dt
  103. * @param DateTimeZone $tz
  104. * @return DateTime
  105. */
  106. static public function parseICalendarDateTime($dt,DateTimeZone $tz = null) {
  107. // Format is YYYYMMDD + "T" + hhmmss
  108. $result = preg_match('/^([1-3][0-9]{3})([0-1][0-9])([0-3][0-9])T([0-2][0-9])([0-5][0-9])([0-5][0-9])([Z]?)$/',$dt,$matches);
  109. if (!$result) {
  110. throw new Sabre_DAV_Exception_BadRequest('The supplied iCalendar datetime value is incorrect: ' . $dt);
  111. }
  112. if ($matches[7]==='Z' || is_null($tz)) {
  113. $tz = new DateTimeZone('UTC');
  114. }
  115. $date = new DateTime($matches[1] . '-' . $matches[2] . '-' . $matches[3] . ' ' . $matches[4] . ':' . $matches[5] .':' . $matches[6], $tz);
  116. // Still resetting the timezone, to normalize everything to UTC
  117. $date->setTimeZone(new DateTimeZone('UTC'));
  118. return $date;
  119. }
  120. /**
  121. * Parses an iCalendar (rfc5545) formatted datetime and returns a DateTime object
  122. *
  123. * @param string $date
  124. * @param DateTimeZone $tz
  125. * @return DateTime
  126. */
  127. static public function parseICalendarDate($date) {
  128. // Format is YYYYMMDD
  129. $result = preg_match('/^([1-3][0-9]{3})([0-1][0-9])([0-3][0-9])$/',$date,$matches);
  130. if (!$result) {
  131. throw new Sabre_DAV_Exception_BadRequest('The supplied iCalendar date value is incorrect: ' . $date);
  132. }
  133. $date = new DateTime($matches[1] . '-' . $matches[2] . '-' . $matches[3], new DateTimeZone('UTC'));
  134. return $date;
  135. }
  136. /**
  137. * Parses an iCalendar (RFC5545) formatted duration and returns a string suitable
  138. * for strtotime or DateTime::modify.
  139. *
  140. * NOTE: When we require PHP 5.3 this can be replaced by the DateTimeInterval object, which
  141. * supports ISO 8601 Intervals, which is a superset of ICalendar durations.
  142. *
  143. * For now though, we're just gonna live with this messy system
  144. *
  145. * @param string $duration
  146. * @return string
  147. */
  148. static public function parseICalendarDuration($duration) {
  149. $result = preg_match('/^(?P<plusminus>\+|-)?P((?P<week>\d+)W)?((?P<day>\d+)D)?(T((?P<hour>\d+)H)?((?P<minute>\d+)M)?((?P<second>\d+)S)?)?$/', $duration, $matches);
  150. if (!$result) {
  151. throw new Sabre_DAV_Exception_BadRequest('The supplied iCalendar duration value is incorrect: ' . $duration);
  152. }
  153. $parts = array(
  154. 'week',
  155. 'day',
  156. 'hour',
  157. 'minute',
  158. 'second',
  159. );
  160. $newDur = '';
  161. foreach($parts as $part) {
  162. if (isset($matches[$part]) && $matches[$part]) {
  163. $newDur.=' '.$matches[$part] . ' ' . $part . 's';
  164. }
  165. }
  166. $newDur = ($matches['plusminus']==='-'?'-':'+') . trim($newDur);
  167. return $newDur;
  168. }
  169. }