drupal_process_form() does not clear the form on submit when the page cache is activated:

// We'll clear out the cached copies of the form and its stored data
// here, as we've finished with them. The in-memory copies are still
// here, though.
if (variable_get('cache', CACHE_DISABLED) == CACHE_DISABLED && !empty($form_state['values']['form_build_id'])) {
  cache_clear_all('form_'. $form_state['values']['form_build_id'], 'cache_form');
  cache_clear_all('storage_'. $form_state['values']['form_build_id'], 'cache_form');
}

chx suggested that it might be because the form build id is set in stone when using a form on a cached page. But in that case, drupal_get_form() will rebuild the form anyway, so this check can probably go away.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Damien Tournoud’s picture

Status: Active » Needs review
FileSize
1000 bytes

Untested patch for review.

andypost’s picture

Patch is trivial, so rtbc...

catch’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: +Quick fix
Dries’s picture

Version: 7.x-dev » 6.x-dev

Committed to CVS HEAD. This might need to go into Drupal 6 so updating version for Gabor.

chx’s picture

Version: 6.x-dev » 7.x-dev
Status: Reviewed & tested by the community » Needs work

Huh, what? The presumption was that the form, as cached, is reusable for folks, why this patch was necessary?

Gábor Hojtsy’s picture

Committed and then rolled back in Drupal 6 due to chx's comment.

chx’s picture

Status: Needs work » Needs review
FileSize
3.87 KB

I am not happy with Gabor's so quickly jumping the gun :( oh well.

When writing FAPI3 two years ago (wow so long) we put an extra effort in so that anonymous forms especially the login form is cacheable. The reason for this was, originally we wanted every form to be cached and in this case, forms would break if they would be cached by the page cache but not the form cache. We have decided at the end against this so the code might reflect the earlier decision. Rebuilding the login form when the page cache expires is a quick enough operation not to worry about.

However, the patch made us discover a bug , where #cache TRUE forms can be broken for anonymous users when page caching is on. See, the build id will be the same and then if anon user A rebuilds the form based on her submission then anon user B wil see the wrong form.

Status: Needs review » Needs work

The last submitted patch failed testing.

Gábor Hojtsy’s picture

I am happy that I was quick in jumping the gun, after all you opposed committing the patch, and there should be nothing committed in a form of backport in D6, which is actively opposed in D7. I am also happy that this triggered finding an actual bug. Good.

andypost’s picture

Why not to leave - better to check cache than call 2 cache_clear_all()

-      if (variable_get('cache', CACHE_DISABLED) == CACHE_DISABLED && !empty($form_state['values']['form_build_id'])) {
+      if (variable_get('cache', CACHE_DISABLED) != CACHE_DISABLED && !empty($form_state['values']['form_build_id'])) {

sun’s picture

Status: Needs work » Reviewed & tested by the community
FileSize
910 bytes

First of all, this needs to be rolled back quickly.

Next (yeah, you know what comes), if there were tests, the original patch would not have passed.

Damien Tournoud’s picture

@sun: I don't see why you think that the original patch would not have passed. As far as I know, this is nothing more then a performance optimization. Please stop you #fail campaign, it's annoying for everyone else.

andypost’s picture

@Damien Tournoud as performance I propose to include check for "is cache enabled"

Dries’s picture

I've rolled back this patch so we can discuss it more.

catch’s picture

Status: Reviewed & tested by the community » Needs work

#7 no longer applies so back to cnw.

jbrauer’s picture

FileSize
3.23 KB

Re-rolling #7. Used a version of this patch in D6 and it works for solving problems with user registration, AHAH and page caching where the build ids were previously stepping on one another.

sun’s picture

Issue tags: -Quick fix

Let's revisit this. I'm not sure I understand chx's reasoning to additionally include the session ID in the cache ID, since a new form_build_id is generated for every build of a form, except when a form is retrieved from cache, which should only happen for POST requests.

yonailo’s picture

@sun, If I have well understood chx in comment #7, if #cache = TRUE and page caching is ON, then anonymous users can get the same "form_build_id", even without performing any POST requests. The session_id stuff would allow to not get the cached form copy if it does not belong to the user that created the cached page the first time.

But I think that the condition to not clearing out the form cache if the cache of pages is ON, is still very valid, I confess that I have not tested the patch in #16, but I would expect to have problems with #cache = TRUE + a form in a cached page if we remove the "form" cached version and at the same time we keep running with the cached page version....

The right question to answer here is: does "form cache" + "page cache" + #cache = TRUE work (D6), and how does it work ?
The current answer (D6) is "yes, as long as the form cache is not removed before the cache page", and the current problem with the current behavior is "pollution of form_cache entries".

PS: I can confirm that I have experienced issues with AHAH forms inside cached pages if the form cache version is deleted without deleting the page's cache. Deleting the form cache always as the patch in #7 does, does not help IMHO.

PSS: The "global $user" right after the declaration of "fonction drupal_process_form" is useless IMHO too.

Hope this helps

sun’s picture

Version: 7.x-dev » 8.x-dev

Apparently, all patches here conflicted with #1694574: drupal_process_form() deletes cached form + form_state despite still needed for later POSTs with enabled page caching and would have made that bug even more apparent.

DaneMacaulay’s picture

This one made us think for a bit, heres my recap.

Problem: cached forms may reach a state where the build id is no longer valid.
Cause: The form build id no longer exists in the caching table because it is older than 6 hours and we've performed garbage collection via cron, removing it from the form_cache table.
Solution (not really): set max page cache lifetime to 6 hours so that we regenerate form build ids around the same time our build ids become invalid and are set to be deleted by cron.

Timeline of a broken form:
0 hour: generate page and form id, cache both.
+6 hours: form_cache's build id is now expired, but still valid (Drupal just checks if it exists in the cache table)
Sometime after 6 hours: cron runs, deletes expired build ids and breaks cached pages.

Note: on form render, Drupal will create a new build id if the current id is expired.

quicksketch’s picture

Issue summary: View changes

Thanks @DaneMacaulay, that's a good summary. That helped me understand what we're dealing with here.

I should add that in almost all cases, the first build ID has absolutely no value, because it's just a blank form, possibly pre-populated with some default values. Let's say an anonymous user is leaving a comment and uses the "Preview" button. If the cache_form table (or key_value_expire table in D8) has an entry, then that version of the comment form is used. If not, the form is regenerated for anonymous (with a new build ID) so that it can be submitted. Regenerating the form to submit it is trivial, as we do this for all authenticated users on every page load with a form on it.

So in summary, keeping the form builds for first-load anonymous users has no value. Therefor, clearing the build on the first submit has no penalty. So the patch here makes an improvement as it prevent the cache_form table from being filled up with worthless caches (one per *every* form ever generated *or* submitted!) For consistency, in addition to this patch , the best thing to do would be to not save an initial build for anonymous users in the first place.

quicksketch’s picture

So in summary, keeping the form builds for first-load anonymous users has no value.

Scratch that. After reading through #1694574: drupal_process_form() deletes cached form + form_state despite still needed for later POSTs with enabled page caching, it's apparent that any use of #ajax is dependent up on this first-time build ID. If we removed it for anonymous users, things like AJAX file uploads would not work for anonymous users (very common in modules like Webform). So this exposes yet another bug: If your cache lifetime is longer than 6 hours, after that time period, AJAX uploads will fail as well for anonymous users.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

  • Dries committed 33368da on 8.3.x
    - Patch #343415 by Damien Tournoud: form cache is not cleared on submit...
  • Dries committed 13c9e7f on 8.3.x
    - Rolled back patch #343415.  Needs more work and discussion.
    
    

  • Dries committed 33368da on 8.3.x
    - Patch #343415 by Damien Tournoud: form cache is not cleared on submit...
  • Dries committed 13c9e7f on 8.3.x
    - Rolled back patch #343415.  Needs more work and discussion.
    
    

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

  • Dries committed 33368da on 8.4.x
    - Patch #343415 by Damien Tournoud: form cache is not cleared on submit...
  • Dries committed 13c9e7f on 8.4.x
    - Rolled back patch #343415.  Needs more work and discussion.
    
    

  • Dries committed 33368da on 8.4.x
    - Patch #343415 by Damien Tournoud: form cache is not cleared on submit...
  • Dries committed 13c9e7f on 8.4.x
    - Rolled back patch #343415.  Needs more work and discussion.
    
    

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.8.x-dev

Drupal 8.6.x will not receive any further development aside from security fixes. Bug reports should be targeted against the 8.8.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.9.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

  • Dries committed 33368da on 9.1.x
    - Patch #343415 by Damien Tournoud: form cache is not cleared on submit...
  • Dries committed 13c9e7f on 9.1.x
    - Rolled back patch #343415.  Needs more work and discussion.
    
    

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

catch’s picture

Status: Needs work » Closed (outdated)

This has been resolved by now, in issues like #512026: Move $form_state storage from cache to new state/key-value system. Marking outdated.

catch’s picture

Issue tags: +Bug Smash Initiative