PluginProbe
User Access Manager / 2.1.6
User Access Manager v2.1.6
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.6, at src/Setup/Database/DatabaseHandler.php

520 lines 14.8 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 * 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 * Checks if a database update is necessary.
308 *
309 * @return bool
310 */
311 public function isDatabaseUpdateNecessary()
312 {
313 if ($this->wordpress->isSuperAdmin() === true) {
314 foreach ($this->wordpress->getSites() as $site) {
315 $table = $this->database->getBlogPrefix($site->blog_id).'options';
316 $select = "SELECT option_value FROM {$table} WHERE option_name = '%s' LIMIT 1";
317 $select = $this->database->prepare($select, 'uam_db_version');
318 $currentDbVersion = $this->database->getVariable($select);
319
320 if ($currentDbVersion !== null
321 && version_compare($currentDbVersion, UserAccessManager::DB_VERSION, '<') === true
322 ) {
323 return true;
324 }
325 }
326 }
327
328 $currentDbVersion = $this->wordpress->getOption('uam_db_version');
329 return version_compare($currentDbVersion, UserAccessManager::DB_VERSION, '<');
330 }
331
332 /**
333 * Creates a database backup.
334 *
335 * @return bool
336 */
337 public function backupDatabase()
338 {
339 $currentDbVersion = $this->wordpress->getOption('uam_db_version');
340
341 if (empty($currentDbVersion) === true
342 || version_compare($currentDbVersion, '1.2', '<') === true
343 ) {
344 return false;
345 }
346
347 $tables = [
348 $this->database->getUserGroupTable(),
349 $this->database->getUserGroupToObjectTable()
350 ];
351
352 $currentDbVersion = str_replace('.', '-', $currentDbVersion);
353 $success = true;
354
355 foreach ($tables as $table) {
356 $createQuery = "CREATE TABLE `{$table}_{$currentDbVersion}` LIKE `{$table}`";
357 $success = $success && ($this->database->query($createQuery) !== false);
358 $insertQuery = "INSERT `{$table}_{$currentDbVersion}` SELECT * FROM `{$table}`";
359 $success = $success && ($this->database->query($insertQuery) !== false);
360 }
361
362 return $success;
363 }
364
365 /**
366 * Returns the version for which a backup was created.
367 *
368 * @return array
369 */
370 public function getBackups()
371 {
372 $versions = [];
373 $tables = (array)$this->database->getColumn(
374 "SHOW TABLES LIKE '{$this->database->getPrefix()}uam_%'"
375 );
376
377 foreach ($tables as $table) {
378 if (preg_match('/.*\_([0-9\-]+)/i', $table, $matches) === 1) {
379 $version = str_replace('-', '.', $matches[1]);
380 $versions[$version] = $version;
381 }
382 }
383
384 return $versions;
385 }
386
387 /**
388 * Returns the backup tables for the given version.
389 *
390 * @param string $version
391 *
392 * @return array
393 */
394 private function getBackupTables($version)
395 {
396 $backupTables = [];
397 $tables = [
398 $this->database->getUserGroupTable(),
399 $this->database->getUserGroupToObjectTable()
400 ];
401
402 $versionForDb = str_replace('.', '-', $version);
403
404 foreach ($tables as $table) {
405 $backupTable = (string)$this->database->getVariable(
406 "SHOW TABLES LIKE '{$table}_{$versionForDb}'"
407 );
408
409 if ($backupTable !== '') {
410 $backupTables[$table] = $backupTable;
411 }
412 }
413
414 return $backupTables;
415 }
416
417 /**
418 * Reverts the database to the given version.
419 *
420 * @param string $version
421 *
422 * @return bool
423 */
424 public function revertDatabase($version)
425 {
426 $success = true;
427 $tables = $this->getBackupTables($version);
428
429 foreach ($tables as $table => $backupTable) {
430 $dropQuery = "DROP TABLE IF EXISTS `{$table}`";
431 $success = $success && ($this->database->query($dropQuery) !== false);
432 $renameQuery = "RENAME TABLE `{$backupTable}` TO `{$table}`";
433 $success = $success && ($this->database->query($renameQuery) !== false);
434 }
435
436 if ($success === true) {
437 $this->wordpress->updateOption('uam_db_version', $version);
438 }
439
440 return $success;
441 }
442
443 /**
444 * Deletes the given database backup.
445 *
446 * @param string $version
447 *
448 * @return bool
449 */
450 public function deleteBackup($version)
451 {
452 $success = true;
453 $tables = $this->getBackupTables($version);
454
455 foreach ($tables as $table => $backupTable) {
456 $dropQuery = "DROP TABLE IF EXISTS `{$backupTable}`";
457 $success = $success && ($this->database->query($dropQuery) !== false);
458 }
459
460 return $success;
461 }
462
463 /**
464 * Returns the ordered updates.
465 *
466 * @return UpdateInterface[]
467 */
468 private function getOrderedDatabaseUpdates()
469 {
470 $rawUpdates = $this->updateFactory->getDatabaseUpdates();
471 $updates = [];
472
473 foreach ($rawUpdates as $rawUpdate) {
474 $updates[$rawUpdate->getVersion()] = $rawUpdate;
475 }
476
477 uksort($updates, 'version_compare');
478 return $updates;
479 }
480
481 /**
482 * Updates the database.
483 *
484 * @return bool
485 */
486 public function updateDatabase()
487 {
488 $currentDbVersion = $this->wordpress->getOption('uam_db_version');
489
490 if (empty($currentDbVersion) === true) {
491 return false;
492 }
493
494 $success = true;
495
496 foreach ($this->getOrderedDatabaseUpdates() as $orderedUpdate) {
497 if (version_compare($currentDbVersion, $orderedUpdate->getVersion(), '<') === true) {
498 $success = $success && $orderedUpdate->update();
499 }
500 }
501
502 if ($success === true) {
503 $this->wordpress->updateOption('uam_db_version', UserAccessManager::DB_VERSION);
504 }
505
506 return $success;
507 }
508
509 /**
510 * Removes the tables.
511 */
512 public function removeTables()
513 {
514 foreach ($this->getTables() as $table) {
515 $dropQuery = "DROP TABLE IF EXISTS `{$table->getName()}`";
516 $this->database->query($dropQuery);
517 }
518 }
519 }
520