PluginProbe
Stream – Activity Log & Audit Trail / 3.0.4
Stream – Activity Log & Audit Trail v3.0.4
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.4, at classes/class-log.php

311 lines 10.2 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 if ( is_null( $user_id ) ) {
47 $user_id = get_current_user_id();
48 }
49
50 if ( is_null( $object_id ) ) {
51 $object_id = 0;
52 }
53
54 $wp_cron_tracking = isset( $this->plugin->settings->options['advanced_wp_cron_tracking'] ) ? $this->plugin->settings->options['advanced_wp_cron_tracking'] : false;
55 $author = new Author( $user_id );
56 $agent = $author->get_current_agent();
57
58 // WP Cron tracking requires opt-in and WP Cron to be enabled
59 if ( ! $wp_cron_tracking && 'wp_cron' === $agent ) {
60 return false;
61 }
62
63 $user = new \WP_User( $user_id );
64
65 if ( $this->is_record_excluded( $connector, $context, $action, $user ) ) {
66 return false;
67 }
68
69 $user_meta = array(
70 'user_email' => (string) ! empty( $user->user_email ) ? $user->user_email : '',
71 'display_name' => (string) $author->get_display_name(),
72 'user_login' => (string) ! empty( $user->user_login ) ? $user->user_login : '',
73 'user_role_label' => (string) $author->get_role(),
74 'agent' => (string) $agent,
75 );
76
77 if ( 'wp_cli' === $agent && function_exists( 'posix_getuid' ) ) {
78 $uid = posix_getuid();
79 $user_info = posix_getpwuid( $uid );
80
81 $user_meta['system_user_id'] = (int) $uid;
82 $user_meta['system_user_name'] = (string) $user_info['name'];
83 }
84
85 // Prevent any meta with null values from being logged
86 $stream_meta = array_filter(
87 $args,
88 function( $var ) {
89 return ! is_null( $var );
90 }
91 );
92
93 // Add user meta to Stream meta
94 $stream_meta['user_meta'] = $user_meta;
95
96 // All meta must be strings, so we will serialize any array meta values
97 array_walk(
98 $stream_meta,
99 function( &$v ) {
100 $v = (string) maybe_serialize( $v );
101 }
102 );
103
104 // Get the current time in milliseconds
105 $iso_8601_extended_date = wp_stream_get_iso_8601_extended_date();
106
107 $recordarr = array(
108 'object_id' => (int) $object_id,
109 'site_id' => (int) is_multisite() ? get_current_site()->id : 1,
110 'blog_id' => (int) apply_filters( 'wp_stream_blog_id_logged', get_current_blog_id() ),
111 'user_id' => (int) $user_id,
112 'user_role' => (string) ! empty( $user->roles ) ? $user->roles[0] : '',
113 'created' => (string) $iso_8601_extended_date,
114 'summary' => (string) vsprintf( $message, $args ),
115 'connector' => (string) $connector,
116 'context' => (string) $context,
117 'action' => (string) $action,
118 'ip' => (string) wp_stream_filter_input( INPUT_SERVER, 'REMOTE_ADDR', FILTER_VALIDATE_IP ),
119 'meta' => (array) $stream_meta,
120 );
121
122 if ( 0 === $recordarr['object_id'] ) {
123 unset( $recordarr['object_id'] );
124 }
125
126 $result = $this->plugin->db->insert( $recordarr );
127
128 $this->debug_backtrace( $recordarr );
129
130 return $result;
131 }
132
133 /**
134 * This function is use to check whether or not a record should be excluded from the log
135 *
136 * @param string $connector Name of the connector being logged
137 * @param string $context Name of the context being logged
138 * @param string $action Name of the action being logged
139 * @param \WP_User $user The user being logged
140 * @param string $ip IP address being logged
141 *
142 * @return bool
143 */
144 public function is_record_excluded( $connector, $context, $action, $user = null, $ip = null ) {
145 if ( is_null( $user ) ) {
146 $user = wp_get_current_user();
147 }
148
149 if ( is_null( $ip ) ) {
150 $ip = wp_stream_filter_input( INPUT_SERVER, 'REMOTE_ADDR', FILTER_VALIDATE_IP );
151 } else {
152 $ip = wp_stream_filter_var( $ip, FILTER_VALIDATE_IP );
153 }
154
155 $user_role = isset( $user->roles[0] ) ? $user->roles[0] : null;
156
157 $record = array(
158 'connector' => $connector,
159 'context' => $context,
160 'action' => $action,
161 'author' => $user->ID,
162 'role' => $user_role,
163 'ip_address' => $ip,
164 );
165
166 $exclude_settings = isset( $this->plugin->settings->options['exclude_rules'] ) ? $this->plugin->settings->options['exclude_rules'] : array();
167
168 if ( is_multisite() && is_plugin_active_for_network( $this->plugin->locations['plugin'] ) && ! is_network_admin() ) {
169 $multisite_options = (array) get_site_option( 'wp_stream_network', array() );
170 $multisite_exclude_settings = isset( $multisite_options['exclude_rules'] ) ? $multisite_options['exclude_rules'] : array();
171
172 if ( ! empty( $multisite_exclude_settings ) ) {
173 foreach ( $multisite_exclude_settings['exclude_row'] as $key => $rule ) {
174 $exclude_settings['exclude_row'][] = $multisite_exclude_settings['exclude_row'][ $key ];
175 $exclude_settings['author_or_role'][] = $multisite_exclude_settings['author_or_role'][ $key ];
176 $exclude_settings['connector'][] = $multisite_exclude_settings['connector'][ $key ];
177 $exclude_settings['context'][] = $multisite_exclude_settings['context'][ $key ];
178 $exclude_settings['action'][] = $multisite_exclude_settings['action'][ $key ];
179 $exclude_settings['ip_address'][] = $multisite_exclude_settings['ip_address'][ $key ];
180 }
181 }
182 }
183
184 if ( isset( $exclude_settings['exclude_row'] ) && ! empty( $exclude_settings['exclude_row'] ) ) {
185 foreach ( $exclude_settings['exclude_row'] as $key => $value ) {
186 // Prepare values
187 $author_or_role = isset( $exclude_settings['author_or_role'][ $key ] ) ? $exclude_settings['author_or_role'][ $key ] : '';
188 $connector = isset( $exclude_settings['connector'][ $key ] ) ? $exclude_settings['connector'][ $key ] : '';
189 $context = isset( $exclude_settings['context'][ $key ] ) ? $exclude_settings['context'][ $key ] : '';
190 $action = isset( $exclude_settings['action'][ $key ] ) ? $exclude_settings['action'][ $key ] : '';
191 $ip_address = isset( $exclude_settings['ip_address'][ $key ] ) ? $exclude_settings['ip_address'][ $key ] : '';
192
193 $exclude = array(
194 'connector' => ! empty( $connector ) ? $connector : null,
195 'context' => ! empty( $context ) ? $context : null,
196 'action' => ! empty( $action ) ? $action : null,
197 'ip_address' => ! empty( $ip_address ) ? $ip_address : null,
198 'author' => is_numeric( $author_or_role ) ? absint( $author_or_role ) : null,
199 'role' => ( ! empty( $author_or_role ) && ! is_numeric( $author_or_role ) ) ? $author_or_role : null,
200 );
201
202 $exclude_rules = array_filter( $exclude, 'strlen' );
203
204 if ( ! empty( $exclude_rules ) ) {
205 $excluded = true;
206
207 foreach ( $exclude_rules as $exclude_key => $exclude_value ) {
208 if ( $record[ $exclude_key ] !== $exclude_value ) {
209 $excluded = false;
210 break;
211 }
212 }
213
214 if ( $excluded ) {
215 return true;
216 }
217 }
218 }
219 }
220
221 return false;
222 }
223
224 /**
225 * Send a full backtrace of calls to the PHP error log for debugging
226 *
227 * @param array $recordarr
228 *
229 * @return void
230 */
231 public function debug_backtrace( $recordarr ) {
232 /**
233 * Enable debug backtrace on records.
234 *
235 * This filter is for developer use only. When enabled, Stream will send
236 * a full debug backtrace of PHP calls for each record. Optionally, you may
237 * use the available $recordarr parameter to specify what types of records to
238 * create backtrace logs for.
239 *
240 * @param array $recordarr
241 *
242 * @return bool Set to FALSE by default (backtrace disabled)
243 */
244 $enabled = apply_filters( 'wp_stream_debug_backtrace', false, $recordarr );
245
246 if ( ! $enabled ) {
247 return;
248 }
249
250 if ( version_compare( PHP_VERSION, '5.3.6', '<' ) ) {
251 error_log( 'WP Stream debug backtrace requires at least PHP 5.3.6' );
252 return;
253 }
254
255 // Record details
256 $summary = isset( $recordarr['summary'] ) ? $recordarr['summary'] : null;
257 $author = isset( $recordarr['author'] ) ? $recordarr['author'] : null;
258 $connector = isset( $recordarr['connector'] ) ? $recordarr['connector'] : null;
259 $context = isset( $recordarr['context'] ) ? $recordarr['context'] : null;
260 $action = isset( $recordarr['action'] ) ? $recordarr['action'] : null;
261
262 // Stream meta
263 $stream_meta = isset( $recordarr['meta'] ) ? $recordarr['meta'] : null;
264
265 unset( $stream_meta['user_meta'] );
266
267 if ( $stream_meta ) {
268 array_walk( $stream_meta, function( &$value, $key ) {
269 $value = sprintf( '%s: %s', $key, ( '' === $value ) ? 'null' : $value );
270 });
271
272 $stream_meta = implode( ', ', $stream_meta );
273 }
274
275 // User meta
276 $user_meta = isset( $recordarr['meta']['user_meta'] ) ? $recordarr['meta']['user_meta'] : null;
277
278 if ( $user_meta ) {
279 array_walk( $user_meta, function( &$value, $key ) {
280 $value = sprintf( '%s: %s', $key, ( '' === $value ) ? 'null' : $value );
281 });
282
283 $user_meta = implode( ', ', $user_meta );
284 }
285
286 // Debug backtrace
287 ob_start();
288
289 // @codingStandardsIgnoreStart
290 debug_print_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS ); // Option to ignore args requires PHP 5.3.6
291 // @codingStandardsIgnoreEnd
292
293 $backtrace = ob_get_clean();
294 $backtrace = array_values( array_filter( explode( "\n", $backtrace ) ) );
295
296 $output = sprintf(
297 "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",
298 $summary,
299 $author,
300 $connector,
301 $context,
302 $action,
303 $stream_meta,
304 $user_meta,
305 implode( "\n", $backtrace )
306 );
307
308 error_log( $output );
309 }
310 }
311