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

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