PluginProbe
PublishPress Planner – Editorial Calendar, Marketing Content, Kanban Board / 4.8.0
PublishPress Planner – Editorial Calendar, Marketing Content, Kanban Board v4.8.0
trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.1.0 1.10.0 1.11.2 1.11.3 1.11.4 1.12.0 1.12.1 1.13.0 1.14.0 1.14.1 1.15.0 1.16.0 1.16.1 1.16.2 1.16.3 1.17.0 1.18.0 1.18.1 All 140 releases
publishpress / modules / debug / debug.php

debug.php in PublishPress Planner – Editorial Calendar, Marketing Content, Kanban Board 4.8.0, at modules/debug/debug.php

381 lines 13.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package PublishPress
4 * @author PublishPress
5 *
6 * Copyright (c) 2022 PublishPress
7 *
8 * ------------------------------------------------------------------------------
9 * Based on Edit Flow
10 * Author: Daniel Bachhuber, Scott Bressler, Mohammad Jangda, Automattic, and
11 * others
12 * Copyright (c) 2009-2016 Mohammad Jangda, Daniel Bachhuber, et al.
13 * ------------------------------------------------------------------------------
14 *
15 * This file is part of PublishPress
16 *
17 * PublishPress is free software: you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation, either version 3 of the License, or
20 * (at your option) any later version.
21 *
22 * PublishPress is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with PublishPress. If not, see <http://www.gnu.org/licenses/>.
29 */
30
31 use PublishPress\Notifications\Traits\Dependency_Injector;
32
33 if (! class_exists('PP_Debug')) {
34 /**
35 * Class PP_Debug
36 */
37 #[\AllowDynamicProperties]
38 class PP_Debug extends PP_Module
39 {
40 use Dependency_Injector;
41
42 const FILE = 'debug-publishpress.log';
43
44 const PAGE_SLUG = 'publishpress_debug_log';
45
46 const ACTION_DELETE_LOG = 'delete_log';
47
48 const REQUIRED_CAPABILITY = 'activate_plugins';
49
50 protected $path;
51
52 protected $initialized = false;
53
54 protected $messages = [];
55
56 /**
57 * Load the PP_Debug class as an PublishPress module
58 */
59 public function __construct()
60 {
61 $this->viewsPath = __DIR__ . '/views';
62
63 parent::__construct();
64
65 // Register the module with PublishPress
66 $this->module_url = $this->get_module_url(__FILE__);
67 $args = [
68 'title' => __('Debug', 'publishpress'),
69 'short_description' => false,
70 'extended_description' => false,
71 'module_url' => $this->module_url,
72 'icon_class' => 'dashicons dashicons-bug',
73 'slug' => 'debug',
74 'default_options' => [
75 'enabled' => 'off',
76 ],
77 'configure_page_cb' => 'print_configure_view',
78 ];
79 $this->module = PublishPress()->register_module('debug', $args);
80 }
81
82 /**
83 * Initialize all the class' functionality.
84 */
85 public function init()
86 {
87 $uploadDir = wp_get_upload_dir();
88 if (is_array($uploadDir) && isset($uploadDir['path'])) {
89 $uploadDir = $uploadDir['path'];
90 }
91
92 $this->path = $uploadDir . '/' . self::FILE;
93
94 if ($this->currentUserCanSeeDebugLog() && is_admin()) {
95 add_action('admin_init', [$this, 'register_settings']);
96 add_action('admin_bar_menu', [$this, 'admin_bar_menu'], 99);
97 add_action('admin_menu', [$this, 'admin_menu']);
98 add_action('admin_enqueue_scripts', [$this, 'enqueue_admin_scripts']);
99 }
100
101
102 add_action('publishpress_debug_write_log', [$this, 'write'], 10, 3);
103
104 $this->initialized = true;
105 }
106
107 private function currentUserCanSeeDebugLog()
108 {
109 return current_user_can(self::REQUIRED_CAPABILITY);
110 }
111
112 public function enqueue_admin_scripts()
113 {
114 if (isset($_GET['page']) && $_GET['page'] === self::PAGE_SLUG) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
115 if (! $this->currentUserCanSeeDebugLog()) {
116 return;
117 }
118
119 wp_enqueue_style(
120 'publishpress-debug',
121 PUBLISHPRESS_URL . 'modules/debug/assets/css/debug.css',
122 [],
123 PUBLISHPRESS_VERSION,
124 'screen'
125 );
126
127 wp_enqueue_script(
128 'publishpress-debug',
129 PUBLISHPRESS_URL . 'modules/debug/assets/js/debug.js',
130 [],
131 PUBLISHPRESS_VERSION
132 );
133 }
134 }
135
136 /**
137 * Register settings for notifications, so we can partially use the Settings API
138 * (We use the Settings API for form generation, but not saving).
139 *
140 */
141 public function register_settings()
142 {
143 }
144
145 /**
146 * Validate the field submitted by the user
147 *
148 * @since 0.7
149 */
150 public function settings_validate($new_options)
151 {
152 if (! $this->currentUserCanSeeDebugLog()) {
153 return $new_options;
154 }
155
156 // Follow whitelist validation for modules
157 if (array_key_exists('post_status_widget', $new_options) && $new_options['post_status_widget'] != 'on') {
158 $new_options['post_status_widget'] = 'off';
159 }
160
161 if (array_key_exists('my_posts_widget', $new_options) && $new_options['my_posts_widget'] != 'on') {
162 $new_options['my_posts_widget'] = 'off';
163 }
164
165 return $new_options;
166 }
167
168 /**
169 * Settings page for the dashboard
170 *
171 * @since 0.7
172 */
173 public function print_configure_view()
174 {
175 settings_fields($this->module->options_group_name);
176 do_settings_sections($this->module->options_group_name);
177 }
178
179 /**
180 * Write the given message into the log file.
181 *
182 * @param $message
183 * @param $id
184 * @param $line
185 *
186 * @throws Exception
187 */
188 public function write($message, $id = null, $line = 0)
189 {
190 if (! $this->get_service('DEBUGGING')) {
191 return;
192 }
193
194 // Make sure we have a string to write.
195 if (! is_string($message)) {
196 if (is_bool($message)) {
197 $message = $message ? 'true' : 'false';
198 } else {
199 $message = print_r($message, true); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
200 }
201 }
202
203 // Prepend the id, if set.
204 if (! empty($id)) {
205 if (! empty($line)) {
206 $id .= ':' . $line;
207 }
208
209 $message = $id . ' --> ' . $message;
210 }
211
212 // Add the timestamp to the message.
213 $message = sprintf('[%s] %s', gmdate('Y-m-d H:i:s T O'), $message) . "\n";
214
215 error_log($message, 3, $this->path); // phpcs:ignore WordPress.PHP.DevelopmentFunctions
216 }
217
218 public function admin_bar_menu()
219 {
220 if (! $this->currentUserCanSeeDebugLog()) {
221 return;
222 }
223
224 global $wp_admin_bar;
225
226 $args = [
227 'id' => 'publishpress_debug',
228 'title' => esc_html__('PublishPress Debug Log', 'publishpress'),
229 'href' => admin_url('admin.php?page=' . self::PAGE_SLUG),
230 ];
231
232 $wp_admin_bar->add_menu($args);
233 }
234
235 public function admin_menu()
236 {
237 $publishpress = $this->get_service('publishpress');
238
239 // Admin menu.
240 add_submenu_page(
241 $publishpress->get_menu_slug(),
242 esc_html__('Debug Log', 'publishpress'),
243 esc_html__('Debug Log', 'publishpress'),
244 self::REQUIRED_CAPABILITY,
245 'publishpress_debug_log',
246 [$this, 'view_log_page']
247 );
248 }
249
250 public function view_log_page()
251 {
252 if (! $this->currentUserCanSeeDebugLog()) {
253 return;
254 }
255
256 $this->handle_actions();
257
258 global $wp_version;
259
260 $is_log_found = file_exists($this->path);
261
262 // Get all the plugins and versions
263 $plugins = get_plugins();
264 $pluginsData = [];
265 foreach ($plugins as $plugin => $data) {
266 $pluginsData[$plugin] = (is_plugin_active(
267 $plugin
268 ) ? 'ACTIVATED' : 'deactivated') . ' [' . esc_html($data['Version']) . ']';
269 }
270
271 $debug_data = [
272 'php' => [
273 'version' => PHP_VERSION,
274 'os' => PHP_OS,
275 'date_default_timezone_get' => date_default_timezone_get(),
276 'date(e)' => date('e'), // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
277 'date(T)' => date('T'), // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
278 ],
279 'wordpress' => [
280 'version' => esc_html($wp_version),
281 'date_format' => esc_html(get_option('date_format')),
282 'time_format' => esc_html(get_option('time_format')),
283 'timezone_string' => esc_html(get_option('timezone_string')),
284 'gmt_offset' => esc_html(get_option('gmt_offset')),
285 'plugins' => $pluginsData,
286 ],
287 ];
288
289 $context = [
290 'label' => [
291 'title' => esc_html__('PublishPress Debug Log', 'publishpress'),
292 'file_info' => esc_html__('File info', 'publishpress'),
293 'path' => esc_html__('Path', 'publishpress'),
294 'log_content' => esc_html__('Log content', 'publishpress'),
295 'size' => esc_html__('Size', 'publishpress'),
296 'creation_time' => esc_html__('Created on', 'publishpress'),
297 'modification_time' => esc_html__('Modified on', 'publishpress'),
298 'delete_file' => esc_html__('Delete file', 'publishpress'),
299 'debug_data' => esc_html__('Debug data', 'publishpress'),
300 'log_file' => esc_html__('Log File', 'publishpress'),
301 ],
302 'message' => [
303 'log_not_found' => esc_html__('Log file not found.', 'publishpress'),
304 'contact_support_tip' => esc_html__(
305 'If you see any error or look for information regarding PublishPress, please don\'t hesitate to contact the support team. E-mail us:',
306 'publishpress'
307 ),
308 'click_to_delete' => esc_html__(
309 'Click to delete the log file. Be careful, this operation can not be undone. ',
310 'publishpress'
311 ),
312 ],
313 'contact_email' => 'help@publishpress.com',
314 'link_delete' => esc_url(
315 admin_url(
316 sprintf(
317 'admin.php?page=%s&action=%s&_wpnonce=%s',
318 self::PAGE_SLUG,
319 self::ACTION_DELETE_LOG,
320 wp_create_nonce(self::ACTION_DELETE_LOG)
321 )
322 )
323 ),
324 'is_log_found' => $is_log_found,
325 'file' => [
326 'path' => esc_html($this->path),
327 'size' => $is_log_found ? round(filesize($this->path) / 1024, 2) : 0,
328 'modification_time' => $is_log_found ? gmdate('Y-m-d H:i:s T O', filemtime($this->path)) : '',
329 'content' => $is_log_found ? esc_html(file_get_contents($this->path)) : '',
330 ],
331 'debug_data' => print_r($debug_data, true), // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
332 'messages' => $this->messages,
333 ];
334
335 echo $this->view->render('view_log', $context, $this->viewsPath); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
336 }
337
338 protected function handle_actions()
339 {
340 if (! $this->currentUserCanSeeDebugLog()) {
341 return;
342 }
343
344 // Are we on the correct page?
345 if (! array_key_exists('page', $_GET) || $_GET['page'] !== self::PAGE_SLUG) {
346 return;
347 }
348
349 // Do we have an action?
350 if (! array_key_exists('action', $_GET) || empty($_GET['action'])) {
351 return;
352 }
353
354 $action = sanitize_key($_GET['action']);
355
356 // Do we have a nonce?
357 if (! array_key_exists('_wpnonce', $_GET) || empty($_GET['_wpnonce'])) {
358 $this->messages[] = esc_html__('Action nonce not found.', 'publishpress');
359
360 return;
361 }
362
363 // Check the nonce.
364 if (! wp_verify_nonce(sanitize_text_field($_GET['_wpnonce']), $action)) {
365 $this->messages[] = esc_html__('Invalid action nonce.', 'publishpress');
366
367 return;
368 }
369
370 if ($action === self::ACTION_DELETE_LOG) {
371 if (file_exists($this->path)) {
372 unlink($this->path); // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.file_ops_unlink
373 }
374 }
375
376 wp_redirect(admin_url('admin.php?page=' . self::PAGE_SLUG));
377 exit;
378 }
379 }
380 }
381