AlkantarClanX12

Your IP : 216.73.217.24


Current Path : /www/capitalgmcbuickregina_830/public/wp-content/plugins/wp-cerber/admin/
Upload File :
Current File : /www/capitalgmcbuickregina_830/public/wp-content/plugins/wp-cerber/admin/CRB_Traffic_Log_Screen.php

<?php

/**
 * Generates HTML code for the Traffic Log admin page to view, filter, and search HTTP requests log entry
 *
 * This file contains the refactored class for rendering the Traffic Log screen.
 * The main entry point is CRB_Traffic_Log_Screen::render_screen().
 *
 * @since 9.6.9.7
 *
 */
final class CRB_Traffic_Log_Screen {

	/** @var array<string,mixed> Render arguments for this screen render pass. */
	private array $args;

	/** Whether toolbar and search controls should be rendered. */
	private bool $ui_controls_enabled;

	/** Whether Traffic Inspector logging is enabled for this render pass. */
	private bool $logging_enabled;

	/** Whether the current request applies Traffic Log search or filter criteria. */
	private bool $search_active;

	/** Whether the Traffic Log table has no stored entries. */
	private bool $traffic_log_empty;

	/**
	 * Initializes request-local Traffic Log screen state.
	 *
	 * @param array<string,mixed> $args Screen rendering arguments.
	 *
	 * @since 9.8.1
	 */
	private function __construct( array $args = array() ) {
		$this->args = $args;
		$this->ui_controls_enabled = empty( $args['compact_view'] );
		$this->logging_enabled = (bool) crb_get_settings( 'timode' );
		$this->search_active = (bool) array_intersect_key( CRB_Traffic_Log::QUERY_PARAMS, crb_get_query_params() );
		$this->traffic_log_empty = CRB_Traffic_Log::is_empty();
	}

	/**
	 * Renders and outputs the HTTP Traffic Log admin screen.
	 *
	 * @param array<string,mixed> $args Optional arguments to control UI, filtering, and row limits.
	 * @param bool $echo Whether to echo the result or return it as a string.
	 *
	 * @return void|string
	 *
	 * @since 9.8.1
	 */
	public static function render_screen( array $args = array(), $echo = true ) {

		$screen = new self( $args );
		$result_html = $screen->render();

		if ( $echo ) {
			echo $result_html;

			return;
		}

		return $result_html;
	}

	/**
	 * Renders HTTP Traffic Log admin screen.
	 *
	 * This is the main orchestrator method. It fetches data and calls other
	 * rendering methods to build the final HTML output for the screen.
	 *
	 * @return string
	 *
	 * @since 9.6.9.7
	 */
	private function render() {

		$result_html = '';

		$fetched = CRB_Traffic_Log::fetch_rows( $this->args );

		$filters = $fetched->get_element( 'filters', array() );
		$traffic_log_rows = $fetched->get_element( 'rows', array() );
		$total_rows = (int) $fetched->get_element( 'total', 0 );

		if ( $this->ui_controls_enabled ) {
			$toolbar_html = self::render_toolbar( $this->traffic_log_empty, (int) crb_get_settings( 'tithreshold' ), (bool) $total_rows );
			$info_blocks_html = self::render_info_blocks( $filters['ip'], $filters['user'] );
			$form_html = self::render_search_form();

			$result_html .= '<div class="cerber-margin">' . $toolbar_html . $form_html . $info_blocks_html . '</div>';
		}

		if ( $fetched->has_errors() ) {
			$result_html .= crb_ui_renderer()->render_element( crb_ui_log_fetch_error_box( $fetched ) );
		}
		elseif ( $traffic_log_rows ) {
			// Fetch and prepare all related data
			$activity_rows = self::fetch_activity_events( $traffic_log_rows );
			$grouped_events = self::group_activity_events( $activity_rows );
			$enriched_data = self::enrich_log_data( $traffic_log_rows );

			// Render the main content table
			$table_html = self::render_log_table( $traffic_log_rows, $enriched_data, $grouped_events, $this->args );

			// Add pagination
			if ( $this->ui_controls_enabled ) {
				$table_html .= cerber_page_navi( $total_rows, $filters['per_page'] );
			}

			$result_html .= $table_html;

			if ( ! $this->logging_enabled ) {
				$result_html = '<p class="cerber-margin" style="padding: 0.5em; font-weight: 600;">' . __( 'Logging is currently disabled, you are viewing historical information.', 'wp-cerber' ) . '</p>' . $result_html;
			}
		}
		else {
			// Render the "no results" message
			$result_html .= $this->render_empty_state();
		}

		return $result_html;
	}

