aboutsummaryrefslogtreecommitdiffstats
path: root/Zotlabs/Lib/DB_Upgrade.php
blob: e11c2eb10dfe73da6872d1efccc91e1c454e574d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
<?php
/**
 * A class to handle database schema upgrades.
 *
 * SPDX-FileCopyrightText: 2024 Hubzilla Community
 * SPDX-FileContributor: Harald Eilertsen
 *
 * SPDX-License-Identifier: MIT
 */

namespace Zotlabs\Lib;

use Zotlabs\Lib\Config;

/**
 * Upgrade the database schema if necessary.
 *
 * Compares the currently active database schema version with the version
 * required for this version of Hubzilla, and performs the upgrade if needed.
 *
 * If the difference consists of more than one revision of the schema, each of
 * the intermediate upgrades are performed in turn.
 */
class DB_Upgrade {

	/**
	 * Check the installed and required schema versions and perform the upgrade
	 * if necessary.
	 *
	 * @param int $db_version	The required DB schema version.
	 */
	public static function run(int $db_revision): void {

		$build = Config::Get('system', 'db_version', 0);
		if(! intval($build))
			$build = Config::Set('system', 'db_version', $db_revision);

		if($build == $db_revision) {
			// Nothing to be done.
			return;
		}
		else {
			$stored = intval($build);
			if(! $stored) {
				logger('Critical: check_config unable to determine database schema version');
				return;
			}

			$current = intval($db_revision);

			if($stored < $current) {

				// The last update we performed was $stored.
				// Start at $stored + 1 and continue until we have completed $current

				for($x = $stored + 1; $x <= $current; $x ++) {
					$s = '_' . $x;
					$cls = '\\Zotlabs\Update\\' . $s ;
					if(! class_exists($cls)) {
						return;
					}

					// There could be a lot of processes running or about to run.
					// We want exactly one process to run the update command.
					// So store the fact that we're taking responsibility
					// after first checking to see if somebody else already has.

					// If the update fails or times-out completely you may need to
					// delete the config entry to try again.

					Config::Load('database');

					if(Config::Get('database', $s))
						break;
					Config::Set('database',$s, '1');


					$c =  new $cls();

					$retval = $c->run();

					if($retval != UPDATE_SUCCESS) {


						$source = t('Source code of failed update: ') . "\n\n" . @file_get_contents('Zotlabs/Update/' . $s . '.php');


						// Prevent sending hundreds of thousands of emails by creating
						// a lockfile.

						$lockfile = 'store/[data]/mailsent';

						if ((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 86400)))
							return;
						@unlink($lockfile);
						//send the administrator an e-mail
						file_put_contents($lockfile, $x);

						$r = q("select account_language from account where account_email = '%s' limit 1",
							dbesc(\App::$config['system']['admin_email'])
						);
						push_lang(($r) ? $r[0]['account_language'] : 'en');
						z_mail(
							[
								'toEmail'        => \App::$config['system']['admin_email'],
								'messageSubject' => sprintf( t('Update Error at %s'), z_root()),
								'textVersion'    => replace_macros(get_intltext_template('update_fail_eml.tpl'),
									[
										'$sitename' => \App::$config['system']['sitename'],
										'$siteurl' =>  z_root(),
										'$update' => $x,
										'$error' => sprintf( t('Update %s failed. See error logs.'), $x),
										'$baseurl' => z_root(),
										'$source' => $source
									]
								)
							]
						);

						//try the logger
						logger('CRITICAL: Update Failed: ' . $x);
						pop_lang();
					}
					else {
						Config::Set('database',$s, 'success');
					}
				}
			}
			Config::Set('system', 'db_version', $db_revision);
		}
	}
}