PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 2.2.11
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v2.2.11
4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 3.8.0 All 110 releases
wp-optimize / includes / wp-optimize-database-information.php

wp-optimize-database-information.php in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 2.2.11, at includes/wp-optimize-database-information.php

554 lines 13.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('ABSPATH')) die('No direct access allowed');
4
5 class WP_Optimize_Database_Information {
6
7 const UNKNOWN_DB = 'unknown';
8 const MARIA_DB = 'MariaDB';
9 const PERCONA_DB = 'Percona';
10 // for some reason coding standard parser give error here WordPress.DB.RestrictedFunctions.mysql_mysql_db
11 // @codingStandardsIgnoreLine
12 const MYSQL_DB = 'MysqlDB';
13
14 const MYISAM_ENGINE = 'MyISAM';
15 const MEMORY_ENGINE = 'Memory';
16 const INNODB_ENGINE = 'InnoDB';
17 const ARCHIVE_ENGINE = 'ARCHIVE';
18 const CSV_ENGINE = 'CSV';
19 const NDB_ENGINE = 'NDB';
20 const ARIA_ENGINE = 'Aria'; // MariaDB
21 const VIEW = 'VIEW';
22
23 /**
24 * Returns server type MySQL or MariaDB if mysql database or Unknown if not mysql.
25 *
26 * @return string
27 */
28 public function get_server_type() {
29 global $wpdb;
30 static $server_type = null;
31
32 if (!$wpdb->is_mysql) return self::UNKNOWN_DB;
33
34 if (null !== $server_type) return $server_type;
35
36 $server_type = self::MYSQL_DB;
37
38 $variables = $wpdb->get_results('SHOW SESSION VARIABLES LIKE "version%"');
39
40 if (!empty($variables)) {
41 foreach ($variables as $variable) {
42 if (preg_match('/mariadb/i', $variable->Value)) {
43 $server_type = self::MARIA_DB;
44 }
45 if (preg_match('/percona/i', $variable->Value)) {
46 $server_type = self::PERCONA_DB;
47 }
48 }
49 }
50
51 return $server_type;
52 }
53
54 /**
55 * Returns database server version
56 *
57 * @return string|bool
58 */
59 public function get_version() {
60 $version = $this->get_option_value('version');
61
62 if (!empty($version)) {
63 if (preg_match('/^(\d+)(\.\d+)+/', $version, $match)) {
64 return $match[0];
65 }
66 }
67
68 return false;
69 }
70
71 /**
72 * Return table type by $table_name.
73 *
74 * @param String $table_name Database table name.
75 * @return String|Boolean - returns false upon failure
76 */
77 public function get_table_type($table_name) {
78 $table_info = $this->get_table_status($table_name);
79
80 if ($table_info) {
81 if (!$table_info->Engine && $this->is_view($table_name)) return self::VIEW;
82
83 return $table_info->Engine;
84 }
85
86 return false;
87 }
88
89 /**
90 * Returns information about database table.
91 *
92 * @param string $table_name
93 * @param bool $update if true, then force request to database and don't use cached values.
94 * @return bool|mixed
95 */
96 public function get_table_status($table_name, $update = false) {
97 global $wpdb;
98
99 if (false == $update) {
100 $tables_info = $this->get_show_table_status();
101
102 foreach ($tables_info as $table_info) {
103 if ($table_name == $table_info->Name) return $table_info;
104 }
105 } else {
106 return $wpdb->get_row($wpdb->prepare('SHOW TABLE STATUS LIKE %s;', $table_name));
107 }
108
109 return false;
110 }
111
112 /**
113 * Returns result for query SHOW TABLE STATUS.
114 *
115 * @return array
116 */
117 public function get_show_table_status() {
118 global $wpdb;
119 static $tables_info = array();
120
121 if (empty($tables_info) || !is_array($tables_info)) {
122 $tables_info = $wpdb->get_results('SHOW TABLE STATUS');
123 }
124
125 // If option innodb_file_per_table is disabled then Data_free column will have summary overhead value for all table.
126 if (!empty($tables_info)) {
127 foreach ($tables_info as $i => $table) {
128 if (self::INNODB_ENGINE == $table->Engine && false == $this->is_option_enabled('innodb_file_per_table')) {
129 $tables_info[$i]->Data_free = 0;
130 }
131 }
132 }
133
134 return $tables_info;
135 }
136
137 /**
138 * Returns result for query SHOW FULL TABLES as associative array [table_name] => table_type.
139 *
140 * @return array
141 */
142 public function get_show_full_tables() {
143 global $wpdb;
144
145 static $tables_info = array();
146
147 if (empty($tables_info) || !is_array($tables_info)) {
148 $_tables_info = $wpdb->get_results('SHOW FULL TABLES', ARRAY_N);
149
150 if (!empty($_tables_info)) {
151 foreach ($_tables_info as $row) {
152 $tables_info[$row[0]] = $row[1];
153 }
154 }
155 }
156
157 return $tables_info;
158 }
159
160 /**
161 * Checks if table is a VIEW.
162 *
163 * @param string $table_name
164 * @return bool
165 */
166 public function is_view($table_name) {
167 $tables_info = $this->get_show_full_tables();
168
169 if (!array_key_exists($table_name, $tables_info)) return false;
170
171 return ('VIEW' == $tables_info[$table_name]);
172 }
173
174 /**
175 * Returns true if DDL supported.
176 *
177 * @return bool
178 */
179 public function has_online_ddl() {
180 if (self::MYSQL_DB == $this->get_server_type()) {
181 if (version_compare($this->get_version(), '5.7', '>=')) {
182 return true;
183 } else {
184 return false;
185 }
186 } elseif (self::MARIA_DB == $this->get_server_type()) {
187 if (version_compare($this->get_version(), '10.0.0', '>=')) {
188 return true;
189 } else {
190 return false;
191 }
192 }
193
194 return false;
195 }
196
197 /**
198 * Returns database option variable
199 *
200 * @param string $option_name Name of database option.
201 * @return mixed|null
202 */
203 public function get_option_value($option_name) {
204 global $wpdb;
205 static $options = array();
206
207 if (array_key_exists($option_name, $options)) return $options[$option_name];
208
209 $option = $wpdb->get_row(
210 $wpdb->prepare('SHOW SESSION VARIABLES LIKE %s', $option_name)
211 );
212
213 if (!empty($option)) {
214 $options[$option_name] = $option->Value;
215 return $option->Value;
216 }
217
218 return null;
219 }
220
221 /**
222 * Returns true if database option $option_name
223 *
224 * @param string $option_name Name of database option name.
225 * @return bool
226 */
227 public function is_option_enabled($option_name) {
228 $option_value = $this->get_option_value($option_name);
229
230 if ('ON' == strtoupper($option_value)) return true;
231 return false;
232 }
233
234 /**
235 * Returns true if table $table_name is optimizable
236 *
237 * @param string $table_name Name of database table
238 * @return bool
239 */
240 public function is_table_optimizable($table_name) {
241 $server_type = $this->get_server_type();
242 $server_version = $this->get_version();
243 $table_type = $this->get_table_type($table_name);
244
245 // return true if table is MyISAM.
246 if (self::MYISAM_ENGINE == $table_type) return true;
247
248 // return true if table is Archive or Aria.
249 if (self::ARCHIVE_ENGINE == $table_type || self::ARIA_ENGINE == $table_type) return true;
250
251 // if InnoDB then check if we can optimize.
252 if (self::INNODB_ENGINE == $table_type) {
253 // check for MysqlDB.
254 if (self::MYSQL_DB == $server_type && $this->has_online_ddl()) {
255 return true;
256 }
257
258 // check for MariaDB.
259 if (self::MARIA_DB == $server_type) {
260 // if innodb_file_per_table enabled or version not older than 10.1.1 and innodb_defragment enabled.
261 if ($this->is_option_enabled('innodb_file_per_table') || (version_compare($server_version, '10.1.1', '>=') && $this->is_option_enabled('innodb_defragment'))) {
262 return true;
263 }
264 }
265 }
266
267 // otherwise return false.
268 return false;
269 }
270
271 /**
272 * Returns true if table type is supported for optimization.
273 *
274 * @param string $table_name Name of database table
275 * @return bool
276 */
277 public function is_table_type_optimize_supported($table_name) {
278 $table_type = $this->get_table_type($table_name);
279
280 $supported_table_types = array(
281 self::MYISAM_ENGINE,
282 self::INNODB_ENGINE,
283 self::ARCHIVE_ENGINE,
284 self::ARIA_ENGINE,
285 );
286
287 return in_array($table_type, $supported_table_types);
288 }
289
290 /**
291 * Returns true if table type is supported for repair.
292 *
293 * @param string $table_name
294 * @return bool
295 */
296 public function is_table_type_repair_supported($table_name) {
297 $table_type = $this->get_table_type($table_name);
298
299 $supported_table_types = array(
300 self::MYISAM_ENGINE,
301 self::ARCHIVE_ENGINE,
302 self::CSV_ENGINE,
303 );
304
305 return in_array($table_type, $supported_table_types);
306 }
307
308 /**
309 * Run CHECK TABLE query and returns statuses for single or list of tables.
310 *
311 * @param array|string $table
312 */
313 public function check_table($table) {
314 global $wpdb;
315
316 if (is_array($table)) {
317 $table = join(',', $table);
318 }
319
320 $result = array();
321
322 if (empty($table)) return $result;
323
324 $query_result = $wpdb->get_results('CHECK TABLE '.$table.';');
325
326 if (empty($query_result)) return $result;
327
328 foreach ($query_result as $row) {
329 $table_name_parts = explode('.', rtrim($row->Table, ' .'));
330 $table_name = array_pop($table_name_parts);
331
332 if (!array_key_exists($table_name, $result)) {
333 $result[$table_name] = array(
334 'status' => '',
335 'corrupted' => false,
336 );
337 }
338
339 if ('error' == $row->Msg_type) {
340 $result[$table_name]['status'] = $row->Msg_type;
341
342 if (preg_match('/corrupt/i', $row->Msg_text)) {
343 $result[$table_name]['corrupted'] = true;
344 } else {
345 $result[$table_name]['message'] = $row->Msg_text;
346 }
347 }
348
349 if ('status' == $row->Msg_type) {
350 $result[$table_name]['status'] = $row->Msg_text;
351 }
352 }
353
354 return $result;
355 }
356
357 /**
358 * Check all supported for repair tables and return statuses for them.
359 *
360 * @return array
361 */
362 public function check_all_tables() {
363 static $result = null;
364
365 if (null !== $result) return $result;
366
367 $tables = $this->get_show_table_status();
368 $supported_tables = array();
369
370 foreach ($tables as $table) {
371 if ('' == $table->Engine || $this->is_table_type_repair_supported($table->Name)) {
372 $supported_tables[] = $table->Name;
373 }
374 }
375
376 $result = $this->check_table($supported_tables);
377
378 return $result;
379 }
380
381 /**
382 * Returns true if table needing repair.
383 *
384 * @param string $table_name Database table name.
385 */
386 public function is_table_needing_repair($table_name) {
387 $table_statuses = $this->check_all_tables();
388
389 if (is_array($table_statuses) && array_key_exists($table_name, $table_statuses) && $table_statuses[$table_name]['corrupted']) {
390 return true;
391 } else {
392 return false;
393 }
394 }
395
396 /**
397 * Check if $table using by any of installed plugins.
398 *
399 * @param string $table
400 * @return bool
401 */
402 public function is_table_using_by_plugin($table) {
403 $plugin_name = $this->get_table_plugin($table);
404
405 // if we can't determine which plugin use $table then return true.
406 if (false == $plugin_name) {
407 return true;
408 }
409
410 // is WordPress core table or using by any of installed plugins then return true.
411 if (__('WordPress core', 'wp-optimize') == $plugin_name || in_array($plugin_name, $this->get_all_installed_plugins())) {
412 return true;
413 }
414
415 return false;
416 }
417
418 /**
419 * Get information about relations between tables and plugins. [ 'table' => 'plugin', ... ].
420 *
421 * @return array
422 */
423 private function get_all_plugin_tables_relationship() {
424 static $plugin_tables;
425
426 $wp_core_tables = array(
427 'blogs',
428 'blogversions',
429 'commentmeta',
430 'comments',
431 'links',
432 'options',
433 'postmeta',
434 'posts',
435 'term_relationships',
436 'term_taxonomy',
437 'termmeta',
438 'terms',
439 'usermeta',
440 'users',
441 'site',
442 'sitemeta',
443 );
444
445 if (is_array($plugin_tables)) return $plugin_tables;
446
447 $plugin_tables_json_file = WPO_PLUGIN_MAIN_PATH.'/plugin.json';
448 $plugin_tables = array();
449
450 if (is_file($plugin_tables_json_file) && is_readable($plugin_tables_json_file)) {
451 // get data from plugin.json file.
452 $plugin_tables = json_decode(file_get_contents($plugin_tables_json_file), true);
453 }
454
455 foreach ($wp_core_tables as $table) {
456 $plugin_tables[$table] = __('WordPress core', 'wp-optimize');
457 }
458
459 // add WP-Optimize tables.
460 $plugin_tables['tm_taskmeta'] = 'wp-optimize';
461 $plugin_tables['tm_tasks'] = 'wp-optimize';
462
463 return $plugin_tables;
464 }
465
466 /**
467 * Try to get plugin name by table name and return it or return false if plugin is not defined.
468 *
469 * @param string $table
470 * @return string|bool
471 */
472 public function get_table_plugin($table) {
473 global $wpdb;
474
475 // delete table prefix.
476 $table = preg_replace('/^'.$wpdb->prefix.'([0-9]+_)?/', '', $table);
477 $plugins_tables = $this->get_all_plugin_tables_relationship();
478
479 if (array_key_exists($table, $plugins_tables)) {
480 return $plugins_tables[$table];
481 }
482
483 return false;
484 }
485
486 /**
487 * Get all installed plugin slugs.
488 *
489 * @return array
490 */
491 public function get_all_installed_plugins() {
492 static $installed_plugins;
493
494 if (is_array($installed_plugins)) return $installed_plugins;
495
496 $installed_plugins = array();
497
498 if (!function_exists('get_plugins')) include_once(ABSPATH.'wp-admin/includes/plugin.php');
499
500 $plugins = get_plugins();
501
502 foreach ($plugins as $plugin_file => $plugin_data) {
503 if ('' != $plugin_data['TextDomain']) {
504 $installed_plugins[] = $plugin_data['TextDomain'];
505 } else {
506 $plugin_file_parts = explode('/', $plugin_file);
507 $installed_plugins[]= $plugin_file_parts[0];
508 }
509 }
510
511 return $installed_plugins;
512 }
513
514 /**
515 * Check current plugin status installed/not installed and active/inactive.
516 *
517 * @param string $plugin
518 * @return array - ['installed' => true|false, 'active' => true|false]
519 */
520 public function get_plugin_status($plugin) {
521 $plugins = get_plugins();
522
523 // return true for wp-optimize without checking.
524 if ('wp-optimize' == $plugin) {
525 return array(
526 'installed' => true,
527 'active' => true,
528 );
529 }
530
531 $installed = false;
532 $active = false;
533
534 foreach ($plugins as $plugin_file => $plugin_data) {
535 if ('' != $plugin_data['TextDomain']) {
536 $plugin_slug = $plugin_data['TextDomain'];
537 } else {
538 $plugin_file_parts = explode('/', $plugin_file);
539 $plugin_slug = $plugin_file_parts[0];
540 }
541
542 if ($plugin == $plugin_slug) {
543 $installed = true;
544 $active = is_plugin_active($plugin_file);
545 }
546 }
547
548 return array(
549 'installed' => $installed,
550 'active' => $active,
551 );
552 }
553 }
554