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 / views / log.php

log.php in phpinfo() WP – Site Health, PHP Compatibility & Server Audit 7.2.5, at views/log.php

271 lines 13.1 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 $content_dir = WP_CONTENT_DIR;
5 $log_dir = "$content_dir/logs/phpinfo-WP";
6 $log_file = "$log_dir/log.txt";
7
8 if (!file_exists($log_dir)) wp_mkdir_p($log_dir);
9 if (!file_exists($log_file)) file_put_contents($log_file, '');
10
11 $notice = '';
12
13 // Parse entries — stored as "message<br />" lines, newest first
14 $raw = file_get_contents($log_file);
15 $lines = array_filter(array_map('trim', explode('<br />', $raw)));
16 $entries = array_reverse(array_values($lines));
17
18 function phpinfowp_parse_log_entry(string $raw): array {
19 $action = 'unknown';
20 $file = '';
21 $detail = '';
22 $dt = '';
23 $user = '';
24
25 if (strpos($raw, 'backed up') !== false) $action = 'backup';
26 elseif (strpos($raw, 'restored') !== false) $action = 'restore';
27 elseif (strpos($raw, 'autofix applied') !== false) $action = 'autofix';
28 elseif (strpos($raw, 'autofix block reverted') !== false) $action = 'autofix-revert';
29 elseif (strpos($raw, 'edited') !== false) $action = 'edit';
30
31 if (strpos($raw, '.user.ini') !== false) $file = '.user.ini';
32 elseif (strpos($raw, '.htaccess') !== false || strpos($raw, 'htaccess') !== false) $file = '.htaccess';
33
34 if (preg_match('/(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/', $raw, $m)) $dt = $m[1];
35 if (preg_match('/by\s+(\S+)\s*$/', $raw, $m)) $user = $m[1];
36
37 if ($action === 'autofix' && preg_match('/autofix applied:\s*(.+?)\s+on\s+\d{4}-\d{2}-\d{2}/i', $raw, $m)) {
38 $detail = trim($m[1]);
39 }
40
41 switch ($action) {
42 case 'edit':
43 $description = $file ? sprintf(__('Edited %s', 'phpinfo-wp'), $file) : __('Edited config', 'phpinfo-wp');
44 break;
45 case 'backup':
46 $description = $file ? sprintf(__('Backed up %s', 'phpinfo-wp'), $file) : __('Backed up config', 'phpinfo-wp');
47 break;
48 case 'restore':
49 $description = $file ? sprintf(__('Restored %s from backup', 'phpinfo-wp'), $file) : __('Restored from backup', 'phpinfo-wp');
50 break;
51 case 'autofix':
52 if ($detail) {
53 $dir_count = substr_count($detail, ',') + 1;
54 $description = sprintf(
55 _n('Auto-fix applied to %1$d directory: %2$s', 'Auto-fix applied to %1$d directories: %2$s', $dir_count, 'phpinfo-wp'),
56 $dir_count,
57 $detail
58 );
59 } else {
60 $description = __('Config Grader auto-fix applied', 'phpinfo-wp');
61 }
62 break;
63 case 'autofix-revert':
64 $description = __('Config Grader auto-fix block reverted', 'phpinfo-wp');
65 break;
66 default:
67 $description = trim(preg_replace([
68 '/\s+on\s+\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\s+by\s+\S+\s*$/i',
69 '/<br\s*\/?>/i',
70 ], '', $raw)) ?: $raw;
71 break;
72 }
73
74 return compact('action', 'file', 'detail', 'description', 'dt', 'user', 'raw');
75 }
76
77 function phpinfowp_relative_time(string $dt): string {
78 if (!$dt) return '';
79 $diff = time() - (int) strtotime($dt . ' UTC');
80 if ($diff < 60) return __('just now', 'phpinfo-wp');
81 if ($diff < 3600) return sprintf(__('%dm ago', 'phpinfo-wp'), round($diff / 60));
82 if ($diff < 86400) return sprintf(__('%dh ago', 'phpinfo-wp'), round($diff / 3600));
83 if ($diff < 604800) return sprintf(__('%dd ago', 'phpinfo-wp'), round($diff / 86400));
84 return gmdate('M j, Y', strtotime($dt . ' UTC'));
85 }
86
87 $parsed = array_map('phpinfowp_parse_log_entry', $entries);
88 $counts = ['all' => count($parsed), 'edit' => 0, 'backup' => 0, 'restore' => 0, 'autofix' => 0];
89 foreach ($parsed as $e) {
90 if ($e['action'] === 'autofix' || $e['action'] === 'autofix-revert') {
91 $counts['autofix']++;
92 } elseif (isset($counts[$e['action']])) {
93 $counts[$e['action']]++;
94 }
95 }
96
97 $filter = sanitize_key($_GET['log_filter'] ?? 'all');
98 if (!in_array($filter, ['all', 'edit', 'backup', 'restore', 'autofix'])) $filter = 'all';
99 $search = sanitize_text_field($_GET['log_search'] ?? '');
100
101 $filtered = array_filter($parsed, function ($e) use ($filter, $search) {
102 if ($filter !== 'all') {
103 if ($filter === 'autofix') {
104 if ($e['action'] !== 'autofix' && $e['action'] !== 'autofix-revert') return false;
105 } elseif ($e['action'] !== $filter) {
106 return false;
107 }
108 }
109 if ($search) {
110 $hay = strtolower($e['raw'] . ' ' . $e['description']);
111 if (strpos($hay, strtolower($search)) === false) return false;
112 }
113 return true;
114 });
115 ?>
116
117 <div class="phpinfowp-pro-page phpinfowp-log-page">
118
119 <div class="phpinfowp-page-header">
120 <div>
121 <h1><?php _e('Activity Log', 'phpinfo-wp'); ?></h1>
122 <p class="phpinfowp-page-subtitle">
123 <?php _e('Tracks every PHP Config change made through phpinfo() WP', 'phpinfo-wp'); ?> &middot;
124 <strong><?php echo count($parsed); ?></strong> <?php echo _n('entry', 'entries', count($parsed), 'phpinfo-wp'); ?>
125 </p>
126 </div>
127 </div>
128
129 <?php if ($notice): ?>
130 <div class="notice notice-success inline is-dismissible" style="margin:0 0 16px"><p><?php echo esc_html($notice); ?></p></div>
131 <?php endif; ?>
132
133 <!-- Filter + Search bar -->
134 <div class="phpinfowp-log-controls">
135 <div class="phpinfowp-log-filters">
136 <?php
137 $tabs = [
138 'all' => ['label' => __('All', 'phpinfo-wp'), 'count' => $counts['all']],
139 'edit' => ['label' => __('Edits', 'phpinfo-wp'), 'count' => $counts['edit']],
140 'backup' => ['label' => __('Backups', 'phpinfo-wp'), 'count' => $counts['backup']],
141 'restore' => ['label' => __('Restores', 'phpinfo-wp'), 'count' => $counts['restore']],
142 'autofix' => ['label' => __('Auto-fixes', 'phpinfo-wp'),'count' => $counts['autofix']],
143 ];
144 foreach ($tabs as $key => $tab):
145 $active = $filter === $key;
146 $url = add_query_arg(['log_filter' => $key, 'log_search' => $search], admin_url('admin.php?page=phpinfowp-log'));
147 ?>
148 <a href="<?php echo esc_url($url); ?>"
149 class="phpinfowp-log-filter-pill <?php echo $active ? 'active' : ''; ?>">
150 <?php echo esc_html($tab['label']); ?>
151 <span class="phpinfowp-log-filter-count"><?php echo esc_html($tab['count']); ?></span>
152 </a>
153 <?php endforeach; ?>
154 </div>
155
156 <div style="position:relative">
157 <input type="text" id="phpinfowp-log-search-input"
158 value="<?php echo esc_attr($search); ?>"
159 placeholder="<?php echo esc_attr__('Search entries…', 'phpinfo-wp'); ?>"
160 class="regular-text"
161 style="padding-right:32px"
162 oninput="phpinfowpLogSearch(this.value)">
163 <button type="button" id="phpinfowp-log-search-clear"
164 style="display:<?php echo $search ? '' : 'none'; ?>;position:absolute;right:6px;top:50%;transform:translateY(-50%);background:none;border:none;cursor:pointer;color:#999;font-size:18px;line-height:1;padding:0"
165 onclick="phpinfowpLogSearchClear()">&times;</button>
166 </div>
167 </div>
168
169 <!-- Timeline -->
170 <?php if (empty($parsed)): ?>
171 <div class="phpinfowp-log-empty">
172 <span class="dashicons dashicons-list-view" style="font-size:40px;width:40px;height:40px;color:#c0c0c0"></span>
173 <p style="margin:12px 0 4px;font-size:15px;color:#444"><?php _e('No activity recorded yet', 'phpinfo-wp'); ?></p>
174 <p style="margin:0;font-size:13px;color:#888"><?php
175 printf(
176 __('Use the %s to start tracking changes.', 'phpinfo-wp'),
177 '<a href="' . esc_url(admin_url('admin.php?page=phpinfowp-htaccess')) . '">' . __('PHP Config editor', 'phpinfo-wp') . '</a>'
178 );
179 ?></p>
180 </div>
181 <?php elseif (empty($filtered)): ?>
182 <div class="phpinfowp-log-empty">
183 <span class="dashicons dashicons-search" style="font-size:40px;width:40px;height:40px;color:#c0c0c0"></span>
184 <p style="margin:12px 0 4px;font-size:15px;color:#444"><?php _e('No entries match your filter', 'phpinfo-wp'); ?></p>
185 </div>
186 <?php else: ?>
187 <div class="phpinfowp-timeline" id="phpinfowp-timeline">
188 <?php foreach ($filtered as $e):
189 switch ($e['action']) {
190 case 'edit':
191 $action_meta = ['label' => __('EDIT', 'phpinfo-wp'), 'color' => '#777BB3', 'bg' => '#f3f0ff', 'icon' => 'dashicons-edit'];
192 break;
193 case 'backup':
194 $action_meta = ['label' => __('BACKUP', 'phpinfo-wp'), 'color' => '#0073aa', 'bg' => '#e8f4fc', 'icon' => 'dashicons-upload'];
195 break;
196 case 'restore':
197 $action_meta = ['label' => __('RESTORE', 'phpinfo-wp'), 'color' => '#dba617', 'bg' => '#fff8e5', 'icon' => 'dashicons-undo'];
198 break;
199 case 'autofix':
200 $action_meta = ['label' => __('AUTO-FIX', 'phpinfo-wp'), 'color' => '#7c3aed', 'bg' => '#f5f0ff', 'icon' => 'dashicons-admin-tools'];
201 break;
202 case 'autofix-revert':
203 $action_meta = ['label' => __('REVERTED', 'phpinfo-wp'), 'color' => '#9b6bf2', 'bg' => '#f5f0ff', 'icon' => 'dashicons-undo'];
204 break;
205 default:
206 $action_meta = ['label' => __('EVENT', 'phpinfo-wp'), 'color' => '#666', 'bg' => '#f6f7f7', 'icon' => 'dashicons-info'];
207 break;
208 }
209 ?>
210 <div class="phpinfowp-timeline-entry" style="border-left-color:<?php echo $action_meta['color']; ?>"
211 data-raw="<?php echo esc_attr(strtolower($e['raw'] . ' ' . $e['description'])); ?>">
212
213 <div class="phpinfowp-timeline-icon" style="background:<?php echo $action_meta['bg']; ?>;color:<?php echo $action_meta['color']; ?>">
214 <span class="dashicons <?php echo $action_meta['icon']; ?>" style="font-size:16px;width:16px;height:16px;line-height:1"></span>
215 </div>
216
217 <div class="phpinfowp-timeline-body">
218 <div class="phpinfowp-timeline-top">
219 <span class="phpinfowp-timeline-badge" style="background:<?php echo $action_meta['color']; ?>">
220 <?php echo esc_html($action_meta['label']); ?>
221 </span>
222 <?php if ($e['file']): ?>
223 <code class="phpinfowp-timeline-file"><?php echo esc_html($e['file']); ?></code>
224 <?php endif; ?>
225 <?php if ($e['user']): ?>
226 <span class="phpinfowp-timeline-user">
227 <span class="dashicons dashicons-admin-users" style="font-size:12px;width:12px;height:12px;vertical-align:middle;margin-right:2px;color:#999"></span>
228 <?php echo esc_html($e['user']); ?>
229 </span>
230 <?php endif; ?>
231 </div>
232 <div class="phpinfowp-timeline-desc" style="font-size:14px;color:#1d2327;margin:4px 0 2px;line-height:1.4">
233 <?php echo esc_html($e['description']); ?>
234 </div>
235 <div class="phpinfowp-timeline-meta">
236 <?php if ($e['dt']): ?>
237 <span title="<?php echo esc_attr($e['dt']); ?> UTC"><?php echo esc_html(phpinfowp_relative_time($e['dt'])); ?></span>
238 <span style="color:#ccc">&middot;</span>
239 <span style="color:#aaa"><?php echo esc_html($e['dt']); ?> UTC</span>
240 <?php else: ?>
241 <span style="color:#aaa"><?php echo esc_html($e['raw']); ?></span>
242 <?php endif; ?>
243 </div>
244 </div>
245
246 </div>
247 <?php endforeach; ?>
248 </div>
249 <?php endif; ?>
250
251 </div>
252
253 <script>
254 function phpinfowpLogSearch(q) {
255 q = q.toLowerCase().trim();
256 document.getElementById('phpinfowp-log-search-clear').style.display = q ? '' : 'none';
257 var entries = document.querySelectorAll('#phpinfowp-timeline .phpinfowp-timeline-entry');
258 entries.forEach(function(el) {
259 var match = !q || el.dataset.raw.includes(q);
260 el.style.display = match ? '' : 'none';
261 });
262 }
263
264 function phpinfowpLogSearchClear() {
265 document.getElementById('phpinfowp-log-search-input').value = '';
266 phpinfowpLogSearch('');
267 }
268 <?php if ($search): ?>
269 phpinfowpLogSearch(<?php echo json_encode($search); ?>);
270 <?php endif; ?>
271 </script>