////////////////////////////////////////////////////////////////////////////// // A Shortcut guide to getting data from a Google Health EMR // ////////////////////////////////////////////////////////////////////////////// // FIRST, go to www.google.com/h9, the Google Health developers' sandbox, and create yourself a free account. Put some dummy data in it, make up some medical conditions and tests. // SECOND, download and install the Zend OAuth code from http://framework.zend.com/download/gdata // THIRD, Change this to point to the location of your private signing key. What's a private signing key? See: http://code.google.com/apis/health/getting_started.html#DomainRegistration define('HEALTH_PRIVATE_KEY', '/path/to/your/rsa_private_key.pem'); // The following AuthOpen authentication connects your application to Google. // The legalities: /** * Zend Framework * * LICENSE * * This source file is subject to the new BSD license that is bundled * with this package in the file LICENSE.txt. * It is also available through the world-wide-web at this URL: * http://framework.zend.com/license/new-bsd * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to license@zend.com so we can send you a copy immediately. * * @category Zend * @package Zend_Gdata * @subpackage Demos * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ $EMRname = "Google Health"; ////////////////////////////////////////////////////////////////////////////// // End Configuration // ////////////////////////////////////////////////////////////////////////////// // Load the Zend Gdata classes. require_once 'Zend/Loader.php'; Zend_Loader::loadClass('Zend_Gdata_AuthSub'); Zend_Loader::loadClass('Zend_Gdata_Health'); Zend_Loader::loadClass('Zend_Gdata_Health_Query'); session_start(); // Google H9 Sandbox AuthSub/OAuth scope define('SCOPE', 'https://www.google.com/h9/feeds/'); try { // Setup the HTTP client and fetch an AuthSub token for H9 $client = authenticate(@$_GET['token']); $useH9 = true; $healthService = new Zend_Gdata_Health($client, 'google-HealthPHPSample-v1.0', $useH9); } catch(Zend_Gdata_App_Exception $e) { $cmdData["loginMsg"]='Error: ' . $e->getMessage(); echo json_encode($cmdData); exit; } ////////////////////////////////////////////////////////////////////////////// // End Authentication // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // Begin Sample Code // ////////////////////////////////////////////////////////////////////////////// /* if(isset($_GET["revoke"])) { // ============================================================================= // Revoke the AuthSub session token // ============================================================================= $revoked = Zend_Gdata_AuthSub::AuthSubRevokeToken($client->getAuthSubToken(), $client) ? 'yes' : 'no'; unset($_SESSION['sessionToken']); echo 'Link to EMR data revoked: ' . @$revoked; exit; } */ getTokenInfo($client); // this needed to make second and subsequent calls to this page work. Don't know exactly why. //echo "Token info: ", getTokenInfo($client); //echo "Session Token", $client->getAuthSubToken(); $query = new Zend_Gdata_Health_Query(); $query->setDigest("true"); $profileFeed = $healthService->getHealthProfileFeed($query); // break down the feed $entry = $profileFeed->entry[0]; // digest=true was set so we only have 1 $allergies = $entry->getCcr()->getAllergies(); $conditions = $entry->getCcr()->getConditions(); $immunizations = $entry->getCcr()->getImmunizations(); $tests = $entry->getCcr()->getLabResults(); $meds= $entry->getCcr()->getMedications(); $procedures = $entry->getCcr()->getProcedures(); // This is where your app starts. ************************************************* // You've got data, now parse it. For example: getAllTests(); getAllMeds(); // An example of another way of using the medications data //foreach ($meds as $med) { //$xmlStr = $med->ownerDocument->saveXML($med); //echo '
' . $xmlStr . '
'; //} //*********************************** supporting functions *********************************** // get medical Test data from Google Health API // To learn how to build these queries: http://code.google.com/apis/health/ccrg_reference.html function getAllTests() { global $tests; $test = $tests->item(0); $xpath = new DOMXpath($test->ownerDocument); $testnames = $xpath->query("//ccr:Body/ccr:Results/ccr:Result/ccr:Test/ccr:Description/ccr:Text"); foreach ($testnames as $name) { $nameOut[]= $name->nodeValue; } $dates= $xpath->query("//ccr:Body/ccr:Results/ccr:Result/ccr:Test/ccr:DateTime/ccr:ExactDateTime"); foreach ($dates as $date) { $dateOut[] = $date->nodeValue; // human-readable } // continue with queries for other parts of the Tests. } // get data from Google Health API function getAllMeds() { global $meds; // do your own thing } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // If you prefer to set queries by calling methods of a Query object, Google gives some sample code for that. // // See http://framework.zend.com/svn/framework/standard/trunk/demos/Zend/Gdata/Health.php // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // more support functions ******************************************************* function getCurrentUrl() { $phpRequestUri = htmlentities(substr($_SERVER['REQUEST_URI'], 0, strcspn($_SERVER['REQUEST_URI'], "\n\r")), ENT_QUOTES); if (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on') { $protocol = 'https://'; } else { $protocol = '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 . $phpRequestUri; } function authenticate($singleUseToken=null) { global $cmdData,$EMRname; $sessionToken = isset($_SESSION['sessionToken']) ? $_SESSION['sessionToken'] : null; // If there is no AuthSub session or one-time token waiting for us, // redirect the user to Google Health's AuthSub handler to get one. if (!$sessionToken && !$singleUseToken) { $next = getCurrentUrl(); // 'next' is where you want to go after the user says it's ok to link to you. $secure = 1; $session = 1; $authSubHandler = 'https://www.google.com/h9/authsub'; $permission = 1; // 1 - allows reading of the profile && posting notices $authSubURL = Zend_Gdata_AuthSub::getAuthSubTokenUri($next, SCOPE, $secure, $session, $authSubHandler); $authSubURL .= '&permission=' . $permission; $cmdData["loginMsg"]="

VisiHealth will graphically display your already-existing health account on $EMRname.
First step: Link your Google Health Account

"; echo json_encode($cmdData); exit(); } $client = new Zend_Gdata_HttpClient(); $client->setAuthSubPrivateKeyFile(HEALTH_PRIVATE_KEY, null, true); // Convert an AuthSub one-time token into a session token if needed if ($singleUseToken && !$sessionToken) { //echo "session:$sessionToken "; //echo "single:$singleUseToken "; $sessionToken = Zend_Gdata_AuthSub::getAuthSubSessionToken($singleUseToken, $client); $_SESSION['sessionToken'] = $sessionToken; } $client->setAuthSubToken($sessionToken); return $client; } function getTokenInfo($client) { $sessionToken = $client->getAuthSubToken(); return Zend_Gdata_AuthSub::getAuthSubTokenInfo($sessionToken, $client); } function revokeToken($client) { $sessionToken = $client->getAuthSubToken(); return Zend_Gdata_AuthSub::AuthSubRevokeToken($sessionToken, $client); } /** Prettifies an XML string into a human-readable and indented work of art * @param string $xml The XML as a string * @param boolean $html_output True if the output should be escaped (for use in HTML) */ function xmlpp($xml, $html_output=true) { $xml_obj = new SimpleXMLElement($xml); $level = 4; $indent = 0; // current indentation level $pretty = array(); // get an array containing each XML element $xml = explode("\n", preg_replace('/>\s*\n<", $xml_obj->asXML())); // shift off opening XML tag if present if (count($xml) && preg_match('/^<\?\s*xml/', $xml[0])) { $pretty[] = array_shift($xml); } foreach ($xml as $el) { if (preg_match('/^<([\w])+[^>\/]*>$/U', $el)) { // opening tag, increase indent $pretty[] = str_repeat(' ', $indent) . $el; $indent += $level; } else { if (preg_match('/^<\/.+>$/', $el)) { $indent -= $level; // closing tag, decrease indent } if ($indent < 0) { $indent += $level; } $pretty[] = str_repeat(' ', $indent) . $el; } } $xml = implode("\n", $pretty); return ($html_output) ? htmlentities($xml) : $xml; }