]>
Commit | Line | Data |
---|---|---|
c4ad3d4f A |
1 | <?php |
2 | ||
3 | declare(strict_types=1); | |
4 | ||
5 | namespace Shaarli\Front\Controller\Visitor; | |
6 | ||
c4ad3d4f A |
7 | use Shaarli\Container\ShaarliContainer; |
8 | use Shaarli\Front\Exception\AlreadyInstalledException; | |
9 | use Shaarli\Front\Exception\ResourcePermissionException; | |
c2cd15da | 10 | use Shaarli\Helper\ApplicationUtils; |
c4ad3d4f A |
11 | use Shaarli\Languages; |
12 | use Shaarli\Security\SessionManager; | |
13 | use Slim\Http\Request; | |
14 | use Slim\Http\Response; | |
15 | ||
16 | /** | |
17 | * Slim controller used to render install page, and create initial configuration file. | |
18 | */ | |
19 | class InstallController extends ShaarliVisitorController | |
20 | { | |
21 | public const SESSION_TEST_KEY = 'session_tested'; | |
22 | public const SESSION_TEST_VALUE = 'Working'; | |
23 | ||
24 | public function __construct(ShaarliContainer $container) | |
25 | { | |
26 | parent::__construct($container); | |
27 | ||
28 | if (is_file($this->container->conf->getConfigFileExt())) { | |
29 | throw new AlreadyInstalledException(); | |
30 | } | |
31 | } | |
32 | ||
33 | /** | |
34 | * Display the install template page. | |
35 | * Also test file permissions and sessions beforehand. | |
36 | */ | |
37 | public function index(Request $request, Response $response): Response | |
38 | { | |
39 | // Before installation, we'll make sure that permissions are set properly, and sessions are working. | |
40 | $this->checkPermissions(); | |
41 | ||
53054b2b A |
42 | if ( |
43 | static::SESSION_TEST_VALUE | |
c4ad3d4f A |
44 | !== $this->container->sessionManager->getSessionParameter(static::SESSION_TEST_KEY) |
45 | ) { | |
46 | $this->container->sessionManager->setSessionParameter(static::SESSION_TEST_KEY, static::SESSION_TEST_VALUE); | |
47 | ||
48 | return $this->redirect($response, '/install/session-test'); | |
49 | } | |
50 | ||
51 | [$continents, $cities] = generateTimeZoneData(timezone_identifiers_list(), date_default_timezone_get()); | |
52 | ||
53 | $this->assignView('continents', $continents); | |
54 | $this->assignView('cities', $cities); | |
55 | $this->assignView('languages', Languages::getAvailableLanguages()); | |
56 | ||
0cf76ccb A |
57 | $phpEol = new \DateTimeImmutable(ApplicationUtils::getPhpEol(PHP_VERSION)); |
58 | ||
8a6b7e96 A |
59 | $permissions = array_merge( |
60 | ApplicationUtils::checkResourcePermissions($this->container->conf), | |
61 | ApplicationUtils::checkDatastoreMutex() | |
62 | ); | |
63 | ||
0cf76ccb A |
64 | $this->assignView('php_version', PHP_VERSION); |
65 | $this->assignView('php_eol', format_date($phpEol, false)); | |
66 | $this->assignView('php_has_reached_eol', $phpEol < new \DateTimeImmutable()); | |
67 | $this->assignView('php_extensions', ApplicationUtils::getPhpExtensionsRequirement()); | |
8a6b7e96 | 68 | $this->assignView('permissions', $permissions); |
0cf76ccb A |
69 | |
70 | $this->assignView('pagetitle', t('Install Shaarli')); | |
71 | ||
c4ad3d4f A |
72 | return $response->write($this->render('install')); |
73 | } | |
74 | ||
75 | /** | |
76 | * Route checking that the session parameter has been properly saved between two distinct requests. | |
77 | * If the session parameter is preserved, redirect to install template page, otherwise displays error. | |
78 | */ | |
79 | public function sessionTest(Request $request, Response $response): Response | |
80 | { | |
81 | // This part makes sure sessions works correctly. | |
82 | // (Because on some hosts, session.save_path may not be set correctly, | |
83 | // or we may not have write access to it.) | |
53054b2b A |
84 | if ( |
85 | static::SESSION_TEST_VALUE | |
c4ad3d4f A |
86 | !== $this->container->sessionManager->getSessionParameter(static::SESSION_TEST_KEY) |
87 | ) { | |
88 | // Step 2: Check if data in session is correct. | |
89 | $msg = t( | |
53054b2b A |
90 | '<pre>Sessions do not seem to work correctly on your server.<br>' . |
91 | 'Make sure the variable "session.save_path" is set correctly in your PHP config, ' . | |
92 | 'and that you have write access to it.<br>' . | |
93 | 'It currently points to %s.<br>' . | |
94 | 'On some browsers, accessing your server via a hostname like \'localhost\' ' . | |
95 | 'or any custom hostname without a dot causes cookie storage to fail. ' . | |
c4ad3d4f A |
96 | 'We recommend accessing your server via it\'s IP address or Fully Qualified Domain Name.<br>' |
97 | ); | |
98 | $msg = sprintf($msg, $this->container->sessionManager->getSavePath()); | |
99 | ||
100 | $this->assignView('message', $msg); | |
101 | ||
102 | return $response->write($this->render('error')); | |
103 | } | |
104 | ||
105 | return $this->redirect($response, '/install'); | |
106 | } | |
107 | ||
108 | /** | |
109 | * Save installation form and initialize config file and datastore if necessary. | |
110 | */ | |
111 | public function save(Request $request, Response $response): Response | |
112 | { | |
113 | $timezone = 'UTC'; | |
53054b2b A |
114 | if ( |
115 | !empty($request->getParam('continent')) | |
c4ad3d4f A |
116 | && !empty($request->getParam('city')) |
117 | && isTimeZoneValid($request->getParam('continent'), $request->getParam('city')) | |
118 | ) { | |
119 | $timezone = $request->getParam('continent') . '/' . $request->getParam('city'); | |
120 | } | |
121 | $this->container->conf->set('general.timezone', $timezone); | |
122 | ||
123 | $login = $request->getParam('setlogin'); | |
124 | $this->container->conf->set('credentials.login', $login); | |
53054b2b | 125 | $salt = sha1(uniqid('', true) . '_' . mt_rand()); |
c4ad3d4f A |
126 | $this->container->conf->set('credentials.salt', $salt); |
127 | $this->container->conf->set('credentials.hash', sha1($request->getParam('setpassword') . $login . $salt)); | |
128 | ||
129 | if (!empty($request->getParam('title'))) { | |
130 | $this->container->conf->set('general.title', escape($request->getParam('title'))); | |
131 | } else { | |
132 | $this->container->conf->set( | |
133 | 'general.title', | |
53054b2b | 134 | 'Shared bookmarks on ' . escape(index_url($this->container->environment)) |
c4ad3d4f A |
135 | ); |
136 | } | |
137 | ||
138 | $this->container->conf->set('translation.language', escape($request->getParam('language'))); | |
139 | $this->container->conf->set('updates.check_updates', !empty($request->getParam('updateCheck'))); | |
140 | $this->container->conf->set('api.enabled', !empty($request->getParam('enableApi'))); | |
141 | $this->container->conf->set( | |
142 | 'api.secret', | |
143 | generate_api_secret( | |
144 | $this->container->conf->get('credentials.login'), | |
145 | $this->container->conf->get('credentials.salt') | |
146 | ) | |
147 | ); | |
87ae3c4f | 148 | $this->container->conf->set('general.header_link', $this->container->basePath . '/'); |
c4ad3d4f A |
149 | |
150 | try { | |
151 | // Everything is ok, let's create config file. | |
152 | $this->container->conf->write($this->container->loginManager->isLoggedIn()); | |
153 | } catch (\Exception $e) { | |
3ee8351e A |
154 | $this->assignView('message', t('Error while writing config file after configuration update.')); |
155 | $this->assignView('stacktrace', $e->getMessage() . PHP_EOL . $e->getTraceAsString()); | |
c4ad3d4f A |
156 | |
157 | return $response->write($this->render('error')); | |
158 | } | |
159 | ||
c4ad3d4f A |
160 | $this->container->sessionManager->setSessionParameter( |
161 | SessionManager::KEY_SUCCESS_MESSAGES, | |
162 | [t('Shaarli is now configured. Please login and start shaaring your bookmarks!')] | |
163 | ); | |
164 | ||
87ae3c4f | 165 | return $this->redirect($response, '/login'); |
c4ad3d4f A |
166 | } |
167 | ||
168 | protected function checkPermissions(): bool | |
169 | { | |
170 | // Ensure Shaarli has proper access to its resources | |
0cf76ccb | 171 | $errors = ApplicationUtils::checkResourcePermissions($this->container->conf, true); |
c4ad3d4f A |
172 | if (empty($errors)) { |
173 | return true; | |
174 | } | |
175 | ||
3ee8351e | 176 | $message = t('Insufficient permissions:') . PHP_EOL; |
c4ad3d4f | 177 | foreach ($errors as $error) { |
3ee8351e | 178 | $message .= PHP_EOL . $error; |
c4ad3d4f | 179 | } |
c4ad3d4f A |
180 | |
181 | throw new ResourcePermissionException($message); | |
182 | } | |
183 | } |