如何使用PHP动态发布一个ical文件以便谷歌日历读取?

116
任何关于PHP ical的谷歌搜索结果都会带来phpicalendar和如何解析或读取ical文件的内容。我只想编写一个从我的数据库获取事件并以ical格式输出它们的PHP文件。
我的问题是我找不到任何地方来回答两个问题:
  1. 精确的ical格式是什么,包括头部、文件格式、尾部等等?换句话说,文件必须具有什么才能被Google日历等正确读取?
  2. 如果我使用.php扩展名构建此文件,如何将其发布为ical?我必须写入新的.ics文件吗?还是只要内容符合正确的格式,Google Calendar等就会将.php文件作为ical读取(就像style.css.php文件如果内容实际上是CSS等,则会被视为CSS文件)?
如果您能给予任何帮助或指导,将不胜感激!!!
7个回答

137
如果Google日历不需要*.ics扩展名(这将需要服务器上的URL重写),那么这应该非常简单。
$ical = "BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
UID:" . md5(uniqid(mt_rand(), true)) . "@yourhost.test
DTSTAMP:" . gmdate('Ymd').'T'. gmdate('His') . "Z
DTSTART:19970714T170000Z
DTEND:19970715T035959Z
SUMMARY:Bastille Day Party
END:VEVENT
END:VCALENDAR";

//set correct content-type-header
header('Content-type: text/calendar; charset=utf-8');
header('Content-Disposition: inline; filename=calendar.ics');
echo $ical;
exit;

这基本上就是你需要做的,让客户端认为你正在提供一个iCalendar文件,尽管可能存在一些缓存、文本编码等问题。但你可以从这个简单的代码开始进行实验。


1
谢谢。我认为那些头文件就是我所缺少的。我想在将此文件通过URL提供给Google日历时,还需要一些最后的步骤,因为它会显示“正在从URL导入日历...”,但却永远无法完成。也许这是一个不同的问题需要发布吗? - rhodesjason
3
没错。我更新了上面的例子 - 我还添加了一个DTSTAMP属性,它将告诉客户端事件何时已更新。 - Stefan Gehrig
1
好的 Gehrig,你是个天才。那个方法有效了。谢谢。(据我所知,Google日历也几乎立即更新了。) - rhodesjason
3
如果我没记错的话,程序使用UID来确定事件是否已被删除。如果一个php脚本总是生成另一个UID(->mt_rand),程序将始终认为整个内容已更改。一切都消失了,一切都是新的。个人建议:如果数据库中的事件相同,应该保持相同的UID,只使用记录ID(以及一些主机信息)。DTSTAMP是用来显示有些东西已经改变了的,这应该足够了。 - Seirddriezel
4
谷歌日历需要使用*.ics扩展名。如果你正在使用.htaccess,可以添加以下内容实现: RewriteEngine on RewriteRule ^calendar.ics$ my_php_script.php [QSA] - Fanky
显示剩余8条评论

25

除了Stefan Gehrig的答案和Dave None的答案(以及mmmshuddup的回复)之外,我也想分享一下个人经验:

当我在http://severinghaus.org/projects/icv/使用ICS验证器时,无论是使用\n还是PHP_EOL,都出现了验证问题。

后来我了解到必须使用\r\n才能正确验证,以下是我的解决方案:

function dateToCal($timestamp) {
  return date('Ymd\Tgis\Z', $timestamp);
}

function escapeString($string) {
  return preg_replace('/([\,;])/','\\\$1', $string);
}    

    $eol = "\r\n";
    $load = "BEGIN:VCALENDAR" . $eol .
    "VERSION:2.0" . $eol .
    "PRODID:-//project/author//NONSGML v1.0//EN" . $eol .
    "CALSCALE:GREGORIAN" . $eol .
    "BEGIN:VEVENT" . $eol .
    "DTEND:" . dateToCal($end) . $eol .
    "UID:" . $id . $eol .
    "DTSTAMP:" . dateToCal(time()) . $eol .
    "DESCRIPTION:" . htmlspecialchars($title) . $eol .
    "URL;VALUE=URI:" . htmlspecialchars($url) . $eol .
    "SUMMARY:" . htmlspecialchars($description) . $eol .
    "DTSTART:" . dateToCal($start) . $eol .
    "END:VEVENT" . $eol .
    "END:VCALENDAR";

    $filename="Event-".$id;

    // Set the headers
    header('Content-type: text/calendar; charset=utf-8');
    header('Content-Disposition: attachment; filename=' . $filename);

    // Dump load
    echo $load;

