Skip to content

Commit 1084a16

Browse files
jaapmarcusalnux
andauthored
Improvements Quick installer (hestiacp#2503)
* hestiacp#2468 Fix mixed ssl content OC * Add PHP version detection to Quick installers Change version if need to a supported version Update Quick installers in general Update versions for MediaWiki, Prestashop and Nextcloud * Bug in wordpress installer * Set drupal installer to the correct dir * Use Supported php version to install the software Prestashop refuses to load with php8.0 * install into specific directory I add the option to install to specific directory, but i dont know if there is a charset filtrate function * I add a number an letters filters only adding a filter numbers and letters * adding directory and other i add directory form text input , utf8mb4 instead of utf8 and random prefix table * Update WordpressSetup.php * databaseAdd utf8mb4 by default adding utf8mb4 on apps by default * Update HestiaApp.php * Change error message when Quick install is disabled * Add French to list And "Remove" code that hides submit button * Typo and set default language to en_US * Add error message why app is not availble Also resolved preformace issue v-list-sys-php caused a lot of delays as it got looked every time a new app was loaded With the current 8 apps it was manageble how ever could go out of hand quickly Co-authored-by: Leonardo Allende Pasten <alnux@users.noreply.github.com>
1 parent e7860dd commit 1084a16

File tree

19 files changed

+431
-148
lines changed

19 files changed

+431
-148
lines changed

bin/v-run-cli-cmd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ if [ "$basecmd" != 'ps' -a \
6666
"$basecmd" != 'php7.4' -a \
6767
"$basecmd" != 'php8.0' -a \
6868
"$basecmd" != 'php' -a \
69+
"$basecmd" != "wp" -a \
6970
"$basecmd" != 'composer' ]; then
7071
check_result "$E_FORBIDEN" "Error: Cli command not enabled"
7172
fi

web/add/webapp/index.php

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@
2121
// Check if domain belongs to the user
2222
$v_domain = $_GET['domain'];
2323
exec(HESTIA_CMD."v-list-web-domain ".$user." ".escapeshellarg($v_domain)." json", $output, $return_var);
24-
if ($return_var > 0){
24+
if ($return_var > 0) {
2525
check_return_code_redirect($return_var, $output, '/list/web/');
2626
}
27-
27+
unset($output);
28+
exec(HESTIA_CMD."v-list-sys-php json", $output, $return_var);
29+
$php_versions = json_decode(implode('', $output), true);
2830
unset($output);
2931

3032
// Check GET request
@@ -37,9 +39,19 @@
3739
try {
3840
$app_installer = new $app_installer_class($v_domain, $hestia);
3941
$info = $app_installer -> info();
40-
if ($info['enabled'] != true) {
41-
$_SESSION['error_msg'] = sprintf(_('%s installer missing'), $app);
42+
foreach ($php_versions as $version) {
43+
if (in_array($version, $info['php_support'])) {
44+
$supported = true;
45+
$supported_versions[] = $version;
46+
}
47+
}
48+
if ($supported) {
49+
$info['enabled'] = true;
4250
} else {
51+
$info['enabled'] = false;
52+
$_SESSION['error_msg'] = sprintf(_('Unable to install %s, %s is not available'), $app, 'PHP-'.end($info['php_support']));
53+
}
54+
if ($info['enabled'] == true) {
4355
$installer = new \Hestia\WebApp\AppWizard($app_installer, $v_domain, $hestia);
4456
$GLOBALS['WebappInstaller'] = $installer;
4557
}
@@ -90,7 +102,21 @@
90102
if ($matches[1] != "Resources") {
91103
$app_installer_class = '\Hestia\WebApp\Installers\\'.$matches[1].'\\' . $matches[1] . 'Setup';
92104
$app_installer = new $app_installer_class($v_domain, $hestia);
93-
$v_web_apps[] = $app_installer -> info();
105+
$appInstallerInfo = $app_installer -> info();
106+
$supported = false;
107+
$supported_versions = array();
108+
foreach ($php_versions as $version) {
109+
if (in_array($version, $appInstallerInfo['php_support'])) {
110+
$supported = true;
111+
$supported_versions[] = $version;
112+
}
113+
}
114+
if ($supported) {
115+
$appInstallerInfo['enabled'] = true;
116+
} else {
117+
$appInstallerInfo['enabled'] = false;
118+
}
119+
$v_web_apps[] = $appInstallerInfo;
94120
}
95121
}
96122
}

web/src/app/System/HestiaApp.php

Lines changed: 97 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,17 @@
44

55
namespace Hestia\System;
66

7-
class HestiaApp {
8-
7+
class HestiaApp
8+
{
99
protected const TMPDIR_DOWNLOADS="/tmp/hestia-webapp";
10+
protected $phpsupport = false;
1011

11-
public function __construct() {
12+
public function __construct()
13+
{
1214
@mkdir(self::TMPDIR_DOWNLOADS);
1315
}
1416

15-
public function run(string $cmd, $args, &$cmd_result=null) : bool
17+
public function run(string $cmd, $args, &$cmd_result=null): bool
1618
{
1719
$cli_script = HESTIA_CMD . '/' . basename($cmd);
1820
$cli_arguments = '';
@@ -25,19 +27,24 @@ public function run(string $cmd, $args, &$cmd_result=null) : bool
2527
$cli_arguments = escapeshellarg($args);
2628
}
2729

28-
exec ($cli_script . ' ' . $cli_arguments . ' 2>&1', $output, $exit_code);
30+
exec($cli_script . ' ' . $cli_arguments . ' 2>&1', $output, $exit_code);
2931

3032
$result['code'] = $exit_code;
3133
$result['args'] = $cli_arguments;
3234
$result['raw'] = $output;
33-
$result['text'] = implode( PHP_EOL, $output);
35+
$result['text'] = implode(PHP_EOL, $output);
3436
$result['json'] = json_decode($result['text'], true);
3537
$cmd_result = (object)$result;
36-
38+
if ($exit_code > 0) {
39+
//log error message in nginx-error.log
40+
trigger_error($result['text']);
41+
//throw exception if command fails
42+
throw new \Exception($result['text']);
43+
}
3744
return ($exit_code === 0);
3845
}
3946

40-
public function runUser(string $cmd, $args, &$cmd_result=null) : bool
47+
public function runUser(string $cmd, $args, &$cmd_result=null): bool
4148
{
4249
if (!empty($args) && is_array($args)) {
4350
array_unshift($args, $this->user());
@@ -53,13 +60,13 @@ public function installComposer($version)
5360

5461
$signature = implode(PHP_EOL, $output);
5562
if (empty($signature)) {
56-
throw new \Exception("Error reading composer signature");
63+
throw new \Exception("Error reading composer signature");
5764
}
5865

5966
$composer_setup = self::TMPDIR_DOWNLOADS . DIRECTORY_SEPARATOR . 'composer-setup-' . $signature . '.php';
6067

6168
exec("wget https://getcomposer.org/installer --quiet -O " . escapeshellarg($composer_setup), $output, $return_code);
62-
if ($return_code !== 0 ) {
69+
if ($return_code !== 0) {
6370
throw new \Exception("Error downloading composer");
6471
}
6572

@@ -69,33 +76,34 @@ public function installComposer($version)
6976
}
7077

7178
$install_folder = $this->getUserHomeDir() . DIRECTORY_SEPARATOR . '.composer';
72-
79+
7380
if (!file_exists($install_folder)) {
7481
exec(HESTIA_CMD .'v-rebuild-user '.$this -> user(), $output, $return_code);
75-
if($return_code !== 0){
82+
if ($return_code !== 0) {
7683
throw new \Exception("Unable to rebuild user");
7784
}
7885
}
79-
86+
8087
$this->runUser('v-run-cli-cmd', ["/usr/bin/php", $composer_setup, "--quiet", "--install-dir=".$install_folder, "--filename=composer", "--$version" ], $status);
8188

8289
unlink($composer_setup);
8390

84-
if ($status->code !== 0 ) {
91+
if ($status->code !== 0) {
8592
throw new \Exception("Error installing composer");
8693
}
8794
}
88-
89-
public function updateComposer($version){
95+
96+
public function updateComposer($version)
97+
{
9098
$this->runUser('v-run-cli-cmd', ["composer", "selfupdate","--$version"]);
9199
}
92100

93-
public function runComposer($args, &$cmd_result=null,$version=1) : bool
101+
public function runComposer($args, &$cmd_result=null, $version=1): bool
94102
{
95103
$composer = $this->getUserHomeDir() . DIRECTORY_SEPARATOR . '.composer' . DIRECTORY_SEPARATOR . 'composer';
96-
if(!is_file($composer)) {
104+
if (!is_file($composer)) {
97105
$this->installComposer($version);
98-
}else{
106+
} else {
99107
$this->updateComposer($version);
100108
}
101109

@@ -108,21 +116,34 @@ public function runComposer($args, &$cmd_result=null,$version=1) : bool
108116
return $this->runUser('v-run-cli-cmd', $args, $cmd_result);
109117
}
110118

119+
public function runWp($args, &$cmd_result=null): bool
120+
{
121+
$wp = $this->getUserHomeDir() . DIRECTORY_SEPARATOR . '.wp' . DIRECTORY_SEPARATOR . 'wp';
122+
if (!is_file($wp)) {
123+
$this -> runUser('v-add-user-wp-cli');
124+
} else {
125+
$this->runUser('v-run-cli-cmd', [$wp, 'cli', 'update']);
126+
}
127+
array_unshift($args, $wp);
128+
129+
return $this->runUser('v-run-cli-cmd', $args, $cmd_result);
130+
}
131+
111132
// Logged in user
112-
public function realuser() : string
133+
public function realuser(): string
113134
{
114135
return $_SESSION['user'];
115136
}
116137

117138
// Effective user
118-
public function user() : string
139+
public function user(): string
119140
{
120141
$user = $this->realuser();
121142
if ($_SESSION['userContext'] === 'admin' && !empty($_SESSION['look'])) {
122143
$user = $_SESSION['look'];
123144
}
124145

125-
if(strpos($user, DIRECTORY_SEPARATOR) !== false) {
146+
if (strpos($user, DIRECTORY_SEPARATOR) !== false) {
126147
throw new \Exception("illegal characters in username");
127148
}
128149
return $user;
@@ -134,25 +155,65 @@ public function getUserHomeDir()
134155
return $info['dir'];
135156
}
136157

137-
public function userOwnsDomain(string $domain) : bool
158+
public function userOwnsDomain(string $domain): bool
138159
{
139160
return $this->runUser('v-list-web-domain', [$domain, 'json']);
140161
}
141162

142-
public function databaseAdd(string $dbname, string $dbuser, string $dbpass)
163+
public function databaseAdd(string $dbname, string $dbuser, string $dbpass, string $charset = 'utf8mb4')
143164
{
144-
$v_password = tempnam("/tmp","hst");
165+
$v_password = tempnam("/tmp", "hst");
145166
$fp = fopen($v_password, "w");
146167
fwrite($fp, $dbpass."\n");
147168
fclose($fp);
148-
$status = $this->runUser('v-add-database', [$dbname, $dbuser, $v_password]);
169+
$status = $this->runUser('v-add-database', [$dbname, $dbuser, $v_password, 'mysql', 'localhost', $charset]);
149170
unlink($v_password);
150171
return $status;
151172
}
152-
153-
public function changeWebTemplate(string $domain, string $template){
173+
174+
public function changeWebTemplate(string $domain, string $template)
175+
{
154176
$status = $this->runUser('v-change-web-domain-tpl', [$domain, $template]);
155-
}
177+
}
178+
public function changeBackendTemplate(string $domain, string $template)
179+
{
180+
$status = $this->runUser('v-change-web-domain-backend-tpl', [$domain, $template]);
181+
}
182+
183+
public function listSuportedPHP()
184+
{
185+
if (!$this -> phpsupport) {
186+
$status = $this -> run('v-list-sys-php', 'json', $result);
187+
$this -> phpsupport = $result -> json;
188+
}
189+
return $this -> phpsupport;
190+
}
191+
192+
/*
193+
Return highest available supported php version
194+
Eg: Package requires: 7.3 or 7.4 and system has 8.0 and 7.4 it will return 7.4
195+
Package requires: 8.0 or 8.1 and system has 8.0 and 7.4 it will return 8.0
196+
Package requires: 7.4 or 8.0 and system has 8.0 and 7.4 it will return 8.0
197+
If package isn't supported by the available php version false will returned
198+
*/
199+
public function getSupportedPHP($support)
200+
{
201+
$versions = $this -> listSuportedPHP();
202+
$supported = false;
203+
$supported_versions = array();
204+
205+
foreach ($versions as $version) {
206+
if (in_array($version, $support)) {
207+
$supported = true;
208+
$supported_versions[] = $version;
209+
}
210+
}
211+
if ($supported) {
212+
return $supported_versions[count($supported_versions) - 1];
213+
} else {
214+
return false;
215+
}
216+
}
156217

157218
public function getWebDomainIp(string $domain)
158219
{
@@ -163,13 +224,13 @@ public function getWebDomainIp(string $domain)
163224

164225
public function getWebDomainPath(string $domain)
165226
{
166-
return Util::join_paths( $this->getUserHomeDir() , "web", $domain);
227+
return Util::join_paths($this->getUserHomeDir(), "web", $domain);
167228
}
168229

169230
public function downloadUrl(string $src, $path=null, &$result=null)
170231
{
171-
if (strpos($src,'http://') !== 0 &&
172-
strpos($src,'https://')!== 0 ) {
232+
if (strpos($src, 'http://') !== 0 &&
233+
strpos($src, 'https://')!== 0) {
173234
return false;
174235
}
175236

@@ -178,11 +239,11 @@ public function downloadUrl(string $src, $path=null, &$result=null)
178239
return false;
179240
}
180241

181-
if(!preg_match('/URL:\s*(.+?)\s*\[(.+?)\]\s*->\s*"(.+?)"/', implode(PHP_EOL, $output), $matches)) {
242+
if (!preg_match('/URL:\s*(.+?)\s*\[(.+?)\]\s*->\s*"(.+?)"/', implode(PHP_EOL, $output), $matches)) {
182243
return false;
183244
}
184245

185-
if(empty($matches) || count($matches) != 4) {
246+
if (empty($matches) || count($matches) != 4) {
186247
return false;
187248
}
188249

@@ -200,8 +261,8 @@ public function archiveExtract(string $src, string $path, $skip_components=null)
200261

201262
if (realpath($src)) {
202263
$archive_file = $src;
203-
} else {
204-
if( !$this->downloadUrl($src, null, $download_result) ) {
264+
} else {
265+
if (!$this->downloadUrl($src, null, $download_result)) {
205266
throw new \Exception("Error downloading archive");
206267
}
207268
$archive_file = $download_result->file;

web/src/app/System/Util.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,12 @@ public static function join_paths()
2121
return preg_replace('#/+#', '/', join('/', $paths));
2222
}
2323

24-
public static function generate_string(int $length = 16)
24+
public static function generate_string(int $length = 16, $full = true)
2525
{
26-
$chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~`!@|#[]$%^&*() _-=+{}:;<>?,./';
26+
$chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
27+
if ($full) {
28+
$chars .= '~`!@|#[]$%^&*() _-=+{}:;<>?,./';
29+
}
2730
$random_string = '';
2831
for ($i = 0; $i < $length; $i++) {
2932
$random_string .= $chars[random_int(0, strlen($chars) - 1)];

0 commit comments

Comments
 (0)