Skip to content

Commit 5b0f19a

Browse files
author
Jack Bates
committed
* Moved iCalendar parsing function into it's own class, complete with offsets support
* Fixed bug with $depth < 'infinity' * TODO If this parser works & has all necessary features, add documentation
1 parent 40e077e commit 5b0f19a

File tree

4 files changed

+218
-103
lines changed

4 files changed

+218
-103
lines changed

caldav.php

+4-2
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,8 @@ function propfind($options, &$files) {
168168
if (is_dir($absolutePath)) {
169169
$file['props'][] = $this->mkprop('resourcetype', 'collection');
170170

171-
if ($depth < $options['depth']) {
171+
if ($depth < $options['depth'] ||
172+
$options['depth'] == 'infinity') {
172173
$handle = opendir($absolutePath);
173174
if (!$handle) {
174175
return;
@@ -230,7 +231,8 @@ function report($options, &$files) {
230231
if (is_dir($absolutePath)) {
231232
$file['props'][] = $this->mkprop('resourcetype', 'collection');
232233

233-
if ($depth < $options['depth']) {
234+
if ($depth < $options['depth'] ||
235+
$options['depth'] == 'infinity') {
234236
$handle = opendir($absolutePath);
235237
if (!$handle) {
236238
return;

lib/HTTP/CalDAV/Server.php

+18-99
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@
2020
* @author Jack Bates <[email protected]>
2121
* @copyright 2006 The PHP Group
2222
* @license PHP License 3.0 http://www.php.net/license/3_0.txt
23-
* @version CVS: $Id: Server.php,v 1.4 2006/04/13 22:33:13 jablko Exp $
23+
* @version CVS: $Id: Server.php,v 1.5 2006/04/18 03:22:12 jablko Exp $
2424
* @link http://pear.php.net/package/HTTP_CalDAV_Server
2525
* @see HTTP_WebDAV_Server
2626
*/
2727

2828
require_once 'Tools/ReportParser.php';
29+
require_once 'Tools/ICalendarParser.php';
2930

3031
/**
3132
* CalDav Server class
@@ -37,7 +38,7 @@
3738
* @author Jack Bates <[email protected]>
3839
* @copyright 2006 The PHP Group
3940
* @license PHP License 3.0 http://www.php.net/license/3_0.txt
40-
* @version CVS: $Id: Server.php,v 1.4 2006/04/13 22:33:13 jablko Exp $
41+
* @version CVS: $Id: Server.php,v 1.5 2006/04/18 03:22:12 jablko Exp $
4142
* @link http://pear.php.net/package/HTTP_CalDAV_Server
4243
* @see HTTP_WebDAV_Server
4344
*/
@@ -69,7 +70,9 @@ function report_request_helper(&$options)
6970
$options = array();
7071
$options['path'] = $this->path;
7172

72-
$options['depth'] = 'infinity';
73+
/* The request MAY include a Depth header. If no Depth header is
74+
included, Depth:0 is assumed. */
75+
$options['depth'] = 0;
7376
if (isset($_SERVER['HTTP_DEPTH'])) {
7477
$options['depth'] = $_SERVER['HTTP_DEPTH'];
7578
}
@@ -147,30 +150,36 @@ function getProp($reqprop, $file, $options)
147150

148151
$status = $this->get($options);
149152
if (empty($status)) {
150-
$status = '403 Forbidden';
153+
$status = '404 Not Found';
151154
}
152155

153156
if ($status !== true) {
154157
return $this->calDavProp('calendar-data', null, $status);
155158
}
156159

157160
if ($options['mimetype'] != 'text/calendar') {
158-
return $this->calDavProp('calendar-data', null, '404 Not Found');
161+
return $this->calDavProp('calendar-data', null,
162+
'404 Not Found');
159163
}
160164

161165
if ($options['stream']) {
162166
$handle = $options['stream'];
163167
} else if ($options['data']) {
164168
// What about data?
165169
} else {
166-
return $this->calDavProp('calendar-data', null, '404 Not Found');
170+
return $this->calDavProp('calendar-data', null,
171+
'404 Not Found');
167172
}
168173

169-
if (!($value = $this->_parseComponent($handle, $reqprop['value'], $filters))) {
170-
return $this->calDavProp('calendar-data', null, '404 Not Found');
174+
$parser = new ICalendarParser($handle, null, null,
175+
$reqprop['value'], $filters);
176+
if (!$parser->success) {
177+
return $this->calDavProp('calendar-data', null,
178+
'404 Not Found');
171179
}
172180

173-
return HTTP_CalDAV_Server::calDavProp('calendar-data', $value);
181+
return HTTP_CalDAV_Server::calDavProp('calendar-data',
182+
$parser->comps[count($parser->comps) - 1]);
174183
}
175184

176185
// incase the requested property had a value, like calendar-data
@@ -179,96 +188,6 @@ function getProp($reqprop, $file, $options)
179188
return $reqprop;
180189
}
181190

182-
function _parseComponent($handle, $value=null, $filters=null)
183-
{
184-
$comps = array();
185-
$compValues = array($value);
186-
$compFilters = array($filters);
187-
while (($line = fgets($handle, 4096)) !== false) {
188-
$line = explode(':', trim($line));
189-
190-
if ($line[0] == 'END') {
191-
if ($line[1] != $comps[count($comps) - 1]->name) {
192-
return;
193-
}
194-
195-
if (is_array($compFilters[count($compFilters) - 1]['filters'])) {
196-
foreach ($compFilters[count($compFilters) - 1]['filters'] as $filter) {
197-
if ($filter['name'] == 'time-range') {
198-
if ($filter['value']['start'] > $comps[count($comps) - 1]->properties['DTEND'][0]->value || $filter['value']['end'] < $comps[count($comps) - 1]->properties['DTSTART'][0]->value) {
199-
array_pop($compValues);
200-
array_pop($compFilters);
201-
continue;
202-
}
203-
}
204-
}
205-
}
206-
207-
// If we're about to pop the root component, we ignore the rest
208-
// of our input
209-
if (count($comps) == 1) {
210-
return array_pop($comps);
211-
}
212-
213-
if (!$comps[count($comps) - 2]->add_component(array_pop($comps))) {
214-
return;
215-
}
216-
217-
array_pop($compValues);
218-
array_pop($compFilters);
219-
continue;
220-
}
221-
222-
if ($line[0] == 'BEGIN') {
223-
$compName = $line[1];
224-
if (is_array($compValues[count($compValues) - 1]['comps']) &&
225-
!isset($compValues[count($compValues) - 1]['comps'][$compName])) {
226-
while (($line = fgets($handle, 4096)) !== false) {
227-
if (trim($line) == "END:$compName") {
228-
continue (2);
229-
}
230-
}
231-
232-
return;
233-
}
234-
235-
$className = 'iCalendar_' . ltrim(strtolower($compName), 'v');
236-
if ($line[1] == 'VCALENDAR') {
237-
$className = 'iCalendar';
238-
}
239-
240-
if (!class_exists($className)) {
241-
while (($line = fgets($handle, 4096)) !== false) {
242-
if (trim($line) == "END:$compName") {
243-
continue (2);
244-
}
245-
}
246-
247-
return;
248-
}
249-
250-
$comps[] = new $className;
251-
$compValues[] = $compValues[count($compValues) - 1]['comps'][$compName];
252-
$compFilters[] = $compFilters[count($compFilters) - 1]['comps'][$compName];
253-
continue;
254-
}
255-
256-
$line[0] = explode(';=', $line[0]);
257-
$propName = array_shift($line[0]);
258-
if (is_array($compValues[count($compValues) - 1]['props']) &&
259-
!in_array($propName,
260-
$compValues[count($compValues) - 1]['props'])) {
261-
continue;
262-
}
263-
264-
$params = array();
265-
while (!empty($line[0])) {
266-
$params[array_shift($line[0])] = array_shift($line[0]);
267-
}
268-
$comps[count($comps) - 1]->add_property($propName, $line[1], $params);
269-
}
270-
}
271-
272191
function _multistatus($responses)
273192
{
274193
// now we generate the response header...
+193
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
<?php
2+
3+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4+
5+
/**
6+
* Helper for parsing iCalendar format
7+
*
8+
* Long description for file (if any)...
9+
*
10+
* PHP versions 4 & 5
11+
*
12+
* LICENSE: This source file is subject to version 3.0 of the PHP license
13+
* that is available through the world-wide-web at the following URI:
14+
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
15+
* the PHP License & are unable to obtain it through the web, please
16+
* send a note to [email protected] so we can mail you a copy immediately
17+
*
18+
* @category HTTP
19+
* @package HTTP_CalDAV_Server
20+
* @author Jack Bates <[email protected]>
21+
* @copyright 2006 The PHP Group
22+
* @license PHP License 3.0 http://www.php.net/license/3_0.txt
23+
* @version CVS: $Id: ICalendarParser.php,v 1.1 2006/04/18 03:22:12 jablko Exp $
24+
* @link http://pear.php.net/package/HTTP_CalDAV_Server
25+
* @see HTTP_WebDAV_Server
26+
*/
27+
28+
/**
29+
* Helper for parsing iCalendar format
30+
*
31+
* Long description
32+
*
33+
* @category HTTP
34+
* @package HTTP_CalDAV_Server
35+
* @author Jack Bates <[email protected]>
36+
* @copyright 2006 The PHP Group
37+
* @license PHP License 3.0 http://www.php.net/license/3_0.txt
38+
* @version CVS: $Id: ICalendarParser.php,v 1.1 2006/04/18 03:22:12 jablko Exp $
39+
* @link http://pear.php.net/package/HTTP_CalDAV_Server
40+
* @see HTTP_WebDAV_Server
41+
*/
42+
class ICalendarParser
43+
{
44+
/**
45+
* Success state flag
46+
*
47+
* @var bool
48+
* @access public
49+
*/
50+
var $success = false;
51+
52+
/**
53+
* Parsed components are collected here in post-order
54+
*
55+
* @var array
56+
* @access public
57+
*/
58+
var $comps = array();
59+
60+
/**
61+
* Parsed components' offsets are collected here in post-order
62+
*
63+
* @var array
64+
* @access public
65+
*/
66+
var $offsets = array();
67+
68+
/**
69+
* Constructor
70+
*
71+
* @param resource input stream handle
72+
* @access public
73+
*/
74+
function ICalendarParser($handle, $beginOffset=null, $endOffset=null,
75+
$value=null, $filters=null)
76+
{
77+
$comps = array();
78+
$beginOffsets = array();
79+
$compValues = array($value);
80+
$compFilters = array($filters);
81+
$this->success = true;
82+
while (($offset = ftell($handle)) !== false &&
83+
($line = fgets($handle, 4096)) !== false) {
84+
if (isset($endOffset) && $offset > $endOffset) {
85+
return;
86+
}
87+
88+
$line = explode(':', trim($line));
89+
90+
if ($line[0] == 'END') {
91+
if ($line[1] != $comps[count($comps) - 1]->name) {
92+
$this->success = false;
93+
return;
94+
}
95+
96+
if (is_array($compFilters[count($compFilters) - 1]['filters'])) {
97+
foreach ($compFilters[count($compFilters) - 1]['filters'] as $filter) {
98+
if ($filter['name'] == 'time-range') {
99+
if ($filter['value']['start'] > $comps[count($comps) - 1]->properties['DTEND'][0]->value || $filter['value']['end'] < $comps[count($comps) - 1]->properties['DTSTART'][0]->value) {
100+
array_pop($compValues);
101+
array_pop($compFilters);
102+
continue;
103+
}
104+
}
105+
}
106+
}
107+
108+
if (count($comps) > 1 &&
109+
!$comps[count($comps) - 2]->add_component($comps[count(
110+
$comps) - 1])) {
111+
$this->success = false;
112+
return;
113+
}
114+
115+
if (($offset = ftell($handle)) === false) {
116+
$this->success = false;
117+
return;
118+
}
119+
120+
$this->comps[] = array_pop($comps);
121+
$this->offsets[] = array(array_pop($beginOffsets), $offset);
122+
array_pop($compValues);
123+
array_pop($compFilters);
124+
continue;
125+
}
126+
127+
if ($line[0] == 'BEGIN') {
128+
$compName = $line[1];
129+
if (is_array($compValues[count($compValues) - 1]['comps']) &&
130+
!isset($compValues[count($compValues) - 1]['comps'][$compName])) {
131+
while (($line = fgets($handle, 4096)) !== false) {
132+
if (trim($line) == "END:$compName") {
133+
continue (2);
134+
}
135+
}
136+
137+
$this->success = false;
138+
return;
139+
}
140+
141+
$className = 'iCalendar_' . ltrim(strtolower($compName), 'v');
142+
if ($line[1] == 'VCALENDAR') {
143+
$className = 'iCalendar';
144+
}
145+
146+
if (!class_exists($className)) {
147+
while (($line = fgets($handle, 4096)) !== false) {
148+
if (trim($line) == "END:$compName") {
149+
continue (2);
150+
}
151+
}
152+
153+
$this->success = false;
154+
return;
155+
}
156+
157+
$comps[] = new $className;
158+
$beginOffsets[] = $offset;
159+
$compValues[] = $compValues[count($compValues) - 1]['comps'][$compName];
160+
$compFilters[] = $compFilters[count($compFilters) - 1]['comps'][$compName];
161+
continue;
162+
}
163+
164+
$line[0] = explode(';=', $line[0]);
165+
$propName = array_shift($line[0]);
166+
if (is_array($compValues[count($compValues) - 1]['props']) &&
167+
!in_array($propName,
168+
$compValues[count($compValues) - 1]['props'])) {
169+
continue;
170+
}
171+
172+
$params = array();
173+
while (!empty($line[0])) {
174+
$params[array_shift($line[0])] = array_shift($line[0]);
175+
}
176+
$comps[count($comps) - 1]->add_property($propName, $line[1], $params);
177+
}
178+
179+
if (!feof($handle)) {
180+
$this->success = false;
181+
}
182+
}
183+
}
184+
185+
/*
186+
* Local variables:
187+
* tab-width: 4
188+
* c-basic-offset: 4
189+
* c-handling-comment-ender-p: nil
190+
* End:
191+
*/
192+
193+
?>

0 commit comments

Comments
 (0)