From bcd130ea21e1cde0b575f2053518bd0d8e9062bc Mon Sep 17 00:00:00 2001 From: PierreLebedel Date: Fri, 25 Oct 2024 14:34:45 +0200 Subject: [PATCH] restrict vcard fields by version --- src/VCard.php | 106 +++++++++++++++++++++++++++++++++++++++++--- src/VCardField.php | 38 +++++++++------- src/VCardParser.php | 14 +++--- 3 files changed, 131 insertions(+), 27 deletions(-) diff --git a/src/VCard.php b/src/VCard.php index 5667437..7a36aba 100644 --- a/src/VCard.php +++ b/src/VCard.php @@ -8,21 +8,117 @@ class VCard { + public ?string $version = null; + public stdClass $formattedData; public stdClass $rawData; - public stdClass $unexpectedData; + public stdClass $invalidData; + + public stdClass $unprocessedData; public function __construct() { - $this->formattedData = new stdClass(); + $this->formattedData = new stdClass; $this->rawData = new stdClass; - $this->unexpectedData = new stdClass; + $this->invalidData = new stdClass; + $this->unprocessedData = new stdClass; + } + + public function setVersion(string $version): self + { + $this->version = $version; + $this->initVersionData(); + + return $this; } - public function getVersion(): string + public function getVersion(): ?string { - return $this->formattedData->version ?? '4.0'; + return $this->version; + } + + public function initVersionData(): self + { + if (! $this->version) { + return $this; + } + + $dataFields = [ + 'fn' => 'fullName', + 'n' => 'name', + 'adr' => 'addresses', + 'bday' => 'birthday', + 'email' => 'emails', + 'geo' => 'geo', + 'key' => 'key', + 'logo' => 'logo', + 'n' => 'name', + 'note' => 'note', + 'org' => 'organization', + 'photo' => 'photo', + 'rev' => 'revision', + 'role' => 'role', + 'sound' => 'sound', + 'tel' => 'phones', + 'title' => 'title', + 'tz' => 'timezone', + 'uid' => 'uid', + 'url' => 'url', + 'version' => 'version', + ]; + + if ($this->version == '2.1') { + $dataFields += [ + 'agent' => 'agent', + 'label' => 'label', + 'lang' => 'lang', + 'mailer' => 'mailer', + ]; + + } elseif ($this->version == '3.0') { + $dataFields += [ + 'agent' => 'agent', + 'categories' => 'categories', + 'class' => 'class', + 'impp' => 'impp', + 'label' => 'label', + 'mailer' => 'mailer', + 'name' => 'name', + 'nickname' => 'nicknames', + 'prodid' => 'prodid', + 'profile' => 'profile', + 'sort-string' => 'sort-string', + 'source' => 'source', + ]; + + } elseif ($this->version == '4.0') { + $dataFields += [ + 'anniversary' => 'anniversary', + 'caladruri' => 'caladruri', + 'caluri' => 'caluri', + 'categories' => 'categories', + 'clientpidmap' => 'clientpidmap', + 'fburl' => 'fburl', + 'gender' => 'gender', + 'impp' => 'impp', + 'kind' => 'kind', + 'lang' => 'langs', + 'member' => 'member', + 'nickname' => 'nicknames', + 'prodid' => 'prodid', + 'related' => 'related', + 'source' => 'source', + 'xml' => 'xml', + ]; + } + + foreach ($dataFields as $field => $alias) { + $this->formattedData->{$alias} = null; + $this->rawData->{$field} = null; + } + + return $this; } } diff --git a/src/VCardField.php b/src/VCardField.php index cffe4f4..97e7ec7 100644 --- a/src/VCardField.php +++ b/src/VCardField.php @@ -30,7 +30,7 @@ class VCardField protected $isMultiple = false; - protected $isUnexpected = false; + protected $isUnprocessed = false; public function __construct(public string $rawContents) { @@ -87,15 +87,6 @@ protected function parseAttributes() $this->attributes = $newAttributes; } - public function version(): self - { - $this->isString = true; - $this->formattedValue = $this->value; - $this->rawValue = $this->value; - - return $this; - } - public function string(): self { $this->isString = true; @@ -237,9 +228,10 @@ public function timezone(): self return $this; } - public function as(string $formattedName) :self + public function as(string $formattedName): self { $this->formattedName = $formattedName; + return $this; } @@ -254,8 +246,8 @@ public function in(array $stringPossibilities): self public function addAttribute(string $attribute, array $constrainedBy = []): self { - if($attribute=='type' && array_key_exists('type', $this->attributes)){ - if(in_array('pref', array_map('strtolower', $this->attributes['type']))){ + if ($attribute == 'type' && array_key_exists('type', $this->attributes)) { + if (in_array('pref', array_map('strtolower', $this->attributes['type']))) { $this->formattedValue->attributes['pref'] = 1; } } @@ -296,17 +288,29 @@ public function addAttribute(string $attribute, array $constrainedBy = []): self return $this; } - public function unexpected(): self + public function unprocecced(): self { - $this->isUnexpected = true; + $this->isUnprocessed = true; return $this; } public function render(VCard $vCard) { - if ($this->isUnexpected) { - $vCard->unexpectedData->{$this->name} = $this->rawContents; + if ($this->isUnprocessed) { + $vCard->unprocessedData->{$this->name} = $this->rawContents; + + return; + } + + if (! property_exists($vCard->rawData, $this->name)) { + $vCard->invalidData->{$this->name} = $this->rawContents; + + return; + } + + if (! property_exists($vCard->formattedData, $this->formattedName)) { + $vCard->invalidData->{$this->name} = '[formatted] '.$this->rawContents; return; } diff --git a/src/VCardParser.php b/src/VCardParser.php index 380507b..22c100e 100644 --- a/src/VCardParser.php +++ b/src/VCardParser.php @@ -207,28 +207,32 @@ protected function parseLine(int $lineNumber, string $lineContents): void 'name', 'units1', 'units2', - ])->addAttribute('type'), + ])->addAttribute('type')->as('organization'), 'photo' => $field->uri()->addAttribute('type'), 'prodid' => $field->string(), 'profile' => $field->string(), 'related' => $field->uri()->addAttribute('type'), - 'rev' => $field->datetime(), + 'rev' => $field->datetime()->as('revision'), 'role' => $field->string()->addAttribute('type'), 'sort-string' => $field->string(), 'sound' => $field->uri()->addAttribute('type'), 'source' => $field->uri(), 'tel' => $field->object()->multiple()->addAttribute('type', ['home', 'msg', 'work', 'pref', 'voice', 'fax', 'cell', 'video', 'pager', 'bbs', 'modem', 'car', 'isdn', 'pcs'])->as('phones'), 'title' => $field->string()->addAttribute('type'), - 'tz' => $field->timezone()->addAttribute('type'), + 'tz' => $field->timezone()->addAttribute('type')->as('timezone'), 'uid' => $field->string()->ltrim(['urn:uuid:']), 'url' => $field->uri()->addAttribute('type'), - 'version' => $field->version(), + 'version' => $field->string(), 'xml' => $field->string(), - default => $field->unexpected(), + default => $field->unprocecced(), }; //dump($field); + if ($field->name == 'version') { + $this->getVCard()->setVersion($field->value); + } + $field->render($this->getVCard()); } }