Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
 
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/>.
17
 
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
 */
31
 
32
defined('MOODLE_INTERNAL') || die();
33
 
34
/// Add required files
35
/**
36
 * Include the necessary
37
 */
38
    require_once($CFG->libdir.'/xmlize.php');
39
 
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);
73
    /** XML Processing Error */
74
    define('INCORRECT_FEEDBACK_FOR_REQUIRED',   16);
75
    /** XML Processing Error */
76
    define('INCORRECT_FEEDBACK_FOR_OPTIONAL',   17);
77
 
78
/// Define algorithm used to select the xml file
79
    /** To select the newer file available to perform checks */
80
    define('ENV_SELECT_NEWER',                   0);
81
    /** To enforce the use of the file under dataroot */
82
    define('ENV_SELECT_DATAROOT',                1);
83
    /** To enforce the use of the file under admin (release) */
84
    define('ENV_SELECT_RELEASE',                 2);
85
 
86
/**
87
 * This function checks all the requirements defined in environment.xml.
88
 *
89
 * @param string $version version to check.
90
 * @param int $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use. Default ENV_SELECT_NEWER (BC)
91
 * @return array with two elements. The first element true/false, depending on
92
 *      on whether the check passed. The second element is an array of environment_results
93
 *      objects that has detailed information about the checks and which ones passed.
94
 */
95
function check_moodle_environment($version, $env_select = ENV_SELECT_NEWER) {
96
    if ($env_select != ENV_SELECT_NEWER and $env_select != ENV_SELECT_DATAROOT and $env_select != ENV_SELECT_RELEASE) {
97
        throw new coding_exception('Incorrect value of $env_select parameter');
98
    }
99
 
100
/// Get the more recent version before the requested
101
    if (!$version = get_latest_version_available($version, $env_select)) {
102
        return array(false, array());
103
    }
104
 
105
/// Perform all the checks
106
    if (!$environment_results = environment_check($version, $env_select)) {
107
        return array(false, array());
108
    }
109
 
110
/// Iterate over all the results looking for some error in required items
111
/// or some error_code
112
    $result = true;
113
    foreach ($environment_results as $environment_result) {
114
        if (!$environment_result->getStatus() && $environment_result->getLevel() == 'required'
115
          && !$environment_result->getBypassStr()) {
116
            $result = false; // required item that is not bypased
117
        } else if ($environment_result->getStatus() && $environment_result->getLevel() == 'required'
118
          && $environment_result->getRestrictStr()) {
119
            $result = false; // required item that is restricted
120
        } else if ($environment_result->getErrorCode()) {
121
            $result = false;
122
        }
123
    }
124
 
125
    return array($result, $environment_results);
126
}
127
 
128
 
129
/**
130
 * Returns array of critical errors in plain text format
131
 * @param array $environment_results array of results gathered
132
 * @return array errors
133
 */
134
function environment_get_errors($environment_results) {
135
    global $CFG;
136
    $errors = array();
137
 
138
    // Iterate over each environment_result
139
    foreach ($environment_results as $environment_result) {
140
        $type = $environment_result->getPart();
141
        $info = $environment_result->getInfo();
142
        $status = $environment_result->getStatus();
143
        $plugin = $environment_result->getPluginName();
144
        $error_code = $environment_result->getErrorCode();
145
 
146
        $a = new stdClass();
147
        if ($error_code) {
148
            $a->error_code = $error_code;
149
            $errors[] = array($info, get_string('environmentxmlerror', 'admin', $a));
150
            return $errors;
151
        }
152
 
153
        /// Calculate the status value
154
        if ($environment_result->getBypassStr() != '') {
155
            // not interesting
156
            continue;
157
        } else if ($environment_result->getRestrictStr() != '') {
158
            // error
159
        } else {
160
            if ($status) {
161
                // ok
162
                continue;
163
            } else {
164
                if ($environment_result->getLevel() == 'optional') {
165
                    // just a warning
166
                    continue;
167
                } else {
168
                    // error
169
                }
170
            }
171
        }
172
 
173
        // We are comparing versions
174
        $rec = new stdClass();
175
        if ($rec->needed = $environment_result->getNeededVersion()) {
176
            $rec->current = $environment_result->getCurrentVersion();
177
            if ($environment_result->getLevel() == 'required') {
178
                $stringtouse = 'environmentrequireversion';
179
            } else {
180
                $stringtouse = 'environmentrecommendversion';
181
            }
182
        // We are checking installed & enabled things
183
        } else if ($environment_result->getPart() == 'custom_check') {
184
            if ($environment_result->getLevel() == 'required') {
185
                $stringtouse = 'environmentrequirecustomcheck';
186
            } else {
187
                $stringtouse = 'environmentrecommendcustomcheck';
188
            }
189
        } else if ($environment_result->getPart() == 'php_setting') {
190
            if ($status) {
191
                $stringtouse = 'environmentsettingok';
192
            } else if ($environment_result->getLevel() == 'required') {
193
                $stringtouse = 'environmentmustfixsetting';
194
            } else {
195
                $stringtouse = 'environmentshouldfixsetting';
196
            }
197
        } else {
198
            if ($environment_result->getLevel() == 'required') {
199
                $stringtouse = 'environmentrequireinstall';
200
            } else {
201
                $stringtouse = 'environmentrecommendinstall';
202
            }
203
        }
204
        $report = get_string($stringtouse, 'admin', $rec);
205
 
206
        // Here we'll store all the feedback found
207
        $feedbacktext = '';
208
        // Append  the feedback if there is some
209
        $feedbacktext .= $environment_result->strToReport($environment_result->getFeedbackStr(), 'error');
210
        // Append the restrict if there is some
211
        $feedbacktext .= $environment_result->strToReport($environment_result->getRestrictStr(), 'error');
212
 
213
        if ($plugin === '') {
214
            $report = '[' . get_string('coresystem') . '] ' . $report;
215
        } else {
216
            $report = '[' . $plugin . '] ' . $report;
217
        }
218
 
219
        $report .= ' - ' . html_to_text($feedbacktext);
220
 
221
        if ($environment_result->getPart() == 'custom_check'){
222
            $errors[] = array($info, $report);
223
        } else {
224
            $errors[] = array(($info !== '' ? "$type $info" : $type), $report);
225
        }
226
    }
227
 
228
    return $errors;
229
}
230
 
231
 
232
/**
233
 * This function will normalize any version to just a serie of numbers
234
 * separated by dots. Everything else will be removed.
235
 *
236
 * @param string $version the original version
237
 * @return string the normalized version
238
 */
239
function normalize_version($version) {
240
 
241
/// 1.9 Beta 2 should be read 1.9 on enviromental checks, not 1.9.2
242
/// we can discard everything after the first space
243
    $version = trim($version);
244
    $versionarr = explode(" ",$version);
245
    if (!empty($versionarr)) {
246
        $version = $versionarr[0];
247
    }
248
/// Replace everything but numbers and dots by dots
249
    $version = preg_replace('/[^\.\d]/', '.', $version);
250
/// Combine multiple dots in one
251
    $version = preg_replace('/(\.{2,})/', '.', $version);
252
/// Trim possible leading and trailing dots
253
    $version = trim($version, '.');
254
 
255
    return $version;
256
}
257
 
258
 
259
/**
260
 * This function will load the environment.xml file and xmlize it
261
 *
262
 * @staticvar array $data
263
 * @uses ENV_SELECT_NEWER
264
 * @uses ENV_SELECT_DATAROOT
265
 * @uses ENV_SELECT_RELEASE
266
 * @param int|string $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use. String means plugin name.
267
 * @return mixed the xmlized structure or false on error
268
 */
