sirtet
sirtet

Reputation: 85

How to create a list view of Google Calendar with PHP

I need to put a List of Events from Google Calendar on a webpage. The list i need can be seen in Google Calendar itself, it's the event list (agenda-style) with content from multiple calendars in different color. Google calendar allows also to have this list in an Iframe, but problem is, to see these lists a user must be logged in, or i would need to make the calendar public, what i can't do.

There used to be a private url for calendars, but now only an iCal feed is available privately.

So i tried to find a PHP script to create such a list. Surprisingly, i did not find much. Most pages relied on a public calendar, or are just very basic examples about how to connect, like Google's php example here https://developers.google.com/google-apps/calendar/quickstart/php#step_3_set_up_the_sample which i managed to get working, but that is quite far from what i need. I need some html output that i can format, and data from 3 different calendars.

To get that done is a bit over my head, but maybe someone has done something like that before, seen it done somewhere else? Or is able to just shake it out of their sleeve? Or has a better suggestion?

Another attempt i made was using phantomjs to login to the calendar and make a screenshot, but i can't run that on my webserver.

Upvotes: 1

Views: 2670

Answers (2)

uselessinfoguru
uselessinfoguru

Reputation: 19

here's some code which will display an event if the GET phone number is somewhere in a google event field in 1 of 5 different phone number formats, you'll need a service account which the calendar is shared with and the My Project.json file you get when creating the service account needs to be put into the working folder on your server (same folder you're putting the .

<?php

//error_reporting(E_ALL);
//ini_set("display_errors", 1);

require_once __DIR__.'/vendor/autoload.php'; 

$client = new Google_Client();
$credentialJson= __DIR__ . '/My Project-somehexidecimal.json'; //name of your My Project .json file
$calendarId='youremail'; //your google calendar id
$phone= $_GET['phone'];

$display = preg_replace('/^(\d{3})(\d{3})(\d{4})$/', '\1-\2-\3', $phone);
$display1 = preg_replace('/^(\d{3})(\d{3})(\d{4})$/', '(\1) \2-\3', $phone);
$display2 = preg_replace('/^(\d{3})(\d{3})(\d{4})$/', '\1\2\3', $phone);
$display3 = preg_replace('/^(\d{3})(\d{3})(\d{4})$/', '\1 \2 \3', $phone);
$display4 = preg_replace('/^(\d{3})(\d{3})(\d{4})$/', '(\1)\2-\3', $phone);

$client->setAuthConfig($credentialJson);
$client->addScope('https://www.googleapis.com/auth/calendar');

$service = new Google_Service_Calendar($client);

$params = array(
'q' => $display,
'singleEvents' => true,
//'orderBy' => 'startTime',
'timeMin' => date(DateTime::ATOM),
'maxResults' => 1
);
$params1 = array(
'q' => $display1,
'singleEvents' => true,
//'orderBy' => 'startTime',
'timeMin' => date(DateTime::ATOM),
'maxResults' => 1 
);
$params2 = array(
'q' => $display2,
'singleEvents' => true,
//'orderBy' => 'startTime',
'timeMin' => date(DateTime::ATOM),
'maxResults' => 1 
);
$params3 = array(
'q' => $display3,
'singleEvents' => true,
//'orderBy' => 'startTime',
'timeMin' => date(DateTime::ATOM),
'maxResults' => 1
);
$params4 = array(
'q' => $display4,
'singleEvents' => true,
//'orderBy' => 'startTime',
'timeMin' => date(DateTime::ATOM),
'maxResults' => 1
);

$events = $service->events->listEvents($calendarId, $params);

if (count($events->getItems()) == 0) {
$events = $service->events->listEvents($calendarId, $params1);
}
if (count($events->getItems()) == 0) {
$events = $service->events->listEvents($calendarId, $params2);
}
if (count($events->getItems()) == 0) {
$events = $service->events->listEvents($calendarId, $params3);
}
if (count($events->getItems()) == 0) {
$events = $service->events->listEvents($calendarId, $params4);
}
if (count($events->getItems()) == 0) {
print "No upcoming events found.\n";
}
$calTimeZone = $events->timeZone;

date_default_timezone_set($calTimeZone);

foreach ($events->getItems() as $event) {

        $starttime= $event->getstart()['dateTime'];
        $endtime= $event->getend()['dateTime'];
        $description=$event->getDescription();
        $summary=$event->getSummary();
        $eventid = $event->getid();
        $location = $event->getlocation();

     $eventDateStr = $event->start->dateTime;
     if(empty($eventDateStr))
     {
         $eventDateStr = $event->start->date;
     }

     $temp_timezone = $event->start->timeZone;

     if (!empty($temp_timezone)) {
     $timezone = new DateTimeZone($temp_timezone);
 } else { $timezone = new DateTimeZone($calTimeZone);
     }

     $eventdate = new DateTime($eventDateStr,$timezone);
     $link = $event->htmlLink;
             $TZlink = $link . "&ctz=" . $calTimeZone;
     $newmonth = $eventdate->format("M");
     $newday = $eventdate->format("j");
            }


    ?>
    <div class="event-container">
    <div class="eventDate">
    <span class="month"><?php

    echo $newmonth;

     ?></span><br />
    <span class="day"><?php

    echo $newday;

     ?></span><span class="dayTrail"></span>
</div>
<div class="eventBody">
    <a href="<?php echo $TZlink;
?>">

    <?php echo $summary, '<br>', $location, '<br>', $description;
    ?>
    </a>
</div>
</div>
 <?php

 $notes= html_entity_decode ($description)
?>

Upvotes: 0

sirtet
sirtet

Reputation: 85

I managed to mimic the agenda-view with the below code.

There were a few gotchas for me, namely the end-date on full-day events being the next day, and non- full-day events returning dateTime vs only date for full-day.

The code is over-complicated i think, that's me reaching the solution in slow iterative steps...

<html>
  <head>
    <style type="text/css">
      html {
        font-family: sans-serif;
      }
      .trips {
        color:red;
      }
      .courses {
        color:blue;
      }
      .canceled {
        color:orange;
        text-decoration:line-through;
      }
      .marketing {
        color:green;
      }
      tr>td {
        vertical-align: top;
      }
      td.time {
        width: 110px;
      }
      td.date {
        width: 140px;
      }
      td.summary {
        font-weight:bold;
      }
      td {
        padding: 0 0 5px 0;
        border-bottom: 2px solid grey;
      }
      td td {
        border-bottom: none;
      }
      span.location {
        font-weight:normal;
        color:black;
        margin-left:10px;
      }
    </style>
  </head>
  <body>
    [html comment broken up, to keep syntax highlighting in the php below]
    < ! -- // having a html comment around php keeps php debug output from echo, print_r etc in source view
<?php
  /******************
  * list calendar-events mimicking the google calendar agenda-view
  * allows to show a non-public calendars to non-authenticated clients
  * code fragments from
  * http://www.daimto.com/google-calendar-api-with-php-service-account/
  * https://developers.google.com/google-apps/calendar/v3/reference/events/list#response
  * https://developers.google.com/google-apps/calendar/quickstart/php#step_3_set_up_the_sample
  ******************/
  require_once 'google-api-php-client/src/Google/autoload.php';
  session_start();
  $Email_address = '[email protected]';
  // for security reasons, keep key_file outside webroot:
  $key_file_location = '/home/t...../...41.p12';
  $client = new Google_Client();
  $client-> setApplicationName("K....");
  $key = file_get_contents($key_file_location);
  // the calendars to query
  $calendars = array(
    'trips'    => '[email protected]',
    'courses'  => '[email protected]',
    'canceled' => '[email protected]',
  );
  $agenda = array(); // the merged result from all calendarsi
  $maxResults = 15; // no. of results to get (per calendar)
  $firstDate = new DateTime(); // the date from which on we want the agenda
  $firstDate->setTime(0,0,0); // date "without" time, we think in full days only
  // $firstDate->modify('+2 days'); // testing other start-dates
  setlocale (LC_ALL, 'de_DE'); // to get weekdays & monthnames correct
  $scopes ="https://www.googleapis.com/auth/calendar.readonly";
  $cred = new Google_Auth_AssertionCredentials(
    $Email_address,
    array($scopes),
    $key
  );
  $client->setAssertionCredentials($cred);
  if($client->getAuth()->isAccessTokenExpired()) {
    $client->getAuth()->refreshTokenWithAssertion($cred);
  }
  $service = new Google_Service_Calendar($client);

  foreach($calendars as $cal_name => $cal_id) {
    // get the dates from each calendar
    $calendar_res = $service->calendars->get($cal_id);
    $optParams = array(
      'maxResults' => $maxResults,
      'orderBy' => 'startTime',
      'singleEvents' => true,
      'timeMin' => $firstDate->format('c')
    );
    $events = $service->events->listEvents($calendar_res->id, $optParams);

    foreach ($events->getItems() as $event) {
      $startDate = new DateTime();
      $endDate = new DateTime();
      // full-day events use 'date', others 'dateTime' so we need to treat separately:
      if(isset($event->start->date)){
        // it's a full day event, only a date is given
        $startDate->setTimestamp(strtotime($event->start->date));
        $endDate->setTimestamp(strtotime($event->end->date));
        // full-day end-date is returned by google as the next day (midnight),
        // correct this for our display:
        $endDate->sub(new DateInterval('P1D'));
        // remove times, they would contain data from the last processed non- full-day event
        // also, we will test ifset to recognize full- against non- full-day events
        unset($startTime);
        unset($endTime);
      }else{
        // it's a non-full day, having start/end dates AND times
        $startDate->setTimestamp(strtotime($event->start->dateTime));
        $endDate->setTimestamp(strtotime($event->end->dateTime));
        // extract times
        $startTime = $startDate->format('G:i');
        $endTime = $endDate->format('G:i');
        // set times to zero, so date comparison works correctly
        $startDate->setTime(0,0,0);
        $endDate->setTime(0,0,0);
      }

      // for every day of the event, make an entry in the agenda
      $currDate = $startDate; // the date we are about to add an entry to
      while ($endDate >= $currDate){
        // don't add entries that are before our first wanted date
        if ($currDate >= $firstDate){
          if (isset ($startTime)){
            $time = $startTime . " - " . $endTime;
          }else{
            $time = "Ganztägig";
          };
          // we save the date in a way so the agenda-array can later be sorted by it
          $agenda[$currDate->format('Y-m-d')][] =
            array(
              'cal' => $cal_name,
              'summary' => $event->getSummary(),
              'location' => $event->getLocation(),
              'start' => $startDate->format('Y-m-d') . " - " . $startTime,
              'end' => $endDate->format('Y-m-d') . " - " . $endTime,
              'time' => $time
            );
        };
        // go to next day
        $currDate->modify('+1 day');
      };
    }
  }

  // the agenda-array is not yet sorted, events were added by calendar by date, not just by date
  ksort ($agenda); // sort by key (date)
  //var_dump($agenda);
  //print_r($agenda);
?>
    // end of html comment around php (keeps debug output in source view) -->

<?
  //output
  echo "    <table>";
  foreach ($agenda as $aDate => $events){
    // a row for every date
    echo "\n      <tr>";
    echo "\n        <td class=\"date\">" . strftime('%a %e. %B', strtotime($aDate)) . "</td>";
    echo "\n        <td>";
    // a table of events for every day
    echo "\n          <table >";
    foreach ($events as $aEvent){
      // a row for every event
      echo "\n            <tr>";
      echo "\n              <td class=\"time\">" . $aEvent['time'] ."</td>";
      echo "\n              <td class=\"" . $aEvent['cal'] . " summary\">" . $aEvent['summary'];
      echo "\n                <span class=\"location\">" . $aEvent['location'] . "</span>";
      echo "\n              </td>";
      echo "\n            </tr>";
     };
    echo "\n          </table>";
    echo "\n        </td>";
    echo "\n      </tr>";
  };
  echo "\n    <table>\n";
?>
  </body>
</html>

Upvotes: 1

Related Questions