ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
VCardConverter.php
Go to the documentation of this file.
1<?php
2
3namespace 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}
An exception for terminatinating execution or to throw for unit testing.
The VCard component.
Definition: VCard.php:18
static parseVCardDateTime($date)
This method parses a vCard date and or time value.
const VCARD30
vCard 3.0.
Definition: Document.php:44
const VCARD21
vCard 2.1.
Definition: Document.php:39
const VCARD40
vCard 4.0.
Definition: Document.php:49
BINARY property.
Definition: Binary.php:21
URI property.
Definition: Uri.php:17
parameters()
Returns an iterable list of children.
Definition: Property.php:196
getValueType()
Returns the type of value.
getParts()
Returns a multi-valued property.
Definition: Property.php:152
add($name, $value=null)
Adds a new parameter.
Definition: Property.php:174
getValue()
Returns the current value.
Definition: Property.php:115
This utility converts vcards from one version to another.
convertUriToBinary(Component\VCard $output, Property\Uri $newProperty)
Converts a URI property to a BINARY property.
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.
convertProperty(Component\VCard $input, Component\VCard $output, Property $property, $targetVersion)
Handles conversion of a single property.
convertParameters30(Property $newProperty, array $parameters)
Adds parameters to a new property for vCard 3.0.
convert(Component\VCard $input, $targetVersion)
Converts a vCard object to a new version.
$x
Definition: complexTest.php:9
foreach($paths as $path) if($argc< 3) $input