269
function load_environment_xml($env_select=ENV_SELECT_NEWER) {
270
 
271
    global $CFG;
272
 
273
    static $data = array(); // Only load and xmlize once by request.
274
 
275
    if (isset($data[$env_select])) {
276
        return $data[$env_select];
277
    }
278
    $contents = false;
279
 
280
    if (is_numeric($env_select)) {
281
        $file = $CFG->dataroot.'/environment/environment.xml';
282
        $internalfile = $CFG->dirroot.'/'.$CFG->admin.'/environment.xml';
283
        switch ($env_select) {
284
            case ENV_SELECT_NEWER:
285
                if (!is_file($file) || !is_readable($file) || filemtime($file) < filemtime($internalfile) ||
286
                    !$contents = file_get_contents($file)) {
287
                    /// Fallback to fixed $CFG->admin/environment.xml
288
                    if (!is_file($internalfile) || !is_readable($internalfile) || !$contents = file_get_contents($internalfile)) {
289
                        $contents = false;
290
                    }
291
                }
292
                break;
293
            case ENV_SELECT_DATAROOT:
294
                if (!is_file($file) || !is_readable($file) || !$contents = file_get_contents($file)) {
295
                    $contents = false;
296
                }
297
                break;
298
            case ENV_SELECT_RELEASE:
299
                if (!is_file($internalfile) || !is_readable($internalfile) || !$contents = file_get_contents($internalfile)) {
300
                    $contents = false;
301
                }
302
                break;
303
        }
304
    } else {
305
        if ($plugindir = core_component::get_component_directory($env_select)) {
306
            $pluginfile = "$plugindir/environment.xml";
307
            if (!is_file($pluginfile) || !is_readable($pluginfile) || !$contents = file_get_contents($pluginfile)) {
308
                $contents = false;
309
            }
310
        }
311
    }
312
    // XML the whole file.
313
    if ($contents !== false) {
314
        $contents = xmlize($contents);
315
    }
316
 
317
    $data[$env_select] = $contents;
318
 
319
    return $data[$env_select];
320
}
321
 
322
 
323
/**
324
 * This function will return the list of Moodle versions available
325
 *
326
 * @return array of versions
327
 */
328
function get_list_of_environment_versions($contents) {
329
    $versions = array();
330
 
331
    if (isset($contents['COMPATIBILITY_MATRIX']['#']['MOODLE'])) {
332
        foreach ($contents['COMPATIBILITY_MATRIX']['#']['MOODLE'] as $version) {
333
            $versions[] = $version['@']['version'];
334
        }
335
    }
336
 
337
    if (isset($contents['COMPATIBILITY_MATRIX']['#']['PLUGIN'])) {
338
        $versions[] = 'all';
339
    }
340
 
341
    return $versions;
342
}
343
 
344
 
345
/**
346
 * This function will return the most recent version in the environment.xml
347
 * file previous or equal to the version requested
348
 *
349
 * @param string $version top version from which we start to look backwards
350
 * @param int $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use.
351
 * @return string|bool string more recent version or false if not found
352
 */
353
function get_latest_version_available($version, $env_select) {
354
    if ($env_select != ENV_SELECT_NEWER and $env_select != ENV_SELECT_DATAROOT and $env_select != ENV_SELECT_RELEASE) {
355
        throw new coding_exception('Incorrect value of $env_select parameter');
356
    }
357
 
358
/// Normalize the version requested
359
    $version = normalize_version($version);
360
 
361
/// Load xml file
362
    if (!$contents = load_environment_xml($env_select)) {
363
        return false;
364
    }
365
 
366
/// Detect available versions
367
    if (!$versions = get_list_of_environment_versions($contents)) {
368
        return false;
369
    }
370
/// First we look for exact version
371
    if (in_array($version, $versions, true)) {
372
        return $version;
373
    } else {
374
        $found_version = false;
375
    /// Not exact match, so we are going to iterate over the list searching
376
    /// for the latest version before the requested one
377
        foreach ($versions as $arrversion) {
378
            if (version_compare($arrversion, $version, '<')) {
379
                $found_version = $arrversion;
380
            }
381
        }
382
    }
383
 
384
    return $found_version;
385
}
386
 
387
 
388
/**
389
 * This function will return the xmlized data belonging to one Moodle version
390
 *
391
 * @param string $version top version from which we start to look backwards
392
 * @param int|string $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use. String means plugin name.
393
 * @return mixed the xmlized structure or false on error
394
 */
395
function get_environment_for_version($version, $env_select) {
396
 
397
/// Normalize the version requested
398
    $version = normalize_version($version);
399
 
400
/// Load xml file
401
    if (!$contents = load_environment_xml($env_select)) {
402
        return false;
403
    }
404
 
405
/// Detect available versions
406
    if (!$versions = get_list_of_environment_versions($contents)) {
407
        return false;
408
    }
409
 
410
    // If $env_select is not numeric then this is being called on a plugin, and not the core environment.xml
411
    // If a version of 'all' is in the arry is also means that the new <PLUGIN> tag was found, this should
412
    // be matched against any version of Moodle.
413
    if (!is_numeric($env_select) && in_array('all', $versions)
414
            && environment_verify_plugin($env_select, $contents['COMPATIBILITY_MATRIX']['#']['PLUGIN'][0])) {
415
        return $contents['COMPATIBILITY_MATRIX']['#']['PLUGIN'][0];
416
    }
417
 
418
/// If the version requested is available
419
    if (!in_array($version, $versions, true)) {
420
        return false;
421
    }
422
 
423
/// We now we have it. Extract from full contents.
424
    $fl_arr = array_flip($versions);
425
 
426
    return $contents['COMPATIBILITY_MATRIX']['#']['MOODLE'][$fl_arr[$version]];
427
}
428
 
429
/**
430
 * Checks if a plugin tag has a name attribute and it matches the plugin being tested.
431
 *
432
 * @param string $plugin the name of the plugin.
433
 * @param array $pluginxml the xmlised structure for the plugin tag being tested.
434
 * @return boolean true if the name attribute exists and matches the plugin being tested.
435
 */
436
function environment_verify_plugin($plugin, $pluginxml) {
437
    if (!isset($pluginxml['@']['name']) || $pluginxml['@']['name'] != $plugin) {
438
        return false;
439
    }
440
    return true;
441
}
442
 
443
/**
444
 * This function will check for everything (DB, PHP and PHP extensions for now)
445
 * returning an array of environment_result objects.
446
 *
447
 * @global object
448
 * @param string $version xml version we are going to use to test this server
449
 * @param int $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use.
450
 * @return environment_results[] array of results encapsulated in one environment_result object
451
 */
