diff --git a/customer_domains.php b/customer_domains.php index 07dfd09c..dfc5b884 100644 --- a/customer_domains.php +++ b/customer_domains.php @@ -181,7 +181,8 @@ if ($page == 'overview' || $page == 'domains') { $openbasedir = [ 0 => lng('domain.docroot'), - 1 => lng('domain.homedir') + 1 => lng('domain.homedir'), + 2 => lng('domain.docparent') ]; $pathSelect = FileDir::makePathfield($userinfo['documentroot'], $userinfo['guid'], $userinfo['guid']); @@ -302,7 +303,8 @@ if ($page == 'overview' || $page == 'domains') { $openbasedir = [ 0 => lng('domain.docroot'), - 1 => lng('domain.homedir') + 1 => lng('domain.homedir'), + 2 => lng('domain.docparent') ]; // create serveralias options diff --git a/lib/Froxlor/Api/Commands/SubDomains.php b/lib/Froxlor/Api/Commands/SubDomains.php index c8ec1862..29f43a4f 100644 --- a/lib/Froxlor/Api/Commands/SubDomains.php +++ b/lib/Froxlor/Api/Commands/SubDomains.php @@ -62,7 +62,7 @@ class SubDomains extends ApiCommand implements ResourceEntity * optional, overwrites path value with an URL to generate a redirect, alternatively use the path * parameter also for URLs * @param int $openbasedir_path - * optional, either 0 for domains-docroot or 1 for customers-homedir + * optional, either 0 for domains-docroot, 1 for customers-homedir or 2 for parent-directory of domains-docroot * @param int $phpsettingid * optional, php-settings-id, if empty the $domain value is used * @param int $redirectcode @@ -202,7 +202,7 @@ class SubDomains extends ApiCommand implements ResourceEntity $_doredirect = false; $path = $this->validateDomainDocumentRoot($path, $url, $customer, $completedomain, $_doredirect); - if ($openbasedir_path != 1) { + if ($openbasedir_path > 2 && $openbasedir_path < 0) { $openbasedir_path = 0; } @@ -583,7 +583,7 @@ class SubDomains extends ApiCommand implements ResourceEntity * @param bool $isemaildomain * optional * @param int $openbasedir_path - * optional, either 0 for domains-docroot or 1 for customers-homedir + * optional, either 0 for domains-docroot, 1 for customers-homedir or 2 for parent-directory of domains-docroot * @param int $phpsettingid * optional, php-settings-id, if empty the $domain value is used * @param int $redirectcode @@ -704,7 +704,7 @@ class SubDomains extends ApiCommand implements ResourceEntity } // check changes of openbasedir-path variable - if ($openbasedir_path != 1) { + if ($openbasedir_path > 2 && $openbasedir_path < 0) { $openbasedir_path = 0; } @@ -957,7 +957,7 @@ class SubDomains extends ApiCommand implements ResourceEntity LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` `pd` ON `pd`.`id`=`d`.`parentdomainid` WHERE `d`.`customerid` IN (" . implode(', ', $customer_ids) . ") AND `d`.`email_only` = '0' - AND `d`.`id` NOT IN (" . implode(', ', $customer_stdsubs) . ")" . $this->getSearchWhere($query_fields, true) . " GROUP BY `d`.`id` ORDER BY `parentdomainname` " . $this->getOrderBy(true) . $this->getLimit()); + AND `d`.`id` NOT IN (" . implode(', ', $customer_stdsubs) . ")" . $this->getSearchWhere($query_fields, true) . " GROUP BY `d`.`id` ORDER BY `parentdomainname` ASC, `d`.`parentdomainid` ASC " . $this->getOrderBy(true) . $this->getLimit()); $result = []; Database::pexecute($domains_stmt, $query_fields, true, true); diff --git a/lib/Froxlor/Cron/Http/Apache.php b/lib/Froxlor/Cron/Http/Apache.php index 82b9e813..6a8504f2 100644 --- a/lib/Froxlor/Cron/Http/Apache.php +++ b/lib/Froxlor/Cron/Http/Apache.php @@ -994,6 +994,8 @@ class Apache extends HttpConfigBase if ($domain['openbasedir'] == '1') { if ($domain['openbasedir_path'] == '1' || strstr($domain['documentroot'], ":") !== false) { $_phpappendopenbasedir = Domain::appendOpenBasedirPath($domain['customerroot'], true); + } else if ($domain['openbasedir_path'] == '2' && strpos(dirname($domain['documentroot']).'/', $domain['customerroot']) !== false) { + $_phpappendopenbasedir = Domain::appendOpenBasedirPath(dirname($domain['documentroot']).'/', true); } else { $_phpappendopenbasedir = Domain::appendOpenBasedirPath($domain['documentroot'], true); } diff --git a/lib/Froxlor/Cron/Http/Php/Fcgid.php b/lib/Froxlor/Cron/Http/Php/Fcgid.php index 8add4866..cede6dac 100644 --- a/lib/Froxlor/Cron/Http/Php/Fcgid.php +++ b/lib/Froxlor/Cron/Http/Php/Fcgid.php @@ -172,6 +172,8 @@ class Fcgid if ($this->domain['openbasedir_path'] == '0' && strstr($this->domain['documentroot'], ":") === false) { $openbasedir = Domain::appendOpenBasedirPath($this->domain['documentroot'], true); + } else if ($this->domain['openbasedir_path'] == '2' && strpos(dirname($this->domain['documentroot']).'/', $this->domain['customerroot']) !== false) { + $openbasedir = Domain::appendOpenBasedirPath(dirname($this->domain['documentroot']).'/', true); } else { $openbasedir = Domain::appendOpenBasedirPath($this->domain['customerroot'], true); } diff --git a/lib/Froxlor/Cron/Http/Php/Fpm.php b/lib/Froxlor/Cron/Http/Php/Fpm.php index 6ed3fb1c..4ebfabb9 100644 --- a/lib/Froxlor/Cron/Http/Php/Fpm.php +++ b/lib/Froxlor/Cron/Http/Php/Fpm.php @@ -239,6 +239,8 @@ pm.max_children = 1 if ($this->domain['openbasedir_path'] == '0' && strstr($this->domain['documentroot'], ":") === false) { $openbasedir = Domain::appendOpenBasedirPath($this->domain['documentroot'], true); + } else if ($this->domain['openbasedir_path'] == '2' && strpos(dirname($this->domain['documentroot']).'/', $this->domain['customerroot']) !== false) { + $openbasedir = Domain::appendOpenBasedirPath(dirname($this->domain['documentroot']).'/', true); } else { $openbasedir = Domain::appendOpenBasedirPath($this->domain['customerroot'], true); } diff --git a/lib/Froxlor/UI/Callbacks/Domain.php b/lib/Froxlor/UI/Callbacks/Domain.php index 8479f94e..4ea22f7b 100644 --- a/lib/Froxlor/UI/Callbacks/Domain.php +++ b/lib/Froxlor/UI/Callbacks/Domain.php @@ -74,7 +74,11 @@ class Domain public static function domainExternalLinkInfo(array $attributes) { - $result = '' . $attributes['data'] . ''; + $result = ''; + if ($attributes['fields']['parentdomainid'] != 0) { + $result = ''; + } + $result .= '' . $attributes['data'] . ''; // check for statistics if parentdomainid==0 to show stats-link for customers if ((int)UI::getCurrentUser()['adminsession'] == 0 && $attributes['fields']['parentdomainid'] == 0) { $statsapp = 'webalizer'; diff --git a/lib/Froxlor/UI/Pagination.php b/lib/Froxlor/UI/Pagination.php index d7babfc4..656e864c 100644 --- a/lib/Froxlor/UI/Pagination.php +++ b/lib/Froxlor/UI/Pagination.php @@ -90,9 +90,11 @@ class Pagination } else { // add default ordering by given order if (!empty($default_sorting)) { - $this->sortfield = array_key_first($default_sorting); - $this->sortorder = array_shift($default_sorting) ?? $this->sortorder; - $this->addOrderBy($this->sortfield, $this->sortorder); + while (!empty($default_sorting)) { + $this->sortfield = array_key_first($default_sorting); + $this->sortorder = array_shift($default_sorting) ?? $this->sortorder; + $this->addOrderBy($this->sortfield, $this->sortorder); + } } // add default ordering by given fields if (count($fields) > 0 && empty($this->sortfield)) { diff --git a/lib/formfields/customer/domains/formfield.domains_add.php b/lib/formfields/customer/domains/formfield.domains_add.php index 7ed184a7..029516de 100644 --- a/lib/formfields/customer/domains/formfield.domains_add.php +++ b/lib/formfields/customer/domains/formfield.domains_add.php @@ -53,9 +53,10 @@ return [ ], 'path' => [ 'label' => lng('panel.path'), - 'desc' => (Settings::Get('panel.pathedit') != 'Dropdown' ? lng('panel.pathDescriptionSubdomain') : null), + 'desc' => (Settings::Get('panel.pathedit') != 'Dropdown' ? lng('panel.pathDescriptionSubdomain').(Settings::Get('system.documentroot_use_default_value') == 1 ? lng('panel.pathDescriptionEx') : '') : null), 'type' => $pathSelect['type'], 'select_var' => $pathSelect['select_var'] ?? '', + 'selected' => $pathSelect['value'], 'value' => $pathSelect['value'], 'note' => $pathSelect['note'] ?? '', ], diff --git a/lib/formfields/customer/domains/formfield.domains_edit.php b/lib/formfields/customer/domains/formfield.domains_edit.php index c3397358..2374029b 100644 --- a/lib/formfields/customer/domains/formfield.domains_edit.php +++ b/lib/formfields/customer/domains/formfield.domains_edit.php @@ -55,10 +55,12 @@ return [ ], 'path' => [ 'label' => lng('panel.path'), - 'desc' => (Settings::Get('panel.pathedit') != 'Dropdown' ? lng('panel.pathDescriptionSubdomain') : null) . (isset($pathSelect['note']) ? '
' . $pathSelect['value'] : ''), + 'desc' => (Settings::Get('panel.pathedit') != 'Dropdown' ? lng('panel.pathDescriptionSubdomain').(Settings::Get('system.documentroot_use_default_value') == 1 ? lng('panel.pathDescriptionEx') : '') : null), 'type' => $pathSelect['type'], 'select_var' => $pathSelect['value'], - 'selected' => $pathSelect['value'] + 'selected' => $pathSelect['value'], + 'value' => $pathSelect['value'], + 'note' => $pathSelect['note'] ?? '', ], 'url' => [ 'visible' => Settings::Get('panel.pathedit') == 'Dropdown', diff --git a/lib/formfields/customer/extras/formfield.backup.php b/lib/formfields/customer/extras/formfield.backup.php index da72834a..d6cdce7a 100644 --- a/lib/formfields/customer/extras/formfield.backup.php +++ b/lib/formfields/customer/extras/formfield.backup.php @@ -31,6 +31,7 @@ return [ 'desc' => lng('panel.backuppath.description') . '
' . (Settings::Get('panel.pathedit') != 'Dropdown' ? lng('panel.pathDescription') : null), 'type' => $pathSelect['type'], 'select_var' => $pathSelect['select_var'] ?? '', + 'selected' => $pathSelect['value'], 'value' => $pathSelect['value'], 'note' => $pathSelect['note'] ?? '', ], diff --git a/lib/formfields/customer/extras/formfield.htaccess_add.php b/lib/formfields/customer/extras/formfield.htaccess_add.php index ec85d4e1..22f9a79f 100644 --- a/lib/formfields/customer/extras/formfield.htaccess_add.php +++ b/lib/formfields/customer/extras/formfield.htaccess_add.php @@ -40,6 +40,7 @@ return [ 'desc' => (Settings::Get('panel.pathedit') != 'Dropdown' ? lng('panel.pathDescription') : null), 'type' => $pathSelect['type'], 'select_var' => $pathSelect['select_var'] ?? '', + 'selected' => $pathSelect['value'], 'value' => $pathSelect['value'], 'note' => $pathSelect['note'] ?? '', 'mandatory' => true diff --git a/lib/formfields/customer/extras/formfield.htpasswd_add.php b/lib/formfields/customer/extras/formfield.htpasswd_add.php index 58c6ba2c..6277cdcb 100644 --- a/lib/formfields/customer/extras/formfield.htpasswd_add.php +++ b/lib/formfields/customer/extras/formfield.htpasswd_add.php @@ -41,6 +41,7 @@ return [ 'desc' => (Settings::Get('panel.pathedit') != 'Dropdown' ? lng('panel.pathDescription') : null), 'type' => $pathSelect['type'], 'select_var' => $pathSelect['select_var'] ?? '', + 'selected' => $pathSelect['value'], 'value' => $pathSelect['value'], 'note' => $pathSelect['note'] ?? '', 'mandatory' => true diff --git a/lib/formfields/customer/ftp/formfield.ftp_add.php b/lib/formfields/customer/ftp/formfield.ftp_add.php index 6ae68494..c2320cd2 100644 --- a/lib/formfields/customer/ftp/formfield.ftp_add.php +++ b/lib/formfields/customer/ftp/formfield.ftp_add.php @@ -50,6 +50,7 @@ return [ 'desc' => (Settings::Get('panel.pathedit') != 'Dropdown' ? lng('panel.pathDescription') : null), 'type' => $pathSelect['type'], 'select_var' => $pathSelect['select_var'] ?? '', + 'selected' => $pathSelect['value'], 'value' => $pathSelect['value'], 'note' => $pathSelect['note'] ?? '', 'mandatory' => true diff --git a/lib/formfields/customer/ftp/formfield.ftp_edit.php b/lib/formfields/customer/ftp/formfield.ftp_edit.php index 73bc101b..6375d568 100644 --- a/lib/formfields/customer/ftp/formfield.ftp_edit.php +++ b/lib/formfields/customer/ftp/formfield.ftp_edit.php @@ -42,8 +42,10 @@ return [ 'desc' => (Settings::Get('panel.pathedit') != 'Dropdown' ? lng('panel.pathDescription') : null), 'type' => $pathSelect['type'], 'select_var' => $pathSelect['select_var'] ?? '', + 'selected' => $pathSelect['value'], 'value' => $pathSelect['value'], 'note' => $pathSelect['note'] ?? '', + 'mandatory' => true ], 'ftp_password' => [ 'label' => lng('login.password'), diff --git a/lng/de.lng.php b/lng/de.lng.php index ac447272..7e83832e 100644 --- a/lng/de.lng.php +++ b/lng/de.lng.php @@ -636,6 +636,7 @@ return [ 'openbasedirpath' => 'OpenBasedir-Pfad', 'docroot' => 'Oben angegebener Pfad', 'homedir' => 'Heimverzeichnis', + 'docparent' => 'Elternverzeichnis des oben angegebenen Pfads', ], 'domains' => [ 'description' => 'Hier können Sie (Sub-)Domains erstellen und deren Pfade ändern.
Nach jeder Änderung braucht das System etwas Zeit, um die Konfiguration neu einzulesen.', @@ -655,7 +656,7 @@ return [ 'associated_with_domain' => 'Verbunden mit', 'aliasdomains' => 'Aliasdomains', 'redirectifpathisurl' => 'Redirect-Code (Standard: leer)', - 'redirectifpathisurlinfo' => 'Der Redirect-Code kann gewählt werden, wenn der eingegebene Pfad eine URL ist.
HINWEIS:Änderungen werden nur wirksam wenn der Pfad eine URL ist.', + 'redirectifpathisurlinfo' => 'Der Redirect-Code kann gewählt werden, wenn der eingegebene Pfad eine URL ist.
HINWEIS: Änderungen werden nur wirksam wenn der Pfad eine URL ist.', 'issubof' => 'Diese Domain ist eine Subdomain von der Domain', 'issubofinfo' => 'Diese Einstellung muss gesetzt werden, wenn Sie eine Subdomain einer Hauptdomain als Hauptdomain anlegen (z. B. soll "www.domain.tld" hinzugefügt werden, somit muss hier "domain.tld" ausgewählt werden).', 'nosubtomaindomain' => 'Keine Subdomain einer Hauptdomain', @@ -1132,7 +1133,7 @@ Vielen Dank, Ihr Administrator', 'translator' => 'Übersetzung', 'reset' => 'Änderungen verwerfen', 'pathDescription' => 'Sollte das Verzeichnis nicht existieren, wird es automatisch erstellt.', - 'pathDescriptionEx' => '
Sollte eine Weiterleitung auf eine andere Domain gewünscht sein, muss der Eintrag mit http:// oder https:// beginnen.', + 'pathDescriptionEx' => '

Bitte beachten: Der Pfad / ist nicht erlaubt aufgrund administrativer Einstellungen, er wird automatisch auf /gewaehlte.subdomain.tld/ gesetzt, sofern nicht ein anderer Ordner angegeben wird.', 'pathDescriptionSubdomain' => 'Sollte das Verzeichnis nicht existieren, wird es automatisch erstellt.
Sollte eine Weiterleitung auf eine andere Domain gewünscht sein, muss der Eintrag mit http:// oder https:// beginnen.
Endet die URL mit einem / (Slash) geht Froxlor von einem Ordner aus, wenn nicht, wird es wie eine Datei behandelt.', 'back' => 'Zurück', 'reseller' => 'Reseller', diff --git a/lng/en.lng.php b/lng/en.lng.php index 18436845..658a38e2 100644 --- a/lng/en.lng.php +++ b/lng/en.lng.php @@ -700,6 +700,7 @@ return [ 'openbasedirpath' => 'OpenBasedir-path', 'docroot' => 'Path from field above', 'homedir' => 'Home directory', + 'docparent' => 'Parent-directory of path from field above', ], 'domains' => [ 'description' => 'Here you can create (sub-)domains and change their paths.
The system will need some time to apply the new settings after every change.', @@ -719,7 +720,7 @@ return [ 'associated_with_domain' => 'Associated', 'aliasdomains' => 'Alias domains', 'redirectifpathisurl' => 'Redirect code (default: empty)', - 'redirectifpathisurlinfo' => 'You only need to select one of these if you entered an URL as path
NOTE:Changes are only applied if the given path is an URL.', + 'redirectifpathisurlinfo' => 'You only need to select one of these if you entered an URL as path
NOTE: Changes are only applied if the given path is an URL.', 'issubof' => 'This domain is a subdomain of another domain', 'issubofinfo' => 'You have to set this to the correct domain if you want to add a subdomain as full-domain (e.g. you want to add "www.domain.tld", you have to select "domain.tld" here)', 'nosubtomaindomain' => 'No subdomain of a full domain', @@ -1240,7 +1241,7 @@ Yours sincerely, your administrator', 'translator' => 'Translator', 'reset' => 'Discard changes', 'pathDescription' => 'If the directory doesn\'t exist, it will be created automatically.', - 'pathDescriptionEx' => '

If you want a redirect to another domain than this entry has to start with http:// or https://.', + 'pathDescriptionEx' => '

Please note: The path / is not allowed due to administrative settings, it will automatically be set to /chosen.subdomain.tld/ if not set to another directory.', 'pathDescriptionSubdomain' => 'If the directory doesn\'t exist, it will be created automatically.

If you want a redirect to another domain than this entry has to start with http:// or https://.

If the URL ends with / it is considered a folder, if not, it is treated as file.', 'back' => 'Back', 'reseller' => 'reseller',