	/**
	 * Fetches related activity events for a given set of traffic log rows.
	 *
	 * @param array $log_rows The traffic log rows.
	 *
	 * @return array The fetched activity rows.
	 *
	 * @since 9.6.9.7
	 */
	private static function fetch_activity_events( $log_rows ) {
		if ( ! $log_rows ) {
			return array();
		}

		$session_ids = array_keys( $log_rows );
		$query = 'SELECT * FROM ' . CERBER_LOG_TABLE . ' WHERE session_id IN ("' . implode( '", "', array_map( 'cerber_db_real_escape', $session_ids ) ) . '" ) ORDER BY stamp DESC';

		$activity_rows = crb_q_cache_get( array(
			array( $query, MYSQL_FETCH_OBJECT )
		), CERBER_LOG_TABLE );

		return $activity_rows ?: array();
	}

	/**
	 * Groups activity events by session ID.
	 *
	 * @param array $activity_rows The activity rows to group.
	 *
	 * @return array The events grouped by session_id.
	 *
	 * @since 9.6.9.7
	 */
	private static function group_activity_events( $activity_rows ) {
		if ( ! $activity_rows ) {
			return array();
		}

		$events = array();
		foreach ( $activity_rows as $activity_row ) {
			$events[ $activity_row->session_id ][] = $activity_row;
		}

		return $events;
	}

	/**
	 * Enriches log data with user information, ACL status, and post titles.
	 *
	 * @param array $log_rows The traffic log rows.
	 *
	 * @return array An array of enriched data: ['users' => [], 'acl' => [], 'block' => [], 'entities' => []].
	 *
	 * @since 9.6.9.7
	 */
	private static function enrich_log_data( $log_rows ) {
		global $wpdb;

		$enriched_data = array(
			'users'    => array(),
			'acl'      => array(),
			'block'    => array(),
			'entities' => array(),
		);

		if ( ! $log_rows ) {
			return $enriched_data;
		}

		$roles = wp_roles()->roles;

		foreach ( $log_rows as $traffic_row ) {
			// Enrich user data
			if ( $traffic_row->user_id && ! isset( $enriched_data['users'][ $traffic_row->user_id ] ) ) {
				if ( $user_data = crb_get_userdata( $traffic_row->user_id ) ) {
					$user_roles = '';
					if ( ! is_multisite() && $user_data->roles ) {
						$role_names = array();
						foreach ( $user_data->roles as $role_key ) {
							if ( isset( $roles[ $role_key ]['name'] ) ) {
								$role_names[] = $roles[ $role_key ]['name'];
							}
						}
						$user_roles = '<span class="crb_act_role">' . implode( ', ', $role_names ) . '</span>';
					}
					$name = $user_data->display_name;
				}
				else {
					$name = __( 'Unknown', 'wp-cerber' ) . ' (' . $traffic_row->user_id . ')';
					$user_roles = '';
				}
				$enriched_data['users'][ $traffic_row->user_id ] = array( 'name' => $name, 'roles' => $user_roles );
			}

			// Enrich IP ACL status
			if ( ! isset( $enriched_data['acl'][ $traffic_row->ip ] ) ) {
				$enriched_data['acl'][ $traffic_row->ip ] = cerber_acl_check( $traffic_row->ip );
			}

			// Enrich IP block status
			if ( ! isset( $enriched_data['block'][ $traffic_row->ip ] ) ) {
				$enriched_data['block'][ $traffic_row->ip ] = cerber_block_check( $traffic_row->ip );
			}

			// Enrich WordPress entity (e.g., post title)
			if ( $traffic_row->wp_type == 601 && $traffic_row->wp_id > 0 && ! isset( $enriched_data['entities'][ $traffic_row->wp_id ] ) ) {
				$post_title = cerber_db_get_var( 'SELECT post_title FROM ' . $wpdb->posts . ' WHERE ID = ' . absint( $traffic_row->wp_id ) );
				if ( $post_title ) {
					$enriched_data['entities'][ $traffic_row->wp_id ] = apply_filters( 'the_title', $post_title, $traffic_row->wp_id );
				}
			}
		}

		return $enriched_data;
	}

