clubmaster/vobject

PHP 的 VObject 库允许您轻松解析和操作 iCalendar 和 vCard 对象

2.0.2 2012-10-06 12:36 UTC

This package is not auto-updated.

Last update: 2024-09-22 03:14:00 UTC


README

Build Status

VObject 库允许您使用 PHP 轻松解析和操作 iCalendarvCard 对象。VObject 库的目标是创建一个非常完整的库,具有易于使用的 API。

该项目是从 SabreDAV 分离出来的,该项目已经使用了数年。VObject 库有 100% 的单元测试覆盖率。

安装

VObject 需要 PHP 5.3,应使用 composer 进行安装。有关 composer 的一般说明可以在 [composer 网站](https://getcomposer.org.cn/doc/00-intro.md composer 网站上找到)。

之后,只需如下声明 vobject 依赖项

"require" : {
    "sabre/vobject" : "dev-master"
}

然后,运行 composer.phar update,您应该就可以正常使用了。但是,一旦第一个版本发布,您应该将 dev-master 切换到 2.0.*

使用

解析

在我们的示例中,我们将使用以下 vCard

BEGIN:VCARD
VERSION:3.0
PRODID:-//Sabre//Sabre VObject 2.0//EN
N:Planck;Max;;;
FN:Max Planck
EMAIL;TYPE=WORK:mplanck@example.org
item1.TEL;TYPE=CELL:(+49)3144435678
item1.X-ABLabel:Private cell
item2.TEL;TYPE=WORK:(+49)5554564744
item2.X-ABLabel:Work
END:VCARD

如果我们只想打印出 Max 的全名,我们可以直接使用属性访问

use Sabre\VObject;

$card = VObject\Reader::read($data);
echo $card->FN;

更改属性

创建属性与这非常相似。如果我们想添加他的生日,我们只需设置属性

$card->BDAY = '1858-04-23';

注意,在上面的示例中,我们实际上正在更新可能已经存在的任何 BDAY。如果我们想添加一个新的属性,而不是覆盖先前的属性,我们可以使用 add 方法。

$card->add('EMAIL','max@example.org');

参数

如果我们想同时指定这是 max 的家庭电子邮件地址,我们可以使用第三个参数

$card->add('EMAIL', 'max@example'org', array('type' => 'HOME'));

如果我们想读取所有电子邮件地址及其类型,这将看起来像这样

foreach($card->EMAIL as $email) {

    echo $email['TYPE'], ' - ', $email;

}

在我们的示例中,您可以看到 TEL 属性是前缀的。这些都是 '组',允许您将多个相关属性组合在一起。组可以是任何用户定义的名称。

这个特定的示例是由 OS X 地址簿生成的,它使用 X-ABLabel 允许用户为属性指定自定义标签。OS X 地址簿使用组将标签与属性关联。

如果未指定组,VObject 库会简单地忽略它,因此这将起作用

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

但是,如果您想针对特定的组 + 属性,这也是可能的

echo $card->{'ITEM1.TEL'};

因此,如果您想显示所有电话号码及其自定义标签,将使用以下语法

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

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

}

序列化/保存

如果您想生成更新的 VObject,只需调用 serialize() 方法即可。

echo $card->serialize();

组件

iCalendar 与 vCard 不同,始终有子组件。vCards 通常只是扁平列表,而 iCalendar 对象倾向于具有树状结构。以下段落将使用以下对象作为示例

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Sabre//Sabre VObject 2.0//EN
BEGIN:VEVENT
SUMMARY:Curiosity landing
DTSTART:20120806T051439Z
LOCATION:Mars
END:VEVENT
END:VCALENDAR

由于事件、任务和日志始终在子组件中,因此我们也是这样访问它们的。

use Sabre\VObject;

$calendar = VObject\Reader::read($data);
echo $calendar->VEVENT->SUMMARY;

使用工厂方法向日历添加组件

$event = VObject\Component::create('VEVENT');
$calendar->add($event);

$event->SUMMARY = 'Curiosity launch';
$event->DTSTART = '20111126T150202Z';
$event->LOCATION = 'Cape Carnival';

顺便说一句,克隆也按预期工作,因为整个结构都会与其一起克隆。

$clonedEvent = clone $calendar->VEVENT[0];
$calendar->add($clonedEvent);

日期和时间处理

如果您曾经处理过iCalendar时区,您就知道这可能会很复杂。指定时区的方式有缺陷,这可能是我在某一天可能会写一篇文章的主题。VObject尽力确定正确的时区。已经测试和验证了许多标准格式,并为微软生成的时区信息和其他情况实现了特殊代码。

要获取真正的php DateTime对象,您可以按如下方式请求:

$event = $calendar->VEVENT;
$start = $event->DTSTART->getDateTime();
echo $start->format(\DateTime::W3C);

要使用DateTime对象设置属性,可以使用以下语法:

$dateTime = new \DateTime('2012-08-07 23:53:00', new DateTimeZone('Europe/Amsterdam'));
$event->DTSTART->setDateTime($dateTime, VObject\Property\DateTime::DATE);

第二个参数指定了您设置的日期类型。以下有三种选项:

  1. LOCAL 这是一个浮点时间,没有时区信息。这基本上是指定事件在当前的时区发生。这将被编码为DTSTART;VALUE=DATE-TIME:20120807235300
  2. UTC 这指定时间应以UTC时间编码。这被编码为DTSTART;VALUE=DATE-TIME:20120807205300Z。注意额外的Z以及它“提前”两个小时。
  3. LOCALTZ 指定它应该以本地时区编码。例如 DTSTART;VALUE=DATE-TIME;TZID=Europe/Amsterdam:20120807235300
  4. DATE 这是一个仅包含日期,不包含时间的日期。在这种情况下,这将编码为DTSTART;VALUE=DATE:20120807

一些重要的注意事项

  • 当指定了TZID时,还应有一个与之匹配的包含所有时区信息的VTIMEZONE对象。VObject目前不能自动嵌入此信息。然而,在实际中,其他客户端似乎在没有这些信息的情况下也能很好地工作。然而,为了完整性,这将会在将来添加。
  • 如前所述,时区确定过程有时可能会失败。请报告您发现的任何问题,我会尽快添加解决方案!

重复规则

重复规则允许事件重复,例如对于每周会议或周年纪念。这是通过RRULE属性完成的。RRULE属性允许有很多不同的规则。VObject仅实现了在日历软件中实际出现的那些规则。

要了解更多关于RRULE及其所有选项的信息,请查看RFC5545。VObject支持以下选项:

  1. UNTIL 用于结束日期。
  2. INTERVAL 例如“每隔两天”。
  3. COUNT 在x项之后停止重复。
  4. FREQ=DAILY 用于每天重复,以及BYDAY用于限制某些天数。
  5. FREQ=WEEKLY 用于每周重复,BYDAY用于将此扩展到每周的多个工作日,以及WKST用于指定周的开始日。
  6. FREQ=MONTHLY 用于每月重复,BYMONTHDAY用于将此扩展到一个月中的某些天,BYDAY用于将此扩展到一个月中的某些工作日,以及BYSETPOS用于限制最后两个扩展。
  7. FREQ=YEARLY 用于每年重复,BYMONTH用于将此扩展到一年中的某些月份,以及BYDAYBYWEEKDAY用于进一步扩展BYMONTH规则。

VObject支持用于排除的EXDATE属性,但不支持RDATEEXRULE属性。如果您对此感兴趣,请提交github问题,因为这会使它出现在我的雷达上。

这是一个相当复杂的话题,无法详细说明。然而,《RFC》有很多示例。

困难的部分不是编写RRULE,而是扩展它们。最复杂且难以阅读的代码隐藏在这个组件中。龙在这里。

因此,如果我们在每月第二个星期一开会,这将指定如下:

BEGIN:VCALENDAR
  VERSION:2.0
  BEGIN:VEVENT
    UID:1102c450-e0d7-11e1-9b23-0800200c9a66
    DTSTART:20120109T140000Z
    RRULE:FREQ=MONTHLY;BYDAY=MO;BYSETPOS=2
  END:VEVENT
END:VCALENDAR

请注意,通常不允许这样缩进对象,但这确实使阅读更加容易。这也是我第一次添加UID,这是所有VEVENT、VTODO和VJOURNAL对象必需的!

为了找出今年所有的会议,我们可以使用以下语法

use Sabre\VObject;

$calendar = VObject\Reader::read($data);
$calendar->expand(new DateTime('2012-01-01'), new DateTime('2012-12-31'));

展开方法的作用是查看其内部事件,并展开重复规则。我们的日历现在包含12个事件。第一个将移除RRULE,每个后续的VEVENT将具有正确的会议日期和一个RECURRENCE-ID设置。

结果如下所示

BEGIN:VCALENDAR
  VERSION:2.0
  BEGIN:VEVENT
    UID:1102c450-e0d7-11e1-9b23-0800200c9a66
    DTSTART:20120109T140000Z
  END:VEVENT
  BEGIN:VEVENT
    UID:1102c450-e0d7-11e1-9b23-0800200c9a66
    RECURRENCE-ID:20120213T140000Z
    DTSTART:20120213T140000Z
  END:VEVENT
  BEGIN:VEVENT
    UID:1102c450-e0d7-11e1-9b23-0800200c9a66
    RECURRENCE-ID:20120312T140000Z
    DTSTART:20120312T140000Z
  END:VEVENT
  ..etc..
END:VCALENDAR

要显示日期列表,我们将这样做

foreach($calendar->VEVENT as $event) {
    echo $event->DTSTART->getDateTime()->format(\DateTime::ATOM);
}

在重复事件中,也可以覆盖单个实例。VObject也会考虑这些。我们需要指定开始和结束日期的原因是,有些重复规则可以是“永不结束”。

您应该确保选择一个合理的日期范围。因为如果您选择一个50年的时间范围,对于每天重复的事件;这将导致超过18K个对象。

空闲忙碌报告生成

某些日历软件可以利用空闲忙碌报告来显示人们何时可用。

您可以使用FreeBusyGenerator从日历自动生成这些报告。

以下是基于我们最近事件的一个示例

// We're giving it the calendar object. It's also possible to specify multiple objects,
// by setting them as an array.
//
// We must also specify a start and end date, because recurring events are expanded.
$fbGenerator = new VObject\FreeBusyGenerator(
    new DateTime('2012-01-01'),
    new DateTime('2012-12-31'),
    $calendar
);

// Grabbing the report
$freebusy = $fbGenerator->result();

// The freebusy report is another VCALENDAR object, so we can serialize it as usual:
echo $freebusy->serialize();

此脚本的输出将如下所示

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Sabre//Sabre VObject 2.0//EN
CALSCALE:GREGORIAN
BEGIN:VFREEBUSY
DTSTART;VALUE=DATE-TIME:20111231T230000Z
DTEND;VALUE=DATE-TIME:20111231T230000Z
DTSTAMP;VALUE=DATE-TIME:20120808T131628Z
FREEBUSY;FBTYPE=BUSY:20120109T140000Z/20120109T140000Z
FREEBUSY;FBTYPE=BUSY:20120213T140000Z/20120213T140000Z
FREEBUSY;FBTYPE=BUSY:20120312T140000Z/20120312T140000Z
FREEBUSY;FBTYPE=BUSY:20120409T140000Z/20120409T140000Z
FREEBUSY;FBTYPE=BUSY:20120514T140000Z/20120514T140000Z
FREEBUSY;FBTYPE=BUSY:20120611T140000Z/20120611T140000Z
FREEBUSY;FBTYPE=BUSY:20120709T140000Z/20120709T140000Z
FREEBUSY;FBTYPE=BUSY:20120813T140000Z/20120813T140000Z
FREEBUSY;FBTYPE=BUSY:20120910T140000Z/20120910T140000Z
FREEBUSY;FBTYPE=BUSY:20121008T140000Z/20121008T140000Z
FREEBUSY;FBTYPE=BUSY:20121112T140000Z/20121112T140000Z
FREEBUSY;FBTYPE=BUSY:20121210T140000Z/20121210T140000Z
END:VFREEBUSY
END:VCALENDAR