109 if (!in_array(
$charset, self::$SUPPORTED_CHARSETS)) {
110 throw new \InvalidArgumentException(
'Unsupported encoding. (Supported encodings: ' . implode(
', ', self::$SUPPORTED_CHARSETS) .
')');
126 $this->lineIndex = 0;
127 $this->startLine = 0;
135 } elseif (is_resource(
$input)) {
138 throw new \InvalidArgumentException(
'This parser can only read from strings or streams.');
154 if (3 <= strlen($line)
155 && ord($line[0]) === 0xef
156 && ord($line[1]) === 0xbb
157 && ord($line[2]) === 0xbf) {
158 $line = substr($line, 3);
161 switch (strtoupper($line)) {
162 case 'BEGIN:VCALENDAR' :
169 throw new ParseException(
'This parser only supports VCARD and VCALENDAR files');
172 $this->root =
new $class([],
false);
178 if (strtoupper(substr($line, 0, 4)) ===
'END:') {
188 $name = strtoupper(substr($line, 4));
189 if (
$name !== $this->root->name) {
190 throw new ParseException(
'Invalid MimeDir file. expected: "END:' . $this->root->name .
'" got: "END:' .
$name .
'"');
206 if (strtoupper(substr($line, 0, 6)) ===
'BEGIN:') {
208 $component = $this->root->createComponent(substr($line, 6), [],
false);
214 if (strtoupper(substr($line, 0, 4)) ===
'END:') {
224 $name = strtoupper(substr($line, 4));
225 if (
$name !== $component->name) {
226 throw new ParseException(
'Invalid MimeDir file. expected: "END:' . $component->name .
'" got: "END:' .
$name .
'"');
286 if (!\is_null($this->lineBuffer)) {
288 $this->lineBuffer = null;
291 $eof = \feof($this->
input);
296 throw new EofException(
'End of document reached prematurely');
312 $nextLine = \rtrim(\fgets($this->
input),
"\r\n");
317 if ($nextLine[0] ===
"\t" || $nextLine[0] ===
" ") {
318 $curLine = \substr($nextLine, 1);
322 $this->lineBuffer = $nextLine;
339 if ($this->options & self::OPTION_FORGIVING) {
340 $propNameToken =
'A-Z0-9\-\._\\/';
342 $propNameToken =
'A-Z0-9\-\.';
345 $paramNameToken =
'A-Z0-9\-';
350 ^(?P<name> [$propNameToken]+ ) (?=[;:]) # property name 352 (?<=:)(?P<propValue> .+)$ # property value 354 ;(?P<paramName> [$paramNameToken]+) (?=[=;:]) # parameter name 356 (=|,)(?P<paramValue> # parameter value 358 \"(?: [$qSafeChar]+)\" 363 preg_match_all($regex, $line, $matches, PREG_SET_ORDER);
380 foreach ($matches as $match) {
382 if (isset($match[
'paramValue'])) {
383 if ($match[
'paramValue'] && $match[
'paramValue'][0] ===
'"') {
384 $value = substr($match[
'paramValue'], 1, -1);
386 $value = $match[
'paramValue'];
391 if (is_null($lastParam)) {
392 throw new ParseException(
'Invalid Mimedir file. Line starting at ' . $this->startLine .
' did not follow iCalendar/vCard conventions');
394 if (is_null($property[
'parameters'][$lastParam])) {
395 $property[
'parameters'][$lastParam] = $value;
396 } elseif (is_array($property[
'parameters'][$lastParam])) {
397 $property[
'parameters'][$lastParam][] = $value;
399 $property[
'parameters'][$lastParam] = [
400 $property[
'parameters'][$lastParam],
406 if (isset($match[
'paramName'])) {
407 $lastParam = strtoupper($match[
'paramName']);
408 if (!isset($property[
'parameters'][$lastParam])) {
409 $property[
'parameters'][$lastParam] = null;
413 if (isset($match[
'propValue'])) {
414 $property[
'value'] = $match[
'propValue'];
417 if (isset($match[
'name']) && $match[
'name']) {
418 $property[
'name'] = strtoupper($match[
'name']);
423 throw new \LogicException(
'This code should not be reachable');
428 if (is_null($property[
'value'])) {
429 $property[
'value'] =
'';
431 if (!$property[
'name']) {
432 if ($this->options & self::OPTION_IGNORE_INVALID_LINES) {
435 throw new ParseException(
'Invalid Mimedir file. Line starting at ' . $this->startLine .
' did not follow iCalendar/vCard conventions');
443 $namedParameters = [];
444 $namelessParameters = [];
446 foreach ($property[
'parameters'] as
$name => $value) {
447 if (!is_null($value)) {
448 $namedParameters[
$name] = $value;
450 $namelessParameters[] =
$name;
454 $propObj = $this->root->createProperty($property[
'name'], null, $namedParameters);
456 foreach ($namelessParameters as $namelessParameter) {
457 $propObj->add(null, $namelessParameter);
460 if (strtoupper($propObj[
'ENCODING']) ===
'QUOTED-PRINTABLE') {
464 if ($this->root->getDocumentType() ===
Document::VCARD21 && isset($propObj[
'CHARSET'])) {
466 $charset = (string)$propObj[
'CHARSET'];
472 $property[
'value'] = utf8_encode($property[
'value']);
474 case 'windows-1252' :
475 $property[
'value'] = mb_convert_encoding($property[
'value'],
'UTF-8',
$charset);
478 throw new ParseException(
'Unsupported CHARSET: ' . $propObj[
'CHARSET']);
480 $propObj->setRawMimeDirValue($property[
'value']);
551 $regex =
'# (?: (\\\\ (?: \\\\ | N | n | ; | , ) )';
557 $matches = preg_split($regex,
$input, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
562 foreach ($matches as $match) {
632 preg_replace_callback(
635 switch ($matches[2]) {
668 (?: [^:])+ # Anything but a colon 669 (?: "[^"]")* # A parameter in double quotes 670 : # start of the value we really care about 674 preg_match($regex, $this->rawLine, $matches);
676 $value = $matches[1];
679 $value = str_replace(
"\n ",
"\n", $value);
684 if ($this->options & self::OPTION_FORGIVING) {
685 while (substr($value, -1) ===
'=') {
$lineIndex
The real current line number.
setInput($input)
Sets the input buffer.
parse($input=null, $options=0)
Parses an iCalendar or vCard file.
parseDocument()
Parses an entire document.
unescapeParam($input)
Unescapes a parameter value.
static $SUPPORTED_CHARSETS
The list of character sets we support when decoding.
$stream
PHP stream implementation.
readProperty($line)
Reads a property or component from a line.
setCharset($charset)
By default all input will be assumed to be UTF-8.
extractQuotedPrintableValue()
Gets the full quoted printable value.
readLine()
Reads a single line from the buffer.
parseLine($line)
Parses a line, and if it hits a component, it will also attempt to parse the entire component...
Exception thrown by Reader if an invalid object was attempted to be parsed.
Exception thrown by parser when the end of the stream has been reached, before this was expected...
static unescapeValue($input, $delimiter=';')
Unescapes a property value.