#793042 by franz: Required file fields not validated properly when Content permission...
[project/filefield.git] / filefield_widget.inc
CommitLineData
9412a7cc
JP
1<?php
2// $Id$
a679aaae 3
9412a7cc
JP
4/**
5 * @file
90a92972 6 * This file contains CCK widget related functionality.
9412a7cc
JP
7 *
8 * Uses content.module to store the fid and field specific metadata,
90a92972 9 * and Drupal's files table to store the actual file data.
9412a7cc
JP
10 */
11
22e736e6 12/**
87d3e491 13 * Implementation of CCK's hook_widget_settings($op == 'form').
22e736e6 14 */
22e736e6
DP
15function filefield_widget_settings_form($widget) {
16 $form = array();
11e9b45d
NH
17
18 // Convert the extensions list to be a human-friendly comma-separated list.
19 $extensions = is_string($widget['file_extensions']) ? $widget['file_extensions'] : 'txt';
22e736e6
DP
20 $form['file_extensions'] = array(
21 '#type' => 'textfield',
22 '#title' => t('Permitted upload file extensions'),
11e9b45d 23 '#default_value' => $extensions,
22e736e6 24 '#size' => 64,
4217ecf5 25 '#maxlength' => 512,
22e736e6 26 '#description' => t('Extensions a user can upload to this field. Separate extensions with a space and do not include the leading dot. Leaving this blank will allow users to upload a file with any extension.'),
11e9b45d 27 '#element_validate' => array('_filefield_widget_settings_extensions_validate'),
3fdeaa24 28 '#pre_render' => array('_filefield_widget_settings_extensions_value'),
22e736e6
DP
29 '#weight' => 1,
30 );
87d3e491 31
70785e17
NH
32 $form['progress_indicator'] = array(
33 '#type' => 'radios',
34 '#title' => t('Progress indicator'),
35 '#options' => array(
36 'bar' => t('Bar with progress meter'),
37 'throbber' => t('Throbber'),
38 ),
39 '#default_value' => empty($widget['progress_indicator']) ? 'bar' : $widget['progress_indicator'],
40 '#description' => t('Your server supports upload progress capabilities. The "throbber" display does not indicate progress but takes up less room on the form, you may want to use it if you\'ll only be uploading small files or if experiencing problems with the progress bar.'),
41 '#weight' => 5,
42 '#access' => filefield_progress_implementation(),
43 );
44
22e736e6
DP
45 $form['path_settings'] = array(
46 '#type' => 'fieldset',
47 '#title' => t('Path settings'),
e76d77f0
NH
48 '#collapsible' => TRUE,
49 '#collapsed' => TRUE,
22e736e6
DP
50 '#weight' => 6,
51 );
22e736e6
DP
52 $form['path_settings']['file_path'] = array(
53 '#type' => 'textfield',
54 '#title' => t('File path'),
55 '#default_value' => is_string($widget['file_path']) ? $widget['file_path'] : '',
af2b0845 56 '#description' => t('Optional subdirectory within the "%directory" directory where files will be stored. Do not include preceding or trailing slashes.', array('%directory' => variable_get('file_directory_path', 'files') . '/')),
22e736e6
DP
57 '#element_validate' => array('_filefield_widget_settings_file_path_validate'),
58 '#suffix' => theme('token_help', 'user'),
59 );
60
61 $form['max_filesize'] = array(
62 '#type' => 'fieldset',
63 '#title' => t('File size restrictions'),
64 '#description' => t('Limits for the size of files that a user can upload. Note that these settings only apply to newly uploaded files, whereas existing files are not affected.'),
65 '#weight' => 6,
66 '#collapsible' => TRUE,
67 '#collapsed' => TRUE,
68 );
69 $form['max_filesize']['max_filesize_per_file'] = array(
70 '#type' => 'textfield',
71 '#title' => t('Maximum upload size per file'),
72 '#default_value' => is_string($widget['max_filesize_per_file'])
73 ? $widget['max_filesize_per_file']
74 : '',
7982f68b 75 '#description' => t('Specify the size limit that applies to each file separately. Enter a value like "512" (bytes), "80K" (kilobytes) or "50M" (megabytes) in order to restrict the allowed file size. If you leave this empty the file sizes will be limited only by PHP\'s maximum post and file upload sizes (current limit <strong>%limit</strong>).', array('%limit' => format_size(file_upload_max_size()))),
22e736e6
DP
76 '#element_validate' => array('_filefield_widget_settings_max_filesize_per_file_validate'),
77 );
78 $form['max_filesize']['max_filesize_per_node'] = array(
79 '#type' => 'textfield',
80 '#title' => t('Maximum upload size per node'),
81 '#default_value' => is_string($widget['max_filesize_per_node'])
82 ? $widget['max_filesize_per_node']
83 : '',
84 '#description' => t('Specify the total size limit for all files in field on a given node. Enter a value like "512" (bytes), "80K" (kilobytes) or "50M" (megabytes) in order to restrict the total size of a node. Leave this empty if there should be no size restriction.'),
85 '#element_validate' => array('_filefield_widget_settings_max_filesize_per_node_validate'),
86 );
87d3e491 87
22e736e6
DP
88 return $form;
89}
90
87d3e491
NH
91/**
92 * Implementation of CCK's hook_widget_settings($op == 'save').
93 */
22e736e6 94function filefield_widget_settings_save($widget) {
70785e17 95 return array('file_extensions', 'file_path', 'progress_indicator', 'max_filesize_per_file', 'max_filesize_per_node');
22e736e6
DP
96}
97
3fdeaa24
NH
98/**
99 * A FAPI #pre_render() function to set a cosmetic default value for extensions.
100 */
101function _filefield_widget_settings_extensions_value($element) {
102 $element['#value'] = implode(', ', explode(' ', $element['#value']));
103 return $element;
104}
105
106/**
107 * A FAPI #element_validate callback to strip commas from extension lists.
108 */
11e9b45d
NH
109function _filefield_widget_settings_extensions_validate($element, &$form_state) {
110 // Remove commas from file extensions.
111 $value = str_replace(',', ' ', $element['#value']);
112 $value = array_filter(explode(' ', $value));
113 $value = implode(' ', $value);
114 form_set_value($element, $value, $form_state);
115}
116
22e736e6
DP
117function _filefield_widget_settings_file_path_validate($element, &$form_state) {
118 // Strip slashes from the beginning and end of $widget['file_path']
119 $form_state['values']['file_path'] = trim($form_state['values']['file_path'], '\\/');
5322fc46
NH
120
121 // Do not allow the file path to be the same as the file_directory_path().
122 // This causes all sorts of problems with things like file_create_url().
123 if (strpos($form_state['values']['file_path'], file_directory_path()) === 0) {
124 form_error($element, t('The file path (@file_path) cannot start with the system files directory (@files_directory), as this may cause conflicts when building file URLs.', array('@file_path' => $form_state['values']['file_path'], '@files_directory' => file_directory_path())));
125 }
22e736e6
DP
126}
127
128function _filefield_widget_settings_max_filesize_per_file_validate($element, &$form_state) {
129 if (empty($form_state['values']['max_filesize_per_file'])) {
130 return; // Empty means no size restrictions, so don't throw an error.
131 }
87d3e491
NH
132 elseif (!is_numeric(parse_size($form_state['values']['max_filesize_per_file']))) {
133 form_error($element, t('The "@field" option must contain a valid value. You can either leave the text field empty or enter a string like "512" (bytes), "80K" (kilobytes) or "50M" (megabytes).', array('@field' => t('Maximum upload size per file'))));
22e736e6
DP
134 }
135}
136
137function _filefield_widget_settings_max_filesize_per_node_validate($element, &$form_state) {
138 if (empty($form_state['values']['max_filesize_per_node'])) {
139 return; // Empty means no size restrictions, so don't throw an error.
140 }
87d3e491
NH
141 elseif (!is_numeric(parse_size($form_state['values']['max_filesize_per_node']))) {
142 form_error($element, t('The "@field" option must contain a valid value. You can either leave the text field empty or enter a string like "512" (bytes), "80K" (kilobytes) or "50M" (megabytes).', array('@field' => t('Maximum upload size per node'))));
22e736e6
DP
143 }
144}
145
bf602673 146/**
147 * Determine the widget's files directory
148 *
87d3e491
NH
149 * @param $field
150 * A CCK field array.
25f2014e
NH
151 * @param $account
152 * The user account object to calculate the file path for.
87d3e491
NH
153 * @return
154 * The files directory path, with any tokens replaced.
bf602673 155 */
25f2014e
NH
156function filefield_widget_file_path($field, $account = NULL) {
157 $account = isset($account) ? $account : $GLOBALS['user'];
158 $dest = $field['widget']['file_path'];
14907c69
NH
159 // Replace user level tokens.
160 // Node level tokens require a lot of complexity like temporary storage
161 // locations when values don't exist. See the filefield_paths module.
bf602673 162 if (module_exists('token')) {
25f2014e 163 $dest = token_replace($dest, 'user', $account);
bf602673 164 }
14907c69
NH
165 // Replace nasty characters in the path if possible.
166 if (module_exists('transliteration')) {
f21581e9 167 module_load_include('inc', 'transliteration');
14907c69
NH
168 $dest_array = array_filter(explode('/', $dest));
169 foreach ($dest_array as $key => $directory) {
170 $dest_array[$key] = transliteration_clean_filename($directory);
171 }
172 $dest = implode('/', $dest_array);
173 }
bf602673 174
175 return file_directory_path() .'/'. $dest;
176}
177
87d3e491
NH
178/**
179 * Given a FAPI element, save any files that may have been uploaded into it.
180 *
181 * This function should only be called during validate, submit, or
182 * value_callback functions.
183 *
184 * @param $element
185 * The FAPI element whose values are being saved.
186 */
8ffd8e3d
DP
187function filefield_save_upload($element) {
188 $upload_name = $element['#field_name'] .'_'. $element['#delta'];
25f2014e 189 $field = content_fields($element['#field_name'], $element['#type_name']);
8ffd8e3d
DP
190
191 if (empty($_FILES['files']['name'][$upload_name])) {
192 return 0;
193 }
194
25f2014e 195 $dest = filefield_widget_file_path($field);
8ffd8e3d 196 if (!field_file_check_directory($dest, FILE_CREATE_DIRECTORY)) {
32984cd2 197 watchdog('filefield', 'The upload directory %directory for the file field %field (content type %type) could not be created or is not accessible. A newly uploaded file could not be saved in this directory as a consequence, and the upload was canceled.', array('%directory' => $dest, '%field' => $element['#field_name'], '%type' => $element['#type_name']));
8ffd8e3d
DP
198 form_set_error($upload_name, t('The file could not be uploaded.'));
199 return 0;
200 }
201
202 if (!$file = field_file_save_upload($upload_name, $element['#upload_validators'], $dest)) {
32984cd2 203 watchdog('filefield', 'The file upload failed. %upload', array('%upload' => $upload_name));
29194778 204 form_set_error($upload_name, t('The file in the @field field was unable to be uploaded.', array('@field' => $element['#title'])));
8ffd8e3d
DP
205 return 0;
206 }
207 return $file['fid'];
208}
209
22e736e6 210/**
87d3e491 211 * The #value_callback for the filefield_widget type element.
22e736e6 212 */
d2f124d5 213function filefield_widget_value($element, $edit = FALSE) {
7e784adc 214 if (!$edit) {
692a0c14 215 $file = field_file_load($element['#default_value']['fid']);
d2f124d5
DP
216 $item = $element['#default_value'];
217 }
218 else {
93c5556a 219 $item = $edit;
692a0c14
NH
220 $field = content_fields($element['#field_name'], $element['#type_name']);
221
222 // Uploads take priority over value of fid text field.
8ffd8e3d 223 if ($fid = filefield_save_upload($element)) {
9811a70a 224 $item['fid'] = $fid;
7e784adc 225 }
01c15c1d
NH
226 // Check for #filefield_value_callback values.
227 // Because FAPI does not allow multiple #value_callback values like it does
228 // for #element_validate and #process, this fills the missing functionality
229 // to allow FileField to be extended purely through FAPI.
230 elseif (isset($element['#filefield_value_callback'])) {
231 foreach ($element['#filefield_value_callback'] as $callback) {
232 $callback($element, $item);
233 }
234 }
5322fc46 235
692a0c14 236 // Load file if the FID has changed so that it can be saved by CCK.
9811a70a 237 $file = field_file_load($item['fid']);
692a0c14 238
3ecf9d5c
NH
239 // If the file entry doesn't exist, don't save anything.
240 if (empty($file)) {
241 $item = array();
242 }
243
692a0c14
NH
244 // Checkboxes loose their value when empty.
245 // If the list field is present make sure its unchecked value is saved.
4a03547e 246 if (!empty($field['list_field']) && empty($edit['list'])) {
692a0c14
NH
247 $item['list'] = 0;
248 }
d2f124d5 249 }
692a0c14 250 // Merge file and item data so it is available to all widgets.
93c5556a
NH
251 if (isset($item['data']) && isset($file['data'])) {
252 $file['data'] = array_merge($item['data'], $file['data']);
253 }
6e7782b4 254 $item = array_merge($item, $file);
1bffec9e 255
6e7782b4 256 return $item;
d2f124d5
DP
257}
258
87d3e491
NH
259/**
260 * An element #process callback for the filefield_widget field type.
261 *
262 * Expands the filefield_widget type to include the upload field, upload and
263 * remove buttons, and the description field.
264 */
d2f124d5 265function filefield_widget_process($element, $edit, &$form_state, $form) {
9c0b75b0 266 // The widget is being presented, so apply the JavaScript.
267 drupal_add_js(drupal_get_path('module', 'filefield') .'/filefield.js');
7e784adc 268
8ffd8e3d
DP
269 $item = $element['#value'];
270 $field_name = $element['#field_name'];
271 $delta = $element['#delta'];
3897ed27 272 $element['#theme'] = 'filefield_widget_item';
8ffd8e3d 273
6877d63b 274 $field = $form['#field_info'][$field_name];
ad6c5ff0 275
3897ed27
NH
276 // Title is not necessary for each individual field.
277 if ($field['multiple'] > 0) {
278 unset($element['#title']);
279 }
280
4b58ccde
NH
281 // Set up the buttons first since we need to check if they were clicked.
282 $element['filefield_upload'] = array(
283 '#type' => 'submit',
284 '#value' => t('Upload'),
4b58ccde
NH
285 '#submit' => array('node_form_submit_build_node'),
286 '#ahah' => array( // with JavaScript
287 'path' => 'filefield/ahah/'. $element['#type_name'] .'/'. $element['#field_name'] .'/'. $element['#delta'],
288 'wrapper' => $element['#id'] .'-ahah-wrapper',
289 'method' => 'replace',
290 'effect' => 'fade',
291 ),
292 '#field_name' => $element['#field_name'],
293 '#delta' => $element['#delta'],
294 '#type_name' => $element['#type_name'],
295 '#upload_validators' => $element['#upload_validators'],
296 '#weight' => 100,
297 '#post' => $element['#post'],
298 );
299 $element['filefield_remove'] = array(
cfc7028a
NH
300 // With default CCK edit forms, $element['#parents'] is array($element['#field_name'], $element['#delta']).
301 // However, if some module (for example, flexifield) places our widget deeper in the tree, we want to
302 // use that information in constructing the button name.
303 '#name' => implode('_', $element['#parents']) .'_filefield_remove',
4b58ccde
NH
304 '#type' => 'submit',
305 '#value' => t('Remove'),
4b58ccde
NH
306 '#submit' => array('node_form_submit_build_node'),
307 '#ahah' => array( // with JavaScript
308 'path' => 'filefield/ahah/'. $element['#type_name'] .'/'. $element['#field_name'] .'/'. $element['#delta'],
309 'wrapper' => $element['#id'] .'-ahah-wrapper',
310 'method' => 'replace',
311 'effect' => 'fade',
312 ),
313 '#field_name' => $element['#field_name'],
314 '#delta' => $element['#delta'],
315 '#weight' => 101,
316 '#post' => $element['#post'],
317 );
318
319 // Because the output of this field changes depending on the button clicked,
320 // we need to ask FAPI immediately if the remove button was clicked.
321 // It's not good that we call this private function, but
322 // $form_state['clicked_button'] is only available after this #process
323 // callback is finished.
324 if (_form_button_was_clicked($element['filefield_remove'])) {
319a4dc5
NH
325 // Delete the file if it is currently unused. Note that field_file_delete()
326 // does a reference check in addition to our basic status check.
327 if (isset($edit['fid'])) {
328 $removed_file = field_file_load($edit['fid']);
329 if ($removed_file['status'] == 0) {
330 field_file_delete($removed_file);
331 }
332 }
3a35dc81 333 $item = array('fid' => 0, 'list' => $field['list_default'], 'data' => array('description' => ''));
8ffd8e3d 334 }
7e784adc 335
4b58ccde
NH
336 // Set access on the buttons.
337 $element['filefield_upload']['#access'] = empty($item['fid']);
338 $element['filefield_remove']['#access'] = !empty($item['fid']);
339
e3623331 340 // Add progress bar support to the upload if possible.
70785e17
NH
341 $progress_indicator = isset($field['widget']['progress_indicator']) ? $field['widget']['progress_indicator'] : 'bar';
342 if ($progress_indicator != 'throbber' && $implementation = filefield_progress_implementation()) {
e3623331
NH
343 $upload_progress_key = md5(mt_rand());
344
345 if ($implementation == 'uploadprogress') {
346 $element['UPLOAD_IDENTIFIER'] = array(
347 '#type' => 'hidden',
348 '#value' => $upload_progress_key,
349 '#attributes' => array('class' => 'filefield-progress'),
350 );
351 }
352 elseif ($implementation == 'apc') {
353 $element['APC_UPLOAD_PROGRESS'] = array(
354 '#type' => 'hidden',
355 '#value' => $upload_progress_key,
356 '#attributes' => array('class' => 'filefield-progress'),
357 );
358 }
359
360 // Add the upload progress callback.
361 $element['filefield_upload']['#ahah']['progress']['type'] = 'bar';
362 $element['filefield_upload']['#ahah']['progress']['path'] = 'filefield/progress/' . $upload_progress_key;
363 }
364
123172a6
NH
365 // Set the FID.
366 $element['fid'] = array(
367 '#type' => 'hidden',
368 '#value' => $item['fid'],
369 );
d2f124d5 370
6e7782b4 371 if ($item['fid'] != 0) {
e49d0f07
NH
372 $element['preview'] = array(
373 '#type' => 'markup',
374 '#value' => theme('filefield_widget_preview', $item),
375 );
d2f124d5 376 }
28b1c58e 377
0b168c78
NH
378 // Grant access to temporary files.
379 if ($item['fid'] && isset($item['status']) && $item['status'] == 0 && variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC) == FILE_DOWNLOADS_PRIVATE) {
380 $_SESSION['filefield_access'][] = $item['fid'];
381 }
382
28b1c58e
DP
383 // placeholder.. will be serialized into the data column. this is a place for widgets
384 // to put additional data.
a679aaae
NH
385 $element['data'] = array(
386 '#tree' => 'true',
387 '#access' => !empty($item['fid']),
388 );
2635f5af 389
4a03547e 390 if (!empty($field['description_field'])) {
2635f5af 391 $element['data']['description'] = array(
392 '#type' => 'textfield',
393 '#title' => t('Description'),
394 '#value' => isset($item['data']['description']) ? $item['data']['description'] : '',
994c57b0 395 '#type' => variable_get('filefield_description_type', 'textfield'),
f56c699b 396 '#maxlength' => variable_get('filefield_description_length', 128),
2635f5af 397 );
398 }
28b1c58e 399
4a03547e 400 if (!empty($field['list_field'])) {
28b1c58e 401 $element['list'] = array(
f24fc10c 402 '#type' => empty($item['fid']) ? 'hidden' : 'checkbox',
28b1c58e 403 '#title' => t('List'),
22920f33 404 '#value' => isset($item['list']) && !empty($item['fid']) ? $item['list'] : $field['list_default'],
28b1c58e
DP
405 '#attributes' => array('class' => 'filefield-list'),
406 );
407 }
35873ed9
NH
408 else {
409 $element['list'] = array(
410 '#type' => 'hidden',
411 '#value' => '1',
412 );
413 }
d2f124d5 414
8ffd8e3d
DP
415 foreach ($element['#upload_validators'] as $callback => $arguments) {
416 $help_func = $callback .'_help';
ad6bb31f
DP
417 if (function_exists($help_func)) {
418 $desc[] = call_user_func_array($help_func, $arguments);
419 }
8ffd8e3d
DP
420 }
421 $element['upload'] = array(
422 '#name' => 'files['. $element['#field_name'] .'_'. $element['#delta'] .']',
423 '#type' => 'file',
8ffd8e3d 424 '#description' => implode('<br />', $desc),
3897ed27 425 '#size' => 22,
8ffd8e3d 426 '#attributes' => array(
f976317f 427 'accept' => implode(',', array_filter(explode(' ', $field['widget']['file_extensions']))),
3897ed27
NH
428 ),
429 '#access' => empty($item['fid']),
8ffd8e3d
DP
430 );
431
f613b75e 432 $element['#attributes']['id'] = $element['#id'] .'-ahah-wrapper';
f613b75e 433 $element['#prefix'] = '<div '. drupal_attributes($element['#attributes']) .'>';
aa3a8ca0 434 $element['#suffix'] = '</div>';
d2f124d5 435
d2f124d5
DP
436 return $element;
437}
438
87d3e491
NH
439/**
440 * An #element_validate callback for the filefield_widget field.
441 */
123172a6
NH
442function filefield_widget_validate(&$element, &$form_state) {
443 // If referencing an existing file, only allow if there are existing
444 // references. This prevents unmanaged files (outside of FileField) from
445 // being deleted if this node were to be deleted.
446 if (!empty($element['fid']['#value'])) {
447 $field = content_fields($element['#field_name'], $element['#type_name']);
448 if ($file = field_file_load($element['fid']['#value'])) {
449 $file = (object) $file;
ab6a2015 450 if ($file->status == FILE_STATUS_PERMANENT) {
6a189547 451 if (field_file_references($file) == 0) {
72b7664c 452 form_error($element, t('Referencing to the file used in the %field field is not allowed.', array('%field' => $element['#title'])));
ab6a2015 453 }
123172a6
NH
454 }
455 }
456 else {
457 form_error($element, t('The file referenced by the %field field does not exist.', array('%field' => $element['#title'])));
458 }
459 }
d2f124d5
DP
460}
461
d2f124d5
DP
462/**
463 * FormAPI theme function. Theme the output of an image field.
464 */
bad2b17f 465function theme_filefield_widget($element) {
fe4cb62e 466 $element['#id'] .= '-upload'; // Link the label to the upload field.
c6e8be79 467 return theme('form_element', $element, $element['#children']);
d2f124d5
DP
468}
469
22e736e6 470function theme_filefield_widget_preview($item) {
96f6f7a9
NH
471 // Remove the current description so that we get the filename as the link.
472 if (isset($item['data']['description'])) {
473 unset($item['data']['description']);
474 }
475
839679c0
NH
476 return '<div class="filefield-file-info">'.
477 '<div class="filename">'. theme('filefield_file', $item) .'</div>'.
478 '<div class="filesize">'. format_size($item['filesize']) .'</div>'.
479 '<div class="filemime">'. $item['filemime'] .'</div>'.
480 '</div>';
22e736e6
DP
481}
482
483function theme_filefield_widget_item($element) {
3897ed27 484 // Put the upload button directly after the upload field.
ad98c19d 485 $element['upload']['#field_suffix'] = drupal_render($element['filefield_upload']);
3897ed27
NH
486 $element['upload']['#theme'] = 'filefield_widget_file';
487
488 $output = '';
489 $output .= '<div class="filefield-element clear-block">';
490
491 if ($element['fid']['#value'] != 0) {
839679c0 492 $output .= '<div class="widget-preview">';
3897ed27
NH
493 $output .= drupal_render($element['preview']);
494 $output .= '</div>';
495 }
496
839679c0 497 $output .= '<div class="widget-edit">';
3897ed27
NH
498 $output .= drupal_render($element);
499 $output .= '</div>';
500 $output .= '</div>';
501
502 return $output;
503}
504
505/**
ab322a18
NH
506 * Custom theme function for FileField upload elements.
507 *
508 * This function allows us to put the "Upload" button immediately after the
509 * file upload field by respecting the #field_suffix property.
3897ed27
NH
510 */
511function theme_filefield_widget_file($element) {
512 $output = '';
513
514 $output .= '<div class="filefield-upload clear-block">';
515
516 if (isset($element['#field_prefix'])) {
517 $output .= $element['#field_prefix'];
518 }
519
520 _form_set_class($element, array('form-file'));
521 $output .= '<input type="file" name="'. $element['#name'] .'"'. ($element['#attributes'] ? ' '. drupal_attributes($element['#attributes']) : '') .' id="'. $element['#id'] .'" size="'. $element['#size'] ."\" />\n";
522
523 if (isset($element['#field_suffix'])) {
524 $output .= $element['#field_suffix'];
525 }
526
527 $output .= '</div>';
528
529 return theme('form_element', $element, $output);
bad2b17f 530}
d2f124d5 531
2be7e4b0 532/**
87d3e491
NH
533 * Additional #validate handler for the node form.
534 *
535 * This function checks the #required properties on file fields and calculates
536 * node upload totals for all file fields. The #required property is not
537 * properly supported on file fields by Drupal core, so we do this manually.
2be7e4b0 538 */
2be7e4b0 539function filefield_node_form_validate($form, &$form_state) {
176b5844 540 foreach ($form['#field_info'] as $field_name => $field) {
b6644f47 541 if (!(in_array($field['module'], array('imagefield', 'filefield')))) continue;
2be7e4b0 542 $empty = $field['module'] .'_content_is_empty';
e76d77f0 543 $valid = FALSE;
f92ea317 544 $total_filesize = 0;
9b86f834 545 if (!empty($form_state['values'][$field_name])) {
e76d77f0 546 foreach ($form_state['values'][$field_name] as $delta => $item) {
9b86f834
NH
547 if ($empty($item, $field)) continue;
548 $valid = TRUE;
549 $total_filesize += (int)$item['filesize'];
550 }
2be7e4b0 551 }
9412a7cc 552
ef179f8a 553 if (!$valid && $field['required'] && filefield_edit_access($type_name, $field_name)) {
f92ea317
DP
554 form_set_error($field_name, t('%title field is required.', array('%title' => $field['widget']['label'])));
555 }
556 $max_filesize = parse_size($field['widget']['max_filesize_per_node']);
5af49125 557 if ($max_filesize && $total_filesize > $max_filesize) {
7982f68b 558 form_set_error($field_name, t('Total filesize for %title, %tsize, exceeds field settings of %msize.',
f92ea317 559 array(
7e784adc 560 '%title' => $field['widget']['label'],
561 '%tsize' => format_size($total_filesize),
f92ea317
DP
562 '%msize' => format_size($max_filesize)
563 )
564 ));
565 }
2be7e4b0
DP
566 }
567}