3 * Build (create) and fetch vCard 2.1 and 3.0 text blocks.
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.
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
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);
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);
38 // Part numbers for GEO components
39 define('VCARD_GEO_LAT', 0);
40 define('VCARD_GEO_LON', 1);
45 require_once 'PEAR.php';
48 * This class builds a single vCard (version 3.0 or 2.1).
50 * General note: we use the terms "set" "add" and "get" as function
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.
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
61 * "Get" returns the full vCard line for a single iteration.
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
72 class Contact_Vcard_Build
extends PEAR
75 * Values for vCard components.
83 * Parameters for vCard components.
91 * Tracks which component (N, ADR, TEL, etc) value was last set or added.
92 * Used when adding parameters automatically to the proper component.
97 var $autoparam = null;
102 * @param string $version The vCard version to build; affects which
103 * parameters are allowed and which components
104 * are returned by fetch().
108 * @see Contact_Vcard_Build::fetch()
110 function Contact_Vcard_Build($version = '3.0')
113 $this->setErrorHandling(PEAR_ERROR_PRINT
);
114 $this->setVersion($version);
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.
122 * Escapes a string so that...
126 * newline => literal \n
128 * @param mixed &$text The string or array or strings to escape.
131 * @return mixed Void on success, or a PEAR_Error object on failure.
133 function escape(&$text)
135 if (is_object($text)) {
137 $msg = 'The escape() method works only with string literals and arrays.';
138 return $this->raiseError($msg);
141 if (is_array($text)) {
143 foreach ($text as $key => $val) {
151 // escape colons not led by a backslash
152 $regex = '(?<!\\\\)(\:)';
153 $text = preg_replace("/$regex/i", "\\:", $text);
155 // escape semicolons not led by a backslash
156 $regex = '(?<!\\\\)(\;)';
157 $text = preg_replace("/$regex/i", "\\;", $text);
159 // escape commas not led by a backslash
160 $regex = '(?<!\\\\)(\,)';
161 $text = preg_replace("/$regex/i", "\\,", $text);
165 $text = preg_replace("/$regex/i", "\\n", $text);
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);
174 // fix http(s)\:// to http(s)://
175 $text = str_replace('http\://', 'http://', $text);
176 $text = str_replace('https\://', 'http://', $text);
182 * Adds a parameter value for a given component and parameter name.
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.
191 * $vcard = new Contact_Vcard_Build();
193 * // set "TYPE=HOME,PREF" for the first TEL component
194 * $vcard->addParam('TYPE', 'HOME', 'TEL', 0);
195 * $vcard->addParam('TYPE', 'PREF', 'TEL', 0);
197 * @param string $param_name The parameter name, such as TYPE, VALUE,
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.
211 * @return mixed Void on success, or a PEAR_Error object on failure.
213 function addParam($param_name, $param_value, $comp = null, $iter = null)
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
;
221 // using a null iteration means the param should be associated
222 // with the latest/most-recent iteration of the selected
224 if ($iter === null) {
225 $iter = $this->countIter($comp) - 1;
228 // massage the text arguments
229 $comp = strtoupper(trim($comp));
230 $param_name = strtoupper(trim($param_name));
231 $param_value = trim($param_value);
233 if (! is_integer($iter) ||
$iter < 0) {
235 $msg = "$iter is not a valid iteration number for $comp; ";
236 $msg .= "must be a positive integer.";
238 return $this->raiseError($msg);
242 $result = $this->validateParam($param_name, $param_value, $comp, $iter);
244 if (PEAR
::isError($result)) {
247 $this->param
[$comp][$iter][$param_name][] = $param_value;
252 * Validates parameter names and values based on the vCard version
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.
263 * @return mixed Boolean true if the parameter is valid, or a
264 * PEAR_Error object if not.
267 function validateParam($name, $text, $comp = null, $iter = null)
269 $name = strtoupper($name);
270 $text = strtoupper($text);
275 case 'TEL;PREF;CELL':
276 case 'TEL;PREF;VOICE':
283 // all param values must have only the characters A-Z 0-9 and -.
284 if (preg_match('/[^a-zA-Z0-9\-]/i', $text)) {
286 $msg = "vCard [$comp] [$iter] [$name]: ";
287 $msg .= 'The parameter value may contain only ';
288 $msg .= 'a-z, A-Z, 0-9, and dashes (-).';
290 return $this->raiseError($msg);
296 if ($this->value
['VERSION'][0][0][0] == '2.1') {
298 // Validate against version 2.1 (pretty strict)
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',
317 if (! in_array($text, $types)) {
318 $msg = "vCard 2.1 [$comp] [$iter]: ";
319 $msg .= "$text is not a recognized TYPE.";
321 $result = $this->raiseError($msg);
328 if ($text != '7BIT' &&
331 $text != 'QUOTED-PRINTABLE') {
332 $msg = "vCard 2.1 [$comp] [$iter]: ";
333 $msg .= "$text is not a recognized ENCODING.";
335 $result = $this->raiseError($msg);
342 // all charsets are OK
347 // all languages are OK
352 if ($text != 'INLINE' &&
353 $text != 'CONTENT-ID' &&
358 $msg = "vCard 2.1 [$comp] [$iter]: ";
359 $msg .= "$text is not a recognized VALUE.";
361 $result = $this->raiseError($msg);
368 $msg = "vCard 2.1 [$comp] [$iter]: ";
369 $msg .= "$name is an unknown or invalid parameter name.";
371 return $this->raiseError($msg);
375 } elseif ($this->value
['VERSION'][0][0][0] == '3.0') {
377 // Validate against version 3.0 (pretty lenient)
387 // all languages are OK
392 if ($text != '8BIT' &&
395 $msg = "vCard 3.0 [$comp] [$iter]: ";
396 $msg .= "The only allowed ENCODING";
397 $msg .= " parameters are 8BIT and B.";
399 $result = $this->raiseError($msg);
406 if ($text != 'BINARY' &&
407 $text != 'PHONE-NUMBER' &&
410 $text != 'UTC-OFFSET' &&
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.";
418 return $this->raiseError($msg);
425 $msg = "vCard 3.0 [$comp] [$iter]: ";
426 $msg .= "Unknown or invalid parameter name ($name).";
428 return $this->raiseError($msg);
434 $msg = "[$comp] [$iter] Unknown vCard version number or other error.";
435 return $this->raiseError($msg);
444 * Gets back the parameter string for a given component.
446 * @param string $comp The component to get parameters for
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.
456 function getParam($comp, $iter = 0)
458 $comp = strtoupper($comp);
461 if (isset($this->param
[$comp][$iter]) &&
462 is_array($this->param
[$comp][$iter])) {
464 // loop through the array of parameters for
467 foreach ($this->param
[$comp][$iter] as $param_name => $param_val) {
469 // if there were previous parameter names, separate with
475 if ($param_val === null) {
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;
483 // set the parameter name...
484 $text .= strtoupper($param_name) . '=';
486 // ...then escape and comma-separate the parameter
488 $this->escape($param_val);
489 $text .= implode(',', $param_val);
494 // if there were no parameters, this will be blank.
500 * Resets the vCard values and params to be blank.
502 * @param string $version The vCard version to reset to ('2.1' or
503 * '3.0' -- default is the same version as
509 function reset($version = null)
511 $prev = $this->value
['VERSION'][0][0][0];
513 $this->value
= array();
514 $this->param
= array();
515 $this->autoparam
= null;
517 if ($version === null) {
518 $this->setVersion($prev);
520 $this->setVersion($version);
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.
530 * @param string $comp The component to set the value for ('N',
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
535 * @param mixed $text A string or array; the set of repeated values
536 * for this component-iteration part.
541 function setValue($comp, $iter, $part, $text)
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;
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.
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
560 * @param mixed $text A string or array; the set of repeated values
561 * for this component-iteration part.
566 function addValue($comp, $iter, $part, $text)
568 $comp = strtoupper($comp);
570 settype($text, 'array');
572 foreach ($text as $val) {
573 $this->value
[$comp][$iter][$part][] = $val;
575 $this->autoparam
= $comp;
579 * Generic, all-purpose method to get back the data stored in $this->value.
581 * @param string $comp The component to set the value for ('N',
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
586 * @param mixed $rept The repetition number within the part to get;
587 * if null, get all repetitions of the part within the
591 * @return string The value, escaped and delimited, of all
592 * repetitions in the component-iteration part (or specific
593 * repetition within the part).
595 function getValue($comp, $iter = 0, $part = 0, $rept = null)
597 if ($rept === null &&
598 is_array($this->value
[$comp][$iter][$part]) ) {
600 // get all repetitions of a part
602 foreach ($this->value
[$comp][$iter][$part] as $key => $val) {
603 $list[] = trim($val);
606 $this->escape($list);
607 return implode(',', $list);
611 // get a specific repetition of a part
612 $text = trim($this->value
[$comp][$iter][$part][$rept]);
613 $this->escape($text);
618 * Sets the full N component of the vCard. Will replace all other
619 * values. There can only be one N component per vCard.
621 * @param mixed $family Single (string) or multiple (array)
623 * @param mixed $given Single (string) or multiple (array)
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.
635 function setName($family, $given, $addl, $prefix, $suffix)
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);
647 * Gets back the full N component (first iteration only, since there
648 * can only be one N component per vCard).
651 * @return string The first N component-interation of the vCard.
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
);
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.
668 * @param string $text Override the automatic generation of FN from N
669 * elements with the specified text.
672 * @return mixed Void on success, or a PEAR_Error object on failure.
674 function setFormattedName($text = null)
676 $this->autoparam
= 'FN';
678 if ($text !== null) {
679 $this->setValue('FN', 0, 0, $text);
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'])) {
688 // first (given) name, first iteration, first repetition
689 $text .= $this->getValue('N', 0, VCARD_N_GIVEN
, 0);
691 // add a space after, if there was text
696 // last (family) name, first iteration, first repetition
697 $text .= $this->getValue('N', 0, VCARD_N_FAMILY
, 0);
699 // add a space after, if there was text
704 // last-name suffix, first iteration, first repetition
705 $text .= $this->getValue('N', 0, VCARD_N_SUFFIX
, 0);
707 $this->setValue('FN', 0, 0, $text);
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);
717 * Gets back the full FN component value. Only ever returns iteration
718 * zero, because only one FN component is allowed per vCard.
721 * @uses self::getMeta()
722 * @return string The FN value of the vCard.
723 * @uses self::getMeta()
725 function getFormattedName()
727 return $this->getMeta('FN', 0) . $this->getValue('FN', 0, 0);
731 * Sets the version of the the vCard. Only one iteration.
733 * @param string $text The text value of the verson text ('3.0' or '2.1').
736 * @return mixed Void on success, or a PEAR_Error object on failure.
738 function setVersion($text = '3.0')
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.');
744 $this->setValue('VERSION', 0, 0, $text);
748 * Gets back the version of the the vCard. Only one iteration.
751 * @uses self::getMeta()
752 * @return string The data-source of the vCard.
754 function getVersion()
756 return $this->getMeta('VERSION', 0) . $this->getValue('VERSION', 0);
760 * Sets the data-source of the the vCard. Only one iteration.
762 * @param string $text The text value of the data-source text.
767 function setSource($text)
769 $this->autoparam
= 'SOURCE';
770 $this->setValue('SOURCE', 0, 0, $text);
774 * Gets back the data-source of the the vCard. Only one iteration.
777 * @return string The data-source of the vCard.
781 return $this->getMeta('SOURCE', 0) . $this->getValue('SOURCE', 0, 0);
785 * Sets the displayed name of the vCard data-source. Only one iteration.
786 * If no name is specified, copies the value of SOURCE.
788 * @param string $text The text value of the displayed data-source
789 * name. If null, copies the value of SOURCE.
792 * @return mixed Void on success, or a PEAR_Error object on failure.
794 function setSourceName($text = null)
796 $this->autoparam
= 'NAME';
798 if ($text === null) {
799 if (is_array($this->value
['SOURCE'])) {
800 $text = $this->getValue('SOURCE', 0, 0);
802 $msg = 'NAME not specified and SOURCE not set; cannot set NAME.';
803 return $this->raiseError($msg);
807 $this->setValue('NAME', 0, 0, $text);
811 * Gets back the displayed data-source name of the the vCard. Only
815 * @return string The data-source name of the vCard.
817 function getSourceName()
819 return $this->getMeta('NAME', 0) . $this->getValue('NAME', 0, 0);
823 * Sets the value of the PHOTO component. There is only one allowed
826 * @param string $text The value to set for this component.
827 * @param boolean $url True or false, depending if $text is one.
832 function setPhoto($text, $url = false)
834 if ($url === false) {
835 $this->autoparam
= 'PHOTO';
836 $this->setValue('PHOTO', 0, 0, $text);
839 $this->autoparam
= 'PHOTO;VALUE=URI';
840 $this->setValue('PHOTO;VALUE=URI', 0, 0, $text);
844 * Gets back the value of the PHOTO component. There is only one
848 * @return string The value of this component or false if no photo is set.
852 if (isset($this->value
['PHOTO'])) {
853 return $this->getMeta('PHOTO') . $this->getValue('PHOTO', 0, 0);
855 if (isset($this->value
['PHOTO;VALUE=URI'])) {
856 return $this->getMeta('PHOTO;VALUE=URI') .
857 $this->getValue('PHOTO;VALUE=URI', 0, 0);
863 * Sets the value of the LOGO component. There is only one allowed
866 * @param string $text The value to set for this component.
871 function setLogo($text)
873 $this->autoparam
= 'LOGO';
874 $this->setValue('LOGO', 0, 0, $text);
878 * Gets back the value of the LOGO component. There is only one
882 * @return string The value of this component.
886 return $this->getMeta('LOGO') . $this->getValue('LOGO', 0, 0);
890 * Sets the value of the SOUND component. There is only one allowed
893 * @param string $text The value to set for this component.
898 function setSound($text)
900 $this->autoparam
= 'SOUND';
901 $this->setValue('SOUND', 0, 0, $text);
905 * Gets back the value of the SOUND component. There is only one
909 * @return string The value of this component.
913 return $this->getMeta('SOUND') . $this->getValue('SOUND', 0, 0);
917 * Sets the value of the KEY component. There is only one allowed
920 * @param string $text The value to set for this component.
925 function setKey($text)
927 $this->autoparam
= 'KEY';
928 $this->setValue('KEY', 0, 0, $text);
932 * Gets back the value of the KEY component. There is only one
936 * @return string The value of this component.
940 return $this->getMeta('KEY') . $this->getValue('KEY', 0, 0);
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]]]".
947 * @param string $text The value to set for this component.
952 function setBirthday($text)
954 $this->autoparam
= 'BDAY';
955 $this->setValue('BDAY', 0, 0, $text);
959 * Gets back the value of the BDAY component. There is only one
963 * @return string The value of this component.
965 function getBirthday()
967 return $this->getMeta('BDAY') . $this->getValue('BDAY', 0, 0);
971 * Sets the value of the TZ component. There is only one allowed per
974 * @param string $text The value to set for this component.
979 function setTZ($text)
981 $this->autoparam
= 'TZ';
982 $this->setValue('TZ', 0, 0, $text);
986 * Gets back the value of the TZ component. There is only one
990 * @return string The value of this component.
994 return $this->getMeta('TZ') . $this->getValue('TZ', 0, 0);
998 * Sets the value of the MAILER component. There is only one allowed
1001 * @param string $text The value to set for this component.
1006 function setMailer($text)
1008 $this->autoparam
= 'MAILER';
1009 $this->setValue('MAILER', 0, 0, $text);
1013 * Gets back the value of the MAILER component. There is only one
1014 * allowed per vCard.
1017 * @return string The value of this component.
1019 function getMailer()
1021 return $this->getMeta('MAILER') . $this->getValue('MAILER', 0, 0);
1025 * Sets the value of the NOTE component. There is only one allowed
1028 * @param string $text The value to set for this component.
1033 function setNote($text)
1035 $this->autoparam
= 'NOTE';
1036 $this->setValue('NOTE', 0, 0, $text);
1040 * Gets back the value of the NOTE component. There is only one
1041 * allowed per vCard.
1044 * @return string The value of this component.
1048 return $this->getMeta('NOTE') . $this->getValue('NOTE', 0, 0);
1052 * Sets the value of the TITLE component. There is only one allowed
1055 * @param string $text The value to set for this component.
1060 function setTitle($text)
1062 $this->autoparam
= 'TITLE';
1063 $this->setValue('TITLE', 0, 0, $text);
1067 * Gets back the value of the TITLE component. There is only one
1068 * allowed per vCard.
1071 * @return string The value of this component.
1075 return $this->getMeta('TITLE') . $this->getValue('TITLE', 0, 0);
1079 * Sets the value of the ROLE component. There is only one allowed
1082 * @param string $text The value to set for this component.
1087 function setRole($text)
1089 $this->autoparam
= 'ROLE';
1090 $this->setValue('ROLE', 0, 0, $text);
1094 * Gets back the value of the ROLE component. There is only one
1095 * allowed per vCard.
1098 * @return string The value of this component.
1102 return $this->getMeta('ROLE') . $this->getValue('ROLE', 0, 0);
1106 * Sets the value of the URL component. There is only one allowed
1109 * @param string $text The value to set for this component.
1114 function setURL($text)
1116 $this->autoparam
= 'URL';
1117 $this->setValue('URL', 0, 0, $text);
1121 * Gets back the value of the URL component. There is only one
1122 * allowed per vCard.
1125 * @return string The value of this component.
1129 return $this->getMeta('URL') . $this->getValue('URL', 0, 0);
1133 * Sets the value of the CLASS component. There is only one allowed
1136 * @param string $text The value to set for this component.
1141 function setClass($text)
1143 $this->autoparam
= 'CLASS';
1144 $this->setValue('CLASS', 0, 0, $text);
1148 * Gets back the value of the CLASS component. There is only one
1149 * allowed per vCard.
1152 * @return string The value of this component.
1156 return $this->getMeta('CLASS') . $this->getValue('CLASS', 0, 0);
1160 * Sets the value of the SORT-STRING component. There is only one
1161 * allowed per vCard.
1163 * @param string $text The value to set for this component.
1168 function setSortString($text)
1170 $this->autoparam
= 'SORT-STRING';
1171 $this->setValue('SORT-STRING', 0, 0, $text);
1175 * Gets back the value of the SORT-STRING component. There is only
1176 * one allowed per vCard.
1179 * @return string The value of this component.
1181 function getSortString()
1183 return $this->getMeta('SORT-STRING') . $this->getValue('SORT-STRING', 0, 0);
1187 * Sets the value of the PRODID component. There is only one allowed
1190 * @param string $text The value to set for this component.
1195 function setProductID($text)
1197 $this->autoparam
= 'PRODID';
1198 $this->setValue('PRODID', 0, 0, $text);
1202 * Gets back the value of the PRODID component. There is only one
1203 * allowed per vCard.
1206 * @return string The value of this component.
1208 function getProductID()
1210 return $this->getMeta('PRODID') . $this->getValue('PRODID', 0, 0);
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.
1218 * @param string $text The value to set for this component.
1223 function setRevision($text)
1225 $this->autoparam
= 'REV';
1226 $this->setValue('REV', 0, 0, $text);
1230 * Gets back the value of the REV component. There is only one
1231 * allowed per vCard.
1234 * @return string The value of this component.
1236 function getRevision()
1238 return $this->getMeta('REV') . $this->getValue('REV', 0, 0);
1242 * Sets the value of the UID component. There is only one allowed
1245 * @param string $text The value to set for this component.
1250 function setUniqueID($text)
1252 $this->autoparam
= 'UID';
1253 $this->setValue('UID', 0, 0, $text);
1257 * Gets back the value of the UID component. There is only one
1258 * allowed per vCard.
1261 * @return string The value of this component.
1263 function getUniqueID()
1265 return $this->getMeta('UID') . $this->getValue('UID', 0, 0);
1269 * Sets the value of the AGENT component. There is only one allowed
1272 * @param string $text The value to set for this component.
1277 function setAgent($text)
1279 $this->autoparam
= 'AGENT';
1280 $this->setValue('AGENT', 0, 0, $text);
1284 * Gets back the value of the AGENT component. There is only one
1285 * allowed per vCard.
1288 * @return string The value of this component.
1292 return $this->getMeta('AGENT') . $this->getValue('AGENT', 0, 0);
1296 * Sets the value of both parts of the GEO component. There is only
1297 * one GEO component allowed per vCard.
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 -).
1307 function setGeo($lat, $lon)
1309 $this->autoparam
= 'GEO';
1310 $this->setValue('GEO', 0, VCARD_GEO_LAT
, $lat);
1311 $this->setValue('GEO', 0, VCARD_GEO_LON
, $lon);
1315 * Gets back the value of the GEO component. There is only one
1316 * allowed per vCard.
1319 * @return string The value of this component.
1323 return $this->getMeta('GEO', 0) .
1324 $this->getValue('GEO', 0, VCARD_GEO_LAT
, 0) . ';' .
1325 $this->getValue('GEO', 0, VCARD_GEO_LON
, 0);
1329 * Sets the value of one entire ADR iteration. There can be zero,
1330 * one, or more ADR components in a vCard.
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.
1357 function addAddress($pob, $extend, $street, $locality, $region,
1358 $postcode, $country)
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);
1372 * Gets back the value of one ADR component iteration.
1374 * @param int $iter The component iteration-number to get the value
1378 * @return mixed The value of this component iteration, or a
1379 * PEAR_Error if the iteration is not valid.
1381 function getAddress($iter)
1383 if (! is_integer($iter) ||
$iter < 0) {
1384 return $this->raiseError('ADR iteration number not valid.');
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
);
1397 * Sets the value of one LABEL component iteration. There can be
1398 * zero, one, or more component iterations in a vCard.
1400 * @param string $text The value to set for this component.
1405 function addLabel($text)
1407 $this->autoparam
= 'LABEL';
1408 $iter = $this->countIter('LABEL');
1409 $this->setValue('LABEL', $iter, 0, $text);
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.
1416 * @param int $iter The component iteration-number to get the value
1420 * @return mixed The value of this component, or a PEAR_Error if
1421 * the iteration number is not valid.
1423 function getLabel($iter)
1425 if (! is_integer($iter) ||
$iter < 0) {
1426 return $this->raiseError('LABEL iteration number not valid.');
1428 return $this->getMeta('LABEL', $iter) .
1429 $this->getValue('LABEL', $iter, 0);
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
1438 * @param string $text The value to set for this component.
1439 * @param string $type The type: phone, mobile, fax or voice
1442 * @return mixed void on success, PEAR_Error on failure
1443 * @uses self::_getTelephoneType()
1445 function addTelephone($text, $type = 'phone')
1447 $autoparam = $this->_getTelephoneType($type);
1448 if (PEAR
::isError($autoparam)) {
1452 $iter = $this->countIter($autoparam);
1453 $this->setValue($autoparam, $iter, 0, $text);
1455 $this->autoparam
= $autoparam;
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.
1462 * @param int $iter The component iteration-number to get the value
1464 * @param string $type The type: phone, mobile, fax, voice
1467 * @return mixed The value of this component, or a PEAR_Error if the
1468 * iteration number is not valid.
1469 * @uses self::_getTelephoneType()
1471 function getTelephone($iter, $type = 'phone')
1473 $autoparam = $this->_getTelephoneType($type);
1474 if (PEAR
::isError($autoparam)) {
1478 if (!is_integer($iter) ||
$iter < 0) {
1479 return $this->raiseError($autoparam . ' iteration number not valid.');
1482 return $this->getMeta($autoparam, $iter) .
1483 $this->getValue($autoparam, $iter, 0);
1487 * Sets the value of one EMAIL component iteration. There can be zero,
1488 * one, or more component iterations in a vCard.
1490 * @param string $text The value to set for this component.
1495 function addEmail($text)
1497 $this->autoparam
= 'EMAIL';
1498 $iter = $this->countIter('EMAIL');
1499 $this->setValue('EMAIL', $iter, 0, $text);
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.
1506 * @param int $iter The component iteration-number to get the value
1511 * @return mixed The value of this component, or a PEAR_Error if the
1512 * iteration number is not valid.
1515 function getEmail($iter)
1517 if (! is_integer($iter) ||
$iter < 0) {
1518 return $this->raiseError('EMAIL iteration number not valid.');
1520 return $this->getMeta('EMAIL', $iter) .
1521 $this->getValue('EMAIL', $iter, 0);
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.
1529 * @param mixed $text String (one repetition) or array (multiple
1530 * reptitions) of the component iteration value.
1535 function addNickname($text)
1537 $this->autoparam
= 'NICKNAME';
1538 $this->addValue('NICKNAME', 0, 0, $text);
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.
1547 * @return string The value of this component.
1549 function getNickname()
1551 return $this->getMeta('NICKNAME') . $this->getValue('NICKNAME', 0, 0);
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.
1559 * @param mixed $text String (one repetition) or array (multiple reptitions)
1560 * of the component iteration value.
1565 function addCategories($text)
1567 $this->autoparam
= 'CATEGORIES';
1568 $this->addValue('CATEGORIES', 0, 0, $text);
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.
1577 * @return string The value of this component.
1579 function getCategories()
1581 return $this->getMeta('CATEGORIES', 0) .
1582 $this->getValue('CATEGORIES', 0, 0);
1586 * Sets the full value of the ORG component. There can be only one
1587 * ORG component in a vCard.
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.)
1597 * @param mixed $text String (one ORG part) or array (of ORG parts) to
1598 * use as the value for the component iteration.
1603 function addOrganization($text)
1605 $this->autoparam
= 'ORG';
1607 settype($text, 'array');
1609 $base = $this->countRept('ORG', 0);
1611 // start at the original base point, and add
1613 foreach ($text as $part => $val) {
1614 $this->setValue('ORG', 0, $base +
$part, $val);
1619 * Gets back the value of the ORG component.
1621 * @return string The value of this component.
1624 function getOrganization()
1626 $text = $this->getMeta('ORG', 0);
1628 $k = $this->countRept('ORG', 0);
1631 for ($part = 0; $part < $k; $part++
) {
1633 $text .= $this->getValue('ORG', 0, $part);
1635 if ($part != $last) {
1645 * Builds a vCard from a Contact_Vcard_Parse result array. Only send
1646 * one vCard from the parse-results.
1648 * Usage (to build from first vCard in parsed results):
1650 * $parse = new Contact_Vcard_Parse(); // new parser
1651 * $info = $parse->fromFile('sample.vcf'); // parse file
1653 * $vcard = new Contact_Vcard_Build(); // new builder
1654 * $vcard->setFromArray($info[0]); // [0] is the first card
1656 * @param array $src One vCard entry as parsed using
1657 * Contact_Vcard_Parse.
1661 * @see Contact_Vcard_Parse::fromFile()
1662 * @see Contact_Vcard_Parse::fromText()
1664 function setFromArray($src)
1666 // reset to a blank values and params
1667 $this->value
= array();
1668 $this->param
= array();
1670 // loop through components (N, ADR, TEL, etc)
1671 foreach ($src as $comp => $comp_val) {
1673 // set the autoparam property. not really needed, but let's
1674 // behave after an expected fashion, shall we? ;-)
1675 $this->autoparam
= $comp;
1677 // iteration number of each component
1678 foreach ($comp_val as $iter => $iter_val) {
1681 foreach ($iter_val as $kind => $kind_val) {
1684 foreach ($kind_val as $part => $part_val) {
1686 // repetition number and text value
1687 foreach ($part_val as $rept => $text) {
1689 // ignore data when $kind is neither 'value'
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);
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).
1712 * @return string A properly formatted vCard text block.
1716 // vCard version is required
1717 if (! is_array($this->value
['VERSION'])) {
1718 return $this->raiseError('VERSION not set (required).');
1721 // FN component is required
1722 if (! is_array($this->value
['FN'])) {
1723 return $this->raiseError('FN component not set (required).');
1726 // N component is required
1727 if (! is_array($this->value
['N'])) {
1728 return $this->raiseError('N component not set (required).');
1731 // initialize the vCard lines
1735 $lines[] = "BEGIN:VCARD";
1737 // version (required)
1738 // available in both 2.1 and 3.0
1739 $lines[] = $this->getVersion();
1741 // profile (3.0 only)
1742 if ($this->value
['VERSION'][0][0][0] == '3.0') {
1743 $lines[] = "PROFILE:VCARD";
1746 // formatted name (required)
1747 // available in both 2.1 and 3.0
1748 $lines[] = $this->getFormattedName();
1750 // structured name (required)
1751 // available in both 2.1 and 3.0
1752 $lines[] = $this->getName();
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();
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();
1766 // nicknames (3.0 only)
1767 if (isset($this->value
['NICKNAME']) &&
1768 $this->value
['VERSION'][0][0][0] == '3.0') {
1769 $lines[] = $this->getNickname();
1773 // available in both 2.1 and 3.0
1774 $_photo = $this->getPhoto();
1775 if ($_photo !== false) {
1780 // available in both 2.1 and 3.0
1781 if (isset($this->value
['BDAY'])) {
1782 $lines[] = $this->getBirthday();
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);
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);
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);
1810 if (isset($this->value
['TEL;PREF;CELL'])) {
1811 foreach ($this->value
['TEL;PREF;CELL'] as $key => $val) {
1812 $lines[] = $this->getTelephone($key, 'mobile');
1817 if (isset($this->value
['TEL;PREF;VOICE'])) {
1818 foreach ($this->value
['TEL;PREF;VOICE'] as $key => $val) {
1819 $lines[] = $this->getTelephone($key, 'voice');
1824 if (isset($this->value
['TEL;PREF;FAX'])) {
1825 foreach ($this->value
['TEL;PREF;FAX'] as $key => $val) {
1826 $lines[] = $this->getTelephone($key, 'fax');
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);
1839 // available in both 2.1 and 3.0
1840 if (isset($this->value
['MAILER'])) {
1841 $lines[] = $this->getMailer();
1845 // available in both 2.1 and 3.0
1846 if (isset($this->value
['TZ'])) {
1847 $lines[] = $this->getTZ();
1851 // available in both 2.1 and 3.0
1852 if (isset($this->value
['GEO'])) {
1853 $lines[] = $this->getGeo();
1857 // available in both 2.1 and 3.0
1858 if (isset($this->value
['TITLE'])) {
1859 $lines[] = $this->getTitle();
1863 // available in both 2.1 and 3.0
1864 if (isset($this->value
['ROLE'])) {
1865 $lines[] = $this->getRole();
1869 // available in both 2.1 and 3.0
1870 if (isset($this->value
['LOGO'])) {
1871 $lines[] = $this->getLogo();
1875 // available in both 2.1 and 3.0
1876 if (isset($this->value
['AGENT'])) {
1877 $lines[] = $this->getAgent();
1881 // available in both 2.1 and 3.0
1882 if (isset($this->value
['ORG'])) {
1883 $lines[] = $this->getOrganization();
1886 // categories (3.0 only)
1887 if (isset($this->value
['CATEGORIES']) &&
1888 $this->value
['VERSION'][0][0][0] == '3.0') {
1889 $lines[] = $this->getCategories();
1893 // available in both 2.1 and 3.0
1894 if (isset($this->value
['NOTE'])) {
1895 $lines[] = $this->getNote();
1898 // prodid (3.0 only)
1899 if (isset($this->value
['PRODID']) &&
1900 $this->value
['VERSION'][0][0][0] == '3.0') {
1901 $lines[] = $this->getProductID();
1905 // available in both 2.1 and 3.0
1906 if (isset($this->value
['REV'])) {
1907 $lines[] = $this->getRevision();
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();
1916 // name-pronounciation sound
1917 // available in both 2.1 and 3.0
1918 if (isset($this->value
['SOUND'])) {
1919 $lines[] = $this->getSound();
1923 // available in both 2.1 and 3.0
1924 if (isset($this->value
['UID'])) {
1925 $lines[] = $this->getUniqueID();
1929 // available in both 2.1 and 3.0
1930 if (isset($this->value
['URL'])) {
1931 $lines[] = $this->getURL();
1935 if (isset($this->value
['CLASS']) &&
1936 $this->value
['VERSION'][0][0][0] == '3.0') {
1937 $lines[] = $this->getClass();
1941 // available in both 2.1 and 3.0
1942 if (isset($this->value
['KEY'])) {
1943 $lines[] = $this->getKey();
1947 $lines[] = "END:VCARD";
1949 // version 3.0 uses \n for new lines,
1950 // version 2.1 uses \r\n
1952 if ($this->value
['VERSION'][0][0][0] == '2.1') {
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));
1967 // recode the lines from UTF-8 to lowest covering charset
1968 $lines = $this->charsetRecode($lines);
1970 // compile the array of lines into a single text block
1971 // and return (with a trailing newline)
1972 return implode($newline, $lines). $newline;
1976 * Send the vCard as a downloadable file.
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
1985 * @return void or Pear_Error in case of an error.
1987 function send($filename, $disposition = 'attachment', $charset = 'us-ascii')
1989 $vcard = $this->fetch();
1990 if (PEAR
::isError($vcard)) {
1994 header('Content-Type: application/directory; ' .
1995 'profile="vcard"; ' .
1996 'charset=' . $charset);
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\"");
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.
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,
2018 * @return string The line prefix metadata.
2020 function getMeta($comp, $iter = 0)
2022 $params = $this->getParam($comp, $iter);
2024 if (trim($params) == '') {
2026 $text = $comp . ':';
2028 // has parameters. put an extra semicolon in.
2029 $text = $comp . ';' . $params . ':';
2036 * Recode the lines to the 'smallest' encoding and add the charset info
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')
2043 * @param array $lines the vCard's lines
2045 * @return array the recoded and properly tagged lines
2047 function charsetRecode($lines) {
2049 $charsets = array('US-ASCII', 'ISO-8859-1', 'CP1250');
2051 if ((function_exists('iconv_strlen') or function_exists('mb_strlen')) and function_exists('iconv')) {
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
2058 foreach ($lines as $number => $line) {
2059 $lineCharset = 'UTF-8';
2060 if (function_exists('iconv_strlen')) {
2061 $strlen = iconv_strlen($line, 'UTF-8');
2063 $strlen = mb_strlen($line, 'UTF-8');
2065 foreach ($charsets as $charset) {
2066 $iconvd = iconv('UTF-8', $charset, $line);
2067 if (strlen($iconvd) == $strlen) {
2068 $lineCharset = $charset;
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);
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);
2095 * Count the number of iterations for an element type.
2097 * @param string $type The element type to count iterations for
2101 * @return int The number of iterations for that type.
2103 function countIter($type)
2105 if (!isset($this->value
[$type])) {
2108 return count($this->value
[$type]);
2112 * Count the number of repetitions for an element type and iteration
2115 * @param string $type The element type to count iterations for
2117 * @param int $rept The iteration number to count repetitions for.
2120 * @return int The number of repetitions for that type and iteration.
2122 function countRept($type, $rept)
2124 if (!isset($this->value
[$type][$rept])) {
2127 return count($this->value
[$type][$rept]);
2131 * Emulated destructor.
2134 * @return boolean true
2136 function _Contact_Vcard_Build()
2144 * @param string $comp The component to set the value for ('N',
2146 * @param int $iter The component-iteration to set 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
2152 * @param mixed $text A string or array; the set of repeated values
2153 * for this component-iteration part.
2158 function _setValue($comp, $iter, $part, $rept, $text)
2160 $this->value
[strtoupper($comp)][$iter][$part][$rept] = $text;
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
2170 * @param mixed $rept The repetition number within the part to get;
2171 * if null, get all repetitions of the part within the
2173 * @param mixed $text A string or array; the set of repeated values
2174 * for this component-iteration part.
2179 function _setParam($comp, $iter, $part, $rept, $text)
2181 $this->param
[strtoupper($comp)][$iter][$part][$rept] = $text;
2187 * Resolves a HR friendly type to the internal
2188 * type used in the VCARD spec.
2190 * @param string $type The type?!
2193 * @return mixed string $type or Pear_Error
2194 * @see self::addTelephone()
2195 * @ses self::getTelephone()
2198 function _getTelephoneType($type)
2207 return 'TEL;PREF;CELL';
2211 return 'TEL;PREF;VOICE';
2215 return 'TEL;PREF;FAX';
2219 $msg = 'Type: ' . $type . ' is not yet implemented.';
2220 return $this->raiseError($msg);