452
function environment_check($version, $env_select) {
453
    global $CFG;
454
 
455
    if ($env_select != ENV_SELECT_NEWER and $env_select != ENV_SELECT_DATAROOT and $env_select != ENV_SELECT_RELEASE) {
456
        throw new coding_exception('Incorrect value of $env_select parameter');
457
    }
458
 
459
/// Normalize the version requested
460
    $version = normalize_version($version);
461
 
462
    $results = array(); //To store all the results
463
 
464
/// Only run the moodle versions checker on upgrade, not on install
465
    if (!empty($CFG->version)) {
466
        $results[] = environment_check_moodle($version, $env_select);
467
    }
468
    $results[] = environment_check_unicode($version, $env_select);
469
    $results[] = environment_check_database($version, $env_select);
470
    $results[] = environment_check_php($version, $env_select);
471
 
472
    if ($result = environment_check_pcre_unicode($version, $env_select)) {
473
        $results[] = $result;
474
    }
475
 
476
    $phpext_results = environment_check_php_extensions($version, $env_select);
477
    $results = array_merge($results, $phpext_results);
478
 
479
    $phpsetting_results = environment_check_php_settings($version, $env_select);
480
    $results = array_merge($results, $phpsetting_results);
481
 
482
    $custom_results = environment_custom_checks($version, $env_select);
483
    $results = array_merge($results, $custom_results);
484
 
1441 ariadna 485
    // Locate any installed plugins belonging to deleted plugin types and block the install/upgrade process until they are removed.
486
    // Plugins on disk which aren't installed and which are either deprecated or deleted will be ignored by install/upgrade anyway,
487
    // so are not checked here.
488
    $pluginman = \core_plugin_manager::instance();
489
    foreach (core_component::get_deleted_plugin_types() as $plugintype => $dir) {
490
        foreach ($pluginman->get_installed_plugins($plugintype) as $name => $version) {
491
            $plugin = $plugintype . '_' . $name;
492
 
493
            $result = new environment_results('custom_check');
494
            $result->setInfo('Deleted plugin detected');
495
            $result->setFeedbackStr(['deletedplugintypesdetected', 'admin', $plugin]);
496
            $result->setStatus(false);
497
            $result->plugin = $plugin;
498
            $results[] = $result;
499
        }
500
    }
501
 
1 efrain 502
    // Always use the plugin directory version of environment.xml,
503
    // add-on developers need to keep those up-to-date with future info.
504
    foreach (core_component::get_plugin_types() as $plugintype => $unused) {
505
        foreach (core_component::get_plugin_list_with_file($plugintype, 'environment.xml') as $pluginname => $unused) {
506
            $plugin = $plugintype . '_' . $pluginname;
507
 
508
            $result = environment_check_database($version, $plugin);
509
            if ($result->error_code != NO_VERSION_DATA_FOUND
510
                and $result->error_code != NO_DATABASE_SECTION_FOUND
511
                and $result->error_code != NO_DATABASE_VENDORS_FOUND) {
512
 
513
                $result->plugin = $plugin;
514
                $results[] = $result;
515
            }
516
 
517
            $result = environment_check_php($version, $plugin);
518
            if ($result->error_code != NO_VERSION_DATA_FOUND
519
                and $result->error_code != NO_PHP_SECTION_FOUND
520
                and $result->error_code != NO_PHP_VERSION_FOUND) {
521
 
522
                $result->plugin = $plugin;
523
                $results[] = $result;
524
            }
525
 
526
            $pluginresults = environment_check_php_extensions($version, $plugin);
527
            foreach ($pluginresults as $result) {
528
                if ($result->error_code != NO_VERSION_DATA_FOUND
529
                    and $result->error_code != NO_PHP_EXTENSIONS_SECTION_FOUND) {
530
 
531
                    $result->plugin = $plugin;
532
                    $results[] = $result;
533
                }
534
            }
535
 
536
            $pluginresults = environment_check_php_settings($version, $plugin);
537
            foreach ($pluginresults as $result) {
538
                if ($result->error_code != NO_VERSION_DATA_FOUND) {
539
                    $result->plugin = $plugin;
540
                    $results[] = $result;
541
                }
542
            }
543
 
544
            $pluginresults = environment_custom_checks($version, $plugin);
545
            foreach ($pluginresults as $result) {
546
                if ($result->error_code != NO_VERSION_DATA_FOUND) {
547
                    $result->plugin = $plugin;
548
                    $results[] = $result;
549
                }
550
            }
551
        }
552
    }
553
 
554
    return $results;
555
}
556
 
557
 
558
/**
559
 * This function will check if php extensions requirements are satisfied
560
 *
561
 * @uses NO_VERSION_DATA_FOUND
562
 * @uses NO_PHP_EXTENSIONS_SECTION_FOUND
563
 * @uses NO_PHP_EXTENSIONS_NAME_FOUND
564
 * @param string $version xml version we are going to use to test this server
565
 * @param int|string $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use. String means plugin name.
566
 * @return array array of results encapsulated in one environment_result object
567
 */
568
function environment_check_php_extensions($version, $env_select) {
569
 
570
    $results = array();
571
 
572
/// Get the enviroment version we need
573
    if (!$data = get_environment_for_version($version, $env_select)) {
574
    /// Error. No version data found
575
        $result = new environment_results('php_extension');
576
        $result->setStatus(false);
577
        $result->setErrorCode(NO_VERSION_DATA_FOUND);
578
        return array($result);
579
    }
580
 
581
/// Extract the php_extension part
582
    if (!isset($data['#']['PHP_EXTENSIONS']['0']['#']['PHP_EXTENSION'])) {
583
    /// Error. No PHP section found
584
        $result = new environment_results('php_extension');
585
        $result->setStatus(false);
586
        $result->setErrorCode(NO_PHP_EXTENSIONS_SECTION_FOUND);
587
        return array($result);
588
    }
589
/// Iterate over extensions checking them and creating the needed environment_results
590
    foreach($data['#']['PHP_EXTENSIONS']['0']['#']['PHP_EXTENSION'] as $extension) {
591
        $result = new environment_results('php_extension');
592
    /// Check for level
593
        $level = get_level($extension);
594
    /// Check for extension name
595
        if (!isset($extension['@']['name'])) {
596
            $result->setStatus(false);
597
            $result->setErrorCode(NO_PHP_EXTENSIONS_NAME_FOUND);
598
        } else {
599
            $extension_name = $extension['@']['name'];
600
        /// The name exists. Just check if it's an installed extension
601
            if (!extension_loaded($extension_name)) {
602
                $result->setStatus(false);
603
            } else {
604
                $result->setStatus(true);
605
            }
606
            $result->setLevel($level);
607
            $result->setInfo($extension_name);
608
        }
609
 
610
    /// Do any actions defined in the XML file.
611
        process_environment_result($extension, $result);
612
 
613
    /// Add the result to the array of results
614
        $results[] = $result;
615
    }
616
 
617
 
618
    return $results;
619
}
620
 
621
/**
622
 * This function will check if php extensions requirements are satisfied
623
 *
624
 * @uses NO_VERSION_DATA_FOUND
625
 * @uses NO_PHP_SETTINGS_NAME_FOUND
626
 * @param string $version xml version we are going to use to test this server
627
 * @param int|string $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use. String means plugin name.
628
 * @return array array of results encapsulated in one environment_result object
629
 */
630
function environment_check_php_settings($version, $env_select) {
631
 
632
    $results = array();
633
 
634
/// Get the enviroment version we need
635
    if (!$data = get_environment_for_version($version, $env_select)) {
636
    /// Error. No version data found
637
        $result = new environment_results('php_setting');
638
        $result->setStatus(false);
639
        $result->setErrorCode(NO_VERSION_DATA_FOUND);
640
        $results[] = $result;
641
        return $results;
642
    }
643
 
644
/// Extract the php_setting part
645
    if (!isset($data['#']['PHP_SETTINGS']['0']['#']['PHP_SETTING'])) {
646
    /// No PHP section found - ignore
647
        return $results;
648
    }
649
/// Iterate over settings checking them and creating the needed environment_results
650
    foreach($data['#']['PHP_SETTINGS']['0']['#']['PHP_SETTING'] as $setting) {
651
        $result = new environment_results('php_setting');
652
    /// Check for level
653
        $level = get_level($setting);
654
        $result->setLevel($level);
655
    /// Check for extension name
656
        if (!isset($setting['@']['name'])) {
657
            $result->setStatus(false);
658
            $result->setErrorCode(NO_PHP_SETTINGS_NAME_FOUND);
659
        } else {
660
            $setting_name  = $setting['@']['name'];
661
            $setting_value = $setting['@']['value'];
662
            $result->setInfo($setting_name);
663
 
664
            if ($setting_name == 'memory_limit') {
665
                $current = ini_get('memory_limit');
666
                if ($current == -1) {
667
                    $result->setStatus(true);
668
                } else {
669
                    $current  = get_real_size($current);
670
                    $minlimit = get_real_size($setting_value);
671
                    if ($current < $minlimit) {
672
                        @ini_set('memory_limit', $setting_value);
673
                        $current = ini_get('memory_limit');
674
                        $current = get_real_size($current);
675
                    }
676
                    $result->setStatus($current >= $minlimit);
677
                }
678
 
679
            } else {
680
                $current = ini_get_bool($setting_name);
681
            /// The name exists. Just check if it's an installed extension
682
                if ($current == $setting_value) {
683
                    $result->setStatus(true);
684
                } else {
685
                    $result->setStatus(false);
686
                }
687
            }
688
        }
689
 
690
    /// Do any actions defined in the XML file.
691
        process_environment_result($setting, $result);
692
 
693
    /// Add the result to the array of results
694
        $results[] = $result;
695
    }
696
 
697
 
698
    return $results;
699
}
700
 
