Google Analytics query report - PHP - php

I'm trying to display the google analytics report in my web application which is to display top 10 pages and display browsers count,
i am using this link Hello Analytics Reporting API v4; PHP quickstart for service account to develop it. I am getting below error,
Error calling POST https://analyticsreporting.googleapis.com/v4/reports:batchGet: (401) Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential
CODE :
$analytics = initializeAnalytics();
$response = getReport($analytics);
printResults($response);
function initializeAnalytics()
{
// Use the developers console and download your service account
// credentials in JSON format. Place them in this directory or
// change the key file location if necessary.
$KEY_FILE_LOCATION = __DIR__ . '/preprod-b18917fe321f.json';
// Create and configure a new client object.
$client = new Google_Client();
$client->setApplicationName("Hello Analytics Reporting");
$client->setAuthConfig('{"web":{}}'); // provided the .json credentials
$client->setScopes(['https://www.googleapis.com/auth/analytics.readonly']);
$analytics = new Google_Service_AnalyticsReporting($client);
return $analytics;
}
function getReport($analytics) {
// Replace with your view ID, for example XXXX.
$VIEW_ID = "xxxxxx";
// Create the DateRange object.
$dateRange = new Google_Service_AnalyticsReporting_DateRange();
$dateRange->setStartDate("7daysAgo");
$dateRange->setEndDate("today");
// Create the Metrics object.
$sessions = new Google_Service_AnalyticsReporting_Metric();
$sessions->setExpression("ga:sessions");
$sessions->setAlias("sessions");
// Create the ReportRequest object.
$request = new Google_Service_AnalyticsReporting_ReportRequest();
$request->setViewId($VIEW_ID);
$request->setDateRanges($dateRange);
$request->setMetrics(array($sessions));
$body = new Google_Service_AnalyticsReporting_GetReportsRequest();
$body->setReportRequests( array( $request) );
return $analytics->reports->batchGet( $body );
}
/**
* Parses and prints the Analytics Reporting API V4 response.
*
* #param An Analytics Reporting API V4 response.
*/
function printResults($reports) {
for ( $reportIndex = 0; $reportIndex < count( $reports ); $reportIndex++ ) {
$report = $reports[ $reportIndex ];
$header = $report->getColumnHeader();
$dimensionHeaders = $header->getDimensions();
$metricHeaders = $header->getMetricHeader()->getMetricHeaderEntries();
$rows = $report->getData()->getRows();
for ( $rowIndex = 0; $rowIndex < count($rows); $rowIndex++) {
$row = $rows[ $rowIndex ];
$dimensions = $row->getDimensions();
$metrics = $row->getMetrics();
for ($i = 0; $i < count($dimensionHeaders) && $i < count($dimensions); $i++) {
print($dimensionHeaders[$i] . ": " . $dimensions[$i] . "\n");
}
for ($j = 0; $j < count($metrics); $j++) {
$values = $metrics[$j]->getValues();
for ($k = 0; $k < count($values); $k++) {
$entry = $metricHeaders[$k];
print($entry->getName() . ": " . $values[$k] . "\n");
}
}
}
}
}
Anyone please give me an idea to get rid of this error.

