New vfs-upload widget to upload files into vfs:

- if file already exists, show download and delete link
- if file does NOT exist, show upload box
Name or value of widget is either:
- vfs path or
- $app:$id:$relative_name (if empty($id) a temporary directory in users
  home directory is created and application is responsible to move
  content of that directory to the entry directory (/apps/$app/$id)
This commit is contained in:
Ralf Becker 2009-07-11 09:07:59 +00:00
parent abbe9915fa
commit 49c5b2933c
3 changed files with 181 additions and 1 deletions

View File

@ -21,6 +21,10 @@
* - vfs-mime aka File icon: mime type icon or thumbnail (if configured AND enabled in the user-prefs)
* - vfs-uid aka File owner: Owner of file, or 'root' if none
* - vfs-gid aka File group: Group of file, or 'root' if none
* - vfs-upload aka VFS file: displays either download and delete (x) links or a file upload
* value is either a vfs path or colon separated $app:$id:$relative_path, eg: infolog:123:special/offer
* if empty($id) / new entry, file is created in a hidden temporary directory in users home directory
* and calling app is responsible to move content of that dir to entry directory, after entry is saved
*
* All widgets accept as value a full path.
* vfs-mime and vfs itself also allow an array with values like stat (incl. 'path'!) as value.
@ -36,6 +40,7 @@ class vfs_widget
*/
var $public_functions = array(
'pre_process' => True,
'post_process' => true, // post_process is only used for vfs-upload (all other widgets set $cell['readlonly']!)
);
/**
* availible extensions and there names for the editor
@ -49,6 +54,7 @@ class vfs_widget
'vfs-mime' => 'File icon', // mime type icon or thumbnail
'vfs-uid' => 'File owner', // Owner of file, or 'root' if none
'vfs-gid' => 'File group', // Group of file, or 'root' if none
'vfs-upload' => 'VFS file', // displays either download and delete (x) links or a file upload
);
/**
@ -67,7 +73,7 @@ class vfs_widget
function pre_process($form_name,&$value,&$cell,&$readonlys,&$extension_data,&$tmpl)
{
$type = $cell['type'];
$readonly = $cell['readonly'] || $readonlys;
if ($type != 'vfs-upload') $cell['readonly'] = true; // to not call post-process
// check if we have a path and not the raw value, in that case we have to do a stat first
if (in_array($type,array('vfs-size','vfs-mode','vfs-uid','vfs-gid')) && !is_numeric($value) || $type == 'vfs' && !$value)
@ -83,6 +89,83 @@ class vfs_widget
switch($type)
{
case 'vfs-upload': // option: allowed mime types (regular expression) if limited
if(empty($value)) $value = $cell['name']; // if no value via content array, use widget name
$extension_data = array('value' => $value, 'mimetype' => $cell['size'], 'type' => $type);
if ($value[0] != '/')
{
list($app,$id,$relpath) = explode(':',$value,3);
if (empty($id))
{
static $tmppath = array(); // static var, so all vfs-uploads get created in the same temporary dir
if (!isset($tmppath[$app])) $tmppath[$app] = '/home/'.$GLOBALS['egw_info']['user']['account_lid'].'/.'.$app.'_'.md5(time().session_id());
$value = $tmppath[$app];
}
else
{
$value = egw_link::vfs_path($app,$id,'',true);
}
if (!empty($relpath)) $value .= '/'.$relpath;
}
$path = $extension_data['path'] = $value;
$dir = egw_vfs::dirname($path);
static $files = array(); // static var, to scan each directory only once
if (!isset($files[$dir])) $files[$dir] = egw_vfs::file_exists($dir) ? egw_vfs::scandir($dir) : array();
$basename = egw_vfs::basename($path);
$basename_len = strlen($basename);
foreach($files[$dir] as $file)
{
if (substr($file,0,$basename_len) == $basename)
{
$file_exists = true;
break;
}
}
if ($file_exists) // display download link and delete icon
{
$path = $extension_data['path'] = $dir.'/'.$file;
$value = empty($cell['label']) ? $file : lang($cell['label']); // display (translated) Label or filename (if label empty)
$vfs_link = etemplate::empty_cell('label',$cell['name'],array(
'size' => ','.egw_vfs::download_url($path).',,,,,'.$path,
));
// if dir is writable, add delete link
if (egw_vfs::is_writable($dir))
{
$cell = etemplate::empty_cell('hbox','',array('size' => ',,0,0'));
etemplate::add_child($cell,$vfs_link);
$delete_icon = etemplate::empty_cell('button',$path,array(
'label' => 'delete',
'size' => 'delete', // icon
'onclick' => "return confirm('Delete this file');",
'span' => ',leftPad5',
));
etemplate::add_child($cell,$delete_icon);
}
else
{
$cell = $vfs_link;
}
}
else // file does NOT exists --> display file upload
{
$cell['type'] = 'file';
// if no explicit help message set and we only allow certain file types --> show them
if (empty($cell['help']) && $cell['size'])
{
if (($type = mime_magic::mime2ext($cell['size'])))
{
$type = '*.'.strtoupper($type);
}
else
{
$type = $cell['size'];
}
$cell['help'] = lang('Allowed file type: %1',$type);
}
}
break;
case 'vfs-size': // option: add size in bytes in brackets
$value = egw_vfs::hsize($size = is_numeric($value) ? $value : $stat['size']);
if ($cell['size']) $value .= ' ('.$size.')';
@ -258,4 +341,89 @@ class vfs_widget
return true;
}
/**
* postprocessing method, called after the submission of the form
*
* It has to copy the allowed/valid data from $value_in to $value, otherwise the widget
* will return no data (if it has a preprocessing method). The framework insures that
* the post-processing of all contained widget has been done before.
*
* Only used by vfs-upload so far
*
* @param string $name form-name of the widget
* @param mixed &$value the extension returns here it's input, if there's any
* @param mixed &$extension_data persistent storage between calls or pre- and post-process
* @param boolean &$loop can be set to true to request a re-submision of the form/dialog
* @param object &$tmpl the eTemplate the widget belongs too
* @param mixed &value_in the posted values (already striped of magic-quotes)
* @return boolean true if $value has valid content, on false no content will be returned!
*/
function post_process($name,&$value,&$extension_data,&$loop,&$tmpl,$value_in)
{
if (!$extension_data || $extension_data['type'] != 'vfs-upload')
{
return false;
}
//echo '<p>'.__METHOD__."('$name',".array2string($value).','.array2string($extension_data).",$loop,,".array2string($value_in)."</p>\n";
// check if delete icon clicked
if ($_POST['submit_button'] == str_replace($extension_data['value'],$extension_data['path'],$name))
{
if (!egw_vfs::remove($extension_data['path']))
{
etemplate::set_validation_error($name,lang('Error deleting %1!',$extension_data['path']));
}
$loop = true;
return false;
}
// handle file upload
$name = preg_replace('/^exec\[([^]]+)\](.*)$/','\\1\\2',$name); // remove exec prefix
$filename = etemplate::get_array($_FILES['exec']['name'],$name);
if (empty($filename))
{
return false; // no file attached
}
$tmp_name = etemplate::get_array($_FILES['exec']['tmp_name'],$name);
$error = etemplate::get_array($_FILES['exec']['error'],$name);
if ($error || empty($tmp_name) || function_exists('is_uploaded_file') && !is_uploaded_file($tmp_name) || !file_exists($tmp_name))
{
return false;
}
// check if type matches required mime-type, if specified
if (!empty($extension_data['mimetype']))
{
$type = etemplate::get_array($_FILES['exec']['type'],$name);
$is_preg = $extension_data['mimetype'][0] == '/' || $extension_data['mimetype'] != preg_quote($extension_data['mimetype']);
//echo "<p>preg_quote('{$extension_data['mimetype']}')='".preg_quote($extension_data['mimetype'])."' --> is_preg=".array2string($is_preg)."</p>\n";
if (!$is_preg && strcasecmp($extension_data['mimetype'],$type) ||
$is_preg && !preg_match($extension_data['mimetype'][0]=='/'?$extension_data['mimetype']:'/'.$extension_data['mimetype'].'/',$type))
{
etemplate::set_validation_error($name,lang('File is of wrong type (%1 != %2)!',$type,$extension_data['mimetype']));
return false;
}
}
$path = $extension_data['path'];
// add extension to path
$parts = explode('.',$filename);
if (($extension = array_pop($parts)) && mime_magic::ext2mime($extension)) // really an extension --> add it to path
{
$path .= '.'.$extension;
}
if (!egw_vfs::file_exists($dir = egw_vfs::dirname($path)) && !egw_vfs::mkdir($dir,null,STREAM_MKDIR_RECURSIVE))
{
etemplate::set_validation_error($name,lang('Error create parent directory %1!',$dir));
return false;
}
if (!copy($tmp_name,egw_vfs::PREFIX.$path))
{
etemplate::set_validation_error($name,lang('Error copying uploaded file to vfs!'));
return false;
}
$value = $path; // return path of file, important if only a temporary location is used
return true;
}
}

