ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
VCardConverter.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Sabre\VObject;
4 
13 
32  function convert(Component\VCard $input, $targetVersion) {
33 
34  $inputVersion = $input->getDocumentType();
35  if ($inputVersion === $targetVersion) {
36  return clone $input;
37  }
38 
39  if (!in_array($inputVersion, [Document::VCARD21, Document::VCARD30, Document::VCARD40])) {
40  throw new \InvalidArgumentException('Only vCard 2.1, 3.0 and 4.0 are supported for the input data');
41  }
42  if (!in_array($targetVersion, [Document::VCARD30, Document::VCARD40])) {
43  throw new \InvalidArgumentException('You can only use vCard 3.0 or 4.0 for the target version');
44  }
45 
46  $newVersion = $targetVersion === Document::VCARD40 ? '4.0' : '3.0';
47 
48  $output = new Component\VCard([
49  'VERSION' => $newVersion,
50  ]);
51 
52  // We might have generated a default UID. Remove it!
53  unset($output->UID);
54 
55  foreach ($input->children() as $property) {
56 
57  $this->convertProperty($input, $output, $property, $targetVersion);
58 
59  }
60 
61  return $output;
62 
63  }
64 
75  protected function convertProperty(Component\VCard $input, Component\VCard $output, Property $property, $targetVersion) {
76 
77  // Skipping these, those are automatically added.
78  if (in_array($property->name, ['VERSION', 'PRODID'])) {
79  return;
80  }
81 
82  $parameters = $property->parameters();
83  $valueType = null;
84  if (isset($parameters['VALUE'])) {
85  $valueType = $parameters['VALUE']->getValue();
86  unset($parameters['VALUE']);
87  }
88  if (!$valueType) {
89  $valueType = $property->getValueType();
90  }
91  $newProperty = $output->createProperty(
92  $property->name,
93  $property->getParts(),
94  [], // parameters will get added a bit later.
95  $valueType
96  );
97 
98 
99  if ($targetVersion === Document::VCARD30) {
100 
101  if ($property instanceof Property\Uri && in_array($property->name, ['PHOTO', 'LOGO', 'SOUND'])) {
102 
103  $newProperty = $this->convertUriToBinary($output, $newProperty);
104 
105  } elseif ($property instanceof Property\VCard\DateAndOrTime) {
106 
107  // In vCard 4, the birth year may be optional. This is not the
108  // case for vCard 3. Apple has a workaround for this that
109  // allows applications that support Apple's extension still
110  // omit birthyears in vCard 3, but applications that do not
111  // support this, will just use a random birthyear. We're
112  // choosing 1604 for the birthyear, because that's what apple
113  // uses.
114  $parts = DateTimeParser::parseVCardDateTime($property->getValue());
115  if (is_null($parts['year'])) {
116  $newValue = '1604-' . $parts['month'] . '-' . $parts['date'];
117  $newProperty->setValue($newValue);
118  $newProperty['X-APPLE-OMIT-YEAR'] = '1604';
119  }
120 
121  if ($newProperty->name == 'ANNIVERSARY') {
122  // Microsoft non-standard anniversary
123  $newProperty->name = 'X-ANNIVERSARY';
124 
125  // We also need to add a new apple property for the same
126  // purpose. This apple property needs a 'label' in the same
127  // group, so we first need to find a groupname that doesn't
128  // exist yet.
129  $x = 1;
130  while ($output->select('ITEM' . $x . '.')) {
131  $x++;
132  }
133  $output->add('ITEM' . $x . '.X-ABDATE', $newProperty->getValue(), ['VALUE' => 'DATE-AND-OR-TIME']);
134  $output->add('ITEM' . $x . '.X-ABLABEL', '_$!<Anniversary>!$_');
135  }
136 
137  } elseif ($property->name === 'KIND') {
138 
139  switch (strtolower($property->getValue())) {
140  case 'org' :
141  // vCard 3.0 does not have an equivalent to KIND:ORG,
142  // but apple has an extension that means the same
143  // thing.
144  $newProperty = $output->createProperty('X-ABSHOWAS', 'COMPANY');
145  break;
146 
147  case 'individual' :
148  // Individual is implicit, so we skip it.
149  return;
150 
151  case 'group' :
152  // OS X addressbook property
153  $newProperty = $output->createProperty('X-ADDRESSBOOKSERVER-KIND', 'GROUP');
154  break;
155  }
156 
157 
158  }
159 
160  } elseif ($targetVersion === Document::VCARD40) {
161 
162  // These properties were removed in vCard 4.0
163  if (in_array($property->name, ['NAME', 'MAILER', 'LABEL', 'CLASS'])) {
164  return;
165  }
166 
167  if ($property instanceof Property\Binary) {
168 
169  $newProperty = $this->convertBinaryToUri($output, $newProperty, $parameters);
170 
171  } elseif ($property instanceof Property\VCard\DateAndOrTime && isset($parameters['X-APPLE-OMIT-YEAR'])) {
172 
173  // If a property such as BDAY contained 'X-APPLE-OMIT-YEAR',
174  // then we're stripping the year from the vcard 4 value.
175  $parts = DateTimeParser::parseVCardDateTime($property->getValue());
176  if ($parts['year'] === $property['X-APPLE-OMIT-YEAR']->getValue()) {
177  $newValue = '--' . $parts['month'] . '-' . $parts['date'];
178  $newProperty->setValue($newValue);
179  }
180 
181  // Regardless if the year matched or not, we do need to strip
182  // X-APPLE-OMIT-YEAR.
183  unset($parameters['X-APPLE-OMIT-YEAR']);
184 
185  }
186  switch ($property->name) {
187  case 'X-ABSHOWAS' :
188  if (strtoupper($property->getValue()) === 'COMPANY') {
189  $newProperty = $output->createProperty('KIND', 'ORG');
190  }
191  break;
192  case 'X-ADDRESSBOOKSERVER-KIND' :
193  if (strtoupper($property->getValue()) === 'GROUP') {
194  $newProperty = $output->createProperty('KIND', 'GROUP');
195  }
196  break;
197  case 'X-ANNIVERSARY' :
198  $newProperty->name = 'ANNIVERSARY';
199  // If we already have an anniversary property with the same
200  // value, ignore.
201  foreach ($output->select('ANNIVERSARY') as $anniversary) {
202  if ($anniversary->getValue() === $newProperty->getValue()) {
203  return;
204  }
205  }
206  break;
207  case 'X-ABDATE' :
208  // Find out what the label was, if it exists.
209  if (!$property->group) {
210  break;
211  }
212  $label = $input->{$property->group . '.X-ABLABEL'};
213 
214  // We only support converting anniversaries.
215  if (!$label || $label->getValue() !== '_$!<Anniversary>!$_') {
216  break;
217  }
218 
219  // If we already have an anniversary property with the same
220  // value, ignore.
221  foreach ($output->select('ANNIVERSARY') as $anniversary) {
222  if ($anniversary->getValue() === $newProperty->getValue()) {
223  return;
224  }
225  }
226  $newProperty->name = 'ANNIVERSARY';
227  break;
228  // Apple's per-property label system.
229  case 'X-ABLABEL' :
230  if ($newProperty->getValue() === '_$!<Anniversary>!$_') {
231  // We can safely remove these, as they are converted to
232  // ANNIVERSARY properties.
233  return;
234  }
235  break;
236 
237  }
238 
239  }
240 
241  // set property group
242  $newProperty->group = $property->group;
243 
244  if ($targetVersion === Document::VCARD40) {
245  $this->convertParameters40($newProperty, $parameters);
246  } else {
247  $this->convertParameters30($newProperty, $parameters);
248  }
249 
250  // Lastly, we need to see if there's a need for a VALUE parameter.
251  //
252  // We can do that by instantating a empty property with that name, and
253  // seeing if the default valueType is identical to the current one.
254  $tempProperty = $output->createProperty($newProperty->name);
255  if ($tempProperty->getValueType() !== $newProperty->getValueType()) {
256  $newProperty['VALUE'] = $newProperty->getValueType();
257  }
258 
259  $output->add($newProperty);
260 
261 
262  }
263 
276  protected function convertBinaryToUri(Component\VCard $output, Property\Binary $newProperty, array &$parameters) {
277 
278  $value = $newProperty->getValue();
279  $newProperty = $output->createProperty(
280  $newProperty->name,
281  null, // no value
282  [], // no parameters yet
283  'URI' // Forcing the BINARY type
284  );
285 
286  $mimeType = 'application/octet-stream';
287 
288  // See if we can find a better mimetype.
289  if (isset($parameters['TYPE'])) {
290 
291  $newTypes = [];
292  foreach ($parameters['TYPE']->getParts() as $typePart) {
293  if (in_array(
294  strtoupper($typePart),
295  ['JPEG', 'PNG', 'GIF']
296  )) {
297  $mimeType = 'image/' . strtolower($typePart);
298  } else {
299  $newTypes[] = $typePart;
300  }
301  }
302 
303  // If there were any parameters we're not converting to a
304  // mime-type, we need to keep them.
305  if ($newTypes) {
306  $parameters['TYPE']->setParts($newTypes);
307  } else {
308  unset($parameters['TYPE']);
309  }
310 
311  }
312 
313  $newProperty->setValue('data:' . $mimeType . ';base64,' . base64_encode($value));
314  return $newProperty;
315 
316  }
317 
330  protected function convertUriToBinary(Component\VCard $output, Property\Uri $newProperty) {
331 
332  $value = $newProperty->getValue();
333 
334  // Only converting data: uris
335  if (substr($value, 0, 5) !== 'data:') {
336  return $newProperty;
337  }
338 
339  $newProperty = $output->createProperty(
340  $newProperty->name,
341  null, // no value
342  [], // no parameters yet
343  'BINARY'
344  );
345 
346  $mimeType = substr($value, 5, strpos($value, ',') - 5);
347  if (strpos($mimeType, ';')) {
348  $mimeType = substr($mimeType, 0, strpos($mimeType, ';'));
349  $newProperty->setValue(base64_decode(substr($value, strpos($value, ',') + 1)));
350  } else {
351  $newProperty->setValue(substr($value, strpos($value, ',') + 1));
352  }
353  unset($value);
354 
355  $newProperty['ENCODING'] = 'b';
356  switch ($mimeType) {
357 
358  case 'image/jpeg' :
359  $newProperty['TYPE'] = 'JPEG';
360  break;
361  case 'image/png' :
362  $newProperty['TYPE'] = 'PNG';
363  break;
364  case 'image/gif' :
365  $newProperty['TYPE'] = 'GIF';
366  break;
367 
368  }
369 
370 
371  return $newProperty;
372 
373  }
374 
383  protected function convertParameters40(Property $newProperty, array $parameters) {
384 
385  // Adding all parameters.
386  foreach ($parameters as $param) {
387 
388  // vCard 2.1 allowed parameters with no name
389  if ($param->noName) $param->noName = false;
390 
391  switch ($param->name) {
392 
393  // We need to see if there's any TYPE=PREF, because in vCard 4
394  // that's now PREF=1.
395  case 'TYPE' :
396  foreach ($param->getParts() as $paramPart) {
397 
398  if (strtoupper($paramPart) === 'PREF') {
399  $newProperty->add('PREF', '1');
400  } else {
401  $newProperty->add($param->name, $paramPart);
402  }
403 
404  }
405  break;
406  // These no longer exist in vCard 4
407  case 'ENCODING' :
408  case 'CHARSET' :
409  break;
410 
411  default :
412  $newProperty->add($param->name, $param->getParts());
413  break;
414 
415  }
416 
417  }
418 
419  }
420 
429  protected function convertParameters30(Property $newProperty, array $parameters) {
430 
431  // Adding all parameters.
432  foreach ($parameters as $param) {
433 
434  // vCard 2.1 allowed parameters with no name
435  if ($param->noName) $param->noName = false;
436 
437  switch ($param->name) {
438 
439  case 'ENCODING' :
440  // This value only existed in vCard 2.1, and should be
441  // removed for anything else.
442  if (strtoupper($param->getValue()) !== 'QUOTED-PRINTABLE') {
443  $newProperty->add($param->name, $param->getParts());
444  }
445  break;
446 
447  /*
448  * Converting PREF=1 to TYPE=PREF.
449  *
450  * Any other PREF numbers we'll drop.
451  */
452  case 'PREF' :
453  if ($param->getValue() == '1') {
454  $newProperty->add('TYPE', 'PREF');
455  }
456  break;
457 
458  default :
459  $newProperty->add($param->name, $param->getParts());
460  break;
461 
462  }
463 
464  }
465 
466  }
467 }
This utility converts vcards from one version to another.
if($argc< 3) $input
URI property.
Definition: Uri.php:17
convertUriToBinary(Component\VCard $output, Property\Uri $newProperty)
Converts a URI property to a BINARY property.
convert(Component\VCard $input, $targetVersion)
Converts a vCard object to a new version.
getValueType()
Returns the type of value.
getParts()
Returns a multi-valued property.
Definition: Property.php:152
BINARY property.
Definition: Binary.php:21
add($name, $value=null)
Adds a new parameter.
Definition: Property.php:174
const VCARD30
vCard 3.0.
Definition: Document.php:44
convertParameters30(Property $newProperty, array $parameters)
Adds parameters to a new property for vCard 3.0.
parameters()
Returns an iterable list of children.
Definition: Property.php:196
convertParameters40(Property $newProperty, array $parameters)
Adds parameters to a new property for vCard 4.0.
convertBinaryToUri(Component\VCard $output, Property\Binary $newProperty, array &$parameters)
Converts a BINARY property to a URI property.
getValue()
Returns the current value.
Definition: Property.php:115
const VCARD21
vCard 2.1.
Definition: Document.php:39
const VCARD40
vCard 4.0.
Definition: Document.php:49
convertProperty(Component\VCard $input, Component\VCard $output, Property $property, $targetVersion)
Handles conversion of a single property.
The VCard component.
Definition: VCard.php:18
$x
Definition: complexTest.php:9
static parseVCardDateTime($date)
This method parses a vCard date and or time value.