701
/**
702
 * This function will do the custom checks.
703
 *
704
 * @uses CUSTOM_CHECK_FUNCTION_MISSING
705
 * @uses CUSTOM_CHECK_FILE_MISSING
706
 * @uses NO_CUSTOM_CHECK_FOUND
707
 * @param string $version xml version we are going to use to test this server.
708
 * @param int|string $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use. String means plugin name.
709
 * @return array array of results encapsulated in environment_result objects.
710
 */
711
function environment_custom_checks($version, $env_select) {
712
    global $CFG;
713
 
714
    $results = array();
715
 
716
/// Get current Moodle version (release) for later compare
717
    $release = isset($CFG->release) ? $CFG->release : $version; /// In case $CFG fails (at install) use $version
718
    $current_version = normalize_version($release);
719
 
720
/// Get the enviroment version we need
721
    if (!$data = get_environment_for_version($version, $env_select)) {
722
    /// Error. No version data found - but this will already have been reported.
723
        return $results;
724
    }
725
 
726
/// Extract the CUSTOM_CHECKS part
727
    if (!isset($data['#']['CUSTOM_CHECKS']['0']['#']['CUSTOM_CHECK'])) {
728
    /// No custom checks found - not a problem
729
        return $results;
730
    }
731
 
732
/// Iterate over extensions checking them and creating the needed environment_results
733
    foreach($data['#']['CUSTOM_CHECKS']['0']['#']['CUSTOM_CHECK'] as $check) {
734
        $result = new environment_results('custom_check');
735
 
736
    /// Check for level
737
        $level = get_level($check);
738
 
739
    /// Check for extension name
740
        if (isset($check['@']['function'])) {
741
            $function = $check['@']['function'];
742
            $file = null;
743
            if (isset($check['@']['file'])) {
744
                $file = $CFG->dirroot . '/' . $check['@']['file'];
745
                if (is_readable($file)) {
746
                    include_once($file);
747
                }
748
            }
749
 
750
            if (is_callable($function)) {
751
                $result->setLevel($level);
752
                $result->setInfo($function);
753
                $result = call_user_func($function, $result);
754
            } else if (!$file or is_readable($file)) {
755
            /// Only show error for current version (where function MUST exist)
756
            /// else, we are performing custom checks against future versiosn
757
            /// and function MAY not exist, so it doesn't cause error, just skip
758
            /// custom check by returning null. MDL-15939
759
                if (version_compare($current_version, $version, '>=')) {
760
                    $result->setStatus(false);
761
                    $result->setInfo($function);
762
                    $result->setErrorCode(CUSTOM_CHECK_FUNCTION_MISSING);
763
                } else {
764
                    $result = null;
765
                }
766
            } else {
767
            /// Only show error for current version (where function MUST exist)
768
            /// else, we are performing custom checks against future versiosn
769
            /// and function MAY not exist, so it doesn't cause error, just skip
770
            /// custom check by returning null. MDL-15939
771
                if (version_compare($current_version, $version, '>=')) {
772
                    $result->setStatus(false);
773
                    $result->setInfo($function);
774
                    $result->setErrorCode(CUSTOM_CHECK_FILE_MISSING);
775
                } else {
776
                    $result = null;
777
                }
778
            }
779
        } else {
780
            $result->setStatus(false);
781
            $result->setErrorCode(NO_CUSTOM_CHECK_FOUND);
782
        }
783
 
784
        if (!is_null($result)) {
785
        /// Do any actions defined in the XML file.
786
            process_environment_result($check, $result);
787
 
788
        /// Add the result to the array of results
789
            $results[] = $result;
790
        }
791
    }
792
 
793
    return $results;
794
}
795
 
796
/**
797
 * This function will check if Moodle requirements are satisfied
798
 *
799
 * @uses NO_VERSION_DATA_FOUND
800
 * @param string $version xml version we are going to use to test this server
801
 * @param int|string $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use. String means plugin name.
802
 * @return object results encapsulated in one environment_result object
803
 */
804
function environment_check_moodle($version, $env_select) {
805
 
806
    $result = new environment_results('moodle');
807
 
808
/// Get the enviroment version we need
809
    if (!$data = get_environment_for_version($version, $env_select)) {
810
    /// Error. No version data found
811
        $result->setStatus(false);
812
        $result->setErrorCode(NO_VERSION_DATA_FOUND);
813
        return $result;
814
    }
815
 
816
/// Extract the moodle part
817
    if (!isset($data['@']['requires'])) {
818
        $needed_version = '1.0'; /// Default to 1.0 if no moodle requires is found
819
    } else {
820
    /// Extract required moodle version
821
        $needed_version = $data['@']['requires'];
822
    }
823
 
824
/// Now search the version we are using
825
    $release = get_config('', 'release');
826
    $current_version = normalize_version($release);
827
    if (strpos($release, 'dev') !== false) {
828
        // When final version is required, dev is NOT enough so, at all effects
829
        // it's like we are running the previous version.
830
        $versionarr = explode('.', $current_version);
831
        if (isset($versionarr[1]) and $versionarr[1] > 0) {
832
            $versionarr[1]--;
833
            $current_version = implode('.', $versionarr);
834
        } else {
835
            $current_version = $current_version - 0.1;
836
        }
837
    }
838
 
839
/// And finally compare them, saving results
840
    if (version_compare($current_version, $needed_version, '>=')) {
841
        $result->setStatus(true);
842
    } else {
843
        $result->setStatus(false);
844
    }
845
    $result->setLevel('required');
846
    $result->setCurrentVersion($release);
847
    $result->setNeededVersion($needed_version);
848
 
849
    return $result;
850
}
851
 
852
/**
853
 * This function will check if php requirements are satisfied
854
 *
855
 * @uses NO_VERSION_DATA_FOUND
856
 * @uses NO_PHP_SECTION_FOUND
857
 * @uses NO_PHP_VERSION_FOUND
858
 * @param string $version xml version we are going to use to test this server
859
 * @param int|string $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use. String means plugin name.
860
 * @return object results encapsulated in one environment_result object
861
 */
