PluginProbe
404 Solution / trunk
404 Solution vtrunk
4.3.5 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 4.2.0 4.1.19 4.1.18 4.1.17 4.1.16 4.1.15 4.1.13 4.1.12 4.1.11 4.1.10 4.1.9 4.1.8 4.1.7 4.1.6 4.1.5 4.1.4 4.1.3 trunk 2.30.0 All 109 releases
404-solution / includes / uninstall / UninstallStatisticsReader.php

UninstallStatisticsReader.php in 404 Solution trunk, at includes/uninstall/UninstallStatisticsReader.php

139 lines 5.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // allow-no-test-found: covered by tests/UninstallDiagnosticsEntryPointTest.php public uninstall modal/email entry points
3
4 if (!defined('ABSPATH')) {
5 exit;
6 }
7
8 /**
9 * Reads uninstall feedback statistics for redirects, captured hits, logs,
10 * and debug-file size.
11 */
12 class ABJ_404_Solution_UninstallStatisticsReader {
13
14 /**
15 * @return int Number of active non-trashed redirects, or 0 if unavailable.
16 */
17 public function getRedirectCount(): int {
18 global $wpdb;
19
20 $tableName = $this->redirectsTableName();
21
22 // DAO-bypass-approved: Diagnostic table-existence probe for redirect-count display
23 $tableExists = $wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $tableName)) === $tableName;
24 if (!$tableExists) {
25 return 0;
26 }
27
28 // DAO-bypass-approved: Diagnostic count for uninstall-modal preview
29 $count = $wpdb->get_var("SELECT COUNT(*) FROM $tableName WHERE status != " . ABJ404_STATUS_TRASH);
30 return $count ? intval($count) : 0;
31 }
32
33 /**
34 * @return array{
35 * redirects: array{all:int,manual:int,auto:int,regex:int,trash:int},
36 * captured: array{all:int,captured:int,ignored:int,later:int,trash:int},
37 * log_count: int,
38 * log_table_size_mb: int|float,
39 * debug_file_size_mb: int|float,
40 * _errors?: list<string>
41 * }
42 */
43 public function getPluginStatistics(): array {
44 $stats = array(
45 'redirects' => array('all' => 0, 'manual' => 0, 'auto' => 0, 'regex' => 0, 'trash' => 0),
46 'captured' => array('all' => 0, 'captured' => 0, 'ignored' => 0, 'later' => 0, 'trash' => 0),
47 'log_count' => 0,
48 'log_table_size_mb' => 0,
49 'debug_file_size_mb' => 0,
50 );
51
52 if (!class_exists('ABJ_404_Solution_DataAccess')) {
53 return $stats;
54 }
55
56 global $wpdb;
57 if (!isset($wpdb) || !method_exists($wpdb, 'get_results')) {
58 return $stats;
59 }
60
61 try {
62 $viewRead = abj_service('view_read_service');
63
64 $redirectCounts = $viewRead->getRedirectStatusCounts(true);
65 if (is_array($redirectCounts)) {
66 $stats['redirects'] = array(
67 'all' => self::intValue($redirectCounts, 'all'),
68 'manual' => self::intValue($redirectCounts, 'manual'),
69 'auto' => self::intValue($redirectCounts, 'auto'),
70 'regex' => self::intValue($redirectCounts, 'regex'),
71 'trash' => self::intValue($redirectCounts, 'trash'),
72 );
73 }
74
75 $capturedCounts = $viewRead->getCapturedStatusCounts(true);
76 if (is_array($capturedCounts)) {
77 $stats['captured'] = array(
78 'all' => self::intValue($capturedCounts, 'all'),
79 'captured' => self::intValue($capturedCounts, 'captured'),
80 'ignored' => self::intValue($capturedCounts, 'ignored'),
81 'later' => self::intValue($capturedCounts, 'later'),
82 'trash' => self::intValue($capturedCounts, 'trash'),
83 );
84 }
85
86 $stats['log_count'] = $viewRead->getLogsCount(0);
87
88 $logTableSizeBytes = $viewRead->getLogDiskUsage();
89 if ($logTableSizeBytes > 0) {
90 $stats['log_table_size_mb'] = round($logTableSizeBytes / (1024 * 1024), 2);
91 }
92
93 if (class_exists('ABJ_404_Solution_Logging')) {
94 $logger = abj_service('logging');
95 $debugFilePath = $logger->getDebugFilePath();
96 if (file_exists($debugFilePath)) {
97 $debugFileSize = filesize($debugFilePath);
98 $stats['debug_file_size_mb'] = round($debugFileSize / (1024 * 1024), 2);
99 }
100 }
101 } catch (\Throwable $e) {
102 $stats['_errors'][] = 'getDebugFileSize: ' . $e->getMessage();
103 }
104
105 return $stats;
106 }
107
108 /**
109 * @param array<string, mixed> $values
110 * @return int
111 */
112 private static function intValue(array $values, string $key): int {
113 return isset($values[$key]) && is_numeric($values[$key]) ? (int)$values[$key] : 0;
114 }
115
116 /**
117 * @return string
118 */
119 private function redirectsTableName(): string {
120 global $wpdb;
121
122 if (class_exists('ABJ_404_Solution_ServiceContainer', false)) {
123 $container = ABJ_404_Solution_ServiceContainer::getInstance();
124 if ($container->has('db_core')) {
125 $dbCore = $container->get('db_core');
126 if ($dbCore instanceof ABJ_404_Solution_DatabaseCoreInterface) {
127 return $dbCore->tableNameResolver()->getPrefixedTableName('abj404_redirects');
128 }
129 }
130 }
131
132 // Plugin tables are created lowercased; normalize $wpdb->prefix to
133 // lowercase so MySQL hosts with a mixed-case prefix still find the
134 // physical table (CentralizedTableNameTest invariant).
135 $prefix = isset($wpdb->prefix) && is_string($wpdb->prefix) ? strtolower($wpdb->prefix) : '';
136 return $prefix . 'abj404_redirects';
137 }
138 }
139