]> git.mxchange.org Git - friendica.git/blob - src/Module/Admin/Summary.php
7d159a483c47853fc962c76d461d6514b460a8f9
[friendica.git] / src / Module / Admin / Summary.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2022, 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\Module\Admin;
23
24 use Friendica\App;
25 use Friendica\Core\Addon;
26 use Friendica\Core\Config\ValueObject\Cache;
27 use Friendica\Core\Logger;
28 use Friendica\Core\Renderer;
29 use Friendica\Core\Update;
30 use Friendica\Database\DBA;
31 use Friendica\Database\DBStructure;
32 use Friendica\DI;
33 use Friendica\Core\Config\Factory\Config;
34 use Friendica\Model\Register;
35 use Friendica\Module\BaseAdmin;
36 use Friendica\Network\HTTPClient\Client\HttpClientAccept;
37 use Friendica\Network\HTTPException\ServiceUnavailableException;
38 use Friendica\Network\Probe;
39 use Friendica\Util\DateTimeFormat;
40
41 class Summary extends BaseAdmin
42 {
43         protected function content(array $request = []): string
44         {
45                 parent::content();
46
47                 $a = DI::app();
48
49                 // are there MyISAM tables in the DB? If so, trigger a warning message
50                 $warningtext = [];
51
52                 $templateEngine = Renderer::getTemplateEngine();
53                 $errors = [];
54                 $templateEngine->testInstall($errors);
55                 foreach ($errors as $error) {
56                         $warningtext[] = DI::l10n()->t('Template engine (%s) error: %s', $templateEngine::$name, $error);
57                 }
58
59                 if (DBA::count('information_schema.tables', ['engine' => 'myisam', 'table_schema' => DBA::databaseName()])) {
60                         $warningtext[] = DI::l10n()->t('Your DB still runs with MyISAM tables. You should change the engine type to InnoDB. As Friendica will use InnoDB only features in the future, you should change this! See <a href="%s">here</a> for a guide that may be helpful converting the table engines. You may also use the command <tt>php bin/console.php dbstructure toinnodb</tt> of your Friendica installation for an automatic conversion.<br />', 'https://dev.mysql.com/doc/refman/5.7/en/converting-tables-to-innodb.html');
61                 }
62
63                 // are there InnoDB tables in Antelope in the DB? If so, trigger a warning message
64                 if (DBA::count('information_schema.tables', ['ENGINE' => 'InnoDB', 'ROW_FORMAT' => ['COMPACT', 'REDUNDANT'], 'table_schema' => DBA::databaseName()])) {
65                         $warningtext[] = DI::l10n()->t('Your DB still runs with InnoDB tables in the Antelope file format. You should change the file format to Barracuda. Friendica is using features that are not provided by the Antelope format. See <a href="%s">here</a> for a guide that may be helpful converting the table engines. You may also use the command <tt>php bin/console.php dbstructure toinnodb</tt> of your Friendica installation for an automatic conversion.<br />', 'https://dev.mysql.com/doc/refman/5.7/en/innodb-file-format.html');
66                 }
67
68                 // Avoid the database error 1615 "Prepared statement needs to be re-prepared", see https://github.com/friendica/friendica/issues/8550
69                 if (!DI::config()->get('database', 'pdo_emulate_prepares')) {
70                         $table_definition_cache = DBA::getVariable('table_definition_cache');
71                         $table_open_cache = DBA::getVariable('table_open_cache');
72                         if (!empty($table_definition_cache) && !empty($table_open_cache)) {
73                                 $suggested_definition_cache = min(400 + round($table_open_cache / 2, 1), 2000);
74                                 if ($suggested_definition_cache > $table_definition_cache) {
75                                         $warningtext[] = DI::l10n()->t('Your table_definition_cache is too low (%d). This can lead to the database error "Prepared statement needs to be re-prepared". Please set it at least to %d. See <a href="%s">here</a> for more information.<br />', $table_definition_cache, $suggested_definition_cache, 'https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_table_definition_cache');
76                                 }
77                         }
78                 }
79
80                 // Check if github.com/friendica/stable/VERSION is higher then
81                 // the local version of Friendica. Check is opt-in, source may be stable or develop branch
82                 if (DI::config()->get('system', 'check_new_version_url', 'none') != 'none') {
83                         $gitversion = DI::config()->get('system', 'git_friendica_version');
84                         if (version_compare(App::VERSION, $gitversion) < 0) {
85                                 $warningtext[] = DI::l10n()->t('There is a new version of Friendica available for download. Your current version is %1$s, upstream version is %2$s', App::VERSION, $gitversion);
86                         }
87                 }
88
89                 if (DI::config()->get('system', 'dbupdate', DBStructure::UPDATE_NOT_CHECKED) == DBStructure::UPDATE_NOT_CHECKED) {
90                         DBStructure::performUpdate();
91                 }
92
93                 if (DI::config()->get('system', 'dbupdate') == DBStructure::UPDATE_FAILED) {
94                         $warningtext[] = DI::l10n()->t('The database update failed. Please run "php bin/console.php dbstructure update" from the command line and have a look at the errors that might appear.');
95                 }
96
97                 if (DI::config()->get('system', 'update') == Update::FAILED) {
98                         $warningtext[] = DI::l10n()->t('The last update failed. Please run "php bin/console.php dbstructure update" from the command line and have a look at the errors that might appear. (Some of the errors are possibly inside the logfile.)');
99                 }
100
101                 $last_worker_call = DI::config()->get('system', 'last_worker_execution', false);
102                 if (!$last_worker_call) {
103                         $warningtext[] = DI::l10n()->t('The worker was never executed. Please check your database structure!');
104                 } elseif ((strtotime(DateTimeFormat::utcNow()) - strtotime($last_worker_call)) > 60 * 60) {
105                         $warningtext[] = DI::l10n()->t('The last worker execution was on %s UTC. This is older than one hour. Please check your crontab settings.', $last_worker_call);
106                 }
107
108                 // Legacy config file warning
109                 if (file_exists('.htconfig.php')) {
110                         $warningtext[] = DI::l10n()->t('Friendica\'s configuration now is stored in config/local.config.php, please copy config/local-sample.config.php and move your config from <code>.htconfig.php</code>. See <a href="%s">the Config help page</a> for help with the transition.', DI::baseUrl()->get() . '/help/Config');
111                 }
112
113                 if (file_exists('config/local.ini.php')) {
114                         $warningtext[] = DI::l10n()->t('Friendica\'s configuration now is stored in config/local.config.php, please copy config/local-sample.config.php and move your config from <code>config/local.ini.php</code>. See <a href="%s">the Config help page</a> for help with the transition.', DI::baseUrl()->get() . '/help/Config');
115                 }
116
117                 // Check server vitality
118                 if (!self::checkSelfHostMeta()) {
119                         $well_known = DI::baseUrl()->get() . Probe::HOST_META;
120                         $warningtext[] = DI::l10n()->t('<a href="%s">%s</a> is not reachable on your system. This is a severe configuration issue that prevents server to server communication. See <a href="%s">the installation page</a> for help.',
121                                 $well_known, $well_known, DI::baseUrl()->get() . '/help/Install');
122                 }
123
124                 // Check logfile permission
125                 if (DI::config()->get('system', 'debugging')) {
126                         $file = DI::config()->get('system', 'logfile');
127
128                         $fileSystem = DI::fs();
129
130                         try {
131                                 $stream = $fileSystem->createStream($file);
132
133                                 if (!isset($stream)) {
134                                         throw new ServiceUnavailableException('Stream is null.');
135                                 }
136
137                         } catch (\Throwable $exception) {
138                                 $warningtext[] = DI::l10n()->t('The logfile \'%s\' is not usable. No logging possible (error: \'%s\')', $file, $exception->getMessage());
139                         }
140
141                         $file = DI::config()->get('system', 'dlogfile');
142
143                         try {
144                                 if (!empty($file)) {
145                                         $stream = $fileSystem->createStream($file);
146
147                                         if (!isset($stream)) {
148                                                 throw new ServiceUnavailableException('Stream is null.');
149                                         }
150                                 }
151                         } catch (\Throwable $exception) {
152                                 $warningtext[] = DI::l10n()->t('The debug logfile \'%s\' is not usable. No logging possible (error: \'%s\')', $file, $exception->getMessage());
153                         }
154                 }
155
156                 // check legacy basepath settings
157                 $configLoader = (new Config())->createConfigFileLoader($a->getBasePath(), $_SERVER);
158                 $configCache = new Cache();
159                 $configLoader->setupCache($configCache);
160                 $confBasepath = $configCache->get('system', 'basepath');
161                 $currBasepath = DI::config()->get('system', 'basepath');
162                 if ($confBasepath !== $currBasepath || !is_dir($currBasepath)) {
163                         if (is_dir($confBasepath) && DI::config()->set('system', 'basepath', $confBasepath)) {
164                                 DI::logger()->info('Friendica\'s system.basepath was updated successfully.', [
165                                         'from' => $currBasepath,
166                                         'to'   => $confBasepath,
167                                 ]);
168                                 $warningtext[] = DI::l10n()->t('Friendica\'s system.basepath was updated from \'%s\' to \'%s\'. Please remove the system.basepath from your db to avoid differences.',
169                                         $currBasepath,
170                                         $confBasepath);
171                         } elseif (!is_dir($currBasepath)) {
172                                 DI::logger()->alert('Friendica\'s system.basepath is wrong.', [
173                                         'from' => $currBasepath,
174                                         'to'   => $confBasepath,
175                                 ]);
176                                 $warningtext[] = DI::l10n()->t('Friendica\'s current system.basepath \'%s\' is wrong and the config file \'%s\' isn\'t used.',
177                                         $currBasepath,
178                                         $confBasepath);
179                         } else {
180                                 DI::logger()->alert('Friendica\'s system.basepath is wrong.', [
181                                         'from' => $currBasepath,
182                                         'to'   => $confBasepath,
183                                 ]);
184                                 $warningtext[] = DI::l10n()->t('Friendica\'s current system.basepath \'%s\' is not equal to the config file \'%s\'. Please fix your configuration.',
185                                         $currBasepath,
186                                         $confBasepath);
187                         }
188                 }
189
190                 $accounts = [
191                         [DI::l10n()->t('Normal Account'), 0],
192                         [DI::l10n()->t('Automatic Follower Account'), 0],
193                         [DI::l10n()->t('Public Forum Account'), 0],
194                         [DI::l10n()->t('Automatic Friend Account'), 0],
195                         [DI::l10n()->t('Blog Account'), 0],
196                         [DI::l10n()->t('Private Forum Account'), 0]
197                 ];
198
199                 $users = 0;
200                 $pageFlagsCountStmt = DBA::p('SELECT `page-flags`, COUNT(`uid`) AS `count` FROM `user` WHERE `uid` != ? GROUP BY `page-flags`', 0);
201                 while ($pageFlagsCount = DBA::fetch($pageFlagsCountStmt)) {
202                         $accounts[$pageFlagsCount['page-flags']][1] = $pageFlagsCount['count'];
203                         $users += $pageFlagsCount['count'];
204                 }
205                 DBA::close($pageFlagsCountStmt);
206
207                 Logger::debug('accounts', ['accounts' => $accounts]);
208
209                 $pending = Register::getPendingCount();
210
211                 $deferred = DBA::count('workerqueue', ['NOT `done` AND `retrial` > ?', 0]);
212
213                 $workerqueue = DBA::count('workerqueue', ['NOT `done` AND `retrial` = ?', 0]);
214
215                 // We can do better, but this is a quick queue status
216                 $queues = ['label' => DI::l10n()->t('Message queues'), 'deferred' => $deferred, 'workerq' => $workerqueue];
217
218                 $variables = DBA::toArray(DBA::p('SHOW variables LIKE "max_allowed_packet"'));
219                 $max_allowed_packet = $variables ? $variables[0]['Value'] : 0;
220
221                 $server_settings = [
222                         'label' => DI::l10n()->t('Server Settings'),
223                         'php'   => [
224                                 'upload_max_filesize' => ini_get('upload_max_filesize'),
225                                 'post_max_size'       => ini_get('post_max_size'),
226                                 'memory_limit'        => ini_get('memory_limit')
227                         ],
228                         'mysql' => [
229                                 'max_allowed_packet' => $max_allowed_packet
230                         ]
231                 ];
232
233                 $t = Renderer::getMarkupTemplate('admin/summary.tpl');
234                 return Renderer::replaceMacros($t, [
235                         '$title'          => DI::l10n()->t('Administration'),
236                         '$page'           => DI::l10n()->t('Summary'),
237                         '$queues'         => $queues,
238                         '$users'          => [DI::l10n()->t('Registered users'), $users],
239                         '$accounts'       => $accounts,
240                         '$pending'        => [DI::l10n()->t('Pending registrations'), $pending],
241                         '$version'        => [DI::l10n()->t('Version'), App::VERSION],
242                         '$platform'       => App::PLATFORM,
243                         '$codename'       => App::CODENAME,
244                         '$build'          => DI::config()->get('system', 'build'),
245                         '$addons'         => [DI::l10n()->t('Active addons'), Addon::getEnabledList()],
246                         '$serversettings' => $server_settings,
247                         '$warningtext'    => $warningtext,
248                 ]);
249         }
250
251         private static function checkSelfHostMeta()
252         {
253                 // Fetch the host-meta to check if this really is a vital server
254                 return DI::httpClient()->get(DI::baseUrl()->get() . Probe::HOST_META, HttpClientAccept::XRD_XML)->isSuccess();
255         }
256
257 }