Update google-api-php-client from 1.0.6-beta to 1.1.7

This commit is contained in:
Francesco Rovelli 2016-04-26 15:58:15 +02:00 committed by Vincent Petry
parent 4ffc936624
commit c1583f03ab
No known key found for this signature in database
GPG Key ID: AF8F9EFC56562186
33 changed files with 3660 additions and 1823 deletions

View File

@ -25,10 +25,13 @@ For the latest installation and setup instructions, see [the documentation](http
See the examples/ directory for examples of the key client features.
```PHP
<?php
require_once 'google-api-php-client/autoload.php'; // or wherever autoload.php is located
require_once 'google-api-php-client/src/Google/autoload.php'; // or wherever autoload.php is located
$client = new Google_Client();
$client->setApplicationName("Client_Library_Examples");
$client->setDeveloperKey("YOUR_APP_KEY");
$service = new Google_Service_Books($client);
$optParams = array('filter' => 'free-ebooks');
$results = $service->volumes->listVolumes('Henry David Thoreau', $optParams);
@ -36,8 +39,13 @@ See the examples/ directory for examples of the key client features.
foreach ($results as $item) {
echo $item['volumeInfo']['title'], "<br /> \n";
}
```
### Service Specific Examples ###
YouTube: https://github.com/youtube/api-samples/tree/master/php
## Frequently Asked Questions ##
### What do I do if something isn't working? ###
@ -50,6 +58,10 @@ If there is a specific bug with the library, please file a issue in the Github i
We accept contributions via Github Pull Requests, but all contributors need to be covered by the standard Google Contributor License Agreement. You can find links, and more instructions, in the documentation: https://developers.google.com/api-client-library/php/contribute
### I want an example of X! ###
If X is a feature of the library, file away! If X is an example of using a specific service, the best place to go is to the teams for those specific APIs - our preference is to link to their examples rather than add them to the library, as they can then pin to specific versions of the library. If you have any examples for other APIs, let us know and we will happily add a link to the README above!
### Why do you still support 5.2? ###
When we started working on the 1.0.0 branch we knew there were several fundamental issues to fix with the 0.6 releases of the library. At that time we looked at the usage of the library, and other related projects, and determined that there was still a large and active base of PHP 5.2 installs. You can see this in statistics such as the PHP versions chart in the WordPress stats: http://wordpress.org/about/stats/. We will keep looking at the types of usage we see, and try to take advantage of newer PHP features where possible.
@ -68,10 +80,26 @@ $opt_params = array(
);
```
### How do I set a field to null? ###
The library strips out nulls from the objects sent to the Google APIs as its the default value of all of the uninitialised properties. To work around this, set the field you want to null to Google_Model::NULL_VALUE. This is a placeholder that will be replaced with a true null when sent over the wire.
## Code Quality ##
Copy the ruleset.xml in style/ into a new directory named GAPI/ in your
/usr/share/php/PHP/CodeSniffer/Standards (or appropriate equivalent directory),
and run code sniffs with:
Run the PHPUnit tests with PHPUnit. You can configure an API key and token in BaseTest.php to run all calls, but this will require some setup on the Google Developer Console.
phpcs --standard=GAPI src/
phpunit tests/
### Coding Style
To check for coding style violations, run
```
vendor/bin/phpcs src --standard=style/ruleset.xml -np
```
To automatically fix (fixable) coding style violations, run
```
vendor/bin/phpcbf src --standard=style/ruleset.xml
```

View File

@ -14,7 +14,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
require_once "Google/Http/Request.php";
if (!class_exists('Google_Client')) {
require_once dirname(__FILE__) . '/../autoload.php';
}
/**
* Abstract class for the Authentication in the API client

View File

@ -15,14 +15,12 @@
* limitations under the License.
*/
require_once "Google/Auth/OAuth2.php";
require_once "Google/Signer/P12.php";
require_once "Google/Utils.php";
if (!class_exists('Google_Client')) {
require_once dirname(__FILE__) . '/../autoload.php';
}
/**
* Credentials object used for OAuth 2.0 Signed JWT assertion grants.
*
* @author Chirag Shah <chirags@google.com>
*/
class Google_Auth_AssertionCredentials
{

View File

@ -15,7 +15,9 @@
* limitations under the License.
*/
require_once "Google/Exception.php";
if (!class_exists('Google_Client')) {
require_once dirname(__FILE__) . '/../autoload.php';
}
class Google_Auth_Exception extends Google_Exception
{

View File

@ -15,7 +15,9 @@
* limitations under the License.
*/
require_once "Google/Auth/Exception.php";
if (!class_exists('Google_Client')) {
require_once dirname(__FILE__) . '/../autoload.php';
}
/**
* Class to hold information about an authenticated login.

View File

@ -15,21 +15,13 @@
* limitations under the License.
*/
require_once "Google/Auth/Abstract.php";
require_once "Google/Auth/AssertionCredentials.php";
require_once "Google/Auth/Exception.php";
require_once "Google/Auth/LoginTicket.php";
require_once "Google/Client.php";
require_once "Google/Http/Request.php";
require_once "Google/Utils.php";
require_once "Google/Verifier/Pem.php";
if (!class_exists('Google_Client')) {
require_once dirname(__FILE__) . '/../autoload.php';
}
/**
* Authentication class that deals with the OAuth 2 web-server authentication flow
*
* @author Chris Chabot <chabotc@google.com>
* @author Chirag Shah <chirags@google.com>
*
*/
class Google_Auth_OAuth2 extends Google_Auth_Abstract
{
@ -40,6 +32,7 @@ class Google_Auth_OAuth2 extends Google_Auth_Abstract
const AUTH_TOKEN_LIFETIME_SECS = 300; // five minutes in seconds
const MAX_TOKEN_LIFETIME_SECS = 86400; // one day in seconds
const OAUTH2_ISSUER = 'accounts.google.com';
const OAUTH2_ISSUER_HTTPS = 'https://accounts.google.com';
/** @var Google_Auth_AssertionCredentials $assertionCredentials */
private $assertionCredentials;
@ -86,28 +79,34 @@ class Google_Auth_OAuth2 extends Google_Auth_Abstract
/**
* @param string $code
* @param boolean $crossClient
* @throws Google_Auth_Exception
* @return string
*/
public function authenticate($code)
public function authenticate($code, $crossClient = false)
{
if (strlen($code) == 0) {
throw new Google_Auth_Exception("Invalid code");
}
$arguments = array(
'code' => $code,
'grant_type' => 'authorization_code',
'client_id' => $this->client->getClassConfig($this, 'client_id'),
'client_secret' => $this->client->getClassConfig($this, 'client_secret')
);
if ($crossClient !== true) {
$arguments['redirect_uri'] = $this->client->getClassConfig($this, 'redirect_uri');
}
// We got here from the redirect from a successful authorization grant,
// fetch the access token
$request = new Google_Http_Request(
self::OAUTH2_TOKEN_URI,
'POST',
array(),
array(
'code' => $code,
'grant_type' => 'authorization_code',
'redirect_uri' => $this->client->getClassConfig($this, 'redirect_uri'),
'client_id' => $this->client->getClassConfig($this, 'client_id'),
'client_secret' => $this->client->getClassConfig($this, 'client_secret')
)
$arguments
);
$request->disableGzip();
$response = $this->client->getIo()->makeRequest($request);
@ -119,15 +118,15 @@ class Google_Auth_OAuth2 extends Google_Auth_Abstract
} else {
$decodedResponse = json_decode($response->getResponseBody(), true);
if ($decodedResponse != null && $decodedResponse['error']) {
$decodedResponse = $decodedResponse['error'];
$errorText = $decodedResponse['error'];
if (isset($decodedResponse['error_description'])) {
$decodedResponse .= ": " . $decodedResponse['error_description'];
$errorText .= ": " . $decodedResponse['error_description'];
}
}
throw new Google_Auth_Exception(
sprintf(
"Error fetching OAuth2 access token, message: '%s'",
$decodedResponse
$errorText
),
$response->getResponseHttpCode()
);
@ -151,11 +150,15 @@ class Google_Auth_OAuth2 extends Google_Auth_Abstract
'access_type' => $this->client->getClassConfig($this, 'access_type'),
);
$params = $this->maybeAddParam($params, 'approval_prompt');
// Prefer prompt to approval prompt.
if ($this->client->getClassConfig($this, 'prompt')) {
$params = $this->maybeAddParam($params, 'prompt');
} else {
$params = $this->maybeAddParam($params, 'approval_prompt');
}
$params = $this->maybeAddParam($params, 'login_hint');
$params = $this->maybeAddParam($params, 'hd');
$params = $this->maybeAddParam($params, 'openid.realm');
$params = $this->maybeAddParam($params, 'prompt');
$params = $this->maybeAddParam($params, 'include_granted_scopes');
// If the list of scopes contains plus.login, add request_visible_actions
@ -236,17 +239,21 @@ class Google_Auth_OAuth2 extends Google_Auth_Abstract
if ($this->assertionCredentials) {
$this->refreshTokenWithAssertion();
} else {
$this->client->getLogger()->debug('OAuth2 access token expired');
if (! array_key_exists('refresh_token', $this->token)) {
throw new Google_Auth_Exception(
"The OAuth 2.0 access token has expired,"
." and a refresh token is not available. Refresh tokens"
." are not returned for responses that were auto-approved."
);
$error = "The OAuth 2.0 access token has expired,"
." and a refresh token is not available. Refresh tokens"
." are not returned for responses that were auto-approved.";
$this->client->getLogger()->error($error);
throw new Google_Auth_Exception($error);
}
$this->refreshToken($this->token['refresh_token']);
}
}
$this->client->getLogger()->debug('OAuth2 authentication');
// Add the OAuth2 header to the request
$request->setRequestHeaders(
array('Authorization' => 'Bearer ' . $this->token['access_token'])
@ -298,6 +305,7 @@ class Google_Auth_OAuth2 extends Google_Auth_Abstract
}
}
$this->client->getLogger()->debug('OAuth2 access token expired');
$this->refreshTokenRequest(
array(
'grant_type' => 'assertion',
@ -317,6 +325,14 @@ class Google_Auth_OAuth2 extends Google_Auth_Abstract
private function refreshTokenRequest($params)
{
if (isset($params['assertion'])) {
$this->client->getLogger()->info(
'OAuth2 access token refresh with Signed JWT assertion grants.'
);
} else {
$this->client->getLogger()->info('OAuth2 access token refresh');
}
$http = new Google_Http_Request(
self::OAUTH2_TOKEN_URI,
'POST',
@ -414,7 +430,9 @@ class Google_Auth_OAuth2 extends Google_Auth_Abstract
/**
* Retrieve and cache a certificates file.
* @param $url location
*
* @param $url string location
* @throws Google_Auth_Exception
* @return array certificates
*/
public function retrieveCertsFromLocation($url)
@ -471,18 +489,24 @@ class Google_Auth_OAuth2 extends Google_Auth_Abstract
$audience = $this->client->getClassConfig($this, 'client_id');
}
return $this->verifySignedJwtWithCerts($id_token, $certs, $audience, self::OAUTH2_ISSUER);
return $this->verifySignedJwtWithCerts(
$id_token,
$certs,
$audience,
array(self::OAUTH2_ISSUER, self::OAUTH2_ISSUER_HTTPS)
);
}
/**
* Verifies the id token, returns the verified token contents.
*
* @param $jwt the token
* @param $jwt string the token
* @param $certs array of certificates
* @param $required_audience the expected consumer of the token
* @param $required_audience string the expected consumer of the token
* @param [$issuer] the expected issues, defaults to Google
* @param [$max_expiry] the max lifetime of a token, defaults to MAX_TOKEN_LIFETIME_SECS
* @return token information if valid, false if not
* @throws Google_Auth_Exception
* @return mixed token information if valid, false if not
*/
public function verifySignedJwtWithCerts(
$jwt,
@ -577,13 +601,15 @@ class Google_Auth_OAuth2 extends Google_Auth_Abstract
);
}
// support HTTP and HTTPS issuers
// @see https://developers.google.com/identity/sign-in/web/backend-auth
$iss = $payload['iss'];
if ($issuer && $iss != $issuer) {
if ($issuer && !in_array($iss, (array) $issuer)) {
throw new Google_Auth_Exception(
sprintf(
"Invalid issuer, %s != %s: %s",
"Invalid issuer, %s not in %s: %s",
$iss,
$issuer,
"[".implode(",", (array) $issuer)."]",
$json_body
)
);

View File

@ -15,19 +15,17 @@
* limitations under the License.
*/
require_once "Google/Auth/Abstract.php";
require_once "Google/Http/Request.php";
if (!class_exists('Google_Client')) {
require_once dirname(__FILE__) . '/../autoload.php';
}
/**
* Simple API access implementation. Can either be used to make requests
* completely unauthenticated, or by using a Simple API Access developer
* key.
* @author Chris Chabot <chabotc@google.com>
* @author Chirag Shah <chirags@google.com>
*/
class Google_Auth_Simple extends Google_Auth_Abstract
{
private $key = null;
private $client;
public function __construct(Google_Client $client, $config = null)
@ -55,6 +53,9 @@ class Google_Auth_Simple extends Google_Auth_Abstract
{
$key = $this->client->getClassConfig($this, 'developer_key');
if ($key) {
$this->client->getLogger()->debug(
'Simple API Access developer key authentication'
);
$request->setQueryParam('key', $key);
}
return $request;

View File

@ -14,9 +14,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
require_once "Google/Cache/Abstract.php";
require_once "Google/Cache/Exception.php";
if (!class_exists('Google_Client')) {
require_once dirname(__FILE__) . '/../autoload.php';
}
/**
* A persistent storage class based on the APC cache, which is not
@ -28,11 +29,21 @@ require_once "Google/Cache/Exception.php";
*/
class Google_Cache_Apc extends Google_Cache_Abstract
{
/**
* @var Google_Client the current client
*/
private $client;
public function __construct(Google_Client $client)
{
if (! function_exists('apc_add') ) {
throw new Google_Cache_Exception("Apc functions not available");
$error = "Apc functions not available";
$client->getLogger()->error($error);
throw new Google_Cache_Exception($error);
}
$this->client = $client;
}
/**
@ -42,12 +53,26 @@ class Google_Cache_Apc extends Google_Cache_Abstract
{
$ret = apc_fetch($key);
if ($ret === false) {
$this->client->getLogger()->debug(
'APC cache miss',
array('key' => $key)
);
return false;
}
if (is_numeric($expiration) && (time() - $ret['time'] > $expiration)) {
$this->client->getLogger()->debug(
'APC cache miss (expired)',
array('key' => $key, 'var' => $ret)
);
$this->delete($key);
return false;
}
$this->client->getLogger()->debug(
'APC cache hit',
array('key' => $key, 'var' => $ret)
);
return $ret['data'];
}
@ -56,10 +81,21 @@ class Google_Cache_Apc extends Google_Cache_Abstract
*/
public function set($key, $value)
{
$rc = apc_store($key, array('time' => time(), 'data' => $value));
$var = array('time' => time(), 'data' => $value);
$rc = apc_store($key, $var);
if ($rc == false) {
$this->client->getLogger()->error(
'APC cache set failed',
array('key' => $key, 'var' => $var)
);
throw new Google_Cache_Exception("Couldn't store data");
}
$this->client->getLogger()->debug(
'APC cache set',
array('key' => $key, 'var' => $var)
);
}
/**
@ -68,6 +104,10 @@ class Google_Cache_Apc extends Google_Cache_Abstract
*/
public function delete($key)
{
$this->client->getLogger()->debug(
'APC cache delete',
array('key' => $key)
);
apc_delete($key);
}
}

View File

@ -14,7 +14,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
require_once "Google/Exception.php";
if (!class_exists('Google_Client')) {
require_once dirname(__FILE__) . '/../autoload.php';
}
class Google_Cache_Exception extends Google_Exception
{

View File

@ -15,8 +15,9 @@
* limitations under the License.
*/
require_once "Google/Cache/Abstract.php";
require_once "Google/Cache/Exception.php";
if (!class_exists('Google_Client')) {
require_once dirname(__FILE__) . '/../autoload.php';
}
/*
* This class implements a basic on disk storage. While that does
@ -32,34 +33,60 @@ class Google_Cache_File extends Google_Cache_Abstract
private $path;
private $fh;
/**
* @var Google_Client the current client
*/
private $client;
public function __construct(Google_Client $client)
{
$this->path = $client->getClassConfig($this, 'directory');
$this->client = $client;
$this->path = $this->client->getClassConfig($this, 'directory');
}
public function get($key, $expiration = false)
{
$storageFile = $this->getCacheFile($key);
$data = false;
if (!file_exists($storageFile)) {
$this->client->getLogger()->debug(
'File cache miss',
array('key' => $key, 'file' => $storageFile)
);
return false;
}
if ($expiration) {
$mtime = filemtime($storageFile);
if ((time() - $mtime) >= $expiration) {
$this->client->getLogger()->debug(
'File cache miss (expired)',
array('key' => $key, 'file' => $storageFile)
);
$this->delete($key);
return false;
}
}
if ($this->acquireReadLock($storageFile)) {
$data = fread($this->fh, filesize($storageFile));
$data = unserialize($data);
if (filesize($storageFile) > 0) {
$data = fread($this->fh, filesize($storageFile));
$data = unserialize($data);
} else {
$this->client->getLogger()->debug(
'Cache file was empty',
array('file' => $storageFile)
);
}
$this->unlock($storageFile);
}
$this->client->getLogger()->debug(
'File cache hit',
array('key' => $key, 'file' => $storageFile, 'var' => $data)
);
return $data;
}
@ -72,6 +99,16 @@ class Google_Cache_File extends Google_Cache_Abstract
$data = serialize($value);
$result = fwrite($this->fh, $data);
$this->unlock($storageFile);
$this->client->getLogger()->debug(
'File cache set',
array('key' => $key, 'file' => $storageFile, 'var' => $value)
);
} else {
$this->client->getLogger()->notice(
'File cache set failed',
array('key' => $key, 'file' => $storageFile)
);
}
}
@ -79,10 +116,19 @@ class Google_Cache_File extends Google_Cache_Abstract
{
$file = $this->getCacheFile($key);
if (file_exists($file) && !unlink($file)) {
$this->client->getLogger()->error(
'File cache delete failed',
array('key' => $key, 'file' => $file)
);
throw new Google_Cache_Exception("Cache file could not be deleted");
}
$this->client->getLogger()->debug(
'File cache delete',
array('key' => $key, 'file' => $file)
);
}
private function getWriteableCacheFile($file)
{
return $this->getCacheFile($file, true);
@ -92,7 +138,7 @@ class Google_Cache_File extends Google_Cache_Abstract
{
return $this->getCacheDir($file, $forWrite) . '/' . md5($file);
}
private function getCacheDir($file, $forWrite)
{
// use the first 2 characters of the hash as a directory prefix
@ -100,31 +146,49 @@ class Google_Cache_File extends Google_Cache_Abstract
// and thus give some basic amount of scalability
$storageDir = $this->path . '/' . substr(md5($file), 0, 2);
if ($forWrite && ! is_dir($storageDir)) {
if (! mkdir($storageDir, 0755, true)) {
if (! mkdir($storageDir, 0700, true)) {
$this->client->getLogger()->error(
'File cache creation failed',
array('dir' => $storageDir)
);
throw new Google_Cache_Exception("Could not create storage directory: $storageDir");
}
}
return $storageDir;
}
private function acquireReadLock($storageFile)
{
return $this->acquireLock(LOCK_SH, $storageFile);
}
private function acquireWriteLock($storageFile)
{
$rc = $this->acquireLock(LOCK_EX, $storageFile);
if (!$rc) {
$this->client->getLogger()->notice(
'File cache write lock failed',
array('file' => $storageFile)
);
$this->delete($storageFile);
}
return $rc;
}
private function acquireLock($type, $storageFile)
{
$mode = $type == LOCK_EX ? "w" : "r";
$this->fh = fopen($storageFile, $mode);
if (!$this->fh) {
$this->client->getLogger()->error(
'Failed to open file during lock acquisition',
array('file' => $storageFile)
);
return false;
}
if ($type == LOCK_EX) {
chmod($storageFile, 0600);
}
$count = 0;
while (!flock($this->fh, $type | LOCK_NB)) {
// Sleep for 10ms.
@ -135,7 +199,7 @@ class Google_Cache_File extends Google_Cache_Abstract
}
return true;
}
public function unlock($storageFile)
{
if ($this->fh) {

View File

@ -15,8 +15,9 @@
* limitations under the License.
*/
require_once "Google/Cache/Abstract.php";
require_once "Google/Cache/Exception.php";
if (!class_exists('Google_Client')) {
require_once dirname(__FILE__) . '/../autoload.php';
}
/**
* A persistent storage class based on the memcache, which is not
@ -35,11 +36,22 @@ class Google_Cache_Memcache extends Google_Cache_Abstract
private $host;
private $port;
/**
* @var Google_Client the current client
*/
private $client;
public function __construct(Google_Client $client)
{
if (!function_exists('memcache_connect') && !class_exists("Memcached")) {
throw new Google_Cache_Exception("Memcache functions not available");
$error = "Memcache functions not available";
$client->getLogger()->error($error);
throw new Google_Cache_Exception($error);
}
$this->client = $client;
if ($client->isAppEngine()) {
// No credentials needed for GAE.
$this->mc = new Memcached();
@ -48,11 +60,14 @@ class Google_Cache_Memcache extends Google_Cache_Abstract
$this->host = $client->getClassConfig($this, 'host');
$this->port = $client->getClassConfig($this, 'port');
if (empty($this->host) || (empty($this->port) && (string) $this->port != "0")) {
throw new Google_Cache_Exception("You need to supply a valid memcache host and port");
$error = "You need to supply a valid memcache host and port";
$client->getLogger()->error($error);
throw new Google_Cache_Exception($error);
}
}
}
/**
* @inheritDoc
*/
@ -66,12 +81,26 @@ class Google_Cache_Memcache extends Google_Cache_Abstract
$ret = memcache_get($this->connection, $key);
}
if ($ret === false) {
$this->client->getLogger()->debug(
'Memcache cache miss',
array('key' => $key)
);
return false;
}
if (is_numeric($expiration) && (time() - $ret['time'] > $expiration)) {
$this->client->getLogger()->debug(
'Memcache cache miss (expired)',
array('key' => $key, 'var' => $ret)
);
$this->delete($key);
return false;
}
$this->client->getLogger()->debug(
'Memcache cache hit',
array('key' => $key, 'var' => $ret)
);
return $ret['data'];
}
@ -94,8 +123,18 @@ class Google_Cache_Memcache extends Google_Cache_Abstract
$rc = memcache_set($this->connection, $key, $data, false);
}
if ($rc == false) {
$this->client->getLogger()->error(
'Memcache cache set failed',
array('key' => $key, 'var' => $data)
);
throw new Google_Cache_Exception("Couldn't store data in cache");
}
$this->client->getLogger()->debug(
'Memcache cache set',
array('key' => $key, 'var' => $data)
);
}
/**
@ -110,11 +149,16 @@ class Google_Cache_Memcache extends Google_Cache_Abstract
} else {
memcache_delete($this->connection, $key, 0);
}
$this->client->getLogger()->debug(
'Memcache cache delete',
array('key' => $key)
);
}
/**
* Lazy initialiser for memcache connection. Uses pconnect for to take
* advantage of the persistence pool where possible.
* Lazy initialiser for memcache connection. Uses pconnect for to take
* advantage of the persistence pool where possible.
*/
private function connect()
{
@ -129,9 +173,12 @@ class Google_Cache_Memcache extends Google_Cache_Abstract
} else {
$this->connection = memcache_pconnect($this->host, $this->port);
}
if (! $this->connection) {
throw new Google_Cache_Exception("Couldn't connect to memcache server");
$error = "Couldn't connect to memcache server";
$this->client->getLogger()->error($error);
throw new Google_Cache_Exception($error);
}
}
}

View File

@ -15,28 +15,17 @@
* limitations under the License.
*/
require_once 'Google/Auth/AssertionCredentials.php';
require_once 'Google/Cache/File.php';
require_once 'Google/Cache/Memcache.php';
require_once 'Google/Config.php';
require_once 'Google/Collection.php';
require_once 'Google/Exception.php';
require_once 'Google/IO/Curl.php';
require_once 'Google/IO/Stream.php';
require_once 'Google/Model.php';
require_once 'Google/Service.php';
require_once 'Google/Service/Resource.php';
if (!class_exists('Google_Client')) {
require_once dirname(__FILE__) . '/autoload.php';
}
/**
* The Google API Client
* http://code.google.com/p/google-api-php-client/
*
* @author Chris Chabot <chabotc@google.com>
* @author Chirag Shah <chirags@google.com>
* https://github.com/google/google-api-php-client
*/
class Google_Client
{
const LIBVER = "1.0.6-beta";
const LIBVER = "1.1.5";
const USER_AGENT_SUFFIX = "google-api-php-client/";
/**
* @var Google_Auth_Abstract $auth
@ -58,6 +47,11 @@ class Google_Client
*/
private $config;
/**
* @var Google_Logger_Abstract $logger
*/
private $logger;
/**
* @var boolean $deferExecution
*/
@ -97,7 +91,8 @@ class Google_Client
}
if ($config->getIoClass() == Google_Config::USE_AUTO_IO_SELECTION) {
if (function_exists('curl_version') && function_exists('curl_exec')) {
if (function_exists('curl_version') && function_exists('curl_exec')
&& !$this->isAppEngine()) {
$config->setIoClass("Google_IO_Curl");
} else {
$config->setIoClass("Google_IO_Stream");
@ -119,15 +114,45 @@ class Google_Client
/**
* Attempt to exchange a code for an valid authentication token.
* If $crossClient is set to true, the request body will not include
* the request_uri argument
* Helper wrapped around the OAuth 2.0 implementation.
*
* @param $code string code from accounts.google.com
* @param $crossClient boolean, whether this is a cross-client authentication
* @return string token
*/
public function authenticate($code)
public function authenticate($code, $crossClient = false)
{
$this->authenticated = true;
return $this->getAuth()->authenticate($code);
return $this->getAuth()->authenticate($code, $crossClient);
}
/**
* Loads a service account key and parameters from a JSON
* file from the Google Developer Console. Uses that and the
* given array of scopes to return an assertion credential for
* use with refreshTokenWithAssertionCredential.
*
* @param string $jsonLocation File location of the project-key.json.
* @param array $scopes The scopes to assert.
* @return Google_Auth_AssertionCredentials.
* @
*/
public function loadServiceAccountJson($jsonLocation, $scopes)
{
$data = json_decode(file_get_contents($jsonLocation));
if (isset($data->type) && $data->type == 'service_account') {
// Service Account format.
$cred = new Google_Auth_AssertionCredentials(
$data->client_email,
$scopes,
$data->private_key
);
return $cred;
} else {
throw new Google_Exception("Invalid service account JSON file.");
}
}
/**
@ -136,6 +161,7 @@ class Google_Client
* the "Download JSON" button on in the Google Developer
* Console.
* @param string $json the configuration json
* @throws Google_Exception
*/
public function setAuthConfig($json)
{
@ -164,6 +190,7 @@ class Google_Client
}
/**
* @throws Google_Auth_Exception
* @return array
* @visible For Testing
*/
@ -205,9 +232,9 @@ class Google_Client
/**
* Set the IO object
* @param Google_Io_Abstract $auth
* @param Google_IO_Abstract $io
*/
public function setIo(Google_Io_Abstract $io)
public function setIo(Google_IO_Abstract $io)
{
$this->config->setIoClass(get_class($io));
$this->io = $io;
@ -215,7 +242,7 @@ class Google_Client
/**
* Set the Cache object
* @param Google_Cache_Abstract $auth
* @param Google_Cache_Abstract $cache
*/
public function setCache(Google_Cache_Abstract $cache)
{
@ -223,6 +250,16 @@ class Google_Client
$this->cache = $cache;
}
/**
* Set the Logger object
* @param Google_Logger_Abstract $logger
*/
public function setLogger(Google_Logger_Abstract $logger)
{
$this->config->setLoggerClass(get_class($logger));
$this->logger = $logger;
}
/**
* Construct the OAuth 2.0 authorization request URI.
* @return string
@ -414,11 +451,10 @@ class Google_Client
/**
* Fetches a fresh OAuth 2.0 access token with the given refresh token.
* @param string $refreshToken
* @return void
*/
public function refreshToken($refreshToken)
{
return $this->getAuth()->refreshToken($refreshToken);
$this->getAuth()->refreshToken($refreshToken);
}
/**
@ -449,12 +485,12 @@ class Google_Client
/**
* Verify a JWT that was signed with your own certificates.
*
* @param $jwt the token
* @param $certs array of certificates
* @param $required_audience the expected consumer of the token
* @param [$issuer] the expected issues, defaults to Google
* @param $id_token string The JWT token
* @param $cert_location array of certificates
* @param $audience string the expected consumer of the token
* @param $issuer string the expected issuer, defaults to Google
* @param [$max_expiry] the max lifetime of a token, defaults to MAX_TOKEN_LIFETIME_SECS
* @return token information if valid, false if not
* @return mixed token information if valid, false if not
*/
public function verifySignedJwt($id_token, $cert_location, $audience, $issuer, $max_expiry = null)
{
@ -464,8 +500,7 @@ class Google_Client
}
/**
* @param Google_Auth_AssertionCredentials $creds
* @return void
* @param $creds Google_Auth_AssertionCredentials
*/
public function setAssertionCredentials(Google_Auth_AssertionCredentials $creds)
{
@ -539,6 +574,8 @@ class Google_Client
/**
* Helper method to execute deferred HTTP requests.
*
* @param $request Google_Http_Request|Google_Http_Batch
* @throws Google_Exception
* @return object of the type of the expected class or array.
*/
public function execute($request)
@ -606,10 +643,23 @@ class Google_Client
return $this->cache;
}
/**
* @return Google_Logger_Abstract Logger implementation
*/
public function getLogger()
{
if (!isset($this->logger)) {
$class = $this->config->getLoggerClass();
$this->logger = new $class($this);
}
return $this->logger;
}
/**
* Retrieve custom configuration for a specific class.
* @param $class string|object - class or instance of class to retrieve
* @param $key string optional - key to retrieve
* @return array
*/
public function getClassConfig($class, $key = null)
{
@ -623,9 +673,9 @@ class Google_Client
* Set configuration specific to a given class.
* $config->setClassConfig('Google_Cache_File',
* array('directory' => '/tmp/cache'));
* @param $class The class name for the configuration
* @param $class string|object - The class name for the configuration
* @param $config string key or an array of configuration values
* @param $value optional - if $config is a key, the value
* @param $value string optional - if $config is a key, the value
*
*/
public function setClassConfig($class, $config, $value = null)
@ -633,7 +683,7 @@ class Google_Client
if (!is_string($class)) {
$class = get_class($class);
}
return $this->config->setClassConfig($class, $config, $value);
$this->config->setClassConfig($class, $config, $value);
}

View File

@ -1,6 +1,8 @@
<?php
require_once "Google/Model.php";
if (!class_exists('Google_Client')) {
require_once dirname(__FILE__) . '/autoload.php';
}
/**
* Extension to the regular Google_Model that automatically
@ -48,10 +50,13 @@ class Google_Collection extends Google_Model implements Iterator, Countable
public function count()
{
if (!isset($this->modelData[$this->collection_key])) {
return 0;
}
return count($this->modelData[$this->collection_key]);
}
public function offsetExists ($offset)
public function offsetExists($offset)
{
if (!is_numeric($offset)) {
return parent::offsetExists($offset);

View File

@ -25,6 +25,9 @@ class Google_Config
const GZIP_UPLOADS_ENABLED = true;
const GZIP_UPLOADS_DISABLED = false;
const USE_AUTO_IO_SELECTION = "auto";
const TASK_RETRY_NEVER = 0;
const TASK_RETRY_ONCE = 1;
const TASK_RETRY_ALWAYS = -1;
protected $configuration;
/**
@ -44,6 +47,7 @@ class Google_Config
'auth_class' => 'Google_Auth_OAuth2',
'io_class' => self::USE_AUTO_IO_SELECTION,
'cache_class' => 'Google_Cache_File',
'logger_class' => 'Google_Logger_Null',
// Don't change these unless you're working against a special development
// or testing environment.
@ -54,6 +58,21 @@ class Google_Config
'Google_IO_Abstract' => array(
'request_timeout_seconds' => 100,
),
'Google_IO_Curl' => array(
'disable_proxy_workaround' => false,
'options' => null,
),
'Google_Logger_Abstract' => array(
'level' => 'debug',
'log_format' => "[%datetime%] %level%: %message% %context%\n",
'date_format' => 'd/M/Y:H:i:s O',
'allow_newlines' => true
),
'Google_Logger_File' => array(
'file' => 'php://stdout',
'mode' => 0640,
'lock' => false,
),
'Google_Http_Request' => array(
// Disable the use of gzip on calls if set to true. Defaults to false.
'disable_gzip' => self::GZIP_ENABLED,
@ -89,6 +108,36 @@ class Google_Config
'federated_signon_certs_url' =>
'https://www.googleapis.com/oauth2/v1/certs',
),
'Google_Task_Runner' => array(
// Delays are specified in seconds
'initial_delay' => 1,
'max_delay' => 60,
// Base number for exponential backoff
'factor' => 2,
// A random number between -jitter and jitter will be added to the
// factor on each iteration to allow for better distribution of
// retries.
'jitter' => .5,
// Maximum number of retries allowed
'retries' => 0
),
'Google_Service_Exception' => array(
'retry_map' => array(
'500' => self::TASK_RETRY_ALWAYS,
'503' => self::TASK_RETRY_ALWAYS,
'rateLimitExceeded' => self::TASK_RETRY_ALWAYS,
'userRateLimitExceeded' => self::TASK_RETRY_ALWAYS
)
),
'Google_IO_Exception' => array(
'retry_map' => !extension_loaded('curl') ? array() : array(
CURLE_COULDNT_RESOLVE_HOST => self::TASK_RETRY_ALWAYS,
CURLE_COULDNT_CONNECT => self::TASK_RETRY_ALWAYS,
CURLE_OPERATION_TIMEOUTED => self::TASK_RETRY_ALWAYS,
CURLE_SSL_CONNECT_ERROR => self::TASK_RETRY_ALWAYS,
CURLE_GOT_NOTHING => self::TASK_RETRY_ALWAYS
)
),
// Set a default directory for the file cache.
'Google_Cache_File' => array(
'directory' => sys_get_temp_dir() . '/Google_Client'
@ -98,7 +147,11 @@ class Google_Config
if ($ini_file_location) {
$ini = parse_ini_file($ini_file_location, true);
if (is_array($ini) && count($ini)) {
$this->configuration = array_merge($this->configuration, $ini);
$merged_configuration = $ini + $this->configuration;
if (isset($ini['classes']) && isset($this->configuration['classes'])) {
$merged_configuration['classes'] = $ini['classes'] + $this->configuration['classes'];
}
$this->configuration = $merged_configuration;
}
}
}
@ -107,9 +160,9 @@ class Google_Config
* Set configuration specific to a given class.
* $config->setClassConfig('Google_Cache_File',
* array('directory' => '/tmp/cache'));
* @param $class The class name for the configuration
* @param $class string The class name for the configuration
* @param $config string key or an array of configuration values
* @param $value optional - if $config is a key, the value
* @param $value string optional - if $config is a key, the value
*/
public function setClassConfig($class, $config, $value = null)
{
@ -144,6 +197,15 @@ class Google_Config
return $this->configuration['cache_class'];
}
/**
* Return the configured logger class.
* @return string
*/
public function getLoggerClass()
{
return $this->configuration['logger_class'];
}
/**
* Return the configured Auth class.
* @return string
@ -156,7 +218,7 @@ class Google_Config
/**
* Set the auth class.
*
* @param $class the class name to set
* @param $class string the class name to set
*/
public function setAuthClass($class)
{
@ -172,7 +234,7 @@ class Google_Config
/**
* Set the IO class.
*
* @param $class the class name to set
* @param $class string the class name to set
*/
public function setIoClass($class)
{
@ -188,7 +250,7 @@ class Google_Config
/**
* Set the cache class.
*
* @param $class the class name to set
* @param $class string the class name to set
*/
public function setCacheClass($class)
{
@ -201,8 +263,25 @@ class Google_Config
$this->configuration['cache_class'] = $class;
}
/**
* Set the logger class.
*
* @param $class string the class name to set
*/
public function setLoggerClass($class)
{
$prev = $this->configuration['logger_class'];
if (!isset($this->configuration['classes'][$class]) &&
isset($this->configuration['classes'][$prev])) {
$this->configuration['classes'][$class] =
$this->configuration['classes'][$prev];
}
$this->configuration['logger_class'] = $class;
}
/**
* Return the configured IO class.
*
* @return string
*/
public function getIoClass()
@ -229,7 +308,7 @@ class Google_Config
/**
* Set the client ID for the auth class.
* @param $key string - the API console client ID
* @param $clientId string - the API console client ID
*/
public function setClientId($clientId)
{
@ -238,7 +317,7 @@ class Google_Config
/**
* Set the client secret for the auth class.
* @param $key string - the API console client secret
* @param $secret string - the API console client secret
*/
public function setClientSecret($secret)
{
@ -248,7 +327,8 @@ class Google_Config
/**
* Set the redirect uri for the auth class. Note that if using the
* Javascript based sign in flow, this should be the string 'postmessage'.
* @param $key string - the URI that users should be redirected to
*
* @param $uri string - the URI that users should be redirected to
*/
public function setRedirectUri($uri)
{
@ -305,6 +385,11 @@ class Google_Config
* Set the hd (hosted domain) parameter streamlines the login process for
* Google Apps hosted accounts. By including the domain of the user, you
* restrict sign-in to accounts at that domain.
*
* This should not be used to ensure security on your application - check
* the hd values within an id token (@see Google_Auth_LoginTicket) after sign
* in to ensure that the user is from the domain you were expecting.
*
* @param $hd string - the domain to use.
*/
public function setHostedDomain($hd)

View File

@ -15,12 +15,12 @@
* limitations under the License.
*/
require_once 'Google/Client.php';
require_once 'Google/Http/Request.php';
require_once 'Google/Http/REST.php';
if (!class_exists('Google_Client')) {
require_once dirname(__FILE__) . '/../autoload.php';
}
/**
* @author Chirag Shah <chirags@google.com>
* Class to handle batched requests to the Google API service.
*/
class Google_Http_Batch
{
@ -35,12 +35,15 @@ class Google_Http_Batch
private $expected_classes = array();
private $base_path;
private $root_url;
public function __construct(Google_Client $client, $boundary = false)
private $batch_path;
public function __construct(Google_Client $client, $boundary = false, $rootUrl = '', $batchPath = '')
{
$this->client = $client;
$this->base_path = $this->client->getBasePath();
$this->root_url = rtrim($rootUrl ? $rootUrl : $this->client->getBasePath(), '/');
$this->batch_path = $batchPath ? $batchPath : 'batch';
$this->expected_classes = array();
$boundary = (false == $boundary) ? mt_rand() : $boundary;
$this->boundary = str_replace('"', '', $boundary);
@ -62,14 +65,13 @@ class Google_Http_Batch
/** @var Google_Http_Request $req */
foreach ($this->requests as $key => $req) {
$body .= "--{$this->boundary}\n";
$body .= $req->toBatchString($key) . "\n";
$body .= $req->toBatchString($key) . "\n\n";
$this->expected_classes["response-" . $key] = $req->getExpectedClass();
}
$body = rtrim($body);
$body .= "\n--{$this->boundary}--";
$body .= "--{$this->boundary}--";
$url = $this->base_path . '/batch';
$url = $this->root_url . '/' . $this->batch_path;
$httpRequest = new Google_Http_Request($url, 'POST');
$httpRequest->setRequestHeaders(
array('Content-Type' => 'multipart/mixed; boundary=' . $this->boundary)
@ -125,10 +127,10 @@ class Google_Http_Batch
}
try {
$response = Google_Http_REST::decodeHttpResponse($response);
$response = Google_Http_REST::decodeHttpResponse($response, $this->client);
$responses[$key] = $response;
} catch (Google_Service_Exception $e) {
// Store the exception as the response, so succesful responses
// Store the exception as the response, so successful responses
// can be processed.
$responses[$key] = $e;
}

View File

@ -15,12 +15,13 @@
* limitations under the License.
*/
require_once 'Google/Http/Request.php';
if (!class_exists('Google_Client')) {
require_once dirname(__FILE__) . '/../autoload.php';
}
/**
* Implement the caching directives specified in rfc2616. This
* implementation is guided by the guidance offered in rfc2616-sec13.
* @author Chirag Shah <chirags@google.com>
*/
class Google_Http_CacheParser
{

View File

@ -15,15 +15,13 @@
* limitations under the License.
*/
require_once 'Google/Client.php';
require_once 'Google/Exception.php';
require_once 'Google/Http/Request.php';
require_once 'Google/Http/REST.php';
require_once 'Google/Utils.php';
if (!class_exists('Google_Client')) {
require_once dirname(__FILE__) . '/../autoload.php';
}
/**
* @author Chirag Shah <chirags@google.com>
*
* Manage large file uploads, which may be media but can be any type
* of sizable data.
*/
class Google_Http_MediaFileUpload
{
@ -128,35 +126,16 @@ class Google_Http_MediaFileUpload
}
/**
* Send the next part of the file to upload.
* @param [$chunk] the next set of bytes to send. If false will used $data passed
* at construct time.
*/
public function nextChunk($chunk = false)
* Sends a PUT-Request to google drive and parses the response,
* setting the appropiate variables from the response()
*
* @param Google_Http_Request $httpRequest the Reuqest which will be send
*
* @return false|mixed false when the upload is unfinished or the decoded http response
*
*/
private function makePutRequest(Google_Http_Request $httpRequest)
{
if (false == $this->resumeUri) {
$this->resumeUri = $this->getResumeUri();
}
if (false == $chunk) {
$chunk = substr($this->data, $this->progress, $this->chunkSize);
}
$lastBytePos = $this->progress + strlen($chunk) - 1;
$headers = array(
'content-range' => "bytes $this->progress-$lastBytePos/$this->size",
'content-type' => $this->request->getRequestHeader('content-type'),
'content-length' => $this->chunkSize,
'expect' => '',
);
$httpRequest = new Google_Http_Request(
$this->resumeUri,
'PUT',
$headers,
$chunk
);
if ($this->client->getClassConfig("Google_Http_Request", "enable_gzip_for_uploads")) {
$httpRequest->enableGzip();
} else {
@ -182,13 +161,61 @@ class Google_Http_MediaFileUpload
// No problems, but upload not complete.
return false;
} else {
return Google_Http_REST::decodeHttpResponse($response);
return Google_Http_REST::decodeHttpResponse($response, $this->client);
}
}
/**
* @param $meta
* @param $params
* Send the next part of the file to upload.
* @param [$chunk] the next set of bytes to send. If false will used $data passed
* at construct time.
*/
public function nextChunk($chunk = false)
{
if (false == $this->resumeUri) {
$this->resumeUri = $this->fetchResumeUri();
}
if (false == $chunk) {
$chunk = substr($this->data, $this->progress, $this->chunkSize);
}
$lastBytePos = $this->progress + strlen($chunk) - 1;
$headers = array(
'content-range' => "bytes $this->progress-$lastBytePos/$this->size",
'content-type' => $this->request->getRequestHeader('content-type'),
'content-length' => $this->chunkSize,
'expect' => '',
);
$httpRequest = new Google_Http_Request(
$this->resumeUri,
'PUT',
$headers,
$chunk
);
return $this->makePutRequest($httpRequest);
}
/**
* Resume a previously unfinished upload
* @param $resumeUri the resume-URI of the unfinished, resumable upload.
*/
public function resume($resumeUri)
{
$this->resumeUri = $resumeUri;
$headers = array(
'content-range' => "bytes */$this->size",
'content-length' => 0,
);
$httpRequest = new Google_Http_Request(
$this->resumeUri,
'PUT',
$headers
);
return $this->makePutRequest($httpRequest);
}
/**
* @return array|bool
* @visible for testing
*/
@ -265,7 +292,12 @@ class Google_Http_MediaFileUpload
return self::UPLOAD_MULTIPART_TYPE;
}
private function getResumeUri()
public function getResumeUri()
{
return ( $this->resumeUri !== null ? $this->resumeUri : $this->fetchResumeUri() );
}
private function fetchResumeUri()
{
$result = null;
$body = $this->request->getPostBody();
@ -289,13 +321,21 @@ class Google_Http_MediaFileUpload
}
$message = $code;
$body = @json_decode($response->getResponseBody());
if (!empty( $body->error->errors ) ) {
if (!empty($body->error->errors) ) {
$message .= ': ';
foreach ($body->error->errors as $error) {
$message .= "{$error->domain}, {$error->message};";
}
$message = rtrim($message, ';');
}
throw new Google_Exception("Failed to start the resumable upload (HTTP {$message})");
$error = "Failed to start the resumable upload (HTTP {$message})";
$this->client->getLogger()->error($error);
throw new Google_Exception($error);
}
public function setChunkSize($chunkSize)
{
$this->chunkSize = $chunkSize;
}
}

View File

@ -15,21 +15,18 @@
* limitations under the License.
*/
require_once 'Google/Client.php';
require_once 'Google/Http/Request.php';
require_once 'Google/Service/Exception.php';
require_once 'Google/Utils/URITemplate.php';
if (!class_exists('Google_Client')) {
require_once dirname(__FILE__) . '/../autoload.php';
}
/**
* This class implements the RESTful transport of apiServiceRequest()'s
*
* @author Chris Chabot <chabotc@google.com>
* @author Chirag Shah <chirags@google.com>
*/
class Google_Http_REST
{
/**
* Executes a Google_Http_Request
* Executes a Google_Http_Request and (if applicable) automatically retries
* when errors occur.
*
* @param Google_Client $client
* @param Google_Http_Request $req
@ -38,10 +35,31 @@ class Google_Http_REST
* invalid or malformed post body, invalid url)
*/
public static function execute(Google_Client $client, Google_Http_Request $req)
{
$runner = new Google_Task_Runner(
$client,
sprintf('%s %s', $req->getRequestMethod(), $req->getUrl()),
array(get_class(), 'doExecute'),
array($client, $req)
);
return $runner->run();
}
/**
* Executes a Google_Http_Request
*
* @param Google_Client $client
* @param Google_Http_Request $req
* @return array decoded result
* @throws Google_Service_Exception on server side error (ie: not authenticated,
* invalid or malformed post body, invalid url)
*/
public static function doExecute(Google_Client $client, Google_Http_Request $req)
{
$httpRequest = $client->getIo()->makeRequest($req);
$httpRequest->setExpectedClass($req->getExpectedClass());
return self::decodeHttpResponse($httpRequest);
return self::decodeHttpResponse($httpRequest, $client);
}
/**
@ -49,9 +67,10 @@ class Google_Http_REST
* @static
* @throws Google_Service_Exception
* @param Google_Http_Request $response The http response to be decoded.
* @param Google_Client $client
* @return mixed|null
*/
public static function decodeHttpResponse($response)
public static function decodeHttpResponse($response, Google_Client $client = null)
{
$code = $response->getResponseHttpCode();
$body = $response->getResponseBody();
@ -76,14 +95,34 @@ class Google_Http_REST
$errors = $decoded['error']['errors'];
}
throw new Google_Service_Exception($err, $code, null, $errors);
$map = null;
if ($client) {
$client->getLogger()->error(
$err,
array('code' => $code, 'errors' => $errors)
);
$map = $client->getClassConfig(
'Google_Service_Exception',
'retry_map'
);
}
throw new Google_Service_Exception($err, $code, null, $errors, $map);
}
// Only attempt to decode the response, if the response code wasn't (204) 'no content'
if ($code != '204') {
if ($response->getExpectedRaw()) {
return $body;
}
$decoded = json_decode($body, true);
if ($decoded === null || $decoded === "") {
throw new Google_Service_Exception("Invalid json in service response: $body");
$error = "Invalid json in service response: $body";
if ($client) {
$client->getLogger()->error($error);
}
throw new Google_Service_Exception($error);
}
if ($response->getExpectedClass()) {
@ -117,10 +156,10 @@ class Google_Http_REST
} else if ($paramSpec['location'] == 'query') {
if (isset($paramSpec['repeated']) && is_array($paramSpec['value'])) {
foreach ($paramSpec['value'] as $value) {
$queryVars[] = $paramName . '=' . rawurlencode($value);
$queryVars[] = $paramName . '=' . rawurlencode(rawurldecode($value));
}
} else {
$queryVars[] = $paramName . '=' . rawurlencode($paramSpec['value']);
$queryVars[] = $paramName . '=' . rawurlencode(rawurldecode($paramSpec['value']));
}
}
}

View File

@ -15,7 +15,9 @@
* limitations under the License.
*/
require_once 'Google/Utils.php';
if (!class_exists('Google_Client')) {
require_once dirname(__FILE__) . '/../autoload.php';
}
/**
* HTTP Request to be executed by IO classes. Upon execution, the
@ -49,6 +51,7 @@ class Google_Http_Request
protected $responseBody;
protected $expectedClass;
protected $expectedRaw = false;
public $accessKey;
@ -80,7 +83,7 @@ class Google_Http_Request
*/
public function setBaseComponent($baseComponent)
{
$this->baseComponent = $baseComponent;
$this->baseComponent = rtrim($baseComponent, '/');
}
/**
@ -127,7 +130,7 @@ class Google_Http_Request
return $this->queryParams;
}
/**
/**
* Set a new query parameter.
* @param $key - string to set, does not need to be URL encoded
* @param $value - string to set, does not need to be URL encoded
@ -188,6 +191,31 @@ class Google_Http_Request
return $this->expectedClass;
}
/**
* Enable expected raw response
*/
public function enableExpectedRaw()
{
$this->expectedRaw = true;
}
/**
* Disable expected raw response
*/
public function disableExpectedRaw()
{
$this->expectedRaw = false;
}
/**
* Expected raw response or not.
* @return boolean expected raw response
*/
public function getExpectedRaw()
{
return $this->expectedRaw;
}
/**
* @param array $headers The HTTP response headers
* to be normalized.
@ -413,7 +441,7 @@ class Google_Http_Request
/**
* Our own version of parse_str that allows for multiple variables
* with the same name.
* with the same name.
* @param $string - the query string to parse
*/
private function parseQuery($string)
@ -437,7 +465,7 @@ class Google_Http_Request
/**
* A version of build query that allows for multiple
* duplicate keys.
* duplicate keys.
* @param $parts array of key value pairs
*/
private function buildQuery($parts)
@ -455,7 +483,7 @@ class Google_Http_Request
return implode('&', $return);
}
/**
/**
* If we're POSTing and have no body to send, we can send the query
* parameters in there, which avoids length issues with longer query
* params.

View File

@ -19,10 +19,9 @@
* Abstract IO base class
*/
require_once 'Google/Client.php';
require_once 'Google/IO/Exception.php';
require_once 'Google/Http/CacheParser.php';
require_once 'Google/Http/Request.php';
if (!class_exists('Google_Client')) {
require_once dirname(__FILE__) . '/../autoload.php';
}
abstract class Google_IO_Abstract
{
@ -33,6 +32,17 @@ abstract class Google_IO_Abstract
"HTTP/1.1 200 Connection established\r\n\r\n",
);
private static $ENTITY_HTTP_METHODS = array("POST" => null, "PUT" => null);
private static $HOP_BY_HOP = array(
'connection' => true,
'keep-alive' => true,
'proxy-authenticate' => true,
'proxy-authorization' => true,
'te' => true,
'trailers' => true,
'transfer-encoding' => true,
'upgrade' => true
);
/** @var Google_Client */
protected $client;
@ -47,9 +57,10 @@ abstract class Google_IO_Abstract
}
/**
* Executes a Google_Http_Request and returns the resulting populated Google_Http_Request
* @param Google_Http_Request $request
* @return Google_Http_Request $request
* Executes a Google_Http_Request
* @param Google_Http_Request $request the http request to be executed
* @return array containing response headers, body, and http code
* @throws Google_IO_Exception on curl or IO error
*/
abstract public function executeRequest(Google_Http_Request $request);
@ -58,13 +69,13 @@ abstract class Google_IO_Abstract
* @param $options
*/
abstract public function setOptions($options);
/**
* Set the maximum request time in seconds.
* @param $timeout in seconds
*/
abstract public function setTimeout($timeout);
/**
* Get the maximum request time in seconds.
* @return timeout in seconds
@ -99,12 +110,12 @@ abstract class Google_IO_Abstract
return false;
}
/**
* Execute an HTTP Request
*
* @param Google_HttpRequest $request the http request to be executed
* @return Google_HttpRequest http request with the response http code,
* @param Google_Http_Request $request the http request to be executed
* @return Google_Http_Request http request with the response http code,
* response headers and response body filled in
* @throws Google_IO_Exception on curl or IO error
*/
@ -131,7 +142,7 @@ abstract class Google_IO_Abstract
}
if (!isset($responseHeaders['Date']) && !isset($responseHeaders['date'])) {
$responseHeaders['Date'] = date("r");
$responseHeaders['date'] = date("r");
}
$request->setResponseHttpCode($respHttpCode);
@ -219,28 +230,24 @@ abstract class Google_IO_Abstract
/**
* Update a cached request, using the headers from the last response.
* @param Google_HttpRequest $cached A previously cached response.
* @param Google_Http_Request $cached A previously cached response.
* @param mixed Associative array of response headers from the last request.
*/
protected function updateCachedRequest($cached, $responseHeaders)
{
if (isset($responseHeaders['connection'])) {
$hopByHop = array_merge(
self::$HOP_BY_HOP,
explode(
',',
$responseHeaders['connection']
$hopByHop = self::$HOP_BY_HOP;
if (!empty($responseHeaders['connection'])) {
$connectionHeaders = array_map(
'strtolower',
array_filter(
array_map('trim', explode(',', $responseHeaders['connection']))
)
);
$endToEnd = array();
foreach ($hopByHop as $key) {
if (isset($responseHeaders[$key])) {
$endToEnd[$key] = $responseHeaders[$key];
}
}
$cached->setResponseHeaders($endToEnd);
$hopByHop += array_fill_keys($connectionHeaders, true);
}
$endToEnd = array_diff_key($responseHeaders, $hopByHop);
$cached->setResponseHeaders($endToEnd);
}
/**
@ -323,7 +330,7 @@ abstract class Google_IO_Abstract
// Times will have colons in - so we just want the first match.
$header_parts = explode(': ', $header, 2);
if (count($header_parts) == 2) {
$headers[$header_parts[0]] = $header_parts[1];
$headers[strtolower($header_parts[0])] = $header_parts[1];
}
}

View File

@ -21,7 +21,9 @@
* @author Stuart Langley <slangley@google.com>
*/
require_once 'Google/IO/Abstract.php';
if (!class_exists('Google_Client')) {
require_once dirname(__FILE__) . '/../autoload.php';
}
class Google_IO_Curl extends Google_IO_Abstract
{
@ -29,12 +31,31 @@ class Google_IO_Curl extends Google_IO_Abstract
const NO_QUIRK_VERSION = 0x071E00;
private $options = array();
/** @var bool $disableProxyWorkaround */
private $disableProxyWorkaround;
public function __construct(Google_Client $client)
{
if (!extension_loaded('curl')) {
$error = 'The cURL IO handler requires the cURL extension to be enabled';
$client->getLogger()->critical($error);
throw new Google_IO_Exception($error);
}
parent::__construct($client);
$this->disableProxyWorkaround = $this->client->getClassConfig(
'Google_IO_Curl',
'disable_proxy_workaround'
);
}
/**
* Execute an HTTP Request
*
* @param Google_HttpRequest $request the http request to be executed
* @return Google_HttpRequest http request with the response http code,
* response headers and response body filled in
* @param Google_Http_Request $request the http request to be executed
* @return array containing response headers, body, and http code
* @throws Google_IO_Exception on curl or IO error
*/
public function executeRequest(Google_Http_Request $request)
@ -53,21 +74,30 @@ class Google_IO_Curl extends Google_IO_Abstract
}
curl_setopt($curl, CURLOPT_HTTPHEADER, $curlHeaders);
}
curl_setopt($curl, CURLOPT_URL, $request->getUrl());
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $request->getRequestMethod());
curl_setopt($curl, CURLOPT_USERAGENT, $request->getUserAgent());
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
// The SSL version will be determined by the underlying library
// @see https://github.com/google/google-api-php-client/pull/644
//curl_setopt($curl, CURLOPT_SSLVERSION, 1);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HEADER, true);
if ($request->canGzip()) {
curl_setopt($curl, CURLOPT_ENCODING, 'gzip,deflate');
}
$options = $this->client->getClassConfig('Google_IO_Curl', 'options');
if (is_array($options)) {
$this->setOptions($options);
}
foreach ($this->options as $key => $var) {
curl_setopt($curl, $key, $var);
}
@ -76,16 +106,39 @@ class Google_IO_Curl extends Google_IO_Abstract
curl_setopt($curl, CURLOPT_CAINFO, dirname(__FILE__) . '/cacerts.pem');
}
$this->client->getLogger()->debug(
'cURL request',
array(
'url' => $request->getUrl(),
'method' => $request->getRequestMethod(),
'headers' => $requestHeaders,
'body' => $request->getPostBody()
)
);
$response = curl_exec($curl);
if ($response === false) {
throw new Google_IO_Exception(curl_error($curl));
$error = curl_error($curl);
$code = curl_errno($curl);
$map = $this->client->getClassConfig('Google_IO_Exception', 'retry_map');
$this->client->getLogger()->error('cURL ' . $error);
throw new Google_IO_Exception($error, $code, null, $map);
}
$headerSize = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
list($responseHeaders, $responseBody) = $this->parseHttpResponse($response, $headerSize);
$responseCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
$this->client->getLogger()->debug(
'cURL response',
array(
'code' => $responseCode,
'headers' => $responseHeaders,
'body' => $responseBody,
)
);
return array($responseBody, $responseHeaders, $responseCode);
}
@ -106,7 +159,7 @@ class Google_IO_Curl extends Google_IO_Abstract
{
// Since this timeout is really for putting a bound on the time
// we'll set them both to the same. If you need to specify a longer
// CURLOPT_TIMEOUT, or a tigher CONNECTTIMEOUT, the best thing to
// CURLOPT_TIMEOUT, or a higher CONNECTTIMEOUT, the best thing to
// do is use the setOptions method for the values individually.
$this->options[CURLOPT_CONNECTTIMEOUT] = $timeout;
$this->options[CURLOPT_TIMEOUT] = $timeout;
@ -130,6 +183,10 @@ class Google_IO_Curl extends Google_IO_Abstract
*/
protected function needsQuirk()
{
if ($this->disableProxyWorkaround) {
return false;
}
$ver = curl_version();
$versionNum = $ver['version_number'];
return $versionNum < Google_IO_Curl::NO_QUIRK_VERSION;

View File

@ -15,8 +15,55 @@
* limitations under the License.
*/
require_once 'Google/Exception.php';
class Google_IO_Exception extends Google_Exception
{
if (!class_exists('Google_Client')) {
require_once dirname(__FILE__) . '/../autoload.php';
}
class Google_IO_Exception extends Google_Exception implements Google_Task_Retryable
{
/**
* @var array $retryMap Map of errors with retry counts.
*/
private $retryMap = array();
/**
* Creates a new IO exception with an optional retry map.
*
* @param string $message
* @param int $code
* @param Exception|null $previous
* @param array|null $retryMap Map of errors with retry counts.
*/
public function __construct(
$message,
$code = 0,
Exception $previous = null,
array $retryMap = null
) {
if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
parent::__construct($message, $code, $previous);
} else {
parent::__construct($message, $code);
}
if (is_array($retryMap)) {
$this->retryMap = $retryMap;
}
}
/**
* Gets the number of times the associated task can be retried.
*
* NOTE: -1 is returned if the task can be retried indefinitely
*
* @return integer
*/
public function allowedRetries()
{
if (isset($this->retryMap[$this->code])) {
return $this->retryMap[$this->code];
}
return 0;
}
}

View File

@ -21,7 +21,9 @@
* @author Stuart Langley <slangley@google.com>
*/
require_once 'Google/IO/Abstract.php';
if (!class_exists('Google_Client')) {
require_once dirname(__FILE__) . '/../autoload.php';
}
class Google_IO_Stream extends Google_IO_Abstract
{
@ -40,12 +42,23 @@ class Google_IO_Stream extends Google_IO_Abstract
"verify_peer" => true,
);
public function __construct(Google_Client $client)
{
if (!ini_get('allow_url_fopen')) {
$error = 'The stream IO handler requires the allow_url_fopen runtime ' .
'configuration to be enabled';
$client->getLogger()->critical($error);
throw new Google_IO_Exception($error);
}
parent::__construct($client);
}
/**
* Execute an HTTP Request
*
* @param Google_HttpRequest $request the http request to be executed
* @return Google_HttpRequest http request with the response http code,
* response headers and response body filled in
* @param Google_Http_Request $request the http request to be executed
* @return array containing response headers, body, and http code
* @throws Google_IO_Exception on curl or IO error
*/
public function executeRequest(Google_Http_Request $request)
@ -74,7 +87,7 @@ class Google_IO_Stream extends Google_IO_Abstract
$requestSslContext = array_key_exists('ssl', $default_options) ?
$default_options['ssl'] : array();
if (!array_key_exists("cafile", $requestSslContext)) {
if (!$this->client->isAppEngine() && !array_key_exists("cafile", $requestSslContext)) {
$requestSslContext["cafile"] = dirname(__FILE__) . '/cacerts.pem';
}
@ -97,6 +110,16 @@ class Google_IO_Stream extends Google_IO_Abstract
$url = self::ZLIB . $url;
}
$this->client->getLogger()->debug(
'Stream request',
array(
'url' => $url,
'method' => $request->getRequestMethod(),
'headers' => $requestHeaders,
'body' => $request->getPostBody()
)
);
// We are trapping any thrown errors in this method only and
// throwing an exception.
$this->trappedErrorNumber = null;
@ -109,13 +132,13 @@ class Google_IO_Stream extends Google_IO_Abstract
// END - error trap.
if ($this->trappedErrorNumber) {
throw new Google_IO_Exception(
sprintf(
"HTTP Error: Unable to connect: '%s'",
$this->trappedErrorString
),
$this->trappedErrorNumber
$error = sprintf(
"HTTP Error: Unable to connect: '%s'",
$this->trappedErrorString
);
$this->client->getLogger()->error('Stream ' . $error);
throw new Google_IO_Exception($error, $this->trappedErrorNumber);
}
$response_data = false;
@ -132,17 +155,26 @@ class Google_IO_Stream extends Google_IO_Abstract
}
if (false === $response_data) {
throw new Google_IO_Exception(
sprintf(
"HTTP Error: Unable to connect: '%s'",
$respHttpCode
),
$error = sprintf(
"HTTP Error: Unable to connect: '%s'",
$respHttpCode
);
$this->client->getLogger()->error('Stream ' . $error);
throw new Google_IO_Exception($error, $respHttpCode);
}
$responseHeaders = $this->getHttpResponseHeaders($http_response_header);
$this->client->getLogger()->debug(
'Stream response',
array(
'code' => $respHttpCode,
'headers' => $responseHeaders,
'body' => $response_data,
)
);
return array($response_data, $responseHeaders, $respHttpCode);
}

File diff suppressed because it is too large Load Diff

View File

@ -20,11 +20,14 @@
* from a given json schema.
* http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5
*
* @author Chirag Shah <chirags@google.com>
*
*/
class Google_Model implements ArrayAccess
{
/**
* If you need to specify a NULL JSON value, use Google_Model::NULL_VALUE
* instead - it will be replaced when converting to JSON with a real null.
*/
const NULL_VALUE = "{}gapi-php-null";
protected $internal_gapi_mappings = array();
protected $modelData = array();
protected $processed = array();
@ -33,15 +36,21 @@ class Google_Model implements ArrayAccess
* Polymorphic - accepts a variable number of arguments dependent
* on the type of the model subclass.
*/
public function __construct()
final public function __construct()
{
if (func_num_args() == 1 && is_array(func_get_arg(0))) {
// Initialize the model with the array's contents.
$array = func_get_arg(0);
$this->mapTypes($array);
}
$this->gapiInit();
}
/**
* Getter that handles passthrough access to the data array, and lazy object creation.
* @param string $key Property name.
* @return mixed The value if any, or null.
*/
public function __get($key)
{
$keyTypeName = $this->keyType($key);
@ -87,7 +96,7 @@ class Google_Model implements ArrayAccess
*/
protected function mapTypes($array)
{
// Hard initilise simple types, lazy load more complex ones.
// Hard initialise simple types, lazy load more complex ones.
foreach ($array as $key => $val) {
if ( !property_exists($this, $this->keyType($key)) &&
property_exists($this, $key)) {
@ -102,6 +111,16 @@ class Google_Model implements ArrayAccess
$this->modelData = $array;
}
/**
* Blank initialiser to be used in subclasses to do post-construction initialisation - this
* avoids the need for subclasses to have to implement the variadics handling in their
* constructors.
*/
protected function gapiInit()
{
return;
}
/**
* Create a simplified object suitable for straightforward
* conversion to JSON. This is relatively expensive
@ -116,7 +135,7 @@ class Google_Model implements ArrayAccess
foreach ($this->modelData as $key => $val) {
$result = $this->getSimpleValue($val);
if ($result !== null) {
$object->$key = $result;
$object->$key = $this->nullPlaceholderCheck($result);
}
}
@ -128,7 +147,7 @@ class Google_Model implements ArrayAccess
$result = $this->getSimpleValue($this->$name);
if ($result !== null) {
$name = $this->getMappedName($name);
$object->$name = $result;
$object->$name = $this->nullPlaceholderCheck($result);
}
}
@ -149,13 +168,24 @@ class Google_Model implements ArrayAccess
$a_value = $this->getSimpleValue($a_value);
if ($a_value !== null) {
$key = $this->getMappedName($key);
$return[$key] = $a_value;
$return[$key] = $this->nullPlaceholderCheck($a_value);
}
}
return $return;
}
return $value;
}
/**
* Check whether the value is the null placeholder and return true null.
*/
private function nullPlaceholderCheck($value)
{
if ($value === self::NULL_VALUE) {
return null;
}
return $value;
}
/**
* If there is an internal name mapping, use that.

View File

@ -17,6 +17,8 @@
class Google_Service
{
public $batchPath;
public $rootUrl;
public $version;
public $servicePath;
public $availableScopes;
@ -36,4 +38,19 @@ class Google_Service
{
return $this->client;
}
/**
* Create a new HTTP Batch handler for this service
*
* @return Google_Http_Batch
*/
public function createBatch()
{
return new Google_Http_Batch(
$this->client,
false,
$this->rootUrl,
$this->batchPath
);
}
}

View File

@ -1,8 +1,25 @@
<?php
/*
* Copyright 2014 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
require_once 'Google/Exception.php';
if (!class_exists('Google_Client')) {
require_once dirname(__FILE__) . '/../autoload.php';
}
class Google_Service_Exception extends Google_Exception
class Google_Service_Exception extends Google_Exception implements Google_Task_Retryable
{
/**
* Optional list of errors returned in a JSON body of an HTTP error response.
@ -10,19 +27,27 @@ class Google_Service_Exception extends Google_Exception
protected $errors = array();
/**
* Override default constructor to add ability to set $errors.
* @var array $retryMap Map of errors with retry counts.
*/
private $retryMap = array();
/**
* Override default constructor to add the ability to set $errors and a retry
* map.
*
* @param string $message
* @param int $code
* @param Exception|null $previous
* @param [{string, string}] errors List of errors returned in an HTTP
* response. Defaults to [].
* @param array|null $retryMap Map of errors with retry counts.
*/
public function __construct(
$message,
$code = 0,
Exception $previous = null,
$errors = array()
$errors = array(),
array $retryMap = null
) {
if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
parent::__construct($message, $code, $previous);
@ -31,6 +56,10 @@ class Google_Service_Exception extends Google_Exception
}
$this->errors = $errors;
if (is_array($retryMap)) {
$this->retryMap = $retryMap;
}
}
/**
@ -50,4 +79,27 @@ class Google_Service_Exception extends Google_Exception
{
return $this->errors;
}
/**
* Gets the number of times the associated task can be retried.
*
* NOTE: -1 is returned if the task can be retried indefinitely
*
* @return integer
*/
public function allowedRetries()
{
if (isset($this->retryMap[$this->code])) {
return $this->retryMap[$this->code];
}
$errors = $this->getErrors();
if (!empty($errors) && isset($errors[0]['reason']) &&
isset($this->retryMap[$errors[0]['reason']])) {
return $this->retryMap[$errors[0]['reason']];
}
return 0;
}
}

View File

@ -15,21 +15,15 @@
* limitations under the License.
*/
require_once 'Google/Client.php';
require_once 'Google/Exception.php';
require_once 'Google/Utils.php';
require_once 'Google/Http/Request.php';
require_once 'Google/Http/MediaFileUpload.php';
require_once 'Google/Http/REST.php';
if (!class_exists('Google_Client')) {
require_once dirname(__FILE__) . '/../autoload.php';
}
/**
* Implements the actual methods/resources of the discovered Google API using magic function
* calling overloading (__call()), which on call will see if the method name (plus.activities.list)
* is available in this service, and if so construct an apiHttpRequest representing it.
*
* @author Chris Chabot <chabotc@google.com>
* @author Chirag Shah <chirags@google.com>
*
*/
class Google_Service_Resource
{
@ -39,16 +33,16 @@ class Google_Service_Resource
'fields' => array('type' => 'string', 'location' => 'query'),
'trace' => array('type' => 'string', 'location' => 'query'),
'userIp' => array('type' => 'string', 'location' => 'query'),
'userip' => array('type' => 'string', 'location' => 'query'),
'quotaUser' => array('type' => 'string', 'location' => 'query'),
'data' => array('type' => 'string', 'location' => 'body'),
'mimeType' => array('type' => 'string', 'location' => 'header'),
'uploadType' => array('type' => 'string', 'location' => 'query'),
'mediaUpload' => array('type' => 'complex', 'location' => 'query'),
'prettyPrint' => array('type' => 'string', 'location' => 'query'),
);
/** @var Google_Service $service */
private $service;
/** @var string $rootUrl */
private $rootUrl;
/** @var Google_Client $client */
private $client;
@ -56,6 +50,9 @@ class Google_Service_Resource
/** @var string $serviceName */
private $serviceName;
/** @var string $servicePath */
private $servicePath;
/** @var string $resourceName */
private $resourceName;
@ -64,17 +61,18 @@ class Google_Service_Resource
public function __construct($service, $serviceName, $resourceName, $resource)
{
$this->service = $service;
$this->rootUrl = $service->rootUrl;
$this->client = $service->getClient();
$this->servicePath = $service->servicePath;
$this->serviceName = $serviceName;
$this->resourceName = $resourceName;
$this->methods = isset($resource['methods']) ?
$this->methods = is_array($resource) && isset($resource['methods']) ?
$resource['methods'] :
array($resourceName => $resource);
}
/**
* TODO(ianbarber): This function needs simplifying.
* TODO: This function needs simplifying.
* @param $name
* @param $arguments
* @param $expected_class - optional, the expected class name
@ -84,6 +82,15 @@ class Google_Service_Resource
public function call($name, $arguments, $expected_class = null)
{
if (! isset($this->methods[$name])) {
$this->client->getLogger()->error(
'Service method unknown',
array(
'service' => $this->serviceName,
'resource' => $this->resourceName,
'method' => $name
)
);
throw new Google_Exception(
"Unknown function: " .
"{$this->serviceName}->{$this->resourceName}->{$name}()"
@ -108,10 +115,13 @@ class Google_Service_Resource
$this->convertToArrayAndStripNulls($parameters['postBody']);
}
$postBody = json_encode($parameters['postBody']);
if ($postBody === false && $parameters['postBody'] !== false) {
throw new Google_Exception("JSON encoding failed. Ensure all strings in the request are UTF-8 encoded.");
}
unset($parameters['postBody']);
}
// TODO(ianbarber): optParams here probably should have been
// TODO: optParams here probably should have been
// handled already - this may well be redundant code.
if (isset($parameters['optParams'])) {
$optParams = $parameters['optParams'];
@ -124,11 +134,20 @@ class Google_Service_Resource
}
$method['parameters'] = array_merge(
$method['parameters'],
$this->stackParameters
$this->stackParameters,
$method['parameters']
);
foreach ($parameters as $key => $val) {
if ($key != 'postBody' && ! isset($method['parameters'][$key])) {
$this->client->getLogger()->error(
'Service parameter unknown',
array(
'service' => $this->serviceName,
'resource' => $this->resourceName,
'method' => $name,
'parameter' => $key
)
);
throw new Google_Exception("($name) unknown parameter: '$key'");
}
}
@ -138,6 +157,15 @@ class Google_Service_Resource
$paramSpec['required'] &&
! isset($parameters[$paramName])
) {
$this->client->getLogger()->error(
'Service parameter missing',
array(
'service' => $this->serviceName,
'resource' => $this->resourceName,
'method' => $name,
'parameter' => $paramName
)
);
throw new Google_Exception("($name) missing required param: '$paramName'");
}
if (isset($parameters[$paramName])) {
@ -151,10 +179,18 @@ class Google_Service_Resource
}
}
$servicePath = $this->service->servicePath;
$this->client->getLogger()->info(
'Service Call',
array(
'service' => $this->serviceName,
'resource' => $this->resourceName,
'method' => $name,
'arguments' => $parameters,
)
);
$url = Google_Http_REST::createRequestUri(
$servicePath,
$this->servicePath,
$method['path'],
$parameters
);
@ -164,7 +200,12 @@ class Google_Service_Resource
null,
$postBody
);
$httpRequest->setBaseComponent($this->client->getBasePath());
if ($this->rootUrl) {
$httpRequest->setBaseComponent($this->rootUrl);
} else {
$httpRequest->setBaseComponent($this->client->getBasePath());
}
if ($postBody) {
$contentTypeHeader = array();
@ -187,6 +228,10 @@ class Google_Service_Resource
);
}
if (isset($parameters['alt']) && $parameters['alt']['value'] == 'media') {
$httpRequest->enableExpectedRaw();
}
if ($this->client->shouldDefer()) {
// If we are in batch or upload mode, return the raw request.
return $httpRequest;

View File

@ -15,8 +15,9 @@
* limitations under the License.
*/
require_once 'Google/Auth/Exception.php';
require_once 'Google/Signer/Abstract.php';
if (!class_exists('Google_Client')) {
require_once dirname(__FILE__) . '/../autoload.php';
}
/**
* Signs data.
@ -45,6 +46,8 @@ class Google_Signer_P12 extends Google_Signer_Abstract
// at the time.
if (!$password && strpos($p12, "-----BEGIN RSA PRIVATE KEY-----") !== false) {
$this->privateKey = openssl_pkey_get_private($p12);
} elseif ($password === 'notasecret' && strpos($p12, "-----BEGIN PRIVATE KEY-----") !== false) {
$this->privateKey = openssl_pkey_get_private($p12);
} else {
// This throws on error
$certs = array();

View File

@ -18,8 +18,6 @@
/**
* Collection of static utility methods used for convenience across
* the client library.
*
* @author Chirag Shah <chirags@google.com>
*/
class Google_Utils
{

View File

@ -16,7 +16,7 @@
*/
/**
* Implementation of levels 1-3 of the URI Template spec.
* Implementation of levels 1-3 of the URI Template spec.
* @see http://tools.ietf.org/html/rfc6570
*/
class Google_Utils_URITemplate
@ -26,7 +26,7 @@ class Google_Utils_URITemplate
const TYPE_SCALAR = "4";
/**
* @var $operators array
* @var $operators array
* These are valid at the start of a template block to
* modify the way in which the variables inside are
* processed.
@ -64,7 +64,7 @@ class Google_Utils_URITemplate
/**
* This function finds the first matching {...} block and
* executes the replacement. It then calls itself to find
* subsequent blocks, if any.
* subsequent blocks, if any.
*/
private function resolveNextSection($string, $parameters)
{
@ -213,7 +213,7 @@ class Google_Utils_URITemplate
if (isset($parameters[$key])) {
$data_type = $this->getDataType($parameters[$key]);
switch($data_type) {
switch ($data_type) {
case self::TYPE_SCALAR:
$value = $this->getValue($parameters[$key], $length);
break;

View File

@ -15,8 +15,9 @@
* limitations under the License.
*/
require_once 'Google/Auth/Exception.php';
require_once 'Google/Verifier/Abstract.php';
if (!class_exists('Google_Client')) {
require_once dirname(__FILE__) . '/../autoload.php';
}
/**
* Verifies signatures using PEM encoded certificates.