这使我的解析错误停止,并使我的ICS文件正确验证。


头部信息是重要的部分,供将来查看的人参考。大多数应用程序和程序似乎并不担心NewLine换行符。只有验证器才会关注它。但最重要的是头部部分。我们曾经尝试过没有它,遇到了很多问题。 - jfreak53
1
escapeString是用来做什么的?我以为它应该转义一些字符,但你似乎使用htmlspecialchars来代替它。 - Luc
2
一个快速的修复方法:date('Ymd\THis\Z', $timestamp)。应该用 H 而不是 g。 - Pedro Góes

7

有一个优秀的eluceo/ical包,可以轻松创建ics文件。

以下是文档中的示例用法:

// 1. Create new calendar
$vCalendar = new \Eluceo\iCal\Component\Calendar('www.example.com');

// 2. Create an event
$vEvent = new \Eluceo\iCal\Component\Event();
$vEvent->setDtStart(new \DateTime('2012-12-24'));
$vEvent->setDtEnd(new \DateTime('2012-12-24'));
$vEvent->setNoTime(true);
$vEvent->setSummary('Christmas');

// Adding Timezone (optional)
$vEvent->setUseTimezone(true);

// 3. Add event to calendar
$vCalendar->addComponent($vEvent);

// 4. Set headers
header('Content-Type: text/calendar; charset=utf-8');
header('Content-Disposition: attachment; filename="cal.ics"');

// 5. Output
echo $vCalendar->render();

5

4

http://www.kanzaki.com/docs/ical/有一份更易读的较旧规范版本,它可以作为起点-许多事情仍然相同。

此外,在我的网站上,我提供了以下资源:

  1. 一些有用资源列表(请参见侧边栏右下角):
    • ical Spec RFC 5545
    • ical测试资源
  2. 一些笔记记录了我在过去几年中使用.ics的经历。特别是,您可能会发现这个重复事件“cheatsheet”非常有用。

需要注意的.ics区域:

  • '全天'事件
  • 日期类型(时区,UTC或本地'浮动')-请了解区别
  • 重复规则的互操作性

2
  1. 精确的ical格式:http://www.ietf.org/rfc/rfc2445.txt
  2. 根据规范,它必须以.ics结尾

编辑:实际上我不确定 - 第6186行提供了一个以.ics命名格式的示例,但它还指出您可以使用url参数。我认为这并不重要,只要MIME类型正确即可。

编辑:维基百科的示例:http://en.wikipedia.org/wiki/ICalendar

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
DTSTART:19970714T170000Z
DTEND:19970715T035959Z
SUMMARY:Bastille Day Party
END:VEVENT
END:VCALENDAR

服务器上配置了MIME类型。


1
我已经尝试多次阅读那个规范,但就目前而言,我无法理解ical文件的外观。你能否至少指出一些开始讨论.ics文件应包含哪些头部、放置MIME类型等内容的行? - rhodesjason

2

请确保字符串的格式如此,否则它将无法工作

 $content = "BEGIN:VCALENDAR\n".
            "VERSION:2.0\n".
            "PRODID:-//hacksw/handcal//NONSGML v1.0//EN\n".
            "BEGIN:VEVENT\n".
            "UID:".uniqid()."\n".
            "DTSTAMP:".$time."\n".
            "DTSTART:".$time."\n".
            "DTEND:".$time."\n".
            "SUMMARY:".$summary."\n".
            "END:VEVENT\n".
            "END:VCALENDAR";

1
最好使用 PHP_EOL 而不是 "\n" - Yes Barry
4
PHP_EOL是针对不同环境的换行符,所以在Windows系统中会输出\r\n,请注意这一点! - Chris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接