Skip to content

Listing Google groups and memberships from api via PHP

I recently was tasked with pulling a listing of all my organizations Google Groups along with their membership for an internal application. My programming language of choice is PHP. Thankfully, Google has provided a nice PHP library for accessing their api’s.

There appears to be very few examples currently available for doing what I needed, so after I created my script I decided it might be of use to someone else.


setApplicationName("Client_Library_Examples");
$dir = new Google_Service_Directory($client);
$domain = 'yourdomain.com';

if (isset($_SESSION['service_token'])) {
$client->setAccessToken($_SESSION['service_token']);
}

$key = file_get_contents($key_file_location);
$cred = new Google_Auth_AssertionCredentials(
$service_account_name,
array('https://www.googleapis.com/auth/admin.directory.group.readonly'),
$key
);

$cred->sub = "admin@yourdomain.com"; // a privilidged users email address
$client->setAssertionCredentials($cred);
if ($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion($cred);
}

$_SESSION['service_token'] = $client->getAccessToken();

// Get all of our groups
$googleGroups = $dir->groups->listGroups(array('domain'=>$domain));
$groups = $googleGroups->getGroups();

// if we have a paginated result set, continue doing a lookup until we are at the end
while (isset($googleGroups->nextPageToken) && ($googleGroups->nextPageToken != '')) {
$googleGroups = $dir->groups->listGroups(array('domain'=>$domain,'pageToken'=>$googleGroups->nextPageToken));
$groups = array_merge($groups, $googleGroups->getGroups());
}

// Ok, we have all our groups. Now lets build an array that we can use later to populate with group members
$lists = array();
foreach ($groups as $key=>$val) {
$lists[$val->id] = array('id'=>$val->id,'description'=>$val->description,'email'=>$val->email,'name'=>$val->name,'members'=>'');
}

// Doing a batch query for all members of the groups to reduce execution time
$client->setUseBatch(true);
$batch = new Google_Http_Batch($client);
foreach ($groups as $k=>$v) {
$members = $dir->members->listMembers($v->email);
$batch->add($members, $v->id);
}

// execute our batch query
$results = $batch->execute();

// turn off batch queries now so we can query for more members in the case of paginated result sets
$client->setUseBatch(False);
foreach ($results as $k=>$v) {
$all = $v->getMembers();
$id = substr($k, 9); // the array key is in the form of response-XXX, lets get rid of the response- bit

while (isset($v->nextPageToken) && ($v->nextPageToken != '')) {
$members = $dir->members->listMembers($lists[$id]['email'],array("pageToken"=>$v->nextPageToken));
$v->nextPageToken = $members->nextPageToken;
$all = array_merge($all, $members->getMembers());
}

foreach ($all as $key=>$val) {
$lists[$id]['members'][] = $val->email;
}

}

$time_elapsed_secs = microtime(true) - $start;
print "\n\n" . $time_elapsed_secs . "\n\n";

The script will build an array called $lists that contains the names and memberships of all your org’s groups. I hope this helps someone solve the problem I had.

PHP Quartile function

So I recently had to write some code for a ranking system based on quartiles. After an initial Google search, I was not able to find any code that reliably produced the results based on Method 1 from the Wikipedia page. I am sure this is due to the fact that there are many different formulas. I ran across this interesting article on why Excel has multiple quartile functions. Since I could not find existing code that worked for me, I wrote the following code. I hope this helps someone else with the problem I had.

function quartile($arr) {
  $count = count($arr);
  $middleval = floor(($count-1)/2); // find the middle value, or the lowest middle value
  if($count % 2) { // odd number, middle is the median
    $median = $arr[$middleval];
  } else { // even number, calculate avg of 2 medians
    $low = $arr[$middleval];
    $high = $arr[$middleval+1];
    $median = (($low+$high)/2);
  }
  return number_format((float)$median, 2, '.', '');
}

$values = array(1.22, 1.29, 2.00, 2.17, 2.38, 2.43, 2.44, 2.50, 2.56, 2.57, 3.00, 3.00, 3.00, 3.13, 3.38, 3.50, 3.71);
$second = quartile($values);

$tmp = array();
foreach ($values as $key=>$val) {
  if ($val > $second) {
    $tmp['third'][] = $val;
  } else if ($val < $second) {
    $tmp['first'][] = $val;
  }
}

$first = quartile($tmp['first']);
$third = quartile($tmp['third']);

So the function just produces the median value. I first find the median value of the entire array, which is the second quartile. After I have found the second quartile, I then loop through the array and create a new array for the first and third quartiles based on where the values fall in relation to the second quartile. After the new arrays are created, I find each of their median's.

PHP implementation of cron

I recently needed to create an application that creates recurring calendar events. After thinking about this for a while, I decided that doing something similar to unix cron was the solution.

This is the unix cron format:

* * * * * command to be executed
- - - - -
| | | | |
| | | | +----- day of week (0 - 6) (Sunday=0)
| | | +------- month (1 - 12)
| | +--------- day of month (1 - 31)
| +----------- hour (0 - 23)
+------------- min (0 - 59)

My app does not need to worry about min or hour. I only need to account for day of the month, month and day of the week.
I allow the user to specify the recurring dates in a way that is similar to how cron accepts ranges.
The dates can be either a single date, multiple dates separated by commas, a range of dates using the minus sign, or * for every.

Here is the form I use for submission:
recurring task manager

Here is the code that handles the possible range of inputs:

