Hello,

I have found a strange behaviour of a finder today. It works perfectly for an admin and for an anonymous user. However when it comes to an authorized one I see the following message.

The form has become outdated. Copy any unsaved work in the form below and then reload this page.

Reproduction case.

  • Create a content finder with an autocomplete widget.
  • Create a user and being authorized as this user (not as an admin) try to search for a node using this finder.

Just in case my finder is here

$finder = new finder;
$finder->disabled = FALSE; /* Edit this to true to make a default finder disabled initially */
$finder->api_version = 2;
$finder->name = 'content_finder';
$finder->views_view = 'finder_node';
$finder->views_display = 'page_1';
$finder->title = 'Поиск по местам';
$finder->description = 'Поиск по названию места';
$finder->path = 'content-finder';
$finder->block = TRUE;
$finder->status = TRUE;
$finder->settings = array(
  'search_tab' => 'node',
  'block' => TRUE,
  'form_on_page' => 0,
  'find_button' => TRUE,
  'find_text' => 'Find',
  'go_button' => 0,
  'go_text' => 'Go',
  'ajax_effect' => 'none',
  'show_results' => 'completed',
  'results_style' => 'views',
  'no_results' => 'default',
  'pager' => 10,
  'redirect' => 'always',
  'element_logic' => 'AND',
  'url' => 'enabled',
  'url_delimiter' => ',',
  'validate_empty' => 0,
);
$finder->elements = array(
  'title' => (object) array(
    'id' => 'title',
    'finder' => 'content_finder',
    'settings' => array(
      'field_logic' => 'OR',
      'value_logic' => 'AND',
      'match' => 'e',
      'fields' => array(
        'node.title' => (object) array(
          'table' => 'node',
          'field' => 'title',
          'relationship' => NULL,
        ),
      ),
      'max_suggestions' => '15',
      'autocomplete_field_logic' => 'OR',
      'autocomplete_value_logic' => 'AND',
      'autocomplete_match' => 'c',
      'autocomplete_delimit' => ' ',
      'autosubmit' => 1,
      'size' => '60',
    ),
    'title' => 'Поиск места',
    'element' => 'autocomplete',
    'weight' => '0',
  ),
);

Comments

Georgii’s picture

And one important note here. Everything is OK if

  • you are logged in as an admin on one browser
  • you are logged as an ordinary user on another browser
  • you clear case as an admin
  • everything works for an ordinary user.

But if there are more than one non-admin user on the web-site  - then it is a problem for avery user except of one of them. Let's say:

  • 3 users (admin, test-user1 and test-user2)
  • admin clears cache
  • test-user1 uses finder - no problems
  • test-user2 uses finder - an error message
  • test-user1 logs out and logs in. Uses finder - an error message.

To me it looks like there is a hash value generated somewhere to validate a finder form and it is getting outdated for multiple users.

danielb’s picture

Is this a block?

Georgii’s picture

Yes it is. However, I have just checked that the same issue is with the form on a page. Can I help with debugging in any way?

danielb’s picture

Try turning off caching at admin/config/development/performance

Cache pages for anonymous users
Cache blocks

danielb’s picture

Interesting http://drupal.org/node/240828

doesn't help this though

danielb’s picture

When you change users to test this, make sure you reload the finder form, in case you're just leaving a finder tab open and reusing it? Also make sure nothing gets cleared in the backend between loading the form and submitting it.

Georgii’s picture

danielb, it looks like the "Cache blocks" is that bad guy. When this option is enabled (even if "Cache pages for anonymous users" is turned on) I see the problem described. When it's disabled - the issue is gone.

Georgii’s picture

I have an assumption that the form in a block hasa sort of a hash for validation purposes. And validation algorithm is different for anonymous users, registered users and admins. With admins and anonymous it works but for registerd ones this hash is cached and validation works only once...

danielb’s picture

Drupal adds a #token thing (which is reflected in a hidden field) for registered users to prevent people tricking others into submitting a form for them, which is useful for stuff like node editing, or administration forms, but not really an issue in something like a finder form.

    // Form constructors may explicitly set #token to FALSE when cross site
    // request forgery is irrelevant to the form, such as search forms.

http://api.drupal.org/api/drupal/includes--form.inc/function/drupal_prep...

It is possible that adding $form['#token'] = FALSE; in finder_form() in finder/includes/form.inc might fix it?

Georgii’s picture

Status: Active » Reviewed & tested by the community

danielb, that worked like a charm!
finder/includes/form.inc

