Quickstart: Run a Drive App in PHP seems to be using an outdated version of [google-api-php-client][2], also it doesn't provide example on how to upload a file using Service Account.
In my project I'll need to add a file (spreadsheet) using Service Account, add a spreadsheet, share the spreadsheet with another user and add rows to the spreadsheet.
I'm able to get an empty list of spreadsheets, but I couldn't figure it out how to upload a file using Service Account.
The PHP Class google-api-php-client/examples/spreadsheet.php:
<?php
use Google\Spreadsheet\DefaultServiceRequest;
use Google\Spreadsheet\ServiceRequestFactory;
use Google\Spreadsheet\SpreadsheetService;
define('JPATH_PLATFORM',1);
require_once realpath(dirname(__FILE__) . '/../autoload.php');
class GoogleSpreadSheet
{
protected $data;
protected $client_id = null ; //Client ID
protected $service_account_name = null; //Email Address
protected $key_file_location = null; //key.p12
protected $client = null;
protected $aplication_name = null;
protected $_errors = array();
protected $scopes = array( 'https://www.googleapis.com/auth/drive'
, 'https://www.googleapis.com/auth/drive.appdata'
, 'https://www.googleapis.com/auth/drive.apps.readonly'
, 'https://spreadsheets.google.com/feeds'
);
/**
* Class constructor
* @param mixed $properties Either and associative array or another
* object to set the initial properties of the object.
*/
public function __construct($properties = null){
if ($properties !== null)
{
$this->setProperties($properties);
}
$this->data = new stdClass();
$this->getClient();
}
/**
* Get Google_Client object
* @return mixed Google_Client object if client ID and application_name are set OR null
*/
public function getClient(){
if(empty($this->client) AND $this->get('client_id') AND $this->get('aplication_name')){
$this->client = new Google_Client();
$this->client->setApplicationName($this->get('aplication_name'));
$this->client->setClientId($this->get('client_id'));
}
return $this->client;
}
/**
* Get Service AccessToken
* @return AccessToken
*/
public function getToken()
{
$key = file_get_contents($this->get('key_file_location'));
$cred = new Google_Auth_AssertionCredentials(
$this->service_account_name,
$this->get('scopes', array()),
$key
);
$this->client->setAssertionCredentials($cred);
if($this->client->getAuth()->isAccessTokenExpired()) {
$this->client->getAuth()->refreshTokenWithAssertion($cred);
}
$service_token = json_decode($this->client->getAccessToken());
return $service_token->access_token;
}
/**
* Get Available Spreadsheets
*/
public function getSpreadsheetsList()
{
$accessToken = $this->getToken();
$serviceRequest = new DefaultServiceRequest($accessToken);
ServiceRequestFactory::setInstance($serviceRequest);
$spreadsheetService = new SpreadsheetService();
$spreadsheetFeed = $spreadsheetService->getSpreadsheets();
echo '<pre>'; print_r($spreadsheetFeed);
foreach($spreadsheetFeed as $item) {
$spreadsheets[basename($item->getId())] = $item->getTitle();
}
$this->data->spreadsheets = isset($spreadsheets) ? $spreadsheets : false;
}
/**
* Insert new file.
*
* @param string $title Title of the file to insert, including the extension.
* @param string $description Description of the file to insert.
* @param string $parentId Parent folder's ID.
* @param string $mimeType MIME type of the file to insert.
* @param string $filename Filename of the file to insert.
* @return Google_DriveFile The file that was inserted. NULL is returned if an API error occurred.
*/
public function insertFile($title, $description, $mimeType='application/vnd.google-apps.spreadsheet', $filename=null, $parentId=null) {
//Google_DriveService $service Drive API service instance.
$service = new Google_Service_Drive($this->getClient());
$file = new Google_Service_Drive_DriveFile();
$file->setTitle($title);
$file->setDescription($description);
$file->setMimeType($mimeType);
// Set the parent folder.
if ($parentId != null) {
$parent = new Google_ParentReference();
$parent->setId($parentId);
$file->setParents(array($parent));
}
try {
if(!empty($filename)){
$data = file_get_contents($filename);
}else{
$data = '';
}
$createdFile = $service->files->insert($file, array(
'data' => $data,
'mimeType' => $mimeType,
));
// Uncomment the following line to print the File ID
// print 'File ID: %s' % $createdFile->getId();
return $createdFile;
} catch (Exception $e) {
$this->setError($e->getMessage());
print "An error occurred: " . $e->getMessage();
}
}
/**
* Sets a default value if not alreay assigned
* @param string $property The name of the property.
* @param mixed $default The default value.
* @return mixed
*/
public function def($property, $default = null)
{
$value = $this->get($property, $default);
return $this->set($property, $value);
}
/**
* Returns a property of the object or the default value if the property is not set.
* @param string $property The name of the property.
* @param mixed $default The default value.
* @return mixed The value of the property.
*/
public function get($property, $default = null)
{
if (isset($this->$property))
{
return $this->$property;
}
return $default;
}
/**
* Returns an associative array of object properties.
* @param boolean $public If true, returns only the public properties.
* @return array
*/
public function getProperties($public = true)
{
$vars = get_object_vars($this);
if ($public)
{
foreach ($vars as $key => $value)
{
if ('_' == substr($key, 0, 1))
{
unset($vars[$key]);
}
}
}
return $vars;
}
/**
* Get the most recent error message.
* @param integer $i Option error index.
* @param boolean $toString Indicates if JError objects should return their error message.
* @return string Error message
*/
public function getError($i = null, $toString = true)
{
// Find the error
if ($i === null)
{
// Default, return the last message
$error = end($this->_errors);
}
elseif (!array_key_exists($i, $this->_errors))
{
// If $i has been specified but does not exist, return false
return false;
}
else
{
$error = $this->_errors[$i];
}
// Check if only the string is requested
if ($error instanceof Exception && $toString)
{
return (string) $error;
}
return $error;
}
/**
* Return all errors, if any.
* @return array Array of error messages or JErrors.
*/
public function getErrors()
{
return $this->_errors;
}
/**
* Modifies a property of the object, creating it if it does not already exist.
* @param string $property The name of the property.
* @param mixed $value The value of the property to set.
* @return mixed Previous value of the property.
*/
public function set($property, $value = null)
{
$previous = isset($this->$property) ? $this->$property : null;
$this->$property = $value;
return $previous;
}
/**
* Set the object properties based on a named array/hash.
* @param mixed $properties Either an associative array or another object.
* @return boolean
*/
public function setProperties($properties)
{
if (is_array($properties) || is_object($properties))
{
foreach ((array) $properties as $k => $v)
{
// Use the set function which might be overridden.
$this->set($k, $v);
}
return true;
}
return false;
}
/**
* Add an error message.
* @param string $error Error message.
* @return void
*/
public function setError($error)
{
array_push($this->_errors, $error);
}
}
$opt = array();
$opt['key_file_location'] = realpath(dirname(__FILE__)).'/key_ss.p12';
$opt['client_id'] = '*********.apps.googleusercontent.com';
$opt['service_account_name']= '*********@developer.gserviceaccount.com';
$opt['aplication_name'] = 'MY APPLICATION NAME';
$GoogleSS = new GoogleSpreadSheet($opt);
$GoogleSS->insertFile('test', 'description');
$GoogleSS->getSpreadsheetsList();
I also have a modified version of /google-api-php-client/autoload.php:
<?php
function google_api_php_client_autoload($className) {
$classPath = explode('_', $className);
if ($classPath[0] != 'Google') {
return;
}
if (count($classPath) > 3) {
// Maximum class file path depth in this project is 3.
$classPath = array_slice($classPath, 0, 3);
}
$filePath = dirname(__FILE__) . '/src/' . implode('/', $classPath) . '.php';
if (file_exists($filePath)) {
require_once($filePath);
}
}
function google_spreadsheet_api_php_client_autoload($className) {
$classPath = explode('\\', $className);
if (count($classPath) == 1) {
$filePath = dirname(__FILE__) . '/src/Google/Spreadsheet/' . $className . '.php';
}else{
$filePath = dirname(__FILE__) . '/src/' . implode('/', $classPath) . '.php';
}
if (file_exists($filePath)) {
require_once($filePath);
}
}
spl_autoload_register('google_api_php_client_autoload');
spl_autoload_register('google_spreadsheet_api_php_client_autoload');
When I execute the code I get:
Notice: Undefined index: uploadType in /var/www/google-api-php-client/src/Google/Service/Resource.php on line 175
Notice: Undefined index: uploadType in /var/www/google-api-php-client/src/Google/Service/Resource.php on line 175
An error occurred: Error calling POST https://www.googleapis.com/drive/v2/files: (401) Login Required
Google\Spreadsheet\SpreadsheetFeed Object
( .... )
In order to reproduce the problem you will also need to download php-google-spreadsheet-client and upload the the Spreadsheet directory to /google-api-php-client/src/Google/
I've tried to provide as much details as possible, but please let me know if something is unclear.