2017-02-02 2 views
0

UPDATE: Ich habe eine Antwort auf meine Frage hinzugefügt, die mein Problem löst (obwohl es nicht 100% getestet) - muss immer noch auf die Token-Aktualisierung warten. Würde immer noch gerne andere Eingaben hören.Spaß mit Google Analytics API; Token-Fehler

Ich habe ein Problem bei der Arbeit mit Google Analytics API für PHP.

Ich initiiere die API (das vollständige Skript davon kann here gefunden werden; es ist eine ältere Version) über eine Funktion in meinem Konstruktor aufgerufen, wo ich alle Variablen der API einrichten und definieren und dann überprüfen, um sicherzustellen Ich habe ein gültiges Token. Ich habe einen AJAX-Controller, der 4 Funktionen in meiner Klasse asynchron aufruft, um dem Benutzer über googles chart api relevante Analytics-Statistiken anzuzeigen. Wenn ein Fehler auftritt, wird in diesem bestimmten Diagrammblock ein Fehler angezeigt. Wenn wir einen Fehler haben, besteht eine 100% ige Chance, dass der Fehler davon kommt, ob wir ein richtiges Token erstellen oder nicht, da die Anweisungen, die die Daten von GA erhalten, vorbereitet werden.

Da alle 4 Diagramme/Anzeigen verschiedenen Funktionen in der Klasse entsprechen, führen wir 4 Abfragen zu Google Analytics aus. Manchmal erhält eines der Diagramme jedoch eine Token-Fehler-Antwort, manchmal mehr als eines der Diagramme ... Manchmal passiert es gar nicht. Ich dachte mir, dass dies möglicherweise auf die Tatsache zurückzuführen war, dass ich im AJAX-Aufruf meine Klasse als new initiierte, anstatt eine Instanz der Klasse zu bekommen, und daher nur 1 Anruf, z. ein Konstrukt der Klasse, um unser Token zu erhalten. Also implementierte ich ein Singleton-Design, das die Klasse einmal über $ga = Google_Analytics_Stats::getInstance($gaInfo); aufruft, aber das Problem bleibt bestehen.

Weiß jemand, was diesen intermittierenden Token-Fehler verursachen könnte?

Aus Gründen der Klarheit

Google_Analytics_Stats initialisiert GoogleAnalyticsAPI in initAnalytics($gaInfo) wo $gaInfo ist das entsprechende Konto und E-Mail-Informationen. Ajax.php schaltet zwischen Funktionen auf Typ basiert, die in Google_Analytics_Stats sind, die nur einmal initialisiert wird mit $ga = Google_Analytics_Stats::getInstance($gaInfo);

AJAX-Aufruf:

<?php 
require ('../framework.php'); 
$login->protect(false); 
if (!isAjax()) { 
    redirect('index.php'); 
} 
// dont forget these functions use date so user timezone effects it!!! 
error_reporting(0); 
$ga = Google_Analytics_Stats::getInstance($gaInfo); 

switch (isset($_GET['type']) ? $_GET['type'] : '') { 
    case 'map': 
     if (isset($_GET['ga_length'])) { 
      echo $ga->getVisitsByCountries($_GET['ga_length']); 
     } 
     else { 
      $error = array(
       "status" => "error", 
       "error" => 'No length defined' 
      ); 
      echo json_encode($error); 
     } 

     break; 
    case 'bounceRate': 
     echo $ga->displayBounceRate(); 
     break; 
    case 'visitsToday': 
     echo $ga->getVisitsToday(); 
     break; 
    case 'momVisits': 
     echo $ga->displayMonthOverMonthVisits(); 
     break; 
    case 'newVsReturn': 
     if (isset($_GET['ga_length'])) { 
      echo $ga->getNewVsReturn($_GET['ga_length']); 
     } 
     else { 
      $error = array(
       "status" => "error", 
       "error" => 'No length defined' 
      ); 
      echo json_encode($error); 
     } 
     break; 
    case 'visitsByDate': 
     if (isset($_GET['ga_length'])) { 
      echo $ga->getVisitsByDate($_GET['ga_length']); 
     } 
     else { 
      $error = array(
       "status" => "error", 
       "error" => 'No length defined' 
      ); 
      echo json_encode($error); 
     } 
     break; 
} 
?> 

