New duplicate check#2133
Conversation
WalkthroughThe pull request introduces enhancements to the Changes
Possibly related PRs
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Outside diff range and nitpick comments (3)
classes/models/FrmEntryMeta.php (1)
128-132: Consider additional validation for the unique ID.The implementation correctly stores the unique ID in entry metadata with proper sanitization. However, consider adding validation for the unique ID format to ensure it matches the expected pattern.
$unique_id = FrmAppHelper::get_post_param( 'unique_id', '', 'sanitize_key' ); -if ( $unique_id ) { +if ( $unique_id && preg_match('/^[a-z0-9]{9}$/', $unique_id) ) { self::add_entry_meta( $entry_id, 0, '', compact( 'unique_id' ) ); }js/formidable.js (1)
1743-1748: Consider extracting unique ID generation to a separate function.The unique ID generation logic could be moved to a dedicated function for better maintainability and reusability.
Consider refactoring like this:
+ function generateUniqueId() { + return Array.from(crypto.getRandomValues(new Uint8Array(8))) + .map(b => b.toString(16).padStart(2, '0')) + .join('') + .substring(0, 9); + } + const uniqueIDInput = document.createElement('input'); uniqueIDInput.type = 'hidden'; uniqueIDInput.name = 'unique_id'; - uniqueIDInput.value = Math.random().toString(36).substring(2, 11); + uniqueIDInput.value = generateUniqueId(); object.appendChild(uniqueIDInput);classes/models/FrmEntry.php (1)
132-132: Update the@sincetag in the docblockThe
@since x.xtag should be updated with the appropriate version number to accurately document when this method was introduced.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (3)
classes/models/FrmEntry.php(3 hunks)classes/models/FrmEntryMeta.php(1 hunks)js/formidable.js(1 hunks)
🧰 Additional context used
🪛 GitHub Check: PHPStan
classes/models/FrmEntry.php
[failure] 155-155:
Only numeric types are allowed in -, int|false given on the left side.
🔇 Additional comments (4)
classes/models/FrmEntryMeta.php (1)
128-132: Verify JavaScript integration for unique ID generation.
Let's verify that the JavaScript code correctly generates and sends the unique ID in the expected format.
✅ Verification successful
Let me try a different search pattern to find the JavaScript code related to form submission and unique ID handling.
Based on the search results, I can now provide a final response as we have found the relevant JavaScript implementation for unique ID generation and form submission handling.
The unique ID generation and form submission integration is properly implemented
The JavaScript code in js/formidable.js correctly handles the unique ID generation:
- A hidden input field is created with name="unique_id"
- The value is generated using
Math.random().toString(36).substring(2, 11)which creates a random alphanumeric string - The field is properly appended to the form before submission
- The form submission handling includes both AJAX and regular form submission paths
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check the JavaScript implementation of unique ID generation
# Expected: Find the unique ID generation in the form submission code
# Search for unique ID generation in JavaScript files
echo "Searching for unique ID generation in JavaScript files..."
rg -A 5 "unique_id.*=" --type js
# Search for form submission handling
echo "Searching for form submission handling..."
ast-grep --pattern 'submitFormNow($$$) {
$$$
}'
Length of output: 304
Script:
#!/bin/bash
# Search for unique ID related code with broader patterns
echo "Searching for unique ID related code..."
rg -i "unique.*id" --type js -A 5
# Search for form submission with different pattern
echo "Searching for form submission code..."
rg "submit.*form" --type js -A 5
# Look for AJAX form submission
echo "Searching for AJAX form submission..."
rg "ajax.*submit|submit.*ajax" --type js -A 5
Length of output: 43687
js/formidable.js (1)
1743-1748: Verify the unique ID implementation in the backend.
The unique ID is being added to prevent duplicate form submissions, but we should verify that:
- The backend properly handles and stores this unique ID
- The duplicate check mechanism correctly uses this value
- The one-month extension of the duplicate check window is properly implemented
✅ Verification successful
Based on the shell script results, I can now generate the final response as the code shows clear evidence of how the unique ID is handled.
The unique ID implementation is properly handled in the backend
The verification confirms that:
- The unique ID is properly stored in
frm_item_metastable withfield_id=0(seeFrmEntryMeta.php) - The duplicate check mechanism uses this value by checking entries within a time window (see
FrmEntry::maybe_extend_duplicate_entry_time) - The one-month extension is correctly implemented using
MONTH_IN_SECONDSwhen a unique ID match is found
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check if the backend properly handles the unique ID
# Check for unique_id field handling in PHP files
rg -A 5 "unique_id" --type php
# Check for duplicate check related code
rg -A 10 "duplicate.*check|check.*duplicate" --type php
Length of output: 11179
classes/models/FrmEntry.php (2)
54-55: Enhancing duplicate entry time logic
The addition of maybe_extend_duplicate_entry_time effectively adjusts the duplicate entry time based on the presence of a unique ID, improving the accuracy of duplicate entry detection.
85-87: Skip processing for field IDs equal to zero
By adding a check to skip field_id equal to zero, the code correctly avoids processing invalid or special fields during the duplicate check, ensuring only relevant data is considered.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Outside diff range and nitpick comments (1)
classes/models/FrmEntry.php (1)
131-167: Consider adding error logging for debugging.The implementation looks solid, but consider adding debug logging when:
- A unique ID is found but malformed
- Database errors occur during the lookup
This will help track any issues in production.
Apply this diff to add logging:
private static function maybe_extend_duplicate_entry_time( $duplicate_entry_time, $created_at ) { if ( 60 !== $duplicate_entry_time ) { // Only check if the time has not been filtered. return $duplicate_entry_time; } $unique_id = FrmAppHelper::get_post_param( 'unique_id', '', 'sanitize_key' ); if ( ! $unique_id ) { // Only continue if a unique ID was generated on form submit. return $duplicate_entry_time; } $timestamp = strtotime( $created_at ); if ( false === $timestamp ) { $timestamp = time(); + if ( defined('WP_DEBUG') && WP_DEBUG ) { + error_log( sprintf( 'FrmEntry: Invalid created_at timestamp for unique_id %s', $unique_id ) ); + } } $unique_id_match = FrmDb::get_var( 'frm_item_metas', array( 'field_id' => 0, 'meta_value' => serialize( compact( 'unique_id' ) ), 'created_at >' => gmdate( 'Y-m-d H:i:s', $timestamp - MONTH_IN_SECONDS ), ), 'id' ); + if ( $unique_id_match === false && defined('WP_DEBUG') && WP_DEBUG ) { + error_log( sprintf( 'FrmEntry: Database error while checking unique_id %s', $unique_id ) ); + } // Extend the check to a month when unique ID is detected. return $unique_id_match ? MONTH_IN_SECONDS : $duplicate_entry_time; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
classes/models/FrmEntry.php(3 hunks)
🔇 Additional comments (3)
classes/models/FrmEntry.php (3)
54-55: LGTM: New method call is properly integrated.
The placement of maybe_extend_duplicate_entry_time is correct as it allows modifying the duplicate check window before constructing the database query conditions.
85-87: LGTM: Properly excludes metadata field from duplicate check.
The condition correctly skips field ID 0, which is used for storing the unique ID metadata, preventing it from affecting the duplicate entry comparison logic.
131-167: Verify the implementation works as expected.
Let's verify two critical aspects:
- The unique ID is stored in the correct format
- The duplicate check window is properly extended
✅ Verification successful
Implementation verified and working as expected
The verification shows the implementation is correct and complete:
- The unique ID is properly:
- Generated client-side with
Math.random()and stored as a hidden input - Sanitized server-side using
sanitize_key - Stored in serialized format in
frm_item_metastable withfield_id=0
- Generated client-side with
- The duplicate check window correctly:
- Defaults to 60 seconds
- Extends to
MONTH_IN_SECONDSwhen a matching unique ID is found - Uses proper timestamp comparison with
created_at >condition
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify unique ID storage format and duplicate check window extension
# Check if any entries have the unique ID stored in the expected format
echo "Checking unique ID format in database..."
rg -A 5 "a:1:\{s:9:\"unique_id\";"
# Check if the duplicate check window is being extended
echo "Checking duplicate check window extension..."
rg -A 10 "MONTH_IN_SECONDS"
# Check for any existing error logs related to this feature
echo "Checking for any existing error logs..."
rg "FrmEntry: (Invalid|Database error)"
Length of output: 2661
Script:
#!/bin/bash
# Let's verify the unique ID implementation more thoroughly
# Check how unique_id is generated and used
echo "Checking unique_id usage..."
rg -B 3 -A 3 "unique_id"
# Check for serialized data handling in frm_item_metas table
echo "Checking serialized data handling..."
ast-grep --pattern 'serialize($_)'
# Check for duplicate entry time window implementations
echo "Checking duplicate entry time implementations..."
rg -B 3 -A 3 "duplicate_entry_time"
# Check for any related tests
echo "Checking related tests..."
fd "test" -e php -x rg -l "unique_id|duplicate_entry"
Length of output: 6140
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Outside diff range and nitpick comments (1)
js/formidable.js (1)
1597-1607: Secure implementation of unique key generationThe implementation correctly uses the Web Crypto API (
crypto.getRandomValues()) for cryptographically secure random number generation, which is perfect for preventing duplicate form submissions.Add return description to JSDoc
The JSDoc comment is missing a description for the @return tag.
Apply this diff to improve the documentation:
/** * @since x.x * - * @return {string} + * @return {string} A 9-character cryptographically secure random string */🧰 Tools
🪛 eslint (1.23.1)
[error] 1600-1600: Missing JSDoc @return description.
(jsdoc/require-returns-description)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
js/formidable.js(2 hunks)
🧰 Additional context used
🪛 eslint (1.23.1)
js/formidable.js
[error] 1600-1600: Missing JSDoc @return description.
(jsdoc/require-returns-description)
🔇 Additional comments (1)
js/formidable.js (1)
1755-1761: LGTM! Clean implementation of unique ID field
The implementation correctly adds a hidden input field with a unique ID right before form submission, which will work seamlessly with both AJAX and regular form submissions. This change effectively addresses the issue of duplicate form submissions on iPhones by providing a consistent unique identifier.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Outside diff range and nitpick comments (1)
classes/models/FrmEntry.php (1)
167-175: Consider adding an index hint for the queryThe query looks for entries with matching unique ID within last month. Consider adding an index hint to optimize this frequently used query.
$unique_id_match = FrmDb::get_var( - 'frm_item_metas', + 'frm_item_metas USE INDEX (field_id)', array( 'field_id' => 0, 'meta_value' => serialize( compact( 'unique_id' ) ), 'created_at >' => gmdate( 'Y-m-d H:i:s', $timestamp - MONTH_IN_SECONDS ), ), 'id' );
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
classes/models/FrmEntry.php(3 hunks)
🔇 Additional comments (4)
classes/models/FrmEntry.php (4)
54-55: LGTM: Method call placement is correct
The maybe_extend_duplicate_entry_time is called at the appropriate point in the flow, before the duplicate entry check logic.
85-87: LGTM: Correctly skips unique ID from duplicate comparison
The check to skip field_id=0 is essential as it prevents the stored unique ID from affecting the duplicate entry detection logic.
162-165: LGTM: Proper handling of invalid timestamp
The code properly handles potential false return from strtotime() by falling back to current time.
131-179: Verify the impact of extending duplicate window to 1 month
The implementation correctly extends duplicate detection window to 1 month when unique ID matches. However, we should verify:
- Impact on database size from storing unique IDs
- Performance impact of longer duplicate check window
✅ Verification successful
Extending duplicate window to 1 month is safe with proper controls in place
The implementation has several safeguards that make this change safe:
- The extended window only applies when:
- The default 60-second window hasn't been filtered (
if ( 60 !== $duplicate_entry_time )) - A unique ID is present in the submission
- The
frm_extend_duplicate_entry_time_on_unique_id_matchfilter returns true
- The default 60-second window hasn't been filtered (
- Database impact is minimized because:
- Unique IDs are only stored temporarily (auto-cleaned after 1 month)
- Only matches from the last month are queried (
created_at >condition) - Users can opt-out via filter if performance issues arise
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check average number of entries per month to assess impact
rg -A 5 "created_at.*MONTH" . --type php | grep -v "test"
# Check current table size
mysql -e "SELECT table_name, table_rows, data_length, index_length
FROM information_schema.tables
WHERE table_name = 'frm_item_metas';"
Length of output: 638
Script:
#!/bin/bash
# Let's check for other uses of unique_id and duplicate entry time checks
rg -B 2 -A 5 "duplicate.*entry.*time" . --type php
# Check for any other places where we store data in frm_item_metas with field_id = 0
ast-grep --pattern 'FrmDb::get_var($$$"frm_item_metas"$$$)'
# Look for any performance related filters or configurations
rg "frm_extend_duplicate_entry_time" . --type php
Length of output: 4971
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Outside diff range and nitpick comments (1)
classes/models/FrmEntry.php (1)
141-177: LGTM! Well-implemented unique ID check with proper error handling.The implementation includes:
- Configurable opt-out filter for performance optimization
- Proper sanitization of user input
- Robust error handling for invalid timestamps
- Clear month-long window for duplicate detection
Consider adding unit tests to verify:
- The opt-out filter functionality
- Timestamp error handling
- Different unique ID scenarios
🧰 Tools
🪛 GitHub Check: PHPStan
[failure] 141-141:
PHPDoc tag @param references unknown parameter: $duplicate_entry_time
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (2)
classes/models/FrmEntry.php(3 hunks)js/formidable.js(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- js/formidable.js
🧰 Additional context used
🪛 GitHub Check: PHPStan
classes/models/FrmEntry.php
[failure] 141-141:
PHPDoc tag @param references unknown parameter: $duplicate_entry_time
🔇 Additional comments (3)
classes/models/FrmEntry.php (3)
54-57: LGTM! Early duplicate detection implementation looks good.
The placement of the unique ID check before other duplicate checks is optimal for performance, as it allows for early returns when duplicates are found.
88-90: LGTM! Proper handling of special metadata fields.
The condition correctly skips processing for field ID 0, which is used for storing metadata like the unique ID.
Line range hint 54-177: Verify integration with form submission process.
The implementation looks solid, but let's verify the complete flow of the unique ID through the system.
✅ Verification successful
The verification results show a complete integration flow:
- In
js/formidable.js, a unique ID is generated and added to the form submission via a hidden input field named 'unique_id'. - The unique ID is processed during form submission as shown in the reviewed code.
- The entry meta updates are handled through
FrmEntryMeta::update_entry_metas()which is properly integrated in both create and update flows inFrmEntry.php.
Let's verify one final aspect - the unique ID generation and form submission initialization:
Integration verified successfully
The implementation shows a complete, working flow for handling duplicate submissions:
- Client-side: A unique ID is properly generated via
getUniqueKey()and injected into form submissions through a hidden input field. - Server-side: The unique ID is checked against entries from the last month using
maybe_check_for_unique_id_match(). - Integration points: The unique ID check is properly integrated into the form submission flow through
FrmEntryMeta::update_entry_metas().
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify the integration points for unique ID handling
# Check for unique ID field in JavaScript form submission code
echo "Checking for unique ID handling in JS..."
rg -A 5 "unique_id" --type js
# Check for unique ID storage in entry metadata
echo "Checking for unique ID storage in entry meta..."
rg -A 5 "field_id\s*=>\s*0" --type php
# Check for form submission handling
echo "Checking form submission handlers..."
rg -A 5 "submitFormNow|update_entry_metas" --type php
Length of output: 3791
Script:
#!/bin/bash
# Check unique ID generation and form submission initialization
echo "Checking unique ID generation..."
rg -B 5 "getUniqueKey" --type js
echo "Checking form submission initialization..."
rg -B 5 "frm_ajax_submit|addUniqueIdToForm" --type js
Length of output: 4723
🧰 Tools
🪛 GitHub Check: PHPStan
[failure] 141-141:
PHPDoc tag @param references unknown parameter: $duplicate_entry_time
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Outside diff range and nitpick comments (2)
classes/models/FrmEntry.php (2)
133-138: Fix incorrect PHPDoc return type.The PHPDoc states
@return intbut the method returns a boolean value.Apply this diff to fix the documentation:
/** * @since x.x * * @param string $created_at * @return bool */
163-171: Consider using JSON instead of PHP serialization.Using PHP's
serialize()for data storage can be problematic if the data structure changes or if you need to interact with this data from other systems.Consider using
json_encode()instead:- 'meta_value' => serialize( compact( 'unique_id' ) ), + 'meta_value' => json_encode( compact( 'unique_id' ) ),
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
classes/models/FrmEntry.php(3 hunks)
🔇 Additional comments (4)
classes/models/FrmEntry.php (4)
54-56: LGTM! Early duplicate check implementation looks good.
The new unique ID check is well-placed as an early return condition before proceeding with other duplicate checks.
87-89: LGTM! Good defensive programming.
Skipping field_id=0 prevents processing system metadata used for storing the unique ID, which is the correct approach.
158-161: LGTM! Good timestamp validation.
The code properly handles invalid timestamps by falling back to the current time.
168-168: Verify MONTH_IN_SECONDS constant availability.
The code uses the MONTH_IN_SECONDS constant. Let's verify it's available.
✅ Verification successful
MONTH_IN_SECONDS constant is defined in stubs.php
The constant is properly defined in the project's stubs.php file, which is commonly used to define WordPress-related constants for development purposes. The constant is defined as 30 * DAY_IN_SECONDS, following WordPress core's definition pattern.
Let me verify if DAY_IN_SECONDS is also defined:
Let me check if HOUR_IN_SECONDS is also defined to complete the verification chain:
Let me verify the final constant MINUTE_IN_SECONDS to complete the entire chain:
MONTH_IN_SECONDS constant is properly defined and available
The constant is correctly defined in stubs.php with a complete chain of time-based constants:
- MINUTE_IN_SECONDS = 60
- HOUR_IN_SECONDS = 60 * MINUTE_IN_SECONDS
- DAY_IN_SECONDS = 24 * HOUR_IN_SECONDS
- MONTH_IN_SECONDS = 30 * DAY_IN_SECONDS
The usage in FrmEntry.php is safe and follows WordPress conventions.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check if MONTH_IN_SECONDS is defined in WordPress core or in this codebase
# Check WordPress core constant
rg "define.*MONTH_IN_SECONDS"
# Check if it's defined in this codebase
ast-grep --pattern 'define($_, "MONTH_IN_SECONDS")'
Length of output: 147
Script:
#!/bin/bash
# Check if DAY_IN_SECONDS is defined
rg "define.*DAY_IN_SECONDS"
Length of output: 274
Script:
#!/bin/bash
# Check if HOUR_IN_SECONDS is defined
rg "define.*HOUR_IN_SECONDS"
Length of output: 155
Script:
#!/bin/bash
# Check if MINUTE_IN_SECONDS is defined
rg "define.*MINUTE_IN_SECONDS"
Length of output: 142
|
@Crabcyborg The customer has replied and confirmed that the resubmission issue in Safari has been fixed with the latest patch. Customer tested under the following cuircumstances:
The partially displayed in the tests refer to how the message was displayed which is illustrated here: https://cln.sh/vHdqjNZ6 |
|
Thank you @Achilles28! |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Outside diff range and nitpick comments (3)
classes/models/FrmEntry.php (3)
133-138: Fix incorrect PHPDoc return type.The method returns a boolean but the PHPDoc indicates it returns an int.
Apply this diff to fix the documentation:
/** * @since x.x * * @param string $created_at - * @return int + * @return bool */
163-171: Consider adding an index for performance optimization.The query on
frm_item_metastable filtering byfield_idandmeta_valuecould benefit from an index, especially as the table grows.Consider adding a composite index on (field_id, meta_value) to optimize the duplicate check query:
ALTER TABLE `frm_item_metas` ADD INDEX `idx_field_meta` (`field_id`, `meta_value`(191));
152-156: Consider additional validation for unique_id.While
sanitize_keyprovides basic sanitization, consider adding length validation and more specific error handling for invalid unique IDs.Consider applying this diff:
$unique_id = FrmAppHelper::get_post_param( 'unique_id', '', 'sanitize_key' ); -if ( ! $unique_id ) { +if ( ! $unique_id || strlen($unique_id) !== 9 ) { // Only continue if a unique ID was generated on form submit. return false; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
classes/models/FrmEntry.php(3 hunks)
🔇 Additional comments (3)
classes/models/FrmEntry.php (3)
54-56: LGTM! Early duplicate check optimization.
The early check for unique ID matches is well-placed and helps optimize performance by avoiding unnecessary duplicate checks when an exact match is found.
87-89: LGTM! Proper handling of metadata fields.
Correctly skips field ID 0 during duplicate checks, maintaining clean separation between metadata (like unique_id) and actual form data.
158-161: LGTM! Proper timestamp fallback.
Good defensive programming by providing a fallback to current time if the timestamp parsing fails.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Outside diff range and nitpick comments (4)
classes/models/FrmEntryMeta.php (2)
128-133: Consider documenting the metadata structure.Since this implementation stores system data (unique ID) in entry metadata with
field_id=0, it would be helpful to document this convention in a code comment or documentation. This helps maintain the code and prevents accidental conflicts with future system metadata.Example addition to the comments:
// This unique ID is inserted with JS on form submit. // It is used to check for duplicate entries. +// The unique ID is stored in entry metadata with field_id=0 to distinguish it from regular field data.
128-133: Consider adding error logging for debugging.While the implementation is solid, adding debug logging when the unique ID is missing or invalid could help troubleshoot issues in production.
$unique_id = FrmAppHelper::get_post_param( 'unique_id', '', 'sanitize_key' ); +if ( defined( 'WP_DEBUG' ) && WP_DEBUG && empty( $unique_id ) ) { + error_log( 'Formidable Forms: Missing unique_id in form submission' ); +} if ( $unique_id && FrmEntry::should_check_for_unique_id_match() ) {classes/models/FrmEntry.php (2)
133-138: Fix return type hint in PHPDoc.The method only returns boolean values, so the return type hint should be updated.
- * @return false|int + * @return bool
Line range hint
54-166: Excellent implementation for preventing duplicate form submissions.The solution effectively addresses the iPhone resubmission issue by:
- Using a unique ID to track submissions
- Storing the ID in entry metadata
- Providing configurable duplicate checking
- Including proper validation and error handling
This aligns perfectly with the PR objectives and has been confirmed working by users.
Consider adding unit tests to verify:
- Unique ID generation and storage
- Duplicate detection with various time windows
- Filter hook functionality
Would you like me to help create these tests?🧰 Tools
🪛 GitHub Check: PHPStan
[failure] 139-139:
Method FrmEntry::maybe_check_for_unique_id_match() never returns int so it can be removed from the return type.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (2)
classes/models/FrmEntry.php(3 hunks)classes/models/FrmEntryMeta.php(1 hunks)
🧰 Additional context used
🪛 GitHub Check: PHPStan
classes/models/FrmEntry.php
[failure] 139-139:
Method FrmEntry::maybe_check_for_unique_id_match() never returns int so it can be removed from the return type.
🔇 Additional comments (6)
classes/models/FrmEntryMeta.php (2)
128-133: LGTM! The implementation properly handles the unique ID storage.
The code correctly:
- Sanitizes the unique ID input using
sanitize_key - Stores it in entry metadata with appropriate conditions
- Uses clear and descriptive comments
128-133: Verify the integration with JavaScript changes.
The comment indicates that the unique ID is inserted via JavaScript. Let's verify this integration to ensure the complete solution works as expected.
✅ Verification successful
Based on the search results, I can see that the JavaScript integration for the unique ID is properly implemented. The code shows:
- The unique ID is added during form submission in
js/formidable.js:
// Add a unique ID, used for duplicate checks.
const uniqueIDInput = document.createElement('input');
uniqueIDInput.type = 'hidden';
uniqueIDInput.name = 'unique_id';
uniqueIDInput.value = getUniqueKey();
object.appendChild(uniqueIDInput);- The form submission handling is properly set up with event listeners and the unique ID is added before the form is submitted.
Integration with JavaScript is properly implemented.
The JavaScript code adds a hidden input field with the unique ID during form submission, which matches with the PHP code that processes this unique ID. The integration is complete and working as expected.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for the JavaScript implementation that generates and inserts the unique ID.
# Expected: Find the JavaScript code that handles the unique ID insertion.
# Search for unique ID related code in JavaScript files
rg -t js "unique_id"
# Search for form submission handling code
ast-grep --pattern 'function $_(form) {
$$$
unique_id
$$$
}'
Length of output: 144
Script:
#!/bin/bash
# Let's get more context around the JavaScript implementation
rg -t js -B 5 -A 5 "unique_id"
# Also search for form submission related code that might handle this
rg -t js "beforeSubmit|submit" -B 5 -A 5
Length of output: 127757
classes/models/FrmEntry.php (4)
139-166: LGTM! Well-structured implementation of unique ID checking.
The method effectively:
- Validates the unique ID presence
- Handles invalid timestamps gracefully
- Uses a reasonable time window (1 month) for duplicate checks
- Properly serializes the meta value
🧰 Tools
🪛 GitHub Check: PHPStan
[failure] 139-139:
Method FrmEntry::maybe_check_for_unique_id_match() never returns int so it can be removed from the return type.
171-181: LGTM! Well-designed control method with extensibility.
The method provides a clean way to toggle unique ID checking with a filter hook for customization.
54-56: LGTM! Proper integration of unique ID checking.
The early return when a unique ID match is found is correctly placed and efficiently prevents unnecessary processing.
87-89: LGTM! Proper handling of system metadata.
The check correctly skips processing of system metadata (field_id = 0) which is important for the unique ID implementation.
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #2133 +/- ##
============================================
+ Coverage 27.16% 27.17% +0.01%
- Complexity 8187 8200 +13
============================================
Files 127 127
Lines 27183 27202 +19
============================================
+ Hits 7384 7392 +8
- Misses 19799 19810 +11 ☔ View full report in Codecov by Sentry. |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Outside diff range and nitpick comments (1)
classes/models/FrmEntry.php (1)
155-163: Consider making the time window configurable.The 1-month window (
MONTH_IN_SECONDS) for checking duplicate entries is currently hardcoded. Consider making this configurable through a filter hook, similar to howfrm_check_for_unique_id_matchworks.Example filter usage:
$time_window = apply_filters( 'frm_unique_id_time_window', MONTH_IN_SECONDS ); 'created_at >' => gmdate( 'Y-m-d H:i:s', $timestamp - $time_window ),🧰 Tools
🪛 GitHub Check: codecov/patch
[warning] 155-163: classes/models/FrmEntry.php#L155-L163
Added lines #L155 - L163 were not covered by tests
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
classes/models/FrmEntry.php(3 hunks)
🧰 Additional context used
🪛 GitHub Check: codecov/patch
classes/models/FrmEntry.php
[warning] 55-55: classes/models/FrmEntry.php#L55
Added line #L55 was not covered by tests
[warning] 88-88: classes/models/FrmEntry.php#L88
Added line #L88 was not covered by tests
[warning] 141-141: classes/models/FrmEntry.php#L141
Added line #L141 was not covered by tests
[warning] 150-152: classes/models/FrmEntry.php#L150-L152
Added lines #L150 - L152 were not covered by tests
[warning] 155-163: classes/models/FrmEntry.php#L155-L163
Added lines #L155 - L163 were not covered by tests
[warning] 165-165: classes/models/FrmEntry.php#L165
Added line #L165 was not covered by tests
🔇 Additional comments (4)
classes/models/FrmEntry.php (4)
54-56: LGTM! Early return for unique ID match is well-placed.
The addition of the unique ID check before other duplicate checks is an efficient approach that aligns with the PR objectives.
🧰 Tools
🪛 GitHub Check: codecov/patch
[warning] 55-55: classes/models/FrmEntry.php#L55
Added line #L55 was not covered by tests
87-89: LGTM! Skip processing for field_id=0 is a good optimization.
The check prevents unnecessary processing of metadata entries with field_id=0, which are used for storing the unique_id.
🧰 Tools
🪛 GitHub Check: codecov/patch
[warning] 88-88: classes/models/FrmEntry.php#L88
Added line #L88 was not covered by tests
168-182: LGTM! Well-documented filter hook for performance control.
The method provides a clean way to disable unique ID checks if needed, with clear documentation and appropriate use of WordPress filter patterns.
133-166: 🛠️ Refactor suggestion
Add unit tests and consider improving error handling.
The new method looks good but has a few areas for improvement:
- Add unit tests to cover this critical duplicate detection logic.
- Consider adding debug logging for when unique ID checks fail.
- Using
serialize()for DB storage can be problematic if the serialization format changes.
🧰 Tools
🪛 GitHub Check: codecov/patch
[warning] 141-141: classes/models/FrmEntry.php#L141
Added line #L141 was not covered by tests
[warning] 150-152: classes/models/FrmEntry.php#L150-L152
Added lines #L150 - L152 were not covered by tests
[warning] 155-163: classes/models/FrmEntry.php#L155-L163
Added lines #L155 - L163 were not covered by tests
[warning] 165-165: classes/models/FrmEntry.php#L165
Added line #L165 was not covered by tests
Related ticket https://secure.helpscout.net/conversation/2765614867/215349/
The issue
Reopening a page on an iPhone re-submits the POST request. Our duplicate check defaults to 60 seconds, but it's likely someone will open a page again hours later, maybe even days later.
The solution
I'm adding a unique string that gets added right before the form is submitted.
If this string is detected, it is checked in the duplicate check, and saved to entry meta under field 0, serialized as an array like
a:1:{s:9:"unique_id";s:9:"a34d2ypgn";}.When this exact item meta row is detected, during the duplicate check, it will return true immediately if there is a match.
The refresh events don't re-trigger the JavaScript, so all of these requests will send the same unique string.
Pre-release
formidable-6.16.3b.zip
To opt out In case the database query causes performance issues
This has been confirmed by the customer