'filefield/js', 'callback' => 'filefield_js', //'access' => user_access(), 'access' => TRUE, 'type' => MENU_CALLBACK ); } else if ($_SESSION['filefield']) { // Add handlers for previewing new uploads. foreach ($_SESSION['filefield'] as $fieldname => $files) { if (is_array($files)) { foreach($files as $delta => $file) { if ($file['preview']) { $items[] = array( 'path' => $file['preview'], 'callback' => '_filefield_preview', 'access' => TRUE, 'type' => MENU_CALLBACK ); } } } } } return $items; } /** * transfer a file that is in a 'preview' state. * @todo multiple support */ function _filefield_preview() { foreach ($_SESSION['filefield'] as $fieldname => $files) { foreach ($files as $delta => $file) { if ($file['preview'] == $_GET['q']) { file_transfer($file['filepath'], array('Content-Type: '. mime_header_encode($file['filemime']), 'Content-Length: '. $file['filesize'])); exit(); } } } } function filefield_perm() { return array('view filefield uploads'); } /** * Implementation of hook_field_info(). */ function filefield_field_info() { return array( 'file' => array('label' => 'File'), ); } /** * Implementation of hook_field_settings(). */ function filefield_field_settings($op, $field) { switch ($op) { case 'form': $form = array(); return $form; case 'validate': break; case 'save': return array(); case 'database columns': $columns = array( 'fid' => array('type' => 'int', 'not null' => TRUE, 'default' => '0'), 'description' => array('type' => 'varchar', length => 255, 'not null' => TRUE, 'default' => "''", 'sortable' => TRUE), 'list' => array('type' => 'int', 'not null' => TRUE, 'default' => '0'), ); return $columns; } } function filefield_default_item() { return array( 'fid' => 0, 'description' => '', 'list' => 0, ); } /** * insert a file into the database. * @param $node * node object file will be associated with. * @param $file * file to be inserted, passed by reference since fid should be attached. * */ function filefield_file_insert($node, $field, &$file) { $fieldname = $field['field_name']; // allow tokenized paths. if (function_exists('token_replace')) { global $user; $widget_file_path = token_replace($field['widget']['file_path'], 'user', $user); } else { $widget_file_path = $field['widget']['file_path']; } $filepath = file_create_path($widget_file_path) . '/' . $file['filename']; if (filefield_check_directory($widget_file_path) && $file = file_save_upload((object)$file, $filepath)) { $file = (array)$file; $file['fid'] = db_next_id('{files}_fid'); db_query('INSERT into {files} (fid, nid, filename, filepath, filemime, filesize) VALUES (%d, %d, "%s","%s","%s",%d)', $file['fid'], $node->nid, $file['filename'], $file['filepath'], $file['filemime'], $file['filesize']); module_invoke_all('filefield', 'file_save', $node, $field, $file); return (array)$file; } else { // Include file name in upload error. form_set_error(NULL, t('File upload was unsuccessful.')); return FALSE; } } /** * update the file record if necessary * @param $node * @param $file * @param $field */ function filefield_file_update($node, $field, &$file) { $file = (array)$file; if ($file['delete'] == TRUE) { module_invoke_all('filefield', 'file_delete', $node, $field, $file); _filefield_file_delete($node, $field, $file); return array(); } if ($file['fid'] == 'upload') { return filefield_file_insert($node, $field, $file); } else { // if fid is not numeric here we should complain. // else we update the file table. } return $file; } /** * Implementation of hook_field(). */ function filefield_field($op, $node, $field, &$node_field, $teaser, $page) { $fieldname = $field['field_name']; switch ($op) { // called after content.module loads default data. case 'load': if (count($node_field)) { foreach ($node_field as $delta => $file) { if (!empty($file)) { $file = _filefield_file_load($file['fid']); // In certain cases, content.module calls this function with // $node_field[$delta] set, even if the field has not yet been // stored at all or has already been deleted. In that case, // $file['fid'] == 0 and file_load() returns an empty array. // When that happens, unset() the delta so that subsequent hooks // are not bothered. if (empty($file)) { unset($node_field[$delta]); } else { // otherwise, merge our info with CCK's, and all is fine. $node_field[$delta] = array_merge((array)$node_field[$delta], $file); } } } $node_field = array_values($node_field); // compact deltas return array($fieldname => $node_field); } return array(); // called before content.module defaults. case 'insert': foreach ($node_field as $delta => $item) { $node_field[$delta] = filefield_file_insert($node, $field, $item); // Remove non-existant files from node_field if (empty($node_field[$delta])) { unset($node_field[$delta]); } } $node_field = array_values($node_field); // compact deltas filefield_clear_field_session($fieldname); break; // called before content.module defaults. case 'update': foreach ($node_field as $delta => $item) { $node_field[$delta] = filefield_file_update($node, $field, $item); // If the file has been deleted, unset the file entry so that it's // actually deleted from the database, or at least set it to a // default item if CCK won't delete it. if (empty($node_field[$delta])) { if ($field['multiple']) { unset($node_field[$delta]); } else { $node_field[$delta] = filefield_default_item(); } } } $node_field = array_values($node_field); // compact deltas filefield_clear_field_session($fieldname); break; case 'delete': foreach ($node_field as $delta => $item) { _filefield_file_delete($node, $field, $item); } break; } } /** * Implementation of hook_widget_info(). */ function filefield_widget_info() { return array( 'file' => array( 'label' => 'File', 'field types' => array('file'), ), ); } /** * Implementation of hook_widget_settings(). */ function filefield_widget_settings($op, $widget) { switch ($op) { case 'callbacks': return array('default value' => CONTENT_CALLBACK_CUSTOM); case 'form': $form = array(); $form['file_extensions'] = array ( '#type' => 'textfield', '#title' => t('Permitted upload file extensions'), '#default_value' => $widget['file_extensions'] ? $widget['file_extensions'] : 'txt', '#size' => 64, '#description' => t('Extensions a user can upload to this field. Separate extensions with a space and do not include the leading dot.'), ); $form['file_path'] = array( '#type' => 'textfield', '#title' => t('File path'), '#default_value' => $widget['file_path'] ? $widget['file_path'] : '', '#description' => t('Optional subdirectory within the "%dir" directory where files will be stored. Do not include trailing slash.', array('%dir' => variable_get('file_directory_path', 'files'))), '#after_build' => array('filefield_form_check_directory'), ); if (function_exists('token_replace')) { $form['file_path']['#description'] .= theme('token_help', 'user'); } $form['show_list'] = array( '#type' => 'checkbox', '#title' => t('Show "List" option'), '#default_value' => isset($widget['show_list']) ? $widget['show_list'] : 1, '#description' => t('If enabled, the user can choose for each file whether it should be listed or not. If disabled, the "List" checkbox will be hidden and files are always listed.'), ); return $form; case 'validate': break; case 'save': return array('file_extensions', 'file_path', 'show_list'); } } function filefield_clear_session() { if (is_array($_SESSION['filefield']) && count($_SESSION['filefield'])) { foreach (array_keys($_SESSION['filefield']) as $fieldname) { filefield_clear_field_session($fieldname); } unset($_SESSION['filefield']); } } function filefield_clear_field_session($fieldname) { if (is_array($_SESSION['filefield'][$fieldname]) && count($_SESSION['filefield'][$fieldname])) { foreach ($_SESSION['filefield'][$fieldname] as $delta => $file) { if (is_file($file['filepath'])) { file_delete($file['filepath']); } } unset($_SESSION['filefield'][$fieldname]); } } function _filefield_file_delete($node, $field, $file) { if (is_numeric($file['fid'])) { db_query('DELETE FROM {files} WHERE fid = %d', $file['fid']); } else { unset($_SESSION['filefield'][$field['field_name']][$file['sessionid']]); } module_invoke_all('filefield', 'delete', $node, $field, $file); return file_delete($file['filepath']); } /** * Implementation of hook_widget(). */ function filefield_widget($op, $node, $field, &$node_field) { $fieldname = $field['field_name']; switch ($op) { case 'default value': return array(); case 'prepare form values': _filefield_widget_prepare_form_values($node, $field, $node_field); break; case 'form': return _filefield_widget_form($node, $field, $node_field); case 'validate': _filefield_widget_validate($node, $field, $node_field); break; } } function _filefield_widget_prepare_form_values($node, $field, &$node_field) { $fieldname = $field['field_name']; // @todo split this into its own function. determine if we can make it a form element. if (!count($_POST)) { filefield_clear_session(); } // Attach new files if ($file = file_check_upload($fieldname . '_upload')) { $file = (array)$file; // test allowed extensions. We do this when the file is uploaded, rather than waiting for the // field itseld to reach op==validate. $last_ext = array_pop(explode('.', $file['filename'])); $allowed_extensions = array_unique(explode(' ', trim($field['widget']['file_extensions']))); $valid = FALSE; foreach ($allowed_extensions as $allowed_ext) { $allowed_ext = '.'. $allowed_ext; $file_ext = substr($file['filename'], strlen($file['filename']) - strlen($allowed_ext)); if (strtolower($file_ext) == strtolower($allowed_ext)) { $valid = TRUE; break; } } if (!$valid) { // set base validation error message. 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' => $last_ext, '%allowed_extensions' => $field['widget']['file_extensions']))); } // let extended validation from other module happen so we get all error messages. // if you implement hook_filefield_file() return FALSE to stop the upload. if (in_array(FALSE, module_invoke_all('filefield', 'file_validate', $node, $field, $file))) { $valid = FALSE; } if (!$valid) { return FALSE; } // let modules massage act on the file. module_invoke_all('filefield', 'file_prepare', $node, $field, $file); $filepath = file_create_filename($file['filename'], file_create_path($field['widget']['file_path'])); if (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC) == FILE_DOWNLOADS_PRIVATE) { if (strpos($filepath, file_directory_path()) !== FALSE) { $filepath = trim(substr($filepath, strlen(file_directory_path())), '\\/'); } $filepath = 'system/files/'. $filepath; }; // prepare file array. $file['fid'] = 'upload'; $file['preview'] = $filepath; // if this is a single value filefield mark any other files for deletion. if (!$field['multiple']) { if (is_array($node_field)) { foreach($node_field as $delta => $session_file) { $node_field[$delta]['delete'] = TRUE; } } // Remove old temporary file from session. filefield_clear_field_session($fieldname); } $file_id = count($node_field) + count($_SESSION['filefield'][$fieldname]); $_SESSION['filefield'][$fieldname][$file_id] = $file; } // Load files from preview state. before committing actions. if (is_array($_SESSION['filefield'][$fieldname]) && count($_SESSION['filefield'][$fieldname])) { foreach($_SESSION['filefield'][$fieldname] as $delta => $file) { $node_field[] = $file; } } } function _filefield_widget_form($node, $field, &$node_field) { drupal_add_js('misc/progress.js'); drupal_add_js('misc/upload.js'); $fieldname = $field['field_name']; drupal_add_css(drupal_get_path('module', 'filefield') .'/filefield.css'); $form = array(); $form[$fieldname] = array( '#type' => 'fieldset', '#title' => t($field['widget']['label']), '#description' => t('Changes made to the attachments are not permanent until you save this post.'), '#weight' => $field['widget']['weight'], '#collapsible' => TRUE, '#collapsed' => FALSE, '#tree' => TRUE, '#prefix' => '
'. t('If a new file is uploaded, this file will be replaced upon submitting this form.') .'
', '#prefix' => '