MDL-9616 - Custom checks in environment.xml
[moodle.git] / lib / environmentlib.php
CommitLineData
f58b518f 1<?php //$Id$
2
3///////////////////////////////////////////////////////////////////////////
4// //
5// NOTICE OF COPYRIGHT //
6// //
7// Moodle - Modular Object-Oriented Dynamic Learning Environment //
8// http://moodle.com //
9// //
10// Copyright (C) 2001-3001 Martin Dougiamas http://dougiamas.com //
11// (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com //
12// //
13// This program is free software; you can redistribute it and/or modify //
14// it under the terms of the GNU General Public License as published by //
15// the Free Software Foundation; either version 2 of the License, or //
16// (at your option) any later version. //
17// //
18// This program is distributed in the hope that it will be useful, //
19// but WITHOUT ANY WARRANTY; without even the implied warranty of //
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
21// GNU General Public License for more details: //
22// //
23// http://www.gnu.org/copyleft/gpl.html //
24// //
25///////////////////////////////////////////////////////////////////////////
26
27// This library includes all the necessary stuff to execute some standard
28// tests of required versions and libraries to run Moodle. It can be
29// used from the admin interface, and both at install and upgrade.
30//
31// All the info is stored in the admin/environment.xml file,
00d3a0fd 32// supporting to have an updated version in dataroot/environment
f58b518f 33
049c0f4a 34/// Add required files
35 require_once($CFG->libdir.'/xmlize.php');
36
37/// Define a buch of XML processing errors
00d3a0fd 38 define('NO_ERROR', 0);
39 define('NO_VERSION_DATA_FOUND', 1);
40 define('NO_DATABASE_SECTION_FOUND', 2);
41 define('NO_DATABASE_VENDORS_FOUND', 3);
42 define('NO_DATABASE_VENDOR_MYSQL_FOUND', 4);
43 define('NO_DATABASE_VENDOR_POSTGRES_FOUND', 5);
44 define('NO_PHP_SECTION_FOUND', 6);
45 define('NO_PHP_VERSION_FOUND', 7);
46 define('NO_PHP_EXTENSIONS_SECTION_FOUND', 8);
47 define('NO_PHP_EXTENSIONS_NAME_FOUND', 9);
48 define('NO_DATABASE_VENDOR_VERSION_FOUND', 10);
a392be33 49 define('NO_UNICODE_SECTION_FOUND', 11);
bac40536 50 define('NO_CUSTOM_CHECK_FOUND', 12);
51 define('CUSTOM_CHECK_FILE_MISSING', 13);
52 define('CUSTOM_CHECK_FUNCTION_MISSING', 14);
f58b518f 53
54/**
55 * This function will perform the whole check, returning
56 * true or false as final result. Also, he full array of
57 * environment_result will be returned in the parameter list.
58 * The function looks for the best version to compare and
59 * everything. This is the only function that should be called
60 * ever from the rest of Moodle.
61 * @param string version version to check.
62 * @param array results array of results checked.
63 * @return boolean true/false, depending of results
64 */
049c0f4a 65function check_moodle_environment($version, &$environment_results, $print_table=true) {
66
67 $status = true;
f58b518f 68
878d309c 69/// This are cached per request
70 static $result = true;
71 static $env_results;
72 static $cache_exists = false;
73
74/// if we have results cached, use them
75 if ($cache_exists) {
76 $environment_results = $env_results;
77/// No cache exists, calculate everything
78 } else {
79 /// Get the more recent version before the requested
80 if (!$version = get_latest_version_available($version)) {
81 $status = false;
82 }
f58b518f 83
878d309c 84 /// Perform all the checks
85 if (!($environment_results = environment_check($version)) && $status) {
86 $status = false;
87 }
f58b518f 88
878d309c 89 /// Iterate over all the results looking for some error in required items
90 /// or some error_code
91 if ($status) {
92 foreach ($environment_results as $environment_result) {
95a39282 93 if (!$environment_result->getStatus() && $environment_result->getLevel() == 'required'
94 && !$environment_result->getBypassStr()) {
95 $result = false; // required item that is not bypased
96 } else if ($environment_result->getStatus() && $environment_result->getLevel() == 'required'
97 && $environment_result->getRestrictStr()) {
98 $result = false; // required item that is restricted
99 } else if ($environment_result->getErrorCode()) {
878d309c 100 $result = false;
101 }
049c0f4a 102 }
f58b518f 103 }
878d309c 104 /// Going to end, we store environment_results to cache
105 $env_results = $environment_results;
106 $cache_exists = true;
107 } ///End of cache block
f58b518f 108
049c0f4a 109/// If we have decided to print all the information, just do it
110 if ($print_table) {
e909788d 111 print_moodle_environment($result && $status, $environment_results);
049c0f4a 112 }
113
114 return ($result && $status);
115}
116
117/**
118 * This function will print one beautiful table with all the environmental
119 * configuration and how it suits Moodle needs.
120 * @param boolean final result of the check (true/false)
121 * @param array environment_results array of results gathered
122 */
123function print_moodle_environment($result, $environment_results) {
124
125/// Get some strings
126 $strname = get_string('name');
127 $strinfo = get_string('info');
128 $strreport = get_string('report');
129 $strstatus = get_string('status');
130 $strok = get_string('ok');
131 $strerror = get_string('error');
132 $strcheck = get_string('check');
b0e2a189 133 $strbypassed = get_string('bypassed');
95a39282 134 $strrestricted = get_string('restricted');
e909788d 135 $strenvironmenterrortodo = get_string('environmenterrortodo', 'admin');
049c0f4a 136
9e2d15e5 137/// Here we'll store all the feedback found
138 $feedbacktext = '';
139
049c0f4a 140/// Table header
bac40536 141 $table = new stdClass;
049c0f4a 142 $table->head = array ($strname, $strinfo, $strreport, $strstatus);
143 $table->align = array ('center', 'center', 'left', 'center');
144 $table->wrap = array ('nowrap', '', '', 'nowrap');
145 $table->size = array ('10', 10, '100%', '10');
146 $table->width = '90%';
edc13d62 147 $table->class = 'environmenttable generaltable';
049c0f4a 148
149/// Iterate over each environment_result
150 $continue = true;
151 foreach ($environment_results as $environment_result) {
95a39282 152 $errorline = false;
153 $warningline = false;
049c0f4a 154 if ($continue) {
155 $type = $environment_result->getPart();
156 $info = $environment_result->getInfo();
157 $status = $environment_result->getStatus();
158 $error_code = $environment_result->getErrorCode();
159 /// Process Report field
878d309c 160 $rec = new stdClass();
049c0f4a 161 /// Something has gone wrong at parsing time
162 if ($error_code) {
163 $stringtouse = 'environmentxmlerror';
164 $rec->error_code = $error_code;
165 $status = $strerror;
166 $errorline = true;
167 $continue = false;
168 }
169
170 if ($continue) {
171 /// We are comparing versions
172 if ($rec->needed = $environment_result->getNeededVersion()) {
173 $rec->current = $environment_result->getCurrentVersion();
174 if ($environment_result->getLevel() == 'required') {
175 $stringtouse = 'environmentrequireversion';
176 } else {
177 $stringtouse = 'environmentrecommendversion';
178 }
179 /// We are checking installed & enabled things
180 } else {
181 if ($environment_result->getLevel() == 'required') {
182 $stringtouse = 'environmentrequireinstall';
183 } else {
184 $stringtouse = 'environmentrecommendinstall';
185 }
186 }
187 /// Calculate the status value
95a39282 188 if ($environment_result->getBypassStr() != '') { //Handle bypassed result (warning)
b0e2a189 189 $status = $strbypassed;
95a39282 190 $warningline = true;
191 } else if ($environment_result->getRestrictStr() != '') { //Handle restricted result (error)
192 $status = $strrestricted;
b0e2a189 193 $errorline = true;
95a39282 194 } else {
195 if ($status) { //Handle ok result (ok)
196 $status = $strok;
197 } else {
198 if ($environment_result->getLevel() == 'optional') {//Handle check result (warning)
199 $status = $strcheck;
200 $warningline = true;
201 } else { //Handle error result (error)
202 $status = $strcheck;
203 $errorline = true;
204 }
205 }
049c0f4a 206 }
207 }
208
209 /// Build the text
210 $report = get_string($stringtouse, 'admin', $rec);
95a39282 211 /// Format error or warning line
212 if ($errorline || $warningline) {
213 $styletoapply = $errorline? 'error':'warn';
214 $type = '<span class="'.$styletoapply.'">'.$type.'</span>';
215 $info = '<span class="'.$styletoapply.'">'.$info.'</span>';
216 $report = '<span class="'.$styletoapply.'">'.$report.'</span>';
217 $status = '<span class="'.$styletoapply.'">'.$status.'</span>';
049c0f4a 218 }
219 /// Add the row to the table
220 $table->data[] = array ($type, $info, $report, $status);
9e2d15e5 221 ///Process the feedback if necessary
222 if ($feedbackstr = $environment_result->getFeedbackStr()) {
223 $feedbacktext .= '<li class="environmenttable">'.get_string($feedbackstr, 'admin').'</li>';
224 }
b0e2a189 225 ///Process the bypass if necessary
226 if ($bypassstr = $environment_result->getBypassStr()) {
227 $feedbacktext .= '<li class="environmenttable">'.get_string($bypassstr, 'admin').'</li>';
228 }
95a39282 229 ///Process the restrict if necessary
230 if ($restrictstr = $environment_result->getRestrictStr()) {
231 $feedbacktext .= '<li class="environmenttable">'.get_string($restrictstr, 'admin').'</li>';
232 }
049c0f4a 233 }
234 }
235
236/// Print table
237 print_table($table);
e909788d 238
9e2d15e5 239/// And feedback accumulated text
240 if ($feedbacktext) {
cc60cd9b 241 print_simple_box('<ul>'.$feedbacktext.'</ul>', 'center', '90%', '', '', 'environmentbox generalbox');
9e2d15e5 242 }
243
e909788d 244/// Finally, if any error has happened, print the summary box
245 if (!$result) {
cc60cd9b 246 print_simple_box($strenvironmenterrortodo, 'center', '', '', '', 'environmentbox errorbox');
e909788d 247 }
f58b518f 248}
249
250
251/**
252 * This function will normalize any version to just a serie of numbers
253 * separated by dots. Everything else will be removed.
254 * @param string $version the original version
255 * @return string the normalized version
256 */
257function normalize_version($version) {
258/// Replace everything but numbers and dots by dots
259 $version = preg_replace('/[^\.\d]/', '.', $version);
260/// Combine multiple dots in one
261 $version = preg_replace('/(\.{2,})/', '.', $version);
262/// Trim possible leading and trailing dots
263 $version = trim($version, '.');
264
265 return $version;
266}
267
268
269/**
270 * This function will load the environment.xml file and xmlize it
271 * @return mixed the xmlized structure or false on error
272 */
273function load_environment_xml() {
274
275 global $CFG;
276
277 static $data; //Only load and xmlize once by request
278
279 if (!empty($data)) {
280 return $data;
281 }
282
00d3a0fd 283/// First of all, take a look inside $CFG->dataroot/environment/environment.xml
284 $file = $CFG->dataroot.'/environment/environment.xml';
38fca5d7 285 $internalfile = $CFG->dirroot.'/'.$CFG->admin.'/environment.xml';
286 if (!is_file($file) || !is_readable($file) || filemtime($file) < filemtime($internalfile) ||
287 !$contents = file_get_contents($file)) {
d83f8373 288 /// Fallback to fixed $CFG->admin/environment.xml
38fca5d7 289 if (!is_file($internalfile) || !is_readable($internalfile) || !$contents = file_get_contents($internalfile)) {
f58b518f 290 return false;
291 }
292 }
293/// XML the whole file
294 $data = xmlize($contents);
295
296 return $data;
297}
298
299
300/**
301 * This function will return the list of Moodle versions available
302 * @return mixed array of versions. False on error.
303 */
304function get_list_of_environment_versions ($contents) {
305
306 static $versions = array();
307
308 if (!empty($versions)) {
309 return $versions;
310 }
311
312 if (isset($contents['COMPATIBILITY_MATRIX']['#']['MOODLE'])) {
313 foreach ($contents['COMPATIBILITY_MATRIX']['#']['MOODLE'] as $version) {
314 $versions[] = $version['@']['version'];
315 }
316 }
317
318 return $versions;
319}
320
321
322/**
323 * This function will return the most recent version in the environment.xml
324 * file previous or equal to the version requested
325 * @param string version top version from which we start to look backwards
326 * @return string more recent version or false if not found
327 */
328function get_latest_version_available ($version) {
329
330/// Normalize the version requested
331 $version = normalize_version($version);
332
333/// Load xml file
334 if (!$contents = load_environment_xml()) {
335 return false;
336 }
337
338/// Detect available versions
339 if (!$versions = get_list_of_environment_versions($contents)) {
340 return false;
341 }
342/// First we look for exact version
343 if (in_array($version, $versions)) {
344 return $version;
345 } else {
346 $found_version = false;
347 /// Not exact match, so we are going to iterate over the list searching
348 /// for the latest version before the requested one
349 foreach ($versions as $arrversion) {
350 if (version_compare($arrversion, $version, '<')) {
351 $found_version = $arrversion;
352 }
353 }
354 }
355
356 return $found_version;
357}
358
359
360/**
361 * This function will return the xmlized data belonging to one Moodle version
362 * @return mixed the xmlized structure or false on error
363 */
364function get_environment_for_version($version) {
365
366/// Normalize the version requested
367 $version = normalize_version($version);
368
369/// Load xml file
370 if (!$contents = load_environment_xml()) {
371 return false;
372 }
373
374/// Detect available versions
375 if (!$versions = get_list_of_environment_versions($contents)) {
376 return false;
377 }
378
379/// If the version requested is available
380 if (!in_array($version, $versions)) {
381 return false;
382 }
383
384/// We now we have it. Extract from full contents.
385 $fl_arr = array_flip($versions);
386
387 return $contents['COMPATIBILITY_MATRIX']['#']['MOODLE'][$fl_arr[$version]];
388}
389
390
391/**
392 * This function will check for everything (DB, PHP and PHP extensions for now)
393 * returning an array of environment_result objects.
394 * @param string $version xml version we are going to use to test this server
395 * @return array array of results encapsulated in one environment_result object
396 */
397function environment_check($version) {
398
399/// Normalize the version requested
400 $version = normalize_version($version);
401
402 $results = array(); //To store all the results
403
a392be33 404 $results[] = environment_check_unicode($version);
f58b518f 405 $results[] = environment_check_database($version);
406 $results[] = environment_check_php($version);
407
408 $phpext_results = environment_check_php_extensions($version);
bac40536 409 $results = array_merge($results, $phpext_results);
f58b518f 410
bac40536 411 $custom_results = environment_custom_checks($version);
412 $results = array_merge($results, $custom_results);
f58b518f 413
414 return $results;
415}
416
417
418/**
419 * This function will check if php extensions requirements are satisfied
420 * @param string $version xml version we are going to use to test this server
421 * @return array array of results encapsulated in one environment_result object
422 */
423function environment_check_php_extensions($version) {
424
425 $results = array();
426
427/// Get the enviroment version we need
428 if (!$data = get_environment_for_version($version)) {
429 /// Error. No version data found
049c0f4a 430 $result = new environment_results('php_extension');
f58b518f 431 $result->setStatus(false);
432 $result->setErrorCode(NO_VERSION_DATA_FOUND);
433 return $result;
434 }
435
436/// Extract the php_extension part
437 if (!isset($data['#']['PHP_EXTENSIONS']['0']['#']['PHP_EXTENSION'])) {
438 /// Error. No PHP section found
049c0f4a 439 $result = new environment_results('php_extension');
f58b518f 440 $result->setStatus(false);
441 $result->setErrorCode(NO_PHP_EXTENSIONS_SECTION_FOUND);
442 return $result;
9e2d15e5 443 }
444/// Iterate over extensions checking them and creating the needed environment_results
445 foreach($data['#']['PHP_EXTENSIONS']['0']['#']['PHP_EXTENSION'] as $extension) {
446 $result = new environment_results('php_extension');
447 /// Check for level
bac40536 448 $level = get_level($extension);
9e2d15e5 449 /// Check for extension name
450 if (!isset($extension['@']['name'])) {
451 $result->setStatus(false);
452 $result->setErrorCode(NO_PHP_EXTENSIONS_NAME_FOUND);
453 } else {
454 $extension_name = $extension['@']['name'];
455 /// The name exists. Just check if it's an installed extension
456 if (!extension_loaded($extension_name)) {
f58b518f 457 $result->setStatus(false);
f58b518f 458 } else {
9e2d15e5 459 $result->setStatus(true);
f58b518f 460 }
9e2d15e5 461 $result->setLevel($level);
462 $result->setInfo($extension_name);
f58b518f 463 }
bac40536 464
465 /// Do any actions defined in the XML file.
466 process_environment_result($extension, $result);
b0e2a189 467
9e2d15e5 468 /// Add the result to the array of results
469 $results[] = $result;
f58b518f 470 }
471
9e2d15e5 472
f58b518f 473 return $results;
474}
475
bac40536 476/**
477 * This function will do the custom checks.
478 * @param string $version xml version we are going to use to test this server.
479 * @return array array of results encapsulated in environment_result objects.
480 */
481function environment_custom_checks($version) {
482 global $CFG;
483
484 $results = array();
485
486/// Get the enviroment version we need
487 if (!$data = get_environment_for_version($version)) {
488 /// Error. No version data found - but this will already have been reported.
489 return $results;
490 }
491
492/// Extract the CUSTOM_CHECKS part
493 if (!isset($data['#']['CUSTOM_CHECKS']['0']['#']['CUSTOM_CHECK'])) {
494 /// No custom checks found - not a problem
495 return $results;
496 }
497
498/// Iterate over extensions checking them and creating the needed environment_results
499 foreach($data['#']['CUSTOM_CHECKS']['0']['#']['CUSTOM_CHECK'] as $check) {
500 $result = new environment_results('custom_check');
501
502 /// Check for level
503 $level = get_level($check);
504
505 /// Check for extension name
506 if (isset($check['@']['file']) && isset($check['@']['function'])) {
507 $file = $CFG->dirroot . '/' . $check['@']['file'];
508 echo $file;
509 $function = $check['@']['function'];
510 if (is_readable($file)) {
511 include_once($file);
512 if (function_exists($function)) {
513 $result->setLevel($level);
514 $result->setInfo($function);
515 $result = $function($result);
516 } else {
517 $result->setStatus(false);
518 $result->setErrorCode(CUSTOM_CHECK_FUNCTION_MISSING);
519 }
520 } else {
521 $result->setStatus(false);
522 $result->setErrorCode(CUSTOM_CHECK_FILE_MISSING);
523 }
524 } else {
525 $result->setStatus(false);
526 $result->setErrorCode(NO_CUSTOM_CHECK_FOUND);
527 }
528
529 if (!is_null($result)) {
530 /// Do any actions defined in the XML file.
531 process_environment_result($check, $result);
532
533 /// Add the result to the array of results
534 $results[] = $result;
535 }
536 }
537
538 return $results;
539}
f58b518f 540
541/**
542 * This function will check if php requirements are satisfied
543 * @param string $version xml version we are going to use to test this server
544 * @return object results encapsulated in one environment_result object
545 */
546function environment_check_php($version) {
547
548 $result = new environment_results('php');
549
550/// Get the enviroment version we need
551 if (!$data = get_environment_for_version($version)) {
552 /// Error. No version data found
553 $result->setStatus(false);
554 $result->setErrorCode(NO_VERSION_DATA_FOUND);
555 return $result;
556 }
557
558/// Extract the php part
559 if (!isset($data['#']['PHP'])) {
560 /// Error. No PHP section found
561 $result->setStatus(false);
562 $result->setErrorCode(NO_PHP_SECTION_FOUND);
563 return $result;
564 } else {
565 /// Extract level and version
bac40536 566 $level = get_level($data['#']['PHP']['0']);
f58b518f 567 if (!isset($data['#']['PHP']['0']['@']['version'])) {
568 $result->setStatus(false);
569 $result->setErrorCode(NO_PHP_VERSION_FOUND);
570 return $result;
571 } else {
572 $needed_version = $data['#']['PHP']['0']['@']['version'];
573 }
574 }
575
576/// Now search the version we are using
577 $current_version = normalize_version(phpversion());
578
579/// And finally compare them, saving results
580 if (version_compare($current_version, $needed_version, '>=')) {
581 $result->setStatus(true);
582 } else {
583 $result->setStatus(false);
f58b518f 584 }
585 $result->setLevel($level);
586 $result->setCurrentVersion($current_version);
587 $result->setNeededVersion($needed_version);
bac40536 588
589/// Do any actions defined in the XML file.
590 process_environment_result($data['#']['PHP'][0], $result);
f58b518f 591
592 return $result;
593}
594
595
a392be33 596/**
597 * This function will check if unicode database requirements are satisfied
598 * @param string $version xml version we are going to use to test this server
599 * @return object results encapsulated in one environment_result object
600 */
601function environment_check_unicode($version) {
602 global $db;
603
604 $result = new environment_results('unicode');
605
606 /// Get the enviroment version we need
607 if (!$data = get_environment_for_version($version)) {
608 /// Error. No version data found
609 $result->setStatus(false);
610 $result->setErrorCode(NO_VERSION_DATA_FOUND);
611 return $result;
612 }
613
614 /// Extract the unicode part
615
616 if (!isset($data['#']['UNICODE'])) {
617 /// Error. No DATABASE section found
618 $result->setStatus(false);
619 $result->setErrorCode(NO_UNICODE_SECTION_FOUND);
620 return $result;
621 } else {
622 /// Extract level
bac40536 623 $level = get_level($data['#']['UNICODE']['0']);
a392be33 624 }
625
626 if (!$unicodedb = setup_is_unicodedb()) {
627 $result->setStatus(false);
628 } else {
629 $result->setStatus(true);
630 }
631
632 $result->setLevel($level);
633
bac40536 634/// Do any actions defined in the XML file.
635 process_environment_result($data['#']['UNICODE'][0], $result);
a392be33 636
637 return $result;
638}
639
f58b518f 640/**
641 * This function will check if database requirements are satisfied
642 * @param string $version xml version we are going to use to test this server
643 * @return object results encapsulated in one environment_result object
644 */
645function environment_check_database($version) {
646
647 global $db;
648
649 $result = new environment_results('database');
650
651 $vendors = array(); //Array of vendors in version
652
653/// Get the enviroment version we need
654 if (!$data = get_environment_for_version($version)) {
655 /// Error. No version data found
656 $result->setStatus(false);
657 $result->setErrorCode(NO_VERSION_DATA_FOUND);
658 return $result;
659 }
660
661/// Extract the database part
662 if (!isset($data['#']['DATABASE'])) {
663 /// Error. No DATABASE section found
664 $result->setStatus(false);
665 $result->setErrorCode(NO_DATABASE_SECTION_FOUND);
666 return $result;
667 } else {
668 /// Extract level
bac40536 669 $level = get_level($data['#']['DATABASE']['0']);
f58b518f 670 }
671
672/// Extract DB vendors. At least 2 are mandatory (mysql & postgres)
673 if (!isset($data['#']['DATABASE']['0']['#']['VENDOR'])) {
674 /// Error. No VENDORS found
675 $result->setStatus(false);
676 $result->setErrorCode(NO_DATABASE_VENDORS_FOUND);
677 return $result;
678 } else {
679 /// Extract vendors
680 foreach ($data['#']['DATABASE']['0']['#']['VENDOR'] as $vendor) {
681 if (isset($vendor['@']['name']) && isset($vendor['@']['version'])) {
682 $vendors[$vendor['@']['name']] = $vendor['@']['version'];
9e2d15e5 683 $vendorsxml[$vendor['@']['name']] = $vendor;
f58b518f 684 }
685 }
686 }
687/// Check we have the mysql vendor version
688 if (empty($vendors['mysql'])) {
689 $result->setStatus(false);
690 $result->setErrorCode(NO_DATABASE_VENDOR_MYSQL_FOUND);
691 return $result;
692 }
693/// Check we have the postgres vendor version
694 if (empty($vendors['postgres'])) {
695 $result->setStatus(false);
696 $result->setErrorCode(NO_DATABASE_VENDOR_POSTGRES_FOUND);
697 return $result;
698 }
699
700/// Now search the version we are using (depending of vendor)
ed7656bf 701 $current_vendor = set_dbfamily();
702
f58b518f 703 $dbinfo = $db->ServerInfo();
704 $current_version = normalize_version($dbinfo['version']);
705 $needed_version = $vendors[$current_vendor];
706
e3058eb3 707/// Check we have a needed version
708 if (!$needed_version) {
709 $result->setStatus(false);
710 $result->setErrorCode(NO_DATABASE_VENDOR_VERSION_FOUND);
711 return $result;
712 }
713
f58b518f 714/// And finally compare them, saving results
715 if (version_compare($current_version, $needed_version, '>=')) {
716 $result->setStatus(true);
717 } else {
718 $result->setStatus(false);
f58b518f 719 }
720 $result->setLevel($level);
721 $result->setCurrentVersion($current_version);
722 $result->setNeededVersion($needed_version);
723 $result->setInfo($current_vendor);
724
bac40536 725/// Do any actions defined in the XML file.
726 process_environment_result($vendorsxml[$current_vendor], $result);
9e2d15e5 727
f58b518f 728 return $result;
729
730}
731
b0e2a189 732/**
733 * This function will post-process the result record by executing the specified
734 * function, modifying it as necessary, also a custom message will be added
735 * to the result object to be printed by the display layer.
736 * Every bypass function must be defined in this file and it'll return
737 * true/false to decide if the original test is bypassed or no. Also
738 * such bypass functions are able to directly handling the result object
739 * although it should be only under exceptional conditions.
740 *
741 * @param string xmldata containing the bypass data
95a39282 742 * @param object result object to be updated
b0e2a189 743 */
744function process_environment_bypass($xml, &$result) {
745
76bb0d20 746/// Only try to bypass if we were in error and it was required
747 if ($result->getStatus() || $result->getLevel() == 'optional') {
b0e2a189 748 return;
749 }
750
751/// It there is bypass info (function and message)
74506a51 752 if (is_array($xml['#']) && isset($xml['#']['BYPASS'][0]['@']['function']) && isset($xml['#']['BYPASS'][0]['@']['message'])) {
b0e2a189 753 $function = $xml['#']['BYPASS'][0]['@']['function'];
754 $message = $xml['#']['BYPASS'][0]['@']['message'];
755 /// Look for the function
756 if (function_exists($function)) {
757 /// Call it, and if bypass = true is returned, apply meesage
758 if ($function($result)) {
759 /// We only set the bypass message if the function itself hasn't defined it before
760 if (empty($result->getBypassStr)) {
761 $result->setBypassStr($message);
762 }
763 }
764 }
765 }
766}
767
95a39282 768/**
769 * This function will post-process the result record by executing the specified
770 * function, modifying it as necessary, also a custom message will be added
771 * to the result object to be printed by the display layer.
772 * Every restrict function must be defined in this file and it'll return
773 * true/false to decide if the original test is restricted or no. Also
774 * such restrict functions are able to directly handling the result object
775 * although it should be only under exceptional conditions.
776 *
777 * @param string xmldata containing the restrict data
778 * @param object result object to be updated
779 */
780function process_environment_restrict($xml, &$result) {
781
782/// Only try to restrict if we were not in error and it was required
783 if (!$result->getStatus() || $result->getLevel() == 'optional') {
784 return;
785 }
786/// It there is restrict info (function and message)
787 if (is_array($xml['#']) && isset($xml['#']['RESTRICT'][0]['@']['function']) && isset($xml['#']['RESTRICT'][0]['@']['message'])) {
788 $function = $xml['#']['RESTRICT'][0]['@']['function'];
789 $message = $xml['#']['RESTRICT'][0]['@']['message'];
790 /// Look for the function
791 if (function_exists($function)) {
792 /// Call it, and if restrict = true is returned, apply meesage
793 if ($function($result)) {
794 /// We only set the restrict message if the function itself hasn't defined it before
795 if (empty($result->getRestrictStr)) {
796 $result->setRestrictStr($message);
797 }
798 }
799 }
800 }
801}
802
9e2d15e5 803/**
804 * This function will detect if there is some message available to be added to the
805 * result in order to clarify enviromental details.
b0e2a189 806 * @param string xmldata containing the feedback data
9e2d15e5 807 * @param object reult object to be updated
808 */
809function process_environment_messages($xml, &$result) {
810
811/// If there is feedback info
74506a51 812 if (is_array($xml['#']) && isset($xml['#']['FEEDBACK'][0]['#'])) {
9e2d15e5 813 $feedbackxml = $xml['#']['FEEDBACK'][0]['#'];
814
815 if (!$result->status and $result->getLevel() == 'required') {
816 if (isset($feedbackxml['ON_ERROR'][0]['@']['message'])) {
817 $result->setFeedbackStr($feedbackxml['ON_ERROR'][0]['@']['message']);
818 }
819 } else if (!$result->status and $result->getLevel() == 'optional') {
820 if (isset($feedbackxml['ON_CHECK'][0]['@']['message'])) {
821 $result->setFeedbackStr($feedbackxml['ON_CHECK'][0]['@']['message']);
822 }
823 } else {
824 if (isset($feedbackxml['ON_OK'][0]['@']['message'])) {
825 $result->setFeedbackStr($feedbackxml['ON_OK'][0]['@']['message']);
826 }
827 }
828 }
829}
830
f58b518f 831
832//--- Helper Class to return results to caller ---//
833
834
835/**
836 * This class is used to return the results of the environment
837 * main functions (environment_check_xxxx)
838 */
839class environment_results {
840
049c0f4a 841 var $part; //which are we checking (database, php, php_extension)
f58b518f 842 var $status; //true/false
843 var $error_code; //integer. See constants at the beginning of the file
844 var $level; //required/optional
845 var $current_version; //current version detected
846 var $needed_version; //version needed
847 var $info; //Aux. info (DB vendor, library...)
9e2d15e5 848 var $feedback_str; //String to show on error|on check|on ok
849 var $bypass_str; //String to show if some bypass has happened
95a39282 850 var $restrict_str; //String to show if some restrict has happened
f58b518f 851
852 /**
853 * Constructor of the environment_result class. Just set default values
854 */
855 function environment_results($part) {
856 $this->part=$part;
857 $this->status=false;
049c0f4a 858 $this->error_code=NO_ERROR;
f58b518f 859 $this->level='required';
860 $this->current_version='';
861 $this->needed_version='';
862 $this->info='';
9e2d15e5 863 $this->feedback_str='';
864 $this->bypass_str='';
95a39282 865 $this->restrict_str='';
f58b518f 866 }
867
868 /**
869 * Set the status
870 * @param boolean the status (true/false)
871 */
872 function setStatus($status) {
873 $this->status=$status;
874 if ($status) {
875 $this->setErrorCode(NO_ERROR);
876 }
877 }
878
879 /**
880 * Set the error_code
881 * @param integer the error code (see constants above)
882 */
883 function setErrorCode($error_code) {
884 $this->error_code=$error_code;
885 }
886
887 /**
888 * Set the level
889 * @param string the level (required, optional)
890 */
891 function setLevel($level) {
892 $this->level=$level;
893 }
894
895 /**
896 * Set the current version
897 * @param string the current version
898 */
899 function setCurrentVersion($current_version) {
900 $this->current_version=$current_version;
901 }
902
903 /**
904 * Set the needed version
905 * @param string the needed version
906 */
907 function setNeededVersion($needed_version) {
908 $this->needed_version=$needed_version;
909 }
910
911 /**
912 * Set the auxiliary info
913 * @param string the auxiliary info
914 */
9e2d15e5 915 function setInfo($info) {
916 $this->info=$info;
917 }
918
919 /**
920 * Set the feedback string
921 * @param string the feedback string
922 */
923 function setFeedbackStr($str) {
924 $this->feedback_str=$str;
925 }
f58b518f 926
b0e2a189 927 /**
928 * Set the bypass string
929 * @param string the bypass string
930 */
931 function setBypassStr($str) {
932 $this->bypass_str=$str;
933 }
934
95a39282 935 /**
936 * Set the restrict string
937 * @param string the restrict string
938 */
939 function setRestrictStr($str) {
940 $this->restrict_str=$str;
941 }
942
f58b518f 943 /**
944 * Get the status
945 * @return boolean result
946 */
947 function getStatus() {
948 return $this->status;
949 }
950
951 /**
952 * Get the error code
953 * @return integer error code
954 */
955 function getErrorCode() {
956 return $this->error_code;
957 }
958
959 /**
960 * Get the level
961 * @return string level
962 */
963 function getLevel() {
964 return $this->level;
965 }
966
967 /**
968 * Get the current version
969 * @return string current version
970 */
971 function getCurrentVersion() {
972 return $this->current_version;
973 }
974
975 /**
976 * Get the needed version
977 * @return string needed version
978 */
979 function getNeededVersion() {
980 return $this->needed_version;
981 }
982
983 /**
984 * Get the aux info
985 * @return string info
986 */
987 function getInfo() {
988 return $this->info;
989 }
990
991 /**
992 * Get the part this result belongs to
993 * @return string part
994 */
995 function getPart() {
996 return $this->part;
997 }
9e2d15e5 998
999 /**
1000 * Get the feedback string
1001 * @return string feedback string
1002 */
1003 function getFeedbackStr() {
1004 return $this->feedback_str;
1005 }
b0e2a189 1006
1007 /**
1008 * Get the bypass string
1009 * @return string bypass string
1010 */
1011 function getBypassStr() {
1012 return $this->bypass_str;
1013 }
95a39282 1014
1015 /**
1016 * Get the restrict string
1017 * @return string restrict string
1018 */
1019 function getRestrictStr() {
1020 return $this->restrict_str;
1021 }
f58b518f 1022}
1023
9e2d15e5 1024/// Here all the bypass functions are coded to be used by the environment
1025/// checker. All those functions will receive the result object and will
1026/// return it modified as needed (status and bypass string)
1027
b0e2a189 1028/**
1029 * This function will bypass MySQL 4.1.16 reqs if:
1030 * - We are using MySQL > 4.1.12, informing about problems with non latin chars in the future
1031 *
1032 * @param object result object to handle
95a39282 1033 * @return boolean true/false to determinate if the bypass has to be performed (true) or no (false)
b0e2a189 1034 */
1035function bypass_mysql416_reqs ($result) {
1036/// See if we are running MySQL >= 4.1.12
1037 if (version_compare($result->getCurrentVersion(), '4.1.12', '>=')) {
1038 return true;
1039 }
1040
1041 return false;
1042}
1043
95a39282 1044/// Here all the restrict functions are coded to be used by the environment
1045/// checker. All those functions will receive the result object and will
1046/// return it modified as needed (status and bypass string)
1047
1048/**
1049 * This function will restrict PHP reqs if:
1050 * - We are using PHP 5.0.x, informing about the buggy version
1051 *
1052 * @param object result object to handle
1053 * @return boolean true/false to determinate if the restrict has to be performed (true) or no (false)
1054 */
1055function restrict_php50_version($result) {
1056 if (version_compare($result->getCurrentVersion(), '5.0.0', '>=')
1057 and version_compare($result->getCurrentVersion(), '5.0.99', '<')) {
1058 return true;
1059 }
1060 return false;
1061}
bac40536 1062
1063/**
1064 * @param array $element the element from the environment.xml file that should have
1065 * either a level="required" or level="optional" attribute.
1066 * @read string "required" or "optional".
1067 */
1068function get_level($element) {
1069 $level = 'required';
1070 if (isset($element['@']['level'])) {
1071 $level = $element['@']['level'];
1072 if (!in_array($level, array('required', 'optional'))) {
1073 debugging('The level of a check in the environment.xml file must be "required" or level="optional".', DEBUG_DEVELOPER);
1074 $level = 'required';
1075 }
1076 } else {
1077 debugging('Checks in the environment.xml file must have a level="required" or level="optional" attribute.', DEBUG_DEVELOPER);
1078 }
1079 return $level;
1080}
1081
1082/**
1083 * Once the result has been determined, look in the XML for any
1084 * messages, or other things that should be done depending on the outcome.
1085 * @param array $element the element from the environment.xml file which
1086 * may have children defining what should be done with the outcome.
1087 * @param object $result the result of the test, which may be modified by
1088 * this function as specified in the XML.
1089 */
1090function process_environment_result($element, &$result) {
1091/// Process messages, modifying the $result if needed.
1092 process_environment_messages($element, $result);
1093/// Process bypass, modifying $result if needed.
1094 process_environment_bypass($element, $result);
1095/// Process restrict, modifying $result if needed.
1096 process_environment_restrict($element, $result);
1097}
f58b518f 1098?>