Skip to content
Snippets Groups Projects
form.inc 74.6 KiB
Newer Older
/**
 * @defgroup form Form generation
 * @{
 * Functions to enable the processing and display of HTML forms.
 * Drupal uses these functions to achieve consistency in its form processing and
 * presentation, while simplifying code and reducing the amount of HTML that
 * must be explicitly generated by modules.
 *
 * The drupal_get_form() function handles retrieving, processing, and
 * displaying a rendered HTML form for modules automatically. For example:
 *
 * // Display the user registration form.
 * $output = drupal_get_form('user_register');
 *
 * Forms can also be built and submitted programmatically without any user input
 * using the drupal_execute() function.
 *
 * For information on the format of the structured arrays used to define forms,
 * and more detailed explanations of the Form API workflow, see the
 * @link http://api.drupal.org/api/HEAD/file/developer/topics/forms_api_reference.html reference @endlink
 * and the @link http://api.drupal.org/api/HEAD/file/developer/topics/forms_api.html quickstart guide. @endlink
 * Retrieves a form from a constructor function, or from the cache if
 * the form was built in a previous page-load. The form is then passesed
 * on for processing, after and rendered for display if necessary.
 *   The unique string identifying the desired form. If a function
 *   with that name exists, it is called to build the form array.
 *   Modules that need to generate the same form (or very similar forms)
 *   using different $form_ids can implement hook_forms(), which maps
 *   different $form_id values to the proper form constructor function. Examples
 *   may be found in node_forms(), search_forms(), and user_forms().
 * @param ...
 *   Any additional arguments needed by the form constructor function.
 * @return
 *   The rendered form.
 */
