Code coverage for /20081101/modules/upload/upload.module

Line #Times calledCode
1
<?php
2
// $Id: upload.module,v 1.213 2008/10/12 02:42:56 webchick Exp $
3
4
/**
5
 * @file
6
 * File-handling and attaching files to nodes.
7
 *
8
 */
9
10
/**
11
 * Implementation of hook_help().
12
 */
1362
function upload_help($path, $arg) {
14
  switch ($path) {
1541
    case 'admin/help#upload':
160
      $output = '<p>' . t('The upload module allows users to upload files
to the site. The ability to upload files is important for members of a
community who want to share work. It is also useful to administrators who
want to keep uploaded files connected to posts.') . '</p>';
170
      $output .= '<p>' . t('Users with the upload files permission can
upload attachments to posts. Uploads may be enabled for specific content
types on the content types settings page. Each user role can be customized
to limit or control the file size of uploads, or the maximum dimension of
image files.') . '</p>';
180
      $output .= '<p>' . t('For more information, see the online handbook
entry for <a href="@upload">Upload module</a>.', array('@upload' =>
'http://drupal.org/handbook/modules/upload/')) . '</p>';
190
      return $output;
2041
    case 'admin/settings/upload':
210
      return '<p>' . t('Users with the <a href="@permissions">upload files
permission</a> can upload attachments. Users with the <a
href="@permissions">view uploaded files permission</a> can view uploaded
attachments. You can choose which post types can take attachments on the <a
href="@types">content types settings</a> page.', array('@permissions' =>
url('admin/user/permissions'), '@types' => url('admin/settings/types'))) .
'</p>';
220
  }
2341
}
24
25
/**
26
 * Implementation of hook_theme().
27
 */
2862
function upload_theme() {
29
  return array(
30
    'upload_attachments' => array(
316
      'arguments' => array('files' => NULL),
326
    ),
33
    'upload_form_current' => array(
346
      'arguments' => array('form' => NULL),
356
    ),
36
    'upload_form_new' => array(
376
      'arguments' => array('form' => NULL),
386
    ),
396
  );
400
}
41
42
/**
43
 * Implementation of hook_perm().
44
 */
4562
function upload_perm() {
46
  return array(
47
    'upload files' => array(
481
      'title' => t('Upload files'),
491
      'description' => t('Attach images and other files to content.'),
501
    ),
51
    'view uploaded files' => array(
521
      'title' => t('View uploaded files'),
531
      'description' => t('View and download files attached to content.'),
541
    ),
551
  );
560
}
57
58
/**
59
 * Implementation of hook_link().
60
 */
6162
function upload_link($type, $node = NULL, $teaser = FALSE) {
627
  $links = array();
63
64
  // Display a link with the number of attachments
657
  if ($teaser && $type == 'node' && isset($node->files) &&
user_access('view uploaded files')) {
660
    $num_files = 0;
670
    foreach ($node->files as $file) {
680
      if ($file->list) {
690
        $num_files++;
700
      }
710
    }
720
    if ($num_files) {
730
      $links['upload_attachments'] = array(
740
        'title' => format_plural($num_files, '1 attachment', '@count
attachments'),
750
        'href' => "node/$node->nid",
760
        'attributes' => array('title' => t('Read full article to view
attachments.')),
77
        'fragment' => 'attachments'
780
      );
790
    }
800
  }
81
827
  return $links;
830
}
84
85
/**
86
 * Implementation of hook_menu().
87
 */
8862
function upload_menu() {
891
  $items['upload/js'] = array(
901
    'page callback' => 'upload_js',
911
    'access arguments' => array('upload files'),
921
    'type' => MENU_CALLBACK,
93
  );
941
  $items['admin/settings/uploads'] = array(
951
    'title' => 'File uploads',
961
    'description' => 'Control how files may be attached to content.',
971
    'page callback' => 'drupal_get_form',
981
    'page arguments' => array('upload_admin_settings'),
991
    'access arguments' => array('administer site configuration'),
1001
    'type' => MENU_NORMAL_ITEM,
101
  );
1021
  return $items;
1030
}
104
10562
function upload_menu_alter(&$items) {
1061
  $items['system/files']['access arguments'] = array('view uploaded
files');
1071
}
108
109
/**
110
 * Determine the limitations on files that a given user may upload. The
user
111
 * may be in multiple roles so we select the most permissive limitations
from
112
 * all of their roles.
113
 *
114
 * @param $user
115
 *   A Drupal user object.
116
 * @return
117
 *   An associative array with the following keys:
118
 *     'extensions'
119
 *       A white space separated string containing all the file extensions
this
120
 *       user may upload.
121
 *     'file_size'
122
 *       The maximum size of a file upload in bytes.
123
 *     'user_size'
124
 *       The total number of bytes for all for a user's files.
125
 *     'resolution'
126
 *       A string specifying the maximum resolution of images.
127
 */
12862
function _upload_file_limits($user) {
12914
  $file_limit = variable_get('upload_uploadsize_default', 1);
13014
  $user_limit = variable_get('upload_usersize_default', 1);
13114
  $all_extensions = explode(' ', variable_get('upload_extensions_default',
'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp'));
13214
  foreach ($user->roles as $rid => $name) {
13314
    $extensions = variable_get("upload_extensions_$rid",
variable_get('upload_extensions_default', 'jpg jpeg gif png txt doc xls pdf
ppt pps odt ods odp'));
13414
    $all_extensions = array_merge($all_extensions, explode(' ',
$extensions));
135
136
    // A zero value indicates no limit, take the least restrictive limit.
13714
    $file_size = variable_get("upload_uploadsize_$rid",
variable_get('upload_uploadsize_default', 1)) * 1024 * 1024;
13814
    $file_limit = ($file_limit && $file_size) ? max($file_limit,
$file_size) : 0;
139
14014
    $user_size = variable_get("upload_usersize_$rid",
variable_get('upload_usersize_default', 1)) * 1024 * 1024;
14114
    $user_limit = ($user_limit && $user_size) ? max($user_limit,
$user_size) : 0;
14214
  }
14314
  $all_extensions = implode(' ', array_unique($all_extensions));
144
  return array(
14514
    'extensions' => $all_extensions,
14614
    'file_size' => $file_limit,
14714
    'user_size' => $user_limit,
14814
    'resolution' => variable_get('upload_max_resolution', 0),
14914
  );
1500
}
151
152
/**
153
 * Implementation of hook_file_download().
154
 */
15562
function upload_file_download($filepath) {
1560
  $filepath = file_create_path($filepath);
1570
  $result = db_query("SELECT f.*, u.nid FROM {files} f INNER JOIN {upload}
u ON f.fid = u.fid WHERE filepath = '%s'", $filepath);
1580
  if ($file = db_fetch_object($result)) {
1590
    if (user_access('view uploaded files') && ($node =
node_load($file->nid)) && node_access('view', $node)) {
160
      return array(
1610
        'Content-Type: ' . $file->filemime,
1620
        'Content-Length: ' . $file->filesize,
1630
      );
1640
    }
165
    else {
1660
      return -1;
167
    }
1680
  }
1690
}
170
171
/**
172
 * Save new uploads and store them in the session to be associated to the
node
173
 * on upload_save.
174
 *
175
 * @param $node
176
 *   A node object to associate with uploaded files.
177
 */
17862
function upload_node_form_submit(&$form, &$form_state) {
1797
  global $user;
180
1817
  $limits = _upload_file_limits($user);
182
  $validators = array(
1837
    'file_validate_extensions' => array($limits['extensions']),
1847
    'file_validate_image_resolution' => array($limits['resolution']),
1857
    'file_validate_size' => array($limits['file_size'],
$limits['user_size']),
1867
  );
187
188
  // Save new file uploads.
1897
  if (user_access('upload files') && ($file = file_save_upload('upload',
$validators, file_directory_path()))) {
1903
    $file->list = variable_get('upload_list_default', 1);
1913
    $file->description = $file->filename;
1923
    $file->weight = 0;
1933
    $file->new = TRUE;
1943
    $form['#node']->files[$file->fid] = $file;
1953
    $form_state['values']['files'][$file->fid] = (array)$file;
1963
  }
197
1987
  if (isset($form_state['values']['files'])) {
1995
    foreach ($form_state['values']['files'] as $fid => $file) {
2005
      $form_state['values']['files'][$fid]['new'] =
!empty($form['#node']->files[$fid]->new);
2015
    }
2025
  }
203
204
  // Order the form according to the set file weight values.
2057
  if (!empty($form_state['values']['files'])) {
2065
    $microweight = 0.001;
2075
    foreach ($form_state['values']['files'] as $fid => $file) {
2085
      if (is_numeric($fid)) {
2095
        $form_state['values']['files'][$fid]['#weight'] = $file['weight'] +
$microweight;
2105
        $microweight += 0.001;
2115
      }
2125
    }
2135
    uasort($form_state['values']['files'], 'element_sort');
2145
  }
2157
}
216
21762
function upload_form_alter(&$form, $form_state, $form_id) {
21837
  if ($form_id == 'node_type_form' && isset($form['identity']['type'])) {
2190
    $form['workflow']['upload'] = array(
2200
      '#type' => 'radios',
2210
      '#title' => t('Attachments'),
2220
      '#default_value' => variable_get('upload_' .
$form['#node_type']->type, 1),
2230
      '#options' => array(t('Disabled'), t('Enabled')),
224
    );
2250
  }
226
22737
  if (!empty($form['#node_edit_form'])) {
2287
    $node = $form['#node'];
2297
    if (variable_get("upload_$node->type", TRUE)) {
230
      // Attachments fieldset
2317
      $form['attachments'] = array(
2327
        '#type' => 'fieldset',
2337
        '#access' => user_access('upload files'),
2347
        '#title' => t('File attachments'),
2357
        '#collapsible' => TRUE,
2367
        '#collapsed' => empty($node->files),
2377
        '#description' => t('Changes made to the attachments are not
permanent until you save this post. The first "listed" file will be
included in RSS feeds.'),
2387
        '#prefix' => '<div class="attachments">',
2397
        '#suffix' => '</div>',
2407
        '#weight' => 30,
241
      );
242
243
      // Wrapper for fieldset contents (used by ahah.js).
2447
      $form['attachments']['wrapper'] = array(
2457
        '#prefix' => '<div id="attach-wrapper">',
2467
        '#suffix' => '</div>',
247
      );
248
249
      // Make sure necessary directories for upload.module exist and are
250
      // writable before displaying the attachment form.
2517
      $path = file_directory_path();
2527
      $temp = file_directory_temp();
253
      // Note: pass by reference
2547
      if (!file_check_directory($path, FILE_CREATE_DIRECTORY) ||
!file_check_directory($temp, FILE_CREATE_DIRECTORY)) {
2550
        $form['attachments']['#description'] =  t('File attachments are
disabled. The file directories have not been properly configured.');
2560
        if (user_access('administer site configuration')) {
2570
          $form['attachments']['#description'] .= ' ' . t('Please visit the
<a href="@admin-file-system">file system configuration page</a>.',
array('@admin-file-system' => url('admin/settings/file-system')));
2580
        }
259
        else {
2600
          $form['attachments']['#description'] .= ' ' . t('Please contact
the site administrator.');
261
        }
2620
      }
263
      else {
2647
        $form['attachments']['wrapper'] += _upload_form($node);
2657
        $form['#attributes']['enctype'] = 'multipart/form-data';
266
      }
2677
    }
2687
    $form['#submit'][] = 'upload_node_form_submit';
2697
  }
27037
}
271
272
/**
273
 * Implementation of hook_file_load().
274
 */
27562
function upload_file_load(&$file) {
276
  // Add the upload specific data into the file object.
27711
  $values = db_query('SELECT * FROM {upload} u WHERE u.fid = :fid',
array(':fid' => $file->fid))->fetch(PDO::FETCH_ASSOC);
27811
  foreach ((array)$values as $key => $value) {
27911
    $file->{$key} = $value;
28011
  }
28111
}
282
283
/**
284
 * Implementation of hook_file_references().
285
 */
28662
function upload_file_references(&$file) {
287
  // If upload.module is still using a file, do not let other modules
delete it.
2881
  $count = db_query('SELECT COUNT(*) FROM {upload} WHERE fid = :fid',
array(':fid' => $file->fid))->fetchField();
2891
  if ($count) {
290
    // Return the name of the module and how many references it has to the
file.
2910
    return array('upload' => $count);
2920
  }
2931
}
294
295
/**
296
 * Implementation of hook_file_delete().
297
 */
29862
function upload_file_delete(&$file) {
299
  // Delete all information associated with the file.
3001
  db_delete('upload')->condition('fid', $file->fid)->execute();
3011
}
302
303
304
/**
305
 * Implementation of hook_nodeapi_load().
306
 */
30762
function upload_nodeapi_load(&$node, $teaser) {
30821
  if (variable_get("upload_$node->type", 1) == 1) {
30921
    $output = array('files' => upload_load($node));
31021
    return $output;
3110
  }
3120
}
313
314
/**
315
 * Implementation of hook_nodeapi_view().
316
 */
31762
function upload_nodeapi_view(&$node, $teaser) {
3187
  if (isset($node->files) && user_access('view uploaded files')) {
319
    // Add the attachments list to node body with a heavy
320
    // weight to ensure they're below other elements
3217
    if (count($node->files)) {
3225
      if (!$teaser && user_access('view uploaded files')) {
3235
        $node->content['files'] = array(
3245
          '#markup' => theme('upload_attachments', $node->files),
3255
          '#weight' => 50,
326
        );
3275
      }
3285
    }
3297
  }
3307
}
331
332
/**
333
 * Implementation of hook_nodeapi_insert().
334
 */
33562
function upload_nodeapi_insert(&$node, $teaser) {
3361
  if (user_access('upload files')) {
3371
    upload_save($node);
3381
  }
3391
}
340
341
/**
342
 * Implementation of hook_nodeapi_update().
343
 */
34462
function upload_nodeapi_update(&$node, $teaser) {
3457
  if (user_access('upload files')) {
3467
    upload_save($node);
3477
  }
3487
}
349
350
/**
351
 * Implementation of hook_nodeapi_delete().
352
 */
35362
function upload_nodeapi_delete(&$node, $teaser) {
3540
  db_delete('upload')->condition('nid', $node->nid)->execute();
3550
  if (!is_array($node->files)) {
3560
    return;
3570
  }
3580
  foreach($node->files as $file) {
3590
    file_delete($file);
3600
  }
3610
}
362
363
/**
364
 * Implementation of hook_nodeapi_delete_revision().
365
 */
36662
function upload_nodeapi_delete_revision(&$node, $teaser) {
3670
  db_delete('upload')->condition('vid', $node->vid)->execute();
3680
  if (!is_array($node->files)) {
3690
    return;
3700
  }
3710
  foreach ($node->files as $file) {
3720
    file_delete($file);
3730
  }
3740
}
375
376
/**
377
 * Implementation of hook_nodeapi_search_result().
378
 */
37962
function upload_nodeapi_search_result(&$node, $teaser) {
3800
  return isset($node->files) && is_array($node->files) ?
format_plural(count($node->files), '1 attachment', '@count attachments') :
NULL;
3810
}
382
383
/**
384
 * Implementation of hook_nodeapi_rss_item().
385
 */
38662
function upload_nodeapi_rss_item(&$node, $teaser) {
3870
  if (is_array($node->files)) {
3880
    $files = array();
3890
    foreach ($node->files as $file) {
3900
      if ($file->list) {
3910
        $files[] = $file;
3920
      }
3930
    }
3940
    if (count($files) > 0) {
395
      // RSS only allows one enclosure per item
3960
      $file = array_shift($files);
397
      return array(
398
        array(
3990
          'key' => 'enclosure',
400
          'attributes' => array(
4010
            'url' => file_create_url($file->filepath),
4020
            'length' => $file->filesize,
4030
            'type' => $file->filemime
4040
          )
4050
        )
4060
      );
4070
    }
4080
  }
4090
  return array();
4100
}
411
412
/**
413
 * Displays file attachments in table
414
 *
415
 * @ingroup themeable
416
 */
41762
function theme_upload_attachments($files) {
4185
  $header = array(t('Attachment'), t('Size'));
4195
  $rows = array();
4205
  foreach ($files as $file) {
4215
    $file = (object)$file;
4225
    if ($file->list && empty($file->remove)) {
4235
      $href = file_create_url($file->filepath);
4245
      $text = $file->description ? $file->description : $file->filename;
4255
      $rows[] = array(l($text, $href), format_size($file->filesize));
4265
    }
4275
  }
4285
  if (count($rows)) {
4295
    return theme('table', $header, $rows, array('id' => 'attachments'));
4300
  }
4310
}
432
433
/**
434
 * Determine how much disk space is occupied by a user's uploaded files.
435
 *
436
 * @param $uid
437
 *   The integer user id of a user.
438
 * @return
439
 *   The amount of disk space used by the user in bytes.
440
 */
44162
function upload_space_used($uid) {
4420
  return file_space_used($uid);
4430
}
444
445
/**
446
 * Determine how much disk space is occupied by uploaded files.
447
 *
448
 * @return
449
 *   The amount of disk space used by uploaded files in bytes.
450
 */
45162
function upload_total_space_used() {
4520
  return db_result(db_query('SELECT SUM(f.filesize) FROM {files} f INNER
JOIN {upload} u ON f.fid = u.fid'));
4530
}
454
45562
function upload_save(&$node) {
4568
  if (empty($node->files) || !is_array($node->files)) {
4573
    return;
4580
  }
459
4605
  foreach ($node->files as $fid => $file) {
461
    // Convert file to object for compatibility
4625
    $file = (object)$file;
463
464
    // Remove file. Process removals first since no further processing
465
    // will be required.
4665
    if (!empty($file->remove)) {
467
      // Remove the reference from this revision.
4681
      db_delete('upload')->condition('fid', $file->fid)->condition('vid',
$node->vid)->execute();
469
      // Try a soft delete, if the file isn't used elsewhere it'll be
deleted.
4701
      file_delete($file);
471
      // Remove it from the session in the case of new uploads,
472
      // that you want to disassociate before node submission.
4731
      unset($node->files[$fid]);
474
      // Move on, so the removed file won't be added to new revisions.
4751
      continue;
4760
    }
477
478
    // Create a new revision, or associate a new file needed.
4795
    if (!empty($node->old_vid) || $file->new) {
4803
      db_query("INSERT INTO {upload} (fid, nid, vid, list, description,
weight) VALUES (%d, %d, %d, %d, '%s', %d)", $file->fid, $node->nid,
$node->vid, $file->list, $file->description, $file->weight);
4813
    }
482
    // Update existing revision.
483
    else {
4843
      db_query("UPDATE {upload} SET list = %d, description = '%s', weight =
%d WHERE fid = %d AND vid = %d", $file->list, $file->description,
$file->weight, $file->fid, $node->vid);
485
    }
4865
    file_set_status($file, FILE_STATUS_PERMANENT);
4875
  }
4885
}
489
49062
function _upload_form($node) {
4917
  global $user;
492
493
  $form = array(
4947
    '#theme' => 'upload_form_new',
4957
    '#cache' => TRUE,
4967
  );
497
4987
  if (!empty($node->files) && is_array($node->files)) {
4993
    $form['files']['#theme'] = 'upload_form_current';
5003
    $form['files']['#tree'] = TRUE;
5013
    foreach ($node->files as $file) {
5023
      $file = (object)$file;
5033
      $key = $file->fid;
504
5053
      $form['files'][$key]['description'] = array('#type' => 'textfield',
'#default_value' => !empty($file->description) ? $file->description :
$file->filename, '#maxlength' => 256, '#description' => '<small>' .
file_create_url($file->filepath) . '</small>');
5063
      $form['files'][$key]['size'] = array('#markup' =>
format_size($file->filesize));
5073
      $form['files'][$key]['remove'] = array('#type' => 'checkbox',
'#default_value' => !empty($file->remove));
5083
      $form['files'][$key]['list'] = array('#type' => 'checkbox', 
'#default_value' => $file->list);
5093
      $form['files'][$key]['weight'] = array('#type' => 'weight', '#delta'
=> count($node->files), '#default_value' => $file->weight);
5103
      $form['files'][$key]['filename'] = array('#type' => 'value', 
'#value' => $file->filename);
5113
      $form['files'][$key]['filepath'] = array('#type' => 'value', 
'#value' => $file->filepath);
5123
      $form['files'][$key]['filemime'] = array('#type' => 'value', 
'#value' => $file->filemime);
5133
      $form['files'][$key]['filesize'] = array('#type' => 'value', 
'#value' => $file->filesize);
5143
      $form['files'][$key]['fid'] = array('#type' => 'value',  '#value' =>
$file->fid);
5153
      $form['files'][$key]['new'] = array('#type' => 'value', '#value' =>
FALSE);
5163
    }
5173
  }
518
5197
  if (user_access('upload files')) {
5207
    $limits = _upload_file_limits($user);
521
5227
    $limit_description = t('The maximum size of file uploads is %filesize.
', array('%filesize' => format_size($limits['file_size'])));
5237
    if (!empty($limits['resolution'])) {
5240
      if (image_get_toolkit()) {
5250
        $limit_description .= t('Images larger than %resolution will be
resized. ', array('%resolution' => $limits['resolution']));
5260
      }
527
      else {
5280
        $limit_description .= t('Images may not be larger than %resolution.
', array('%resolution' => $limits['resolution']));
529
      }
5300
    }
5317
    if ($user->uid != 1) {
5327
      $limit_description .= t('Only files with the following extensions may
be uploaded: %extensions. ', array('%extensions' =>
$limits['extensions']));
5337
    }
534
5357
    $form['new']['#weight'] = 10;
5367
    $form['new']['upload'] = array(
5377
      '#type' => 'file',
5387
      '#title' => t('Attach new file'),
5397
      '#size' => 40,
5407
      '#description' => $limit_description,
541
    );
5427
    $form['new']['attach'] = array(
5437
      '#type' => 'submit',
5447
      '#value' => t('Attach'),
5457
      '#name' => 'attach',
546
      '#ahah' => array(
5477
        'path' => 'upload/js',
5487
        'wrapper' => 'attach-wrapper',
5497
        'progress' => array('type' => 'bar', 'message' => t('Please
wait...')),
5507
      ),
5517
      '#submit' => array('node_form_submit_build_node'),
552
    );
5537
  }
554
5557
  return $form;
5560
}
557
558
/**
559
 * Theme the attachments list.
560
 *
561
 * @ingroup themeable
562
 */
56362
function theme_upload_form_current(&$form) {
5643
  $header = array('', t('Delete'), t('List'), t('Description'),
t('Weight'), t('Size'));
5653
  drupal_add_tabledrag('upload-attachments', 'order', 'sibling',
'upload-weight');
566
5673
  foreach (element_children($form) as $key) {
568
    // Add class to group weight fields for drag and drop.
5693
    $form[$key]['weight']['#attributes']['class'] = 'upload-weight';
570
5713
    $row = array('');
5723
    $row[] = drupal_render($form[$key]['remove']);
5733
    $row[] = drupal_render($form[$key]['list']);
5743
    $row[] = drupal_render($form[$key]['description']);
5753
    $row[] = drupal_render($form[$key]['weight']);
5763
    $row[] = drupal_render($form[$key]['size']);
5773
    $rows[] = array('data' => $row, 'class' => 'draggable');
5783
  }
5793
  $output = theme('table', $header, $rows, array('id' =>
'upload-attachments'));
5803
  $output .= drupal_render($form);
5813
  return $output;
5820
}
583
584
/**
585
 * Theme the attachment form.
586
 * Note: required to output prefix/suffix.
587
 *
588
 * @ingroup themeable
589
 */
59062
function theme_upload_form_new($form) {
5917
  drupal_add_tabledrag('upload-attachments', 'order', 'sibling',
'upload-weight');
5927
  $output = drupal_render($form);
5937
  return $output;
5940
}
595
59662
function upload_load($node) {
59721
  $files = array();
598
59921
  if ($node->vid) {
60021
    $result = db_query('SELECT u.fid FROM {upload} u WHERE u.vid = :vid
ORDER BY u.weight, u.fid', array(':vid' => $node->vid));
60121
    foreach ($result as $file) {
60211
      $files[$file->fid] = file_load($file->fid);
60311
    }
60421
  }
605
60621
  return $files;
6070
}
608
609
/**
610
 * Menu-callback for JavaScript-based uploads.
611
 */
61262
function upload_js() {
6130
  $cached_form_state = array();
6140
  $files = array();
615
616
  // Load the form from the Form API cache.
6170
  if (!($cached_form = form_get_cache($_POST['form_build_id'],
$cached_form_state)) || !isset($cached_form['#node']) ||
!isset($cached_form['attachments'])) {
6180
    form_set_error('form_token', t('Validation error, please try again. If
this error persists, please contact the site administrator.'));
6190
    $output = theme('status_messages');
6200
    print drupal_to_js(array('status' => TRUE, 'data' => $output));
6210
    exit();
6220
  }
623
6240
  $form_state = array('values' => $_POST);
625
626
  // Handle new uploads, and merge tmp files into node-files.
6270
  upload_node_form_submit($cached_form, $form_state);
628
6290
  if (!empty($form_state['values']['files'])) {
6300
    foreach ($form_state['values']['files'] as $fid => $file) {
6310
      if (isset($cached_form['#node']->files[$fid])) {
6320
        $files[$fid] = $cached_form['#node']->files[$fid];
6330
      }
6340
    }
6350
  }
636
6370
  $node = $cached_form['#node'];
638
6390
  $node->files = $files;
640
6410
  $form = _upload_form($node);
642
6430
  unset($cached_form['attachments']['wrapper']['new']);
6440
  $cached_form['attachments']['wrapper'] =
array_merge($cached_form['attachments']['wrapper'], $form);
645
6460
  $cached_form['attachments']['#collapsed'] = FALSE;
647
6480
  form_set_cache($_POST['form_build_id'], $cached_form,
$cached_form_state);
649
6500
  foreach ($files as $fid => $file) {
6510
    if (is_numeric($fid)) {
6520
      $form['files'][$fid]['description']['#default_value'] =
$form_state['values']['files'][$fid]['description'];
6530
      $form['files'][$fid]['list']['#default_value'] =
!empty($form_state['values']['files'][$fid]['list']);
6540
      $form['files'][$fid]['remove']['#default_value'] =
!empty($form_state['values']['files'][$fid]['remove']);
6550
      $form['files'][$fid]['weight']['#default_value'] =
$form_state['values']['files'][$fid]['weight'];
6560
    }
6570
  }
658
659
  // Render the form for output.
660
  $form += array(
6610
    '#post' => $_POST,
6620
    '#programmed' => FALSE,
6630
    '#tree' => FALSE,
6640
    '#parents' => array(),
6650
  );
6660
  drupal_alter('form', $form, array(), 'upload_js');
6670
  $form_state = array('submitted' => FALSE);
6680
  $form = form_builder('upload_js', $form, $form_state);
6690
  $output = theme('status_messages') . drupal_render($form);
670
671
  // We send the updated file attachments form.
672
  // Don't call drupal_json(). ahah.js uses an iframe and
673
  // the header output by drupal_json() causes problems in some browsers.
6740
  print drupal_to_js(array('status' => TRUE, 'data' => $output));
6750
  exit;
6760
}
67762