PluginProbe
User Access Manager / 2.1.5
User Access Manager v2.1.5
2.3.20 2.3.19 2.3.18 2.3.17 2.3.16 2.3.15 2.3.14 2.3.13 trunk 0.6 0.6.1 0.6.2 0.7 0.7 Beta 0.7.0.1 0.8 0.8.0.1 0.8.0.2 0.9 0.9.1 0.9.1.1 0.9.1.2 0.9.1.3 0.9.1.4 1.0 All 136 releases
user-access-manager / src / Setup / Database / DatabaseHandler.php

DatabaseHandler.php in User Access Manager 2.1.5, at src/Setup/Database/DatabaseHandler.php

507 lines 14.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * DatabaseHandler.php
4 *
5 * The DatabaseHandler class file.
6 *
7 * PHP versions 5
8 *
9 * @author Alexander Schneider <alexanderschneider85@gmail.com>
10 * @copyright 2008-2017 Alexander Schneider
11 * @license http://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2
12 * @version SVN: $id$
13 * @link http://wordpress.org/extend/plugins/user-access-manager/
14 */
15 namespace UserAccessManager\Setup\Database;
16
17 use UserAccessManager\Database\Database;
18 use UserAccessManager\Setup\Update\UpdateFactory;
19 use UserAccessManager\Setup\Update\UpdateInterface;
20 use UserAccessManager\UserAccessManager;
21 use UserAccessManager\Wrapper\Wordpress;
22
23 /**
24 * Class DatabaseHandler
25 *
26 * @package UserAccessManager\Setup\Database
27 */
28 class DatabaseHandler
29 {
30 const MISSING_TABLES = 'MISSING_TABLE';
31 const MISSING_COLUMNS = 'MISSING_COLUMNS';
32 const MODIFIED_COLUMNS = 'MODIFIED_COLUMNS';
33 const EXTRA_COLUMNS = 'EXTRA_COLUMNS';
34
35 /**
36 * @var Wordpress
37 */
38 private $wordpress;
39
40 /**
41 * @var Database
42 */
43 private $database;
44
45 /**
46 * @var DatabaseObjectFactory
47 */
48 private $databaseObjectFactory;
49
50 /**
51 * @var UpdateFactory
52 */
53 private $updateFactory;
54
55 /**
56 * DatabaseHandler constructor.
57 *
58 * @param Wordpress $wordpress
59 * @param Database $database
60 * @param DatabaseObjectFactory $databaseObjectFactory
61 * @param UpdateFactory $updateFactory
62 */
63 public function __construct(
64 Wordpress $wordpress,
65 Database $database,
66 DatabaseObjectFactory $databaseObjectFactory,
67 UpdateFactory $updateFactory
68 ) {
69 $this->wordpress = $wordpress;
70 $this->database = $database;
71 $this->databaseObjectFactory = $databaseObjectFactory;
72 $this->updateFactory = $updateFactory;
73 }
74
75 /**
76 * Checks if the table exists.
77 *
78 * @param string $table
79 *
80 * @return bool
81 */
82 private function tableExists($table)
83 {
84 $dbTable = $this->database->getVariable("SHOW TABLES LIKE '{$table}'");
85
86 return ($table === $dbTable);
87 }
88
89 /**
90 * Adds a table.
91 *
92 * @param Table $table
93 */
94 private function addTable(Table $table)
95 {
96 $this->database->dbDelta((string)$table);
97 }
98
99 /**
100 * Returns all tables.
101 *
102 * @return Table[]
103 */
104 private function getTables()
105 {
106 $charsetCollate = $this->database->getCharset();
107 $tables = [];
108
109 $tables[] = $this->databaseObjectFactory->createTable(
110 $this->database->getUserGroupTable(),
111 $charsetCollate,
112 [
113 $this->databaseObjectFactory->createColumn('ID', 'INT(11)', false, null, true, true),
114 $this->databaseObjectFactory->createColumn('groupname', 'TINYTEXT'),
115 $this->databaseObjectFactory->createColumn('groupdesc', 'TEXT'),
116 $this->databaseObjectFactory->createColumn('read_access', 'TINYTEXT'),
117 $this->databaseObjectFactory->createColumn('write_access', 'TINYTEXT'),
118 $this->databaseObjectFactory->createColumn('ip_range', 'MEDIUMTEXT', true)
119 ]
120 );
121
122 $tables[] = $this->databaseObjectFactory->createTable(
123 $this->database->getUserGroupToObjectTable(),
124 $charsetCollate,
125 [
126 $this->databaseObjectFactory->createColumn('object_id', 'VARCHAR(32)', false, null, true),
127 $this->databaseObjectFactory->createColumn('general_object_type', 'VARCHAR(64)'),
128 $this->databaseObjectFactory->createColumn('object_type', 'VARCHAR(32)', false, null, true),
129 $this->databaseObjectFactory->createColumn('group_id', 'VARCHAR(32)', false, null, true),
130 $this->databaseObjectFactory->createColumn('group_type', 'VARCHAR(32)', false, null, true),
131 $this->databaseObjectFactory->createColumn('from_date', 'DATETIME', true),
132 $this->databaseObjectFactory->createColumn('to_date', 'DATETIME', true)
133 ]
134 );
135
136 return $tables;
137 }
138
139 /**
140 * Adds the tables to the database.
141 */
142 public function install()
143 {
144 foreach ($this->getTables() as $table) {
145 if ($this->tableExists($table->getName()) === false) {
146 $this->addTable($table);
147 }
148 }
149
150 $this->wordpress->addOption('uam_db_version', UserAccessManager::DB_VERSION);
151 }
152
153 /**
154 * Returns the existing columns for a table.
155 *
156 * @param Table $table
157 *
158 * @return Column[]
159 */
160 private function getExistingColumns(Table $table)
161 {
162 $query = "SHOW COLUMNS FROM `{$table->getName()}`;";
163 $existingRawColumns = $this->database->getResults($query);
164 $existingColumns = [];
165
166 foreach ($existingRawColumns as $existingRawColumn) {
167 $existingColumns[$existingRawColumn->Field] = $this->databaseObjectFactory->createColumn(
168 $existingRawColumn->Field,
169 strtoupper($existingRawColumn->Type),
170 $existingRawColumn->Null === 'YES',
171 $existingRawColumn->Default,
172 $existingRawColumn->Key === 'PRI',
173 $existingRawColumn->Extra === 'auto_increment'
174 );
175 }
176
177 return $existingColumns;
178 }
179
180 /**
181 * @return array
182 */
183 public function getCorruptedDatabaseInformation()
184 {
185 $information = [
186 self::MISSING_TABLES => [],
187 self::MISSING_COLUMNS => [],
188 self::MODIFIED_COLUMNS => [],
189 self::EXTRA_COLUMNS => []
190 ];
191
192 foreach ($this->getTables() as $table) {
193 if ($this->tableExists($table->getName()) === false) {
194 $information[self::MISSING_TABLES][] = $table;
195 continue;
196 }
197
198 $existingColumns = $this->getExistingColumns($table);
199
200 foreach ($table->getColumns() as $column) {
201 if (isset($existingColumns[$column->getName()]) === false) {
202 $information[self::MISSING_COLUMNS][] = [$table, $column];
203 continue;
204 }
205
206 $existingColumn = $existingColumns[$column->getName()];
207 unset($existingColumns[$column->getName()]);
208
209 if ((string)$column !== (string)$existingColumn) {
210 $information[self::MODIFIED_COLUMNS][] = [$table, $column];
211 continue;
212 }
213 }
214
215 foreach ($existingColumns as $existingColumn) {
216 $information[self::EXTRA_COLUMNS][] = [$table, $existingColumn];
217 }
218 }
219
220 return $information;
221 }
222
223 /**
224 * Adds a new column.
225 *
226 * @param Table $table
227 * @param Column $column
228 *
229 * @return bool
230 */
231 private function addColumn(Table $table, Column $column)
232 {
233 return $this->database->query("ALTER TABLE `{$table->getName()}` ADD $column;") !== false;
234 }
235
236 /**
237 * Modify an existing column.
238 *
239 * @param Table $table
240 * @param Column $column
241 *
242 * @return bool
243 */
244 private function modifyColumn(Table $table, Column $column)
245 {
246 return $this->database->query("ALTER TABLE `{$table->getName()}` MODIFY $column;") !== false;
247 }
248
249 /**
250 * Drops an existing column.
251 *
252 * @param Table $table
253 * @param Column $column
254 *
255 * @return bool
256 */
257 private function dropColumn(Table $table, Column $column)
258 {
259 return $this->database->query("ALTER TABLE `{$table->getName()}` DROP `{$column->getName()}`;") !== false;
260 }
261
262 /**
263 * Repairs a corrupt database.
264 *
265 * @param array $information
266 *
267 * @return bool
268 */
269 public function repairDatabase(array $information = [])
270 {
271 $success = true;
272 $information = ($information === []) ? $this->getCorruptedDatabaseInformation() : $information;
273
274 foreach ($information[self::MISSING_TABLES] as $table) {
275 $this->addTable($table);
276 }
277
278 foreach ($information[self::MISSING_COLUMNS] as $columnInformation) {
279 $success = $success && $this->addColumn($columnInformation[0], $columnInformation[1]);
280 }
281
282 foreach ($information[self::MODIFIED_COLUMNS] as $columnInformation) {
283 $success = $success && $this->modifyColumn($columnInformation[0], $columnInformation[1]);
284 }
285
286 foreach ($information[self::EXTRA_COLUMNS] as $columnInformation) {
287 $success = $success && $this->dropColumn($columnInformation[0], $columnInformation[1]);
288 }
289
290 return $success;
291 }
292
293 /**
294 * Checks if a database update is necessary.
295 *
296 * @return bool
297 */
298 public function isDatabaseUpdateNecessary()
299 {
300 if ($this->wordpress->isSuperAdmin() === true) {
301 foreach ($this->wordpress->getSites() as $site) {
302 $table = $this->database->getBlogPrefix($site->blog_id).'options';
303 $select = "SELECT option_value FROM {$table} WHERE option_name = '%s' LIMIT 1";
304 $select = $this->database->prepare($select, 'uam_db_version');
305 $currentDbVersion = $this->database->getVariable($select);
306
307 if ($currentDbVersion !== null
308 && version_compare($currentDbVersion, UserAccessManager::DB_VERSION, '<') === true
309 ) {
310 return true;
311 }
312 }
313 }
314
315 $currentDbVersion = $this->wordpress->getOption('uam_db_version');
316 return version_compare($currentDbVersion, UserAccessManager::DB_VERSION, '<');
317 }
318
319 /**
320 * Creates a database backup.
321 *
322 * @return bool
323 */
324 public function backupDatabase()
325 {
326 $currentDbVersion = $this->wordpress->getOption('uam_db_version');
327
328 if (empty($currentDbVersion) === true
329 || version_compare($currentDbVersion, '1.2', '<') === true
330 ) {
331 return false;
332 }
333
334 $tables = [
335 $this->database->getUserGroupTable(),
336 $this->database->getUserGroupToObjectTable()
337 ];
338
339 $currentDbVersion = str_replace('.', '-', $currentDbVersion);
340 $success = true;
341
342 foreach ($tables as $table) {
343 $createQuery = "CREATE TABLE `{$table}_{$currentDbVersion}` LIKE `{$table}`";
344 $success = $success && ($this->database->query($createQuery) !== false);
345 $insertQuery = "INSERT `{$table}_{$currentDbVersion}` SELECT * FROM `{$table}`";
346 $success = $success && ($this->database->query($insertQuery) !== false);
347 }
348
349 return $success;
350 }
351
352 /**
353 * Returns the version for which a backup was created.
354 *
355 * @return array
356 */
357 public function getBackups()
358 {
359 $versions = [];
360 $tables = (array)$this->database->getColumn(
361 "SHOW TABLES LIKE '{$this->database->getPrefix()}uam_%'"
362 );
363
364 foreach ($tables as $table) {
365 if (preg_match('/.*\_([0-9\-]+)/i', $table, $matches) === 1) {
366 $version = str_replace('-', '.', $matches[1]);
367 $versions[$version] = $version;
368 }
369 }
370
371 return $versions;
372 }
373
374 /**
375 * Returns the backup tables for the given version.
376 *
377 * @param string $version
378 *
379 * @return array
380 */
381 private function getBackupTables($version)
382 {
383 $backupTables = [];
384 $tables = [
385 $this->database->getUserGroupTable(),
386 $this->database->getUserGroupToObjectTable()
387 ];
388
389 $versionForDb = str_replace('.', '-', $version);
390
391 foreach ($tables as $table) {
392 $backupTable = (string)$this->database->getVariable(
393 "SHOW TABLES LIKE '{$table}_{$versionForDb}'"
394 );
395
396 if ($backupTable !== '') {
397 $backupTables[$table] = $backupTable;
398 }
399 }
400
401 return $backupTables;
402 }
403
404 /**
405 * Reverts the database to the given version.
406 *
407 * @param string $version
408 *
409 * @return bool
410 */
411 public function revertDatabase($version)
412 {
413 $success = true;
414 $tables = $this->getBackupTables($version);
415
416 foreach ($tables as $table => $backupTable) {
417 $dropQuery = "DROP TABLE IF EXISTS `{$table}`";
418 $success = $success && ($this->database->query($dropQuery) !== false);
419 $renameQuery = "RENAME TABLE `{$backupTable}` TO `{$table}`";
420 $success = $success && ($this->database->query($renameQuery) !== false);
421 }
422
423 if ($success === true) {
424 $this->wordpress->updateOption('uam_db_version', $version);
425 }
426
427 return $success;
428 }
429
430 /**
431 * Deletes the given database backup.
432 *
433 * @param string $version
434 *
435 * @return bool
436 */
437 public function deleteBackup($version)
438 {
439 $success = true;
440 $tables = $this->getBackupTables($version);
441
442 foreach ($tables as $table => $backupTable) {
443 $dropQuery = "DROP TABLE IF EXISTS `{$backupTable}`";
444 $success = $success && ($this->database->query($dropQuery) !== false);
445 }
446
447 return $success;
448 }
449
450 /**
451 * Returns the ordered updates.
452 *
453 * @return UpdateInterface[]
454 */
455 private function getOrderedDatabaseUpdates()
456 {
457 $rawUpdates = $this->updateFactory->getDatabaseUpdates();
458 $updates = [];
459
460 foreach ($rawUpdates as $rawUpdate) {
461 $updates[$rawUpdate->getVersion()] = $rawUpdate;
462 }
463
464 uksort($updates, 'version_compare');
465 return $updates;
466 }
467
468 /**
469 * Updates the database.
470 *
471 * @return bool
472 */
473 public function updateDatabase()
474 {
475 $currentDbVersion = $this->wordpress->getOption('uam_db_version');
476
477 if (empty($currentDbVersion) === true) {
478 return false;
479 }
480
481 $success = true;
482
483 foreach ($this->getOrderedDatabaseUpdates() as $orderedUpdate) {
484 if (version_compare($currentDbVersion, $orderedUpdate->getVersion(), '<') === true) {
485 $success = $success && $orderedUpdate->update();
486 }
487 }
488
489 if ($success === true) {
490 $this->wordpress->updateOption('uam_db_version', UserAccessManager::DB_VERSION);
491 }
492
493 return $success;
494 }
495
496 /**
497 * Removes the tables.
498 */
499 public function removeTables()
500 {
501 foreach ($this->getTables() as $table) {
502 $dropQuery = "DROP TABLE IF EXISTS `{$table->getName()}`";
503 $this->database->query($dropQuery);
504 }
505 }
506 }
507