initial sabre upgrade (needs lots of work - to wit: authentication, redo the browser interface, and rework event export/import)
This commit is contained in:
197
vendor/sabre/vobject/lib/Parser/Json.php
vendored
Normal file
197
vendor/sabre/vobject/lib/Parser/Json.php
vendored
Normal file
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
|
||||
namespace Sabre\VObject\Parser;
|
||||
|
||||
use Sabre\VObject\Component\VCalendar;
|
||||
use Sabre\VObject\Component\VCard;
|
||||
use Sabre\VObject\ParseException;
|
||||
use Sabre\VObject\EofException;
|
||||
|
||||
/**
|
||||
* Json Parser.
|
||||
*
|
||||
* This parser parses both the jCal and jCard formats.
|
||||
*
|
||||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
class Json extends Parser {
|
||||
|
||||
/**
|
||||
* The input data.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $input;
|
||||
|
||||
/**
|
||||
* Root component.
|
||||
*
|
||||
* @var Document
|
||||
*/
|
||||
protected $root;
|
||||
|
||||
/**
|
||||
* This method starts the parsing process.
|
||||
*
|
||||
* If the input was not supplied during construction, it's possible to pass
|
||||
* it here instead.
|
||||
*
|
||||
* If either input or options are not supplied, the defaults will be used.
|
||||
*
|
||||
* @param resource|string|array|null $input
|
||||
* @param int $options
|
||||
*
|
||||
* @return Sabre\VObject\Document
|
||||
*/
|
||||
function parse($input = null, $options = 0) {
|
||||
|
||||
if (!is_null($input)) {
|
||||
$this->setInput($input);
|
||||
}
|
||||
if (is_null($this->input)) {
|
||||
throw new EofException('End of input stream, or no input supplied');
|
||||
}
|
||||
|
||||
if (0 !== $options) {
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
switch ($this->input[0]) {
|
||||
case 'vcalendar' :
|
||||
$this->root = new VCalendar([], false);
|
||||
break;
|
||||
case 'vcard' :
|
||||
$this->root = new VCard([], false);
|
||||
break;
|
||||
default :
|
||||
throw new ParseException('The root component must either be a vcalendar, or a vcard');
|
||||
|
||||
}
|
||||
foreach ($this->input[1] as $prop) {
|
||||
$this->root->add($this->parseProperty($prop));
|
||||
}
|
||||
if (isset($this->input[2])) foreach ($this->input[2] as $comp) {
|
||||
$this->root->add($this->parseComponent($comp));
|
||||
}
|
||||
|
||||
// Resetting the input so we can throw an feof exception the next time.
|
||||
$this->input = null;
|
||||
|
||||
return $this->root;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a component.
|
||||
*
|
||||
* @param array $jComp
|
||||
*
|
||||
* @return \Sabre\VObject\Component
|
||||
*/
|
||||
function parseComponent(array $jComp) {
|
||||
|
||||
// We can remove $self from PHP 5.4 onward.
|
||||
$self = $this;
|
||||
|
||||
$properties = array_map(
|
||||
function($jProp) use ($self) {
|
||||
return $self->parseProperty($jProp);
|
||||
},
|
||||
$jComp[1]
|
||||
);
|
||||
|
||||
if (isset($jComp[2])) {
|
||||
|
||||
$components = array_map(
|
||||
function($jComp) use ($self) {
|
||||
return $self->parseComponent($jComp);
|
||||
},
|
||||
$jComp[2]
|
||||
);
|
||||
|
||||
} else $components = [];
|
||||
|
||||
return $this->root->createComponent(
|
||||
$jComp[0],
|
||||
array_merge($properties, $components),
|
||||
$defaults = false
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses properties.
|
||||
*
|
||||
* @param array $jProp
|
||||
*
|
||||
* @return \Sabre\VObject\Property
|
||||
*/
|
||||
function parseProperty(array $jProp) {
|
||||
|
||||
list(
|
||||
$propertyName,
|
||||
$parameters,
|
||||
$valueType
|
||||
) = $jProp;
|
||||
|
||||
$propertyName = strtoupper($propertyName);
|
||||
|
||||
// This is the default class we would be using if we didn't know the
|
||||
// value type. We're using this value later in this function.
|
||||
$defaultPropertyClass = $this->root->getClassNameForPropertyName($propertyName);
|
||||
|
||||
$parameters = (array)$parameters;
|
||||
|
||||
$value = array_slice($jProp, 3);
|
||||
|
||||
$valueType = strtoupper($valueType);
|
||||
|
||||
if (isset($parameters['group'])) {
|
||||
$propertyName = $parameters['group'] . '.' . $propertyName;
|
||||
unset($parameters['group']);
|
||||
}
|
||||
|
||||
$prop = $this->root->createProperty($propertyName, null, $parameters, $valueType);
|
||||
$prop->setJsonValue($value);
|
||||
|
||||
// We have to do something awkward here. FlatText as well as Text
|
||||
// represents TEXT values. We have to normalize these here. In the
|
||||
// future we can get rid of FlatText once we're allowed to break BC
|
||||
// again.
|
||||
if ($defaultPropertyClass === 'Sabre\VObject\Property\FlatText') {
|
||||
$defaultPropertyClass = 'Sabre\VObject\Property\Text';
|
||||
}
|
||||
|
||||
// If the value type we received (e.g.: TEXT) was not the default value
|
||||
// type for the given property (e.g.: BDAY), we need to add a VALUE=
|
||||
// parameter.
|
||||
if ($defaultPropertyClass !== get_class($prop)) {
|
||||
$prop["VALUE"] = $valueType;
|
||||
}
|
||||
|
||||
return $prop;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the input data.
|
||||
*
|
||||
* @param resource|string|array $input
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function setInput($input) {
|
||||
|
||||
if (is_resource($input)) {
|
||||
$input = stream_get_contents($input);
|
||||
}
|
||||
if (is_string($input)) {
|
||||
$input = json_decode($input);
|
||||
}
|
||||
$this->input = $input;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
696
vendor/sabre/vobject/lib/Parser/MimeDir.php
vendored
Normal file
696
vendor/sabre/vobject/lib/Parser/MimeDir.php
vendored
Normal file
@@ -0,0 +1,696 @@
|
||||
<?php
|
||||
|
||||
namespace Sabre\VObject\Parser;
|
||||
|
||||
use Sabre\VObject\ParseException;
|
||||
use Sabre\VObject\EofException;
|
||||
use Sabre\VObject\Component;
|
||||
use Sabre\VObject\Component\VCalendar;
|
||||
use Sabre\VObject\Component\VCard;
|
||||
use Sabre\VObject\Document;
|
||||
|
||||
/**
|
||||
* MimeDir parser.
|
||||
*
|
||||
* This class parses iCalendar 2.0 and vCard 2.1, 3.0 and 4.0 files. This
|
||||
* parser will return one of the following two objects from the parse method:
|
||||
*
|
||||
* Sabre\VObject\Component\VCalendar
|
||||
* Sabre\VObject\Component\VCard
|
||||
*
|
||||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
class MimeDir extends Parser {
|
||||
|
||||
/**
|
||||
* The input stream.
|
||||
*
|
||||
* @var resource
|
||||
*/
|
||||
protected $input;
|
||||
|
||||
/**
|
||||
* Root component.
|
||||
*
|
||||
* @var Component
|
||||
*/
|
||||
protected $root;
|
||||
|
||||
/**
|
||||
* By default all input will be assumed to be UTF-8.
|
||||
*
|
||||
* However, both iCalendar and vCard might be encoded using different
|
||||
* character sets. The character set is usually set in the mime-type.
|
||||
*
|
||||
* If this is the case, use setEncoding to specify that a different
|
||||
* encoding will be used. If this is set, the parser will automatically
|
||||
* convert all incoming data to UTF-8.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $charset = 'UTF-8';
|
||||
|
||||
/**
|
||||
* The list of character sets we support when decoding.
|
||||
*
|
||||
* This would be a const expression but for now we need to support PHP 5.5
|
||||
*/
|
||||
protected static $SUPPORTED_CHARSETS = [
|
||||
'UTF-8',
|
||||
'ISO-8859-1',
|
||||
'Windows-1252',
|
||||
];
|
||||
|
||||
/**
|
||||
* Parses an iCalendar or vCard file.
|
||||
*
|
||||
* Pass a stream or a string. If null is parsed, the existing buffer is
|
||||
* used.
|
||||
*
|
||||
* @param string|resource|null $input
|
||||
* @param int $options
|
||||
*
|
||||
* @return Sabre\VObject\Document
|
||||
*/
|
||||
function parse($input = null, $options = 0) {
|
||||
|
||||
$this->root = null;
|
||||
|
||||
if (!is_null($input)) {
|
||||
$this->setInput($input);
|
||||
}
|
||||
|
||||
if (0 !== $options) {
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
$this->parseDocument();
|
||||
|
||||
return $this->root;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* By default all input will be assumed to be UTF-8.
|
||||
*
|
||||
* However, both iCalendar and vCard might be encoded using different
|
||||
* character sets. The character set is usually set in the mime-type.
|
||||
*
|
||||
* If this is the case, use setEncoding to specify that a different
|
||||
* encoding will be used. If this is set, the parser will automatically
|
||||
* convert all incoming data to UTF-8.
|
||||
*
|
||||
* @param string $charset
|
||||
*/
|
||||
function setCharset($charset) {
|
||||
|
||||
if (!in_array($charset, self::$SUPPORTED_CHARSETS)) {
|
||||
throw new \InvalidArgumentException('Unsupported encoding. (Supported encodings: ' . implode(', ', self::$SUPPORTED_CHARSETS) . ')');
|
||||
}
|
||||
$this->charset = $charset;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the input buffer. Must be a string or stream.
|
||||
*
|
||||
* @param resource|string $input
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function setInput($input) {
|
||||
|
||||
// Resetting the parser
|
||||
$this->lineIndex = 0;
|
||||
$this->startLine = 0;
|
||||
|
||||
if (is_string($input)) {
|
||||
// Convering to a stream.
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
fwrite($stream, $input);
|
||||
rewind($stream);
|
||||
$this->input = $stream;
|
||||
} elseif (is_resource($input)) {
|
||||
$this->input = $input;
|
||||
} else {
|
||||
throw new \InvalidArgumentException('This parser can only read from strings or streams.');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an entire document.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function parseDocument() {
|
||||
|
||||
$line = $this->readLine();
|
||||
|
||||
// BOM is ZERO WIDTH NO-BREAK SPACE (U+FEFF).
|
||||
// It's 0xEF 0xBB 0xBF in UTF-8 hex.
|
||||
if (3 <= strlen($line)
|
||||
&& ord($line[0]) === 0xef
|
||||
&& ord($line[1]) === 0xbb
|
||||
&& ord($line[2]) === 0xbf) {
|
||||
$line = substr($line, 3);
|
||||
}
|
||||
|
||||
switch (strtoupper($line)) {
|
||||
case 'BEGIN:VCALENDAR' :
|
||||
$class = VCalendar::$componentMap['VCALENDAR'];
|
||||
break;
|
||||
case 'BEGIN:VCARD' :
|
||||
$class = VCard::$componentMap['VCARD'];
|
||||
break;
|
||||
default :
|
||||
throw new ParseException('This parser only supports VCARD and VCALENDAR files');
|
||||
}
|
||||
|
||||
$this->root = new $class([], false);
|
||||
|
||||
while (true) {
|
||||
|
||||
// Reading until we hit END:
|
||||
$line = $this->readLine();
|
||||
if (strtoupper(substr($line, 0, 4)) === 'END:') {
|
||||
break;
|
||||
}
|
||||
$result = $this->parseLine($line);
|
||||
if ($result) {
|
||||
$this->root->add($result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$name = strtoupper(substr($line, 4));
|
||||
if ($name !== $this->root->name) {
|
||||
throw new ParseException('Invalid MimeDir file. expected: "END:' . $this->root->name . '" got: "END:' . $name . '"');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a line, and if it hits a component, it will also attempt to parse
|
||||
* the entire component.
|
||||
*
|
||||
* @param string $line Unfolded line
|
||||
*
|
||||
* @return Node
|
||||
*/
|
||||
protected function parseLine($line) {
|
||||
|
||||
// Start of a new component
|
||||
if (strtoupper(substr($line, 0, 6)) === 'BEGIN:') {
|
||||
|
||||
$component = $this->root->createComponent(substr($line, 6), [], false);
|
||||
|
||||
while (true) {
|
||||
|
||||
// Reading until we hit END:
|
||||
$line = $this->readLine();
|
||||
if (strtoupper(substr($line, 0, 4)) === 'END:') {
|
||||
break;
|
||||
}
|
||||
$result = $this->parseLine($line);
|
||||
if ($result) {
|
||||
$component->add($result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$name = strtoupper(substr($line, 4));
|
||||
if ($name !== $component->name) {
|
||||
throw new ParseException('Invalid MimeDir file. expected: "END:' . $component->name . '" got: "END:' . $name . '"');
|
||||
}
|
||||
|
||||
return $component;
|
||||
|
||||
} else {
|
||||
|
||||
// Property reader
|
||||
$property = $this->readProperty($line);
|
||||
if (!$property) {
|
||||
// Ignored line
|
||||
return false;
|
||||
}
|
||||
return $property;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* We need to look ahead 1 line every time to see if we need to 'unfold'
|
||||
* the next line.
|
||||
*
|
||||
* If that was not the case, we store it here.
|
||||
*
|
||||
* @var null|string
|
||||
*/
|
||||
protected $lineBuffer;
|
||||
|
||||
/**
|
||||
* The real current line number.
|
||||
*/
|
||||
protected $lineIndex = 0;
|
||||
|
||||
/**
|
||||
* In the case of unfolded lines, this property holds the line number for
|
||||
* the start of the line.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $startLine = 0;
|
||||
|
||||
/**
|
||||
* Contains a 'raw' representation of the current line.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $rawLine;
|
||||
|
||||
/**
|
||||
* Reads a single line from the buffer.
|
||||
*
|
||||
* This method strips any newlines and also takes care of unfolding.
|
||||
*
|
||||
* @throws \Sabre\VObject\EofException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function readLine() {
|
||||
|
||||
if (!is_null($this->lineBuffer)) {
|
||||
$rawLine = $this->lineBuffer;
|
||||
$this->lineBuffer = null;
|
||||
} else {
|
||||
do {
|
||||
$eof = feof($this->input);
|
||||
|
||||
$rawLine = fgets($this->input);
|
||||
|
||||
if ($eof || (feof($this->input) && $rawLine === false)) {
|
||||
throw new EofException('End of document reached prematurely');
|
||||
}
|
||||
if ($rawLine === false) {
|
||||
throw new ParseException('Error reading from input stream');
|
||||
}
|
||||
$rawLine = rtrim($rawLine, "\r\n");
|
||||
} while ($rawLine === ''); // Skipping empty lines
|
||||
$this->lineIndex++;
|
||||
}
|
||||
$line = $rawLine;
|
||||
|
||||
$this->startLine = $this->lineIndex;
|
||||
|
||||
// Looking ahead for folded lines.
|
||||
while (true) {
|
||||
|
||||
$nextLine = rtrim(fgets($this->input), "\r\n");
|
||||
$this->lineIndex++;
|
||||
if (!$nextLine) {
|
||||
break;
|
||||
}
|
||||
if ($nextLine[0] === "\t" || $nextLine[0] === " ") {
|
||||
$line .= substr($nextLine, 1);
|
||||
$rawLine .= "\n " . substr($nextLine, 1);
|
||||
} else {
|
||||
$this->lineBuffer = $nextLine;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
$this->rawLine = $rawLine;
|
||||
return $line;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a property or component from a line.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function readProperty($line) {
|
||||
|
||||
if ($this->options & self::OPTION_FORGIVING) {
|
||||
$propNameToken = 'A-Z0-9\-\._\\/';
|
||||
} else {
|
||||
$propNameToken = 'A-Z0-9\-\.';
|
||||
}
|
||||
|
||||
$paramNameToken = 'A-Z0-9\-';
|
||||
$safeChar = '^";:,';
|
||||
$qSafeChar = '^"';
|
||||
|
||||
$regex = "/
|
||||
^(?P<name> [$propNameToken]+ ) (?=[;:]) # property name
|
||||
|
|
||||
(?<=:)(?P<propValue> .+)$ # property value
|
||||
|
|
||||
;(?P<paramName> [$paramNameToken]+) (?=[=;:]) # parameter name
|
||||
|
|
||||
(=|,)(?P<paramValue> # parameter value
|
||||
(?: [$safeChar]*) |
|
||||
\"(?: [$qSafeChar]+)\"
|
||||
) (?=[;:,])
|
||||
/xi";
|
||||
|
||||
//echo $regex, "\n"; die();
|
||||
preg_match_all($regex, $line, $matches, PREG_SET_ORDER);
|
||||
|
||||
$property = [
|
||||
'name' => null,
|
||||
'parameters' => [],
|
||||
'value' => null
|
||||
];
|
||||
|
||||
$lastParam = null;
|
||||
|
||||
/**
|
||||
* Looping through all the tokens.
|
||||
*
|
||||
* Note that we are looping through them in reverse order, because if a
|
||||
* sub-pattern matched, the subsequent named patterns will not show up
|
||||
* in the result.
|
||||
*/
|
||||
foreach ($matches as $match) {
|
||||
|
||||
if (isset($match['paramValue'])) {
|
||||
if ($match['paramValue'] && $match['paramValue'][0] === '"') {
|
||||
$value = substr($match['paramValue'], 1, -1);
|
||||
} else {
|
||||
$value = $match['paramValue'];
|
||||
}
|
||||
|
||||
$value = $this->unescapeParam($value);
|
||||
|
||||
if (is_null($lastParam)) {
|
||||
throw new ParseException('Invalid Mimedir file. Line starting at ' . $this->startLine . ' did not follow iCalendar/vCard conventions');
|
||||
}
|
||||
if (is_null($property['parameters'][$lastParam])) {
|
||||
$property['parameters'][$lastParam] = $value;
|
||||
} elseif (is_array($property['parameters'][$lastParam])) {
|
||||
$property['parameters'][$lastParam][] = $value;
|
||||
} else {
|
||||
$property['parameters'][$lastParam] = [
|
||||
$property['parameters'][$lastParam],
|
||||
$value
|
||||
];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (isset($match['paramName'])) {
|
||||
$lastParam = strtoupper($match['paramName']);
|
||||
if (!isset($property['parameters'][$lastParam])) {
|
||||
$property['parameters'][$lastParam] = null;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (isset($match['propValue'])) {
|
||||
$property['value'] = $match['propValue'];
|
||||
continue;
|
||||
}
|
||||
if (isset($match['name']) && $match['name']) {
|
||||
$property['name'] = strtoupper($match['name']);
|
||||
continue;
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \LogicException('This code should not be reachable');
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
}
|
||||
|
||||
if (is_null($property['value'])) {
|
||||
$property['value'] = '';
|
||||
}
|
||||
if (!$property['name']) {
|
||||
if ($this->options & self::OPTION_IGNORE_INVALID_LINES) {
|
||||
return false;
|
||||
}
|
||||
throw new ParseException('Invalid Mimedir file. Line starting at ' . $this->startLine . ' did not follow iCalendar/vCard conventions');
|
||||
}
|
||||
|
||||
// vCard 2.1 states that parameters may appear without a name, and only
|
||||
// a value. We can deduce the value based on it's name.
|
||||
//
|
||||
// Our parser will get those as parameters without a value instead, so
|
||||
// we're filtering these parameters out first.
|
||||
$namedParameters = [];
|
||||
$namelessParameters = [];
|
||||
|
||||
foreach ($property['parameters'] as $name => $value) {
|
||||
if (!is_null($value)) {
|
||||
$namedParameters[$name] = $value;
|
||||
} else {
|
||||
$namelessParameters[] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
$propObj = $this->root->createProperty($property['name'], null, $namedParameters);
|
||||
|
||||
foreach ($namelessParameters as $namelessParameter) {
|
||||
$propObj->add(null, $namelessParameter);
|
||||
}
|
||||
|
||||
if (strtoupper($propObj['ENCODING']) === 'QUOTED-PRINTABLE') {
|
||||
$propObj->setQuotedPrintableValue($this->extractQuotedPrintableValue());
|
||||
} else {
|
||||
$charset = $this->charset;
|
||||
if ($this->root->getDocumentType() === Document::VCARD21 && isset($propObj['CHARSET'])) {
|
||||
// vCard 2.1 allows the character set to be specified per property.
|
||||
$charset = (string)$propObj['CHARSET'];
|
||||
}
|
||||
switch ($charset) {
|
||||
case 'UTF-8' :
|
||||
break;
|
||||
case 'ISO-8859-1' :
|
||||
$property['value'] = utf8_encode($property['value']);
|
||||
break;
|
||||
case 'Windows-1252' :
|
||||
$property['value'] = mb_convert_encoding($property['value'], 'UTF-8', $charset);
|
||||
break;
|
||||
default :
|
||||
throw new ParseException('Unsupported CHARSET: ' . $propObj['CHARSET']);
|
||||
}
|
||||
$propObj->setRawMimeDirValue($property['value']);
|
||||
}
|
||||
|
||||
return $propObj;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescapes a property value.
|
||||
*
|
||||
* vCard 2.1 says:
|
||||
* * Semi-colons must be escaped in some property values, specifically
|
||||
* ADR, ORG and N.
|
||||
* * Semi-colons must be escaped in parameter values, because semi-colons
|
||||
* are also use to separate values.
|
||||
* * No mention of escaping backslashes with another backslash.
|
||||
* * newlines are not escaped either, instead QUOTED-PRINTABLE is used to
|
||||
* span values over more than 1 line.
|
||||
*
|
||||
* vCard 3.0 says:
|
||||
* * (rfc2425) Backslashes, newlines (\n or \N) and comma's must be
|
||||
* escaped, all time time.
|
||||
* * Comma's are used for delimeters in multiple values
|
||||
* * (rfc2426) Adds to to this that the semi-colon MUST also be escaped,
|
||||
* as in some properties semi-colon is used for separators.
|
||||
* * Properties using semi-colons: N, ADR, GEO, ORG
|
||||
* * Both ADR and N's individual parts may be broken up further with a
|
||||
* comma.
|
||||
* * Properties using commas: NICKNAME, CATEGORIES
|
||||
*
|
||||
* vCard 4.0 (rfc6350) says:
|
||||
* * Commas must be escaped.
|
||||
* * Semi-colons may be escaped, an unescaped semi-colon _may_ be a
|
||||
* delimiter, depending on the property.
|
||||
* * Backslashes must be escaped
|
||||
* * Newlines must be escaped as either \N or \n.
|
||||
* * Some compound properties may contain multiple parts themselves, so a
|
||||
* comma within a semi-colon delimited property may also be unescaped
|
||||
* to denote multiple parts _within_ the compound property.
|
||||
* * Text-properties using semi-colons: N, ADR, ORG, CLIENTPIDMAP.
|
||||
* * Text-properties using commas: NICKNAME, RELATED, CATEGORIES, PID.
|
||||
*
|
||||
* Even though the spec says that commas must always be escaped, the
|
||||
* example for GEO in Section 6.5.2 seems to violate this.
|
||||
*
|
||||
* iCalendar 2.0 (rfc5545) says:
|
||||
* * Commas or semi-colons may be used as delimiters, depending on the
|
||||
* property.
|
||||
* * Commas, semi-colons, backslashes, newline (\N or \n) are always
|
||||
* escaped, unless they are delimiters.
|
||||
* * Colons shall not be escaped.
|
||||
* * Commas can be considered the 'default delimiter' and is described as
|
||||
* the delimiter in cases where the order of the multiple values is
|
||||
* insignificant.
|
||||
* * Semi-colons are described as the delimiter for 'structured values'.
|
||||
* They are specifically used in Semi-colons are used as a delimiter in
|
||||
* REQUEST-STATUS, RRULE, GEO and EXRULE. EXRULE is deprecated however.
|
||||
*
|
||||
* Now for the parameters
|
||||
*
|
||||
* If delimiter is not set (null) this method will just return a string.
|
||||
* If it's a comma or a semi-colon the string will be split on those
|
||||
* characters, and always return an array.
|
||||
*
|
||||
* @param string $input
|
||||
* @param string $delimiter
|
||||
*
|
||||
* @return string|string[]
|
||||
*/
|
||||
static function unescapeValue($input, $delimiter = ';') {
|
||||
|
||||
$regex = '# (?: (\\\\ (?: \\\\ | N | n | ; | , ) )';
|
||||
if ($delimiter) {
|
||||
$regex .= ' | (' . $delimiter . ')';
|
||||
}
|
||||
$regex .= ') #x';
|
||||
|
||||
$matches = preg_split($regex, $input, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
|
||||
|
||||
$resultArray = [];
|
||||
$result = '';
|
||||
|
||||
foreach ($matches as $match) {
|
||||
|
||||
switch ($match) {
|
||||
case '\\\\' :
|
||||
$result .= '\\';
|
||||
break;
|
||||
case '\N' :
|
||||
case '\n' :
|
||||
$result .= "\n";
|
||||
break;
|
||||
case '\;' :
|
||||
$result .= ';';
|
||||
break;
|
||||
case '\,' :
|
||||
$result .= ',';
|
||||
break;
|
||||
case $delimiter :
|
||||
$resultArray[] = $result;
|
||||
$result = '';
|
||||
break;
|
||||
default :
|
||||
$result .= $match;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$resultArray[] = $result;
|
||||
return $delimiter ? $resultArray : $result;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescapes a parameter value.
|
||||
*
|
||||
* vCard 2.1:
|
||||
* * Does not mention a mechanism for this. In addition, double quotes
|
||||
* are never used to wrap values.
|
||||
* * This means that parameters can simply not contain colons or
|
||||
* semi-colons.
|
||||
*
|
||||
* vCard 3.0 (rfc2425, rfc2426):
|
||||
* * Parameters _may_ be surrounded by double quotes.
|
||||
* * If this is not the case, semi-colon, colon and comma may simply not
|
||||
* occur (the comma used for multiple parameter values though).
|
||||
* * If it is surrounded by double-quotes, it may simply not contain
|
||||
* double-quotes.
|
||||
* * This means that a parameter can in no case encode double-quotes, or
|
||||
* newlines.
|
||||
*
|
||||
* vCard 4.0 (rfc6350)
|
||||
* * Behavior seems to be identical to vCard 3.0
|
||||
*
|
||||
* iCalendar 2.0 (rfc5545)
|
||||
* * Behavior seems to be identical to vCard 3.0
|
||||
*
|
||||
* Parameter escaping mechanism (rfc6868) :
|
||||
* * This rfc describes a new way to escape parameter values.
|
||||
* * New-line is encoded as ^n
|
||||
* * ^ is encoded as ^^.
|
||||
* * " is encoded as ^'
|
||||
*
|
||||
* @param string $input
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function unescapeParam($input) {
|
||||
|
||||
return
|
||||
preg_replace_callback(
|
||||
'#(\^(\^|n|\'))#',
|
||||
function($matches) {
|
||||
switch ($matches[2]) {
|
||||
case 'n' :
|
||||
return "\n";
|
||||
case '^' :
|
||||
return '^';
|
||||
case '\'' :
|
||||
return '"';
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
},
|
||||
$input
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the full quoted printable value.
|
||||
*
|
||||
* We need a special method for this, because newlines have both a meaning
|
||||
* in vCards, and in QuotedPrintable.
|
||||
*
|
||||
* This method does not do any decoding.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function extractQuotedPrintableValue() {
|
||||
|
||||
// We need to parse the raw line again to get the start of the value.
|
||||
//
|
||||
// We are basically looking for the first colon (:), but we need to
|
||||
// skip over the parameters first, as they may contain one.
|
||||
$regex = '/^
|
||||
(?: [^:])+ # Anything but a colon
|
||||
(?: "[^"]")* # A parameter in double quotes
|
||||
: # start of the value we really care about
|
||||
(.*)$
|
||||
/xs';
|
||||
|
||||
preg_match($regex, $this->rawLine, $matches);
|
||||
|
||||
$value = $matches[1];
|
||||
// Removing the first whitespace character from every line. Kind of
|
||||
// like unfolding, but we keep the newline.
|
||||
$value = str_replace("\n ", "\n", $value);
|
||||
|
||||
// Microsoft products don't always correctly fold lines, they may be
|
||||
// missing a whitespace. So if 'forgiving' is turned on, we will take
|
||||
// those as well.
|
||||
if ($this->options & self::OPTION_FORGIVING) {
|
||||
while (substr($value, -1) === '=') {
|
||||
// Reading the line
|
||||
$this->readLine();
|
||||
// Grabbing the raw form
|
||||
$value .= "\n" . $this->rawLine;
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
80
vendor/sabre/vobject/lib/Parser/Parser.php
vendored
Normal file
80
vendor/sabre/vobject/lib/Parser/Parser.php
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace Sabre\VObject\Parser;
|
||||
|
||||
/**
|
||||
* Abstract parser.
|
||||
*
|
||||
* This class serves as a base-class for the different parsers.
|
||||
*
|
||||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
abstract class Parser {
|
||||
|
||||
/**
|
||||
* Turning on this option makes the parser more forgiving.
|
||||
*
|
||||
* In the case of the MimeDir parser, this means that the parser will
|
||||
* accept slashes and underscores in property names, and it will also
|
||||
* attempt to fix Microsoft vCard 2.1's broken line folding.
|
||||
*/
|
||||
const OPTION_FORGIVING = 1;
|
||||
|
||||
/**
|
||||
* If this option is turned on, any lines we cannot parse will be ignored
|
||||
* by the reader.
|
||||
*/
|
||||
const OPTION_IGNORE_INVALID_LINES = 2;
|
||||
|
||||
/**
|
||||
* Bitmask of parser options.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $options;
|
||||
|
||||
/**
|
||||
* Creates the parser.
|
||||
*
|
||||
* Optionally, it's possible to parse the input stream here.
|
||||
*
|
||||
* @param mixed $input
|
||||
* @param int $options Any parser options (OPTION constants).
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function __construct($input = null, $options = 0) {
|
||||
|
||||
if (!is_null($input)) {
|
||||
$this->setInput($input);
|
||||
}
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method starts the parsing process.
|
||||
*
|
||||
* If the input was not supplied during construction, it's possible to pass
|
||||
* it here instead.
|
||||
*
|
||||
* If either input or options are not supplied, the defaults will be used.
|
||||
*
|
||||
* @param mixed $input
|
||||
* @param int $options
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract function parse($input = null, $options = 0);
|
||||
|
||||
/**
|
||||
* Sets the input data.
|
||||
*
|
||||
* @param mixed $input
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
abstract function setInput($input);
|
||||
|
||||
}
|
||||
428
vendor/sabre/vobject/lib/Parser/XML.php
vendored
Normal file
428
vendor/sabre/vobject/lib/Parser/XML.php
vendored
Normal file
@@ -0,0 +1,428 @@
|
||||
<?php
|
||||
|
||||
namespace Sabre\VObject\Parser;
|
||||
|
||||
use Sabre\VObject\Component;
|
||||
use Sabre\VObject\Component\VCalendar;
|
||||
use Sabre\VObject\Component\VCard;
|
||||
use Sabre\VObject\EofException;
|
||||
use Sabre\VObject\ParseException;
|
||||
use Sabre\Xml as SabreXml;
|
||||
|
||||
/**
|
||||
* XML Parser.
|
||||
*
|
||||
* This parser parses both the xCal and xCard formats.
|
||||
*
|
||||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Ivan Enderlin
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
class XML extends Parser {
|
||||
|
||||
const XCAL_NAMESPACE = 'urn:ietf:params:xml:ns:icalendar-2.0';
|
||||
const XCARD_NAMESPACE = 'urn:ietf:params:xml:ns:vcard-4.0';
|
||||
|
||||
/**
|
||||
* The input data.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $input;
|
||||
|
||||
/**
|
||||
* A pointer/reference to the input.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $pointer;
|
||||
|
||||
/**
|
||||
* Document, root component.
|
||||
*
|
||||
* @var Sabre\VObject\Document
|
||||
*/
|
||||
protected $root;
|
||||
|
||||
/**
|
||||
* Creates the parser.
|
||||
*
|
||||
* Optionally, it's possible to parse the input stream here.
|
||||
*
|
||||
* @param mixed $input
|
||||
* @param int $options Any parser options (OPTION constants).
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function __construct($input = null, $options = 0) {
|
||||
|
||||
if (0 === $options) {
|
||||
$options = parent::OPTION_FORGIVING;
|
||||
}
|
||||
|
||||
parent::__construct($input, $options);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse xCal or xCard.
|
||||
*
|
||||
* @param resource|string $input
|
||||
* @param int $options
|
||||
*
|
||||
* @throws \Exception
|
||||
*
|
||||
* @return Sabre\VObject\Document
|
||||
*/
|
||||
function parse($input = null, $options = 0) {
|
||||
|
||||
if (!is_null($input)) {
|
||||
$this->setInput($input);
|
||||
}
|
||||
|
||||
if (0 !== $options) {
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
if (is_null($this->input)) {
|
||||
throw new EofException('End of input stream, or no input supplied');
|
||||
}
|
||||
|
||||
switch ($this->input['name']) {
|
||||
|
||||
case '{' . self::XCAL_NAMESPACE . '}icalendar':
|
||||
$this->root = new VCalendar([], false);
|
||||
$this->pointer = &$this->input['value'][0];
|
||||
$this->parseVCalendarComponents($this->root);
|
||||
break;
|
||||
|
||||
case '{' . self::XCARD_NAMESPACE . '}vcards':
|
||||
foreach ($this->input['value'] as &$vCard) {
|
||||
|
||||
$this->root = new VCard(['version' => '4.0'], false);
|
||||
$this->pointer = &$vCard;
|
||||
$this->parseVCardComponents($this->root);
|
||||
|
||||
// We just parse the first <vcard /> element.
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ParseException('Unsupported XML standard');
|
||||
|
||||
}
|
||||
|
||||
return $this->root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a xCalendar component.
|
||||
*
|
||||
* @param Component $parentComponent
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function parseVCalendarComponents(Component $parentComponent) {
|
||||
|
||||
foreach ($this->pointer['value'] ?: [] as $children) {
|
||||
|
||||
switch (static::getTagName($children['name'])) {
|
||||
|
||||
case 'properties':
|
||||
$this->pointer = &$children['value'];
|
||||
$this->parseProperties($parentComponent);
|
||||
break;
|
||||
|
||||
case 'components':
|
||||
$this->pointer = &$children;
|
||||
$this->parseComponent($parentComponent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a xCard component.
|
||||
*
|
||||
* @param Component $parentComponent
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function parseVCardComponents(Component $parentComponent) {
|
||||
|
||||
$this->pointer = &$this->pointer['value'];
|
||||
$this->parseProperties($parentComponent);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse xCalendar and xCard properties.
|
||||
*
|
||||
* @param Component $parentComponent
|
||||
* @param string $propertyNamePrefix
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function parseProperties(Component $parentComponent, $propertyNamePrefix = '') {
|
||||
|
||||
foreach ($this->pointer ?: [] as $xmlProperty) {
|
||||
|
||||
list($namespace, $tagName) = SabreXml\Service::parseClarkNotation($xmlProperty['name']);
|
||||
|
||||
$propertyName = $tagName;
|
||||
$propertyValue = [];
|
||||
$propertyParameters = [];
|
||||
$propertyType = 'text';
|
||||
|
||||
// A property which is not part of the standard.
|
||||
if ($namespace !== self::XCAL_NAMESPACE
|
||||
&& $namespace !== self::XCARD_NAMESPACE) {
|
||||
|
||||
$propertyName = 'xml';
|
||||
$value = '<' . $tagName . ' xmlns="' . $namespace . '"';
|
||||
|
||||
foreach ($xmlProperty['attributes'] as $attributeName => $attributeValue) {
|
||||
$value .= ' ' . $attributeName . '="' . str_replace('"', '\"', $attributeValue) . '"';
|
||||
}
|
||||
|
||||
$value .= '>' . $xmlProperty['value'] . '</' . $tagName . '>';
|
||||
|
||||
$propertyValue = [$value];
|
||||
|
||||
$this->createProperty(
|
||||
$parentComponent,
|
||||
$propertyName,
|
||||
$propertyParameters,
|
||||
$propertyType,
|
||||
$propertyValue
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// xCard group.
|
||||
if ($propertyName === 'group') {
|
||||
|
||||
if (!isset($xmlProperty['attributes']['name'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->pointer = &$xmlProperty['value'];
|
||||
$this->parseProperties(
|
||||
$parentComponent,
|
||||
strtoupper($xmlProperty['attributes']['name']) . '.'
|
||||
);
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
// Collect parameters.
|
||||
foreach ($xmlProperty['value'] as $i => $xmlPropertyChild) {
|
||||
|
||||
if (!is_array($xmlPropertyChild)
|
||||
|| 'parameters' !== static::getTagName($xmlPropertyChild['name']))
|
||||
continue;
|
||||
|
||||
$xmlParameters = $xmlPropertyChild['value'];
|
||||
|
||||
foreach ($xmlParameters as $xmlParameter) {
|
||||
|
||||
$propertyParameterValues = [];
|
||||
|
||||
foreach ($xmlParameter['value'] as $xmlParameterValues) {
|
||||
$propertyParameterValues[] = $xmlParameterValues['value'];
|
||||
}
|
||||
|
||||
$propertyParameters[static::getTagName($xmlParameter['name'])]
|
||||
= implode(',', $propertyParameterValues);
|
||||
|
||||
}
|
||||
|
||||
array_splice($xmlProperty['value'], $i, 1);
|
||||
|
||||
}
|
||||
|
||||
$propertyNameExtended = ($this->root instanceof VCalendar
|
||||
? 'xcal'
|
||||
: 'xcard') . ':' . $propertyName;
|
||||
|
||||
switch ($propertyNameExtended) {
|
||||
|
||||
case 'xcal:geo':
|
||||
$propertyType = 'float';
|
||||
$propertyValue['latitude'] = 0;
|
||||
$propertyValue['longitude'] = 0;
|
||||
|
||||
foreach ($xmlProperty['value'] as $xmlRequestChild) {
|
||||
$propertyValue[static::getTagName($xmlRequestChild['name'])]
|
||||
= $xmlRequestChild['value'];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'xcal:request-status':
|
||||
$propertyType = 'text';
|
||||
|
||||
foreach ($xmlProperty['value'] as $xmlRequestChild) {
|
||||
$propertyValue[static::getTagName($xmlRequestChild['name'])]
|
||||
= $xmlRequestChild['value'];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'xcal:freebusy':
|
||||
$propertyType = 'freebusy';
|
||||
// We don't break because we only want to set
|
||||
// another property type.
|
||||
|
||||
case 'xcal:categories':
|
||||
case 'xcal:resources':
|
||||
case 'xcal:exdate':
|
||||
foreach ($xmlProperty['value'] as $specialChild) {
|
||||
$propertyValue[static::getTagName($specialChild['name'])]
|
||||
= $specialChild['value'];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'xcal:rdate':
|
||||
$propertyType = 'date-time';
|
||||
|
||||
foreach ($xmlProperty['value'] as $specialChild) {
|
||||
|
||||
$tagName = static::getTagName($specialChild['name']);
|
||||
|
||||
if ('period' === $tagName) {
|
||||
|
||||
$propertyParameters['value'] = 'PERIOD';
|
||||
$propertyValue[] = implode('/', $specialChild['value']);
|
||||
|
||||
}
|
||||
else {
|
||||
$propertyValue[] = $specialChild['value'];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$propertyType = static::getTagName($xmlProperty['value'][0]['name']);
|
||||
|
||||
foreach ($xmlProperty['value'] as $value) {
|
||||
$propertyValue[] = $value['value'];
|
||||
}
|
||||
|
||||
if ('date' === $propertyType) {
|
||||
$propertyParameters['value'] = 'DATE';
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$this->createProperty(
|
||||
$parentComponent,
|
||||
$propertyNamePrefix . $propertyName,
|
||||
$propertyParameters,
|
||||
$propertyType,
|
||||
$propertyValue
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a component.
|
||||
*
|
||||
* @param Component $parentComponent
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function parseComponent(Component $parentComponent) {
|
||||
|
||||
$components = $this->pointer['value'] ?: [];
|
||||
|
||||
foreach ($components as $component) {
|
||||
|
||||
$componentName = static::getTagName($component['name']);
|
||||
$currentComponent = $this->root->createComponent(
|
||||
$componentName,
|
||||
null,
|
||||
false
|
||||
);
|
||||
|
||||
$this->pointer = &$component;
|
||||
$this->parseVCalendarComponents($currentComponent);
|
||||
|
||||
$parentComponent->add($currentComponent);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a property.
|
||||
*
|
||||
* @param Component $parentComponent
|
||||
* @param string $name
|
||||
* @param array $parameters
|
||||
* @param string $type
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function createProperty(Component $parentComponent, $name, $parameters, $type, $value) {
|
||||
|
||||
$property = $this->root->createProperty(
|
||||
$name,
|
||||
null,
|
||||
$parameters,
|
||||
$type
|
||||
);
|
||||
$parentComponent->add($property);
|
||||
$property->setXmlValue($value);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the input data.
|
||||
*
|
||||
* @param resource|string $input
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function setInput($input) {
|
||||
|
||||
if (is_resource($input)) {
|
||||
$input = stream_get_contents($input);
|
||||
}
|
||||
|
||||
if (is_string($input)) {
|
||||
|
||||
$reader = new SabreXml\Reader();
|
||||
$reader->elementMap['{' . self::XCAL_NAMESPACE . '}period']
|
||||
= 'Sabre\VObject\Parser\XML\Element\KeyValue';
|
||||
$reader->elementMap['{' . self::XCAL_NAMESPACE . '}recur']
|
||||
= 'Sabre\VObject\Parser\XML\Element\KeyValue';
|
||||
$reader->xml($input);
|
||||
$input = $reader->parse();
|
||||
|
||||
}
|
||||
|
||||
$this->input = $input;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tag name from a Clark notation.
|
||||
*
|
||||
* @param string $clarkedTagName
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function getTagName($clarkedTagName) {
|
||||
|
||||
list(, $tagName) = SabreXml\Service::parseClarkNotation($clarkedTagName);
|
||||
return $tagName;
|
||||
|
||||
}
|
||||
}
|
||||
70
vendor/sabre/vobject/lib/Parser/XML/Element/KeyValue.php
vendored
Normal file
70
vendor/sabre/vobject/lib/Parser/XML/Element/KeyValue.php
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace Sabre\VObject\Parser\XML\Element;
|
||||
|
||||
use Sabre\Xml as SabreXml;
|
||||
|
||||
/**
|
||||
* Our own sabre/xml key-value element.
|
||||
*
|
||||
* It just removes the clark notation.
|
||||
*
|
||||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Ivan Enderlin
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
class KeyValue extends SabreXml\Element\KeyValue {
|
||||
|
||||
/**
|
||||
* The deserialize method is called during xml parsing.
|
||||
*
|
||||
* This method is called staticly, this is because in theory this method
|
||||
* may be used as a type of constructor, or factory method.
|
||||
*
|
||||
* Often you want to return an instance of the current class, but you are
|
||||
* free to return other data as well.
|
||||
*
|
||||
* Important note 2: You are responsible for advancing the reader to the
|
||||
* next element. Not doing anything will result in a never-ending loop.
|
||||
*
|
||||
* If you just want to skip parsing for this element altogether, you can
|
||||
* just call $reader->next();
|
||||
*
|
||||
* $reader->parseInnerTree() will parse the entire sub-tree, and advance to
|
||||
* the next element.
|
||||
*
|
||||
* @param XML\Reader $reader
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
static function xmlDeserialize(SabreXml\Reader $reader) {
|
||||
|
||||
// If there's no children, we don't do anything.
|
||||
if ($reader->isEmptyElement) {
|
||||
$reader->next();
|
||||
return [];
|
||||
}
|
||||
|
||||
$values = [];
|
||||
$reader->read();
|
||||
|
||||
do {
|
||||
|
||||
if ($reader->nodeType === SabreXml\Reader::ELEMENT) {
|
||||
|
||||
$name = $reader->localName;
|
||||
$values[$name] = $reader->parseCurrentElement()['value'];
|
||||
|
||||
} else {
|
||||
$reader->read();
|
||||
}
|
||||
|
||||
} while ($reader->nodeType !== SabreXml\Reader::END_ELEMENT);
|
||||
|
||||
$reader->read();
|
||||
|
||||
return $values;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user