38: $form['#action'] = url($finder->path);
39: $form['#token'] = FALSE;
40: $form['finder_form'] = array(

danielb’s picture

Version: 7.x-2.0-alpha5 » 7.x-2.x-dev
Status: Reviewed & tested by the community » Fixed

I've added that to the repository, it will appear in future releases. Thanks for testing it out!

Georgii’s picture

Thanks for your support!

constantinejohny’s picture

Hi, I am sorry to say this, but #10 did not help me :/
I am still getting these messages:

Notice: Undefined index: form_token in function drupal_validate_form() (line: 1096 in file /hosting/www/mydomain/includes/form.inc).
 The form has become outdated. Copy any unsaved work in the form below and then reload this page.

It only appears for users that are not logged in. I have a page, not a block. And cache is disabled on all the site.

K1T5UN3’s picture

Version: 7.x-2.x-dev » 7.x-2.0-alpha6
Status: Fixed » Active

Hello,

Using Finder 7.x-2.0-alpha6 and the default content-finder, I still encounter this issue when using the form as an anonymous user.

Same settings and error messages as #13.

constantinejohny’s picture

OK, I'm trying to fix this. When I edited #10 solution with this:

finder/includes/form.inc

38: $form['#action'] = url($finder->path);
39: $form['token'] = FALSE;
40: $form['finder_form'] = array(

it works OK. Was the # a typo, or was it really supposed to be there?

K1T5UN3’s picture

Oh I didn't even notice that. Indeed the # shouldn't be there, because a token is a form element, not a property.

danielb’s picture

No the # is supposed to be there. It is not a form element, if it was a form element it would be an array value with #properties of it's own, such as #type.
See the code in http://api.drupal.org/api/drupal/includes--form.inc/function/drupal_prep...
which checks '#token'.
It then removes #token, and therefore the code in drupal_validate_form() which produces those errors should not run.
So what you are saying is happening... should not happen.

K1T5UN3’s picture

Ok, my bad.

I took a quick look at the drupal_prepare_form function. The form token of the finder is not getting unsetted because the uid of the anonymous user is 0, so the if (!empty($user->uid) && !$form_state['programmed']) condition in this function doesn't validate.

By manually unsetting the form token in finder/includes/form.inc, the error is gone. I don't know if it's the better way to fix the issue, though.

constantinejohny’s picture

When I used #token, it outputted an error that "Value fomr_token is not valid" which I don't get, it should have skipped this part of code when the #token was set to FALSE.

Now I am using token and everything works... Am using Drupal 7.10 and the new alpha version of Finder.

Georgii’s picture

Let me summarize:
It looks like the bug-fix for an authenticated user introduced problems for anonymous ones. If that's the case I think there should be additional "if" clause checking for

global $user
$user->uid

Not equal to 0 and only in that case do $form['token'] = FALSE;

I'm not able to check it now, but will try do to that in 6-7 hours.

Will keep you posted.

Georgii’s picture

Here is the final version that works for me in all cases (anonymous and authenticated users)

  global $user;
  if ($user->uid) {
    $form['#token'] = FALSE;
  }
Georgii’s picture

Status: Active » Needs review
danielb’s picture

That makes sense to me Georgii.

danielb’s picture

Status: Needs review » Fixed

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

dhallennem’s picture

For me, if someone have the same problem, it is because of the AuthCache module which unset the form['#token'].

Sneakyvv’s picture

for me $form['#token'] = FALSE didn't work

I dove into the core and found this

if (isset($form['#token'])) {
    if (!drupal_valid_token($form_state['values']['form_token'], $form['#token'])) {
      $path = current_path();
      $query = drupal_get_query_parameters();
      $url = url($path, array('query' => $query));

      // Setting this error will cause the form to fail validation.
      form_set_error('form_token', t('The form has become outdated. Copy any unsaved work in the form below and then <a href="@link">reload this page</a>.', array('@link' => $url)));
    }

So it seems you would have to either

unset($form['#token'])
or
$form['#token'] = NULL

Jivan’s picture

$neakyvv, you saved my day.

For information purposes :

This solution also works for a customized user profile form, and I suppose for every form that will show this error message.

I implemented hook_form_user_profile_form_alter() in my template.php to reconfigure user-profile-form, and also added a custom user-profile-form.tpl.php called by hook_theme().

Everything displayed correctly but after submit the form didn't validate anymore and this error message (the form has become outdated) was shown.

By adding $form['#token'] = NULL; in hook_form_user_profile_form_alter() everything works correctly now.

Thanx.

Mo Omar’s picture

I get the same message when a user tries to comment on a node when this user is not an admin. I am not using finder and my drupal version is 7.22

Can I apply the same solution? Can someone tells me where and what to do exactly? or should I open a new issue?

qqboy’s picture

Issue summary: View changes

$form['#token'] = NULL

works not else in my case

@Sneakyvv great.

Bhuvana_Indukuri’s picture

@Sneakyvv - You saved my day!

jyotisankar’s picture

Hi
I am using Drupal version 7.41. I am facing the same issue "The form has become outdated. Copy any unsaved work in the form below and then reload this page." When I logged in as a different role other than administration and trying to create a different user from some other role getting this error message.

The codebase that I found in from.inc referring to the discussion above is :

function _drupal_invalid_token_set_form_error() {
$path = current_path();
$query = drupal_get_query_parameters();
$url = url($path, array('query' => $query));

// Setting this error will cause the form to fail validation.
form_set_error('form_token', t('The form has become outdated. Copy any unsaved work in the form below and then reload this page.', array('@link' => $url)));
}

The above function is being called in

if (isset($form['#token'])) {
if (!drupal_valid_token($form_state['values']['form_token'], $form['#token']) || !empty($form_state['invalid_token'])) {
_drupal_invalid_token_set_form_error();
// Stop here and don't run any further validation handlers, because they
// could invoke non-safe operations which opens the door for CSRF
// vulnerabilities.
$validated_forms[$form_id] = TRUE;
return;
}
}

Can anyone help me out on this.

Thanks

trakinos’s picture

Just a quick update:
If you are using $hooks to theme a form, you have to put this code in the array:

'arguments' => array('form' => NULL)
alex_optim’s picture

You need only to make
unset($form['#token']); in hook_form_alter.
It works for me.

nitin.k’s picture

Setting form token to FALSE might be a solution but sometimes the function which you pass in "access callback" can lead to this error too.

danielb’s picture

Status: Closed (fixed) » Needs work

I suppose this needs looking at again. I haven't encountered the issue but unset/null would be an acceptable change to make if that resolves the issue for some people.

praveen_91’s picture

hi, all
is it right to set unset($form['#token']); for drupal form security purpose ?

gjuliane’s picture

function my_module_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == 'name_of_form') {
    unset($form['#token']);
  }
}

This works for me in my module.