########################### upload_field.info ############################
; $Id$
name = FAPI Upload field
description = A FAPI element to handle file uploads.
package = Other
core = 6.x
########################### upload_field.module ############################
'. t('A module that provides a FAPI element to handle file uploads.') .'
';
return $output;
}
}
/**
* Implementation of hook_theme().
*/
function upload_field_theme() {
return array(
'upload_field' => array(
'arguments' => array('element' => NULL),
),
'image_upload_field' => array(
'arguments' => array('element' => NULL),
),
'upload_field_preview' => array(
'arguments' => array('file' => FALSE),
),
'upload_field_image_preview' => array(
'arguments' => array('file' => FALSE),
),
);
}
/**
* Implementation of hook_elements
*
* Defines an file form element that is linked into the native Drupal file handling system.
*/
function upload_field_elements() {
$type['upload_field'] = array(
'#input' => TRUE,
'#collapsible' => TRUE,
'#collapsed' => FALSE,
'#default_value' => '',
'#process' => array('_upload_field_expand'),
'#element_validate' => array('upload_field_element_validate'),
'#file_formatter' => 'upload_field_preview',
'#file_validators' => array(),
);
$type['image_upload_field'] = array(
'#input' => TRUE,
'#collapsible' => TRUE,
'#collapsed' => FALSE,
'#default_value' => '',
'#process' => array('_upload_field_expand'),
'#element_validate' => array('upload_field_element_validate'),
'#file_formatter' => 'upload_field_image_preview',
'#file_validators' => array('file_validate_is_image' => array()),
);
return $type;
}
/**
* Our process callback to expand the control.
*
* There are two main roles performed, to rename the field name
* into one that is usable by Drupal native file functionality,
* and to add the extra attributes for fields with is_image set
*/
function _upload_field_expand($element) {
$element['#original_name'] = $element['#name'];
$element['#name'] = 'files['. $element['#name'] .']';
return $element;
}
/**
* This handles the uploading and workflow
*
* @param unknown_type $form
* @param unknown_type $edit
* @return unknown
*/
function form_type_image_upload_field_value($form, $edit = FALSE) {
return form_type_upload_field_value($form, $edit);
}
/**
* This handles the uploading and workflow
*
* @param unknown_type $form
* @param unknown_type $edit
* @return unknown
*/
function form_type_upload_field_value($form, $edit = FALSE) {
if ($edit !== FALSE) {
$field_name = upload_field_name($form);
$key = $field_name .'_form_key';
if (!array_key_exists($key, $form['#post'])) {
form_set_error($field_name, t('Upload field form error, please try to load the form again. If this error persists, please contact the site administrator.'));
return $form['#default_value'];
}
// handle the extras first
$field_key = $form['#post'][$key];
$action = $form['#post'][$field_name][$field_name .'_action'];
if (is_object($form['#default_value'])) {
if ($action == 'delete') {
upload_field_session_handler('delete', $form, $field_key);
}
if ($action == 'restore') {
upload_field_session_handler('restore', $form, $field_key);
}
}
if ($action == 'revert') {
upload_field_session_handler('revert', $form, $field_key);
}
$file = file_save_upload($field_name, $form['#file_validators']);
return !empty($file) ?
upload_field_session_handler('store', $form, $field_key, $file) : upload_field_session_handler('value', $form, $field_key);
}
else {
return $form['#default_value'];
}
}
/**
* The custom validation required for files that are marked
* as deleted, but are required.
*
* @param array $element
* @param array $form_state
*/
function upload_field_element_validate($element, &$form_state) {
if ($element['#required'] && is_object($element['#value']) && property_exists($element['#value'], 'submit_action') && $element['#value']->submit_action == UPLOAD_FIELD_DELETE) {
form_error($element, t('!name field is required.', array('!name' => $element['#title'])));
}
}
function upload_field_equals($a = FALSE, $b = FALSE) {
if (is_object($a) && is_object($b)) {
return $a->fid == $b->fid;
}
return FALSE;
}
/**
* Theme function to format the output.
*
* We use the container-inline class so that all three of the HTML elements
* are placed next to each other, rather than on separate lines.
*/
function theme_image_upload_field($element) {
return theme_upload_field($element);
}
/**
* Theme function to format the output.
*
* We use the container-inline class so that all three of the HTML elements
* are placed next to each other, rather than on separate lines.
*/
function theme_upload_field($element) {
$key_field = _upload_field_form_key_field($element);
$action_field = _upload_field_action_field($element);
$fieldset_attributes = array('class' => '');
if ($element['#collapsible']) {
drupal_add_js('misc/collapse.js');
$fieldset_attributes['class'] .= ' collapsible';
if ($element['#collapsed']) {
$fieldset_attributes['class'] .= ' collapsed';
}
}
_form_set_class($element, array('form-file'));
$preview = '';
if ($element['#file_formatter']) {
$preview = theme($element['#file_formatter'], $element['#value']);
}
return '\n";
}
function _upload_field_form_key_field($element) {
$key = upload_field_name($element) .'_form_key';
$field[$key]= array(
'#type' => 'hidden',
'#name' => $key,
'#value' => _upload_field_key($key, $element['#post'], $element),
);
return $field;
}
function _upload_field_action_field($element) {
$field = array();
if (is_object($element['#value'])) {
$field_name = upload_field_name($element);
$key = $field_name .'_action';
$field[$key]= array(
'#type' => 'checkbox',
'#id' => form_clean_id("edit-{$key}"),
'#name' => "{$field_name}[{$key}]",
'#value' => 0,
'#weight' => -10,
);
if (upload_field_equals($element['#value'], $element['#default_value'])) {
if (property_exists($element['#value'], 'submit_action') && $element['#value']->submit_action == UPLOAD_FIELD_DELETE) {
$field[$key]['#return_value'] = 'restore';
$field[$key]['#title'] = t('Restore original');
}
else {
$field[$key]['#return_value'] = 'delete';
$field[$key]['#title'] = t('Delete original');
$field[$key]['#value'] = (property_exists($element['#value'], 'submit_action')
? ($element['#value']->submit_action == UPLOAD_FIELD_DELETE ? 'delete' : 0)
: 0);
}
}
else {
$field[$key]['#return_value'] = 'revert';
$field[$key]['#title'] = (is_object($element['#default_value']) ? t('Discard replacment') : t('Discard upload'));
}
}
return $field;
}
function theme_upload_field_preview($file = FALSE) {
if ($file) {
$class = 'upload-field-preview';
if ($file->filemime) {
list($base_mime, $extended_mime) = explode('/', $file->filemime);
$class = trim($class .' mime-'. $base_mime .' '. ($extended_mime ? ' mime-'. $base_mime .'-'. $extended_mime : ''));
}
$size = ($file->filesize > 1048576) ? sprintf("%01.2f", $file->filesize / 1048576) .'MB' : sprintf("%01.2f", $file->filesize / 1024) .'KB';
return '
'. check_plain($file->filename) .' ('. $size .')
';
}
else {
return '
---
';
}
}
function theme_upload_field_image_preview($file = FALSE) {
$src = $file ? 'upload_field/'. $file->fid : drupal_get_path('module', 'upload_field') .'/no_image.gif';
return ' ';
}
function upload_field_save(&$file, $dest = 0, $replace = FILE_EXISTS_RENAME, $presetname = FALSE) {
if (is_object($file)) {
$base = file_directory_path();
if (strstr($dest, $base) === FALSE) {
$dest = $base . '/' . ltrim($dest, '/');
}
file_check_directory($dest, 1);
if (!property_exists($file, 'submit_action')) {
$file->submit_action = UPLOAD_FIELD_NONE;
}
switch ($file->submit_action) {
case UPLOAD_FIELD_NONE:
return $file->fid;
case UPLOAD_FIELD_DELETE:
file_set_status($file, FILE_STATUS_TEMPORARY);
return 0;
case UPLOAD_FIELD_REPLACE:
$_file = clone $file;
$_file->fid = $file->original_fid;
file_set_status($_file, FILE_STATUS_TEMPORARY);
drupal_write_record('files', $_file);
// fall through
case UPLOAD_FIELD_NEW:
$uploaded = FALSE;
if($presetname) {
$destination = file_create_filename($file->filename, $dest);
if( upload_field_imagecache_action($presetname, $file->filepath, $destination)) {
$file->filepath = $destination;
$uploaded = TRUE;
}
}
if (!$uploaded) {
file_move($file, $dest .'/'. $file->filename, FILE_EXISTS_RENAME);
}
if($uploaded) {
$file->status = FILE_STATUS_PERMANENT;
drupal_write_record('files', $file, 'fid');
return $file->fid;
}
else {
drupal_set_message(t('Error occured while saving the image!'), 'error');
return 0;
}
}
}
return 0;
}
/**
* Hooks into imageache preset for save action
*/
function upload_field_imagecache_action($presetname, $path, $dst) {
if (!function_exists(imagecache_preset_by_name)) {
return FALSE;
}
if (!$preset = imagecache_preset_by_name($presetname)) {
return FALSE;
}
if (is_file($dst)) {
return TRUE;
}
$src = $path;
if (!is_file($src) && !is_file($src = file_create_path($src))) {
return FALSE;
};
if (!getimagesize($src)) {
return FALSE;
}
$lockfile = file_directory_temp() .'/'. $preset['presetname'] . basename($src);
if (file_exists($lockfile)) {
watchdog('imagecache', 'Imagecache already generating: %dst, Lock file: %tmp.', array('%dst' => $dst, '%tmp' => $lockfile), WATCHDOG_NOTICE);
return FALSE;
}
touch($lockfile);
register_shutdown_function('file_delete', realpath($lockfile));
if (file_exists($dst) || imagecache_build_derivative($preset['actions'], $src, $dst)) {
return TRUE;
}
// Generate an error if image could not generate.
watchdog('imagecache', 'Failed generating an image from %image using imagecache preset %preset.', array('%image' => $path, '%preset' => $preset['presetname']), WATCHDOG_ERROR);
return FALSE;
}
/**
* Implementation of hook_menu
*
* This is for node editing only
*/
function upload_field_menu() {
$items = array();
$items['upload_field/%'] = array(
'title' => 'Upload field preview',
'file' => 'image.preview.inc',
'type' => MENU_CALLBACK,
'access arguments' => array('access content'),
'page callback' => 'upload_field_image_preview',
'page arguments' => array(1),
);
return $items;
}
function upload_field_preview($fid) {
//$_SESSION['files']['upload_field'][FORM_FIELD_ID][FIELD_NAME]
//$_SESSION['files']['upload_field'][FORM_FIELD_ID][FIELD_NAME . '_default']
if (is_numeric($fid) && is_array($_SESSION['files']['upload_field'])) {
foreach ($_SESSION['files']['upload_field'] as $form_field_key => $field) {
if (is_array($field)) {
foreach ($field as $file) {
if (is_object($file) && $file->fid == $fid) {
if (property_exists($file, 'submit_action') && $file->submit_action == UPLOAD_FIELD_DELETE) {
return 'marked_delete';
}
return $file;
}
}
}
}
}
return 'no_image';
}
function upload_field_name($form) {
return (array_key_exists('#original_name', $form)) ? $form['#original_name'] : $form['#name'];
}
function upload_field_session_handler($op, &$form, $field_key = FALSE, $file = '') {
$field_name = upload_field_name($form);
switch ($op) {
case 'revert':
$_SESSION['files']['upload_field'][$field_key][$field_name] = $_SESSION['files']['upload_field'][$field_key][$field_name .'_default'];
break;
case 'value':
$file = (isset($_SESSION['files']['upload_field'][$field_key][$field_name])) ? $_SESSION['files']['upload_field'][$field_key][$field_name] : $_SESSION['files']['upload_field'][$field_key][$field_name .'_default'];
return is_object($file) ? $file : '';
break;
case 'restore':
case 'delete':
$submit_action = ($op == 'restore') ? UPLOAD_FIELD_NONE : UPLOAD_FIELD_DELETE;
$_SESSION['files']['upload_field'][$field_key][$field_name .'_default']->submit_action = $submit_action;
unset($_SESSION['files']['upload_field'][$field_key][$field_name]);
if (is_object($form['#default_value'])) {
$form['#default_value']->submit_action = $submit_action;
}
break;
case 'store':
if (is_object(($_SESSION['files']['upload_field'][$field_key][$field_name .'_default']))) {
$file->submit_action = UPLOAD_FIELD_REPLACE;
$file->original_fid = $_SESSION['files']['upload_field'][$field_key][$field_name .'_default']->fid;
}
else {
$file->submit_action = UPLOAD_FIELD_NEW;
}
$_SESSION['files']['upload_field'][$field_key][$field_name] = $file;
return $file;
break;
case 'store default':
$_SESSION['files']['upload_field'][$field_key][$field_name .'_default'] = $file;
$_SESSION['files']['upload_field'][$field_key]['timestamp'] = time();
return $file;
break;
}
}
/**
* Parses the post array for a valid field key to distingish
* between different forms that use the same upload_field.
*
* @param string $key Field name
*/
function _upload_field_key($key, $post = array(), $form = '') {
if (isset($post[$key])) {
return $post[$key];
}
else {
if (empty($_SESSION['files']['upload_field']['last_known_key'])) {
$_SESSION['files']['upload_field']['last_known_key'] = 1;
}
// set the session for formators that need this populated
// on the original form display
$key = $_SESSION['files']['upload_field']['last_known_key']++;
upload_field_session_handler('store default', $form, $key, $form['#value']);
return $key;
}
}
########################### image.preview.inc ############################
filepath;
$info = image_get_info($image);
if ($info) {
// create temp file, minimise conflicts by instant touch
$tmp_file = file_destination(file_directory_temp() .'/upload_field.'. $info['extension'], FILE_EXISTS_RENAME);
if (!image_scale($image, $tmp_file, 75, 75)) {
$tmp_file = $image;
}
$tmp_info = image_get_info($tmp_file);
if ($tmp_info) {
$headers = array(
'Content-type: '. $tmp_info['mime_type'],
'Content-Length: '. $tmp_info['file_size'],
'Cache-Control: max-age=0, no-cache',
'Expires: '. gmdate('D, d M Y H:i:s', time()) .' GMT',
'Last-Modified: '. time(),
);
ob_end_clean();
foreach ($headers as $header) {
$header = preg_replace('/\r?\n(?!\t| )/', '', $header);
drupal_set_header($header);
}
// Transfer file in 1024 byte chunks to save memory usage.
if ($fd = fopen($tmp_file, 'rb')) {
while (!feof($fd)) {
print fread($fd, 1024);
}
fclose($fd);
}
}
// We're using the original if it is too small - do not delete!
if ($image != $tmp_file) {
unlink($tmp_file);
}
}
if (!headers_sent()) {
drupal_not_found();
}
exit;
}