moodlelib.php 376 KB
Newer Older
1
<?php
skodak's avatar
skodak committed
2
3
// This file is part of Moodle - http://moodle.org/
//
4
5
6
7
8
9
10
11
12
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
skodak's avatar
skodak committed
13
//
14
15
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16

17
/**
dhawes's avatar
dhawes committed
18
 * moodlelib.php - Moodle main library
19
20
21
 *
 * Main library file of miscellaneous general-purpose Moodle functions.
 * Other main libraries:
dhawes's avatar
dhawes committed
22
23
 *  - weblib.php      - functions that produce web output
 *  - datalib.php     - functions that access the database
24
 *
25
26
27
28
 * @package    core
 * @subpackage lib
 * @copyright  1999 onwards Martin Dougiamas  http://dougiamas.com
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
29
 */
julmis's avatar
julmis committed
30

31
32
defined('MOODLE_INTERNAL') || die();

33
// CONSTANTS (Encased in phpdoc proper comments).
moodler's avatar
   
moodler committed
34

35
// Date and time constants.
36
37
38
39
40
/**
 * Time constant - the number of seconds in a year
 */
define('YEARSECS', 31536000);

41
/**
42
 * Time constant - the number of seconds in a week
43
 */
44
define('WEEKSECS', 604800);
45
46
47
48

/**
 * Time constant - the number of seconds in a day
 */
49
define('DAYSECS', 86400);
50
51
52
53

/**
 * Time constant - the number of seconds in an hour
 */
54
define('HOURSECS', 3600);
55
56
57
58

/**
 * Time constant - the number of seconds in a minute
 */
59
define('MINSECS', 60);
60
61
62
63

/**
 * Time constant - the number of minutes in a day
 */
64
define('DAYMINS', 1440);
65
66
67
68

/**
 * Time constant - the number of minutes in an hour
 */
69
define('HOURMINS', 60);
martin's avatar
martin committed
70

71
72
// Parameter constants - every call to optional_param(), required_param()
// or clean_param() should have a specified type of parameter.
73

74
/**
75
 * PARAM_ALPHA - contains only English ascii letters [a-zA-Z].
76
 */
77
define('PARAM_ALPHA',    'alpha');
dhawes's avatar
dhawes committed
78
79

/**
80
 * PARAM_ALPHAEXT the same contents as PARAM_ALPHA (English ascii letters [a-zA-Z]) plus the chars in quotes: "_-" allowed
81
 * NOTE: originally this allowed "/" too, please use PARAM_SAFEPATH if "/" needed
dhawes's avatar
dhawes committed
82
 */
83
define('PARAM_ALPHAEXT', 'alphaext');
dhawes's avatar
dhawes committed
84
85

/**
86
 * PARAM_ALPHANUM - expected numbers 0-9 and English ascii letters [a-zA-Z] only.
dhawes's avatar
dhawes committed
87
 */
88
define('PARAM_ALPHANUM', 'alphanum');
dhawes's avatar
dhawes committed
89
90

/**
91
 * PARAM_ALPHANUMEXT - expected numbers 0-9, letters (English ascii letters [a-zA-Z]) and _- only.
dhawes's avatar
dhawes committed
92
 */
93
define('PARAM_ALPHANUMEXT', 'alphanumext');
dhawes's avatar
dhawes committed
94

95
/**
96
 * PARAM_AUTH - actually checks to make sure the string is a valid auth plugin
97
 */
98
define('PARAM_AUTH',  'auth');
99
100

/**
101
 * PARAM_BASE64 - Base 64 encoded format
102
 */
103
define('PARAM_BASE64',   'base64');
104

dhawes's avatar
dhawes committed
105
/**
106
 * PARAM_BOOL - converts input into 0 or 1, use for switches in forms and urls.
dhawes's avatar
dhawes committed
107
 */
108
define('PARAM_BOOL',     'bool');
dhawes's avatar
dhawes committed
109
110

/**
111
 * PARAM_CAPABILITY - A capability name, like 'moodle/role:manage'. Actually
Petr Skoda's avatar
Petr Skoda committed
112
 * checked against the list of capabilities in the database.
113
 */
114
define('PARAM_CAPABILITY',   'capability');
115
116

/**
117
 * PARAM_CLEANHTML - cleans submitted HTML code. Note that you almost never want
118
119
 * to use this. The normal mode of operation is to use PARAM_RAW when receiving
 * the input (required/optional_param or formslib) and then sanitise the HTML
120
121
 * using format_text on output. This is for the rare cases when you want to
 * sanitise the HTML on input. This cleaning may also fix xhtml strictness.
dhawes's avatar
dhawes committed
122
 */
123
define('PARAM_CLEANHTML', 'cleanhtml');
dhawes's avatar
dhawes committed
124

