added google xoauth2 support + fixed a journaling issue

This commit is contained in:
SJ
2012-09-28 10:34:04 +02:00
parent f930aacc84
commit 55de53bb26
111 changed files with 38812 additions and 4 deletions

View File

@ -0,0 +1,39 @@
<?php
/*
* Copyright 2010 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.
*/
/**
* Wrapper for the (experimental!) JSON-RPC protocol, for production use regular REST calls instead
*
* @author Chris Chabot <chabotc@google.com>
*/
class apiBatch {
/**
* Execute one or multiple Google API requests, takes one or multiple requests as param
* Example usage:
* $ret = apiBatch::execute(
* $apiClient->activities->list(array('@public', '@me'), 'listActivitiesKey'),
* $apiClient->people->get(array('userId' => '@me'), 'getPeopleKey')
* );
* print_r($ret['getPeopleKey']);
*/
static public function execute( /* polymorphic */) {
$requests = func_get_args();
return apiRPC::execute($requests);
}
}

View File

@ -0,0 +1,89 @@
<?php
/**
* Copyright 2012 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.
*/
/**
* @author Chirag Shah <chirags@google.com>
*
*/
class apiMediaFileUpload {
public $mimeType;
public $fileName;
public $chunkSize;
public static function process($metadata, $method, &$params) {
$payload = array();
$data = isset($params['data']) ? $params['data']['value'] : false;
$mimeType = isset($params['mimeType']) ? $params['mimeType']['value'] : false;
$file = isset($params['file']) ? $params['file']['value'] : false;
$uploadPath = $method['mediaUpload']['protocols']['simple']['path'];
unset($params['data']);
unset($params['mimeType']);
unset($params['file']);
if ($file) {
if (substr($file, 0, 1) != '@') {
$file = '@' . $file;
}
$payload['file'] = $file;
$payload['content-type'] = 'multipart/form-data';
$payload['restBasePath'] = $uploadPath;
// This is a standard file upload with curl.
return $payload;
}
$parsedMeta = is_string($metadata) ? json_decode($metadata, true) : $metadata;
if ($metadata && false == $data) {
// Process as a normal API request.
return false;
}
// Process as a media upload request.
$params['uploadType'] = array(
'type' => 'string',
'location' => 'query',
'value' => 'media',
);
// Determine which type.
$payload['restBasePath'] = $uploadPath;
if (false == $metadata || false == $parsedMeta) {
// This is a simple media upload.
$payload['content-type'] = $mimeType;
$payload['data'] = $data;
} else {
// This is a multipart/related upload.
$boundary = isset($params['boundary']) ? $params['boundary'] : mt_rand();
$boundary = str_replace('"', '', $boundary);
$payload['content-type'] = 'multipart/related; boundary=' . $boundary;
$related = "--$boundary\r\n";
$related .= "Content-Type: application/json; charset=UTF-8\r\n";
$related .= "\r\n" . $metadata . "\r\n";
$related .= "--$boundary\r\n";
$related .= "Content-Type: $mimeType\r\n";
$related .= "Content-Transfer-Encoding: base64\r\n";
$related .= "\r\n" . base64_encode($data) . "\r\n";
$related .= "--$boundary--";
$payload['data'] = $related;
}
return $payload;
}
}

View File

@ -0,0 +1,115 @@
<?php
/*
* Copyright 2011 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.
*/
/**
* This class defines attributes, valid values, and usage which is generated from
* a given json schema. http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5
*
* @author Chirag Shah <chirags@google.com>
*
*/
class apiModel {
public function __construct( /* polymorphic */ ) {
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);
}
}
/**
* Initialize this object's properties from an array.
*
* @param array Used to seed this object's properties.
* @return void
*/
private function mapTypes($array) {
foreach ($array as $key => $val) {
$this->$key = $val;
$keyTypeName = "__$key" . 'Type';
$keyDataType = "__$key" . 'DataType';
if ($this->useObjects() && property_exists($this, $keyTypeName)) {
if ($this->isAssociativeArray($val)) {
if (isset($this->$keyDataType) && 'map' == $this->$keyDataType) {
foreach($val as $arrayKey => $arrayItem) {
$val[$arrayKey] = $this->createObjectFromName($keyTypeName, $arrayItem);
}
$this->$key = $val;
} else {
$this->$key = $this->createObjectFromName($keyTypeName, $val);
}
} else if (is_array($val)) {
$arrayObject = array();
foreach ($val as $arrayIndex => $arrayItem) {
$arrayObject[$arrayIndex] = $this->createObjectFromName($keyTypeName, $arrayItem);
}
$this->$key = $arrayObject;
}
}
}
}
/**
* Returns true only if the array is associative.
* @param array $array
* @return bool True if the array is associative.
*/
private function isAssociativeArray($array) {
if (!is_array($array)) {
return false;
}
$keys = array_keys($array);
foreach($keys as $key) {
if (is_string($key)) {
return true;
}
}
return false;
}
/**
* Given a variable name, discover its type.
*
* @param $name
* @param $item
* @return object The object from the item.
*/
private function createObjectFromName($name, $item) {
$type = $this->$name;
return new $type($item);
}
protected function useObjects() {
global $apiConfig;
return (isset($apiConfig['use_objects']) && $apiConfig['use_objects']);
}
/**
* Verify if $obj is an array.
* @throws apiException Thrown if $obj isn't an array.
* @param array $obj Items that should be validated.
* @param string $type Array items should be of this type.
* @param string $method Method expecting an array as an argument.
*/
protected function assertIsArray($obj, $type, $method) {
if ($obj && !is_array($obj)) {
throw new apiException("Incorrect parameter type passed to $method(), expected an"
. " array containing items of type $type.");
}
}
}