862
function environment_check_php($version, $env_select) {
863
 
864
    $result = new environment_results('php');
865
 
866
/// Get the enviroment version we need
867
    if (!$data = get_environment_for_version($version, $env_select)) {
868
    /// Error. No version data found
869
        $result->setStatus(false);
870
        $result->setErrorCode(NO_VERSION_DATA_FOUND);
871
        return $result;
872
    }
873
 
874
/// Extract the php part
875
    if (!isset($data['#']['PHP'])) {
876
    /// Error. No PHP section found
877
        $result->setStatus(false);
878
        $result->setErrorCode(NO_PHP_SECTION_FOUND);
879
        return $result;
880
    } else {
881
    /// Extract level and version
882
        $level = get_level($data['#']['PHP']['0']);
883
        if (!isset($data['#']['PHP']['0']['@']['version'])) {
884
            $result->setStatus(false);
885
            $result->setErrorCode(NO_PHP_VERSION_FOUND);
886
            return $result;
887
        } else {
888
            $needed_version = $data['#']['PHP']['0']['@']['version'];
889
        }
890
    }
891
 
892
/// Now search the version we are using
893
    $current_version = normalize_version(phpversion());
894
 
895
/// And finally compare them, saving results
896
    if (version_compare($current_version, $needed_version, '>=')) {
897
        $result->setStatus(true);
898
    } else {
899
        $result->setStatus(false);
900
    }
901
    $result->setLevel($level);
902
    $result->setCurrentVersion($current_version);
903
    $result->setNeededVersion($needed_version);
904
 
905
/// Do any actions defined in the XML file.
906
    process_environment_result($data['#']['PHP'][0], $result);
907
 
908
    return $result;
909
}
910
 
911
/**
912
 * Looks for buggy PCRE implementation, we need unicode support in Moodle...
913
 * @param string $version xml version we are going to use to test this server
914
 * @param int|string $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use. String means plugin name.
915
 * @return ?environment_results results encapsulated in one environment_result object, null if irrelevant
916
 */
917
function environment_check_pcre_unicode($version, $env_select) {
918
    $result = new environment_results('pcreunicode');
919
 
920
    // Get the environment version we need
921
    if (!$data = get_environment_for_version($version, $env_select)) {
922
        // Error. No version data found!
923
        $result->setStatus(false);
924
        $result->setErrorCode(NO_VERSION_DATA_FOUND);
925
        return $result;
926
    }
927
 
928
    if (!isset($data['#']['PCREUNICODE'])) {
929
        return null;
930
    }
931
 
932
    $level = get_level($data['#']['PCREUNICODE']['0']);
933
    $result->setLevel($level);
934
 
935
    if (!function_exists('preg_match')) {
936
        // The extension test fails instead.
937
        return null;
938
 
939
    } else if (@preg_match('/\pL/u', 'a') and @preg_match('/á/iu', 'Á')) {
940
        $result->setStatus(true);
941
 
942
    } else {
943
        $result->setStatus(false);
944
    }
945
 
946
    // Do any actions defined in the XML file.
947
    process_environment_result($data['#']['PCREUNICODE'][0], $result);
948
 
949
    return $result;
950
}
951
 
952
/**
953
 * This function will check if unicode database requirements are satisfied
954
 *
955
 * @uses NO_VERSION_DATA_FOUND
956
 * @uses NO_UNICODE_SECTION_FOUND
957
 * @param string $version xml version we are going to use to test this server
958
 * @param int|string $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use. String means plugin name.
959
 * @return object results encapsulated in one environment_result object
960
 */
961
function environment_check_unicode($version, $env_select) {
962
    global $DB;
963
 
964
    $result = new environment_results('unicode');
965
 
966
    /// Get the enviroment version we need
967
    if (!$data = get_environment_for_version($version, $env_select)) {
968
    /// Error. No version data found
969
        $result->setStatus(false);
970
        $result->setErrorCode(NO_VERSION_DATA_FOUND);
971
        return $result;
972
    }
973
 
974
    /// Extract the unicode part
975
 
976
    if (!isset($data['#']['UNICODE'])) {
977
    /// Error. No UNICODE section found
978
        $result->setStatus(false);
979
        $result->setErrorCode(NO_UNICODE_SECTION_FOUND);
980
        return $result;
981
    } else {
982
    /// Extract level
983
        $level = get_level($data['#']['UNICODE']['0']);
984
    }
985
 
986
    if (!$unicodedb = $DB->setup_is_unicodedb()) {
987
        $result->setStatus(false);
988
    } else {
989
        $result->setStatus(true);
990
    }
991
 
992
    $result->setLevel($level);
993
 
994
/// Do any actions defined in the XML file.
995
    process_environment_result($data['#']['UNICODE'][0], $result);
996
 
997
    return $result;
998
}
999
 
1000
/**
1001
 * This function will check if database requirements are satisfied
1002
 *
1003
 * @uses NO_VERSION_DATA_FOUND
1004
 * @uses NO_DATABASE_SECTION_FOUND
1005
 * @uses NO_DATABASE_VENDORS_FOUND
1006
 * @uses NO_DATABASE_VENDOR_MYSQL_FOUND
1007
 * @uses NO_DATABASE_VENDOR_POSTGRES_FOUND
1008
 * @uses NO_DATABASE_VENDOR_VERSION_FOUND
1009
 * @param string $version xml version we are going to use to test this server
1010
 * @param int|string $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use. String means plugin name.
1011
 * @return object results encapsulated in one environment_result object
1012
 */
1013
function environment_check_database($version, $env_select) {
1014
 
1015
    global $DB;
1016
 
1017
    $result = new environment_results('database');
1018
 
1019
    $vendors = array();  //Array of vendors in version
1020
 
1021
/// Get the enviroment version we need
1022
    if (!$data = get_environment_for_version($version, $env_select)) {
1023
    /// Error. No version data found
1024
        $result->setStatus(false);
1025
        $result->setErrorCode(NO_VERSION_DATA_FOUND);
1026
        return $result;
1027
    }
1028
 
1029
/// Extract the database part
1030
    if (!isset($data['#']['DATABASE'])) {
1031
    /// Error. No DATABASE section found
1032
        $result->setStatus(false);
1033
        $result->setErrorCode(NO_DATABASE_SECTION_FOUND);
1034
        return $result;
1035
    } else {
1036
    /// Extract level
1037
        $level = get_level($data['#']['DATABASE']['0']);
1038
    }
1039
 
1040
/// Extract DB vendors. At least 2 are mandatory (mysql & postgres)
1041
    if (!isset($data['#']['DATABASE']['0']['#']['VENDOR'])) {
1042
    /// Error. No VENDORS found
1043
        $result->setStatus(false);
1044
        $result->setErrorCode(NO_DATABASE_VENDORS_FOUND);
1045
        return $result;
1046
    } else {
1047
    /// Extract vendors
1048
        foreach ($data['#']['DATABASE']['0']['#']['VENDOR'] as $vendor) {
1049
            if (isset($vendor['@']['name']) && isset($vendor['@']['version'])) {
1050
                $vendors[$vendor['@']['name']] = $vendor['@']['version'];
1051
                $vendorsxml[$vendor['@']['name']] = $vendor;
1052
            }
1053
        }
1054
    }
1055
/// Check we have the mysql vendor version
1056
    if (empty($vendors['mysql'])) {
1057
        $result->setStatus(false);
1058
        $result->setErrorCode(NO_DATABASE_VENDOR_MYSQL_FOUND);
1059
        return $result;
1060
    }
1061
/// Check we have the postgres vendor version
1062
    if (empty($vendors['postgres'])) {
1063
        $result->setStatus(false);
1064
        $result->setErrorCode(NO_DATABASE_VENDOR_POSTGRES_FOUND);
1065
        return $result;
1066
    }
1067
 
1068
/// Now search the version we are using (depending of vendor)
1069
    $current_vendor = $DB->get_dbvendor();
1070
 
1071
    $dbinfo = $DB->get_server_info();
1072
    $current_version = normalize_version($dbinfo['version']);
1073
 
1441 ariadna 1074
    // Check we have a needed version.
1075
    if (empty($vendors[$current_vendor])) {
1 efrain 1076
        $result->setStatus(false);
1077
        $result->setErrorCode(NO_DATABASE_VENDOR_VERSION_FOUND);
1078
        return $result;
1079
    }
1080
 
1441 ariadna 1081
    $needed_version = $vendors[$current_vendor];
1082
 
1 efrain 1083
    // Check if the DB Vendor has been properly configured.
1084
    // Hack: this is required when playing with MySQL and MariaDB since they share the same PHP module and base DB classes,
1085
    // whilst they are slowly evolving using separate directions though MariaDB is still an "almost" drop-in replacement.
1086
    $dbvendorismysql = ($current_vendor === 'mysql');
1087
    $dbtypeismariadb = (stripos($dbinfo['description'], 'mariadb') !== false);
1088
    if ($dbvendorismysql && $dbtypeismariadb) {
1089
        $result->setStatus(false);
1090
        $result->setLevel($level);
1091
        $result->setInfo($current_vendor . ' (' . $dbinfo['description'] . ')');
1092
        $result->setFeedbackStr('environmentmariadbwrongdbtype');
1093
        return $result;
1094
    }
1095
 
1096
/// And finally compare them, saving results
1097
    if (version_compare($current_version, $needed_version, '>=')) {
1098
        $result->setStatus(true);
1099
    } else {
1100
        $result->setStatus(false);
1101
    }
1102
    $result->setLevel($level);
1103
    $result->setCurrentVersion($current_version);
1104
    $result->setNeededVersion($needed_version);
1105
    $result->setInfo($current_vendor . ' (' . $dbinfo['description'] . ')');
1106
 
1107
/// Do any actions defined in the XML file.
1108
    process_environment_result($vendorsxml[$current_vendor], $result);
1109
 
1110
    return $result;
1111
 
1112
}
1113
 
