* Fix issues with brackets in directory names
* Update dependencies
This commit is contained in:
parent
49b4ec839c
commit
97cbdd15c9
|
@ -43,6 +43,7 @@ class ErrorManager
|
||||||
*/
|
*/
|
||||||
const PRODUCTION = 1;
|
const PRODUCTION = 1;
|
||||||
const DEVELOPMENT = 2;
|
const DEVELOPMENT = 2;
|
||||||
|
const CLI_DEVELOPMENT = 4;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Term colors
|
* Term colors
|
||||||
|
@ -269,11 +270,22 @@ class ErrorManager
|
||||||
|
|
||||||
$html_report = null;
|
$html_report = null;
|
||||||
|
|
||||||
if (self::$enabled != self::PRODUCTION || self::$email_errors) {
|
if (self::$enabled & self::DEVELOPMENT || self::$email_errors) {
|
||||||
$html_report = self::htmlReport($report);
|
$html_report = self::htmlReport($report);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PHP_SAPI == 'cli' || 0 === strpos($_SERVER['HTTP_USER_AGENT'] ?? '', 'curl/'))
|
$is_curl = 0 === strpos($_SERVER['HTTP_USER_AGENT'] ?? '', 'curl/');
|
||||||
|
$is_cli = PHP_SAPI == 'cli';
|
||||||
|
|
||||||
|
if (!$is_cli) {
|
||||||
|
http_response_code(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($is_curl && !headers_sent()) {
|
||||||
|
header('Content-Type: text/plain; charset=utf-8', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($is_cli || $is_curl) && (self::$enabled & self::DEVELOPMENT || self::$enabled & self::CLI_DEVELOPMENT))
|
||||||
{
|
{
|
||||||
foreach ($report->errors as $e)
|
foreach ($report->errors as $e)
|
||||||
{
|
{
|
||||||
|
@ -315,7 +327,11 @@ class ErrorManager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (self::$enabled == self::PRODUCTION)
|
else if (($is_cli || $is_curl) && self::$enabled & self::PRODUCTION) {
|
||||||
|
self::termPrint(' /!\\ An internal server error occurred ', self::RED);
|
||||||
|
self::termPrint(' Error reference was: ' . $report->context->id, self::YELLOW);
|
||||||
|
}
|
||||||
|
else if (self::$enabled & self::PRODUCTION)
|
||||||
{
|
{
|
||||||
self::htmlProduction($report);
|
self::htmlProduction($report);
|
||||||
}
|
}
|
||||||
|
@ -520,7 +536,7 @@ class ErrorManager
|
||||||
'date' => date(DATE_ATOM),
|
'date' => date(DATE_ATOM),
|
||||||
'os' => PHP_OS,
|
'os' => PHP_OS,
|
||||||
'language' => 'PHP ' . PHP_VERSION,
|
'language' => 'PHP ' . PHP_VERSION,
|
||||||
'environment' => self::$enabled == self::DEVELOPMENT ? 'development' : 'production:' . self::$enabled,
|
'environment' => self::$enabled & self::DEVELOPMENT ? 'development' : 'production:' . self::$enabled,
|
||||||
'php_sapi' => PHP_SAPI,
|
'php_sapi' => PHP_SAPI,
|
||||||
'remote_ip' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null,
|
'remote_ip' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null,
|
||||||
'http_method' => isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : null,
|
'http_method' => isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : null,
|
||||||
|
@ -718,6 +734,8 @@ class ErrorManager
|
||||||
/**
|
/**
|
||||||
* Enable error manager
|
* Enable error manager
|
||||||
* @param integer $type Type of error management (ErrorManager::PRODUCTION or ErrorManager::DEVELOPMENT)
|
* @param integer $type Type of error management (ErrorManager::PRODUCTION or ErrorManager::DEVELOPMENT)
|
||||||
|
* You can also use ErrorManager::PRODUCTION | ErrorManager::CLI_DEVELOPMENT to get error messages in CLI but still hide errors
|
||||||
|
* on web front-end.
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
static public function enable($type = self::DEVELOPMENT)
|
static public function enable($type = self::DEVELOPMENT)
|
||||||
|
@ -734,9 +752,9 @@ class ErrorManager
|
||||||
ini_set('log_errors', false);
|
ini_set('log_errors', false);
|
||||||
ini_set('html_errors', false);
|
ini_set('html_errors', false);
|
||||||
ini_set('zend.exception_ignore_args', false); // We want to get the args in exceptions (since PHP 7.4)
|
ini_set('zend.exception_ignore_args', false); // We want to get the args in exceptions (since PHP 7.4)
|
||||||
error_reporting($type == self::DEVELOPMENT ? -1 : E_ALL & ~E_DEPRECATED & ~E_STRICT);
|
error_reporting($type & self::DEVELOPMENT ? -1 : E_ALL & ~E_DEPRECATED & ~E_STRICT);
|
||||||
|
|
||||||
if ($type == self::DEVELOPMENT && PHP_SAPI != 'cli')
|
if ($type & self::DEVELOPMENT && PHP_SAPI != 'cli')
|
||||||
{
|
{
|
||||||
self::setHtmlHeader('<!DOCTYPE html><meta charset="utf-8" /><style type="text/css">
|
self::setHtmlHeader('<!DOCTYPE html><meta charset="utf-8" /><style type="text/css">
|
||||||
body { font-family: sans-serif; } * { margin: 0; padding: 0; }
|
body { font-family: sans-serif; } * { margin: 0; padding: 0; }
|
||||||
|
@ -760,7 +778,7 @@ class ErrorManager
|
||||||
|
|
||||||
set_error_handler([__CLASS__, 'errorHandler']);
|
set_error_handler([__CLASS__, 'errorHandler']);
|
||||||
|
|
||||||
if ($type == self::DEVELOPMENT)
|
if ($type & self::DEVELOPMENT)
|
||||||
{
|
{
|
||||||
self::startTimer('_global');
|
self::startTimer('_global');
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,7 @@ abstract class NextCloud
|
||||||
self::PROP_NC_DDC,
|
self::PROP_NC_DDC,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
protected string $prefix = '';
|
||||||
protected string $root_url;
|
protected string $root_url;
|
||||||
protected Server $server;
|
protected Server $server;
|
||||||
protected AbstractStorage $storage;
|
protected AbstractStorage $storage;
|
||||||
|
@ -326,6 +327,8 @@ abstract class NextCloud
|
||||||
{
|
{
|
||||||
$this->requireAuth();
|
$this->requireAuth();
|
||||||
|
|
||||||
|
$base_uri = null;
|
||||||
|
|
||||||
// Find out which route we are using and replace URI
|
// Find out which route we are using and replace URI
|
||||||
foreach (self::ROUTES as $route => $method) {
|
foreach (self::ROUTES as $route => $method) {
|
||||||
if ($method != 'webdav') {
|
if ($method != 'webdav') {
|
||||||
|
@ -338,6 +341,10 @@ abstract class NextCloud
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$base_uri) {
|
||||||
|
throw new Exception('Invalid WebDAV URL', 404);
|
||||||
|
}
|
||||||
|
|
||||||
// Android app is using "/remote.php/dav/files/user//" as root
|
// Android app is using "/remote.php/dav/files/user//" as root
|
||||||
// so let's alias that as well
|
// so let's alias that as well
|
||||||
// ownCloud Android is requesting just /dav/files/
|
// ownCloud Android is requesting just /dav/files/
|
||||||
|
@ -345,6 +352,8 @@ abstract class NextCloud
|
||||||
$base_uri = $match[0];
|
$base_uri = $match[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->server->prefix = $this->prefix;
|
||||||
|
|
||||||
$this->server->setBaseURI($base_uri);
|
$this->server->setBaseURI($base_uri);
|
||||||
$this->server->route($uri);
|
$this->server->route($uri);
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,6 +92,11 @@ class Server
|
||||||
*/
|
*/
|
||||||
public string $original_uri;
|
public string $original_uri;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prefix, if you want to force some clients inside a path, eg. '/documents/'
|
||||||
|
*/
|
||||||
|
public string $prefix = '';
|
||||||
|
|
||||||
protected AbstractStorage $storage;
|
protected AbstractStorage $storage;
|
||||||
|
|
||||||
public function setStorage(AbstractStorage $storage)
|
public function setStorage(AbstractStorage $storage)
|
||||||
|
@ -109,6 +114,15 @@ class Server
|
||||||
$this->base_uri = rtrim($uri, '/') . '/';
|
$this->base_uri = rtrim($uri, '/') . '/';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function _prefix(string $uri): string
|
||||||
|
{
|
||||||
|
if (!$this->prefix) {
|
||||||
|
return $uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rtrim(rtrim($this->prefix, '/') . '/' . ltrim($uri, '/'), '/');
|
||||||
|
}
|
||||||
|
|
||||||
protected function html_directory(string $uri, iterable $list): ?string
|
protected function html_directory(string $uri, iterable $list): ?string
|
||||||
{
|
{
|
||||||
// Not a file: let's serve a directory listing if you are browsing with a web browser
|
// Not a file: let's serve a directory listing if you are browsing with a web browser
|
||||||
|
@ -187,6 +201,8 @@ class Server
|
||||||
throw new Exception('We can only delete to infinity', 400);
|
throw new Exception('We can only delete to infinity', 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$uri = $this->_prefix($uri);
|
||||||
|
|
||||||
$this->checkLock($uri);
|
$this->checkLock($uri);
|
||||||
|
|
||||||
$this->storage->delete($uri);
|
$this->storage->delete($uri);
|
||||||
|
@ -233,6 +249,8 @@ class Server
|
||||||
$hash = bin2hex(base64_decode($_SERVER['HTTP_CONTENT_MD5']));
|
$hash = bin2hex(base64_decode($_SERVER['HTTP_CONTENT_MD5']));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$uri = $this->_prefix($uri);
|
||||||
|
|
||||||
$this->checkLock($uri);
|
$this->checkLock($uri);
|
||||||
|
|
||||||
if (!empty($_SERVER['HTTP_IF_MATCH'])) {
|
if (!empty($_SERVER['HTTP_IF_MATCH'])) {
|
||||||
|
@ -271,6 +289,8 @@ class Server
|
||||||
|
|
||||||
public function http_head(string $uri, array &$props = []): ?string
|
public function http_head(string $uri, array &$props = []): ?string
|
||||||
{
|
{
|
||||||
|
$uri = $this->_prefix($uri);
|
||||||
|
|
||||||
$requested_props = self::BASIC_PROPERTIES;
|
$requested_props = self::BASIC_PROPERTIES;
|
||||||
$requested_props[] = 'DAV::getetag';
|
$requested_props[] = 'DAV::getetag';
|
||||||
|
|
||||||
|
@ -325,6 +345,8 @@ class Server
|
||||||
$props = [];
|
$props = [];
|
||||||
$this->http_head($uri, $props);
|
$this->http_head($uri, $props);
|
||||||
|
|
||||||
|
$uri = $this->_prefix($uri);
|
||||||
|
|
||||||
$is_collection = !empty($props['DAV::resourcetype']) && $props['DAV::resourcetype'] == 'collection';
|
$is_collection = !empty($props['DAV::resourcetype']) && $props['DAV::resourcetype'] == 'collection';
|
||||||
$out = '';
|
$out = '';
|
||||||
|
|
||||||
|
@ -523,6 +545,8 @@ class Server
|
||||||
|
|
||||||
protected function _http_copymove(string $uri, string $method): ?string
|
protected function _http_copymove(string $uri, string $method): ?string
|
||||||
{
|
{
|
||||||
|
$uri = $this->_prefix($uri);
|
||||||
|
|
||||||
$destination = $_SERVER['HTTP_DESTINATION'] ?? null;
|
$destination = $_SERVER['HTTP_DESTINATION'] ?? null;
|
||||||
$depth = $_SERVER['HTTP_DEPTH'] ?? 1;
|
$depth = $_SERVER['HTTP_DEPTH'] ?? 1;
|
||||||
|
|
||||||
|
@ -581,6 +605,7 @@ class Server
|
||||||
throw new Exception('Unsupported body for MKCOL', 415);
|
throw new Exception('Unsupported body for MKCOL', 415);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$uri = $this->_prefix($uri);
|
||||||
$this->storage->mkcol($uri);
|
$this->storage->mkcol($uri);
|
||||||
|
|
||||||
http_response_code(201);
|
http_response_code(201);
|
||||||
|
@ -656,6 +681,7 @@ class Server
|
||||||
// We only support depth of 0 and 1
|
// We only support depth of 0 and 1
|
||||||
$depth = isset($_SERVER['HTTP_DEPTH']) && empty($_SERVER['HTTP_DEPTH']) ? 0 : 1;
|
$depth = isset($_SERVER['HTTP_DEPTH']) && empty($_SERVER['HTTP_DEPTH']) ? 0 : 1;
|
||||||
|
|
||||||
|
$uri = $this->_prefix($uri);
|
||||||
$body = file_get_contents('php://input');
|
$body = file_get_contents('php://input');
|
||||||
|
|
||||||
if (false !== strpos($body, '<!DOCTYPE ')) {
|
if (false !== strpos($body, '<!DOCTYPE ')) {
|
||||||
|
@ -756,7 +782,12 @@ class Server
|
||||||
foreach ($items as $uri => $item) {
|
foreach ($items as $uri => $item) {
|
||||||
$e = '<d:response>';
|
$e = '<d:response>';
|
||||||
|
|
||||||
$path = '/' . str_replace('%2F', '/', rawurlencode(trim($this->base_uri . $uri, '/')));
|
if ($this->prefix) {
|
||||||
|
$uri = substr($uri, strlen($this->prefix));
|
||||||
|
}
|
||||||
|
|
||||||
|
$uri = trim(rtrim($this->base_uri, '/') . '/' . ltrim($uri, '/'), '/');
|
||||||
|
$path = '/' . str_replace('%2F', '/', rawurlencode($uri));
|
||||||
|
|
||||||
if (($item['DAV::resourcetype'] ?? null) == 'collection') {
|
if (($item['DAV::resourcetype'] ?? null) == 'collection') {
|
||||||
$path .= '/';
|
$path .= '/';
|
||||||
|
@ -929,6 +960,7 @@ class Server
|
||||||
|
|
||||||
public function http_proppatch(string $uri): ?string
|
public function http_proppatch(string $uri): ?string
|
||||||
{
|
{
|
||||||
|
$uri = $this->_prefix($uri);
|
||||||
$this->checkLock($uri);
|
$this->checkLock($uri);
|
||||||
|
|
||||||
$body = file_get_contents('php://input');
|
$body = file_get_contents('php://input');
|
||||||
|
@ -948,6 +980,7 @@ class Server
|
||||||
|
|
||||||
public function http_lock(string $uri): ?string
|
public function http_lock(string $uri): ?string
|
||||||
{
|
{
|
||||||
|
$uri = $this->_prefix($uri);
|
||||||
// We don't use this currently, but maybe later?
|
// We don't use this currently, but maybe later?
|
||||||
//$depth = !empty($this->_SERVER['HTTP_DEPTH']) ? 1 : 0;
|
//$depth = !empty($this->_SERVER['HTTP_DEPTH']) ? 1 : 0;
|
||||||
//$timeout = isset($_SERVER['HTTP_TIMEOUT']) ? explode(',', $_SERVER['HTTP_TIMEOUT']) : [];
|
//$timeout = isset($_SERVER['HTTP_TIMEOUT']) ? explode(',', $_SERVER['HTTP_TIMEOUT']) : [];
|
||||||
|
@ -1039,6 +1072,7 @@ class Server
|
||||||
|
|
||||||
public function http_unlock(string $uri): ?string
|
public function http_unlock(string $uri): ?string
|
||||||
{
|
{
|
||||||
|
$uri = $this->_prefix($uri);
|
||||||
$token = $this->getLockToken();
|
$token = $this->getLockToken();
|
||||||
|
|
||||||
if (!$token) {
|
if (!$token) {
|
||||||
|
@ -1169,6 +1203,7 @@ class Server
|
||||||
}
|
}
|
||||||
|
|
||||||
$uri = substr($uri, strlen($this->base_uri));
|
$uri = substr($uri, strlen($this->base_uri));
|
||||||
|
$uri = $this->_prefix($uri);
|
||||||
return $uri;
|
return $uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,11 +51,11 @@ class Storage extends AbstractStorage
|
||||||
|
|
||||||
public function list(string $uri, ?array $properties): iterable
|
public function list(string $uri, ?array $properties): iterable
|
||||||
{
|
{
|
||||||
$dirs = glob($this->users->current()->path . $uri . '/*', \GLOB_ONLYDIR);
|
$dirs = self::glob($this->users->current()->path . $uri, '/*', \GLOB_ONLYDIR);
|
||||||
$dirs = array_map('basename', $dirs);
|
$dirs = array_map('basename', $dirs);
|
||||||
natcasesort($dirs);
|
natcasesort($dirs);
|
||||||
|
|
||||||
$files = glob($this->users->current()->path . $uri . '/*');
|
$files = self::glob($this->users->current()->path . $uri, '/*');
|
||||||
$files = array_map('basename', $files);
|
$files = array_map('basename', $files);
|
||||||
$files = array_diff($files, $dirs);
|
$files = array_diff($files, $dirs);
|
||||||
natcasesort($files);
|
natcasesort($files);
|
||||||
|
@ -291,7 +291,7 @@ class Storage extends AbstractStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_dir($target)) {
|
if (is_dir($target)) {
|
||||||
foreach (glob($target . '/*') as $file) {
|
foreach (self::glob($target, '/*') as $file) {
|
||||||
$this->delete(substr($file, strlen($this->users->current()->path)));
|
$this->delete(substr($file, strlen($this->users->current()->path)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,12 +421,18 @@ class Storage extends AbstractStorage
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static protected function glob(string $path, string $pattern = '', int $flags = 0): array
|
||||||
|
{
|
||||||
|
$path = preg_replace('/[\*\?\[\]]/', '\\\\$0', $path);
|
||||||
|
return glob($path . $pattern, $flags);
|
||||||
|
}
|
||||||
|
|
||||||
static public function getDirectorySize(string $path): int
|
static public function getDirectorySize(string $path): int
|
||||||
{
|
{
|
||||||
$total = 0;
|
$total = 0;
|
||||||
$path = rtrim($path, '/');
|
$path = rtrim($path, '/');
|
||||||
|
|
||||||
foreach (glob($path . '/*', GLOB_NOSORT) as $f) {
|
foreach (self::glob($path, '/*', GLOB_NOSORT) as $f) {
|
||||||
if (is_dir($f)) {
|
if (is_dir($f)) {
|
||||||
$total += self::getDirectorySize($f);
|
$total += self::getDirectorySize($f);
|
||||||
}
|
}
|
||||||
|
@ -440,7 +446,7 @@ class Storage extends AbstractStorage
|
||||||
|
|
||||||
static public function deleteDirectory(string $path): void
|
static public function deleteDirectory(string $path): void
|
||||||
{
|
{
|
||||||
foreach (glob($path . '/*', GLOB_NOSORT) as $f) {
|
foreach (self::glob($path, '/*', GLOB_NOSORT) as $f) {
|
||||||
if (is_dir($f)) {
|
if (is_dir($f)) {
|
||||||
self::deleteDirectory($f);
|
self::deleteDirectory($f);
|
||||||
@rmdir($f);
|
@rmdir($f);
|
||||||
|
@ -458,7 +464,7 @@ class Storage extends AbstractStorage
|
||||||
$last = 0;
|
$last = 0;
|
||||||
$path = rtrim($path, '/');
|
$path = rtrim($path, '/');
|
||||||
|
|
||||||
foreach (glob($path . '/*', GLOB_NOSORT) as $f) {
|
foreach (self::glob($path, '/*', GLOB_NOSORT) as $f) {
|
||||||
if (is_dir($f)) {
|
if (is_dir($f)) {
|
||||||
$m = self::getDirectoryMTime($f);
|
$m = self::getDirectoryMTime($f);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue