Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Creating tests for Tribe__PUE__Notices class. #2332

Merged
merged 22 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
a5e4431
Creating tests for Tribe__PUE__Notices class.
redscar Dec 20, 2024
04a3be4
Implemented new method `clear_all_notices` for testing. Working on fi…
redscar Dec 20, 2024
7f0bc16
Created new tests, added fix to `Notices.php`.
redscar Dec 20, 2024
04e1205
Fixed typo.
redscar Dec 20, 2024
068eefc
Added `@since`
redscar Dec 20, 2024
8379874
Added use statement back.
redscar Dec 20, 2024
a466513
Merge branch 'release/T25.imp' into fix/PUE_Notices_duplication
redscar Jan 6, 2025
5dd711d
Rewrote populate logic to implement sanitize_notices method that fixe…
redscar Jan 6, 2025
6a06b02
Updated WP version for slic.
redscar Jan 6, 2025
c057af7
Merge branch 'release/T25.imp' into fix/PUE_Notices_duplication
redscar Jan 8, 2025
23536d9
Reverting changes I made to tests-php-eva.yml
redscar Jan 8, 2025
fadc09e
Reverting changes I made to tests-php.yml
redscar Jan 8, 2025
32cfabc
Added changelog entry.
redscar Jan 8, 2025
a2f4bd4
Refactored populate logic to optimize it.
redscar Jan 8, 2025
2e4bddf
Remove redundant blank lines in Notices.php
redscar Jan 8, 2025
25e30e8
Simplify populate and store logic of notices
dpanta94 Jan 9, 2025
6cd59cc
Fix test cases
dpanta94 Jan 9, 2025
19a673f
Added memory exhaustion test
dpanta94 Jan 9, 2025
4671719
Update src/Tribe/PUE/Notices.php
dpanta94 Jan 9, 2025
5f2c642
Update src/Tribe/PUE/Notices.php
dpanta94 Jan 9, 2025
3235b4e
Added TBD to `save_notices`.
redscar Jan 9, 2025
1d1c108
Removed the `clear_all_notices` method and replaced `tribe()` calls w…
redscar Jan 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions changelog/fix-PUE_Notices_duplication
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: fix

Improved data sanitization for tribe_pue_key_notices to prevent memory exhaustion errors caused by corrupted data. [ET-2277]
112 changes: 100 additions & 12 deletions src/Tribe/PUE/Notices.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,36 @@ class Tribe__PUE__Notices {
const EXPIRED_KEY = 'expired_key';
const STORE_KEY = 'tribe_pue_key_notices';

/**
* List of registered plugin names for use in notifications.
*
* Holds an array of plugin names that are registered during
* a request. Only registered plugins will appear in notifications.
*
* @var string[]
*/
protected $registered = [];

/**
* Notices previously saved in the database.
*
* Holds the saved notices retrieved from the database,
* typically via the `get_option` function. It serves as a reference for
* comparing or merging with current notices.
*
* @var array<string, array<string, bool>>
*/
protected $saved_notices = [];

/**
* Notices to be displayed or processed during the current request.
*
* Contains the current set of notices, which may include
* notices added during the current request. It is merged with
* `$saved_notices` to ensure consistency.
*
* @var array<string, array<string, bool>>
*/
protected $notices = [];

protected $plugin_names = [
Expand Down Expand Up @@ -85,28 +113,72 @@ public function register_name( $plugin_name ) {
}

/**
* Restores plugins added on previous requests to the relevant notification
* groups.
* Restores and sanitizes plugin notices to ensure data integrity and prevent memory issues.
*
* Retrieves saved notices from the database, validates and sanitizes them,
* and merges them with the current request's notices. If discrepancies or corrupted data
* are detected, it updates the database to reflect the corrected state.
*
* @since TBD Switched from `array_merge_recursive` to `wp_parse_args` to fix data duplication issues. Added additional sanitation and memory safeguards to handle large data sets effectively.
*
* @return void
*/
protected function populate() {
$this->saved_notices = (array) get_option( self::STORE_KEY, [] );
$saved_notices = get_option( self::STORE_KEY, [] );

if ( empty( $this->saved_notices ) ) {
return;
// If $saved_notices is not an array, reset it to an empty array.
$original_saved_notices = is_array( $saved_notices ) ? $saved_notices : [];

// Sanitize $saved_notices.
$sanitized_saved_notices = $this->sanitize_notices( $original_saved_notices );

// Update the option if sanitized data differs or the original data was not an array.
if ( $saved_notices !== $sanitized_saved_notices ) {
update_option( self::STORE_KEY, $sanitized_saved_notices );
}

$this->notices = array_merge_recursive( $this->notices, $this->saved_notices );
unset( $saved_notices );

// Set the sanitized saved notices to the class property.
$this->saved_notices = $sanitized_saved_notices;

// Cleanup
foreach ( $this->notices as $key => &$plugin_lists ) {
// Purge any elements that are not arrays
if ( ! is_array( $plugin_lists ) ) {
unset( $this->notices[ $key ] );
// Unset $sanitized_saved_notices to free memory.
unset( $sanitized_saved_notices, $original_saved_notices );

// Merge and sanitize notices with the saved notices.
$this->notices = $this->sanitize_notices(
wp_parse_args( $this->notices, $this->saved_notices )
);

// Save the final sanitized and merged notices back to the database if they differ.
if ( $this->saved_notices !== $this->notices ) {
update_option( self::STORE_KEY, $this->notices );
}
}

/**
* Recursively sanitizes notices to prevent nesting and ensure data integrity.
*
* @param array $notices The array of notices to sanitize.
*
* @return array Sanitized notices.
dpanta94 marked this conversation as resolved.
Show resolved Hide resolved
*/
protected function sanitize_notices( array $notices ): array {
foreach ( $notices as $key => &$plugin_list ) {
// Ensure the value is an array; otherwise, reset it.
if ( ! is_array( $plugin_list ) ) {
$plugin_list = [];
Camwyn marked this conversation as resolved.
Show resolved Hide resolved
continue;
}

foreach ( $plugin_list as $plugin => $data ) {
// Flatten deeply nested arrays and set the value to `true`.
$plugin_list[ $plugin ] = true;
}
}
}

return $notices;
}
/**
* Saves any license key notices already added.
*/
Expand Down Expand Up @@ -566,4 +638,20 @@ protected function get_formatted_plugin_names( $group ) {

return '<span class="plugin-list">' . $html . '</span>';
}

/**
* Clears all stored and saved notices.
*
* This method resets both the `notices` and `saved_notices` properties to empty arrays,
* effectively removing all license key notifications from memory.
*
* Note: This does not persist changes to the database. To save changes,
* ensure `save_notices()` is called after invoking this method.
*
* @return void
dpanta94 marked this conversation as resolved.
Show resolved Hide resolved
*/
public function clear_all_notices() {
$this->notices = [];
$this->saved_notices = [];
}
}
Loading
Loading