title: Highcharts with Google Analytics Oauth 2.0
body: <p>For some time i had a working Highchart with Google Analytics with the followigh code:</p>
  
  <pre><code>&lt;?php
  
    // session_start for caching
    session_start();
  
    require 'analytics.class.php';
  
    try {
  
        // construct the class
        $oAnalytics = new analytics('XXXXXXXXX@mail.com', 'PASSXXXXX');
  
        // set it up to use caching
        $oAnalytics-&gt;useCache();
  
        $oAnalytics-&gt;setProfileById('ga:XXXXXXXXX');
  
        $current=date("Y-m-d",time());
        $previous=date("Y-m-d",strtotime("- 30 day", time()));
        $oAnalytics-&gt;setDateRange($previous, $current);
  
        //put visitors to array
        $visitorlst=$oAnalytics-&gt;getVisitors();
        //put new visitors to array
        $newvisitorlst=$oAnalytics-&gt;getNewVisitors();
        // use dimensions and metrics for output
        // see: http://code.google.com/intl/nl/apis/analytics/docs/gdata/gdataReferenceDimensionsMetrics.html  IMPORTANT
  
    } catch (Exception $e) { 
        echo 'Caught exception: ' . $e-&gt;getMessage(); 
    }
    $allarray='';
    $newarray='';
    $thedate=$previous;
    $n=30;
    $j=30;
    foreach( $visitorlst as $val)
    {
      $n--;
        $da = explode("-", $thedate);
      $mon=$da[1]-1;
      $allarray.="[Date.UTC(".$da[0].",".$mon.",".$da[2]."), ".$val."],";
      $thedate=date("Y-m-d",strtotime("- ".$n." day", time()));
    }
    $thedate=$previous;
    foreach( $newvisitorlst as $val)
    {
      $j--;    
        $da = explode("-", $thedate);
      $month=$da[1]-1;
      $newarray.="[Date.UTC(".$da[0].",".$month.",".$da[2]."), ".$val."],";
      $thedate=date("Y-m-d",strtotime("- ".$j." day", time()));
    }
  ?&gt;
  &lt;!DOCTYPE html&gt;
  &lt;html lang="en"&gt;
  &lt;head&gt;
  &lt;meta charset="utf-8"&gt;
  &lt;title&gt;Demo hightchart with GA&lt;/title&gt;
  &lt;meta name="description" content="This is an example to show how to get GA by PHP then parse it to JS" /&gt;
  &lt;script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"&gt;&lt;/script&gt;
  &lt;script src="http://code.highcharts.com/highcharts.js" type="text/javascript"&gt;&lt;/script&gt;
  &lt;script src="http://code.highcharts.com/modules/exporting.js"&gt;&lt;/script&gt;
  &lt;!-- Additional files for the Highslide popup effect --&gt;
  &lt;script type="text/javascript" src="http://www.highcharts.com/highslide/highslide-full.min.js"&gt;&lt;/script&gt;
  &lt;script type="text/javascript" src="http://www.highcharts.com/highslide/highslide.config.js" charset="utf-8"&gt;&lt;/script&gt;
  &lt;link rel="stylesheet" type="text/css" href="http://www.highcharts.com/highslide/highslide.css" /&gt;
  &lt;/head&gt;
  &lt;body&gt;
  &lt;script&gt;
  
  $(function () {
      var chart;
  
      $(document).ready(function() {
  
          chart = new Highcharts.Chart({
  
              chart: {
  
                  renderTo: 'container',
  
                  type: 'line',
  
                  marginRight: 130,
  
                  marginBottom: 25
  
              },
  
              title: {
              text: 'Daily visits at www.XXXXXXX.net'
          },
  
          subtitle: {
              text: 'Source: Google Analytics'
          },
  
          xAxis: {
              type: 'datetime',
              tickInterval: 7 * 24 * 3600 * 1000, // one week
              tickWidth: 0,
              gridLineWidth: 1,
              labels: {
                  align: 'left',
                  x: 3,
                  y: -3
              }
          },
  
          yAxis: [{ // left y axis
              title: {
                  text: null
              },
              labels: {
                  align: 'left',
                  x: 3,
                  y: 16,
                  formatter: function() {
                      return Highcharts.numberFormat(this.value, 0);
                  }
              },
              showFirstLabel: false
          }, { // right y axis
              linkedTo: 0,
              gridLineWidth: 0,
              opposite: true,
              title: {
                  text: null
              },
              labels: {
                  align: 'right',
                  x: -3,
                  y: 16,
                  formatter: function() {
                      return Highcharts.numberFormat(this.value, 0);
                  }
              },
              showFirstLabel: false
          }],
  
          legend: {
              align: 'left',
              verticalAlign: 'top',
              y: 20,
              floating: true,
              borderWidth: 0
          },
  
          tooltip: {
              shared: true,
              crosshairs: true
          },
  
          plotOptions: {
              series: {
                  cursor: 'pointer',
                  point: {
                      events: {
                          click: function() {
                              hs.htmlExpand(null, {
                                  pageOrigin: {
                                      x: this.pageX,
                                      y: this.pageY
                                  },
                                  headingText: this.series.name,
                                  maincontentText: Highcharts.dateFormat('%A, %b %e, %Y', this.x) +':&lt;br/&gt; '+
                                      this.y +' visits',
                                  width: 200
                              });
                          }
                      }
                  },
                  marker: {
                      lineWidth: 1
                  }
              }
          },
  
              series: [
              /*{
  
                  name: 'Chrome',
                  data:[[Date.UTC(1999,  9, 27,4,0,0,0), 23.6   ],
                  [Date.UTC(1999, 10, 10), 33.06],
                  [Date.UTC(1999, 10, 18), 23.6 ],
              ]
                  //data: [23.6, 24.15, 26.11, 27.46, 30.13, 33.06, 36.41, 37.23, 36.71, 37.01, 40.67, 41.52]
  
              },*/ 
              {
  
              name: 'All visits',
              data:[
                  &lt;?php echo $allarray; ?&gt;
              ]},{
              name: 'New visitors',
              data:[
                  &lt;?php echo $newarray; ?&gt;
              ]
                  //data: [46.42, 47.24, 47.19, 46.97, 45.79, 44.09, 42.56, 40.85, 42.07, 41.06, 38.58, 38.27]
  
              }]
  
          });
  
      });
  
  });
  
  &lt;/script&gt;
  &lt;div id="container" style="min-width: 400px; height: 400px; margin: 0 auto"&gt;&lt;/div&gt;
  
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>And it comes with analytics.class.php</p>
  
  <pre><code>&lt;?php
  /**
   * Google Analytics PHP API
   * 
   * This class can be used to retrieve data from the Google Analytics API with PHP
   * It fetches data as array for use in applications or scripts
   *  
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   *
   * Credits: http://www.alexc.me/
   * parsing the profile XML to a PHP array
   *   
   *
   * @link http://www.swis.nl
   * @copyright 2009 SWIS BV
   * @author Vincent Kleijnendorst - SWIS BV (vkleijnendorst [AT] swis [DOT] nl)
   * 
   * @version 0.1
   */
    class analytics{
  
      private $_sUser;
      private $_sPass;
      private $_sAuth;
      private $_sProfileId;
  
      private $_sStartDate;
      private $_sEndDate;
  
      private $_bUseCache;
      private $_iCacheAge;
  
      /**
      * public constructor
      * 
      * @param string $sUser
      * @param string $sPass
      * @return analytics
      */
      public function __construct($sUser, $sPass){
          $this-&gt;_sUser = $sUser;
          $this-&gt;_sPass = $sPass;
  
          $this-&gt;_bUseCache = false;
  
          $this-&gt;auth();
      }
  
  
      /**
      * Google Authentification, returns session when set
      */
      private function auth(){
  
          if (isset($_SESSION['auth'])){
              $this-&gt;_sAuth = $_SESSION['auth'];
              return;
          }
  
          $aPost = array ( 'accountType'   =&gt; 'GOOGLE', 
                           'Email'         =&gt; $this-&gt;_sUser,
                           'Passwd'        =&gt; $this-&gt;_sPass,
                           'service'       =&gt; 'analytics',
                           'source'        =&gt; 'SWIS-Webbeheer-4.0');
  
          $sResponse = $this-&gt;getUrl('https://www.google.com/accounts/ClientLogin', $aPost);
  
          $_SESSION['auth'] = '';
          if (strpos($sResponse, "\n") !== false){
              $aResponse = explode("\n", $sResponse);
              foreach ($aResponse as $sResponse){
                  if (substr($sResponse, 0, 4) == 'Auth'){
                      $_SESSION['auth'] = trim(substr($sResponse, 5));
                  }
              }
          }
          if ($_SESSION['auth'] == ''){
              unset($_SESSION['auth']);
              throw new Exception('Retrieving Auth hash failed!');
          }
          $this-&gt;_sAuth = $_SESSION['auth']; 
      }
  
      /**
      * Use caching (bool)
      * Whether or not to store GA data in a session for a given period
      * 
      * @param bool $bCaching (true/false)
      * @param int $iCacheAge seconds (default: 10 minutes)
      */
      public function useCache($bCaching = true, $iCacheAge = 600){
          $this-&gt;_bUseCache = $bCaching;
          $this-&gt;_iCacheAge = $iCacheAge;
          if ($bCaching &amp;&amp; !isset($_SESSION['cache'])){
              $_SESSION['cache'] = array();     
          }
      }
  
  
      /**
      * Get GA XML with auth key
      * 
      * @param string $sUrl
      * @return string XML
      */
      private function getXml($sUrl){
  
          return $this-&gt;getUrl($sUrl, array(), array('Authorization: GoogleLogin auth=' . $this-&gt;_sAuth));
      }
  
  
      /**
      * Sets GA Profile ID  (Example: ga:12345)
      */        
      public function setProfileById($sProfileId){
  
              $this-&gt;_sProfileId = $sProfileId; 
      }
  
      /**
      * Sets Profile ID by a given accountname
      * 
      */
      public function setProfileByName($sAccountName){
  
          if (isset($_SESSION['profile'])){
              $this-&gt;_sProfileId = $_SESSION['profile'];
              return;
          }
  
          $this-&gt;_sProfileId = '';
          $sXml = $this-&gt;getXml('https://www.google.com/analytics/feeds/accounts/default');
          $aAccounts = $this-&gt;parseAccountList($sXml);
  
          foreach($aAccounts as $aAccount){
              if (isset($aAccount['accountName']) &amp;&amp; $aAccount['accountName'] == $sAccountName){
                  if (isset($aAccount['tableId'])){
                      $this-&gt;_sProfileId =  $aAccount['tableId'];
                  }
              }    
          }
          if ($this-&gt;_sProfileId == ''){
              throw new Exception('No profile ID found!');
          }
  
          $_SESSION['profile'] = $this-&gt;_sProfileId;
      }
  
      /**
      * Returns an array with profileID =&gt; accountName
      * 
      */
      public function getProfileList(){
  
          $sXml = $this-&gt;getXml('https://www.google.com/analytics/feeds/accounts/default');
          $aAccounts = $this-&gt;parseAccountList($sXml);
          $aReturn = array();
          foreach($aAccounts as $aAccount){ 
              $aReturn[$aAccount['tableId']] =  $aAccount['title'];
          }       
          return $aReturn;
      }
  
      /**
      * get resulsts from cache if set and not older then cacheAge
      * 
      * @param string $sKey
      * @return mixed cached data
      */
      private function getCache($sKey){
  
          if ($this-&gt;_bUseCache === false){
              return false;
          }
  
          if (!isset($_SESSION['cache'][$this-&gt;_sProfileId])){
              $_SESSION['cache'][$this-&gt;_sProfileId] = array();
          }  
          if (isset($_SESSION['cache'][$this-&gt;_sProfileId][$sKey])){
              if (time() - $_SESSION['cache'][$this-&gt;_sProfileId][$sKey]['time'] &lt; $this-&gt;_iCacheAge){
                  return $_SESSION['cache'][$this-&gt;_sProfileId][$sKey]['data'];
              } 
          }
          return false;
      }
  
      /**
      * Cache data in session
      * 
      * @param string $sKey
      * @param mixed $mData Te cachen data
      */
      private function setCache($sKey, $mData){
  
          if ($this-&gt;_bUseCache === false){
              return false;
          }
  
          if (!isset($_SESSION['cache'][$this-&gt;_sProfileId])){
              $_SESSION['cache'][$this-&gt;_sProfileId] = array();
          }  
          $_SESSION['cache'][$this-&gt;_sProfileId][$sKey] = array(  'time'  =&gt; time(),
                                                                  'data'  =&gt; $mData);
      }
  
      /**
      * Parses GA XML to an array (dimension =&gt; metric)
      * Check http://code.google.com/intl/nl/apis/analytics/docs/gdata/gdataReferenceDimensionsMetrics.html 
      * for usage of dimensions and metrics
      * 
      * @param array  $aProperties  (GA properties: metrics &amp; dimensions)
      * 
      * @return array result
      */
      public function getData($aProperties = array()){
          $aParams = array();
          foreach($aProperties as $sKey =&gt; $sProperty){
              $aParams[] = $sKey . '=' . $sProperty;
          }
  
          $sUrl = 'https://www.google.com/analytics/feeds/data?ids=' . $this-&gt;_sProfileId . 
                                                          '&amp;start-date=' . $this-&gt;_sStartDate . 
                                                          '&amp;end-date=' . $this-&gt;_sEndDate . '&amp;' . 
                                                          implode('&amp;', $aParams);
          $aCache = $this-&gt;getCache($sUrl);
          if ($aCache !== false){
              return $aCache;
          }
  
          $sXml = $this-&gt;getXml($sUrl);
  
          $aResult = array();
  
          $oDoc = new DOMDocument();
          $oDoc-&gt;loadXML($sXml);
          $oEntries = $oDoc-&gt;getElementsByTagName('entry');
          foreach($oEntries as $oEntry){
              $oTitle = $oEntry-&gt;getElementsByTagName('title');
              $sTitle = $oTitle-&gt;item(0)-&gt;nodeValue;
  
              $oMetric = $oEntry-&gt;getElementsByTagName('metric'); 
  
              // Fix the array key when multiple dimensions are given
              if (strpos($sTitle, ' | ') !== false &amp;&amp; strpos($aProperties['dimensions'], ',') !== false){
  
                  $aDimensions = explode(',', $aProperties['dimensions']);
                  $aDimensions[] = '|';
                  $aDimensions[] = '=';
                  $sTitle = preg_replace('/\s\s+/', ' ', trim(str_replace($aDimensions, '', $sTitle)));  
  
              }
              $sTitle = str_replace($aProperties['dimensions'] . '=', '', $sTitle);
  
              $aResult[$sTitle] = $oMetric-&gt;item(0)-&gt;getAttribute('value');
          }
          // cache the results (if caching is true)
          $this-&gt;setCache($sUrl, $aResult);
  
          return $aResult;
      }
  
      /**
      * Parse XML from account list
      * 
      * @param string $sXml
      */
      private function parseAccountList($sXml){
  
          $oDoc = new DOMDocument();
          $oDoc-&gt;loadXML($sXml);
          $oEntries = $oDoc-&gt;getElementsByTagName('entry');
          $i = 0;
          $aProfiles = array();
          foreach($oEntries as $oEntry){
  
              $aProfiles[$i] = array();
              $oTitle = $oEntry-&gt;getElementsByTagName('title');
              $aProfiles[$i]["title"] = $oTitle-&gt;item(0)-&gt;nodeValue;
              $oEntryId = $oEntry-&gt;getElementsByTagName('id');
              $aProfiles[$i]["entryid"] = $oEntryId-&gt;item(0)-&gt;nodeValue;
              $oProperties = $oEntry-&gt;getElementsByTagName('property');
              foreach($oProperties as $oProperty){
                  if (strcmp($oProperty-&gt;getAttribute('name'), 'ga:accountId') == 0){
                      $aProfiles[$i]["accountId"] = $oProperty-&gt;getAttribute('value');
                  }    
                  if (strcmp($oProperty-&gt;getAttribute('name'), 'ga:accountName') == 0){
                      $aProfiles[$i]["accountName"] = $oProperty-&gt;getAttribute('value');
                  }
                  if (strcmp($oProperty-&gt;getAttribute('name'), 'ga:profileId') == 0){
                      $aProfiles[$i]["profileId"] = $oProperty-&gt;getAttribute('value');
                  }
                  if (strcmp($oProperty-&gt;getAttribute('name'), 'ga:webPropertyId') == 0){
                      $aProfiles[$i]["webPropertyId"] = $oProperty-&gt;getAttribute('value');
                  }
              }
              $oTableId = $oEntry-&gt;getElementsByTagName('tableId');
              $aProfiles[$i]["tableId"] = $oTableId-&gt;item(0)-&gt;nodeValue;
              $i++;
          }
          return $aProfiles;
      }
  
      /**
      * Get data from given URL
      * Uses Curl if installed, falls back to file_get_contents if not
      * 
      * @param string $sUrl
      * @param array $aPost
      * @param array $aHeader
      * @return string Response
      */
      private function getUrl($sUrl, $aPost = array(), $aHeader = array()){
  
  
          if (count($aPost) &gt; 0){
              // build POST query
              $sMethod = 'POST'; 
              $sPost = http_build_query($aPost);    
              $aHeader[] = 'Content-type: application/x-www-form-urlencoded';
              $aHeader[] = 'Content-Length: ' . strlen($sPost);
              $sContent = $aPost;
          } else {
              $sMethod = 'GET';
              $sContent = null;
          }
  
          if (function_exists('curl_init')){
              // If Curl is installed, use it!
              $rRequest = curl_init();
              curl_setopt($rRequest, CURLOPT_URL, $sUrl);
              curl_setopt($rRequest, CURLOPT_RETURNTRANSFER, 1);
  
              if ($sMethod == 'POST'){
                  curl_setopt($rRequest, CURLOPT_POST, 1); 
                  curl_setopt($rRequest, CURLOPT_POSTFIELDS, $aPost); 
              } else {
                  curl_setopt($rRequest, CURLOPT_HTTPHEADER, $aHeader);
              }
  
              $sOutput = curl_exec($rRequest);
              if ($sOutput === false){
                  throw new Exception('Curl error (' . curl_error($rRequest) . ')');    
              }
  
              $aInfo = curl_getinfo($rRequest);
  
              if ($aInfo['http_code'] != 200){
                  // not a valid response from GA
                  if ($aInfo['http_code'] == 400){
                      throw new Exception('Bad request (' . $aInfo['http_code'] . ') url: ' . $sUrl);     
                  }
                  if ($aInfo['http_code'] == 403){
                      throw new Exception('Access denied (' . $aInfo['http_code'] . ') url: ' . $sUrl);     
                  }
                  throw new Exception('Not a valid response (' . $aInfo['http_code'] . ') url: ' . $sUrl);
              }
  
              curl_close($rRequest);
  
          } else {
              // Curl is not installed, use file_get_contents
  
              // create headers and post
              $aContext = array('http' =&gt; array ( 'method' =&gt; $sMethod,
                                                  'header'=&gt; implode("\r\n", $aHeader) . "\r\n",
                                                  'content' =&gt; $sContent));
              $rContext = stream_context_create($aContext);
              $sOutput = @file_get_contents($sUrl, 0, $rContext);
              if (strpos($http_response_header[0], '200') === false){
                  // not a valid response from GA   
                  throw new Exception('Not a valid response (' . $http_response_header[0] . ') url: ' . $sUrl);       
              }
          }
          return $sOutput;
      }   
  
      /**
      * Sets the date range for GA data
      * 
      * @param string $sStartDate (YYY-MM-DD)
      * @param string $sEndDate   (YYY-MM-DD)
      */
      public function setDateRange($sStartDate, $sEndDate){
  
          $this-&gt;_sStartDate = $sStartDate; 
          $this-&gt;_sEndDate   = $sEndDate;
  
      }
  
      /**
      * Sets de data range to a given month
      * 
      * @param int $iMonth
      * @param int $iYear
      */
      public function setMonth($iMonth, $iYear){  
  
          $this-&gt;_sStartDate = date('Y-m-d', strtotime($iYear . '-' . $iMonth . '-01')); 
          $this-&gt;_sEndDate   = date('Y-m-d', strtotime($iYear . '-' . $iMonth . '-' . date('t', strtotime($iYear . '-' . $iMonth . '-01'))));
      }
  
      /**
      * Get visitors for given period
      * 
      */
      public function getVisitors(){
  
          return $this-&gt;getData(array( 'dimensions' =&gt; 'ga:day',
                                       'metrics'    =&gt; 'ga:visits',
                                       'sort'       =&gt; 'ga:day'));
      }
  
      /**
      * Get pageviews for given period
      * 
      */    
      public function getPageviews(){
  
          return $this-&gt;getData(array( 'dimensions' =&gt; 'ga:day',
                                       'metrics'    =&gt; 'ga:pageviews',
                                       'sort'       =&gt; 'ga:day'));
      }
  
      /**
      * Get visitors per hour for given period
      * 
      */    
      public function getVisitsPerHour(){
  
          return $this-&gt;getData(array( 'dimensions' =&gt; 'ga:hour',
                                       'metrics'    =&gt; 'ga:visits',
                                       'sort'       =&gt; 'ga:hour'));
      }
  
      /**
      * Get Browsers for given period
      * 
      */    
      public function getBrowsers(){
  
          $aData = $this-&gt;getData(array(  'dimensions' =&gt; 'ga:browser,ga:browserVersion',
                                          'metrics'    =&gt; 'ga:visits',
                                          'sort'       =&gt; 'ga:visits'));             
          arsort($aData);
          return $aData;                                                                                                                                                                           
      }
  
      /**
      * Get Operating System for given period
      * 
      */    
      public function getOperatingSystem(){
  
          $aData = $this-&gt;getData(array(   'dimensions' =&gt; 'ga:operatingSystem',
                                           'metrics'    =&gt; 'ga:visits',
                                           'sort'       =&gt; 'ga:visits'));
          // sort descending by number of visits
          arsort($aData);
          return $aData; 
      }
      /**
      * Get screen resolution for given period
      * 
      */    
      public function getScreenResolution(){
  
          $aData = $this-&gt;getData(array(   'dimensions' =&gt; 'ga:screenResolution',
                                           'metrics'    =&gt; 'ga:visits',
                                           'sort'       =&gt; 'ga:visits'));
  
          // sort descending by number of visits 
          arsort($aData);
          return $aData; 
      }
  
      /**
      * Get referrers for given period
      * 
      */    
      public function getReferrers(){
  
          $aData = $this-&gt;getData(array(   'dimensions' =&gt; 'ga:source',
                                           'metrics'    =&gt; 'ga:visits',
                                           'sort'       =&gt; 'ga:source'));
  
          // sort descending by number of visits 
          arsort($aData);
          return $aData; 
      }
  
      /**
      * Get search words for given period
      * 
      */    
      public function getSearchWords(){
          $aData = $this-&gt;getData(array(   'dimensions' =&gt; 'ga:keyword',
                                           'metrics'    =&gt; 'ga:visits',
                                           'sort'       =&gt; 'ga:keyword'));
          // sort descending by number of visits                                                                                                                                                     
          arsort($aData);
          return $aData; 
      }
  }
  </code></pre>
  
  <p>But Google change the Oauth so i need to implement the new authorize system like <a href="https://github.com/wanze/Google-Analytics-API-PHP" rel="nofollow">https://github.com/wanze/Google-Analytics-API-PHP</a>
  prefered with service account.
  Anyone has change the old implementation with new Oauth2?</p>