123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328 |
- <?php
- /**
- * @file
- *
- * Pages for background batch.
- *
- * @todo Implement proper error page instead of just 404.
- */
- /**
- * System settings page.
- */
- function background_batch_settings_form() {
- $form = array();
- $form['background_batch_delay'] = array(
- '#type' => 'textfield',
- '#default_value' => variable_get('background_batch_delay', BACKGROUND_BATCH_DELAY),
- '#title' => 'Delay',
- '#description' => t('Time in microseconds for progress refresh'),
- );
- $form['background_batch_process_lifespan'] = array(
- '#type' => 'textfield',
- '#default_value' => variable_get('background_batch_process_lifespan', BACKGROUND_BATCH_PROCESS_LIFESPAN),
- '#title' => 'Process lifespan',
- '#description' => t('Time in milliseconds for progress lifespan'),
- );
- $form['background_batch_show_eta'] = array(
- '#type' => 'checkbox',
- '#default_value' => variable_get('background_batch_show_eta', BACKGROUND_BATCH_PROCESS_ETA),
- '#title' => 'Show ETA of batch process',
- '#description' => t('Whether ETA (estimated time of arrival) information should be shown'),
- );
- return system_settings_form($form);
- }
- /**
- * Overview of current and recent batch jobs.
- */
- function background_batch_overview_page() {
- $data = array();
- $bids = db_select('batch', 'b')
- ->fields('b', array('bid'))
- ->orderBy('b.bid', 'ASC')
- ->execute()
- ->fetchAllKeyed(0, 0);
- foreach ($bids as $bid) {
- $progress = progress_get_progress('_background_batch:' . $bid);
- $eta = progress_estimate_completion($progress);
- $data[] = array(
- $progress->end ? $bid : l($bid, 'batch', array('query' => array('op' => 'start', 'id' => $bid))),
- sprintf("%.2f%%", $progress->progress * 100),
- $progress->message,
- $progress->start ? format_date((int)$progress->start, 'small') : t('N/A'),
- $progress->end ? format_date((int)$progress->end, 'small') : ($eta ? format_date((int)$eta, 'small') : t('N/A')),
- );
- }
- $header = array('Batch ID', 'Progress', 'Message', 'Started', 'Finished/ETA');
- return theme('table', array(
- 'header' => $header,
- 'rows' => $data
- ));
- }
- /**
- * State-based dispatcher for the batch processing page.
- */
- function background_batch_page() {
- $id = isset($_REQUEST['id']) ? $_REQUEST['id'] : FALSE;
- if (!$id) {
- return drupal_not_found();
- }
- // Retrieve the current state of batch from db.
- $data = db_query("SELECT batch FROM {batch} WHERE bid = :bid", array(':bid' => $id))->fetchColumn();
- if (!$data) {
- return drupal_not_found();
- }
- $batch =& batch_get();
- $batch = unserialize($data);
- // Check if the current user owns (has access to) this batch.
- global $user;
- if ($batch['uid'] != $user->uid) {
- return drupal_access_denied();
- }
- $op = isset($_REQUEST['op']) ? $_REQUEST['op'] : '';
- switch ($op) {
- case 'start':
- return _background_batch_page_start();
- case 'do':
- return _background_batch_page_do_js();
- case 'do_nojs':
- return _background_batch_page_do_nojs();
- case 'finished':
- progress_remove_progress('_background_batch:' . $id);
- return _batch_finished();
- default:
- drupal_goto('admin/config/system/batch/overview');
- }
- }
- /**
- * Start a batch job in the background
- */
- function _background_batch_initiate($process = NULL) {
- require_once('includes/batch.inc');
- $batch =& batch_get();
- $id = $batch['id'];
- $handle = 'background_batch:' . $id;
- if (!$process) {
- $process = background_process_get_process($handle);
- }
- if ($process) {
- // If batch is already in progress, goto to the status page instead of starting it.
- if ($process->exec_status == BACKGROUND_PROCESS_STATUS_RUNNING) {
- return $process;
- }
- // If process is locked and hasn't started for X seconds, then relaunch
- if (
- $process->exec_status == BACKGROUND_PROCESS_STATUS_LOCKED &&
- $process->start_stamp + variable_get('background_process_redispatch_threshold', BACKGROUND_PROCESS_REDISPATCH_THRESHOLD) < time()
- ) {
- $process = BackgroundProcess::load($process);
- $process->dispatch();
- }
- return $process;
- }
- else {
- // Hasn't run yet or has stopped. (re)start batch job.
- $process = new BackgroundProcess($handle);
- $process->service_host = 'background_batch';
- if ($process->lock()) {
- $message = $batch['sets'][0]['init_message'];
- progress_initialize_progress('_' . $handle, $message);
- if (function_exists('progress_set_progress_start')) {
- progress_set_progress_start('_' . $handle, $batch['timestamp']);
- }
- else {
- db_query("UPDATE {progress} SET start = :start WHERE name = :name", array(':start' => $batch['timestamp'], ':name' => '_' . $handle));
- }
- $result = $process->execute('_background_batch_process', array($id));
- return $process;
- }
- }
- }
- function _background_batch_page_start() {
- _background_batch_initiate();
- if (isset($_COOKIE['has_js']) && $_COOKIE['has_js']) {
- return _background_batch_page_progress_js();
- }
- else {
- return _background_batch_page_do_nojs();
- }
- }
- /**
- * Batch processing page with JavaScript support.
- */
- function _background_batch_page_progress_js() {
- require_once('includes/batch.inc');
- $batch = batch_get();
- $current_set = _batch_current_set();
- drupal_set_title($current_set['title'], PASS_THROUGH);
- // Merge required query parameters for batch processing into those provided by
- // batch_set() or hook_batch_alter().
- $batch['url_options']['query']['id'] = $batch['id'];
- $js_setting['batch'] = array();
- $js_setting['batch']['errorMessage'] = $current_set['error_message'] . '<br />' . $batch['error_message'];
- // Check wether ETA information should be shown.
- if (variable_get('background_batch_show_eta', BACKGROUND_BATCH_PROCESS_ETA)) {
- $js_setting['batch']['initMessage'] = 'ETA: ' . t('N/A') . '<br/>' . $current_set['init_message'];
- }
- else {
- $js_setting['batch']['initMessage'] = $current_set['init_message'];
- }
- $js_setting['batch']['uri'] = url($batch['url'], $batch['url_options']);
- $js_setting['batch']['delay'] = variable_get('background_batch_delay', BACKGROUND_BATCH_DELAY);
- drupal_add_js($js_setting, 'setting');
- drupal_add_library('background_batch', 'background-process.batch');
- return '<div id="progress"></div>';
- }
- /**
- * Do one pass of execution and inform back the browser about progression
- * (used for JavaScript-mode only).
- */
- function _background_batch_page_do_js() {
- // HTTP POST required.
- if ($_SERVER['REQUEST_METHOD'] != 'POST') {
- drupal_set_message(t('HTTP POST is required.'), 'error');
- drupal_set_title(t('Error'));
- return '';
- }
- $batch = &batch_get();
- $id = $batch['id'];
- drupal_save_session(FALSE);
- $percentage = t('N/A');
- $message = '';
- if ($progress = progress_get_progress('_background_batch:' . $id)) {
- $percentage = $progress->progress * 100;
- $message = $progress->message;
- progress_estimate_completion($progress);
- // Check wether ETA information should be shown.
- if (variable_get('background_batch_show_eta', BACKGROUND_BATCH_PROCESS_ETA)) {
- $message = "ETA: " . ($progress->estimate ? format_date((int)$progress->estimate, 'large') : t('N/A')) . "<br/>$message";
- }
- else {
- $js_setting['batch']['initMessage'] = $message;
- }
- }
- if ($batch['sets'][$batch['current_set']]['count'] == 0) {
- // The background process has self-destructed, and the batch job is done.
- $percentage = 100;
- $message = '';
- }
- elseif ($process = background_process_get_process('background_batch:' . $id)) {
- _background_batch_initiate($process);
- }
- else {
- // Not running ... and stale?
- _background_batch_initiate();
- }
- drupal_json_output(array('status' => TRUE, 'percentage' => sprintf("%.02f", $percentage), 'message' => $message));
- }
- /**
- * Output a batch processing page without JavaScript support.
- *
- * @see _batch_process()
- */
- function _background_batch_page_do_nojs() {
- $batch = &batch_get();
- $id = $batch['id'];
- _background_batch_initiate();
- $current_set = _batch_current_set();
- drupal_set_title($current_set['title'], PASS_THROUGH);
- $new_op = 'do_nojs';
- // This is one of the later requests; do some processing first.
- // Error handling: if PHP dies due to a fatal error (e.g. a nonexistent
- // function), it will output whatever is in the output buffer, followed by
- // the error message.
- ob_start();
- $fallback = $current_set['error_message'] . '<br />' . $batch['error_message'];
- $fallback = theme('maintenance_page', array('content' => $fallback, 'show_messages' => FALSE));
- // We strip the end of the page using a marker in the template, so any
- // additional HTML output by PHP shows up inside the page rather than below
- // it. While this causes invalid HTML, the same would be true if we didn't,
- // as content is not allowed to appear after </html> anyway.
- list($fallback) = explode('<!--partial-->', $fallback);
- print $fallback;
- $percentage = t('N/A');
- $message = '';
- // Get progress
- if ($progress = progress_get_progress('_background_batch:' . $id)) {
- $percentage = $progress->progress * 100;
- $message = $progress->message;
- progress_estimate_completion($progress);
- // Check wether ETA information should be shown.
- if (variable_get('background_batch_show_eta', BACKGROUND_BATCH_PROCESS_ETA)) {
- $message = "ETA: " . ($progress->estimate ? format_date((int)$progress->estimate, 'large') : t('N/A')) . "<br/>$message";
- }
- }
- if ($batch['sets'][$batch['current_set']]['count'] == 0) {
- // The background process has self-destructed, and the batch job is done.
- $percentage = 100;
- $message = '';
- }
- elseif ($process = background_process_get_process('background_batch:' . $id)) {
- _background_batch_initiate($process);
- }
- else {
- // Not running ... and stale?
- _background_batch_initiate();
- }
- if ($percentage == 100) {
- $new_op = 'finished';
- }
- // PHP did not die; remove the fallback output.
- ob_end_clean();
- // Merge required query parameters for batch processing into those provided by
- // batch_set() or hook_batch_alter().
- $batch['url_options']['query']['id'] = $batch['id'];
- $batch['url_options']['query']['op'] = $new_op;
- $url = url($batch['url'], $batch['url_options']);
- $element = array(
- '#tag' => 'meta',
- '#attributes' => array(
- 'http-equiv' => 'Refresh',
- 'content' => '0; URL=' . $url,
- ),
- );
- drupal_add_html_head($element, 'batch_progress_meta_refresh');
- return theme('progress_bar', array('percent' => sprintf("%.02f", $percentage), 'message' => $message));
- }
|