View File

@ -33,6 +33,7 @@ alignment of label and input-field in table-cell etemplate de Ausrichtung der Be
alignment of the v/hbox containing table-cell etemplate de Ausrichtung der die V/HBox enthaltenden Tabellenzelle
all days etemplate de alle Tage
all operations save the template! etemplate de alle Operation speichern das Template!
allowed file type: %1 etemplate de Erlaubter Dateityp: %1
am etemplate de Vormittag
an indexed column speeds up querys using that column (cost space on the disk !!!) etemplate de eine indizierte Spalte beschleunigt Anfragen die diese benutzen (kostet Plattenplatz !!!)
application etemplate de Anwendung
@ -146,6 +147,9 @@ enter filename to upload and attach, use [browse...] to search for it etemplate
enter the new version number here (> old_version), empty for no update-file etemplate de Neue Versionsnummer eingeben (größer als alte), leer wenn keine Update-Datei erzeugt werden soll
enter the new version number here (has to be > old_version) etemplate de Neue Versionsnummer eingeben (muss größer als die alte sein)
entry saved etemplate de Eintrag gespeichert
error copying uploaded file to vfs! etemplate de Fehler beim Kopieren der hochgeladenen Datei ins VFS!
error create parent directory %1! etemplate de Fehler beim Anlegen des Elternverzeichnisses %1!
error deleting %1! etemplate de Fehler beim Löschen von %1!
error: template not found !!! etemplate de Fehler: eTemplate nicht gefunden !!!
error: webserver is not allowed to write into '%1' !!! etemplate de Fehler: der Webserver hat keine Schreibberechtigung in '%1' !!!
error: while saving !!! etemplate de Fehler: beim Speichern !!!
@ -164,7 +168,9 @@ extensions loaded: etemplate de Erweiterungen geladen:
field etemplate de Feld
field must not be empty !!! etemplate de Das Feld darf nicht leer sein !!!
file etemplate de Datei
file '%1' not found! etemplate de Datei '%1' nicht gefunden!
file contains more than one etemplate, last one is shown !!! etemplate de Datei enthält mehr als ein eTemplate, das letzte wird angezeigt !!!
file is of wrong type (%1 != %2)! etemplate de Datei hat ungültigen Typ (%1 != %2)!
file writen etemplate de Datei geschrieben
fileupload etemplate de DateiUpload
first etemplate de Zuerst

