Como posso usar o PHP para publicar dinamicamente um arquivo ical para ser lido pelo Google Calendar?

106

Qualquer pesquisa no Google sobre PHP ical apenas traz o phpicalendar e como analisar ou ler arquivos IN ical. Só quero escrever um arquivo PHP que extraia eventos do meu banco de dados e os grava em formato ical.

Meu problema é que não consigo encontrar nenhum lugar que responda a duas perguntas:

  1. Qual é o formato ical exato , incluindo cabeçalhos, formato de arquivo, rodapés, etc.? Em outras palavras, o que o arquivo precisa ter, exatamente, para ser lido corretamente pelo Google Agenda, etc.?
  2. Se eu construir este arquivo usando uma extensão .php, como faço para publicá-lo como ical? Tenho que gravar em um novo arquivo .ics? Ou o Google Agenda etc. lerá um arquivo .php, desde que o conteúdo esteja no formato correto? (Muito parecido com um arquivo style.css.php será lido como um arquivo CSS se o conteúdo for realmente CSS, etc.)

Qualquer ajuda que vocês puderem dar ou me apontar será muito apreciada !!!

Rhodesjason
fonte

Respostas:

128

Isso deve ser muito simples se o Google Calendar não exigir a *.ics-extensão (o que exigirá alguma regravação de URL no servidor).

$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;

Isso é basicamente tudo que você precisa para fazer um cliente pensar que você está servindo um arquivo iCalendar, embora possa haver alguns problemas relacionados ao cache, codificação de texto e assim por diante. Mas você pode começar a experimentar este código simples.

Stefan Gehrig
fonte
1
Obrigado. Acho que esses cabeçalhos é o que estava faltando. Presumo que haja algumas etapas finais para preparar este Google Agenda, pois quando tento alimentar esse arquivo para o Google Agenda via URL, ele diz "Importando agenda do url ...", mas fica pendurado para sempre. Talvez seja uma pergunta diferente para postar?
rhodesjason
3
Exatamente. Eu atualizei o exemplo acima - e também adicionei uma propriedade DTSTAMP que dirá a um cliente quando os eventos foram atualizados.
Stefan Gehrig
1
Ok Gehrig, você é um gênio. Isso funcionou. Obrigado. (Pelo que posso dizer, o Google Agenda está sendo atualizado quase imediatamente também.)
rhodesjason
3
Se não estou errado. Os programas usam o UID para ver se um evento é excluído. Se um script php sempre gerar outro UID (-> mt_rand), os programas sempre pensarão que todo o conteúdo mudou. Tudo desapareceu e tudo é novo. Pessoalmente, gostaria de manter o mesmo UID se o evento for o mesmo no banco de dados e usar apenas o recordID (e algumas informações do host). O DTSTAMP existe para mostrar que algo mudou. Isso deve ser o suficiente.
Seirddriezel
3
O calendário do Google EXIGE a extensão * .ics. Se estiver usando .htaccess, você pode adicionar RewriteEngine on RewriteRule ^calendar.ics$ my_php_script.php [QSA]
Fanky
19

Uma nota de experiência pessoal, além da resposta de Stefan Gehrig e da resposta de Dave None (e a resposta de mmmshuddup):

Eu estava tendo problemas de validação usando \ ne PHP_EOL quando usei o validador ICS em http://severinghaus.org/projects/icv/

Aprendi que precisava usar \ r \ n para validar corretamente, então esta foi minha solução:

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;

Isso interrompeu meus erros de análise e fez com que meus arquivos ICS fossem validados corretamente.

Kane Ford
fonte
As informações do cabeçalho são a parte importante, para sua informação, para quem está olhando para o futuro. Na maioria das vezes, a maioria dos aplicativos e programas não se preocupa com as quebras do NewLine. Parece que apenas os validadores fazem isso. Mas o mais importante é a parte do cabeçalho. Tentamos por um tempo sem ele e estávamos tendo muitos problemas.
jfreak53
1
Para que serve o escapeString? Achei que deveria escapar uma ou duas coisas, mas você parece usar htmlspecialcharspara isso.
Luc
1
Uma solução rápida: data ('Ymd \ THis \ Z', $ timestamp). Deve ser um H em vez de g.
Pedro Góes
6

Existe um excelente pacote eluceo / ical que permite criar facilmente arquivos ics.

Aqui está um exemplo de uso do docs:

// 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();
Ivan Yarych
fonte
4

http://www.kanzaki.com/docs/ical/ tem uma versão um pouco mais legível da especificação anterior. Ajuda como ponto de partida - muitas coisas ainda são as mesmas.

Também no meu site , tenho

  1. Algumas listas de recursos úteis (ver barra lateral inferior direita) em
    • ical Spec RFC 5545
    • Recursos de teste ical
  2. Algumas notas registradas em minha jornada de trabalho ao .icslongo dos últimos anos. Em particular, você pode achar útil esta 'folha de cheats' de eventos repetidos .

.ics áreas que precisam de tratamento cuidadoso:

  • eventos de 'dia todo'
  • tipos de datas (fuso horário, UTC ou local 'flutuante') - nb para entender a distinção
  • interoperabilidade de regras de recorrência
anmari
fonte
2
  1. Formato ical exato: http://www.ietf.org/rfc/rfc2445.txt
  2. De acordo com a especificação, deve terminar em .ics

Editar: na verdade, não tenho certeza - a linha 6186 dá um exemplo no formato de nomenclatura .ics, mas também afirma que você pode usar parâmetros de url. Acho que não importa, desde que o tipo MIME esteja correto.

Editar: Exemplo da wikipedia: 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

O tipo MIME é configurado no servidor.

Lod3n
fonte
1
Eu tentei ler essa especificação muitas vezes, mas não consigo fazer cara ou coroa com relação à aparência do arquivo ical. Você pode, pelo menos, apontar-me algumas linhas onde começa a realmente falar sobre o que o arquivo .ics deve conter até o cabeçalho, onde colocar o tipo MIME, etc?
rhodesjason
2

Certifique-se de formatar a string assim ou não funcionará

 $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";
Dave None
fonte
1
é melhor usar em PHP_EOLvez de "\n".
Sim Barry
4
PHP_EOL é um ambiente específico para linhas finais, portanto, no Windows ele será gerado, \r\nportanto, tenha isso em mente!
Chris