mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-21 23:43:17 +01:00
* Filemanager/WebDAV: support for newer ownCloud clients (eg. version 1.1.1)
This commit is contained in:
parent
9c2fb9ffda
commit
99e1cad866
@ -55,9 +55,9 @@ class vfs_webdav_server extends HTTP_WebDAV_Server_Filesystem
|
||||
* Reimplemented to not check our vfs base path with realpath and connect to mysql DB
|
||||
*
|
||||
* @access public
|
||||
* @param string
|
||||
* @param $prefix=null prefix filesystem path with given path, eg. "/webdav" for owncloud 4.5 remote.php
|
||||
*/
|
||||
function ServeRequest($base = false)
|
||||
function ServeRequest($prefix=null)
|
||||
{
|
||||
// special treatment for litmus compliance test
|
||||
// reply on its identifier header
|
||||
@ -67,7 +67,7 @@ class vfs_webdav_server extends HTTP_WebDAV_Server_Filesystem
|
||||
header("X-Litmus-reply: ".$this->_SERVER['HTTP_X_LITMUS']);
|
||||
}
|
||||
// let the base class do all the work
|
||||
HTTP_WebDAV_Server::ServeRequest();
|
||||
HTTP_WebDAV_Server::ServeRequest($prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -296,6 +296,9 @@ class vfs_webdav_server extends HTTP_WebDAV_Server_Filesystem
|
||||
$info['props'][] = HTTP_WebDAV_Server::mkprop ('getcontenttype', 'application/x-non-readable');
|
||||
}
|
||||
$info['props'][] = HTTP_WebDAV_Server::mkprop ('getcontentlength', filesize($fspath));
|
||||
// for files generate etag from inode (sqlfs: fs_id), modification time and size
|
||||
$stat = stat($fspath);
|
||||
$info['props'][] = HTTP_WebDAV_Server::mkprop('getetag', '"'.$stat['ino'].':'.$stat['mtime'].':'.$stat['size'].'"');
|
||||
}
|
||||
/* returning the supportedlock property causes Windows DAV provider and Konqueror to not longer work
|
||||
ToDo: return it only if explicitly requested ($options['props'])
|
||||
@ -310,8 +313,6 @@ class vfs_webdav_server extends HTTP_WebDAV_Server_Filesystem
|
||||
<D:locktype><D:write/></D:lockscope>
|
||||
</D:lockentry>');
|
||||
*/
|
||||
// ToDo: etag from inode and modification time
|
||||
|
||||
//error_log(__METHOD__."($path) info=".array2string($info));
|
||||
return $info;
|
||||
}
|
||||
@ -622,6 +623,10 @@ class vfs_webdav_server extends HTTP_WebDAV_Server_Filesystem
|
||||
*/
|
||||
function GET(&$options)
|
||||
{
|
||||
if (is_dir($this->base . $options["path"]))
|
||||
{
|
||||
return $this->autoindex($options);
|
||||
}
|
||||
if (($ok = parent::GET($options)) && $this->force_download)
|
||||
{
|
||||
if(html::$user_agent == 'msie' && self::$ua_version < 9.0)
|
||||
@ -636,4 +641,196 @@ class vfs_webdav_server extends HTTP_WebDAV_Server_Filesystem
|
||||
}
|
||||
return $ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display an automatic index (listing and properties) for a collection
|
||||
*
|
||||
* @param array $options parameter passing array, index "path" contains requested path
|
||||
*/
|
||||
protected function autoindex($options)
|
||||
{
|
||||
$propfind_options = array(
|
||||
'path' => $options['path'],
|
||||
'depth' => 1,
|
||||
);
|
||||
$files = array();
|
||||
if (($ret = $this->PROPFIND($propfind_options,$files)) !== true)
|
||||
{
|
||||
return $ret; // no collection
|
||||
}
|
||||
header('Content-type: text/html; charset='.translation::charset());
|
||||
echo "<html>\n<head>\n\t<title>".'EGroupware WebDAV server '.htmlspecialchars($options['path'])."</title>\n";
|
||||
echo "\t<meta http-equiv='content-type' content='text/html; charset=utf-8' />\n";
|
||||
echo "\t<style type='text/css'>\n.th { background-color: #e0e0e0; }\n.row_on { background-color: #F1F1F1; vertical-align: top; }\n".
|
||||
".row_off { background-color: #ffffff; vertical-align: top; }\ntd { padding-left: 5px; }\nth { padding-left: 5px; text-align: left; }\n\t</style>\n";
|
||||
echo "</head>\n<body>\n";
|
||||
|
||||
echo '<h1>WebDAV ';
|
||||
list(,$base) = explode(parse_url($GLOBALS['egw_info']['server']['webserver_url'], PHP_URL_PATH), $this->base_uri, 2);
|
||||
$path = $base;
|
||||
foreach(explode('/',$this->_unslashify($options['path'])) as $n => $name)
|
||||
{
|
||||
$path .= ($n != 1 ? '/' : '').$name;
|
||||
echo html::a_href(htmlspecialchars($name.'/'),$path);
|
||||
}
|
||||
echo "</h1>\n";
|
||||
|
||||
static $props2show = array(
|
||||
'DAV:displayname' => 'Displayname',
|
||||
'DAV:getlastmodified' => 'Last modified',
|
||||
'DAV:getetag' => 'ETag',
|
||||
'DAV:getcontenttype' => 'Content type',
|
||||
'DAV:resourcetype' => 'Resource type',
|
||||
//'DAV:owner' => 'Owner',
|
||||
//'DAV:current-user-privilege-set' => 'current-user-privilege-set',
|
||||
//'DAV:getcontentlength' => 'Size',
|
||||
//'DAV:sync-token' => 'sync-token',
|
||||
);
|
||||
$n = 0;
|
||||
foreach($files['files'] as $file)
|
||||
{
|
||||
if (!isset($collection_props))
|
||||
{
|
||||
$collection_props = $this->props2array($file['props']);
|
||||
echo '<h3>'.lang('Collection listing').': '.htmlspecialchars($collection_props['DAV:displayname'])."</h3>\n";
|
||||
continue; // own entry --> displaying properies later
|
||||
}
|
||||
if(!$n++)
|
||||
{
|
||||
echo "<table>\n\t<tr class='th'>\n\t\t<th>#</th>\n\t\t<th>".lang('Name')."</th>";
|
||||
foreach($props2show as $label) echo "\t\t<th>".lang($label)."</th>\n";
|
||||
echo "\t</tr>\n";
|
||||
}
|
||||
$props = $this->props2array($file['props']);
|
||||
//echo $file['path']; _debug_array($props);
|
||||
$class = $class == 'row_on' ? 'row_off' : 'row_on';
|
||||
|
||||
if (substr($file['path'],-1) == '/')
|
||||
{
|
||||
$name = basename(substr($file['path'],0,-1)).'/';
|
||||
}
|
||||
else
|
||||
{
|
||||
$name = basename($file['path']);
|
||||
}
|
||||
|
||||
echo "\t<tr class='$class'>\n\t\t<td>$n</td>\n\t\t<td>".
|
||||
html::a_href(htmlspecialchars($name),$base.strtr($file['path'], array(
|
||||
'%' => '%25',
|
||||
'#' => '%23',
|
||||
'?' => '%3F',
|
||||
)))."</td>\n";
|
||||
foreach($props2show as $prop => $label)
|
||||
{
|
||||
echo "\t\t<td>".($prop=='DAV:getlastmodified'&&!empty($props[$prop])?date('Y-m-d H:i:s',$props[$prop]):$props[$prop])."</td>\n";
|
||||
}
|
||||
echo "\t</tr>\n";
|
||||
}
|
||||
if (!$n)
|
||||
{
|
||||
echo '<p>'.lang('Collection empty.')."</p>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "</table>\n";
|
||||
}
|
||||
echo '<h3>'.lang('Properties')."</h3>\n";
|
||||
echo "<table>\n\t<tr class='th'><th>".lang('Namespace')."</th><th>".lang('Name')."</th><th>".lang('Value')."</th></tr>\n";
|
||||
foreach($collection_props as $name => $value)
|
||||
{
|
||||
$class = $class == 'row_on' ? 'row_off' : 'row_on';
|
||||
$ns = explode(':',$name);
|
||||
$name = array_pop($ns);
|
||||
$ns = implode(':',$ns);
|
||||
echo "\t<tr class='$class'>\n\t\t<td>".htmlspecialchars($ns)."</td><td style='white-space: nowrap'>".htmlspecialchars($name)."</td>\n";
|
||||
echo "\t\t<td>".$value."</td>\n\t</tr>\n";
|
||||
}
|
||||
echo "</table>\n";
|
||||
/*$dav = array(1);
|
||||
$allow = false;
|
||||
$this->OPTIONS($options['path'], $dav, $allow);
|
||||
echo "<p>DAV: ".implode(', ', $dav)."</p>\n";*/
|
||||
|
||||
echo "</body>\n</html>\n";
|
||||
|
||||
common::egw_exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a property value for output
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return string
|
||||
*/
|
||||
protected function prop_value($value)
|
||||
{
|
||||
if (is_array($value))
|
||||
{
|
||||
if (isset($value[0]['ns']))
|
||||
{
|
||||
$value = $this->_hierarchical_prop_encode($value);
|
||||
}
|
||||
$value = array2string($value);
|
||||
}
|
||||
if ($value[0] == '<' && function_exists('tidy_repair_string'))
|
||||
{
|
||||
$value = tidy_repair_string($value, array(
|
||||
'indent' => true,
|
||||
'show-body-only' => true,
|
||||
'output-encoding' => 'utf-8',
|
||||
'input-encoding' => 'utf-8',
|
||||
'input-xml' => true,
|
||||
'output-xml' => true,
|
||||
'wrap' => 0,
|
||||
));
|
||||
}
|
||||
if (($href=preg_match('/\<(D:)?href\>[^<]+\<\/(D:)?href\>/i',$value)))
|
||||
{
|
||||
$value = preg_replace('/\<(D:)?href\>('.preg_quote($this->base_uri.'/','/').')?([^<]+)\<\/(D:)?href\>/i','<\\1href><a href="\\2\\3">\\3</a></\\4href>',$value);
|
||||
}
|
||||
$value = $value[0] == '<' || strpos($value, "\n") !== false ? '<pre>'.htmlspecialchars($value).'</pre>' : htmlspecialchars($value);
|
||||
|
||||
if ($href)
|
||||
{
|
||||
$value = preg_replace('/<a href="(.+)">/', '<a href="\\1">', $value);
|
||||
$value = str_replace('</a>', '</a>', $value);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return numeric indexed array with values for keys 'ns', 'name' and 'val' as array 'ns:name' => 'val'
|
||||
*
|
||||
* @param array $props
|
||||
* @return array
|
||||
*/
|
||||
protected function props2array(array $props)
|
||||
{
|
||||
$arr = array();
|
||||
foreach($props as $prop)
|
||||
{
|
||||
$ns_hash = array('DAV:' => 'D');
|
||||
switch($prop['ns'])
|
||||
{
|
||||
case 'DAV:';
|
||||
$ns = 'DAV';
|
||||
break;
|
||||
default:
|
||||
$ns = $prop['ns'];
|
||||
}
|
||||
if (is_array($prop['val']))
|
||||
{
|
||||
$prop['val'] = $this->_hierarchical_prop_encode($prop['val'], $prop['ns'], $ns_defs='', $ns_hash);
|
||||
// hack to show real namespaces instead of not (visibly) defined shortcuts
|
||||
unset($ns_hash['DAV:']);
|
||||
$value = strtr($v=$this->prop_value($prop['val']),array_flip($ns_hash));
|
||||
}
|
||||
else
|
||||
{
|
||||
$value = $this->prop_value($prop['val']);
|
||||
}
|
||||
$arr[$ns.':'.$prop['name']] = $value;
|
||||
}
|
||||
return $arr;
|
||||
}
|
||||
}
|
90
remote.php
Normal file
90
remote.php
Normal file
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
/**
|
||||
* FileManger - WebDAV access for ownCloud clients
|
||||
*
|
||||
* ownCloud clients sync by default local ownCloud dir to /clientsync on server.
|
||||
*
|
||||
* EGroupware now temporary mounts vfs://default/home/$user on /clientsync,
|
||||
* so ownCloud clients syncs with users home-dir, unless admin mounts an other directory.
|
||||
*
|
||||
* @link http://owncloud.org/sync-clients/
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage vfs
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2006-12 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
$starttime = microtime(true);
|
||||
|
||||
/**
|
||||
* check if the given user has access
|
||||
*
|
||||
* Create a session or if the user has no account return authenticate header and 401 Unauthorized
|
||||
*
|
||||
* @param array &$account
|
||||
* @return int session-id
|
||||
*/
|
||||
function check_access(&$account)
|
||||
{
|
||||
if (isset($_GET['auth']))
|
||||
{
|
||||
list($_SERVER['PHP_AUTH_USER'],$_SERVER['PHP_AUTH_PW']) = explode(':',base64_decode($_GET['auth']),2);
|
||||
}
|
||||
return egw_digest_auth::autocreate_session_callback($account);
|
||||
}
|
||||
|
||||
$GLOBALS['egw_info'] = array(
|
||||
'flags' => array(
|
||||
'disable_Template_class' => True,
|
||||
'noheader' => True,
|
||||
'currentapp' => preg_match('|/remote.php/webdav/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!
|
||||
)
|
||||
);
|
||||
require_once(__DIR__.'/phpgwapi/inc/class.egw_digest_auth.inc.php');
|
||||
|
||||
// if you move this file somewhere else, you need to adapt the path to the header!
|
||||
try
|
||||
{
|
||||
include(__DIR__.'/header.inc.php');
|
||||
}
|
||||
catch (egw_exception_no_permission_app $e)
|
||||
{
|
||||
if (isset($GLOBALS['egw_info']['user']['apps']['filemanager']))
|
||||
{
|
||||
$GLOBALS['egw_info']['currentapp'] = 'filemanager';
|
||||
}
|
||||
elseif (isset($GLOBALS['egw_info']['user']['apps']['sitemgr-link']))
|
||||
{
|
||||
$GLOBALS['egw_info']['currentapp'] = 'sitemgr-link';
|
||||
}
|
||||
else
|
||||
{
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
//$headertime = microtime(true);
|
||||
|
||||
// temporary mount ownCloud default /clientsync as /home/$user, if not explicitly mounted
|
||||
// so ownCloud dir contains users home-dir by default
|
||||
if (strpos($_SERVER['REQUEST_URI'],'/remote.php/webdav/clientsync') !== false &&
|
||||
($fstab=egw_vfs::mount()) && !isset($fstab['/clientsync']))
|
||||
{
|
||||
$is_root_backup = egw_vfs::$is_root;
|
||||
egw_vfs::$is_root = true;
|
||||
$ok = egw_vfs::mount($url='vfs://default/home/$user', $clientsync='/clientsync', null, false);
|
||||
egw_vfs::$is_root = $is_root_backup;
|
||||
//error_log("mounting ownCloud default '$clientsync' as '$url' ".($ok ? 'successful' : 'failed!'));
|
||||
}
|
||||
|
||||
// webdav is stateless: we dont need to keep the session open, it only blocks other calls to same basic-auth session
|
||||
$GLOBALS['egw']->session->commit_session();
|
||||
|
||||
$webdav_server = new vfs_webdav_server();
|
||||
$webdav_server->ServeRequest('/webdav');
|
||||
//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));
|
Loading…
Reference in New Issue
Block a user