1114
/**
1115
 * This function will post-process the result record by executing the specified
1116
 * function, modifying it as necessary, also a custom message will be added
1117
 * to the result object to be printed by the display layer.
1118
 * Every bypass function must be defined in this file and it'll return
1119
 * true/false to decide if the original test is bypassed or no. Also
1120
 * such bypass functions are able to directly handling the result object
1121
 * although it should be only under exceptional conditions.
1122
 *
1123
 * @param array $xml xml containing the bypass data
1124
 * @param environment_results $result object to be updated
1125
 * @return void
1126
 */
1127
function process_environment_bypass($xml, &$result) {
1128
 
1129
/// Only try to bypass if we were in error and it was required
1130
    if ($result->getStatus() || $result->getLevel() == 'optional') {
1131
        return;
1132
    }
1133
 
1134
/// It there is bypass info (function and message)
1135
    if (is_array($xml['#']) && isset($xml['#']['BYPASS'][0]['@']['function']) && isset($xml['#']['BYPASS'][0]['@']['message'])) {
1136
        $function = $xml['#']['BYPASS'][0]['@']['function'];
1137
        $message  = $xml['#']['BYPASS'][0]['@']['message'];
1138
    /// Look for the function
1139
        if (function_exists($function)) {
1140
        /// Call it, and if bypass = true is returned, apply meesage
1141
            if ($function($result)) {
1142
            /// We only set the bypass message if the function itself hasn't defined it before
1143
                if (empty($result->getBypassStr)) {
1144
                    if (isset($xml['#']['BYPASS'][0]['@']['plugin'])) {
1145
                        $result->setBypassStr(array($message, $xml['#']['BYPASS'][0]['@']['plugin']));
1146
                    } else {
1147
                        $result->setBypassStr($message);
1148
                    }
1149
                }
1150
            }
1151
        }
1152
    }
1153
}
1154
 
1155
/**
1156
 * This function will post-process the result record by executing the specified
1157
 * function, modifying it as necessary, also a custom message will be added
1158
 * to the result object to be printed by the display layer.
1159
 * Every restrict function must be defined in this file and it'll return
1160
 * true/false to decide if the original test is restricted or no. Also
1161
 * such restrict functions are able to directly handling the result object
1162
 * although it should be only under exceptional conditions.
1163
 *
1164
 * @param array $xml xmldata containing the restrict data
1165
 * @param environment_results $result object to be updated
1166
 * @return void
1167
 */
1168
function process_environment_restrict($xml, &$result) {
1169
 
1170
/// Only try to restrict if we were not in error and it was required
1171
    if (!$result->getStatus() || $result->getLevel() == 'optional') {
1172
        return;
1173
    }
1174
/// It there is restrict info (function and message)
1175
    if (is_array($xml['#']) && isset($xml['#']['RESTRICT'][0]['@']['function']) && isset($xml['#']['RESTRICT'][0]['@']['message'])) {
1176
        $function = $xml['#']['RESTRICT'][0]['@']['function'];
1177
        $message  = $xml['#']['RESTRICT'][0]['@']['message'];
1178
    /// Look for the function
1179
        if (function_exists($function)) {
1180
        /// Call it, and if restrict = true is returned, apply meesage
1181
            if ($function($result)) {
1182
            /// We only set the restrict message if the function itself hasn't defined it before
1183
                if (empty($result->getRestrictStr)) {
1184
                    if (isset($xml['#']['RESTRICT'][0]['@']['plugin'])) {
1185
                        $result->setRestrictStr(array($message, $xml['#']['RESTRICT'][0]['@']['plugin']));
1186
                    } else {
1187
                        $result->setRestrictStr($message);
1188
                    }
1189
                }
1190
            }
1191
        }
1192
    }
1193
}
1194
 
1195
/**
1196
 * This function will detect if there is some message available to be added to the
1197
 * result in order to clarify enviromental details.
1198
 *
1199
 * @uses INCORRECT_FEEDBACK_FOR_REQUIRED
1200
 * @uses INCORRECT_FEEDBACK_FOR_OPTIONAL
1201
 * @param array $xml xmldata containing the feedback data
1202
 * @param environment_results $result object to be updated
1203
 */
1204
function process_environment_messages($xml, &$result) {
1205
 
1206
/// If there is feedback info
1207
    if (is_array($xml['#']) && isset($xml['#']['FEEDBACK'][0]['#'])) {
1208
        $feedbackxml = $xml['#']['FEEDBACK'][0]['#'];
1209
 
1210
        // Detect some incorrect feedback combinations.
1211
        if ($result->getLevel() == 'required' and isset($feedbackxml['ON_CHECK'])) {
1212
            $result->setStatus(false);
1213
            $result->setErrorCode(INCORRECT_FEEDBACK_FOR_REQUIRED);
1214
        } else if ($result->getLevel() == 'optional' and isset($feedbackxml['ON_ERROR'])) {
1215
            $result->setStatus(false);
1216
            $result->setErrorCode(INCORRECT_FEEDBACK_FOR_OPTIONAL);
1217
        }
1218
 
1219
        if (!$result->status and $result->getLevel() == 'required') {
1220
            if (isset($feedbackxml['ON_ERROR'][0]['@']['message'])) {
1221
                if (isset($feedbackxml['ON_ERROR'][0]['@']['plugin'])) {
1222
                    $result->setFeedbackStr(array($feedbackxml['ON_ERROR'][0]['@']['message'], $feedbackxml['ON_ERROR'][0]['@']['plugin']));
1223
                } else {
1224
                    $result->setFeedbackStr($feedbackxml['ON_ERROR'][0]['@']['message']);
1225
                }
1226
            }
1227
        } else if (!$result->status and $result->getLevel() == 'optional') {
1228
            if (isset($feedbackxml['ON_CHECK'][0]['@']['message'])) {
1229
                if (isset($feedbackxml['ON_CHECK'][0]['@']['plugin'])) {
1230
                    $result->setFeedbackStr(array($feedbackxml['ON_CHECK'][0]['@']['message'], $feedbackxml['ON_CHECK'][0]['@']['plugin']));
1231
                } else {
1232
                    $result->setFeedbackStr($feedbackxml['ON_CHECK'][0]['@']['message']);
1233
                }
1234
            }
1235
        } else {
1236
            if (isset($feedbackxml['ON_OK'][0]['@']['message'])) {
1237
                if (isset($feedbackxml['ON_OK'][0]['@']['plugin'])) {
1238
                    $result->setFeedbackStr(array($feedbackxml['ON_OK'][0]['@']['message'], $feedbackxml['ON_OK'][0]['@']['plugin']));
1239
                } else {
1240
                    $result->setFeedbackStr($feedbackxml['ON_OK'][0]['@']['message']);
1241
                }
1242
            }
1243
        }
1244
    }
1245
}
1246
 