Hauptcode (nur 1. erforderlichen Teile für Konzeptualisierung):

class Google_Analytics_Stats { 

    private $ga; 
    // array for default $len 
    private $bounce_rate_current = ''; 
    private $monthly_visitors_current = ''; 
    // rounding precision 
    private $precision = 1; 
    private $len; 
    public static $instance; 

    function __construct($gaInfo) 
    { 
     $this->initAnalytics($gaInfo); 
     $this->len = array(
      'start-date' => date(DATE_FORMAT, strtotime('-1 month')), 
      'end-date' => date(DATE_FORMAT) 
     ); 
    } 
    public static function getInstance($gaInfo) 
    { 
     if (!isset(self::$instance)) { 
      self::$instance = new Google_Analytics_Stats($gaInfo); 
     } 
     return self::$instance; 
    } 
    private function initAnalytics($gaInfo) 
    { 
     try { 
      $ga = new GoogleAnalyticsAPI('service'); 
      $accountId = $gaInfo['account_id']; 
      $ga->auth->setClientId($gaInfo['client_id']); 
      $ga->auth->setEmail($gaInfo['email']); 
      $ga->auth->setPrivateKey($gaInfo['key_src']); 
      $auth = $ga->auth->getAccessToken(); 
      // try and get access token 
      if ($auth['http_code'] == 200) { 
       $accessToken = $auth['access_token']; 
       $tokenExpires = $auth['expires_in']; 
       $tokenCreated = time(); 
      } 
      else { 
       throw new Exception('Token error'); 
      } 
      // set token and account id 
      $ga->setAccessToken($accessToken); 
      $ga->setAccountId($accountId); 
      // set defaults 
      /* 
       if (isset($this->len)) { 
       $ga->setDefaultQueryParams($this->len); 
       } 
      */ 
      $this->ga = $ga; 
     } 
     catch (Exception $e) { 
      $error = array(
       "status" => "error", 
       "error" => $e->getMessage() 
      ); 
      //output result 
      echo json_encode($error); 
     } 
    } 

    public function getBounceRate($params = '') 
    { 
     $defaults = array('metrics' => 'ga:bounceRate'); 
     $_params = array_merge($defaults, $params); 
     $result = $this->ga->_query($_params); 
     return $result['rows'][0][0]; 
    } 

    public function getBounceRateCurrent() 
    { 
     $params = array(
      'start-date' => date(DATE_FORMAT, strtotime('-1 month')), 
      'end-date' => date(DATE_FORMAT) //now 
     ); 
     $result = $this->getBounceRate($params); 
     return round($result, $this->precision); 
    } 

    public function bounceRateTextual($percentage) 
    { 
     if ($this->inRange($percentage, 0, 25.9)) { 
      return array('display' => 'success', 'text' => 'Extremel low'); 
     } 
     elseif ($this->inRange($percentage, 26, 40.9)) { 
      return array('display' => 'success', 'text' => 'Below average'); 
     } 
     elseif ($this->inRange($percentage, 41, 55.9)) { 
      return array('display' => 'warning', 'text' => 'Average'); 
     } 
     elseif ($this->inRange($percentage, 56, 70.9)) { 
      return array('display' => 'danger', 'text' => 'Higher than average'); 
     } 
     else { 
      return array('display' => 'danger', 'text' => 'Extremely high'); 
     } 
    } 