function drupal_get_form($form_id) {
  $form_state = array('storage' => NULL, 'submitted' => FALSE);
  $expire = max(ini_get('session.cookie_lifetime'), 86400);

  $args = func_get_args();

  if (isset($_SESSION['batch_form_state'])) {
    // We've been redirected here after a batch processing : the form has
    // already been processed, so we grab the post-process $form_state value
    // and move on to form display. See _batch_finished() function.
    $form_state = $_SESSION['batch_form_state'];
    unset($_SESSION['batch_form_state']);
    // If the incoming $_POST 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.
    if (isset($_POST['form_id']) && $_POST['form_id'] == $form_id && !empty($_POST['form_build_id'])) {
      if ($cached = cache_get('form_'. $_POST['form_build_id'], 'cache_form')) {
        $form = $cached->data;
        if ($cached = cache_get('storage_'. $_POST['form_build_id'], 'cache_form')) {
          $form_state['storage'] = $cached->data;
        }
      }
    // If the previous bit of code didn't result in a populated $form
    // object, we're hitting the form for the first time and we need
    // to build it from scratch.
    if (!isset($form)) {
      array_shift($args);
      array_unshift($args, $form_state);
      array_unshift($args, $form_id);

      $form = call_user_func_array('drupal_retrieve_form', $args);
      $form_build_id = 'form-'. md5(mt_rand());
      $form['#build_id'] = $form_build_id;
      drupal_prepare_form($form_id, $form, $form_state);
      if (!empty($form['#cache'])) {
        cache_set('form_'. $form_build_id, $form, 'cache_form', $expire);
      }
    // Now that we know we have a form, we'll process it (validating,
    // submitting, and handling the results returned by its submission
    // handlers. Submit handlers accumulate data in the form_state by
    // altering the $form_state variable, which is passed into them by
    // reference.
    drupal_process_form($form_id, $form, $form_state);
  }

  // Most simple, single-step forms will be finished by this point --
  // drupal_process_form() usually redirects to another page (or to
  // a 'fresh' copy of the form) once processing is complete. If one
  // of the form's handlers has set $form_state['redirect'] to FALSE,
  // the form will simply be re-rendered with the values still in its
  // fields.
  //
  // If $form_state['storage'] or $form_state['rebuild'] have been
  // set by any submit or validate handlers, however, we know that
  // we're in a complex multi-part process of some sort and the form's
  // workflow is NOT complete. We need to construct a fresh copy of
  // the form, passing in the latest $form_state in addition to any
  // other variables passed into drupal_get_form().

  if (!empty($form_state['rebuild']) || !empty($form_state['storage'])) {
    array_shift($args);
    array_unshift($args, $form_state);
    array_unshift($args, $form_id);
    $form = call_user_func_array('drupal_retrieve_form', $args);
    // We need a new build_id for the new version of the form.
    $form_build_id = 'form-'. md5(mt_rand());
    $form['#build_id'] = $form_build_id;
    drupal_prepare_form($form_id, $form, $form_state);

    // Now, we cache the form structure so it can be retrieved later for
    // validation. If $form_state['storage'] is populated, we'll also cache
    // it so that it can be used to resume complex multi-step processes.
    cache_set('form_'. $form_build_id, $form, 'cache_form', $expire);
    if (!empty($form_state['storage'])) {
      cache_set('storage_'. $form_build_id, $form_state['storage'], 'cache_form', $expire);

    // Clear out all post data, as we don't want the previous step's
    // data to pollute this one and trigger validate/submit handling,
    // then process the form for rendering.
    $_POST = array();
    $form['#post'] = array();
    drupal_process_form($form_id, $form, $form_state);
  // If we haven't redirected to a new location by now, we want to
  // render whatever form array is currently in hand.
  return drupal_render_form($form_id, $form);
}
 * Retrieves a form using a form_id, populates it with $form_state['values'],
 * processes it, and returns any validation errors encountered. This
 * function is the programmatic counterpart to drupal_get_form().
 *
 * @param $form_id
 *   The unique string identifying the desired form. If a function
 *   with that name exists, it is called to build the form array.
 *   Modules that need to generate the same form (or very similar forms)
 *   using different $form_ids can implement hook_forms(), which maps
 *   different $form_id values to the proper form constructor function. Examples
 *   may be found in node_forms(), search_forms(), and user_forms().
 * @param $form_state
 *   A keyed array containing the current state of the form. Most
 *   important is the $form_state['values'] collection, a tree of data
 *   used to simulate the incoming $_POST information from a user's
 *   form submission.
 *   Any additional arguments needed by the form constructor function.
 *
 * For example:
 *
 * // register a new user
 * $form_state = array();
 * $form_state['values']['name'] = 'robo-user';
 * $form_state['values']['mail'] = 'robouser@example.com';
 * $form_state['values']['pass'] = 'password';
 * drupal_execute('user_register', $form_state);
 *
 * // Create a new node
 * $node = array('type' => 'story');
 * $form_state['values']['title'] = 'My node';
 * $form_state['values']['body'] = 'This is the body text!';
 * $form_state['values']['name'] = 'robo-user';
 * drupal_execute('story_node_form', $form_state, $node);
function drupal_execute($form_id, &$form_state) {
  $form = call_user_func_array('drupal_retrieve_form', $args);
  $form['#post'] = $form_state['values'];
  drupal_prepare_form($form_id, $form, $form_state);
  drupal_process_form($form_id, $form, $form_state);
/**
 * Retrieves the structured array that defines a given form.
 *
 * @param $form_id
 *   The unique string identifying the desired form. If a function
 *   with that name exists, it is called to build the form array.
 *   Modules that need to generate the same form (or very similar forms)
 *   using different $form_ids can implement hook_forms(), which maps
 *   different $form_id values to the proper form constructor function.
 * @param $form_state
 *   A keyed array containing the current state of the form.
 *   Any additional arguments needed by the form constructor function.
function drupal_retrieve_form($form_id, &$form_state) {
  // We save two copies of the incoming arguments: one for modules to use
  // when mapping form ids to constructor functions, and another to pass to
  // the constructor function itself. We shift out the first argument -- the
  // $form_id itself -- from the list to pass into the constructor function,

  // We first check to see if there's a function named after the $form_id.
  // If there is, we simply pass the arguments on to it to get the form.
    // In cases where many form_ids need to share a central constructor function,
    // such as the node editing form, modules can implement hook_forms(). It
    // maps one or more form_ids to the correct constructor functions.
    //
    // We cache the results of that hook to save time, but that only works
    // for modules that know all their form_ids in advance. (A module that
    // adds a small 'rate this comment' form to each comment in a list
    // would need a unique form_id for each one, for example.)
    //
    // So, we call the hook if $forms isn't yet populated, OR if it doesn't
    // yet have an entry for the requested form_id.
    if (!isset($forms) || !isset($forms[$form_id])) {
      $forms = module_invoke_all('forms', $form_id, $args);
    }
    $form_definition = $forms[$form_id];
    if (isset($form_definition['callback arguments'])) {
      $args = array_merge($form_definition['callback arguments'], $args);
    }
    if (isset($form_definition['callback'])) {
      $callback = $form_definition['callback'];
    }
  }
  // If $callback was returned by a hook_forms() implementation, call it.
  // Otherwise, call the function named after the form id.
  $form = call_user_func_array(isset($callback) ? $callback : $form_id, $args);

  // We store the original function arguments, rather than the final $arg
  // value, so that form_alter functions can see what was originally
  // passed to drupal_retrieve_form(). This allows the contents of #parameters
  // to be saved and passed in at a later date to recreate the form.
}

/**
 * This function is the heart of form API. The form gets built, validated and in
 * appropriate cases, submitted.
 *
 * @param $form_id
 *   The unique string identifying the current form.
 * @param $form
 *   An associative array containing the structure of the form.
 * @param $form_state
 *   A keyed array containing the current state of the form. This
 *   includes the current persistent storage data for the form, and
 *   any data passed along by earlier steps when displaying a
 *   multi-step form. Additional information, like the sanitized $_POST
 *   data, is also accumulated here.
function drupal_process_form($form_id, &$form, &$form_state) {
  $form_state['values'] = array();

  $form = form_builder($form_id, $form, $form_state);
  if ((!empty($form['#programmed'])) || (!empty($form['#post']) && (($form['#post']['form_id'] == $form_id)))) {
    drupal_validate_form($form_id, $form, $form_state);

    if ((!empty($form_state['submitted'])) && !form_get_errors() && empty($form_state['rebuild'])) {
      $form_state['redirect'] = NULL;
      form_execute_handlers('submit', $form, $form_state);

      // 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');
      }

      // If batches were set in the submit handlers, we process them now,
      // possibly ending execution.
        // The batch uses its own copies of $form and $form_state for
        // late execution of submit handers and post-batch redirection.
        $batch['form'] = $form;
        $batch['form_state'] = $form_state;
        $batch['progressive'] = !$form['#programmed'];
        batch_process();
        // Execution continues only for programmatic forms.
        // For 'regular' forms, we get redirected to the batch processing
        // page. Form redirection will be handled in _batch_finished(),
        // after the batch is processed.

      // If no submit handlers have populated the $form_state['storage']
      // bundle, and the $form_state['rebuild'] flag has not been set,
      // we're finished and should redirect to a new destination page
      // if one has been set (and a fresh, unpopulated copy of the form
      // if one hasn't). If the form was called by drupal_execute(),
      // however, we'll skip this and let the calling function examine
      // the resulting $form_state bundle itself.
      if (!$form['#programmed'] && empty($form_state['rebuild']) && empty($form_state['storage'])) {
         drupal_redirect_form($form, $form_state['redirect']);
    }
  }
}

/**
 * Prepares a structured form array by adding required elements,
 * executing any hook_form_alter functions, and optionally inserting
 * a validation token to prevent tampering.
 *
 * @param $form_id
 *   A unique string identifying the form for validation, submission,
 *   theming, and hook_form_alter functions.
 * @param $form
 *   An associative array containing the structure of the form.
 * @param $form_state
 *   A keyed array containing the current state of the form. Passed
 *   in here so that hook_form_alter() calls can use it, as well.
function drupal_prepare_form($form_id, &$form, &$form_state) {
  $form['#programmed'] = isset($form['#post']);
  if (isset($form['#build_id'])) {
    $form['form_build_id'] = array(
      '#type' => 'hidden',
      '#value' => $form['#build_id'],
      '#id' => $form['#build_id'],
      '#name' => 'form_build_id',
    );
  }

  // Add a token, based on either #token or form_id, to any form displayed to
  // authenticated users. This ensures that any submitted form was actually
  // requested previously by the user and protects against cross site request
  // forgeries.
    if ($form['#token'] === FALSE || $user->uid == 0 || $form['#programmed']) {
      $form['form_token'] = array('#type' => 'token', '#default_value' => drupal_get_token($form['#token']));
  else if (isset($user->uid) && $user->uid && !$form['#programmed']) {
    $form['#token'] = $form_id;
    $form['form_token'] = array(
      '#id' => form_clean_id('edit-'. $form_id .'-form-token'),
      '#type' => 'token',
      '#default_value' => drupal_get_token($form['#token']),
    );
  }

    $form['form_id'] = array(
      '#type' => 'hidden',
      '#value' => $form_id,
      '#id' => form_clean_id("edit-$form_id"),
    );
  if (!isset($form['#id'])) {
    $form['#id'] = form_clean_id($form_id);
  $form += _element_info('form');
  if (!isset($form['#validate'])) {
    if (function_exists($form_id .'_validate')) {
      $form['#validate'] = array($form_id .'_validate');
  if (!isset($form['#submit'])) {
    if (function_exists($form_id .'_submit')) {
      // We set submit here so that it can be altered.
      $form['#submit'] = array($form_id .'_submit');
  drupal_alter('form_'. $form_id, $form, $form_state);
  drupal_alter('form', $form, $form_state, $form_id);
 * Validates user-submitted form data from the $form_state using
 * the validate functions defined in a structured form array.
 *
 * @param $form_id
 *   A unique string identifying the form for validation, submission,
 *   theming, and hook_form_alter functions.
 * @param $form
 *   An associative array containing the structure of the form.
 * @param $form_state
 *   A keyed array containing the current state of the form. The current
 *   user-submitted data is stored in $form_state['values'], though
 *   form validation functions are passed an explicit copy of the
 *   values for the sake of simplicity. Validation handlers can also
 *   $form_state to pass information on to submit handlers. For example:
 *     $form_state['data_for_submision'] = $data;
 *   This technique is useful when validation requires file parsing,
 *   web service requests, or other expensive requests that should
 *   not be repeated in the submission step.
function drupal_validate_form($form_id, $form, &$form_state) {
  static $validated_forms = array();

  if (isset($validated_forms[$form_id])) {
    return;
  }
  // If the session token was set by drupal_prepare_form(), ensure that it
  // matches the current user's session.
    if (!drupal_valid_token($form_state['values']['form_token'], $form['#token'])) {
      // Setting this error will cause the form to fail validation.
      form_set_error('form_token', t('Validation error, please try again. If this error persists, please contact the site administrator.'));
  _form_validate($form, $form_state, $form_id);
  $validated_forms[$form_id] = TRUE;
/**
 * Renders a structured form array into themed HTML.
 *
 * @param $form_id
 *   A unique string identifying the form for validation, submission,
 *   theming, and hook_form_alter functions.
 * @param $form
 *   An associative array containing the structure of the form.
 * @return
 *   A string containing the path of the page to display when processing
 *   is complete.
 */
function drupal_render_form($form_id, &$form) {
  // Don't override #theme if someone already set it.
  if (!isset($form['#theme'])) {
    init_theme();
    $registry = theme_get_registry();
    if (isset($registry[$form_id])) {
  return $output;
}

/**
 * Redirect the user to a URL after a form has been processed.
 *
 * @param $form
 *   An associative array containing the structure of the form.
 * @param $redirect
 *   An optional value containing the destination path to redirect
 *   to if none is specified by the form.
 */
function drupal_redirect_form($form, $redirect = NULL) {
  if ($goto !== FALSE && isset($form['#redirect'])) {
  if (!isset($goto) || ($goto !== FALSE)) {
    if (isset($goto)) {
      if (is_array($goto)) {
        call_user_func_array('drupal_goto', $goto);
      }
      else {
        drupal_goto($goto);
      }
    }
    drupal_goto($_GET['q']);
  }
/**
 * Performs validation on form elements. First ensures required fields are
 * completed, #maxlength is not exceeded, and selected options were in the
 * list of options given to the user. Then calls user-defined validators.
 *
 * @param $elements
 *   An associative array containing the structure of the form.
 * @param $form_state
 *   A keyed array containing the current state of the form. The current
 *   user-submitted data is stored in $form_state['values'], though
 *   form validation functions are passed an explicit copy of the
 *   values for the sake of simplicity. Validation handlers can also
 *   $form_state to pass information on to submit handlers. For example:
 *     $form_state['data_for_submision'] = $data;
 *   This technique is useful when validation requires file parsing,
 *   web service requests, or other expensive requests that should
 *   not be repeated in the submission step.
 * @param $form_id
 *   A unique string identifying the form for validation, submission,
 *   theming, and hook_form_alter functions.
 */
function _form_validate($elements, &$form_state, $form_id = NULL) {
  // Recurse through all children.
  foreach (element_children($elements) as $key) {
    if (isset($elements[$key]) && $elements[$key]) {
      _form_validate($elements[$key], $form_state);
  /* Validate the current input */
  if (!isset($elements['#validated']) || !$elements['#validated']) {
    if (isset($elements['#needs_validation'])) {
      // An empty textfield returns '' so we use empty(). An empty checkbox
      // and a textfield could return '0' and empty('0') returns TRUE so we
      // need a special check for the '0' string.
      if ($elements['#required'] && empty($elements['#value']) && $elements['#value'] !== '0') {
        form_error($elements, t('!name field is required.', array('!name' => $elements['#title'])));
      // Verify that the value is not longer than #maxlength.
      if (isset($elements['#maxlength']) && drupal_strlen($elements['#value']) > $elements['#maxlength']) {
        form_error($elements, t('!name cannot be longer than %max characters but is currently %length characters long.', array('!name' => empty($elements['#title']) ? $elements['#parents'][0] : $elements['#title'], '%max' => $elements['#maxlength'], '%length' => drupal_strlen($elements['#value']))));
      }

       // Add legal choice check if element has #options. Can be skipped, but
       // then you must validate your own element.
      if (isset($elements['#options']) && isset($elements['#value']) && !isset($elements['#DANGEROUS_SKIP_CHECK'])) {
        if ($elements['#type'] == 'select') {
          $options = form_options_flatten($elements['#options']);
        }
        else {
          $options = $elements['#options'];
        }
        if (is_array($elements['#value'])) {
          $value = $elements['#type'] == 'checkboxes' ? array_keys(array_filter($elements['#value'])) : $elements['#value'];
          foreach ($value as $v) {
            if (!isset($options[$v])) {
              form_error($elements, t('An illegal choice has been detected. Please contact the site administrator.'));
              watchdog('form', t('Illegal choice %choice in !name element.', array('%choice' => $v, '!name' => empty($elements['#title']) ? $elements['#parents'][0] : $elements['#title'])), WATCHDOG_ERROR);
        elseif (!isset($options[$elements['#value']])) {
          form_error($elements, t('An illegal choice has been detected. Please contact the site administrator.'));
          watchdog('form', t('Illegal choice %choice in %name element.', array('%choice' => $elements['#value'], '%name' => empty($elements['#title']) ? $elements['#parents'][0] : $elements['#title'])), WATCHDOG_ERROR);
    // Call user-defined form level validators.
    if (isset($form_id)) {
      form_execute_handlers('validate', $elements, $form_state);
    }
    // Call any element-specific validators. These must act on the element
    // #value data.
    elseif (isset($elements['#element_validate'])) {
      foreach ($elements['#element_validate'] as $function) {
        if (function_exists($function))  {
/**
 * A helper function used to execute custom validation and submission
 * handlers for a given form. Button-specific handlers are checked
 * first. If none exist, the function falls back to form-level handlers.
 *
 * @param $type
 *   The type of handler to execute. 'validate' or 'submit' are the
 *   defaults used by Form API.
 * @param $form
 *   An associative array containing the structure of the form.
 * @param $form_state
 *   A keyed array containing the current state of the form. If the user
 *   submitted the form by clicking a button with custom handler functions
 *   defined, those handlers will be stored here.
 */
function form_execute_handlers($type, &$form, &$form_state) {
  $return = FALSE;
  if (isset($form_state[$type .'_handlers'])) {
    $handlers = $form_state[$type .'_handlers'];
  }
  elseif (isset($form['#'. $type])) {
    $handlers = $form['#'. $type];
  }
  else {
    $handlers = array();
  }

  foreach ($handlers as $function) {
    if (function_exists($function))  {
      if ($type == 'submit' && ($batch =& batch_get())) {
        // Some previous _submit handler has set a batch. We store the call
        // in a special 'control' batch set, for execution at the correct
        // time during the batch processing workflow.
        $batch['sets'][] = array('form_submit' => $function);
/**
 * File an error against a form element. If the name of the element is
 * edit[foo][bar] then you may pass either foo or foo][bar as $name
 * foo will set an error for all its children.
 */
function form_set_error($name = NULL, $message = '') {
  static $form = array();
  if (isset($name) && !isset($form[$name])) {
    $form[$name] = $message;
  }
  return $form;
}

/**
 * Return an associative array of all errors.
 */
function form_get_errors() {
  $form = form_set_error();
  if (!empty($form)) {
    return $form;
  }
}

/**
 * Return the error message filed against the form with the specified name.
 */
function form_get_error($element) {
  $form = form_set_error();
  $key = $element['#parents'][0];
  if (isset($form[$key])) {
    return $form[$key];
  }
  $key = implode('][', $element['#parents']);
  if (isset($form[$key])) {
    return $form[$key];
  }
}

/**
 * Flag an element as having an error.
 */
  form_set_error(implode('][', $element['#parents']), $message);
 * Walk through the structured form array, adding any required
 * properties to each element and mapping the incoming $_POST
 * data to the proper elements.
 *   A unique string identifying the form for validation, submission,
 *   theming, and hook_form_alter functions.
 * @param $form
 *   An associative array containing the structure of the form.
 * @param $form_state
 *   A keyed array containing the current state of the form. In this
 *   context, it is used to accumulate information about which button
 *   was clicked when the form was submitted, as well as the sanitized
 *   $_POST data.
function form_builder($form_id, $form, &$form_state) {
  // Initialize as unprocessed.
  $form['#processed'] = FALSE;

  /* Use element defaults */
  if ((!empty($form['#type'])) && ($info = _element_info($form['#type']))) {
    // Overlay $info onto $form, retaining preexisting keys in $form.
  if (isset($form['#type']) && $form['#type'] == 'form' && !empty($form['#programmed'])) {
    $form_state['submitted'] = TRUE;
  }

  if (isset($form['#input']) && $form['#input']) {
    _form_builder_handle_input_element($form_id, $form, $form_state);
  // We start off assuming all form elements are in the correct order.
  $form['#sorted'] = TRUE;

  // Recurse through all child elements.
  foreach (element_children($form) as $key) {
    $form[$key]['#post'] = $form['#post'];
    $form[$key]['#programmed'] = $form['#programmed'];
    // Don't squash an existing tree value.
    if (!isset($form[$key]['#tree'])) {
      $form[$key]['#tree'] = $form['#tree'];
    }
    // Deny access to child elements if parent is denied.
    if (isset($form['#access']) && !$form['#access']) {
      $form[$key]['#access'] = FALSE;
    }

    // Don't squash existing parents value.
    if (!isset($form[$key]['#parents'])) {
      // Check to see if a tree of child elements is present. If so,
      // continue down the tree if required.
      $form[$key]['#parents'] = $form[$key]['#tree'] && $form['#tree'] ? array_merge($form['#parents'], array($key)) : array($key);
    // Assign a decimal placeholder weight to preserve original array order.
    if (!isset($form[$key]['#weight'])) {
      $form[$key]['#weight'] = $count/1000;
    }
      // If one of the child elements has a weight then we will need to sort
      // later.
    $form[$key] = form_builder($form_id, $form[$key], $form_state);
  // The #after_build flag allows any piece of a form to be altered
  // after normal input parsing has been completed.
  if (isset($form['#after_build']) && !isset($form['#after_build_done'])) {
    foreach ($form['#after_build'] as $function) {
      $form['#after_build_done'] = TRUE;
    }
  }

  // Now that we've processed everything, we can go back to handle the funky
  // Internet Explorer button-click scenario.
  _form_builder_ie_cleanup($form, $form_state);

  // After handling the special IE case, we no longer need the buttons collection.
  unset($form_state['buttons']);

  return $form;
}

/**
 * Populate the #value and #name properties of input elements so they
 * can be processed and rendered. Also, execute any #process handlers
 * attached to a specific element.
 */
function _form_builder_handle_input_element($form_id, &$form, &$form_state) {
  if (!isset($form['#name'])) {
    $name = array_shift($form['#parents']);
    $form['#name'] = $name;
    if ($form['#type'] == 'file') {
      // To make it easier to handle $_FILES in file.inc, we place all
      // file fields in the 'files' array. Also, we do not support
      // nested file names.
      $form['#name'] = 'files['. $form['#name'] .']';
    }
    elseif (count($form['#parents'])) {
      $form['#name'] .= '['. implode('][', $form['#parents']) .']';
    }
    array_unshift($form['#parents'], $name);
  }
  if (!isset($form['#id'])) {
    $form['#id'] = form_clean_id('edit-'. implode('-', $form['#parents']));
  }

  if (!empty($form['#disabled'])) {
    $form['#attributes']['disabled'] = 'disabled';
  }

  if (!isset($form['#value']) && !array_key_exists('#value', $form)) {
    $function = !empty($form['#value_callback']) ? $form['#value_callback'] : 'form_type_'. $form['#type'] .'_value';
    if (($form['#programmed']) || ((!isset($form['#access']) || $form['#access']) && isset($form['#post']) && (isset($form['#post']['form_id']) && $form['#post']['form_id'] == $form_id))) {
      $edit = $form['#post'];
      foreach ($form['#parents'] as $parent) {
        $edit = isset($edit[$parent]) ? $edit[$parent] : NULL;
      }
      if (!$form['#programmed'] || isset($edit)) {
        // Call #type_value to set the form value;
        if (function_exists($function)) {
          $form['#value'] = $function($form, $edit);
        if (!isset($form['#value']) && isset($edit)) {
          $form['#value'] = $edit;
      // Mark all posted values for validation.
      if (isset($form['#value']) || (isset($form['#required']) && $form['#required'])) {
        $form['#needs_validation'] = TRUE;
      }
      // Call #type_value without a second argument to request default_value handling.
      // Final catch. If we haven't set a value yet, use the explicit default value.
      if(!isset($form['#value'])) {
        $form['#value'] = isset($form['#default_value']) ? $form['#default_value'] : '';
  // Determine which button (if any) was clicked to submit the form.
  // We compare the incoming values with the buttons defined in the form,
  // and flag the one that matches. We have to do some funky tricks to
  // deal with Internet Explorer's handling of single-button forms, though.
  if (!empty($form['#post']) && isset($form['#executes_submit_callback'])) {
    // First, accumulate a collection of buttons, divided into two bins:
    // those that execute full submit callbacks and those that only validate.
    $button_type = $form['#executes_submit_callback'] ? 'submit' : 'button';
    $form_state['buttons'][$button_type][] = $form;

    // See if a submit button was clicked. In Internet Explorer, if ONLY
    // one submit button is present, AND the enter key is used to submit
    // the form, no form value is sent for it and we'll never detect a
    // match. In most cases, though, the following code will properly handle
    // finding the clicked button and storing any custom validate and
    // submit handlers it has defined.
    if (isset($form['#post'][$form['#name']]) && $form['#post'][$form['#name']] == $form['#value']) {
      $form_state['submitted'] = $form_state['submitted'] || $form['#executes_submit_callback'];

      // In most cases, we want to use form_set_value() to manipulate
      // the global variables. In this special case, we want to make sure that
      // the value of this element is listed in $form_variables under 'op'.
      $form_state['values'][$form['#name']] = $form['#value'];
      $form_state['clicked_button'] = $form;

      if (isset($form['#validate'])) {
        $form_state['validate_handlers'] = $form['#validate'];
      }
      if (isset($form['#submit'])) {
        $form_state['submit_handlers'] = $form['#submit'];
      }
    }
  }
  // Allow for elements to expand to multiple elements, e.g., radios,
  // checkboxes and files.
  if (isset($form['#process']) && !$form['#processed']) {
    foreach ($form['#process'] as $process) {
      if (function_exists($process)) {
        $args = array_merge(array($form), array(isset($edit) ? $edit : NULL), array($form_state));
        $form = call_user_func_array($process, $args);
      }
    }
    $form['#processed'] = TRUE;
  }
  form_set_value($form, $form['#value'], $form_state);
}

/**
 * Helper function to determine the value for a checkbox form element.
 *
 * @param $form
 *   The form element whose value is being populated.
 *   The incoming POST data to populate the form element. If this is FALSE,
 *   the element's default value should be returned.
 *   The data that will appear in the $form_state['values'] collection
 *   for this element. Return nothing to use the default.
function form_type_checkbox_value($form, $edit = FALSE) {
  if ($edit !== FALSE) {
    return !empty($edit) ? $form['#return_value'] : 0;
  }
}

/**
 * Helper function to determine the value for a checkboxes form element.
 *
 * @param $form
 *   The form element whose value is being populated.
 *   The incoming POST data to populate the form element. If this is FALSE,
 *   the element's default value should be returned.
 *   The data that will appear in the $form_state['values'] collection
 *   for this element. Return nothing to use the default.
 function form_type_checkboxes_value($form, $edit = FALSE) {
  if ($edit === FALSE) {
    $value = array();
    $form += array('#default_value' => array());
    foreach ($form['#default_value'] as $key) {
      $value[$key] = 1;
    }
    return $value;
  }
}

/**
 * Helper function to determine the value for a password_confirm form
 * element.
 *
 * @param $form
 *   The form element whose value is being populated.
 *   The incoming POST data to populate the form element. If this is FALSE,
 *   the element's default value should be returned.
 *   The data that will appear in the $form_state['values'] collection
 *   for this element. Return nothing to use the default.
function form_type_password_confirm_value($form, $edit = FALSE) {
  if ($edit === FALSE) {
    $form += array('#default_value' => array());
    return $form['#default_value'] + array('pass1' => '', 'pass2' => '');
  }
}

/**
 * Helper function to determine the value for a select form element.
 *
 * @param $form
 *   The form element whose value is being populated.
 *   The incoming POST data to populate the form element. If this is FALSE,
 *   the element's default value should be returned.
 *   The data that will appear in the $form_state['values'] collection
 *   for this element. Return nothing to use the default.
function form_type_select_value($form, $edit = FALSE) {
  if ($edit !== FALSE) {
    if (isset($form['#multiple']) && $form['#multiple']) {
      return (is_array($edit)) ? drupal_map_assoc($edit) : array();
    }
    else {
      return $edit;
    }
  }
}

/**
 * Helper function to determine the value for a textfield form element.
 *
 * @param $form
 *   The form element whose value is being populated.
 *   The incoming POST data to populate the form element. If this is FALSE,
 *   the element's default value should be returned.
 *   The data that will appear in the $form_state['values'] collection
 *   for this element. Return nothing to use the default.
function form_type_textfield_value($form, $edit = FALSE) {
  if ($edit !== FALSE) {
    // Equate $edit to the form value to ensure it's marked for
    // validation.
    return str_replace(array("\r", "\n"), '', $edit);
  }
}

/**
 * Helper function to determine the value for form's token value.
 *
 * @param $form
 *   The form element whose value is being populated.
 *   The incoming POST data to populate the form element. If this is FALSE,
 *   the element's default value should be returned.
 *   The data that will appear in the $form_state['values'] collection
 *   for this element. Return nothing to use the default.
function form_type_token_value($form, $edit = FALSE) {
  if ($edit !== FALSE) {