Error calling POST https://analyticsreporting.googleapis.com/v4/reports:batchGet: (401) Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential
Means that you are not logged in you are not properly authenticating the client before running the code.
posible issues with service accounts
Check $client->setAuthConfig('{"web":{}}'); make sure this is the correct path to the json key file. should probably be $KEY_FILE_LOCATION
Make sure that you created service account credentials on Google Developer console and not something else this code will only work with a service account key file.
Make sure that you granted the service account access to your google analytics account. Take the service account email address and add it as a user in Google analytics at the account level.
Issue with json file location
If you still have issues with the file you can put the location into an env
// Load the Google API PHP Client Library.
require_once __DIR__ . '/vendor/autoload.php';
// Use the developers console and download your service account
// credentials in JSON format. Place the file in this directory or
// change the key file location if necessary.
putenv('GOOGLE_APPLICATION_CREDENTIALS='.__DIR__.'/service-account.json');
/**
* Gets the Google client refreshing auth if needed.
* Documentation: https://developers.google.com/identity/protocols/OAuth2ServiceAccount
* Initializes a client object.
* #return A google client object.
*/
function getGoogleClient() {
return getServiceAccountClient();
}
/**
* Builds the Google client object.
* Documentation: https://developers.google.com/api-client-library/php/auth/service-accounts
* Scopes will need to be changed depending upon the API's being accessed.
* array(Google_Service_Analytics::ANALYTICS_READONLY, Google_Service_Analytics::ANALYTICS)
* List of Google Scopes: https://developers.google.com/identity/protocols/googlescopes
* #return A google client object.
*/
function getServiceAccountClient() {
try {
// Create and configure a new client object.
$client = new Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope([YOUR SCOPES HERE]);
return $client;
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
}
ServiceAccount.php

The error tells us that a user needs be logged in. You simply need to add the authentication part.
I suggest you to look at a sample Google Oauth & Analytics v4 in PHP.

Related

How to upload to google drive with service account and php

Down you can see my code and it uploads files to my google drive. Now I am trying to use service account to let the people to upload files to my Google drive without their google accounts (Visitors will submit html form with their file and my app will upload that file to my drive ). But I am stuck with it. Can not find even just one working example. Any ideas?
$client = new Google\Client();
$client->setAuthConfig('credentials.json');
$client->addScope(Google\Service\Drive::DRIVE);
$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
$client->setRedirectUri($redirect_uri);
if (isset($_GET['code'])) {
$token = $client->fetchAccessTokenWithAuthCode($_GET['code']);
$client->setAccessToken($token);
// store in the session also
$_SESSION['upload_token'] = $token;
// redirect back to the example
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
if (!empty($_SESSION['upload_token'])) {
$client->setAccessToken($_SESSION['upload_token']);
if ($client->isAccessTokenExpired()) {
unset($_SESSION['upload_token']);
}
} else {
$authUrl = $client->createAuthUrl();
}
echo $client->getAccessToken();
if ($_SERVER['REQUEST_METHOD'] == 'GET' && $client->getAccessToken()) {
// We'll setup an empty 1MB file to upload.
DEFINE("TESTFILE", 'test.jpg');
if (!file_exists(TESTFILE)) {
$fh = fopen(TESTFILE, 'w');
fseek($fh, 1024 * 1024);
fwrite($fh, "!", 1);
fclose($fh);
}
// This is uploading a file directly, with no metadata associated.
$file = new Google\Service\Drive\DriveFile();
$service = new Google_Service_Drive($client);
$file->setName("Hello World!");
$result = $service->files->create(
$file,
[
'data' => file_get_contents(TESTFILE),
'mimeType' => 'application/octet-stream',
'uploadType' => 'media'
]
);
$permissionService = new Google_Service_Drive_Permission();
$permissionService->role = "reader";
$permissionService->type = "anyone"; // anyone with the link can view the file
$service->permissions->create($result->id, $permissionService);
The following code will show you how to set up service account authorization.
Remember though the files will be uploaded to the service accounts drive account. If you want them uploaded to your personal drive account. You need to share a directory on your drive account with the service account. You do that though the web app like you would any other user, using the service account email address. Its the property that looks like an email.
You should just be able to remove the auth you have now and then use this. You will however need set the parents in the upload metadata to be that of that directory you want the fill uploaded to.
// Load the Google API PHP Client Library.
require_once __DIR__ . '/vendor/autoload.php';
// Use the developers console and download your service account
// credentials in JSON format. Place the file in this directory or
// change the key file location if necessary.
putenv('GOOGLE_APPLICATION_CREDENTIALS='.__DIR__.'/service-account.json');
/**
* Gets the Google client refreshing auth if needed.
* Documentation: https://developers.google.com/identity/protocols/OAuth2ServiceAccount
* Initializes a client object.
* #return A google client object.
*/
function getGoogleClient() {
return getServiceAccountClient();
}
/**
* Builds the Google client object.
* Documentation: https://developers.google.com/api-client-library/php/auth/service-accounts
* Scopes will need to be changed depending upon the API's being accessed.
* array(Google_Service_Analytics::DRIVE)
* List of Google Scopes: https://developers.google.com/identity/protocols/googlescopes
* #return A google client object.
*/
function getServiceAccountClient() {
try {
// Create and configure a new client object.
$client = new Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(array(Google_Service_Analytics::DRIVE));
return $client;
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
}
Doing something like this will then get you the same service object.
$service = new Google_Service_Drive(getGoogleClient());

Set Google Account on Server side without showing dialog for account selection

This is code from which I get GA data but it is always ask in browser for account selection. How to define default account in PHP script.
What I missing?
This is equal to index.php in GA documentation but I use Symfony framework and decided to change this route
/**
* #Route("/get-google-analytics-data")
*/
public function getGoogleAnalyticsData () {
$ga = $this->get('google_analytics_service');
$client = new \Google_Client();
$client->setAuthConfig(__DIR__ . '/client_secrets.json');
$client->addScope(\Google_Service_Analytics::ANALYTICS_READONLY);
// If the user has already authorized this app then get an access token
// else redirect to ask the user to authorize access to Google Analytics.
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
// Set the access token on the client.
$client->setAccessToken($_SESSION['access_token']);
// Create an authorized analytics service object.
$analytics = new \Google_Service_AnalyticsReporting($client);
// Call the Analytics Reporting API V4.
$response = $ga->getReport($analytics);
// Print the response.
return new \Symfony\Component\HttpFoundation\Response($ga->printResults($response));
} else {
$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback';
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
return $this->redirect($redirect_uri);
}
This is equal to oauth2callback.php in GA documentation.
}
/**
* #Route("/oauth2callback", name="gaOA2callback")
*/
public function gaOA2callback () {
$client = new \Google_Client();
$client->setAuthConfig(__DIR__ .'/client_secrets.json');
$client->setRedirectUri('http://' . $_SERVER["HTTP_HOST"] . '/oauth2callback');
$client->addScope(\Google_Service_Analytics::ANALYTICS_READONLY);
// Handle authorization flow from the server.
if (! isset($_GET['code'])) {
$auth_url = $client->createAuthUrl();
header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
return $this->redirect($auth_url);
} else {
$client->authenticate($_GET['code']);
$_SESSION['access_token'] = $client->getAccessToken();
$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/get-google-analytics-data';
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
return $this->redirect($redirect_uri);
}
}
First of all, this was a bad idea. I had use wrong way of communicate with GA API.
function initializeAnalytics()
{
// Use the developers console and download your service account
// credentials in JSON format. Place them in this directory or
// change the key file location if necessary.
$KEY_FILE_LOCATION = __DIR__ . '/service-account-credentials.json';
// Create and configure a new client object.
$client = new \Google_Client();
$client->setApplicationName("Hello Analytics Reporting");
$client->setAuthConfig($KEY_FILE_LOCATION);
$client->setScopes(['https://www.googleapis.com/auth/analytics.readonly', 'https://www.googleapis.com/auth/analytics']);
$analytics = new \Google_Service_AnalyticsReporting($client);
return $analytics;
}
You can see .json file included in function. This file you can download from Google console Dashboard from your OAuth 2.0 client IDs
.
https://console.developers.google.com/apis/credentials?project=&authuser=1
If you do not have those you will ned to create a new one.
Most important thing, enter a valid VIEW_ID, if you do not do that you
will get permission denied error and probably you will look for
solution on other places.
About permission, user of this API is not your email. it is service email, zou will find it in .json file. And also you will need to set roles for that service email. For basic use view permissions will be just fine.
At end, to get data you can do that with function like this.
$VIEW_ID = "123625914"; // **view ID is look like this, you will find bunch of those vieew on GA Reporting Dashboard for your project.**
function getReport($analytics, $nameSystem) {
// Replace with your view ID, for example XXXX.
$VIEW_ID = "123625914";
// Create the DateRange object.
$dateRange = new \Google_Service_AnalyticsReporting_DateRange();
$dateRange->setStartDate("4000daysAgo");
$dateRange->setEndDate("today");
$today = new \Google_Service_AnalyticsReporting_DateRange();
$today->setStartDate("today");
$today->setEndDate("today");
// Create the Metrics object.
$views = new \Google_Service_AnalyticsReporting_Metric();
$views->setExpression("ga:pageviews");
$views->setAlias("views");
$user = new \Google_Service_AnalyticsReporting_Metric();
$user->setExpression("ga:users");
$user->setAlias("user");
$country = new \Google_Service_AnalyticsReporting_Dimension();
$country->setName("ga:country");
$continent = new \Google_Service_AnalyticsReporting_Dimension();
$continent->setName("ga:continent");
$event = new \Google_Service_AnalyticsReporting_Dimension();
$event->setName("ga:eventLabel");
$event->setName("ga:eventCategory");
// Create the ReportRequest object.
$request = new \Google_Service_AnalyticsReporting_ReportRequest();
$request->setViewId($VIEW_ID);
$request->setDateRanges([$dateRange, $today]);
$request->setMetrics(array($views, $user));
$request->setDimensions(array($event));
$request->setFiltersExpression('ga:eventCategory==' . $nameSystem);
$request1 = new \Google_Service_AnalyticsReporting_ReportRequest();
$request1->setViewId($VIEW_ID);
$request1->setDateRanges([$dateRange, $today]);
$request1->setMetrics(array($user));
$request1->setDimensions(array($continent, $event));
$request->setFiltersExpression('ga:eventCategory==' . $nameSystem);
$request2 = new \Google_Service_AnalyticsReporting_ReportRequest();
$request2->setViewId($VIEW_ID);
$request2->setDateRanges([$dateRange, $today]);
$request2->setMetrics(array($user));
$request2->setDimensions(array($event));
$request2->setFiltersExpression('ga:eventCategory==' . $nameSystem);
$body = new \Google_Service_AnalyticsReporting_GetReportsRequest();
$body->setReportRequests( array( $request, $request1, $request2) );
return $analytics->reports->batchGet( $body );
}

Why do I get 404 Error when using Google Classroom API?

I am writing an app in PHP which will connect to my domains's Google Classroom. However I get the following error when I try to do anything with the Google Classroom API:
Message: Error calling GET https://www.googleapis.com/v1/courses?pageSize=100: (404) Not Found
My code so far:
$scopes = array(
'https://www.googleapis.com/auth/classroom.courses',
'https://www.googleapis.com/auth/classroom.courses.readonly',
'https://www.googleapis.com/auth/classroom.rosters',
'https://www.googleapis.com/auth/classroom.rosters.readonly'
);
$gServiceEmail = "random#developer.gserviceaccount.com";
$gServiceKey = file_get_contents("../path/to/cert.p12");
$client = new Google_Client();
$gAuth = new Google_Auth_AssertionCredentials(
$gServiceEmail,
$scopes,
$gServiceKey
);
$gAuth->sub = "user#mydomain.com";
$client->setAssertionCredentials($gAuth);
$service = new Google_Service_Classroom($client);
$results = $service->courses->listCourses();
I have enabled the scopes in the API Settings in the Google Admin Console for the service account and enabled the api in the developer console. Where am I going wrong?
I think your endpoint is wrong according to the documentation of Classroom API. Try changing it to https://classroom.googleapis.com
sample request:
GET https://classroom.googleapis.com/v1/courses?pageSize=100&key={YOUR_API_KEY}
Course with id is not found.
For a list of courses, use the courses.list(), as shown in the following sample.
$client = getClient();
$service = new Google_Service_Classroom($client);
// Print the first 10 courses the user has access to.
$optParams = array(
'pageSize' => 10
);
$results = $service->courses->listCourses($optParams);
if (count($results->getCourses()) == 0) {
print "No courses found.\n";
} else {
print "Courses:\n";
foreach ($results->getCourses() as $course) {
printf("%s (%s)\n", $course->getName(), $course->getId());
}
}
References:
https://developers.google.com/classroom/quickstart/php?hl=en
https://developers.google.com/classroom/guides/manage-courses?hl=en

Unable to listUserMessages() - 500 Backend Error

When using the below code to attempt to list messages received by a brand new gmail account I just set up, I get
[Google_Service_Exception] Error calling GET https://www.googleapis.com/gmail/v1/users/myGmailAccount%40gmail.com/messages: (500) Backend Error
I know the validation portion is working correctly because I'm able to make minor modifications and query the books api as shown in this example. Below is the code I'm using to attempt to query recent messages received...
const EMAIL = 'myGmailAccount#gmail.com';
private $permissions = [
'https://www.googleapis.com/auth/gmail.readonly'
];
private $serviceAccount = 'xxxxxxxxxxxxxxxxx#developer.gserviceaccount.com';
/** #var Google_Service_Gmail */
private $gmail = null;
/** #var null|string */
private static $serviceToken = null;
public function __construct()
{
$client = new Google_Client();
$client->setApplicationName($this->applicationName);
$this->gmail = new Google_Service_Gmail($client);
//authentication
if (isset(self::$serviceToken)) {
$client->setAccessToken(self::$serviceToken);
}
$credentials = new Google_Auth_AssertionCredentials(
$this->serviceAccount,
$this->permissions,
$this->getKey()
);
$client->setAssertionCredentials($credentials);
if($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion($credentials);
}
self::$serviceToken = $client->getAccessToken();
}
public function getMessages()
{
$this->gmail->users_messages->listUsersMessages(self::EMAIL);
}
I have granted API access to gmail:
The 500 makes me believe this is an internal error with the gmail API or I'm missing something the PHP client isn't validating.
This one work for me. My understanding is service account doesn't have a mailbox and it's not too sure which mailbox it should work on. So you can't use listUsersMessages() function to get all messages.
So you will need to specify which email address that the service account need to work on.
Make sure that the scope has been allowed on Web App API to
1. Add this line:
$credentials->sub = self::EMAIL;
Before:
$client->setAssertionCredentials($credentials);
2. Then Update your getMessages() to:
$this->gmail->users_messages->listUsersMessages("me");
Hope this helps!
I imagine the account has logged in to the web interface already, right? Have you tried with a separate user? How about doing something like labels list instead? Did you try using the APIs explorer site? https://developers.google.com/apis-explorer/#p/gmail/v1/
Can you provide the first 5 digits of the developer's client ID (it's not secret anyway) so I can try to track down the error?
For this to work you have to impersonate an user account (the service account doesn't have a mailbox, as lthh89vt points out).
If you try to access the mailbox directly you will get the (500) Back End error.
The full code is:
$client_email = '1234567890-a1b2c3d4e5f6g7h8i#developer.gserviceaccount.com';
$private_key = file_get_contents('MyProject.p12');
$scopes = array('https://www.googleapis.com/auth/gmail.readonly');
$user_to_impersonate = 'user#example.org';
$credentials = new Google_Auth_AssertionCredentials(
$client_email,
$scopes,
$private_key,
'notasecret', // Default P12 password
'http://oauth.net/grant_type/jwt/1.0/bearer', // Default grant type
$user_to_impersonate,
);
$client = new Google_Client();
$client->setAssertionCredentials($credentials);
if ($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion();
}
$service = new Google_Service_Gmail($client);
$results = $service->users_messages->listUsersMessages('me');
Full instructions can be found on Google APIs Client Library for PHP

Service Applications and Google Analytics API V3: Error 101 (net::ERR_CONNECTION_RESET)

I'm trying to get some info of my Google Analytics account using PHP. I already followed the steps for creating a Service Account in the Google Console API in this answer. I'm using the Google API Client for PHP.
This is the code I've got so far:
<?php
$path_to_src = 'src';
// These files are in /src, upload its contents to your web server
require_once $path_to_src . '/Google_Client.php';
require_once $path_to_src . '/contrib/Google_AnalyticsService.php';
$path_to_keyfile = '***'; //my private key
// Initialise the Google Client object
$client = new Google_Client();
// Your 'Product name'
$client->setApplicationName('My App Name');
$client->setAssertionCredentials(
new Google_AssertionCredentials(
'**', //gserviceaccount mail
array('https://www.googleapis.com/auth/analytics.readonly'),
file_get_contents($path_to_keyfile)
)
);
// Get this from the Google Console, API Access page
$client->setClientId('***'); // my cliente ID
$client->setAccessType('offline_access');
$analytics = new Google_AnalyticsService($client);
// create service and get data
$service = new Google_AnalyticsService($client);
// We have finished setting up the connection,
// now get some data and output the number of visits this week.
// Your analytics profile id. (Admin -> Profile Settings -> Profile ID)
$analytics_id = 'ga:****'; // my profile id
$lastWeek = date('Y-m-d', strtotime('-1 week'));
$today = date('Y-m-d');
try {
$results = $analytics->data_ga->get($analytics_id,
$lastWeek,
$today,'ga:visits');
echo '<b>Number of visits this week:</b> ';
echo $results['totalsForAllResults']['ga:visits'];
} catch(Exception $e) {
echo 'There was an error : - ' . $e->getMessage();
}
I've enabled the openssl extension in PHP:
When browsing to the location of the php script, I just get a almost forever loading and the following error:
I'm using PHP 5.4.7:
After debuging the Google API Client code, it looks like the script is breaking at this line:
if (!openssl_sign($data, $signature, $this->privateKey, "sha256"))
Anything below this line does not get called. Looks like the error happens in this line. Is there a incompatibility here, or something?
One thing for starters you should change:
You instantiate the AnalyticsService twice. Take out the one you're not using:
$service = new Google_AnalyticsService($client);
See if that helps your problem at all.

Categories