PluginProbe
Stream – Activity Log & Audit Trail / 3.0.6
Stream – Activity Log & Audit Trail v3.0.6
4.4.0 4.3.0 4.2.2 4.2.1 trunk 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.1 3.1.1 3.10.0 3.2.0 3.2.1 3.2.2 3.2.3 All 50 releases
stream / classes / class-log.php

class-log.php in Stream – Activity Log & Audit Trail 3.0.6, at classes/class-log.php

326 lines 10.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace WP_Stream;
3
4 class Log {
5 /**
6 * Hold Plugin class
7 * @var Plugin
8 */
9 public $plugin;
10
11 /**
12 * Previous Stream record ID, used for chaining same-session records
13 *
14 * @var int
15 */
16 private $prev_record;
17
18 /**
19 * Class constructor.
20 *
21 * @param Plugin $plugin The main Plugin class.
22 */
23 public function __construct( $plugin ) {
24 $this->plugin = $plugin;
25
26 // Ensure function used in various methods is pre-loaded
27 if ( ! function_exists( 'is_plugin_active_for_network' ) ) {
28 require_once( ABSPATH . '/wp-admin/includes/plugin.php' );
29 }
30 }
31
32 /**
33 * Log handler
34 *
35 * @param Connector $connector Connector responsible for logging the event
36 * @param string $message sprintf-ready error message string
37 * @param array $args sprintf (and extra) arguments to use
38 * @param int $object_id Target object id
39 * @param string $context Context of the event
40 * @param string $action Action of the event
41 * @param int $user_id User responsible for the event
42 *
43 * @return mixed True if updated, otherwise false|WP_Error
44 */
45 public function log( $connector, $message, $args, $object_id, $context, $action, $user_id = null ) {
46 global $wp_roles;
47
48 if ( is_null( $user_id ) ) {
49 $user_id = get_current_user_id();
50 }
51
52 if ( is_null( $object_id ) ) {
53 $object_id = 0;
54 }
55
56 $wp_cron_tracking = isset( $this->plugin->settings->options['advanced_wp_cron_tracking'] ) ? $this->plugin->settings->options['advanced_wp_cron_tracking'] : false;
57 $author = new Author( $user_id );
58 $agent = $author->get_current_agent();
59
60 // WP Cron tracking requires opt-in and WP Cron to be enabled
61 if ( ! $wp_cron_tracking && 'wp_cron' === $agent ) {
62 return false;
63 }
64
65 $user = new \WP_User( $user_id );
66
67 if ( $this->is_record_excluded( $connector, $context, $action, $user ) ) {
68 return false;
69 }
70
71 $user_meta = array(
72 'user_email' => (string) ! empty( $user->user_email ) ? $user->user_email : '',
73 'display_name' => (string) $author->get_display_name(),
74 'user_login' => (string) ! empty( $user->user_login ) ? $user->user_login : '',
75 'user_role_label' => (string) $author->get_role(),
76 'agent' => (string) $agent,
77 );
78
79 if ( 'wp_cli' === $agent && function_exists( 'posix_getuid' ) ) {
80 $uid = posix_getuid();
81 $user_info = posix_getpwuid( $uid );
82
83 $user_meta['system_user_id'] = (int) $uid;
84 $user_meta['system_user_name'] = (string) $user_info['name'];
85 }
86
87 // Prevent any meta with null values from being logged
88 $stream_meta = array_filter(
89 $args,
90 function( $var ) {
91 return ! is_null( $var );
92 }
93 );
94
95 // Add user meta to Stream meta
96 $stream_meta['user_meta'] = $user_meta;
97
98 // All meta must be strings, so we will serialize any array meta values
99 array_walk(
100 $stream_meta,
101 function( &$v ) {
102 $v = (string) maybe_serialize( $v );
103 }
104 );
105
106 // Get the current time in milliseconds
107 $iso_8601_extended_date = wp_stream_get_iso_8601_extended_date();
108
109 if ( ! empty( $user->roles ) ) {
110 $roles = array_values( $user->roles );
111 $role = $roles[0];
112 } elseif ( is_multisite() && is_super_admin() && $wp_roles->is_role( 'administrator' ) ) {
113 $role = 'administrator';
114 } else {
115 $role = '';
116 }
117
118 $recordarr = array(
119 'object_id' => (int) $object_id,
120 'site_id' => (int) is_multisite() ? get_current_site()->id : 1,
121 'blog_id' => (int) apply_filters( 'wp_stream_blog_id_logged', get_current_blog_id() ),
122 'user_id' => (int) $user_id,
123 'user_role' => (string) $role,
124 'created' => (string) $iso_8601_extended_date,
125 'summary' => (string) vsprintf( $message, $args ),
126 'connector' => (string) $connector,
127 'context' => (string) $context,
128 'action' => (string) $action,
129 'ip' => (string) wp_stream_filter_input( INPUT_SERVER, 'REMOTE_ADDR', FILTER_VALIDATE_IP ),
130 'meta' => (array) $stream_meta,
131 );
132
133 if ( 0 === $recordarr['object_id'] ) {
134 unset( $recordarr['object_id'] );
135 }
136
137 $result = $this->plugin->db->insert( $recordarr );
138
139 $this->debug_backtrace( $recordarr );
140
141 return $result;
142 }
143
144 /**
145 * This function is use to check whether or not a record should be excluded from the log
146 *
147 * @param string $connector Name of the connector being logged
148 * @param string $context Name of the context being logged
149 * @param string $action Name of the action being logged
150 * @param \WP_User $user The user being logged
151 * @param string $ip IP address being logged
152 *
153 * @return bool
154 */
155 public function is_record_excluded( $connector, $context, $action, $user = null, $ip = null ) {
156 if ( is_null( $user ) ) {
157 $user = wp_get_current_user();
158 }
159
160 if ( is_null( $ip ) ) {
161 $ip = wp_stream_filter_input( INPUT_SERVER, 'REMOTE_ADDR', FILTER_VALIDATE_IP );
162 } else {
163 $ip = wp_stream_filter_var( $ip, FILTER_VALIDATE_IP );
164 }
165
166 if ( ! empty( $user->roles ) ) {
167 $roles = array_values( $user->roles );
168 $role = $roles[0];
169 } else {
170 $role = '';
171 }
172 $record = array(
173 'connector' => $connector,
174 'context' => $context,
175 'action' => $action,
176 'author' => $user->ID,
177 'role' => $role,
178 'ip_address' => $ip,
179 );
180
181 $exclude_settings = isset( $this->plugin->settings->options['exclude_rules'] ) ? $this->plugin->settings->options['exclude_rules'] : array();
182
183 if ( is_multisite() && is_plugin_active_for_network( $this->plugin->locations['plugin'] ) && ! is_network_admin() ) {
184 $multisite_options = (array) get_site_option( 'wp_stream_network', array() );
185 $multisite_exclude_settings = isset( $multisite_options['exclude_rules'] ) ? $multisite_options['exclude_rules'] : array();
186
187 if ( ! empty( $multisite_exclude_settings ) ) {
188 foreach ( $multisite_exclude_settings['exclude_row'] as $key => $rule ) {
189 $exclude_settings['exclude_row'][] = $multisite_exclude_settings['exclude_row'][ $key ];
190 $exclude_settings['author_or_role'][] = $multisite_exclude_settings['author_or_role'][ $key ];
191 $exclude_settings['connector'][] = $multisite_exclude_settings['connector'][ $key ];
192 $exclude_settings['context'][] = $multisite_exclude_settings['context'][ $key ];
193 $exclude_settings['action'][] = $multisite_exclude_settings['action'][ $key ];
194 $exclude_settings['ip_address'][] = $multisite_exclude_settings['ip_address'][ $key ];
195 }
196 }
197 }
198
199 if ( isset( $exclude_settings['exclude_row'] ) && ! empty( $exclude_settings['exclude_row'] ) ) {
200 foreach ( $exclude_settings['exclude_row'] as $key => $value ) {
201 // Prepare values
202 $author_or_role = isset( $exclude_settings['author_or_role'][ $key ] ) ? $exclude_settings['author_or_role'][ $key ] : '';
203 $connector = isset( $exclude_settings['connector'][ $key ] ) ? $exclude_settings['connector'][ $key ] : '';
204 $context = isset( $exclude_settings['context'][ $key ] ) ? $exclude_settings['context'][ $key ] : '';
205 $action = isset( $exclude_settings['action'][ $key ] ) ? $exclude_settings['action'][ $key ] : '';
206 $ip_address = isset( $exclude_settings['ip_address'][ $key ] ) ? $exclude_settings['ip_address'][ $key ] : '';
207
208 $exclude = array(
209 'connector' => ! empty( $connector ) ? $connector : null,
210 'context' => ! empty( $context ) ? $context : null,
211 'action' => ! empty( $action ) ? $action : null,
212 'ip_address' => ! empty( $ip_address ) ? $ip_address : null,
213 'author' => is_numeric( $author_or_role ) ? absint( $author_or_role ) : null,
214 'role' => ( ! empty( $author_or_role ) && ! is_numeric( $author_or_role ) ) ? $author_or_role : null,
215 );
216
217 $exclude_rules = array_filter( $exclude, 'strlen' );
218
219 if ( ! empty( $exclude_rules ) ) {
220 $excluded = true;
221
222 foreach ( $exclude_rules as $exclude_key => $exclude_value ) {
223 if ( $record[ $exclude_key ] !== $exclude_value ) {
224 $excluded = false;
225 break;
226 }
227 }
228
229 if ( $excluded ) {
230 return true;
231 }
232 }
233 }
234 }
235
236 return false;
237 }
238
239 /**
240 * Send a full backtrace of calls to the PHP error log for debugging
241 *
242 * @param array $recordarr
243 *
244 * @return void
245 */
246 public function debug_backtrace( $recordarr ) {
247 /**
248 * Enable debug backtrace on records.
249 *
250 * This filter is for developer use only. When enabled, Stream will send
251 * a full debug backtrace of PHP calls for each record. Optionally, you may
252 * use the available $recordarr parameter to specify what types of records to
253 * create backtrace logs for.
254 *
255 * @param array $recordarr
256 *
257 * @return bool Set to FALSE by default (backtrace disabled)
258 */
259 $enabled = apply_filters( 'wp_stream_debug_backtrace', false, $recordarr );
260
261 if ( ! $enabled ) {
262 return;
263 }
264
265 if ( version_compare( PHP_VERSION, '5.3.6', '<' ) ) {
266 error_log( 'WP Stream debug backtrace requires at least PHP 5.3.6' );
267 return;
268 }
269
270 // Record details
271 $summary = isset( $recordarr['summary'] ) ? $recordarr['summary'] : null;
272 $author = isset( $recordarr['author'] ) ? $recordarr['author'] : null;
273 $connector = isset( $recordarr['connector'] ) ? $recordarr['connector'] : null;
274 $context = isset( $recordarr['context'] ) ? $recordarr['context'] : null;
275 $action = isset( $recordarr['action'] ) ? $recordarr['action'] : null;
276
277 // Stream meta
278 $stream_meta = isset( $recordarr['meta'] ) ? $recordarr['meta'] : null;
279
280 unset( $stream_meta['user_meta'] );
281
282 if ( $stream_meta ) {
283 array_walk( $stream_meta, function( &$value, $key ) {
284 $value = sprintf( '%s: %s', $key, ( '' === $value ) ? 'null' : $value );
285 });
286
287 $stream_meta = implode( ', ', $stream_meta );
288 }
289
290 // User meta
291 $user_meta = isset( $recordarr['meta']['user_meta'] ) ? $recordarr['meta']['user_meta'] : null;
292
293 if ( $user_meta ) {
294 array_walk( $user_meta, function( &$value, $key ) {
295 $value = sprintf( '%s: %s', $key, ( '' === $value ) ? 'null' : $value );
296 });
297
298 $user_meta = implode( ', ', $user_meta );
299 }
300
301 // Debug backtrace
302 ob_start();
303
304 // @codingStandardsIgnoreStart
305 debug_print_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS ); // Option to ignore args requires PHP 5.3.6
306 // @codingStandardsIgnoreEnd
307
308 $backtrace = ob_get_clean();
309 $backtrace = array_values( array_filter( explode( "\n", $backtrace ) ) );
310
311 $output = sprintf(
312 "WP Stream Debug Backtrace\n\n Summary | %s\n Author | %s\n Connector | %s\n Context | %s\n Action | %s\nStream Meta | %s\nAuthor Meta | %s\n\n%s\n",
313 $summary,
314 $author,
315 $connector,
316 $context,
317 $action,
318 $stream_meta,
319 $user_meta,
320 implode( "\n", $backtrace )
321 );
322
323 error_log( $output );
324 }
325 }
326