PluginProbe
phpinfo() WP – Site Health, PHP Compatibility & Server Audit / 7.2.5
phpinfo() WP – Site Health, PHP Compatibility & Server Audit v7.2.5
7.2.7 7.2.6 7.2.5 7.2.4 7.2.3 7.2.0 7.2.1 7.2.2 7.1.0 7.0.3 7.0.4 7.0.5 trunk 6.0 7.0.0 7.0.1 7.0.2
phpinfo-wp / includes / class-snapshots.php

class-snapshots.php in phpinfo() WP – Site Health, PHP Compatibility & Server Audit 7.2.5, at includes/class-snapshots.php

167 lines 6.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 defined('ABSPATH') or die('Unauthorized Access');
3
4 class Phpinfo_WP_Snapshots {
5
6 private static function _pro(): bool { return Phpinfo_WP_License::is_valid(); }
7
8 // Only track directives that actually matter — full ini_get_all() is hundreds of noisy keys
9 const TRACKED = [
10 'memory_limit', 'upload_max_filesize', 'post_max_size', 'max_execution_time',
11 'max_input_time', 'max_input_vars', 'max_file_uploads', 'display_errors',
12 'display_startup_errors', 'error_reporting', 'error_log', 'log_errors',
13 'expose_php', 'allow_url_fopen', 'allow_url_include', 'disable_functions',
14 'file_uploads', 'default_socket_timeout', 'date.timezone',
15 'session.gc_maxlifetime', 'session.use_strict_mode',
16 'session.cookie_httponly', 'session.cookie_secure',
17 'opcache.enable', 'opcache.memory_consumption', 'opcache.max_accelerated_files',
18 'opcache.validate_timestamps', 'opcache.revalidate_freq',
19 'zlib.output_compression', 'default_charset', 'short_open_tag',
20 'mbstring.internal_encoding', 'precision', 'serialize_precision',
21 ];
22
23 private static function table(): string {
24 global $wpdb;
25 return $wpdb->prefix . 'phpinfowp_snapshots';
26 }
27
28 public static function install_table(): void {
29 global $wpdb;
30 $charset = $wpdb->get_charset_collate();
31 $sql = "CREATE TABLE IF NOT EXISTS " . self::table() . " (
32 id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
33 label VARCHAR(255) NOT NULL DEFAULT '',
34 created_by BIGINT UNSIGNED NOT NULL DEFAULT 0,
35 created_at DATETIME NOT NULL,
36 snapshot_data LONGTEXT NOT NULL,
37 PRIMARY KEY (id),
38 KEY created_at (created_at)
39 ) {$charset};";
40 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
41 dbDelta($sql);
42 }
43
44 public static function capture(): array {
45 if (!self::_pro()) return [];
46 $data = [];
47 foreach (self::TRACKED as $key) {
48 $val = ini_get($key);
49 $data[$key] = ($val === false) ? null : $val;
50 }
51 // Also record PHP version itself
52 $data['__php_version'] = PHP_VERSION;
53 return $data;
54 }
55
56 public static function take(string $label = '', int $user_id = 0): int {
57 if (!self::_pro()) return 0;
58 global $wpdb;
59 $data = self::capture();
60 $wpdb->insert(self::table(), [
61 'label' => $label ?: 'Manual snapshot',
62 'created_by' => $user_id ?: get_current_user_id(),
63 'created_at' => current_time('mysql', true),
64 'snapshot_data' => wp_json_encode($data),
65 ]);
66 return (int) $wpdb->insert_id;
67 }
68
69 public static function list(int $limit = 50): array {
70 if (!self::_pro()) return [];
71 global $wpdb;
72 return $wpdb->get_results($wpdb->prepare(
73 "SELECT id, label, created_by, created_at FROM " . self::table() . " ORDER BY created_at DESC LIMIT %d",
74 $limit
75 ));
76 }
77
78 public static function get(int $id): ?object {
79 if (!self::_pro()) return null;
80 global $wpdb;
81 $row = $wpdb->get_row($wpdb->prepare(
82 "SELECT * FROM " . self::table() . " WHERE id = %d LIMIT 1", $id
83 ));
84 if (!$row) return null;
85 $row->snapshot_data = json_decode($row->snapshot_data, true) ?? [];
86 return $row;
87 }
88
89 public static function delete(int $id): void {
90 if (!self::_pro()) return;
91 global $wpdb;
92 $wpdb->delete(self::table(), ['id' => $id], ['%d']);
93 }
94
95 public static function get_latest(): ?object {
96 if (!self::_pro()) return null;
97 global $wpdb;
98 $row = $wpdb->get_row(
99 "SELECT * FROM " . self::table() . " ORDER BY created_at DESC LIMIT 1"
100 );
101 if (!$row) return null;
102 $row->snapshot_data = json_decode($row->snapshot_data, true) ?? [];
103 return $row;
104 }
105
106 public static function get_previous_to(int $id): ?object {
107 if (!self::_pro()) return null;
108 global $wpdb;
109 $row = $wpdb->get_row($wpdb->prepare(
110 "SELECT * FROM " . self::table() . " WHERE id < %d ORDER BY id DESC LIMIT 1", $id
111 ));
112 if (!$row) return null;
113 $row->snapshot_data = json_decode($row->snapshot_data, true) ?? [];
114 return $row;
115 }
116
117 // Returns array of ['type'=>added|removed|changed, 'key'=>..., 'old'=>..., 'new'=>...]
118 public static function diff(array $old_data, array $new_data): array {
119 if (!self::_pro()) return [];
120 $changes = [];
121
122 foreach ($old_data as $key => $old_val) {
123 if (!array_key_exists($key, $new_data)) {
124 $changes[] = ['type' => 'removed', 'key' => $key, 'old' => $old_val, 'new' => null];
125 } elseif ((string) $old_val !== (string) $new_data[$key]) {
126 $changes[] = ['type' => 'changed', 'key' => $key, 'old' => $old_val, 'new' => $new_data[$key]];
127 }
128 }
129 foreach ($new_data as $key => $new_val) {
130 if (!array_key_exists($key, $old_data)) {
131 $changes[] = ['type' => 'added', 'key' => $key, 'old' => null, 'new' => $new_val];
132 }
133 }
134
135 usort($changes, function ($a, $b) {
136 return strcmp($a['key'], $b['key']);
137 });
138 return $changes;
139 }
140
141 // Auto-snapshot called by cron. Returns diff vs. previous if changes detected.
142 public static function auto_snapshot(): array {
143 if (!self::_pro()) return [];
144 $new_id = self::take('Auto (weekly)', 0);
145 $new = self::get($new_id);
146 $prev = self::get_previous_to($new_id);
147
148 if (!$prev) return [];
149 return self::diff($prev->snapshot_data, $new->snapshot_data);
150 }
151
152 public static function prune(int $keep = 30): void {
153 if (!self::_pro()) return;
154 if (!Phpinfo_WP_License::is_unlimited()) {
155 $keep = 3;
156 }
157 global $wpdb;
158 $ids = $wpdb->get_col($wpdb->prepare(
159 "SELECT id FROM " . self::table() . " ORDER BY created_at DESC LIMIT %d, 9999", $keep
160 ));
161 if ($ids) {
162 $placeholders = implode(',', array_fill(0, count($ids), '%d'));
163 $wpdb->query($wpdb->prepare("DELETE FROM " . self::table() . " WHERE id IN ($placeholders)", ...$ids));
164 }
165 }
166 }
167