1247
 
1248
//--- Helper Class to return results to caller ---//
1249
 
1250
 
1251
/**
1252
 * Helper Class to return results to caller
1253
 *
1254
 * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
1255
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1256
 * @package moodlecore
1257
 */
1258
class environment_results {
1259
    /**
1260
     * @var string Which are we checking (database, php, php_extension, php_extension)
1261
     */
1262
    var $part;
1263
    /**
1264
     * @var bool true means the test passed and all is OK. false means it failed.
1265
     */
1266
    var $status;
1267
    /**
1268
     * @var integer See constants at the beginning of the file
1269
     */
1270
    var $error_code;
1271
    /**
1272
     * @var string required/optional/recommended.
1273
     */
1274
    var $level;
1275
    /**
1276
     * @var string current version detected
1277
     */
1278
    var $current_version;
1279
    /**
1280
     * @var string version needed
1281
     */
1282
    var $needed_version;
1283
    /**
1284
     * @var string Aux. info (DB vendor, library...)
1285
     */
1286
    var $info;
1287
    /**
1288
     * @var string String to show on error|on check|on ok
1289
     */
1290
    var $feedback_str;
1291
    /**
1292
     * @var string String to show if some bypass has happened
1293
     */
1294
    var $bypass_str;
1295
    /**
1296
     * @var string String to show if some restrict has happened
1297
     */
1298
    var $restrict_str;
1299
    /**
1300
     * @var string|null full plugin name or null if main environment
1301
     */
1302
    var $plugin = null;
1303
    /**
1304
     * Constructor of the environment_result class. Just set default values
1305
     *
1306
     * @param string $part
1307
     */
1308
    public function __construct($part) {
1309
        $this->part=$part;
1310
        $this->status=false;
1311
        $this->error_code=NO_ERROR;
1312
        $this->level='required';
1313
        $this->current_version='';
1314
        $this->needed_version='';
1315
        $this->info='';
1316
        $this->feedback_str='';
1317
        $this->bypass_str='';
1318
        $this->restrict_str='';
1319
    }
1320
 
1321
    /**
1322
     * Old syntax of class constructor. Deprecated in PHP7.
1323
     *
1324
     * @deprecated since Moodle 3.1
1325
     */
1326
    public function environment_results($part) {
1327
        debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
1328
        self::__construct($part);
1329
    }
1330
 
1331
    /**
1332
     * Set the status
1333
     *
1334
     * @param bool $testpassed true means the test passed and all is OK. false means it failed.
1335
     */
1336
    function setStatus($testpassed) {
1337
        $this->status = $testpassed;
1338
        if ($testpassed) {
1339
            $this->setErrorCode(NO_ERROR);
1340
        }
1341
    }
1342
 
1343
    /**
1344
     * Set the error_code
1345
     *
1346
     * @param integer $error_code the error code (see constants above)
1347
     */
1348
    function setErrorCode($error_code) {
1349
        $this->error_code=$error_code;
1350
    }
1351
 
1352
    /**
1353
     * Set the level
1354
     *
1355
     * @param string $level the level (required, optional)
1356
     */
1357
    function setLevel($level) {
1358
        $this->level=$level;
1359
    }
1360
 
1361
    /**
1362
     * Set the current version
1363
     *
1364
     * @param string $current_version the current version
1365
     */
1366
    function setCurrentVersion($current_version) {
1367
        $this->current_version=$current_version;
1368
    }
1369
 
1370
    /**
1371
     * Set the needed version
1372
     *
1373
     * @param string $needed_version the needed version
1374
     */
1375
    function setNeededVersion($needed_version) {
1376
        $this->needed_version=$needed_version;
1377
    }
1378
 
1379
    /**
1380
     * Set the auxiliary info
1381
     *
1382
     * @param string $info the auxiliary info
1383
     */
1384
    function setInfo($info) {
1385
        $this->info=$info;
1386
    }
1387
 
1388
    /**
1389
     * Set the feedback string
1390
     *
1391
     * @param mixed $str the feedback string that will be fetched from the admin lang file.
1392
     *                  pass just the string or pass an array of params for get_string
1393
     *                  You always should put your string in admin.php but a third param is useful
1394
     *                  to pass an $a object / string to get_string
1395
     */
1396
    function setFeedbackStr($str) {
1397
        $this->feedback_str=$str;
1398
    }
1399
 
1400
 
1401
    /**
1402
     * Set the bypass string
1403
     *
1404
     * @param string $str the bypass string that will be fetched from the admin lang file.
1405
     *                  pass just the string or pass an array of params for get_string
1406
     *                  You always should put your string in admin.php but a third param is useful
1407
     *                  to pass an $a object / string to get_string
1408
     */
1409
    function setBypassStr($str) {
1410
        $this->bypass_str=$str;
1411
    }
1412
 
1413
    /**
1414
     * Set the restrict string
1415
     *
1416
     * @param string $str the restrict string that will be fetched from the admin lang file.
1417
     *                  pass just the string or pass an array of params for get_string
1418
     *                  You always should put your string in admin.php but a third param is useful
1419
     *                  to pass an $a object / string to get_string
1420
     */
1421
    function setRestrictStr($str) {
1422
        $this->restrict_str=$str;
1423
    }
1424
 
1425
    /**
1426
     * Get the status
1427
     *
1428
     * @return bool true means the test passed and all is OK. false means it failed.
1429
     */
1430
    function getStatus() {
1431
        return $this->status;
1432
    }
1433
 
1434
    /**
1435
     * Get the error code
1436
     *
1437
     * @return integer error code
1438
     */
1439
    function getErrorCode() {
1440
        return $this->error_code;
1441
    }
1442
 
1443
    /**
1444
     * Get the level
1445
     *
1446
     * @return string level
1447
     */
1448
    function getLevel() {
1449
        return $this->level;
1450
    }
1451
 
1452
    /**
1453
     * Get the current version
1454
     *
1455
     * @return string current version
1456
     */
1457
    function getCurrentVersion() {
1458
        return $this->current_version;
1459
    }
1460
 
1461
    /**
1462
     * Get the needed version
1463
     *
1464
     * @return string needed version
1465
     */
1466
    function getNeededVersion() {
1467
        return $this->needed_version;
1468
    }
1469
 
1470
    /**
1471
     * Get the aux info
1472
     *
1473
     * @return string info
1474
     */
1475
    function getInfo() {
1476
        return $this->info;
1477
    }
1478
 
1479
    /**
1480
     * Get the part this result belongs to
1481
     *
1482
     * @return string part
1483
     */
1484
    function getPart() {
1485
        return $this->part;
1486
    }
1487
 
1488
    /**
1489
     * Get the feedback string
1490
     *
1491
     * @return mixed feedback string (can be an array of params for get_string or a single string to fetch from
1492
     *                  admin.php lang file).
1493
     */
1494
    function getFeedbackStr() {
1495
        return $this->feedback_str;
1496
    }
1497
 
1498
    /**
1499
     * Get the bypass string
1500
     *
1501
     * @return mixed bypass string (can be an array of params for get_string or a single string to fetch from
1502
     *                  admin.php lang file).
1503
     */
1504
    function getBypassStr() {
1505
        return $this->bypass_str;
1506
    }
1507
 
1508
    /**
1509
     * Get the restrict string
1510
     *
1511
     * @return mixed restrict string (can be an array of params for get_string or a single string to fetch from
1512
     *                  admin.php lang file).
1513
     */
1514
    function getRestrictStr() {
1515
        return $this->restrict_str;
1516
    }
1517
 
1518
    /**
1519
     * @todo Document this function
1520
     *
1521
     * @param mixed $string params for get_string, either a string to fetch from admin.php or an array of
1522
     *                       params for get_string.
1523
     * @param string $class css class(es) for message.
1524
     * @return string feedback string fetched from lang file wrapped in p tag with class $class or returns
1525
     *                              empty string if $string is empty.
1526
     */
1527
    function strToReport($string, $class){
1528
        if (!empty($string)){
1529
            if (is_array($string)){
1530
                $str = call_user_func_array('get_string', $string);
1531
            } else {
1532
                $str = get_string($string, 'admin');
1533
            }
1534
            return '<p class="'.$class.'">'.$str.'</p>';
1535
        } else {
1536
            return '';
1537
        }
1538
    }
1539
 
1540
    /**
1541
     * Get plugin name.
1542
     *
1543
     * @return string plugin name
1544
     */
1545
    function getPluginName() {
1546
        if ($this->plugin) {
1547
            $manager = core_plugin_manager::instance();
1548
            list($plugintype, $pluginname) = core_component::normalize_component($this->plugin);
1549
            return $manager->plugintype_name($plugintype) . ' / ' . $manager->plugin_name($this->plugin);
1550
        } else {
1551
            return '';
1552
        }
1553
    }
1554
}
1555
 
