1. 8.2.x core/includes/form.inc batch
  2. 8.0.x core/includes/form.inc batch
  3. 8.1.x core/includes/form.inc batch
  4. 8.3.x core/includes/form.inc batch
  5. 6.x includes/form.inc batch
  6. 7.x includes/form.inc batch

Functions allowing forms processing to be spread out over several page requests, thus ensuring that the processing does not get interrupted because of a PHP timeout, while allowing the user to receive feedback on the progress of the ongoing operations.

The API is primarily designed to integrate nicely with the Form API workflow, but can also be used by non-FAPI scripts (like update.php) or even simple page callbacks (which should probably be used sparingly).

Example:

$batch = array(
  'title' => t('Exporting'),
  'operations' => array(
    array('my_function_1', array($account->uid, 'story')),
    array('my_function_2', array()),
  ),
  'finished' => 'my_finished_callback',
  'file' => 'path_to_file_containing_myfunctions',
);
batch_set($batch);
// Only needed if not inside a form _submit handler.
// Setting redirect in batch_process.
batch_process('node/1');

Note: if the batch 'title', 'init_message', 'progress_message', or 'error_message' could contain any user input, it is the responsibility of the code calling batch_set() to sanitize them first with a function like check_plain() or filter_xss().

Sample batch operations:

// Simple and artificial: load a node of a given type for a given user
function my_function_1($uid, $type, &$context) {
  // The $context array gathers batch context information about the execution (read),
  // as well as 'return values' for the current operation (write)
  // The following keys are provided :
  // 'results' (read / write): The array of results gathered so far by
  //   the batch processing, for the current operation to append its own.
  // 'message' (write): A text message displayed in the progress page.
  // The following keys allow for multi-step operations :
  // 'sandbox' (read / write): An array that can be freely used to
  //   store persistent data between iterations. It is recommended to
  //   use this instead of $_SESSION, which is unsafe if the user
  //   continues browsing in a separate window while the batch is processing.
  // 'finished' (write): A float number between 0 and 1 informing
  //   the processing engine of the completion level for the operation.
  //   1 (or no value explicitly set) means the operation is finished
  //   and the batch processing can continue to the next operation.

  $node = node_load(array('uid' => $uid, 'type' => $type));
  $context['results'][] = $node->nid .' : '. $node->title;
  $context['message'] = $node->title;
}

// More advanced example: multi-step operation - load all nodes, five by five
function my_function_2(&$context) {
  if (empty($context['sandbox'])) {
    $context['sandbox']['progress'] = 0;
    $context['sandbox']['current_node'] = 0;
    $context['sandbox']['max'] = db_result(db_query('SELECT COUNT(DISTINCT nid) FROM {node}'));
  }
  $limit = 5;
  $result = db_query_range("SELECT nid FROM {node} WHERE nid > %d ORDER BY nid ASC", $context['sandbox']['current_node'], 0, $limit);
  while ($row = db_fetch_array($result)) {
    $node = node_load($row['nid'], NULL, TRUE);
    $context['results'][] = $node->nid .' : '. $node->title;
    $context['sandbox']['progress']++;
    $context['sandbox']['current_node'] = $node->nid;
    $context['message'] = $node->title;
  }
  if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
  }
}

Sample 'finished' callback:

function batch_test_finished($success, $results, $operations) {
  if ($success) {
    $message = format_plural(count($results), 'One post processed.', '@count posts processed.');
  }
  else {
    $message = t('Finished with an error.');
  }
  drupal_set_message($message);
  // Providing data for the redirected page is done through $_SESSION.
  foreach ($results as $result) {
    $items[] = t('Loaded node %title.', array('%title' => $result));
  }
  $_SESSION['my_batch_results'] = $items;
}

File

includes/form.inc, line 2422

Functions

Namesort descending Location Description
batch_get includes/form.inc Retrieves the current batch.
batch_process includes/form.inc Processes the batch.
batch_set includes/form.inc Opens a new batch.

Comments

matt2000’s picture

This should be obvious, but I've seen code that misses it: Never put your progress increment ($context['sandbox']['progress']++;) inside a conditional or a loop that may not complete, or your batch job may get stuck forever.

Shiny’s picture

noahlively’s picture

That link doesn't work anymore

mikeytown2’s picture

larowlan’s picture

Note that if your batch operation function is not called, make sure you're using the file argument to your batch array, even if the function that does the processing is in the same file as the batch_set call - you still need to use the file argument otherwise your batch will fail silently

Garrett Albright’s picture

Note that the 'file' parameter of your batch definition array must be set, even if the functions you're going to be calling will be in the same file. Otherwise, your operation functions will not be called, and you won't see an error anywhere alerting you to this.

Max_Headroom’s picture

Since PHP5.3, if you get this warning:
Parameter 1 to my_function_1() expected to be a reference, value given.

If you have:

$batch = array(
  'title' => t('Exporting'),
  'operations' => array(
    array('my_function_1', array($some_info)),
  ),
  'finished' => 'my_finished_callback',
  'file' => 'path_to_file_containing_myfunctions',

Change

function my_function_1(&$some_info, &$context) {
//Do stuff
}

To

//Remove reference to $some_info
function my_function_1($some_info, &$context) {
//Do stuff
}
serjas’s picture

i have an affliate window csv which has nearly 1 lac rows, i want to save this as nodes, and i tried with batch API.

but still i am getting php timeout error ..please help

function MODULE_aw_batch(){  
  $operations = array();
  $csv = file_directory_path().'/aw/datafeed_134642.csv';
  $file = fopen($csv, 'r');
  while (($data = fgetcsv($file)) !== FALSE) {
      $operations[] = array('MODULE_aw_op', array($data));
  }
  $batch = array(
    'title' => t('Generating feeds'), // Title to display while running.
    'operations' => $operations,
    'finished' => 'MODULE_aw_finished', // Last function to call.
    'init_message' => t('Importing...it may take 4-5 hours'),
    'progress_message' => t('Processed @current out of @total.'),
    'error_message' => t('Import feeds has encountered an error.'),
  );
  batch_set($batch);
  batch_process('admin/content/node/overview');
}
jufran20’s picture

Is it possible to manage all processes as a transaction? (commit, rollback)
In each process, I save a node, but I need you to save all nodes or if there is an error not save any.
My tables are InnoDB but I don't know how it do.
Thanks