	/**
	 * Renders the top toolbar with quick filters and action buttons.
	 *
	 * @param bool $is_log_empty Whether the log is completely empty.
	 * @param int $threshold The processing time threshold for a "long" request.
	 * @param bool $has_results Whether there are log rows to display.
	 *
	 * @return string The HTML for the toolbar.
	 *
	 * @since 9.6.9.7
	 */
	private static function render_toolbar( $is_log_empty, $threshold, $has_results ) {
		$filter_links = '';
		$search_button = '';
		$export_button = '';
		$refresh_button = '';

		if ( ! $is_log_empty ) {
			$nav_links = array(
				array( array(), __( 'View all', 'wp-cerber' ) ),
				array( array( 'filter_set' => 1 ), __( 'Suspicious requests', 'wp-cerber' ) ),
				array( array( 'filter_http_code' => 399, 'filter_http_code_mode' => 'GT' ), __( 'Errors', 'wp-cerber' ) ),
				array( array( 'filter_user' => '*' ), __( 'Users', 'wp-cerber' ) ),
				array( array( 'filter_user' => 0 ), __( 'Non-authenticated', 'wp-cerber' ) ),
				array( array( 'filter_method' => 'POST', 'filter_wp_type' => 520, 'filter_wp_type_mode' => 'GT' ), __( 'Form submissions', 'wp-cerber' ) ),
				array( array( 'filter_http_code' => 404 ), __( 'Page Not Found', 'wp-cerber' ) ),
				array( array( 'filter_wp_type' => 520 ), 'REST API' ),
				array( array( 'filter_wp_type' => 515 ), 'XML-RPC' ),
				array( array( 'filter_user' => get_current_user_id() ), __( 'My requests', 'wp-cerber' ) ),
				array( array( 'filter_ip' => cerber_get_remote_ip() ), __( 'My IP', 'wp-cerber' ) ),
			);

			if ( $threshold ) {
				$nav_links[] = array( array( 'filter_processing' => $threshold ), __( 'Longer than', 'wp-cerber' ) . ' ' . (int) $threshold . ' ms' );
			}

			$filter_links = crb_build_quick_nav_block( $nav_links, 'traffic' );
			$search_button = '<a href="#" id="traffic-search-btn" class="button button-secondary cerber-button" title="Search in the request history"><i class="crb-icon crb-icon-bx-search"></i> ' . __( 'Advanced Search', 'wp-cerber' ) . '</a>';
		}

		if ( $has_results ) {
			// This URL is escaped, no escaping is needed
			$export_url = cerber_admin_link_add( array( 'cerber_admin_do' => 'export', 'type' => 'traffic' ), true );
			$export_button = '<a class="button button-secondary cerber-button" href="' . $export_url . '"><i class="crb-icon crb-icon-bx-download"></i> ' . __( 'Export', 'wp-cerber' ) . '</a>';
		}

		if ( crb_get_settings( 'timode' ) && $has_results ) {
			$refresh_button = '<a href="" style="white-space: pre;"><i class="dashicons dashicons-update" style=""></i> <span>' . __( 'Refresh', 'wp-cerber' ) . '</span></a>';
		}

		$right_actions = $search_button . ' ' . $export_button;

		return '<div id="crb-admin-toolbar-secondary-row"><div><div style="display: table-cell; width: 80%;">' . $filter_links . '</div><div style="display: table-cell;">' . $refresh_button . '</div></div><div>' . $right_actions . '</div></div><br style="clear: both;">';
	}


	/**
	 * Renders additional info blocks when filtering by IP or user.
	 *
	 * @param string $filter_ip The IP being filtered, if any.
	 * @param int $filter_user The user ID being filtered, if any.
	 *
	 * @return string The HTML for the info blocks.
	 *
	 * @since 9.6.9.7
	 */
	private static function render_info_blocks( $filter_ip, $filter_user ) {
		$info_html = '';

		if ( $filter_ip ) {
			$info_html .= cerber_ip_extra_view( $filter_ip, 'traffic' );
		}

		if ( is_numeric( $filter_user ) && $filter_user > 0 ) {
			$info_html .= cerber_user_extra_view( $filter_user, 'traffic' );
		}

		return $info_html;
	}

