Files
deskhub/DeskHub-Webseite/tests/fixtures/webdav_server.php
T
2026-10-19 18:05:51 +00:00

74 lines
3.3 KiB
PHP

<?php
/**
* Minimaler WebDAV-Server für Tests (Router für "php -S"). Speichert unter dem Ordner aus DAV_ROOT, URL-Präfix /dav,
* Basic-Anmeldung nas / geheim. Kennt MKCOL, PUT, PROPFIND, HEAD, GET, DELETE. Gibt es die Datei ".truncate" im Wurzelordner,
* speichert PUT nur die Hälfte (simuliert einen abgebrochenen Upload).
*/
$root = rtrim((string) getenv('DAV_ROOT'), '/\\');
$method = $_SERVER['REQUEST_METHOD'];
$path = rawurldecode((string) parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH));
if (($_SERVER['PHP_AUTH_USER'] ?? '') !== 'nas' || ($_SERVER['PHP_AUTH_PW'] ?? '') !== (getenv('DAV_PASS') ?: 'geheim')) {
header('WWW-Authenticate: Basic realm="NAS"');
http_response_code(401);
exit;
}
if (!str_starts_with($path, '/dav')) { http_response_code(404); exit; }
$rel = trim(substr($path, 4), '/');
if (str_contains($rel, '..')) { http_response_code(400); exit; }
$file = $root . ($rel === '' ? '' : '/' . $rel);
$entry = function (string $href, string $name, ?string $full) {
$isDir = $full === null || is_dir($full);
$size = $isDir ? '' : '<D:getcontentlength>' . filesize($full) . '</D:getcontentlength>';
$mod = $full !== null ? gmdate('D, d M Y H:i:s', filemtime($full)) . ' GMT' : '';
return '<D:response><D:href>' . htmlspecialchars($href) . '</D:href><D:propstat><D:prop>' . $size
. '<D:getlastmodified>' . $mod . '</D:getlastmodified><D:resourcetype>' . ($isDir ? '<D:collection/>' : '') . '</D:resourcetype></D:prop>'
. '<D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>';
};
switch ($method) {
case 'MKCOL':
if (file_exists($file)) { http_response_code(405); exit; }
if (!is_dir(dirname($file))) { http_response_code(409); exit; }
mkdir($file, 0755);
http_response_code(201);
break;
case 'PUT':
if (!is_dir(dirname($file))) { http_response_code(409); exit; }
$data = (string) file_get_contents('php://input');
if (file_exists($root . '/.truncate')) $data = substr($data, 0, (int) (strlen($data) / 2));
$existed = file_exists($file);
file_put_contents($file, $data);
http_response_code($existed ? 204 : 201);
break;
case 'DELETE':
if (!file_exists($file)) { http_response_code(404); exit; }
is_dir($file) ? @rmdir($file) : unlink($file);
http_response_code(204);
break;
case 'HEAD':
case 'GET':
if (!is_file($file)) { http_response_code(404); exit; }
header('Content-Length: ' . filesize($file));
if ($method === 'GET') readfile($file);
break;
case 'PROPFIND':
if (!file_exists($file) && $rel !== '') { http_response_code(404); exit; }
$xml = '<?xml version="1.0" encoding="utf-8"?><D:multistatus xmlns:D="DAV:">';
$xml .= $entry($path, basename($rel), $rel === '' ? null : $file);
if (is_dir($file) && ($_SERVER['HTTP_DEPTH'] ?? '1') !== '0') {
foreach (scandir($file) ?: [] as $e) {
if ($e === '.' || $e === '..' || $e[0] === '.') continue;
$xml .= $entry(rtrim($path, '/') . '/' . rawurlencode($e), $e, $file . '/' . $e);
}
}
$xml .= '</D:multistatus>';
http_response_code(207);
header('Content-Type: application/xml; charset=utf-8');
echo $xml;
break;
default:
http_response_code(405);
}