]> git.mxchange.org Git - friendica.git/blob - src/Console/AutomaticInstallation.php
bump version 2023.12
[friendica.git] / src / Console / AutomaticInstallation.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2023, the Friendica project
4  *
5  * @license GNU AGPL version 3 or any later version
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  *
20  */
21
22 namespace Friendica\Console;
23
24 use Asika\SimpleConsole\Console;
25 use Friendica\App;
26 use Friendica\App\BaseURL;
27 use Friendica\Core\Config\Capability\IManageConfigValues;
28 use Friendica\Core\Config\ValueObject\Cache;
29 use Friendica\Core\Installer;
30 use Friendica\Core\Theme;
31 use Friendica\Database\Database;
32 use Friendica\Util\BasePath;
33 use RuntimeException;
34
35 class AutomaticInstallation extends Console
36 {
37         /** @var App\Mode */
38         private $appMode;
39         /** @var \Friendica\Core\Config\ValueObject\Cache */
40         private $configCache;
41         /** @var IManageConfigValues */
42         private $config;
43         /** @var Database */
44         private $dba;
45
46         protected function getHelp()
47         {
48                 return <<<HELP
49 Installation - Install Friendica automatically
50 Synopsis
51         bin/console autoinstall [-h|--help|-?] [-v] [-a] [-f]
52
53 Description
54     Installs Friendica with data based on the local.config.php file or environment variables
55
56 Notes
57     Not checking .htaccess/URL-Rewrite during CLI installation.
58
59 Options
60     -h|--help|-?            Show help information
61     -v                      Show more debug information.
62     -a                      All setup checks are required (except .htaccess)
63     -f|--file <config>      prepared config file (e.g. "config/local.config.php" itself) which will override every other config option - except the environment variables)
64     -s|--savedb               Save the DB credentials to the file (if environment variables is used)
65     -H|--dbhost <host>        The host of the mysql/mariadb database (env MYSQL_HOST)
66     -p|--dbport <port>        The port of the mysql/mariadb database (env MYSQL_PORT)
67     -s|--dbsocket <socket>    The socket of the mysql/mariadb database (env MYSQL_SOCKET)
68     -d|--dbdata <database>    The name of the mysql/mariadb database (env MYSQL_DATABASE)
69     -u|--dbuser <username>    The username of the mysql/mariadb database login (env MYSQL_USER or MYSQL_USERNAME)
70     -P|--dbpass <password>    The password of the mysql/mariadb database login (env MYSQL_PASSWORD)
71     -U|--url <url>            The full base URL of Friendica - f.e. 'https://friendica.local/sub' (env FRIENDICA_URL) 
72     -B|--phppath <php_path>   The path of the PHP binary (env FRIENDICA_PHP_PATH)
73     -b|--basepath <base_path> The basepath of Friendica (env FRIENDICA_BASE_PATH)
74     -t|--tz <timezone>        The timezone of Friendica (env FRIENDICA_TZ)
75     -L|--lang <language>      The language of Friendica (env FRIENDICA_LANG)
76  
77 Environment variables
78    MYSQL_HOST                  The host of the mysql/mariadb database (mandatory if mysql and environment is used)
79    MYSQL_PORT                  The port of the mysql/mariadb database
80    MYSQL_SOCKET                The socket of the mysql/mariadb database
81    MYSQL_USERNAME|MYSQL_USER   The username of the mysql/mariadb database login (MYSQL_USERNAME is for mysql, MYSQL_USER for mariadb)
82    MYSQL_PASSWORD              The password of the mysql/mariadb database login
83    MYSQL_DATABASE              The name of the mysql/mariadb database
84    FRIENDICA_URL               The full base URL of Friendica - f.e. 'https://friendica.local/sub'
85    FRIENDICA_PHP_PATH          The path of the PHP binary - leave empty for auto detection
86    FRIENDICA_BASE_PATH         The basepath of Friendica - leave empty for auto detection
87    FRIENDICA_ADMIN_MAIL        The admin email address of Friendica (this email will be used for admin access)
88    FRIENDICA_TZ                The timezone of Friendica
89    FRIENDICA_LANG              The langauge of Friendica
90    
91 Examples
92         bin/console autoinstall -f 'input.config.php
93                 Installs Friendica with the prepared 'input.config.php' file
94
95         bin/console autoinstall --savedb
96                 Installs Friendica with environment variables and saves them to the 'config/local.config.php' file
97
98         bin/console autoinstall -H localhost -p 3365 -u user -P password1234 -d friendica -U https://friendica.fqdn
99                 Installs Friendica with a local mysql database with credentials
100 HELP;
101         }
102
103         public function __construct(App\Mode $appMode, Cache $configCache, IManageConfigValues $config, Database $dba, array $argv = null)
104         {
105                 parent::__construct($argv);
106
107                 $this->appMode     = $appMode;
108                 $this->configCache = $configCache;
109                 $this->config      = $config;
110                 $this->dba         = $dba;
111         }
112
113         protected function doExecute(): int
114         {
115                 // Initialise the app
116                 $this->out("Initializing setup...");
117
118                 $installer = new Installer();
119
120                 $configCache  = $this->configCache;
121                 $basePathConf = $configCache->get('system', 'basepath');
122                 $basepath     = new BasePath($basePathConf);
123                 $installer->setUpCache($configCache, $basepath->getPath());
124
125                 $this->out(" Complete!\n");
126
127                 // Check Environment
128                 $this->out("Checking environment...");
129
130                 $installer->resetChecks();
131
132                 if (!$this->runBasicChecks($installer, $configCache)) {
133                         $errorMessage = $this->extractErrors($installer->getChecks());
134                         throw new RuntimeException($errorMessage);
135                 }
136
137                 $this->out(" Complete!\n");
138
139                 // if a config file is set,
140                 $config_file = $this->getOption(['f', 'file']);
141
142                 if (!empty($config_file)) {
143                         $this->out("Loading config file '$config_file'...");
144                         if (!file_exists($config_file)) {
145                                 throw new RuntimeException("ERROR: Config file does not exist.");
146                         }
147
148                         //append config file to the config cache
149                         $config = include($config_file);
150                         if (!is_array($config)) {
151                                 throw new Exception('Error loading config file ' . $config_file);
152                         }
153                         $configCache->load($config, Cache::SOURCE_FILE);
154                 } else {
155                         // Creating config file
156                         $this->out("Creating config file...");
157
158                         $save_db = $this->getOption(['s', 'savedb'], false);
159
160                         $db_host = $this->getOption(['H', 'dbhost'], ($save_db) ? (getenv('MYSQL_HOST')) : Installer::DEFAULT_HOST);
161                         $db_port = $this->getOption(['p', 'dbport'], ($save_db) ? getenv('MYSQL_PORT') : null);
162                         $db_socket = $this->getOption(['s', 'dbsocket'], ($save_db) ? getenv('MYSQL_SOCKET') : null);
163                         $configCache->set('database', 'hostname', $db_host . (!empty($db_port) ? ':' . $db_port : ''));
164                         $configCache->set('database', 'database',
165                                 $this->getOption(['d', 'dbdata'],
166                                         ($save_db) ? getenv('MYSQL_DATABASE') : ''));
167                         $configCache->set('database', 'username',
168                                 $this->getOption(['u', 'dbuser'],
169                                         ($save_db) ? getenv('MYSQL_USER') . getenv('MYSQL_USERNAME') : ''));
170                         $configCache->set('database', 'password',
171                                 $this->getOption(['P', 'dbpass'],
172                                         ($save_db) ? getenv('MYSQL_PASSWORD') : ''));
173
174                         $php_path = $this->getOption(['b', 'phppath'], !empty('FRIENDICA_PHP_PATH') ? getenv('FRIENDICA_PHP_PATH') : null);
175                         if (!empty($php_path)) {
176                                 $configCache->set('config', 'php_path', $php_path);
177                         } else {
178                                 $configCache->set('config', 'php_path', $installer->getPHPPath());
179                         }
180
181                         $configCache->set('config', 'admin_email',
182                                 $this->getOption(['A', 'admin'],
183                                         !empty(getenv('FRIENDICA_ADMIN_MAIL')) ? getenv('FRIENDICA_ADMIN_MAIL') : ''));
184                         $configCache->set('system', 'default_timezone',
185                                 $this->getOption(['T', 'tz'],
186                                         !empty(getenv('FRIENDICA_TZ')) ? getenv('FRIENDICA_TZ') : Installer::DEFAULT_TZ));
187                         $configCache->set('system', 'language',
188                                 $this->getOption(['L', 'lang'],
189                                         !empty(getenv('FRIENDICA_LANG')) ? getenv('FRIENDICA_LANG') : Installer::DEFAULT_LANG));
190
191                         $basepath = $this->getOption(['b', 'basepath'], !empty(getenv('FRIENDICA_BASE_PATH')) ? getenv('FRIENDICA_BASE_PATH') : null);
192                         if (!empty($basepath)) {
193                                 $configCache->set('system', 'basepath', $basepath);
194                         }
195
196                         $url = $this->getOption(['U', 'url'], !empty(getenv('FRIENDICA_URL')) ? getenv('FRIENDICA_URL') : null);
197
198                         if (empty($url)) {
199                                 $this->out('The Friendica URL has to be set during CLI installation.');
200                                 return 1;
201                         } else {
202                                 $configCache->set('system', 'url', $url);
203                         }
204
205                         $installer->createConfig($configCache);
206                 }
207
208                 $this->out(" Complete!\n");
209
210                 // Check database connection
211                 $this->out("Checking database...");
212
213                 $installer->resetChecks();
214
215                 if (!$installer->checkDB($this->dba)) {
216                         $errorMessage = $this->extractErrors($installer->getChecks());
217                         throw new RuntimeException($errorMessage);
218                 }
219
220                 $this->out(" Complete!\n");
221
222                 // Install database
223                 $this->out("Inserting data into database...\n");
224
225                 $installer->resetChecks();
226
227                 if (!$installer->installDatabase()) {
228                         $errorMessage = $this->extractErrors($installer->getChecks());
229                         throw new RuntimeException($errorMessage);
230                 }
231
232                 if (!empty($config_file) && $config_file != 'config' . DIRECTORY_SEPARATOR . 'local.config.php') {
233                         // Copy config file
234                         $this->out("Copying config file...");
235                         if (!copy($config_file, $basePathConf . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'local.config.php')) {
236                                 throw new RuntimeException("ERROR: Saving config file failed. Please copy '$config_file' to '" . $basePathConf . "'" . DIRECTORY_SEPARATOR . "config" . DIRECTORY_SEPARATOR . "local.config.php' manually.\n");
237                         }
238                 }
239
240                 $this->out(" Complete!\n");
241
242                 // Install theme
243                 $this->out("Installing theme");
244                 if (!empty($this->config->get('system', 'theme'))) {
245                         Theme::install($this->config->get('system', 'theme'));
246                         $this->out(" Complete\n");
247                 } else {
248                         $this->out(" Theme setting is empty. Please check the file 'config/local.config.php'\n");
249                 }
250
251                 $this->out("\nInstallation is finished");
252
253                 return 0;
254         }
255
256         /**
257          * @param Installer                                $installer   The Installer instance
258          * @param \Friendica\Core\Config\ValueObject\Cache $configCache The config cache
259          *
260          * @return bool true if checks were successfully, otherwise false
261          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
262          */
263         private function runBasicChecks(Installer $installer, Cache $configCache)
264         {
265                 $checked = true;
266
267                 $installer->resetChecks();
268                 if (!$installer->checkFunctions()) {
269                         $checked = false;
270                 }
271                 if (!$installer->checkImagick()) {
272                         $checked = false;
273                 }
274                 if (!$installer->checkLocalIni()) {
275                         $checked = false;
276                 }
277                 if (!$installer->checkSmarty3()) {
278                         $checked = false;
279                 }
280                 if (!$installer->checkKeys()) {
281                         $checked = false;
282                 }
283
284                 $php_path = $configCache->get('config', 'php_path');
285
286                 if (!$installer->checkPHP($php_path, true)) {
287                         $checked = false;
288                 }
289
290                 $this->out(" NOTICE: Not checking .htaccess/URL-Rewrite during CLI installation.\n");
291
292                 return $checked;
293         }
294
295         /**
296          * @param array $results
297          *
298          * @return string
299          */
300         private function extractErrors($results)
301         {
302                 $errorMessage      = '';
303                 $allChecksRequired = $this->getOption('a') !== null;
304
305                 foreach ($results as $result) {
306                         if (($allChecksRequired || $result['required'] === true) && $result['status'] === false) {
307                                 $errorMessage .= "--------\n";
308                                 $errorMessage .= $result['title'] . ': ' . $result['help'] . "\n";
309                         }
310                 }
311
312                 return $errorMessage;
313         }
314 }