* WebDAV/Filemanager: fixed not working home-directores

This commit is contained in:
Ralf Becker 2012-04-10 07:39:10 +00:00
parent a7b41998cf
commit 8bca2eb07f
4 changed files with 589 additions and 129 deletions

View File

@ -7,7 +7,7 @@
* @package api
* @subpackage vfs
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2008-9 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2008-10 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @version $Id$
*/
@ -34,11 +34,11 @@
*
* The two following methods can be used to persitently mount further filesystems (without editing the code):
*
* - boolean/array egw_vfs::mount($url,$path) to mount $ur on $path or to return the fstab when called without argument
* - boolean|array egw_vfs::mount($url,$path) to mount $ur on $path or to return the fstab when called without argument
* - boolean egw_vfs::umount($path) to unmount a path or url
*
* The stream wrapper interface allows to access hugh files in junks to not be limited by the
* memory_limit setting of php. To do you should path a resource to the opened file and not the content:
* memory_limit setting of php. To do you should pass the opened file as resource and not the content:
*
* $file = egw_vfs::fopen('/home/user/somefile','r');
* $content = fread($file,1024);
@ -180,20 +180,42 @@ class egw_vfs extends vfs_stream_wrapper
{
$ret = false;
if (($from_fp = self::fopen($from,'r')) &&
($to_fp = self::fopen($to,'w')))
$old_props = self::file_exists($to) ? self::propfind($to,null) : array();
// copy properties (eg. file comment), if there are any and evtl. existing old properties
$props = self::propfind($from,null);
foreach($old_props as $prop)
{
$ret = stream_copy_to_stream($from_fp,$to_fp) !== false;
if (!self::find_prop($props,$prop))
{
$prop['val'] = null; // null = delete prop
$props[] = $prop;
}
}
if ($from_fp)
{
fclose($from_fp);
}
if ($to_fp)
{
fclose($to_fp);
}
return $ret;
// using self::copy_uploaded() to treat copying incl. properties as atomar operation in respect of notifications
return self::copy_uploaded(self::PREFIX.$from,$to,$props,false); // false = no is_uploaded_file check!
}
/**
* Find a specific property in an array of properties (eg. returned by propfind)
*
* @param array &$props
* @param array|string $name property array or name
* @param string $ns=self::DEFAULT_PROP_NAMESPACE namespace, only if $prop is no array
* @return &array reference to property in $props or null if not found
*/
static function &find_prop(array &$props,$name,$ns=self::DEFAULT_PROP_NAMESPACE)
{
if (is_array($name))
{
$ns = $name['ns'];
$name = $name['name'];
}
foreach($props as &$prop)
{
if ($prop['name'] == $name && $prop['ns'] == $ns) return $prop;
}
return null;
}
/**
@ -276,10 +298,14 @@ class egw_vfs extends vfs_stream_wrapper
*
* @param string $url=null url of the filesystem to mount, eg. oldvfs://default/
* @param string $path=null path to mount the filesystem in the vfs, eg. /
* @return array/boolean array with fstab, if called without parameter or true on successful mount
* @param boolean $check_url=null check if url is an existing directory, before mounting it
* default null only checks if url does not contain a $ as used in $user or $pass
* @return array|boolean array with fstab, if called without parameter or true on successful mount
*/
static function mount($url=null,$path=null)
static function mount($url=null,$path=null,$check_url=null)
{
if (is_null($check_url)) $check_url = strpos($url,'$') === false;
if (!isset($GLOBALS['egw_info']['server']['vfs_fstab'])) // happens eg. in setup
{
$api_config = config::read('phpgwapi');
@ -306,7 +332,7 @@ class egw_vfs extends vfs_stream_wrapper
}
self::load_wrapper(parse_url($url,PHP_URL_SCHEME));
if (!file_exists($url) || opendir($url) === false)
if ($check_url && (!file_exists($url) || opendir($url) === false))
{
if (self::LOG_LEVEL > 0) error_log(__METHOD__.'('.array2string($url).','.array2string($path).') url does NOT exist!');
return false; // url does not exist
@ -317,7 +343,11 @@ class egw_vfs extends vfs_stream_wrapper
config::save_value('vfs_fstab',self::$fstab,'phpgwapi');
$GLOBALS['egw_info']['server']['vfs_fstab'] = self::$fstab;
// invalidate session cache
if (method_exists($GLOBALS['egw'],'invalidate_session_cache')) // egw object in setup is limited
{
$GLOBALS['egw']->invalidate_session_cache();
}
if (self::LOG_LEVEL > 1) error_log(__METHOD__.'('.array2string($url).','.array2string($path).') returns true (successful new mount).');
return true;
}
@ -343,15 +373,32 @@ class egw_vfs extends vfs_stream_wrapper
config::save_value('vfs_fstab',self::$fstab,'phpgwapi');
$GLOBALS['egw_info']['server']['vfs_fstab'] = self::$fstab;
// invalidate session cache
if (method_exists($GLOBALS['egw'],'invalidate_session_cache')) // egw object in setup is limited
{
$GLOBALS['egw']->invalidate_session_cache();
}
if (self::LOG_LEVEL > 1) error_log(__METHOD__.'('.array2string($url).','.array2string($path).') returns true (successful unmount).');
return true;
}
/**
* Check if file is hidden: name starts with a '.' or is Thumbs.db
*
* @param string $path
* @return boolean
*/
public static function is_hidden($path)
{
$file = self::basename($path);
return $file[0] == '.' || $file == 'Thumbs.db';
}
/**
* find = recursive search over the filesystem
*
* @param string/array $base base of the search
* @param string|array $base base of the search
* @param array $options=null the following keys are allowed:
* - type => {d|f|F} d=dirs, f=files (incl. symlinks), F=files (incl. symlinks to files), default all
* - depth => {true|false(default)} put the contents of a dir before the dir itself
@ -371,7 +418,7 @@ class egw_vfs extends vfs_stream_wrapper
* - limit => N,[n=0] return N entries from position n on, which defaults to 0
* - follow => {true|false(default)} follow symlinks
* - hidden => {true|false(default)} include hidden files (name starts with a '.' or is Thumbs.db)
* @param string/array/true $exec=null function to call with each found file/dir as first param and stat array as last param or
* @param string|array/true $exec=null function to call with each found file/dir as first param and stat array as last param or
* true to return file => stat pairs
* @param array $exec_params=null further params for exec as array, path is always the first param and stat the last!
* @return array of pathes if no $exec, otherwise path => stat pairs
@ -447,7 +494,7 @@ class egw_vfs extends vfs_stream_wrapper
{
if ($file == '.' || $file == '..') continue; // ignore current and parent dir!
if (($file[0] == '.' || $file == 'Thumbs.db') && !$options['hidden']) continue; // ignore hidden files
if (self::is_hidden($file) && !$options['hidden']) continue; // ignore hidden files
$file = self::concat($path,$file);
@ -571,7 +618,7 @@ class egw_vfs extends vfs_stream_wrapper
if ($options['url'])
{
$stat = lstat($path);
$stat = @lstat($path);
}
else
{
@ -653,7 +700,7 @@ class egw_vfs extends vfs_stream_wrapper
/**
* Recursiv remove all given url's, including it's content if they are files
*
* @param string/array $urls url or array of url's
* @param string|array $urls url or array of url's
* @param boolean $allow_urls=false allow to use url's, default no only pathes (to stay within the vfs)
* @return array
*/
@ -685,9 +732,9 @@ class egw_vfs extends vfs_stream_wrapper
}
if (is_dir($url) && !is_link($url))
{
return rmdir($url);
return egw_vfs::rmdir($url,0);
}
return unlink($url);
return egw_vfs::unlink($url);
}
/**
@ -695,10 +742,11 @@ class egw_vfs extends vfs_stream_wrapper
* which is wrong in case of our vfs, as we use the current users id and memberships
*
* @param string $path
* @param int $check=4 mode to check: 4 = read, 2 = write, 1 = executable
* @param int $check mode to check: one or more or'ed together of: 4 = egw_vfs::READABLE,
* 2 = egw_vfs::WRITABLE, 1 = egw_vfs::EXECUTABLE
* @return boolean
*/
static function is_readable($path,$check = 4)
static function is_readable($path,$check = self::READABLE)
{
return self::check_access($path,$check);
}
@ -707,13 +755,52 @@ class egw_vfs extends vfs_stream_wrapper
* The stream_wrapper interface checks is_{readable|writable|executable} against the webservers uid,
* which is wrong in case of our vfs, as we use the current users id and memberships
*
* @param array/string $path stat array or path
* @param int $check mode to check: one or more or'ed together of: 4 = read, 2 = write, 1 = executable
* @param array $stat=null stat array, to not query it again
* @param string $path path
* @param int $check mode to check: one or more or'ed together of: 4 = egw_vfs::READABLE,
* 2 = egw_vfs::WRITABLE, 1 = egw_vfs::EXECUTABLE
* @param array|boolean $stat=null stat array or false, to not query it again
* @param int $user=null user used for check, if not current user (egw_vfs::$user)
* @return boolean
*/
static function check_access($path,$check,$stat=null)
static function check_access($path, $check, $stat=null, $user=null)
{
if (is_null($stat) && $user && $user != self::$user)
{
static $path_user_stat = array();
$backup_user = self::$user;
self::$user = $user;
if (!isset($path_user_stat[$path]) || !isset($path_user_stat[$path][$user]))
{
self::clearstatcache($path);
$path_user_stat[$path][$user] = self::url_stat($path, 0);
self::clearstatcache($path); // we need to clear the stat-cache after the call too, as the next call might be the regular user again!
}
if (($stat = $path_user_stat[$path][$user]))
{
// some backend mounts use $user:$pass in their url, for them we have to deny access!
if (strpos(self::resolve_url($path, false, false, false), '$user') !== false)
{
$ret = false;
}
else
{
$ret = self::check_access($path, $check, $stat);
}
}
else
{
$ret = false; // no access, if we can not stat the file
}
self::$user = $backup_user;
//error_log(__METHOD__."(path=$path||stat[name]={$stat['name']},stat[mode]=".sprintf('%o',$stat['mode']).",$check,$user) ".array2string($ret));
return $ret;
}
if (self::$is_root)
{
return true;
@ -722,7 +809,7 @@ class egw_vfs extends vfs_stream_wrapper
// throw exception if stat array is used insead of path, can be removed soon
if (is_array($path))
{
throw new egw_exception_wrong_parameter('path has to be string, use check_acces($path,$check,$stat=null)!');
throw new egw_exception_wrong_parameter('path has to be string, use check_access($path,$check,$stat=null)!');
}
// query stat array, if not given
if (is_null($stat))
@ -736,6 +823,20 @@ class egw_vfs extends vfs_stream_wrapper
//error_log(__METHOD__."(path=$path||stat[name]={$stat['name']},stat[mode]=".sprintf('%o',$stat['mode']).",$check) no stat array!");
return false; // file not found
}
// check if we use an EGroupwre stream wrapper, or a stock php one
// if it's not an EGroupware one, we can NOT use uid, gid and mode!
if (($scheme = parse_url($stat['url'],PHP_URL_SCHEME)) && !(class_exists(self::scheme2class($scheme))))
{
switch($check)
{
case self::READABLE:
return is_readable($stat['url']);
case self::WRITABLE:
return is_writable($stat['url']);
case self::EXECUTABLE:
return is_executable($stat['url']);
}
}
// check if other rights grant access
if (($stat['mode'] & $check) == $check)
{
@ -751,12 +852,7 @@ class egw_vfs extends vfs_stream_wrapper
// check if there's a group access and we have the right membership
if (($stat['mode'] & ($check << 3)) == ($check << 3) && $stat['gid'])
{
static $memberships;
if (is_null($memberships))
{
$memberships = $GLOBALS['egw']->accounts->memberships(self::$user,true);
}
if (in_array(-abs($stat['gid']),$memberships))
if (($memberships = $GLOBALS['egw']->accounts->memberships(self::$user, true)) && in_array(-abs($stat['gid']), $memberships))
{
//error_log(__METHOD__."(path=$path||stat[name]={$stat['name']},stat[mode]=".sprintf('%o',$stat['mode']).",$check) access via group rights!");
return true;
@ -778,7 +874,7 @@ class egw_vfs extends vfs_stream_wrapper
*/
static function is_writable($path)
{
return self::is_readable($path,2);
return self::is_readable($path,self::WRITABLE);
}
/**
@ -790,7 +886,7 @@ class egw_vfs extends vfs_stream_wrapper
*/
static function is_executable($path)
{
return self::is_readable($path,1);
return self::is_readable($path,self::EXECUTABLE);
}
/**
@ -811,7 +907,7 @@ class egw_vfs extends vfs_stream_wrapper
*
* @param string $path string with path
* @param int $rights=null rights to set, or null to delete the entry
* @param int/boolean $owner=null owner for whom to set the rights, null for the current user, or false to delete all rights for $path
* @param int|boolean $owner=null owner for whom to set the rights, null for the current user, or false to delete all rights for $path
* @return boolean true if acl is set/deleted, false on error
*/
static function eacl($url,$rights=null,$owner=null)
@ -825,7 +921,7 @@ class egw_vfs extends vfs_stream_wrapper
* Calls itself recursive, to get the parent directories
*
* @param string $path
* @return array/boolean array with array('path'=>$path,'owner'=>$owner,'rights'=>$rights) or false if $path not found
* @return array|boolean array with array('path'=>$path,'owner'=>$owner,'rights'=>$rights) or false if $path not found
*/
static function get_eacl($path)
{
@ -836,7 +932,7 @@ class egw_vfs extends vfs_stream_wrapper
* Store properties for a single ressource (file or dir)
*
* @param string $path string with path
* @param array $props array or array with values for keys 'name', 'ns', 'val' (null to delete the prop)
* @param array $props array of array with values for keys 'name', 'ns', 'val' (null to delete the prop)
* @return boolean true if props are updated, false otherwise (eg. ressource not found)
*/
static function proppatch($path,array $props)
@ -874,7 +970,7 @@ class egw_vfs extends vfs_stream_wrapper
/**
* Convert a symbolic mode string or octal mode to an integer
*
* @param string/int $set comma separated mode string to set [ugo]+[+=-]+[rwx]+
* @param string|int $set comma separated mode string to set [ugo]+[+=-]+[rwx]+
* @param int $mode=0 current mode of the file, necessary for +/- operation
* @return int
*/
@ -1022,6 +1118,10 @@ class egw_vfs extends vfs_stream_wrapper
{
$img = $GLOBALS['egw']->common->image('etemplate',$icon='mime'.$size.'_unknown');
}
if ($et_image === 'url')
{
return $img;
}
if ($et_image)
{
return 'etemplate/'.$icon;
@ -1030,7 +1130,7 @@ class egw_vfs extends vfs_stream_wrapper
}
/**
* Human readable size values in k or M
* Human readable size values in k, M or G
*
* @param int $size
* @return string
@ -1039,7 +1139,8 @@ class egw_vfs extends vfs_stream_wrapper
{
if ($size < 1024) return $size;
if ($size < 1024*1024) return sprintf('%3.1lfk',(float)$size/1024);
return sprintf('%3.1lfM',(float)$size/(1024*1024));
if ($size < 1024*1024*1024) return sprintf('%3.1lfM',(float)$size/(1024*1024));
return sprintf('%3.1lfG',(float)$size/(1024*1024*1024));
}
/**
@ -1059,8 +1160,10 @@ class egw_vfs extends vfs_stream_wrapper
/**
* Get the directory / parent of a given path or url(!), return false for '/'!
*
* Also works around PHP under Windows returning dirname('/something') === '\\', which is NOT understood by EGroupware's VFS!
*
* @param string $path path or url
* @return string/boolean parent or false if there's none ($path == '/')
* @return string|boolean parent or false if there's none ($path == '/')
*/
static function dirname($url)
{
@ -1169,7 +1272,7 @@ class egw_vfs extends vfs_stream_wrapper
}
// we do NOT need to encode % itself, as our path are already url encoded, with the exception of ' ' and '+'
// we urlencode double quotes '"', as that fixes many problems in html markup
return '/webdav.php'.strtr($path,array('+' => '%2B',' ' => '%20','"' => '%22'));
return '/webdav.php'.strtr($path,array('+' => '%2B',' ' => '%20','"' => '%22')).($force_download ? '?download' : '');
}
/**
@ -1337,6 +1440,35 @@ class egw_vfs extends vfs_stream_wrapper
return self::$lock_cache[$path] = $result;
}
/**
* Get backend specific information (data and etemplate), to integrate as tab in filemanagers settings dialog
*
* @param string $path
* @param array $content=null
* @return array|boolean array with values for keys 'data','etemplate','name','label','help' or false if not supported by backend
*/
static function getExtraInfo($path,array $content=null)
{
$extra = array();
if (($extra_info = self::_call_on_backend('extra_info',array($path,$content),true))) // true = fail silent if backend does NOT support it
{
$extra[] = $extra_info;
}
if (($vfs_extra = $GLOBALS['egw']->hooks->process(array(
'location' => 'vfs_extra',
'path' => $path,
'content' => $content,
))))
{
foreach($vfs_extra as $app => $data)
{
$extra = $extra ? array_merge($extra, $data) : $data;
}
}
return $extra;
}
/**
* Mapps entries of applications to a path for the locking
*
@ -1412,6 +1544,234 @@ class egw_vfs extends vfs_stream_wrapper
self::$db = isset($GLOBALS['egw_setup']->db) ? $GLOBALS['egw_setup']->db : $GLOBALS['egw']->db;
self::$lock_cache = array();
}
/**
* Returns the URL to the thumbnail of the given file. The thumbnail may simply
* be the mime-type icon, or - if activated - the preview with the given thsize.
*
* @param string $file name of the file
* @param int $thsize the size of the preview - false if the default should be used.
* @param string $mime if you already know the mime type of the file, you can supply
* it here. Otherwise supply "false".
*/
public static function thumbnail_url($file, $thsize = false, $mime = false)
{
// Retrive the mime-type of the file
if (!$mime)
{
$mime = egw_vfs::mime_content_type($file);
}
$image = "";
// Seperate the mime type into the primary and the secondary part
list($mime_main, $mime_sub) = explode('/', $mime);
if ($mime_main == 'egw')
{
$image = $GLOBALS['egw']->common->image($mime_sub, 'navbar');
}
else if ($file && $mime_main == 'image' && in_array($mime_sub, array('png','jpeg','jpg','gif','bmp')) &&
(string)$GLOBALS['egw_info']['server']['link_list_thumbnail'] != '0' &&
(string)$GLOBALS['egw_info']['user']['preferences']['common']['link_list_thumbnail'] != '0' &&
(!is_array($value) && ($stat = egw_vfs::stat($file)) ? $stat['size'] : $value['size']) < 1500000)
{
if (substr($file, 0, 6) == '/apps/')
{
$file = parse_url(egw_vfs::resolve_url_symlinks($path), PHP_URL_PATH);
}
//Assemble the thumbnail parameters
$thparams = array();
$thparams['path'] = $file;
if ($thsize)
{
$thparams['thsize'] = $thsize;
}
$image = $GLOBALS['egw']->link('/etemplate/thumbnail.php', $thparams);
}
else
{
list($app, $name) = explode("/", egw_vfs::mime_icon($mime), 2);
$image = $GLOBALS['egw']->common->image($app, $name);
}
return $image;
}
/**
* Get the configured start directory for the current user
*
* @return string
*/
static public function get_home_dir()
{
$start = '/home/'.$GLOBALS['egw_info']['user']['account_lid'];
// check if user specified a valid startpath in his prefs --> use it
if (($path = $GLOBALS['egw_info']['user']['preferences']['filemanager']['startfolder']) &&
$path[0] == '/' && egw_vfs::is_dir($path) && egw_vfs::check_access($path, egw_vfs::READABLE))
{
$start = $path;
}
return $start;
}
/**
* Copies the files given in $src to $dst.
*
* @param array $src contains the source file
* @param string $dst is the destination directory
*/
static public function copy_files(array $src, $dst, &$errs, array &$copied)
{
if (self::is_dir($dst))
{
foreach ($src as $file)
{
// Check whether the file has already been copied - prevents from
// recursion
if (!in_array($file, $copied))
{
// Calculate the target filename
$target = egw_vfs::concat($dst, egw_vfs::basename($file));
if (self::is_dir($file))
{
if ($file !== $target)
{
// Create the target directory
egw_vfs::mkdir($target,null,STREAM_MKDIR_RECURSIVE);
$files = egw_vfs::find($file, array(
"hidden" => true
));
$copied[] = $file;
$copied[] = $target; // < newly created folder must not be copied again!
if (egw_vfs::copy_files(egw_vfs::find($file), $target,
$errs, $copied))
{
continue;
}
}
$errs++;
}
else
{
// Copy a single file - check whether the file should be
// copied onto itself.
// TODO: Check whether target file already exists and give
// return those files so that a dialog might be displayed
// on the client side which lets the user decide.
if ($target !== $file && egw_vfs::copy($file, $target))
{
$copied[] = $file;
}
else
{
$errs++;
}
}
}
}
}
return $errs == 0;
}
/**
* Moves the files given in src to dst
*/
static public function move_files(array $src, $dst, &$errs, array &$moved)
{
if (egw_vfs::is_dir($dst))
{
foreach($src as $file)
{
$target = egw_vfs::concat($dst, egw_vfs::basename($file));
if ($file != $target && egw_vfs::rename($file, $target))
{
$moved[] = $file;
}
else
{
++$errs;
}
}
return $errs == 0;
}
return false;
}
/**
* Copy an uploaded file into the vfs, optionally set some properties (eg. comment or other cf's)
*
* Treat copying incl. properties as atomar operation in respect of notifications (one notification about an added file).
*
* @param array|string $src path to uploaded file or etemplate file array (value for key 'tmp_name')
* @param string $target path or directory to copy uploaded file
* @param array|string $props=null array with properties (name => value pairs, eg. 'comment' => 'FooBar','#cfname' => 'something'),
* array as for proppatch (array of array with values for keys 'name', 'val' and optional 'ns') or string with comment
* @param boolean $check_is_uploaded_file=true should method perform an is_uploaded_file check, default yes
* @return boolean|array stat array on success, false on error
*/
static public function copy_uploaded($src,$target,$props=null,$check_is_uploaded_file=true)
{
$tmp_name = is_array($src) ? $src['tmp_name'] : $src;
if (self::stat($target) && self::is_dir($target))
{
$target = self::concat($target, self::encodePathComponent(is_array($src) ? $src['name'] : basename($tmp_name)));
}
if ($check_is_uploaded_file && !is_uploaded_file($tmp_name))
{
if (self::LOG_LEVEL) error_log(__METHOD__."($tmp_name, $target, ".array2string($props).",$check_is_uploaded_file) returning FALSE !is_uploaded_file()");
return false;
}
if (!(self::is_writable($target) || self::is_writable(self::dirname($target))))
{
if (self::LOG_LEVEL) error_log(__METHOD__."($tmp_name, $target, ".array2string($props).",$check_is_uploaded_file) returning FALSE !writable");
return false;
}
if ($props)
{
if (!is_array($props)) $props = array(array('name' => 'comment','val' => $props));
// if $props is name => value pairs, convert it to internal array or array with values for keys 'name', 'val' and optional 'ns'
if (!isset($props[0]))
{
foreach($props as $name => $val)
{
if (($name == 'comment' || $name[0] == '#') && $val) // only copy 'comment' and cfs
{
$vfs_props[] = array(
'name' => $name,
'val' => $val,
);
}
}
$props = $vfs_props;
}
}
if ($props)
{
// set props before copying the file, so notifications already contain them
if (!self::stat($target))
{
self::touch($target); // create empty file, to be able to attach properties
self::$treat_as_new = true; // notify as new
}
self::proppatch($target, $props);
}
$ret = copy($tmp_name,self::PREFIX.$target) ? self::stat($target) : false;
if (self::LOG_LEVEL > 1 || !$ret && self::LOG_LEVEL) error_log(__METHOD__."($tmp_name, $target, ".array2string($props).") returning ".array2string($ret));
return $ret;
}
}
egw_vfs::init_static();

View File

@ -30,7 +30,6 @@
* The stream wrapper interface is according to the docu on php.net
*
* @link http://www.php.net/manual/en/function.stream-wrapper-register.php
* @ToDo versioning
*/
class sqlfs_stream_wrapper implements iface_stream_wrapper
{
@ -80,10 +79,6 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
*/
const LOG_LEVEL = 1;
/**
* We do versioning AND store the content in the db, NOT YET IMPLEMENTED
*/
const VERSIONING = 0;
/**
* We store the content in the DB (no versioning)
*/
@ -142,7 +137,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
*
* @var array $path => info-array pairs
*/
static private $stat_cache = array();
static protected $stat_cache = array();
/**
* Reference to the PDO object we use
*
@ -165,6 +160,21 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
*/
static public $extra_columns = ',fs_link';
/**
* Clears our stat-cache
*
* Normaly not necessary, as it is automatically cleared/updated, UNLESS egw_vfs::$user changes!
*
* @param string $path='/'
*/
public static function clearstatcache($path='/')
{
//error_log(__METHOD__."('$path')");
self::$stat_cache = array();
$GLOBALS['egw']->session->appsession('extended_acl',self::EACL_APPNAME,self::$extended_acl = null);
}
/**
* This method is called immediately after your stream object is created.
*
@ -174,10 +184,13 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
* - STREAM_USE_PATH If path is relative, search for the resource using the include_path.
* - STREAM_REPORT_ERRORS If this flag is set, you are responsible for raising errors using trigger_error() during opening of the stream.
* If this flag is not set, you should not raise any errors.
* @param string $opened_path full path of the file/resource, if the open was successfull and STREAM_USE_PATH was set
* @param string &$opened_path full path of the file/resource, if the open was successfull and STREAM_USE_PATH was set
* @param array $overwrite_new=null if set create new file with values overwriten by the given ones
* @param string $class=__CLASS__ class to use to call static methods, eg url_stat (workaround for no late static binding in php < 5.3)
* @todo remove $class parameter and use static::url_stat() once we require PHP5.3!
* @return boolean true if the ressource was opened successful, otherwise false
*/
function stream_open ( $url, $mode, $options, &$opened_path )
function stream_open ( $url, $mode, $options, &$opened_path, array $overwrite_new=null, $class=__CLASS__ )
{
if (self::LOG_LEVEL > 1) error_log(__METHOD__."($url,$mode,$options)");
@ -189,16 +202,16 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
$this->opened_mode = $mode = str_replace('b','',$mode); // we are always binary, like every Linux system
$this->opened_stream = null;
if (!($stat = self::url_stat($path,STREAM_URL_STAT_QUIET)) || $mode[0] == 'x') // file not found or file should NOT exist
if (!is_null($overwrite_new) || !($stat = call_user_func(array($class,'url_stat'),$path,STREAM_URL_STAT_QUIET)) || $mode[0] == 'x') // file not found or file should NOT exist
{
if ($mode[0] == 'r' || // does $mode require the file to exist (r,r+)
$mode[0] == 'x' || // or file should not exist, but does
!($dir_stat=self::url_stat($dir,STREAM_URL_STAT_QUIET)) || // or parent dir does not exist create it
!($dir_stat=call_user_func(array($class,'url_stat'),$dir,STREAM_URL_STAT_QUIET)) || // or parent dir does not exist create it
!egw_vfs::check_access($dir,egw_vfs::WRITABLE,$dir_stat)) // or we are not allowed to create it
{
self::_remove_password($url);
if (self::LOG_LEVEL) error_log(__METHOD__."($url,$mode,$options) file does not exist or can not be created!");
if (!($options & STREAM_URL_STAT_QUIET))
if (($options & STREAM_REPORT_ERRORS))
{
trigger_error(__METHOD__."($url,$mode,$options) file does not exist or can not be created!",E_USER_WARNING);
}
@ -207,8 +220,8 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
}
// new file --> create it in the DB
$new_file = true;
$query = 'INSERT INTO '.self::TABLE.' (fs_name,fs_dir,fs_mode,fs_uid,fs_gid,fs_created,fs_modified,fs_creator,fs_mime,fs_size'.
') VALUES (:fs_name,:fs_dir,:fs_mode,:fs_uid,:fs_gid,:fs_created,:fs_modified,:fs_creator,:fs_mime,:fs_size)';
$query = 'INSERT INTO '.self::TABLE.' (fs_name,fs_dir,fs_mode,fs_uid,fs_gid,fs_created,fs_modified,fs_creator,fs_mime,fs_size,fs_active'.
') VALUES (:fs_name,:fs_dir,:fs_mode,:fs_uid,:fs_gid,:fs_created,:fs_modified,:fs_creator,:fs_mime,:fs_size,:fs_active)';
if (self::LOG_LEVEL > 2) $query = '/* '.__METHOD__.': '.__LINE__.' */ '.$query;
$stmt = self::$pdo->prepare($query);
$values = array(
@ -225,7 +238,9 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
'fs_creator' => egw_vfs::$user,
'fs_mime' => 'application/octet-stream', // required NOT NULL!
'fs_size' => 0,
'fs_active' => self::_pdo_boolean(true),
);
if ($overwrite_new) $values = array_merge($values,$overwrite_new);
if (!$stmt->execute($values) || !($this->opened_fs_id = self::$pdo->lastInsertId('egw_sqlfs_fs_id_seq')))
{
$this->opened_stream = $this->opened_path = $this->opened_mode = null;
@ -245,6 +260,17 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
self::mkdir_recursive($fs_dir,0700,true);
}
}
// check if opend file is a directory
elseif($stat && ($stat['mode'] & self::MODE_DIR) == self::MODE_DIR)
{
if (self::LOG_LEVEL) error_log(__METHOD__."($url,$mode,$options) Is a directory!");
if (($options & STREAM_REPORT_ERRORS))
{
trigger_error(__METHOD__."($url,$mode,$options) Is a directory!",E_USER_WARNING);
}
$this->opened_stream = $this->opened_path = $this->opened_mode = null;
return false;
}
else
{
if ($mode == 'r' && !egw_vfs::check_access($url,egw_vfs::READABLE ,$stat) ||// we are not allowed to read
@ -253,7 +279,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
self::_remove_password($url);
$op = $mode == 'r' ? 'read' : 'edited';
if (self::LOG_LEVEL) error_log(__METHOD__."($url,$mode,$options) file can not be $op!");
if (!($options & STREAM_URL_STAT_QUIET))
if (($options & STREAM_REPORT_ERRORS))
{
trigger_error(__METHOD__."($url,$mode,$options) file can not be $op!",E_USER_WARNING);
}
@ -514,13 +540,13 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
* @param string $url
* @return boolean TRUE on success or FALSE on failure
*/
static function unlink ( $url )
static function unlink ( $url, $parent_stat=null )
{
if (self::LOG_LEVEL > 1) error_log(__METHOD__."($url)");
$path = parse_url($url,PHP_URL_PATH);
if (!($stat = self::url_stat($path,STREAM_URL_STAT_LINK)) || !egw_vfs::check_access(egw_vfs::dirname($path),egw_vfs::WRITABLE))
if (!($stat = self::url_stat($path,STREAM_URL_STAT_LINK)) || !egw_vfs::check_access(egw_vfs::dirname($path),egw_vfs::WRITABLE, $parent_stat))
{
self::_remove_password($url);
if (self::LOG_LEVEL) error_log(__METHOD__."($url) permission denied!");
@ -569,12 +595,14 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
if (self::LOG_LEVEL > 1) error_log(__METHOD__."($url_from,$url_to)");
$path_from = parse_url($url_from,PHP_URL_PATH);
$from_dir = egw_vfs::dirname($path_from);
$path_to = parse_url($url_to,PHP_URL_PATH);
$to_dir = egw_vfs::dirname($path_to);
$operation = self::url2operation($url_from);
// we have to use array($class,'url_stat'), as $class.'::url_stat' requires PHP 5.2.3 and we currently only require 5.2+
if (!($from_stat = call_user_func(array($class,'url_stat'),$path_from,0)) || !egw_vfs::check_access(dirname($path_from),egw_vfs::WRITABLE))
if (!($from_stat = call_user_func(array($class,'url_stat'),$path_from,0)) ||
!egw_vfs::check_access($from_dir,egw_vfs::WRITABLE,$from_dir_stat = call_user_func(array($class,'url_stat'),$from_dir,0)))
{
self::_remove_password($url_from);
self::_remove_password($url_to);
@ -609,11 +637,12 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
unset(self::$stat_cache[$path_from]);
unset(self::$stat_cache[$path_to]);
$stmt = self::$pdo->prepare('UPDATE '.self::TABLE.' SET fs_dir=:fs_dir,fs_name=:fs_name WHERE fs_id=:fs_id');
$stmt = self::$pdo->prepare('UPDATE '.self::TABLE.' SET fs_dir=:fs_dir,fs_name=:fs_name WHERE fs_dir=:old_dir AND fs_name=:old_name');
$ok = $stmt->execute(array(
'fs_dir' => $to_dir_stat['ino'],
'fs_name' => egw_vfs::basename($path_to),
'fs_id' => $from_stat['ino'],
'fs_dir' => $to_dir_stat['ino'],
'fs_name' => egw_vfs::basename($path_to),
'old_dir' => $from_dir_stat['ino'],
'old_name' => $from_stat['name'],
));
unset($stmt);
@ -635,7 +664,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
/**
* due to problems with recursive directory creation, we have our own here
*/
function mkdir_recursive($pathname, $mode, $depth=0)
private static function mkdir_recursive($pathname, $mode, $depth=0)
{
$maxdepth=10;
$depth2propagate = (int)$depth + 1;
@ -665,7 +694,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
{
self::_remove_password($url);
if (self::LOG_LEVEL) error_log(__METHOD__."('$url',$mode,$options) already exist!");
if (!($options & STREAM_URL_STAT_QUIET))
if (!($options & STREAM_REPORT_ERRORS))
{
//throw new Exception(__METHOD__."('$url',$mode,$options) already exist!");
trigger_error(__METHOD__."('$url',$mode,$options) already exist!",E_USER_WARNING);
@ -691,7 +720,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
{
self::_remove_password($url);
if (self::LOG_LEVEL) error_log(__METHOD__."('$url',$mode,$options) permission denied!");
if (!($options & STREAM_URL_STAT_QUIET))
if (!($options & STREAM_REPORT_ERRORS))
{
trigger_error(__METHOD__."('$url',$mode,$options) permission denied!",E_USER_WARNING);
}
@ -756,7 +785,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
$err_msg = __METHOD__."($url,$options) ".(!$stat ? 'not found!' :
($stat['mime'] != self::DIR_MIME_TYPE ? 'not a directory!' : 'permission denied!'));
if (self::LOG_LEVEL) error_log($err_msg);
if (!($options & STREAM_URL_STAT_QUIET))
if (!($options & STREAM_REPORT_ERRORS))
{
trigger_error($err_msg,E_USER_WARNING);
}
@ -768,7 +797,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
{
self::_remove_password($url);
if (self::LOG_LEVEL) error_log(__METHOD__."($url,$options) dir is not empty!");
if (!($options & STREAM_URL_STAT_QUIET))
if (!($options & STREAM_REPORT_ERRORS))
{
trigger_error(__METHOD__."('$url',$options) dir is not empty!",E_USER_WARNING);
}
@ -971,7 +1000,8 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
}
$this->opened_dir = array();
$query = 'SELECT fs_id,fs_name,fs_mode,fs_uid,fs_gid,fs_size,fs_mime,fs_created,fs_modified'.self::$extra_columns.
' FROM '.self::TABLE." WHERE fs_dir=? ORDER BY fs_mime='httpd/unix-directory' DESC, fs_name ASC";
' FROM '.self::TABLE.' WHERE fs_dir=? AND fs_active='.self::_pdo_boolean(true).
" ORDER BY fs_mime='httpd/unix-directory' DESC, fs_name ASC";
//if (self::LOG_LEVEL > 2) $query = '/* '.__METHOD__.': '.__LINE__.' */ '.$query;
if (self::LOG_LEVEL > 2) $query = '/* '.__METHOD__."($url,$options)".' */ '.$query;
@ -1020,7 +1050,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
*/
static function url_stat ( $url, $flags, $eacl_access=null )
{
if (self::LOG_LEVEL > 1) error_log(__METHOD__."('$url',$flags)");
if (self::LOG_LEVEL > 1) error_log(__METHOD__."('$url',$flags,$eacl_access)");
$path = parse_url($url,PHP_URL_PATH);
@ -1044,7 +1074,8 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
self::_pdo();
}
$base_query = 'SELECT fs_id,fs_name,fs_mode,fs_uid,fs_gid,fs_size,fs_mime,fs_created,fs_modified'.self::$extra_columns.
' FROM '.self::TABLE.' WHERE fs_name'.self::$case_sensitive_equal.'? AND fs_dir=';
' FROM '.self::TABLE.' WHERE fs_active='.self::_pdo_boolean(true).
' AND fs_name'.self::$case_sensitive_equal.'? AND fs_dir=';
$parts = explode('/',$path);
// if we have extendes acl access to the url, we dont need and can NOT include the sql for the readable check
@ -1075,7 +1106,8 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
// we also store negatives (all methods creating new files/dirs have to unset the stat-cache!)
return self::$stat_cache[$path] = false;
}
$query = 'SELECT fs_id FROM '.self::TABLE.' WHERE fs_dir=('.$query.') AND fs_name'.self::$case_sensitive_equal.self::$pdo->quote($name);
$query = 'SELECT fs_id FROM '.self::TABLE.' WHERE fs_dir=('.$query.') AND fs_active='.
self::_pdo_boolean(true).' AND fs_name'.self::$case_sensitive_equal.self::$pdo->quote($name);
// if we are not root AND have no extended acl access, we need to make sure the user has the right to tranverse all parent directories (read-rights)
if (!egw_vfs::$is_root && !$eacl_access)
@ -1118,7 +1150,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
*
* @return string
*/
private function _sql_readable()
protected function _sql_readable()
{
static $sql_read_acl;
@ -1283,7 +1315,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
* Read the extended acl via acl::get_grants('sqlfs')
*
*/
private static function _read_extended_acl()
static protected function _read_extended_acl()
{
if ((self::$extended_acl = $GLOBALS['egw']->session->appsession('extended_acl',self::EACL_APPNAME)) != false)
{
@ -1385,7 +1417,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
*/
function get_eacl($path)
{
if (!($stat = self::url_stat($path,STREAM_URL_STAT_QUIET)))
if (!($stat = self::url_stat($_path=$path,STREAM_URL_STAT_QUIET)))
{
error_log(__METHOD__.__LINE__.' '.array2string($path).' not found!');
return false; // not found
@ -1402,11 +1434,11 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
}
if (($path = egw_vfs::dirname($path)))
{
return array_merge((array)self::get_eacl($path),$eacls);
$eacls = array_merge((array)self::get_eacl($path),$eacls);
}
// sort by length descending, to show precedence
usort($eacls,create_function('$a,$b','return strlen($b["path"])-strlen($a["path"]);'));
//error_log(__METHOD__."('$_path') returning ".array2string($eacls));
return $eacls;
}
@ -1486,7 +1518,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
* @param array $info
* @return array
*/
static private function _vfsinfo2stat($info)
static protected function _vfsinfo2stat($info)
{
$stat = array(
'ino' => $info['fs_id'],
@ -1563,7 +1595,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
self::$pdo = new PDO($dsn,$egw_db->User,'$egw_db->Password');
}
// set client charset of the connection
$charset = $GLOBALS['egw']->translation->charset();
$charset = translation::charset();
switch(self::$pdo_type)
{
case 'mysql':
@ -1586,7 +1618,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
* @param mixed $time
* @return string Y-m-d H:i:s
*/
static private function _pdo_timestamp($time)
static protected function _pdo_timestamp($time)
{
if (is_numeric($time))
{
@ -1668,7 +1700,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
*
* @param string &$url
*/
static private function _remove_password(&$url)
static protected function _remove_password(&$url)
{
$parts = parse_url($url);
@ -1711,7 +1743,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
* Store properties for a single ressource (file or dir)
*
* @param string|int $path string with path or integer fs_id
* @param array $props array or array with values for keys 'name', 'ns', 'val' (null to delete the prop)
* @param array $props array of array with values for keys 'name', 'ns', 'val' (null to delete the prop)
* @return boolean true if props are updated, false otherwise (eg. ressource not found)
*/
static function proppatch($path,array $props)
@ -1814,7 +1846,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
}
if (!is_array($path_ids))
{
$props = $props[$row['fs_id']];
$props = $props[$row['fs_id']] ? $props[$row['fs_id']] : array(); // return empty array for no props
}
elseif ($props && isset($stat)) // need to map fs_id's to pathes
{

View File

@ -62,16 +62,9 @@ class vfs_webdav_server extends HTTP_WebDAV_Server_Filesystem
// special treatment for litmus compliance test
// reply on its identifier header
// not needed for the test itself but eases debugging
if (function_exists('apache_request_headers'))
{
foreach (apache_request_headers() as $key => $value)
{
if (stristr($key, 'litmus'))
{
error_log("Litmus test $value");
header('X-Litmus-reply: '.$value);
}
}
if (isset($this->_SERVER['HTTP_X_LITMUS'])) {
error_log("Litmus test ".$this->_SERVER['HTTP_X_LITMUS']);
header("X-Litmus-reply: ".$this->_SERVER['HTTP_X_LITMUS']);
}
// let the base class do all the work
HTTP_WebDAV_Server::ServeRequest();
@ -135,7 +128,28 @@ class vfs_webdav_server extends HTTP_WebDAV_Server_Filesystem
$source = $this->base .$options["path"];
if (!file_exists($source)) return "404 Not found";
if (is_dir($source)) { // resource is a collection
switch ($options["depth"]) {
case "infinity": // valid
break;
case "0": // valid for COPY only
if ($del) { // MOVE?
return "400 Bad request";
}
break;
case "1": // invalid for both COPY and MOVE
default:
return "400 Bad request";
}
}
$dest = $this->base . $options["dest"];
$destdir = dirname($dest);
if (!file_exists($destdir) || !is_dir($destdir)) {
return "409 Conflict";
}
$new = !file_exists($dest);
$existing_col = false;
@ -165,11 +179,6 @@ class vfs_webdav_server extends HTTP_WebDAV_Server_Filesystem
}
}
if (is_dir($source) && ($options["depth"] != "infinity")) {
// RFC 2518 Section 9.2, last paragraph
return "400 Bad request";
}
if ($del) {
if (!rename($source, $dest)) {
return "500 Internal server error";
@ -189,9 +198,8 @@ class vfs_webdav_server extends HTTP_WebDAV_Server_Filesystem
mysql_query($query);
*/
} else {
if (is_dir($source)) {
$files = System::find($source);
$files = array_reverse($files);
if (is_dir($source) && $options['depth'] == 'infinity') {
$files = egw_vfs::find($source,array('depth' => true,'url' => true)); // depth=true: return dirs first, url=true: allow urls!
} else {
$files = array($source);
}
@ -243,6 +251,9 @@ class vfs_webdav_server extends HTTP_WebDAV_Server_Filesystem
*/
function fileinfo($path)
{
// internally we require some url-encoding, as vfs_stream_wrapper uses URL's internally
$path = str_replace(array('#','?'),array('%23','%3F'),$path);
//error_log(__METHOD__."($path)");
// map URI path to filesystem path
$fspath = $this->base . $path;
@ -251,15 +262,24 @@ class vfs_webdav_server extends HTTP_WebDAV_Server_Filesystem
$info = array();
// TODO remove slash append code when base class is able to do it itself
$info['path'] = is_dir($fspath) ? $this->_slashify($path) : $path;
// remove all urlencoding we need internally in EGw, HTTP_WebDAV_Server will add it's own!
// rawurldecode does NOT touch +
$info['path'] = rawurldecode($info['path']);
$info['props'] = array();
// no special beautified displayname here ...
$info['props'][] = HTTP_WebDAV_Server::mkprop ('displayname', egw_vfs::basename(self::_unslashify($path)));
$info['props'][] = HTTP_WebDAV_Server::mkprop ('displayname', egw_vfs::basename(self::_unslashify($info['path'])));
// creation and modification time
$info['props'][] = HTTP_WebDAV_Server::mkprop ('creationdate', filectime($fspath));
$info['props'][] = HTTP_WebDAV_Server::mkprop ('getlastmodified', filemtime($fspath));
// Microsoft extensions: last access time and 'hidden' status
$info["props"][] = HTTP_WebDAV_Server::mkprop("lastaccessed", fileatime($fspath));
$info["props"][] = HTTP_WebDAV_Server::mkprop("ishidden", egw_vfs::is_hidden($fspath));
// type and size (caller already made sure that path exists)
if (is_dir($fspath)) {
// directory (WebDAV collection)
@ -292,7 +312,7 @@ class vfs_webdav_server extends HTTP_WebDAV_Server_Filesystem
*/
// ToDo: etag from inode and modification time
//error_log(__METHOD__."($path) info=".print_r($info,true));
//error_log(__METHOD__."($path) info=".array2string($info));
return $info;
}
@ -395,6 +415,28 @@ class vfs_webdav_server extends HTTP_WebDAV_Server_Filesystem
return egw_vfs::mime_content_type($path);
}
/**
* Check if path is readable by current user
*
* @param string $fspath
* @return boolean
*/
function _is_readable($fspath)
{
return egw_vfs::is_readable($fspath);
}
/**
* Check if path is writable by current user
*
* @param string $fspath
* @return boolean
*/
function _is_writable($fspath)
{
return egw_vfs::is_writable($fspath);
}
/**
* PROPPATCH method handler
*
@ -527,7 +569,7 @@ class vfs_webdav_server extends HTTP_WebDAV_Server_Filesystem
{
return egw_vfs::checkLock($path);
}
/**
* GET method handler for directories
*
@ -543,4 +585,45 @@ class vfs_webdav_server extends HTTP_WebDAV_Server_Filesystem
parent::GetDir($fspath, $options);
}
private $force_download = false;
/**
* Constructor
*
* Reimplement to add a Content-Disposition header, if ?download is appended to the REQUEST_URI
*/
function __construct()
{
if ($_SERVER['REQUEST_METHOD'] == 'GET' && ($this->force_download = strpos($_SERVER['REQUEST_URI'],'?download')))
{
$_SERVER['REQUEST_URI'] = substr($_SERVER['REQUEST_URI'],0,$this->force_download);
}
parent::HTTP_WebDAV_Server();
}
/**
* GET method handler
*
* Reimplement to add a Content-Disposition header, if ?download is appended to the REQUEST_URI
*
* @param array parameter passing array
* @return bool true on success
*/
function GET(&$options)
{
if (($ok = parent::GET($options)) && $this->force_download)
{
if(html::$user_agent == 'msie') // && self::$ua_version == '5.5')
{
$attachment = '';
}
else
{
$attachment = ' attachment;';
}
header('Content-disposition:'.$attachment.' filename="'.egw_vfs::basename($options['path']).'"');
}
return $ok;
}
}

View File

@ -32,26 +32,11 @@ function check_access(&$account)
return egw_digest_auth::autocreate_session_callback($account);
}
// if we are called with a /apps/$app path, use that $app as currentapp, to not require filemanager rights for the links
$parts = explode('/',isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : $_SERVER['ORIG_PATH_INFO']);
//error_log("webdav: explode".print_r($parts,true));
if(count($parts) == 1)
{
error_log(__METHOD__. "Malformed Url: missing slash:\n".$_SERVER['SERVER_NAME']."\n PATH_INFO:".$_SERVER['PATH_INFO'].
"\n REQUEST_URI".$_SERVER['REQUEST_URI']."\n ORIG_SCRIPT_NAME:".$_SERVER['ORIG_SCRIPT_NAME'].
"\n REMOTE_ADDR:".$_SERVER['REMOTE_ADDR']."\n PATH_INFO:".$_SERVER['PATH_INFO']."\n HTTP_USER_AGENT:".$_SERVER['HTTP_USER_AGENT']) ;
header("HTTP/1.1 501 Not implemented");
header("X-WebDAV-Status: 501 Not implemented", true);
exit;
}
$app = count($parts) > 3 && $parts[1] == 'apps' ? $parts[2] : 'filemanager';
$GLOBALS['egw_info'] = array(
'flags' => array(
'disable_Template_class' => True,
'noheader' => True,
'currentapp' => $app,
'currentapp' => preg_match('|/webdav.php/apps/([A-Za-z0-9_-]+)/|', $_SERVER['REQUEST_URI'], $matches) ? $matches[1] : 'filemanager',
'autocreate_session_callback' => 'check_access',
'no_exception_handler' => 'basic_auth', // we use a basic auth exception handler (sends exception message as basic auth realm)
'auth_realm' => 'EGroupware WebDAV server', // cant use vfs_webdav_server::REALM as autoloading and include path not yet setup!
@ -94,4 +79,4 @@ if (strstr($user_agent, 'microsoft-webdav') !== false ||
$webdav_server->cnrnd = true;
}
$webdav_server->ServeRequest();
//error_log(sprintf("WebDAV %s request took %5.3f s (header include took %5.3f s)",$_SERVER['REQUEST_METHOD'],microtime(true)-$starttime,$headertime-$starttime));
//error_log(sprintf('WebDAV %s request: status "%s", took %5.3f s'.($headertime?' (header include took %5.3f s)':''),$_SERVER['REQUEST_METHOD'].' '.$_SERVER['PATH_INFO'],$webdav_server->_http_status,microtime(true)-$starttime,$headertime-$starttime));