This is the key function for making multi-step forms advance from step to
step. It is called by drupal_process_form() when all user input processing,
including calling validation and submission handlers, for the request is
finished. If a validate or submit handler set $form_state['rebuild'] to TRUE,
and if other conditions don't preempt a rebuild from happening, then this
function is called to generate a new $form, the next step in the form
workflow, to be returned for rendering.

Ajax form submissions are almost always multi-step workflows, so that is one
common use-case during which form rebuilding occurs. See ajax_form_callback()
for more information about creating Ajax-enabled forms.

Parameters

$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().

$form_state
A keyed array containing the current state of the form.

$old_form
(optional) A previously built $form. Used to retain the #build_id and
#action properties in Ajax callbacks and similar partial form rebuilds. The
only properties copied from $old_form are the ones which both exist in
$old_form and for which $form_state['rebuild_info']['copy'][PROPERTY] is
TRUE. If $old_form is not passed, the entire $form is rebuilt freshly.
'rebuild_info' needs to be a separate top-level property next to
'build_info', since the contained data must not be cached.

Code

<?php
functiondrupal_rebuild_form($form_id, &$form_state, $old_form = NULL) {
$form = drupal_retrieve_form($form_id, $form_state);
// If only parts of the form will be returned to the browser (e.g., Ajax or
// RIA clients), re-use the old #build_id to not require client-side code to
// manually update the hidden 'build_id' input element.
// Otherwise, a new #build_id is generated, to not clobber the previous
// build's data in the form cache; also allowing the user to go back to an
// earlier build, make changes, and re-submit.
// @see drupal_prepare_form()
if (isset($old_form['#build_id']) && !empty($form_state['rebuild_info']['copy']['#build_id'])) {
$form['#build_id'] = $old_form['#build_id'];
}
else {
$form['#build_id'] = 'form-' . drupal_hash_base64(uniqid(mt_rand(), TRUE) . mt_rand());
}
// #action defaults to request_uri(), but in case of Ajax and other partial
// rebuilds, the form is submitted to an alternate URL, and the original
// #action needs to be retained.
if (isset($old_form['#action']) && !empty($form_state['rebuild_info']['copy']['#action'])) {
$form['#action'] = $old_form['#action'];
}
drupal_prepare_form($form_id, $form, $form_state);
// Caching is normally done in drupal_process_form(), but what needs to be
// cached is the $form structure before it passes through form_builder(),
// so we need to do it here.
// @todo For Drupal 8, find a way to avoid this code duplication.
if (empty($form_state['no_cache'])) {
form_set_cache($form['#build_id'], $form, $form_state);
}
// Clear out all group associations as these might be different when
// re-rendering the form.
$form_state['groups'] = array();
// Return a fully built form that is ready for rendering.
returnform_builder($form_id, $form, $form_state);
}
?>