125
126
127
128
129
/**
 * PARAM_EMAIL - an email address following the RFC
 */
define('PARAM_EMAIL',   'email');

dhawes's avatar
dhawes committed
130
/**
131
 * PARAM_FILE - safe file name, all dangerous chars are stripped, protects against XSS, SQL injections and directory traversals
dhawes's avatar
dhawes committed
132
 */
133
define('PARAM_FILE',   'file');
134
135

/**
136
 * PARAM_FLOAT - a real/floating point number.
137
138
139
 *
 * Note that you should not use PARAM_FLOAT for numbers typed in by the user.
 * It does not work for languages that use , as a decimal separator.
140
 * Use PARAM_LOCALISEDFLOAT instead.
141
 */
142
define('PARAM_FLOAT',  'float');
143

144
145
146
147
148
149
150
/**
 * PARAM_LOCALISEDFLOAT - a localised real/floating point number.
 * This is preferred over PARAM_FLOAT for numbers typed in by the user.
 * Cleans localised numbers to computer readable numbers; false for invalid numbers.
 */
define('PARAM_LOCALISEDFLOAT',  'localisedfloat');

151
/**
152
153
154
155
156
157
 * PARAM_HOST - expected fully qualified domain name (FQDN) or an IPv4 dotted quad (IP address)
 */
define('PARAM_HOST',     'host');

/**
 * PARAM_INT - integers only, use when expecting only numbers.
158
 */
159
160
161
162
163
164
165
166
define('PARAM_INT',      'int');

/**
 * PARAM_LANG - checks to see if the string is a valid installed language in the current site.
 */
define('PARAM_LANG',  'lang');

/**
167
168
 * PARAM_LOCALURL - expected properly formatted URL as well as one that refers to the local server itself. (NOT orthogonal to the
 * others! Implies PARAM_URL!)
169
170
 */
define('PARAM_LOCALURL', 'localurl');
dhawes's avatar
dhawes committed
171
172

/**
173
 * PARAM_NOTAGS - all html tags are stripped from the text. Do not abuse this type.
dhawes's avatar
dhawes committed
174
 */
175
define('PARAM_NOTAGS',   'notags');
dhawes's avatar
dhawes committed
176

177
/**
178
179
 * PARAM_PATH - safe relative path name, all dangerous chars are stripped, protects against XSS, SQL injections and directory
 * traversals note: the leading slash is not removed, window drive letter is not allowed
skodak's avatar
skodak committed
180
 */
181
define('PARAM_PATH',     'path');
skodak's avatar
skodak committed
182

183
/**
184
 * PARAM_PEM - Privacy Enhanced Mail format
185
 */
186
define('PARAM_PEM',      'pem');
187

dhawes's avatar
dhawes committed
188
/**
189
 * PARAM_PERMISSION - A permission, one of CAP_INHERIT, CAP_ALLOW, CAP_PREVENT or CAP_PROHIBIT.
dhawes's avatar
dhawes committed
190
 */
191
define('PARAM_PERMISSION',   'permission');
dhawes's avatar
dhawes committed
192

193
/**
194
 * PARAM_RAW specifies a parameter that is not cleaned/processed in any way except the discarding of the invalid utf-8 characters
195
 */
196
define('PARAM_RAW', 'raw');
197

198
199
200
201
202
/**
 * PARAM_RAW_TRIMMED like PARAM_RAW but leading and trailing whitespace is stripped.
 */
define('PARAM_RAW_TRIMMED', 'raw_trimmed');

203
/**
204
 * PARAM_SAFEDIR - safe directory name, suitable for include() and require()
205
 */
206
define('PARAM_SAFEDIR',  'safedir');
207

208
/**
209
 * PARAM_SAFEPATH - several PARAM_SAFEDIR joined by "/", suitable for include() and require(), plugin paths, etc.
210
 */
211
define('PARAM_SAFEPATH',  'safepath');
212

dhawes's avatar
dhawes committed
213
/**
214
 * PARAM_SEQUENCE - expects a sequence of numbers like 8 to 1,5,6,4,6,8,9.  Numbers and comma only.
dhawes's avatar
dhawes committed
215
 */
216
define('PARAM_SEQUENCE',  'sequence');
dhawes's avatar
dhawes committed
217
218

/**
219
 * PARAM_TAG - one tag (interests, blogs, etc.) - mostly international characters and space, <> not supported
dhawes's avatar
dhawes committed
220
 */
221
define('PARAM_TAG',   'tag');
dhawes's avatar
dhawes committed
222
223

/**
224
 * PARAM_TAGLIST - list of tags separated by commas (interests, blogs, etc.)
dhawes's avatar
dhawes committed
225
 */