	/**
	 * Renders the main log table.
	 *
	 * @param array $log_rows The traffic log rows.
	 * @param array $enriched_data Additional data for users, ACL, etc.
	 * @param array $events Grouped activity events.
	 * @param array $args Original arguments for rendering options.
	 *
	 * @return string The HTML for the log table.
	 *
	 * @since 9.6.9.7
	 */
	private static function render_log_table( $log_rows, $enriched_data, $events, $args ) {
		$columns = array(
			'crb_date_col'     => __( 'Date', 'wp-cerber' ),
			'crb_request_col'  => __( 'Request', 'wp-cerber' ),
			'crb_ip_col'       => '<div class="crb_act_icon"></div>' . __( 'IP Address', 'wp-cerber' ),
			'crb_hostinfo_col' => __( 'Host Info', 'wp-cerber' ),
			'crb_ua_col'       => __( 'User Agent', 'wp-cerber' ),
			'crb_user_col'     => __( 'Local User', 'wp-cerber' ),
		);

		$table_heading = '';
		foreach ( $columns as $id => $title ) {
			$table_heading .= '<th id="' . crb_attr_escape( $id ) . '">' . $title . '</th>';
		}

		$table_footer = '<th>' . implode( '</th><th>', $columns ) . '</th>';

		$table_body = '';
		$is_even_row = false;
		foreach ( $log_rows as $log_entry ) {
			$row_class = $is_even_row ? 'crb-even' : 'crb-odd';
			$table_body .= self::render_table_row( $log_entry, $enriched_data, $events, $row_class, $args );
			$is_even_row = ! $is_even_row;
		}

		return '<table id="crb-traffic" class="widefat crb-table cerber-margin"><thead><tr>' . $table_heading . '</tr></thead><tfoot><tr>' . $table_footer . '</tr></tfoot><tbody>' . $table_body . '</tbody></table>';
	}

	/**
	 * Renders a single row in the log table, including the hidden details row.
	 *
	 * @param object $log_entry A single log entry object.
	 * @param array $enriched_data Additional data for users, ACL, etc.
	 * @param array $events Grouped activity events.
	 * @param string $row_class The CSS class for the row (crb-even/crb-odd).
	 * @param array $args Original arguments for rendering options.
	 *
	 * @return string The HTML for a single `<tr>` pair.
	 *
	 * @since 9.6.9.7
	 */
	private static function render_table_row( $log_entry, $enriched_data, $events, $row_class, $args ) {
		$base_url = cerber_admin_link( 'traffic' );

		// Date cell
		if ( 'ago' == ( $args['date'] ?? '' ) ) {
			$date_cell = cerber_ago_time( $log_entry->stamp );
		}
		else {
			$date_cell = '<span title="' . crb_attr_escape( $log_entry->stamp . ' / ' . $log_entry->session_id ) . '">' . cerber_date( $log_entry->stamp ) . '</span>';
		}

		// User cell
		$user_cell = '';
		if ( $log_entry->user_id && isset( $enriched_data['users'][ $log_entry->user_id ] ) ) {
			$user = $enriched_data['users'][ $log_entry->user_id ];
			$user_cell = '<a href="' . crb_escape_url( $base_url . '&filter_user=' . $log_entry->user_id ) . '"><b>' . crb_escape_html( $user['name'] ) . '</b></a><br/>' . $user['roles'];
		}

		// Host Info cell
		$country_html = ( lab_lab() ) ? '<p style="">' . crb_country_html( $log_entry->country, $log_entry->ip ) . '</p>' : '';
		if ( ! empty( $log_entry->hostname ) ) {
			$hostname = $log_entry->hostname;
		}
		else {
			$ip_info = cerber_get_ip_info( $log_entry->ip );
			$hostname = $ip_info['hostname_html'] ?? crb_get_ajax_placeholder( 'hostname', cerber_get_id_ip( $log_entry->ip ) );
		}
		$host_info_cell = $hostname . $country_html;

		// User Agent cell
		$ua_cell = crb_escape_html( CRB_User_Agent_Parser::detect( $log_entry->request_details[1] ?? '' ) );

		// IP cell
		$ip_cell = crb_admin_ip_cell( $log_entry->ip, $base_url . '&amp;filter_ip=' . $log_entry->ip );

		// Request cell (the most complex one)
		$request_details_html = self::render_request_details( $log_entry, $enriched_data, $events, $base_url );
		$toggle_class = $request_details_html['details'] ? 'crb-toggle' : '';

		// Build the final row HTML
		$visible_row = '<tr class="' . $row_class . ' ' . $toggle_class . '">
            <td>' . $date_cell . '</td>
            <td class="crb-request">' . $request_details_html['summary'] . '</td>
            <td>' . $ip_cell . '</td>
            <td>' . $host_info_cell . '</td>
            <td>' . $ua_cell . '</td>
            <td>' . $user_cell . '</td>
        </tr>';

		$hidden_row = '<tr class="' . $row_class . ' crb-request-details" style="display: none;">
            <td></td>
            <td colspan="5" class="crb-traffic-details" data-session-id="' . crb_attr_escape( $log_entry->session_id ) . '">
                <div>' . $request_details_html['details'] . '</div>
            </td>
        </tr>';

		return $visible_row . $hidden_row;
	}

