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 (#924)
by
unknown
03:44
created

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