driver = $driver; } /** * Insert a record * * @param array $record New record. * * @return int */ public function insert( $record ) { if ( defined( 'WP_IMPORTING' ) && WP_IMPORTING ) { return false; } /** * Filter allows modification of record information * * @param array $record * * @return array */ $record = apply_filters( 'mainwp_module_log_record_array', $record ); /** * Hook mainwp_module_log_enable_insert_log_type. * * @since 5.5. */ $enable_log_type = apply_filters( 'mainwp_module_log_enable_insert_log_type', true, $record ); if ( ! $enable_log_type ) { return false; } $data = $this->sanitize_record( $record ); if ( empty( $data ) ) { return false; } $record_id = $this->driver->insert_record( $data ); if ( ! $record_id ) { /** * Fires on a record insertion error * * @param array $record * @param mixed $result */ do_action( 'mainwp_module_log_record_insert_error', $record, false ); return false; } /** * Fires after a record has been inserted * * @param int $record_id * @param array $record */ do_action( 'mainwp_module_log_record_inserted', $record_id, $record ); return absint( $record_id ); } /** * Ensure the record matches our schema. * * @param array $record Record to store. * * @return array */ protected function sanitize_record( $record ) { if ( ! is_array( $record ) ) { return array(); } $record_defaults = array( 'site_id' => null, 'user_id' => null, 'user_login' => null, 'created' => null, 'log_type_id' => null, 'item' => null, 'connector' => null, 'context' => null, 'action' => null, 'state' => null, 'duration' => null, 'meta' => array(), ); // Records can have only these fields. $record = array_intersect_key( $record, $record_defaults ); // Sanitize all record values. return array_map( function ( $value ) { if ( ! is_array( $value ) ) { return wp_strip_all_tags( $value ); } return $value; }, $record ); } /** * Get logs records * * @param array $args Arguments to filter result by. * * @return array Log Records */ public function get_records( $args ) { $defaults = array( // Search param. 'search' => null, 'search_field' => 'item', 'records_per_page' => get_option( 'posts_per_page', 20 ), 'paged' => 1, // Order. 'order' => 'desc', 'orderby' => 'date', ); $args = wp_parse_args( $args, $defaults ); /** * Filter allows additional arguments to query $args * * @return array Array of query arguments */ $args = apply_filters( 'mainwp_module_log_query_args', $args ); $result = (array) $this->driver->get_records( $args ); $this->found_records_count = isset( $result['count'] ) ? $result['count'] : 0; $this->logs_wp_options = isset( $result['sites_opts'] ) && is_array( $result['sites_opts'] ) ? $result['sites_opts'] : array(); $this->logs_extra_data = isset( $result['extra_data'] ) && is_array( $result['extra_data'] ) ? $result['extra_data'] : array(); return empty( $result['items'] ) ? array() : $result['items']; } /** * Helper function, backwards compatibility * * @param array $args Argument to filter result by. * * @return array Log Records */ public function query( $args ) { return $this->get_records( $args ); } /** * Return the number of records found in last request * * @return int */ public function get_found_records_count() { return $this->found_records_count; } /** * Return the number of records found in last request * * @return int */ public function get_logs_sites_opts() { return $this->logs_wp_options; } /** * Return the number of records found in last request * * @return int */ public function get_logs_extra_data() { return $this->logs_extra_data; } /** * Public getter to return table names * * @return array */ public function get_table_names() { return $this->driver->get_table_names(); } /** * Create compact logs and erase records from the database. * * @param int $start_time start time to compact. * @param int $end_time end time to compact. * * @return mixed results. */ public function create_compact_and_erase_records( $start_time, $end_time ) { //phpcs:ignore -- NOSONAR - complex. global $wpdb; $where_compact = $wpdb->prepare( ' AND `logs`.`created` >= %d AND `logs`.`created` <= %d ', $start_time, $end_time ); $sql = "SELECT `logs`.* FROM {$wpdb->mainwp_tbl_logs} logs WHERE `logs`.`connector` != 'compact' " . $where_compact; $logs = MainWP_DB::instance()->query( $sql ); $stats_data = array(); $done = false; while ( $logs && ( $item = MainWP_DB::fetch_object( $logs ) ) ) { $conn = $item->connector; $cont = $item->context; $act = $item->action; if ( empty( $conn ) || empty( $cont ) || empty( $act ) ) { continue; } $year = (int) gmdate( 'Y', intval( $item->created / 1000000 ) ); if ( $year < 2020 ) { return; } if ( ! isset( $stats_data[ $year ] ) ) { $stats_data[ $year ] = array(); } if ( ! isset( $stats_data[ $year ][ $conn ] ) ) { $stats_data[ $year ][ $conn ] = array(); } if ( ! isset( $stats_data[ $year ][ $conn ][ $cont ] ) ) { $stats_data[ $year ][ $conn ][ $cont ] = array(); } if ( ! isset( $stats_data[ $year ][ $conn ][ $cont ][ $act ] ) ) { $stats_data[ $year ][ $conn ][ $cont ][ $act ] = array( 'count' => 0, 'duration' => 0, ); } $stats_data[ $year ][ $conn ][ $cont ][ $act ]['count'] += 1; $stats_data[ $year ][ $conn ][ $cont ][ $act ]['duration'] += $item->duration; $done = true; } if ( $done ) { foreach ( $stats_data as $year => $data ) { $year_data = array( 'data' => $data, ); do_action( 'mainwp_compact_action', 'saved', $year, $year_data, $start_time, $end_time ); } $this->erase_log_records( $start_time, $end_time ); } } /** * Clears logs records from the database. * * @param int $start_time start time. * @param int $end_time start end. * * @return int results number. */ private function erase_log_records( $start_time, $end_time ) { global $wpdb; $where = $wpdb->prepare( ' AND `logs`.`created` >= %d AND `logs`.`created` <= %d', $start_time, $end_time ); return $wpdb->query( //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Destructive operation; caching DELETE is inappropriate. "DELETE `logs`, `meta` FROM {$wpdb->mainwp_tbl_logs} AS `logs` LEFT JOIN {$wpdb->mainwp_tbl_logs_meta} AS `meta` ON `meta`.`meta_log_id` = `logs`.`log_id` WHERE `logs`.`connector` != 'compact' " . $where // phpcs:ignore -- escaped. ); } /** * Metho check if site action log existed. * * @param int $site_id Site Id. * @param string $object_id Object Id. * * @return mixed Results. */ public function is_site_action_log_existed( $site_id = false, $object_id = false ) { //phpcs:ignore -- NOSONAR compatible. return false; } }