Usage instructions

Getting started

Make sure you followed all the steps in the installation instructions, and you've included the autoloader in your code.

A basic parsing example

Assuming there is a vCard in your local directory, named cowboyhenk.vcf, the following complete example will parse it and display the FN property:

use Sabre\VObject;

include 'vendor/autoload.php';

$vcard = VObject\Reader::read(
    fopen('cowboyhenk.vcf','r')
);
echo $vcard->FN;

That is all.

For all the following examples, we are assuming that you have already included the autoloader, and also that you've called

use Sabre\VObject;

at the top of your script. This is just to avoid repetition.

The actual manual

Creating vCards

To create a vCard, you can simply instantiate the VCard component, and pass the properties you need:

$vcard = new VObject\Component\VCard([
    'FN'  => 'Cowboy Henk',
    'TEL' => '+1 555 34567 455',
    'N'   => ['Henk', 'Cowboy', '', 'Dr.', 'MD'],
]);

echo $vcard->serialize();

This will output:

BEGIN:VCARD
VERSION:3.0
PRODID:-//Sabre//Sabre VObject 4.0.0-beta1//EN
FN:Cowboy Henk
TEL:+1 555 34567 455
N:Henk;Cowboy;;Dr.;MD
END:VCARD

Manipulating properties

The vCard also allows object-access to manipulate properties:

// Overwrites or sets a property:
$vcard->FN = 'Doctor McNinja';

// Removes a property
unset($vcard->FN);

// Checks for existence of a property:

isset($vcard->FN);

Certain properties, such as TEL, ADR or EMAIL may appear more than once. To add any additional properties, use the add() method on the vCard.

$vcard->add('TEL', '+1 555 34567 456', ['type' => 'fax']);

The third argument of the add() method allows you to specify a list of parameters.

Working with parameters

To get access to a parameter, you can simply use array-access:

$type = $vcard->TEL['TYPE'];
echo (string)$type;

Parameters can also appear multiple times. To get to their values, just loop through them:

if ($param = $vcard->TEL['TYPE']) {
    foreach($param as $value) {
      echo $value, "\n";
    }
}

To change parameters for properties, you can use array-access syntax:

$vcard->TEL['TYPE'] = ['WORK','FAX'];

Or when you're working with singular parameters:

$vcard->TEL['PREF'] = 1;

It is also possible add a list of parameters while creating the property.

$vcard->add(
    'EMAIL',
    'foo@example.org',
    [
        'type' => ['home', 'work'],
        'pref' => 1,
    ]
);

Parsing vCard

To parse a vCard or iCalendar object, simply call:

// $data must be either a string, or a stream.
$vcard = VObject\Reader::read($data);

When you're working with data generated by broken software (such as the latest Microsoft Outlook), you can pass a 'forgiving' option that will do an attempt to mend the broken data.

$vcard = VObject\Reader::read($data, VObject\Reader::OPTION_FORGIVING);

Many vCards these days are encoded as UTF-8. If however you are running into a vCard with a different encoding, you can specify this as the third option:

$vcard = VObject\Reader::read($data, 0, 'ISO-8859-1');

Currently ISO-8859-1 and Windows-1252 are supported. This feature appeared in vObject 4.

Reading property values

For properties that are stored as a string, you can simply call:

echo (string)$vcard->FN;

For properties that contain more than 1 part, such as ADR, N or ORG you can call getParts().

print_r(
    $vcard->ORG->getParts()
);

Looping through properties.

Properties such as ADR, EMAIL and TEL may appear more than once in a vCard. To loop through them, you can simply throw them in a foreach() statement:

foreach($vcard->TEL as $tel) {
    echo 'Phone number: ', $tel, "\n";
}

foreach($vcard->ADR as $adr) {
    print_r($adr->getParts());
}

vCard property grouping

It's allowed in vCards to group multiple properties together with an arbitrary string.

Apple clients use this feature to assign custom labels to things like phone numbers and email addresses. Below is an example:

BEGIN:VCARD
VERSION:3.0
groupname.TEL:+1 555 12342567
groupname.X-ABLABEL:UK number
END:VCARD

In our example, you can see that the TEL properties are prefixed. These are 'groups' and allow you to group multiple related properties together.

In most situations these group names are ignored, so when you execute the following example, the TEL properties are still traversed.

foreach($vcard->TEL as $tel) {
    echo $tel, "\n";
}

But if you would like to target a specific group + property, this is possible too:

echo (string)$vcard->{'groupname.TEL'};

To expand that example a little bit; if you'd like to traverse through all phone numbers and display their custom labels, you'd do something like this:

foreach($vcard->TEL as $tel) {

    echo $vcard->{$tel->group . '.X-ABLABEL'}, ': ';
    echo $tel, "\n";

}

Getting a property by its TYPE value

Many vCard properties, such as TEL, ADR and EMAIL support a TYPE attribute.

BEGIN:VCARD
TEL;TYPE=HOME,FAX:+15551234566
EMAIL;TYPE=HOME;TYPE=WORK:foobar@example.org
END:VCARD

If you quickly want to get all the properties that have a specific TYPE value, you can do this with:

$email = $vcard->getByType('EMAIL','WORK');

This function only returns the first property it finds, and will return null if no property with that TYPE could be found.

Converting between different vCard versions

Since sabre/vobject 3.1, there's also a feature to convert between various vCard versions. Currently it's possible to convert from vCard 2.1, 3.0 and 4.0 and to 3.0 and 4.0. It's not yet possible to convert to vCard 2.1.

To do this, simply call the convert() method on the vCard object.

$input = <<<VCARD
BEGIN:VCARD
VERSION:2.1
FN;CHARSET=UTF-8:Foo
TEL;PREF;HOME:+1 555 555 555
END:VCARD
VCARD;

$vcard = VObject\Reader::read($input);
$vcard = $vcard->convert(VObject\Document::VCARD40);

echo $vcard->serialize();

// This will output:
/*
BEGIN:VCARD
VERSION:4.0
FN:Foo
TEL;PREF=1;TYPE=HOME:+1 555 555 555
END:VCARD
*/

It's important to note that not every bit of information can be cleanly converted between versions. So there's a possibility that you loose some small bits of information going back and forward. For instance, vCard 2.1 is the only vCard version that supports the AGENT property, so it's dropped when going to vCard 3 or higher.

Validating vCard

When you parse a vCard, the parser grabs all the values and does basic syntax checking. It does not however, validate every value.

You can ask the parser to validate the entire document by calling the validate function though:

$result = $vcard->validate();

The returned value is an array of messages and might look like this:

[
    [
        'level' => 2,
        'message' => '...',
        'node' => ...A VObject component or property...
    ]
]

Each item constitutes a problem with the document. Every item contains a level containing a number between 1 and 3. 3 Means that the document is invalid, 2 means a warning. A warning means it's valid but it could cause interoperability issues, and 1 means that there was a problem earlier, but the problem was automatically repaired.

The message is a human-readable string with more information about the problem, and lastly the node refers to the actual VObject Component or Property object that had the issue.

You can also pass several options. The options have to be passed as a bitfield:

$vcalendar->validate(Sabre\VObject\Node::REPAIR);
$vcalendar->validate(Sabre\VObject\Node::PROFILE_CARDDAV);

The REPAIR option automatically repairs the object, if possible. Without REPAIR the validator does not change the object.

The PROFILE_CARDDAV validates the object specifically for within the use of CardDAV. vCards CardDAV servers have a few additional special restrictions (must have a UID property for instance).

The validator is not perfect, and we improve it when we come across new issues, so any suggestions are welcome.

Support

Head over to the SabreDAV mailing list for any questions.