	/**
	 * Formats URI data for display.
	 *
	 * @param string $raw_uri The raw URI from the log entry.
	 *
	 * @return array An array containing 'display_html' and 'card' data.
	 *
	 * @since 9.6.9.7
	 */
	private static function format_uri_data( $raw_uri ) {
		$full_uri = urldecode( $raw_uri );
		$display_uri = $full_uri;

		if ( ! defined( 'CERBER_FULL_URI' ) || ! CERBER_FULL_URI ) {
			$site_home_url = cerber_get_home_url();
			if ( 0 === strpos( $full_uri, $site_home_url ) ) {
				$display_uri = substr( $full_uri, strlen( rtrim( $site_home_url, '/' ) ) );
			}
		}

		$is_truncated = strlen( $display_uri ) > 220;
		$display_html = crb_escape_html( $is_truncated ? substr( $display_uri, 0, 220 ) : $display_uri );
		if ( $is_truncated ) {
			$display_html .= ' <span style="color: red;">&hellip;</span>';
		}

		$card = array();
		if ( $is_truncated ) {
			$card = array( 'title' => 'Full URL', 'content' => $full_uri, 'type' => 'monospace' );
		}

		return array(
			'display_html' => $display_html,
			'card'         => $card,
		);
	}

	/**
	 * Builds a structured array of request details data from a log entry.
	 *
	 * @param object $log_entry A single log entry object.
	 *
	 * @return array A structured array of data cards for rendering.
	 *
	 * @since 9.6.9.7
	 */
	private static function build_request_details_data( $log_entry ) {
		$details = $log_entry->request_details;
		$fields = $log_entry->request_fields;
		$cards = array();

		// Server headers and redirection
		$server_headers = array();
		if ( ! empty( $details[10] ) ) {
			foreach ( $details[10] as $item ) {
				$e = explode( ':', $item, 2 );
				if ( count( $e ) == 2 ) {
					$server_headers[ trim( $e[0] ) ] = trim( $e[1] );
				}
			}
		}
		if ( ! empty( $server_headers['Location'] ) ) {
			$cards[] = array( 'title' => 'Redirection URL', 'content' => urldecode( $server_headers['Location'] ), 'type' => 'monospace' );
		}

		// Common request data
		if ( ! empty( $details[2] ) ) {
			$cards[] = array( 'title' => 'Referrer', 'content' => urldecode( $details[2] ), 'type' => 'monospace' );
		}
		if ( ! empty( $details[1] ) ) {
			$cards[] = array( 'title' => 'User Agent', 'content' => $details[1], 'type' => 'monospace' );
		}

		// Request body data
		if ( ! empty( $fields[1] ) ) {
			crb_highlight_fields_type_two( $fields[1], 1 );
			$cards[] = array( 'title' => __( 'Form Fields', 'wp-cerber' ), 'content' => $fields[1], 'type' => 'table' );
		}
		if ( ! empty( $fields[4] ) ) {
			$cards[] = array( 'title' => __( 'JSON Payload', 'wp-cerber' ), 'content' => $fields[4], 'type' => 'table' );
		}
		if ( ! empty( $fields[2] ) ) {
			$cards[] = array( 'title' => __( 'Query Parameters', 'wp-cerber' ), 'content' => $fields[2], 'type' => 'table' );
		}

		// Files
		if ( ! empty( $fields[3] ) ) {
			$files_content = array();
			foreach ( $fields[3] as $field_name => $file ) {
				$f_err = is_array( $file['error'] ) ? array_shift( $file['error'] ) : $file['error'];
				if ( $f_err == UPLOAD_ERR_NO_FILE ) {
					continue;
				}
				$f_name = is_array( $file['name'] ) ? array_shift( $file['name'] ) : $file['name'];
				$f_size = is_array( $file['size'] ) ? array_shift( $file['size'] ) : $file['size'];
				$files_content[ $field_name ] = crb_escape_html( $f_name ) . ', size: ' . absint( $f_size ) . ' bytes';
			}
			if ( $files_content ) {
				$cards[] = array( 'title' => __( 'Files Submitted', 'wp-cerber' ), 'content' => $files_content, 'type' => 'table' );
			}
		}

		// Other details
		if ( ! empty( $details[5] ) ) {
			$cards[] = array( 'title' => __( 'XML-RPC Payload', 'wp-cerber' ), 'content' => $details[5], 'type' => 'monospace' );
		}
		if ( ! empty( $details[6] ) ) {
			$cards[] = array( 'title' => __( 'Client Request Headers', 'wp-cerber' ), 'content' => $details[6], 'type' => 'table' );
		}
		if ( ! empty( $server_headers ) ) {
			if ( ! empty( $details[11] ) ) {
				crb_highlight_fields_type_one( $server_headers, array( 'Location' => $details[11] ) );
			}
			$cards[] = array( 'title' => __( 'Server Response Headers', 'wp-cerber' ), 'content' => $server_headers, 'type' => 'table' );
		}
		if ( ! empty( $details[8] ) ) {
			crb_highlight_fields_type_two( $details[8], 2 );
			$cards[] = array( 'title' => __( 'Client Request Cookies', 'wp-cerber' ), 'content' => $details[8], 'type' => 'table' );
		}

		// Server Response Cookies
		if ( ! empty( $details[9] ) ) {
			$server_cookies = array();
			foreach ( $details[9] as $item ) {
				if ( 0 === stripos( $item, 'Set-Cookie:' ) ) {
					$item = substr( $item, 11 );
				}
				$parts = explode( '=', $item, 2 );
				if ( count( $parts ) == 2 ) {
					$pos = strpos( $parts[1], ';' );
					$server_cookies[ trim( $parts[0] ) ] = urldecode( substr( $parts[1], 0, $pos ) ) . substr( $parts[1], $pos );
				}
			}
			crb_highlight_fields_type_two( $server_cookies, 2 );
			$cards[] = array( 'title' => __( 'Server Response Cookies', 'wp-cerber' ), 'content' => $server_cookies, 'type' => 'table' );
		}

		if ( ! empty( $details[7] ) ) {
			$cards[] = array( 'title' => '$_SERVER', 'content' => $details[7], 'type' => 'table' );
		}

		// PHP Errors
		if ( $err_list = $log_entry->php_errors ) {
			$errors = array();
			foreach ( $err_list as $err ) {
				$errors[] = array(
					'type'   => cerber_get_err_level( $err[0] ) . ' (' . $err[0] . ')',
					'info'   => $err[1],
					'file'   => $err[2],
					'line'   => $err[3],
					'source' => crb_get_file_owner( $err[2] ) ?: ''
				);
			}
			$cards[] = array( 'title' => __( 'Software Errors', 'wp-cerber' ), 'content' => $errors, 'type' => 'table' );
		}

		return $cards;
	}

