Commit | Line | Data |
---|---|---|
96db14f9 | 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/>. | |
db9d4a3d | 17 | |
18 | /** | |
8580535b | 19 | * Various upgrade/install related functions and classes. |
db9d4a3d | 20 | * |
78bfb562 | 21 | * @package core |
96db14f9 | 22 | * @subpackage upgrade |
23 | * @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com) | |
24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
db9d4a3d | 25 | */ |
26 | ||
78bfb562 PS |
27 | defined('MOODLE_INTERNAL') || die(); |
28 | ||
72fb21b6 | 29 | /** UPGRADE_LOG_NORMAL = 0 */ |
db9d4a3d | 30 | define('UPGRADE_LOG_NORMAL', 0); |
72fb21b6 | 31 | /** UPGRADE_LOG_NOTICE = 1 */ |
db9d4a3d | 32 | define('UPGRADE_LOG_NOTICE', 1); |
72fb21b6 | 33 | /** UPGRADE_LOG_ERROR = 2 */ |
795a08ad | 34 | define('UPGRADE_LOG_ERROR', 2); |
35 | ||
36 | /** | |
37 | * Exception indicating unknown error during upgrade. | |
72fb21b6 | 38 | * |
d32fb550 | 39 | * @package core |
72fb21b6 | 40 | * @subpackage upgrade |
d32fb550 | 41 | * @copyright 2009 Petr Skoda {@link http://skodak.org} |
72fb21b6 | 42 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
795a08ad | 43 | */ |
44 | class upgrade_exception extends moodle_exception { | |
4f0c2d00 | 45 | function __construct($plugin, $version, $debuginfo=NULL) { |
795a08ad | 46 | global $CFG; |
47 | $a = (object)array('plugin'=>$plugin, 'version'=>$version); | |
4f0c2d00 | 48 | parent::__construct('upgradeerror', 'admin', "$CFG->wwwroot/$CFG->admin/index.php", $a, $debuginfo); |
795a08ad | 49 | } |
50 | } | |
51 | ||
52 | /** | |
53 | * Exception indicating downgrade error during upgrade. | |
72fb21b6 | 54 | * |
d32fb550 | 55 | * @package core |
72fb21b6 | 56 | * @subpackage upgrade |
d32fb550 | 57 | * @copyright 2009 Petr Skoda {@link http://skodak.org} |
72fb21b6 | 58 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
795a08ad | 59 | */ |
60 | class downgrade_exception extends moodle_exception { | |
61 | function __construct($plugin, $oldversion, $newversion) { | |
62 | global $CFG; | |
63 | $plugin = is_null($plugin) ? 'moodle' : $plugin; | |
64 | $a = (object)array('plugin'=>$plugin, 'oldversion'=>$oldversion, 'newversion'=>$newversion); | |
65 | parent::__construct('cannotdowngrade', 'debug', "$CFG->wwwroot/$CFG->admin/index.php", $a); | |
66 | } | |
67 | } | |
68 | ||
72fb21b6 | 69 | /** |
d32fb550 | 70 | * @package core |
72fb21b6 | 71 | * @subpackage upgrade |
d32fb550 | 72 | * @copyright 2009 Petr Skoda {@link http://skodak.org} |
72fb21b6 | 73 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
74 | */ | |
795a08ad | 75 | class upgrade_requires_exception extends moodle_exception { |
76 | function __construct($plugin, $pluginversion, $currentmoodle, $requiremoodle) { | |
77 | global $CFG; | |
365a5941 | 78 | $a = new stdClass(); |
795a08ad | 79 | $a->pluginname = $plugin; |
80 | $a->pluginversion = $pluginversion; | |
81 | $a->currentmoodle = $currentmoodle; | |
17da2e6f | 82 | $a->requiremoodle = $requiremoodle; |
795a08ad | 83 | parent::__construct('pluginrequirementsnotmet', 'error', "$CFG->wwwroot/$CFG->admin/index.php", $a); |
84 | } | |
85 | } | |
86 | ||
72fb21b6 | 87 | /** |
d32fb550 | 88 | * @package core |
72fb21b6 | 89 | * @subpackage upgrade |
d32fb550 | 90 | * @copyright 2009 Petr Skoda {@link http://skodak.org} |
72fb21b6 | 91 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
92 | */ | |
795a08ad | 93 | class plugin_defective_exception extends moodle_exception { |
94 | function __construct($plugin, $details) { | |
95 | global $CFG; | |
96 | parent::__construct('detectedbrokenplugin', 'error', "$CFG->wwwroot/$CFG->admin/index.php", $plugin, $details); | |
97 | } | |
98 | } | |
db9d4a3d | 99 | |
bdbcb6d7 | 100 | /** |
b3d5bd33 PŠ |
101 | * Misplaced plugin exception. |
102 | * | |
103 | * Note: this should be used only from the upgrade/admin code. | |
104 | * | |
bdbcb6d7 PS |
105 | * @package core |
106 | * @subpackage upgrade | |
107 | * @copyright 2009 Petr Skoda {@link http://skodak.org} | |
108 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
109 | */ | |
110 | class plugin_misplaced_exception extends moodle_exception { | |
b3d5bd33 PŠ |
111 | /** |
112 | * Constructor. | |
113 | * @param string $component the component from version.php | |
114 | * @param string $expected expected directory, null means calculate | |
115 | * @param string $current plugin directory path | |
116 | */ | |
117 | public function __construct($component, $expected, $current) { | |
bdbcb6d7 | 118 | global $CFG; |
b3d5bd33 PŠ |
119 | if (empty($expected)) { |
120 | list($type, $plugin) = core_component::normalize_component($component); | |
121 | $plugintypes = core_component::get_plugin_types(); | |
122 | if (isset($plugintypes[$type])) { | |
123 | $expected = $plugintypes[$type] . '/' . $plugin; | |
124 | } | |
125 | } | |
126 | if (strpos($expected, '$CFG->dirroot') !== 0) { | |
127 | $expected = str_replace($CFG->dirroot, '$CFG->dirroot', $expected); | |
128 | } | |
129 | if (strpos($current, '$CFG->dirroot') !== 0) { | |
130 | $current = str_replace($CFG->dirroot, '$CFG->dirroot', $current); | |
131 | } | |
bdbcb6d7 PS |
132 | $a = new stdClass(); |
133 | $a->component = $component; | |
134 | $a->expected = $expected; | |
135 | $a->current = $current; | |
136 | parent::__construct('detectedmisplacedplugin', 'core_plugin', "$CFG->wwwroot/$CFG->admin/index.php", $a); | |
137 | } | |
138 | } | |
139 | ||
0c5406ca PS |
140 | /** |
141 | * Sets maximum expected time needed for upgrade task. | |
142 | * Please always make sure that upgrade will not run longer! | |
143 | * | |
144 | * The script may be automatically aborted if upgrade times out. | |
145 | * | |
146 | * @category upgrade | |
147 | * @param int $max_execution_time in seconds (can not be less than 60 s) | |
148 | */ | |
149 | function upgrade_set_timeout($max_execution_time=300) { | |
150 | global $CFG; | |
151 | ||
152 | if (!isset($CFG->upgraderunning) or $CFG->upgraderunning < time()) { | |
153 | $upgraderunning = get_config(null, 'upgraderunning'); | |
154 | } else { | |
155 | $upgraderunning = $CFG->upgraderunning; | |
156 | } | |
157 | ||
158 | if (!$upgraderunning) { | |
b814d1b4 PS |
159 | if (CLI_SCRIPT) { |
160 | // never stop CLI upgrades | |
161 | $upgraderunning = 0; | |
162 | } else { | |
163 | // web upgrade not running or aborted | |
164 | print_error('upgradetimedout', 'admin', "$CFG->wwwroot/$CFG->admin/"); | |
165 | } | |
0c5406ca PS |
166 | } |
167 | ||
168 | if ($max_execution_time < 60) { | |
169 | // protection against 0 here | |
170 | $max_execution_time = 60; | |
171 | } | |
172 | ||
173 | $expected_end = time() + $max_execution_time; | |
174 | ||
175 | if ($expected_end < $upgraderunning + 10 and $expected_end > $upgraderunning - 10) { | |
176 | // no need to store new end, it is nearly the same ;-) | |
177 | return; | |
178 | } | |
179 | ||
5563f5fb PS |
180 | if (CLI_SCRIPT) { |
181 | // there is no point in timing out of CLI scripts, admins can stop them if necessary | |
3ef7279f | 182 | core_php_time_limit::raise(); |
5563f5fb | 183 | } else { |
3ef7279f | 184 | core_php_time_limit::raise($max_execution_time); |
5563f5fb | 185 | } |
0c5406ca PS |
186 | set_config('upgraderunning', $expected_end); // keep upgrade locked until this time |
187 | } | |
188 | ||
db9d4a3d | 189 | /** |
190 | * Upgrade savepoint, marks end of each upgrade block. | |
191 | * It stores new main version, resets upgrade timeout | |
192 | * and abort upgrade if user cancels page loading. | |
193 | * | |
194 | * Please do not make large upgrade blocks with lots of operations, | |
195 | * for example when adding tables keep only one table operation per block. | |
196 | * | |
39b90b51 | 197 | * @category upgrade |
db9d4a3d | 198 | * @param bool $result false if upgrade step failed, true if completed |
199 | * @param string or float $version main version | |
200 | * @param bool $allowabort allow user to abort script execution here | |
201 | * @return void | |
202 | */ | |
203 | function upgrade_main_savepoint($result, $version, $allowabort=true) { | |
204 | global $CFG; | |
205 | ||
bb44ef99 RT |
206 | //sanity check to avoid confusion with upgrade_mod_savepoint usage. |
207 | if (!is_bool($allowabort)) { | |
208 | $errormessage = 'Parameter type mismatch. Are you mixing up upgrade_main_savepoint() and upgrade_mod_savepoint()?'; | |
209 | throw new coding_exception($errormessage); | |
210 | } | |
211 | ||
795a08ad | 212 | if (!$result) { |
520cea92 | 213 | throw new upgrade_exception(null, $version); |
795a08ad | 214 | } |
215 | ||
216 | if ($CFG->version >= $version) { | |
217 | // something really wrong is going on in main upgrade script | |
218 | throw new downgrade_exception(null, $CFG->version, $version); | |
db9d4a3d | 219 | } |
220 | ||
795a08ad | 221 | set_config('version', $version); |
222 | upgrade_log(UPGRADE_LOG_NORMAL, null, 'Upgrade savepoint reached'); | |
223 | ||
db9d4a3d | 224 | // reset upgrade timeout to default |
225 | upgrade_set_timeout(); | |
226 | ||
227 | // this is a safe place to stop upgrades if user aborts page loading | |
228 | if ($allowabort and connection_aborted()) { | |
229 | die; | |
230 | } | |
231 | } | |
232 | ||
233 | /** | |
234 | * Module upgrade savepoint, marks end of module upgrade blocks | |
235 | * It stores module version, resets upgrade timeout | |
236 | * and abort upgrade if user cancels page loading. | |
237 | * | |
39b90b51 | 238 | * @category upgrade |
db9d4a3d | 239 | * @param bool $result false if upgrade step failed, true if completed |
240 | * @param string or float $version main version | |
241 | * @param string $modname name of module | |
242 | * @param bool $allowabort allow user to abort script execution here | |
243 | * @return void | |
244 | */ | |
245 | function upgrade_mod_savepoint($result, $version, $modname, $allowabort=true) { | |
246 | global $DB; | |
247 | ||
bde002b8 PS |
248 | $component = 'mod_'.$modname; |
249 | ||
795a08ad | 250 | if (!$result) { |
bde002b8 | 251 | throw new upgrade_exception($component, $version); |
795a08ad | 252 | } |
253 | ||
bde002b8 PS |
254 | $dbversion = $DB->get_field('config_plugins', 'value', array('plugin'=>$component, 'name'=>'version')); |
255 | ||
db9d4a3d | 256 | if (!$module = $DB->get_record('modules', array('name'=>$modname))) { |
257 | print_error('modulenotexist', 'debug', '', $modname); | |
258 | } | |
259 | ||
bde002b8 | 260 | if ($dbversion >= $version) { |
795a08ad | 261 | // something really wrong is going on in upgrade script |
bde002b8 | 262 | throw new downgrade_exception($component, $dbversion, $version); |
db9d4a3d | 263 | } |
bde002b8 PS |
264 | set_config('version', $version, $component); |
265 | ||
266 | upgrade_log(UPGRADE_LOG_NORMAL, $component, 'Upgrade savepoint reached'); | |
db9d4a3d | 267 | |
268 | // reset upgrade timeout to default | |
269 | upgrade_set_timeout(); | |
270 | ||
271 | // this is a safe place to stop upgrades if user aborts page loading | |
272 | if ($allowabort and connection_aborted()) { | |
273 | die; | |
274 | } | |
275 | } | |
276 | ||
277 | /** | |
278 | * Blocks upgrade savepoint, marks end of blocks upgrade blocks | |
279 | * It stores block version, resets upgrade timeout | |
280 | * and abort upgrade if user cancels page loading. | |
281 | * | |
39b90b51 | 282 | * @category upgrade |
db9d4a3d | 283 | * @param bool $result false if upgrade step failed, true if completed |
284 | * @param string or float $version main version | |
285 | * @param string $blockname name of block | |
286 | * @param bool $allowabort allow user to abort script execution here | |
287 | * @return void | |
288 | */ | |
795a08ad | 289 | function upgrade_block_savepoint($result, $version, $blockname, $allowabort=true) { |
db9d4a3d | 290 | global $DB; |
291 | ||
bde002b8 PS |
292 | $component = 'block_'.$blockname; |
293 | ||
795a08ad | 294 | if (!$result) { |
bde002b8 | 295 | throw new upgrade_exception($component, $version); |
795a08ad | 296 | } |
297 | ||
bde002b8 PS |
298 | $dbversion = $DB->get_field('config_plugins', 'value', array('plugin'=>$component, 'name'=>'version')); |
299 | ||
db9d4a3d | 300 | if (!$block = $DB->get_record('block', array('name'=>$blockname))) { |
301 | print_error('blocknotexist', 'debug', '', $blockname); | |
302 | } | |
303 | ||
bde002b8 | 304 | if ($dbversion >= $version) { |
795a08ad | 305 | // something really wrong is going on in upgrade script |
bde002b8 | 306 | throw new downgrade_exception($component, $dbversion, $version); |
db9d4a3d | 307 | } |
bde002b8 PS |
308 | set_config('version', $version, $component); |
309 | ||
310 | upgrade_log(UPGRADE_LOG_NORMAL, $component, 'Upgrade savepoint reached'); | |
db9d4a3d | 311 | |
312 | // reset upgrade timeout to default | |
313 | upgrade_set_timeout(); | |
314 | ||
315 | // this is a safe place to stop upgrades if user aborts page loading | |
316 | if ($allowabort and connection_aborted()) { | |
317 | die; | |
318 | } | |
319 | } | |
320 | ||
321 | /** | |
322 | * Plugins upgrade savepoint, marks end of blocks upgrade blocks | |
323 | * It stores plugin version, resets upgrade timeout | |
324 | * and abort upgrade if user cancels page loading. | |
325 | * | |
39b90b51 | 326 | * @category upgrade |
db9d4a3d | 327 | * @param bool $result false if upgrade step failed, true if completed |
328 | * @param string or float $version main version | |
329 | * @param string $type name of plugin | |
330 | * @param string $dir location of plugin | |
331 | * @param bool $allowabort allow user to abort script execution here | |
332 | * @return void | |
333 | */ | |
17da2e6f | 334 | function upgrade_plugin_savepoint($result, $version, $type, $plugin, $allowabort=true) { |
bde002b8 PS |
335 | global $DB; |
336 | ||
17da2e6f | 337 | $component = $type.'_'.$plugin; |
338 | ||
795a08ad | 339 | if (!$result) { |
17da2e6f | 340 | throw new upgrade_exception($component, $version); |
db9d4a3d | 341 | } |
342 | ||
bde002b8 PS |
343 | $dbversion = $DB->get_field('config_plugins', 'value', array('plugin'=>$component, 'name'=>'version')); |
344 | ||
345 | if ($dbversion >= $version) { | |
795a08ad | 346 | // Something really wrong is going on in the upgrade script |
bde002b8 | 347 | throw new downgrade_exception($component, $dbversion, $version); |
795a08ad | 348 | } |
17da2e6f | 349 | set_config('version', $version, $component); |
795a08ad | 350 | upgrade_log(UPGRADE_LOG_NORMAL, $component, 'Upgrade savepoint reached'); |
351 | ||
db9d4a3d | 352 | // Reset upgrade timeout to default |
353 | upgrade_set_timeout(); | |
354 | ||
355 | // This is a safe place to stop upgrades if user aborts page loading | |
356 | if ($allowabort and connection_aborted()) { | |
357 | die; | |
358 | } | |
359 | } | |
360 | ||
9008ec16 PS |
361 | /** |
362 | * Detect if there are leftovers in PHP source files. | |
363 | * | |
364 | * During main version upgrades administrators MUST move away | |
365 | * old PHP source files and start from scratch (or better | |
366 | * use git). | |
367 | * | |
368 | * @return bool true means borked upgrade, false means previous PHP files were properly removed | |
369 | */ | |
370 | function upgrade_stale_php_files_present() { | |
371 | global $CFG; | |
372 | ||
373 | $someexamplesofremovedfiles = array( | |
fea4557c EL |
374 | // Removed in 3.3. |
375 | '/badges/backpackconnect.php', | |
376 | '/calendar/yui/src/info/assets/skins/sam/moodle-calendar-info.css', | |
377 | '/competency/classes/external/exporter.php', | |
378 | '/mod/forum/forum.js', | |
379 | '/user/pixgroup.php', | |
85ef6fe2 EL |
380 | // Removed in 3.2. |
381 | '/calendar/preferences.php', | |
382 | '/lib/alfresco/', | |
383 | '/lib/jquery/jquery-1.12.1.min.js', | |
384 | '/lib/password_compat/tests/', | |
385 | '/lib/phpunit/classes/unittestcase.php', | |
bbd7f7f7 | 386 | // Removed in 3.1. |
f8b059f2 EL |
387 | '/lib/classes/log/sql_internal_reader.php', |
388 | '/lib/zend/', | |
389 | '/mod/forum/pix/icon.gif', | |
390 | '/tag/templates/tagname.mustache', | |
5222ab7f SC |
391 | // Removed in 3.0. |
392 | '/mod/lti/grade.php', | |
0d1e5456 | 393 | '/tag/coursetagslib.php', |
aac67170 AG |
394 | // Removed in 2.9. |
395 | '/lib/timezone.txt', | |
396 | // Removed in 2.8. | |
397 | '/course/delete_category_form.php', | |
4e8a07d2 TH |
398 | // Removed in 2.7. |
399 | '/admin/tool/qeupgradehelper/version.php', | |
400 | // Removed in 2.6. | |
bde002b8 | 401 | '/admin/block.php', |
72e3a3c9 | 402 | '/admin/oacleanup.php', |
4e8a07d2 | 403 | // Removed in 2.5. |
c1782ec6 EL |
404 | '/backup/lib.php', |
405 | '/backup/bb/README.txt', | |
301ebbe5 | 406 | '/lib/excel/test.php', |
4e8a07d2 | 407 | // Removed in 2.4. |
c8b3346c | 408 | '/admin/tool/unittest/simpletestlib.php', |
4e8a07d2 | 409 | // Removed in 2.3. |
37d72977 | 410 | '/lib/minify/builder/', |
4e8a07d2 | 411 | // Removed in 2.2. |
9008ec16 | 412 | '/lib/yui/3.4.1pr1/', |
4e8a07d2 | 413 | // Removed in 2.2. |
9008ec16 PS |
414 | '/search/cron_php5.php', |
415 | '/course/report/log/indexlive.php', | |
416 | '/admin/report/backups/index.php', | |
417 | '/admin/generator.php', | |
4e8a07d2 | 418 | // Removed in 2.1. |
9008ec16 | 419 | '/lib/yui/2.8.0r4/', |
4e8a07d2 | 420 | // Removed in 2.0. |
9008ec16 PS |
421 | '/blocks/admin/block_admin.php', |
422 | '/blocks/admin_tree/block_admin_tree.php', | |
423 | ); | |
424 | ||
425 | foreach ($someexamplesofremovedfiles as $file) { | |
426 | if (file_exists($CFG->dirroot.$file)) { | |
427 | return true; | |
428 | } | |
429 | } | |
430 | ||
431 | return false; | |
432 | } | |
db9d4a3d | 433 | |
434 | /** | |
435 | * Upgrade plugins | |
db9d4a3d | 436 | * @param string $type The type of plugins that should be updated (e.g. 'enrol', 'qtype') |
17da2e6f | 437 | * return void |
db9d4a3d | 438 | */ |
17da2e6f | 439 | function upgrade_plugins($type, $startcallback, $endcallback, $verbose) { |
db9d4a3d | 440 | global $CFG, $DB; |
441 | ||
442 | /// special cases | |
443 | if ($type === 'mod') { | |
194cdca8 | 444 | return upgrade_plugins_modules($startcallback, $endcallback, $verbose); |
795a08ad | 445 | } else if ($type === 'block') { |
194cdca8 | 446 | return upgrade_plugins_blocks($startcallback, $endcallback, $verbose); |
db9d4a3d | 447 | } |
448 | ||
bd3b3bba | 449 | $plugs = core_component::get_plugin_list($type); |
db9d4a3d | 450 | |
17da2e6f | 451 | foreach ($plugs as $plug=>$fullplug) { |
ebb98bf5 | 452 | // Reset time so that it works when installing a large number of plugins |
3ef7279f | 453 | core_php_time_limit::raise(600); |
aff24313 | 454 | $component = clean_param($type.'_'.$plug, PARAM_COMPONENT); // standardised plugin name |
db9d4a3d | 455 | |
3e858ea7 | 456 | // check plugin dir is valid name |
aff24313 PS |
457 | if (empty($component)) { |
458 | throw new plugin_defective_exception($type.'_'.$plug, 'Invalid plugin directory name.'); | |
3e858ea7 PS |
459 | } |
460 | ||
795a08ad | 461 | if (!is_readable($fullplug.'/version.php')) { |
462 | continue; | |
db9d4a3d | 463 | } |
464 | ||
365a5941 | 465 | $plugin = new stdClass(); |
bde002b8 PS |
466 | $plugin->version = null; |
467 | $module = $plugin; // Prevent some notices when plugin placed in wrong directory. | |
795a08ad | 468 | require($fullplug.'/version.php'); // defines $plugin with version etc |
bde002b8 | 469 | unset($module); |
bdbcb6d7 | 470 | |
98ea6973 DM |
471 | if (empty($plugin->version)) { |
472 | throw new plugin_defective_exception($component, 'Missing $plugin->version number in version.php.'); | |
3e858ea7 PS |
473 | } |
474 | ||
98ea6973 DM |
475 | if (empty($plugin->component)) { |
476 | throw new plugin_defective_exception($component, 'Missing $plugin->component declaration in version.php.'); | |
477 | } | |
478 | ||
479 | if ($plugin->component !== $component) { | |
480 | throw new plugin_misplaced_exception($plugin->component, null, $fullplug); | |
db9d4a3d | 481 | } |
482 | ||
17da2e6f | 483 | $plugin->name = $plug; |
484 | $plugin->fullname = $component; | |
795a08ad | 485 | |
db9d4a3d | 486 | if (!empty($plugin->requires)) { |
487 | if ($plugin->requires > $CFG->version) { | |
795a08ad | 488 | throw new upgrade_requires_exception($component, $plugin->version, $CFG->version, $plugin->requires); |
ef14c1e7 PS |
489 | } else if ($plugin->requires < 2010000000) { |
490 | throw new plugin_defective_exception($component, 'Plugin is not compatible with Moodle 2.x or later.'); | |
db9d4a3d | 491 | } |
492 | } | |
493 | ||
9b683d13 | 494 | // try to recover from interrupted install.php if needed |
495 | if (file_exists($fullplug.'/db/install.php')) { | |
496 | if (get_config($plugin->fullname, 'installrunning')) { | |
497 | require_once($fullplug.'/db/install.php'); | |
498 | $recover_install_function = 'xmldb_'.$plugin->fullname.'_install_recovery'; | |
499 | if (function_exists($recover_install_function)) { | |
500 | $startcallback($component, true, $verbose); | |
501 | $recover_install_function(); | |
f6f06d69 | 502 | unset_config('installrunning', $plugin->fullname); |
9b683d13 | 503 | update_capabilities($component); |
c6d75bff | 504 | log_update_descriptions($component); |
c976e271 | 505 | external_update_descriptions($component); |
9b683d13 | 506 | events_update_definition($component); |
309ae892 | 507 | \core\task\manager::reset_scheduled_tasks_for_component($component); |
9b683d13 | 508 | message_update_providers($component); |
6c0bfb14 | 509 | \core\message\inbound\manager::update_handlers_for_component($component); |
afed8d0f RK |
510 | if ($type === 'message') { |
511 | message_update_processors($plug); | |
512 | } | |
de260e0f | 513 | upgrade_plugin_mnet_functions($component); |
c026a28d | 514 | core_tag_area::reset_definitions_for_component($component); |
9b683d13 | 515 | $endcallback($component, true, $verbose); |
516 | } | |
517 | } | |
518 | } | |
db9d4a3d | 519 | |
bde002b8 | 520 | $installedversion = $DB->get_field('config_plugins', 'value', array('name'=>'version', 'plugin'=>$component)); // No caching! |
795a08ad | 521 | if (empty($installedversion)) { // new installation |
194cdca8 | 522 | $startcallback($component, true, $verbose); |
db9d4a3d | 523 | |
795a08ad | 524 | /// Install tables if defined |
525 | if (file_exists($fullplug.'/db/install.xml')) { | |
526 | $DB->get_manager()->install_from_xmldb_file($fullplug.'/db/install.xml'); | |
db9d4a3d | 527 | } |
9b683d13 | 528 | |
529 | /// store version | |
530 | upgrade_plugin_savepoint(true, $plugin->version, $type, $plug, false); | |
531 | ||
795a08ad | 532 | /// execute post install file |
533 | if (file_exists($fullplug.'/db/install.php')) { | |
534 | require_once($fullplug.'/db/install.php'); | |
f6f06d69 PS |
535 | set_config('installrunning', 1, $plugin->fullname); |
536 | $post_install_function = 'xmldb_'.$plugin->fullname.'_install'; | |
795a08ad | 537 | $post_install_function(); |
f6f06d69 | 538 | unset_config('installrunning', $plugin->fullname); |
795a08ad | 539 | } |
540 | ||
795a08ad | 541 | /// Install various components |
542 | update_capabilities($component); | |
c6d75bff | 543 | log_update_descriptions($component); |
c976e271 | 544 | external_update_descriptions($component); |
795a08ad | 545 | events_update_definition($component); |
309ae892 | 546 | \core\task\manager::reset_scheduled_tasks_for_component($component); |
795a08ad | 547 | message_update_providers($component); |
6c0bfb14 | 548 | \core\message\inbound\manager::update_handlers_for_component($component); |
afed8d0f RK |
549 | if ($type === 'message') { |
550 | message_update_processors($plug); | |
551 | } | |
de260e0f | 552 | upgrade_plugin_mnet_functions($component); |
c026a28d | 553 | core_tag_area::reset_definitions_for_component($component); |
194cdca8 | 554 | $endcallback($component, true, $verbose); |
795a08ad | 555 | |
556 | } else if ($installedversion < $plugin->version) { // upgrade | |
557 | /// Run the upgrade function for the plugin. | |
194cdca8 | 558 | $startcallback($component, false, $verbose); |
795a08ad | 559 | |
560 | if (is_readable($fullplug.'/db/upgrade.php')) { | |
561 | require_once($fullplug.'/db/upgrade.php'); // defines upgrading function | |
562 | ||
563 | $newupgrade_function = 'xmldb_'.$plugin->fullname.'_upgrade'; | |
564 | $result = $newupgrade_function($installedversion); | |
565 | } else { | |
566 | $result = true; | |
567 | } | |
568 | ||
bde002b8 | 569 | $installedversion = $DB->get_field('config_plugins', 'value', array('name'=>'version', 'plugin'=>$component)); // No caching! |
795a08ad | 570 | if ($installedversion < $plugin->version) { |
571 | // store version if not already there | |
572 | upgrade_plugin_savepoint($result, $plugin->version, $type, $plug, false); | |
573 | } | |
574 | ||
575 | /// Upgrade various components | |
576 | update_capabilities($component); | |
c6d75bff | 577 | log_update_descriptions($component); |
c976e271 | 578 | external_update_descriptions($component); |
795a08ad | 579 | events_update_definition($component); |
309ae892 | 580 | \core\task\manager::reset_scheduled_tasks_for_component($component); |
795a08ad | 581 | message_update_providers($component); |
6c0bfb14 | 582 | \core\message\inbound\manager::update_handlers_for_component($component); |
afed8d0f | 583 | if ($type === 'message') { |
bde002b8 | 584 | // Ugly hack! |
afed8d0f RK |
585 | message_update_processors($plug); |
586 | } | |
de260e0f | 587 | upgrade_plugin_mnet_functions($component); |
c026a28d | 588 | core_tag_area::reset_definitions_for_component($component); |
194cdca8 | 589 | $endcallback($component, false, $verbose); |
795a08ad | 590 | |
591 | } else if ($installedversion > $plugin->version) { | |
592 | throw new downgrade_exception($component, $installedversion, $plugin->version); | |
db9d4a3d | 593 | } |
594 | } | |
db9d4a3d | 595 | } |
596 | ||
597 | /** | |
598 | * Find and check all modules and load them up or upgrade them if necessary | |
72fb21b6 | 599 | * |
600 | * @global object | |
601 | * @global object | |
db9d4a3d | 602 | */ |
194cdca8 | 603 | function upgrade_plugins_modules($startcallback, $endcallback, $verbose) { |
db9d4a3d | 604 | global $CFG, $DB; |
605 | ||
bd3b3bba | 606 | $mods = core_component::get_plugin_list('mod'); |
db9d4a3d | 607 | |
17da2e6f | 608 | foreach ($mods as $mod=>$fullmod) { |
db9d4a3d | 609 | |
3e858ea7 | 610 | if ($mod === 'NEWMODULE') { // Someone has unzipped the template, ignore it |
db9d4a3d | 611 | continue; |
612 | } | |
613 | ||
aff24313 | 614 | $component = clean_param('mod_'.$mod, PARAM_COMPONENT); |
db9d4a3d | 615 | |
3e858ea7 | 616 | // check module dir is valid name |
aff24313 PS |
617 | if (empty($component)) { |
618 | throw new plugin_defective_exception('mod_'.$mod, 'Invalid plugin directory name.'); | |
3e858ea7 PS |
619 | } |
620 | ||
795a08ad | 621 | if (!is_readable($fullmod.'/version.php')) { |
622 | throw new plugin_defective_exception($component, 'Missing version.php'); | |
db9d4a3d | 623 | } |
624 | ||
01889f01 | 625 | $module = new stdClass(); |
bde002b8 PS |
626 | $plugin = new stdClass(); |
627 | $plugin->version = null; | |
994e5662 | 628 | require($fullmod .'/version.php'); // Defines $plugin with version etc. |
01889f01 DM |
629 | |
630 | // Check if the legacy $module syntax is still used. | |
17d2a336 | 631 | if (!is_object($module) or (count((array)$module) > 0)) { |
01889f01 DM |
632 | throw new plugin_defective_exception($component, 'Unsupported $module syntax detected in version.php'); |
633 | } | |
634 | ||
635 | // Prepare the record for the {modules} table. | |
636 | $module = clone($plugin); | |
bde002b8 PS |
637 | unset($module->version); |
638 | unset($module->component); | |
639 | unset($module->dependencies); | |
640 | unset($module->release); | |
bdbcb6d7 | 641 | |
98ea6973 DM |
642 | if (empty($plugin->version)) { |
643 | throw new plugin_defective_exception($component, 'Missing $plugin->version number in version.php.'); | |
3e858ea7 PS |
644 | } |
645 | ||
98ea6973 DM |
646 | if (empty($plugin->component)) { |
647 | throw new plugin_defective_exception($component, 'Missing $plugin->component declaration in version.php.'); | |
648 | } | |
649 | ||
650 | if ($plugin->component !== $component) { | |
651 | throw new plugin_misplaced_exception($plugin->component, null, $fullmod); | |
db9d4a3d | 652 | } |
653 | ||
bde002b8 PS |
654 | if (!empty($plugin->requires)) { |
655 | if ($plugin->requires > $CFG->version) { | |
656 | throw new upgrade_requires_exception($component, $plugin->version, $CFG->version, $plugin->requires); | |
657 | } else if ($plugin->requires < 2010000000) { | |
ef14c1e7 | 658 | throw new plugin_defective_exception($component, 'Plugin is not compatible with Moodle 2.x or later.'); |
db9d4a3d | 659 | } |
660 | } | |
661 | ||
ff05bb31 TH |
662 | if (empty($module->cron)) { |
663 | $module->cron = 0; | |
664 | } | |
665 | ||
3e858ea7 PS |
666 | // all modules must have en lang pack |
667 | if (!is_readable("$fullmod/lang/en/$mod.php")) { | |
668 | throw new plugin_defective_exception($component, 'Missing mandatory en language pack.'); | |
669 | } | |
670 | ||
db9d4a3d | 671 | $module->name = $mod; // The name MUST match the directory |
672 | ||
bde002b8 | 673 | $installedversion = $DB->get_field('config_plugins', 'value', array('name'=>'version', 'plugin'=>$component)); // No caching! |
db9d4a3d | 674 | |
9b683d13 | 675 | if (file_exists($fullmod.'/db/install.php')) { |
676 | if (get_config($module->name, 'installrunning')) { | |
677 | require_once($fullmod.'/db/install.php'); | |
678 | $recover_install_function = 'xmldb_'.$module->name.'_install_recovery'; | |
679 | if (function_exists($recover_install_function)) { | |
680 | $startcallback($component, true, $verbose); | |
681 | $recover_install_function(); | |
682 | unset_config('installrunning', $module->name); | |
683 | // Install various components too | |
684 | update_capabilities($component); | |
c6d75bff | 685 | log_update_descriptions($component); |
c976e271 | 686 | external_update_descriptions($component); |
9b683d13 | 687 | events_update_definition($component); |
309ae892 | 688 | \core\task\manager::reset_scheduled_tasks_for_component($component); |
9b683d13 | 689 | message_update_providers($component); |
6c0bfb14 | 690 | \core\message\inbound\manager::update_handlers_for_component($component); |
de260e0f | 691 | upgrade_plugin_mnet_functions($component); |
c026a28d | 692 | core_tag_area::reset_definitions_for_component($component); |
9b683d13 | 693 | $endcallback($component, true, $verbose); |
694 | } | |
695 | } | |
696 | } | |
697 | ||
bde002b8 | 698 | if (empty($installedversion)) { |
194cdca8 | 699 | $startcallback($component, true, $verbose); |
db9d4a3d | 700 | |
795a08ad | 701 | /// Execute install.xml (XMLDB) - must be present in all modules |
702 | $DB->get_manager()->install_from_xmldb_file($fullmod.'/db/install.xml'); | |
db9d4a3d | 703 | |
2e3da297 | 704 | /// Add record into modules table - may be needed in install.php already |
705 | $module->id = $DB->insert_record('modules', $module); | |
bde002b8 | 706 | upgrade_mod_savepoint(true, $plugin->version, $module->name, false); |
2e3da297 | 707 | |
db9d4a3d | 708 | /// Post installation hook - optional |
709 | if (file_exists("$fullmod/db/install.php")) { | |
710 | require_once("$fullmod/db/install.php"); | |
9b683d13 | 711 | // Set installation running flag, we need to recover after exception or error |
712 | set_config('installrunning', 1, $module->name); | |
3412cb43 | 713 | $post_install_function = 'xmldb_'.$module->name.'_install'; |
db9d4a3d | 714 | $post_install_function(); |
9b683d13 | 715 | unset_config('installrunning', $module->name); |
db9d4a3d | 716 | } |
717 | ||
795a08ad | 718 | /// Install various components |
719 | update_capabilities($component); | |
c6d75bff | 720 | log_update_descriptions($component); |
c976e271 | 721 | external_update_descriptions($component); |
795a08ad | 722 | events_update_definition($component); |
309ae892 | 723 | \core\task\manager::reset_scheduled_tasks_for_component($component); |
795a08ad | 724 | message_update_providers($component); |
6c0bfb14 | 725 | \core\message\inbound\manager::update_handlers_for_component($component); |
de260e0f | 726 | upgrade_plugin_mnet_functions($component); |
c026a28d | 727 | core_tag_area::reset_definitions_for_component($component); |
795a08ad | 728 | |
194cdca8 | 729 | $endcallback($component, true, $verbose); |
db9d4a3d | 730 | |
bde002b8 | 731 | } else if ($installedversion < $plugin->version) { |
795a08ad | 732 | /// If versions say that we need to upgrade but no upgrade files are available, notify and continue |
194cdca8 | 733 | $startcallback($component, false, $verbose); |
795a08ad | 734 | |
735 | if (is_readable($fullmod.'/db/upgrade.php')) { | |
736 | require_once($fullmod.'/db/upgrade.php'); // defines new upgrading function | |
737 | $newupgrade_function = 'xmldb_'.$module->name.'_upgrade'; | |
bde002b8 | 738 | $result = $newupgrade_function($installedversion, $module); |
795a08ad | 739 | } else { |
740 | $result = true; | |
741 | } | |
742 | ||
bde002b8 | 743 | $installedversion = $DB->get_field('config_plugins', 'value', array('name'=>'version', 'plugin'=>$component)); // No caching! |
795a08ad | 744 | $currmodule = $DB->get_record('modules', array('name'=>$module->name)); |
bde002b8 | 745 | if ($installedversion < $plugin->version) { |
795a08ad | 746 | // store version if not already there |
bde002b8 | 747 | upgrade_mod_savepoint($result, $plugin->version, $mod, false); |
795a08ad | 748 | } |
749 | ||
3412cb43 TH |
750 | // update cron flag if needed |
751 | if ($currmodule->cron != $module->cron) { | |
752 | $DB->set_field('modules', 'cron', $module->cron, array('name' => $module->name)); | |
753 | } | |
754 | ||
755 | // Upgrade various components | |
795a08ad | 756 | update_capabilities($component); |
c6d75bff | 757 | log_update_descriptions($component); |
c976e271 | 758 | external_update_descriptions($component); |
795a08ad | 759 | events_update_definition($component); |
309ae892 | 760 | \core\task\manager::reset_scheduled_tasks_for_component($component); |
795a08ad | 761 | message_update_providers($component); |
6c0bfb14 | 762 | \core\message\inbound\manager::update_handlers_for_component($component); |
de260e0f | 763 | upgrade_plugin_mnet_functions($component); |
c026a28d | 764 | core_tag_area::reset_definitions_for_component($component); |
795a08ad | 765 | |
194cdca8 | 766 | $endcallback($component, false, $verbose); |
795a08ad | 767 | |
bde002b8 PS |
768 | } else if ($installedversion > $plugin->version) { |
769 | throw new downgrade_exception($component, $installedversion, $plugin->version); | |
795a08ad | 770 | } |
771 | } | |
772 | } | |
db9d4a3d | 773 | |
db9d4a3d | 774 | |
795a08ad | 775 | /** |
776 | * This function finds all available blocks and install them | |
777 | * into blocks table or do all the upgrade process if newer. | |
72fb21b6 | 778 | * |
779 | * @global object | |
780 | * @global object | |
795a08ad | 781 | */ |
194cdca8 | 782 | function upgrade_plugins_blocks($startcallback, $endcallback, $verbose) { |
795a08ad | 783 | global $CFG, $DB; |
784 | ||
795a08ad | 785 | require_once($CFG->dirroot.'/blocks/moodleblock.class.php'); |
786 | ||
787 | $blocktitles = array(); // we do not want duplicate titles | |
788 | ||
789 | //Is this a first install | |
790 | $first_install = null; | |
791 | ||
bd3b3bba | 792 | $blocks = core_component::get_plugin_list('block'); |
795a08ad | 793 | |
17da2e6f | 794 | foreach ($blocks as $blockname=>$fullblock) { |
795a08ad | 795 | |
796 | if (is_null($first_install)) { | |
f46eba7e | 797 | $first_install = ($DB->count_records('block_instances') == 0); |
795a08ad | 798 | } |
799 | ||
aff24313 | 800 | if ($blockname === 'NEWBLOCK') { // Someone has unzipped the template, ignore it |
795a08ad | 801 | continue; |
db9d4a3d | 802 | } |
803 | ||
aff24313 | 804 | $component = clean_param('block_'.$blockname, PARAM_COMPONENT); |
db9d4a3d | 805 | |
3e858ea7 | 806 | // check block dir is valid name |
aff24313 PS |
807 | if (empty($component)) { |
808 | throw new plugin_defective_exception('block_'.$blockname, 'Invalid plugin directory name.'); | |
3e858ea7 PS |
809 | } |
810 | ||
8571833f PS |
811 | if (!is_readable($fullblock.'/version.php')) { |
812 | throw new plugin_defective_exception('block/'.$blockname, 'Missing version.php file.'); | |
813 | } | |
365a5941 | 814 | $plugin = new stdClass(); |
bde002b8 | 815 | $plugin->version = null; |
8571833f | 816 | $plugin->cron = 0; |
bde002b8 | 817 | $module = $plugin; // Prevent some notices when module placed in wrong directory. |
8571833f | 818 | include($fullblock.'/version.php'); |
bde002b8 PS |
819 | unset($module); |
820 | $block = clone($plugin); | |
821 | unset($block->version); | |
822 | unset($block->component); | |
823 | unset($block->dependencies); | |
824 | unset($block->release); | |
8571833f | 825 | |
98ea6973 DM |
826 | if (empty($plugin->version)) { |
827 | throw new plugin_defective_exception($component, 'Missing block version number in version.php.'); | |
3e858ea7 PS |
828 | } |
829 | ||
98ea6973 DM |
830 | if (empty($plugin->component)) { |
831 | throw new plugin_defective_exception($component, 'Missing $plugin->component declaration in version.php.'); | |
832 | } | |
833 | ||
834 | if ($plugin->component !== $component) { | |
835 | throw new plugin_misplaced_exception($plugin->component, null, $fullblock); | |
bde002b8 PS |
836 | } |
837 | ||
ef14c1e7 PS |
838 | if (!empty($plugin->requires)) { |
839 | if ($plugin->requires > $CFG->version) { | |
840 | throw new upgrade_requires_exception($component, $plugin->version, $CFG->version, $plugin->requires); | |
841 | } else if ($plugin->requires < 2010000000) { | |
842 | throw new plugin_defective_exception($component, 'Plugin is not compatible with Moodle 2.x or later.'); | |
843 | } | |
844 | } | |
845 | ||
795a08ad | 846 | if (!is_readable($fullblock.'/block_'.$blockname.'.php')) { |
847 | throw new plugin_defective_exception('block/'.$blockname, 'Missing main block class file.'); | |
db9d4a3d | 848 | } |
8571833f | 849 | include_once($fullblock.'/block_'.$blockname.'.php'); |
db9d4a3d | 850 | |
795a08ad | 851 | $classname = 'block_'.$blockname; |
852 | ||
853 | if (!class_exists($classname)) { | |
854 | throw new plugin_defective_exception($component, 'Can not load main class.'); | |
855 | } | |
856 | ||
b921b6ee | 857 | $blockobj = new $classname; // This is what we'll be testing |
795a08ad | 858 | $blocktitle = $blockobj->get_title(); |
859 | ||
860 | // OK, it's as we all hoped. For further tests, the object will do them itself. | |
861 | if (!$blockobj->_self_test()) { | |
862 | throw new plugin_defective_exception($component, 'Self test failed.'); | |
863 | } | |
864 | ||
795a08ad | 865 | $block->name = $blockname; // The name MUST match the directory |
795a08ad | 866 | |
bde002b8 | 867 | $installedversion = $DB->get_field('config_plugins', 'value', array('name'=>'version', 'plugin'=>$component)); // No caching! |
795a08ad | 868 | |
9b683d13 | 869 | if (file_exists($fullblock.'/db/install.php')) { |
870 | if (get_config('block_'.$blockname, 'installrunning')) { | |
871 | require_once($fullblock.'/db/install.php'); | |
872 | $recover_install_function = 'xmldb_block_'.$blockname.'_install_recovery'; | |
873 | if (function_exists($recover_install_function)) { | |
874 | $startcallback($component, true, $verbose); | |
875 | $recover_install_function(); | |
876 | unset_config('installrunning', 'block_'.$blockname); | |
877 | // Install various components | |
878 | update_capabilities($component); | |
c6d75bff | 879 | log_update_descriptions($component); |
c976e271 | 880 | external_update_descriptions($component); |
9b683d13 | 881 | events_update_definition($component); |
309ae892 | 882 | \core\task\manager::reset_scheduled_tasks_for_component($component); |
9b683d13 | 883 | message_update_providers($component); |
6c0bfb14 | 884 | \core\message\inbound\manager::update_handlers_for_component($component); |
de260e0f | 885 | upgrade_plugin_mnet_functions($component); |
c026a28d | 886 | core_tag_area::reset_definitions_for_component($component); |
9b683d13 | 887 | $endcallback($component, true, $verbose); |
888 | } | |
889 | } | |
890 | } | |
891 | ||
bde002b8 | 892 | if (empty($installedversion)) { // block not installed yet, so install it |
795a08ad | 893 | $conflictblock = array_search($blocktitle, $blocktitles); |
894 | if ($conflictblock !== false) { | |
895 | // Duplicate block titles are not allowed, they confuse people | |
896 | // AND PHP's associative arrays ;) | |
c1ddac83 | 897 | throw new plugin_defective_exception($component, get_string('blocknameconflict', 'error', (object)array('name'=>$block->name, 'conflict'=>$conflictblock))); |
795a08ad | 898 | } |
194cdca8 | 899 | $startcallback($component, true, $verbose); |
795a08ad | 900 | |
901 | if (file_exists($fullblock.'/db/install.xml')) { | |
902 | $DB->get_manager()->install_from_xmldb_file($fullblock.'/db/install.xml'); | |
903 | } | |
904 | $block->id = $DB->insert_record('block', $block); | |
bde002b8 | 905 | upgrade_block_savepoint(true, $plugin->version, $block->name, false); |
795a08ad | 906 | |
907 | if (file_exists($fullblock.'/db/install.php')) { | |
908 | require_once($fullblock.'/db/install.php'); | |
9b683d13 | 909 | // Set installation running flag, we need to recover after exception or error |
910 | set_config('installrunning', 1, 'block_'.$blockname); | |
0e35ba6f | 911 | $post_install_function = 'xmldb_block_'.$blockname.'_install'; |
795a08ad | 912 | $post_install_function(); |
9b683d13 | 913 | unset_config('installrunning', 'block_'.$blockname); |
795a08ad | 914 | } |
915 | ||
916 | $blocktitles[$block->name] = $blocktitle; | |
917 | ||
918 | // Install various components | |
919 | update_capabilities($component); | |
c6d75bff | 920 | log_update_descriptions($component); |
c976e271 | 921 | external_update_descriptions($component); |
795a08ad | 922 | events_update_definition($component); |
309ae892 | 923 | \core\task\manager::reset_scheduled_tasks_for_component($component); |
795a08ad | 924 | message_update_providers($component); |
6c0bfb14 | 925 | \core\message\inbound\manager::update_handlers_for_component($component); |
c026a28d | 926 | core_tag_area::reset_definitions_for_component($component); |
de260e0f | 927 | upgrade_plugin_mnet_functions($component); |
795a08ad | 928 | |
194cdca8 | 929 | $endcallback($component, true, $verbose); |
795a08ad | 930 | |
bde002b8 | 931 | } else if ($installedversion < $plugin->version) { |
194cdca8 | 932 | $startcallback($component, false, $verbose); |
795a08ad | 933 | |
934 | if (is_readable($fullblock.'/db/upgrade.php')) { | |
935 | require_once($fullblock.'/db/upgrade.php'); // defines new upgrading function | |
936 | $newupgrade_function = 'xmldb_block_'.$blockname.'_upgrade'; | |
bde002b8 | 937 | $result = $newupgrade_function($installedversion, $block); |
795a08ad | 938 | } else { |
939 | $result = true; | |
940 | } | |
941 | ||
bde002b8 | 942 | $installedversion = $DB->get_field('config_plugins', 'value', array('name'=>'version', 'plugin'=>$component)); // No caching! |
795a08ad | 943 | $currblock = $DB->get_record('block', array('name'=>$block->name)); |
bde002b8 | 944 | if ($installedversion < $plugin->version) { |
795a08ad | 945 | // store version if not already there |
bde002b8 | 946 | upgrade_block_savepoint($result, $plugin->version, $block->name, false); |
795a08ad | 947 | } |
948 | ||
949 | if ($currblock->cron != $block->cron) { | |
950 | // update cron flag if needed | |
1fa84543 | 951 | $DB->set_field('block', 'cron', $block->cron, array('id' => $currblock->id)); |
795a08ad | 952 | } |
953 | ||
b921b6ee | 954 | // Upgrade various components |
795a08ad | 955 | update_capabilities($component); |
c6d75bff | 956 | log_update_descriptions($component); |
c976e271 | 957 | external_update_descriptions($component); |
17da2e6f | 958 | events_update_definition($component); |
309ae892 | 959 | \core\task\manager::reset_scheduled_tasks_for_component($component); |
795a08ad | 960 | message_update_providers($component); |
6c0bfb14 | 961 | \core\message\inbound\manager::update_handlers_for_component($component); |
de260e0f | 962 | upgrade_plugin_mnet_functions($component); |
c026a28d | 963 | core_tag_area::reset_definitions_for_component($component); |
795a08ad | 964 | |
194cdca8 | 965 | $endcallback($component, false, $verbose); |
795a08ad | 966 | |
bde002b8 PS |
967 | } else if ($installedversion > $plugin->version) { |
968 | throw new downgrade_exception($component, $installedversion, $plugin->version); | |
795a08ad | 969 | } |
970 | } | |
971 | ||
972 | ||
973 | // Finally, if we are in the first_install of BLOCKS setup frontpage and admin page blocks | |
974 | if ($first_install) { | |
795a08ad | 975 | //Iterate over each course - there should be only site course here now |
976 | if ($courses = $DB->get_records('course')) { | |
977 | foreach ($courses as $course) { | |
9d1d606e | 978 | blocks_add_default_course_blocks($course); |
db9d4a3d | 979 | } |
980 | } | |
795a08ad | 981 | |
9d1d606e | 982 | blocks_add_default_system_blocks(); |
795a08ad | 983 | } |
984 | } | |
985 | ||
c6d75bff PS |
986 | |
987 | /** | |
988 | * Log_display description function used during install and upgrade. | |
989 | * | |
990 | * @param string $component name of component (moodle, mod_assignment, etc.) | |
991 | * @return void | |
992 | */ | |
993 | function log_update_descriptions($component) { | |
994 | global $DB; | |
995 | ||
b0d1d941 | 996 | $defpath = core_component::get_component_directory($component).'/db/log.php'; |
c6d75bff PS |
997 | |
998 | if (!file_exists($defpath)) { | |
999 | $DB->delete_records('log_display', array('component'=>$component)); | |
1000 | return; | |
1001 | } | |
1002 | ||
1003 | // load new info | |
1004 | $logs = array(); | |
1005 | include($defpath); | |
1006 | $newlogs = array(); | |
1007 | foreach ($logs as $log) { | |
1008 | $newlogs[$log['module'].'-'.$log['action']] = $log; // kind of unique name | |
1009 | } | |
1010 | unset($logs); | |
1011 | $logs = $newlogs; | |
1012 | ||
1013 | $fields = array('module', 'action', 'mtable', 'field'); | |
1014 | // update all log fist | |
1015 | $dblogs = $DB->get_records('log_display', array('component'=>$component)); | |
1016 | foreach ($dblogs as $dblog) { | |
1017 | $name = $dblog->module.'-'.$dblog->action; | |
1018 | ||
1019 | if (empty($logs[$name])) { | |
1020 | $DB->delete_records('log_display', array('id'=>$dblog->id)); | |
1021 | continue; | |
1022 | } | |
1023 | ||
1024 | $log = $logs[$name]; | |
1025 | unset($logs[$name]); | |
1026 | ||
1027 | $update = false; | |
1028 | foreach ($fields as $field) { | |
1029 | if ($dblog->$field != $log[$field]) { | |
1030 | $dblog->$field = $log[$field]; | |
1031 | $update = true; | |
1032 | } | |
1033 | } | |
1034 | if ($update) { | |
1035 | $DB->update_record('log_display', $dblog); | |
1036 | } | |
1037 | } | |
1038 | foreach ($logs as $log) { | |
1039 | $dblog = (object)$log; | |
1040 | $dblog->component = $component; | |
1041 | $DB->insert_record('log_display', $dblog); | |
1042 | } | |
1043 | } | |
1044 | ||
c976e271 | 1045 | /** |
1046 | * Web service discovery function used during install and upgrade. | |
1047 | * @param string $component name of component (moodle, mod_assignment, etc.) | |
1048 | * @return void | |
1049 | */ | |
1050 | function external_update_descriptions($component) { | |
bc81eadb | 1051 | global $DB, $CFG; |
c976e271 | 1052 | |
b0d1d941 | 1053 | $defpath = core_component::get_component_directory($component).'/db/services.php'; |
c976e271 | 1054 | |
1055 | if (!file_exists($defpath)) { | |
bc81eadb | 1056 | require_once($CFG->dirroot.'/lib/externallib.php'); |
c976e271 | 1057 | external_delete_descriptions($component); |
1058 | return; | |
1059 | } | |
1060 | ||
1061 | // load new info | |
1062 | $functions = array(); | |
1063 | $services = array(); | |
1064 | include($defpath); | |
1065 | ||
1066 | // update all function fist | |
1067 | $dbfunctions = $DB->get_records('external_functions', array('component'=>$component)); | |
1068 | foreach ($dbfunctions as $dbfunction) { | |
1069 | if (empty($functions[$dbfunction->name])) { | |
1070 | $DB->delete_records('external_functions', array('id'=>$dbfunction->id)); | |
1071 | // do not delete functions from external_services_functions, beacuse | |
1072 | // we want to notify admins when functions used in custom services disappear | |
c6d75bff PS |
1073 | |
1074 | //TODO: this looks wrong, we have to delete it eventually (skodak) | |
c976e271 | 1075 | continue; |
1076 | } | |
1077 | ||
1078 | $function = $functions[$dbfunction->name]; | |
1079 | unset($functions[$dbfunction->name]); | |
1080 | $function['classpath'] = empty($function['classpath']) ? null : $function['classpath']; | |
1081 | ||
1082 | $update = false; | |
1083 | if ($dbfunction->classname != $function['classname']) { | |
1084 | $dbfunction->classname = $function['classname']; | |
1085 | $update = true; | |
1086 | } | |
1087 | if ($dbfunction->methodname != $function['methodname']) { | |
1088 | $dbfunction->methodname = $function['methodname']; | |
1089 | $update = true; | |
1090 | } | |
1091 | if ($dbfunction->classpath != $function['classpath']) { | |
1092 | $dbfunction->classpath = $function['classpath']; | |
1093 | $update = true; | |
1094 | } | |
12fc8acf | 1095 | $functioncapabilities = array_key_exists('capabilities', $function)?$function['capabilities']:''; |
72f68b51 | 1096 | if ($dbfunction->capabilities != $functioncapabilities) { |
1097 | $dbfunction->capabilities = $functioncapabilities; | |
1098 | $update = true; | |
1099 | } | |
186eba1b JL |
1100 | |
1101 | if (isset($function['services']) and is_array($function['services'])) { | |
1102 | sort($function['services']); | |
1103 | $functionservices = implode(',', $function['services']); | |
1104 | } else { | |
1105 | // Force null values in the DB. | |
1106 | $functionservices = null; | |
1107 | } | |
1108 | ||
1109 | if ($dbfunction->services != $functionservices) { | |
1110 | // Now, we need to check if services were removed, in that case we need to remove the function from them. | |
1111 | $servicesremoved = array_diff(explode(",", $dbfunction->services), explode(",", $functionservices)); | |
1112 | foreach ($servicesremoved as $removedshortname) { | |
1113 | if ($externalserviceid = $DB->get_field('external_services', 'id', array("shortname" => $removedshortname))) { | |
1114 | $DB->delete_records('external_services_functions', array('functionname' => $dbfunction->name, | |
1115 | 'externalserviceid' => $externalserviceid)); | |
1116 | } | |
1117 | } | |
1118 | ||
1119 | $dbfunction->services = $functionservices; | |
1120 | $update = true; | |
1121 | } | |
c976e271 | 1122 | if ($update) { |
1123 | $DB->update_record('external_functions', $dbfunction); | |
1124 | } | |
1125 | } | |
1126 | foreach ($functions as $fname => $function) { | |
365a5941 | 1127 | $dbfunction = new stdClass(); |
c976e271 | 1128 | $dbfunction->name = $fname; |
1129 | $dbfunction->classname = $function['classname']; | |
1130 | $dbfunction->methodname = $function['methodname']; | |
1131 | $dbfunction->classpath = empty($function['classpath']) ? null : $function['classpath']; | |
1132 | $dbfunction->component = $component; | |
12fc8acf | 1133 | $dbfunction->capabilities = array_key_exists('capabilities', $function)?$function['capabilities']:''; |
186eba1b JL |
1134 | |
1135 | if (isset($function['services']) and is_array($function['services'])) { | |
1136 | sort($function['services']); | |
1137 | $dbfunction->services = implode(',', $function['services']); | |
1138 | } else { | |
1139 | // Force null values in the DB. | |
1140 | $dbfunction->services = null; | |
1141 | } | |
1142 | ||
c976e271 | 1143 | $dbfunction->id = $DB->insert_record('external_functions', $dbfunction); |
1144 | } | |
1145 | unset($functions); | |
1146 | ||
1147 | // now deal with services | |
1148 | $dbservices = $DB->get_records('external_services', array('component'=>$component)); | |
1149 | foreach ($dbservices as $dbservice) { | |
1150 | if (empty($services[$dbservice->name])) { | |
bc81eadb | 1151 | $DB->delete_records('external_tokens', array('externalserviceid'=>$dbservice->id)); |
c976e271 | 1152 | $DB->delete_records('external_services_functions', array('externalserviceid'=>$dbservice->id)); |
1153 | $DB->delete_records('external_services_users', array('externalserviceid'=>$dbservice->id)); | |
1154 | $DB->delete_records('external_services', array('id'=>$dbservice->id)); | |
1155 | continue; | |
1156 | } | |
1157 | $service = $services[$dbservice->name]; | |
1158 | unset($services[$dbservice->name]); | |
1159 | $service['enabled'] = empty($service['enabled']) ? 0 : $service['enabled']; | |
1160 | $service['requiredcapability'] = empty($service['requiredcapability']) ? null : $service['requiredcapability']; | |
1161 | $service['restrictedusers'] = !isset($service['restrictedusers']) ? 1 : $service['restrictedusers']; | |
af03513f | 1162 | $service['downloadfiles'] = !isset($service['downloadfiles']) ? 0 : $service['downloadfiles']; |
106c55fb | 1163 | $service['uploadfiles'] = !isset($service['uploadfiles']) ? 0 : $service['uploadfiles']; |
c1b65883 | 1164 | $service['shortname'] = !isset($service['shortname']) ? null : $service['shortname']; |
c976e271 | 1165 | |
1166 | $update = false; | |
c976e271 | 1167 | if ($dbservice->requiredcapability != $service['requiredcapability']) { |
1168 | $dbservice->requiredcapability = $service['requiredcapability']; | |
1169 | $update = true; | |
1170 | } | |
1171 | if ($dbservice->restrictedusers != $service['restrictedusers']) { | |
1172 | $dbservice->restrictedusers = $service['restrictedusers']; | |
1173 | $update = true; | |
1174 | } | |
af03513f JM |
1175 | if ($dbservice->downloadfiles != $service['downloadfiles']) { |
1176 | $dbservice->downloadfiles = $service['downloadfiles']; | |
1177 | $update = true; | |
1178 | } | |
106c55fb DW |
1179 | if ($dbservice->uploadfiles != $service['uploadfiles']) { |
1180 | $dbservice->uploadfiles = $service['uploadfiles']; | |
1181 | $update = true; | |
1182 | } | |
c1b65883 JM |
1183 | //if shortname is not a PARAM_ALPHANUMEXT, fail (tested here for service update and creation) |
1184 | if (isset($service['shortname']) and | |
1185 | (clean_param($service['shortname'], PARAM_ALPHANUMEXT) != $service['shortname'])) { | |
1186 | throw new moodle_exception('installserviceshortnameerror', 'webservice', '', $service['shortname']); | |
1187 | } | |
1188 | if ($dbservice->shortname != $service['shortname']) { | |
1189 | //check that shortname is unique | |
1190 | if (isset($service['shortname'])) { //we currently accepts multiple shortname == null | |
1191 | $existingservice = $DB->get_record('external_services', | |
1192 | array('shortname' => $service['shortname'])); | |
1193 | if (!empty($existingservice)) { | |
1194 | throw new moodle_exception('installexistingserviceshortnameerror', 'webservice', '', $service['shortname']); | |
1195 | } | |
1196 | } | |
1197 | $dbservice->shortname = $service['shortname']; | |
1198 | $update = true; | |
1199 | } | |
c976e271 | 1200 | if ($update) { |
1201 | $DB->update_record('external_services', $dbservice); | |
1202 | } | |
1203 | ||
1204 | $functions = $DB->get_records('external_services_functions', array('externalserviceid'=>$dbservice->id)); | |
1205 | foreach ($functions as $function) { | |
1206 | $key = array_search($function->functionname, $service['functions']); | |
1207 | if ($key === false) { | |
1208 | $DB->delete_records('external_services_functions', array('id'=>$function->id)); | |
1209 | } else { | |
1210 | unset($service['functions'][$key]); | |
1211 | } | |
1212 | } | |
1213 | foreach ($service['functions'] as $fname) { | |
365a5941 | 1214 | $newf = new stdClass(); |
c976e271 | 1215 | $newf->externalserviceid = $dbservice->id; |
1216 | $newf->functionname = $fname; | |
1217 | $DB->insert_record('external_services_functions', $newf); | |
1218 | } | |
1219 | unset($functions); | |
1220 | } | |
1221 | foreach ($services as $name => $service) { | |
c1b65883 JM |
1222 | //check that shortname is unique |
1223 | if (isset($service['shortname'])) { //we currently accepts multiple shortname == null | |
1224 | $existingservice = $DB->get_record('external_services', | |
1225 | array('shortname' => $service['shortname'])); | |
1226 | if (!empty($existingservice)) { | |
1227 | throw new moodle_exception('installserviceshortnameerror', 'webservice'); | |
1228 | } | |
1229 | } | |
1230 | ||
365a5941 | 1231 | $dbservice = new stdClass(); |
c976e271 | 1232 | $dbservice->name = $name; |
1233 | $dbservice->enabled = empty($service['enabled']) ? 0 : $service['enabled']; | |
1234 | $dbservice->requiredcapability = empty($service['requiredcapability']) ? null : $service['requiredcapability']; | |
1235 | $dbservice->restrictedusers = !isset($service['restrictedusers']) ? 1 : $service['restrictedusers']; | |
af03513f | 1236 | $dbservice->downloadfiles = !isset($service['downloadfiles']) ? 0 : $service['downloadfiles']; |
106c55fb | 1237 | $dbservice->uploadfiles = !isset($service['uploadfiles']) ? 0 : $service['uploadfiles']; |
c1b65883 | 1238 | $dbservice->shortname = !isset($service['shortname']) ? null : $service['shortname']; |
c976e271 | 1239 | $dbservice->component = $component; |
e5180580 | 1240 | $dbservice->timecreated = time(); |
c976e271 | 1241 | $dbservice->id = $DB->insert_record('external_services', $dbservice); |
1242 | foreach ($service['functions'] as $fname) { | |
365a5941 | 1243 | $newf = new stdClass(); |
c976e271 | 1244 | $newf->externalserviceid = $dbservice->id; |
1245 | $newf->functionname = $fname; | |
1246 | $DB->insert_record('external_services_functions', $newf); | |
1247 | } | |
1248 | } | |
1249 | } | |
1250 | ||
186eba1b | 1251 | /** |
ee7295ee | 1252 | * Allow plugins and subsystems to add external functions to other plugins or built-in services. |
186eba1b JL |
1253 | * This function is executed just after all the plugins have been updated. |
1254 | */ | |
1255 | function external_update_services() { | |
1256 | global $DB; | |
1257 | ||
1258 | // Look for external functions that want to be added in existing services. | |
1259 | $functions = $DB->get_records_select('external_functions', 'services IS NOT NULL'); | |
1260 | ||
1261 | $servicescache = array(); | |
1262 | foreach ($functions as $function) { | |
1263 | // Prevent edge cases. | |
1264 | if (empty($function->services)) { | |
1265 | continue; | |
1266 | } | |
1267 | $services = explode(',', $function->services); | |
1268 | ||
1269 | foreach ($services as $serviceshortname) { | |
1270 | // Get the service id by shortname. | |
1271 | if (!empty($servicescache[$serviceshortname])) { | |
1272 | $serviceid = $servicescache[$serviceshortname]; | |
1273 | } else if ($service = $DB->get_record('external_services', array('shortname' => $serviceshortname))) { | |
1274 | // If the component is empty, it means that is not a built-in service. | |
1275 | // We don't allow functions to inject themselves in services created by an user in Moodle. | |
1276 | if (empty($service->component)) { | |
1277 | continue; | |
1278 | } | |
1279 | $serviceid = $service->id; | |
1280 | $servicescache[$serviceshortname] = $serviceid; | |
1281 | } else { | |
1282 | // Service not found. | |
1283 | continue; | |
1284 | } | |
1285 | // Finally add the function to the service. | |
1286 | $newf = new stdClass(); | |
1287 | $newf->externalserviceid = $serviceid; | |
1288 | $newf->functionname = $function->name; | |
1289 | ||
1290 | if (!$DB->record_exists('external_services_functions', (array)$newf)) { | |
1291 | $DB->insert_record('external_services_functions', $newf); | |
1292 | } | |
1293 | } | |
1294 | } | |
1295 | } | |
1296 | ||
72fb21b6 | 1297 | /** |
1298 | * upgrade logging functions | |
72fb21b6 | 1299 | */ |
fd1a792e | 1300 | function upgrade_handle_exception($ex, $plugin = null) { |
96e1fdf4 PS |
1301 | global $CFG; |
1302 | ||
a56c457e PS |
1303 | // rollback everything, we need to log all upgrade problems |
1304 | abort_all_db_transactions(); | |
1305 | ||
c19bc39c PS |
1306 | $info = get_exception_info($ex); |
1307 | ||
1308 | // First log upgrade error | |
1309 | upgrade_log(UPGRADE_LOG_ERROR, $plugin, 'Exception: ' . get_class($ex), $info->message, $info->backtrace); | |
1310 | ||
1311 | // Always turn on debugging - admins need to know what is going on | |
96f81ea3 | 1312 | set_debugging(DEBUG_DEVELOPER, true); |
c19bc39c | 1313 | |
fd1a792e | 1314 | default_exception_handler($ex, true, $plugin); |
db9d4a3d | 1315 | } |
1316 | ||
1317 | /** | |
1318 | * Adds log entry into upgrade_log table | |
1319 | * | |
1320 | * @param int $type UPGRADE_LOG_NORMAL, UPGRADE_LOG_NOTICE or UPGRADE_LOG_ERROR | |
bb8b2971 | 1321 | * @param string $plugin frankenstyle component name |
db9d4a3d | 1322 | * @param string $info short description text of log entry |
1323 | * @param string $details long problem description | |
1324 | * @param string $backtrace string used for errors only | |
1325 | * @return void | |
1326 | */ | |
1327 | function upgrade_log($type, $plugin, $info, $details=null, $backtrace=null) { | |
1328 | global $DB, $USER, $CFG; | |
1329 | ||
bb8b2971 PS |
1330 | if (empty($plugin)) { |
1331 | $plugin = 'core'; | |
1332 | } | |
1333 | ||
56da374e | 1334 | list($plugintype, $pluginname) = core_component::normalize_component($plugin); |
bb8b2971 | 1335 | $component = is_null($pluginname) ? $plugintype : $plugintype . '_' . $pluginname; |
795a08ad | 1336 | |
34a2777c | 1337 | $backtrace = format_backtrace($backtrace, true); |
db9d4a3d | 1338 | |
bb8b2971 PS |
1339 | $currentversion = null; |
1340 | $targetversion = null; | |
db9d4a3d | 1341 | |
1342 | //first try to find out current version number | |
bb8b2971 | 1343 | if ($plugintype === 'core') { |
db9d4a3d | 1344 | //main |
bb8b2971 | 1345 | $currentversion = $CFG->version; |
db9d4a3d | 1346 | |
bb8b2971 PS |
1347 | $version = null; |
1348 | include("$CFG->dirroot/version.php"); | |
1349 | $targetversion = $version; | |
795a08ad | 1350 | |
795a08ad | 1351 | } else { |
bb8b2971 | 1352 | $pluginversion = get_config($component, 'version'); |
795a08ad | 1353 | if (!empty($pluginversion)) { |
bb8b2971 PS |
1354 | $currentversion = $pluginversion; |
1355 | } | |
b0d1d941 | 1356 | $cd = core_component::get_component_directory($component); |
bb8b2971 PS |
1357 | if (file_exists("$cd/version.php")) { |
1358 | $plugin = new stdClass(); | |
1359 | $plugin->version = null; | |
bde002b8 | 1360 | $module = $plugin; |
bb8b2971 PS |
1361 | include("$cd/version.php"); |
1362 | $targetversion = $plugin->version; | |
795a08ad | 1363 | } |
db9d4a3d | 1364 | } |
1365 | ||
365a5941 | 1366 | $log = new stdClass(); |
bb8b2971 PS |
1367 | $log->type = $type; |
1368 | $log->plugin = $component; | |
1369 | $log->version = $currentversion; | |
1370 | $log->targetversion = $targetversion; | |
1371 | $log->info = $info; | |
1372 | $log->details = $details; | |
1373 | $log->backtrace = $backtrace; | |
1374 | $log->userid = $USER->id; | |
1375 | $log->timemodified = time(); | |
db9d4a3d | 1376 | try { |
1377 | $DB->insert_record('upgrade_log', $log); | |
1378 | } catch (Exception $ignored) { | |
795a08ad | 1379 | // possible during install or 2.0 upgrade |
db9d4a3d | 1380 | } |
1381 | } | |
1382 | ||
1383 | /** | |
1384 | * Marks start of upgrade, blocks any other access to site. | |
1385 | * The upgrade is finished at the end of script or after timeout. | |
72fb21b6 | 1386 | * |
1387 | * @global object | |
1388 | * @global object | |
1389 | * @global object | |
db9d4a3d | 1390 | */ |
1391 | function upgrade_started($preinstall=false) { | |
de6d81e6 | 1392 | global $CFG, $DB, $PAGE, $OUTPUT; |
db9d4a3d | 1393 | |
1394 | static $started = false; | |
1395 | ||
1396 | if ($preinstall) { | |
1397 | ignore_user_abort(true); | |
1398 | upgrade_setup_debug(true); | |
1399 | ||
1400 | } else if ($started) { | |
1401 | upgrade_set_timeout(120); | |
1402 | ||
1403 | } else { | |
c13a5e71 | 1404 | if (!CLI_SCRIPT and !$PAGE->headerprinted) { |
db9d4a3d | 1405 | $strupgrade = get_string('upgradingversion', 'admin'); |
78946b9b | 1406 | $PAGE->set_pagelayout('maintenance'); |
543f54d3 | 1407 | upgrade_init_javascript(); |
de6d81e6 | 1408 | $PAGE->set_title($strupgrade.' - Moodle '.$CFG->target_release); |
1409 | $PAGE->set_heading($strupgrade); | |
1410 | $PAGE->navbar->add($strupgrade); | |
1411 | $PAGE->set_cacheable(false); | |
1412 | echo $OUTPUT->header(); | |
db9d4a3d | 1413 | } |
1414 | ||
1415 | ignore_user_abort(true); | |
38fc0130 | 1416 | core_shutdown_manager::register_function('upgrade_finished_handler'); |
db9d4a3d | 1417 | upgrade_setup_debug(true); |
1418 | set_config('upgraderunning', time()+300); | |
1419 | $started = true; | |
1420 | } | |
1421 | } | |
1422 | ||
1423 | /** | |
b921b6ee | 1424 | * Internal function - executed if upgrade interrupted. |
db9d4a3d | 1425 | */ |
1426 | function upgrade_finished_handler() { | |
1427 | upgrade_finished(); | |
1428 | } | |
1429 | ||
1430 | /** | |
1431 | * Indicates upgrade is finished. | |
1432 | * | |
1433 | * This function may be called repeatedly. | |
72fb21b6 | 1434 | * |
1435 | * @global object | |
1436 | * @global object | |
db9d4a3d | 1437 | */ |
1438 | function upgrade_finished($continueurl=null) { | |
7e0d6675 | 1439 | global $CFG, $DB, $OUTPUT; |
db9d4a3d | 1440 | |
1441 | if (!empty($CFG->upgraderunning)) { | |
1442 | unset_config('upgraderunning'); | |
24dedb96 SH |
1443 | // We have to forcefully purge the caches using the writer here. |
1444 | // This has to be done after we unset the config var. If someone hits the site while this is set they will | |
1445 | // cause the config values to propogate to the caches. | |
1446 | // Caches are purged after the last step in an upgrade but there is several code routines that exceute between | |
1447 | // then and now that leaving a window for things to fall out of sync. | |
1448 | cache_helper::purge_all(true); | |
db9d4a3d | 1449 | upgrade_setup_debug(false); |
1450 | ignore_user_abort(false); | |
1451 | if ($continueurl) { | |
aa9a6867 | 1452 | echo $OUTPUT->continue_button($continueurl); |
7e0d6675 | 1453 | echo $OUTPUT->footer(); |
db9d4a3d | 1454 | die; |
1455 | } | |
1456 | } | |
1457 | } | |
1458 | ||
72fb21b6 | 1459 | /** |
1460 | * @global object | |
1461 | * @global object | |
1462 | */ | |
db9d4a3d | 1463 | function upgrade_setup_debug($starting) { |
1464 | global $CFG, $DB; | |
1465 | ||
1466 | static $originaldebug = null; | |
1467 | ||
1468 | if ($starting) { | |
1469 | if ($originaldebug === null) { | |
1470 | $originaldebug = $DB->get_debug(); | |
1471 | } | |
1472 | if (!empty($CFG->upgradeshowsql)) { | |
1473 | $DB->set_debug(true); | |
1474 | } | |
1475 | } else { | |
1476 | $DB->set_debug($originaldebug); | |
1477 | } | |
1478 | } | |
1479 | ||
1480 | function print_upgrade_separator() { | |
1481 | if (!CLI_SCRIPT) { | |
1482 | echo '<hr />'; | |
1483 | } | |
1484 | } | |
1485 | ||
795a08ad | 1486 | /** |
1487 | * Default start upgrade callback | |
1488 | * @param string $plugin | |
b921b6ee | 1489 | * @param bool $installation true if installation, false means upgrade |
795a08ad | 1490 | */ |
194cdca8 | 1491 | function print_upgrade_part_start($plugin, $installation, $verbose) { |
3c159385 | 1492 | global $OUTPUT; |
795a08ad | 1493 | if (empty($plugin) or $plugin == 'moodle') { |
1494 | upgrade_started($installation); // does not store upgrade running flag yet | |
194cdca8 | 1495 | if ($verbose) { |
3c159385 | 1496 | echo $OUTPUT->heading(get_string('coresystem')); |
194cdca8 | 1497 | } |
795a08ad | 1498 | } else { |
1499 | upgrade_started(); | |
194cdca8 | 1500 | if ($verbose) { |
3c159385 | 1501 | echo $OUTPUT->heading($plugin); |
194cdca8 | 1502 | } |
795a08ad | 1503 | } |
1504 | if ($installation) { | |
1505 | if (empty($plugin) or $plugin == 'moodle') { | |
1506 | // no need to log - log table not yet there ;-) | |
1507 | } else { | |
1508 | upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Starting plugin installation'); | |
1509 | } | |
1510 | } else { | |
1511 | if (empty($plugin) or $plugin == 'moodle') { | |
1512 | upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Starting core upgrade'); | |
1513 | } else { | |
1514 | upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Starting plugin upgrade'); | |
1515 | } | |
1516 | } | |
1517 | } | |
1518 | ||
1519 | /** | |
1520 | * Default end upgrade callback | |
1521 | * @param string $plugin | |
b921b6ee | 1522 | * @param bool $installation true if installation, false means upgrade |
795a08ad | 1523 | */ |
194cdca8 | 1524 | function print_upgrade_part_end($plugin, $installation, $verbose) { |
aa9a6867 | 1525 | global $OUTPUT; |
795a08ad | 1526 | upgrade_started(); |
1527 | if ($installation) { | |
1528 | if (empty($plugin) or $plugin == 'moodle') { | |
1529 | upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Core installed'); | |
1530 | } else { | |
1531 | upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Plugin installed'); | |
1532 | } | |
1533 | } else { | |
1534 | if (empty($plugin) or $plugin == 'moodle') { | |
1535 | upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Core upgraded'); | |
1536 | } else { | |
1537 | upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Plugin upgraded'); | |
1538 | } | |
1539 | } | |
194cdca8 | 1540 | if ($verbose) { |
2059d6ed RW |
1541 | $notification = new \core\output\notification(get_string('success'), \core\output\notification::NOTIFY_SUCCESS); |
1542 | $notification->set_show_closebutton(false); | |
1543 | echo $OUTPUT->render($notification); | |
194cdca8 | 1544 | print_upgrade_separator(); |
96db14f9 | 1545 | } |
1546 | } | |
1547 | ||
72fb21b6 | 1548 | /** |
b921b6ee | 1549 | * Sets up JS code required for all upgrade scripts. |
72fb21b6 | 1550 | * @global object |
1551 | */ | |
543f54d3 | 1552 | function upgrade_init_javascript() { |
e29380f3 | 1553 | global $PAGE; |
543f54d3 PS |
1554 | // scroll to the end of each upgrade page so that ppl see either error or continue button, |
1555 | // no need to scroll continuously any more, it is enough to jump to end once the footer is printed ;-) | |
1556 | $js = "window.scrollTo(0, 5000000);"; | |
1557 | $PAGE->requires->js_init_code($js); | |
db9d4a3d | 1558 | } |
1559 | ||
db9d4a3d | 1560 | /** |
1561 | * Try to upgrade the given language pack (or current language) | |
af8d4d91 | 1562 | * |
74a4c9a9 | 1563 | * @param string $lang the code of the language to update, defaults to the current language |
db9d4a3d | 1564 | */ |
bd41bdd9 PS |
1565 | function upgrade_language_pack($lang = null) { |
1566 | global $CFG; | |
db9d4a3d | 1567 | |
bd41bdd9 PS |
1568 | if (!empty($CFG->skiplangupgrade)) { |
1569 | return; | |
1570 | } | |
af8d4d91 | 1571 | |
bd41bdd9 PS |
1572 | if (!file_exists("$CFG->dirroot/$CFG->admin/tool/langimport/lib.php")) { |
1573 | // weird, somebody uninstalled the import utility | |
1574 | return; | |
1575 | } | |
1576 | ||
1577 | if (!$lang) { | |
db9d4a3d | 1578 | $lang = current_language(); |
1579 | } | |
1580 | ||
bd41bdd9 PS |
1581 | if (!get_string_manager()->translation_exists($lang)) { |
1582 | return; | |
db9d4a3d | 1583 | } |
1584 | ||
bd41bdd9 PS |
1585 | get_string_manager()->reset_caches(); |
1586 | ||
1587 | if ($lang === 'en') { | |
1588 | return; // Nothing to do | |
db9d4a3d | 1589 | } |
af8d4d91 | 1590 | |
bd41bdd9 PS |
1591 | upgrade_started(false); |
1592 | ||
1593 | require_once("$CFG->dirroot/$CFG->admin/tool/langimport/lib.php"); | |
1594 | tool_langimport_preupgrade_update($lang); | |
1595 | ||
af8d4d91 DM |
1596 | get_string_manager()->reset_caches(); |
1597 | ||
551fe0e5 | 1598 | print_upgrade_separator(); |
db9d4a3d | 1599 | } |
8580535b | 1600 | |
1601 | /** | |
1602 | * Install core moodle tables and initialize | |
1603 | * @param float $version target version | |
1604 | * @param bool $verbose | |
1605 | * @return void, may throw exception | |
1606 | */ | |
1607 | function install_core($version, $verbose) { | |
1608 | global $CFG, $DB; | |
1609 | ||
e2e35e71 | 1610 | // We can not call purge_all_caches() yet, make sure the temp and cache dirs exist and are empty. |
e2e35e71 | 1611 | remove_dir($CFG->cachedir.'', true); |
85b38061 PS |
1612 | make_cache_directory('', true); |
1613 | ||
1614 | remove_dir($CFG->localcachedir.'', true); | |
1615 | make_localcache_directory('', true); | |
1616 | ||
e2e35e71 | 1617 | remove_dir($CFG->tempdir.'', true); |
85b38061 PS |
1618 | make_temp_directory('', true); |
1619 | ||
e2e35e71 | 1620 | remove_dir($CFG->dataroot.'/muc', true); |
85b38061 | 1621 | make_writable_directory($CFG->dataroot.'/muc', true); |
e2e35e71 | 1622 | |
8580535b | 1623 | try { |
3ef7279f | 1624 | core_php_time_limit::raise(600); |
194cdca8 | 1625 | print_upgrade_part_start('moodle', true, $verbose); // does not store upgrade running flag |
8580535b | 1626 | |
1627 | $DB->get_manager()->install_from_xmldb_file("$CFG->libdir/db/install.xml"); | |
1628 | upgrade_started(); // we want the flag to be stored in config table ;-) | |
1629 | ||
1630 | // set all core default records and default settings | |
1631 | require_once("$CFG->libdir/db/install.php"); | |
c6d75bff | 1632 | xmldb_main_install(); // installs the capabilities too |
8580535b | 1633 | |
1634 | // store version | |
1635 | upgrade_main_savepoint(true, $version, false); | |
1636 | ||
df997f84 | 1637 | // Continue with the installation |
c6d75bff PS |
1638 | log_update_descriptions('moodle'); |
1639 | external_update_descriptions('moodle'); | |
8580535b | 1640 | events_update_definition('moodle'); |
309ae892 | 1641 | \core\task\manager::reset_scheduled_tasks_for_component('moodle'); |
8580535b | 1642 | message_update_providers('moodle'); |
6c0bfb14 | 1643 | \core\message\inbound\manager::update_handlers_for_component('moodle'); |
c026a28d | 1644 | core_tag_area::reset_definitions_for_component('moodle'); |
8580535b | 1645 | |
df997f84 | 1646 | // Write default settings unconditionally |
8580535b | 1647 | admin_apply_default_settings(NULL, true); |
1648 | ||
194cdca8 | 1649 | print_upgrade_part_end(null, true, $verbose); |
94ef67cf | 1650 | |
e0d9b7c0 SH |
1651 | // Purge all caches. They're disabled but this ensures that we don't have any persistent data just in case something |
1652 | // during installation didn't use APIs. | |
1653 | cache_helper::purge_all(); | |
8580535b | 1654 | } catch (exception $ex) { |
1655 | upgrade_handle_exception($ex); | |
1766e6a1 MG |
1656 | } catch (Throwable $ex) { |
1657 | // Engine errors in PHP7 throw exceptions of type Throwable (this "catch" will be ignored in PHP5). | |
1658 | upgrade_handle_exception($ex); | |
8580535b | 1659 | } |
1660 | } | |
1661 | ||
1662 | /** | |
1663 | * Upgrade moodle core | |
1664 | * @param float $version target version | |
1665 | * @param bool $verbose | |
1666 | * @return void, may throw exception | |
1667 | */ | |
1668 | function upgrade_core($version, $verbose) { | |
e2049782 | 1669 | global $CFG, $SITE, $DB, $COURSE; |
8580535b | 1670 | |
41209c1e PS |
1671 | raise_memory_limit(MEMORY_EXTRA); |
1672 | ||
3316fe24 | 1673 | require_once($CFG->libdir.'/db/upgrade.php'); // Defines upgrades |
3316fe24 | 1674 | |
8580535b | 1675 | try { |
7b4d5af7 | 1676 | // Reset caches before any output. |
b0dd08dd | 1677 | cache_helper::purge_all(true); |
7b4d5af7 | 1678 | purge_all_caches(); |
dcf9be7f | 1679 | |
8580535b | 1680 | // Upgrade current language pack if we can |
bd41bdd9 | 1681 | upgrade_language_pack(); |
8580535b | 1682 | |
194cdca8 | 1683 | print_upgrade_part_start('moodle', false, $verbose); |
8580535b | 1684 | |
6b4b7490 PS |
1685 | // Pre-upgrade scripts for local hack workarounds. |
1686 | $preupgradefile = "$CFG->dirroot/local/preupgrade.php"; | |
1687 | if (file_exists($preupgradefile)) { | |
3ef7279f | 1688 | core_php_time_limit::raise(); |
6b4b7490 PS |
1689 | require($preupgradefile); |
1690 | // Reset upgrade timeout to default. | |
1691 | upgrade_set_timeout(); | |
17da2e6f | 1692 | } |
1693 | ||
8580535b | 1694 | $result = xmldb_main_upgrade($CFG->version); |
1695 | if ($version > $CFG->version) { | |
1696 | // store version if not already there | |
1697 | upgrade_main_savepoint($result, $version, false); | |
1698 | } | |
1699 | ||
e2049782 MG |
1700 | // In case structure of 'course' table has been changed and we forgot to update $SITE, re-read it from db. |
1701 | $SITE = $DB->get_record('course', array('id' => $SITE->id)); | |
1702 | $COURSE = clone($SITE); | |
1703 | ||
8580535b | 1704 | // perform all other component upgrade routines |
1705 | update_capabilities('moodle'); | |
c6d75bff | 1706 | log_update_descriptions('moodle'); |
c976e271 | 1707 | external_update_descriptions('moodle'); |
8580535b | 1708 | events_update_definition('moodle'); |
309ae892 | 1709 | \core\task\manager::reset_scheduled_tasks_for_component('moodle'); |
8580535b | 1710 | message_update_providers('moodle'); |
6c0bfb14 | 1711 | \core\message\inbound\manager::update_handlers_for_component('moodle'); |
c026a28d | 1712 | core_tag_area::reset_definitions_for_component('moodle'); |
75af47ee SH |
1713 | // Update core definitions. |
1714 | cache_helper::update_definitions(true); | |
8580535b | 1715 | |
94ef67cf | 1716 | // Purge caches again, just to be sure we arn't holding onto old stuff now. |
a5a6e93f | 1717 | cache_helper::purge_all(true); |
7b4d5af7 | 1718 | purge_all_caches(); |
2e5eba85 PS |
1719 | |
1720 | // Clean up contexts - more and more stuff depends on existence of paths and contexts | |
e922fe23 PS |
1721 | context_helper::cleanup_instances(); |
1722 | context_helper::create_instances(null, false); | |
1723 | context_helper::build_all_paths(false); | |
1724 | $syscontext = context_system::instance(); | |
1725 | $syscontext->mark_dirty(); | |
8580535b | 1726 | |
194cdca8 | 1727 | print_upgrade_part_end('moodle', false, $verbose); |
8580535b | 1728 | } catch (Exception $ex) { |
1729 | upgrade_handle_exception($ex); | |
1766e6a1 MG |
1730 | } catch (Throwable $ex) { |
1731 | // Engine errors in PHP7 throw exceptions of type Throwable (this "catch" will be ignored in PHP5). | |
1732 | upgrade_handle_exception($ex); | |
8580535b | 1733 | } |
1734 | } | |
1735 | ||
1736 | /** | |
1737 | * Upgrade/install other parts of moodle | |
1738 | * @param bool $verbose | |
1739 | * @return void, may throw exception | |
1740 | */ | |
1741 | function upgrade_noncore($verbose) { | |
1742 | global $CFG; | |
1743 | ||
41209c1e PS |
1744 | raise_memory_limit(MEMORY_EXTRA); |
1745 | ||
8580535b | 1746 | // upgrade all plugins types |
1747 | try { | |
7b4d5af7 PS |
1748 | // Reset caches before any output. |
1749 | cache_helper::purge_all(true); | |
1750 | purge_all_caches(); | |
1751 | ||
46f6f7f2 | 1752 | $plugintypes = core_component::get_plugin_types(); |
8580535b | 1753 | foreach ($plugintypes as $type=>$location) { |
17da2e6f | 1754 | upgrade_plugins($type, 'print_upgrade_part_start', 'print_upgrade_part_end', $verbose); |
8580535b | 1755 | } |
ee7295ee JL |
1756 | // Upgrade services. |
1757 | // This function gives plugins and subsystems a chance to add functions to existing built-in services. | |
186eba1b JL |
1758 | external_update_services(); |
1759 | ||
94ef67cf | 1760 | // Update cache definitions. Involves scanning each plugin for any changes. |
75af47ee | 1761 | cache_helper::update_definitions(); |
c5701ce7 PS |
1762 | // Mark the site as upgraded. |
1763 | set_config('allversionshash', core_component::get_all_versions_hash()); | |
7b4d5af7 PS |
1764 | |
1765 | // Purge caches again, just to be sure we arn't holding onto old stuff now. | |
1766 | cache_helper::purge_all(true); | |
1767 | purge_all_caches(); | |
1768 | ||
8580535b | 1769 | } catch (Exception $ex) { |
1770 | upgrade_handle_exception($ex); | |
1766e6a1 MG |
1771 | } catch (Throwable $ex) { |
1772 | // Engine errors in PHP7 throw exceptions of type Throwable (this "catch" will be ignored in PHP5). | |
1773 | upgrade_handle_exception($ex); | |
8580535b | 1774 | } |
8580535b | 1775 | } |
3316fe24 | 1776 | |
1777 | /** | |
1778 | * Checks if the main tables have been installed yet or not. | |
e2e35e71 PS |
1779 | * |
1780 | * Note: we can not use caches here because they might be stale, | |
1781 | * use with care! | |
1782 | * | |
3316fe24 | 1783 | * @return bool |
1784 | */ | |
1785 | function core_tables_exist() { | |
1786 | global $DB; | |
1787 | ||
e2e35e71 | 1788 | if (!$tables = $DB->get_tables(false) ) { // No tables yet at all. |
3316fe24 | 1789 | return false; |
9b683d13 | 1790 | |
3316fe24 | 1791 | } else { // Check for missing main tables |
1792 | $mtables = array('config', 'course', 'groupings'); // some tables used in 1.9 and 2.0, preferable something from the start and end of install.xml | |
1793 | foreach ($mtables as $mtable) { | |
1794 | if (!in_array($mtable, $tables)) { | |
1795 | return false; | |
1796 | } | |
1797 | } | |
1798 | return true; | |
9b683d13 | 1799 | } |
ba04999c | 1800 | } |
c71ade2f PL |
1801 | |
1802 | /** | |
1803 | * upgrades the mnet rpc definitions for the given component. | |
1804 | * this method doesn't return status, an exception will be thrown in the case of an error | |
1805 | * | |
1806 | * @param string $component the plugin to upgrade, eg auth_mnet | |
1807 | */ | |
1808 | function upgrade_plugin_mnet_functions($component) { | |
1809 | global $DB, $CFG; | |
1810 | ||
8c59114f | 1811 | list($type, $plugin) = core_component::normalize_component($component); |
1c74b260 | 1812 | $path = core_component::get_plugin_directory($type, $plugin); |
c71ade2f | 1813 | |
17b71716 PS |
1814 | $publishes = array(); |
1815 | $subscribes = array(); | |
c71ade2f PL |
1816 | if (file_exists($path . '/db/mnet.php')) { |
1817 | require_once($path . '/db/mnet.php'); // $publishes comes from this file | |
1818 | } | |
1819 | if (empty($publishes)) { | |
1820 | $publishes = array(); // still need this to be able to disable stuff later | |
1821 | } | |
1822 | if (empty($subscribes)) { | |
1823 | $subscribes = array(); // still need this to be able to disable stuff later | |
1824 | } | |
1825 | ||
1826 | static $servicecache = array(); | |
1827 | ||
1828 | // rekey an array based on the rpc method for easy lookups later | |
1829 | $publishmethodservices = array(); | |
1830 | $subscribemethodservices = array(); | |
1831 | foreach($publishes as $servicename => $service) { | |
1832 | if (is_array($service['methods'])) { | |
1833 | foreach($service['methods'] as $methodname) { | |
1834 | $service['servicename'] = $servicename; | |
1835 | $publishmethodservices[$methodname][] = $service; | |
1836 | } | |
1837 | } | |
1838 | } | |
1839 | ||
1840 | // Disable functions that don't exist (any more) in the source | |
1841 | // Should these be deleted? What about their permissions records? | |
1842 | foreach ($DB->get_records('mnet_rpc', array('pluginname'=>$plugin, 'plugintype'=>$type), 'functionname ASC ') as $rpc) { | |
1843 | if (!array_key_exists($rpc->functionname, $publishmethodservices) && $rpc->enabled) { | |
1844 | $DB->set_field('mnet_rpc', 'enabled', 0, array('id' => $rpc->id)); | |
1845 | } else if (array_key_exists($rpc->functionname, $publishmethodservices) && !$rpc->enabled) { | |
1846 | $DB->set_field('mnet_rpc', 'enabled', 1, array('id' => $rpc->id)); | |
1847 | } | |
1848 | } | |
1849 | ||
1850 | // reflect all the services we're publishing and save them | |
c71ade2f PL |
1851 | static $cachedclasses = array(); // to store reflection information in |
1852 | foreach ($publishes as $service => $data) { | |
1853 | $f = $data['filename']; | |
1854 | $c = $data['classname']; | |
1855 | foreach ($data['methods'] as $method) { | |
6bdfef5d | 1856 | $dataobject = new stdClass(); |
c71ade2f PL |
1857 | $dataobject->plugintype = $type; |
1858 | $dataobject->pluginname = $plugin; | |
1859 | $dataobject->enabled = 1; | |
1860 | $dataobject->classname = $c; | |
1861 | $dataobject->filename = $f; | |
1862 | ||
1863 | if (is_string($method)) { | |
1864 | $dataobject->functionname = $method; | |
1865 | ||
1866 | } else if (is_array($method)) { // wants to override file or class | |
1867 | $dataobject->functionname = $method['method']; | |
1868 | $dataobject->classname = $method['classname']; | |
1869 | $dataobject->filename = $method['filename']; | |
1870 | } | |
1871 | $dataobject->xmlrpcpath = $type.'/'.$plugin.'/'.$dataobject->filename.'/'.$method; | |
1872 | $dataobject->static = false; | |
1873 | ||
1874 | require_once($path . '/' . $dataobject->filename); | |
1875 | $functionreflect = null; // slightly different ways to get this depending on whether it's a class method or a function | |
1876 | if (!empty($dataobject->classname)) { | |
1877 | if (!class_exists($dataobject->classname)) { | |
1878 | throw new moodle_exception('installnosuchmethod', 'mnet', '', (object)array('method' => $dataobject->functionname, 'class' => $dataobject->classname)); | |
1879 | } | |
1880 | $key = $dataobject->filename . '|' . $dataobject->classname; | |
1881 | if (!array_key_exists($key, $cachedclasses)) { // look to see if we've already got a reflection object | |
1882 | try { | |
052141ab CB |
1883 | $cachedclasses[$key] = new ReflectionClass($dataobject->classname); |
1884 | } catch (ReflectionException $e) { // catch these and rethrow them to something more helpful | |
c71ade2f PL |
1885 | throw new moodle_exception('installreflectionclasserror', 'mnet', '', (object)array('method' => $dataobject->functionname, 'class' => $dataobject->classname, 'error' => $e->getMessage())); |
1886 | } | |
1887 | } | |
1888 | $r =& $cachedclasses[$key]; | |
1889 | if (!$r->hasMethod($dataobject->functionname)) { | |
1890 | throw new moodle_exception('installnosuchmethod', 'mnet', '', (object)array('method' => $dataobject->functionname, 'class' => $dataobject->classname)); | |
1891 | } | |
052141ab | 1892 | $functionreflect = $r->getMethod($dataobject->functionname); |
c71ade2f PL |
1893 | $dataobject->static = (int)$functionreflect->isStatic(); |
1894 | } else { | |
1895 | if (!function_exists($dataobject->functionname)) { | |
1896 | throw new moodle_exception('installnosuchfunction', 'mnet', '', (object)array('method' => $dataobject->functionname, 'file' => $dataobject->filename)); | |
1897 | } | |
1898 | try { | |
052141ab CB |
1899 | $functionreflect = new ReflectionFunction($dataobject->functionname); |
1900 | } catch (ReflectionException $e) { // catch these and rethrow them to something more helpful | |
c71ade2f PL |
1901 | throw new moodle_exception('installreflectionfunctionerror', 'mnet', '', (object)array('method' => $dataobject->functionname, '' => $dataobject->filename, 'error' => $e->getMessage())); |
1902 | } | |
1903 | } | |
1904 | $dataobject->profile = serialize(admin_mnet_method_profile($functionreflect)); | |
052141ab | 1905 | $dataobject->help = admin_mnet_method_get_help($functionreflect); |
c71ade2f PL |
1906 | |
1907 | if ($record_exists = $DB->get_record('mnet_rpc', array('xmlrpcpath'=>$dataobject->xmlrpcpath))) { | |
1908 | $dataobject->id = $record_exists->id; | |
1909 | $dataobject->enabled = $record_exists->enabled; | |
1910 | $DB->update_record('mnet_rpc', $dataobject); | |
1911 | } else { | |
1912 | $dataobject->id = $DB->insert_record('mnet_rpc', $dataobject, true); | |
1913 | } | |
c71ade2f | 1914 | |
d5bd0b01 DM |
1915 | // TODO this API versioning must be reworked, here the recently processed method |
1916 | // sets the service API which may not be correct | |
677b6321 PL |
1917 | foreach ($publishmethodservices[$dataobject->functionname] as $service) { |
1918 | if ($serviceobj = $DB->get_record('mnet_service', array('name'=>$service['servicename']))) { | |
1919 | $serviceobj->apiversion = $service['apiversion']; | |
1920 | $DB->update_record('mnet_service', $serviceobj); | |
1921 | } else { | |
1922 | $serviceobj = new stdClass(); | |
1923 | $serviceobj->name = $service['servicename']; | |
f4a2817a | 1924 | $serviceobj->description = empty($service['description']) ? '' : $service['description']; |
677b6321 PL |
1925 | $serviceobj->apiversion = $service['apiversion']; |
1926 | $serviceobj->offer = 1; | |
1927 | $serviceobj->id = $DB->insert_record('mnet_service', $serviceobj); | |
1928 | } | |
1929 | $servicecache[$service['servicename']] = $serviceobj; | |
1930 | if (!$DB->record_exists('mnet_service2rpc', array('rpcid'=>$dataobject->id, 'serviceid'=>$serviceobj->id))) { | |
1931 | $obj = new stdClass(); | |
1932 | $obj->rpcid = $dataobject->id; | |
1933 | $obj->serviceid = $serviceobj->id; | |
1934 | $DB->insert_record('mnet_service2rpc', $obj, true); | |
1935 | } | |
c71ade2f PL |
1936 | } |
1937 | } | |
1938 | } | |
c71ade2f PL |
1939 | // finished with methods we publish, now do subscribable methods |
1940 | foreach($subscribes as $service => $methods) { | |
1941 | if (!array_key_exists($service, $servicecache)) { | |
1942 | if (!$serviceobj = $DB->get_record('mnet_service', array('name' => $service))) { | |
81634f03 | 1943 | debugging("TODO: skipping unknown service $service - somebody needs to fix MDL-21993"); |
c71ade2f PL |
1944 | continue; |
1945 | } | |
1946 | $servicecache[$service] = $serviceobj; | |
1947 | } else { | |
1948 | $serviceobj = $servicecache[$service]; | |
1949 | } | |
1950 | foreach ($methods as $method => $xmlrpcpath) { | |
1951 | if (!$rpcid = $DB->get_field('mnet_remote_rpc', 'id', array('xmlrpcpath'=>$xmlrpcpath))) { | |
1952 | $remoterpc = (object)array( | |
1953 | 'functionname' => $method, | |
1954 | 'xmlrpcpath' => $xmlrpcpath, | |
1955 | 'plugintype' => $type, | |
1956 | 'pluginname' => $plugin, | |
1957 | 'enabled' => 1, | |
1958 | ); | |
1959 | $rpcid = $remoterpc->id = $DB->insert_record('mnet_remote_rpc', $remoterpc, true); | |
1960 | } | |
1961 | if (!$DB->record_exists('mnet_remote_service2rpc', array('rpcid'=>$rpcid, 'serviceid'=>$serviceobj->id))) { | |
1962 | $obj = new stdClass(); | |
1963 | $obj->rpcid = $rpcid; | |
1964 | $obj->serviceid = $serviceobj->id; | |
1965 | $DB->insert_record('mnet_remote_service2rpc', $obj, true); | |
1966 | } | |
677b6321 | 1967 | $subscribemethodservices[$method][] = $service; |
c71ade2f PL |
1968 | } |
1969 | } | |
1970 | ||
1971 | foreach ($DB->get_records('mnet_remote_rpc', array('pluginname'=>$plugin, 'plugintype'=>$type), 'functionname ASC ') as $rpc) { | |
1972 | if (!array_key_exists($rpc->functionname, $subscribemethodservices) && $rpc->enabled) { | |
1973 | $DB->set_field('mnet_remote_rpc', 'enabled', 0, array('id' => $rpc->id)); | |
1974 | } else if (array_key_exists($rpc->functionname, $subscribemethodservices) && !$rpc->enabled) { | |
1975 | $DB->set_field('mnet_remote_rpc', 'enabled', 1, array('id' => $rpc->id)); | |
1976 | } | |
1977 | } | |
1978 | ||
1979 | return true; | |
1980 | } | |
1981 | ||
1982 | /** | |
052141ab | 1983 | * Given some sort of reflection function/method object, return a profile array, ready to be serialized and stored |
c71ade2f | 1984 | * |
052141ab | 1985 | * @param ReflectionFunctionAbstract $function reflection function/method object from which to extract information |
c71ade2f | 1986 | * |
052141ab | 1987 | * @return array associative array with function/method information |
c71ade2f | 1988 | */ |
052141ab CB |
1989 | function admin_mnet_method_profile(ReflectionFunctionAbstract $function) { |
1990 | $commentlines = admin_mnet_method_get_docblock($function); | |
1991 | $getkey = function($key) use ($commentlines) { | |
1992 | return array_values(array_filter($commentlines, function($line) use ($key) { | |
1993 | return $line[0] == $key; | |
1994 | })); | |
1995 | }; | |
1996 | $returnline = $getkey('@return'); | |
1997 | return array ( | |
1998 | 'parameters' => array_map(function($line) { | |
1999 | return array( | |
2000 | 'name' => trim($line[2], " \t\n\r\0\x0B$"), | |
2001 | 'type' => $line[1], | |
2002 | 'description' => $line[3] | |
2003 | ); | |
2004 | }, $getkey('@param')), | |
2005 | ||
2006 | 'return' => array( | |
2007 | 'type' => !empty($returnline[0][1]) ? $returnline[0][1] : 'void', | |
2008 | 'description' => !empty($returnline[0][2]) ? $returnline[0][2] : '' | |
2009 | ) | |
c71ade2f | 2010 | ); |
052141ab CB |
2011 | } |
2012 | ||
2013 | /** | |
2014 | * Given some sort of reflection function/method object, return an array of docblock lines, where each line is an array of | |
2015 | * keywords/descriptions | |
2016 | * | |
2017 | * @param ReflectionFunctionAbstract $function reflection function/method object from which to extract information | |
2018 | * | |
2019 | * @return array docblock converted in to an array | |
2020 | */ | |
2021 | function admin_mnet_method_get_docblock(ReflectionFunctionAbstract $function) { | |
2022 | return array_map(function($line) { | |
2023 | $text = trim($line, " \t\n\r\0\x0B*/"); | |
2024 | if (strpos($text, '@param') === 0) { | |
2025 | return preg_split('/\s+/', $text, 4); | |
2026 | } | |
2027 | ||
2028 | if (strpos($text, '@return') === 0) { | |
2029 | return preg_split('/\s+/', $text, 3); | |
2030 | } | |
2031 | ||
2032 | return array($text); | |
2033 | }, explode("\n", $function->getDocComment())); | |
2034 | } | |
2035 | ||
2036 | /** | |
2037 | * Given some sort of reflection function/method object, return just the help text | |
2038 | * | |
2039 | * @param ReflectionFunctionAbstract $function reflection function/method object from which to extract information | |
2040 | * | |
2041 | * @return string docblock help text | |
2042 | */ | |
2043 | function admin_mnet_method_get_help(ReflectionFunctionAbstract $function) { | |
2044 | $helplines = array_map(function($line) { | |
2045 | return implode(' ', $line); | |
2046 | }, array_values(array_filter(admin_mnet_method_get_docblock($function), function($line) { | |
2047 | return strpos($line[0], '@') !== 0 && !empty($line[0]); | |
2048 | }))); | |
2049 | ||
2050 | return implode("\n", $helplines); | |
c71ade2f | 2051 | } |
424a19b1 | 2052 | |
941de296 MG |
2053 | /** |
2054 | * Detect draft file areas with missing root directory records and add them. | |
2055 | */ | |
2056 | function upgrade_fix_missing_root_folders_draft() { | |
2057 | global $DB; | |
2058 | ||
2059 | $transaction = $DB->start_delegated_transaction(); | |
2060 | ||
2061 | $sql = "SELECT contextid, itemid, MAX(timecreated) AS timecreated, MAX(timemodified) AS timemodified | |
2062 | FROM {files} | |
2063 | WHERE (component = 'user' AND filearea = 'draft') | |
2064 | GROUP BY contextid, itemid | |
2065 | HAVING MAX(CASE WHEN filename = '.' AND filepath = '/' THEN 1 ELSE 0 END) = 0"; | |
2066 | ||
2067 | $rs = $DB->get_recordset_sql($sql); | |
2068 | $defaults = array('component' => 'user', | |
2069 | 'filearea' => 'draft', | |
2070 | 'filepath' => '/', | |
2071 | 'filename' => '.', | |
2072 | 'userid' => 0, // Don't rely on any particular user for these system records. | |
2073 | 'filesize' => 0, | |
e6a47804 AN |
2074 | // Note: This does not use the file_storage API's hash calculator |
2075 | // because access to core APIs is not allowed during upgrade. | |
2076 | 'contenthash' => sha1(''), | |
2077 | ); | |
941de296 MG |
2078 | foreach ($rs as $r) { |
2079 | $r->pathnamehash = sha1("/$r->contextid/user/draft/$r->itemid/."); | |
2080 | $DB->insert_record('files', (array)$r + $defaults); | |
2081 | } | |
2082 | $rs->close(); | |
2083 | $transaction->allow_commit(); | |
2084 | } | |
71611510 MN |
2085 | |
2086 | /** | |
2087 | * This function verifies that the database is not using an unsupported storage engine. | |
2088 | * | |
2089 | * @param environment_results $result object to update, if relevant | |
2090 | * @return environment_results|null updated results object, or null if the storage engine is supported | |
2091 | */ | |
2092 | function check_database_storage_engine(environment_results $result) { | |
2093 | global $DB; | |
2094 | ||
2095 | // Check if MySQL is the DB family (this will also be the same for MariaDB). | |
2096 | if ($DB->get_dbfamily() == 'mysql') { | |
2097 | // Get the database engine we will either be using to install the tables, or what we are currently using. | |
2098 | $engine = $DB->get_dbengine(); | |
2099 | // Check if MyISAM is the storage engine that will be used, if so, do not proceed and display an error. | |
2100 | if ($engine == 'MyISAM') { | |
2101 | $result->setInfo('unsupported_db_storage_engine'); | |
2102 | $result->setStatus(false); | |
2103 | return $result; | |
2104 | } | |
2105 | } | |
2106 | ||
2107 | return null; | |
2108 | } | |
1bd4b9fc SL |
2109 | |
2110 | /** | |
2111 | * Method used to check the usage of slasharguments config and display a warning message. | |
2112 | * | |
2113 | * @param environment_results $result object to update, if relevant. | |
2114 | * @return environment_results|null updated results or null if slasharguments is disabled. | |
2115 | */ | |
2116 | function check_slasharguments(environment_results $result){ | |
2117 | global $CFG; | |
2118 | ||
e284ac02 | 2119 | if (!during_initial_install() && empty($CFG->slasharguments)) { |
1bd4b9fc SL |
2120 | $result->setInfo('slasharguments'); |
2121 | $result->setStatus(false); | |
2122 | return $result; | |
2123 | } | |
2124 | ||
2125 | return null; | |
2126 | } | |
9b8104ce SL |
2127 | |
2128 | /** | |
2129 | * This function verifies if the database has tables using innoDB Antelope row format. | |
2130 | * | |
2131 | * @param environment_results $result | |
2132 | * @return environment_results|null updated results object, or null if no Antelope table has been found. | |
2133 | */ | |
2134 | function check_database_tables_row_format(environment_results $result) { | |
2135 | global $DB; | |
2136 | ||
2137 | if ($DB->get_dbfamily() == 'mysql') { | |
2138 | $generator = $DB->get_manager()->generator; | |
2139 | ||
2140 | foreach ($DB->get_tables(false) as $table) { | |
2141 | $columns = $DB->get_columns($table, false); | |
c7ccb543 | 2142 | $size = $generator->guess_antelope_row_size($columns); |
9b8104ce SL |
2143 | $format = $DB->get_row_format($table); |
2144 | ||
2145 | if ($size <= $generator::ANTELOPE_MAX_ROW_SIZE) { | |
2146 | continue; | |
2147 | } | |
2148 | ||
2149 | if ($format === 'Compact' or $format === 'Redundant') { | |
2150 | $result->setInfo('unsupported_db_table_row_format'); | |
2151 | $result->setStatus(false); | |
2152 | return $result; | |
2153 | } | |
2154 | } | |
2155 | } | |
2156 | ||
2157 | return null; | |
2158 | } | |
ebea19cb | 2159 | |
0bbefd81 AG |
2160 | /** |
2161 | * This function verfies that the database has tables using InnoDB Antelope row format. | |
2162 | * | |
2163 | * @param environment_results $result | |
2164 | * @return environment_results|null updated results object, or null if no Antelope table has been found. | |
2165 | */ | |
2166 | function check_mysql_file_format(environment_results $result) { | |
2167 | global $DB; | |
2168 | ||
2169 | if ($DB->get_dbfamily() == 'mysql') { | |
2170 | $collation = $DB->get_dbcollation(); | |
2171 | $collationinfo = explode('_', $collation); | |
2172 | $charset = reset($collationinfo); | |
2173 | ||
2174 | if ($charset == 'utf8mb4') { | |
2175 | if ($DB->get_row_format() !== "Barracuda") { | |
2176 | $result->setInfo('mysql_full_unicode_support#File_format'); | |
2177 | $result->setStatus(false); | |
2178 | return $result; | |
2179 | } | |
2180 | } | |
2181 | } | |
2182 | return null; | |
2183 | } | |
2184 | ||
2185 | /** | |
2186 | * This function verfies that the database has a setting of one file per table. This is required for 'utf8mb4'. | |
2187 | * | |
2188 | * @param environment_results $result | |
2189 | * @return environment_results|null updated results object, or null if innodb_file_per_table = 1. | |
2190 | */ | |
2191 | function check_mysql_file_per_table(environment_results $result) { | |
2192 | global $DB; | |
2193 | ||
2194 | if ($DB->get_dbfamily() == 'mysql') { | |
2195 | $collation = $DB->get_dbcollation(); | |
2196 | $collationinfo = explode('_', $collation); | |
2197 | $charset = reset($collationinfo); | |
2198 | ||
2199 | if ($charset == 'utf8mb4') { | |
2200 | if (!$DB->is_file_per_table_enabled()) { | |
2201 | $result->setInfo('mysql_full_unicode_support#File_per_table'); | |
2202 | $result->setStatus(false); | |
2203 | return $result; | |
2204 | } | |
2205 | } | |
2206 | } | |
2207 | return null; | |
2208 | } | |
2209 | ||
2210 | /** | |
2211 | * This function verfies that the database has the setting of large prefix enabled. This is required for 'utf8mb4'. | |
2212 | * | |
2213 | * @param environment_results $result | |
2214 | * @return environment_results|null updated results object, or null if innodb_large_prefix = 1. | |
2215 | */ | |
2216 | function check_mysql_large_prefix(environment_results $result) { | |
2217 | global $DB; | |
2218 | ||
2219 | if ($DB->get_dbfamily() == 'mysql') { | |
2220 | $collation = $DB->get_dbcollation(); | |
2221 | $collationinfo = explode('_', $collation); | |
2222 | $charset = reset($collationinfo); | |
2223 | ||
2224 | if ($charset == 'utf8mb4') { | |
2225 | if (!$DB->is_large_prefix_enabled()) { | |
2226 | $result->setInfo('mysql_full_unicode_support#Large_prefix'); | |
2227 | $result->setStatus(false); | |
2228 | return $result; | |
2229 | } | |
2230 | } | |
2231 | } | |
2232 | return null; | |
2233 | } | |
2234 | ||
2235 | /** | |
2236 | * This function checks the database to see if it is using incomplete unicode support. | |
2237 | * | |
2238 | * @param environment_results $result $result | |
2239 | * @return environment_results|null updated results object, or null if unicode is fully supported. | |
2240 | */ | |
2241 | function check_mysql_incomplete_unicode_support(environment_results $result) { | |
2242 | global $DB; | |
2243 | ||
2244 | if ($DB->get_dbfamily() == 'mysql') { | |
2245 | $collation = $DB->get_dbcollation(); | |
2246 | $collationinfo = explode('_', $collation); | |
2247 | $charset = reset($collationinfo); | |
2248 | ||
2249 | if ($charset == 'utf8') { | |
2250 | $result->setInfo('mysql_full_unicode_support'); | |
2251 | $result->setStatus(false); | |
2252 | return $result; | |
2253 | } | |
2254 | } | |
2255 | return null; | |
2256 | } | |
2257 | ||
ebea19cb FM |
2258 | /** |
2259 | * Upgrade the minmaxgrade setting. | |
2260 | * | |
2261 | * This step should only be run for sites running 2.8 or later. Sites using 2.7 will be fine | |
2262 | * using the new default system setting $CFG->grade_minmaxtouse. | |
2263 | * | |
2264 | * @return void | |
2265 | */ | |
2266 | function upgrade_minmaxgrade() { | |
2267 | global $CFG, $DB; | |
2268 | ||
2269 | // 2 is a copy of GRADE_MIN_MAX_FROM_GRADE_GRADE. | |
2270 | $settingvalue = 2; | |
2271 | ||
2272 | // Set the course setting when: | |
2273 | // - The system setting does not exist yet. | |
2274 | // - The system seeting is not set to what we'd set the course setting. | |
2275 | $setcoursesetting = !isset($CFG->grade_minmaxtouse) || $CFG->grade_minmaxtouse != $settingvalue; | |
2276 | ||
2277 | // Identify the courses that have inconsistencies grade_item vs grade_grade. | |
2278 | $sql = "SELECT DISTINCT(gi.courseid) | |
82cca1ab G |
2279 | FROM {grade_grades} gg |
2280 | JOIN {grade_items} gi | |
ebea19cb | 2281 | ON gg.itemid = gi.id |
82cca1ab | 2282 | WHERE gi.itemtype NOT IN (?, ?) |
ebea19cb FM |
2283 | AND (gg.rawgrademax != gi.grademax OR gg.rawgrademin != gi.grademin)"; |
2284 | ||
2285 | $rs = $DB->get_recordset_sql($sql, array('course', 'category')); | |
2286 | foreach ($rs as $record) { | |
2287 | // Flag the course to show a notice in the gradebook. | |
2288 | set_config('show_min_max_grades_changed_' . $record->courseid, 1); | |
2289 | ||
2290 | // Set the appropriate course setting so that grades displayed are not changed. | |
2291 | $configname = 'minmaxtouse'; | |
2292 | if ($setcoursesetting && | |
2293 | !$DB->record_exists('grade_settings', array('courseid' => $record->courseid, 'name' => $configname))) { | |
2294 | // Do not set the setting when the course already defines it. | |
2295 | $data = new stdClass(); | |
2296 | $data->courseid = $record->courseid; | |
2297 | $data->name = $configname; | |
2298 | $data->value = $settingvalue; | |
2299 | $DB->insert_record('grade_settings', $data); | |
2300 | } | |
2301 | ||
2302 | // Mark the grades to be regraded. | |
2303 | $DB->set_field('grade_items', 'needsupdate', 1, array('courseid' => $record->courseid)); | |
2304 | } | |
2305 | $rs->close(); | |
2306 | } | |
98b32c9e DM |
2307 | |
2308 | ||
2309 | /** | |
2310 | * Assert the upgrade key is provided, if it is defined. | |
2311 | * | |
2312 | * The upgrade key can be defined in the main config.php as $CFG->upgradekey. If | |
2313 | * it is defined there, then its value must be provided every time the site is | |
2314 | * being upgraded, regardless the administrator is logged in or not. | |
2315 | * | |
2316 | * This is supposed to be used at certain places in /admin/index.php only. | |
2317 | * | |
2318 | * @param string|null $upgradekeyhash the SHA-1 of the value provided by the user | |
2319 | */ | |
2320 | function check_upgrade_key($upgradekeyhash) { | |
2321 | global $CFG, $PAGE; | |
2322 | ||
2323 | if (isset($CFG->config_php_settings['upgradekey'])) { | |
2324 | if ($upgradekeyhash === null or $upgradekeyhash !== sha1($CFG->config_php_settings['upgradekey'])) { | |
2325 | if (!$PAGE->headerprinted) { | |
2326 | $output = $PAGE->get_renderer('core', 'admin'); | |
2327 | echo $output->upgradekey_form_page(new moodle_url('/admin/index.php', array('cache' => 0))); | |
2328 | die(); | |
2329 | } else { | |
2330 | // This should not happen. | |
2331 | die('Upgrade locked'); | |
2332 | } | |
2333 | } | |
2334 | } | |
2335 | } | |
531381f9 DM |
2336 | |
2337 | /** | |
2338 | * Helper procedure/macro for installing remote plugins at admin/index.php | |
2339 | * | |
2340 | * Does not return, always redirects or exits. | |
2341 | * | |
2342 | * @param array $installable list of \core\update\remote_info | |
2343 | * @param bool $confirmed false: display the validation screen, true: proceed installation | |
2344 | * @param string $heading validation screen heading | |
2345 | * @param moodle_url|string|null $continue URL to proceed with installation at the validation screen | |
8726c07c | 2346 | * @param moodle_url|string|null $return URL to go back on cancelling at the validation screen |
531381f9 | 2347 | */ |
2d00be61 | 2348 | function upgrade_install_plugins(array $installable, $confirmed, $heading='', $continue=null, $return=null) { |
b0fc7898 | 2349 | global $CFG, $PAGE; |
531381f9 DM |
2350 | |
2351 | if (empty($return)) { | |
2352 | $return = $PAGE->url; | |
2353 | } | |
2354 | ||
b0fc7898 DM |
2355 | if (!empty($CFG->disableupdateautodeploy)) { |
2356 | redirect($return); | |
2357 | } | |
2358 | ||
531381f9 DM |
2359 | if (empty($installable)) { |
2360 | redirect($return); | |
2361 | } | |
2362 | ||
2363 | $pluginman = core_plugin_manager::instance(); | |
2364 | ||
2365 | if ($confirmed) { | |
2366 | // Installation confirmed at the validation results page. | |
2d00be61 DM |
2367 | if (!$pluginman->install_plugins($installable, true, true)) { |
2368 | throw new moodle_exception('install_plugins_failed', 'core_plugin', $return); | |
531381f9 | 2369 | } |
d9a5b810 | 2370 | |
8726c07c | 2371 | // Always redirect to admin/index.php to perform the database upgrade. |
d9a5b810 DM |
2372 | // Do not throw away the existing $PAGE->url parameters such as |
2373 | // confirmupgrade or confirmrelease if $PAGE->url is a superset of the | |
2374 | // URL we must go to. | |
2375 | $mustgoto = new moodle_url('/admin/index.php', array('cache' => 0, 'confirmplugincheck' => 0)); | |
2376 | if ($mustgoto->compare($PAGE->url, URL_MATCH_PARAMS)) { | |
2377 | redirect($PAGE->url); | |
2378 | } else { | |
2379 | redirect($mustgoto); | |
2380 | } | |
531381f9 DM |
2381 | |
2382 | } else { | |
2383 | $output = $PAGE->get_renderer('core', 'admin'); | |
2384 | echo $output->header(); | |
2385 | if ($heading) { | |
2386 | echo $output->heading($heading, 3); | |
2387 | } | |
2388 | echo html_writer::start_tag('pre', array('class' => 'plugin-install-console')); | |
2d00be61 | 2389 | $validated = $pluginman->install_plugins($installable, false, false); |
531381f9 DM |
2390 | echo html_writer::end_tag('pre'); |
2391 | if ($validated) { | |
4d7528f9 | 2392 | echo $output->plugins_management_confirm_buttons($continue, $return); |
531381f9 | 2393 | } else { |
4d7528f9 | 2394 | echo $output->plugins_management_confirm_buttons(null, $return); |
531381f9 DM |
2395 | } |
2396 | echo $output->footer(); | |
2397 | die(); | |
2398 | } | |
2399 | } | |
c4d69228 SL |
2400 | /** |
2401 | * Method used to check the installed unoconv version. | |
2402 | * | |
2403 | * @param environment_results $result object to update, if relevant. | |
2404 | * @return environment_results|null updated results or null if unoconv path is not executable. | |
2405 | */ | |
0eecf876 | 2406 | function check_unoconv_version(environment_results $result) { |
c4d69228 SL |
2407 | global $CFG; |
2408 | ||
0eecf876 | 2409 | if (!during_initial_install() && !empty($CFG->pathtounoconv) && file_is_executable(trim($CFG->pathtounoconv))) { |
84440fe3 SL |
2410 | $currentversion = 0; |
2411 | $supportedversion = 0.7; | |
0eecf876 AG |
2412 | $unoconvbin = \escapeshellarg($CFG->pathtounoconv); |
2413 | $command = "$unoconvbin --version"; | |
2414 | exec($command, $output); | |
84440fe3 SL |
2415 | |
2416 | // If the command execution returned some output, then get the unoconv version. | |
6937d89b | 2417 | if ($output) { |
6937d89b SL |
2418 | foreach ($output as $response) { |
2419 | if (preg_match('/unoconv (\\d+\\.\\d+)/', $response, $matches)) { | |
2420 | $currentversion = (float)$matches[1]; | |
2421 | } | |
2422 | } | |
84440fe3 SL |
2423 | } |
2424 | ||
2425 | if ($currentversion < $supportedversion) { | |
2426 | $result->setInfo('unoconv version not supported'); | |
2427 | $result->setStatus(false); | |
2428 | return $result; | |
c4d69228 SL |
2429 | } |
2430 | } | |
2431 | return null; | |
2432 | } | |
ab3759ff CB |
2433 | |
2434 | /** | |
89556019 | 2435 | * Checks for up-to-date TLS libraries. NOTE: this is not currently used, see MDL-57262. |
ab3759ff CB |
2436 | * |
2437 | * @param environment_results $result object to update, if relevant. | |
2438 | * @return environment_results|null updated results or null if unoconv path is not executable. | |
2439 | */ | |
2440 | function check_tls_libraries(environment_results $result) { | |
2441 | global $CFG; | |
2442 | ||
4a1165ba DM |
2443 | if (!function_exists('curl_version')) { |
2444 | $result->setInfo('cURL PHP extension is not installed'); | |
2445 | $result->setStatus(false); | |
2446 | return $result; | |
2447 | } | |
2448 | ||
ab3759ff CB |
2449 | if (!\core\upgrade\util::validate_php_curl_tls(curl_version(), PHP_ZTS)) { |
2450 | $result->setInfo('invalid ssl/tls configuration'); | |
2451 | $result->setStatus(false); | |
2452 | return $result; | |
2453 | } | |
2454 | ||
2455 | if (!\core\upgrade\util::can_use_tls12(curl_version(), php_uname('r'))) { | |
2456 | $result->setInfo('ssl/tls configuration not supported'); | |
2457 | $result->setStatus(false); | |
2458 | return $result; | |
2459 | } | |
2460 | ||
2461 | return null; | |
2462 | } | |
f2330472 AA |
2463 | |
2464 | /** | |
2465 | * Check if recommended version of libcurl is installed or not. | |
2466 | * | |
2467 | * @param environment_results $result object to update, if relevant. | |
2468 | * @return environment_results|null updated results or null. | |
2469 | */ | |
2470 | function check_libcurl_version(environment_results $result) { | |
2471 | ||
acefc7d9 VZ |
2472 | if (!function_exists('curl_version')) { |
2473 | $result->setInfo('cURL PHP extension is not installed'); | |
2474 | $result->setStatus(false); | |
2475 | return $result; | |
2476 | } | |
2477 | ||
f2330472 AA |
2478 | // Supported version and version number. |
2479 | $supportedversion = 0x071304; | |
2480 | $supportedversionstring = "7.19.4"; | |
2481 | ||
2482 | // Installed version. | |
2483 | $curlinfo = curl_version(); | |
2484 | $currentversion = $curlinfo['version_number']; | |
2485 | ||
2486 | if ($currentversion < $supportedversion) { | |
2487 | // Test fail. | |
2488 | // Set info, we want to let user know how to resolve the problem. | |
2489 | $result->setInfo('Libcurl version check'); | |
2490 | $result->setNeededVersion($supportedversionstring); | |
2491 | $result->setCurrentVersion($curlinfo['version']); | |
2492 | $result->setStatus(false); | |
2493 | return $result; | |
2494 | } | |
2495 | ||
2496 | return null; | |
2497 | } |