264b2c50765f8d05a4f987f4730add1c769dfe0f
[moodle.git] / lib / boxlib.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * Box REST Client Library for PHP5 Developers
19  *
20  *
21  * @package moodlecore
22  * @author James Levy <james@box.net>
23  * @link http://enabled.box.net
24  * @access public
25  * @version 1.0
26  * @copyright copyright Box.net 2007
27  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
28  */
30 /**
31  * @package moodlecore
32  * @copyright copyright Box.net 2007
33  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
34  */
35 class boxclient {
36     /** @var string */
37     public $auth_token = '';
38     /** @var string */
39     private $_box_api_url = 'https://www.box.com/api/1.0/rest';
40     private $_box_api_upload_url = 'http://upload.box.com/api/1.0/upload';
41     private $_box_api_download_url = 'http://www.box.com/api/1.0/download';
42     private $_box_api_auth_url = 'http://www.box.com/api/1.0/auth';
43     private $_error_code = '';
44     private $_error_msg = '';
45     /** @var bool */
46     private $debug = false;
48     /**
49      * @param string $api_key
50      * @param string $auth_token
51      * @param bool $debug
52      */
53     public function __construct($api_key, $auth_token = '', $debug = false) {
54         $this->api_key    = $api_key;
55         $this->auth_token = $auth_token;
56         if (!empty($debug)) {
57             $this->debug = true;
58         } else {
59             $this->debug = false;
60         }
61     }
62     /**
63      * Setup for Functions
64      *
65      * @param string $method
66      * @param array $params
67      * @return array
68      */
69     function makeRequest($method, $params = array()) {
70         $this->_clearErrors();
71         $c = new curl(array('debug'=>$this->debug, 'cache'=>true, 'module_cache'=>'repository'));
72         $c->setopt(array('CURLOPT_FOLLOWLOCATION'=>1));
73         try {
74             if ($method == 'upload'){
75                 $request = $this->_box_api_upload_url.'/'.
76                     $this->auth_token.'/'.$params['folder_id'];
77                 $xml = $c->post($request, $params);
78             }else{
79                 $args = array();
80                 $xml = $c->get($this->_box_api_url, $params);
81             }
82             $xml_parser = xml_parser_create();
83             // set $data here
84             xml_parse_into_struct($xml_parser, $xml, $data);
85             xml_parser_free($xml_parser);
86         } catch (moodle_exception $e) {
87             $this->setError(0, 'connection time-out or invalid url');
88             return false;
89         }
90         return $data;
91     }
92     /**
93      * @param array $params
94      * @return array
95      */
96     function getTicket($params = array()) {
97         $params['api_key'] = $this->api_key;
98         $params['action']  = 'get_ticket';
99         $ret_array = array();
100         $data = $this->makeRequest('action=get_ticket', $params);
101         if ($this->_checkForError($data)) {
102             return false;
103         }
104         foreach ($data as $a) {
105             switch ($a['tag']) {
106             case 'STATUS':
107                 $ret_array['status'] = $a['value'];
108                 break;
109             case 'TICKET':
110                 $ret_array['ticket'] = $a['value'];
111                 break;
112             }
113         }
114         return $ret_array;
115     }
117     /**
118      * $options['username'] and $options['password'] must be
119      * given, we  will use them to obtain a valid auth_token
120      * To get a token, you should use following code:
121      *
122      * <code>
123      * $box = new boxclient('dmls97d8j3i9tn7av8y71m9eb55vrtj4');
124      * Get a ticket
125      * $t = $box->getTicket();
126      * $box->getAuthToken($t['ticket'], array(
127      *              'username'=>'dongsheng@moodle.com',
128      *              'password'=>'xxx'));
129      * </code>
130      *
131      * @param string $ticket
132      * @param string $username
133      * @param string $password
134      * @return mixed
135      */
136     function getAuthToken($ticket, $username, $password) {
137         $c = new curl(array('debug'=>$this->debug));
138         $c->setopt(array('CURLOPT_FOLLOWLOCATION'=>0));
139         $param =  array(
140             'login_form1'=>'',
141             'login'=>$username,
142             'password'=>$password,
143             'dologin'=>1,
144             '__login'=>1
145             );
146         try {
147             $ret = $c->post($this->_box_api_auth_url.$ticket, $param);
148         } catch (moodle_exception $e) {
149             $this->setError(0, 'connection time-out or invalid url');
150             return false;
151         }
152         $header = $c->getResponse();
153         if(empty($header['location'])) {
154             throw new repository_exception('invalidpassword', 'repository_boxnet');
155         }
156         $location = $header['location'];
157         preg_match('#auth_token=(.*)$#i', $location, $matches);
158         $auth_token = $matches[1];
159         if(!empty($auth_token)) {
160             $this->auth_token = $auth_token;
161             return $auth_token;
162         } else {
163             throw new repository_exception('invalidtoken', 'repository_boxnet');
164         }
165     }
166     /**
167      * @param string $path Unused
168      * @param array $params
169      * @return array
170      */
171     function getfiletree($path, $params = array()) {
172         $this->_clearErrors();
173         $params['auth_token'] = $this->auth_token;
174         $params['folder_id']  = 0;
175         $params['api_key']    = $this->api_key;
176         $params['action']     = 'get_account_tree';
177         $params['onelevel']   = 1;
178         $params['params[]']   = 'nozip';
179         $c = new curl(array('debug'=>$this->debug, 'cache'=>true, 'module_cache'=>'repository'));
180         $c->setopt(array('CURLOPT_FOLLOWLOCATION'=>1));
181         try {
182             $args = array();
183             $xml = $c->get($this->_box_api_url, $params);
184         } catch (Exception $e){
185         }
186         $ret = array();
187         $o = simplexml_load_string(trim($xml));
188         if($o->status == 'listing_ok') {
189             $tree = $o->tree->folder;
190             $this->buildtree($tree, $ret);
191         }
192         return $ret;
193     }
195     /**
196      * Get box.net file info
197      *
198      * @param string $fileid
199      * @return string|null
200      */
201     function get_file_info($fileid) {
202         $this->_clearErrors();
203         $params = array();
204         $params['action']     = 'get_file_info';
205         $params['file_id']    = $fileid;
206         $params['auth_token'] = $this->auth_token;
207         $params['api_key']    = $this->api_key;
208         $http = new curl(array('debug'=>$this->debug, 'cache'=>true, 'module_cache'=>'repository'));
209         $xml = $http->get($this->_box_api_url, $params);
210         $o = simplexml_load_string(trim($xml));
211         if ($o->status == 's_get_file_info') {
212             return $o->info;
213         } else {
214             return null;
215         }
216     }
218     /**
219      * @param array $sax
220      * @param array $tree Passed by reference
221      */
222     function buildtree($sax, &$tree){
223         $sax = (array)$sax;
224         $count = 0;
225         foreach($sax as $k=>$v){
226             if($k == 'folders'){
227                 $o = $sax[$k];
228                 foreach($o->folder as $z){
229                     $tmp = array('title'=>(string)$z->attributes()->name,
230                         'size'=>0, 'date'=>userdate(time()),
231                         'thumbnail'=>'https://www.box.com/img/small_folder_icon.gif',
232                         'path'=>array('name'=>(string)$z->attributes()->name, 'path'=>(int)$z->attributes()->id));
233                     $tmp['children'] = array();
234                     $this->buildtree($z, $tmp['children']);
235                     $tree[] = $tmp;
236                 }
237             } elseif ($k == 'files') {
238                 $val = $sax[$k]->file;
239                 foreach($val as $file){
240                     $thumbnail = (string)$file->attributes()->thumbnail;
241                     if (!preg_match('#^(?:http://)?([^/]+)#i', $thumbnail)) {
242                         $thumbnail =  'http://www.box.com'.$thumbnail;
243                     }
244                     $tmp = array('title'=>(string)$file->attributes()->file_name,
245                         'size'=>display_size((int)$file->attributes()->size),
246                         'thumbnail'=>$thumbnail,
247                         'date'=>userdate((int)$file->attributes()->updated),
248                         'source'=> $this->_box_api_download_url
249                             .$this->auth_token.'/'.(string)$file->attributes()->id,
250                         'url'=>(string)$file->attributes()->shared_link);
251                     $tree[] = $tmp;
252                 }
253             }
254             $count++;
255         }
256     }
257     /**
258      * @param array $params
259      * @return bool|array Array or false
260      */
261     function getAccountTree($params = array()) {
262         $params['auth_token'] = $this->auth_token;
263         $params['folder_id']  = 0;
264         $params['api_key']    = $this->api_key;
265         $params['action']     = 'get_account_tree';
266         $params['onelevel']   = 1;
267         $params['params[]']   = 'nozip';
268         $ret_array = array();
269         $data = $this->makeRequest('action=get_account_tree', $params);
270         if ($this->_checkForError($data)) {
271             return false;
272         }
273         $tree_count=count($data);
274         $entry_count = 0;
275         for ($i=0; $i<$tree_count; $i++) {
276             $a = $data[$i];
277             switch ($a['tag'])
278             {
279             case 'FOLDER':
280                 if (@is_array($a['attributes'])) {
281                     $ret_array['folder_id'][$i] = $a['attributes']['ID'];
282                     $ret_array['folder_name'][$i] = $a['attributes']['NAME'];
283                     $ret_array['shared'][$i] = $a['attributes']['SHARED'];
284                 }
285                 break;
287             case 'FILE':
288                 if (@is_array($a['attributes'])) {
289                     $ret_array['file_id'][$i] = $a['attributes']['ID'];
290                     @$ret_array['file_name'][$i] = $a['attributes']['FILE_NAME'];
291                     @$ret_array['file_keyword'][$i] = $a['attributes']['KEYWORD'];
292                     @$ret_array['file_size'][$i] = display_size($a['attributes']['SIZE']);
293                     @$ret_array['file_date'][$i] = userdate($a['attributes']['UPDATED']);
294                     if (preg_match('#^(?:http://)?([^/]+)#i', $a['attributes']['THUMBNAIL'])) {
295                         @$ret_array['thumbnail'][$i] =  $a['attributes']['THUMBNAIL'];
296                     } else {
297                         @$ret_array['thumbnail'][$i] =  'http://www.box.com'.$a['attributes']['THUMBNAIL'];
298                     }
299                     $entry_count++;
300                 }
301                 break;
302             }
303         }
304         return $ret_array;
305     }
307     /**
308      * @param string $new_folder_name
309      * @param array $params
310      * @return bool|array Array or false
311      */
312     function CreateFolder($new_folder_name, $params = array()) {
313         $params['auth_token'] =  $this->auth_token;
314         $params['api_key']    = $this->api_key;
315         $params['action']     = 'create_folder';
316         $params['name']       = $new_folder_name;
317         $defaults = array(
318             'parent_id'  => 0, //Set to '0' by default. Change to create within sub-folder.
319             'share'     => 1, //Set to '1' by default. Set to '0' to make folder private.
320         );
321         foreach ($defaults as $key => $value) {
322             if (!array_key_exists($key, $params)) {
323                 $params[$key] = $value;
324             }
325         }
327         $ret_array = array();
328         $data = $this->makeRequest('action=create_folder', $params);
329         if ($this->_checkForError($data)) {
330             return false;
331         }
332         foreach ($data as $a) {
333             if (!empty($a['value'])) {
334                 switch ($a['tag']) {
336                 case 'FOLDER_ID':
337                     $ret_array['folder_id'] = $a['value'];
338                     break;
340                 case 'FOLDER_NAME':
341                     $ret_array['folder_name'] = $a['value'];
342                     break;
344                 case 'FOLDER_TYPE_ID':
345                     $ret_array['folder_type_id'] = $a['value'];
346                     break;
348                 case 'SHARED':
349                     $ret_array['shared'] = $a['value'];
350                     break;
352                 case 'PASSWORD':
353                     $ret_array['password'] = $a['value'];
354                     break;
355                 }
356             } else {
357                 $ret_array[strtolower($a['tag'])] = null;
358             }
359         }
360         return $ret_array;
361     }
363     /**
364      * Upload a File
365      * @param array $params the file MUST be present in key 'file' and be a moodle stored_file object.
366      * @return array|bool Array or false
367      */
368     function UploadFile ($params = array()) {
369         $params['auth_token'] = $this->auth_token;
370         // this param should be the full path of the file
371         $params['new_file1']  = $params['file'];
372         unset($params['file']);
373         $defaults = array(
374             'folder_id' => 0, //Set to '0' by default. Change to create within sub-folder.
375             'share'     => 1, //Set to '1' by default. Set to '0' to make folder private.
376         );
377         foreach ($defaults as $key => $value) {
378             if (!array_key_exists($key, $params)) {
379                 $params[$key] = $value;
380             }
381         }
382         $ret_array = array();
383         $entry_count = 0;
384         $data = $this->makeRequest('upload', $params);
385         if ($this->_checkForError($data)) {
386             return false;
387         }
388         for ($i=0, $tree_count=count($data); $i<$tree_count; $i++) {
389             $a = $data[$i];
390             switch ($a['tag']) {
391             case 'STATUS':
392                 $ret_array['status'] = $a['value'];
393                 break;
395             case 'FILE':
396                 if (is_array($a['attributes'])) {
397                     @$ret_array['file_name'][$i] = $a['attributes']['FILE_NAME'];
398                     @$ret_array['id'][$i] = $a['attributes']['ID'];
399                     @$ret_array['folder_name'][$i] = $a['attributes']['FOLDER_NAME'];
400                     @$ret_array['error'][$i] = $a['attributes']['ERROR'];
401                     @$ret_array['public_name'][$i] = $a['attributes']['PUBLIC_NAME'];
402                     $entry_count++;
403                 }
404                 break;
405             }
406         }
408         return $ret_array;
409     }
410     /**
411      * @param string $fileid
412      * @param string $newname
413      * @return bool
414      */
415     function RenameFile($fileid, $newname) {
416         $params = array(
417             'api_key'    => $this->api_key,
418             'auth_token' => $this->auth_token,
419             'action'     => 'rename',
420             'target'     => 'file',
421             'target_id'  => $fileid,
422             'new_name'   => $newname,
423         );
424         $data = $this->makeRequest('action=rename', $params);
425         if ($this->_checkForError($data)) {
426             return false;
427         }
428         foreach ($data as $a) {
429             switch ($a['tag']) {
430                 case 'STATUS':
431                     if ($a['value'] == 's_rename_node') {
432                         return true;
433                     }
434             }
435         }
436         return false;
437     }
439     /**
440      * Register New User
441      *
442      * @param array $params
443      * @return array|bool Outcome Array or false
444      */
445     function RegisterUser($params = array()) {
446         $params['api_key'] = $this->api_key;
447         $params['action']  = 'register_new_user';
448         $params['login']   = $_REQUEST['login'];
449         $params['password'] = $_REQUEST['password'];
450         $ret_array = array();
451         $data = $this->makeRequest('action=register_new_user', $params);
452         if ($this->_checkForError($data)) {
453             return false;
454         }
455         foreach ($data as $a) {
456             switch ($a['tag']) {
457             case 'STATUS':
458                 $ret_array['status'] = $a['value'];
459                 break;
461             case 'AUTH_TOKEN':
462                 $ret_array['auth_token'] = $a['value'];
463                 break;
465             case 'LOGIN':
466                 $ret_array['login'] = $a['value'];
467                 break;
468             case 'SPACE_AMOUNT':
469                 $ret_array['space_amount'] = $a['value'];
470                 break;
471             case 'SPACE_USED':
472                 $ret_array['space_used'] = $a['value'];
473                 break;
474             }
475         }
477         return $ret_array;
478     }
480     /**
481      * Add Tags  (http://enabled.box.net/docs/rest#add_to_tag)
482      *
483      * @param string $tag
484      * @param string $id Set to ID of file or folder
485      * @param string $target_type File or folder
486      * @param array $params
487      * @return array|bool Outcome Array or false
488      */
489     function AddTag($tag, $id, $target_type, $params = array()) {
490         $params['auth_token'] = $this->auth_token;
491         $params['api_key']    = $this->api_key;
492         $params['action']     = 'add_to_tag';
493         $params['target']     = $target_type; // File or folder
494         $params['target_id']  = $id; // Set to ID of file or folder
495         $params['tags[]']     = $tag;
496         $ret_array = array();
497         $data = $this->makeRequest('action=add_to_tag', $params);
498         if ($this->_checkForError($data)) {
499             return false;
500         }
501         foreach ($data as $a) {
502             switch ($a['tag']) {
503             case 'STATUS':
504                 $ret_array['status'] = $a['value'];
506                 break;
507             }
508         }
509         return $ret_array;
510     }
512     /**
513      * Public Share  (http://enabled.box.net/docs/rest#public_share)
514      *
515      * @param string $message
516      * @param string $emails
517      * @param string $id Set to ID of file or folder
518      * @param string $target_type File or folder
519      * @param string $password
520      * @param array $params
521      * @return array|bool Outcome Array or false
522      */
523     function PublicShare($message, $emails, $id, $target_type, $password, $params = array()) {
524         $params['auth_token'] = $this->auth_token;
525         $params['api_key']    = $this->api_key;
526         $params['action']     = 'public_share';
527         $params['target']     = $target_type;
528         $params['target_id']  = $id;
529         $params['password']   =  $password;
530         $params['message']    = $message;
531         $params['emails']     = $emails;
532         $ret_array = array();
533         $data = $this->makeRequest('action=public_share', $params);
534         if ($this->_checkForError($data)) {
535             return false;
536         }
537         foreach ($data as $a) {
538             switch ($a['tag']) {
539             case 'STATUS':
540                 $ret_array['status'] = $a['value'];
541                 break;
542             case 'PUBLIC_NAME':
543                 $ret_array['public_name'] = $a['value'];
544                 break;
545             }
546         }
548         return $ret_array;
549     }
550     /**
551      * Get Friends  (http://enabled.box.net/docs/rest#get_friends)
552      *
553      * @param array $params
554      * @return array|bool Outcome Array or false
555      */
556     function GetFriends ($params = array()) {
557         $params['auth_token'] = $this->auth_token;
558         $params['action']     = 'get_friends';
559         $params['api_key']    = $this->api_key;
560         $params['params[]']   = 'nozip';
561         $ret_array = array();
562         $data = $this->makeRequest('action=get_friends', $params);
563         if ($this->_checkForError($data)) {
564             return false;
565         }
566         foreach ($data as $a) {
567             switch ($a['tag']) {
568             case 'NAME':
569                 $ret_array['name'] = $a['value'];
570                 break;
571             case 'EMAIL':
572                 $ret_array['email'] = $a['value'];
573                 break;
574             case 'ACCEPTED':
575                 $ret_array['accepted'] = $a['value'];
576                 break;
577             case 'AVATAR_URL':
578                 $ret_array['avatar_url'] = $a['value'];
579                 break;
580             case 'ID':
581                 $ret_array['id'] = $a['value'];
582                 break;
583             case 'URL':
584                 $ret_array['url'] = $a['value'];
585                 break;
586             case 'STATUS':
587                 $ret_array['status'] = $a['value'];
588                 break;
589             }
590         }
591         return $ret_array;
592     }
594     /**
595      * Logout User  (http://enabled.box.net/docs/rest#get_friends)
596      *
597      * @param array $params
598      * @return array|bool Outcome Array or false
599      */
600     function Logout($params = array()) {
601         $params['auth_token'] = $this->auth_token;
602         $params['api_key']    = $this->api_key;
603         $params['action']     = 'logout';
604         $ret_array = array();
605         $data = $this->makeRequest('action=logout', $params);
606         if ($this->_checkForError($data)) {
607             return false;
608         }
609         foreach ($data as $a) {
610             switch ($a['tag']) {
611             case 'ACTION':
612                 $ret_array['logout'] = $a['value'];
614                 break;
615             }
616             return $ret_array;
617         }
618     }
619     /**
620      * @param array $data
621      * @return bool
622      */
623     function _checkForError($data) {
624         if ($this->_error_msg != '') {
625             return true;
626         }
627         if (@$data[0]['attributes']['STAT'] == 'fail') {
628             $this->_error_code = $data[1]['attributes']['CODE'];
629             $this->_error_msg = $data[1]['attributes']['MSG'];
630             return true;
631         }
632         return false;
633     }
635     /**
636      * @return bool
637      */
638     public function isError() {
639         if  ($this->_error_msg != '') {
640             return true;
641         }
642         return false;
643     }
644     /**
645      *
646      */
647     public function setError($code = 0, $msg){
648         $this->_error_code = $code;
649         $this->_error_msg  = $msg;
650     }
651     /**
652      * @return string
653      */
654     function getErrorMsg() {
655         return '<p>Error: (' . $this->_error_code . ') ' . $this->_error_msg . '</p>';
656     }
657     /**
658      * @return string
659      */
660     function getErrorCode() {
661         return $this->_error_code;
662     }
663     /**
664      *
665      */
666     function _clearErrors() {
667         $this->_error_code = '';
668         $this->_error_msg = '';
669     }