PageRenderTime 72ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/moodlelib.php

https://bitbucket.org/ceu/moodle_demo
PHP | 8638 lines | 5266 code | 1197 blank | 2175 comment | 1270 complexity | 12a22e63472578b4f37557a8a5fa5727 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.0, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. <?php // $Id$
  2. ///////////////////////////////////////////////////////////////////////////
  3. // //
  4. // NOTICE OF COPYRIGHT //
  5. // //
  6. // Moodle - Modular Object-Oriented Dynamic Learning Environment //
  7. // http://moodle.org //
  8. // //
  9. // Copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com //
  10. // //
  11. // This program is free software; you can redistribute it and/or modify //
  12. // it under the terms of the GNU General Public License as published by //
  13. // the Free Software Foundation; either version 2 of the License, or //
  14. // (at your option) any later version. //
  15. // //
  16. // This program is distributed in the hope that it will be useful, //
  17. // but WITHOUT ANY WARRANTY; without even the implied warranty of //
  18. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
  19. // GNU General Public License for more details: //
  20. // //
  21. // http://www.gnu.org/copyleft/gpl.html //
  22. // //
  23. ///////////////////////////////////////////////////////////////////////////
  24. /**
  25. * moodlelib.php - Moodle main library
  26. *
  27. * Main library file of miscellaneous general-purpose Moodle functions.
  28. * Other main libraries:
  29. * - weblib.php - functions that produce web output
  30. * - datalib.php - functions that access the database
  31. * @author Martin Dougiamas
  32. * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
  33. * @package moodlecore
  34. */
  35. /// CONSTANTS (Encased in phpdoc proper comments)/////////////////////////
  36. /**
  37. * Used by some scripts to check they are being called by Moodle
  38. */
  39. define('MOODLE_INTERNAL', true);
  40. /// Date and time constants ///
  41. /**
  42. * Time constant - the number of seconds in a year
  43. */
  44. define('YEARSECS', 31536000);
  45. /**
  46. * Time constant - the number of seconds in a week
  47. */
  48. define('WEEKSECS', 604800);
  49. /**
  50. * Time constant - the number of seconds in a day
  51. */
  52. define('DAYSECS', 86400);
  53. /**
  54. * Time constant - the number of seconds in an hour
  55. */
  56. define('HOURSECS', 3600);
  57. /**
  58. * Time constant - the number of seconds in a minute
  59. */
  60. define('MINSECS', 60);
  61. /**
  62. * Time constant - the number of minutes in a day
  63. */
  64. define('DAYMINS', 1440);
  65. /**
  66. * Time constant - the number of minutes in an hour
  67. */
  68. define('HOURMINS', 60);
  69. /// Parameter constants - every call to optional_param(), required_param() ///
  70. /// or clean_param() should have a specified type of parameter. //////////////
  71. /**
  72. * PARAM_RAW specifies a parameter that is not cleaned/processed in any way;
  73. * originally was 0, but changed because we need to detect unknown
  74. * parameter types and swiched order in clean_param().
  75. */
  76. define('PARAM_RAW', 666);
  77. /**
  78. * PARAM_CLEAN - obsoleted, please try to use more specific type of parameter.
  79. * It was one of the first types, that is why it is abused so much ;-)
  80. */
  81. define('PARAM_CLEAN', 0x0001);
  82. /**
  83. * PARAM_INT - integers only, use when expecting only numbers.
  84. */
  85. define('PARAM_INT', 0x0002);
  86. /**
  87. * PARAM_INTEGER - an alias for PARAM_INT
  88. */
  89. define('PARAM_INTEGER', 0x0002);
  90. /**
  91. * PARAM_NUMBER - a real/floating point number.
  92. */
  93. define('PARAM_NUMBER', 0x000a);
  94. /**
  95. * PARAM_ALPHA - contains only english letters.
  96. */
  97. define('PARAM_ALPHA', 0x0004);
  98. /**
  99. * PARAM_ACTION - an alias for PARAM_ALPHA, use for various actions in formas and urls
  100. * @TODO: should we alias it to PARAM_ALPHANUM ?
  101. */
  102. define('PARAM_ACTION', 0x0004);
  103. /**
  104. * PARAM_FORMAT - an alias for PARAM_ALPHA, use for names of plugins, formats, etc.
  105. * @TODO: should we alias it to PARAM_ALPHANUM ?
  106. */
  107. define('PARAM_FORMAT', 0x0004);
  108. /**
  109. * PARAM_NOTAGS - all html tags are stripped from the text. Do not abuse this type.
  110. */
  111. define('PARAM_NOTAGS', 0x0008);
  112. /**
  113. * PARAM_MULTILANG - alias of PARAM_TEXT.
  114. */
  115. define('PARAM_MULTILANG', 0x0009);
  116. /**
  117. * PARAM_TEXT - general plain text compatible with multilang filter, no other html tags.
  118. */
  119. define('PARAM_TEXT', 0x0009);
  120. /**
  121. * PARAM_FILE - safe file name, all dangerous chars are stripped, protects against XSS, SQL injections and directory traversals
  122. */
  123. define('PARAM_FILE', 0x0010);
  124. /**
  125. * PARAM_TAG - one tag (interests, blogs, etc.) - mostly international alphanumeric with spaces
  126. */
  127. define('PARAM_TAG', 0x0011);
  128. /**
  129. * PARAM_TAGLIST - list of tags separated by commas (interests, blogs, etc.)
  130. */
  131. define('PARAM_TAGLIST', 0x0012);
  132. /**
  133. * PARAM_PATH - safe relative path name, all dangerous chars are stripped, protects against XSS, SQL injections and directory traversals
  134. * note: the leading slash is not removed, window drive letter is not allowed
  135. */
  136. define('PARAM_PATH', 0x0020);
  137. /**
  138. * PARAM_HOST - expected fully qualified domain name (FQDN) or an IPv4 dotted quad (IP address)
  139. */
  140. define('PARAM_HOST', 0x0040);
  141. /**
  142. * PARAM_URL - expected properly formatted URL. Please note that domain part is required, http://localhost/ is not acceppted but http://localhost.localdomain/ is ok.
  143. */
  144. define('PARAM_URL', 0x0080);
  145. /**
  146. * 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!)
  147. */
  148. define('PARAM_LOCALURL', 0x0180);
  149. /**
  150. * PARAM_CLEANFILE - safe file name, all dangerous and regional chars are removed,
  151. * use when you want to store a new file submitted by students
  152. */
  153. define('PARAM_CLEANFILE',0x0200);
  154. /**
  155. * PARAM_ALPHANUM - expected numbers and letters only.
  156. */
  157. define('PARAM_ALPHANUM', 0x0400);
  158. /**
  159. * PARAM_BOOL - converts input into 0 or 1, use for switches in forms and urls.
  160. */
  161. define('PARAM_BOOL', 0x0800);
  162. /**
  163. * PARAM_CLEANHTML - cleans submitted HTML code and removes slashes
  164. * note: do not forget to addslashes() before storing into database!
  165. */
  166. define('PARAM_CLEANHTML',0x1000);
  167. /**
  168. * PARAM_ALPHAEXT the same contents as PARAM_ALPHA plus the chars in quotes: "/-_" allowed,
  169. * suitable for include() and require()
  170. * @TODO: should we rename this function to PARAM_SAFEDIRS??
  171. */
  172. define('PARAM_ALPHAEXT', 0x2000);
  173. /**
  174. * PARAM_SAFEDIR - safe directory name, suitable for include() and require()
  175. */
  176. define('PARAM_SAFEDIR', 0x4000);
  177. /**
  178. * PARAM_SEQUENCE - expects a sequence of numbers like 8 to 1,5,6,4,6,8,9. Numbers and comma only.
  179. */
  180. define('PARAM_SEQUENCE', 0x8000);
  181. /**
  182. * PARAM_PEM - Privacy Enhanced Mail format
  183. */
  184. define('PARAM_PEM', 0x10000);
  185. /**
  186. * PARAM_BASE64 - Base 64 encoded format
  187. */
  188. define('PARAM_BASE64', 0x20000);
  189. /// Page types ///
  190. /**
  191. * PAGE_COURSE_VIEW is a definition of a page type. For more information on the page class see moodle/lib/pagelib.php.
  192. */
  193. define('PAGE_COURSE_VIEW', 'course-view');
  194. /// Debug levels ///
  195. /** no warnings at all */
  196. define ('DEBUG_NONE', 0);
  197. /** E_ERROR | E_PARSE */
  198. define ('DEBUG_MINIMAL', 5);
  199. /** E_ERROR | E_PARSE | E_WARNING | E_NOTICE */
  200. define ('DEBUG_NORMAL', 15);
  201. /** E_ALL without E_STRICT for now, do show recoverable fatal errors */
  202. define ('DEBUG_ALL', 6143);
  203. /** DEBUG_ALL with extra Moodle debug messages - (DEBUG_ALL | 32768) */
  204. define ('DEBUG_DEVELOPER', 38911);
  205. /**
  206. * Blog access level constant declaration
  207. */
  208. define ('BLOG_USER_LEVEL', 1);
  209. define ('BLOG_GROUP_LEVEL', 2);
  210. define ('BLOG_COURSE_LEVEL', 3);
  211. define ('BLOG_SITE_LEVEL', 4);
  212. define ('BLOG_GLOBAL_LEVEL', 5);
  213. /**
  214. * Tag constanst
  215. */
  216. //To prevent problems with multibytes strings, this should not exceed the
  217. //length of "varchar(255) / 3 (bytes / utf-8 character) = 85".
  218. define('TAG_MAX_LENGTH', 50);
  219. /**
  220. * Password policy constants
  221. */
  222. define ('PASSWORD_LOWER', 'abcdefghijklmnopqrstuvwxyz');
  223. define ('PASSWORD_UPPER', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
  224. define ('PASSWORD_DIGITS', '0123456789');
  225. define ('PASSWORD_NONALPHANUM', '.,;:!?_-+/*@#&$');
  226. if (!defined('SORT_LOCALE_STRING')) { // PHP < 4.4.0 - TODO: remove in 2.0
  227. define('SORT_LOCALE_STRING', SORT_STRING);
  228. }
  229. /// PARAMETER HANDLING ////////////////////////////////////////////////////
  230. /**
  231. * Returns a particular value for the named variable, taken from
  232. * POST or GET. If the parameter doesn't exist then an error is
  233. * thrown because we require this variable.
  234. *
  235. * This function should be used to initialise all required values
  236. * in a script that are based on parameters. Usually it will be
  237. * used like this:
  238. * $id = required_param('id');
  239. *
  240. * @param string $parname the name of the page parameter we want
  241. * @param int $type expected type of parameter
  242. * @return mixed
  243. */
  244. function required_param($parname, $type=PARAM_CLEAN) {
  245. // detect_unchecked_vars addition
  246. global $CFG;
  247. if (!empty($CFG->detect_unchecked_vars)) {
  248. global $UNCHECKED_VARS;
  249. unset ($UNCHECKED_VARS->vars[$parname]);
  250. }
  251. if (isset($_POST[$parname])) { // POST has precedence
  252. $param = $_POST[$parname];
  253. } else if (isset($_GET[$parname])) {
  254. $param = $_GET[$parname];
  255. } else {
  256. error('A required parameter ('.$parname.') was missing');
  257. }
  258. return clean_param($param, $type);
  259. }
  260. /**
  261. * Returns a particular value for the named variable, taken from
  262. * POST or GET, otherwise returning a given default.
  263. *
  264. * This function should be used to initialise all optional values
  265. * in a script that are based on parameters. Usually it will be
  266. * used like this:
  267. * $name = optional_param('name', 'Fred');
  268. *
  269. * @param string $parname the name of the page parameter we want
  270. * @param mixed $default the default value to return if nothing is found
  271. * @param int $type expected type of parameter
  272. * @return mixed
  273. */
  274. function optional_param($parname, $default=NULL, $type=PARAM_CLEAN) {
  275. // detect_unchecked_vars addition
  276. global $CFG;
  277. if (!empty($CFG->detect_unchecked_vars)) {
  278. global $UNCHECKED_VARS;
  279. unset ($UNCHECKED_VARS->vars[$parname]);
  280. }
  281. if (isset($_POST[$parname])) { // POST has precedence
  282. $param = $_POST[$parname];
  283. } else if (isset($_GET[$parname])) {
  284. $param = $_GET[$parname];
  285. } else {
  286. return $default;
  287. }
  288. return clean_param($param, $type);
  289. }
  290. /**
  291. * Used by {@link optional_param()} and {@link required_param()} to
  292. * clean the variables and/or cast to specific types, based on
  293. * an options field.
  294. * <code>
  295. * $course->format = clean_param($course->format, PARAM_ALPHA);
  296. * $selectedgrade_item = clean_param($selectedgrade_item, PARAM_CLEAN);
  297. * </code>
  298. *
  299. * @uses $CFG
  300. * @uses PARAM_RAW
  301. * @uses PARAM_CLEAN
  302. * @uses PARAM_CLEANHTML
  303. * @uses PARAM_INT
  304. * @uses PARAM_NUMBER
  305. * @uses PARAM_ALPHA
  306. * @uses PARAM_ALPHANUM
  307. * @uses PARAM_ALPHAEXT
  308. * @uses PARAM_SEQUENCE
  309. * @uses PARAM_BOOL
  310. * @uses PARAM_NOTAGS
  311. * @uses PARAM_TEXT
  312. * @uses PARAM_SAFEDIR
  313. * @uses PARAM_CLEANFILE
  314. * @uses PARAM_FILE
  315. * @uses PARAM_PATH
  316. * @uses PARAM_HOST
  317. * @uses PARAM_URL
  318. * @uses PARAM_LOCALURL
  319. * @uses PARAM_PEM
  320. * @uses PARAM_BASE64
  321. * @uses PARAM_TAG
  322. * @uses PARAM_SEQUENCE
  323. * @param mixed $param the variable we are cleaning
  324. * @param int $type expected format of param after cleaning.
  325. * @return mixed
  326. */
  327. function clean_param($param, $type) {
  328. global $CFG;
  329. if (is_array($param)) { // Let's loop
  330. $newparam = array();
  331. foreach ($param as $key => $value) {
  332. $newparam[$key] = clean_param($value, $type);
  333. }
  334. return $newparam;
  335. }
  336. switch ($type) {
  337. case PARAM_RAW: // no cleaning at all
  338. return $param;
  339. case PARAM_CLEAN: // General HTML cleaning, try to use more specific type if possible
  340. if (is_numeric($param)) {
  341. return $param;
  342. }
  343. $param = stripslashes($param); // Needed for kses to work fine
  344. $param = clean_text($param); // Sweep for scripts, etc
  345. return addslashes($param); // Restore original request parameter slashes
  346. case PARAM_CLEANHTML: // prepare html fragment for display, do not store it into db!!
  347. $param = stripslashes($param); // Remove any slashes
  348. $param = clean_text($param); // Sweep for scripts, etc
  349. return trim($param);
  350. case PARAM_INT:
  351. return (int)$param; // Convert to integer
  352. case PARAM_NUMBER:
  353. return (float)$param; // Convert to integer
  354. case PARAM_ALPHA: // Remove everything not a-z
  355. return preg_replace('/[^a-zA-Z]/i', '', $param);
  356. case PARAM_ALPHANUM: // Remove everything not a-zA-Z0-9
  357. return preg_replace('/[^A-Za-z0-9]/i', '', $param);
  358. case PARAM_ALPHAEXT: // Remove everything not a-zA-Z/_-
  359. return preg_replace('/[^a-zA-Z\/_-]/i', '', $param);
  360. case PARAM_SEQUENCE: // Remove everything not 0-9,
  361. return preg_replace('/[^0-9,]/i', '', $param);
  362. case PARAM_BOOL: // Convert to 1 or 0
  363. $tempstr = strtolower($param);
  364. if ($tempstr == 'on' or $tempstr == 'yes' ) {
  365. $param = 1;
  366. } else if ($tempstr == 'off' or $tempstr == 'no') {
  367. $param = 0;
  368. } else {
  369. $param = empty($param) ? 0 : 1;
  370. }
  371. return $param;
  372. case PARAM_NOTAGS: // Strip all tags
  373. return strip_tags($param);
  374. case PARAM_TEXT: // leave only tags needed for multilang
  375. return clean_param(strip_tags($param, '<lang><span>'), PARAM_CLEAN);
  376. case PARAM_SAFEDIR: // Remove everything not a-zA-Z0-9_-
  377. return preg_replace('/[^a-zA-Z0-9_-]/i', '', $param);
  378. case PARAM_CLEANFILE: // allow only safe characters
  379. return clean_filename($param);
  380. case PARAM_FILE: // Strip all suspicious characters from filename
  381. $param = preg_replace('~[[:cntrl:]]|[&<>"`\|\':\\\\/]~u', '', $param);
  382. $param = preg_replace('~\.\.+~', '', $param);
  383. if ($param === '.') {
  384. $param = '';
  385. }
  386. return $param;
  387. case PARAM_PATH: // Strip all suspicious characters from file path
  388. $param = str_replace('\\', '/', $param);
  389. $param = preg_replace('~[[:cntrl:]]|[&<>"`\|\':]~u', '', $param);
  390. $param = preg_replace('~\.\.+~', '', $param);
  391. $param = preg_replace('~//+~', '/', $param);
  392. return preg_replace('~/(\./)+~', '/', $param);
  393. case PARAM_HOST: // allow FQDN or IPv4 dotted quad
  394. $param = preg_replace('/[^\.\d\w-]/','', $param ); // only allowed chars
  395. // match ipv4 dotted quad
  396. if (preg_match('/(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/',$param, $match)){
  397. // confirm values are ok
  398. if ( $match[0] > 255
  399. || $match[1] > 255
  400. || $match[3] > 255
  401. || $match[4] > 255 ) {
  402. // hmmm, what kind of dotted quad is this?
  403. $param = '';
  404. }
  405. } elseif ( preg_match('/^[\w\d\.-]+$/', $param) // dots, hyphens, numbers
  406. && !preg_match('/^[\.-]/', $param) // no leading dots/hyphens
  407. && !preg_match('/[\.-]$/', $param) // no trailing dots/hyphens
  408. ) {
  409. // all is ok - $param is respected
  410. } else {
  411. // all is not ok...
  412. $param='';
  413. }
  414. return $param;
  415. case PARAM_URL: // allow safe ftp, http, mailto urls
  416. include_once($CFG->dirroot . '/lib/validateurlsyntax.php');
  417. if (!empty($param) && validateUrlSyntax($param, 's?H?S?F?E?u-P-a?I?p?f?q?r?')) {
  418. // all is ok, param is respected
  419. } else {
  420. $param =''; // not really ok
  421. }
  422. return $param;
  423. case PARAM_LOCALURL: // allow http absolute, root relative and relative URLs within wwwroot
  424. $param = clean_param($param, PARAM_URL);
  425. if (!empty($param)) {
  426. if (preg_match(':^/:', $param)) {
  427. // root-relative, ok!
  428. } elseif (preg_match('/^'.preg_quote($CFG->wwwroot, '/').'/i',$param)) {
  429. // absolute, and matches our wwwroot
  430. } else {
  431. // relative - let's make sure there are no tricks
  432. if (validateUrlSyntax($param, 's-u-P-a-p-f+q?r?')) {
  433. // looks ok.
  434. } else {
  435. $param = '';
  436. }
  437. }
  438. }
  439. return $param;
  440. case PARAM_PEM:
  441. $param = trim($param);
  442. // PEM formatted strings may contain letters/numbers and the symbols
  443. // forward slash: /
  444. // plus sign: +
  445. // equal sign: =
  446. // , surrounded by BEGIN and END CERTIFICATE prefix and suffixes
  447. if (preg_match('/^-----BEGIN CERTIFICATE-----([\s\w\/\+=]+)-----END CERTIFICATE-----$/', trim($param), $matches)) {
  448. list($wholething, $body) = $matches;
  449. unset($wholething, $matches);
  450. $b64 = clean_param($body, PARAM_BASE64);
  451. if (!empty($b64)) {
  452. return "-----BEGIN CERTIFICATE-----\n$b64\n-----END CERTIFICATE-----\n";
  453. } else {
  454. return '';
  455. }
  456. }
  457. return '';
  458. case PARAM_BASE64:
  459. if (!empty($param)) {
  460. // PEM formatted strings may contain letters/numbers and the symbols
  461. // forward slash: /
  462. // plus sign: +
  463. // equal sign: =
  464. if (0 >= preg_match('/^([\s\w\/\+=]+)$/', trim($param))) {
  465. return '';
  466. }
  467. $lines = preg_split('/[\s]+/', $param, -1, PREG_SPLIT_NO_EMPTY);
  468. // Each line of base64 encoded data must be 64 characters in
  469. // length, except for the last line which may be less than (or
  470. // equal to) 64 characters long.
  471. for ($i=0, $j=count($lines); $i < $j; $i++) {
  472. if ($i + 1 == $j) {
  473. if (64 < strlen($lines[$i])) {
  474. return '';
  475. }
  476. continue;
  477. }
  478. if (64 != strlen($lines[$i])) {
  479. return '';
  480. }
  481. }
  482. return implode("\n",$lines);
  483. } else {
  484. return '';
  485. }
  486. case PARAM_TAG:
  487. // Please note it is not safe to use the tag name directly anywhere,
  488. // it must be processed with s(), urlencode() before embedding anywhere.
  489. // remove some nasties
  490. $param = preg_replace('~[[:cntrl:]]|[<>`]~u', '', $param);
  491. //as long as magic_quotes_gpc is used, a backslash will be a
  492. //problem, so remove *all* backslash - BUT watch out for SQL injections caused by this sloppy design (skodak)
  493. $param = str_replace('\\', '', $param);
  494. //convert many whitespace chars into one
  495. $param = preg_replace('/\s+/', ' ', $param);
  496. $textlib = textlib_get_instance();
  497. $param = $textlib->substr(trim($param), 0, TAG_MAX_LENGTH);
  498. return $param;
  499. case PARAM_TAGLIST:
  500. $tags = explode(',', $param);
  501. $result = array();
  502. foreach ($tags as $tag) {
  503. $res = clean_param($tag, PARAM_TAG);
  504. if ($res != '') {
  505. $result[] = $res;
  506. }
  507. }
  508. if ($result) {
  509. return implode(',', $result);
  510. } else {
  511. return '';
  512. }
  513. default: // throw error, switched parameters in optional_param or another serious problem
  514. error("Unknown parameter type: $type");
  515. }
  516. }
  517. /**
  518. * Return true if given value is integer or string with integer value
  519. *
  520. * @param mixed $value String or Int
  521. * @return bool true if number, false if not
  522. */
  523. function is_number($value) {
  524. if (is_int($value)) {
  525. return true;
  526. } else if (is_string($value)) {
  527. return ((string)(int)$value) === $value;
  528. } else {
  529. return false;
  530. }
  531. }
  532. /**
  533. * This function is useful for testing whether something you got back from
  534. * the HTML editor actually contains anything. Sometimes the HTML editor
  535. * appear to be empty, but actually you get back a <br> tag or something.
  536. *
  537. * @param string $string a string containing HTML.
  538. * @return boolean does the string contain any actual content - that is text,
  539. * images, objcts, etc.
  540. */
  541. function html_is_blank($string) {
  542. return trim(strip_tags($string, '<img><object><applet><input><select><textarea><hr>')) == '';
  543. }
  544. /**
  545. * Set a key in global configuration
  546. *
  547. * Set a key/value pair in both this session's {@link $CFG} global variable
  548. * and in the 'config' database table for future sessions.
  549. *
  550. * Can also be used to update keys for plugin-scoped configs in config_plugin table.
  551. * In that case it doesn't affect $CFG.
  552. *
  553. * A NULL value will delete the entry.
  554. *
  555. * @param string $name the key to set
  556. * @param string $value the value to set (without magic quotes)
  557. * @param string $plugin (optional) the plugin scope
  558. * @uses $CFG
  559. * @return bool
  560. */
  561. function set_config($name, $value, $plugin=NULL) {
  562. /// No need for get_config because they are usually always available in $CFG
  563. global $CFG;
  564. if (empty($plugin)) {
  565. if (!array_key_exists($name, $CFG->config_php_settings)) {
  566. // So it's defined for this invocation at least
  567. if (is_null($value)) {
  568. unset($CFG->$name);
  569. } else {
  570. $CFG->$name = (string)$value; // settings from db are always strings
  571. }
  572. }
  573. if (get_field('config', 'name', 'name', $name)) {
  574. if ($value===null) {
  575. return delete_records('config', 'name', $name);
  576. } else {
  577. return set_field('config', 'value', addslashes($value), 'name', $name);
  578. }
  579. } else {
  580. if ($value===null) {
  581. return true;
  582. }
  583. $config = new object();
  584. $config->name = $name;
  585. $config->value = addslashes($value);
  586. return insert_record('config', $config);
  587. }
  588. } else { // plugin scope
  589. if ($id = get_field('config_plugins', 'id', 'name', $name, 'plugin', $plugin)) {
  590. if ($value===null) {
  591. return delete_records('config_plugins', 'name', $name, 'plugin', $plugin);
  592. } else {
  593. return set_field('config_plugins', 'value', addslashes($value), 'id', $id);
  594. }
  595. } else {
  596. if ($value===null) {
  597. return true;
  598. }
  599. $config = new object();
  600. $config->plugin = addslashes($plugin);
  601. $config->name = $name;
  602. $config->value = addslashes($value);
  603. return insert_record('config_plugins', $config);
  604. }
  605. }
  606. }
  607. /**
  608. * Get configuration values from the global config table
  609. * or the config_plugins table.
  610. *
  611. * If called with no parameters it will do the right thing
  612. * generating $CFG safely from the database without overwriting
  613. * existing values.
  614. *
  615. * If called with 2 parameters it will return a $string single
  616. * value or false of the value is not found.
  617. *
  618. * @param string $plugin
  619. * @param string $name
  620. * @uses $CFG
  621. * @return hash-like object or single value
  622. *
  623. */
  624. function get_config($plugin=NULL, $name=NULL) {
  625. global $CFG;
  626. if (!empty($name)) { // the user is asking for a specific value
  627. if (!empty($plugin)) {
  628. return get_field('config_plugins', 'value', 'plugin' , $plugin, 'name', $name);
  629. } else {
  630. return get_field('config', 'value', 'name', $name);
  631. }
  632. }
  633. // the user is after a recordset
  634. if (!empty($plugin)) {
  635. if ($configs=get_records('config_plugins', 'plugin', $plugin, '', 'name,value')) {
  636. $configs = (array)$configs;
  637. $localcfg = array();
  638. foreach ($configs as $config) {
  639. $localcfg[$config->name] = $config->value;
  640. }
  641. return (object)$localcfg;
  642. } else {
  643. return false;
  644. }
  645. } else {
  646. // this was originally in setup.php
  647. if ($configs = get_records('config')) {
  648. $localcfg = (array)$CFG;
  649. foreach ($configs as $config) {
  650. if (!isset($localcfg[$config->name])) {
  651. $localcfg[$config->name] = $config->value;
  652. }
  653. // do not complain anymore if config.php overrides settings from db
  654. }
  655. $localcfg = (object)$localcfg;
  656. return $localcfg;
  657. } else {
  658. // preserve $CFG if DB returns nothing or error
  659. return $CFG;
  660. }
  661. }
  662. }
  663. /**
  664. * Removes a key from global configuration
  665. *
  666. * @param string $name the key to set
  667. * @param string $plugin (optional) the plugin scope
  668. * @uses $CFG
  669. * @return bool
  670. */
  671. function unset_config($name, $plugin=NULL) {
  672. global $CFG;
  673. unset($CFG->$name);
  674. if (empty($plugin)) {
  675. return delete_records('config', 'name', $name);
  676. } else {
  677. return delete_records('config_plugins', 'name', $name, 'plugin', $plugin);
  678. }
  679. }
  680. /**
  681. * Get volatile flags
  682. *
  683. * @param string $type
  684. * @param int $changedsince
  685. * @return records array
  686. *
  687. */
  688. function get_cache_flags($type, $changedsince=NULL) {
  689. $type = addslashes($type);
  690. $sqlwhere = 'flagtype=\'' . $type . '\' AND expiry >= ' . time();
  691. if ($changedsince !== NULL) {
  692. $changedsince = (int)$changedsince;
  693. $sqlwhere .= ' AND timemodified > ' . $changedsince;
  694. }
  695. $cf = array();
  696. if ($flags=get_records_select('cache_flags', $sqlwhere, '', 'name,value')) {
  697. foreach ($flags as $flag) {
  698. $cf[$flag->name] = $flag->value;
  699. }
  700. }
  701. return $cf;
  702. }
  703. /**
  704. * Use this funciton to get a list of users from a config setting of type admin_setting_users_with_capability.
  705. * @param string $value the value of the config setting.
  706. * @param string $capability the capability - must match the one passed to the admin_setting_users_with_capability constructor.
  707. * @return array of user objects.
  708. */
  709. function get_users_from_config($value, $capability) {
  710. global $CFG;
  711. if ($value == '$@ALL@$') {
  712. $users = get_users_by_capability(get_context_instance(CONTEXT_SYSTEM), $capability);
  713. } else if ($value) {
  714. $usernames = explode(',', $value);
  715. $users = get_records_select('user', "username IN ('" . implode("','", $usernames) . "') AND mnethostid = " . $CFG->mnet_localhost_id);
  716. } else {
  717. $users = array();
  718. }
  719. return $users;
  720. }
  721. /**
  722. * Get volatile flags
  723. *
  724. * @param string $type
  725. * @param string $name
  726. * @param int $changedsince
  727. * @return records array
  728. *
  729. */
  730. function get_cache_flag($type, $name, $changedsince=NULL) {
  731. $type = addslashes($type);
  732. $name = addslashes($name);
  733. $sqlwhere = 'flagtype=\'' . $type . '\' AND name=\'' . $name . '\' AND expiry >= ' . time();
  734. if ($changedsince !== NULL) {
  735. $changedsince = (int)$changedsince;
  736. $sqlwhere .= ' AND timemodified > ' . $changedsince;
  737. }
  738. return get_field_select('cache_flags', 'value', $sqlwhere);
  739. }
  740. /**
  741. * Set a volatile flag
  742. *
  743. * @param string $type the "type" namespace for the key
  744. * @param string $name the key to set
  745. * @param string $value the value to set (without magic quotes) - NULL will remove the flag
  746. * @param int $expiry (optional) epoch indicating expiry - defaults to now()+ 24hs
  747. * @return bool
  748. */
  749. function set_cache_flag($type, $name, $value, $expiry=NULL) {
  750. $timemodified = time();
  751. if ($expiry===NULL || $expiry < $timemodified) {
  752. $expiry = $timemodified + 24 * 60 * 60;
  753. } else {
  754. $expiry = (int)$expiry;
  755. }
  756. if ($value === NULL) {
  757. return unset_cache_flag($type,$name);
  758. }
  759. $type = addslashes($type);
  760. $name = addslashes($name);
  761. if ($f = get_record('cache_flags', 'name', $name, 'flagtype', $type)) { // this is a potentail problem in DEBUG_DEVELOPER
  762. if ($f->value == $value and $f->expiry == $expiry and $f->timemodified == $timemodified) {
  763. return true; //no need to update; helps rcache too
  764. }
  765. $f->value = addslashes($value);
  766. $f->expiry = $expiry;
  767. $f->timemodified = $timemodified;
  768. return update_record('cache_flags', $f);
  769. } else {
  770. $f = new object();
  771. $f->flagtype = $type;
  772. $f->name = $name;
  773. $f->value = addslashes($value);
  774. $f->expiry = $expiry;
  775. $f->timemodified = $timemodified;
  776. return (bool)insert_record('cache_flags', $f);
  777. }
  778. }
  779. /**
  780. * Removes a single volatile flag
  781. *
  782. * @param string $type the "type" namespace for the key
  783. * @param string $name the key to set
  784. * @uses $CFG
  785. * @return bool
  786. */
  787. function unset_cache_flag($type, $name) {
  788. return delete_records('cache_flags',
  789. 'name', addslashes($name),
  790. 'flagtype', addslashes($type));
  791. }
  792. /**
  793. * Garbage-collect volatile flags
  794. *
  795. */
  796. function gc_cache_flags() {
  797. return delete_records_select('cache_flags', 'expiry < ' . time());
  798. }
  799. /**
  800. * Refresh current $USER session global variable with all their current preferences.
  801. * @uses $USER
  802. */
  803. function reload_user_preferences() {
  804. global $USER;
  805. //reset preference
  806. $USER->preference = array();
  807. if (!isloggedin() or isguestuser()) {
  808. // no permanent storage for not-logged-in user and guest
  809. } else if ($preferences = get_records('user_preferences', 'userid', $USER->id)) {
  810. foreach ($preferences as $preference) {
  811. $USER->preference[$preference->name] = $preference->value;
  812. }
  813. }
  814. return true;
  815. }
  816. /**
  817. * Sets a preference for the current user
  818. * Optionally, can set a preference for a different user object
  819. * @uses $USER
  820. * @todo Add a better description and include usage examples. Add inline links to $USER and user functions in above line.
  821. * @param string $name The key to set as preference for the specified user
  822. * @param string $value The value to set forthe $name key in the specified user's record
  823. * @param int $otheruserid A moodle user ID
  824. * @return bool
  825. */
  826. function set_user_preference($name, $value, $otheruserid=NULL) {
  827. global $USER;
  828. if (!isset($USER->preference)) {
  829. reload_user_preferences();
  830. }
  831. if (empty($name)) {
  832. return false;
  833. }
  834. $nostore = false;
  835. if (empty($otheruserid)){
  836. if (!isloggedin() or isguestuser()) {
  837. $nostore = true;
  838. }
  839. $userid = $USER->id;
  840. } else {
  841. if (isguestuser($otheruserid)) {
  842. $nostore = true;
  843. }
  844. $userid = $otheruserid;
  845. }
  846. $return = true;
  847. if ($nostore) {
  848. // no permanent storage for not-logged-in user and guest
  849. } else if ($preference = get_record('user_preferences', 'userid', $userid, 'name', addslashes($name))) {
  850. if ($preference->value === $value) {
  851. return true;
  852. }
  853. if (!set_field('user_preferences', 'value', addslashes((string)$value), 'id', $preference->id)) {
  854. $return = false;
  855. }
  856. } else {
  857. $preference = new object();
  858. $preference->userid = $userid;
  859. $preference->name = addslashes($name);
  860. $preference->value = addslashes((string)$value);
  861. if (!insert_record('user_preferences', $preference)) {
  862. $return = false;
  863. }
  864. }
  865. // update value in USER session if needed
  866. if ($userid == $USER->id) {
  867. $USER->preference[$name] = (string)$value;
  868. }
  869. return $return;
  870. }
  871. /**
  872. * Unsets a preference completely by deleting it from the database
  873. * Optionally, can set a preference for a different user id
  874. * @uses $USER
  875. * @param string $name The key to unset as preference for the specified user
  876. * @param int $otheruserid A moodle user ID
  877. */
  878. function unset_user_preference($name, $otheruserid=NULL) {
  879. global $USER;
  880. if (!isset($USER->preference)) {
  881. reload_user_preferences();
  882. }
  883. if (empty($otheruserid)){
  884. $userid = $USER->id;
  885. } else {
  886. $userid = $otheruserid;
  887. }
  888. //Delete the preference from $USER if needed
  889. if ($userid == $USER->id) {
  890. unset($USER->preference[$name]);
  891. }
  892. //Then from DB
  893. return delete_records('user_preferences', 'userid', $userid, 'name', addslashes($name));
  894. }
  895. /**
  896. * Sets a whole array of preferences for the current user
  897. * @param array $prefarray An array of key/value pairs to be set
  898. * @param int $otheruserid A moodle user ID
  899. * @return bool
  900. */
  901. function set_user_preferences($prefarray, $otheruserid=NULL) {
  902. if (!is_array($prefarray) or empty($prefarray)) {
  903. return false;
  904. }
  905. $return = true;
  906. foreach ($prefarray as $name => $value) {
  907. // The order is important; test for return is done first
  908. $return = (set_user_preference($name, $value, $otheruserid) && $return);
  909. }
  910. return $return;
  911. }
  912. /**
  913. * If no arguments are supplied this function will return
  914. * all of the current user preferences as an array.
  915. * If a name is specified then this function
  916. * attempts to return that particular preference value. If
  917. * none is found, then the optional value $default is returned,
  918. * otherwise NULL.
  919. * @param string $name Name of the key to use in finding a preference value
  920. * @param string $default Value to be returned if the $name key is not set in the user preferences
  921. * @param int $otheruserid A moodle user ID
  922. * @uses $USER
  923. * @return string
  924. */
  925. function get_user_preferences($name=NULL, $default=NULL, $otheruserid=NULL) {
  926. global $USER;
  927. if (!isset($USER->preference)) {
  928. reload_user_preferences();
  929. }
  930. if (empty($otheruserid)){
  931. $userid = $USER->id;
  932. } else {
  933. $userid = $otheruserid;
  934. }
  935. if ($userid == $USER->id) {
  936. $preference = $USER->preference;
  937. } else {
  938. $preference = array();
  939. if ($prefdata = get_records('user_preferences', 'userid', $userid)) {
  940. foreach ($prefdata as $pref) {
  941. $preference[$pref->name] = $pref->value;
  942. }
  943. }
  944. }
  945. if (empty($name)) {
  946. return $preference; // All values
  947. } else if (array_key_exists($name, $preference)) {
  948. return $preference[$name]; // The single value
  949. } else {
  950. return $default; // Default value (or NULL)
  951. }
  952. }
  953. /// FUNCTIONS FOR HANDLING TIME ////////////////////////////////////////////
  954. /**
  955. * Given date parts in user time produce a GMT timestamp.
  956. *
  957. * @param int $year The year part to create timestamp of
  958. * @param int $month The month part to create timestamp of
  959. * @param int $day The day part to create timestamp of
  960. * @param int $hour The hour part to create timestamp of
  961. * @param int $minute The minute part to create timestamp of
  962. * @param int $second The second part to create timestamp of
  963. * @param mixed $timezone Timezone modifier, if 99 then use default user's timezone
  964. * @param bool $applydst Toggle Daylight Saving Time, default true, will be
  965. * applied only if timezone is 99 or string.
  966. * @return int timestamp
  967. * @todo Finish documenting this function
  968. */
  969. function make_timestamp($year, $month=1, $day=1, $hour=0, $minute=0, $second=0, $timezone=99, $applydst=true) {
  970. //save input timezone, required for dst offset check.
  971. $passedtimezone = $timezone;
  972. $timezone = get_user_timezone_offset($timezone);
  973. if (abs($timezone) > 13) { //server time
  974. $time = mktime((int)$hour, (int)$minute, (int)$second, (int)$month, (int)$day, (int)$year);
  975. } else {
  976. $time = gmmktime((int)$hour, (int)$minute, (int)$second, (int)$month, (int)$day, (int)$year);
  977. $time = usertime($time, $timezone);
  978. //Apply dst for string timezones or if 99 then try dst offset with user's default timezone
  979. if ($applydst && ((99 == $passedtimezone) || !is_numeric($passedtimezone))) {
  980. $time -= dst_offset_on($time, $passedtimezone);
  981. }
  982. }
  983. return $time;
  984. }
  985. /**
  986. * Given an amount of time in seconds, returns string
  987. * formatted nicely as weeks, days, hours etc as needed
  988. *
  989. * @uses MINSECS
  990. * @uses HOURSECS
  991. * @uses DAYSECS
  992. * @uses YEARSECS
  993. * @param int $totalsecs ?
  994. * @param array $str ?
  995. * @return string
  996. */
  997. function format_time($totalsecs, $str=NULL) {
  998. $totalsecs = abs($totalsecs);
  999. if (!$str) { // Create the str structure the slow way
  1000. $str->day = get_string('day');
  1001. $str->days = get_string('days');
  1002. $str->hour = get_string('hour');
  1003. $str->hours = get_string('hours');
  1004. $str->min = get_string('min');
  1005. $str->mins = get_string('mins');
  1006. $str->sec = get_string('sec');
  1007. $str->secs = get_string('secs');
  1008. $str->year = get_string('year');
  1009. $str->years = get_string('years');
  1010. }
  1011. $years = floor($totalsecs/YEARSECS);
  1012. $remainder = $totalsecs - ($years*YEARSECS);
  1013. $days = floor($remainder/DAYSECS);
  1014. $remainder = $totalsecs - ($days*DAYSECS);
  1015. $hours = floor($remainder/HOURSECS);
  1016. $remainder = $remainder - ($hours*HOURSECS);
  1017. $mins = floor($remainder/MINSECS);
  1018. $secs = $remainder - ($mins*MINSECS);
  1019. $ss = ($secs == 1) ? $str->sec : $str->secs;
  1020. $sm = ($mins == 1) ? $str->min : $str->mins;
  1021. $sh = ($hours == 1) ? $str->hour : $str->hours;
  1022. $sd = ($days == 1) ? $str->day : $str->days;
  1023. $sy = ($years == 1) ? $str->year : $str->years;
  1024. $oyears = '';
  1025. $odays = '';
  1026. $ohours = '';
  1027. $omins = '';
  1028. $osecs = '';
  1029. if ($years) $oyears = $years .' '. $sy;
  1030. if ($days) $odays = $days .' '. $sd;
  1031. if ($hours) $ohours = $hours .' '. $sh;
  1032. if ($mins) $omins = $mins .' '. $sm;
  1033. if ($secs) $osecs = $secs .' '. $ss;
  1034. if ($years) return trim($oyears .' '. $odays);
  1035. if ($days) return trim($odays .' '. $ohours);
  1036. if ($hours) return trim($ohours .' '. $omins);
  1037. if ($mins) return trim($omins .' '. $osecs);
  1038. if ($secs) return $osecs;
  1039. return get_string('now');
  1040. }
  1041. /**
  1042. * Returns a formatted string that represents a date in user time
  1043. * <b>WARNING: note that the format is for strftime(), not date().</b>
  1044. * Because of a bug in most Windows time libraries, we can't use
  1045. * the nicer %e, so we have to use %d which has leading zeroes.
  1046. * A lot of the fuss in the function is just getting rid of these leading
  1047. * zeroes as efficiently as possible.
  1048. *
  1049. * If parameter fixday = true (default), then take off leading
  1050. * zero from %d, else mantain it.
  1051. *
  1052. * @uses HOURSECS
  1053. * @param int $date timestamp in GMT
  1054. * @param string $format strftime format
  1055. * @param mixed $timezone by default, uses the user's time zone. if numeric and
  1056. * not 99 then daylight saving will not be added.
  1057. * @param bool $fixday If true (default) then the leading
  1058. * zero from %d is removed. If false then the leading zero is mantained.
  1059. * @return string
  1060. */
  1061. function userdate($date, $format='', $timezone=99, $fixday = true) {
  1062. global $CFG;
  1063. if (empty($format)) {
  1064. $format = get_string('strftimedaydatetime');
  1065. }
  1066. if (!empty($CFG->nofixday)) { // Config.php can force %d not to be fixed.
  1067. $fixday = false;
  1068. } else if ($fixday) {
  1069. $formatnoday = str_replace('%d', 'DD', $format);
  1070. $fixday = ($formatnoday != $format);
  1071. }
  1072. //add daylight saving offset for string timezones only, as we can't get dst for
  1073. //float values. if timezone is 99 (user default timezone), then try update dst.
  1074. if ((99 == $timezone) || !is_numeric($timezone)) {
  1075. $date += dst_offset_on($date, $timezone);
  1076. }
  1077. $timezone = get_user_timezone_offset($timezone);
  1078. if (abs($timezone) > 13) { /// Server time
  1079. if ($fixday) {
  1080. $datestring = strftime($formatnoday, $date);
  1081. $daystring = str_replace(' 0', '', strftime(' %d', $date));
  1082. $datestring = str_replace('DD', $daystring, $datestring);
  1083. } else {
  1084. $datestring = strftime($format, $date);
  1085. }
  1086. } else {
  1087. $date += (int)($timezone * 3600);
  1088. if ($fixday) {
  1089. $datestring = gmstrftime($formatnoday, $date);
  1090. $daystring = str_replace(' 0', '', gmstrftime(' %d', $date));
  1091. $datestring = str_replace('DD', $daystring, $datestring);
  1092. } else {
  1093. $datestring = gmstrftime($format, $date);
  1094. }
  1095. }
  1096. /// If we are running under Windows convert from windows encoding to UTF-8
  1097. /// (because it's impossible to specify UTF-8 to fetch locale info in Win32)
  1098. if ($CFG->ostype == 'WINDOWS') {
  1099. if ($localewincharset = get_string('localewincharset')) {
  1100. $textlib = textlib_get_instance();
  1101. $datestring = $textlib->convert($datestring, $localewincharset, 'utf-8');
  1102. }
  1103. }
  1104. return $datestring;
  1105. }
  1106. /**
  1107. * Given a $time timestamp in GMT (seconds since epoch),
  1108. * returns an array that represents the date in user time
  1109. *
  1110. * @uses HOURSECS
  1111. * @param int $time Timestamp in GMT
  1112. * @param mixed $timezone offset time with timezone, if float and not 99, then no
  1113. * dst offset is applyed
  1114. * @return array An array that represents the date in user time
  1115. * @todo Finish documenting this function
  1116. */
  1117. function usergetdate($time, $timezone=99) {
  1118. //save input timezone, required for dst offset check.
  1119. $passedtimezone = $timezone;
  1120. $timezone = get_user_timezone_offset($timezone);
  1121. if (abs($timezone) > 13) { // Server time
  1122. return getdate($time);
  1123. }
  1124. //add daylight saving offset for string timezones only, as we can't get dst for
  1125. //float values. if timezone is 99 (user default timezone), then try update dst.
  1126. if ($passedtimezone == 99 || !is_numeric($passedtimezone)) {
  1127. $time += dst_offset_on($time, $passedtimezone);
  1128. }
  1129. $time += intval((float)$timezone * HOURSECS);
  1130. $datestring = gmstrftime('%B_%A_%j_%Y_%m_%w_%d_%H_%M_%S', $time);
  1131. //be careful to ensure the returned array matches that produced by getdate() above
  1132. list(
  1133. $getdate['month'],
  1134. $getdate['weekday'],
  1135. $getdate['yday'],
  1136. $getdate['year'],
  1137. $getdate['mon'],
  1138. $getdate['wday'],
  1139. $getdate['mday'],
  1140. $getdate['hours'],
  1141. $getdate['minutes'],
  1142. $getdate['seconds']
  1143. ) = explode('_', $datestring);
  1144. return $getdate;
  1145. }
  1146. /**
  1147. * Given a GMT timestamp (seconds since epoch), offsets it by
  1148. * the timezone. eg 3pm in India is 3pm GMT - 7 * 3600 seconds
  1149. *
  1150. * @uses HOURSECS
  1151. * @param int $date Timestamp in GMT
  1152. * @param float $timezone
  1153. * @return int
  1154. */
  1155. function usertime($date, $timezone=99) {
  1156. $timezone = get_user_timezone_offset($timezone);
  1157. if (abs($timezone) > 13) {
  1158. return $date;
  1159. }
  1160. return $date - (int)($timezone * HOURSECS);
  1161. }
  1162. /**
  1163. * Given a time, return the GMT timestamp of the most recent midnight
  1164. * for the current user.
  1165. *
  1166. * @param int $date Timestamp in GMT
  1167. * @param float $timezone ?
  1168. * @return ?
  1169. */
  1170. function usergetmidnight($date, $timezone=99) {
  1171. $userdate = usergetdate($date, $timezone);
  1172. // Time of midnight of this user's day, in GMT
  1173. return make_timestamp($userdate['year'], $userdate['mon'], $userdate['mday'], 0, 0, 0, $timezone);
  1174. }
  1175. /**
  1176. * Returns a string that prints the user's timezone
  1177. *
  1178. * @param float $timezone The user's timezone
  1179. * @return string
  1180. */
  1181. function usertimezone($timezone=99) {
  1182. $tz = get_user_timezone($timezone);
  1183. if (!is_float($tz)) {
  1184. return $tz;
  1185. }
  1186. if(abs($tz) > 13) { // Server time
  1187. return get_string('serverlocaltime');
  1188. }
  1189. if($tz == intval($tz)) {
  1190. // Don't show .0 for whole hours
  1191. $tz = intval($tz);
  1192. }
  1193. if($tz == 0) {
  1194. return 'UTC';
  1195. }
  1196. else if($tz > 0) {
  1197. return 'UTC+'.$tz;
  1198. }
  1199. else {
  1200. return 'UTC'.$tz;
  1201. }
  1202. }
  1203. /**
  1204. * Returns a float which represents the user's timezone difference from GMT in hours
  1205. * Checks various settings and picks the most dominant of those which have a value
  1206. *
  1207. * @uses $CFG
  1208. * @uses $USER
  1209. * @param float $tz If this value is provided and not equal to 99, it will be returned as is and no other settings will be checked
  1210. * @return int
  1211. */
  1212. function get_user_timezone_offset($tz = 99) {
  1213. global $USER, $CFG;
  1214. $tz = get_user_timezone($tz);
  1215. if (is_float($tz)) {
  1216. return $tz;
  1217. } else {
  1218. $tzrecord = get_timezone_record($tz);
  1219. if (empty($tzrecord)) {
  1220. return 99.0;
  1221. }
  1222. return (float)$tzrecord->gmtoff / HOURMINS;
  1223. }
  1224. }
  1225. /**
  1226. * Returns an int which represents the systems's timezone difference from GMT in seconds
  1227. * @param mixed $tz timezone
  1228. * @return int if found, false is timezone 99 or error
  1229. */
  1230. function get_timezone_offset($tz) {
  1231. global $CFG;
  1232. if ($tz == 99) {
  1233. return false;
  1234. }
  1235. if (is_numeric($tz)) {
  1236. return intval($tz * 60*60);
  1237. }
  1238. if (!$tzrecord = get_timezone_record($tz)) {
  1239. return false;
  1240. }
  1241. return intval($tzrecord->gmtoff * 60);
  1242. }
  1243. /**
  1244. * Returns a float or a string which denotes the user's timezone
  1245. * A float value means that a simple offset from GMT is used, while a string (it will be the name of a timezone in the database)
  1246. * means that for this timezone there are also DST rules to be taken into account
  1247. * Checks various settings and picks the most dominant of those which have a value
  1248. *
  1249. * @uses $USER
  1250. * @uses $CFG
  1251. * @param mixed $tz If this value is provided and not equal to 99, it will be returned as is and no other settings will be checked
  1252. * @return mixed
  1253. */
  1254. function get_user_timezone($tz = 99) {
  1255. global $USER, $CFG;
  1256. $timezones = array(
  1257. $tz,
  1258. isset($CFG->forcetimezone) ? $CFG->forcetimezone : 99,
  1259. isset($USER->timezone) ? $USER->timezone : 99,
  1260. isset($CFG->timezone) ? $CFG->timezone : 99,
  1261. );
  1262. $tz = 99;
  1263. while(($tz == '' || $tz == 99 || $tz == NULL) && $next = each($timezones)) {
  1264. $tz = $next['value'];
  1265. }
  1266. return is_numeric($tz) ? (float) $tz : $tz;
  1267. }
  1268. /**
  1269. * ?
  1270. *
  1271. * @uses $CFG
  1272. * @uses $db
  1273. * @param string $timezonename ?
  1274. * @return object
  1275. */
  1276. function get_timezone_record($timezonename) {
  1277. global $CFG, $db;
  1278. static $cache = NULL;
  1279. if ($cache === NULL) {
  1280. $cache = array();
  1281. }
  1282. if (isset($cache[$timezonename])) {
  1283. return $cache[$timezonename];
  1284. }
  1285. return $cache[$timezonename] = get_record_sql('SELECT * FROM '.$CFG->prefix.'timezone
  1286. WHERE name = '.$db->qstr($timezonename).' ORDER BY year DESC', true);
  1287. }
  1288. /**
  1289. * ?
  1290. *
  1291. * @uses $CFG
  1292. * @uses $USER
  1293. * @param ? $fromyear ?
  1294. * @param ? $to_year ?
  1295. * @return bool
  1296. */
  1297. function calculate_user_dst_table($from_year = NULL, $to_year = NULL, $strtimezone = NULL) {
  1298. global $CFG, $SESSION;
  1299. $usertz = get_user_timezone($strtimezone);
  1300. if (is_float($usertz)) {
  1301. // Trivial timezone, no DST
  1302. return false;
  1303. }
  1304. if (!empty($SESSION->dst_offsettz) && $SESSION->dst_offsettz != $usertz) {
  1305. // We have precalculated values, but the user's effective TZ has changed in the meantime, so reset
  1306. unset($SESSION->dst_offsets);
  1307. unset($SESSION->dst_range);
  1308. }
  1309. if (!empty($SESSION->dst_offsets) && empty($from_year) && empty($to_year)) {
  1310. // Repeat calls which do not request specific year ranges stop here, we have already calculated the table
  1311. // This will be the return path most of the time, pretty light compu…

Large files files are truncated, but you can click here to view the full file