403 ) ); } $reads = array(); $level = ob_get_level(); // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found -- The native output-buffer callback must accept and discard this parameter so unsealed evidence is never flushed. ob_start( static fn( string $chunk ): string => '' ); try { self::render_page( $scope, $reads ); $html = ob_get_clean(); } finally { while ( ob_get_level() > $level ) { ob_end_clean(); } } $valid = is_string( $html ) && strlen( $html ) <= 2097152 && Derived::native_context( $caller ) === $origin; $valid = $valid && Store::render_groups( $scope, $reads ); if ( ! $reads ) { $valid = $valid && $scope->valid_for_all( array( 'logged_ai_view_network_events' ) ); } if ( ! $valid || Derived::native_context( $caller ) !== $origin ) { wp_die( esc_html__( 'Network evidence or access changed while rendering. Reload.', 'logged-ai' ), '', array( 'response' => 403 ) ); } // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Every dynamic fragment was context-escaped in render_page; only the sealed buffer is emitted, without invoking another output callback. echo $html; // Escaped while buffered; no native output callbacks after the seal. } /** * Render scoped network filters, event detail and a bounded timeline while recording reads for final sealing. * * @param Scope $scope Server-selected current operation scope with its required native permissions. * @param array $reads Rendered source groups appended by reference for the page's final current-evidence seal. * * @return void */ private static function render_page( Scope $scope, array &$reads ): void { $request_query = \LoggedAI\AdminInput::query(); try { $time = TimeDisplay::site(); } catch ( \Throwable $error ) { wp_die( esc_html__( 'Site timezone context changed. Reload this view.', 'logged-ai' ), '', array( 'response' => 403 ) ); } nocache_headers(); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only network navigation uses validated filters, IDs and cursors within the current authorized scope. $input = $request_query; $cursor = $input['cursor'] ?? ''; $filters = Activity::input_filters( $input, array( 'page', 'event', 'event_uid', 'cursor' ) ); if ( isset( $input['event_uid'] ) && ( ! isset( $input['event'] ) || ! is_string( $input['event_uid'] ) || ! preg_match( '/\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/D', $input['event_uid'] ) ) ) { wp_die( esc_html__( 'This recorded event is unavailable or no longer retained.', 'logged-ai' ), '', array( 'response' => 404 ) ); } if ( is_wp_error( $filters ) || ! is_string( $cursor ) ) { wp_die( esc_html__( 'Invalid filter or cursor. Network scope has not changed.', 'logged-ai' ), '', array( 'response' => 400 ) ); } $base = add_query_arg( array_merge( array( 'page' => 'logged-ai-network' ), Activity::url_filters( $filters ), $cursor ? array( 'cursor' => $cursor ) : array() ), Scope::network_admin_url( 'admin.php' ) ); $rows = Store::listing( $scope, $filters, $cursor, 50 ); echo '
' . esc_html__( 'These facts originated in this network’s administrative context. Plugin, theme and WordPress files are shared across the installation, so their effects can extend to other networks. Site activity remains in each site’s own timeline.', 'logged-ai' ) . '
'; echo ( '' . ( esc_html( sprintf( /* translators: 1: Value shown in this message. 2: Value shown in this message. */ __( 'Network #%1$s · Times shown in %2$s (current site setting)', 'logged-ai' ), $scope->network_id, $time->zone() ) ) ) . '
' ); Activity::filter_form( $filters, true ); if ( isset( $input['event'] ) ) { echo '' . esc_html__( 'Back to filtered network activity', 'logged-ai' ) . '
'; $detail = is_string( $input['event'] ) ? Store::detail( $scope, $input['event'] ) : new \WP_Error( 'event', 'Event unavailable.' ); if ( ! is_wp_error( $detail ) && isset( $input['event_uid'] ) && $input['event_uid'] !== ( $detail['uid'] ?? null ) ) { $detail = new \WP_Error( 'event', __( 'This recorded event is unavailable or no longer retained.', 'logged-ai' ) ); } if ( is_wp_error( $detail ) ) { echo ( '' . ( esc_html( PresentationTranslations::text( $detail->get_error_message() ) ) ) . '
' ); } else { $reads[] = array( 'value' => $detail, 'detail' => true, ); echo ( '' . ( esc_html( sprintf( /* translators: 1: Value shown in this message. 2: Value shown in this message. */ __( 'Occurred: %1$s · Ingested: %2$s', 'logged-ai' ), $time->text( $detail['occurred_at'] ), $time->text( $detail['ingested_at'] ) ) ) ) . '
' . '' . esc_html__( 'Canonical evidence below retains UTC timestamps.', 'logged-ai' ) . '
' . '' . ( esc_html( wp_json_encode( $detail, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ) ) ) . '' ); } } if ( is_wp_error( $rows ) ) { echo ( '
' . ( esc_html( PresentationTranslations::text( $rows->get_error_message() ) ) ) . '
' ); } else { $reads[] = array( 'value' => $rows, 'detail' => false, ); echo ( '| ' . esc_html__( 'Time (selected timezone)', 'logged-ai' ) . ' | ' . '' . esc_html__( 'Event', 'logged-ai' ) . ' | ' . '' . esc_html__( 'Actor', 'logged-ai' ) . ' | ' . '' . esc_html__( 'Outcome', 'logged-ai' ) . ' | ' . '
|---|---|---|---|
| ' . ( esc_html( $time->text( $event['occurred_at'] ) ) ) . ' | ' . '' . '' . ( esc_html( $event['code'] ) ) . '' . ' | ' . '' . ( esc_html( ( $event['actor_id'] ? sprintf( /* translators: 1: Value shown in this message. */ __( 'User #%1$s', 'logged-ai' ), $event['actor_id'] ) : $event['actor_kind'] ) ) ) . ' | ' . '' . ( esc_html( $event['outcome'] ) ) . ' | ' . '