// day
if (isset($_POST['taskDay']) && ($_POST['taskDay'] != '') && ($_POST['taskDay'] != '*')) {
  $_POST['taskDay'] = str_replace(' ', '', $_POST['taskDay']);
  if (strpos($_POST['taskDay'], ',')) { // specific days
    $days = explode(',',$_POST['taskDay']);
  } else if (strpos($_POST['taskDay'], '-')) { // day range
    $x = explode('-',$_POST['taskDay']);
    for ($i = $x[0]; $i <= $x[1]; $i++) {
      $days[] = $i;
    }
  } else if ( ($_POST['taskDay'] > 0) && ($_POST['taskDay'] < 32) ) {
    $days[] = $_POST['taskDay'];
  }
} else {
  $day = '*'; // $_POST['taskDay'] was left blank, set it to *
}

// month
if (isset($_POST['taskMonth']) && ($_POST['taskMonth'] != '') && ($_POST['taskMonth'] != '*')) {
  $_POST['taskMonth'] = str_replace(' ', '', $_POST['taskMonth']);
  if (strpos($_POST['taskMonth'], ',')) { // specific months
            $months = explode(',',$_POST['taskMonth']);
  } elseif (strpos($_POST['taskMonth'], '-')) { // month range
            $x = explode('-',$_POST['taskMonth']);
            for ($i = $x[0]; $i <= $x[1]; $i++) {
              $months[] = $i;
            }
  } else if ( ($_POST['taskMonth'] > 0) && ($_POST['taskMonth'] < 13) ) {
            $months[] = $_POST['taskMonth'];
  }
} else {
  $month = '*'; // $_POST['taskMonth'] was left blank, set it to *
}

// week
if (isset($_POST['taskWeek']) && ($_POST['taskWeek'] != '') && ($_POST['taskWeek'] != '*')) {
  $_POST['taskWeek'] = str_replace(' ', '', $_POST['taskWeek']);
  if (strpos($_POST['taskWeek'], ',')) { // specific days of week
    $weeks = explode(',',$_POST['taskWeek']);
  } elseif (strpos($_POST['taskWeek'], '-')) { // days of the week range
    $x = explode('-',$_POST['taskWeek']);
    for ($i = $x[0]; $i <= $x[1]; $i++) {
      $weeks[] = $i;
    }
  } else if ( ($_POST['taskWeek'] >= 0) && ($_POST['taskWeek'] < 8) ) {
    $weeks[] = $_POST['taskWeek'];
  }
} else {
  $week = '*'; // $_POST['taskWeek'] was left blank, set it to *
}

So what we end up with is the possibility for either a * entity for $day, $month, $week or an array of dates.
Now the fun begins. I'm note sure if this way is the most efficient way of checking the dates. I am satisfied with this code for my first iteration. But even as I am writing this post, I have been modifying the code, so I expect to have revised this multiple times before I put it into production.

// hard coded start date for this example
$start = '02/01/2014';
// transform date to an array
$x = explode('/', $start);

// hard coded the end date as 2 years from start date
$end = ++$x[2] . "-12-31";

// how many days between start and end
$datetime1 = new DateTime($start);
$datetime2 = new DateTime($end);
$interval = $datetime1->diff($datetime2);
$max = $interval->format('%a');

for ($i = 0; $i < $max; $i++) {
  $string = "+" . $i . " day";
  $new = date("Y-m-d", strtotime($string, strtotime($start)));
  $day_of_week = date('N', strtotime($new)); // numeric day of week: Sunday = 0
  $x = explode('-', $new);
  if ($day == '*') {
    if ($month == '*') {
      if ($week == '*') {
        print "\n" . $new . "\n";
      } else {
        foreach ($weeks as $key=>$val) {
          if ($day_of_week == $val) {
            print "\n" . $new . "\n";
          }
        }
      }
    } else {
      if ($week == '*') {
        foreach ($months as $key=>$val) {
          if ($x[1] == $val) {
            print "\n" . $new . "\n";
          }
        }
      } else {
        foreach ($months as $key=>$val) {
          if ($x[1] == $val) {
            foreach ($weeks as $k=>$v) {
              if ($day_of_week == $v) {
                print "\n" . $new . "\n";
              }
            }
          }
        }
      }
    }
  } else {
    foreach ($days as $key=>$val) {
      if ($val == $x[2]) {
        if ($month == '*') {
          if ($week == '*') {
            print "\n" . $new . "\n";
          } else {
            foreach ($weeks as $k=>$v) {
              if ($day_of_week == $v) {
                print "\n" . $new . "\n";
              }
            }
          }
        } else {
          foreach ($months as $k1=>$v1) {
            if ($x[1] == $v1) {
              if ($week == '*') {
                print "\n" . $new . "\n";
              } else {
                foreach ($weeks as $k2=>$v2) {
                  if ($day_of_week == $v2) {
                    print "\n" . $new . "\n";
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

So now, if you execute this code you will get a print out of every date between the start date and two years in the future. Not very exciting. So lets play around with some of the hard coded day of month, month, and day of week variables.

First, lets see what happens if we set the recurrence to be the first day of the month every June and December

$day = '1';
$days = array();
$days[] = '1'
$month = '6,12';
$months = array();
$months[] = '6';
$months[] = '12';
$week = '*';
$weeks = array();

Notice that I manually added a $days and $months array element.
When you execute this code, you will get a print out like this:

2014-06-01

2014-12-01

2015-06-01

2015-12-01

One more example, what if we wanted to do something on the first day of the month, but only if that day was a Monday?

$day = '1';
$days[] = '1';
$month = '*';
$week = '1';
$weeks = array();
$weeks[] = '1'; // numeric day of week: Sunday = 0

Notice that I set a day array element and a weeks array element for this example. And here is the output:

2014-09-01

2014-12-01

2015-06-01