Google provides a Google Health extension to the Google Data PHP Client Library that helps connect and use the Health Data API. The library requires PHP 5.1.4+ and is available as a separate download, in addition to downloading the Zend components. For help setting up the client library, see the article on Getting Started with the Google Data PHP Client Library.
This document describes the PHP alternative to working with the raw protocol, described in the Developer's Guide.
This document is intended for programmers who want to write PHP client applications that interact with Google Health. The following instructions assume some knowledge of building, deploying, and running PHP web applications.
The Google Data PHP Client Library includes extensions to most Google Health-specific objects to make the service easier to use.
The XML element in a feed or entry corresponds to a single PHP class in the
library. For example, the <atom:feed> element and the
<atom:entry> element correspond to the
Zend_Gdata_Health_ProfileFeed and Zend_Gdata_Health_ProfileEntry classes, respectively.
This client library is by no means the only way of connecting to and using the Google Health API. If you're interested in reading more about the underlying protocol that this library uses, see the Developer's Guide which discusses the raw protocol.
Google provides a Google Health extension to the Google Data PHP Client Library to help you write PHP client applications that connect to Google Health. The library requires PHP 5.1.4+ and should be used in conjunction with the GData component of Zend Framework.
Google Health extends the Google Data feeds with elements from the ccr namespace. A user's entire Google Health profile is stored in the
Continuity of Care Record. This CCR data corresponds to an instance of the class Zend_Gdata_Health_Extension_Ccr.
To obtain a copy of the Zend_Gdata_Health library, downloaded the latest copy.
For additional help setting up the PHP client library, see our article on Getting Started with the Google Data PHP Client Library.
A sample application is provided under the /demos directory of the source package, also available here.
Using AuthSub, users can grant your web application access to their Google Health profile. Both AuthSub and
OAuth are the recommend means to connect with Google Health
because each token is directly linked to a specific profile in the user's account. Unlike other Google Data APIs, it is required that all requests from your application be digitally signed.
This means that you must either use OAuth, or request initial AuthSub tokens with the secure=1 parameter. Using AuthSub with secure=0 tokens is
limited to the H9 Developer's Sandbox during development.
Both Google Health and the H9 Developer's Sandbox use their
own AuthSub handlers. When generating the link to the AuthSub approval page, you can specify a handler
by passing its URL as the last argument to Zend_Gdata_AuthSub::getAuthSubTokenUri().
Tip: When beginning development, it's recommended to
request an AuthSub token with next=http://localhost and secure=0. If you're ready to test
with your own domains, follow the steps in the
Domain Registration & Signing Requests of the Getting Started Guide.
The following code generates the correct URL to the H9 AuthSub approval page using secure=0 tokens:
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata_AuthSub');
Zend_Loader::loadClass('Zend_Gdata_Health');
function generateAuthSubURL() {
$next = 'http://localhost';
$scope = 'https://www.google.com/h9/feeds';
$authSubHandler = 'https://www.google.com/h9/authsub';
$secure = 0;
$session = 1;
$authSubURL = Zend_Gdata_AuthSub::getAuthSubTokenUri($next, $scope, $secure, $session, $authSubHandler);
// 1 - allows posting notices && allows reading profile data
$permission = 1;
$authSubURL .= '&permission=' . $permission;
return '<a href="' . $authSubURL . '">Link your H9 Account</a>';
}
echo generateAuthSubURL();
Note: If your application will read data from a user's profile, be sure to include the
permission=1 query parameter.
Google Health requires that all API requests be digitally signed, and as a result, the process for generating the AuthSub URL
changes slighly if you're requesting secure=1 tokens for either /h9 or /health . You can no longer
use http://localhost as the next URL. The secure=1 parameter must also be used.
The following code generates the correct URL to the Google Health AuthSub approval page using secure=1 tokens:
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata_AuthSub');
Zend_Loader::loadClass('Zend_Gdata_Health');
// Util for determining the current URL the web app is running from
function getCurrentUrl() {
$php_request_uri = htmlentities(substr($_SERVER['REQUEST_URI'], 0, strcspn($_SERVER['REQUEST_URI'], "\n\r")), ENT_QUOTES);
$protocol = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on' ? 'https://' : 'http://';
$host = $_SERVER['HTTP_HOST'];
if ($_SERVER['SERVER_PORT'] != '' &&
(($protocol == 'http://' && $_SERVER['SERVER_PORT'] != '80') ||
($protocol == 'https://' && $_SERVER['SERVER_PORT'] != '443'))) {
$port = ':' . $_SERVER['SERVER_PORT'];
} else {
$port = '';
}
return $protocol . $host . $port . $php_request_uri;
}
function generateAuthSubURL() {
$next = getCurrentUrl();
$scope = 'https://www.google.com/health/feeds';
$authSubHandler = 'https://www.google.com/health/authsub';
$secure = 1;
$session = 1;
$authSubURL = Zend_Gdata_AuthSub::getAuthSubTokenUri($next, $scope, $secure, $session, $authSubHandler);
// 1 - allows posting notices && allows reading profile data
$permission = 1;
$authSubURL .= '&permission=' . $permission;
return '<a href="' . $authSubURL . '">Link your Google Health Account</a>';
}
echo generateAuthSubURL();
Note: Before you can interact with Google Health, you must register your application with Google and Google Health. Please see Domain Registration & Signing Requests in the Getting Started Guide.
After a successful authorization from AuthSub, the user returns to your next URL with a single-use token
appended to the end. For example, http://www.example.com/health.php?token=singleUseToken.
The following code demonstrates how to extract a single-use token from the URL, upgrade it to a session token, and successfully instantiate a service object using the H9 Sandbox:
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata_AuthSub');
Zend_Loader::loadClass('Zend_Gdata_Health');
$sessionToken = Zend_Gdata_AuthSub::getAuthSubSessionToken($_GET['token']);
$client = Zend_Gdata_AuthSub::getHttpClient($sessionToken);
$useH9Sandbox = true;
$healthService = new Zend_Gdata_Health($client, 'googleInc-MyTestAppName-v1.0', $useH9Sandbox);
For /health, the process is slightly different because of signed requests:
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata_AuthSub');
Zend_Loader::loadClass('Zend_Gdata_Health');
function setupHttpClient($singleUseToken) {
$client = new Zend_Gdata_HttpClient();
// This sets your private key to be used to sign subsequent requests
// Upload the corresponding public x509 certificate to https://www.google.com/accounts/ManageDomains
$client->setAuthSubPrivateKeyFile('/path/to/your/rsa_private_key.pem', null, true);
// Upgrade the single-use token to a long-lived session token
$sessionToken = Zend_Gdata_AuthSub::getAuthSubSessionToken(trim($singleUseToken), $client);
// Set the long-lived session token for subsequent requests
$client->setAuthSubToken($sessionToken);
return $client;
}
$client = setupHttpClient($_GET['token']);
$useH9Sandbox = false;
$healthService = new Zend_Gdata_Health($client, 'googleInc-MyTestAppName-v1.0', $useH9Sandbox);
Note: To use the H9 Sandbox, set $useH9Sandbox = true.
It's important to call setAuthSubPrivateKeyFile before upgrading the single use token. After you have a session token, use setAuthSubToken
to set the healthService's token. Subsequent API requests will use that private key and session token to sign requests.
For help creating a private key and public certificate, see Creating a self-signing X.509 public certificate in the Getting Started Guide.
It's suggested that your application provide users a way to revoke access to their linked profile. The PHP client library
contains the Zend_Gdata_AuthSub::AuthSubRevokeToken() method for revoking an AuthSub/OAuth token.
The following code revokes the token contained in $currentSessionToken:
$currentSessionToken = $client->getAuthSubToken(); Zend_Gdata_AuthSub::AuthSubRevokeToken($currentSessionToken, $client);
Use ClientLogin authentication if your client is a standalone, single-user "installed" client (such as a desktop application).
After including the Zend_Gdata_ClientLogin class, create a new http client object by calling Zend_Gdata_ClientLogin::getHttpClient
with the user's credentials:
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
Zend_Loader::loadClass('Zend_Gdata_Health');
// Parameters for ClientLogin authentication
$healthServiceName = Zend_Gdata_Health::HEALTH_SERVICE_NAME;
// Create an authenticated HTTP client
$client = Zend_Gdata_ClientLogin::getHttpClient("user@gmail.com", "pa$$w0rd", $healthServiceName);
// Create an instance of the Health service
$healthService = new Zend_Gdata_Health($client);
Note: To setup your client for the H9 Sandbox, pass in the 'weaver' service name
instead: $client = Zend_Gdata_ClientLogin::getHttpClient("user@gmail.com", "pa$$w0rd", Zend_Gdata_Health::H9_SANDBOX_SERVICE_NAME).
For more information about ClientLogin authentication, including sample requests and responses, see the Authentication for Installed Applications documentation.
Note: As described in the ClientLogin documentation, the authentication request may fail and issue a CAPTCHA challenge. If you want Google to display and handle the CAPTCHA challenge, then send the user to https://www.google.com/accounts/DisplayUnlockCaptcha?service=health (rather than to the CAPTCHA-handling URL given in the ClientLogin documentation).
The profile feed allows you to retrieve a CCR document describing a user's health information. Each profile is encapsulated inside of an
Atom <atom:entry>.
To query the user's profile feed, your initial AuthSub token needs to have been requested with the permission=1 parameter set. The process of extracting
data from the profile requires two steps, sending a query and iterating through the resulting feed. The Zend_Gdata_Health_Query class helps simplify this
task by automatically constructing a query URL based on the parameters you set.
The following example shows how to query the profile feed and return the user's entire CCR data. It assumes the user has already visited the AuthSub approval page and your application has instantiated a health service object.
$query = new Zend_Gdata_Health_Query();
$profileFeed = $healthService->getHealthProfileFeed($query);
foreach ($profileFeed->getEntries() as $entry) {
// print the CCR xml for this entry
$ccr = $entry->getCcr();
echo '<pre>' . $ccr->saveXML($ccr) . '</pre>';
}
Tip: Using $query->setDigest("true") returns all of the user's CCR data in a single Atom <entry>.
The Zend_Gdata_Health_Extension_Ccr class makes use of PHP's magic
_call method to extract a particular section of the CCR data.
You can take advantage of this method by invoking get<CATEGORY>, where CATEGORY
is one of the supported categories found in the Reference Guide.
$query = new Zend_Gdata_Health_Query();
$query->setDigest("true");
$profileFeed = $healthService->getHealthProfileFeed($query);
$entry = $profileFeed->entry[0]; // digest=true was set so we only have 1 <entry>
$allergies = $entry->getCcr()->getAllergies();
$conditions = $entry->getCcr()->getConditions();
$immunizations = $entry->getCcr()->getImmunizations();
$lab_results = $entry->getCcr()->getLabResults();
$medications = $entry->getCcr()->getMedications();
$procedures = $entry->getCcr()->getProcedures();
// An example of using the medications data
foreach ($medications as $med) {
$xmlStr = $med->ownerDocument->saveXML($med);
echo '<pre>' . $xmlStr . '</pre>';
}
// Or, you can use XPath to extract just the names of each medication
$meds = $entry->getCcr()->getMedications()->item(0);
$xpath = new DOMXpath($meds->ownerDocument);
$elements = $xpath->query("//ccr:Medications/ccr:Medication/ccr:Product/ccr:ProductName/ccr:Text");
foreach ($elements as $element) {
echo $element->nodeValue . '<br>';
}
You can use the query object's setCategory() helper to return a subset of the user's CCR data, instead of their entire profile. For example, you can construct a query that only returns medication
data. The helper can also be passed an additional parameter to return particular items within a category. Below are a few examples.
All medication data:
$query = new Zend_Gdata_Health_Query();
$query->setDigest("true");
$profileFeed = $healthService->getHealthProfileFeed($query);
The medication Lipitor:
$query = new Zend_Gdata_Health_Query();
$query->setDigest("true");
$query->setCategory("medication", "Lipitor");
$profileFeed = $healthService->getHealthProfileFeed($query);
The same methodology can be applied to other categories such as conditions, allergies, lab results, etc:
$query = new Zend_Gdata_Health_Query();
$query->setDigest("true");
$query->setCategory("condition", "Calf Pain");
$profileFeed = $healthService->getHealthProfileFeed($query);
A more complex query that returns the top 10 medications with 2 items each:
$query = new Zend_Gdata_Health_Query();
$query->setDigest("true");
$query->setGrouped("true");
$query->setMaxResultsGroup(10);
$query->setMaxResultsInGroup(2);
$query->setCategory("medication");
$profileFeed = $healthService->getHealthProfileFeed($query);
A full list of supported query parameters is available in the query parameters section of the Health API Reference Guide.
Note: This feature is only available when using ClientLogin.
Since ClientLogin requires a profile ID with each of its feeds, applications will want to query this feed first in order
to select the appropriate profile. The profile list feed returns Atom entries corresponding to each profile in the user's
Google Health account. The profile ID is returned in the <atom:content> and the profile name in the
<atom:title> element.
To execute a query against the profile list feed, call the service's getHealthProfileListFeed() method:
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
Zend_Loader::loadClass('Zend_Gdata_Health');
$client = Zend_Gdata_ClientLogin::getHttpClient('user@gmail.com', 'pa$$word', 'health');
$healthService = new Zend_Gdata_Health($client);
$profileListFeed = $healthService->getHealthProfileListFeed();
// print each profile's name and id
foreach ($profileListFeed->getEntries() as $entry) {
echo '<p>Profile name: ' . $entry->getProfileName() . '<br>';
echo 'profile ID: ' . $entry->getProfileID() . '</p>';
}
After determining which profile to use, call setProfileID() with a profile ID
to make future profile queries be restricted to that profile:
// use the first profile from the previous example $profileID = $profileListFeed->entry[0]->getProfileID(); $healthService->setProfileID($profileID); $profileID = $healthService->getProfileID(); echo '<p><b>Querying profileID</b>: ' . $profileID . '</p>'; $profileFeed = $healthService->getHealthProfileFeed(); // TODO: analyze results in $profileFeed
Individual posts to the register feed are known as notices. Notices are sent from third-party applications to inform the user of a new event. With AuthSub/OAuth, notices are the single means by which your application can add new CCR information into a user's profile. Notices can contain plain text (including certain XHTML elements), a CCR document, or both. As an example, notices might be sent to remind users to pick up a prescription, or they might contain lab results in the CCR format.
Notices can be sent by calling the sendHealthNotice() method in your service object:
// TODO: setup $client
$healthService = new Zend_Gdata_Health($client);
$subject = "Title of your notice goes here";
$body = "Notice body can contain <b>html</b> entities";
$ccr = '<ContinuityOfCareRecord xmlns="urn:astm-org:CCR">
<Body>
<Problems>
<Problem>
<DateTime>
<Type><Text>Start date</Text></Type>
<ExactDateTime>2007-04-04T07:00:00Z</ExactDateTime>
</DateTime>
<Description>
<Text>Aortic valve disorders</Text>
<Code>
<Value>410.10</Value>
<CodingSystem>ICD9</CodingSystem>
<Version>2004</Version>
</Code>
</Description>
<Status><Text>Active</Text></Status>
</Problem>
</Problems>
</Body>
</ContinuityOfCareRecord>';
$responseEntry = $healthService->sendHealthNotice($subject, $body, "html", $ccr);
Note: A simple message that does not contain CCR data can be sent using sendHealthNotice($subject, $body).