PluginProbe
Elementor Website Builder – more than just a page builder / 4.3.4
Elementor Website Builder – more than just a page builder v4.3.4
4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 4.3.0-beta3 4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 All 457 releases
elementor / vendor / elementor / wp-one-package / src / LogStore.php

LogStore.php in Elementor Website Builder – more than just a page builder 4.3.4, at vendor/elementor/wp-one-package/src/LogStore.php

156 lines 3.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace ElementorOne;
4
5 if ( ! defined( 'ABSPATH' ) ) {
6 exit;
7 }
8
9 /**
10 * Ring buffer persisted in a non-autoloaded wp_option.
11 */
12 class LogStore {
13
14 public const OPTION_KEY = 'elementor_one_internal_logs';
15
16 public const MAX_ENTRIES = 50;
17
18 public const MAX_MESSAGE_LENGTH = 1048;
19
20 public const MAX_CALL_STACK_LENGTH = 1048;
21
22 /**
23 * @var LogStore|null
24 */
25 private static ?LogStore $instance = null;
26
27 /**
28 * @var bool
29 */
30 private bool $is_writing = false;
31
32 /**
33 * @return LogStore
34 */
35 public static function instance(): LogStore {
36 if ( null === self::$instance ) {
37 self::$instance = new self();
38 }
39
40 return self::$instance;
41 }
42
43 /**
44 * @param string $level
45 * @param string $message
46 * @param array<string, mixed> $context
47 * @return void
48 */
49 public function append( string $level, string $message, array $context = [] ): void {
50 if ( $this->is_writing ) {
51 return;
52 }
53
54 $this->is_writing = true;
55
56 try {
57 $entries = get_option( self::OPTION_KEY, [] );
58
59 if ( ! is_array( $entries ) ) {
60 $entries = [];
61 }
62
63 $entries[] = [
64 'id' => $this->generate_entry_id(),
65 'timestamp' => gmdate( 'c' ),
66 'level' => $level,
67 'message' => $this->truncate_message( $message ),
68 'context' => $this->normalize_context( $context ),
69 ];
70
71 if ( count( $entries ) > self::MAX_ENTRIES ) {
72 $entries = array_slice( $entries, -self::MAX_ENTRIES );
73 }
74
75 update_option( self::OPTION_KEY, $entries, false );
76 } catch ( \Throwable $e ) {
77 unset( $e );
78 } finally {
79 $this->is_writing = false;
80 }
81 }
82
83 /**
84 * @return array<int, array<string, mixed>>
85 */
86 public function all(): array {
87 $entries = get_option( self::OPTION_KEY, [] );
88
89 if ( ! is_array( $entries ) ) {
90 return [];
91 }
92
93 return $entries;
94 }
95
96 /**
97 * @return array<int, array<string, mixed>>
98 */
99 public function all_newest_first(): array {
100 return array_reverse( $this->all() );
101 }
102
103 /**
104 * @return bool
105 */
106 public function clear(): bool {
107 return delete_option( self::OPTION_KEY );
108 }
109
110 /**
111 * @return string
112 */
113 private function generate_entry_id(): string {
114 if ( function_exists( 'wp_generate_uuid4' ) ) {
115 return wp_generate_uuid4();
116 }
117
118 return uniqid( 'log_', true );
119 }
120
121 /**
122 * @param string $message
123 * @return string
124 */
125 private function truncate_message( string $message ): string {
126 if ( strlen( $message ) <= self::MAX_MESSAGE_LENGTH ) {
127 return $message;
128 }
129
130 return substr( $message, 0, self::MAX_MESSAGE_LENGTH );
131 }
132
133 /**
134 * @param array<string, mixed> $context
135 * @return array{source: string, call_stack: string}
136 */
137 private function normalize_context( array $context ): array {
138 $source = isset( $context['source'] ) && is_string( $context['source'] )
139 ? $context['source']
140 : '';
141
142 $call_stack = isset( $context['call_stack'] ) && is_string( $context['call_stack'] )
143 ? $context['call_stack']
144 : '';
145
146 if ( strlen( $call_stack ) > self::MAX_CALL_STACK_LENGTH ) {
147 $call_stack = substr( $call_stack, 0, self::MAX_CALL_STACK_LENGTH );
148 }
149
150 return [
151 'source' => $source,
152 'call_stack' => $call_stack,
153 ];
154 }
155 }
156