PluginProbe ʕ •ᴥ•ʔ
Superb Addons: Blocks, Patterns, Pre-built Pages, Sliders, Popups, Free Forms, Animations & More / 3.4.2
Superb Addons: Blocks, Patterns, Pre-built Pages, Sliders, Popups, Free Forms, Animations & More v3.4.2
4.0.6 4.0.5 4.0.4 4.0.3 4.0.2 4.0.1 4.0.0 trunk 1.0.0 2.0.0 2.0.1 2.0.2 2.0.3 3.0 3.0.1 3.0.2 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.2 3.1.3 3.2.0 3.2.1 3.2.2 3.2.4 3.2.5 3.2.7 3.2.8 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.4.5 3.4.6 3.5.0 3.5.1 3.5.2 3.5.3 3.5.4 3.5.6 3.5.7 3.5.8 3.5.9 3.6.0 3.6.1 3.6.2 3.7.0 3.7.1
superb-blocks / src / data / controllers / class-log-controller.php
superb-blocks / src / data / controllers Last commit date
class-cache-controller.php 1 year ago class-css-controller.php 1 year ago class-domainshift-controller.php 1 year ago class-key-controller.php 1 year ago class-log-controller.php 1 year ago class-option-controller.php 1 year ago class-rest-controller.php 1 year ago
class-log-controller.php
210 lines
1 <?php
2
3 namespace SuperbAddons\Data\Controllers;
4
5 defined('ABSPATH') || exit();
6
7 use Exception;
8
9 class LogController
10 {
11 const LOG_OPTION_KEY = 'superbaddons_errorlogs';
12 const LOG_MAX_ENTRIES = 50;
13
14 const CRON_SHARE_ERROR_LOGS = 'superbaddons_share_error_logs';
15 const SHARE_ENDPOINT = 'addons-status/logs/share';
16 const FEEDBACK_ENDPOINT = 'addons-status/feedback/share';
17
18 public static function GetLogs()
19 {
20 return get_option(self::LOG_OPTION_KEY, false);
21 }
22
23 public static function HandleException($exception)
24 {
25 try {
26 $settings = OptionController::GetSettings();
27 if (!$settings[SettingsOptionKey::LOGS_ENABLED]) {
28 return;
29 }
30
31 $exception_stack = array();
32 $trace = $exception->getTrace();
33 $code = $exception->getCode();
34 $message = $exception->getMessage();
35 $minimum_amount = 2;
36 $current_trace = 1;
37 $should_break_next = false;
38 foreach ($trace as $trace_item) {
39 $trace_class = $trace_item['class'] ?? 'Unknown Class';
40 // Remove ABSPATH from trace to anonymize and prevent including server path
41 $trace_item_string = sprintf("%s (%s): %s -> %s", str_replace(rtrim(ABSPATH, '/\\'), '', $trace_item['file'] ?? 'Unknown File'), $trace_item['line'] ?? '??', $trace_class, $trace_item['function'] ?? 'Unknown Function');
42
43 array_push($exception_stack, $trace_item_string);
44 if ($should_break_next) {
45 // Limit the number of traces to add to the stack
46 break;
47 }
48 if ($current_trace >= $minimum_amount && false === strpos($trace_class, "superb-blocks")) {
49 // Break after adding the next trace
50 $should_break_next = true;
51 }
52 $current_trace++;
53 }
54 $exception_stack = implode("\n\n", $exception_stack);
55
56 if ($code > 0) {
57 $message .= sprintf(" (Code: %d)", $code);
58 }
59
60 LogController::AddLog($message, $exception_stack);
61 } catch (Exception $ex) {
62 // do nothing if error log somehow fails
63 }
64 }
65
66 private static function AddLog($title, $stack)
67 {
68 try {
69 $logs = self::GetLogs();
70 if (!$logs) {
71 $logs = array();
72 }
73
74 $log_count = count($logs);
75 // add new log entry
76 if ($log_count >= self::LOG_MAX_ENTRIES) {
77 // slice to only allow max number of log entries
78 $logs = array_slice($logs, 1, self::LOG_MAX_ENTRIES);
79 }
80
81 if ($log_count >= 1 && isset($logs[$log_count - 1]['stack']) && $logs[$log_count - 1]['stack'] === $stack) {
82 // Don't add duplicate log entries
83 return;
84 }
85
86 array_push($logs, array(
87 "time" => time(),
88 "shared" => false,
89 "version" => sanitize_text_field(SUPERBADDONS_VERSION),
90 "title" => sanitize_text_field($title),
91 "stack" => sanitize_textarea_field($stack)
92 ));
93
94 update_option(self::LOG_OPTION_KEY, $logs, false);
95 } catch (Exception $e) {
96 // do nothing if error log somehow fails
97 }
98 }
99
100 public static function ClearLogs()
101 {
102 if (!self::GetLogs()) {
103 return true;
104 }
105
106 return delete_option(self::LOG_OPTION_KEY);
107 }
108
109 public static function AddCronAction()
110 {
111 add_action(self::CRON_SHARE_ERROR_LOGS, array(self::class, 'ShareErrorLogsCronEvent'));
112 }
113
114 public static function MaybeSubscribeCron()
115 {
116 if (!wp_next_scheduled(self::CRON_SHARE_ERROR_LOGS)) {
117 wp_schedule_event(time(), 'daily', self::CRON_SHARE_ERROR_LOGS);
118 }
119 }
120
121 public static function ShareErrorLogsCronEvent()
122 {
123 try {
124 $settings = OptionController::GetSettings();
125 if (!$settings[SettingsOptionKey::LOG_SHARE_ENABLED]) {
126 return;
127 }
128
129 $logs = self::GetLogs();
130 if (!$logs) {
131 return;
132 }
133
134 $logs_to_share = array();
135 foreach ($logs as $log) {
136 if (!$log['shared']) {
137 array_push($logs_to_share, $log);
138 }
139 }
140
141 if (count($logs_to_share) === 0) {
142 return;
143 }
144
145 $response = DomainShiftController::RemotePost(
146 self::SHARE_ENDPOINT,
147 array(
148 'headers' => array('Content-Type' => 'application/json'),
149 'method' => 'POST',
150 'body' => json_encode(
151 array(
152 'action' => 'share_error_logs',
153 'logs' => $logs_to_share
154 )
155 )
156 )
157 );
158 $status = wp_remote_retrieve_response_code($response);
159 if (!is_array($response) || is_wp_error($response) || $status !== 200) {
160 throw new Exception(sprintf(__("Error logs could not be shared. Status %d.", "superb-blocks"), $status));
161 }
162
163 foreach ($logs as &$log) {
164 $log['shared'] = true;
165 }
166
167 update_option(self::LOG_OPTION_KEY, $logs, false);
168 } catch (Exception $ex) {
169 self::HandleException($ex);
170 }
171 }
172
173 public static function SendFeedback($message)
174 {
175 if (strlen($message) > 1000) {
176 $message = substr($message, 0, 1000) . "...";
177 }
178 $response = DomainShiftController::RemotePost(
179 self::FEEDBACK_ENDPOINT,
180 array(
181 'headers' => array('Content-Type' => 'application/json'),
182 'method' => 'POST',
183 'body' => json_encode(
184 array(
185 'action' => 'share_feedback',
186 'feedback' => array(
187 'message' => sanitize_text_field($message),
188 "time" => time(),
189 "premium" => KeyController::HasValidPremiumKey(),
190 "version" => sanitize_text_field(SUPERBADDONS_VERSION),
191 )
192 )
193 )
194 )
195 );
196 $status = wp_remote_retrieve_response_code($response);
197 if (!is_array($response) || is_wp_error($response) || $status !== 200) {
198 throw new Exception(sprintf(__("Feedback could not be shared. Status %d.", "superb-blocks"), $status));
199 }
200 }
201
202 public static function MaybeUnsubscribeCron()
203 {
204 $timestamp = wp_next_scheduled(self::CRON_SHARE_ERROR_LOGS);
205 if ($timestamp) {
206 wp_unschedule_event($timestamp, self::CRON_SHARE_ERROR_LOGS);
207 }
208 }
209 }
210