3 * Moodle - Modular Object-Oriented Dynamic Learning Environment
5 * Copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 * @author Dan Poltawski <talktodan@gmail.com>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL
25 * Simple implementation of some Google API functions for Moodle.
28 require_once($CFG->libdir.'/filelib.php');
31 * Base class for google authenticated http requests
33 * Most Google API Calls required that requests are sent with an
34 * Authorization header + token. This class extends the curl class
37 abstract class google_auth_request extends curl{
38 protected $token = '';
40 // Must be overriden with the authorization header name
41 public abstract static function get_auth_header_name();
43 protected function request($url, $options = array()){
45 // Adds authorisation head to a request so that it can be authentcated
46 $this->setHeader('Authorization: '. $this->get_auth_header_name().'"'.$this->token.'"');
49 $ret = parent::request($url, $options);
50 // reset headers for next request
51 $this->header = array();
55 public function get_sessiontoken(){
61 * The following two classes are usd to implement AuthSub google
62 * authtentication, as documented here:
63 * http://code.google.com/apis/accounts/docs/AuthSub.html
67 * Used to uprade a google AuthSubRequest one-time token into
68 * a session token which can be used long term.
70 class google_authsub_request extends google_auth_request {
71 const AUTHSESSION_URL = 'https://www.google.com/accounts/AuthSubSessionToken';
74 * Constructor. Calls constructor of its parents
76 * @param string $authtoken The token to upgrade to a session token
78 public function __construct($authtoken){
79 parent::__construct();
80 $this->token = $authtoken;
84 * Requests a long-term session token from google based on the
86 * @return string Sub-Auth token
88 public function get_session_token(){
89 $content = $this->get(google_authsub_request::AUTHSESSION_URL);
91 if( preg_match('/token=(.*)/i', $content, $matches) ){
94 throw new moodle_exception('could not upgrade google authtoken to session token');
98 public static function get_auth_header_name(){
99 return 'AuthSub token=';
104 * Allows http calls using google subauth authorisation
106 class google_authsub extends google_auth_request {
107 const LOGINAUTH_URL = 'https://www.google.com/accounts/AuthSubRequest';
108 const VERIFY_TOKEN_URL = 'https://www.google.com/accounts/AuthSubTokenInfo';
109 const REVOKE_TOKEN_URL = 'https://www.google.com/accounts/AuthSubRevokeToken';
112 * Constructor, allows subauth requests using the response from an initial
113 * AuthSubRequest or with the subauth long-term token. Note that constructing
114 * this object without a valid token will cause an exception to be thrown.
116 * @param string $sessiontoken A long-term subauth session token
117 * @param string $authtoken A one-time auth token wich is used to upgrade to session token
118 * @param mixed @options Options to pass to the base curl object
120 public function __construct($sessiontoken = '', $authtoken = '', $options = array()){
121 parent::__construct($options);
124 $gauth = new google_authsub_request($authtoken);
125 $sessiontoken = $gauth->get_session_token();
128 $this->token = $sessiontoken;
129 if(! $this->valid_token() ){
130 throw new moodle_exception('Invalid subauth token');
135 * Tests if a subauth token used is valid
137 * @return boolean true if token valid
139 public function valid_token(){
140 $this->get(google_authsub::VERIFY_TOKEN_URL);
142 if($this->info['http_code'] === 200){
150 * Calls googles api to revoke the subauth token
152 * @return boolean Returns true if token succesfully revoked
154 public function revoke_session_token(){
155 $this->get(google_authsub::REVOKE_TOKEN_URL);
157 if($this->info['http_code'] === 200){
166 * Creates a login url for subauth request
168 * @param string $returnaddr The address which the user should be redirected to recieve the token
169 * @param string $realm The google realm which is access is being requested
170 * @return string URL to bounce the user to
172 public static function login_url($returnaddr, $realm){
173 $uri = google_authsub::LOGINAUTH_URL.'?next='
174 .urlencode($returnaddr)
177 .'&session=1&secure=0';
182 public static function get_auth_header_name(){
183 return 'AuthSub token=';
188 * Class for manipulating google documents through the google data api
189 * Docs for this can be found here:
190 * http://code.google.com/apis/documents/docs/2.0/developers_guide_protocol.html
193 const REALM = 'http://docs.google.com/feeds/documents';
194 const DOCUMENTFEED_URL = 'http://docs.google.com/feeds/documents/private/full';
195 const USER_PREF_NAME = 'google_authsub_sesskey';
197 private $google_curl = null;
202 * @param object A google_auth_request object which can be used to do http requests
204 public function __construct($google_curl){
205 if(is_a($google_curl, 'google_auth_request')){
206 $this->google_curl = $google_curl;
208 throw new moodle_exception('Google Curl Request object not given');
212 public static function get_sesskey($userid){
213 return get_user_preferences(google_docs::USER_PREF_NAME, false, $userid);
216 public static function set_sesskey($value, $userid){
217 return set_user_preference(google_docs::USER_PREF_NAME, $value, $userid);
220 public static function delete_sesskey($userid){
221 return unset_user_preference(google_docs::USER_PREF_NAME, $userid);
225 * Returns a list of files the user has formated for files api
227 * @param string $search A search string to do full text search on the documents
228 * @return mixed Array of files formated for fileapoi
231 public function get_file_list($search = ''){
232 $url = google_docs::DOCUMENTFEED_URL;
235 $url.='?q='.urlencode($search);
237 $content = $this->google_curl->get($url);
239 $xml = new SimpleXMLElement($content);
242 foreach($xml->entry as $gdoc){
244 $files[] = array( 'title' => "$gdoc->title",
245 'url' => "{$gdoc->content['src']}",
246 'source' => "{$gdoc->content['src']}",
247 'date' => usertime(strtotime($gdoc->updated)),
255 * Sends a file object to google documents
257 * @param object $file File object
258 * @return boolean True on success
260 public function send_file($file){
261 $this->google_curl->setHeader("Content-Length: ". $file->get_filesize());
262 $this->google_curl->setHeader("Content-Type: ". $file->get_mimetype());
263 $this->google_curl->setHeader("Slug: ". $file->get_filename());
265 $this->google_curl->post(google_docs::DOCUMENTFEED_URL, $file->get_content());
267 if($this->google_curl->info['http_code'] === 201){
274 public function download_file($url, $fp){
275 return $this->google_curl->download(array( array('url'=>$url, 'file' => $fp) ));
280 * Class for manipulating picasa through the google data api
281 * Docs for this can be found here:
282 * http://code.google.com/apis/picasaweb/developers_guide_protocol.html
284 class google_picasa {
285 const REALM = 'http://picasaweb.google.com/data/';
286 const USER_PREF_NAME = 'google_authsub_sesskey_picasa';
287 const UPLOAD_LOCATION = 'http://picasaweb.google.com/data/feed/api/user/default/albumid/default';
289 private $google_curl = null;
294 * @param object A google_auth_request object which can be used to do http requests
296 public function __construct($google_curl){
297 if(is_a($google_curl, 'google_auth_request')){
298 $this->google_curl = $google_curl;
300 throw new moodle_exception('Google Curl Request object not given');
304 public static function get_sesskey($userid){
305 return get_user_preferences(google_picasa::USER_PREF_NAME, false, $userid);
308 public static function set_sesskey($value, $userid){
309 return set_user_preference(google_picasa::USER_PREF_NAME, $value, $userid);
312 public static function delete_sesskey($userid){
313 return unset_user_preference(google_picasa::USER_PREF_NAME, $userid);
317 * Sends a file object to picasaweb
319 * @param object $file File object
320 * @return boolean True on success
322 public function send_file($file){
323 $this->google_curl->setHeader("Content-Length: ". $file->get_filesize());
324 $this->google_curl->setHeader("Content-Type: ". $file->get_mimetype());
325 $this->google_curl->setHeader("Slug: ". $file->get_filename());
327 $this->google_curl->post(google_picasa::UPLOAD_LOCATION, $file->get_content());
329 if($this->google_curl->info['http_code'] === 201){
338 * Beginings of an implementation of Clientogin authenticaton for google
339 * accounts as documented here:
340 * http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html#ClientLogin
342 * With this authentication we have to accept a username and password and to post
343 * it to google. Retrieving a token for use afterwards.
345 class google_authclient extends google_auth_request {
346 const LOGIN_URL = 'https://www.google.com/accounts/ClientLogin';
348 public function __construct($sessiontoken = '', $username = '', $password = '', $options = array() ){
349 parent::__construct($options);
351 if($username and $password){
353 'accountType'=>'GOOGLE',
359 $content = $this->post(google_authclient::LOGIN_URL, $param);
361 if( preg_match('/auth=(.*)/i', $content, $matches) ){
362 $sessiontoken = $matches[1];
364 throw new moodle_exception('could not upgrade authtoken');
370 $this->token = $sessiontoken;
372 throw new moodle_exception('no session token specified');
376 public static function get_auth_header_name(){
377 return 'GoogleLogin auth=';