PluginProbe
User Access Manager / 2.1.10
User Access Manager v2.1.10
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.10, at src/Setup/Database/DatabaseHandler.php

544 lines 15.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 = (array)$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 * Add corrupted columns to the information array if the are some.
182 *
183 * @param Table $table
184 * @param array $information
185 */
186 private function addCorruptedRows(Table $table, array &$information)
187 {
188 $existingColumns = $this->getExistingColumns($table);
189
190 foreach ($table->getColumns() as $column) {
191 if (isset($existingColumns[$column->getName()]) === false) {
192 $information[self::MISSING_COLUMNS][] = [$table, $column];
193 continue;
194 }
195
196 $existingColumn = $existingColumns[$column->getName()];
197 unset($existingColumns[$column->getName()]);
198
199 if ((string)$column !== (string)$existingColumn) {
200 $information[self::MODIFIED_COLUMNS][] = [$table, $column];
201 continue;
202 }
203 }
204
205 foreach ($existingColumns as $existingColumn) {
206 $information[self::EXTRA_COLUMNS][] = [$table, $existingColumn];
207 }
208 }
209
210 /**
211 * Returns corrupted database information.
212 *
213 * @return array
214 */
215 public function getCorruptedDatabaseInformation()
216 {
217 $information = [
218 self::MISSING_TABLES => [],
219 self::MISSING_COLUMNS => [],
220 self::MODIFIED_COLUMNS => [],
221 self::EXTRA_COLUMNS => []
222 ];
223
224 foreach ($this->getTables() as $table) {
225 if ($this->tableExists($table->getName()) === false) {
226 $information[self::MISSING_TABLES][] = $table;
227 continue;
228 }
229
230 $this->addCorruptedRows($table, $information);
231 }
232
233 return $information;
234 }
235
236 /**
237 * Adds a new column.
238 *
239 * @param Table $table
240 * @param Column $column
241 *
242 * @return bool
243 */
244 private function addColumn(Table $table, Column $column)
245 {
246 return $this->database->query("ALTER TABLE `{$table->getName()}` ADD $column;") !== false;
247 }
248
249 /**
250 * Modify an existing column.
251 *
252 * @param Table $table
253 * @param Column $column
254 *
255 * @return bool
256 */
257 private function modifyColumn(Table $table, Column $column)
258 {
259 return $this->database->query("ALTER TABLE `{$table->getName()}` MODIFY $column;") !== false;
260 }
261
262 /**
263 * Drops an existing column.
264 *
265 * @param Table $table
266 * @param Column $column
267 *
268 * @return bool
269 */
270 private function dropColumn(Table $table, Column $column)
271 {
272 return $this->database->query("ALTER TABLE `{$table->getName()}` DROP `{$column->getName()}`;") !== false;
273 }
274
275 /**
276 * Repairs a corrupt database.
277 *
278 * @param array $information
279 *
280 * @return bool
281 */
282 public function repairDatabase(array $information = [])
283 {
284 $success = true;
285 $information = ($information === []) ? $this->getCorruptedDatabaseInformation() : $information;
286
287 foreach ($information[self::MISSING_TABLES] as $table) {
288 $this->addTable($table);
289 }
290
291 foreach ($information[self::MISSING_COLUMNS] as $columnInformation) {
292 $success = $success && $this->addColumn($columnInformation[0], $columnInformation[1]);
293 }
294
295 foreach ($information[self::MODIFIED_COLUMNS] as $columnInformation) {
296 $success = $success && $this->modifyColumn($columnInformation[0], $columnInformation[1]);
297 }
298
299 foreach ($information[self::EXTRA_COLUMNS] as $columnInformation) {
300 $success = $success && $this->dropColumn($columnInformation[0], $columnInformation[1]);
301 }
302
303 return $success;
304 }
305
306 /**
307 * Returns all sites where the user access manager is active.
308 *
309 * @return array
310 */
311 private function getActivePluginSites()
312 {
313 $activeSites = [];
314
315 foreach ($this->wordpress->getSites() as $site) {
316 $this->wordpress->switchToBlog($site->blog_id);
317 $plugins = (array)$this->wordpress->getOption('active_plugins', []);
318 $pluginsMap = array_flip($plugins);
319
320 if (isset($pluginsMap['user-access-manager/user-access-manager.php']) === true) {
321 $activeSites[$site->blog_id] = $site->blog_id;
322 }
323
324 $this->wordpress->restoreCurrentBlog();
325 }
326
327 return $activeSites;
328 }
329
330 /**
331 * Checks if a database update is necessary.
332 *
333 * @return bool
334 */
335 public function isDatabaseUpdateNecessary()
336 {
337 if ($this->wordpress->isSuperAdmin() === true) {
338 foreach ($this->getActivePluginSites() as $siteId) {
339 $table = $this->database->getBlogPrefix($siteId).'options';
340 $select = "SELECT option_value FROM {$table} WHERE option_name = '%s' LIMIT 1";
341 $select = $this->database->prepare($select, 'uam_db_version');
342 $currentDbVersion = $this->database->getVariable($select);
343
344 if ($currentDbVersion !== null
345 && version_compare($currentDbVersion, UserAccessManager::DB_VERSION, '<') === true
346 ) {
347 return true;
348 }
349 }
350 }
351
352 $currentDbVersion = $this->wordpress->getOption('uam_db_version');
353 return version_compare($currentDbVersion, UserAccessManager::DB_VERSION, '<');
354 }
355
356 /**
357 * Creates a database backup.
358 *
359 * @return bool
360 */
361 public function backupDatabase()
362 {
363 $currentDbVersion = $this->wordpress->getOption('uam_db_version');
364
365 if (empty($currentDbVersion) === true
366 || version_compare($currentDbVersion, '1.2', '<') === true
367 ) {
368 return false;
369 }
370
371 $tables = [
372 $this->database->getUserGroupTable(),
373 $this->database->getUserGroupToObjectTable()
374 ];
375
376 $currentDbVersion = str_replace('.', '-', $currentDbVersion);
377 $success = true;
378
379 foreach ($tables as $table) {
380 $createQuery = "CREATE TABLE `{$table}_{$currentDbVersion}` LIKE `{$table}`";
381 $success = $success && ($this->database->query($createQuery) !== false);
382 $insertQuery = "INSERT `{$table}_{$currentDbVersion}` SELECT * FROM `{$table}`";
383 $success = $success && ($this->database->query($insertQuery) !== false);
384 }
385
386 return $success;
387 }
388
389 /**
390 * Returns the version for which a backup was created.
391 *
392 * @return array
393 */
394 public function getBackups()
395 {
396 $versions = [];
397 $tables = (array)$this->database->getColumn(
398 "SHOW TABLES LIKE '{$this->database->getPrefix()}uam_%'"
399 );
400
401 foreach ($tables as $table) {
402 if (preg_match('/.*\_([0-9\-]+)/i', $table, $matches) === 1) {
403 $version = str_replace('-', '.', $matches[1]);
404 $versions[$version] = $version;
405 }
406 }
407
408 return $versions;
409 }
410
411 /**
412 * Returns the backup tables for the given version.
413 *
414 * @param string $version
415 *
416 * @return array
417 */
418 private function getBackupTables($version)
419 {
420 $backupTables = [];
421 $tables = [
422 $this->database->getUserGroupTable(),
423 $this->database->getUserGroupToObjectTable()
424 ];
425
426 $versionForDb = str_replace('.', '-', $version);
427
428 foreach ($tables as $table) {
429 $backupTable = (string)$this->database->getVariable(
430 "SHOW TABLES LIKE '{$table}_{$versionForDb}'"
431 );
432
433 if ($backupTable !== '') {
434 $backupTables[$table] = $backupTable;
435 }
436 }
437
438 return $backupTables;
439 }
440
441 /**
442 * Reverts the database to the given version.
443 *
444 * @param string $version
445 *
446 * @return bool
447 */
448 public function revertDatabase($version)
449 {
450 $success = true;
451 $tables = $this->getBackupTables($version);
452
453 foreach ($tables as $table => $backupTable) {
454 $dropQuery = "DROP TABLE IF EXISTS `{$table}`";
455 $success = $success && ($this->database->query($dropQuery) !== false);
456 $renameQuery = "RENAME TABLE `{$backupTable}` TO `{$table}`";
457 $success = $success && ($this->database->query($renameQuery) !== false);
458 }
459
460 if ($success === true) {
461 $this->wordpress->updateOption('uam_db_version', $version);
462 }
463
464 return $success;
465 }
466
467 /**
468 * Deletes the given database backup.
469 *
470 * @param string $version
471 *
472 * @return bool
473 */
474 public function deleteBackup($version)
475 {
476 $success = true;
477 $tables = $this->getBackupTables($version);
478
479 foreach ($tables as $table => $backupTable) {
480 $dropQuery = "DROP TABLE IF EXISTS `{$backupTable}`";
481 $success = $success && ($this->database->query($dropQuery) !== false);
482 }
483
484 return $success;
485 }
486
487 /**
488 * Returns the ordered updates.
489 *
490 * @return UpdateInterface[]
491 */
492 private function getOrderedDatabaseUpdates()
493 {
494 $rawUpdates = $this->updateFactory->getDatabaseUpdates();
495 $updates = [];
496
497 foreach ($rawUpdates as $rawUpdate) {
498 $updates[$rawUpdate->getVersion()] = $rawUpdate;
499 }
500
501 uksort($updates, 'version_compare');
502 return $updates;
503 }
504
505 /**
506 * Updates the database.
507 *
508 * @return bool
509 */
510 public function updateDatabase()
511 {
512 $currentDbVersion = $this->wordpress->getOption('uam_db_version');
513
514 if (empty($currentDbVersion) === true) {
515 return false;
516 }
517
518 $success = true;
519
520 foreach ($this->getOrderedDatabaseUpdates() as $orderedUpdate) {
521 if (version_compare($currentDbVersion, $orderedUpdate->getVersion(), '<') === true) {
522 $success = $success && $orderedUpdate->update();
523 }
524 }
525
526 if ($success === true) {
527 $this->wordpress->updateOption('uam_db_version', UserAccessManager::DB_VERSION);
528 }
529
530 return $success;
531 }
532
533 /**
534 * Removes the tables.
535 */
536 public function removeTables()
537 {
538 foreach ($this->getTables() as $table) {
539 $dropQuery = "DROP TABLE IF EXISTS `{$table->getName()}`";
540 $this->database->query($dropQuery);
541 }
542 }
543 }
544