diff --git a/core/includes/form.inc b/core/includes/form.inc index a12fb34..9316250 100644 --- a/core/includes/form.inc +++ b/core/includes/form.inc @@ -90,6 +90,13 @@ */ /** + * The default cache lifetime for forms, in seconds. + * + * 21600 seconds is six hours. + */ +define('FORM_CACHE_DEFAULT_LIFETIME', 21600); + +/** * Wrapper for drupal_build_form() for use when $form_state is not needed. * * @param $form_id @@ -512,22 +519,50 @@ function form_get_cache($form_build_id, &$form_state) { /** * Store a form in the cache. + * + * The form cache expiration (set in $form_state['cache_expire']) may be either + * a numeric value (in seconds) or a relative date format (for use with the PHP + * strtotime() function). Using a relative date format allows the cache + * expiration to be set independently of the cache build time. For example, if + * the expiration time is set to 'tomorrow', the cache will expire at midnight, + * regardless of whether the the cache was built at 10:00 a.m. or 11:55 p.m. + * + * @see http://www.php.net/manual/en/datetime.formats.relative.php + * */ function form_set_cache($form_build_id, $form, $form_state) { - // 6 hours cache life time for forms should be plenty. - $expire = 21600; + // If this form has a custom cache expiration set, use that. + if (!empty($form_state['cache_expire'])) { + $expire = $form_state['cache_expire']; + } + // Otherwise, retrieve the configured cache lifetime. + else { + $expire = variable_get('form_cache_expire', FORM_CACHE_DEFAULT_LIFETIME); + } + // If the expiration is non-numeric, assume it is a relative datetime. + if (!is_numeric($expire) && ($strtotime = strtotime($exipre))) { + $expire = $strtotime; + } + // A numeric expiration time is given as seconds from now. + elseif (is_numeric($expire)) { + $expire = REQUEST_TIME + $expire; + } + // Fall back to the default. + else { + $expire = REQUEST_TIME + FORM_CACHE_DEFAULT_LIFETIME; + } // Cache form structure. if (isset($form)) { if ($GLOBALS['user']->uid) { $form['#cache_token'] = drupal_get_token(); } - cache('form')->set('form_' . $form_build_id, $form, REQUEST_TIME + $expire); + cache('form')->set('form_' . $form_build_id, $form, $expire); } // Cache form state. if ($data = array_diff_key($form_state, array_flip(form_state_keys_no_cache()))) { - cache('form')->set('form_state_' . $form_build_id, $data, REQUEST_TIME + $expire); + cache('form')->set('form_state_' . $form_build_id, $data, $expire); } } diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc index a5a8885..41ef26d 100644 --- a/core/modules/system/system.admin.inc +++ b/core/modules/system/system.admin.inc @@ -1489,7 +1489,7 @@ function system_site_information_settings() { '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30)), '#description' => t('The maximum number of posts displayed on overview pages such as the front page.'), '#access' => (variable_get('site_frontpage')=='node'), - ); + ); $form['error_page'] = array( '#type' => 'fieldset', '#title' => t('Error pages'), @@ -1674,6 +1674,33 @@ function system_performance_settings() { '#description' => t('The maximum time an external cache can use an old version of a page.') ); + $form_cache_expire = variable_get('form_cache_expire', 21600); + $form['caching']['form_cache_expire'] = array( + '#type' => 'select', + '#title' => t('Expiration of cached forms'), + '#default_value' => $form_cache_expire, + '#options' => array('custom' => '<' . t('custom') . '>') + $period, + '#description' => t('The maximum time form and form_state are cached.') + ); + $form_cache_expire_custom = (is_numeric($form_cache_expire)) ? REQUEST_TIME + $form_cache_expire : strtotime($form_cache_expire); + $form['caching']['form_cache_expire_custom'] = array( + '#type' => 'textfield', + '#title' => t('Custom form cache expiration'), + '#default_value' => $form_cache_expire, + '#field_suffix' => t( + '%expire evaluates to %expiration_date', + array( + '%expire' => $form_cache_expire, + '%expiration_date' => date('Y/m/d - H:i:s', $form_cache_expire_custom), + ) + ), + '#description' => t('Enter a custom expiration time using a relative datetime format.'), + '#states' => array( + 'visible' => array(':input[name="form_cache_expire"]' => array('value' => 'custom')), + ), + '#element_validate' => array('_system_performance_settings_validate_form_caching'), + ); + $directory = 'public://'; $is_writable = is_dir($directory) && is_writable($directory); $disabled = !$is_writable; @@ -1719,6 +1746,36 @@ function system_performance_settings() { } /** + * Validates the form cache part of the system performance form. + * + * Validates the custom form expiration and stores it back into the used + * variable name. + * + * @see system_performance_settings() + */ +function _system_performance_settings_validate_form_caching($element, &$form_state) { + if (!empty($element['#value']) && $form_state['values']['form_cache_expire'] == 'custom') { + $expire = $element['#value']; + if (!is_numeric($expire)) { + $expire = (int) strtotime($element['#value']); + } + else { + $expire += REQUEST_TIME; + } + if ($expire < REQUEST_TIME) { + form_error( + $element, + t("The form's custom expiration is set to a time in the past.") + ); + } + else { + $form_state['values']['form_cache_expire'] = $element['#value']; + } + } + unset($form_state['values']['form_cache_expire_custom']); +} + +/** * Submit callback; clear system caches. * * @ingroup forms