Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

Passed
Pull Request — master (#915)
by
unknown
04:21
created

MySqlDatabase::switchDatabaseToLive()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 2
rs 10
1
<?php declare(strict_types=1);
2
3
abstract class MySqlDatabase {
4
	protected static $dbConn;
5
	protected static $selectedDbName;
6
	private static MySqlProperties $mysqlProperties;
7
	protected $dbResult = null;
8
	protected $dbRecord = null;
9
10
	public function __construct() {
11
		if (!self::$dbConn) {
12
			// Set the mysqli driver to raise exceptions on errors
13
			if (!mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT)) {
14
				$this->error('Failed to enable mysqli error reporting');
15
			}
16
			$mysqlProperties = new MySqlProperties();
17
			self::$dbConn = new mysqli(
18
				$mysqlProperties->getHost(),
19
				$mysqlProperties->getUser(),
20
				$mysqlProperties->getPassword(),
21
				$mysqlProperties->getDatabaseName(),
22
				$mysqlProperties->getPort());
23
			self::$mysqlProperties = $mysqlProperties;
24
			self::$selectedDbName = $mysqlProperties->getDatabaseName();
25
			// Default server charset should be set correctly. Using the default
26
			// avoids the additional query involved in `set_charset`.
27
			$charset = self::$dbConn->character_set_name();
28
			if ($charset != 'utf8') {
29
				$this->error('Unexpected charset: ' . $charset);
30
			}
31
		}
32
	}
33
34
	/**
35
	 * This method will switch the connection to the specified database.
36
	 * Useful for switching back and forth between historical, and live databases.
37
	 *
38
	 * @param string $databaseName The name of the database to switch to
39
	 */
40
	public function switchDatabases(string $databaseName) {
41
		self::$dbConn->select_db($databaseName);
42
		self::$selectedDbName = $databaseName;
43
	}
44
45
	/**
46
	 * Switch back to the configured live database
47
	 */
48
	public function switchDatabaseToLive() {
49
		$this->switchDatabases(self::$mysqlProperties->getDatabaseName());
50
	}
51
52
	/**
53
	 * Returns the size of the selected database in bytes.
54
	 */
55
	public function getDbBytes() {
56
		$query = 'SELECT SUM(data_length + index_length) as db_bytes FROM information_schema.tables WHERE table_schema=' . $this->escapeString(self::$selectedDbName);
57
		$result = self::$dbConn->query($query);
58
		return (int)$result->fetch_assoc()['db_bytes'];
59
	}
60
61
	// This should not be needed except perhaps by persistent connections
62
	public function close() {
63
		if (self::$dbConn) {
64
			self::$dbConn->close();
65
			self::$dbConn = false;
66
		}
67
	}
68
69
	public function query($query) {
70
		$this->dbResult = self::$dbConn->query($query);
71
	}
72
73
	/**
74
	 * Use to populate this instance with the next record of the active query.
75
	 */
76
	public function nextRecord() : bool {
77
		if (!$this->dbResult) {
78
			$this->error('No resource to get record from.');
79
		}
80
81
		if ($this->dbRecord = $this->dbResult->fetch_assoc()) {
82
			return true;
83
		}
84
		return false;
85
	}
86
87
	/**
88
	 * Use instead of nextRecord when exactly one record is expected from the
89
	 * active query.
90
	 */
91
	public function requireRecord() : void {
92
		if (!$this->nextRecord() || $this->getNumRows() != 1) {
93
			$this->error('One record required, but found ' . $this->getNumRows());
94
		}
95
	}
96
97
	public function hasField($name) {
98
		return isset($this->dbRecord[$name]);
99
	}
100
101
	public function getField($name) {
102
		return $this->dbRecord[$name];
103
	}
104
105
	public function getBoolean($name) {
106
		if ($this->dbRecord[$name] == 'TRUE') {
107
			return true;
108
		}
109
//		if($this->dbRecord[$name] == 'FALSE')
110
		return false;
111
//		throw new Exception('Field is not a boolean');
112
	}
113
114
	public function getInt($name) {
115
		return (int)$this->dbRecord[$name];
116
	}
117
118
	public function getFloat($name) {
119
		return (float)$this->dbRecord[$name];
120
	}
121
122
	// WARNING: In the past, Microtime was stored in the database incorrectly.
123
	// For backwards compatibility, set $pad_msec=true to try to guess at the
124
	// intended value. This is not safe if the Microtime length is wrong for an
125
	// unrelated reason!
126
	public function getMicrotime($name, $pad_msec = false) {
127
		$data = $this->dbRecord[$name];
128
		$sec  = substr($data, 0, 10);
129
		$msec = substr($data, 10);
130
		if (strlen($msec) != 6) {
131
			if ($pad_msec) {
132
				$msec = str_pad($msec, 6, '0', STR_PAD_LEFT);
133
			} else {
134
				throw new Exception('Field is not an escaped microtime (' . $data . ')');
135
			}
136
		}
137
		return "$sec.$msec";
138
	}
139
140
	public function getObject($name, $compressed = false) {
141
		$object = $this->getField($name);
142
		if ($compressed === true) {
143
			$object = gzuncompress($object);
144
		}
145
		return unserialize($object);
146
	}
147
148
	public function getRow() {
149
		return $this->dbRecord;
150
	}
151
152
	public function lockTable($table) {
153
		self::$dbConn->query('LOCK TABLES ' . $table . ' WRITE');
154
	}
155
156
	public function unlock() {
157
		self::$dbConn->query('UNLOCK TABLES');
158
	}
159
160
	public function getNumRows() {
161
		return $this->dbResult->num_rows;
162
	}
163
164
	public function getChangedRows() {
165
		return self::$dbConn->affected_rows;
166
	}
167
168
	public function getInsertID() {
169
		return self::$dbConn->insert_id;
170
	}
171
172
	protected function error($err) {
173
		throw new Exception($err);
174
	}
175
176
	public function escape($escape, $autoQuotes = true, $quotes = true) {
177
		if (is_bool($escape)) {
178
			if ($autoQuotes) {
179
				return $this->escapeBoolean($escape);
180
			} else {
181
				return $this->escapeBoolean($escape, $quotes);
182
			}
183
		}
184
		if (is_numeric($escape)) {
185
			return $this->escapeNumber($escape);
186
		}
187
		if (is_string($escape)) {
188
			if ($autoQuotes) {
189
				return $this->escapeString($escape);
190
			} else {
191
				return $this->escapeString($escape, $quotes);
192
			}
193
		}
194
		if (is_array($escape)) {
195
			return $this->escapeArray($escape, $autoQuotes, $quotes);
196
		}
197
		if (is_object($escape)) {
198
			if ($autoQuotes) {
199
				return $this->escapeObject($escape);
200
			} else {
201
				return $this->escapeObject($escape, $quotes);
202
			}
203
		}
204
	}
205
206
	public function escapeString($string, $quotes = true, $nullable = false) {
207
		if ($nullable === true && ($string === null || $string === '')) {
208
			return 'NULL';
209
		}
210
		if ($string === true) {
211
			$string = 'TRUE';
212
		} elseif ($string === false) {
213
			$string = 'FALSE';
214
		}
215
		if (is_array($string)) {
216
			$escapedString = '';
217
			foreach ($string as $value) {
218
				$escapedString .= $this->escapeString($value, $quotes) . ',';
219
			}
220
			return substr($escapedString, 0, -1);
221
		}
222
		if ($quotes) {
223
			return '\'' . self::$dbConn->real_escape_string($string) . '\'';
224
		}
225
		return self::$dbConn->real_escape_string($string);
226
	}
227
228
	public function escapeBinary($binary) {
229
		return '0x' . bin2hex($binary);
230
	}
231
232
	public function escapeArray(array $array, $autoQuotes = true, $quotes = true, $implodeString = ',', $escapeIndividually = true) {
233
		$string = '';
234
		if ($escapeIndividually) {
235
			foreach ($array as $value) {
236
				if (is_array($value)) {
237
					$string .= $this->escapeArray($value, $autoQuotes, $quotes, $implodeString, $escapeIndividually) . $implodeString;
238
				} else {
239
					$string .= $this->escape($value, $autoQuotes, $quotes) . $implodeString;
240
				}
241
			}
242
			$string = substr($string, 0, -1);
243
		} else {
244
			$string = $this->escape(implode($implodeString, $array), $autoQuotes, $quotes);
245
		}
246
		return $string;
247
	}
248
249
	public function escapeNumber($num) {
250
		// Numbers need not be quoted in MySQL queries, so if we know $num is
251
		// numeric, we can simply return its value (no quoting or escaping).
252
		if (is_numeric($num)) {
253
			return $num;
254
		} else {
255
			throw new Exception('Not a number! (' . $num . ')');
256
		}
257
	}
258
259
	public function escapeMicrotime($microtime, $quotes = false) {
260
		$sec_str = sprintf('%010d', $microtime);
261
		$usec_str = sprintf('%06d', fmod($microtime, 1) * 1E6);
262
		return $this->escapeString($sec_str . $usec_str, $quotes);
263
	}
264
265
	public function escapeBoolean($bool, $quotes = true) {
266
		if ($bool === true) {
267
			return $this->escapeString('TRUE', $quotes);
268
		} elseif ($bool === false) {
269
			return $this->escapeString('FALSE', $quotes);
270
		} else {
271
			throw new Exception('Not a boolean: ' . $bool);
272
		}
273
	}
274
275
	public function escapeObject($object, $compress = false, $quotes = true, $nullable = false) {
276
		if ($compress === true) {
277
			return $this->escapeBinary(gzcompress(serialize($object)));
278
		}
279
		return $this->escapeString(serialize($object), $quotes, $nullable);
280
	}
281
282
}
283