| @@ -39,15 +39,19 @@ | ||
| 39 | 39 | * @param array $events Specific events to fetch. |
| 40 | 40 | * @param string $user_id User ID to filter logs. |
| 41 | 41 | * @param string $ip IP address to filter logs. |
| 42 | 42 | * @param int $paged Pagination page number. |
| 43 | + * @param int $per_page Number of logs per page. | |
| 43 | 44 | * |
| 44 | 45 | * @return Audit_Log[]|WP_Error Returns an array of Audit_Log objects or WP_Error on failure. |
| 45 | 46 | * @throws Exception Throws exception on failure. |
| 46 | 47 | */ |
| 47 | - public function fetch( $date_from, $date_to, $events = array(), $user_id = '', $ip = '', $paged = 1 ) { | |
| 48 | - $internal = Audit_Log::query( $date_from, $date_to, $events, $user_id, $ip, $paged ); | |
| 48 | + public function fetch( $date_from, $date_to, $events = array(), $user_id = '', $ip = '', $paged = 1, $per_page = 10 ) { | |
| 49 | + $internal = Audit_Log::query( $date_from, $date_to, $events, $user_id, $ip, $paged, $per_page ); | |
| 49 | 50 | $this->log( sprintf( 'Found %s from local', count( $internal ) ), self::AUDIT_LOG ); |
| 51 | + if ( ! wd_di()->get( WPMUDEV::class )->is_pro() ) { | |
| 52 | + return $internal; | |
| 53 | + } | |
| 50 | 54 | $checkpoint = get_site_option( self::CACHE_LAST_CHECKPOINT ); |
| 51 | 55 | if ( false === $checkpoint ) { |
| 52 | 56 | // This case where user install the plugin, have some local data but never reach to Logs page, then check point will be today. |
| 53 | 57 | $checkpoint = time(); |
| @@ -67,9 +71,9 @@ | ||
| 67 | 71 | if ( count( $cloud ) ) { |
| 68 | 72 | // No data from cloud too. |
| 69 | 73 | Audit_Log::mass_insert( $cloud ); |
| 70 | 74 | // Because this is roughly fetch, so we have to filter out again using the local data. |
| 71 | - $internal = Audit_Log::query( $date_from, $date_to, $events, $user_id, $ip, $paged ); | |
| 75 | + $internal = Audit_Log::query( $date_from, $date_to, $events, $user_id, $ip, $paged, $per_page ); | |
| 72 | 76 | } |
| 73 | 77 | // Cache the last time fetch, this will be useful in case of mixed data. |
| 74 | 78 | update_site_option( self::CACHE_LAST_CHECKPOINT, $date_from ); |
| 75 | 79 | // This case we have the data, however, maybe it can be out of the cached range, so we have to check. |
| @@ -92,9 +96,9 @@ | ||
| 92 | 96 | } |
| 93 | 97 | if ( is_array( $cloud ) ) { |
| 94 | 98 | // Silence the error here, as we actually have data. |
| 95 | 99 | Audit_Log::mass_insert( $cloud ); |
| 96 | - $internal = Audit_Log::query( $date_from, $date_to, $events, $user_id, $ip, $paged ); | |
| 100 | + $internal = Audit_Log::query( $date_from, $date_to, $events, $user_id, $ip, $paged, $per_page ); | |
| 97 | 101 | // Cache the last time fetch, this will be useful in case of mixed data. |
| 98 | 102 | update_site_option( self::CACHE_LAST_CHECKPOINT, $date_from ); |
| 99 | 103 | } |
| 100 | 104 | } |
| @@ -148,33 +152,17 @@ | ||
| 148 | 152 | |
| 149 | 153 | return $data['data']; |
| 150 | 154 | } |
| 151 | 155 | |
| 156 | + | |
| 152 | 157 | /** |
| 153 | - * Flushes logs that need to be synced with the cloud. | |
| 158 | + * Delete all local audit log entries from database and reset checkpoint. | |
| 159 | + * | |
| 160 | + * @return void | |
| 154 | 161 | */ |
| 155 | - public function flush() { | |
| 156 | - $logs = Audit_Log::get_logs_need_flush(); | |
| 157 | - // Build the data. | |
| 158 | - $data = array(); | |
| 159 | - foreach ( $logs as $log ) { | |
| 160 | - $item = $log->export(); | |
| 161 | - unset( $item['synced'] ); | |
| 162 | - unset( $item['safe'] ); | |
| 163 | - unset( $item['id'] ); | |
| 164 | - $item['msg'] = addslashes( $item['msg'] ); | |
| 165 | - $data[] = $item; | |
| 166 | - } | |
| 167 | - if ( count( $data ) ) { | |
| 168 | - $ret = $this->curl_to_api( $data ); | |
| 169 | - if ( ! is_wp_error( $ret ) ) { | |
| 170 | - $this->log( sprintf( 'API sync successful, marking %s logs as synced', count( $data ) ), self::AUDIT_LOG ); | |
| 171 | - foreach ( $logs as $log_item ) { | |
| 172 | - $log_item->synced = 1; | |
| 173 | - $log_item->save(); | |
| 174 | - } | |
| 175 | - } | |
| 176 | - } | |
| 162 | + public function reset(): void { | |
| 163 | + Audit_Log::truncate(); | |
| 164 | + delete_site_option( self::CACHE_LAST_CHECKPOINT ); | |
| 177 | 165 | } |
| 178 | 166 | |
| 179 | 167 | /** |
| 180 | 168 | * Cleans up old logs based on storage settings. |
| @@ -241,84 +229,8 @@ | ||
| 241 | 229 | return $ret; |
| 242 | 230 | } |
| 243 | 231 | |
| 244 | 232 | /** |
| 245 | - * Sends data to the API using a socket connection. | |
| 246 | - * | |
| 247 | - * @param array $data Data to be sent to the API. | |
| 248 | - * | |
| 249 | - * @return bool Returns true on success, false on failure. | |
| 250 | - */ | |
| 251 | - public function socket_to_api( $data ) { | |
| 252 | - $sockets = Array_Cache::get( 'sockets', 'audit', array() ); | |
| 253 | - // We will need to wait a bit. | |
| 254 | - if ( 0 === ( is_array( $sockets ) || $sockets instanceof Countable ? count( $sockets ) : 0 ) ) { | |
| 255 | - // Fall back. | |
| 256 | - return false; | |
| 257 | - } | |
| 258 | - $this->log( | |
| 259 | - sprintf( 'Flush %s to cloud', is_array( $data ) || $data instanceof Countable ? count( $data ) : 0 ), | |
| 260 | - self::AUDIT_LOG | |
| 261 | - ); | |
| 262 | - $start_time = microtime( true ); | |
| 263 | - $sks = $sockets; | |
| 264 | - $r = null; | |
| 265 | - $e = null; | |
| 266 | - if ( ( false === stream_select( $r, $sks, $e, 1 ) ) ) { | |
| 267 | - // This case error happen. | |
| 268 | - return false; | |
| 269 | - } | |
| 270 | - | |
| 271 | - $fp = array_shift( $sockets ); | |
| 272 | - | |
| 273 | - $uri = '/logs/add_multiple'; | |
| 274 | - $vars = http_build_query( $data ); | |
| 275 | - $this->attach_behavior( WPMUDEV::class, WPMUDEV::class ); | |
| 276 | - // We're sending data to the server, so we're not manipulating files. Ignore the error. | |
| 277 | - // @codingStandardsIgnoreStart | |
| 278 | - fwrite( $fp, 'POST ' . $uri . " HTTP/1.1\r\n" ); | |
| 279 | - fwrite( $fp, 'Host: ' . $this->strip_protocol( $this->get_endpoint() ) . "\r\n" ); | |
| 280 | - fwrite( $fp, "Content-Type: application/x-www-form-urlencoded\r\n" ); | |
| 281 | - fwrite( $fp, 'Content-Length: ' . strlen( $vars ) . "\r\n" ); | |
| 282 | - fwrite( $fp, 'apikey: ' . $this->get_apikey() . "\r\n" ); | |
| 283 | - fwrite( $fp, "Connection: close\r\n" ); | |
| 284 | - fwrite( $fp, "\r\n" ); | |
| 285 | - fwrite( $fp, $vars ); | |
| 286 | - stream_set_timeout( $fp, 5 ); | |
| 287 | - $res = ''; | |
| 288 | - while ( ! feof( $fp ) ) { | |
| 289 | - $res .= fgets( $fp, 1024 ); | |
| 290 | - // Check if the transfer has taken too long. | |
| 291 | - $end_time = microtime( true ); | |
| 292 | - if ( $end_time - $start_time > 3 ) { | |
| 293 | - fclose( $fp ); | |
| 294 | - break; | |
| 295 | - } | |
| 296 | - } | |
| 297 | - // @codingStandardsIgnoreEnd | |
| 298 | - return true; | |
| 299 | - } | |
| 300 | - | |
| 301 | - /** | |
| 302 | - * Open a socket to API for faster transmit. | |
| 303 | - */ | |
| 304 | - public function open_socket() { | |
| 305 | - $sockets = Array_Cache::get( 'sockets', 'audit', array() ); | |
| 306 | - $endpoint = $this->strip_protocol( $this->get_endpoint() ); | |
| 307 | - if ( array() === $sockets ) { | |
| 308 | - $fp = stream_socket_client( | |
| 309 | - 'ssl://' . $endpoint . ':443', | |
| 310 | - $errno, | |
| 311 | - $errstr, | |
| 312 | - 5 | |
| 313 | - ); | |
| 314 | - if ( is_resource( $fp ) ) { | |
| 315 | - Array_Cache::set( 'sockets', array( $fp ), 'audit' ); | |
| 316 | - } | |
| 317 | - } | |
| 318 | - } | |
| 319 | - | |
| 320 | - /** | |
| 321 | 233 | * Strips the protocol from a URL. |
| 322 | 234 | * |
| 323 | 235 | * @param string $url URL to process. |
| 324 | 236 | * |
| @@ -410,9 +322,9 @@ | ||
| 410 | 322 | $model = new Audit_Log(); |
| 411 | 323 | |
| 412 | 324 | if ( ( is_array( $events ) || $events instanceof Countable ? count( $events ) : 0 ) > 1 ) { |
| 413 | 325 | if ( $model->has_method( 'mass_insert' ) ) { |
| 414 | - $model->mass_insert( $events ); | |
| 326 | + $model->mass_insert( $events, 0 ); | |
| 415 | 327 | |
| 416 | 328 | return; |
| 417 | 329 | } |
| 418 | 330 | } |
| @@ -421,6 +333,21 @@ | ||
| 421 | 333 | $model->import( $event ); |
| 422 | 334 | $model->synced = 0; |
| 423 | 335 | $model->save(); |
| 424 | 336 | } |
| 337 | + } | |
| 338 | + | |
| 339 | + /** | |
| 340 | + * Get audit events per week. | |
| 341 | + */ | |
| 342 | + public static function get_audit_events_per_week(): int { | |
| 343 | + $timezone = wp_timezone(); | |
| 344 | + $date_to = ( new DateTime( 'now', $timezone ) ) | |
| 345 | + ->setTime( 23, 59, 59 ) | |
| 346 | + ->getTimestamp(); | |
| 347 | + $date_from = ( new DateTime( '-7 days', $timezone ) ) | |
| 348 | + ->setTime( 0, 0, 0 ) | |
| 349 | + ->getTimestamp(); | |
| 350 | + | |
| 351 | + return Audit_Log::count( $date_from, $date_to ); | |
| 425 | 352 | } |
| 426 | 353 | } |