commiting uncommited changes on live site
[weblabels.fsf.org.git] / crm.fsf.org / 20131203 / files / sites / all / modules-new / civicrm / packages / Contact / Vcard / Build.php
1 <?php
2 /**
3 * Build (create) and fetch vCard 2.1 and 3.0 text blocks.
4 *
5 * PHP versions 4 and 5
6 *
7 * LICENSE: This source file is subject to version 3.0 of the PHP license
8 * that is available through the world-wide-web at the following URI:
9 * http://www.php.net/license/3_0.txt. If you did not receive a copy of
10 * the PHP License and are unable to obtain it through the web, please
11 * send a note to license@php.net so we can mail you a copy immediately.
12 *
13 * @category File_Formats
14 * @package Contact_Vcard_Build
15 * @author Paul M. Jones <pjones@ciaweb.net>
16 * @copyright 1997-2007 The PHP Group
17 * @license http://www.php.net/license/3_0.txt PHP License 3.0
18 * @version CVS: $Id: Build.php,v 1.10 2007/11/19 01:22:27 till Exp $
19 * @link http://pear.php.net/package/Contact_Vcard_Build
20 */
21
22 // Part numbers for N components
23 define('VCARD_N_FAMILY', 0);
24 define('VCARD_N_GIVEN', 1);
25 define('VCARD_N_ADDL', 2);
26 define('VCARD_N_PREFIX', 3);
27 define('VCARD_N_SUFFIX', 4);
28
29 // Part numbers for ADR components
30 define('VCARD_ADR_POB', 0);
31 define('VCARD_ADR_EXTEND', 1);
32 define('VCARD_ADR_STREET', 2);
33 define('VCARD_ADR_LOCALITY', 3);
34 define('VCARD_ADR_REGION', 4);
35 define('VCARD_ADR_POSTCODE', 5);
36 define('VCARD_ADR_COUNTRY', 6);
37
38 // Part numbers for GEO components
39 define('VCARD_GEO_LAT', 0);
40 define('VCARD_GEO_LON', 1);
41
42 /**
43 * @ignore
44 */
45 require_once 'PEAR.php';
46
47 /**
48 * This class builds a single vCard (version 3.0 or 2.1).
49 *
50 * General note: we use the terms "set" "add" and "get" as function
51 * prefixes.
52 *
53 * "Set" means there is only one iteration of a component, and it has
54 * only one value repetition, so you set the whole thing at once.
55 *
56 * "Add" means eith multiple iterations of a component are allowed, or
57 * that there is only one iteration allowed but there can be multiple
58 * value repetitions, so you add iterations or repetitions to the current
59 * stack.
60 *
61 * "Get" returns the full vCard line for a single iteration.
62 *
63 * @category File_Formats
64 * @package Contact_Vcard_Build
65 * @author Paul M. Jones <pjones@ciaweb.net>
66 * @copyright 1997-2007 The PHP Group
67 * @license http://www.php.net/license/3_0.txt PHP License 3.0
68 * @version Release: 1.1.2
69 * @link http://pear.php.net/package/Contact_Vcard_Build
70 *
71 */
72 class Contact_Vcard_Build extends PEAR
73 {
74 /**
75 * Values for vCard components.
76 *
77 * @access public
78 * @var array
79 */
80 var $value = array();
81
82 /**
83 * Parameters for vCard components.
84 *
85 * @access public
86 * @var array
87 */
88 var $param = array();
89
90 /**
91 * Tracks which component (N, ADR, TEL, etc) value was last set or added.
92 * Used when adding parameters automatically to the proper component.
93 *
94 * @access public
95 * @var string
96 */
97 var $autoparam = null;
98
99 /**
100 * Constructor.
101 *
102 * @param string $version The vCard version to build; affects which
103 * parameters are allowed and which components
104 * are returned by fetch().
105 *
106 * @access public
107 * @return void
108 * @see Contact_Vcard_Build::fetch()
109 */
110 function Contact_Vcard_Build($version = '3.0')
111 {
112 $this->PEAR();
113 $this->setErrorHandling(PEAR_ERROR_PRINT);
114 $this->setVersion($version);
115 }
116
117 /**
118 * Prepares a string so it may be safely used as vCard values. DO
119 * NOT use this with binary encodings. Operates on text in-place;
120 * does not return a value. Recursively descends into arrays.
121 *
122 * Escapes a string so that...
123 * : => \;
124 * ; => \;
125 * , => \,
126 * newline => literal \n
127 *
128 * @param mixed &$text The string or array or strings to escape.
129 *
130 * @access public
131 * @return mixed Void on success, or a PEAR_Error object on failure.
132 */
133 function escape(&$text)
134 {
135 if (is_object($text)) {
136
137 $msg = 'The escape() method works only with string literals and arrays.';
138 return $this->raiseError($msg);
139
140 }
141 if (is_array($text)) {
142
143 foreach ($text as $key => $val) {
144 $this->escape($val);
145 $text[$key] = $val;
146 }
147 return;
148 }
149
150 /*
151 // escape colons not led by a backslash
152 $regex = '(?<!\\\\)(\:)';
153 $text = preg_replace("/$regex/i", "\\:", $text);
154
155 // escape semicolons not led by a backslash
156 $regex = '(?<!\\\\)(\;)';
157 $text = preg_replace("/$regex/i", "\\;", $text);
158
159 // escape commas not led by a backslash
160 $regex = '(?<!\\\\)(\,)';
161 $text = preg_replace("/$regex/i", "\\,", $text);
162
163 // escape newlines
164 $regex = '\\n';
165 $text = preg_replace("/$regex/i", "\\n", $text);
166 */
167
168 // combined (per note from Daniel Convissor)
169 $regex = '(?<!\\\\)([\:\;\,\\n])';
170 // changed as a possible fix for Outlook compatibility [CiviCRM]
171 $regex = '(?<!\\\\)([\;\\n])';
172 $text = preg_replace("/$regex/", '\\\$1', $text);
173
174 // fix http(s)\:// to http(s)://
175 $text = str_replace('http\://', 'http://', $text);
176 $text = str_replace('https\://', 'http://', $text);
177
178 return;
179 }
180
181 /**
182 * Adds a parameter value for a given component and parameter name.
183 *
184 * Note that although vCard 2.1 allows you to specify a parameter
185 * value without a name (e.g., "HOME" instead of "TYPE=HOME") this
186 * class is not so lenient. ;-) You must specify a parameter name
187 * (TYPE, ENCODING, etc) when adding a parameter. Call multiple
188 * times if you want to add multiple values to the same parameter.
189 * E.g.:
190 *
191 * $vcard = new Contact_Vcard_Build();
192 *
193 * // set "TYPE=HOME,PREF" for the first TEL component
194 * $vcard->addParam('TYPE', 'HOME', 'TEL', 0);
195 * $vcard->addParam('TYPE', 'PREF', 'TEL', 0);
196 *
197 * @param string $param_name The parameter name, such as TYPE, VALUE,
198 * or ENCODING.
199 * @param string $param_value The parameter value.
200 * @param string $comp The vCard component for which this is a
201 * paramter (ADR, TEL, etc). If null, will be
202 * the component that was last set or added-to.
203 * @param mixed $iter An integer vCard component iteration that this
204 * is a param for. E.g., if you have more than
205 * one ADR component, 0 refers to the first ADR,
206 * 1 to the second ADR, and so on. If null, the
207 * parameter will be added to the last component
208 * iteration available.
209 *
210 * @access public
211 * @return mixed Void on success, or a PEAR_Error object on failure.
212 */
213 function addParam($param_name, $param_value, $comp = null, $iter = null)
214 {
215 // if component is not specified, default to the last component
216 // that was set or added.
217 if ($comp === null) {
218 $comp = $this->autoparam;
219 }
220
221 // using a null iteration means the param should be associated
222 // with the latest/most-recent iteration of the selected
223 // component.
224 if ($iter === null) {
225 $iter = $this->countIter($comp) - 1;
226 }
227
228 // massage the text arguments
229 $comp = strtoupper(trim($comp));
230 $param_name = strtoupper(trim($param_name));
231 $param_value = trim($param_value);
232
233 if (! is_integer($iter) || $iter < 0) {
234
235 $msg = "$iter is not a valid iteration number for $comp; ";
236 $msg .= "must be a positive integer.";
237
238 return $this->raiseError($msg);
239
240 }
241
242 $result = $this->validateParam($param_name, $param_value, $comp, $iter);
243
244 if (PEAR::isError($result)) {
245 return $result;
246 }
247 $this->param[$comp][$iter][$param_name][] = $param_value;
248
249 }
250
251 /**
252 * Validates parameter names and values based on the vCard version
253 * (2.1 or 3.0).
254 *
255 * @param string $name The parameter name (e.g., TYPE or ENCODING).
256 * @param string $text The parameter value (e.g., HOME or BASE64).
257 * @param string $comp Optional, the component name (e.g., ADR or
258 * PHOTO). Only used for error messaging.
259 * @param string $iter Optional, the iteration of the component.
260 * Only used for error messaging.
261 *
262 * @access public
263 * @return mixed Boolean true if the parameter is valid, or a
264 * PEAR_Error object if not.
265 *
266 */
267 function validateParam($name, $text, $comp = null, $iter = null)
268 {
269 $name = strtoupper($name);
270 $text = strtoupper($text);
271
272 switch ($comp) {
273
274 case 'TEL':
275 case 'TEL;PREF;CELL':
276 case 'TEL;PREF;VOICE':
277 case 'TEL;PREF;FAX':
278 case 'EMAIL':
279 case 'ADR':
280 break;
281
282 default:
283 // all param values must have only the characters A-Z 0-9 and -.
284 if (preg_match('/[^a-zA-Z0-9\-]/i', $text)) {
285
286 $msg = "vCard [$comp] [$iter] [$name]: ";
287 $msg .= 'The parameter value may contain only ';
288 $msg .= 'a-z, A-Z, 0-9, and dashes (-).';
289
290 return $this->raiseError($msg);
291
292 }
293 break;
294 }
295
296 if ($this->value['VERSION'][0][0][0] == '2.1') {
297
298 // Validate against version 2.1 (pretty strict)
299
300 $types = array (
301 'DOM', 'INTL', 'POSTAL', 'PARCEL','HOME', 'WORK',
302 'PREF', 'VOICE', 'FAX', 'MSG', 'CELL', 'PAGER',
303 'BBS', 'MODEM', 'CAR', 'ISDN', 'VIDEO',
304 'AOL', 'APPLELINK', 'ATTMAIL', 'CIS', 'EWORLD',
305 'INTERNET', 'IBMMAIL', 'MCIMAIL',
306 'POWERSHARE', 'PRODIGY', 'TLX', 'X400',
307 'GIF', 'CGM', 'WMF', 'BMP', 'MET', 'PMB', 'DIB',
308 'PICT', 'TIFF', 'PDF', 'PS', 'JPEG', 'QTIME',
309 'MPEG', 'MPEG2', 'AVI',
310 'WAVE', 'AIFF', 'PCM',
311 'X509', 'PGP'
312 );
313
314 switch ($name) {
315
316 case 'TYPE':
317 if (! in_array($text, $types)) {
318 $msg = "vCard 2.1 [$comp] [$iter]: ";
319 $msg .= "$text is not a recognized TYPE.";
320
321 $result = $this->raiseError($msg);
322 } else {
323 $result = true;
324 }
325 break;
326
327 case 'ENCODING':
328 if ($text != '7BIT' &&
329 $text != '8BIT' &&
330 $text != 'BASE64' &&
331 $text != 'QUOTED-PRINTABLE') {
332 $msg = "vCard 2.1 [$comp] [$iter]: ";
333 $msg .= "$text is not a recognized ENCODING.";
334
335 $result = $this->raiseError($msg);
336 } else {
337 $result = true;
338 }
339 break;
340
341 case 'CHARSET':
342 // all charsets are OK
343 $result = true;
344 break;
345
346 case 'LANGUAGE':
347 // all languages are OK
348 $result = true;
349 break;
350
351 case 'VALUE':
352 if ($text != 'INLINE' &&
353 $text != 'CONTENT-ID' &&
354 $text != 'CID' &&
355 $text != 'URL' &&
356 $text != 'VCARD') {
357
358 $msg = "vCard 2.1 [$comp] [$iter]: ";
359 $msg .= "$text is not a recognized VALUE.";
360
361 $result = $this->raiseError($msg);
362 } else {
363 $result = true;
364 }
365 break;
366
367 default:
368 $msg = "vCard 2.1 [$comp] [$iter]: ";
369 $msg .= "$name is an unknown or invalid parameter name.";
370
371 return $this->raiseError($msg);
372 break;
373 }
374
375 } elseif ($this->value['VERSION'][0][0][0] == '3.0') {
376
377 // Validate against version 3.0 (pretty lenient)
378
379 switch ($name) {
380
381 case 'TYPE':
382 // all types are OK
383 $result = true;
384 break;
385
386 case 'LANGUAGE':
387 // all languages are OK
388 $result = true;
389 break;
390
391 case 'ENCODING':
392 if ($text != '8BIT' &&
393 $text != 'B') {
394
395 $msg = "vCard 3.0 [$comp] [$iter]: ";
396 $msg .= "The only allowed ENCODING";
397 $msg .= " parameters are 8BIT and B.";
398
399 $result = $this->raiseError($msg);
400 } else {
401 $result = true;
402 }
403 break;
404
405 case 'VALUE':
406 if ($text != 'BINARY' &&
407 $text != 'PHONE-NUMBER' &&
408 $text != 'TEXT' &&
409 $text != 'URI' &&
410 $text != 'UTC-OFFSET' &&
411 $text != 'VCARD') {
412
413 $msg = "vCard 3.0 [$comp] [$iter]: The only allowed VALUE ";
414 $msg .= "parameters are ";
415 $msg .= "BINARY, PHONE-NUMBER, TEXT, URI, UTC-OFFSET,";
416 $msg .= " and VCARD.";
417
418 return $this->raiseError($msg);
419 }
420 $result = true;
421 break;
422
423 default:
424
425 $msg = "vCard 3.0 [$comp] [$iter]: ";
426 $msg .= "Unknown or invalid parameter name ($name).";
427
428 return $this->raiseError($msg);
429 break;
430 }
431
432 } else {
433
434 $msg = "[$comp] [$iter] Unknown vCard version number or other error.";
435 return $this->raiseError($msg);
436
437 }
438
439 return $result;
440
441 }
442
443 /**
444 * Gets back the parameter string for a given component.
445 *
446 * @param string $comp The component to get parameters for
447 * (ADR, TEL, etc).
448 *
449 * @param int $iter The vCard component iteration to get the param
450 * list for. E.g., if you have more than one ADR component,
451 * 0 refers to the first ADR, 1 to the second ADR, and so on.
452 *
453 * @access public
454 * @return string
455 */
456 function getParam($comp, $iter = 0)
457 {
458 $comp = strtoupper($comp);
459 $text = '';
460
461 if (isset($this->param[$comp][$iter]) &&
462 is_array($this->param[$comp][$iter])) {
463
464 // loop through the array of parameters for
465 // the component
466
467 foreach ($this->param[$comp][$iter] as $param_name => $param_val) {
468
469 // if there were previous parameter names, separate with
470 // a semicolon
471 if ($text != '') {
472 $text .= ';';
473 }
474
475 if ($param_val === null) {
476
477 // no parameter value was specified, which is typical
478 // for vCard version 2.1 -- the name is the value.
479 $this->escape($param_name);
480 $text .= $param_name;
481
482 } else {
483 // set the parameter name...
484 $text .= strtoupper($param_name) . '=';
485
486 // ...then escape and comma-separate the parameter
487 // values.
488 $this->escape($param_val);
489 $text .= implode(',', $param_val);
490 }
491 }
492 }
493
494 // if there were no parameters, this will be blank.
495 return $text;
496 }
497
498
499 /**
500 * Resets the vCard values and params to be blank.
501 *
502 * @param string $version The vCard version to reset to ('2.1' or
503 * '3.0' -- default is the same version as
504 * previously set).
505 *
506 * @access public
507 * @return void
508 */
509 function reset($version = null)
510 {
511 $prev = $this->value['VERSION'][0][0][0];
512
513 $this->value = array();
514 $this->param = array();
515 $this->autoparam = null;
516
517 if ($version === null) {
518 $this->setVersion($prev);
519 } else {
520 $this->setVersion($version);
521 }
522 }
523
524 /**
525 * Generic, all-purpose method to store a string or array in
526 * $this->value, in a way suitable for later output as a vCard
527 * element. This forces the value to be the passed text or array
528 * value, overriding any prior values.
529 *
530 * @param string $comp The component to set the value for ('N',
531 * 'ADR', etc).
532 * @param int $iter The component-iteration to set the value for.
533 * @param int $part The part number of the component-iteration to set
534 * the value for.
535 * @param mixed $text A string or array; the set of repeated values
536 * for this component-iteration part.
537 *
538 * @access public
539 * @return void
540 */
541 function setValue($comp, $iter, $part, $text)
542 {
543 $comp = strtoupper($comp);
544 settype($text, 'array');
545 $this->value[$comp][$iter][$part] = $text;
546 //mark this component as having been set.
547 $this->autoparam = $comp;
548 }
549
550 /**
551 * Generic, all-purpose method to add a repetition of a string or
552 * array in $this->value, in a way suitable for later output as a
553 * vCard element. This appends the value to be the passed text or
554 * array value, leaving any prior values in place.
555 *
556 * @param string $comp The component to set the value for ('N', 'ADR', etc).
557 * @param int $iter The component-iteration to set the value for.
558 * @param int $part The part number of the component-iteration to set
559 * the value for.
560 * @param mixed $text A string or array; the set of repeated values
561 * for this component-iteration part.
562 *
563 * @access public
564 * @return void
565 */
566 function addValue($comp, $iter, $part, $text)
567 {
568 $comp = strtoupper($comp);
569
570 settype($text, 'array');
571
572 foreach ($text as $val) {
573 $this->value[$comp][$iter][$part][] = $val;
574 }
575 $this->autoparam = $comp;
576 }
577
578 /**
579 * Generic, all-purpose method to get back the data stored in $this->value.
580 *
581 * @param string $comp The component to set the value for ('N',
582 * 'ADR', etc).
583 * @param int $iter The component-iteration to set the value for.
584 * @param int $part The part number of the component-iteration to get
585 * the value for.
586 * @param mixed $rept The repetition number within the part to get;
587 * if null, get all repetitions of the part within the
588 * iteration.
589 *
590 * @access public
591 * @return string The value, escaped and delimited, of all
592 * repetitions in the component-iteration part (or specific
593 * repetition within the part).
594 */
595 function getValue($comp, $iter = 0, $part = 0, $rept = null)
596 {
597 if ($rept === null &&
598 is_array($this->value[$comp][$iter][$part]) ) {
599
600 // get all repetitions of a part
601 $list = array();
602 foreach ($this->value[$comp][$iter][$part] as $key => $val) {
603 $list[] = trim($val);
604 }
605
606 $this->escape($list);
607 return implode(',', $list);
608
609 }
610
611 // get a specific repetition of a part
612 $text = trim($this->value[$comp][$iter][$part][$rept]);
613 $this->escape($text);
614 return $text;
615 }
616
617 /**
618 * Sets the full N component of the vCard. Will replace all other
619 * values. There can only be one N component per vCard.
620 *
621 * @param mixed $family Single (string) or multiple (array)
622 * family/last name.
623 * @param mixed $given Single (string) or multiple (array)
624 * given/first name.
625 * @param mixed $addl Single (string) or multiple (array)
626 * additional/middle name.
627 * @param mixed $prefix Single (string) or multiple (array) honorific
628 * prefix such as Mr., Miss, etc.
629 * @param mixed $suffix Single (string) or multiple (array) honorific
630 * suffix such as III, Jr., Ph.D., etc.
631 *
632 * @access public
633 * @return void
634 */
635 function setName($family, $given, $addl, $prefix, $suffix)
636 {
637 $this->autoparam = 'N';
638 $this->setValue('N', 0, VCARD_N_FAMILY, $family);
639 $this->setValue('N', 0, VCARD_N_GIVEN, $given);
640 $this->setValue('N', 0, VCARD_N_ADDL, $addl);
641 $this->setValue('N', 0, VCARD_N_PREFIX, $prefix);
642 $this->setValue('N', 0, VCARD_N_SUFFIX, $suffix);
643 }
644
645
646 /**
647 * Gets back the full N component (first iteration only, since there
648 * can only be one N component per vCard).
649 *
650 * @access public
651 * @return string The first N component-interation of the vCard.
652 */
653 function getName()
654 {
655 return $this->getMeta('N', 0) .
656 $this->getValue('N', 0, VCARD_N_FAMILY) . ';' .
657 $this->getValue('N', 0, VCARD_N_GIVEN) . ';' .
658 $this->getValue('N', 0, VCARD_N_ADDL) . ';' .
659 $this->getValue('N', 0, VCARD_N_PREFIX) . ';' .
660 $this->getValue('N', 0, VCARD_N_SUFFIX);
661 }
662
663 /**
664 * Sets the FN component of the card. If no text is passed as the
665 * FN value, constructs an FN automatically from N components. There
666 * is only one FN iteration per vCard.
667 *
668 * @param string $text Override the automatic generation of FN from N
669 * elements with the specified text.
670 *
671 * @access public
672 * @return mixed Void on success, or a PEAR_Error object on failure.
673 */
674 function setFormattedName($text = null)
675 {
676 $this->autoparam = 'FN';
677
678 if ($text !== null) {
679 $this->setValue('FN', 0, 0, $text);
680 return;
681 }
682
683 // no text was specified for the FN, so build it
684 // from the current N components if an N exists
685 if (is_array($this->value['N'])) {
686
687 // build from N.
688 // first (given) name, first iteration, first repetition
689 $text .= $this->getValue('N', 0, VCARD_N_GIVEN, 0);
690
691 // add a space after, if there was text
692 if ($text != '') {
693 $text .= ' ';
694 }
695
696 // last (family) name, first iteration, first repetition
697 $text .= $this->getValue('N', 0, VCARD_N_FAMILY, 0);
698
699 // add a space after, if there was text
700 if ($text != '') {
701 $text .= ' ';
702 }
703
704 // last-name suffix, first iteration, first repetition
705 $text .= $this->getValue('N', 0, VCARD_N_SUFFIX, 0);
706
707 $this->setValue('FN', 0, 0, $text);
708 return;
709 }
710
711 // no N exists, and no FN was set, so return.
712 $msg = 'FN not specified and N not set; cannot set FN.';
713 return $this->raiseError($msg);
714 }
715
716 /**
717 * Gets back the full FN component value. Only ever returns iteration
718 * zero, because only one FN component is allowed per vCard.
719 *
720 * @access public
721 * @uses self::getMeta()
722 * @return string The FN value of the vCard.
723 * @uses self::getMeta()
724 */
725 function getFormattedName()
726 {
727 return $this->getMeta('FN', 0) . $this->getValue('FN', 0, 0);
728 }
729
730 /**
731 * Sets the version of the the vCard. Only one iteration.
732 *
733 * @param string $text The text value of the verson text ('3.0' or '2.1').
734 *
735 * @access public
736 * @return mixed Void on success, or a PEAR_Error object on failure.
737 */
738 function setVersion($text = '3.0')
739 {
740 $this->autoparam = 'VERSION';
741 if ($text != '3.0' && $text != '2.1') {
742 return $this->raiseError('Version must be 3.0 or 2.1 to be valid.');
743 }
744 $this->setValue('VERSION', 0, 0, $text);
745 }
746
747 /**
748 * Gets back the version of the the vCard. Only one iteration.
749 *
750 * @access public
751 * @uses self::getMeta()
752 * @return string The data-source of the vCard.
753 */
754 function getVersion()
755 {
756 return $this->getMeta('VERSION', 0) . $this->getValue('VERSION', 0);
757 }
758
759 /**
760 * Sets the data-source of the the vCard. Only one iteration.
761 *
762 * @param string $text The text value of the data-source text.
763 *
764 * @access public
765 * @return void
766 */
767 function setSource($text)
768 {
769 $this->autoparam = 'SOURCE';
770 $this->setValue('SOURCE', 0, 0, $text);
771 }
772
773 /**
774 * Gets back the data-source of the the vCard. Only one iteration.
775 *
776 * @access public
777 * @return string The data-source of the vCard.
778 */
779 function getSource()
780 {
781 return $this->getMeta('SOURCE', 0) . $this->getValue('SOURCE', 0, 0);
782 }
783
784 /**
785 * Sets the displayed name of the vCard data-source. Only one iteration.
786 * If no name is specified, copies the value of SOURCE.
787 *
788 * @param string $text The text value of the displayed data-source
789 * name. If null, copies the value of SOURCE.
790 *
791 * @access public
792 * @return mixed Void on success, or a PEAR_Error object on failure.
793 */
794 function setSourceName($text = null)
795 {
796 $this->autoparam = 'NAME';
797
798 if ($text === null) {
799 if (is_array($this->value['SOURCE'])) {
800 $text = $this->getValue('SOURCE', 0, 0);
801 } else {
802 $msg = 'NAME not specified and SOURCE not set; cannot set NAME.';
803 return $this->raiseError($msg);
804 }
805 }
806
807 $this->setValue('NAME', 0, 0, $text);
808 }
809
810 /**
811 * Gets back the displayed data-source name of the the vCard. Only
812 * one iteration.
813 *
814 * @access public
815 * @return string The data-source name of the vCard.
816 */
817 function getSourceName()
818 {
819 return $this->getMeta('NAME', 0) . $this->getValue('NAME', 0, 0);
820 }
821
822 /**
823 * Sets the value of the PHOTO component. There is only one allowed
824 * per vCard.
825 *
826 * @param string $text The value to set for this component.
827 * @param boolean $url True or false, depending if $text is one.
828 *
829 * @access public
830 * @return void
831 */
832 function setPhoto($text, $url = false)
833 {
834 if ($url === false) {
835 $this->autoparam = 'PHOTO';
836 $this->setValue('PHOTO', 0, 0, $text);
837 return;
838 }
839 $this->autoparam = 'PHOTO;VALUE=URI';
840 $this->setValue('PHOTO;VALUE=URI', 0, 0, $text);
841 }
842
843 /**
844 * Gets back the value of the PHOTO component. There is only one
845 * allowed per vCard.
846 *
847 * @access public
848 * @return string The value of this component or false if no photo is set.
849 */
850 function getPhoto()
851 {
852 if (isset($this->value['PHOTO'])) {
853 return $this->getMeta('PHOTO') . $this->getValue('PHOTO', 0, 0);
854 }
855 if (isset($this->value['PHOTO;VALUE=URI'])) {
856 return $this->getMeta('PHOTO;VALUE=URI') .
857 $this->getValue('PHOTO;VALUE=URI', 0, 0);
858 }
859 return false;
860 }
861
862 /**
863 * Sets the value of the LOGO component. There is only one allowed
864 * per vCard.
865 *
866 * @param string $text The value to set for this component.
867 *
868 * @access public
869 * @return void
870 */
871 function setLogo($text)
872 {
873 $this->autoparam = 'LOGO';
874 $this->setValue('LOGO', 0, 0, $text);
875 }
876
877 /**
878 * Gets back the value of the LOGO component. There is only one
879 * allowed per vCard.
880 *
881 * @access public
882 * @return string The value of this component.
883 */
884 function getLogo()
885 {
886 return $this->getMeta('LOGO') . $this->getValue('LOGO', 0, 0);
887 }
888
889 /**
890 * Sets the value of the SOUND component. There is only one allowed
891 * per vCard.
892 *
893 * @param string $text The value to set for this component.
894 *
895 * @access public
896 * @return void
897 */
898 function setSound($text)
899 {
900 $this->autoparam = 'SOUND';
901 $this->setValue('SOUND', 0, 0, $text);
902 }
903
904 /**
905 * Gets back the value of the SOUND component. There is only one
906 * allowed per vCard.
907 *
908 * @access public
909 * @return string The value of this component.
910 */
911 function getSound()
912 {
913 return $this->getMeta('SOUND') . $this->getValue('SOUND', 0, 0);
914 }
915
916 /**
917 * Sets the value of the KEY component. There is only one allowed
918 * per vCard.
919 *
920 * @param string $text The value to set for this component.
921 *
922 * @access public
923 * @return void
924 */
925 function setKey($text)
926 {
927 $this->autoparam = 'KEY';
928 $this->setValue('KEY', 0, 0, $text);
929 }
930
931 /**
932 * Gets back the value of the KEY component. There is only one
933 * allowed per vCard.
934 *
935 * @access public
936 * @return string The value of this component.
937 */
938 function getKey()
939 {
940 return $this->getMeta('KEY') . $this->getValue('KEY', 0, 0);
941 }
942
943 /**
944 * Sets the value of the BDAY component. There is only one allowed
945 * per vCard. Date format is "yyyy-mm-dd[Thh:ii[:ss[Z|-06:00]]]".
946 *
947 * @param string $text The value to set for this component.
948 *
949 * @access public
950 * @return void
951 */
952 function setBirthday($text)
953 {
954 $this->autoparam = 'BDAY';
955 $this->setValue('BDAY', 0, 0, $text);
956 }
957
958 /**
959 * Gets back the value of the BDAY component. There is only one
960 * allowed per vCard.
961 *
962 * @access public
963 * @return string The value of this component.
964 */
965 function getBirthday()
966 {
967 return $this->getMeta('BDAY') . $this->getValue('BDAY', 0, 0);
968 }
969
970 /**
971 * Sets the value of the TZ component. There is only one allowed per
972 * vCard.
973 *
974 * @param string $text The value to set for this component.
975 *
976 * @access public
977 * @return void
978 */
979 function setTZ($text)
980 {
981 $this->autoparam = 'TZ';
982 $this->setValue('TZ', 0, 0, $text);
983 }
984
985 /**
986 * Gets back the value of the TZ component. There is only one
987 * allowed per vCard.
988 *
989 * @access public
990 * @return string The value of this component.
991 */
992 function getTZ()
993 {
994 return $this->getMeta('TZ') . $this->getValue('TZ', 0, 0);
995 }
996
997 /**
998 * Sets the value of the MAILER component. There is only one allowed
999 * per vCard.
1000 *
1001 * @param string $text The value to set for this component.
1002 *
1003 * @access public
1004 * @return void
1005 */
1006 function setMailer($text)
1007 {
1008 $this->autoparam = 'MAILER';
1009 $this->setValue('MAILER', 0, 0, $text);
1010 }
1011
1012 /**
1013 * Gets back the value of the MAILER component. There is only one
1014 * allowed per vCard.
1015 *
1016 * @access public
1017 * @return string The value of this component.
1018 */
1019 function getMailer()
1020 {
1021 return $this->getMeta('MAILER') . $this->getValue('MAILER', 0, 0);
1022 }
1023
1024 /**
1025 * Sets the value of the NOTE component. There is only one allowed
1026 * per vCard.
1027 *
1028 * @param string $text The value to set for this component.
1029 *
1030 * @access public
1031 * @return void
1032 */
1033 function setNote($text)
1034 {
1035 $this->autoparam = 'NOTE';
1036 $this->setValue('NOTE', 0, 0, $text);
1037 }
1038
1039 /**
1040 * Gets back the value of the NOTE component. There is only one
1041 * allowed per vCard.
1042 *
1043 * @access public
1044 * @return string The value of this component.
1045 */
1046 function getNote()
1047 {
1048 return $this->getMeta('NOTE') . $this->getValue('NOTE', 0, 0);
1049 }
1050
1051 /**
1052 * Sets the value of the TITLE component. There is only one allowed
1053 * per vCard.
1054 *
1055 * @param string $text The value to set for this component.
1056 *
1057 * @access public
1058 * @return void
1059 */
1060 function setTitle($text)
1061 {
1062 $this->autoparam = 'TITLE';
1063 $this->setValue('TITLE', 0, 0, $text);
1064 }
1065
1066 /**
1067 * Gets back the value of the TITLE component. There is only one
1068 * allowed per vCard.
1069 *
1070 * @access public
1071 * @return string The value of this component.
1072 */
1073 function getTitle()
1074 {
1075 return $this->getMeta('TITLE') . $this->getValue('TITLE', 0, 0);
1076 }
1077
1078 /**
1079 * Sets the value of the ROLE component. There is only one allowed
1080 * per vCard.
1081 *
1082 * @param string $text The value to set for this component.
1083 *
1084 * @access public
1085 * @return void
1086 */
1087 function setRole($text)
1088 {
1089 $this->autoparam = 'ROLE';
1090 $this->setValue('ROLE', 0, 0, $text);
1091 }
1092
1093 /**
1094 * Gets back the value of the ROLE component. There is only one
1095 * allowed per vCard.
1096 *
1097 * @access public
1098 * @return string The value of this component.
1099 */
1100 function getRole()
1101 {
1102 return $this->getMeta('ROLE') . $this->getValue('ROLE', 0, 0);
1103 }
1104
1105 /**
1106 * Sets the value of the URL component. There is only one allowed
1107 * per vCard.
1108 *
1109 * @param string $text The value to set for this component.
1110 *
1111 * @access public
1112 * @return void
1113 */
1114 function setURL($text)
1115 {
1116 $this->autoparam = 'URL';
1117 $this->setValue('URL', 0, 0, $text);
1118 }
1119
1120 /**
1121 * Gets back the value of the URL component. There is only one
1122 * allowed per vCard.
1123 *
1124 * @access public
1125 * @return string The value of this component.
1126 */
1127 function getURL()
1128 {
1129 return $this->getMeta('URL') . $this->getValue('URL', 0, 0);
1130 }
1131
1132 /**
1133 * Sets the value of the CLASS component. There is only one allowed
1134 * per vCard.
1135 *
1136 * @param string $text The value to set for this component.
1137 *
1138 * @access public
1139 * @return void
1140 */
1141 function setClass($text)
1142 {
1143 $this->autoparam = 'CLASS';
1144 $this->setValue('CLASS', 0, 0, $text);
1145 }
1146
1147 /**
1148 * Gets back the value of the CLASS component. There is only one
1149 * allowed per vCard.
1150 *
1151 * @access public
1152 * @return string The value of this component.
1153 */
1154 function getClass()
1155 {
1156 return $this->getMeta('CLASS') . $this->getValue('CLASS', 0, 0);
1157 }
1158
1159 /**
1160 * Sets the value of the SORT-STRING component. There is only one
1161 * allowed per vCard.
1162 *
1163 * @param string $text The value to set for this component.
1164 *
1165 * @access public
1166 * @return void
1167 */
1168 function setSortString($text)
1169 {
1170 $this->autoparam = 'SORT-STRING';
1171 $this->setValue('SORT-STRING', 0, 0, $text);
1172 }
1173
1174 /**
1175 * Gets back the value of the SORT-STRING component. There is only
1176 * one allowed per vCard.
1177 *
1178 * @access public
1179 * @return string The value of this component.
1180 */
1181 function getSortString()
1182 {
1183 return $this->getMeta('SORT-STRING') . $this->getValue('SORT-STRING', 0, 0);
1184 }
1185
1186 /**
1187 * Sets the value of the PRODID component. There is only one allowed
1188 * per vCard.
1189 *
1190 * @param string $text The value to set for this component.
1191 *
1192 * @access public
1193 * @return void
1194 */
1195 function setProductID($text)
1196 {
1197 $this->autoparam = 'PRODID';
1198 $this->setValue('PRODID', 0, 0, $text);
1199 }
1200
1201 /**
1202 * Gets back the value of the PRODID component. There is only one
1203 * allowed per vCard.
1204 *
1205 * @access public
1206 * @return string The value of this component.
1207 */
1208 function getProductID()
1209 {
1210 return $this->getMeta('PRODID') . $this->getValue('PRODID', 0, 0);
1211 }
1212
1213 /**
1214 * Sets the value of the REV component. There is only one allowed
1215 * per vCard. This value is free and should reflect whatever you use
1216 * for control - e.g. a DATETIME value.
1217 *
1218 * @param string $text The value to set for this component.
1219 *
1220 * @access public
1221 * @return void
1222 */
1223 function setRevision($text)
1224 {
1225 $this->autoparam = 'REV';
1226 $this->setValue('REV', 0, 0, $text);
1227 }
1228
1229 /**
1230 * Gets back the value of the REV component. There is only one
1231 * allowed per vCard.
1232 *
1233 * @access public
1234 * @return string The value of this component.
1235 */
1236 function getRevision()
1237 {
1238 return $this->getMeta('REV') . $this->getValue('REV', 0, 0);
1239 }
1240
1241 /**
1242 * Sets the value of the UID component. There is only one allowed
1243 * per vCard.
1244 *
1245 * @param string $text The value to set for this component.
1246 *
1247 * @access public
1248 * @return void
1249 */
1250 function setUniqueID($text)
1251 {
1252 $this->autoparam = 'UID';
1253 $this->setValue('UID', 0, 0, $text);
1254 }
1255
1256 /**
1257 * Gets back the value of the UID component. There is only one
1258 * allowed per vCard.
1259 *
1260 * @access public
1261 * @return string The value of this component.
1262 */
1263 function getUniqueID()
1264 {
1265 return $this->getMeta('UID') . $this->getValue('UID', 0, 0);
1266 }
1267
1268 /**
1269 * Sets the value of the AGENT component. There is only one allowed
1270 * per vCard.
1271 *
1272 * @param string $text The value to set for this component.
1273 *
1274 * @access public
1275 * @return void
1276 */
1277 function setAgent($text)
1278 {
1279 $this->autoparam = 'AGENT';
1280 $this->setValue('AGENT', 0, 0, $text);
1281 }
1282
1283 /**
1284 * Gets back the value of the AGENT component. There is only one
1285 * allowed per vCard.
1286 *
1287 * @access public
1288 * @return string The value of this component.
1289 */
1290 function getAgent()
1291 {
1292 return $this->getMeta('AGENT') . $this->getValue('AGENT', 0, 0);
1293 }
1294
1295 /**
1296 * Sets the value of both parts of the GEO component. There is only
1297 * one GEO component allowed per vCard.
1298 *
1299 * @param string $lat The value to set for the longitude part
1300 * (decimal, + or -).
1301 * @param string $lon The value to set for the latitude part
1302 * (decimal, + or -).
1303 *
1304 * @access public
1305 * @return void
1306 */
1307 function setGeo($lat, $lon)
1308 {
1309 $this->autoparam = 'GEO';
1310 $this->setValue('GEO', 0, VCARD_GEO_LAT, $lat);
1311 $this->setValue('GEO', 0, VCARD_GEO_LON, $lon);
1312 }
1313
1314 /**
1315 * Gets back the value of the GEO component. There is only one
1316 * allowed per vCard.
1317 *
1318 * @access public
1319 * @return string The value of this component.
1320 */
1321 function getGeo()
1322 {
1323 return $this->getMeta('GEO', 0) .
1324 $this->getValue('GEO', 0, VCARD_GEO_LAT, 0) . ';' .
1325 $this->getValue('GEO', 0, VCARD_GEO_LON, 0);
1326 }
1327
1328 /**
1329 * Sets the value of one entire ADR iteration. There can be zero,
1330 * one, or more ADR components in a vCard.
1331 *
1332 * @param mixed $pob String (one repetition) or array (multiple
1333 * repetitions) of the p.o. box part of the ADR
1334 * component iteration.
1335 * @param mixed $extend String (one repetition) or array (multiple
1336 * repetitions) of the "extended address" part
1337 * of the ADR component iteration.
1338 * @param mixed $street String (one repetition) or array (multiple
1339 * repetitions) of the street address part of
1340 * the ADR component iteration.
1341 * @param mixed $locality String (one repetition) or array (multiple
1342 * repetitions) of the locailty (e.g., city) part of the
1343 * ADR component iteration.
1344 * @param mixed $region String (one repetition) or array (multiple
1345 * repetitions) of the region (e.g., state, province, or
1346 * governorate) part of the ADR component iteration.
1347 * @param mixed $postcode String (one repetition) or array (multiple
1348 * repetitions) of the postal code (e.g., ZIP code) part
1349 * of the ADR component iteration.
1350 * @param mixed $country String (one repetition) or array (multiple
1351 * repetitions) of the country-name part of the ADR
1352 * component iteration.
1353 *
1354 * @access public
1355 * @return void
1356 */
1357 function addAddress($pob, $extend, $street, $locality, $region,
1358 $postcode, $country)
1359 {
1360 $this->autoparam = 'ADR';
1361 $iter = $this->countIter('ADR');
1362 $this->setValue('ADR', $iter, VCARD_ADR_POB, $pob);
1363 $this->setValue('ADR', $iter, VCARD_ADR_EXTEND, $extend);
1364 $this->setValue('ADR', $iter, VCARD_ADR_STREET, $street);
1365 $this->setValue('ADR', $iter, VCARD_ADR_LOCALITY, $locality);
1366 $this->setValue('ADR', $iter, VCARD_ADR_REGION, $region);
1367 $this->setValue('ADR', $iter, VCARD_ADR_POSTCODE, $postcode);
1368 $this->setValue('ADR', $iter, VCARD_ADR_COUNTRY, $country);
1369 }
1370
1371 /**
1372 * Gets back the value of one ADR component iteration.
1373 *
1374 * @param int $iter The component iteration-number to get the value
1375 * for.
1376 *
1377 * @access public
1378 * @return mixed The value of this component iteration, or a
1379 * PEAR_Error if the iteration is not valid.
1380 */
1381 function getAddress($iter)
1382 {
1383 if (! is_integer($iter) || $iter < 0) {
1384 return $this->raiseError('ADR iteration number not valid.');
1385 }
1386 return $this->getMeta('ADR', $iter) .
1387 $this->getValue('ADR', $iter, VCARD_ADR_POB) . ';' .
1388 $this->getValue('ADR', $iter, VCARD_ADR_EXTEND) . ';' .
1389 $this->getValue('ADR', $iter, VCARD_ADR_STREET) . ';' .
1390 $this->getValue('ADR', $iter, VCARD_ADR_LOCALITY) . ';' .
1391 $this->getValue('ADR', $iter, VCARD_ADR_REGION) . ';' .
1392 $this->getValue('ADR', $iter, VCARD_ADR_POSTCODE) . ';' .
1393 $this->getValue('ADR', $iter, VCARD_ADR_COUNTRY);
1394 }
1395
1396 /**
1397 * Sets the value of one LABEL component iteration. There can be
1398 * zero, one, or more component iterations in a vCard.
1399 *
1400 * @param string $text The value to set for this component.
1401 *
1402 * @access public
1403 * @return void
1404 */
1405 function addLabel($text)
1406 {
1407 $this->autoparam = 'LABEL';
1408 $iter = $this->countIter('LABEL');
1409 $this->setValue('LABEL', $iter, 0, $text);
1410 }
1411
1412 /**
1413 * Gets back the value of one iteration of the LABEL component.
1414 * There can be zero, one, or more component iterations in a vCard.
1415 *
1416 * @param int $iter The component iteration-number to get the value
1417 * for.
1418 *
1419 * @access public
1420 * @return mixed The value of this component, or a PEAR_Error if
1421 * the iteration number is not valid.
1422 */
1423 function getLabel($iter)
1424 {
1425 if (! is_integer($iter) || $iter < 0) {
1426 return $this->raiseError('LABEL iteration number not valid.');
1427 }
1428 return $this->getMeta('LABEL', $iter) .
1429 $this->getValue('LABEL', $iter, 0);
1430 }
1431
1432 /**
1433 * Sets the value of one component iteration. There can be zero,
1434 * one, or more component iterations in a vCard. This function also
1435 * takes a type argument to be able to add mobiles, fax and voice
1436 * as well.
1437 *
1438 * @param string $text The value to set for this component.
1439 * @param string $type The type: phone, mobile, fax or voice
1440 *
1441 * @access public
1442 * @return mixed void on success, PEAR_Error on failure
1443 * @uses self::_getTelephoneType()
1444 */
1445 function addTelephone($text, $type = 'phone')
1446 {
1447 $autoparam = $this->_getTelephoneType($type);
1448 if (PEAR::isError($autoparam)) {
1449 return $autoparam;
1450 }
1451
1452 $iter = $this->countIter($autoparam);
1453 $this->setValue($autoparam, $iter, 0, $text);
1454
1455 $this->autoparam = $autoparam;
1456 }
1457
1458 /**
1459 * Gets back the value of one iteration of the TEL component. There
1460 * can be zero, one, or more component iterations in a vCard.
1461 *
1462 * @param int $iter The component iteration-number to get the value
1463 * for.
1464 * @param string $type The type: phone, mobile, fax, voice
1465 *
1466 * @access public
1467 * @return mixed The value of this component, or a PEAR_Error if the
1468 * iteration number is not valid.
1469 * @uses self::_getTelephoneType()
1470 */
1471 function getTelephone($iter, $type = 'phone')
1472 {
1473 $autoparam = $this->_getTelephoneType($type);
1474 if (PEAR::isError($autoparam)) {
1475 return $autoparam;
1476 }
1477
1478 if (!is_integer($iter) || $iter < 0) {
1479 return $this->raiseError($autoparam . ' iteration number not valid.');
1480 }
1481
1482 return $this->getMeta($autoparam, $iter) .
1483 $this->getValue($autoparam, $iter, 0);
1484 }
1485
1486 /**
1487 * Sets the value of one EMAIL component iteration. There can be zero,
1488 * one, or more component iterations in a vCard.
1489 *
1490 * @param string $text The value to set for this component.
1491 *
1492 * @access public
1493 * @return void
1494 */
1495 function addEmail($text)
1496 {
1497 $this->autoparam = 'EMAIL';
1498 $iter = $this->countIter('EMAIL');
1499 $this->setValue('EMAIL', $iter, 0, $text);
1500 }
1501
1502 /**
1503 * Gets back the value of one iteration of the EMAIL component. There can
1504 * be zero, one, or more component iterations in a vCard.
1505 *
1506 * @param int $iter The component iteration-number to get the value
1507 * for.
1508 *
1509 * @access public
1510 *
1511 * @return mixed The value of this component, or a PEAR_Error if the
1512 * iteration number is not valid.
1513 *
1514 */
1515 function getEmail($iter)
1516 {
1517 if (! is_integer($iter) || $iter < 0) {
1518 return $this->raiseError('EMAIL iteration number not valid.');
1519 }
1520 return $this->getMeta('EMAIL', $iter) .
1521 $this->getValue('EMAIL', $iter, 0);
1522 }
1523
1524 /**
1525 * Sets the full value of the NICKNAME component. There is only one
1526 * component iteration allowed per vCard, but there may be multiple
1527 * value repetitions in the iteration.
1528 *
1529 * @param mixed $text String (one repetition) or array (multiple
1530 * reptitions) of the component iteration value.
1531 *
1532 * @access public
1533 * @return void
1534 */
1535 function addNickname($text)
1536 {
1537 $this->autoparam = 'NICKNAME';
1538 $this->addValue('NICKNAME', 0, 0, $text);
1539 }
1540
1541 /**
1542 * Gets back the value of the NICKNAME component. There is only one
1543 * component allowed per vCard, but there may be multiple value
1544 * repetitions in the iteration.
1545 *
1546 * @access public
1547 * @return string The value of this component.
1548 */
1549 function getNickname()
1550 {
1551 return $this->getMeta('NICKNAME') . $this->getValue('NICKNAME', 0, 0);
1552 }
1553
1554 /**
1555 * Sets the full value of the CATEGORIES component. There is only
1556 * one component iteration allowed per vCard, but there may be
1557 * multiple value repetitions in the iteration.
1558 *
1559 * @param mixed $text String (one repetition) or array (multiple reptitions)
1560 * of the component iteration value.
1561 *
1562 * @access public
1563 * @return void
1564 */
1565 function addCategories($text)
1566 {
1567 $this->autoparam = 'CATEGORIES';
1568 $this->addValue('CATEGORIES', 0, 0, $text);
1569 }
1570
1571 /**
1572 * Gets back the value of the CATEGORIES component. There is only
1573 * one component allowed per vCard, but there may be multiple value
1574 * repetitions in the iteration.
1575 *
1576 * @access public
1577 * @return string The value of this component.
1578 */
1579 function getCategories()
1580 {
1581 return $this->getMeta('CATEGORIES', 0) .
1582 $this->getValue('CATEGORIES', 0, 0);
1583 }
1584
1585 /**
1586 * Sets the full value of the ORG component. There can be only one
1587 * ORG component in a vCard.
1588 *
1589 * The ORG component can have one or more parts (as opposed to
1590 * repetitions of values within those parts). The first part is the
1591 * highest-level organization, the second part is the next-highest,
1592 * the third part is the third-highest, and so on. There can by any
1593 * number of parts in one ORG iteration. (This is different from
1594 * other components, such as NICKNAME, where an iteration has only
1595 * one part but may have many repetitions within that part.)
1596 *
1597 * @param mixed $text String (one ORG part) or array (of ORG parts) to
1598 * use as the value for the component iteration.
1599 *
1600 * @access public
1601 * @return void
1602 */
1603 function addOrganization($text)
1604 {
1605 $this->autoparam = 'ORG';
1606
1607 settype($text, 'array');
1608
1609 $base = $this->countRept('ORG', 0);
1610
1611 // start at the original base point, and add
1612 // new parts
1613 foreach ($text as $part => $val) {
1614 $this->setValue('ORG', 0, $base + $part, $val);
1615 }
1616 }
1617
1618 /**
1619 * Gets back the value of the ORG component.
1620 *
1621 * @return string The value of this component.
1622 * @access public
1623 */
1624 function getOrganization()
1625 {
1626 $text = $this->getMeta('ORG', 0);
1627
1628 $k = $this->countRept('ORG', 0);
1629 $last = $k - 1;
1630
1631 for ($part = 0; $part < $k; $part++) {
1632
1633 $text .= $this->getValue('ORG', 0, $part);
1634
1635 if ($part != $last) {
1636 $text .= ';';
1637 }
1638
1639 }
1640
1641 return $text;
1642 }
1643
1644 /**
1645 * Builds a vCard from a Contact_Vcard_Parse result array. Only send
1646 * one vCard from the parse-results.
1647 *
1648 * Usage (to build from first vCard in parsed results):
1649 *
1650 * $parse = new Contact_Vcard_Parse(); // new parser
1651 * $info = $parse->fromFile('sample.vcf'); // parse file
1652 *
1653 * $vcard = new Contact_Vcard_Build(); // new builder
1654 * $vcard->setFromArray($info[0]); // [0] is the first card
1655 *
1656 * @param array $src One vCard entry as parsed using
1657 * Contact_Vcard_Parse.
1658 *
1659 * @access public
1660 * @return void
1661 * @see Contact_Vcard_Parse::fromFile()
1662 * @see Contact_Vcard_Parse::fromText()
1663 */
1664 function setFromArray($src)
1665 {
1666 // reset to a blank values and params
1667 $this->value = array();
1668 $this->param = array();
1669
1670 // loop through components (N, ADR, TEL, etc)
1671 foreach ($src as $comp => $comp_val) {
1672
1673 // set the autoparam property. not really needed, but let's
1674 // behave after an expected fashion, shall we? ;-)
1675 $this->autoparam = $comp;
1676
1677 // iteration number of each component
1678 foreach ($comp_val as $iter => $iter_val) {
1679
1680 // value or param?
1681 foreach ($iter_val as $kind => $kind_val) {
1682
1683 // part number
1684 foreach ($kind_val as $part => $part_val) {
1685
1686 // repetition number and text value
1687 foreach ($part_val as $rept => $text) {
1688
1689 // ignore data when $kind is neither 'value'
1690 // nor 'param'
1691 if (strtolower($kind) == 'value') {
1692 $this->_setValue($comp, $iter, $part, $rept, $text);
1693 } elseif (strtolower($kind) == 'param') {
1694 $this->_setParam($comp, $iter, $part, $rept, $text);
1695 }
1696 }
1697 }
1698 }
1699 }
1700 }
1701 }
1702
1703
1704 /**
1705 * Fetches a full vCard text block based on $this->value and
1706 * $this->param. The order of the returned components is similar to
1707 * their order in RFC 2426. Honors the value of
1708 * $this->value['VERSION'] to determine which vCard components are
1709 * returned (2.1- or 3.0-compliant).
1710 *
1711 * @access public
1712 * @return string A properly formatted vCard text block.
1713 */
1714 function fetch()
1715 {
1716 // vCard version is required
1717 if (! is_array($this->value['VERSION'])) {
1718 return $this->raiseError('VERSION not set (required).');
1719 }
1720
1721 // FN component is required
1722 if (! is_array($this->value['FN'])) {
1723 return $this->raiseError('FN component not set (required).');
1724 }
1725
1726 // N component is required
1727 if (! is_array($this->value['N'])) {
1728 return $this->raiseError('N component not set (required).');
1729 }
1730
1731 // initialize the vCard lines
1732 $lines = array();
1733
1734 // begin (required)
1735 $lines[] = "BEGIN:VCARD";
1736
1737 // version (required)
1738 // available in both 2.1 and 3.0
1739 $lines[] = $this->getVersion();
1740
1741 // profile (3.0 only)
1742 if ($this->value['VERSION'][0][0][0] == '3.0') {
1743 $lines[] = "PROFILE:VCARD";
1744 }
1745
1746 // formatted name (required)
1747 // available in both 2.1 and 3.0
1748 $lines[] = $this->getFormattedName();
1749
1750 // structured name (required)
1751 // available in both 2.1 and 3.0
1752 $lines[] = $this->getName();
1753
1754 // displayed name of the data source (3.0 only)
1755 if (isset($this->value['NAME']) &&
1756 $this->value['VERSION'][0][0][0] == '3.0') {
1757 $lines[] = $this->getSourceName();
1758 }
1759
1760 // data source (3.0 only)
1761 if (isset($this->value['SOURCE']) &&
1762 $this->value['VERSION'][0][0][0] == '3.0') {
1763 $lines[] = $this->getSource();
1764 }
1765
1766 // nicknames (3.0 only)
1767 if (isset($this->value['NICKNAME']) &&
1768 $this->value['VERSION'][0][0][0] == '3.0') {
1769 $lines[] = $this->getNickname();
1770 }
1771
1772 // personal photo
1773 // available in both 2.1 and 3.0
1774 $_photo = $this->getPhoto();
1775 if ($_photo !== false) {
1776 $lines[] = $_photo;
1777 }
1778
1779 // bday
1780 // available in both 2.1 and 3.0
1781 if (isset($this->value['BDAY'])) {
1782 $lines[] = $this->getBirthday();
1783 }
1784
1785 // adr
1786 // available in both 2.1 and 3.0
1787 if (isset($this->value['ADR'])) {
1788 foreach ($this->value['ADR'] as $key => $val) {
1789 $lines[] = $this->getAddress($key);
1790 }
1791 }
1792
1793 // label
1794 // available in both 2.1 and 3.0
1795 if (isset($this->value['LABEL'])) {
1796 foreach ($this->value['LABEL'] as $key => $val) {
1797 $lines[] = $this->getLabel($key);
1798 }
1799 }
1800
1801 // tel
1802 // available in both 2.1 and 3.0
1803 if (isset($this->value['TEL'])) {
1804 foreach ($this->value['TEL'] as $key => $val) {
1805 $lines[] = $this->getTelephone($key);
1806 }
1807 }
1808
1809 // mobiles
1810 if (isset($this->value['TEL;PREF;CELL'])) {
1811 foreach ($this->value['TEL;PREF;CELL'] as $key => $val) {
1812 $lines[] = $this->getTelephone($key, 'mobile');
1813 }
1814 }
1815
1816 // voice
1817 if (isset($this->value['TEL;PREF;VOICE'])) {
1818 foreach ($this->value['TEL;PREF;VOICE'] as $key => $val) {
1819 $lines[] = $this->getTelephone($key, 'voice');
1820 }
1821 }
1822
1823 // fax
1824 if (isset($this->value['TEL;PREF;FAX'])) {
1825 foreach ($this->value['TEL;PREF;FAX'] as $key => $val) {
1826 $lines[] = $this->getTelephone($key, 'fax');
1827 }
1828 }
1829
1830 // email
1831 // available in both 2.1 and 3.0
1832 if (isset($this->value['EMAIL'])) {
1833 foreach ($this->value['EMAIL'] as $key => $val) {
1834 $lines[] = $this->getEmail($key);
1835 }
1836 }
1837
1838 // mailer
1839 // available in both 2.1 and 3.0
1840 if (isset($this->value['MAILER'])) {
1841 $lines[] = $this->getMailer();
1842 }
1843
1844 // tz
1845 // available in both 2.1 and 3.0
1846 if (isset($this->value['TZ'])) {
1847 $lines[] = $this->getTZ();
1848 }
1849
1850 // geo
1851 // available in both 2.1 and 3.0
1852 if (isset($this->value['GEO'])) {
1853 $lines[] = $this->getGeo();
1854 }
1855
1856 // title
1857 // available in both 2.1 and 3.0
1858 if (isset($this->value['TITLE'])) {
1859 $lines[] = $this->getTitle();
1860 }
1861
1862 // role
1863 // available in both 2.1 and 3.0
1864 if (isset($this->value['ROLE'])) {
1865 $lines[] = $this->getRole();
1866 }
1867
1868 // company logo
1869 // available in both 2.1 and 3.0
1870 if (isset($this->value['LOGO'])) {
1871 $lines[] = $this->getLogo();
1872 }
1873
1874 // agent
1875 // available in both 2.1 and 3.0
1876 if (isset($this->value['AGENT'])) {
1877 $lines[] = $this->getAgent();
1878 }
1879
1880 // org
1881 // available in both 2.1 and 3.0
1882 if (isset($this->value['ORG'])) {
1883 $lines[] = $this->getOrganization();
1884 }
1885
1886 // categories (3.0 only)
1887 if (isset($this->value['CATEGORIES']) &&
1888 $this->value['VERSION'][0][0][0] == '3.0') {
1889 $lines[] = $this->getCategories();
1890 }
1891
1892 // note
1893 // available in both 2.1 and 3.0
1894 if (isset($this->value['NOTE'])) {
1895 $lines[] = $this->getNote();
1896 }
1897
1898 // prodid (3.0 only)
1899 if (isset($this->value['PRODID']) &&
1900 $this->value['VERSION'][0][0][0] == '3.0') {
1901 $lines[] = $this->getProductID();
1902 }
1903
1904 // rev
1905 // available in both 2.1 and 3.0
1906 if (isset($this->value['REV'])) {
1907 $lines[] = $this->getRevision();
1908 }
1909
1910 // sort-string (3.0 only)
1911 if (isset($this->value['SORT-STRING']) &&
1912 $this->value['VERSION'][0][0][0] == '3.0') {
1913 $lines[] = $this->getSortString();
1914 }
1915
1916 // name-pronounciation sound
1917 // available in both 2.1 and 3.0
1918 if (isset($this->value['SOUND'])) {
1919 $lines[] = $this->getSound();
1920 }
1921
1922 // uid
1923 // available in both 2.1 and 3.0
1924 if (isset($this->value['UID'])) {
1925 $lines[] = $this->getUniqueID();
1926 }
1927
1928 // url
1929 // available in both 2.1 and 3.0
1930 if (isset($this->value['URL'])) {
1931 $lines[] = $this->getURL();
1932 }
1933
1934 // class (3.0 only)
1935 if (isset($this->value['CLASS']) &&
1936 $this->value['VERSION'][0][0][0] == '3.0') {
1937 $lines[] = $this->getClass();
1938 }
1939
1940 // key
1941 // available in both 2.1 and 3.0
1942 if (isset($this->value['KEY'])) {
1943 $lines[] = $this->getKey();
1944 }
1945
1946 // required
1947 $lines[] = "END:VCARD";
1948
1949 // version 3.0 uses \n for new lines,
1950 // version 2.1 uses \r\n
1951 $newline = "\n";
1952 if ($this->value['VERSION'][0][0][0] == '2.1') {
1953 $newline = "\r\n";
1954 }
1955
1956 // fold lines at 75 characters
1957 // commented out as a possible fix for Outlook compatibility
1958 // $regex = "(.{1,75})";
1959 // foreach ($lines as $key => $val) {
1960 // if (strlen($val) > 75) {
1961 // // we trim to drop the last newline, which will be added
1962 // // again by the implode function at the end of fetch()
1963 // $lines[$key] = trim(preg_replace("/$regex/i", "\\1$newline ", $val));
1964 // }
1965 // }
1966
1967 // recode the lines from UTF-8 to lowest covering charset
1968 $lines = $this->charsetRecode($lines);
1969
1970 // compile the array of lines into a single text block
1971 // and return (with a trailing newline)
1972 return implode($newline, $lines). $newline;
1973 }
1974
1975 /**
1976 * Send the vCard as a downloadable file.
1977 *
1978 * @param string $filename The file name to give the vCard.
1979 * @param string $disposition How the file should be sent, either
1980 * 'inline' or 'attachment'.
1981 * @param string $charset The character set to use, defaults to
1982 * 'us-ascii'.
1983 *
1984 * @access public
1985 * @return void or Pear_Error in case of an error.
1986 */
1987 function send($filename, $disposition = 'attachment', $charset = 'us-ascii')
1988 {
1989 $vcard = $this->fetch();
1990 if (PEAR::isError($vcard)) {
1991 return $vcard;
1992 }
1993
1994 header('Content-Type: application/directory; ' .
1995 'profile="vcard"; ' .
1996 'charset=' . $charset);
1997
1998 header('Cache-Control: must-revalidate,post-check=0, pre-check=0');
1999 header('Pragma: public');
2000 header('Content-Length: ' . strlen($vcard));
2001 header("Content-Disposition: $disposition; filename=\"$filename\"");
2002
2003 echo $vcard;
2004 }
2005
2006 /**
2007 * Gets the left-side/prefix/before-the-colon (metadata) part of a
2008 * vCard line, including the component identifier, the parameter
2009 * list, and a colon.
2010 *
2011 * @param string $comp The component to get metadata for (ADR, TEL, etc).
2012 * @param int $iter The vCard component iteration to get the metadata
2013 * for. E.g., if you have more than one ADR component,
2014 * 0 refers to the first ADR, 1 to the second ADR,
2015 * and so on.
2016 *
2017 * @access public
2018 * @return string The line prefix metadata.
2019 */
2020 function getMeta($comp, $iter = 0)
2021 {
2022 $params = $this->getParam($comp, $iter);
2023
2024 if (trim($params) == '') {
2025 // no parameters
2026 $text = $comp . ':';
2027 } else {
2028 // has parameters. put an extra semicolon in.
2029 $text = $comp . ';' . $params . ':';
2030 }
2031
2032 return $text;
2033 }
2034
2035 /**
2036 * Recode the lines to the 'smallest' encoding and add the charset info
2037 *
2038 * As, surprise surprise, Microsoft Outlook does not seem to be able to
2039 * handle properly tagged UTF-8 vCards, we try to represent the text in
2040 * smallest charset 'covering' the text in full (currently the test goes
2041 * 'US-ASCII' -> 'ISO-8859-1' -> 'CP1250' and falls back to 'UTF-8')
2042 *
2043 * @param array $lines the vCard's lines
2044 *
2045 * @return array the recoded and properly tagged lines
2046 */
2047 function charsetRecode($lines) {
2048
2049 $charsets = array('US-ASCII', 'ISO-8859-1', 'CP1250');
2050
2051 if ((function_exists('iconv_strlen') or function_exists('mb_strlen')) and function_exists('iconv')) {
2052
2053 // for each line, get the character length of the UTF-8 string
2054 // and try to recode it to every charset in turn; iconv() returns
2055 // truncated strings on recode errors, so if the character length
2056 // after the recode equals the one before - we've found a valid
2057 // charset
2058 foreach ($lines as $number => $line) {
2059 $lineCharset = 'UTF-8';
2060 if (function_exists('iconv_strlen')) {
2061 $strlen = iconv_strlen($line, 'UTF-8');
2062 } else {
2063 $strlen = mb_strlen($line, 'UTF-8');
2064 }
2065 foreach ($charsets as $charset) {
2066 $iconvd = iconv('UTF-8', $charset, $line);
2067 if (strlen($iconvd) == $strlen) {
2068 $lineCharset = $charset;
2069 $line = $iconvd;
2070 break;
2071 }
2072 }
2073 // tag the non-US-ASCII-only, recoded lines properly
2074 if ($lineCharset != 'US-ASCII') {
2075 $lines[$number] = preg_replace('/:/', ";ENCODING=8BIT;CHARSET=$lineCharset:", $line, 1);
2076 }
2077 }
2078
2079 } else {
2080
2081 // if there's no mb_strings or iconv support,
2082 // simply tag the non-US-ASCII-only lines as UTF-8
2083 foreach ($lines as $number => $line) {
2084 if (preg_match('/[^\x00-\x7f]/', $line)) {
2085 $lines[$number] = preg_replace('/:/', ";ENCODING=8BIT;CHARSET=UTF-8:", $line, 1);
2086 }
2087 }
2088
2089 }
2090
2091 return $lines;
2092 }
2093
2094 /**
2095 * Count the number of iterations for an element type.
2096 *
2097 * @param string $type The element type to count iterations for
2098 * (ADR, ORG, etc).
2099 *
2100 * @access public
2101 * @return int The number of iterations for that type.
2102 */
2103 function countIter($type)
2104 {
2105 if (!isset($this->value[$type])) {
2106 return 0;
2107 }
2108 return count($this->value[$type]);
2109 }
2110
2111 /**
2112 * Count the number of repetitions for an element type and iteration
2113 * number.
2114 *
2115 * @param string $type The element type to count iterations for
2116 * (ADR, ORG, etc).
2117 * @param int $rept The iteration number to count repetitions for.
2118 *
2119 * @access public
2120 * @return int The number of repetitions for that type and iteration.
2121 */
2122 function countRept($type, $rept)
2123 {
2124 if (!isset($this->value[$type][$rept])) {
2125 return 0;
2126 }
2127 return count($this->value[$type][$rept]);
2128 }
2129
2130 /**
2131 * Emulated destructor.
2132 *
2133 * @access private
2134 * @return boolean true
2135 */
2136 function _Contact_Vcard_Build()
2137 {
2138 return true;
2139 }
2140
2141 /**
2142 * _setValue
2143 *
2144 * @param string $comp The component to set the value for ('N',
2145 * 'ADR', etc).
2146 * @param int $iter The component-iteration to set the value for.
2147 * the value for.
2148 * @param int $part The part number of the component-iteration to set
2149 * @param mixed $rept The repetition number within the part to get;
2150 * if null, get all repetitions of the part within the
2151 * iteration.
2152 * @param mixed $text A string or array; the set of repeated values
2153 * for this component-iteration part.
2154 *
2155 * @access protected
2156 * @return void
2157 */
2158 function _setValue($comp, $iter, $part, $rept, $text)
2159 {
2160 $this->value[strtoupper($comp)][$iter][$part][$rept] = $text;
2161 }
2162
2163 /**
2164 * _setParam
2165 *
2166 * @param string $comp The component to set the param for.
2167 * @param int $iter The component-iteration to set the param for.
2168 * @param int $part The part number of the component-iteration to set
2169 * the param for.
2170 * @param mixed $rept The repetition number within the part to get;
2171 * if null, get all repetitions of the part within the
2172 * iteration.
2173 * @param mixed $text A string or array; the set of repeated values
2174 * for this component-iteration part.
2175 *
2176 * @access protected
2177 * @return void
2178 */
2179 function _setParam($comp, $iter, $part, $rept, $text)
2180 {
2181 $this->param[strtoupper($comp)][$iter][$part][$rept] = $text;
2182 }
2183
2184 /**
2185 * _getTelephoneType
2186 *
2187 * Resolves a HR friendly type to the internal
2188 * type used in the VCARD spec.
2189 *
2190 * @param string $type The type?!
2191 *
2192 * @access private
2193 * @return mixed string $type or Pear_Error
2194 * @see self::addTelephone()
2195 * @ses self::getTelephone()
2196 * @since 1.1.2
2197 */
2198 function _getTelephoneType($type)
2199 {
2200 switch ($type) {
2201
2202 case 'phone':
2203 return 'TEL';
2204 break;
2205
2206 case 'mobile':
2207 return 'TEL;PREF;CELL';
2208 break;
2209
2210 case 'voice':
2211 return 'TEL;PREF;VOICE';
2212 break;
2213
2214 case 'fax':
2215 return 'TEL;PREF;FAX';
2216 break;
2217
2218 default:
2219 $msg = 'Type: ' . $type . ' is not yet implemented.';
2220 return $this->raiseError($msg);
2221 break;
2222 }
2223 }
2224 }
2225 ?>