Merge branch 'MDL-25910_20_wip_mysqlsocket' of git://github.com/skodak/moodle
[moodle.git] / lib / environmentlib.php
1 <?php
3 // This file is part of Moodle - http://moodle.org/
4 //
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
18 /**
19  * This library includes all the necessary stuff to execute some standard
20  * tests of required versions and libraries to run Moodle. It can be
21  * used from the admin interface, and both at install and upgrade.
22  *
23  * All the info is stored in the admin/environment.xml file,
24  * supporting to have an updated version in dataroot/environment
25  *
26  * @copyright  (C) 2001-3001 Eloy Lafuente (stronk7) {@link http://contiento.com}
27  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
28  * @package    core
29  * @subpackage admin
30  */
32 defined('MOODLE_INTERNAL') || die();
34 /// Add required files
35 /**
36  * Include the necessary
37  */
38     require_once($CFG->libdir.'/xmlize.php');
40 /// Define a bunch of XML processing errors
41     /** XML Processing Error */
42     define('NO_ERROR',                           0);
43     /** XML Processing Error */
44     define('NO_VERSION_DATA_FOUND',              1);
45     /** XML Processing Error */
46     define('NO_DATABASE_SECTION_FOUND',          2);
47     /** XML Processing Error */
48     define('NO_DATABASE_VENDORS_FOUND',          3);
49     /** XML Processing Error */
50     define('NO_DATABASE_VENDOR_MYSQL_FOUND',     4);
51     /** XML Processing Error */
52     define('NO_DATABASE_VENDOR_POSTGRES_FOUND',  5);
53     /** XML Processing Error */
54     define('NO_PHP_SECTION_FOUND',               6);
55     /** XML Processing Error */
56     define('NO_PHP_VERSION_FOUND',               7);
57     /** XML Processing Error */
58     define('NO_PHP_EXTENSIONS_SECTION_FOUND',    8);
59     /** XML Processing Error */
60     define('NO_PHP_EXTENSIONS_NAME_FOUND',       9);
61     /** XML Processing Error */
62     define('NO_DATABASE_VENDOR_VERSION_FOUND',  10);
63     /** XML Processing Error */
64     define('NO_UNICODE_SECTION_FOUND',          11);
65     /** XML Processing Error */
66     define('NO_CUSTOM_CHECK_FOUND',             12);
67     /** XML Processing Error */
68     define('CUSTOM_CHECK_FILE_MISSING',         13);
69     /** XML Processing Error */
70     define('CUSTOM_CHECK_FUNCTION_MISSING',     14);
71     /** XML Processing Error */
72     define('NO_PHP_SETTINGS_NAME_FOUND',        15);
74 /// Define algorithm used to select the xml file
75     /** To select the newer file available to perform checks */
76     define('ENV_SELECT_NEWER',                   0);
77     /** To enforce the use of the file under dataroot */
78     define('ENV_SELECT_DATAROOT',                1);
79     /** To enforce the use of the file under admin (release) */
80     define('ENV_SELECT_RELEASE',                 2);
82 /**
83  * This function will perform the whole check, returning
84  * true or false as final result. Also, he full array of
85  * environment_result will be returned in the parameter list.
86  * The function looks for the best version to compare and
87  * everything. This is the only function that should be called
88  * ever from the rest of Moodle.
89  *
90  * @staticvar bool $result
91  * @staticvar array $env_results
92  * @staticvar bool $cache_exists
93  * @param string $version version to check.
94  * @param array $environment_results results array of results checked.
95  * @param boolean $print_table true/false, whether to print the table or just return results array
96  * @param int $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use. Default ENV_SELECT_NEWER (BC)
97  * @return boolean true/false, depending of results
98  */
99 function check_moodle_environment($version, &$environment_results, $print_table=true, $env_select=ENV_SELECT_NEWER) {
101     $status = true;
103 /// This are cached per request
104     static $result = true;
105     static $env_results;
106     static $cache_exists = false;
108 /// if we have results cached, use them
109     if ($cache_exists) {
110         $environment_results = $env_results;
111 /// No cache exists, calculate everything
112     } else {
113     /// Get the more recent version before the requested
114         if (!$version = get_latest_version_available($version, $env_select)) {
115             $status = false;
116         }
118     /// Perform all the checks
119         if (!($environment_results = environment_check($version, $env_select)) && $status) {
120             $status = false;
121         }
123     /// Iterate over all the results looking for some error in required items
124     /// or some error_code
125         if ($status) {
126             foreach ($environment_results as $environment_result) {
127                 if (!$environment_result->getStatus() && $environment_result->getLevel() == 'required'
128                   && !$environment_result->getBypassStr()) {
129                     $result = false; // required item that is not bypased
130                 } else if ($environment_result->getStatus() && $environment_result->getLevel() == 'required'
131                   && $environment_result->getRestrictStr()) {
132                     $result = false; // required item that is restricted
133                 } else if ($environment_result->getErrorCode()) {
134                     $result = false;
135                 }
136             }
137         }
138     /// Going to end, we store environment_results to cache
139         $env_results = $environment_results;
140         $cache_exists = true;
141     } ///End of cache block
143 /// If we have decided to print all the information, just do it
144     if ($print_table) {
145         print_moodle_environment($result && $status, $environment_results);
146     }
147     return ($result && $status);
150 /**
151  * This function will print one beautiful table with all the environmental
152  * configuration and how it suits Moodle needs.
153  *
154  * @global object
155  * @param boolean $result final result of the check (true/false)
156  * @param array $environment_results array of results gathered
157  * @return void
158  */
159 function print_moodle_environment($result, $environment_results) {
160     global $CFG, $OUTPUT;
162 /// Get some strings
163     $strname = get_string('name');
164     $strinfo = get_string('info');
165     $strreport = get_string('report');
166     $strstatus = get_string('status');
167     $strok = get_string('ok');
168     $strerror = get_string('error');
169     $strcheck = get_string('check');
170     $strbypassed = get_string('bypassed');
171     $strrestricted = get_string('restricted');
172     $strenvironmenterrortodo = get_string('environmenterrortodo', 'admin');
173 /// Table headers
174     $servertable = new html_table();//table for server checks
175     $servertable->head  = array ($strname, $strinfo, $strreport, $strstatus);
176     $servertable->align = array ('center', 'center', 'left', 'center');
177     $servertable->wrap  = array ('nowrap', '', '', 'nowrap');
178     $servertable->size  = array ('10', 10, '100%', '10');
179     $servertable->attributes['class'] = 'environmenttable generaltable';
181     $serverdata = array('ok'=>array(), 'warn'=>array(), 'error'=>array());
183     $othertable = new html_table();//table for custom checks
184     $othertable->head  = array ($strinfo, $strreport, $strstatus);
185     $othertable->align = array ('center', 'left', 'center');
186     $othertable->wrap  = array ('', '', 'nowrap');
187     $othertable->size  = array (10, '100%', '10');
188     $othertable->attributes['class'] = 'environmenttable generaltable';
190     $otherdata = array('ok'=>array(), 'warn'=>array(), 'error'=>array());
192 /// Iterate over each environment_result
193     $continue = true;
194     foreach ($environment_results as $environment_result) {
195         $errorline   = false;
196         $warningline = false;
197         $stringtouse = '';
198         if ($continue) {
199             $type = $environment_result->getPart();
200             $info = $environment_result->getInfo();
201             $status = $environment_result->getStatus();
202             $error_code = $environment_result->getErrorCode();
203         /// Process Report field
204             $rec = new stdClass();
205         /// Something has gone wrong at parsing time
206             if ($error_code) {
207                 $stringtouse = 'environmentxmlerror';
208                 $rec->error_code = $error_code;
209                 $status = $strerror;
210                 $errorline = true;
211                 $continue = false;
212             }
214             if ($continue) {
215             /// We are comparing versions
216                 if ($rec->needed = $environment_result->getNeededVersion()) {
217                     $rec->current = $environment_result->getCurrentVersion();
218                     if ($environment_result->getLevel() == 'required') {
219                         $stringtouse = 'environmentrequireversion';
220                     } else {
221                         $stringtouse = 'environmentrecommendversion';
222                     }
223             /// We are checking installed & enabled things
224                 } else if ($environment_result->getPart() == 'custom_check') {
225                     if ($environment_result->getLevel() == 'required') {
226                         $stringtouse = 'environmentrequirecustomcheck';
227                     } else {
228                         $stringtouse = 'environmentrecommendcustomcheck';
229                     }
230                 } else if ($environment_result->getPart() == 'php_setting') {
231                     if ($status) {
232                         $stringtouse = 'environmentsettingok';
233                     } else if ($environment_result->getLevel() == 'required') {
234                         $stringtouse = 'environmentmustfixsetting';
235                     } else {
236                         $stringtouse = 'environmentshouldfixsetting';
237                     }
238                 } else {
239                     if ($environment_result->getLevel() == 'required') {
240                         $stringtouse = 'environmentrequireinstall';
241                     } else {
242                         $stringtouse = 'environmentrecommendinstall';
243                     }
244                 }
245             /// Calculate the status value
246                 if ($environment_result->getBypassStr() != '') {            //Handle bypassed result (warning)
247                     $status = $strbypassed;
248                     $warningline = true;
249                 } else if ($environment_result->getRestrictStr() != '') {   //Handle restricted result (error)
250                     $status = $strrestricted;
251                     $errorline = true;
252                 } else {
253                     if ($status) {                                          //Handle ok result (ok)
254                         $status = $strok;
255                     } else {
256                         if ($environment_result->getLevel() == 'optional') {//Handle check result (warning)
257                             $status = $strcheck;
258                             $warningline = true;
259                         } else {                                            //Handle error result (error)
260                             $status = $strcheck;
261                             $errorline = true;
262                         }
263                     }
264                 }
265             }
267         /// Build the text
268             $linkparts = array();
269             $linkparts[] = 'admin/environment';
270             $linkparts[] = $type;
271             if (!empty($info)){
272                $linkparts[] = $info;
273             }
274             if (empty($CFG->docroot)) {
275                 $report = get_string($stringtouse, 'admin', $rec);
276             } else {
277                 $report = $OUTPUT->doc_link(join($linkparts, '/'), get_string($stringtouse, 'admin', $rec));
278             }
281         /// Format error or warning line
282             if ($errorline || $warningline) {
283                 $messagetype = $errorline? 'error':'warn';
284             } else {
285                 $messagetype = 'ok';
286             }
287             $status = '<span class="'.$messagetype.'">'.$status.'</span>';
288         /// Here we'll store all the feedback found
289             $feedbacktext = '';
290             ///Append  the feedback if there is some
291             $feedbacktext .= $environment_result->strToReport($environment_result->getFeedbackStr(), $messagetype);
292         ///Append the bypass if there is some
293             $feedbacktext .= $environment_result->strToReport($environment_result->getBypassStr(), 'warn');
294         ///Append the restrict if there is some
295             $feedbacktext .= $environment_result->strToReport($environment_result->getRestrictStr(), 'error');
297             $report .= $feedbacktext;
298         /// Add the row to the table
300             if ($environment_result->getPart() == 'custom_check'){
301                 $otherdata[$messagetype][] = array ($info, $report, $status);
302             } else {
303                 $serverdata[$messagetype][] = array ($type, $info, $report, $status);
304             }
305         }
306     }
307     //put errors first in
308     $servertable->data = array_merge($serverdata['error'], $serverdata['warn'], $serverdata['ok']);
309     $othertable->data = array_merge($otherdata['error'], $otherdata['warn'], $otherdata['ok']);
311 /// Print table
312     echo $OUTPUT->heading(get_string('serverchecks', 'admin'));
313     echo html_writer::table($servertable);
314     if (count($othertable->data)){
315         echo $OUTPUT->heading(get_string('customcheck', 'admin'));
316         echo html_writer::table($othertable);
317     }
319 /// Finally, if any error has happened, print the summary box
320     if (!$result) {
321         echo $OUTPUT->box($strenvironmenterrortodo, 'environmentbox errorbox');
322     }
326 /**
327  * Returns array of critical errors in plain text format
328  * @param array $environment_results array of results gathered
329  * @return array errors
330  */
331 function environment_get_errors($environment_results) {
332     global $CFG;
333     $errors = array();
335     // Iterate over each environment_result
336     foreach ($environment_results as $environment_result) {
337         $type = $environment_result->getPart();
338         $info = $environment_result->getInfo();
339         $status = $environment_result->getStatus();
340         $error_code = $environment_result->getErrorCode();
342         $a = new stdClass();
343         if ($error_code) {
344             $a->error_code = $error_code;
345             $errors[] = array($info, get_string('environmentxmlerror', 'admin', $a));
346             return $errors;
347         }
349         /// Calculate the status value
350         if ($environment_result->getBypassStr() != '') {
351             // not interesting
352             continue;
353         } else if ($environment_result->getRestrictStr() != '') {
354             // error
355         } else {
356             if ($status) {
357                 // ok
358                 continue;
359             } else {
360                 if ($environment_result->getLevel() == 'optional') {
361                     // just a warning
362                     continue;
363                 } else {
364                     // error
365                 }
366             }
367         }
369         // We are comparing versions
370         $rec = new stdClass();
371         if ($rec->needed = $environment_result->getNeededVersion()) {
372             $rec->current = $environment_result->getCurrentVersion();
373             if ($environment_result->getLevel() == 'required') {
374                 $stringtouse = 'environmentrequireversion';
375             } else {
376                 $stringtouse = 'environmentrecommendversion';
377             }
378         // We are checking installed & enabled things
379         } else if ($environment_result->getPart() == 'custom_check') {
380             if ($environment_result->getLevel() == 'required') {
381                 $stringtouse = 'environmentrequirecustomcheck';
382             } else {
383                 $stringtouse = 'environmentrecommendcustomcheck';
384             }
385         } else if ($environment_result->getPart() == 'php_setting') {
386             if ($status) {
387                 $stringtouse = 'environmentsettingok';
388             } else if ($environment_result->getLevel() == 'required') {
389                 $stringtouse = 'environmentmustfixsetting';
390             } else {
391                 $stringtouse = 'environmentshouldfixsetting';
392             }
393         } else {
394             if ($environment_result->getLevel() == 'required') {
395                 $stringtouse = 'environmentrequireinstall';
396             } else {
397                 $stringtouse = 'environmentrecommendinstall';
398             }
399         }
400         $report = get_string($stringtouse, 'admin', $rec);
402         // Here we'll store all the feedback found
403         $feedbacktext = '';
404         // Append  the feedback if there is some
405         $feedbacktext .= $environment_result->strToReport($environment_result->getFeedbackStr(), 'error');
406         // Append the restrict if there is some
407         $feedbacktext .= $environment_result->strToReport($environment_result->getRestrictStr(), 'error');
409         $report .= html_to_text($feedbacktext);
411         if ($environment_result->getPart() == 'custom_check'){
412             $errors[] = array($info, $report);
413         } else {
414             $errors[] = array(($info !== '' ? "$type $info" : $type), $report);
415         }
416     }
418     return $errors;
422 /**
423  * This function will normalize any version to just a serie of numbers
424  * separated by dots. Everything else will be removed.
425  *
426  * @param string $version the original version
427  * @return string the normalized version
428  */
429 function normalize_version($version) {
431 /// 1.9 Beta 2 should be read 1.9 on enviromental checks, not 1.9.2
432 /// we can discard everything after the first space
433     $version = trim($version);
434     $versionarr = explode(" ",$version);
435     if (!empty($versionarr)) {
436         $version = $versionarr[0];
437     }
438 /// Replace everything but numbers and dots by dots
439     $version = preg_replace('/[^\.\d]/', '.', $version);
440 /// Combine multiple dots in one
441     $version = preg_replace('/(\.{2,})/', '.', $version);
442 /// Trim possible leading and trailing dots
443     $version = trim($version, '.');
445     return $version;
449 /**
450  * This function will load the environment.xml file and xmlize it
451  *
452  * @global object
453  * @staticvar mixed $data
454  * @uses ENV_SELECT_NEWER
455  * @uses ENV_SELECT_DATAROOT
456  * @uses ENV_SELECT_RELEASE
457  * @param int $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use. Default ENV_SELECT_NEWER (BC)
458  * @return mixed the xmlized structure or false on error
459  */
460 function load_environment_xml($env_select=ENV_SELECT_NEWER) {
462     global $CFG;
464     static $data; //Only load and xmlize once by request
466     if (!empty($data)) {
467         return $data;
468     }
470 /// First of all, take a look inside $CFG->dataroot/environment/environment.xml
471     $file = $CFG->dataroot.'/environment/environment.xml';
472     $internalfile = $CFG->dirroot.'/'.$CFG->admin.'/environment.xml';
473     switch ($env_select) {
474         case ENV_SELECT_NEWER:
475             if (!is_file($file) || !is_readable($file) || filemtime($file) < filemtime($internalfile) ||
476                 !$contents = file_get_contents($file)) {
477             /// Fallback to fixed $CFG->admin/environment.xml
478                 if (!is_file($internalfile) || !is_readable($internalfile) || !$contents = file_get_contents($internalfile)) {
479                     return false;
480                 }
481             }
482             break;
483         case ENV_SELECT_DATAROOT:
484             if (!is_file($file) || !is_readable($file) || !$contents = file_get_contents($file)) {
485                 return false;
486             }
487             break;
488         case ENV_SELECT_RELEASE:
489             if (!is_file($internalfile) || !is_readable($internalfile) || !$contents = file_get_contents($internalfile)) {
490                 return false;
491             }
492             break;
493     }
494 /// XML the whole file
495     $data = xmlize($contents);
497     return $data;
501 /**
502  * This function will return the list of Moodle versions available
503  *
504  * @staticvar array $versions
505  * @return mixed array of versions. False on error.
506  */
507 function get_list_of_environment_versions ($contents) {
509     static $versions = array();
511     if (!empty($versions)) {
512         return $versions;
513     }
515     if (isset($contents['COMPATIBILITY_MATRIX']['#']['MOODLE'])) {
516         foreach ($contents['COMPATIBILITY_MATRIX']['#']['MOODLE'] as $version) {
517             $versions[] = $version['@']['version'];
518         }
519     }
521     return $versions;
525 /**
526  * This function will return the most recent version in the environment.xml
527  * file previous or equal to the version requested
528  *
529  * @param string $version top version from which we start to look backwards
530  * @param int $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use.
531  * @return string|bool string more recent version or false if not found
532  */
533 function get_latest_version_available ($version, $env_select) {
535 /// Normalize the version requested
536     $version = normalize_version($version);
538 /// Load xml file
539     if (!$contents = load_environment_xml($env_select)) {
540         return false;
541     }
543 /// Detect available versions
544     if (!$versions = get_list_of_environment_versions($contents)) {
545         return false;
546     }
547 /// First we look for exact version
548     if (in_array($version, $versions)) {
549         return $version;
550     } else {
551         $found_version = false;
552     /// Not exact match, so we are going to iterate over the list searching
553     /// for the latest version before the requested one
554         foreach ($versions as $arrversion) {
555             if (version_compare($arrversion, $version, '<')) {
556                 $found_version = $arrversion;
557             }
558         }
559     }
561     return $found_version;
565 /**
566  * This function will return the xmlized data belonging to one Moodle version
567  *
568  * @param string $version top version from which we start to look backwards
569  * @param int $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use.
570  * @return mixed the xmlized structure or false on error
571  */
572 function get_environment_for_version($version, $env_select) {
574 /// Normalize the version requested
575     $version = normalize_version($version);
577 /// Load xml file
578     if (!$contents = load_environment_xml($env_select)) {
579         return false;
580     }
582 /// Detect available versions
583     if (!$versions = get_list_of_environment_versions($contents)) {
584         return false;
585     }
587 /// If the version requested is available
588     if (!in_array($version, $versions)) {
589         return false;
590     }
592 /// We now we have it. Extract from full contents.
593     $fl_arr = array_flip($versions);
595     return $contents['COMPATIBILITY_MATRIX']['#']['MOODLE'][$fl_arr[$version]];
599 /**
600  * This function will check for everything (DB, PHP and PHP extensions for now)
601  * returning an array of environment_result objects.
602  *
603  * @global object
604  * @param string $version xml version we are going to use to test this server
605  * @param int $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use.
606  * @return array array of results encapsulated in one environment_result object
607  */
608 function environment_check($version, $env_select) {
609     global $CFG;
611 /// Normalize the version requested
612     $version = normalize_version($version);
614     $results = array(); //To store all the results
616 /// Only run the moodle versions checker on upgrade, not on install
617     if (!empty($CFG->version)) {
618         $results[] = environment_check_moodle($version, $env_select);
619     }
620     $results[] = environment_check_unicode($version, $env_select);
621     $results[] = environment_check_database($version, $env_select);
622     $results[] = environment_check_php($version, $env_select);
624     $phpext_results = environment_check_php_extensions($version, $env_select);
625     $results = array_merge($results, $phpext_results);
627     $phpsetting_results = environment_check_php_settings($version, $env_select);
628     $results = array_merge($results, $phpsetting_results);
630     $custom_results = environment_custom_checks($version, $env_select);
631     $results = array_merge($results, $custom_results);
633     return $results;
637 /**
638  * This function will check if php extensions requirements are satisfied
639  *
640  * @uses NO_VERSION_DATA_FOUND
641  * @uses NO_PHP_EXTENSIONS_SECTION_FOUND
642  * @uses NO_PHP_EXTENSIONS_NAME_FOUND
643  * @param string $version xml version we are going to use to test this server
644  * @param int $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use.
645  * @return array array of results encapsulated in one environment_result object
646  */
647 function environment_check_php_extensions($version, $env_select) {
649     $results = array();
651 /// Get the enviroment version we need
652     if (!$data = get_environment_for_version($version, $env_select)) {
653     /// Error. No version data found
654         $result = new environment_results('php_extension');
655         $result->setStatus(false);
656         $result->setErrorCode(NO_VERSION_DATA_FOUND);
657         return array($result);
658     }
660 /// Extract the php_extension part
661     if (!isset($data['#']['PHP_EXTENSIONS']['0']['#']['PHP_EXTENSION'])) {
662     /// Error. No PHP section found
663         $result = new environment_results('php_extension');
664         $result->setStatus(false);
665         $result->setErrorCode(NO_PHP_EXTENSIONS_SECTION_FOUND);
666         return array($result);
667     }
668 /// Iterate over extensions checking them and creating the needed environment_results
669     foreach($data['#']['PHP_EXTENSIONS']['0']['#']['PHP_EXTENSION'] as $extension) {
670         $result = new environment_results('php_extension');
671     /// Check for level
672         $level = get_level($extension);
673     /// Check for extension name
674         if (!isset($extension['@']['name'])) {
675             $result->setStatus(false);
676             $result->setErrorCode(NO_PHP_EXTENSIONS_NAME_FOUND);
677         } else {
678             $extension_name = $extension['@']['name'];
679         /// The name exists. Just check if it's an installed extension
680             if (!extension_loaded($extension_name)) {
681                 $result->setStatus(false);
682             } else {
683                 $result->setStatus(true);
684             }
685             $result->setLevel($level);
686             $result->setInfo($extension_name);
687         }
689     /// Do any actions defined in the XML file.
690         process_environment_result($extension, $result);
692     /// Add the result to the array of results
693         $results[] = $result;
694     }
697     return $results;
700 /**
701  * This function will check if php extensions requirements are satisfied
702  *
703  * @uses NO_VERSION_DATA_FOUND
704  * @uses NO_PHP_SETTINGS_NAME_FOUND
705  * @param string $version xml version we are going to use to test this server
706  * @param int $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use.
707  * @return array array of results encapsulated in one environment_result object
708  */
709 function environment_check_php_settings($version, $env_select) {
711     $results = array();
713 /// Get the enviroment version we need
714     if (!$data = get_environment_for_version($version, $env_select)) {
715     /// Error. No version data found
716         $result = new environment_results('php_setting');
717         $result->setStatus(false);
718         $result->setErrorCode(NO_VERSION_DATA_FOUND);
719         return $result;
720     }
722 /// Extract the php_setting part
723     if (!isset($data['#']['PHP_SETTINGS']['0']['#']['PHP_SETTING'])) {
724     /// No PHP section found - ignore
725         return $results;
726     }
727 /// Iterate over settings checking them and creating the needed environment_results
728     foreach($data['#']['PHP_SETTINGS']['0']['#']['PHP_SETTING'] as $setting) {
729         $result = new environment_results('php_setting');
730     /// Check for level
731         $level = get_level($setting);
732         $result->setLevel($level);
733     /// Check for extension name
734         if (!isset($setting['@']['name'])) {
735             $result->setStatus(false);
736             $result->setErrorCode(NO_PHP_SETTINGS_NAME_FOUND);
737         } else {
738             $setting_name  = $setting['@']['name'];
739             $setting_value = $setting['@']['value'];
740             $result->setInfo($setting_name);
742             if ($setting_name == 'memory_limit') {
743                 $current = ini_get('memory_limit');
744                 if ($current == -1) {
745                     $result->setStatus(true);
746                 } else {
747                     $current  = get_real_size($current);
748                     $minlimit = get_real_size($setting_value);
749                     if ($current < $minlimit) {
750                         @ini_set('memory_limit', $setting_value);
751                         $current = ini_get('memory_limit');
752                         $current = get_real_size($current);
753                     }
754                     $result->setStatus($current >= $minlimit);
755                 }
757             } else {
758                 $current = ini_get_bool($setting_name);
759             /// The name exists. Just check if it's an installed extension
760                 if ($current == $setting_value) {
761                     $result->setStatus(true);
762                 } else {
763                     $result->setStatus(false);
764                 }
765             }
766         }
768     /// Do any actions defined in the XML file.
769         process_environment_result($setting, $result);
771     /// Add the result to the array of results
772         $results[] = $result;
773     }
776     return $results;
779 /**
780  * This function will do the custom checks.
781  *
782  * @global object
783  * @uses CUSTOM_CHECK_FUNCTION_MISSING
784  * @uses CUSTOM_CHECK_FILE_MISSING
785  * @uses NO_CUSTOM_CHECK_FOUND
786  * @param string $version xml version we are going to use to test this server.
787  * @param int $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use.
788  * @return array array of results encapsulated in environment_result objects.
789  */
790 function environment_custom_checks($version, $env_select) {
791     global $CFG;
793     $results = array();
795 /// Get current Moodle version (release) for later compare
796     $release = isset($CFG->release) ? $CFG->release : $version; /// In case $CFG fails (at install) use $version
797     $current_version = normalize_version($release);
799 /// Get the enviroment version we need
800     if (!$data = get_environment_for_version($version, $env_select)) {
801     /// Error. No version data found - but this will already have been reported.
802         return $results;
803     }
805 /// Extract the CUSTOM_CHECKS part
806     if (!isset($data['#']['CUSTOM_CHECKS']['0']['#']['CUSTOM_CHECK'])) {
807     /// No custom checks found - not a problem
808         return $results;
809     }
811 /// Iterate over extensions checking them and creating the needed environment_results
812     foreach($data['#']['CUSTOM_CHECKS']['0']['#']['CUSTOM_CHECK'] as $check) {
813         $result = new environment_results('custom_check');
815     /// Check for level
816         $level = get_level($check);
818     /// Check for extension name
819         if (isset($check['@']['file']) && isset($check['@']['function'])) {
820             $file = $CFG->dirroot . '/' . $check['@']['file'];
821             $function = $check['@']['function'];
822             if (is_readable($file)) {
823                 include_once($file);
824                 if (function_exists($function)) {
825                     $result->setLevel($level);
826                     $result->setInfo($function);
827                     $result = $function($result);
828                 } else {
829                 /// Only show error for current version (where function MUST exist)
830                 /// else, we are performing custom checks against future versiosn
831                 /// and function MAY not exist, so it doesn't cause error, just skip
832                 /// custom check by returning null. MDL-15939
833                     if (version_compare($current_version, $version, '>=')) {
834                         $result->setStatus(false);
835                         $result->setInfo($function);
836                         $result->setErrorCode(CUSTOM_CHECK_FUNCTION_MISSING);
837                     } else {
838                         $result = null;
839                     }
840                 }
841             } else {
842             /// Only show error for current version (where function MUST exist)
843             /// else, we are performing custom checks against future versiosn
844             /// and function MAY not exist, so it doesn't cause error, just skip
845             /// custom check by returning null. MDL-15939
846                 if (version_compare($current_version, $version, '>=')) {
847                     $result->setStatus(false);
848                     $result->setInfo($function);
849                     $result->setErrorCode(CUSTOM_CHECK_FILE_MISSING);
850                 } else {
851                     $result = null;
852                 }
853             }
854         } else {
855             $result->setStatus(false);
856             $result->setErrorCode(NO_CUSTOM_CHECK_FOUND);
857         }
859         if (!is_null($result)) {
860         /// Do any actions defined in the XML file.
861             process_environment_result($check, $result);
863         /// Add the result to the array of results
864             $results[] = $result;
865         }
866     }
868     return $results;
871 /**
872  * This function will check if Moodle requirements are satisfied
873  *
874  * @uses NO_VERSION_DATA_FOUND
875  * @param string $version xml version we are going to use to test this server
876  * @param int $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use.
877  * @return object results encapsulated in one environment_result object
878  */
879 function environment_check_moodle($version, $env_select) {
881     $result = new environment_results('moodle');
883 /// Get the enviroment version we need
884     if (!$data = get_environment_for_version($version, $env_select)) {
885     /// Error. No version data found
886         $result->setStatus(false);
887         $result->setErrorCode(NO_VERSION_DATA_FOUND);
888         return $result;
889     }
891 /// Extract the moodle part
892     if (!isset($data['@']['requires'])) {
893         $needed_version = '1.0'; /// Default to 1.0 if no moodle requires is found
894     } else {
895     /// Extract required moodle version
896         $needed_version = $data['@']['requires'];
897     }
899 /// Now search the version we are using
900     $current_version = normalize_version(get_config('', 'release'));
902 /// And finally compare them, saving results
903     if (version_compare($current_version, $needed_version, '>=')) {
904         $result->setStatus(true);
905     } else {
906         $result->setStatus(false);
907     }
908     $result->setLevel('required');
909     $result->setCurrentVersion($current_version);
910     $result->setNeededVersion($needed_version);
912     return $result;
915 /**
916  * This function will check if php requirements are satisfied
917  *
918  * @uses NO_VERSION_DATA_FOUND
919  * @uses NO_PHP_SECTION_FOUND
920  * @uses NO_PHP_VERSION_FOUND
921  * @param string $version xml version we are going to use to test this server
922  * @param int $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use.
923  * @return object results encapsulated in one environment_result object
924  */
925 function environment_check_php($version, $env_select) {
927     $result = new environment_results('php');
929 /// Get the enviroment version we need
930     if (!$data = get_environment_for_version($version, $env_select)) {
931     /// Error. No version data found
932         $result->setStatus(false);
933         $result->setErrorCode(NO_VERSION_DATA_FOUND);
934         return $result;
935     }
937 /// Extract the php part
938     if (!isset($data['#']['PHP'])) {
939     /// Error. No PHP section found
940         $result->setStatus(false);
941         $result->setErrorCode(NO_PHP_SECTION_FOUND);
942         return $result;
943     } else {
944     /// Extract level and version
945         $level = get_level($data['#']['PHP']['0']);
946         if (!isset($data['#']['PHP']['0']['@']['version'])) {
947             $result->setStatus(false);
948             $result->setErrorCode(NO_PHP_VERSION_FOUND);
949             return $result;
950         } else {
951             $needed_version = $data['#']['PHP']['0']['@']['version'];
952         }
953     }
955 /// Now search the version we are using
956     $current_version = normalize_version(phpversion());
958 /// And finally compare them, saving results
959     if (version_compare($current_version, $needed_version, '>=')) {
960         $result->setStatus(true);
961     } else {
962         $result->setStatus(false);
963     }
964     $result->setLevel($level);
965     $result->setCurrentVersion($current_version);
966     $result->setNeededVersion($needed_version);
968 /// Do any actions defined in the XML file.
969     process_environment_result($data['#']['PHP'][0], $result);
971     return $result;
975 /**
976  * This function will check if unicode database requirements are satisfied
977  *
978  * @global object
979  * @uses NO_VERSION_DATA_FOUND
980  * @uses NO_UNICODE_SECTION_FOUND
981  * @param string $version xml version we are going to use to test this server
982  * @param int $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use.
983  * @return object results encapsulated in one environment_result object
984  */
985 function environment_check_unicode($version, $env_select) {
986     global $DB;
988     $result = new environment_results('unicode');
990     /// Get the enviroment version we need
991     if (!$data = get_environment_for_version($version, $env_select)) {
992     /// Error. No version data found
993         $result->setStatus(false);
994         $result->setErrorCode(NO_VERSION_DATA_FOUND);
995         return $result;
996     }
998     /// Extract the unicode part
1000     if (!isset($data['#']['UNICODE'])) {
1001     /// Error. No UNICODE section found
1002         $result->setStatus(false);
1003         $result->setErrorCode(NO_UNICODE_SECTION_FOUND);
1004         return $result;
1005     } else {
1006     /// Extract level
1007         $level = get_level($data['#']['UNICODE']['0']);
1008     }
1010     if (!$unicodedb = $DB->setup_is_unicodedb()) {
1011         $result->setStatus(false);
1012     } else {
1013         $result->setStatus(true);
1014     }
1016     $result->setLevel($level);
1018 /// Do any actions defined in the XML file.
1019     process_environment_result($data['#']['UNICODE'][0], $result);
1021     return $result;
1024 /**
1025  * This function will check if database requirements are satisfied
1026  *
1027  * @global object
1028  * @uses NO_VERSION_DATA_FOUND
1029  * @uses NO_DATABASE_SECTION_FOUND
1030  * @uses NO_DATABASE_VENDORS_FOUND
1031  * @uses NO_DATABASE_VENDOR_MYSQL_FOUND
1032  * @uses NO_DATABASE_VENDOR_POSTGRES_FOUND
1033  * @uses NO_DATABASE_VENDOR_VERSION_FOUND
1034  * @param string $version xml version we are going to use to test this server
1035  * @param int $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use.
1036  * @return object results encapsulated in one environment_result object
1037  */
1038 function environment_check_database($version, $env_select) {
1040     global $DB;
1042     $result = new environment_results('database');
1044     $vendors = array();  //Array of vendors in version
1046 /// Get the enviroment version we need
1047     if (!$data = get_environment_for_version($version, $env_select)) {
1048     /// Error. No version data found
1049         $result->setStatus(false);
1050         $result->setErrorCode(NO_VERSION_DATA_FOUND);
1051         return $result;
1052     }
1054 /// Extract the database part
1055     if (!isset($data['#']['DATABASE'])) {
1056     /// Error. No DATABASE section found
1057         $result->setStatus(false);
1058         $result->setErrorCode(NO_DATABASE_SECTION_FOUND);
1059         return $result;
1060     } else {
1061     /// Extract level
1062         $level = get_level($data['#']['DATABASE']['0']);
1063     }
1065 /// Extract DB vendors. At least 2 are mandatory (mysql & postgres)
1066     if (!isset($data['#']['DATABASE']['0']['#']['VENDOR'])) {
1067     /// Error. No VENDORS found
1068         $result->setStatus(false);
1069         $result->setErrorCode(NO_DATABASE_VENDORS_FOUND);
1070         return $result;
1071     } else {
1072     /// Extract vendors
1073         foreach ($data['#']['DATABASE']['0']['#']['VENDOR'] as $vendor) {
1074             if (isset($vendor['@']['name']) && isset($vendor['@']['version'])) {
1075                 $vendors[$vendor['@']['name']] = $vendor['@']['version'];
1076                 $vendorsxml[$vendor['@']['name']] = $vendor;
1077             }
1078         }
1079     }
1080 /// Check we have the mysql vendor version
1081     if (empty($vendors['mysql'])) {
1082         $result->setStatus(false);
1083         $result->setErrorCode(NO_DATABASE_VENDOR_MYSQL_FOUND);
1084         return $result;
1085     }
1086 /// Check we have the postgres vendor version
1087     if (empty($vendors['postgres'])) {
1088         $result->setStatus(false);
1089         $result->setErrorCode(NO_DATABASE_VENDOR_POSTGRES_FOUND);
1090         return $result;
1091     }
1093 /// Now search the version we are using (depending of vendor)
1094     $current_vendor = $DB->get_dbfamily();
1096     $dbinfo = $DB->get_server_info();
1097     $current_version = normalize_version($dbinfo['version']);
1098     $needed_version = $vendors[$current_vendor];
1100 /// Check we have a needed version
1101     if (!$needed_version) {
1102         $result->setStatus(false);
1103         $result->setErrorCode(NO_DATABASE_VENDOR_VERSION_FOUND);
1104         return $result;
1105     }
1107 /// And finally compare them, saving results
1108     if (version_compare($current_version, $needed_version, '>=')) {
1109         $result->setStatus(true);
1110     } else {
1111         $result->setStatus(false);
1112     }
1113     $result->setLevel($level);
1114     $result->setCurrentVersion($current_version);
1115     $result->setNeededVersion($needed_version);
1116     $result->setInfo($current_vendor);
1118 /// Do any actions defined in the XML file.
1119     process_environment_result($vendorsxml[$current_vendor], $result);
1121     return $result;
1125 /**
1126  * This function will post-process the result record by executing the specified
1127  * function, modifying it as necessary, also a custom message will be added
1128  * to the result object to be printed by the display layer.
1129  * Every bypass function must be defined in this file and it'll return
1130  * true/false to decide if the original test is bypassed or no. Also
1131  * such bypass functions are able to directly handling the result object
1132  * although it should be only under exceptional conditions.
1133  *
1134  * @param string xmldata containing the bypass data
1135  * @param object result object to be updated
1136  * @return void
1137  */
1138 function process_environment_bypass($xml, &$result) {
1140 /// Only try to bypass if we were in error and it was required
1141     if ($result->getStatus() || $result->getLevel() == 'optional') {
1142         return;
1143     }
1145 /// It there is bypass info (function and message)
1146     if (is_array($xml['#']) && isset($xml['#']['BYPASS'][0]['@']['function']) && isset($xml['#']['BYPASS'][0]['@']['message'])) {
1147         $function = $xml['#']['BYPASS'][0]['@']['function'];
1148         $message  = $xml['#']['BYPASS'][0]['@']['message'];
1149     /// Look for the function
1150         if (function_exists($function)) {
1151         /// Call it, and if bypass = true is returned, apply meesage
1152             if ($function($result)) {
1153             /// We only set the bypass message if the function itself hasn't defined it before
1154                 if (empty($result->getBypassStr)) {
1155                     $result->setBypassStr($message);
1156                 }
1157             }
1158         }
1159     }
1162 /**
1163  * This function will post-process the result record by executing the specified
1164  * function, modifying it as necessary, also a custom message will be added
1165  * to the result object to be printed by the display layer.
1166  * Every restrict function must be defined in this file and it'll return
1167  * true/false to decide if the original test is restricted or no. Also
1168  * such restrict functions are able to directly handling the result object
1169  * although it should be only under exceptional conditions.
1170  *
1171  * @param string xmldata containing the restrict data
1172  * @param object result object to be updated
1173  * @return void
1174  */
1175 function process_environment_restrict($xml, &$result) {
1177 /// Only try to restrict if we were not in error and it was required
1178     if (!$result->getStatus() || $result->getLevel() == 'optional') {
1179         return;
1180     }
1181 /// It there is restrict info (function and message)
1182     if (is_array($xml['#']) && isset($xml['#']['RESTRICT'][0]['@']['function']) && isset($xml['#']['RESTRICT'][0]['@']['message'])) {
1183         $function = $xml['#']['RESTRICT'][0]['@']['function'];
1184         $message  = $xml['#']['RESTRICT'][0]['@']['message'];
1185     /// Look for the function
1186         if (function_exists($function)) {
1187         /// Call it, and if restrict = true is returned, apply meesage
1188             if ($function($result)) {
1189             /// We only set the restrict message if the function itself hasn't defined it before
1190                 if (empty($result->getRestrictStr)) {
1191                     $result->setRestrictStr($message);
1192                 }
1193             }
1194         }
1195     }
1198 /**
1199  * This function will detect if there is some message available to be added to the
1200  * result in order to clarify enviromental details.
1201  *
1202  * @param string xmldata containing the feedback data
1203  * @param object reult object to be updated
1204  */
1205 function process_environment_messages($xml, &$result) {
1207 /// If there is feedback info
1208     if (is_array($xml['#']) && isset($xml['#']['FEEDBACK'][0]['#'])) {
1209         $feedbackxml = $xml['#']['FEEDBACK'][0]['#'];
1211         if (!$result->status and $result->getLevel() == 'required') {
1212             if (isset($feedbackxml['ON_ERROR'][0]['@']['message'])) {
1213                 $result->setFeedbackStr($feedbackxml['ON_ERROR'][0]['@']['message']);
1214             }
1215         } else if (!$result->status and $result->getLevel() == 'optional') {
1216             if (isset($feedbackxml['ON_CHECK'][0]['@']['message'])) {
1217                 $result->setFeedbackStr($feedbackxml['ON_CHECK'][0]['@']['message']);
1218             }
1219         } else {
1220             if (isset($feedbackxml['ON_OK'][0]['@']['message'])) {
1221                 $result->setFeedbackStr($feedbackxml['ON_OK'][0]['@']['message']);
1222             }
1223         }
1224     }
1228 //--- Helper Class to return results to caller ---//
1231 /**
1232  * Helper Class to return results to caller
1233  *
1234  * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
1235  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1236  * @package moodlecore
1237  */
1238 class environment_results {
1239     /**
1240      * @var string Which are we checking (database, php, php_extension, php_extension)
1241      */
1242     var $part;
1243     /**
1244      * @var bool
1245      */
1246     var $status;
1247     /**
1248      * @var integer See constants at the beginning of the file
1249      */
1250     var $error_code;
1251     /**
1252      * @var string required/optional
1253      */
1254     var $level;
1255     /**
1256      * @var string current version detected
1257      */
1258     var $current_version;
1259     /**
1260      * @var string version needed
1261      */
1262     var $needed_version;
1263     /**
1264      * @var string Aux. info (DB vendor, library...)
1265      */
1266     var $info;
1267     /**
1268      * @var string String to show on error|on check|on ok
1269      */
1270     var $feedback_str;
1271     /**
1272      * @var string String to show if some bypass has happened
1273      */
1274     var $bypass_str;
1275     /**
1276      * @var string String to show if some restrict has happened
1277      */
1278     var $restrict_str;
1280     /**
1281      * Constructor of the environment_result class. Just set default values
1282      *
1283      * @param string $part
1284      */
1285     function environment_results($part) {
1286         $this->part=$part;
1287         $this->status=false;
1288         $this->error_code=NO_ERROR;
1289         $this->level='required';
1290         $this->current_version='';
1291         $this->needed_version='';
1292         $this->info='';
1293         $this->feedback_str='';
1294         $this->bypass_str='';
1295         $this->restrict_str='';
1296     }
1298     /**
1299      * Set the status
1300      *
1301      * @param boolean $status the status (true/false)
1302      */
1303     function setStatus($status) {
1304         $this->status=$status;
1305         if ($status) {
1306             $this->setErrorCode(NO_ERROR);
1307         }
1308     }
1310     /**
1311      * Set the error_code
1312      *
1313      * @param integer $error_code the error code (see constants above)
1314      */
1315     function setErrorCode($error_code) {
1316         $this->error_code=$error_code;
1317     }
1319     /**
1320      * Set the level
1321      *
1322      * @param string $level the level (required, optional)
1323      */
1324     function setLevel($level) {
1325         $this->level=$level;
1326     }
1328     /**
1329      * Set the current version
1330      *
1331      * @param string $current_version the current version
1332      */
1333     function setCurrentVersion($current_version) {
1334         $this->current_version=$current_version;
1335     }
1337     /**
1338      * Set the needed version
1339      *
1340      * @param string $needed_version the needed version
1341      */
1342     function setNeededVersion($needed_version) {
1343         $this->needed_version=$needed_version;
1344     }
1346     /**
1347      * Set the auxiliary info
1348      *
1349      * @param string $info the auxiliary info
1350      */
1351     function setInfo($info) {
1352         $this->info=$info;
1353     }
1355     /**
1356      * Set the feedback string
1357      *
1358      * @param mixed $str the feedback string that will be fetched from the admin lang file.
1359      *                  pass just the string or pass an array of params for get_string
1360      *                  You always should put your string in admin.php but a third param is useful
1361      *                  to pass an $a object / string to get_string
1362      */
1363     function setFeedbackStr($str) {
1364         $this->feedback_str=$str;
1365     }
1368     /**
1369      * Set the bypass string
1370      *
1371      * @param string $str the bypass string that will be fetched from the admin lang file.
1372      *                  pass just the string or pass an array of params for get_string
1373      *                  You always should put your string in admin.php but a third param is useful
1374      *                  to pass an $a object / string to get_string
1375      */
1376     function setBypassStr($str) {
1377         $this->bypass_str=$str;
1378     }
1380     /**
1381      * Set the restrict string
1382      *
1383      * @param string $str the restrict string that will be fetched from the admin lang file.
1384      *                  pass just the string or pass an array of params for get_string
1385      *                  You always should put your string in admin.php but a third param is useful
1386      *                  to pass an $a object / string to get_string
1387      */
1388     function setRestrictStr($str) {
1389         $this->restrict_str=$str;
1390     }
1392     /**
1393      * Get the status
1394      *
1395      * @return boolean result
1396      */
1397     function getStatus() {
1398         return $this->status;
1399     }
1401     /**
1402      * Get the error code
1403      *
1404      * @return integer error code
1405      */
1406     function getErrorCode() {
1407         return $this->error_code;
1408     }
1410     /**
1411      * Get the level
1412      *
1413      * @return string level
1414      */
1415     function getLevel() {
1416         return $this->level;
1417     }
1419     /**
1420      * Get the current version
1421      *
1422      * @return string current version
1423      */
1424     function getCurrentVersion() {
1425         return $this->current_version;
1426     }
1428     /**
1429      * Get the needed version
1430      *
1431      * @return string needed version
1432      */
1433     function getNeededVersion() {
1434         return $this->needed_version;
1435     }
1437     /**
1438      * Get the aux info
1439      *
1440      * @return string info
1441      */
1442     function getInfo() {
1443         return $this->info;
1444     }
1446     /**
1447      * Get the part this result belongs to
1448      *
1449      * @return string part
1450      */
1451     function getPart() {
1452         return $this->part;
1453     }
1455     /**
1456      * Get the feedback string
1457      *
1458      * @return mixed feedback string (can be an array of params for get_string or a single string to fetch from
1459      *                  admin.php lang file).
1460      */
1461     function getFeedbackStr() {
1462         return $this->feedback_str;
1463     }
1465     /**
1466      * Get the bypass string
1467      *
1468      * @return mixed bypass string (can be an array of params for get_string or a single string to fetch from
1469      *                  admin.php lang file).
1470      */
1471     function getBypassStr() {
1472         return $this->bypass_str;
1473     }
1475     /**
1476      * Get the restrict string
1477      *
1478      * @return mixed restrict string (can be an array of params for get_string or a single string to fetch from
1479      *                  admin.php lang file).
1480      */
1481     function getRestrictStr() {
1482         return $this->restrict_str;
1483     }
1485     /**
1486      * @todo Document this function
1487      *
1488      * @param mixed $string params for get_string, either a string to fetch from admin.php or an array of
1489      *                       params for get_string.
1490      * @param string $class css class(es) for message.
1491      * @return string feedback string fetched from lang file wrapped in p tag with class $class or returns
1492      *                              empty string if $string is empty.
1493      */
1494     function strToReport($string, $class){
1495         if (!empty($string)){
1496             if (is_array($string)){
1497                 $str = call_user_func_array('get_string', $string);
1498             } else {
1499                 $str = get_string($string, 'admin');
1500             }
1501             return '<p class="'.$class.'">'.$str.'</p>';
1502         } else {
1503             return '';
1504         }
1505     }
1508 /// Here all the bypass functions are coded to be used by the environment
1509 /// checker. All those functions will receive the result object and will
1510 /// return it modified as needed (status and bypass string)
1512 /**
1513  * This function will bypass MySQL 4.1.16 reqs if:
1514  *   - We are using MySQL > 4.1.12, informing about problems with non latin chars in the future
1515  *
1516  * @param object result object to handle
1517  * @return boolean true/false to determinate if the bypass has to be performed (true) or no (false)
1518  */
1519 function bypass_mysql416_reqs ($result) {
1520 /// See if we are running MySQL >= 4.1.12
1521     if (version_compare($result->getCurrentVersion(), '4.1.12', '>=')) {
1522         return true;
1523     }
1525     return false;
1528 /// Here all the restrict functions are coded to be used by the environment
1529 /// checker. All those functions will receive the result object and will
1530 /// return it modified as needed (status and bypass string)
1532 /**
1533  * This function will restrict PHP reqs if:
1534  *   - We are using PHP 5.0.x, informing about the buggy version
1535  *
1536  * @param object $result object to handle
1537  * @return boolean true/false to determinate if the restrict has to be performed (true) or no (false)
1538  */
1539 function restrict_php50_version($result) {
1540     if (version_compare($result->getCurrentVersion(), '5.0.0', '>=')
1541       and version_compare($result->getCurrentVersion(), '5.0.99', '<')) {
1542         return true;
1543     }
1544     return false;
1547 /**
1548  * @param array $element the element from the environment.xml file that should have
1549  *      either a level="required" or level="optional" attribute.
1550  * @return string "required" or "optional".
1551  */
1552 function get_level($element) {
1553     $level = 'required';
1554     if (isset($element['@']['level'])) {
1555         $level = $element['@']['level'];
1556         if (!in_array($level, array('required', 'optional'))) {
1557             debugging('The level of a check in the environment.xml file must be "required" or "optional".', DEBUG_DEVELOPER);
1558             $level = 'required';
1559         }
1560     } else {
1561         debugging('Checks in the environment.xml file must have a level="required" or level="optional" attribute.', DEBUG_DEVELOPER);
1562     }
1563     return $level;
1566 /**
1567  * Once the result has been determined, look in the XML for any
1568  * messages, or other things that should be done depending on the outcome.
1569  *
1570  * @param array $element the element from the environment.xml file which
1571  *      may have children defining what should be done with the outcome.
1572  * @param object $result the result of the test, which may be modified by
1573  *      this function as specified in the XML.
1574  */
1575 function process_environment_result($element, &$result) {
1576 /// Process messages, modifying the $result if needed.
1577     process_environment_messages($element, $result);
1578 /// Process bypass, modifying $result if needed.
1579     process_environment_bypass($element, $result);
1580 /// Process restrict, modifying $result if needed.
1581     process_environment_restrict($element, $result);