sabre/vobject
Parse, generate, and manipulate iCalendar (RFC5545) and vCard (RFC6350) data in PHP with an easy-to-use API. sabre/vobject supports reading/writing VObject structures for calendar and contact workflows via Composer install.
Install via Composer:
composer require sabre/vobject "^4.0"
Ensure PHP ≥7.4 (latest releases support up to PHP 8.4). The library is fully namespaced under Sabre\VObject.
First use case: Parse a .vcf contact file or .ics calendar export:
use Sabre\VObject\Reader;
$vcard = Reader::read(file_get_contents('contact.vcf'));
echo $vcard->FN->getValue(); // Output contact name
// New in 4.6.0: Fetch properties by type (e.g., all EMAILs with type 'work')
$emails = $vcard->getByTypes('EMAIL', ['work']);
foreach ($emails as $email) {
echo $email->getValue() . "\n";
}
$calendar = Reader::read(file_get_contents('events.ics'));
foreach ($calendar->VEVENT as $event) {
printf("%s: %s\n", $event->DTSTART->getValue(), $event->SUMMARY);
}
Review the vCard and iCalendar docs for detailed patterns.
Import/Export pipeline: Use Reader::read() (accepts strings, streams, or filenames) to parse ICS/VCF sources, then $component->serialize() to generate RFC-compliant output for download or storage.
Programmatic scheduling: Build events dynamically with createComponent() and attach recurrence rules:
$event = $calendar->createComponent('VEVENT');
$event->set('SUMMARY', 'Team Sync');
$event->DTSTART = new DateTime('2025-06-02 09:00:00');
$event->RRULE = 'FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,WE,FR';
$calendar->add($event);
Type-based property retrieval (new in 4.6.0):
Fetch vCard properties by type (e.g., all EMAIL properties with type work):
$workEmails = $vcard->getByTypes('EMAIL', ['work']);
$allPhones = $vcard->getByTypes('TEL'); // No type filter
iTip broker automation: Use ITip\Broker to auto-generate scheduling messages (REQUEST, CANCEL, REPLY) when events change. Detect significant changes and trigger notifications without manual SMTP code.
Recurrence expansion: Iterate complex RRULEs (including BYSETPOS, YEARLY) via RRuleIterator to render future instances for calendars or reminders:
$iterator = new RRuleIterator($event->RRULE, $event->DTSTART->getDateTime());
foreach ($iterator->getOccurrencesBetween($start, $end) as $occurrence) {
// Render or process each instance
}
Timezone-aware parsing: When handling scheduling, use Reader::read($data, Reader::OPTION_IGNORE_INVALID_LINES | Reader::OPTION_FORGIVING) to safely parse malformed but recoverable inputs (e.g., from legacy clients). Note: Updated timezone handling in 4.6.0 (see Gotchas).
Timezone handling (updated in 4.6.0):
DTSTART/DTEND use the correct value type (e.g., DATE-TIME with TZID or Z).FindFromTimezoneMap::find() no longer throws an exception for invalid timezones—it returns null (consistent with documented behavior). Update error-handling logic if relying on exceptions:
$tz = FindFromTimezoneMap::find('INVALID/TZ');
if ($tz === null) {
// Handle invalid timezone gracefully
}
EST, CST) are now updated to their modern equivalents (e.g., America/New_York). Validate timezone strings in legacy data.RRULE pitfalls: Invalid RRULEs throw InvalidDataException since v4.5.6. Validate rules before setting them (e.g., via Rrule::validate() if using custom rules).
Property groups matter: In vCards, ensure group prefixes (e.g., item1.FN, item1.EMAIL) are preserved or stripped consistently—use getProperty('item1.FN') or rely on select() when groups are unknown. New in 4.6.0: Use getByTypes() to filter properties by type without manual group handling.
Performance: For large calendars, avoid loading full .ics files if you only need a date range; manually parse and skip irrelevant components. Reader::read() is forgiving but may be slower than Document::parse() for known-good data.
Extensibility: Extend Component or Property classes to add custom properties (e.g., X-CUSTOM-REF), and use VObject\NodeList to iterate non-standard fields.
PHP 8.1+ compatibility: Avoid passing null where scalar types are expected. Many methods now declare strict return types (e.g., xmlSerialize(): void). Upgrade to v4.6.0+ for full PHP 8.4 support and timezone fixes.
New in 4.6.0: getByTypes() simplifies querying vCard properties by type. Example:
// Fetch all URLs with type 'home'
$homeUrls = $vcard->getByTypes('URL', ['home']);
How can I help you explore Laravel packages today?