226
define('PARAM_TAGLIST',   'taglist');
dhawes's avatar
dhawes committed
227
228

/**
229
 * PARAM_TEXT - general plain text compatible with multilang filter, no other html tags. Please note '<', or '>' are allowed here.
dhawes's avatar
dhawes committed
230
 */
231
define('PARAM_TEXT',  'text');
dhawes's avatar
dhawes committed
232
233

/**
234
 * PARAM_THEME - Checks to see if the string is a valid theme name in the current site
dhawes's avatar
dhawes committed
235
 */
236
define('PARAM_THEME',  'theme');
dhawes's avatar
dhawes committed
237
238

/**
239
240
 * PARAM_URL - expected properly formatted URL. Please note that domain part is required, http://localhost/ is not accepted but
 * http://localhost.localdomain/ is ok.
dhawes's avatar
dhawes committed
241
 */
242
243
define('PARAM_URL',      'url');

244
/**
245
246
 * PARAM_USERNAME - Clean username to only contains allowed characters. This is to be used ONLY when manually creating user
 * accounts, do NOT use when syncing with external systems!!
247
248
 */
define('PARAM_USERNAME',    'username');
dhawes's avatar
dhawes committed
249

250
251
252
253
/**
 * PARAM_STRINGID - used to check if the given string is valid string identifier for get_string()
 */
define('PARAM_STRINGID',    'stringid');
254

255
// DEPRECATED PARAM TYPES OR ALIASES - DO NOT USE FOR NEW CODE.
dhawes's avatar
dhawes committed
256
/**
257
258
 * PARAM_CLEAN - obsoleted, please use a more specific type of parameter.
 * It was one of the first types, that is why it is abused so much ;-)
259
 * @deprecated since 2.0
dhawes's avatar
dhawes committed
260
 */
261
define('PARAM_CLEAN',    'clean');
dhawes's avatar
dhawes committed
262
263

/**
264
 * PARAM_INTEGER - deprecated alias for PARAM_INT
265
 * @deprecated since 2.0
dhawes's avatar
dhawes committed
266
 */
267
define('PARAM_INTEGER',  'int');
dhawes's avatar
dhawes committed
268

269
/**
270
 * PARAM_NUMBER - deprecated alias of PARAM_FLOAT
271
 * @deprecated since 2.0
272
 */
273
define('PARAM_NUMBER',  'float');
274

275
/**
Petr Skoda's avatar
Petr Skoda committed
276
 * PARAM_ACTION - deprecated alias for PARAM_ALPHANUMEXT, use for various actions in forms and urls
277
 * NOTE: originally alias for PARAM_APLHA
278
 * @deprecated since 2.0
279
 */
280
define('PARAM_ACTION',   'alphanumext');
281
282

/**
283
284
 * PARAM_FORMAT - deprecated alias for PARAM_ALPHANUMEXT, use for names of plugins, formats, etc.
 * NOTE: originally alias for PARAM_APLHA
285
 * @deprecated since 2.0
286
 */
287
define('PARAM_FORMAT',   'alphanumext');
288

289
/**
290
 * PARAM_MULTILANG - deprecated alias of PARAM_TEXT.
291
 * @deprecated since 2.0
292
 */
293
define('PARAM_MULTILANG',  'text');
294

295
296
/**
 * PARAM_TIMEZONE - expected timezone. Timezone can be int +-(0-13) or float +-(0.5-12.5) or
297
 * string separated by '/' and can have '-' &/ '_' (eg. America/North_Dakota/New_Salem
298
299
300
301
 * America/Port-au-Prince)
 */
define('PARAM_TIMEZONE', 'timezone');

302
/**
303
 * PARAM_CLEANFILE - deprecated alias of PARAM_FILE; originally was removing regional chars too
304
 */
305
306
define('PARAM_CLEANFILE', 'file');

307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
/**
 * PARAM_COMPONENT is used for full component names (aka frankenstyle) such as 'mod_forum', 'core_rating', 'auth_ldap'.
 * Short legacy subsystem names and module names are accepted too ex: 'forum', 'rating', 'user'.
 * Only lowercase ascii letters, numbers and underscores are allowed, it has to start with a letter.
 * NOTE: numbers and underscores are strongly discouraged in plugin names!
 */
define('PARAM_COMPONENT', 'component');

/**
 * PARAM_AREA is a name of area used when addressing files, comments, ratings, etc.
 * It is usually used together with context id and component.
 * Only lowercase ascii letters, numbers and underscores are allowed, it has to start with a letter.
 */
define('PARAM_AREA', 'area');

/**
323
 * PARAM_PLUGIN is used for plugin names such as 'forum', 'glossary', 'ldap', 'paypal', 'completionstatus'.
324
325
326
327
328
329
 * Only lowercase ascii letters, numbers and underscores are allowed, it has to start with a letter.
 * NOTE: numbers and underscores are strongly discouraged in plugin names! Underscores are forbidden in module names.
 */
