From 5b0f19af8158984619f20aeffb5b8a0231cfecc2 Mon Sep 17 00:00:00 2001 From: Jack Bates Date: Tue, 18 Apr 2006 03:22:12 +0000 Subject: * 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 --- lib/HTTP/CalDAV/Server.php | 117 +++--------------- lib/HTTP/CalDAV/Tools/ICalendarParser.php | 193 ++++++++++++++++++++++++++++++ lib/HTTP/CalDAV/Tools/ReportParser.php | 5 +- 3 files changed, 214 insertions(+), 101 deletions(-) create mode 100644 lib/HTTP/CalDAV/Tools/ICalendarParser.php (limited to 'lib') diff --git a/lib/HTTP/CalDAV/Server.php b/lib/HTTP/CalDAV/Server.php index 05425a1..de76301 100644 --- a/lib/HTTP/CalDAV/Server.php +++ b/lib/HTTP/CalDAV/Server.php @@ -20,12 +20,13 @@ * @author Jack Bates * @copyright 2006 The PHP Group * @license PHP License 3.0 http://www.php.net/license/3_0.txt - * @version CVS: $Id: Server.php,v 1.4 2006/04/13 22:33:13 jablko Exp $ + * @version CVS: $Id: Server.php,v 1.5 2006/04/18 03:22:12 jablko Exp $ * @link http://pear.php.net/package/HTTP_CalDAV_Server * @see HTTP_WebDAV_Server */ require_once 'Tools/ReportParser.php'; +require_once 'Tools/ICalendarParser.php'; /** * CalDav Server class @@ -37,7 +38,7 @@ require_once 'Tools/ReportParser.php'; * @author Jack Bates * @copyright 2006 The PHP Group * @license PHP License 3.0 http://www.php.net/license/3_0.txt - * @version CVS: $Id: Server.php,v 1.4 2006/04/13 22:33:13 jablko Exp $ + * @version CVS: $Id: Server.php,v 1.5 2006/04/18 03:22:12 jablko Exp $ * @link http://pear.php.net/package/HTTP_CalDAV_Server * @see HTTP_WebDAV_Server */ @@ -69,7 +70,9 @@ class HTTP_CalDAV_Server extends HTTP_WebDAV_Server $options = array(); $options['path'] = $this->path; - $options['depth'] = 'infinity'; + /* The request MAY include a Depth header. If no Depth header is + included, Depth:0 is assumed. */ + $options['depth'] = 0; if (isset($_SERVER['HTTP_DEPTH'])) { $options['depth'] = $_SERVER['HTTP_DEPTH']; } @@ -147,7 +150,7 @@ class HTTP_CalDAV_Server extends HTTP_WebDAV_Server $status = $this->get($options); if (empty($status)) { - $status = '403 Forbidden'; + $status = '404 Not Found'; } if ($status !== true) { @@ -155,7 +158,8 @@ class HTTP_CalDAV_Server extends HTTP_WebDAV_Server } if ($options['mimetype'] != 'text/calendar') { - return $this->calDavProp('calendar-data', null, '404 Not Found'); + return $this->calDavProp('calendar-data', null, + '404 Not Found'); } if ($options['stream']) { @@ -163,14 +167,19 @@ class HTTP_CalDAV_Server extends HTTP_WebDAV_Server } else if ($options['data']) { // What about data? } else { - return $this->calDavProp('calendar-data', null, '404 Not Found'); + return $this->calDavProp('calendar-data', null, + '404 Not Found'); } - if (!($value = $this->_parseComponent($handle, $reqprop['value'], $filters))) { - return $this->calDavProp('calendar-data', null, '404 Not Found'); + $parser = new ICalendarParser($handle, null, null, + $reqprop['value'], $filters); + if (!$parser->success) { + return $this->calDavProp('calendar-data', null, + '404 Not Found'); } - return HTTP_CalDAV_Server::calDavProp('calendar-data', $value); + return HTTP_CalDAV_Server::calDavProp('calendar-data', + $parser->comps[count($parser->comps) - 1]); } // incase the requested property had a value, like calendar-data @@ -179,96 +188,6 @@ class HTTP_CalDAV_Server extends HTTP_WebDAV_Server return $reqprop; } - function _parseComponent($handle, $value=null, $filters=null) - { - $comps = array(); - $compValues = array($value); - $compFilters = array($filters); - while (($line = fgets($handle, 4096)) !== false) { - $line = explode(':', trim($line)); - - if ($line[0] == 'END') { - if ($line[1] != $comps[count($comps) - 1]->name) { - return; - } - - if (is_array($compFilters[count($compFilters) - 1]['filters'])) { - foreach ($compFilters[count($compFilters) - 1]['filters'] as $filter) { - if ($filter['name'] == 'time-range') { - if ($filter['value']['start'] > $comps[count($comps) - 1]->properties['DTEND'][0]->value || $filter['value']['end'] < $comps[count($comps) - 1]->properties['DTSTART'][0]->value) { - array_pop($compValues); - array_pop($compFilters); - continue; - } - } - } - } - - // If we're about to pop the root component, we ignore the rest - // of our input - if (count($comps) == 1) { - return array_pop($comps); - } - - if (!$comps[count($comps) - 2]->add_component(array_pop($comps))) { - return; - } - - array_pop($compValues); - array_pop($compFilters); - continue; - } - - if ($line[0] == 'BEGIN') { - $compName = $line[1]; - if (is_array($compValues[count($compValues) - 1]['comps']) && - !isset($compValues[count($compValues) - 1]['comps'][$compName])) { - while (($line = fgets($handle, 4096)) !== false) { - if (trim($line) == "END:$compName") { - continue (2); - } - } - - return; - } - - $className = 'iCalendar_' . ltrim(strtolower($compName), 'v'); - if ($line[1] == 'VCALENDAR') { - $className = 'iCalendar'; - } - - if (!class_exists($className)) { - while (($line = fgets($handle, 4096)) !== false) { - if (trim($line) == "END:$compName") { - continue (2); - } - } - - return; - } - - $comps[] = new $className; - $compValues[] = $compValues[count($compValues) - 1]['comps'][$compName]; - $compFilters[] = $compFilters[count($compFilters) - 1]['comps'][$compName]; - continue; - } - - $line[0] = explode(';=', $line[0]); - $propName = array_shift($line[0]); - if (is_array($compValues[count($compValues) - 1]['props']) && - !in_array($propName, - $compValues[count($compValues) - 1]['props'])) { - continue; - } - - $params = array(); - while (!empty($line[0])) { - $params[array_shift($line[0])] = array_shift($line[0]); - } - $comps[count($comps) - 1]->add_property($propName, $line[1], $params); - } - } - function _multistatus($responses) { // now we generate the response header... diff --git a/lib/HTTP/CalDAV/Tools/ICalendarParser.php b/lib/HTTP/CalDAV/Tools/ICalendarParser.php new file mode 100644 index 0000000..0e3ffe3 --- /dev/null +++ b/lib/HTTP/CalDAV/Tools/ICalendarParser.php @@ -0,0 +1,193 @@ + + * @copyright 2006 The PHP Group + * @license PHP License 3.0 http://www.php.net/license/3_0.txt + * @version CVS: $Id: ICalendarParser.php,v 1.1 2006/04/18 03:22:12 jablko Exp $ + * @link http://pear.php.net/package/HTTP_CalDAV_Server + * @see HTTP_WebDAV_Server + */ + +/** + * Helper for parsing iCalendar format + * + * Long description + * + * @category HTTP + * @package HTTP_CalDAV_Server + * @author Jack Bates + * @copyright 2006 The PHP Group + * @license PHP License 3.0 http://www.php.net/license/3_0.txt + * @version CVS: $Id: ICalendarParser.php,v 1.1 2006/04/18 03:22:12 jablko Exp $ + * @link http://pear.php.net/package/HTTP_CalDAV_Server + * @see HTTP_WebDAV_Server + */ +class ICalendarParser +{ + /** + * Success state flag + * + * @var bool + * @access public + */ + var $success = false; + + /** + * Parsed components are collected here in post-order + * + * @var array + * @access public + */ + var $comps = array(); + + /** + * Parsed components' offsets are collected here in post-order + * + * @var array + * @access public + */ + var $offsets = array(); + + /** + * Constructor + * + * @param resource input stream handle + * @access public + */ + function ICalendarParser($handle, $beginOffset=null, $endOffset=null, + $value=null, $filters=null) + { + $comps = array(); + $beginOffsets = array(); + $compValues = array($value); + $compFilters = array($filters); + $this->success = true; + while (($offset = ftell($handle)) !== false && + ($line = fgets($handle, 4096)) !== false) { + if (isset($endOffset) && $offset > $endOffset) { + return; + } + + $line = explode(':', trim($line)); + + if ($line[0] == 'END') { + if ($line[1] != $comps[count($comps) - 1]->name) { + $this->success = false; + return; + } + + if (is_array($compFilters[count($compFilters) - 1]['filters'])) { + foreach ($compFilters[count($compFilters) - 1]['filters'] as $filter) { + if ($filter['name'] == 'time-range') { + if ($filter['value']['start'] > $comps[count($comps) - 1]->properties['DTEND'][0]->value || $filter['value']['end'] < $comps[count($comps) - 1]->properties['DTSTART'][0]->value) { + array_pop($compValues); + array_pop($compFilters); + continue; + } + } + } + } + + if (count($comps) > 1 && + !$comps[count($comps) - 2]->add_component($comps[count( + $comps) - 1])) { + $this->success = false; + return; + } + + if (($offset = ftell($handle)) === false) { + $this->success = false; + return; + } + + $this->comps[] = array_pop($comps); + $this->offsets[] = array(array_pop($beginOffsets), $offset); + array_pop($compValues); + array_pop($compFilters); + continue; + } + + if ($line[0] == 'BEGIN') { + $compName = $line[1]; + if (is_array($compValues[count($compValues) - 1]['comps']) && + !isset($compValues[count($compValues) - 1]['comps'][$compName])) { + while (($line = fgets($handle, 4096)) !== false) { + if (trim($line) == "END:$compName") { + continue (2); + } + } + + $this->success = false; + return; + } + + $className = 'iCalendar_' . ltrim(strtolower($compName), 'v'); + if ($line[1] == 'VCALENDAR') { + $className = 'iCalendar'; + } + + if (!class_exists($className)) { + while (($line = fgets($handle, 4096)) !== false) { + if (trim($line) == "END:$compName") { + continue (2); + } + } + + $this->success = false; + return; + } + + $comps[] = new $className; + $beginOffsets[] = $offset; + $compValues[] = $compValues[count($compValues) - 1]['comps'][$compName]; + $compFilters[] = $compFilters[count($compFilters) - 1]['comps'][$compName]; + continue; + } + + $line[0] = explode(';=', $line[0]); + $propName = array_shift($line[0]); + if (is_array($compValues[count($compValues) - 1]['props']) && + !in_array($propName, + $compValues[count($compValues) - 1]['props'])) { + continue; + } + + $params = array(); + while (!empty($line[0])) { + $params[array_shift($line[0])] = array_shift($line[0]); + } + $comps[count($comps) - 1]->add_property($propName, $line[1], $params); + } + + if (!feof($handle)) { + $this->success = false; + } + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-handling-comment-ender-p: nil + * End: + */ + +?> diff --git a/lib/HTTP/CalDAV/Tools/ReportParser.php b/lib/HTTP/CalDAV/Tools/ReportParser.php index f251add..feb2f2d 100644 --- a/lib/HTTP/CalDAV/Tools/ReportParser.php +++ b/lib/HTTP/CalDAV/Tools/ReportParser.php @@ -20,7 +20,7 @@ * @author Jack Bates * @copyright 2006 The PHP Group * @license PHP License 3.0 http://www.php.net/license/3_0.txt - * @version CVS: $Id: ReportParser.php,v 1.3 2006/04/13 22:33:13 jablko Exp $ + * @version CVS: $Id: ReportParser.php,v 1.4 2006/04/18 03:22:12 jablko Exp $ * @link http://pear.php.net/package/HTTP_CalDAV_Server * @see HTTP_WebDAV_Server */ @@ -35,7 +35,7 @@ * @author Jack Bates * @copyright 2006 The PHP Group * @license PHP License 3.0 http://www.php.net/license/3_0.txt - * @version CVS: $Id: ReportParser.php,v 1.3 2006/04/13 22:33:13 jablko Exp $ + * @version CVS: $Id: ReportParser.php,v 1.4 2006/04/18 03:22:12 jablko Exp $ * @link http://pear.php.net/package/HTTP_CalDAV_Server * @see HTTP_WebDAV_Server */ @@ -97,6 +97,7 @@ class ReportParser */ function ReportParser($input) { + // FIXME Take a handle, not a path $handle = fopen($input, 'r'); if (!$handle) { return; -- cgit v1.2.3