e6026a1a3b6df7b18c8ad6c791b8fed889488af8
[moodle.git] / lib / google / Google_Client.php
1 <?php
2 /*
3  * Copyright 2010 Google Inc.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
18 // Check for the required json and curl extensions, the Google APIs PHP Client
19 // won't function without them.
20 if (! function_exists('curl_init')) {
21   throw new Exception('Google PHP API Client requires the CURL PHP extension');
22 }
24 if (! function_exists('json_decode')) {
25   throw new Exception('Google PHP API Client requires the JSON PHP extension');
26 }
28 if (! function_exists('http_build_query')) {
29   throw new Exception('Google PHP API Client requires http_build_query()');
30 }
32 if (! ini_get('date.timezone') && function_exists('date_default_timezone_set')) {
33   date_default_timezone_set('UTC');
34 }
36 // hack around with the include paths a bit so the library 'just works'
37 set_include_path(dirname(__FILE__) . PATH_SEPARATOR . get_include_path());
39 require_once "config.php";
40 // If a local configuration file is found, merge it's values with the default configuration
41 if (file_exists(dirname(__FILE__)  . '/local_config.php')) {
42   $defaultConfig = $apiConfig;
43   require_once (dirname(__FILE__)  . '/local_config.php');
44   $apiConfig = array_merge($defaultConfig, $apiConfig);
45 }
47 // Include the top level classes, they each include their own dependencies
48 require_once 'service/Google_Model.php';
49 require_once 'service/Google_Service.php';
50 require_once 'service/Google_ServiceResource.php';
51 require_once 'auth/Google_AssertionCredentials.php';
52 require_once 'auth/Google_Signer.php';
53 require_once 'auth/Google_P12Signer.php';
54 require_once 'service/Google_BatchRequest.php';
55 require_once 'external/URITemplateParser.php';
56 require_once 'auth/Google_Auth.php';
57 require_once 'cache/Google_Cache.php';
58 require_once 'io/Google_IO.php';
59 require_once('service/Google_MediaFileUpload.php');
61 /**
62  * The Google API Client
63  * http://code.google.com/p/google-api-php-client/
64  *
65  * @author Chris Chabot <chabotc@google.com>
66  * @author Chirag Shah <chirags@google.com>
67  */
68 class Google_Client {
69   /**
70    * @static
71    * @var Google_Auth $auth
72    */
73   static $auth;
75   /**
76    * @static
77    * @var Google_IO $io
78    */
79   static $io;
81   /**
82    * @static
83    * @var Google_Cache $cache
84    */
85   static $cache;
87   /**
88    * @static
89    * @var boolean $useBatch
90    */
91   static $useBatch = false;
93   /** @var array $scopes */
94   protected $scopes = array();
96   /** @var bool $useObjects */
97   protected $useObjects = false;
99   // definitions of services that are discovered.
100   protected $services = array();
102   // Used to track authenticated state, can't discover services after doing authenticate()
103   private $authenticated = false;
105   public function __construct($config = array()) {
106     global $apiConfig;
107     $apiConfig = array_merge($apiConfig, $config);
108     self::$cache = new $apiConfig['cacheClass']();
109     self::$auth = new $apiConfig['authClass']();
110     self::$io = new $apiConfig['ioClass']();
111   }
113   /**
114    * Add a service
115    */
116   public function addService($service, $version = false) {
117     global $apiConfig;
118     if ($this->authenticated) {
119       throw new Google_Exception('Cant add services after having authenticated');
120     }
121     $this->services[$service] = array();
122     if (isset($apiConfig['services'][$service])) {
123       // Merge the service descriptor with the default values
124       $this->services[$service] = array_merge($this->services[$service], $apiConfig['services'][$service]);
125     }
126   }
128   public function authenticate($code = null) {
129     $service = $this->prepareService();
130     $this->authenticated = true;
131     return self::$auth->authenticate($service, $code);
132   }
134   /**
135    * @return array
136    * @visible For Testing
137    */
138   public function prepareService() {
139     $service = array();
140     $scopes = array();
141     if ($this->scopes) {
142       $scopes = $this->scopes;
143     } else {
144       foreach ($this->services as $key => $val) {
145         if (isset($val['scope'])) {
146           if (is_array($val['scope'])) {
147             $scopes = array_merge($val['scope'], $scopes);
148           } else {
149             $scopes[] = $val['scope'];
150           }
151         } else {
152           $scopes[] = 'https://www.googleapis.com/auth/' . $key;
153         }
154         unset($val['discoveryURI']);
155         unset($val['scope']);
156         $service = array_merge($service, $val);
157       }
158     }
159     $service['scope'] = implode(' ', $scopes);
160     return $service;
161   }
163   /**
164    * Set the OAuth 2.0 access token using the string that resulted from calling authenticate()
165    * or Google_Client#getAccessToken().
166    * @param string $accessToken JSON encoded string containing in the following format:
167    * {"access_token":"TOKEN", "refresh_token":"TOKEN", "token_type":"Bearer",
168    *  "expires_in":3600, "id_token":"TOKEN", "created":1320790426}
169    */
170   public function setAccessToken($accessToken) {
171     if ($accessToken == null || 'null' == $accessToken) {
172       $accessToken = null;
173     }
174     self::$auth->setAccessToken($accessToken);
175   }
177   /**
178    * Set the type of Auth class the client should use.
179    * @param string $authClassName
180    */
181   public function setAuthClass($authClassName) {
182     self::$auth = new $authClassName();
183   }
185   /**
186    * Construct the OAuth 2.0 authorization request URI.
187    * @return string
188    */
189   public function createAuthUrl() {
190     $service = $this->prepareService();
191     return self::$auth->createAuthUrl($service['scope']);
192   }
194   /**
195    * Get the OAuth 2.0 access token.
196    * @return string $accessToken JSON encoded string in the following format:
197    * {"access_token":"TOKEN", "refresh_token":"TOKEN", "token_type":"Bearer",
198    *  "expires_in":3600,"id_token":"TOKEN", "created":1320790426}
199    */
200   public function getAccessToken() {
201     $token = self::$auth->getAccessToken();
202     return (null == $token || 'null' == $token) ? null : $token;
203   }
205   /**
206    * Returns if the access_token is expired.
207    * @return bool Returns True if the access_token is expired.
208    */
209   public function isAccessTokenExpired() {
210     return self::$auth->isAccessTokenExpired();
211   }
213   /**
214    * Set the developer key to use, these are obtained through the API Console.
215    * @see http://code.google.com/apis/console-help/#generatingdevkeys
216    * @param string $developerKey
217    */
218   public function setDeveloperKey($developerKey) {
219     self::$auth->setDeveloperKey($developerKey);
220   }
222   /**
223    * Set OAuth 2.0 "state" parameter to achieve per-request customization.
224    * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-3.1.2.2
225    * @param string $state
226    */
227   public function setState($state) {
228     self::$auth->setState($state);
229   }
231   /**
232    * @param string $accessType Possible values for access_type include:
233    *  {@code "offline"} to request offline access from the user. (This is the default value)
234    *  {@code "online"} to request online access from the user.
235    */
236   public function setAccessType($accessType) {
237     self::$auth->setAccessType($accessType);
238   }
240   /**
241    * @param string $approvalPrompt Possible values for approval_prompt include:
242    *  {@code "force"} to force the approval UI to appear. (This is the default value)
243    *  {@code "auto"} to request auto-approval when possible.
244    */
245   public function setApprovalPrompt($approvalPrompt) {
246     self::$auth->setApprovalPrompt($approvalPrompt);
247   }
249   /**
250    * Set the application name, this is included in the User-Agent HTTP header.
251    * @param string $applicationName
252    */
253   public function setApplicationName($applicationName) {
254     global $apiConfig;
255     $apiConfig['application_name'] = $applicationName;
256   }
258   /**
259    * Set the OAuth 2.0 Client ID.
260    * @param string $clientId
261    */
262   public function setClientId($clientId) {
263     global $apiConfig;
264     $apiConfig['oauth2_client_id'] = $clientId;
265     self::$auth->clientId = $clientId;
266   }
268   /**
269    * Get the OAuth 2.0 Client ID.
270    */
271   public function getClientId() {
272     return self::$auth->clientId;
273   }
274   
275   /**
276    * Set the OAuth 2.0 Client Secret.
277    * @param string $clientSecret
278    */
279   public function setClientSecret($clientSecret) {
280     global $apiConfig;
281     $apiConfig['oauth2_client_secret'] = $clientSecret;
282     self::$auth->clientSecret = $clientSecret;
283   }
285   /**
286    * Get the OAuth 2.0 Client Secret.
287    */
288   public function getClientSecret() {
289     return self::$auth->clientSecret;
290   }
292   /**
293    * Set the OAuth 2.0 Redirect URI.
294    * @param string $redirectUri
295    */
296   public function setRedirectUri($redirectUri) {
297     global $apiConfig;
298     $apiConfig['oauth2_redirect_uri'] = $redirectUri;
299     self::$auth->redirectUri = $redirectUri;
300   }
302   /**
303    * Get the OAuth 2.0 Redirect URI.
304    */
305   public function getRedirectUri() {
306     return self::$auth->redirectUri;
307   }
309   /**
310    * Fetches a fresh OAuth 2.0 access token with the given refresh token.
311    * @param string $refreshToken
312    * @return void
313    */
314   public function refreshToken($refreshToken) {
315     self::$auth->refreshToken($refreshToken);
316   }
318   /**
319    * Revoke an OAuth2 access token or refresh token. This method will revoke the current access
320    * token, if a token isn't provided.
321    * @throws Google_AuthException
322    * @param string|null $token The token (access token or a refresh token) that should be revoked.
323    * @return boolean Returns True if the revocation was successful, otherwise False.
324    */
325   public function revokeToken($token = null) {
326     self::$auth->revokeToken($token);
327   }
329   /**
330    * Verify an id_token. This method will verify the current id_token, if one
331    * isn't provided.
332    * @throws Google_AuthException
333    * @param string|null $token The token (id_token) that should be verified.
334    * @return Google_LoginTicket Returns an apiLoginTicket if the verification was
335    * successful.
336    */
337   public function verifyIdToken($token = null) {
338     return self::$auth->verifyIdToken($token);
339   }
341   /**
342    * @param Google_AssertionCredentials $creds
343    * @return void
344    */
345   public function setAssertionCredentials(Google_AssertionCredentials $creds) {
346     self::$auth->setAssertionCredentials($creds);
347   }
349   /**
350    * This function allows you to overrule the automatically generated scopes,
351    * so that you can ask for more or less permission in the auth flow
352    * Set this before you call authenticate() though!
353    * @param array $scopes, ie: array('https://www.googleapis.com/auth/plus.me', 'https://www.googleapis.com/auth/moderator')
354    */
355   public function setScopes($scopes) {
356     $this->scopes = is_string($scopes) ? explode(" ", $scopes) : $scopes;
357   }
359   /**
360    * Declare if objects should be returned by the api service classes.
361    *
362    * @param boolean $useObjects True if objects should be returned by the service classes.
363    * False if associative arrays should be returned (default behavior).
364    * @experimental
365    */
366   public function setUseObjects($useObjects) {
367     global $apiConfig;
368     $apiConfig['use_objects'] = $useObjects;
369   }
371   /**
372    * Declare if objects should be returned by the api service classes.
373    *
374    * @param boolean $useBatch True if the experimental batch support should
375    * be enabled. Defaults to False.
376    * @experimental
377    */
378   public function setUseBatch($useBatch) {
379     self::$useBatch = $useBatch;
380   }
382   /**
383    * @static
384    * @return Google_Auth the implementation of apiAuth.
385    */
386   public static function getAuth() {
387     return Google_Client::$auth;
388   }
390   /**
391    * @static
392    * @return Google_IO the implementation of apiIo.
393    */
394   public static function getIo() {
395     return Google_Client::$io;
396   }
398   /**
399    * @return Google_Cache the implementation of apiCache.
400    */
401   public function getCache() {
402     return Google_Client::$cache;
403   }
406 // Exceptions that the Google PHP API Library can throw
407 class Google_Exception extends Exception {}
408 class Google_AuthException extends Google_Exception {}
409 class Google_CacheException extends Google_Exception {}
410 class Google_IOException extends Google_Exception {}
411 class Google_ServiceException extends Google_Exception {
412   /**
413    * Optional list of errors returned in a JSON body of an HTTP error response.
414    */
415   protected $errors = array();
417   /**
418    * Override default constructor to add ability to set $errors.
419    *
420    * @param string $message
421    * @param int $code
422    * @param Exception|null $previous
423    * @param [{string, string}] errors List of errors returned in an HTTP
424    * response.  Defaults to [].
425    */
426   public function __construct($message, $code = 0, Exception $previous = null,
427                               $errors = array()) {
428     if(version_compare(PHP_VERSION, '5.3.0') >= 0) {
429       parent::__construct($message, $code, $previous);
430     } else {
431       parent::__construct($message, $code);
432     }
433     
434     $this->errors = $errors;
435   }
437   /**
438    * An example of the possible errors returned.
439    *
440    * {
441    *   "domain": "global",
442    *   "reason": "authError",
443    *   "message": "Invalid Credentials",
444    *   "locationType": "header",
445    *   "location": "Authorization",
446    * }
447    *
448    * @return [{string, string}] List of errors return in an HTTP response or [].
449    */
450   public function getErrors() {
451     return $this->errors;
452   }