diff --git a/admin/environment.php b/admin/environment.php index 89871e57d78..479fe5c1fdb 100644 --- a/admin/environment.php +++ b/admin/environment.php @@ -24,524 +24,8 @@ // // /////////////////////////////////////////////////////////////////////////// -// This file includes all the necessary stuff to execute some standard -// test of required versions and libraries to run Moodle. It can be -// invoked from the admin interface, and both at install and upgrade. -// -// All the info is stored in the environment.xml file +// This file is the admin frontend to execute all the checks available +// in the environment.xml file. It includes database, php and +// php_extensions. Also, it's possible to update the xml file +// from moodle.org be able to check more and more versions. -require_once($CFG->libdir.'/xmlize.php'); - -define(NO_ERROR, 0); -define(NO_VERSION_DATA_FOUND, 1); -define(NO_DATABASE_SECTION_FOUND, 2); -define(NO_DATABASE_VENDORS_FOUND, 3); -define(NO_DATABASE_VENDOR_MYSQL_FOUND, 4); -define(NO_DATABASE_VENDOR_POSTGRES_FOUND, 5); -define(DATABASE_OLD_VERSION, 6); -define(NO_PHP_SECTION_FOUND, 7); -define(NO_PHP_VERSION_FOUND, 8); -define(PHP_OLD_VERSION, 9); -define(NO_PHP_EXTENSIONS_SECTION_FOUND, 10); -define(NO_PHP_EXTENSIONS_NAME_FOUND, 11); -define(NO_PHP_EXTENSION_WITH_NAME, 12); - - - - -//--- Presentation functions to display all the interface ---// - - - - - - - - - - -//--- Logic functions to parse and detect everything ---// - -/** - * This function will perform the whole check, returning - * true or false as final result. Also, he full array of - * environment_result will be returned in the parameter list. - * The function looks for the best version to compare and - * everything. This is the only function that should be called - * ever from the rest of Moodle. - * @param string version version to check. - * @param array results array of results checked. - * @return boolean true/false, depending of results - */ -function check_moodle_environment($version, &$environment_results) { - -/// Get the more recent version before the requested - if (!$version = get_latest_version_available($version)) { - return false; - } - -/// Perform all the checks - if(!$environment_results = environment_check($version)) { - return false; - } - -/// Iterate over all the results looking for some error in required items - foreach ($environment_results as $environment_result) { - if (empty($environment_result->result) && $environment_result->level == 'required') { - return false; - } - } - - return true; -} - - - -/** - * This function will normalize any version to just a serie of numbers - * separated by dots. Everything else will be removed. - * @param string $version the original version - * @return string the normalized version - */ -function normalize_version($version) { -/// Replace everything but numbers and dots by dots - $version = preg_replace('/[^\.\d]/', '.', $version); -/// Combine multiple dots in one - $version = preg_replace('/(\.{2,})/', '.', $version); -/// Trim possible leading and trailing dots - $version = trim($version, '.'); - - return $version; -} - -/** - * This function will load the environment.xml file and xmlize it - * @return mixed the xmlized structure or false on error - */ -function load_environment_xml() { - - global $CFG; - - static $data; //Only load and xmlize once by request - - if (!empty($data)) { - return $data; - } - -/// First of all, take a look inside $CFG->moodledata/environment/environment.xml - $file = $CFG->moodledata.'/environment/environment.xml'; - if (!is_file($file) || !is_readable($file) || !$contents = file_get_contents($file)) { - /// Fallback to fixed admin/environment.xml - $file = $CFG->dirroot.'/admin/environment.xml'; - if (!is_file($file) || !is_readable($file) || !$contents = file_get_contents($file)) { - return false; - } - } -/// XML the whole file - $data = xmlize($contents); - - return $data; -} - -/** - * This function will return the list of Moodle versions available - * @return mixed array of versions. False on error. - */ -function get_list_of_environment_versions ($contents) { - - static $versions = array(); - - if (!empty($versions)) { - return $versions; - } - - if (isset($contents['COMPATIBILITY_MATRIX']['#']['MOODLE'])) { - foreach ($contents['COMPATIBILITY_MATRIX']['#']['MOODLE'] as $version) { - $versions[] = $version['@']['version']; - } - } - - return $versions; -} - -/** - * This function will return the most recent version in the environment.xml - * file previous or equal to the version requested - * @param string version top version from which we start to look backwards - * @return string more recent version or false if not found - */ -function get_latest_version_available ($version) { - -/// Normalize the version requested - $version = normalize_version($version); - -/// Load xml file - if (!$contents = load_environment_xml()) { - return false; - } - -/// Detect available versions - if (!$versions = get_list_of_environment_versions($contents)) { - return false; - } -/// First we look for exact version - if (in_array($version, $versions)) { - return $version; - } else { - $found_version = false; - /// Not exact match, so we are going to iterate over the list searching - /// for the latest version before the requested one - foreach ($versions as $arrversion) { - if (version_compare($arrversion, $version, '<')) { - $found_version = $arrversion; - } - } - } - - return $found_version; -} - -/** - * This function will return the xmlized data belonging to one Moodle version - * @return mixed the xmlized structure or false on error - */ -function get_environment_for_version($version) { - -/// Normalize the version requested - $version = normalize_version($version); - -/// Load xml file - if (!$contents = load_environment_xml()) { - return false; - } - -/// Detect available versions - if (!$versions = get_list_of_environment_versions($contents)) { - return false; - } - -/// If the version requested is available - if (!in_array($version, $versions)) { - return false; - } - -/// We now we have it. Extract from full contents. - $fl_arr = array_flip($versions); - - return $contents['COMPATIBILITY_MATRIX']['#']['MOODLE'][$fl_arr[$version]]; -} - -/** - * This function will check for everything (DB, PHP and PHP extensions for now) - * returning an array of environment_result objects. - * @param string $version xml version we are going to use to test this server - * @return array array of results encapsulated in one environment_result object - */ -function environment_check($version) { - -/// Normalize the version requested - $version = normalize_version($version); - - $results = array(); //To store all the results - - $results[] = environment_check_database($version); - $results[] = environment_check_php($version); - - $phpext_results = environment_check_php_extensions($version); - - $results = array_merge ($results, $phpext_results); - - return $results; -} - -/** - * This function will check if php extensions requirements are satisfied - * @param string $version xml version we are going to use to test this server - * @return array array of results encapsulated in one environment_result object - */ -function environment_check_php_extensions($version) { - - $results = array(); - -/// Get the enviroment version we need - if (!$data = get_environment_for_version($version)) { - /// Error. No version data found - $result = new environment_results('php_extensions'); - $result->setStatus(false); - $result->setErrorCode(NO_VERSION_DATA_FOUND); - return $result; - } - -/// Extract the php_extension part - if (!isset($data['#']['PHP_EXTENSIONS']['0']['#']['PHP_EXTENSION'])) { - /// Error. No PHP section found - $result = new environment_results('php_extensions'); - $result->setStatus(false); - $result->setErrorCode(NO_PHP_EXTENSIONS_SECTION_FOUND); - return $result; - } else { - /// Iterate over extensions checking them and creating the needed environment_results - foreach($data['#']['PHP_EXTENSIONS']['0']['#']['PHP_EXTENSION'] as $extension) { - $result = new environment_results('php_extensions'); - /// Check for level - if (isset($extension['@']['level'])) { - $level = $extension['@']['level']; - if ($level != 'optional') { - $level = 'required'; - } - } - /// Check for extension name - if (!isset($extension['@']['name'])) { - $result->setStatus(false); - $result->setErrorCode(NO_PHP_EXTENSIONS_NAME_FOUND); - } else { - $extension_name = $extension['@']['name']; - /// The name exists. Just check if it's an installed extension - if (!extension_loaded($extension_name)) { - $result->setStatus(false); - $result->setErrorCode(NO_PHP_EXTENSION_WITH_NAME); - } else { - $result->setStatus(true); - } - $result->setLevel($level); - $result->setInfo($extension_name); - } - /// Add the result to the array of results - $results[] = $result; - } - } - - return $results; -} - -/** - * This function will check if php requirements are satisfied - * @param string $version xml version we are going to use to test this server - * @return object results encapsulated in one environment_result object - */ -function environment_check_php($version) { - - $result = new environment_results('php'); - -/// Get the enviroment version we need - if (!$data = get_environment_for_version($version)) { - /// Error. No version data found - $result->setStatus(false); - $result->setErrorCode(NO_VERSION_DATA_FOUND); - return $result; - } - -/// Extract the php part - if (!isset($data['#']['PHP'])) { - /// Error. No PHP section found - $result->setStatus(false); - $result->setErrorCode(NO_PHP_SECTION_FOUND); - return $result; - } else { - /// Extract level and version - if (isset($data['#']['PHP']['0']['@']['level'])) { - $level = $data['#']['PHP']['0']['level']; - if ($level != 'optional') { - $level = 'required'; - } - } - if (!isset($data['#']['PHP']['0']['@']['version'])) { - $result->setStatus(false); - $result->setErrorCode(NO_PHP_VERSION_FOUND); - return $result; - } else { - $needed_version = $data['#']['PHP']['0']['@']['version']; - } - } - -/// Now search the version we are using - $current_version = normalize_version(phpversion()); - -/// And finally compare them, saving results - if (version_compare($current_version, $needed_version, '>=')) { - $result->setStatus(true); - } else { - $result->setStatus(false); - $result->setErrorCode(PHP_OLD_VERSION); - } - $result->setLevel($level); - $result->setCurrentVersion($current_version); - $result->setNeededVersion($needed_version); - - return $result; -} - -/** - * This function will check if database requirements are satisfied - * @param string $version xml version we are going to use to test this server - * @return object results encapsulated in one environment_result object - */ -function environment_check_database($version) { - - global $db; - - $result = new environment_results('database'); - - $vendors = array(); //Array of vendors in version - -/// Get the enviroment version we need - if (!$data = get_environment_for_version($version)) { - /// Error. No version data found - $result->setStatus(false); - $result->setErrorCode(NO_VERSION_DATA_FOUND); - return $result; - } - -/// Extract the database part - if (!isset($data['#']['DATABASE'])) { - /// Error. No DATABASE section found - $result->setStatus(false); - $result->setErrorCode(NO_DATABASE_SECTION_FOUND); - return $result; - } else { - /// Extract level - if (isset($data['#']['DATABASE']['0']['@']['level'])) { - $level = $data['#']['DATABASE']['0']['level']; - if ($level != 'optional') { - $level = 'required'; - } - } - } - -/// Extract DB vendors. At least 2 are mandatory (mysql & postgres) - if (!isset($data['#']['DATABASE']['0']['#']['VENDOR'])) { - /// Error. No VENDORS found - $result->setStatus(false); - $result->setErrorCode(NO_DATABASE_VENDORS_FOUND); - return $result; - } else { - /// Extract vendors - foreach ($data['#']['DATABASE']['0']['#']['VENDOR'] as $vendor) { - if (isset($vendor['@']['name']) && isset($vendor['@']['version'])) { - $vendors[$vendor['@']['name']] = $vendor['@']['version']; - } - } - } -/// Check we have the mysql vendor version - if (empty($vendors['mysql'])) { - $result->setStatus(false); - $result->setErrorCode(NO_DATABASE_VENDOR_MYSQL_FOUND); - return $result; - } -/// Check we have the postgres vendor version - if (empty($vendors['postgres'])) { - $result->setStatus(false); - $result->setErrorCode(NO_DATABASE_VENDOR_POSTGRES_FOUND); - return $result; - } - -/// Now search the version we are using (depending of vendor) - $current_vendor = $db->databaseType; - $dbinfo = $db->ServerInfo(); - $current_version = normalize_version($dbinfo['version']); - $needed_version = $vendors[$current_vendor]; - -/// And finally compare them, saving results - if (version_compare($current_version, $needed_version, '>=')) { - $result->setStatus(true); - } else { - $result->setStatus(false); - $result->setErrorCode(DATABASE_OLD_VERSION); - } - $result->setLevel($level); - $result->setCurrentVersion($current_version); - $result->setNeededVersion($needed_version); - $result->setInfo($current_vendor); - - return $result; - -} - - - - -//--- Helper Class to return results to caller ---// - - - - - -/** - * This class is used to return the results of the environment - * main functions (environment_check_xxxx) - */ -class environment_results { - - var $result; //true/false - var $error_code; //integer. See constants at the beginning of the file - var $level; //required/optional - var $current_version; //current version detected - var $needed_version; //version needed - var $info; //Aux. info (DB vendor, library...) - - /** - * Constructor of the environment_result class. Just set default values - */ - function environment_results($part) { - $this->part=$part; - $this->result=false; - $this->error_code=NOTHING_CHECKED_YET; - $this->level='required'; - $this->current_version=''; - $this->needed_version=''; - $this->info=array(); - } - - /** - * Set the result - * @param boolean the result (true/false) - */ - function setStatus($result) { - $this->result=$result; - if (result) { - $this->setErrorCode(NO_ERROR); - } - } - - /** - * Set the error_code - * @param integer the error code (see constants above) - */ - function setErrorCode($error_code) { - $this->error_code=$error_code; - } - - /** - * Set the level - * @param string the level (required, optional) - */ - function setLevel($level) { - $this->level=$level; - } - - /** - * Set the current version - * @param string the current version - */ - function setCurrentVersion($current_version) { - $this->current_version=$current_version; - } - - /** - * Set the needed version - * @param string the needed version - */ - function setNeededVersion($needed_version) { - $this->needed_version=$needed_version; - } - - /** - * Set the auxiliary info - * @param string the auxiliary info - */ - function setInfo($info) { - $this->info[]=$info; - } -} - -?>