define('PARAM_PLUGIN', 'plugin');


330
// Web Services.
331

332
333
334
335
336
337
338
339
340
341
342
343
344
345
/**
 * VALUE_REQUIRED - if the parameter is not supplied, there is an error
 */
define('VALUE_REQUIRED', 1);

/**
 * VALUE_OPTIONAL - if the parameter is not supplied, then the param has no value
 */
define('VALUE_OPTIONAL', 2);

/**
 * VALUE_DEFAULT - if the parameter is not supplied, then the default value is used
 */
define('VALUE_DEFAULT', 0);
346

347
348
349
350
351
352
353
354
355
/**
 * NULL_NOT_ALLOWED - the parameter can not be set to null in the database
 */
define('NULL_NOT_ALLOWED', false);

/**
 * NULL_ALLOWED - the parameter can be set to null in the database
 */
define('NULL_ALLOWED', true);
356

357
358
// Page types.

dhawes's avatar
dhawes committed
359
360
/**
 * PAGE_COURSE_VIEW is a definition of a page type. For more information on the page class see moodle/lib/pagelib.php.
defacer's avatar
   
defacer committed
361
362
363
 */
define('PAGE_COURSE_VIEW', 'course-view');

364
365
366
367
/** Get remote addr constant */
define('GETREMOTEADDR_SKIP_HTTP_CLIENT_IP', '1');
/** Get remote addr constant */
define('GETREMOTEADDR_SKIP_HTTP_X_FORWARDED_FOR', '2');
368
369
370
371
/**
 * GETREMOTEADDR_SKIP_DEFAULT defines the default behavior remote IP address validation.
 */
define('GETREMOTEADDR_SKIP_DEFAULT', GETREMOTEADDR_SKIP_HTTP_X_FORWARDED_FOR|GETREMOTEADDR_SKIP_HTTP_CLIENT_IP);
372

373
// Blog access level constant declaration.
skodak's avatar
skodak committed
374
375
376
377
378
379
define ('BLOG_USER_LEVEL', 1);
define ('BLOG_GROUP_LEVEL', 2);
define ('BLOG_COURSE_LEVEL', 3);
define ('BLOG_SITE_LEVEL', 4);
define ('BLOG_GLOBAL_LEVEL', 5);

380

381
// Tag constants.
382
/**
383
 * To prevent problems with multibytes strings,Flag updating in nav not working on the review page. this should not exceed the
384
385
 * length of "varchar(255) / 3 (bytes / utf-8 character) = 85".
 * TODO: this is not correct, varchar(255) are 255 unicode chars ;-)
386
387
 *
 * @todo define(TAG_MAX_LENGTH) this is not correct, varchar(255) are 255 unicode chars ;-)
388
 */
389
define('TAG_MAX_LENGTH', 50);
390