    public function displayBounceRate() 
    { 
     // has to be called first or current will be empty 
     $current = $this->getBounceRateCurrent(); 
     $out = '<h6 class="text-uppercase">Bounce Rate this month</h6>'; 
     $out .= '<h1>' . $current . '%</h1>'; 
     $changeWrapper = "<span class='text-muted mr-0-5'>Rating:</span><span class='label label-%s label-small'>%s</span>"; 
     $textual = $this->bounceRateTextual($current); 
     $out .= sprintf($changeWrapper, $textual['display'], $textual['text']); 
     return $out; 
    } 
+0

Singleton oder nicht, jeder Ajax-Aufruf wird geladen ein brandneues Anfrage an Ihren Backend und werden daher neue Instanzen Ihrer erstellen Klassen. Verschiedene Ajax-Aufrufe können nicht dieselbe Instanz verwenden. Sie könnten einen Ajax-Aufruf machen, der alle benötigten Charts auf einmal zurückgibt und nur im Frontend separat anzeigt? –

+0

Hey magnus danke für die Antwort.Leider kann ich das nicht tun, da ich direkt in Google-Diagramme rendere, nicht zu erwähnen, dass es nicht überschaubar wäre. Ich denke, was das lässt, ist eine andere Lösung zu finden, vielleicht basierend darauf, warum nachfolgende Token-Anfragen (manchmal) verweigert werden – Alex

Antwort

0

In Ordnung, so dachte ich, dass das Problem war, dass ich ein neues Token so oft bekam, wenn das alte bereits gültig war, dass ich googles System überflutete und sie den Zugriff immer wieder abriefen, um Serverlast zu reduzieren. Also habe ich das Token in einer Sitzungsvariablen gespeichert, zusammen mit dem Zeitpunkt, zu dem das Token erstellt wurde und wann es abläuft. Wenn es abgelaufen ist, erhalte ich ein neues Token. Bisher hat es ohne Token-Fehler funktioniert: finger-crossed: ... Nach anderen Artikeln, die ich online gefunden habe, habe ich auch ein try again-Feature implementiert, das versuchen wird, das Token wieder zu bekommen, sollte getToken falsch zurückkommen. Wenn es dann immer noch fehlschlägt, werfen wir den Token-Fehler.

Als Nebeneffekt, den Front-End-Seite viel schneller ist haha ​​

private function initAnalytics($gaInfo) 
    { 
     try { 
      $ga = new GoogleAnalyticsAPI('service'); 
      $accountId = $gaInfo['account_id']; 
      $ga->auth->setClientId($gaInfo['client_id']); 
      $ga->auth->setEmail($gaInfo['email']); 
      $ga->auth->setPrivateKey($gaInfo['key_src']); 
      // set ga to ga so getToken can use the vars we set above 
      $this->ga = $ga; 
      // attempt to get token; 1st attempt 
      if($this->getToken() === false) { 
       // 2nd attempt 
       if($this->getToken() === false) { 
        throw new Exception ('Token Error. Refresh page.'); 
       } 
      } 
      // unset ga as we are going to set it again with the access token initialized 
      unset($this->ga); 
      $ga->setAccessToken($_SESSION['ga_access_token']); 
      $ga->setAccountId($accountId); 
      // set defaults 
      /* 
       if (isset($this->len)) { 
       $ga->setDefaultQueryParams($this->len); 
       } 
      */ 
      $this->ga = $ga; 

     } 
     catch (Exception $e) { 
      $error = array(
       "status" => "error", 
       "error" => $e->getMessage() 
      ); 
      //output result 
      echo json_encode($error); 
     } 
    } 

    public function getToken() 
    { 
     // check to see if we have a token 
     if (isset($_SESSION['ga_token_created']) && isset($_SESSION['ga_token_expires']) && isset($_SESSION['ga_access_token'])) { 
      // check to see if the token is still valid, if not, refresh it 
      if ((time() - $_SESSION['ga_token_created']) >= $_SESSION['ga_token_expires']) { 
       $auth = $this->ga->auth->refreshAccessToken($refreshToken); 
       if ($auth['http_code'] == 200) { 
        // now we can unset the old session vars ... 
        unset($_SESSION['ga_access_token']); 
        unset($_SESSION['ga_token_created']); 
        unset($_SESSION['ga_token_expires']); 
        // ... and add the new ones 
        $_SESSION['ga_access_token'] = $auth['access_token']; 
        $_SESSION['ga_token_expires'] = $auth['expires_in']; 
        $_SESSION['ga_token_created'] = time(); 
        return true; 
       } else { 
        return false; 
       } 
      } else { 
       return true; 
      } 
     // nothing was set so we go the usual route 
     } else { 
      $auth = $this->ga->auth->getAccessToken(); 
      // try and get access token 
      if ($auth['http_code'] == 200) { 
       $_SESSION['ga_access_token'] = $auth['access_token']; 
       $_SESSION['ga_token_expires'] = $auth['expires_in']; 
       $_SESSION['ga_token_created'] = time(); 
       return true; 
      } else { 
       return false; 
      } 
     } 
    }