PluginProbe
Content Control – The Ultimate Content Restriction Plugin! Restrict Content, Create Conditional Blocks & More / 2.6.2
Content Control – The Ultimate Content Restriction Plugin! Restrict Content, Create Conditional Blocks & More v2.6.2
trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.10 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 2.0.0 2.0.1 2.0.10 2.0.11 2.0.12 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 All 47 releases
content-control / classes / Plugin / Logging.php

Logging.php in Content Control – The Ultimate Content Restriction Plugin! Restrict Content, Create Conditional Blocks & More 2.6.2, at classes/Plugin/Logging.php

455 lines 9.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Logging class.
4 *
5 * @package ContentControl\Plugin
6 */
7
8 namespace ContentControl\Plugin;
9
10 /**
11 * Logging class.
12 */
13 class Logging {
14
15 /**
16 * Log file prefix.
17 */
18 const LOG_FILE_PREFIX = 'content-control-';
19
20 /**
21 * Whether the log file is writable.
22 *
23 * @var bool|null
24 */
25 private $is_writable;
26
27 /**
28 * Log file name.
29 *
30 * @var string
31 */
32 private $filename = '';
33
34 /**
35 * Log file path.
36 *
37 * @var string
38 */
39 private $file = '';
40
41 /**
42 * File system API.
43 *
44 * @var \WP_Filesystem_Base|null
45 */
46 private $fs;
47
48 /**
49 * Log file content.
50 *
51 * @var string|null
52 */
53 private $content;
54
55 /**
56 * Initialize logging.
57 */
58 public function __construct() {
59 $this->init();
60
61 $this->register_hooks();
62 }
63
64 /**
65 * Register hooks.
66 *
67 * @return void
68 */
69 public function register_hooks() {
70 // On shutdown, save the log file.
71 add_action( 'shutdown', [ $this, 'save_logs' ] );
72 }
73
74 /**
75 * Gets the Uploads directory
76 *
77 * @return bool|array{path: string, url: string, subdir: string, basedir: string, baseurl: string, error: string|false} An associated array with baseurl and basedir or false on failure
78 */
79 public function get_upload_dir() {
80 // Used if you only need to fetch data, not create missing folders.
81 $wp_upload_dir = wp_get_upload_dir();
82
83 // phpcs:ignore Squiz.PHP.CommentedOutCode.Found
84 // $wp_upload_dir = wp_upload_dir(); // Disable this on IS_WPCOM if used.
85
86 if ( isset( $wp_upload_dir['error'] ) && false !== $wp_upload_dir['error'] ) {
87 return false;
88 } else {
89 return $wp_upload_dir;
90 }
91 }
92
93 /**
94 * Gets the uploads directory URL
95 *
96 * @param string $path A path to append to end of upload directory URL.
97 * @return bool|string The uploads directory URL or false on failure
98 */
99 public function get_upload_dir_url( $path = '' ) {
100 $upload_dir = $this->get_upload_dir();
101 if ( false !== $upload_dir && isset( $upload_dir['baseurl'] ) ) {
102 $url = preg_replace( '/^https?:/', '', $upload_dir['baseurl'] );
103 if ( null === $url ) {
104 return false;
105 }
106 if ( ! empty( $path ) ) {
107 $url = trailingslashit( $url ) . $path;
108 }
109 return $url;
110 } else {
111 return false;
112 }
113 }
114
115 /**
116 * Chek if logging is enabled.
117 *
118 * @return bool
119 */
120 public function enabled() {
121 $disabled = defined( '\CONTENT_CONTROL_DISABLE_LOGGING' ) && true === \CONTENT_CONTROL_DISABLE_LOGGING;
122
123 return ! $disabled && $this->is_writable();
124 }
125
126 /**
127 * Get working WP Filesystem instance
128 *
129 * @return \WP_Filesystem_Base|false
130 */
131 public function fs() {
132 if ( isset( $this->fs ) ) {
133 return $this->fs;
134 }
135
136 global $wp_filesystem;
137
138 require_once ABSPATH . 'wp-admin/includes/file.php';
139
140 // If for some reason the include doesn't work as expected just return false.
141 if ( ! function_exists( 'WP_Filesystem' ) ) {
142 return false;
143 }
144
145 $writable = WP_Filesystem( false, '', true );
146
147 // We consider the directory as writable if it uses the direct transport,
148 // otherwise credentials would be needed.
149 $this->fs = ( $writable && 'direct' === $wp_filesystem->method ) ? $wp_filesystem : false;
150
151 return $this->fs;
152 }
153
154 /**
155 * Check if the log file is writable.
156 *
157 * @return boolean
158 */
159 public function is_writable() {
160 if ( isset( $this->is_writable ) ) {
161 return $this->is_writable;
162 }
163
164 $file_system = $this->fs();
165
166 if ( false === $file_system ) {
167 $this->is_writable = false;
168 return $this->is_writable;
169 }
170
171 $this->is_writable = 'direct' === $file_system->method;
172
173 $upload_dir = $this->get_upload_dir();
174
175 if ( ! $file_system->is_writable( $upload_dir['basedir'] ) ) {
176 $this->is_writable = false;
177 }
178
179 return $this->is_writable;
180 }
181
182 /**
183 * Get things started
184 *
185 * @return void
186 */
187 public function init() {
188 $upload_dir = $this->get_upload_dir();
189 $file_system = $this->fs();
190
191 if ( false === $upload_dir || false === $file_system ) {
192 return;
193 }
194
195 $file_token = \get_option( 'content_control_debug_log_token' );
196 if ( false === $file_token ) {
197 $file_token = uniqid( (string) wp_rand(), true );
198 \update_option( 'content_control_debug_log_token', $file_token );
199 }
200
201 $this->filename = self::LOG_FILE_PREFIX . "debug-{$file_token}.log"; // ex. content-control-debug-5c2f6a9b9b5a3.log.
202 $this->file = trailingslashit( $upload_dir['basedir'] ) . $this->filename;
203
204 if ( ! $file_system->exists( $this->file ) ) {
205 $this->setup_new_log();
206 } else {
207 $this->content = $this->get_file( $this->file );
208 }
209
210 // Truncate long log files.
211 if ( $file_system->exists( $this->file ) && $file_system->size( $this->file ) >= 1048576 ) {
212 $this->truncate_log();
213 }
214 }
215
216 /**
217 * Get the log file path.
218 *
219 * @return string
220 */
221 public function get_file_path() {
222 return $this->file;
223 }
224
225 /**
226 * Retrieves the url to the file
227 *
228 * @return string|bool The url to the file or false on failure
229 */
230 public function get_file_url() {
231 if ( ! $this->enabled() ) {
232 return false;
233 }
234
235 return $this->get_upload_dir_url( $this->filename );
236 }
237
238 /**
239 * Retrieve the log data
240 *
241 * @return false|string
242 */
243 public function get_log() {
244 return $this->get_log_content();
245 }
246
247 /**
248 * Delete the log file and token.
249 *
250 * @return void
251 */
252 public function delete_logs() {
253 $file_system = $this->fs();
254
255 if ( false === $file_system ) {
256 return;
257 }
258
259 $file_system->delete( $this->file );
260 \delete_option( 'content_control_debug_log_token' );
261 }
262
263 /**
264 * Log message to file
265 *
266 * @param string $message The message to log.
267 *
268 * @return void
269 */
270 public function log( $message = '' ) {
271 $this->write_to_log( wp_date( 'Y-n-d H:i:s' ) . ' - ' . $message );
272 }
273
274 /**
275 * Log unique message to file.
276 *
277 * @param string $message The unique message to log.
278 *
279 * @return void
280 */
281 public function log_unique( $message = '' ) {
282 $contents = $this->get_log_content();
283
284 if ( strpos( $contents, $message ) !== false ) {
285 return;
286 }
287
288 $this->log( $message );
289 }
290
291 /**
292 * Get the log file contents.
293 *
294 * @return false|string
295 */
296 public function get_log_content() {
297 if ( ! isset( $this->content ) ) {
298 $this->content = $this->get_file();
299 }
300
301 return $this->content;
302 }
303
304 /**
305 * Set the log file contents in memory.
306 *
307 * @param mixed $content The content to set.
308 * @param bool $save Whether to save the content to the file immediately.
309 * @return void
310 */
311 private function set_log_content( $content, $save = false ) {
312 $this->content = $content;
313
314 if ( $save ) {
315 $this->save_logs();
316 }
317 }
318
319 /**
320 * Retrieve the contents of a file.
321 *
322 * @param string|boolean $file File to get contents of.
323 *
324 * @return false|string
325 */
326 protected function get_file( $file = false ) {
327 $file = $file ? $file : $this->file;
328
329 $file_system = $this->fs();
330
331 if ( false === $file_system || ! $this->enabled() ) {
332 return '';
333 }
334
335 $content = '';
336
337 if ( $file_system->exists( $file ) ) {
338 $content = $file_system->get_contents( $file );
339 }
340
341 return $content;
342 }
343
344 /**
345 * Write the log message
346 *
347 * @param string $message The message to write.
348 *
349 * @return void
350 */
351 protected function write_to_log( $message = '' ) {
352 if ( ! $this->enabled() ) {
353 return;
354 }
355
356 $contents = $this->get_log_content();
357
358 // If it doesn't end with a new line, add one. \r\n length is 2.
359 if ( substr( $contents, -2 ) !== "\r\n" ) {
360 $contents .= "\r\n";
361 }
362
363 $this->set_log_content( $contents . $message );
364 }
365
366 /**
367 * Save the current contents to file.
368 *
369 * @return void
370 */
371 public function save_logs() {
372 $file_system = $this->fs();
373
374 if ( false === $file_system || ! $this->enabled() ) {
375 return;
376 }
377
378 $file_system->put_contents( $this->file, $this->content, FS_CHMOD_FILE );
379 }
380
381 /**
382 * Get a line count.
383 *
384 * @return int
385 */
386 public function count_lines() {
387 $file = $this->get_log_content();
388 $lines = explode( "\r\n", $file );
389
390 return count( $lines );
391 }
392
393 /**
394 * Truncates a log file to maximum of 250 lines.
395 *
396 * @return void
397 */
398 public function truncate_log() {
399 $content = $this->get_log_content();
400 $lines = explode( "\r\n", $content );
401 $lines = array_slice( $lines, 0, 250 ); // 50 is how many lines you want to keep
402 $truncated_content = implode( "\r\n", $lines );
403 $this->set_log_content( $truncated_content, true );
404 }
405
406 /**
407 * Set up a new log file.
408 *
409 * @return void
410 */
411 public function setup_new_log() {
412 $this->set_log_content( "Content Control Debug Logs:\r\n" . wp_date( 'Y-n-d H:i:s' ) . " - Log file initialized\r\n", true );
413 }
414
415 /**
416 * Delete the log file.
417 *
418 * @return void
419 */
420 public function clear_log() {
421 $file_system = $this->fs();
422
423 if ( false === $file_system ) {
424 return;
425 }
426
427 // Delete the file.
428 // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
429 @$file_system->delete( $this->file );
430
431 if ( $this->enabled() ) {
432 $this->setup_new_log();
433 }
434 }
435
436 /**
437 * Log a deprecated notice.
438 *
439 * @param string $func_name Function name.
440 * @param string $version Versoin deprecated.
441 * @param string $replacement Replacement function (optional).
442 *
443 * @return void
444 */
445 public function log_deprecated_notice( $func_name, $version, $replacement = null ) {
446 if ( ! is_null( $replacement ) ) {
447 $notice = sprintf( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.', $func_name, $version, $replacement );
448 } else {
449 $notice = sprintf( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.', $func_name, $version );
450 }
451
452 $this->log_unique( $notice );
453 }
454 }
455