4
votes

I am using Google PHP client to access spreadsheet data.

I getting this fatal error:

Fatal error: Uncaught exception 'Google_Service_Exception' with message '{ "error": { "code": 403, "message": "The caller does not have permission", "errors": [ { "message": "The caller does not have permission", "domain": "global", "reason": "forbidden" } ], "status": "PERMISSION_DENIED" } }

My code:

  $client = new Google_Client();
  $client->setApplicationName("Google spreadsheets");
  $client->setDeveloperKey("xxxxx");
  $client->setScopes(array('https://www.googleapis.com/auth/drive',    
  'https://www.googleapis.com/auth/spreadsheets.readonly',     
  'https://www.googleapis.com/auth/drive.file'));

  $service = new Google_Service_Sheets($client);

  $range = 'Class Data!A2:E';
  $response = $service->spreadsheets_values->get($sheetid, $range);
  $values = $response->getValues();

  if (count($values) == 0) {
      print "No data found.\n";
  } else {
    print "Name, Major:\n";
    foreach ($values as $row) {
     // Print columns A and E, which correspond to indices 0 and 4.
     printf("%s, %s\n", $row[0], $row[4]);
    }
  }

How to fix this?

4

4 Answers

9
votes

Take the service account email address and share the sheet with it like you would any other user. It will then have access to the sheet

1
votes

Take the 'client_email' from the downloaded JSON file or from your 'service account' and share the spreadsheet with this email address, you will get access to the spreadsheet. This solution worked for me.

0
votes

The error means that you do not have access to that sheet. I suggest you follow the Google Sheets php quick start tutorial, this will show you how to get authentication working.

<?php
require_once __DIR__ . '/vendor/autoload.php';


define('APPLICATION_NAME', 'Google Sheets API PHP Quickstart');
define('CREDENTIALS_PATH', '~/.credentials/sheets.googleapis.com-php-quickstart.json');
define('CLIENT_SECRET_PATH', __DIR__ . '/client_secret.json');
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/sheets.googleapis.com-php-quickstart.json
define('SCOPES', implode(' ', array(
  Google_Service_Sheets::SPREADSHEETS_READONLY)
));

if (php_sapi_name() != 'cli') {
  throw new Exception('This application must be run on the command line.');
}

/**
 * Returns an authorized API client.
 * @return Google_Client the authorized client object
 */
function getClient() {
  $client = new Google_Client();
  $client->setApplicationName(APPLICATION_NAME);
  $client->setScopes(SCOPES);
  $client->setAuthConfig(CLIENT_SECRET_PATH);
  $client->setAccessType('offline');

  // Load previously authorized credentials from a file.
  $credentialsPath = expandHomeDirectory(CREDENTIALS_PATH);
  if (file_exists($credentialsPath)) {
    $accessToken = json_decode(file_get_contents($credentialsPath), true);
  } else {
    // Request authorization from the user.
    $authUrl = $client->createAuthUrl();
    printf("Open the following link in your browser:\n%s\n", $authUrl);
    print 'Enter verification code: ';
    $authCode = trim(fgets(STDIN));

    // Exchange authorization code for an access token.
    $accessToken = $client->fetchAccessTokenWithAuthCode($authCode);

    // Store the credentials to disk.
    if(!file_exists(dirname($credentialsPath))) {
      mkdir(dirname($credentialsPath), 0700, true);
    }
    file_put_contents($credentialsPath, json_encode($accessToken));
    printf("Credentials saved to %s\n", $credentialsPath);
  }
  $client->setAccessToken($accessToken);

  // Refresh the token if it's expired.
  if ($client->isAccessTokenExpired()) {
    $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
    file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
  }
  return $client;
}

/**
 * Expands the home directory alias '~' to the full path.
 * @param string $path the path to expand.
 * @return string the expanded path.
 */
function expandHomeDirectory($path) {
  $homeDirectory = getenv('HOME');
  if (empty($homeDirectory)) {
    $homeDirectory = getenv('HOMEDRIVE') . getenv('HOMEPATH');
  }
  return str_replace('~', realpath($homeDirectory), $path);
}

// Get the API client and construct the service object.
$client = getClient();
$service = new Google_Service_Sheets($client);

// Prints the names and majors of students in a sample spreadsheet:
// https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
$spreadsheetId = '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms';
$range = 'Class Data!A2:E';
$response = $service->spreadsheets_values->get($spreadsheetId, $range);
$values = $response->getValues();

if (count($values) == 0) {
  print "No data found.\n";
} else {
  print "Name, Major:\n";
  foreach ($values as $row) {
    // Print columns A and E, which correspond to indices 0 and 4.
    printf("%s, %s\n", $row[0], $row[4]);
  }
}
0
votes

as per this document you'll not be able to access your own Spreadsheet via API key unless you make your document publicly available:

Source: https://developers.google.com/sheets/api/guides/authorizing

This document says:

  • If the request requires authorization (such as a request for an individual's private data), then the application must provide an OAuth 2.0 token with the request. The application may also provide the API key, but it doesn't have to.
  • If the request doesn't require authorization (such as a request for public data), then the application must provide either the API key or an OAuth 2.0 token, or both—whatever option is most convenient for you.

Unfortunately it is not "very clear" to what it means.

But combining explanations from several sources, it means that API key allows you to "identify yourself" for accessing public information. If you want to get a plublicly available resource as data from google maps, Google still wants to know "who is asking". API Key works here.

Instead, although the text in the the previous link might suggest that OAuth is for accessing data "from other users", in fact, any private data even your own data must be accessed by the OAuth method.

So for accessing private google spreadsheets that contain company data and have not been made publicly-available, then the OAuth keying system must be in place.