View File

@ -0,0 +1,64 @@
<?php
/*
* Copyright 2010 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 'service/apiServiceResource.php';
require_once 'service/apiServiceRequest.php';
require_once 'service/apiBatch.php';
/**
* This class parses the service end points of the api discovery document and constructs
* serviceResource variables for all of them.
*
* For instance when calling with the service document for Plus, it will create apiServiceResource's
* for $this->activities, $this->comments, $this->people, etc.
*
* @author Chris Chabot <chabotc@google.com>
*
*/
class apiService {
public $version = null;
public $restBasePath;
public $rpcPath;
public $resource = null;
public function __construct($serviceName, $discoveryDocument) {
global $apiConfig;
if (!isset($discoveryDocument['version']) || !isset($discoveryDocument['restBasePath']) || !isset($discoveryDocument['rpcPath'])) {
throw new apiServiceException("Invalid discovery document");
}
$this->version = $discoveryDocument['version'];
$this->restBasePath = $apiConfig['basePath'] . $discoveryDocument['restBasePath'];
$this->rpcPath = $apiConfig['basePath'] . $discoveryDocument['rpcPath'];
foreach ($discoveryDocument['resources'] as $resourceName => $resourceTypes) {
$this->$resourceName = new apiServiceResource($this, $serviceName, $resourceName, $resourceTypes);
}
}
/**
* @return string $restBasePath
*/
public function getRestBasePath() {
return $this->restBasePath;
}
/**
* @return string $rpcPath
*/
public function getRpcPath() {
return $this->rpcPath;
}
}

View File

@ -0,0 +1,135 @@
<?php
/*
* Copyright 2010 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.
*/
/**
* Internal representation of a Google API request, used by the apiServiceResource class to
* construct API function calls and passing them to the IO layer who knows how to execute
* the request
*
* @author Chris Chabot <chabotc@google.com>
* @author Chirag Shah <chirags@google.com>
*
*/
class apiServiceRequest {
public $restBasePath;
public $restPath;
public $rpcPath;
public $rpcName;
public $httpMethod;
public $parameters;
public $postBody;
public $batchKey;
public $contentType;
/**
* @param string $restBasePath
* @param string $rpcPath
* @param string $restPath
* @param string $rpcName
* @param string $httpMethod
* @param array $parameters
* @param string $postBody
*/
public function __construct($restBasePath, $rpcPath, $restPath, $rpcName, $httpMethod, $parameters, $postBody = null) {
if (substr($restBasePath, 0, 4) == 'http') {
$this->restBasePath = $restBasePath;
} else {
global $apiConfig;
$this->restBasePath = $apiConfig['basePath'] . $restBasePath;
}
$this->restPath = $restPath;
$this->rpcPath = $rpcPath;
$this->rpcName = $rpcName;
$this->httpMethod = $httpMethod;
$this->parameters = $parameters;
$this->postBody = $postBody;
}
/**
* @return string $postBody
*/
public function getPostBody() {
return $this->postBody;
}
/**
* @param string $postBody The post body.
*/
public function setPostBody($postBody) {
$this->postBody = $postBody;
}
/**
* @return string restBasePath
*/
public function getRestBasePath() {
return $this->restBasePath;
}
/**
* @return string restPath
*/
public function getRestPath() {
return $this->restPath;
}
/**
* @return string $rpcPath
*/
public function getRpcPath() {
return $this->rpcPath;
}
/**
* @return string $rpcName
*/
public function getRpcName() {
return $this->rpcName;
}
/**
* @return string $httpMethod
*/
public function getHttpMethod() {
return $this->httpMethod;
}
/**
* @return array $parameters
*/
public function getParameters() {
return $this->parameters;
}
/**
* @return string $batchKey
*/
public function getBatchKey() {
return $this->batchKey;
}
/**
* @param $batchKey the $batchKey to set
*/
public function setBatchKey($batchKey) {
$this->batchKey = $batchKey;
}
public function setContentType($type) {
$this->contentType = $type;
}
}