1556
/// Here all the restrict functions are coded to be used by the environment
1557
/// checker. All those functions will receive the result object and will
1558
/// return it modified as needed (status and bypass string)
1559
 
1560
/**
1561
 * @param array $element the element from the environment.xml file that should have
1562
 *      either a level="required" or level="optional" attribute.
1563
 * @return string "required" or "optional".
1564
 */
1565
function get_level($element) {
1566
    $level = 'required';
1567
    if (isset($element['@']['level'])) {
1568
        $level = $element['@']['level'];
1569
        if (!in_array($level, ['required', 'optional', 'recommended'])) {
1570
            debugging('The level of a check in the environment.xml file must be "required", "optional" or "recommended".',
1571
                    DEBUG_DEVELOPER);
1572
            $level = 'required';
1573
        }
1574
    } else {
1575
        debugging('Checks in the environment.xml file must have a level="required" or level="optional" attribute.', DEBUG_DEVELOPER);
1576
    }
1577
    return $level;
1578
}
1579
 
1580
/**
1581
 * Once the result has been determined, look in the XML for any
1582
 * messages, or other things that should be done depending on the outcome.
1583
 *
1584
 * @param array $element the element from the environment.xml file which
1585
 *      may have children defining what should be done with the outcome.
1586
 * @param object $result the result of the test, which may be modified by
1587
 *      this function as specified in the XML.
1588
 */
1589
function process_environment_result($element, &$result) {
1590
/// Process messages, modifying the $result if needed.
1591
    process_environment_messages($element, $result);
1592
/// Process bypass, modifying $result if needed.
1593
    process_environment_bypass($element, $result);
1594
/// Process restrict, modifying $result if needed.
1595
    process_environment_restrict($element, $result);
1596
}
1597
 
1598
/**
1599
 * Check if the current PHP version is greater than or equal to
1600
 * PHP version 7.
1601
 *
1602
 * @param object $result an environment_results instance
1603
 * @return bool result of version check
1604
 */
1605
function restrict_php_version_7(&$result) {
1606
    return restrict_php_version($result, '7');
1607
}
1608
 
1609
/**
1610
 * Check if the current PHP version is greater than or equal to an
1611
 * unsupported version.
1612
 *
1613
 * @param object $result an environment_results instance
1614
 * @param string $version the version of PHP that can't be used
1615
 * @return bool result of version check
1616
 */
1617
function restrict_php_version(&$result, $version) {
1618
 
1619
    // Get the current PHP version.
1620
    $currentversion = normalize_version(phpversion());
1621
 
1622
    // Confirm we're using a supported PHP version.
1623
    if (version_compare($currentversion, $version, '<')) {
1624
        // Everything is ok, the restriction doesn't apply.
1625
        return false;
1626
    } else {
1627
        // We're using an unsupported PHP version, apply restriction.
1628
        return true;
1629
    }
1630
}
1631
 
1632
/**
1633
 * Check if the current PHP version is greater than or equal to
1634
 * PHP version 7.1.
1635
 *
1636
 * @param object $result an environment_results instance
1637
 * @return bool result of version check
1638
 */
1639
function restrict_php_version_71(&$result) {
1640
    return restrict_php_version($result, '7.1');
1641
}
1642
 
1643
/**
1644
 * Check if the current PHP version is greater than or equal to
1645
 * PHP version 7.2.
1646
 *
1647
 * @param object $result an environment_results instance
1648
 * @return bool result of version check
1649
 */
1650
function restrict_php_version_72(&$result) {
1651
    return restrict_php_version($result, '7.2');
1652
}
1653
 
1654
/**
1655
 * Check if the current PHP version is greater than or equal to
1656
 * PHP version 7.3.
1657
 *
1658
 * @param object $result an environment_results instance
1659
 * @return bool result of version check
1660
 */
1661
function restrict_php_version_73(&$result) {
1662
    return restrict_php_version($result, '7.3');
1663
}
1664
 
1665
/**
1666
 * Check if the current PHP version is greater than or equal to
1667
 * PHP version 7.4.
1668
 *
1669
 * @param object $result an environment_results instance
1670
 * @return bool result of version check
1671
 */
1672
function restrict_php_version_74(&$result) {
1673
    return restrict_php_version($result, '7.4');
1674
}
1675
 
1676
/**
1677
 * Check if the current PHP version is greater than or equal to
1678
 * PHP version 8.0
1679
 *
1680
 * @param object $result an environment_results instance
1681
 * @return bool result of version check
1682
 */
1683
function restrict_php_version_80($result) {
1684
    return restrict_php_version($result, '8.0');
1685
}
1686
 
1687
/**
1688
 * Check if the current PHP version is greater than or equal to
1689
 * PHP version 8.1
1690
 *
1691
 * @param object $result an environment_results instance
1692
 * @return bool result of version check
1693
 */
1694
function restrict_php_version_81($result) {
1695
    return restrict_php_version($result, '8.1');
1696
}
1697
 
1698
/**
1699
 * Check if the current PHP version is greater than or equal to
1700
 * PHP version 8.2
1701
 *
1702
 * @param object $result an environment_results instance
1703
 * @return bool result of version check
1704
 */
1705
function restrict_php_version_82($result) {
1706
    return restrict_php_version($result, '8.2');
1707
}
1708
 
1709
/**
1710
 * Check if the current PHP version is greater than or equal to
1711
 * PHP version 8.3
1712
 *
1713
 * @param object $result an environment_results instance
1714
 * @return bool result of version check
1715
 */
1716
function restrict_php_version_83($result) {
1717
    return restrict_php_version($result, '8.3');
1718
}
1441 ariadna 1719
 
1720
/**
1721
 * Check if the current PHP version is greater than or equal to
1722
 * PHP version 8.4
1723
 *
1724
 * @param \environment_results $result an environment_results instance
1725
 * @return bool result of version check
1726
 */
1727
function restrict_php_version_84(environment_results $result) {
1728
    return restrict_php_version($result, '8.4');
1729
}