PluginProbe
Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization / 3.11.2
Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization v3.11.2
4.2.13 4.2.12 4.2.11 4.2.10 4.2.9 4.2.8 4.2.7 4.2.6 4.2.5 2.5.5 2.5.6 2.5.7 3.0.0 3.0.1 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.11.0 3.11.1 3.11.2 3.11.3 3.12.0 3.12.1 All 134 releases
optimole-wp / inc / logger.php

logger.php in Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization 3.11.2, at inc/logger.php

255 lines 6.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class Optml_Logger
4 * Handles the logging operations.
5 */
6 class Optml_Logger {
7
8 const LOG_TYPE_OFFLOAD = 'offload';
9 const LOG_TYPE_ROLLBACK = 'rollback';
10
11 const LOG_SEPARATOR = '==========';
12
13 /**
14 * Upload directory.
15 *
16 * @var string
17 */
18 private $upload_dir;
19
20 /**
21 * Log filenames.
22 *
23 * @var array
24 */
25 private $log_filenames = [
26 self::LOG_TYPE_OFFLOAD => 'offload.log',
27 self::LOG_TYPE_ROLLBACK => 'rollback.log',
28 ];
29
30 /**
31 * The single instance of the class.
32 *
33 * @var Optml_Logger
34 */
35 private static $instance = null;
36
37 /**
38 * Ensures only one instance of the class is loaded.
39 *
40 * @return Optml_Logger An instance of the class.
41 */
42 public static function instance() {
43 if ( null === self::$instance ) {
44 self::$instance = new self();
45 }
46
47 return self::$instance;
48 }
49
50 /**
51 * Optml_Logger constructor.
52 * Initializes the upload directory.
53 *
54 * @return void
55 */
56 private function __construct() {
57 $upload_dir = wp_upload_dir();
58 $this->upload_dir = trailingslashit( $upload_dir['basedir'] ) . 'optimole-logs/';
59
60 if ( ! file_exists( $this->upload_dir ) ) {
61 if ( false === wp_mkdir_p( $this->upload_dir ) ) {
62 return;
63 }
64 }
65
66 add_action( 'wp_ajax_optml_fetch_logs', [ $this, 'fetch_logs_ajax_handler' ] );
67 }
68
69 /**
70 * Adds a log entry.
71 *
72 * @param string $type Type of log (offload/rollback).
73 * @param string $message Log message.
74 * @return bool Returns true on success, false on failure.
75 */
76 public function add_log( $type, $message ) {
77 if ( ! array_key_exists( $type, $this->log_filenames ) ) {
78 return false;
79 }
80
81 $this->send_log( $type, $message );
82
83 if ( ! $this->has_permission() ) {
84 return false;
85 }
86
87 $file_path = $this->upload_dir . $this->log_filenames[ $type ];
88 $handle = @fopen( $file_path, 'a' );
89
90 if ( $handle === false ) {
91 return false;
92 }
93
94 fwrite( $handle, '[' . gmdate( 'M d H:i:s' ) . '] ' . $message . "\n" );
95 fclose( $handle );
96 return true;
97 }
98
99 /**
100 * Retrieves the log.
101 *
102 * @param string $type Type of log (offload/rollback).
103 * @param int $lines Number of lines to return from the end of the log file.
104 * @param string $separator Separator line to start retrieving log entries from.
105 *
106 * @return false|string Returns log data or false on failure.
107 */
108 public function get_log( $type, $lines = 500, $separator = '' ) {
109 if ( ! array_key_exists( $type, $this->log_filenames ) ) {
110 return false;
111 }
112
113 $file_path = $this->upload_dir . $this->log_filenames[ $type ];
114
115 if ( $this->has_logs( $type ) ) {
116 $data = $this->tailCustom( $file_path, $lines, true, $separator );
117 return nl2br( esc_textarea( $data ) );
118 }
119
120 return false;
121 }
122
123 /**
124 * Checks if the log file exists.
125 *
126 * @param string $type Type of log (offload/rollback).
127 * @return bool Returns true if log file exists, false otherwise.
128 */
129 public function has_logs( $type ) {
130 if ( ! array_key_exists( $type, $this->log_filenames ) ) {
131 return false;
132 }
133
134 $file_path = $this->upload_dir . $this->log_filenames[ $type ];
135 return file_exists( $file_path );
136 }
137
138 /**
139 * Checks for permission to write to log file.
140 *
141 * @return bool Returns true if permission is granted, false otherwise.
142 */
143 public function has_permission() {
144 return is_writable( $this->upload_dir );
145 }
146
147 /**
148 * Reads the last n lines from a file, or from a specific point defined by a separator.
149 *
150 * @param string $filepath Path to the file.
151 * @param int $lines Number of lines to read from the end of the file.
152 * @param bool $adaptive Use adaptive buffers.
153 * @param string $separator Separator line to start retrieving log entries from.
154 * @return false|string Returns last n lines from the file or false on failure.
155 */
156 private function tailCustom( $filepath, $lines = 1, $adaptive = true, $separator = '' ) {
157 $f = @fopen( $filepath, 'rb' );
158
159 if ( $f === false ) {
160 return false;
161 }
162
163 if ( ! $adaptive ) {
164 $buffer = 4096;
165 } else {
166 $buffer = min( 64, filesize( $filepath ) );
167 }
168
169 fseek( $f, -1, SEEK_END );
170 $output = '';
171 $read = '';
172 $separator_found = false;
173
174 while ( $buffer > 0 && ftell( $f ) > 0 ) {
175 $seek = min( ftell( $f ), $buffer );
176 fseek( $f, -$seek, SEEK_CUR );
177 $output = ( $read = fread( $f, $seek ) ) . $output;
178 fseek( $f, -mb_strlen( $read, '8bit' ), SEEK_CUR );
179
180 if ( ! empty( $separator ) && strpos( $output, $separator ) !== false ) {
181 $separator_found = true;
182 break;
183 }
184
185 $buffer = min( $buffer * 2, 4096 );
186 }
187
188 if ( ! empty( $separator ) && $separator_found ) {
189 $pos = strrpos( $output, $separator );
190 if ( $pos !== false ) {
191 $output = substr( $output, $pos + strlen( $separator ) );
192 }
193 }
194
195 // Extract the desired number of lines
196 $output_lines = explode( "\n", $output );
197 if ( empty( $separator ) || ! $separator_found ) {
198 $output = implode( "\n", array_slice( $output_lines, -$lines ) ); // fetch last n lines
199 } else {
200 $output = implode( "\n", array_slice( $output_lines, 0, $lines ) ); // fetch from separator
201 }
202
203 fclose( $f );
204 return trim( $output );
205 }
206
207 /**
208 * Fetches the logs via AJAX.
209 *
210 * @return void
211 */
212 public function fetch_logs_ajax_handler() {
213 // Check for nonce security
214 $nonce = $_REQUEST['nonce'];
215 if ( ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
216 wp_die( __( 'Security check failed', 'optimole-wp' ) );
217 }
218
219 // Check for necessary parameters
220 if ( ! isset( $_REQUEST['type'] ) || ! in_array( $_REQUEST['type'], array_keys( $this->log_filenames ), true ) ) {
221 wp_die( __( 'Invalid log type', 'optimole-wp' ) );
222 }
223
224 $lines = 10000;
225
226 if ( isset( $_REQUEST['lines'] ) ) {
227 $lines = intval( $_REQUEST['lines'] );
228 }
229
230 // Get log type
231 $type = $_REQUEST['type'];
232
233 // Fetch the logs
234 $logs = $this->get_log( $type, $lines, self::LOG_SEPARATOR );
235
236 // Return the logs
237 echo $logs;
238
239 wp_die();
240 }
241
242 /**
243 * Send logs to Axiom.
244 *
245 * @param string $type Type of log (offload/rollback).
246 * @param string $message Log message.
247
248 * @return void
249 */
250 public function send_log( $type, $message ) {
251 $request = new Optml_Api();
252 $request->send_log( $type, $message );
253 }
254 }
255