I changed the layout of my login block. Now on cached pages (using authcache) I'm getting Notice: Undefined index: form_build_id On non cached pages and when authcache is turned off and only core caching is enabled everything works fine. I'm now trying to figure out if this is an authcache problem, if I should manually remove some cached files from .ht.filecache or if my code is faulty.

Here is my code:
Added to the bottom of template.tpl.php (without php tags)

<?php
function marinelli_form_alter(&$form, &$form_state, $form_id) {

    if ($form_id == "user_login_block") {
        //$form['links'] = Null; // Remove Request New Password and other links from Block form
 //$form['links']['#markup'] = t('Forgotten Password?') . ' ' . t('Forgotten Password?') . ''; // Remove Request New Password from Block form 
        $form['links'][ '#markup' ] = ' <a class="user-register" href="/user/register">' . t('Register') . '</a> | ' . ' <a class="user-password" href="/user/password">' . t('Forgot Password') . '</a>'; // Remove Request New Password from Block form
        $form['name'][ '#title' ] = Null; // Change text on form
        $form['name'][ '#attributes' ] = array('placeholder' => t('username'));
        $form['pass'][ '#title' ] = Null;
        $form['pass'][ '#attributes' ] = array('placeholder' => t('password'));
    }
}

?>

And in the overrides folder block--user--login.tpl.php

<?php
    $elements = drupal_get_form('user_login_block');

    $rendered = render($elements);

    $output  = '<form action="' . $elements[ '#action' ] . 
                              '" method="' . $elements[ '#method' ] . 
                              '" id="' . $elements[ '#id' ] . 
                              '" accept-charset="UTF-8"><div class="login-form-2ndmenu">';
    $output .= '<div class="login-links">';
    $output .= $elements['links'][ '#children' ];
    $output .= '</div>';
    $output .= $elements['name'][ '#children' ];
    $output .= $elements['pass'][ '#children' ];
    $output .= $elements['form_build_id']['#children' ];
    $output .= $elements['form_id'][ '#children' ];
    $output .= $elements['actions'][ '#children' ];
    
    $output .= '</div></form>';
    

    print $output;
    
?>

Comments

wemmies’s picture

Issue summary: View changes

eited to add php tags for better reading

wemmies’s picture

Issue summary: View changes

Deleted some comments for better reading

simg’s picture

I'm assuming authcache works fine if you have the standard code?

I'm not trying to ask awkward questions, but I don't currently know enough about how form rendering works to instantly help you.
There have been issues (caused by my lack of knowledge) with "Notice: Undefined index: form_build_id" some time ago in the dev version, but I think these have been fixed.

I'll try to help you in whatever way I can but I'm really busy with work at the moment

wemmies’s picture

Yes, no problems with autocache, that works fine.

I now found http://api.drupal.org/api/drupal/includes%21form.inc/function/drupal_pre...
After reading that I don't know if I need form_build_id for the login form, but as I got it to work on autocached pages (it does cache the field_build_id per page though) I'll leave it in. I changed the block--user--login.tpl.php code to

<?php
    $elements = drupal_get_form('user_login_block');

    /**
      do all your rendering stuff here
      drupal_render seems to add html to the elements array
      and instead of printing what is returned from drupal_render
 you can use the added html in ['#children'] elements of the arrays 
      to build the form in the order you want.
    **/
    $rendered = render($elements);
    if (!isset($form[ '#build_id' ])) {
    $form[ '#build_id' ] = 'form-' . drupal_hash_base64(uniqid(mt_rand(), TRUE) . mt_rand());
  }
  $form['form_build_id'] = array(
     '#type'  => 'hidden',
     '#value'  => $form[ '#build_id' ],
     '#id'  => $form[ '#build_id' ],
     '#name'  => 'form_build_id',
    
    // Form processing and validation requires this value, so ensure the
     // submitted form value appears literally, regardless of custom #tree      // and #parents being set elsewhere.      '#parents'  => array('form_build_id'),
  );


    $output  = '<form action="' . $elements[ '#action' ] . 
                              '" method="' . $elements[ '#method' ] . 
                              '" id="' . $elements[ '#id' ] . 
                              '" accept-charset="UTF-8"><div class="login-form-2ndmenu">';
    $output .= '<div class="login-links">';
    $output .= $elements['links'][ '#children' ];
    $output .= '</div>';
    $output .= $elements['name'][ '#children' ];
    $output .= $elements['pass'][ '#children' ];
    $output .= render ($form['form_build_id']);
    $output .= $elements['form_id'][ '#children' ];
    $output .= $elements['actions'][ '#children' ];
    
    $output .= '</div></form>';
    

    print $output;
    
?>

Still I'm not quite sure what validation occurs on the form_build_id. This will be something to look into if caching this value might be a security risk?

znerol’s picture

Status: Active » Fixed

Short answer: You may leave out form_build_id from your block--user--login.tpl.php, there are no security implications if this hidden field is not on the page.

Long answer: The value in form_build_id is actually used as the cache-id for the form cache. A long comment in drupal_build_form explains this like so:

  // If the incoming input contains a form_build_id, we'll check the cache for a
  // copy of the form in question. If it's there, we don't have to rebuild the
  // form to proceed. In addition, if there is stored form_state data from a
  // previous step, we'll retrieve it so it can be passed on to the form
  // processing code.
  $check_cache = isset($form_state['input']['form_id']) && $form_state['input']['form_id'] == $form_id && !empty($form_state['input']['form_build_id']);
  if ($check_cache) {
    $form = form_get_cache($form_state['input']['form_build_id'], $form_state);
  }

Whether a form is stored to the form-cache is determined by two $form_state keys:

  • cache: If set to TRUE the original, unprocessed form structure will be cached, which allows the entire form to be rebuilt from cache.
  • no_cache: If set to TRUE the form will NOT be cached, even if 'cache' is set.

Now there are some gory details like on AJAX-forms (using the #ajax form element attribute), the form-cache is actually required. Otherwise there is no way to rebuild the form on subsequent ajax-updates. The mechanism is indeed clever enough to generate a new form-build-id when a form is rebuilt with different parameters (see drupal_rebuild_form, therefore it is no problem to actually leave the hidden form_build_id field on cached pages.

Therefore in the 7.x-2.x branch I took a more sensible approach and the form_build_id is never removed when caching was explicitly requested by e.g. ajax_preprocess_form.

In your case just leaving out the hidden field form_build_id will do the trick. However I think one might run into problems on ajaxified forms with the 7.x-1.x branch - but I did not examine that.

wemmies’s picture

Thank you for elaborating on that. I still have a lot to learn about Drupal.

Status: Fixed » Closed (fixed)

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

Anonymous’s picture

Issue summary: View changes

added a check for only caching with drupal core