PluginProbe ʕ •ᴥ•ʔ
Advanced Database Cleaner – Optimize & Clean Database to Speed Up Site Performance / trunk
Advanced Database Cleaner – Optimize & Clean Database to Speed Up Site Performance vtrunk
4.2.0 trunk 1.0.0 1.1.0 1.1.1 1.2.0 1.2.1 1.2.2 1.2.3 1.3.0 1.3.1 1.3.5 1.3.6 1.3.7 2.0.0 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.1.0 4.1.1
advanced-database-cleaner / includes / classes / class-adbc-settings.php
advanced-database-cleaner / includes / classes Last commit date
addons 6 days ago general-cleanup 6 days ago class-adbc-admin-init.php 6 days ago class-adbc-automation.php 6 days ago class-adbc-hardcoded-items.php 6 days ago class-adbc-migration.php 6 days ago class-adbc-routes.php 6 days ago class-adbc-scan-counter.php 7 months ago class-adbc-settings.php 6 days ago class-adbc-singleton.php 7 months ago
class-adbc-settings.php
370 lines
1 <?php
2
3 // Exit if accessed directly
4 if ( ! defined( 'ABSPATH' ) )
5 exit;
6
7 /**
8 * ADBC settings class.
9 *
10 * This class provides the plugin settings functions.
11 */
12 class ADBC_Settings extends ADBC_Singleton {
13
14
15 // Holds the default settings for the plugin that are accepted to be updated in the database with their validators.
16 private $default_settings = array();
17
18 /**
19 * Stores the plugin settings locally to avoid multiple database calls.
20 *
21 * @var array
22 */
23 private $settings = array();
24
25 /**
26 * Constructor.
27 */
28 protected function __construct() {
29 parent::__construct();
30 $this->prepare_default_settings(); // Initialize the default settings and their validators.
31 $this->load_settings(); // Load settings from the database into the local attribute $settings and validate them.
32 }
33
34 /**
35 * Initialize the default settings and their validators.
36 *
37 * @return void
38 */
39 private function prepare_default_settings() {
40
41 $this->default_settings = [
42 'installed_on' => [
43 'default' => date( "d/m/Y" ),
44 'validator_class' => 'ADBC_Settings_Validator',
45 'validator_method' => 'is_valid_date'
46 ],
47 'left_menu' => [
48 'default' => '1',
49 'validator_class' => 'ADBC_Common_Validator',
50 'validator_method' => 'is_string_equals_0_or_1'
51 ],
52 'tools_menu' => [
53 'default' => '0',
54 'validator_class' => 'ADBC_Common_Validator',
55 'validator_method' => 'is_string_equals_0_or_1'
56 ],
57 'network_menu' => [
58 'default' => is_multisite() ? '1' : '0',
59 'validator_class' => 'ADBC_Common_Validator',
60 'validator_method' => 'is_string_equals_0_or_1'
61 ],
62 'hidden_tabs' => [
63 'default' => [],
64 'validator_class' => 'ADBC_Settings_Validator',
65 'validator_method' => 'are_valid_hiddenable_tabs'
66 ],
67 'send_corrections_to_server' => [
68 'default' => '0',
69 'validator_class' => 'ADBC_Common_Validator',
70 'validator_method' => 'is_string_equals_0_or_1'
71 ],
72 'analytics_enabled' => [
73 'default' => '1',
74 'validator_class' => 'ADBC_Common_Validator',
75 'validator_method' => 'is_string_equals_0_or_1'
76 ],
77 'analytics_execution' => [
78 'default' => [ "success" => 0, "fail" => 0 ],
79 'validator_class' => 'ADBC_Settings_Validator',
80 'validator_method' => 'is_execution_data_valid'
81 ],
82 'addons_activity_enabled' => [
83 'default' => '1',
84 'validator_class' => 'ADBC_Common_Validator',
85 'validator_method' => 'is_string_equals_0_or_1'
86 ],
87 'addons_activity_execution' => [
88 'default' => [ "success" => 0, "fail" => 0 ],
89 'validator_class' => 'ADBC_Settings_Validator',
90 'validator_method' => 'is_execution_data_valid'
91 ],
92 'show_tables_with_invalid_prefix' => [
93 'default' => '1',
94 'validator_class' => 'ADBC_Common_Validator',
95 'validator_method' => 'is_string_equals_0_or_1'
96 ],
97 'sidebar_is_expanded' => [
98 'default' => '1',
99 'validator_class' => 'ADBC_Common_Validator',
100 'validator_method' => 'is_string_equals_0_or_1'
101 ],
102 'file_lines_batch' => [
103 'default' => 10000,
104 'validator_class' => 'ADBC_Settings_Validator',
105 'validator_method' => 'is_scan_setting_valid'
106 ],
107 'database_rows_batch' => [
108 'default' => 100000,
109 'validator_class' => 'ADBC_Settings_Validator',
110 'validator_method' => 'is_performance_settings_valid'
111 ],
112 'file_content_chunks' => [
113 'default' => 1024 * 1, // (for 1024 KB)
114 'validator_class' => 'ADBC_Settings_Validator',
115 'validator_method' => 'is_scan_setting_valid'
116 ],
117 'scan_max_execution_time' => [
118 'default' => 0,
119 'validator_class' => 'ADBC_Settings_Validator',
120 'validator_method' => 'is_scan_setting_valid'
121 ],
122 'reduce_cpu_usage' => [
123 'default' => '0',
124 'validator_class' => 'ADBC_Common_Validator',
125 'validator_method' => 'is_string_equals_0_or_1'
126 ],
127 'cpu_work_time_ms' => [
128 'default' => 1000,
129 'validator_class' => 'ADBC_Settings_Validator',
130 'validator_method' => 'is_cpu_usage_time_valid'
131 ],
132 'cpu_rest_time_ms' => [
133 'default' => 10,
134 'validator_class' => 'ADBC_Settings_Validator',
135 'validator_method' => 'is_cpu_usage_time_valid'
136 ],
137 'api_scan_balance' => [
138 'default' => [],
139 'validator_class' => 'ADBC_Settings_Validator',
140 'validator_method' => 'is_api_scan_balance_valid'
141 ],
142 'security_code' => [
143 'default' => $this->generate_security_code(),
144 'validator_class' => 'ADBC_Settings_Validator',
145 'validator_method' => 'is_security_code_valid'
146 ],
147 'notifications' => [
148 'default' => [],
149 'validator_class' => 'ADBC_Settings_Validator',
150 'validator_method' => 'are_valid_notifications_keys'
151 ],
152 'keep_last' => [
153 'default' => self::default_keep_last(),
154 'validator_class' => 'ADBC_Settings_Validator',
155 'validator_method' => 'is_keep_last_valid'
156 ],
157 'rating_notice_date' => [
158 'default' => date( "d/m/Y" ),
159 'validator_class' => 'ADBC_Settings_Validator',
160 'validator_method' => 'is_valid_date'
161 ],
162 'ltd_migration_reminder_date' => [
163 'default' => '01/01/2000', // Past date so notice shows until user dismisses or delays
164 'validator_class' => 'ADBC_Settings_Validator',
165 'validator_method' => 'is_valid_date'
166 ],
167 'free_migration_done' => [
168 'default' => '0',
169 'validator_class' => 'ADBC_Common_Validator',
170 'validator_method' => 'is_string_equals_0_or_1'
171 ],
172 'sql_or_native_cleanup_method' => [
173 'default' => 'sql',
174 'validator_class' => 'ADBC_Settings_Validator',
175 'validator_method' => 'is_performance_settings_valid'
176 ],
177 'prevent_taking_action_on_wp_items' => [
178 'default' => '1',
179 'validator_class' => 'ADBC_Common_Validator',
180 'validator_method' => 'is_string_equals_0_or_1'
181 ],
182 'show_confirmation_on_dangerous_actions' => [
183 'default' => '1',
184 'validator_class' => 'ADBC_Common_Validator',
185 'validator_method' => 'is_string_equals_0_or_1'
186 ],
187 'general_cleanup_auto_count' => [
188 'default' => [],
189 'validator_class' => 'ADBC_Settings_Validator',
190 'validator_method' => 'is_general_cleanup_auto_count_valid'
191 ],
192 ];
193 }
194
195 /**
196 * Retrieve settings from the database and validate them.
197 *
198 * @return void
199 */
200 private function load_settings() {
201
202 global $wpdb;
203
204 // Acquire a MySQL advisory lock to prevent concurrent settings initialization.
205 // When the settings option is missing (e.g. after deletion), multiple parallel requests
206 // would each generate a different security_code, causing multiple upload folders to be created.
207 // The lock serializes initialization so only the first process generates and saves the settings;
208 // subsequent processes will read the already-persisted values.
209 $lock_name = 'adbc_settings_init';
210 $lock_timeout = 2; // 2 seconds
211 $got_lock = (bool) $wpdb->get_var( $wpdb->prepare( "SELECT GET_LOCK(%s, %d)", $lock_name, $lock_timeout ) );
212
213 $stored_settings = get_option( 'adbc_plugin_settings', [] );
214 $stored_settings = is_array( $stored_settings ) ? $stored_settings : [];
215
216 $db_needs_update = false;
217
218 // Loop through all default settings and check if they exist in the database.
219 foreach ( $this->default_settings as $key => $config ) {
220
221 if ( ! array_key_exists( $key, $stored_settings ) ) { // If the setting does not exist in the database, add it with its default value.
222 if ( $key === 'general_cleanup_auto_count' ) {
223 $value = ADBC_Cleanup_Type_Registry::get_default_auto_count_items_types();
224 } else {
225 $value = $config['default'];
226 }
227 $db_needs_update = true;
228 } else { // If the setting exists, validate it.
229 $value = $stored_settings[ $key ];
230 $validator_class = $config['validator_class'];
231 $validator_method = $config['validator_method'];
232 if ( ! call_user_func( [ $validator_class, $validator_method ], $key, $value ) ) {
233 // Reset to default if validation fails.
234 if ( $key === 'general_cleanup_auto_count' ) {
235 $value = ADBC_Cleanup_Type_Registry::get_default_auto_count_items_types();
236 } else {
237 $value = $config['default'];
238 }
239 $db_needs_update = true;
240 }
241 }
242
243 $this->settings[ $key ] = $value;
244 }
245
246 // Check if there is at least a setting in the DB that is not in the default settings. In this case, we need to update the DB to remove it.
247 foreach ( $stored_settings as $key => $value ) {
248 if ( ! array_key_exists( $key, $this->default_settings ) ) {
249 $db_needs_update = true;
250 break;
251 }
252 }
253
254 // Make sure at least one menu is shown in the admin menu.
255 if ( is_multisite() ) {
256 if ( $this->settings['left_menu'] === '0' && $this->settings['tools_menu'] === '0' && $this->settings['network_menu'] === '0' ) {
257 $this->settings['network_menu'] = '1';
258 $db_needs_update = true;
259 }
260 } else {
261 if ( $this->settings['left_menu'] === '0' && $this->settings['tools_menu'] === '0' ) {
262 $this->settings['left_menu'] = '1';
263 $db_needs_update = true;
264 }
265 }
266
267 // Save if any settings were initialized with defaults
268 if ( $db_needs_update )
269 $this->update_settings_in_db();
270
271 // Release the advisory lock now that settings are persisted.
272 if ( $got_lock )
273 $wpdb->query( $wpdb->prepare( "SELECT RELEASE_LOCK(%s)", $lock_name ) );
274
275 }
276
277 /**
278 * Update settings in the database by keys. We assume all settings with their values have been validated before calling this function.
279 *
280 * @param array $new_settings Array of new settings to update.
281 * @return bool True if the update was successful, false otherwise.
282 */
283 public function update_settings( $new_settings ) {
284 foreach ( $new_settings as $key => $value ) {
285 $this->settings[ $key ] = $value;
286 }
287 return $this->update_settings_in_db();
288 }
289
290 /**
291 * Update settings in the database
292 *
293 * @return bool True if the update was successful, false otherwise.
294 */
295 private function update_settings_in_db() {
296 return update_option( 'adbc_plugin_settings', $this->settings, false );
297 }
298
299 /**
300 * Returns the default settings keys for the plugin from the variable $default_settings (not the database).
301 *
302 * @return array The default settings keys.
303 */
304 public function get_settings_keys() {
305 return array_keys( $this->default_settings );
306 }
307
308 /**
309 * Get all ADBC settings that are stored in the database.
310 *
311 * @return array Settings array or empty array if not found.
312 */
313 public function get_settings( $return_sensitive_settings = true ) {
314
315 $settings = $this->settings;
316
317 // Return all settings except the security code if the parameter is set to false.
318 if ( $return_sensitive_settings === false ) {
319
320 // Unset security code
321 unset( $settings['security_code'] );
322 return $settings;
323 }
324
325 return $settings;
326 }
327
328 /**
329 * Get a specific ADBC setting by key.
330 *
331 * @param string $key Setting key.
332 * @return mixed Setting value or null if not found.
333 */
334 public function get_setting( $key ) {
335 return isset( $this->settings[ $key ] ) ? $this->settings[ $key ] : null;
336 }
337
338 /**
339 * Generate a new ADBC uploads folder security code.
340 *
341 * @return string The generated security code.
342 */
343 private function generate_security_code() {
344 $permitted_chars = '00112233445566778899abcdefghijklmnopqrstuvwxyz___';
345 $security_code = substr( str_shuffle( $permitted_chars ), 0, ADBC_SECURITY_CODE_LENGTH );
346 return $security_code;
347 }
348
349 /**
350 * Returns the recommended default keep-last rules for Action Scheduler data.
351 *
352 * These rules are seeded on new installations. Existing installations receive
353 * missing rules once through the 4.2.0 migration in load_settings().
354 *
355 * @return array<string, array{type: string, value: int}>
356 */
357 private static function default_keep_last() {
358 return [
359 'actionscheduler_completed_actions' => [ 'type' => 'days', 'value' => 30 ],
360 'actionscheduler_failed_actions' => [ 'type' => 'days', 'value' => 30 ],
361 'actionscheduler_canceled_actions' => [ 'type' => 'days', 'value' => 14 ],
362 'actionscheduler_completed_logs' => [ 'type' => 'days', 'value' => 14 ],
363 'actionscheduler_failed_logs' => [ 'type' => 'days', 'value' => 30 ],
364 'actionscheduler_canceled_logs' => [ 'type' => 'days', 'value' => 14 ],
365 'actionscheduler_orphan_logs' => [ 'type' => 'days', 'value' => 14 ],
366 ];
367 }
368
369 }
370