	/**
	 * Renders a string of HTML labels for the request summary line.
	 *
	 * @param object $log_entry A single log entry object.
	 * @param array $status_labels An array of status labels.
	 *
	 * @return string The concatenated HTML for the labels.
	 *
	 * @since 9.6.9.7
	 */
	private static function render_summary_labels( $log_entry, $status_labels ) {
		$labels_html = '';

		// Files label
		if ( ! empty( $log_entry->request_fields[3] ) ) {
			$labels_html .= '<span class="crb-ffile">F</span>';
		}

		// WP Type label
		if ( $wp_type = cerber_get_wp_type( $log_entry->wp_type ) ) {
			$labels_html .= '<span class="crb-wp-type-' . $log_entry->wp_type . '">' . $wp_type . '</span>';
		}

		// HTTP Code label
		$labels_html .= crb_get_http_code_label( (int) $log_entry->http_code );

		// Request Status label
		if ( ! empty( $log_entry->req_status ) ) {
			$status = (int) $log_entry->req_status;
			if ( isset( $status_labels[ $status ] ) ) {
				$labels_html .= '<span class="crb-req-status-' . $status . '" title="' . $status . '">' . $status_labels[ $status ] . '</span>';
			}
		}

		// PHP Errors label
		if ( $errors = $log_entry->php_errors ) {
			$labels_html .= '<span class="crb-php-error">SE &nbsp;' . count( $errors ) . '</span>';
		}

		return $labels_html;
	}

