CalDavClient.class.php 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. <?php
  2. // doc http://sabre.io/dav/building-a-caldav-client/
  3. class CaldavClient{
  4. public $host,$login,$password,$user;
  5. const debug = false;
  6. public function create_event($event,$eventId=null){
  7. $body = '';
  8. $eventId = isset($eventId)? $eventId : time().'-'.rand(0,1000).'.ics';
  9. $body .= 'BEGIN:VCALENDAR'."\r\n";
  10. $body .= 'VERSION:2.0'."\r\n";
  11. $body .= 'PRODID:-//hacksw/handcal//NONSGML v1.0//EN'."\r\n";
  12. $uid = time().'-'.rand(0,1000);
  13. $start = date('Ymd\THis',$event->start);
  14. $end = date('Ymd\THis',$event->end);
  15. $body .= 'BEGIN:VEVENT'."\r\n";
  16. $body .= 'UID:'.$uid."\r\n";
  17. $body .= 'DTSTART:'.$start.'Z'."\r\n";
  18. $body .= 'DTEND:'.$end.'Z'."\r\n";
  19. $body .= 'SUMMARY:'.$event->title."\r\n";
  20. $body .= 'LOCATION:'.$event->location."\r\n";
  21. $body .= 'STATUS:CONFIRMED'."\r\n";
  22. $body .= 'DESCRIPTION:'.$event->description."\r\n";
  23. $body .= 'SEQUENCE:1'."\r\n";
  24. $body .= 'CREATED:'.date('Ymd\THis').'Z'."\r\n";
  25. $body .= 'LAST-MODIFIED:'.date('Ymd\THis').'Z'."\r\n";
  26. if(isset($event->categories)):
  27. foreach($event->categories as $category):
  28. $body .= 'CATEGORIES:'.$category."\r\n";
  29. endforeach;
  30. endif;
  31. if(isset($event->frequency)):
  32. $body .= 'RRULE:FREQ='.strtoupper($event->frequency)."\r\n";
  33. endif;
  34. if(isset($event->alarms)):
  35. foreach($event->alarms as $alarm):
  36. $alarm = strtoupper($alarm);
  37. $alarm = in_array(substr($alarm,-1,1),array('H','M')) ? 'T'.$alarm:$alarm;
  38. $body .= 'BEGIN:VALARM'."\r\n";
  39. $body .= 'ACTION:DISPLAY'."\r\n";
  40. $body .= 'TRIGGER;VALUE=DURATION:-P'.strtoupper($alarm)."\r\n";
  41. $body .= 'DESCRIPTION:'.$event->title."\r\n";
  42. $body .= 'END:VALARM'."\r\n";
  43. endforeach;
  44. endif;
  45. $body .= 'END:VEVENT'."\r\n";
  46. $body .= 'END:VCALENDAR'."\r\n";
  47. $headers = array();
  48. $headers []= 'Content-Type: text/calendar; charset=utf-8';
  49. //if($etag!='') $headers []= 'ETag: "'.$etag.'"';
  50. $out =
  51. self::custom_request(
  52. $this->host.'/'.$this->user.'/'.$this->calendar.'/'.$eventId ,
  53. $this->login.":".$this->password,
  54. 'PUT',
  55. $headers,
  56. $body
  57. );
  58. if($out!='') throw new Exception($out);
  59. return $eventId;
  60. }
  61. public function delete_event($ics){
  62. return
  63. self::custom_request(
  64. $this->host.'/'.$this->user.'/'.$this->calendar.'/'.$ics ,
  65. $this->login.":".$this->password,
  66. 'DELETE',
  67. array(),
  68. ''
  69. );
  70. }
  71. public function get_events($calendar,$start=null,$end=null){
  72. $body = '<c:calendar-query xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">
  73. <d:prop>
  74. <d:getetag />
  75. <c:calendar-data />
  76. </d:prop>
  77. <c:filter>
  78. <c:comp-filter name="VCALENDAR">
  79. <c:comp-filter name="VEVENT">';
  80. if($start!=null || $end!=null)
  81. $body .= '<c:time-range start="'.($start!=null?date('Ymd\THis',$start).'Z':'').'" end="'.($end!=null?date('Ymd\THis',$end).Z:'').'"/>';
  82. $body .= '</c:comp-filter>
  83. </c:comp-filter>
  84. </c:filter>
  85. </c:calendar-query>';
  86. $response = self::custom_request(
  87. $this->host.'/'.$this->user.'/'.$calendar,
  88. $this->login.":".$this->password,
  89. 'REPORT',
  90. array(
  91. 'Depth: 1',
  92. 'Prefer: return-minimal',
  93. 'Content-Type: application/xml; charset=utf-8'
  94. ),
  95. $body);
  96. $events = array();
  97. //print_r($response);
  98. $xml = simplexml_load_string($response);
  99. $errors = $xml->xpath('//d:error');
  100. if(count($errors)>0){
  101. throw new Exception((string)$errors[0]->xpath('s:message')[0]);
  102. }
  103. foreach($xml->xpath('//d:multistatus/d:response') as $xmlEvent) {
  104. $xmlCalendar = (string)$xmlEvent->xpath('d:propstat/d:prop/cal:calendar-data')[0];
  105. $event = IcalEvent::fromFile($xmlCalendar);
  106. $url = explode('/',(string)$xmlEvent->xpath('d:href')[0]);
  107. $event->ics = array_pop($url);
  108. $events[] = $event;
  109. }
  110. return $events ;
  111. }
  112. public function get_calendar_infos($calendar){
  113. $body = '<d:propfind xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/">
  114. <d:prop>
  115. <d:displayname />
  116. <cs:getctag />
  117. </d:prop>
  118. </d:propfind>';
  119. return self::custom_request(
  120. $this->host.'/'.$this->user.'/'.$calendar.'/' ,
  121. $this->login.":".$this->password,
  122. 'PROPFIND',
  123. array(
  124. 'Content-Type: application/xml; charset=utf-8',
  125. 'Depth: 0',
  126. 'Prefer: return-minimal'
  127. ),
  128. $body);
  129. }
  130. public static function custom_request($url,$digest,$method,$headers,$body){
  131. $url = $url;
  132. if(self::debug){
  133. echo '<hr/>';
  134. echo '<b>URL :</b> '.$url.'<br>';
  135. echo '<b>DIGEST :</b> '.$digest.'<br>';
  136. echo '<b>METHOD :</b> '.$method.'<br>';
  137. echo '<b>HEADER :</b> '.json_encode($headers).'<br>';
  138. echo '<pre>'.htmlentities($body).'</pre>';
  139. }
  140. $ch = curl_init();
  141. curl_setopt($ch, CURLOPT_URL, $url);
  142. curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
  143. curl_setopt($ch, CURLOPT_USERPWD, $digest);
  144. curl_setopt($ch, CURLOPT_VERBOSE, 1);
  145. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  146. curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  147. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  148. //curl_setopt($ch, CURLOPT_COOKIE, session_name() . '=' . session_id());
  149. curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
  150. curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
  151. $response = curl_exec($ch);
  152. curl_close($ch);
  153. if(self::debug){
  154. echo '<h3>Response</h3><pre>'.htmlentities($response).'</pre>';
  155. }
  156. return $response;
  157. }
  158. }
  159. class IcalEvent{
  160. public $title,$description,$start,$end,$frequency,$location,$categories,$alarms,$ics;
  161. public static function fromFile($ical){
  162. $event = new self();
  163. $lines = array();
  164. foreach(explode("\n",$ical) as $line):
  165. $columns = explode(":",$line);
  166. if(!isset($columns[1])) continue;
  167. $key = $columns[0];
  168. $value = $columns[1];
  169. $keyvalues = explode(';',$key);
  170. $key = array_shift($keyvalues);
  171. $lines[$key] = $value;
  172. endforeach;
  173. if(isset($lines['SUMMARY'])) $event->title = $lines['SUMMARY'];
  174. if(isset($lines['DESCRIPTION'])) $event->description = $lines['DESCRIPTION'];
  175. if(isset($lines['DTSTART'])) $event->start = strtotime($lines['DTSTART']);
  176. if(isset($lines['DTEND'])) $event->end = strtotime($lines['DTEND']);
  177. if(isset($lines['RRULE'])) $event->frequency = $lines['RRULE'];
  178. if(isset($lines['LOCATION'])) $event->location = $lines['LOCATION'];
  179. return $event;
  180. }
  181. }
  182. ?>