-
Notifications
You must be signed in to change notification settings - Fork 9
/
lib.php
523 lines (466 loc) · 19.8 KB
/
lib.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
<?php
/**
*
* @package mahara
* @subpackage artefact-cloud
* @author Gregor Anzelj
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL
* @copyright (C) 2012-2017 Gregor Anzelj, [email protected]
*
*/
defined('INTERNAL') || die();
require_once(get_config('docroot') . 'artefact/lib.php');
class PluginArtefactCloud extends PluginArtefact {
public static function get_artefact_types() {
return array(
'cloud',
);
}
public static function get_block_types() {
return array();
}
public static function get_plugin_name() {
return 'cloud';
}
public static function menu_items() {
return array(
'content/clouds' => array(
'path' => 'content/clouds',
'title' => get_string('clouds', 'artefact.cloud'),
'url' => 'artefact/cloud/',
// Just one more than Files, so the 'Clouds'
// tab will show just after 'Files' tab
'weight' => 31,
),
);
}
public static function postinst($prevversion) {
if ($prevversion < 2014062600) {
global $SESSION;
// Windows Live SkyDrive became Microsoft One Drive,
// so we need to:
// 1. Update/convert artefact types
if ($artefacts = get_records_array('artefact', 'title', 'skydrive')) {
foreach ($artefacts as $artefact) {
update_record('artefact', array('title' => 'microsoftdrive'), array('id' => $artefact->id));
}
}
// 2. Remove records from blocktype_installed* tables
delete_records('blocktype_installed_category', 'blocktype', 'skydrive');
delete_records('blocktype_installed_viewtype', 'blocktype', 'skydrive');
delete_records('blocktype_config', 'plugin', 'skydrive');
delete_records('blocktype_installed', 'name', 'skydrive');
// 3. Delete 'skydrive' blocktype folder
$folder = get_config('docroot') . 'artefact/cloud/blocktype/skydrive/';
if (file_exists($folder) && is_dir($folder)) {
if (unlink($folder . 'version.php')) {
recursive_skydrive_folder_delete($folder);
} else {
$SESSION->add_error_msg("Could not delete 'skydrive' folder. Delete it manually.");
}
}
}
}
}
/*
* Helper function to recursively delete all files and
* sub-folders in selected folder (with the folder itself)
*
* This is used in 'postinst' function above
*/
function recursive_skydrive_folder_delete($path) {
$files = scandir($path);
foreach ($files as $file) {
if ($file != '.' && $file != '..') {
if (is_dir($path . $file)) {
recursive_folder_delete($path . $file . '/');
} else {
unlink($path . $file);
}
}
}
rmdir($path);
}
class ArtefactTypeCloud extends ArtefactType {
public static function get_icon($options=null) {}
public function __construct($id=0, $data=array()) {
if (empty($id)) {
$data['title'] = get_string($this->get_artefact_type(), 'artefact.cloud'); // ???
}
parent::__construct($id, $data);
}
public static function is_singular() {
return false; // ??? We can have more than one cloud?
}
public static function format_child_data($artefact, $pluginname) {
$a = new StdClass;
$a->id = $artefact->id;
$a->isartefact = true;
$a->title = ''; // ???
$a->text = get_string($artefact->artefacttype, 'artefact.cloud'); // $artefact->title; // ???
$a->container = (bool) $artefact->container;
$a->parent = $artefact->id;
return $a;
}
public static function get_links($id) { }
/**
* Default render method for resume fields - show their description
*/
public function render_self($options) {
return array('html' => clean_html($this->description));
}
public function get_user_services($userid) {
$sql = "SELECT bi.name AS title
FROM {blocktype_installed} bi
WHERE bi.active = 1 AND bi.artefactplugin = 'cloud'";
$services = get_records_sql_array($sql, null);
return $services;
}
public function get_user_preferences($cloud, $userid) {
// Return unserialized field 'description' from table 'artefact'
// where artefacttype=cloud, title=$cloud and owner=$userid
$prefs = get_field('artefact', 'description', 'artefacttype', 'cloud', 'title', $cloud, 'owner', $userid);
if ($prefs) {
$data = unserialize($prefs);
// Add data about when this record was created and modified...
$record = get_record('artefact', 'artefacttype', 'cloud', 'title', $cloud, 'owner', $userid);
$data['record_ctime'] = $record->ctime;
$data['record_mtime'] = $record->mtime;
}
else {
$data = null;
}
return $data;
}
public function set_user_preferences($cloud, $userid, $values) {
$where = array(
'artefacttype' => 'cloud',
'owner' => $userid,
'title' => $cloud,
);
$dbnow = db_format_timestamp(time());
$data = array(
'artefacttype' => 'cloud',
'owner' => $userid,
'title' => $cloud,
'description' => serialize($values),
'author' => $userid,
'ctime' => $dbnow,
'mtime' => $dbnow,
'atime' => $dbnow
);
ensure_record_exists('artefact', $where, $data);
}
}
/*
*
* This class extends the base plugin blocktype class.
*
* It implements additional methods for use with clouds.
* All cloud blocktype classes *should* extend this one.
*
*/
require_once(get_config('docroot') . 'blocktype/lib.php');
abstract class PluginBlocktypeCloud extends PluginBlocktype {
/**
* The cloud blocks use the access token of the user who
* owns the page. This means they don't work with pages
* that don't have an owner (group, institution, site)
*
* @param View $view Allow it on this view?
*/
public static function allowed_in_view(View $view) {
return $view->get('owner') != null;
}
/*
* Method that returns data about cloud,
* needed in 'index.php' (cloud list).
*/
public abstract function service_list();
/*
* Method for requesting request_token
*/
public abstract function request_token();
/*
* Method for requesting access_token
*/
public abstract function access_token($params);
/*
* Method for deleting token(s)
*/
public abstract function delete_token();
/*
* Method for programmatical access revoking
*/
public abstract function revoke_access();
/*
* Method for displaying account info
*/
public abstract function account_info();
/*
* Method for building filelist data for views/pages
*/
public abstract function get_filelist($folder_id, $selected, $ownerid);
/*
* Method for building JSON filelist data for config form
*/
public abstract function get_folder_content($folder_id, $options, $block);
/*
* Method for getting info about folder (on Cloud Service)
*/
public abstract function get_folder_info($folder_id);
/*
* Method for getting info about file (on Cloud Service)
*/
public abstract function get_file_info($file_id);
/*
* Method for downloading file (on Cloud Service)
*/
public abstract function download_file($file_id);
/**
* Saves the specified remote file into a File artefact in the current
* user's file area.
*
* @param string $fileid Remote ID of file to download
* @param int $destfolderid
* @return mixed FALSE on failure, ID of new artefact if successful
*/
public static function download_to_artefact($fileid, $destfolderid) {
$file = static::get_file_info($fileid);
$file['content'] = static::download_file($file['id']);
return static::save_to_artefact($file, $destfolderid);
}
/**
* Saves the specified remote file into a File artefact in the current
* user's file area.
*
* @param string $fileid Remote ID of file to download
* @param int $destfolderid
* @return mixed FALSE on failure, ID of new artefact if successful
*/
protected static function save_to_artefact($file, $destfolderid) {
global $USER, $CFG, $SESSION;
require_once($CFG->docroot . '/lib/uploadmanager.php');
safe_require('artefact', 'file');
// Write file content to local Mahara file repository
$tempdir = get_config('dataroot') . 'artefact/file/temp';
check_dir_exists($tempdir);
$tempfile = tempnam($tempdir, 'cloud.');
file_put_contents($tempfile, $file['content']);
$error = mahara_clam_scan_file($tempfile);
if ($error) {
$SESSION->add_error_msg($error);
@unlink($tempfile);
return false;
}
$data = (object) array(
'parent' => ($destfolderid > 0 ? $destfolderid : null),
'owner' => $USER->get('id'),
'title' => $file['name'],
'author' => $USER->get('id'),
'oldextension' => pathinfo($file['name'], PATHINFO_EXTENSION),
'size' => $file['bytes']
);
$null = null; // HACK to workaround by-reference parameter
try {
$artefactid = ArtefactTypeFile::save_file(
$tempfile,
$data,
$null,
true
);
}
catch (QuotaExceededException $e) {
$SESSION->add_error_msg(get_string('uploadexceedsquota', 'artefact.file'));
@unlink($tempfile);
return false;
}
if (!$artefactid) {
$SESSION->add_error_msg("Error: file not saved.");
@unlink($tempfile);
return false;
}
return $artefactid;
}
/*
* Method for embedding file (on Cloud Service)
*/
public abstract function embed_file($file_id, $options);
}
/**
* Converts bytes into human readable format (use powers of 1024)
* @param integer $bytes
* @param integer $precision when rounding the value
* @return string float value rounded according to precision with correct suffix
* @link http://codeaid.net/php/convert-size-in-bytes-to-a-human-readable-format-%28php%29
*/
function bytes_to_size1024($bytes, $precision=2) {
$unit = array('B','KB','MB','GB','TB','PB','EB');
return @round($bytes / pow(1024, ($i = floor(log($bytes, 1024)))), $precision).''.$unit[$i];
}
/**
* Converts seconds into human readable format (HH:MM:SS),
* even if there are more than 24 hours...
* @param integer $seconds
* @return string time formated as HH:MM:SS
* @link http://bytes.com/topic/php/answers/3917-seconds-converted-hh-mm-ss
*/
function seconds_to_hms($seconds) {
if ($seconds <= 0) return '00:00:00';
$minutes = (int)($seconds / 60);
$seconds = $seconds % 60;
$hours = (int)($minutes / 60);
$minutes = $minutes % 60;
$time = array(
str_pad($hours, 2, "0", STR_PAD_LEFT),
str_pad($minutes, 2, "0", STR_PAD_LEFT),
str_pad($seconds, 2, "0", STR_PAD_LEFT),
);
return implode(':', $time);
}
/**
* Returns folder tree as options for web form select element
* @param integer $parent_id id of the parent folder
* @param integer $level level in the tree (for identation)
*/
function get_foldertree_options($parent_id=null, $level='/') {
global $options;
$current = $level . get_string('home', 'artefact.file');
$options = array('0' => $current);
get_foldertree_recursion($parent_id, $current);
return $options;
}
// Helper function, used in above get_foldertree_options function...
function get_foldertree_recursion($parent_id=null, $level='/') {
global $USER, $options;
if (is_null($parent_id)) {
$folders = get_records_sql_array('
SELECT a.id, a.title, a.parent
FROM {artefact} a
WHERE a.artefacttype = ? AND a.owner = ? AND a.parent IS NULL
ORDER BY a.title', array('folder', $USER->get('id')));
} else {
$folders = get_records_sql_array('
SELECT a.id, a.title, a.parent
FROM {artefact} a
WHERE a.artefacttype = ? AND a.owner = ? AND a.parent = ?
ORDER BY a.title', array('folder', $USER->get('id'), $parent_id));
}
if ($folders) {
foreach ($folders as $folder) {
$current = $level . '/' . $folder->title;
$options[$folder->id] = $current;
// Recursion...
get_foldertree_recursion($folder->id, $current);
}
}
}
// Function to find nearest value (in array of values) to given value
// e.g.: user defined thumbnail width is 75, abvaliable picasa thumbnails are array(32, 48, 64, 72, 104, 144, 150, 160)
// so this function should return 72 (which is nearest form available values)
// Function found at http://www.sitepoint.com/forums/showthread.php?t=537541
function find_nearest($values, $item) {
if (in_array($item,$values)) {
$out = $item;
}
else {
sort($values);
$length = count($values);
for ($i=0; $i<$length; $i++) {
if ($values[$i] > $item) {
if ($i == 0) {
return $values[$i];
}
$out = ($item - $values[$i-1]) > ($values[$i]-$item) ? $values[$i] : $values[$i-1];
break;
}
}
}
if (!isset($out)) {
$out = end($values);
}
return $out;
}
// Function to print out HTTP response status code and description
function get_http_status($code) {
switch (intval($code)) {
case 100: $msg = 'HTTP status: 100 Continue'; break;
case 101: $msg = 'HTTP status: 101 Switching Protocols'; break;
case 102: $msg = 'HTTP status: 102 Processing'; break;
case 200: $msg = 'HTTP status: 200 OK'; break;
case 201: $msg = 'HTTP status: 201 Created'; break;
case 202: $msg = 'HTTP status: 202 Accepted'; break;
case 203: $msg = 'HTTP status: 203 Non-Authoritative Information'; break;
case 204: $msg = 'HTTP status: 204 No Content'; break;
case 205: $msg = 'HTTP status: 205 Reset Content'; break;
case 206: $msg = 'HTTP status: 206 Partial Content'; break;
case 207: $msg = 'HTTP status: 207 Multi-Status'; break;
case 208: $msg = 'HTTP status: 208 Already Reported'; break;
case 226: $msg = 'HTTP status: 226 IM Used'; break;
case 300: $msg = 'HTTP status: 300 Multiple Choices'; break;
case 301: $msg = 'HTTP status: 301 Moved Permanently'; break;
case 302: $msg = 'HTTP status: 302 Found'; break;
case 303: $msg = 'HTTP status: 303 See Other'; break;
case 304: $msg = 'HTTP status: 304 Not Modified'; break;
case 305: $msg = 'HTTP status: 305 Use Proxy'; break;
case 306: $msg = 'HTTP status: 306 Switch Proxy'; break;
case 307: $msg = 'HTTP status: 307 Temporary Redirect'; break;
case 308: $msg = 'HTTP status: 308 Permanent Redirect; Resume Incomplete (Google)'; break;
case 400: $msg = 'HTTP status: 400 Bad Request'; break;
case 401: $msg = 'HTTP status: 401 Unauthorized'; break;
case 402: $msg = 'HTTP status: 402 Payment Required'; break;
case 403: $msg = 'HTTP status: 403 Forbidden'; break;
case 404: $msg = 'HTTP status: 404 Not Found'; break;
case 405: $msg = 'HTTP status: 405 Method Not Allowed'; break;
case 406: $msg = 'HTTP status: 406 Not Acceptable'; break;
case 407: $msg = 'HTTP status: 407 Proxy Authentication Required'; break;
case 408: $msg = 'HTTP status: 408 Request Timeout'; break;
case 409: $msg = 'HTTP status: 409 Conflict'; break;
case 410: $msg = 'HTTP status: 410 Gone'; break;
case 411: $msg = 'HTTP status: 411 Length Required'; break;
case 412: $msg = 'HTTP status: 412 Precondition Failed'; break;
case 413: $msg = 'HTTP status: 413 Payload Too Large'; break;
case 414: $msg = 'HTTP status: 414 Request-URI Too Long'; break;
case 415: $msg = 'HTTP status: 415 Unsupported Media Type'; break;
case 416: $msg = 'HTTP status: 416 Requested Range Not Satisfiable'; break;
case 417: $msg = 'HTTP status: 417 Expectation Failed'; break;
case 419: $msg = 'HTTP status: 419 Authentication Timeout'; break;
case 421: $msg = 'HTTP status: 421 Misdirected Request'; break;
case 422: $msg = 'HTTP status: 422 Unprocessable Entity'; break;
case 423: $msg = 'HTTP status: 423 Locked'; break;
case 424: $msg = 'HTTP status: 424 Failed Dependency'; break;
case 426: $msg = 'HTTP status: 426 Upgrade Required'; break;
case 428: $msg = 'HTTP status: 428 Precondition Required'; break;
case 429: $msg = 'HTTP status: 429 Too Many Requests'; break;
case 431: $msg = 'HTTP status: 431 Request Header Fields Too Large'; break;
case 440: $msg = 'HTTP status: 440 Login Timeout'; break;
case 444: $msg = 'HTTP status: 444 No Response'; break;
case 449: $msg = 'HTTP status: 449 Retry With'; break;
case 450: $msg = 'HTTP status: 450 Blocked by Windows Parental Controls'; break;
case 451: $msg = 'HTTP status: 451 Unavailable For Legal Reasons; Redirect (Microsoft)'; break;
case 494: $msg = 'HTTP status: 494 Request Header Too Large'; break;
case 495: $msg = 'HTTP status: 495 Cert Error'; break;
case 496: $msg = 'HTTP status: 496 No Cert'; break;
case 497: $msg = 'HTTP status: 497 HTTP to HTTPS'; break;
case 498: $msg = 'HTTP status: 498 Token expired/invalid'; break;
case 499: $msg = 'HTTP status: 499 Client Closed Request (Nginx); Token required (Esri)'; break;
case 500: $msg = 'HTTP status: 500 Internal Server Error'; break;
case 501: $msg = 'HTTP status: 501 Not Implemented'; break;
case 502: $msg = 'HTTP status: 502 Bad Gateway'; break;
case 503: $msg = 'HTTP status: 503 Service Unavailable'; break;
case 504: $msg = 'HTTP status: 504 Gateway Timeout'; break;
case 505: $msg = 'HTTP status: 505 HTTP Version Not Supported'; break;
case 506: $msg = 'HTTP status: 506 Variant Also Negotiates'; break;
case 507: $msg = 'HTTP status: 507 Insufficient Storage'; break;
case 508: $msg = 'HTTP status: 508 Loop Detected'; break;
case 509: $msg = 'HTTP status: 509 Bandwidth Limit Exceeded'; break;
case 510: $msg = 'HTTP status: 510 Not Extended'; break;
case 511: $msg = 'HTTP status: 511 Network Authentication Required'; break;
case 520: $msg = 'HTTP status: 520 Unknown Error'; break;
case 522: $msg = 'HTTP status: 522 Origin Connection Time-out'; break;
case 598: $msg = 'HTTP status: 598 Network read timeout error'; break;
case 599: $msg = 'HTTP status: 599 Network connect timeout error'; break;
default: $msg = 'HTTP status: Unknown status with code ' . $code;
}
return $msg;
}