391
// Password policy constants.
392
393
394
395
396
define ('PASSWORD_LOWER', 'abcdefghijklmnopqrstuvwxyz');
define ('PASSWORD_UPPER', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
define ('PASSWORD_DIGITS', '0123456789');
define ('PASSWORD_NONALPHANUM', '.,;:!?_-+/*@#&$');

397
// Feature constants.
398
// Used for plugin_supports() to report features that are, or are not, supported by a module.
399
400

/** True if module can provide a grade */
401
define('FEATURE_GRADE_HAS_GRADE', 'grade_has_grade');
402
403
/** True if module supports outcomes */
define('FEATURE_GRADE_OUTCOMES', 'outcomes');
404
405
/** True if module supports advanced grading methods */
define('FEATURE_ADVANCED_GRADING', 'grade_advanced_grading');
406
407
/** True if module controls the grade visibility over the gradebook */
define('FEATURE_CONTROLS_GRADE_VISIBILITY', 'controlsgradevisbility');
408
409
/** True if module supports plagiarism plugins */
define('FEATURE_PLAGIARISM', 'plagiarism');
410

411
/** True if module has code to track whether somebody viewed it */
412
define('FEATURE_COMPLETION_TRACKS_VIEWS', 'completion_tracks_views');
413
/** True if module has custom completion rules */
414
define('FEATURE_COMPLETION_HAS_RULES', 'completion_has_rules');
415

sam marshall's avatar
sam marshall committed
416
417
/** True if module has no 'view' page (like label) */
define('FEATURE_NO_VIEW_LINK', 'viewlink');
418
/** True (which is default) if the module wants support for setting the ID number for grade calculation purposes. */
419
420
421
422
423
define('FEATURE_IDNUMBER', 'idnumber');
/** True if module supports groups */
define('FEATURE_GROUPS', 'groups');
/** True if module supports groupings */
define('FEATURE_GROUPINGS', 'groupings');
424
425
426
427
/**
 * True if module supports groupmembersonly (which no longer exists)
 * @deprecated Since Moodle 2.8
 */
428
429
define('FEATURE_GROUPMEMBERSONLY', 'groupmembersonly');

430
431
/** Type of module */
define('FEATURE_MOD_ARCHETYPE', 'mod_archetype');
432
/** True if module supports intro editor */
433
define('FEATURE_MOD_INTRO', 'mod_intro');
434
435
/** True if module has default completion */
define('FEATURE_MODEDIT_DEFAULT_COMPLETION', 'modedit_default_completion');
436

dongsheng's avatar
dongsheng committed
437
438
define('FEATURE_COMMENT', 'comment');

439
define('FEATURE_RATE', 'rate');
440
441
/** True if module supports backup/restore of moodle2 format */
define('FEATURE_BACKUP_MOODLE2', 'backup_moodle2');
442

443
444
445
/** True if module can show description on course main page */
define('FEATURE_SHOW_DESCRIPTION', 'showdescription');

446
447
448
/** True if module uses the question bank */
define('FEATURE_USES_QUESTIONS', 'usesquestions');

449
450
451
/**
 * Maximum filename char size
 */
452
define('MAX_FILENAME_SIZE', 100);
453

454
455
456
457
/** Unspecified module archetype */
define('MOD_ARCHETYPE_OTHER', 0);
/** Resource-like type module */
define('MOD_ARCHETYPE_RESOURCE', 1);
Petr Skoda's avatar
Petr Skoda committed
458
/** Assignment module archetype */
459
define('MOD_ARCHETYPE_ASSIGNMENT', 2);
460
461
/** System (not user-addable) module archetype */
define('MOD_ARCHETYPE_SYSTEM', 3);
462

463
464
465
466
467
/**
 * Security token used for allowing access
 * from external application such as web services.
 * Scripts do not use any session, performance is relatively
 * low because we need to load access info in each request.
Petr Skoda's avatar
Petr Skoda committed
468
 * Scripts are executed in parallel.
469
470
471
472
473
474
475
476
477
478
 */
define('EXTERNAL_TOKEN_PERMANENT', 0);

/**
 * Security token used for allowing access
 * of embedded applications, the code is executed in the
 * active user session. Token is invalidated after user logs out.
 * Scripts are executed serially - normal session locking is used.
 */
define('EXTERNAL_TOKEN_EMBEDDED', 1);
479

480
481
482
483
484
485
486
487
488
489
490
491
/**
 * The home page should be the site home
 */
define('HOMEPAGE_SITE', 0);
/**
 * The home page should be the users my page
 */
define('HOMEPAGE_MY', 1);
/**
 * The home page can be chosen by the user
 */
define('HOMEPAGE_USER', 2);
492

493
/**
494
 * URL of the Moodle sites registration portal.
495
 */
496
defined('HUB_MOODLEORGHUBURL') || define('HUB_MOODLEORGHUBURL', 'https://stats.moodle.org');
497

498
499
500
501
/**
 * Moodle mobile app service name
 */
define('MOODLE_OFFICIAL_MOBILE_SERVICE', 'moodle_mobile_app');
502

503
504
505
506
507
/**
 * Indicates the user has the capabilities required to ignore activity and course file size restrictions
 */
define('USER_CAN_IGNORE_FILE_SIZE_LIMITS', -1);

508
/**
509
510
511
512
513
 * Course display settings: display all sections on one page.
 */
define('COURSE_DISPLAY_SINGLEPAGE', 0);
/**
 * Course display settings: split pages into a page per section.
514
 */
515
define('COURSE_DISPLAY_MULTIPAGE', 1);
516

517
/**
518
 * Authentication constant: String used in password field when password is not stored.
519
 */
520
define('AUTH_PASSWORD_NOT_CACHED', 'not cached');
521

522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
/**
 * Email from header to never include via information.
 */
define('EMAIL_VIA_NEVER', 0);

/**
 * Email from header to always include via information.
 */
define('EMAIL_VIA_ALWAYS', 1);

/**
 * Email from header to only include via information if the address is no-reply.
 */
define('EMAIL_VIA_NO_REPLY_ONLY', 2);

537
// PARAMETER HANDLING.
538

539
/**
540
541
 * Returns a particular value for the named variable, taken from
 * POST or GET.  If the parameter doesn't exist then an error is
542
543
 * thrown because we require this variable.
 *
544
545
 * This function should be used to initialise all required values
 * in a script that are based on parameters.  Usually it will be
546
 * used like this:
547
 *    $id = required_param('id', PARAM_INT);
548
 *
549
 * Please note the $type parameter is now required and the value can not be array.
550
551
552
 *
 * @param string $parname the name of the page parameter we want
 * @param string $type expected type of parameter
553
 * @return mixed
554
 * @throws coding_exception
555
 */
556
function required_param($parname, $type) {
557
558
    if (func_num_args() != 2 or empty($parname) or empty($type)) {
        throw new coding_exception('required_param() requires $parname and $type to be specified (parameter: '.$parname.')');
559
    }
560
561
    // POST has precedence.
    if (isset($_POST[$parname])) {
562
563
564
        $param = $_POST[$parname];
    } else if (isset($_GET[$parname])) {
        $param = $_GET[$parname];
565
    } else {
dongsheng's avatar
dongsheng committed
566
        print_error('missingparam', '', '', $parname);
567
568
    }

569
570
    if (is_array($param)) {
        debugging('Invalid array parameter detected in required_param(): '.$parname);
571
        // TODO: switch to fatal error in Moodle 2.3.
572
573
574
        return required_param_array($parname, $type);
    }

575
    return clean_param($param, $type);
576
577
}

578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
/**
 * Returns a particular array value for the named variable, taken from
 * POST or GET.  If the parameter doesn't exist then an error is
 * thrown because we require this variable.
 *
 * This function should be used to initialise all required values
 * in a script that are based on parameters.  Usually it will be
 * used like this:
 *    $ids = required_param_array('ids', PARAM_INT);
 *
 *  Note: arrays of arrays are not supported, only alphanumeric keys with _ and - are supported
 *
 * @param string $parname the name of the page parameter we want
 * @param string $type expected type of parameter
 * @return array
593
 * @throws coding_exception
594
595
596
597
598
 */
function required_param_array($parname, $type) {
    if (func_num_args() != 2 or empty($parname) or empty($type)) {
        throw new coding_exception('required_param_array() requires $parname and $type to be specified (parameter: '.$parname.')');
    }
599
600
    // POST has precedence.
    if (isset($_POST[$parname])) {
601
602
603
604
605
606
607
608
609
610
611
        $param = $_POST[$parname];
    } else if (isset($_GET[$parname])) {
        $param = $_GET[$parname];
    } else {
        print_error('missingparam', '', '', $parname);
    }
    if (!is_array($param)) {
        print_error('missingparam', '', '', $parname);
    }

    $result = array();
612
    foreach ($param as $key => $value) {
613
614
615
616
        if (!preg_match('/^[a-z0-9_-]+$/i', $key)) {
            debugging('Invalid key name in required_param_array() detected: '.$key.', parameter: '.$parname);
            continue;
        }
Petr Skoda's avatar
Petr Skoda committed
617
        $result[$key] = clean_param($value, $type);
618
619
620
    }

    return $result;
621
622
623
}

/**
624
 * Returns a particular value for the named variable, taken from
625
626
 * POST or GET, otherwise returning a given default.
 *
627
628
 * This function should be used to initialise all optional values
 * in a script that are based on parameters.  Usually it will be
629
 * used like this:
630
 *    $name = optional_param('name', 'Fred', PARAM_TEXT);
631
 *
632
 * Please note the $type parameter is now required and the value can not be array.
633
 *
634
 * @param string $parname the name of the page parameter we want
635
 * @param mixed  $default the default value to return if nothing is found
636
 * @param string $type expected type of parameter
637
 * @return mixed
638
 * @throws coding_exception
639
 */
640
function optional_param($parname, $default, $type) {
641
    if (func_num_args() != 3 or empty($parname) or empty($type)) {
642
        throw new coding_exception('optional_param requires $parname, $default + $type to be specified (parameter: '.$parname.')');
643
644
    }

645
646
    // POST has precedence.
    if (isset($_POST[$parname])) {
647
648
649
        $param = $_POST[$parname];
    } else if (isset($_GET[$parname])) {
        $param = $_GET[$parname];
650
651
652
    } else {
        return $default;
    }
653

654
655
    if (is_array($param)) {
        debugging('Invalid array parameter detected in required_param(): '.$parname);
656
        // TODO: switch to $default in Moodle 2.3.
657
658
659
        return optional_param_array($parname, $default, $type);
    }

660
    return clean_param($param, $type);
661
662
}

663
664
665
666
667
668
669
670
671
/**
 * Returns a particular array value for the named variable, taken from
 * POST or GET, otherwise returning a given default.
 *
 * This function should be used to initialise all optional values
 * in a script that are based on parameters.  Usually it will be
 * used like this:
 *    $ids = optional_param('id', array(), PARAM_INT);
 *
672
 * Note: arrays of arrays are not supported, only alphanumeric keys with _ and - are supported
673
674
 *
 * @param string $parname the name of the page parameter we want
675
 * @param mixed $default the default value to return if nothing is found
676
677
 * @param string $type expected type of parameter
 * @return array
678
 * @throws coding_exception
679
680
681
 */
function optional_param_array($parname, $default, $type) {
    if (func_num_args() != 3 or empty($parname) or empty($type)) {
682
        throw new coding_exception('optional_param_array requires $parname, $default + $type to be specified (parameter: '.$parname.')');
683
684
    }

685
686
    // POST has precedence.
    if (isset($_POST[$parname])) {
687
688
689
690
691
692
693
694
695
696
697
698
        $param = $_POST[$parname];
    } else if (isset($_GET[$parname])) {
        $param = $_GET[$parname];
    } else {
        return $default;
    }
    if (!is_array($param)) {
        debugging('optional_param_array() expects array parameters only: '.$parname);
        return $default;
    }

    $result = array();
699
    foreach ($param as $key => $value) {
700
701
702
703
        if (!preg_match('/^[a-z0-9_-]+$/i', $key)) {
            debugging('Invalid key name in optional_param_array() detected: '.$key.', parameter: '.$parname);
            continue;
        }
Petr Skoda's avatar
Petr Skoda committed
704
        $result[$key] = clean_param($value, $type);
705
706
707
    }

    return $result;
708
709
}

710
711
712
713
714
/**
 * Strict validation of parameter values, the values are only converted
 * to requested PHP type. Internally it is using clean_param, the values
 * before and after cleaning must be equal - otherwise
 * an invalid_parameter_exception is thrown.
Petr Skoda's avatar
Petr Skoda committed
715
 * Objects and classes are not accepted.
716
717
 *
 * @param mixed $param
718
 * @param string $type PARAM_ constant
719
720
 * @param bool $allownull are nulls valid value?
 * @param string $debuginfo optional debug information
721
722
 * @return mixed the $param value converted to PHP type
 * @throws invalid_parameter_exception if $param is not of given type
723
 */
724
function validate_param($param, $type, $allownull=NULL_NOT_ALLOWED, $debuginfo='') {
725
    if (is_null($param)) {
726
        if ($allownull == NULL_ALLOWED) {
727
728
729
730
731
732
733
734
735
736
            return null;
        } else {
            throw new invalid_parameter_exception($debuginfo);
        }
    }
    if (is_array($param) or is_object($param)) {
        throw new invalid_parameter_exception($debuginfo);
    }

    $cleaned = clean_param($param, $type);
737
738
739
740
741
742
743
744
745

    if ($type == PARAM_FLOAT) {
        // Do not detect precision loss here.
        if (is_float($param) or is_int($param)) {
            // These always fit.
        } else if (!is_numeric($param) or !preg_match('/^[\+-]?[0-9]*\.?[0-9]*(e[-+]?[0-9]+)?$/i', (string)$param)) {
            throw new invalid_parameter_exception($debuginfo);
        }
    } else if ((string)$param !== (string)$cleaned) {
746
        // Conversion to string is usually lossless.
747
748
749
750
751
752
        throw new invalid_parameter_exception($debuginfo);
    }

    return $cleaned;
}

753
/**
754
755
 * Makes sure array contains only the allowed types, this function does not validate array key names!
 *
756
757
758
759
760
761
762
763
 * <code>
 * $options = clean_param($options, PARAM_INT);
 * </code>
 *
 * @param array $param the variable array we are cleaning
 * @param string $type expected format of param after cleaning.
 * @param bool $recursive clean recursive arrays
 * @return array
764
 * @throws coding_exception
765
766
 */
function clean_param_array(array $param = null, $type, $recursive = false) {
767
768
    // Convert null to empty array.
    $param = (array)$param;
769
770
771
772
773
    foreach ($param as $key => $value) {
        if (is_array($value)) {
            if ($recursive) {
                $param[$key] = clean_param_array($value, $type, true);
            } else {
774
                throw new coding_exception('clean_param_array can not process multidimensional arrays when $recursive is false.');
775
776
777
778
779
780
781
782
            }
        } else {
            $param[$key] = clean_param($value, $type);
        }
    }
    return $param;
}

783
/**
784
785
 * Used by {@link optional_param()} and {@link required_param()} to
 * clean the variables and/or cast to specific types, based on
786
 * an options field.
dhawes's avatar
dhawes committed
787
788
 * <code>
 * $course->format = clean_param($course->format, PARAM_ALPHA);
789
 * $selectedgradeitem = clean_param($selectedgradeitem, PARAM_INT);
dhawes's avatar
dhawes committed
790
 * </code>
791
792
 *
 * @param mixed $param the variable we are cleaning
793
 * @param string $type expected format of param after cleaning.
794
 * @return mixed
795
 * @throws coding_exception
796
 */
797
function clean_param($param, $type) {
798
    global $CFG;
799

800
801
802
803
804
805
806
807
    if (is_array($param)) {
        throw new coding_exception('clean_param() can not process arrays, please use clean_param_array() instead.');
    } else if (is_object($param)) {
        if (method_exists($param, '__toString')) {
            $param = $param->__toString();
        } else {
            throw new coding_exception('clean_param() can not process objects, please use clean_param_array() instead.');
        }
808
809
    }

810
    switch ($type) {
811
812
        case PARAM_RAW:
            // No cleaning at all.
813
            $param = fix_utf8($param);
814
815
            return $param;

816
817
        case PARAM_RAW_TRIMMED:
            // No cleaning, but strip leading and trailing whitespace.
818
            $param = fix_utf8($param);
819
820
            return trim($param);

821
822
823
        case PARAM_CLEAN:
            // General HTML cleaning, try to use more specific type if possible this is deprecated!
            // Please use more specific type instead.
824
825
826
            if (is_numeric($param)) {
                return $param;
            }
827
            $param = fix_utf8($param);
828
829
            // Sweep for scripts, etc.
            return clean_text($param);
moodler's avatar
moodler committed
830

831
832
        case PARAM_CLEANHTML:
            // Clean html fragment.
833
            $param = fix_utf8($param);
834
835
            // Sweep for scripts, etc.
            $param = clean_text($param, FORMAT_HTML);
836
            return trim($param);
837

838
        case PARAM_INT:
839
840
            // Convert to integer.
            return (int)$param;
841

842
        case PARAM_FLOAT:
843
844
            // Convert to float.
            return (float)$param;
845

846
847
848
849
        case PARAM_LOCALISEDFLOAT:
            // Convert to float.
            return unformat_float($param, true);

850
851
        case PARAM_ALPHA:
            // Remove everything not `a-z`.
852
            return preg_replace('/[^a-zA-Z]/i', '', $param);
853

854
855
        case PARAM_ALPHAEXT:
            // Remove everything not `a-zA-Z_-` (originally allowed "/" too).
856
            return preg_replace('/[^a-zA-Z_-]/i', '', $param);
857

858
859
        case PARAM_ALPHANUM:
            // Remove everything not `a-zA-Z0-9`.
860
            return preg_replace('/[^A-Za-z0-9]/i', '', $param);
861

862
863
        case PARAM_ALPHANUMEXT:
            // Remove everything not `a-zA-Z0-9_-`.
864
            return preg_replace('/[^A-Za-z0-9_-]/i', '', $param);
defacer's avatar
   
defacer committed
865

866
867
        case PARAM_SEQUENCE:
            // Remove everything not `0-9,`.
868
            return preg_replace('/[^0-9,]/i', '', $param);
869

870
871
        case PARAM_BOOL:
            // Convert to 1 or 0.
872
            $tempstr = strtolower($param);
873
            if ($tempstr === 'on' or $tempstr === 'yes' or $tempstr === 'true') {
874
                $param = 1;
875
            } else if ($tempstr === 'off' or $tempstr === 'no'  or $tempstr === 'false') {
876
877
878
879
880
                $param = 0;
            } else {
                $param = empty($param) ? 0 : 1;
            }
            return $param;
881

882
883
        case PARAM_NOTAGS:
            // Strip all tags.
884
            $param = fix_utf8($param);
885
            return strip_tags($param);
moodler's avatar
moodler committed
886

887
888
        case PARAM_TEXT:
            // Leave only tags needed for multilang.
889
            $param = fix_utf8($param);
890
891
            // If the multilang syntax is not correct we strip all tags because it would break xhtml strict which is required
            // for accessibility standards please note this cleaning does not strip unbalanced '>' for BC compatibility reasons.
892
893
            do {
                if (strpos($param, '</lang>') !== false) {
894
                    // Old and future mutilang syntax.
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
                    $param = strip_tags($param, '<lang>');
                    if (!preg_match_all('/<.*>/suU', $param, $matches)) {
                        break;
                    }
                    $open = false;
                    foreach ($matches[0] as $match) {
                        if ($match === '</lang>') {
                            if ($open) {
                                $open = false;
                                continue;
                            } else {
                                break 2;
                            }
                        }
                        if (!preg_match('/^<lang lang="[a-zA-Z0-9_-]+"\s*>$/u', $match)) {
                            break 2;
                        } else {
                            $open = true;
                        }
                    }
                    if ($open) {
                        break;
                    }
                    return $param;

                } else if (strpos($param, '</span>') !== false) {
921
                    // Current problematic multilang syntax.
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
                    $param = strip_tags($param,