View File

@ -0,0 +1,207 @@
<?php
/**
* Copyright 2010 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.
*/
/**
* 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 apiServiceRequest representing it.
*
* @author Chris Chabot <chabotc@google.com>
* @author Chirag Shah <chirags@google.com>
*
*/
class apiServiceResource {
// Valid query parameters that work, but don't appear in discovery.
private $stackParameters = array(
'alt' => array('type' => 'string', 'location' => 'query'),
'fields' => array('type' => 'string', 'location' => 'query'),
'trace' => array('type' => 'string', 'location' => 'query'),
'userIp' => array('type' => 'string', 'location' => 'query'),
'userip' => array('type' => 'string', 'location' => 'query'),
'file' => array('type' => 'complex', 'location' => 'body'),
'data' => array('type' => 'string', 'location' => 'body'),
'mimeType' => array('type' => 'string', 'location' => 'header'),
'uploadType' => array('type' => 'string', 'location' => 'query'),
);
/** @var apiService $service */
private $service;
/** @var string $serviceName */
private $serviceName;
/** @var string $resourceName */
private $resourceName;
/** @var array $methods */
private $methods;
public function __construct($service, $serviceName, $resourceName, $resource) {
$this->service = $service;
$this->serviceName = $serviceName;
$this->resourceName = $resourceName;
$this->methods = isset($resource['methods']) ? $resource['methods'] : array($resourceName => $resource);
}
/**
* @param $name
* @param $arguments
* @return apiServiceRequest|array
* @throws apiException
*/
public function __call($name, $arguments) {
if (count($arguments) != 1 && count($arguments) != 2) {
throw new apiException("client method calls expect 1 or 2 parameter (\$client->plus->activities->list(array('userId' => 'me'))");
}
if (! is_array($arguments[0])) {
throw new apiException("client method parameter should be an array (\$client->plus->activities->list(array('userId' => 'me'))");
}
$batchKey = false;
if (isset($arguments[1])) {
if (! is_string($arguments[1])) {
throw new apiException("The batch key parameter should be a string (\$client->plus->activities->list( array('userId' => 'me'), 'batchKey'))");
}
$batchKey = $arguments[1];
}
if (! isset($this->methods[$name])) {
throw new apiException("Unknown function: {$this->serviceName}->{$this->resourceName}->{$name}()");
}
$method = $this->methods[$name];
$parameters = $arguments[0];
// postBody is a special case since it's not defined in the discovery document as parameter, but we abuse the param entry for storing it
$postBody = null;
if (isset($parameters['postBody'])) {
if (is_object($parameters['postBody'])) {
$this->stripNull($parameters['postBody']);
}
// Some APIs require the postBody to be set under the data key.
if (is_array($parameters['postBody']) && 'latitude' == $this->serviceName) {
if (!isset($parameters['postBody']['data'])) {
$rawBody = $parameters['postBody'];
unset($parameters['postBody']);
$parameters['postBody']['data'] = $rawBody;
}
}
$postBody = is_array($parameters['postBody']) || is_object($parameters['postBody'])
? json_encode($parameters['postBody'])
: $parameters['postBody'];
unset($parameters['postBody']);
if (isset($parameters['optParams'])) {
$optParams = $parameters['optParams'];
unset($parameters['optParams']);
$parameters = array_merge($parameters, $optParams);
}
}
if (!isset($method['parameters'])) {
$method['parameters'] = array();
}
$method['parameters'] = array_merge($method['parameters'], $this->stackParameters);
foreach ($parameters as $key => $val) {
if ($key != 'postBody' && ! isset($method['parameters'][$key])) {
throw new apiException("($name) unknown parameter: '$key'");
}
}
if (isset($method['parameters'])) {
foreach ($method['parameters'] as $paramName => $paramSpec) {
if (isset($paramSpec['required']) && $paramSpec['required'] && ! isset($parameters[$paramName])) {
throw new apiException("($name) missing required param: '$paramName'");
}
if (isset($parameters[$paramName])) {
$value = $parameters[$paramName];
$parameters[$paramName] = $paramSpec;
$parameters[$paramName]['value'] = $value;
unset($parameters[$paramName]['required']);
} else {
unset($parameters[$paramName]);
}
}
}
// Discovery v1.0 puts the canonical method id under the 'id' field.
if (! isset($method['id'])) {
$method['id'] = $method['rpcMethod'];
}
// Discovery v1.0 puts the canonical path under the 'path' field.
if (! isset($method['path'])) {
$method['path'] = $method['restPath'];
}
$restBasePath = $this->service->restBasePath;
// Process Media Request
$contentType = false;
if (isset($method['mediaUpload'])) {
$media = apiMediaFileUpload::process($postBody, $method, $parameters);
if (isset($media['content-type'])) {
$contentType = $media['content-type'];
}
if (isset($media['data'])) {
$postBody = $media['data'];
}
if (isset($media['file'])) {
$postBody = array('file' => $media['file']);
}
if (isset($media['restBasePath'])) {
$restBasePath = $media['restBasePath'];
$method['path'] = '';
}
}
$request = new apiServiceRequest(
$restBasePath,
$this->service->rpcPath,
$method['path'],
$method['id'],
$method['httpMethod'],
$parameters, $postBody
);
$request->setContentType($contentType);
if ($batchKey) {
$request->setBatchKey($batchKey);
return $request;
} else {
return apiREST::execute($request);
}
}
protected function useObjects() {
global $apiConfig;
return (isset($apiConfig['use_objects']) && $apiConfig['use_objects']);
}
protected function stripNull(&$o) {
$o = (array) $o;
foreach ($o as $k => $v) {
if ($v === null || strstr($k, "\0*\0__")) {
unset($o[$k]);
}
elseif (is_object($v) || is_array($v)) {
$this->stripNull($o[$k]);
}
}
}
}

