";
$html .= "";
/* Start of generating actions */
$html .= $this->generateFooter();
return $html;
}
/**
* Generates the first block of HTML, including the
";
return $html;
}
/**
* Generates the page footer.
*
* Returns html.
*
* @return string
*/
function generateFooter() {
$version = DAV\Version::VERSION;
return <<Generated by SabreDAV $version (c)2007-2016 http://sabre.io/
HTML;
}
/**
* This method is used to generate the 'actions panel' output for
* collections.
*
* This specifically generates the interfaces for creating new files, and
* creating new directories.
*
* @param DAV\INode $node
* @param mixed $output
* @param string $path
* @return void
*/
function htmlActionsPanel(DAV\INode $node, &$output, $path) {
if (!$node instanceof DAV\ICollection)
return;
// We also know fairly certain that if an object is a non-extended
// SimpleCollection, we won't need to show the panel either.
if (get_class($node) === 'Sabre\\DAV\\SimpleCollection')
return;
ob_start();
echo '
';
$output .= ob_get_clean();
}
/**
* This method takes a path/name of an asset and turns it into url
* suiteable for http access.
*
* @param string $assetName
* @return string
*/
protected function getAssetUrl($assetName) {
return $this->server->getBaseUri() . '?sabreAction=asset&assetName=' . urlencode($assetName);
}
/**
* This method returns a local pathname to an asset.
*
* @param string $assetName
* @return string
* @throws DAV\Exception\NotFound
*/
protected function getLocalAssetPath($assetName) {
$assetDir = __DIR__ . '/assets/';
$path = $assetDir . $assetName;
// Making sure people aren't trying to escape from the base path.
$path = str_replace('\\', '/', $path);
if (strpos($path, '/../') !== false || strrchr($path, '/') === '/..') {
throw new DAV\Exception\NotFound('Path does not exist, or escaping from the base path was detected');
}
if (strpos(realpath($path), realpath($assetDir)) === 0 && file_exists($path)) {
return $path;
}
throw new DAV\Exception\NotFound('Path does not exist, or escaping from the base path was detected');
}
/**
* This method reads an asset from disk and generates a full http response.
*
* @param string $assetName
* @return void
*/
protected function serveAsset($assetName) {
$assetPath = $this->getLocalAssetPath($assetName);
// Rudimentary mime type detection
$mime = 'application/octet-stream';
$map = [
'ico' => 'image/vnd.microsoft.icon',
'png' => 'image/png',
'css' => 'text/css',
];
$ext = substr($assetName, strrpos($assetName, '.') + 1);
if (isset($map[$ext])) {
$mime = $map[$ext];
}
$this->server->httpResponse->setHeader('Content-Type', $mime);
$this->server->httpResponse->setHeader('Content-Length', filesize($assetPath));
$this->server->httpResponse->setHeader('Cache-Control', 'public, max-age=1209600');
$this->server->httpResponse->setStatus(200);
$this->server->httpResponse->setBody(fopen($assetPath, 'r'));
}
/**
* Sort helper function: compares two directory entries based on type and
* display name. Collections sort above other types.
*
* @param array $a
* @param array $b
* @return int
*/
protected function compareNodes($a, $b) {
$typeA = (isset($a['{DAV:}resourcetype']))
? (in_array('{DAV:}collection', $a['{DAV:}resourcetype']->getValue()))
: false;
$typeB = (isset($b['{DAV:}resourcetype']))
? (in_array('{DAV:}collection', $b['{DAV:}resourcetype']->getValue()))
: false;
// If same type, sort alphabetically by filename:
if ($typeA === $typeB) {
return strnatcasecmp($a['displayPath'], $b['displayPath']);
}
return (($typeA < $typeB) ? 1 : -1);
}
/**
* Maps a resource type to a human-readable string and icon.
*
* @param array $resourceTypes
* @param INode $node
* @return array
*/
private function mapResourceType(array $resourceTypes, $node) {
if (!$resourceTypes) {
if ($node instanceof DAV\IFile) {
return [
'string' => 'File',
'icon' => 'file',
];
} else {
return [
'string' => 'Unknown',
'icon' => 'cog',
];
}
}
$types = [
'{http://calendarserver.org/ns/}calendar-proxy-write' => [
'string' => 'Proxy-Write',
'icon' => 'people',
],
'{http://calendarserver.org/ns/}calendar-proxy-read' => [
'string' => 'Proxy-Read',
'icon' => 'people',
],
'{urn:ietf:params:xml:ns:caldav}schedule-outbox' => [
'string' => 'Outbox',
'icon' => 'inbox',
],
'{urn:ietf:params:xml:ns:caldav}schedule-inbox' => [
'string' => 'Inbox',
'icon' => 'inbox',
],
'{urn:ietf:params:xml:ns:caldav}calendar' => [
'string' => 'Calendar',
'icon' => 'calendar',
],
'{http://calendarserver.org/ns/}shared-owner' => [
'string' => 'Shared',
'icon' => 'calendar',
],
'{http://calendarserver.org/ns/}subscribed' => [
'string' => 'Subscription',
'icon' => 'calendar',
],
'{urn:ietf:params:xml:ns:carddav}directory' => [
'string' => 'Directory',
'icon' => 'globe',
],
'{urn:ietf:params:xml:ns:carddav}addressbook' => [
'string' => 'Address book',
'icon' => 'book',
],
'{DAV:}principal' => [
'string' => 'Principal',
'icon' => 'person',
],
'{DAV:}collection' => [
'string' => 'Collection',
'icon' => 'folder',
],
];
$info = [
'string' => [],
'icon' => 'cog',
];
foreach ($resourceTypes as $k => $resourceType) {
if (isset($types[$resourceType])) {
$info['string'][] = $types[$resourceType]['string'];
} else {
$info['string'][] = $resourceType;
}
}
foreach ($types as $key => $resourceInfo) {
if (in_array($key, $resourceTypes)) {
$info['icon'] = $resourceInfo['icon'];
break;
}
}
$info['string'] = implode(', ', $info['string']);
return $info;
}
/**
* Draws a table row for a property
*
* @param string $name
* @param mixed $value
* @return string
*/
private function drawPropertyRow($name, $value) {
$html = new HtmlOutputHelper(
$this->server->getBaseUri(),
$this->server->xml->namespaceMap
);
return "
" . $html->xmlName($name) . "
" . $this->drawPropertyValue($html, $value) . "
";
}
/**
* Draws a table row for a property
*
* @param HtmlOutputHelper $html
* @param mixed $value
* @return string
*/
private function drawPropertyValue($html, $value) {
if (is_scalar($value)) {
return $html->h($value);
} elseif ($value instanceof HtmlOutput) {
return $value->toHtml($html);
} elseif ($value instanceof \Sabre\Xml\XmlSerializable) {
// There's no default html output for this property, we're going
// to output the actual xml serialization instead.
$xml = $this->server->xml->write('{DAV:}root', $value, $this->server->getBaseUri());
// removing first and last line, as they contain our root
// element.
$xml = explode("\n", $xml);
$xml = array_slice($xml, 2, -2);
return "
" . $html->h(implode("\n", $xml)) . "
";
} else {
return "unknown";
}
}
/**
* Returns a plugin name.
*
* Using this name other plugins will be able to access other plugins;
* using \Sabre\DAV\Server::getPlugin
*
* @return string
*/
function getPluginName() {
return 'browser';
}
/**
* Returns a bunch of meta-data about the plugin.
*
* Providing this information is optional, and is mainly displayed by the
* Browser plugin.
*
* The description key in the returned array may contain html and will not
* be sanitized.
*
* @return array
*/
function getPluginInfo() {
return [
'name' => $this->getPluginName(),
'description' => 'Generates HTML indexes and debug information for your sabre/dav server',
'link' => 'http://sabre.io/dav/browser-plugin/',
];
}
}