This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | namespace Elgg; |
||
3 | |||
4 | /** |
||
5 | * Upgrade service for Elgg |
||
6 | * |
||
7 | * This is a straight port of the procedural code used for upgrading before |
||
8 | * Elgg 1.9. |
||
9 | * |
||
10 | * @access private |
||
11 | * |
||
12 | * @package Elgg.Core |
||
13 | * @subpackage Upgrade |
||
14 | */ |
||
15 | class UpgradeService { |
||
16 | |||
17 | /** |
||
18 | * Global Elgg configuration |
||
19 | * |
||
20 | * @var \stdClass |
||
21 | */ |
||
22 | private $CONFIG; |
||
23 | |||
24 | /** |
||
25 | * Constructor |
||
26 | */ |
||
27 | public function __construct() { |
||
28 | global $CONFIG; |
||
29 | $this->CONFIG = $CONFIG; |
||
30 | } |
||
31 | |||
32 | /** |
||
33 | * Run the upgrade process |
||
34 | * |
||
35 | * @return array |
||
36 | */ |
||
37 | public function run() { |
||
38 | $result = array( |
||
39 | 'failure' => false, |
||
40 | 'reason' => '', |
||
41 | ); |
||
42 | |||
43 | // prevent someone from running the upgrade script in parallel (see #4643) |
||
44 | if (!$this->getUpgradeMutex()) { |
||
45 | $result['failure'] = true; |
||
46 | $result['reason'] = _elgg_services()->translator->translate('upgrade:locked'); |
||
47 | return $result; |
||
48 | } |
||
49 | |||
50 | // disable the system log for upgrades to avoid exceptions when the schema changes. |
||
51 | _elgg_services()->events->unregisterHandler('log', 'systemlog', 'system_log_default_logger'); |
||
52 | _elgg_services()->events->unregisterHandler('all', 'all', 'system_log_listener'); |
||
53 | |||
54 | // turn off time limit |
||
55 | set_time_limit(0); |
||
56 | |||
57 | if ($this->getUnprocessedUpgrades()) { |
||
58 | $this->processUpgrades(); |
||
59 | } |
||
60 | |||
61 | _elgg_services()->events->trigger('upgrade', 'system', null); |
||
62 | elgg_flush_caches(); |
||
63 | |||
64 | $this->releaseUpgradeMutex(); |
||
65 | |||
66 | return $result; |
||
67 | } |
||
68 | |||
69 | /** |
||
70 | * Run any php upgrade scripts which are required |
||
71 | * |
||
72 | * @param int $version Version upgrading from. |
||
73 | * @param bool $quiet Suppress errors. Don't use this. |
||
74 | * |
||
75 | * @return bool |
||
76 | */ |
||
77 | protected function upgradeCode($version, $quiet = false) { |
||
78 | $version = (int) $version; |
||
79 | $upgrade_path = _elgg_services()->config->get('path') . 'engine/lib/upgrades/'; |
||
80 | $processed_upgrades = $this->getProcessedUpgrades(); |
||
81 | |||
82 | // upgrading from 1.7 to 1.8. Need to bootstrap. |
||
83 | if (!$processed_upgrades) { |
||
84 | $this->bootstrap17to18(); |
||
85 | |||
86 | // grab accurate processed upgrades |
||
87 | $processed_upgrades = $this->getProcessedUpgrades(); |
||
88 | } |
||
89 | |||
90 | $upgrade_files = $this->getUpgradeFiles($upgrade_path); |
||
91 | |||
92 | if ($upgrade_files === false) { |
||
93 | return false; |
||
94 | } |
||
95 | |||
96 | $upgrades = $this->getUnprocessedUpgrades($upgrade_files, $processed_upgrades); |
||
97 | |||
98 | // Sort and execute |
||
99 | sort($upgrades); |
||
100 | |||
101 | foreach ($upgrades as $upgrade) { |
||
102 | $upgrade_version = $this->getUpgradeFileVersion($upgrade); |
||
103 | $success = true; |
||
104 | |||
105 | if ($upgrade_version <= $version) { |
||
106 | // skip upgrade files from before the installation version of Elgg |
||
107 | // because the upgrade files from before the installation version aren't |
||
108 | // added to the database. |
||
109 | continue; |
||
110 | } |
||
111 | |||
112 | // hide all errors. |
||
113 | if ($quiet) { |
||
114 | // hide include errors as well as any exceptions that might happen |
||
115 | try { |
||
116 | View Code Duplication | if (!@self::includeCode("$upgrade_path/$upgrade")) { |
|
117 | $success = false; |
||
118 | error_log("Could not include $upgrade_path/$upgrade"); |
||
119 | } |
||
120 | } catch (\Exception $e) { |
||
121 | $success = false; |
||
122 | error_log($e->getMessage()); |
||
123 | } |
||
124 | View Code Duplication | } else { |
|
125 | if (!self::includeCode("$upgrade_path/$upgrade")) { |
||
126 | $success = false; |
||
127 | error_log("Could not include $upgrade_path/$upgrade"); |
||
128 | } |
||
129 | } |
||
130 | |||
131 | if ($success) { |
||
132 | // don't set the version to a lower number in instances where an upgrade |
||
133 | // has been merged from a lower version of Elgg |
||
134 | if ($upgrade_version > $version) { |
||
135 | _elgg_services()->datalist->set('version', $upgrade_version); |
||
0 ignored issues
–
show
|
|||
136 | } |
||
137 | |||
138 | // incrementally set upgrade so we know where to start if something fails. |
||
139 | $this->setProcessedUpgrade($upgrade); |
||
140 | } else { |
||
141 | return false; |
||
142 | } |
||
143 | } |
||
144 | |||
145 | return true; |
||
146 | } |
||
147 | |||
148 | /** |
||
149 | * PHP include a file with a very limited scope |
||
150 | * |
||
151 | * @param string $file File path to include |
||
152 | * @return mixed |
||
153 | */ |
||
154 | protected static function includeCode($file) { |
||
155 | // do not remove - some upgrade scripts depend on this |
||
156 | global $CONFIG; |
||
157 | |||
158 | return include $file; |
||
159 | } |
||
160 | |||
161 | /** |
||
162 | * Saves a processed upgrade to a dataset. |
||
163 | * |
||
164 | * @param string $upgrade Filename of the processed upgrade |
||
165 | * (not the path, just the file) |
||
166 | * @return bool |
||
167 | */ |
||
168 | protected function setProcessedUpgrade($upgrade) { |
||
169 | $processed_upgrades = $this->getProcessedUpgrades(); |
||
170 | $processed_upgrades[] = $upgrade; |
||
171 | $processed_upgrades = array_unique($processed_upgrades); |
||
172 | return _elgg_services()->datalist->set('processed_upgrades', serialize($processed_upgrades)); |
||
173 | } |
||
174 | |||
175 | /** |
||
176 | * Gets a list of processes upgrades |
||
177 | * |
||
178 | * @return mixed Array of processed upgrade filenames or false |
||
179 | */ |
||
180 | protected function getProcessedUpgrades() { |
||
181 | $upgrades = _elgg_services()->datalist->get('processed_upgrades'); |
||
182 | $unserialized = unserialize($upgrades); |
||
183 | return $unserialized; |
||
184 | } |
||
185 | |||
186 | /** |
||
187 | * Returns the version of the upgrade filename. |
||
188 | * |
||
189 | * @param string $filename The upgrade filename. No full path. |
||
190 | * @return int|false |
||
191 | * @since 1.8.0 |
||
192 | */ |
||
193 | View Code Duplication | protected function getUpgradeFileVersion($filename) { |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
194 | preg_match('/^([0-9]{10})([\.a-z0-9-_]+)?\.(php)$/i', $filename, $matches); |
||
195 | |||
196 | if (isset($matches[1])) { |
||
197 | return (int) $matches[1]; |
||
198 | } |
||
199 | |||
200 | return false; |
||
201 | } |
||
202 | |||
203 | /** |
||
204 | * Returns a list of upgrade files relative to the $upgrade_path dir. |
||
205 | * |
||
206 | * @param string $upgrade_path The up |
||
207 | * @return array|false |
||
208 | */ |
||
209 | protected function getUpgradeFiles($upgrade_path = null) { |
||
210 | if (!$upgrade_path) { |
||
0 ignored issues
–
show
The expression
$upgrade_path of type string|null is loosely compared to false ; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
![]() |
|||
211 | $upgrade_path = _elgg_services()->config->get('path') . 'engine/lib/upgrades/'; |
||
212 | } |
||
213 | $upgrade_path = sanitise_filepath($upgrade_path); |
||
214 | $handle = opendir($upgrade_path); |
||
215 | |||
216 | if (!$handle) { |
||
217 | return false; |
||
218 | } |
||
219 | |||
220 | $upgrade_files = array(); |
||
221 | |||
222 | View Code Duplication | while ($upgrade_file = readdir($handle)) { |
|
223 | // make sure this is a wellformed upgrade. |
||
224 | if (is_dir($upgrade_path . '$upgrade_file')) { |
||
225 | continue; |
||
226 | } |
||
227 | $upgrade_version = $this->getUpgradeFileVersion($upgrade_file); |
||
228 | if (!$upgrade_version) { |
||
0 ignored issues
–
show
The expression
$upgrade_version of type integer|false is loosely compared to false ; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.
In PHP, under loose comparison (like For 0 == false // true
0 == null // true
123 == false // false
123 == null // false
// It is often better to use strict comparison
0 === false // false
0 === null // false
![]() |
|||
229 | continue; |
||
230 | } |
||
231 | $upgrade_files[] = $upgrade_file; |
||
232 | } |
||
233 | |||
234 | sort($upgrade_files); |
||
235 | |||
236 | return $upgrade_files; |
||
237 | } |
||
238 | |||
239 | /** |
||
240 | * Checks if any upgrades need to be run. |
||
241 | * |
||
242 | * @param null|array $upgrade_files Optional upgrade files |
||
243 | * @param null|array $processed_upgrades Optional processed upgrades |
||
244 | * |
||
245 | * @return array |
||
246 | */ |
||
247 | protected function getUnprocessedUpgrades($upgrade_files = null, $processed_upgrades = null) { |
||
248 | if ($upgrade_files === null) { |
||
249 | $upgrade_files = $this->getUpgradeFiles(); |
||
250 | } |
||
251 | |||
252 | if ($processed_upgrades === null) { |
||
253 | $processed_upgrades = unserialize(_elgg_services()->datalist->get('processed_upgrades')); |
||
254 | if (!is_array($processed_upgrades)) { |
||
255 | $processed_upgrades = array(); |
||
256 | } |
||
257 | } |
||
258 | |||
259 | $unprocessed = array_diff($upgrade_files, $processed_upgrades); |
||
260 | return $unprocessed; |
||
261 | } |
||
262 | |||
263 | /** |
||
264 | * Upgrades Elgg Database and code |
||
265 | * |
||
266 | * @return bool |
||
267 | */ |
||
268 | protected function processUpgrades() { |
||
269 | |||
270 | $dbversion = (int) _elgg_services()->datalist->get('version'); |
||
271 | |||
272 | // No version number? Oh snap...this is an upgrade from a clean installation < 1.7. |
||
273 | // Run all upgrades without error reporting and hope for the best. |
||
274 | // See https://github.com/elgg/elgg/issues/1432 for more. |
||
275 | $quiet = !$dbversion; |
||
276 | |||
277 | // Note: Database upgrades are deprecated as of 1.8. Use code upgrades. See #1433 |
||
278 | if ($this->dbUpgrade($dbversion, '', $quiet)) { |
||
0 ignored issues
–
show
The method
Elgg\UpgradeService::dbUpgrade() has been deprecated with message: 1.8 Use PHP upgrades for sql changes.
This method has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead. ![]() |
|||
279 | system_message(_elgg_services()->translator->translate('upgrade:db')); |
||
280 | } |
||
281 | |||
282 | if ($this->upgradeCode($dbversion, $quiet)) { |
||
283 | system_message(_elgg_services()->translator->translate('upgrade:core')); |
||
284 | |||
285 | // Now we trigger an event to give the option for plugins to do something |
||
286 | $upgrade_details = new \stdClass; |
||
287 | $upgrade_details->from = $dbversion; |
||
288 | $upgrade_details->to = elgg_get_version(); |
||
289 | |||
290 | _elgg_services()->events->trigger('upgrade', 'upgrade', $upgrade_details); |
||
291 | |||
292 | return true; |
||
293 | } |
||
294 | |||
295 | return false; |
||
296 | } |
||
297 | |||
298 | /** |
||
299 | * Boot straps into 1.8 upgrade system from 1.7 |
||
300 | * |
||
301 | * This runs all the 1.7 upgrades, then sets the processed_upgrades to all existing 1.7 upgrades. |
||
302 | * Control is then passed back to the main upgrade function which detects and runs the |
||
303 | * 1.8 upgrades, regardless of filename convention. |
||
304 | * |
||
305 | * @return bool |
||
306 | */ |
||
307 | protected function bootstrap17to18() { |
||
308 | $db_version = (int) _elgg_services()->datalist->get('version'); |
||
309 | |||
310 | // the 1.8 upgrades before the upgrade system change that are interspersed with 1.7 upgrades. |
||
311 | $upgrades_18 = array( |
||
312 | '2010111501.php', |
||
313 | '2010121601.php', |
||
314 | '2010121602.php', |
||
315 | '2010121701.php', |
||
316 | '2010123101.php', |
||
317 | '2011010101.php', |
||
318 | ); |
||
319 | |||
320 | $upgrade_files = $this->getUpgradeFiles(); |
||
321 | $processed_upgrades = array(); |
||
322 | |||
323 | foreach ($upgrade_files as $upgrade_file) { |
||
324 | // ignore if not in 1.7 format or if it's a 1.8 upgrade |
||
325 | if (in_array($upgrade_file, $upgrades_18) || !preg_match("/[0-9]{10}\.php/", $upgrade_file)) { |
||
326 | continue; |
||
327 | } |
||
328 | |||
329 | $upgrade_version = $this->getUpgradeFileVersion($upgrade_file); |
||
330 | |||
331 | // this has already been run in a previous 1.7.X -> 1.7.X upgrade |
||
332 | if ($upgrade_version < $db_version) { |
||
333 | $this->setProcessedUpgrade($upgrade_file); |
||
334 | } |
||
335 | } |
||
336 | } |
||
337 | |||
338 | /** |
||
339 | * Creates a table {prefix}upgrade_lock that is used as a mutex for upgrades. |
||
340 | * |
||
341 | * @return bool |
||
342 | */ |
||
343 | protected function getUpgradeMutex() { |
||
344 | |||
345 | |||
346 | if (!$this->isUpgradeLocked()) { |
||
347 | // lock it |
||
348 | _elgg_services()->db->insertData("create table {$this->CONFIG->dbprefix}upgrade_lock (id INT)"); |
||
349 | _elgg_services()->logger->notice('Locked for upgrade.'); |
||
350 | return true; |
||
351 | } |
||
352 | |||
353 | _elgg_services()->logger->warn('Cannot lock for upgrade: already locked'); |
||
354 | return false; |
||
355 | } |
||
356 | |||
357 | /** |
||
358 | * Unlocks upgrade. |
||
359 | * |
||
360 | * @return void |
||
361 | */ |
||
362 | public function releaseUpgradeMutex() { |
||
363 | |||
364 | _elgg_services()->db->deleteData("drop table {$this->CONFIG->dbprefix}upgrade_lock"); |
||
365 | _elgg_services()->logger->notice('Upgrade unlocked.'); |
||
366 | } |
||
367 | |||
368 | /** |
||
369 | * Checks if upgrade is locked |
||
370 | * |
||
371 | * @return bool |
||
372 | */ |
||
373 | public function isUpgradeLocked() { |
||
374 | |||
375 | |||
376 | $is_locked = count(_elgg_services()->db->getData("SHOW TABLES LIKE '{$this->CONFIG->dbprefix}upgrade_lock'")); |
||
377 | |||
378 | return (bool)$is_locked; |
||
379 | } |
||
380 | |||
381 | /** |
||
382 | * *************************************************************************** |
||
383 | * NOTE: If this is ever removed from Elgg, sites lose the ability to upgrade |
||
384 | * from 1.7.x and earlier to the latest version of Elgg without upgrading to |
||
385 | * 1.8 first. |
||
386 | * *************************************************************************** |
||
387 | * |
||
388 | * Upgrade the database schema in an ordered sequence. |
||
389 | * |
||
390 | * Executes all upgrade files in elgg/engine/schema/upgrades/ in sequential order. |
||
391 | * Upgrade files must be in the standard Elgg release format of YYYYMMDDII.sql |
||
392 | * where II is an incrementor starting from 01. |
||
393 | * |
||
394 | * Files that are < $version will be ignored. |
||
395 | * |
||
396 | * @param int $version The version you are upgrading from in the format YYYYMMDDII. |
||
397 | * @param string $fromdir Optional directory to load upgrades from. default: engine/schema/upgrades/ |
||
398 | * @param bool $quiet If true, suppress all error messages. Only use for the upgrade from <=1.6. |
||
399 | * |
||
400 | * @return int The number of upgrades run. |
||
401 | * @deprecated 1.8 Use PHP upgrades for sql changes. |
||
402 | */ |
||
403 | protected function dbUpgrade($version, $fromdir = "", $quiet = false) { |
||
404 | |||
405 | |||
406 | $version = (int) $version; |
||
407 | |||
408 | if (!$fromdir) { |
||
409 | $fromdir = $this->CONFIG->path . 'engine/schema/upgrades/'; |
||
410 | } |
||
411 | |||
412 | $i = 0; |
||
413 | |||
414 | if ($handle = opendir($fromdir)) { |
||
415 | $sqlupgrades = array(); |
||
416 | |||
417 | while ($sqlfile = readdir($handle)) { |
||
418 | if (!is_dir($fromdir . $sqlfile)) { |
||
419 | if (preg_match('/^([0-9]{10})\.(sql)$/', $sqlfile, $matches)) { |
||
420 | $sql_version = (int) $matches[1]; |
||
421 | if ($sql_version > $version) { |
||
422 | $sqlupgrades[] = $sqlfile; |
||
423 | } |
||
424 | } |
||
425 | } |
||
426 | } |
||
427 | |||
428 | asort($sqlupgrades); |
||
429 | |||
430 | if (sizeof($sqlupgrades) > 0) { |
||
431 | foreach ($sqlupgrades as $sqlfile) { |
||
432 | |||
433 | // hide all errors. |
||
434 | if ($quiet) { |
||
435 | try { |
||
436 | _elgg_services()->db->runSqlScript($fromdir . $sqlfile); |
||
437 | } catch (\DatabaseException $e) { |
||
438 | error_log($e->getmessage()); |
||
439 | } |
||
440 | } else { |
||
441 | _elgg_services()->db->runSqlScript($fromdir . $sqlfile); |
||
442 | } |
||
443 | $i++; |
||
444 | } |
||
445 | } |
||
446 | } |
||
447 | |||
448 | return $i; |
||
449 | } |
||
450 | |||
451 | } |
||
452 | |||
453 |
It seems like the type of the argument is not accepted by the function/method which you are calling.
In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.
We suggest to add an explicit type cast like in the following example: