f73d0e9908b04a58f69230a9325124cc713d9f28
6 * Defines an image field type.
7 * uses content.module to store the fid, and the drupal files table to store the actual file data.
11 * - multiple image support for views integration. -- stange territory.
15 function filefield_init () {
16 //drupal_set_message('POST: <pre>'. print_r($_POST, true) .'</pre>');
20 * Implementation of hook_help().
22 function filefield_help($section) {
24 case
'admin/modules#description':
25 return t('<strong>CCK:</strong> Defines a file field type for content.module.');
29 function filefield_menu($maycache) {
32 // Add handlers for previewing new uploads.
33 if ($_SESSION['filefield']) {
34 foreach ($_SESSION['filefield'] as
$fieldname => $files) {
35 foreach($files as
$delta => $file) {
36 $filename = file_create_filename($file['filename'], file_create_path());
37 // strip file_directory_path() from private downloads path. @see file_create_url
38 if (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC
) == FILE_DOWNLOADS_PRIVATE
) {
39 if (strpos($filename, file_directory_path()) !== false
) {
40 $filename = trim(substr($filename, strlen(file_directory_path())), '\\/');
42 $filename = 'system/files/' .
$filename;
45 'path' => $filename, 'title' => t('file download'),
46 'callback' => '_filefield_preview',
48 'type' => MENU_CALLBACK
50 $file['preview'] = $filename;
51 $_SESSION['filefield'][$fieldname][$delta] = $file;
55 //drupal_set_message('SESSION @ hook_menu: <pre>'. print_r($_SESSION['filefield'], true) .'</pre>');
60 * transfer a file that is in a 'preview' state.
61 * @todo multiple support
63 function _filefield_preview() {
64 foreach ($_SESSION['filefield'] as
$fieldname => $files) {
65 foreach ($files as
$delta => $file) {
66 if ($file['preview'] == $_GET['q']) {
67 file_transfer($file['filepath'], array('Content-Type: '.
mime_header_encode($file['filemime']),
68 'Content-Length: '.
$file['filesize']));
76 * Implementation of hook_field_info().
78 function filefield_field_info() {
80 'file' => array('label' => 'file'),
85 * Implementation of hook_field_settings().
87 function filefield_field_settings($op, $field) {
98 case
'database columns':
100 'fid' => array('type' => 'int', 'not null' => TRUE
, 'default' => '0'),
101 'description' => array('type' => 'varchar', length
=> 255, 'not null' => TRUE
, 'default' => "''", 'sortable' => TRUE
),
102 'list' => array('type' => 'int', 'not null' => TRUE
, 'default' => '0'),
109 * insert a file into the database.
111 * node object file will be associated with.
113 * file to be inserted, passed by reference since fid should be attached.
116 function filefield_file_insert($node, &$file, $field) {
117 $fieldname = $field['field_name'];
118 if ($file = file_save_upload((object)$file, file_directory_path() .
'/'.
$file['filename'])) {
119 $file = (array)$file;
120 $file['fid'] = db_next_id('{files}_fid');
121 db_query('INSERT into {files} (fid, nid, filename, filepath, filemime, filesize)
122 VALUES (%d, %d, "%s","%s","%s",%d)',
123 $file['fid'], $node->nid
, $file['filename'], $file['filepath'], $file['filemime'], $file['filesize']);
127 // Include file name in upload error.
128 form_set_error(NULL
, t('file upload was unsuccessful.'));
135 * update the file record if necessary
140 function filefield_file_update($node, &$file, $field) {
141 $file = (array)$file;
142 //drupal_set_message(' filefield_file_update: <pre>'. print_r($file, true) .'</pre>');
143 if ($file['remove'] == TRUE
) {
144 _filefield_file_delete($file, $field['field_name']);
147 if ($file['fid'] == 'upload') {
148 return filefield_file_insert($node, $file, $field);
151 // if fid is not numeric here we should complain.
152 // else we update the file table.
158 * Implementation of hook_field().
160 function filefield_field($op, $node, $field, &$node_field, $a1, $a2) {
161 //drupal_set_message('pre hook_field: '.$op.'<pre>'.print_r($node_field, true).'</pre>');
162 $fieldname = $field['field_name'];
164 // called after content.module loads default data.
167 foreach ($node_field as
$delta => $file) {
168 //drupal_set_message('loading file form content.module: <pre>'. print_r($file, true) .'</pre>');
169 $dbfile = _filefield_file_load($file['fid']);
170 //drupal_set_message('loading file from db: <pre>'. print_r($dbfile, true) .'</pre>');
172 $values[$delta] = array_merge($file, $dbfile);
173 //$node_field[$delta] = $values[$delta];
176 //drupal_set_message('post: hook_field: '.$op.'<pre>'.print_r($node_field, true).'</pre>');
177 $output = array($fieldname => $values);
182 foreach ($node_field as
$delta => $item) {
183 //drupal_set_message('<pre>'. print_r($item, true) .'</pre>');
184 // do not show images flagged for deletion in preview.
185 if (!$item['remove'] && $item['list']) {
186 $node_field[$delta]['view'] = theme('filefield', $item);
187 $files[] = $node_field[$delta];
190 $view = theme('field', $node, $field, $files, $a1, $a2);
192 $output = '<div class="'.
$field['field_name'] .
'">'.
$view .
'</div>';
195 // called before content.module defaults.
197 foreach ($node_field as
$delta => $item) {
198 $node_field[$delta] = filefield_file_insert($node, $item, $field);
202 // called before content.module defaults.
204 foreach ($node_field as
$delta => $item) {
205 $node_field[$delta] = filefield_file_update($node, $item, $field);
210 foreach ($node_field as
$delta => $item) {
211 _filefield_file_delete($item, $field['field_name']);
215 //drupal_set_message('post hook_field: '.$op.'<pre>'.print_r($node_field, true).'</pre>');
220 * Implementation of hook_widget_info().
222 function filefield_widget_info() {
226 'field types' => array('file'),
232 * Implementation of hook_widget_settings().
234 function filefield_widget_settings($op, $widget) {
238 $form['file_extensions'] = array (
239 '#type' => 'textfield',
240 '#title' => t('Permitted upload file extensions.'),
241 '#default_value' => $widget['file_extensions'] ?
$widget['file_extensions'] : 'txt',
244 '#description' => t('Extensions a user can upload to this field. Seperate extensions with a space and do not include the leading dot.')
250 return array('file_extensions');
255 function filefield_clear_session() {
256 if (is_array($_SESSION['filefield']) && count($_SESSION['filefield'])) {
257 foreach (array_keys($_SESSION['filefield']) as
$fieldname) {
258 filefield_clear_field_session($fieldname);
260 unset($_SESSION['filefield']);
264 function filefield_clear_field_session($fieldname) {
265 if (count($_SESSION['filefield'][$fieldname])) {
266 foreach ($_SESSION['filefield'][$fieldname] as
$files) {
267 foreach ($files as
$delta => $file) {
268 if (is_file($file['filepath'])) {
269 file_delete($file['filepath']);
273 unset($_SESSION['filefield'][$fieldname]);
277 function _filefield_file_delete($file, $fieldname) {
278 //drupal_set_message(' _filefield_file_delete: <pre>'. print_r($file, true) .'</pre>');
279 if (is_numeric($file['fid'])) {
280 db_query('DELETE FROM {files} WHERE fid = %d', $file['fid']);
283 unset($_SESSION['filefield'][$fieldname][$file['sessionid']]);
285 return file_delete($file['filepath']);
289 * Implementation of hook_widget().
291 function filefield_widget($op, $node, $field, &$node_field) {
292 //drupal_set_message('pre filefield_widget: '. $op .'<pre>'. print_r($node_field, true) .'</pre>');
293 $fieldname = $field['field_name'];
295 case
'prepare form values':
296 // drupal_set_message('pre filefield_widget: '. $op .'<pre>'. print_r($node_field, true) .'</pre>');
297 //drupal_set_message('pre filefield_widget node: '. $op .'<pre>'. print_r($node, true) .'</pre>');
298 // clean up the session if we weren't posted.
299 if (!count($_POST)) {
300 filefield_clear_session();
304 if ($file = file_check_upload($fieldname .
'_upload')) {
305 //drupal_set_message('file found!!!');
306 $file = (array)$file;
307 $ext = array_pop(explode('.',$file['filename']));
308 $allowed_extensions = array_unique(explode(' ', trim($field['widget']['file_extensions'])));
309 if (in_array($ext, $allowed_extensions)) {
310 //do mime specific handling.
313 form_set_error($field['field_name'] .
'_upload',t('Files with the extension %ext are not allowed. Please upload a file with an extension from the following list: %allowed_extensions', array('%ext' => theme('placeholder',$ext), '%allowed_extensions' => theme('placeholder', $field['widget']['file_extensions']))));
316 $file['fid'] = 'upload';
317 if (!$field['multiple']) {
318 // Remove old temporary file from session.
319 filefield_clear_field_session($fieldname);
321 $file['sessionid'] = count($_SESSION['filefield'][$fieldname]);
322 $_SESSION['filefield'][$fieldname][$file['sessionid']] = $file;
323 // drupal_set_message('SESSION: <pre>'. print_r($_SESSION['filefield'], true) .'</pre>');
328 // Load files from preview state. before committing actions.
329 /* commented out until cck prepare form values / node_field situation is worked out
330 if (is_array($_SESSION['filefield'][$fieldname]) && count($_SESSION['filefield'][$fieldname])) {
331 foreach($_SESSION['filefield'][$fieldname] as $delta => $file) {
332 $node_field[] = $file;
339 if (is_array($_SESSION['filefield'][$fieldname]) && count($_SESSION['filefield'][$fieldname])) {
340 foreach($_SESSION['filefield'][$fieldname] as
$delta => $file) {
341 $node_field[] = $file;
345 $form = _filefield_widget_form($node, $field, $node_field);
349 if ($field['required']) {
350 if (!count($node_field)) {
351 form_set_error($fieldname, $field['widget']['label'] .
' is required.');
356 case
'process form values':
357 //drupal_set_message('<pre>'. print_r($node, true) .'</pre>');
358 foreach ($node_field as
$delta => $item) {
359 if ($item['fid'] == '0') {
360 $node_field[$delta] = NULL
;
366 //drupal_set_message('post filefield_widget: '. $op .'<pre>'. print_r($node_field, true) .'<pre>');
369 function _filefield_widget_form($node, $field, &$node_field) {
370 $fieldname = $field['field_name'];
371 theme_add_style(drupal_get_path('module', 'filefield') .
'/filefield.css');
374 $form[$fieldname] = array(
375 '#type' => 'fieldset',
376 '#title' => t($field['widget']['label']),
378 '#collapsible' => TRUE
,
379 '#collapsed' => FALSE
,
381 '#theme' => 'filefield_current',
384 $form[$fieldname][$fieldname .
'_upload'] = array(
386 '#description' => t('Attach a file. allowed extensions(%ext)', array('%ext' => theme('placeholder', $field['widget']['file_extensions']))),
391 $form[$fieldname]['Update'] = array(
393 '#value' => t('Update'),
394 '#name' => 'cck_filefield_'.
$fieldname.
'_op',
395 '#attributes' => array('id' => $fieldname.
'-attach-button'),
400 //drupal_set_message('form: <pre>'. print_r($form, TRUE) .'</pre>');
401 //drupal_set_message('filefield_widget_form: nodefield: <pre>'. print_r($node_field, true) .'</pre>');
402 if (is_array($node_field) && count($node_field)) {
403 foreach($node_field as
$delta => $file) {
405 $form[$fieldname][$delta]['icon'] = array(
407 '#value' => theme('filefield_icon', $file),
410 if (strpos($file['fid'], 'upload') === false
) {
411 $filepath = $file['filepath'];
414 $filepath = file_create_filename($file['filename'], file_create_path());
416 $description = file_create_url($filepath);
417 $description = "<small>".
check_plain($description) .
"</small>";
418 $form[$fieldname][$delta]['description'] = array('#type' => 'textfield', '#default_value' => (strlen($file['description'])) ?
$file['description'] : $file['filename'], '#maxlength' => 256, '#description' => $description );
419 $form[$fieldname][$delta]['size'] = array('#type' => 'markup', '#value' => format_size($file['filesize']));
420 $form[$fieldname][$delta]['remove'] = array('#type' => 'checkbox', '#default_value' => $file['remove']);
421 $form[$fieldname][$delta]['list'] = array('#type' => 'checkbox', '#default_value' => $file['list']);
423 $form[$fieldname][$delta]['filename'] = array('#type' => 'value', '#value' => $file['filename']);
424 $form[$fieldname][$delta]['filepath'] = array('#type' => 'value', '#value' => $file['filepath']);
425 $form[$fieldname][$delta]['filemime'] = array('#type' => 'value', '#value' => $file['filemime']);
426 $form[$fieldname][$delta]['filesize'] = array('#type' => 'value', '#value' => $file['filesize']);
427 $form[$fieldname][$delta]['fid'] = array('#type' => 'value', '#value' => $file['fid']);
429 // Special handling for single value fields
430 // mark original item for deletion.
431 if (!$field['multiple'] && $delta == 0 && (count($_SESSION['filefield'][$fieldname]) > 1)) {
432 $form[$fieldname][$delta]['remove']['#value'] = 1;
433 $form[$fieldname][$delta]['replace'] = array(
435 '#value' => t('If a new file is uploaded, the current file will be replaced upon submitting the node edit form.'),
442 //drupal_set_message('filefield_form('. $fieldname .'): <pre>'. print_r($form, TRUE) .'</pre>');
446 function theme_filefield_current(&$form) {
447 $header = array(t('Type'), t('Description'), t('Size'), t('List'), t('Delete'));
448 //drupal_set_message('form: <pre>'. print_r($form, TRUE) .'</pre>');
450 foreach (element_children($form) as
$key) {
451 //drupal_set_message($key);
452 //only display numerically keyed fields in form.
453 //numeric key == $delta
454 if (is_numeric($key)) {
456 $row[] = form_render($form[$key]['icon']);
457 $row[] = form_render($form[$key]['description']);
458 $row[] = form_render($form[$key]['size']);
459 $row[] = form_render($form[$key]['list']);
460 $row[] = form_render($form[$key]['remove']);
465 $output = theme('table', $header, $rows);
467 $output .
= form_render($form);
472 function filefield_field_view_item($field, $node_field_item) {
473 $file = _filefield_file_load($node_field_item['fid']);
474 return theme('filefield_view_file', $file, $node_field_item['description']);
478 function _filefield_file_load($fid = NULL
) {
479 // Exit if we were not passed an fid to load;
481 //drupal_set_message('_filefield_file_load did not recieve an fid');
484 // Test to catch fid, eventuall plan to have node_load syntax
485 // once file_attributes table is complete
486 if (is_numeric($fid)) {
487 $result = db_query('SELECT * FROM {files} WHERE fid = %d', $fid);
488 return db_fetch_array($result);
490 //drupal_set_message('expected file not found.');
494 function theme_filefield_icon($file) {
495 $ext = array_pop(explode('.',$file['filename']));
496 $known_extensions = array('0','ace','aif','ai','ani','asf','asp','avi','bak','bat','bin','bmp','bz2','bz','cab','cdr','cfg','com','conf','cpt','css','cur','dat','db','dcr','dic','diff','dir','dll','dmg','doc','dwg','edir','eml','eps','exe','fla','flv','fon','gif','gz','hqx','html','htm','ico','inc','ini','iso','jpeg','jpg','js','lnk','log','m3u','mdb','midi','mid','mov','mp3','mpeg','mpg','nfo','odb','odc','odf','odg','odm','odp','ods','odt','ogg','otg','oth','otp','ots','ott','patch','pdf','php3','php','phtml','pl','png','pps','ppt','psd','pwl','qt','ram','ra','rar','reg','rpm','rtf','sh','shtml','sit','sql','svg','swf','sxc','sxi','sxw','sys','tar','tgz','tiff','tif','tmp','tpl','ttf','txt','wav','wma','wmv','wp','xls','xml','zip');
497 if (!in_array($ext, $known_extensions)) {
500 $imagepath = drupal_get_path('module','filefield') .
'/ico/'.
$ext .
'.png';
504 return '<div class="filefield-icon-container"><div class="filefield-icon field-icon-'.
$ext .
'"><img src="'.
$imagepath .
'" /></div></div>';
505 //return '<div class="filefield-icon-container"><div class="filefield-icon field-icon-'. $ext .'"> </div></div>'."\n";
508 function theme_filefield_view_file($file) {
509 return theme('filefield', $file);
512 function theme_filefield($file) {
513 $file = (array)$file;
514 if (is_file($file['filepath'])) {
515 if ($file['fid'] == 'upload') {
516 $path = file_create_filename($file['filename'], file_create_path());
519 $path = $file['filepath'];
521 $url = file_create_url($path);
522 $name = $file['filename'];
523 $desc = $file['description'];
524 return '<a href="'.
check_url($url) .
'">'.
check_plain($name).
'</a>';