¿Cómo puedo usar PHP para publicar dinámicamente un archivo ical para que lo lea Google Calendar?

106

Cualquier búsqueda de Google en PHP ical simplemente muestra phpicalendar y cómo analizar o leer archivos IN ical. Solo quiero escribir un archivo PHP que extraiga eventos de mi base de datos y los escriba en formato ical.

Mi problema es que no puedo encontrar ningún sitio que responda a dos preguntas:

  1. ¿Cuál es el formato ical exacto , incluidos encabezados, formato de archivo, pies de página, etc.? En otras palabras, ¿qué debe tener el archivo, exactamente, para que Google Calendar, etc., lo lea correctamente?
  2. Si construyo este archivo con una extensión .php, ¿cómo lo publico como ical? ¿Tengo que escribir en un nuevo archivo .ics? ¿O Google Calendar, etc., leerá un archivo .php tan pronto como el contenido esté en el formato correcto? (Al igual que un archivo style.css.php se leerá como un archivo CSS si el contenido es en realidad CSS, etc.)

¡Cualquier ayuda que puedan darme o señalarme será muy apreciada!

Rhodesjason
fuente

Respuestas:

128

Esto debería ser muy simple si Google Calendar no requiere la *.ics-extensión (que requerirá una reescritura de URL en el 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;

Eso es esencialmente todo lo que necesita para hacer que un cliente piense que está sirviendo un archivo iCalendar, aunque puede haber algunos problemas relacionados con el almacenamiento en caché, la codificación de texto, etc. Pero puedes empezar a experimentar con este sencillo código.

Stefan Gehrig
fuente
1
Gracias. Creo que esos encabezados es lo que me faltaba. Supongo que hay algunos pasos finales para preparar este Calendario de Google, ya que cuando trato de enviar este archivo a Calendario de Google a través de una URL, dice "Importando el calendario desde la URL ..." pero se queda para siempre. ¿Quizás esa es una pregunta diferente para publicar?
Rhodesjason
3
Exactamente. Actualicé el ejemplo anterior y también agregué una propiedad DTSTAMP que le dirá a un cliente cuando se hayan actualizado los eventos.
Stefan Gehrig
1
Está bien Gehrig, eres un genio. Eso funciono. Gracias. (Por lo que puedo decir, Google Calendar también se actualiza casi de inmediato.)
Rhodesjason
3
Si no me equivoco. Los programas usan el UID para ver si se elimina un evento. Si un script php siempre genera otro UID (-> mt_rand), los programas siempre pensarán que todo el contenido ha cambiado. Todo desapareció y todo es nuevo. Personalmente, me quedaría con el mismo UID si el evento es el mismo en la base de datos y solo usaría el ID de registro (y alguna información del host). El DTSTAMP está ahí para mostrar que algo ha cambiado. Eso debería bastar.
Seirddriezel
3
El calendario de Google SÍ requiere la extensión * .ics. Si está utilizando .htaccess, puede hacerlo agregando RewriteEngine on RewriteRule ^calendar.ics$ my_php_script.php [QSA]
Fanky
19

Una nota de experiencia personal además de la respuesta de Stefan Gehrig y la respuesta de Dave None (y la respuesta de mmmshuddup):

Tenía problemas de validación al usar \ ny PHP_EOL cuando usé el validador ICS en http://severinghaus.org/projects/icv/

Aprendí que tenía que usar \ r \ n para que se validara correctamente, así que esta fue mi solució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;

Eso detuvo mis errores de análisis e hizo que mis archivos ICS se validaran correctamente.

Kane Ford
fuente
La información del encabezado es la parte importante para su información para cualquiera que busque en el futuro. En su mayor parte, la mayoría de las aplicaciones y programas no se preocupan por los descansos de NewLine. Parece que sólo los validadores lo hacen. Pero lo más importante es la parte del encabezado. Lo intentamos durante un tiempo sin él y tuvimos muchos problemas.
jfreak53
1
¿Para qué sirve escapeString? Supuse que debería escapar de una cosa o dos, pero parece que usas htmlspecialcharspara eso en su lugar.
Luc
1
Una solución rápida: date ('Ymd \ THis \ Z', $ timestamp). Debería ser una H en lugar de g.
Pedro Góes
6

Existe un excelente paquete eluceo / ical que le permite crear fácilmente archivos ics.

A continuación, se muestra un ejemplo de uso de los documentos:

// 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
fuente
4

http://www.kanzaki.com/docs/ical/ tiene una versión un poco más legible de la especificación anterior. Ayuda como punto de partida, muchas cosas siguen siendo las mismas.

También en mi sitio , tengo

  1. Algunas listas de recursos útiles (consulte la barra lateral en la parte inferior derecha) en
    • ical Spec RFC 5545
    • Recursos de pruebas ical
  2. Algunas notas grabadas en mi viaje de trabajo .icsdurante los últimos años. En particular, puede encontrar útil esta 'hoja de trucos' de eventos repetidos .

.ics áreas que necesitan un manejo cuidadoso:

  • eventos de 'todo el día'
  • tipos de fechas (zona horaria, UTC o local 'flotante'): nota para comprender la distinción
  • interoperabilidad de las reglas de repetición
anmari
fuente
2
  1. Formato exacto: http://www.ietf.org/rfc/rfc2445.txt
  2. Según la especificación, tiene que terminar en .ics

Editar: en realidad no estoy seguro: la línea 6186 da un ejemplo en formato de nomenclatura .ics, pero también indica que puede usar parámetros de URL. No creo que importe, siempre que el tipo MIME sea correcto.

Editar: Ejemplo de 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

El tipo MIME está configurado en el servidor.

lod3n
fuente
1
He intentado leer esa especificación muchas veces, pero no puedo entenderlo en cuanto a cómo se verá el archivo ical. ¿Puede al menos señalarme algunas líneas donde comienza a hablar realmente sobre lo que debería contener el archivo .ics en cuanto al encabezado, dónde colocar el tipo MIME, etc.?
Rhodesjason
2

Asegúrese de formatear la cadena de esta manera o no 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 Ninguno
fuente
1
es mejor usar en PHP_EOLlugar de"\n" .
Sí Barry
4
PHP_EOL es específico del entorno para las líneas finales, por lo que en Windows se generará, ¡ \r\nasí que téngalo en cuenta!
Chris