View File

@ -0,0 +1,117 @@
<?php
/*
* Copyright 2011 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.
*/
/**
* Collection of static utility methods used for convenience across
* the client library.
*
* @author Chirag Shah <chirags@google.com>
*/
class apiUtils {
public static function urlSafeB64Encode($data) {
$b64 = base64_encode($data);
$b64 = str_replace(array('+', '/', '\r', '\n', '='),
array('-', '_'),
$b64);
return $b64;
}
public static function urlSafeB64Decode($b64) {
$b64 = str_replace(array('-', '_'),
array('+', '/'),
$b64);
return base64_decode($b64);
}
/**
* Misc function used to count the number of bytes in a post body, in the world of multi-byte chars
* and the unpredictability of strlen/mb_strlen/sizeof, this is the only way to do that in a sane
* manner at the moment.
*
* This algorithm was originally developed for the
* Solar Framework by Paul M. Jones
*
* @link http://solarphp.com/
* @link http://svn.solarphp.com/core/trunk/Solar/Json.php
* @link http://framework.zend.com/svn/framework/standard/trunk/library/Zend/Json/Decoder.php
* @param string $str
* @return int The number of bytes in a string.
*/
static public function getStrLen($str) {
$strlenVar = strlen($str);
$d = $ret = 0;
for ($count = 0; $count < $strlenVar; ++ $count) {
$ordinalValue = ord($str{$ret});
switch (true) {
case (($ordinalValue >= 0x20) && ($ordinalValue <= 0x7F)):
// characters U-00000000 - U-0000007F (same as ASCII)
$ret ++;
break;
case (($ordinalValue & 0xE0) == 0xC0):
// characters U-00000080 - U-000007FF, mask 110XXXXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$ret += 2;
break;
case (($ordinalValue & 0xF0) == 0xE0):
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$ret += 3;
break;
case (($ordinalValue & 0xF8) == 0xF0):
// characters U-00010000 - U-001FFFFF, mask 11110XXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$ret += 4;
break;
case (($ordinalValue & 0xFC) == 0xF8):
// characters U-00200000 - U-03FFFFFF, mask 111110XX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$ret += 5;
break;
case (($ordinalValue & 0xFE) == 0xFC):
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$ret += 6;
break;
default:
$ret ++;
}
}
return $ret;
}
/**
* Normalize all keys in an array to lower-case.
* @param array $arr
* @return array Normalized array.
*/
public static function normalize($arr) {
if (!is_array($arr)) {
return array();
}
$normalized = array();
foreach ($arr as $key => $val) {
$normalized[strtolower($key)] = $val;
}
return $normalized;
}
}