	/**
	 * Renders the summary and detailed view of a request from prepared data.
	 *
	 * @param object $log_entry A single log entry object.
	 * @param array $enriched_data Additional data for users, ACL, etc.
	 * @param array $events Grouped activity events.
	 * @param string $base_url The base URL for filter links.
	 *
	 * @return array The HTML for the request details, split into 'summary' and 'details'.
	 *
	 * @since 9.6.9.7
	 */
	private static function render_request_details( $log_entry, $enriched_data, $events, $base_url ) {
		$activity_labels = cerber_get_labels( 'activity' );
		$status_labels = cerber_get_labels( 'status' ) + crb_get_lockout_reason();

		// Get formatted URI data and the main body of cards
		$uri_data = self::format_uri_data( $log_entry->uri );
		$cards_data = self::build_request_details_data( $log_entry );

		// Prepend the URI card if it exists
		if ( ! empty( $uri_data['card'] ) ) {
			array_unshift( $cards_data, $uri_data['card'] );
		}

		// Build Details HTML from the final list of cards
		$cards_html = '';
		foreach ( $cards_data as $card ) {
			$title_html = '<p style="font-weight: 600;">' . $card['title'] . '</p>';
			switch ( $card['type'] ) {
				case 'table':

					if ( $table_element = crb_ui_table_view( $card['title'], $card['content'] ) ) {
						$cards_html .= crb_ui_renderer()->render_element( $table_element );
					}

					break;
				case 'monospace':
					$cards_html .= '<div>' . $title_html . '<span class="crb-monospace">' . crb_escape_html( $card['content'] ) . '</span></div>';
					break;
			}
		}

		// Build summary HTML
		$display_uri_html = $uri_data['display_html'];
		$labels_html = self::render_summary_labels( $log_entry, $status_labels );

		$processing_time = '';
		if ( $log_entry->processing ) {
			$processing_time = (int) $log_entry->processing . ' ms';
			$threshold = (int) crb_get_settings( 'tithreshold' );
			if ( $threshold > 0
			     && $log_entry->processing > $threshold ) {
				$processing_time = '<span class="crb-processing crb-above">' . $processing_time . '</span>';
			}
		}

		$more_link = $cards_html ? '<a href="#" class="crb-traffic-more">' . __( 'Details', 'wp-cerber' ) . '</a>' : '';

		$summary_html = '<b>' . $display_uri_html . '</b>'
		                . '<p style="margin-top:1em;">'
		                . '<span class="crb-' . $log_entry->request_method . '">' . $log_entry->request_method . '</span>'
		                . $labels_html
		                . '<span>' . $processing_time . '</span> ' . $more_link . '</p>';

		// Append activity events to summary
		$activity_html = '';
		if ( ! empty( $events[ $log_entry->session_id ] ) ) {
			foreach ( $events[ $log_entry->session_id ] as $activity_row ) {
				$activity_html .= '<p class="' . crb_get_act_style( $activity_row->activity ) . '"><span><a href="' . crb_escape_url( $base_url . '&filter_activity=' . $activity_row->activity ) . '" title="' . crb_attr_escape( $activity_row->activity ) . '" data-no-js="1">' . crb_escape_html( $activity_labels[ $activity_row->activity ] ) . '</a></span>';
				$status = (int) $activity_row->ac_status;
				if ( ! empty( $status ) && $status != 500 ) { // 500 Whitelisted
					$activity_html .= ' &nbsp;<span class = "crb-log-status crb-status-' . $status . '" title="' . crb_attr_escape( $status_labels[ $status ] ) . '">' . crb_escape_html( $status_labels[ $status ] ) . '</span>';
				}
				$activity_html .= '</p>';
			}
		}
		$summary_html .= $activity_html;

		// Append WP entity to summary
		if ( isset( $enriched_data['entities'][ $log_entry->wp_id ] ) ) {
			$summary_html .= '<p><i>' . crb_escape_html( $enriched_data['entities'][ $log_entry->wp_id ] ) . '</i></p>';
		}

		return array(
			'summary' => $summary_html,
			'details' => $cards_html,
		);
	}

	/**
	 * Renders the UI for when no log entries are found using request-local screen state.
	 *
	 * @return string The HTML for the empty state message.
	 *
	 * @since 9.6.9.7
	 */
	private function render_empty_state() {
		$ui_hints = array();
		$base_url = cerber_admin_link( 'traffic' );

		if ( $this->search_active ) {
			$ui_hints[] = __( 'No requests found using the given search criteria', 'wp-cerber' );
			if ( ! $this->traffic_log_empty ) {
				$ui_hints[] = crb_ui_element( 'p', array(), crb_ui_link( $base_url, __( 'View all logged requests', 'wp-cerber' ) ) );
			}
		}
		else {
			$ui_hints[] = __( 'No requests have been logged yet.', 'wp-cerber' );
		}

		if ( ! $this->logging_enabled ) {
			$ui_hints[] = __( 'Note: Logging is currently disabled', 'wp-cerber' );
			if ( ! $this->search_active ) {
				$ui_hints[] = crb_ui_element( 'p', array(), crb_ui_link( 'https://wpcerber.com/wordpress-traffic-logging/', __( 'Documentation', 'wp-cerber' ), array( 'target' => '_blank' ) ) );
			}
		}

		// Self-repair if the log table we think is missing or corrupted
		if ( $this->traffic_log_empty ) {
			cerber_watchdog( true );
		}

		return crb_ui_renderer()->render_element( crb_ui_message_box( $ui_hints ) );
	}

