Merge branch 'MDL-26007_20_wip_enverror' 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         $results[] = $result;
720         return $results;
721     }
723 /// Extract the php_setting part
724     if (!isset($data['#']['PHP_SETTINGS']['0']['#']['PHP_SETTING'])) {
725     /// No PHP section found - ignore
726         return $results;
727     }
728 /// Iterate over settings checking them and creating the needed environment_results
729     foreach($data['#']['PHP_SETTINGS']['0']['#']['PHP_SETTING'] as $setting) {
730         $result = new environment_results('php_setting');
731     /// Check for level
732         $level = get_level($setting);
733         $result->setLevel($level);
734     /// Check for extension name
735         if (!isset($setting['@']['name'])) {
736             $result->setStatus(false);
737             $result->setErrorCode(NO_PHP_SETTINGS_NAME_FOUND);
738         } else {
739             $setting_name  = $setting['@']['name'];
740             $setting_value = $setting['@']['value'];
741             $result->setInfo($setting_name);
743             if ($setting_name == 'memory_limit') {
744                 $current = ini_get('memory_limit');
745                 if ($current == -1) {
746                     $result->setStatus(true);
747                 } else {
748                     $current  = get_real_size($current);
749                     $minlimit = get_real_size($setting_value);
750                     if ($current < $minlimit) {
751                         @ini_set('memory_limit', $setting_value);
752                         $current = ini_get('memory_limit');
753                         $current = get_real_size($current);
754                     }
755                     $result->setStatus($current >= $minlimit);
756                 }
758             } else {
759                 $current = ini_get_bool($setting_name);
760             /// The name exists. Just check if it's an installed extension
761                 if ($current == $setting_value) {
762                     $result->setStatus(true);
763                 } else {
764                     $result->setStatus(false);
765                 }
766             }
767         }
769     /// Do any actions defined in the XML file.
770         process_environment_result($setting, $result);
772     /// Add the result to the array of results
773         $results[] = $result;
774     }
777     return $results;
780 /**
781  * This function will do the custom checks.
782  *
783  * @global object
784  * @uses CUSTOM_CHECK_FUNCTION_MISSING
785  * @uses CUSTOM_CHECK_FILE_MISSING
786  * @uses NO_CUSTOM_CHECK_FOUND
787  * @param string $version xml version we are going to use to test this server.
788  * @param int $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use.
789  * @return array array of results encapsulated in environment_result objects.
790  */
791 function environment_custom_checks($version, $env_select) {
792     global $CFG;
794     $results = array();
796 /// Get current Moodle version (release) for later compare
797     $release = isset($CFG->release) ? $CFG->release : $version; /// In case $CFG fails (at install) use $version
798     $current_version = normalize_version($release);
800 /// Get the enviroment version we need
801     if (!$data = get_environment_for_version($version, $env_select)) {
802     /// Error. No version data found - but this will already have been reported.
803         return $results;
804     }
806 /// Extract the CUSTOM_CHECKS part
807     if (!isset($data['#']['CUSTOM_CHECKS']['0']['#']['CUSTOM_CHECK'])) {
808     /// No custom checks found - not a problem
809         return $results;
810     }
812 /// Iterate over extensions checking them and creating the needed environment_results
813     foreach($data['#']['CUSTOM_CHECKS']['0']['#']['CUSTOM_CHECK'] as $check) {
814         $result = new environment_results('custom_check');
816     /// Check for level
817         $level = get_level($check);
819     /// Check for extension name
820         if (isset($check['@']['file']) && isset($check['@']['function'])) {
821             $file = $CFG->dirroot . '/' . $check['@']['file'];
822             $function = $check['@']['function'];
823             if (is_readable($file)) {
824                 include_once($file);
825                 if (function_exists($function)) {
826                     $result->setLevel($level);
827                     $result->setInfo($function);
828                     $result = $function($result);
829                 } else {
830                 /// Only show error for current version (where function MUST exist)
831                 /// else, we are performing custom checks against future versiosn
832                 /// and function MAY not exist, so it doesn't cause error, just skip
833                 /// custom check by returning null. MDL-15939
834                     if (version_compare($current_version, $version, '>=')) {
835                         $result->setStatus(false);
836                         $result->setInfo($function);
837                         $result->setErrorCode(CUSTOM_CHECK_FUNCTION_MISSING);
838                     } else {
839                         $result = null;
840                     }
841                 }
842             } else {
843             /// Only show error for current version (where function MUST exist)
844             /// else, we are performing custom checks against future versiosn
845             /// and function MAY not exist, so it doesn't cause error, just skip
846             /// custom check by returning null. MDL-15939
847                 if (version_compare($current_version, $version, '>=')) {
848                     $result->setStatus(false);
849                     $result->setInfo($function);
850                     $result->setErrorCode(CUSTOM_CHECK_FILE_MISSING);
851                 } else {
852                     $result = null;
853                 }
854             }
855         } else {
856             $result->setStatus(false);
857             $result->setErrorCode(NO_CUSTOM_CHECK_FOUND);
858         }
860         if (!is_null($result)) {
861         /// Do any actions defined in the XML file.
862             process_environment_result($check, $result);
864         /// Add the result to the array of results
865             $results[] = $result;
866         }
867     }
869     return $results;
872 /**
873  * This function will check if Moodle requirements are satisfied
874  *
875  * @uses NO_VERSION_DATA_FOUND
876  * @param string $version xml version we are going to use to test this server
877  * @param int $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use.
878  * @return object results encapsulated in one environment_result object
879  */
880 function environment_check_moodle($version, $env_select) {
882     $result = new environment_results('moodle');
884 /// Get the enviroment version we need
885     if (!$data = get_environment_for_version($version, $env_select)) {
886     /// Error. No version data found
887         $result->setStatus(false);
888         $result->setErrorCode(NO_VERSION_DATA_FOUND);
889         return $result;
890     }
892 /// Extract the moodle part
893     if (!isset($data['@']['requires'])) {
894         $needed_version = '1.0'; /// Default to 1.0 if no moodle requires is found
895     } else {
896     /// Extract required moodle version
897         $needed_version = $data['@']['requires'];
898     }
900 /// Now search the version we are using
901     $current_version = normalize_version(get_config('', 'release'));
903 /// And finally compare them, saving results
904     if (version_compare($current_version, $needed_version, '>=')) {
905         $result->setStatus(true);
906     } else {
907         $result->setStatus(false);
908     }
909     $result->setLevel('required');
910     $result->setCurrentVersion($current_version);
911     $result->setNeededVersion($needed_version);
913     return $result;
916 /**
917  * This function will check if php requirements are satisfied
918  *
919  * @uses NO_VERSION_DATA_FOUND
920  * @uses NO_PHP_SECTION_FOUND
921  * @uses NO_PHP_VERSION_FOUND
922  * @param string $version xml version we are going to use to test this server
923  * @param int $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use.
924  * @return object results encapsulated in one environment_result object
925  */
926 function environment_check_php($version, $env_select) {
928     $result = new environment_results('php');
930 /// Get the enviroment version we need
931     if (!$data = get_environment_for_version($version, $env_select)) {
932     /// Error. No version data found
933         $result->setStatus(false);
934         $result->setErrorCode(NO_VERSION_DATA_FOUND);
935         return $result;
936     }
938 /// Extract the php part
939     if (!isset($data['#']['PHP'])) {
940     /// Error. No PHP section found
941         $result->setStatus(false);
942         $result->setErrorCode(NO_PHP_SECTION_FOUND);
943         return $result;
944     } else {
945     /// Extract level and version
946         $level = get_level($data['#']['PHP']['0']);
947         if (!isset($data['#']['PHP']['0']['@']['version'])) {
948             $result->setStatus(false);
949             $result->setErrorCode(NO_PHP_VERSION_FOUND);
950             return $result;
951         } else {
952             $needed_version = $data['#']['PHP']['0']['@']['version'];
953         }
954     }
956 /// Now search the version we are using
957     $current_version = normalize_version(phpversion());
959 /// And finally compare them, saving results
960     if (version_compare($current_version, $needed_version, '>=')) {
961         $result->setStatus(true);
962     } else {
963         $result->setStatus(false);
964     }
965     $result->setLevel($level);
966     $result->setCurrentVersion($current_version);
967     $result->setNeededVersion($needed_version);
969 /// Do any actions defined in the XML file.
970     process_environment_result($data['#']['PHP'][0], $result);
972     return $result;
976 /**
977  * This function will check if unicode database requirements are satisfied
978  *
979  * @global object
980  * @uses NO_VERSION_DATA_FOUND
981  * @uses NO_UNICODE_SECTION_FOUND
982  * @param string $version xml version we are going to use to test this server
983  * @param int $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use.
984  * @return object results encapsulated in one environment_result object
985  */
986 function environment_check_unicode($version, $env_select) {
987     global $DB;
989     $result = new environment_results('unicode');
991     /// Get the enviroment version we need
992     if (!$data = get_environment_for_version($version, $env_select)) {
993     /// Error. No version data found
994         $result->setStatus(false);
995         $result->setErrorCode(NO_VERSION_DATA_FOUND);
996         return $result;
997     }
999     /// Extract the unicode part
1001     if (!isset($data['#']['UNICODE'])) {
1002     /// Error. No UNICODE section found
1003         $result->setStatus(false);
1004         $result->setErrorCode(NO_UNICODE_SECTION_FOUND);
1005         return $result;
1006     } else {
1007     /// Extract level
1008         $level = get_level($data['#']['UNICODE']['0']);
1009     }
1011     if (!$unicodedb = $DB->setup_is_unicodedb()) {
1012         $result->setStatus(false);
1013     } else {
1014         $result->setStatus(true);
1015     }
1017     $result->setLevel($level);
1019 /// Do any actions defined in the XML file.
1020     process_environment_result($data['#']['UNICODE'][0], $result);
1022     return $result;
1025 /**
1026  * This function will check if database requirements are satisfied
1027  *
1028  * @global object
1029  * @uses NO_VERSION_DATA_FOUND
1030  * @uses NO_DATABASE_SECTION_FOUND
1031  * @uses NO_DATABASE_VENDORS_FOUND
1032  * @uses NO_DATABASE_VENDOR_MYSQL_FOUND
1033  * @uses NO_DATABASE_VENDOR_POSTGRES_FOUND
1034  * @uses NO_DATABASE_VENDOR_VERSION_FOUND
1035  * @param string $version xml version we are going to use to test this server
1036  * @param int $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use.
1037  * @return object results encapsulated in one environment_result object
1038  */
1039 function environment_check_database($version, $env_select) {
1041     global $DB;
1043     $result = new environment_results('database');
1045     $vendors = array();  //Array of vendors in version
1047 /// Get the enviroment version we need
1048     if (!$data = get_environment_for_version($version, $env_select)) {
1049     /// Error. No version data found
1050         $result->setStatus(false);
1051         $result->setErrorCode(NO_VERSION_DATA_FOUND);
1052         return $result;
1053     }
1055 /// Extract the database part
1056     if (!isset($data['#']['DATABASE'])) {
1057     /// Error. No DATABASE section found
1058         $result->setStatus(false);
1059         $result->setErrorCode(NO_DATABASE_SECTION_FOUND);
1060         return $result;
1061     } else {
1062     /// Extract level
1063         $level = get_level($data['#']['DATABASE']['0']);
1064     }
1066 /// Extract DB vendors. At least 2 are mandatory (mysql & postgres)
1067     if (!isset($data['#']['DATABASE']['0']['#']['VENDOR'])) {
1068     /// Error. No VENDORS found
1069         $result->setStatus(false);
1070         $result->setErrorCode(NO_DATABASE_VENDORS_FOUND);
1071         return $result;
1072     } else {
1073     /// Extract vendors
1074         foreach ($data['#']['DATABASE']['0']['#']['VENDOR'] as $vendor) {
1075             if (isset($vendor['@']['name']) && isset($vendor['@']['version'])) {
1076                 $vendors[$vendor['@']['name']] = $vendor['@']['version'];
1077                 $vendorsxml[$vendor['@']['name']] = $vendor;
1078             }
1079         }
1080     }
1081 /// Check we have the mysql vendor version
1082     if (empty($vendors['mysql'])) {
1083         $result->setStatus(false);
1084         $result->setErrorCode(NO_DATABASE_VENDOR_MYSQL_FOUND);
1085         return $result;
1086     }
1087 /// Check we have the postgres vendor version
1088     if (empty($vendors['postgres'])) {
1089         $result->setStatus(false);
1090         $result->setErrorCode(NO_DATABASE_VENDOR_POSTGRES_FOUND);
1091         return $result;
1092     }
1094 /// Now search the version we are using (depending of vendor)
1095     $current_vendor = $DB->get_dbfamily();
1097     $dbinfo = $DB->get_server_info();
1098     $current_version = normalize_version($dbinfo['version']);
1099     $needed_version = $vendors[$current_vendor];
1101 /// Check we have a needed version
1102     if (!$needed_version) {
1103         $result->setStatus(false);
1104         $result->setErrorCode(NO_DATABASE_VENDOR_VERSION_FOUND);
1105         return $result;
1106     }
1108 /// And finally compare them, saving results
1109     if (version_compare($current_version, $needed_version, '>=')) {
1110         $result->setStatus(true);
1111     } else {
1112         $result->setStatus(false);
1113     }
1114     $result->setLevel($level);
1115     $result->setCurrentVersion($current_version);
1116     $result->setNeededVersion($needed_version);
1117     $result->setInfo($current_vendor);
1119 /// Do any actions defined in the XML file.
1120     process_environment_result($vendorsxml[$current_vendor], $result);
1122     return $result;
1126 /**
1127  * This function will post-process the result record by executing the specified
1128  * function, modifying it as necessary, also a custom message will be added
1129  * to the result object to be printed by the display layer.
1130  * Every bypass function must be defined in this file and it'll return
1131  * true/false to decide if the original test is bypassed or no. Also
1132  * such bypass functions are able to directly handling the result object
1133  * although it should be only under exceptional conditions.
1134  *
1135  * @param string xmldata containing the bypass data
1136  * @param object result object to be updated
1137  * @return void
1138  */
1139 function process_environment_bypass($xml, &$result) {
1141 /// Only try to bypass if we were in error and it was required
1142     if ($result->getStatus() || $result->getLevel() == 'optional') {
1143         return;
1144     }
1146 /// It there is bypass info (function and message)
1147     if (is_array($xml['#']) && isset($xml['#']['BYPASS'][0]['@']['function']) && isset($xml['#']['BYPASS'][0]['@']['message'])) {
1148         $function = $xml['#']['BYPASS'][0]['@']['function'];
1149         $message  = $xml['#']['BYPASS'][0]['@']['message'];
1150     /// Look for the function
1151         if (function_exists($function)) {
1152         /// Call it, and if bypass = true is returned, apply meesage
1153             if ($function($result)) {
1154             /// We only set the bypass message if the function itself hasn't defined it before
1155                 if (empty($result->getBypassStr)) {
1156                     $result->setBypassStr($message);
1157                 }
1158             }
1159         }
1160     }
1163 /**
1164  * This function will post-process the result record by executing the specified
1165  * function, modifying it as necessary, also a custom message will be added
1166  * to the result object to be printed by the display layer.
1167  * Every restrict function must be defined in this file and it'll return
1168  * true/false to decide if the original test is restricted or no. Also
1169  * such restrict functions are able to directly handling the result object
1170  * although it should be only under exceptional conditions.
1171  *
1172  * @param string xmldata containing the restrict data
1173  * @param object result object to be updated
1174  * @return void
1175  */
1176 function process_environment_restrict($xml, &$result) {
1178 /// Only try to restrict if we were not in error and it was required
1179     if (!$result->getStatus() || $result->getLevel() == 'optional') {
1180         return;
1181     }
1182 /// It there is restrict info (function and message)
1183     if (is_array($xml['#']) && isset($xml['#']['RESTRICT'][0]['@']['function']) && isset($xml['#']['RESTRICT'][0]['@']['message'])) {
1184         $function = $xml['#']['RESTRICT'][0]['@']['function'];
1185         $message  = $xml['#']['RESTRICT'][0]['@']['message'];
1186     /// Look for the function
1187         if (function_exists($function)) {
1188         /// Call it, and if restrict = true is returned, apply meesage
1189             if ($function($result)) {
1190             /// We only set the restrict message if the function itself hasn't defined it before
1191                 if (empty($result->getRestrictStr)) {
1192                     $result->setRestrictStr($message);
1193                 }
1194             }
1195         }
1196     }
1199 /**
1200  * This function will detect if there is some message available to be added to the
1201  * result in order to clarify enviromental details.
1202  *
1203  * @param string xmldata containing the feedback data
1204  * @param object reult object to be updated
1205  */
1206 function process_environment_messages($xml, &$result) {
1208 /// If there is feedback info
1209     if (is_array($xml['#']) && isset($xml['#']['FEEDBACK'][0]['#'])) {
1210         $feedbackxml = $xml['#']['FEEDBACK'][0]['#'];
1212         if (!$result->status and $result->getLevel() == 'required') {
1213             if (isset($feedbackxml['ON_ERROR'][0]['@']['message'])) {
1214                 $result->setFeedbackStr($feedbackxml['ON_ERROR'][0]['@']['message']);
1215             }
1216         } else if (!$result->status and $result->getLevel() == 'optional') {
1217             if (isset($feedbackxml['ON_CHECK'][0]['@']['message'])) {
1218                 $result->setFeedbackStr($feedbackxml['ON_CHECK'][0]['@']['message']);
1219             }
1220         } else {
1221             if (isset($feedbackxml['ON_OK'][0]['@']['message'])) {
1222                 $result->setFeedbackStr($feedbackxml['ON_OK'][0]['@']['message']);
1223             }
1224         }
1225     }
1229 //--- Helper Class to return results to caller ---//
1232 /**
1233  * Helper Class to return results to caller
1234  *
1235  * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
1236  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1237  * @package moodlecore
1238  */
1239 class environment_results {
1240     /**
1241      * @var string Which are we checking (database, php, php_extension, php_extension)
1242      */
1243     var $part;
1244     /**
1245      * @var bool
1246      */
1247     var $status;
1248     /**
1249      * @var integer See constants at the beginning of the file
1250      */
1251     var $error_code;
1252     /**
1253      * @var string required/optional
1254      */
1255     var $level;
1256     /**
1257      * @var string current version detected
1258      */
1259     var $current_version;
1260     /**
1261      * @var string version needed
1262      */
1263     var $needed_version;
1264     /**
1265      * @var string Aux. info (DB vendor, library...)
1266      */
1267     var $info;
1268     /**
1269      * @var string String to show on error|on check|on ok
1270      */
1271     var $feedback_str;
1272     /**
1273      * @var string String to show if some bypass has happened
1274      */
1275     var $bypass_str;
1276     /**
1277      * @var string String to show if some restrict has happened
1278      */
1279     var $restrict_str;
1281     /**
1282      * Constructor of the environment_result class. Just set default values
1283      *
1284      * @param string $part
1285      */
1286     function environment_results($part) {
1287         $this->part=$part;
1288         $this->status=false;
1289         $this->error_code=NO_ERROR;
1290         $this->level='required';
1291         $this->current_version='';
1292         $this->needed_version='';
1293         $this->info='';
1294         $this->feedback_str='';
1295         $this->bypass_str='';
1296         $this->restrict_str='';
1297     }
1299     /**
1300      * Set the status
1301      *
1302      * @param boolean $status the status (true/false)
1303      */
1304     function setStatus($status) {
1305         $this->status=$status;
1306         if ($status) {
1307             $this->setErrorCode(NO_ERROR);
1308         }
1309     }
1311     /**
1312      * Set the error_code
1313      *
1314      * @param integer $error_code the error code (see constants above)
1315      */
1316     function setErrorCode($error_code) {
1317         $this->error_code=$error_code;
1318     }
1320     /**
1321      * Set the level
1322      *
1323      * @param string $level the level (required, optional)
1324      */
1325     function setLevel($level) {
1326         $this->level=$level;
1327     }
1329     /**
1330      * Set the current version
1331      *
1332      * @param string $current_version the current version
1333      */
1334     function setCurrentVersion($current_version) {
1335         $this->current_version=$current_version;
1336     }
1338     /**
1339      * Set the needed version
1340      *
1341      * @param string $needed_version the needed version
1342      */
1343     function setNeededVersion($needed_version) {
1344         $this->needed_version=$needed_version;
1345     }
1347     /**
1348      * Set the auxiliary info
1349      *
1350      * @param string $info the auxiliary info
1351      */
1352     function setInfo($info) {
1353         $this->info=$info;
1354     }
1356     /**
1357      * Set the feedback string
1358      *
1359      * @param mixed $str the feedback string that will be fetched from the admin lang file.
1360      *                  pass just the string or pass an array of params for get_string
1361      *                  You always should put your string in admin.php but a third param is useful
1362      *                  to pass an $a object / string to get_string
1363      */
1364     function setFeedbackStr($str) {
1365         $this->feedback_str=$str;
1366     }
1369     /**
1370      * Set the bypass string
1371      *
1372      * @param string $str the bypass string that will be fetched from the admin lang file.
1373      *                  pass just the string or pass an array of params for get_string
1374      *                  You always should put your string in admin.php but a third param is useful
1375      *                  to pass an $a object / string to get_string
1376      */
1377     function setBypassStr($str) {
1378         $this->bypass_str=$str;
1379     }
1381     /**
1382      * Set the restrict string
1383      *
1384      * @param string $str the restrict string that will be fetched from the admin lang file.
1385      *                  pass just the string or pass an array of params for get_string
1386      *                  You always should put your string in admin.php but a third param is useful
1387      *                  to pass an $a object / string to get_string
1388      */
1389     function setRestrictStr($str) {
1390         $this->restrict_str=$str;
1391     }
1393     /**
1394      * Get the status
1395      *
1396      * @return boolean result
1397      */
1398     function getStatus() {
1399         return $this->status;
1400     }
1402     /**
1403      * Get the error code
1404      *
1405      * @return integer error code
1406      */
1407     function getErrorCode() {
1408         return $this->error_code;
1409     }
1411     /**
1412      * Get the level
1413      *
1414      * @return string level
1415      */
1416     function getLevel() {
1417         return $this->level;
1418     }
1420     /**
1421      * Get the current version
1422      *
1423      * @return string current version
1424      */
1425     function getCurrentVersion() {
1426         return $this->current_version;
1427     }
1429     /**
1430      * Get the needed version
1431      *
1432      * @return string needed version
1433      */
1434     function getNeededVersion() {
1435         return $this->needed_version;
1436     }
1438     /**
1439      * Get the aux info
1440      *
1441      * @return string info
1442      */
1443     function getInfo() {
1444         return $this->info;
1445     }
1447     /**
1448      * Get the part this result belongs to
1449      *
1450      * @return string part
1451      */
1452     function getPart() {
1453         return $this->part;
1454     }
1456     /**
1457      * Get the feedback string
1458      *
1459      * @return mixed feedback string (can be an array of params for get_string or a single string to fetch from
1460      *                  admin.php lang file).
1461      */
1462     function getFeedbackStr() {
1463         return $this->feedback_str;
1464     }
1466     /**
1467      * Get the bypass string
1468      *
1469      * @return mixed bypass string (can be an array of params for get_string or a single string to fetch from
1470      *                  admin.php lang file).
1471      */
1472     function getBypassStr() {
1473         return $this->bypass_str;
1474     }
1476     /**
1477      * Get the restrict string
1478      *
1479      * @return mixed restrict string (can be an array of params for get_string or a single string to fetch from
1480      *                  admin.php lang file).
1481      */
1482     function getRestrictStr() {
1483         return $this->restrict_str;
1484     }
1486     /**
1487      * @todo Document this function
1488      *
1489      * @param mixed $string params for get_string, either a string to fetch from admin.php or an array of
1490      *                       params for get_string.
1491      * @param string $class css class(es) for message.
1492      * @return string feedback string fetched from lang file wrapped in p tag with class $class or returns
1493      *                              empty string if $string is empty.
1494      */
1495     function strToReport($string, $class){
1496         if (!empty($string)){
1497             if (is_array($string)){
1498                 $str = call_user_func_array('get_string', $string);
1499             } else {
1500                 $str = get_string($string, 'admin');
1501             }
1502             return '<p class="'.$class.'">'.$str.'</p>';
1503         } else {
1504             return '';
1505         }
1506     }
1509 /// Here all the bypass functions are coded to be used by the environment
1510 /// checker. All those functions will receive the result object and will
1511 /// return it modified as needed (status and bypass string)
1513 /**
1514  * This function will bypass MySQL 4.1.16 reqs if:
1515  *   - We are using MySQL > 4.1.12, informing about problems with non latin chars in the future
1516  *
1517  * @param object result object to handle
1518  * @return boolean true/false to determinate if the bypass has to be performed (true) or no (false)
1519  */
1520 function bypass_mysql416_reqs ($result) {
1521 /// See if we are running MySQL >= 4.1.12
1522     if (version_compare($result->getCurrentVersion(), '4.1.12', '>=')) {
1523         return true;
1524     }
1526     return false;
1529 /// Here all the restrict functions are coded to be used by the environment
1530 /// checker. All those functions will receive the result object and will
1531 /// return it modified as needed (status and bypass string)
1533 /**
1534  * This function will restrict PHP reqs if:
1535  *   - We are using PHP 5.0.x, informing about the buggy version
1536  *
1537  * @param object $result object to handle
1538  * @return boolean true/false to determinate if the restrict has to be performed (true) or no (false)
1539  */
1540 function restrict_php50_version($result) {
1541     if (version_compare($result->getCurrentVersion(), '5.0.0', '>=')
1542       and version_compare($result->getCurrentVersion(), '5.0.99', '<')) {
1543         return true;
1544     }
1545     return false;
1548 /**
1549  * @param array $element the element from the environment.xml file that should have
1550  *      either a level="required" or level="optional" attribute.
1551  * @return string "required" or "optional".
1552  */
1553 function get_level($element) {
1554     $level = 'required';
1555     if (isset($element['@']['level'])) {
1556         $level = $element['@']['level'];
1557         if (!in_array($level, array('required', 'optional'))) {
1558             debugging('The level of a check in the environment.xml file must be "required" or "optional".', DEBUG_DEVELOPER);
1559             $level = 'required';
1560         }
1561     } else {
1562         debugging('Checks in the environment.xml file must have a level="required" or level="optional" attribute.', DEBUG_DEVELOPER);
1563     }
1564     return $level;
1567 /**
1568  * Once the result has been determined, look in the XML for any
1569  * messages, or other things that should be done depending on the outcome.
1570  *
1571  * @param array $element the element from the environment.xml file which
1572  *      may have children defining what should be done with the outcome.
1573  * @param object $result the result of the test, which may be modified by
1574  *      this function as specified in the XML.
1575  */
1576 function process_environment_result($element, &$result) {
1577 /// Process messages, modifying the $result if needed.
1578     process_environment_messages($element, $result);
1579 /// Process bypass, modifying $result if needed.
1580     process_environment_bypass($element, $result);
1581 /// Process restrict, modifying $result if needed.
1582     process_environment_restrict($element, $result);