예제 #1
0
파일: ICalendar.php 프로젝트: ulrikkold/cal
 /**
  * Parses a string containing vCalendar data.
  *
  * @param string $text
  *        	The data to parse.
  * @param string $base
  *        	The type of the base object.
  * @param string $charset
  *        	The encoding charset for $text. Defaults to
  *        	utf-8.
  * @param boolean $clear
  *        	If true clears the iCal object before parsing.
  *        	
  * @return boolean True on successful import, false otherwise.
  */
 function parsevCalendar($text, $base = 'VCALENDAR', $charset = 'utf8', $clear = true)
 {
     if ($clear) {
         $this->clear();
     }
     $matches = array();
     if (preg_match('/(BEGIN:' . $base . '\\r?\\n?)([\\W\\w]*)(END:' . $base . '\\r?\\n?)/i', $text, $matches)) {
         $vCal = $matches[2];
     } else {
         // Text isn't enclosed in BEGIN:VCALENDAR
         // .. END:VCALENDAR. We'll try to parse it anyway.
         $vCal = $text;
     }
     // All subcomponents.
     $matches = null;
     if (preg_match_all('/BEGIN:([\\W\\w]*)(\\r\\n|\\r|\\n)([\\W\\w]*)END:\\1(\\r\\n|\\r|\\n)/Ui', $vCal, $matches)) {
         // vTimezone components are processed first. They are
         // needed to process vEvents that may use a TZID.
         foreach ($matches[0] as $key => $data) {
             $type = trim($matches[1][$key]);
             if ($type != 'VTIMEZONE') {
                 continue;
             }
             $component =& ICalendar::newComponent($type, $this);
             if ($component === false) {
                 // return PEAR::raiseError("Unable to create object for type $type");
             }
             $component->parsevCalendar($data);
             $this->addComponent($component);
             // Remove from the vCalendar data.
             $vCal = str_replace($data, '', $vCal);
         }
         // Now process the non-vTimezone components.
         foreach ($matches[0] as $key => $data) {
             $type = trim($matches[1][$key]);
             if ($type == 'VTIMEZONE') {
                 continue;
             }
             $component =& ICalendar::newComponent($type, $this);
             if ($component === false) {
                 // return PEAR::raiseError("Unable to create object for type $type");
             }
             $component->parsevCalendar($data);
             $this->addComponent($component);
             // Remove from the vCalendar data.
             $vCal = str_replace($data, '', $vCal);
         }
     }
     // Unfold any folded lines.
     $vCal = preg_replace('/[\\r\\n]+[ \\t]/', '', $vCal);
     // Unfold 'quoted printable' folded lines like:
     // BODY;ENCODING=QUOTED-PRINTABLE:=
     // another=20line=
     // last=20line
     while (preg_match_all('/^([^:]+;\\s*ENCODING=QUOTED-PRINTABLE(.*=\\r?\\n)+(.*[^=])?\\r?\\n)/mU', $vCal, $matches)) {
         foreach ($matches[1] as $s) {
             $r = preg_replace('/=\\r?\\n/', '', $s);
             $vCal = str_replace($s, $r, $vCal);
         }
     }
     if (is_object($GLOBALS['LANG'])) {
         $csConvObj =& $GLOBALS['LANG']->csConvObj;
     } elseif (is_object($GLOBALS['TSFE'])) {
         $csConvObj =& $GLOBALS['TSFE']->csConvObj;
     } else {
         require_once \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath('lang') . 'lang.php';
         $LANG = new language();
         if (TYPO3_MODE == 'BE') {
             $LANG->init($GLOBALS['BE_USER']->uc['lang']);
             $csConvObj =& $LANG->csConvObj;
         } else {
             $LANG->init($GLOBALS['TSFE']->config['config']['language']);
             $csConvObj =& $GLOBALS['TSFE']->csConvObj;
         }
     }
     $renderCharset = $csConvObj->parse_charset($GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset'] ? $GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset'] : $this->defaultCharSet);
     // Parse the remaining attributes.
     if (preg_match_all('/(.*):([^\\r\\n]*)[\\r\\n]+/', $vCal, $matches)) {
         foreach ($matches[0] as $attribute) {
             $parts = array();
             preg_match('/([^;^:]*)((;[^:]*)?):([^\\r\\n]*)[\\r\\n]*/', $attribute, $parts);
             $tag = $parts[1];
             $value = $parts[4];
             $params = array();
             // Parse parameters.
             if (!empty($parts[2])) {
                 $param_parts = array();
                 preg_match_all('/;(([^;=]*)(=([^;]*))?)/', $parts[2], $param_parts);
                 foreach ($param_parts[2] as $key => $paramName) {
                     $paramValue = $param_parts[4][$key];
                     $params[strtoupper($paramName)] = $paramValue;
                 }
             }
             // Charset and encoding handling.
             if (isset($params['ENCODING']) && strtoupper($params['ENCODING']) == 'QUOTED-PRINTABLE' || isset($params['QUOTED-PRINTABLE'])) {
                 $value = quoted_printable_decode($value);
                 $value = $csConvObj->conv($value, $csConvObj->parse_charset[$params['CHARSET']] ? $csConvObj->parse_charset[$params['CHARSET']] : 'utf-8', $renderCharset, 1);
             } elseif (isset($params['CHARSET'])) {
                 $value = $csConvObj->conv($value, $csConvObj->parse_charset[$params['CHARSET']], $renderCharset, 1);
             } else {
                 // As per RFC 2279, assume UTF8 if we don't have an
                 // explicit charset parameter.
                 $value = $csConvObj->conv($value, 'utf-8', $renderCharset, 1);
             }
             // Get timezone info for date fields from $params.
             $tzid = isset($params['TZID']) ? trim($params['TZID'], '\\"') : false;
             switch ($tag) {
                 // Date fields.
                 case 'COMPLETED':
                 case 'CREATED':
                 case 'LAST-MODIFIED':
                     $this->setAttribute($tag, $this->_parseDateTime($value, $tzid), $params);
                     break;
                 case 'BDAY':
                     $this->setAttribute($tag, $this->_parseDate($value), $params);
                     break;
                 case 'DTEND':
                 case 'DTSTART':
                 case 'DTSTAMP':
                 case 'DUE':
                 case 'AALARM':
                 case 'RECURRENCE-ID':
                     if (isset($params['VALUE']) && $params['VALUE'] == 'DATE') {
                         $this->setAttribute($tag, $this->_parseDate($value), $params);
                     } else {
                         $this->setAttribute($tag, $this->_parseDateTime($value, $tzid), $params);
                     }
                     break;
                 case 'TRIGGER':
                     if (isset($params['VALUE'])) {
                         if ($params['VALUE'] == 'DATE-TIME') {
                             $this->setAttribute($tag, $this->_parseDateTime($value, $tzid), $params);
                         } else {
                             $this->setAttribute($tag, $this->_parseDuration($value), $params);
                         }
                     } else {
                         $this->setAttribute($tag, $this->_parseDuration($value), $params);
                     }
                     break;
                     // Comma seperated dates.
                 // Comma seperated dates.
                 case 'EXDATE':
                 case 'RDATE':
                     $this->setAttribute($tag, $value, $params);
                     break;
                     // Duration fields.
                 // Duration fields.
                 case 'DURATION':
                     $this->setAttribute($tag, $this->_parseDuration($value), $params);
                     break;
                     // Period of time fields.
                 // Period of time fields.
                 case 'FREEBUSY':
                     $periods = array();
                     preg_match_all('/,([^,]*)/', ',' . $value, $values);
                     foreach ($values[1] as $value) {
                         $periods[] = $this->_parsePeriod($value);
                     }
                     $this->setAttribute($tag, isset($periods[0]) ? $periods[0] : null, $params, true, $periods);
                     break;
                     // UTC offset fields.
                 // UTC offset fields.
                 case 'TZOFFSETFROM':
                 case 'TZOFFSETTO':
                     $this->setAttribute($tag, $this->_parseUtcOffset($value), $params);
                     break;
                     // Integer fields.
                 // Integer fields.
                 case 'PERCENT-COMPLETE':
                 case 'PRIORITY':
                 case 'REPEAT':
                 case 'SEQUENCE':
                     $this->setAttribute($tag, intval($value), $params);
                     break;
                     // Geo fields.
                 // Geo fields.
                 case 'GEO':
                     $floats = explode(';', $value);
                     $value['latitude'] = floatval($floats[0]);
                     $value['longitude'] = floatval($floats[1]);
                     $this->setAttribute($tag, $value, $params);
                     break;
                     // Recursion fields.
                 // Recursion fields.
                 case 'EXRULE':
                 case 'RRULE':
                     $this->setAttribute($tag, trim($value), $params);
                     break;
                     // ADR, ORG and N are lists seperated by unescaped semicolons
                     // with a specific number of slots.
                 // ADR, ORG and N are lists seperated by unescaped semicolons
                 // with a specific number of slots.
                 case 'ADR':
                 case 'N':
                 case 'ORG':
                     $value = trim($value);
                     // As of rfc 2426 2.4.2 semicolon, comma, and colon must
                     // be escaped (comma is unescaped after splitting below).
                     $value = str_replace(array('\\n', '\\N', '\\;', '\\:'), array($this->_newline, $this->_newline, ';', ':'), $value);
                     // Split by unescaped semicolons:
                     $values = preg_split('/(?<!\\\\);/', $value);
                     $value = str_replace('\\;', ';', $value);
                     $values = str_replace('\\;', ';', $values);
                     $this->setAttribute($tag, trim($value), $params, true, $values);
                     break;
                     // String fields.
                 // String fields.
                 default:
                     if ($this->isOldFormat()) {
                         // vCalendar 1.0 and vcCard 2.1 only escape
                         // semicolons and use unescaped semicolons to
                         // create lists.
                         $value = trim($value);
                         // Split by unescaped semicolons:
                         $values = preg_split('/(?<!\\\\);/', $value);
                         $value = str_replace('\\;', ';', $value);
                         $values = str_replace('\\;', ';', $values);
                         $this->setAttribute($tag, trim($value), $params, true, $values);
                     } else {
                         $value = trim($value);
                         // As of rfc 2426 2.4.2 semicolon, comma, and
                         // colon must be escaped (comma is unescaped after
                         // splitting below).
                         $value = str_replace(array('\\n', '\\N', '\\;', '\\:', '\\\\'), array($this->_newline, $this->_newline, ';', ':', '\\'), $value);
                         // Split by unescaped commas:
                         $values = preg_split('/(?<!\\\\),/', $value);
                         $value = str_replace('\\,', ',', $value);
                         $values = str_replace('\\,', ',', $values);
                         $this->setAttribute($tag, trim($value), $params, true, $values);
                     }
                     break;
             }
         }
     }
     return true;
 }