View File

@ -33,6 +33,7 @@ alignment of label and input-field in table-cell etemplate en alignment of label
alignment of the v/hbox containing table-cell etemplate en Alignment of the V/HBox containing table-cell
all days etemplate en all days
all operations save the template! etemplate en all operations save the template!
allowed file type: %1 etemplate en Allowed file type: %1
am etemplate en am
an indexed column speeds up querys using that column (cost space on the disk !!!) etemplate en an indexed column speeds up querys using that column (cost space on the disk !!!)
application etemplate en Application
@ -146,6 +147,9 @@ enter filename to upload and attach, use [browse...] to search for it etemplate
enter the new version number here (> old_version), empty for no update-file etemplate en enter the new version number here (> old_version), empty for no update-file
enter the new version number here (has to be > old_version) etemplate en enter the new version number here (has to be > old_version)
entry saved etemplate en Entry saved
error copying uploaded file to vfs! etemplate en Error copying uploaded file to vfs!
error create parent directory %1! etemplate en Error create parent directory %1!
error deleting %1! etemplate en Error deleting %1!
error: template not found !!! etemplate en Error: Template not found !!!
error: webserver is not allowed to write into '%1' !!! etemplate en Error: webserver is not allowed to write into '%1' !!!
error: while saving !!! etemplate en Error: while saving !!!
@ -164,7 +168,9 @@ extensions loaded: etemplate en Extensions loaded:
field etemplate en Field
field must not be empty !!! etemplate en Field must not be empty !!!
file etemplate en File
file '%1' not found! etemplate en File '%1' not found!
file contains more than one etemplate, last one is shown !!! etemplate en File contains more than one eTemplate, last one is shown !!!
file is of wrong type (%1 != %2)! etemplate en File is of wrong type (%1 != %2)!
file writen etemplate en File writen
fileupload etemplate en FileUpload
first etemplate en First