	/**
	 * Builds and renders the traffic search form using CRB_UI_Form_Builder.
	 *
	 * This version is the most declarative and clean, fully abstracting
	 * the form's structure and layout into the builder class.
	 *
	 * @note It temporarily integrates legacy input fields via a raw_html block. Needs to be refactored ASAP.
	 *
	 * TODO: refactor legacy dropdown select inputs ASAP
	 *
	 * TODO: in the next version it should return CRB_UI_Element The complete search form element
	 *
	 * @return string HTML code for the search form
	 *
	 * @since 9.6.9.8
	 */
	private static function render_search_form(): string {

		$form_builder = CRB_UI_Form_Builder::create( 'crb-traffic-form', 'get' )
		                                   ->add_hidden_field( 'page', 'cerber-traffic' );

		// --- Column 1 ---
		$form_builder
			->add_custom_element( crb_ui_element( 'p', [ 'style' => 'width: 100%;' ], [
				crb_ui_element( 'label', [], 'Activity' ),
				crb_ui_element( 'raw_html', [], '', [ 'content' => crb_get_activity_dd() ] ),
			] ) )
			->add_field( 'text', 'search_traffic[uri]', 'URL contains' )
			->add_select( 'filter_method', 'Request method', [
				'0'    => 'Any',
				'GET'  => 'GET',
				'POST' => 'POST',
			] )
			->add_field( 'text', 'search_traffic[fields]', 'Request fields contain', 'Search in POST, GET, REST API, JSON data' )
			->add_field( 'text', 'search_traffic[details]', 'Miscellaneous details contains', 'Search in cookies, headers, user agents, referrers' )
			->add_field( 'number', 'filter_http_code', 'HTTP Response Code equals' )
			->add_field( 'date', 'search_traffic[date_from]', 'Date from', '', [ 'placeholder' => 'month/day/year' ] )
			->add_field( 'date', 'search_traffic[date_to]', 'Date to', '', [ 'placeholder' => 'month/day/year' ] );

		// --- Column 2 ---
		$form_builder->next_column()
		             ->add_field( 'text', 'search_traffic[ip]', 'Remote IP address contains or equals' )
		             ->add_custom_element( crb_ui_element( 'p', [], [
			             crb_ui_element( 'label', [], 'User' ),
			             crb_ui_element( 'br' ),
			             crb_ui_element( 'raw_html', [], '', [ 'content' => cerber_select( 'filter_user', [], null, 'crb-select2-ajax', '', false, '', [ 'min_symbols' => 3 ] ) ] ),
		             ] ) )
		             ->add_field( 'text', 'filter_user_alt', 'User ID', '', [ 'placeholder' => 'Use comma to specify multiple IDs' ] )
		             ->add_select( 'filter_user_mode', 'User operator', [
			             '0' => 'Include',
			             '1' => 'Exclude',
		             ] )
		             ->add_field( 'text', 'filter_sid', 'RID', '', [ 'placeholder' => 'Request ID' ] )
		             ->add_field( 'text', 'search_traffic[errors]', 'Software errors contain' )
		             ->add_checkbox( 'filter_errors', 'Any software error' )
		             ->add_custom_element( crb_ui_element( 'p', [ 'style' => 'margin-top: 3em;' ], 'The search uses AND logic for all non-empty fields' ) )
		             ->add_submit( 'Search', [ 'style' => 'width: 8rem;' ] );


		$form_element = $form_builder->to_element();

		$the_form = crb_ui_element( 'div', [ 'id' => 'crb-traffic-search', 'style' => 'display: none;' ], [ $form_element ] );

		return crb_ui_renderer()->render_element( $the_form );
	}
}

Home - Capital GMC Buick Regina

No data

Welcome to Capital GMC BUICK – REGINA

Thank you for choosing Capital GMC Buick | Regina, your premier certified Buick and GMC dealership proudly serving drivers in Regina and the surrounding communities. Whether you’re searching for a brand-new Buick or GMC vehicle or a meticulously inspected pre-owned model, we have a diverse selection to match your needs and lifestyle.

Beyond our impressive inventory, we offer a seamless and stress-free financing experience through our well-connected finance centre, where our team of experts is dedicated to securing the best loan or lease options for you, quickly, transparently, and hassle-free.

But our commitment to you doesn’t stop at the sale. Our state-of-the-art service centre is staffed with skilled Buick and GMC technicians who use the latest equipment and genuine OEM parts to keep your vehicle running at its best. From routine maintenance to complex repairs, we’ve got you covered.

Experience top-tier customer service, quality vehicles, and expert care, all in one place. Visit Capital GMC Buick | Regina today or call us at 306-205-8072 with any questions. We’re here to help!

Ask a Question