1.20.x file.module file_ajax_upload()

Ajax callback: Processes file uploads and deletions.

This rebuilds the form element for a particular field item. As long as the form processing is properly encapsulated in the widget element the form should rebuild correctly using FAPI without the need for additional callbacks or processing.

See also

file_menu()

File

modules/file/file.module, line 1104
Defines a "managed_file" Form API field and a "file" field for Field module.

Code

function file_ajax_upload() {
  $args = func_get_args();
  // Token used to validate that the path values are unmodified.
  $token = (string) array_pop($args);
  // Form build key to pull from the form cache.
  $form_build_id = (string) array_pop($args);
  // All remaining arguments are the path to the form element in the form tree.
  $form_parents = $args;
  // Reassemble the #ajax['path'] property so we can validate the token.
  $original_path = 'file/ajax/' . implode('/', $form_parents) . '/' . $form_build_id;
  $original_token = backdrop_hmac_base64($original_path, backdrop_get_private_key() . backdrop_get_hash_salt());
  if ($original_token !== $token) {
    // Path has been tampered with. Reject the request.
    backdrop_set_message(t('Invalid upload token.'), 'error');
    $commands = array();
    $commands[] = ajax_command_remove('.file-ajax-messages');
    $commands[] = ajax_command_prepend(NULL, '<div class="file-ajax-messages">' . theme('status_messages') . '</div>');
    return array('#type' => 'ajax', '#commands' => $commands);
  }

  // Sanitize form parents before using them.
  $form_parents = array_filter($form_parents, 'element_child');

  if (empty($_POST['form_build_id']) || $form_build_id != $_POST['form_build_id']) {
    // Invalid request.
    backdrop_set_message(t('An unrecoverable error occurred. The uploaded file likely exceeded the maximum file size (@size) that this server supports.', array('@size' => format_size(file_upload_max_size()))), 'error');
    $commands = array();
    $commands[] = ajax_command_remove('.file-ajax-messages');
    $commands[] = ajax_command_prepend(NULL, '<div class="file-ajax-messages">' . theme('status_messages') . '</div>');
    return array('#type' => 'ajax', '#commands' => $commands);
  }

  list($form, $form_state, $form_id, $form_build_id, $commands) = ajax_get_form();

  if (!$form) {
    // Invalid form_build_id.
    backdrop_set_message(t('An unrecoverable error occurred. Use of this form has expired. Try reloading the page and submitting again.'), 'error');
    $commands = array();
    $commands[] = ajax_command_remove('.file-ajax-messages');
    $commands[] = ajax_command_prepend(NULL, '<div class="file-ajax-messages">' . theme('status_messages') . '</div>');
    return array('#type' => 'ajax', '#commands' => $commands);
  }

  // Process user input. $form and $form_state are modified in the process.
  backdrop_process_form($form['#form_id'], $form, $form_state);

  // Retrieve the element to be rendered.
  foreach ($form_parents as $parent) {
    $form = $form[$parent];
  }

  $form['#prefix'] .= '<div class="file-ajax-messages">' . theme('status_messages') . '</div>';
  $output = backdrop_render($form);
  $js = backdrop_add_js();
  $settings = backdrop_array_merge_deep_array($js['settings']['data']);

  $commands[] = ajax_command_replace(NULL, $output, $settings);
  return array('#type' => 'ajax', '#commands' => $commands);
}