From 070e3c28618a607a60e46f8e46b1eab4d286f729 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Fri, 26 May 2006 01:47:05 +0000 Subject: [PATCH] added WebDAV access to filemanager, use the following URL: - konq: webdav://localhost/egroupware/filemanager/webdav.php/home - win: http://localhost/egroupware/filemanager/webdav.php/home You can now you drag and drop to updload files or complete folders and you can edit files directly in the filemanger --- phpgwapi/inc/class.vfs.inc.php | 3 +- phpgwapi/inc/class.vfs_sql.inc.php | 9 +- phpgwapi/inc/class.vfs_webdav_server.inc.php | 388 +++++++++++++++++++ phpgwapi/setup/setup.inc.php | 3 +- phpgwapi/setup/tables_current.inc.php | 6 +- phpgwapi/setup/tables_update.inc.php | 19 + 6 files changed, 419 insertions(+), 9 deletions(-) create mode 100644 phpgwapi/inc/class.vfs_webdav_server.inc.php diff --git a/phpgwapi/inc/class.vfs.inc.php b/phpgwapi/inc/class.vfs.inc.php index 0e2da552d1..482e06e540 100644 --- a/phpgwapi/inc/class.vfs.inc.php +++ b/phpgwapi/inc/class.vfs.inc.php @@ -800,7 +800,8 @@ $basedir = ereg_replace ($sep . $sep, $sep, $basedir); } - $basedir = ereg_replace ($sep . '$', '', $basedir); + // remove trailing slash + if ($basedir != '/' && substr($basedir,-1) == '/') $basedir = substr($basedir,0,-1); return $basedir; } diff --git a/phpgwapi/inc/class.vfs_sql.inc.php b/phpgwapi/inc/class.vfs_sql.inc.php index a50141f71a..4b82b1bbaa 100644 --- a/phpgwapi/inc/class.vfs_sql.inc.php +++ b/phpgwapi/inc/class.vfs_sql.inc.php @@ -54,7 +54,7 @@ $this->basedir = $GLOBALS['egw_info']['server']['files_dir']; $this->working_id = $GLOBALS['egw_info']['user']['account_id']; $this->working_lid = $GLOBALS['egw_info']['user']['account_lid']; - $this->now = date ('Y-m-d'); + $this->now = date ('Y-m-d H:i:s'); /* File/dir attributes, each corresponding to a database field. Useful for use in loops @@ -134,7 +134,8 @@ 'link_name' => $this->db->Record['vfs_link_name'], ); } - $this->grants = $GLOBALS['egw']->acl->get_grants('filemanager'); + // group grants in filemanage are used for group-directories, NOT as grants for each group-member!!! + $this->grants = $GLOBALS['egw']->acl->get_grants('filemanager',false); } /** @@ -2327,7 +2328,7 @@ } $this->db->select($this->vfs_table,array_keys($this->attributes),$where,__LINE__,__FILE__); - $record = $this->db->Row(true,$this->vfs_column_prefix); + if (!($record = $this->db->Row(true,$this->vfs_column_prefix))) return array(); /* We return an array of one array to maintain the standard */ $rarray = array (); @@ -2419,7 +2420,7 @@ for ($i = 0; ($record = $this->db->Row(true,$this->vfs_column_prefix)); $i++) { /* Further checking on the directory. This makes sure /home/user/test won't match /home/user/test22 */ - if (@!ereg ("^$dir(/|$)", $record['directory'])) + if (@!ereg ("^$dir(/|$)", $record['directory']) || $record['name'] === '') { continue; } diff --git a/phpgwapi/inc/class.vfs_webdav_server.inc.php b/phpgwapi/inc/class.vfs_webdav_server.inc.php new file mode 100644 index 0000000000..5862f015e1 --- /dev/null +++ b/phpgwapi/inc/class.vfs_webdav_server.inc.php @@ -0,0 +1,388 @@ + * +* ------------------------------------------------------------------------ * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU General Public License as published by the * +* Free Software Foundation; either version 2 of the License, or (at your * +* option) any later version. * +\**************************************************************************/ + +/* $Id: class.socontacts_sql.inc.php 21634 2006-05-24 02:28:57Z ralfbecker $ */ + +require_once('HTTP/WebDAV/Server.php'); + +/** + * FileManger - WebDAV access + * + * Using the PEAR HTTP/WebDAV/Server class (which need to be installed!) + * + * @package filemanger + * @author Ralf Becker + * @copyright (c) 2006 by Ralf Becker + * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License + */ + +class vfs_webdav_server extends HTTP_WebDAV_Server +{ + var $vfs; + + var $dav_powered_by = 'eGroupWare WebDAV server'; + + var $debug = true; + + function vfs_webdav_server() + { + if ($this->debug) foreach($_SERVER as $name => $val) error_log("vfs_webdav_server: \$_SERVER[$name]='$val'"); + + parent::HTTP_WebDAV_Server(); + + $this->vfs =& CreateObject('phpgwapi.vfs'); + } + + /** + * PROPFIND method handler + * + * @param array general parameter passing array + * @param array return array for file properties + * @return bool true on success + */ + function PROPFIND(&$options, &$files) + { + $vfs_data = array( + 'string' => $GLOBALS['egw']->translation->convert($options['path'],'utf-8'), + 'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root + // at first only list the given path itself + 'checksubdirs' => False, + 'nofiles' => True + ); + if (!($vfs_files = $this->vfs->ls($vfs_data))) + { + if ($this->debug) error_log("vfs_webdav_server::PROPFIND(path='$options[path]',depth=$options[depth]) return false"); + return false; // path not found + } +/* + if (!$this->vfs->acl_check($vfs_data+array('operation'=>EGW_ACL_READ))) + { + if ($this->debug) error_log("vfs_webdav_server::PROPFIND(path='$options[path]',depth=$options[depth]) return 403 forbidden"); + return '403 Forbidden'; + } +*/ + // if depth > 0 and path is a directory => show it's contents + if (!empty($options['depth']) && $vfs_files[0]['mime_type'] == 'Directory') + { + $vfs_data['checksubdirs'] = (int) $options['depth'] != 1; + $vfs_data['nofiles'] = false; + + if ($vfs_files[0]['directory'] == '/') // sub-dirs of the root? + { + $vfs_files = array(); // dont return the directory, it shows up double in konq + } + else // return the dir itself with a trailing slash, otherwise empty dirs are reported as non-existent + { + $vfs_files[0]['name'] .= '/'; + } + $vfs_files = array_merge($vfs_files,$this->vfs->ls($vfs_data)); + } + if ($this->debug) error_log("vfs_webdav_server::PROPFIND(path='$options[path]',depth=$options[depth]) ".count($vfs_files).' files'); + + $files['files'] = array(); + $egw_charset = $GLOBALS['egw']->translation->charset(); + foreach($vfs_files as $fileinfo) + { + error_log('dir="'.$fileinfo['directory'].'", name="'.$fileinfo['name'].'": '.$fileinfo['mime_type']); + foreach(array('modified','created') as $date) + { + // our vfs has no modified set, if never modified, use created + list($y,$m,$d,$h,$i,$s) = split("[- :]",$fileinfo[$date] ? $fileinfo[$date] : $fileinfo['created']); + $fileinfo[$date] = mktime((int)$h,(int)$i,(int)$s,(int)$m,(int)$d,(int)$y); + } + $info = array( + 'path' => $GLOBALS['egw']->translation->convert($fileinfo['directory'].'/'.$fileinfo['name'],$egw_charset,'utf-8'), + 'props' => array( + $this->mkprop('displayname',$GLOBALS['egw']->translation->convert($fileinfo['name'],$egw_charset,'utf-8')), + $this->mkprop('creationdate',$fileinfo['created']), + $this->mkprop('getlastmodified',$fileinfo['modified']), + ), + ); + if ($fileinfo['mime_type'] == 'Directory') + { + $info['props'][] = $this->mkprop('resourcetype', 'collection'); + $info['props'][] = $this->mkprop('getcontenttype', 'httpd/unix-directory'); + } + else + { + $info['props'][] = $this->mkprop('resourcetype', ''); + $info['props'][] = $this->mkprop('getcontenttype', $fileinfo['mime_type']); + $info['props'][] = $this->mkprop('getcontentlength', $fileinfo['size']); + } + $files['files'][] = $info; + } + // ok, all done + return true; + } + + /** + * GET method handler + * + * @param array parameter passing array + * @return bool true on success + */ + function GET(&$options) + { + if ($this->debug) error_log('vfs_webdav_server::GET('.print_r($options,true).')'); + + $vfs_data = array( + 'string' => $GLOBALS['egw']->translation->convert($options['path'],'utf-8'), + 'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root + 'checksubdirs' => False, + 'nofiles' => True + ); + // sanity check + if (!($vfs_file = $this->vfs->ls($vfs_data))) + { + return false; + } + $options['mimetype'] = $vfs_file[0]['mime_type']; + $options['size'] = $vfs_file[0]['size']; + + if (($options['data'] = $this->vfs->read($vfs_data)) === false) + { + return '403 Forbidden'; // not sure if this is the right code for access denied + } + return true; + } + + /** + * PUT method handler + * + * @param array parameter passing array + * @return bool true on success + */ + function PUT(&$options) + { + if ($this->debug) error_log('vfs_webdav_server::PUT('.print_r($options,true).')'); + + $vfs_data = array( + 'string' => dirname($GLOBALS['egw']->translation->convert($options['path'],'utf-8')), + 'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root + 'checksubdirs' => False, + 'nofiles' => True + ); + if (!($vfs_file = $this->vfs->ls($vfs_data)) || $vfs_file[0]['mime_type'] != 'Directory') + { + return '409 Conflict'; + } + $vfs_data = array( + 'string' => $GLOBALS['egw']->translation->convert($options['path'],'utf-8'), + 'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root + ); + $options['new'] = !$this->vfs->file_exists($vfs_data); + + $vfs_data['content'] = ''; + while(!feof($options['stream'])) + { + $vfs_data['content'] .= fread($options['stream'],8192); + } + return $this->vfs->write($vfs_data); + } + + /** + * MKCOL method handler + * + * @param array general parameter passing array + * @return bool true on success + */ + function MKCOL($options) + { + if ($this->debug) error_log('vfs_webdav_server::MKCOL('.print_r($options,true).')'); + + $vfs_data = array( + 'string' => dirname($GLOBALS['egw']->translation->convert($options['path'],'utf-8')), + 'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root + 'checksubdirs' => False, + 'nofiles' => True + ); + if (!($vfs_file = $this->vfs->ls($vfs_data))) + { + return '409 Conflict'; + } + if ($this->debug) error_log(print_r($vfs_file,true)); + + if ($vfs_file[0]['mime_type'] != 'Directory') + { + return '403 Forbidden'; + } + + $vfs_data = array( + 'string' => $GLOBALS['egw']->translation->convert($options['path'],'utf-8'), + 'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root + ); + if ($this->vfs->file_exists($vfs_data) ) + { + return '405 Method not allowed'; + } + + if (!empty($_SERVER['CONTENT_LENGTH'])) // no body parsing yet + { + return '415 Unsupported media type'; + } + + if (!$this->vfs->mkdir($vfs_data)) + { + return '403 Forbidden'; + } + + return '201 Created'; + } + + /** + * DELETE method handler + * + * @param array general parameter passing array + * @return bool true on success + */ + function DELETE($options) + { + if ($this->debug) error_log('vfs_webdav_server::DELETE('.print_r($options,true).')'); + + $vfs_data = array( + 'string' => dirname($GLOBALS['egw']->translation->convert($options['path'],'utf-8')), + 'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root + ); + if (!$this->vfs->file_exists($path)) + { + return '404 Not found'; + } + $vfs_data = array( + 'string' => $GLOBALS['egw']->translation->convert($options['path'],'utf-8'), + 'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root + ); + $this->vfs->rm($vfs_data); + + return '204 No Content'; + } + + /** + * MOVE method handler + * + * @param array general parameter passing array + * @return bool true on success + */ + function MOVE($options) + { + return $this->COPY($options, true); + } + + /** + * COPY method handler + * + * @param array general parameter passing array + * @return bool true on success + */ + function COPY($options, $del=false) + { + if ($this->debug) error_log('vfs_webdav_server::'.($del ? 'MOVE' : 'COPY').'('.print_r($options,true).')'); + + // TODO Property updates still broken (Litmus should detect this?) + + if (!empty($_SERVER['CONTENT_LENGTH'])) // no body parsing yet + { + return '415 Unsupported media type'; + } + + // no copying to different WebDAV Servers yet + if (isset($options['dest_url'])) + { + return '502 bad gateway'; + } + + $source = array( + 'string' => $GLOBALS['egw']->translation->convert($options['path'],'utf-8'), + 'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root + ); + if (!$this->vfs->file_exists($source)) + { + return '404 Not found'; + } + + $dest = array( + 'string' => $options['dest'], + 'relatives' => array(RELATIVE_ROOT), // filename is relative to the vfs-root + ); + $new = !$this->vfs->file_exists($dest); + $existing_col = false; + + if (!$new) + { + if ($del && $this->vfs->file_type($dest) == 'Directory') + { + if (!$options['overwrite']) + { + return '412 precondition failed'; + } + $dest['string'] .= basename($GLOBALS['egw']->translation->convert($options['path'],'utf-8')); + if ($this->vfs->file_exists($dest)) + { + $options['dest'] .= basename($GLOBALS['egw']->translation->convert($options['path'],'utf-8')); + } + else + { + $new = true; + $existing_col = true; + } + } + } + + if (!$new) + { + if ($options['overwrite']) + { + $stat = $this->DELETE(array('path' => $options['dest'])); + if (($stat{0} != '2') && (substr($stat, 0, 3) != '404')) + { + return $stat; + } + } + else + { + return '412 precondition failed'; + } + } + + if ($this->vfs->file_type($source) == 'Directory' && ($options['depth'] != 'infinity')) + { + // RFC 2518 Section 9.2, last paragraph + return '400 Bad request'; + } + + $op = $del ? 'mv' : 'cp'; + $vfs_data = array( + 'from' => $source['string'], + 'to' => $dest['string'], + 'relatives' => array(RELATIVE_ROOT,RELATIVE_ROOT) + ); + if (!$this->vfs->$op($vfs_data)) + { + return '500 Internal server error'; + } + return ($new && !$existing_col) ? '201 Created' : '204 No Content'; + } + + /** + * auth check in the session creation in dav.php, to avoid being redirected to login.php + * + * @param unknown_type $type + * @param unknown_type $user + * @param unknown_type $password + * @return boolean true if authorized or false otherwise + */ + function checkAuth($type,$user,$password) + { + if ($this->debug) error_log("vfs_webdav_server::checkAuth('$type','$user','$password')"); + + return $user == $GLOBALS['egw_info']['user']['account_lid'] && $GLOBALS['egw_info']['user']['apps']['filemanager']; + } +} \ No newline at end of file diff --git a/phpgwapi/setup/setup.inc.php b/phpgwapi/setup/setup.inc.php index 38a5b5f5a5..9b901af47e 100755 --- a/phpgwapi/setup/setup.inc.php +++ b/phpgwapi/setup/setup.inc.php @@ -14,7 +14,7 @@ /* Basic information about this app */ $setup_info['phpgwapi']['name'] = 'phpgwapi'; $setup_info['phpgwapi']['title'] = 'eGroupWare API'; - $setup_info['phpgwapi']['version'] = '1.3.004'; + $setup_info['phpgwapi']['version'] = '1.3.005'; $setup_info['phpgwapi']['versions']['current_header'] = '1.28'; $setup_info['phpgwapi']['enable'] = 3; $setup_info['phpgwapi']['app_order'] = 1; @@ -64,3 +64,4 @@ + diff --git a/phpgwapi/setup/tables_current.inc.php b/phpgwapi/setup/tables_current.inc.php index 5afbaebf12..d48109d3e4 100644 --- a/phpgwapi/setup/tables_current.inc.php +++ b/phpgwapi/setup/tables_current.inc.php @@ -247,8 +247,8 @@ 'vfs_owner_id' => array('type' => 'int','precision' => '4','nullable' => False), 'vfs_createdby_id' => array('type' => 'int','precision' => '4'), 'vfs_modifiedby_id' => array('type' => 'int','precision' => '4'), - 'vfs_created' => array('type' => 'date','nullable' => False,'default' => '1970-01-01'), - 'vfs_modified' => array('type' => 'date'), + 'vfs_created' => array('type' => 'timestamp','nullable' => False,'default' => 'current_timestamp'), + 'vfs_modified' => array('type' => 'timestamp'), 'vfs_size' => array('type' => 'int','precision' => '4'), 'vfs_mime_type' => array('type' => 'varchar','precision' => '64'), 'vfs_deleteable' => array('type' => 'char','precision' => '1','default' => 'Y'), @@ -259,7 +259,7 @@ 'vfs_link_directory' => array('type' => 'varchar','precision' => '255'), 'vfs_link_name' => array('type' => 'varchar','precision' => '128'), 'vfs_version' => array('type' => 'varchar','precision' => '30','nullable' => False,'default' => '0.0.0.0'), - 'vfs_content' => array('type' => 'text') + 'vfs_content' => array('type' => 'blob') ), 'pk' => array('vfs_file_id'), 'fk' => array(), diff --git a/phpgwapi/setup/tables_update.inc.php b/phpgwapi/setup/tables_update.inc.php index ba8fc322e9..2905c510fb 100644 --- a/phpgwapi/setup/tables_update.inc.php +++ b/phpgwapi/setup/tables_update.inc.php @@ -96,4 +96,23 @@ return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.3.004'; } + + + $test[] = '1.3.004'; + function phpgwapi_upgrade1_3_004() + { + $GLOBALS['egw_setup']->oProc->AlterColumn('egw_vfs','vfs_created',array( + 'type' => 'timestamp', + 'nullable' => False, + 'default' => 'current_timestamp' + )); + $GLOBALS['egw_setup']->oProc->AlterColumn('egw_vfs','vfs_modified',array( + 'type' => 'timestamp' + )); + $GLOBALS['egw_setup']->oProc->AlterColumn('egw_vfs','vfs_content',array( + 'type' => 'blob' + )); + + return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.3.005'; + } ?>